Don't crash when SimpleCache index is corrupt.
[chromium-blink-merge.git] / ui / gfx / gtk_preserve_window.cc
blob8ea1c4316505dad5f765617f9e800f94699a8efd
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"
7 #include <gdk/gdk.h>
8 #include <gtk/gtk.h>
10 #include "ui/base/gtk/gtk_compat.h"
12 G_BEGIN_DECLS
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
25 // to someone else.
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);
75 if (gdk_window) {
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);
90 if (gdk_window) {
91 GtkAllocation allocation;
92 gtk_widget_get_allocation(widget, &allocation);
94 gdk_window_reparent(gdk_window,
95 gtk_widget_get_parent_window(widget),
96 allocation.x,
97 allocation.y);
98 GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
99 if (!priv->delegate_resize) {
100 gdk_window_resize(gdk_window,
101 allocation.width,
102 allocation.height);
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);
114 } else {
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);
151 } else {
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,
164 gboolean value) {
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);
211 } else {
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;
221 while (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,
240 gboolean delegate) {
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),
248 gpointer 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);
258 } else {
259 return GTK_WIDGET_CLASS(gtk_preserve_window_parent_class)
260 ->get_accessible(widget);
264 G_END_DECLS