1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/gfx/gtk_preserve_window.h"
10 #include "ui/base/gtk/gtk_compat.h"
14 #define GTK_PRESERVE_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
15 GTK_TYPE_PRESERVE_WINDOW, \
16 GtkPreserveWindowPrivate))
18 typedef struct _GtkPreserveWindowPrivate GtkPreserveWindowPrivate
;
20 struct _GtkPreserveWindowPrivate
{
21 // If true, don't create/destroy windows on realize/unrealize.
22 gboolean preserve_window
;
24 // Whether or not we delegate the resize of the GdkWindow
26 gboolean delegate_resize
;
28 // Accessible factory and userdata.
29 AtkObject
* (*accessible_factory
)(void* userdata
);
30 void* accessible_factory_userdata
;
33 G_DEFINE_TYPE(GtkPreserveWindow
, gtk_preserve_window
, GTK_TYPE_FIXED
)
35 static void gtk_preserve_window_destroy(GtkObject
* object
);
36 static void gtk_preserve_window_realize(GtkWidget
* widget
);
37 static void gtk_preserve_window_unrealize(GtkWidget
* widget
);
38 static void gtk_preserve_window_size_allocate(GtkWidget
* widget
,
39 GtkAllocation
* allocation
);
40 static AtkObject
* gtk_preserve_window_get_accessible(GtkWidget
* widget
);
42 static void gtk_preserve_window_class_init(GtkPreserveWindowClass
*klass
) {
43 GtkWidgetClass
* widget_class
= reinterpret_cast<GtkWidgetClass
*>(klass
);
44 widget_class
->realize
= gtk_preserve_window_realize
;
45 widget_class
->unrealize
= gtk_preserve_window_unrealize
;
46 widget_class
->size_allocate
= gtk_preserve_window_size_allocate
;
47 widget_class
->get_accessible
= gtk_preserve_window_get_accessible
;
49 GtkObjectClass
* object_class
= reinterpret_cast<GtkObjectClass
*>(klass
);
50 object_class
->destroy
= gtk_preserve_window_destroy
;
52 GObjectClass
* gobject_class
= G_OBJECT_CLASS(klass
);
53 g_type_class_add_private(gobject_class
, sizeof(GtkPreserveWindowPrivate
));
56 static void gtk_preserve_window_init(GtkPreserveWindow
* widget
) {
57 GtkPreserveWindowPrivate
* priv
= GTK_PRESERVE_WINDOW_GET_PRIVATE(widget
);
58 priv
->preserve_window
= FALSE
;
59 priv
->accessible_factory
= NULL
;
60 priv
->accessible_factory_userdata
= NULL
;
62 // These widgets always have their own window.
63 gtk_widget_set_has_window(GTK_WIDGET(widget
), TRUE
);
66 GtkWidget
* gtk_preserve_window_new() {
67 return GTK_WIDGET(g_object_new(GTK_TYPE_PRESERVE_WINDOW
, NULL
));
70 static void gtk_preserve_window_destroy(GtkObject
* object
) {
71 GtkWidget
* widget
= reinterpret_cast<GtkWidget
*>(object
);
72 GtkPreserveWindowPrivate
* priv
= GTK_PRESERVE_WINDOW_GET_PRIVATE(widget
);
74 GdkWindow
* gdk_window
= gtk_widget_get_window(widget
);
76 gdk_window_set_user_data(gdk_window
, NULL
);
77 // If the window is preserved, someone else must destroy it.
78 if (!priv
->preserve_window
)
79 gdk_window_destroy(gdk_window
);
80 gtk_widget_set_window(widget
, NULL
);
83 GTK_OBJECT_CLASS(gtk_preserve_window_parent_class
)->destroy(object
);
86 static void gtk_preserve_window_realize(GtkWidget
* widget
) {
87 g_return_if_fail(GTK_IS_PRESERVE_WINDOW(widget
));
89 GdkWindow
* gdk_window
= gtk_widget_get_window(widget
);
91 GtkAllocation allocation
;
92 gtk_widget_get_allocation(widget
, &allocation
);
94 gdk_window_reparent(gdk_window
,
95 gtk_widget_get_parent_window(widget
),
98 GtkPreserveWindowPrivate
* priv
= GTK_PRESERVE_WINDOW_GET_PRIVATE(widget
);
99 if (!priv
->delegate_resize
) {
100 gdk_window_resize(gdk_window
,
104 gint event_mask
= gtk_widget_get_events(widget
);
105 event_mask
|= GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
;
106 gdk_window_set_events(gdk_window
, (GdkEventMask
) event_mask
);
107 gdk_window_set_user_data(gdk_window
, widget
);
109 gtk_widget_set_realized(widget
, TRUE
);
111 gtk_widget_style_attach(widget
);
112 gtk_style_set_background(gtk_widget_get_style(widget
),
113 gdk_window
, GTK_STATE_NORMAL
);
115 GTK_WIDGET_CLASS(gtk_preserve_window_parent_class
)->realize(widget
);
119 static void gtk_preserve_window_unrealize(GtkWidget
* widget
) {
120 g_return_if_fail(GTK_IS_PRESERVE_WINDOW(widget
));
122 GtkPreserveWindowPrivate
* priv
= GTK_PRESERVE_WINDOW_GET_PRIVATE(widget
);
123 if (priv
->preserve_window
) {
124 GtkWidgetClass
* widget_class
=
125 GTK_WIDGET_CLASS(gtk_preserve_window_parent_class
);
126 GtkContainerClass
* container_class
=
127 GTK_CONTAINER_CLASS(gtk_preserve_window_parent_class
);
129 if (gtk_widget_get_mapped(widget
)) {
130 widget_class
->unmap(widget
);
132 gtk_widget_set_mapped(widget
, FALSE
);
135 // This is the behavior from GtkWidget, inherited by GtkFixed.
136 // It is unclear why we should not call the potentially overridden
137 // unrealize method (via the callback), but doing so causes errors.
138 container_class
->forall(
139 GTK_CONTAINER(widget
), FALSE
,
140 reinterpret_cast<GtkCallback
>(gtk_widget_unrealize
), NULL
);
142 GdkWindow
* gdk_window
= gtk_widget_get_window(widget
);
144 // TODO(erg): Almost all style handling will need to be overhauled in GTK3.
145 gtk_style_detach(gtk_widget_get_style(widget
));
146 gdk_window_reparent(gdk_window
, gdk_get_default_root_window(), 0, 0);
147 gtk_selection_remove_all(widget
);
148 gdk_window_set_user_data(gdk_window
, NULL
);
150 gtk_widget_set_realized(widget
, FALSE
);
152 GTK_WIDGET_CLASS(gtk_preserve_window_parent_class
)->unrealize(widget
);
156 gboolean
gtk_preserve_window_get_preserve(GtkPreserveWindow
* window
) {
157 g_return_val_if_fail(GTK_IS_PRESERVE_WINDOW(window
), FALSE
);
158 GtkPreserveWindowPrivate
* priv
= GTK_PRESERVE_WINDOW_GET_PRIVATE(window
);
160 return priv
->preserve_window
;
163 void gtk_preserve_window_set_preserve(GtkPreserveWindow
* window
,
165 g_return_if_fail(GTK_IS_PRESERVE_WINDOW(window
));
166 GtkPreserveWindowPrivate
* priv
= GTK_PRESERVE_WINDOW_GET_PRIVATE(window
);
167 priv
->preserve_window
= value
;
169 GtkWidget
* widget
= GTK_WIDGET(window
);
170 GdkWindow
* gdk_window
= gtk_widget_get_window(widget
);
171 if (value
&& !gdk_window
) {
172 GdkWindowAttr attributes
;
173 gint attributes_mask
;
175 // We may not know the width and height, so we rely on the fact
176 // that a size-allocation will resize it later.
177 attributes
.width
= 1;
178 attributes
.height
= 1;
180 attributes
.window_type
= GDK_WINDOW_CHILD
;
181 attributes
.wclass
= GDK_INPUT_OUTPUT
;
182 attributes
.override_redirect
= TRUE
;
184 attributes
.visual
= gtk_widget_get_visual(widget
);
185 attributes
.colormap
= gtk_widget_get_colormap(widget
);
187 attributes
.event_mask
= gtk_widget_get_events(widget
);
188 attributes
.event_mask
|= GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
;
190 attributes_mask
= GDK_WA_VISUAL
| GDK_WA_COLORMAP
| GDK_WA_NOREDIR
;
191 gdk_window
= gdk_window_new(
192 gdk_get_default_root_window(), &attributes
, attributes_mask
);
193 gtk_widget_set_window(widget
, gdk_window
);
194 } else if (!value
&& gdk_window
&& !gtk_widget_get_realized(widget
)) {
195 gdk_window_destroy(gdk_window
);
196 gtk_widget_set_window(widget
, NULL
);
200 void gtk_preserve_window_size_allocate(GtkWidget
* widget
,
201 GtkAllocation
* allocation
) {
202 g_return_if_fail(GTK_IS_PRESERVE_WINDOW(widget
));
204 gtk_widget_set_allocation(widget
, allocation
);
206 if (gtk_widget_get_realized(widget
)) {
207 GtkPreserveWindowPrivate
* priv
= GTK_PRESERVE_WINDOW_GET_PRIVATE(widget
);
208 GdkWindow
* gdk_window
= gtk_widget_get_window(widget
);
209 if (priv
->delegate_resize
) {
210 gdk_window_move(gdk_window
, allocation
->x
, allocation
->y
);
212 gdk_window_move_resize(
213 gdk_window
, allocation
->x
, allocation
->y
,
214 allocation
->width
, allocation
->height
);
218 // Propagate resize to children
219 guint16 border_width
= gtk_container_get_border_width(GTK_CONTAINER(widget
));
220 GList
*children
= GTK_FIXED(widget
)->children
;
222 GtkFixedChild
*child
= reinterpret_cast<GtkFixedChild
*>(children
->data
);
223 if (gtk_widget_get_visible(child
->widget
)) {
224 GtkRequisition child_requisition
;
225 gtk_widget_get_child_requisition(child
->widget
, &child_requisition
);
227 GtkAllocation child_allocation
;
228 child_allocation
.x
= child
->x
+ border_width
;
229 child_allocation
.y
= child
->y
+ border_width
;
230 child_allocation
.width
= child_requisition
.width
;
231 child_allocation
.height
= child_requisition
.height
;
233 gtk_widget_size_allocate(child
->widget
, &child_allocation
);
235 children
= children
->next
;
239 void gtk_preserve_window_delegate_resize(GtkPreserveWindow
* widget
,
241 GtkPreserveWindowPrivate
* priv
= GTK_PRESERVE_WINDOW_GET_PRIVATE(widget
);
242 priv
->delegate_resize
= delegate
;
245 void gtk_preserve_window_set_accessible_factory(
246 GtkPreserveWindow
* widget
,
247 AtkObject
* (*factory
)(void* userdata
),
249 GtkPreserveWindowPrivate
* priv
= GTK_PRESERVE_WINDOW_GET_PRIVATE(widget
);
250 priv
->accessible_factory
= factory
;
251 priv
->accessible_factory_userdata
= userdata
;
254 AtkObject
* gtk_preserve_window_get_accessible(GtkWidget
* widget
) {
255 GtkPreserveWindowPrivate
* priv
= GTK_PRESERVE_WINDOW_GET_PRIVATE(widget
);
256 if (priv
->accessible_factory
) {
257 return priv
->accessible_factory(priv
->accessible_factory_userdata
);
259 return GTK_WIDGET_CLASS(gtk_preserve_window_parent_class
)
260 ->get_accessible(widget
);