Mercurial > vim
annotate src/gui_gtk_f.c @ 2274:7c31d761ffa9 vim73
Fix build problem with Ruby on Windows. (Cesar Romani)
author | Bram Moolenaar <bram@vim.org> |
---|---|
date | Fri, 25 Jun 2010 04:29:11 +0200 |
parents | 770485470e59 |
children | e4d849f4df03 |
rev | line source |
---|---|
7 | 1 /* vi:set ts=8 sts=4 sw=4: |
2 * | |
3 * VIM - Vi IMproved by Bram Moolenaar | |
4 * | |
5 * Do ":help uganda" in Vim to read copying and usage conditions. | |
6 * Do ":help credits" in Vim to see a list of people who contributed. | |
7 * See README.txt for an overview of the Vim source code. | |
8 */ | |
9 | |
10 /* | |
66 | 11 * (C) 1998,1999 by Marcin Dalecki <martin@dalecki.de> |
7 | 12 * |
13 * Support for GTK+ 2 was added by: | |
14 * | |
15 * (C) 2002,2003 Jason Hildebrand <jason@peaceworks.ca> | |
16 * Daniel Elstner <daniel.elstner@gmx.net> | |
17 * | |
1207 | 18 * This is a special purpose container widget, which manages arbitrary |
19 * children at arbitrary positions width arbitrary sizes. This finally puts | |
20 * an end on our resize problems with which we where struggling for such a | |
21 * long time. | |
7 | 22 */ |
23 | |
24 #include "vim.h" | |
25 #include <gtk/gtk.h> /* without this it compiles, but gives errors at | |
26 runtime! */ | |
27 #include "gui_gtk_f.h" | |
28 #include <gtk/gtksignal.h> | |
29 #ifdef WIN3264 | |
30 # include <gdk/gdkwin32.h> | |
31 #else | |
32 # include <gdk/gdkx.h> | |
33 #endif | |
34 | |
35 typedef struct _GtkFormChild GtkFormChild; | |
36 | |
37 struct _GtkFormChild | |
38 { | |
39 GtkWidget *widget; | |
40 GdkWindow *window; | |
41 gint x; /* relative subwidget x position */ | |
42 gint y; /* relative subwidget y position */ | |
43 gint mapped; | |
44 }; | |
45 | |
46 | |
47 static void gtk_form_class_init(GtkFormClass *klass); | |
48 static void gtk_form_init(GtkForm *form); | |
49 | |
50 static void gtk_form_realize(GtkWidget *widget); | |
51 static void gtk_form_unrealize(GtkWidget *widget); | |
52 static void gtk_form_map(GtkWidget *widget); | |
53 static void gtk_form_size_request(GtkWidget *widget, | |
54 GtkRequisition *requisition); | |
55 static void gtk_form_size_allocate(GtkWidget *widget, | |
56 GtkAllocation *allocation); | |
57 #ifndef HAVE_GTK2 /* this isn't needed in gtk2 */ | |
58 static void gtk_form_draw(GtkWidget *widget, | |
59 GdkRectangle *area); | |
60 #endif | |
61 static gint gtk_form_expose(GtkWidget *widget, | |
62 GdkEventExpose *event); | |
63 | |
64 static void gtk_form_remove(GtkContainer *container, | |
65 GtkWidget *widget); | |
66 static void gtk_form_forall(GtkContainer *container, | |
67 gboolean include_internals, | |
68 GtkCallback callback, | |
69 gpointer callback_data); | |
70 | |
71 static void gtk_form_attach_child_window(GtkForm *form, | |
72 GtkFormChild *child); | |
73 static void gtk_form_realize_child(GtkForm *form, | |
74 GtkFormChild *child); | |
75 static void gtk_form_position_child(GtkForm *form, | |
76 GtkFormChild *child, | |
77 gboolean force_allocate); | |
78 static void gtk_form_position_children(GtkForm *form); | |
79 | |
80 static GdkFilterReturn gtk_form_filter(GdkXEvent *gdk_xevent, | |
81 GdkEvent *event, | |
82 gpointer data); | |
83 static GdkFilterReturn gtk_form_main_filter(GdkXEvent *gdk_xevent, | |
84 GdkEvent *event, | |
85 gpointer data); | |
86 | |
87 static void gtk_form_set_static_gravity(GdkWindow *window, | |
88 gboolean use_static); | |
89 | |
90 static void gtk_form_send_configure(GtkForm *form); | |
91 | |
92 static void gtk_form_child_map(GtkWidget *widget, gpointer user_data); | |
93 static void gtk_form_child_unmap(GtkWidget *widget, gpointer user_data); | |
94 | |
95 static GtkWidgetClass *parent_class = NULL; | |
96 | |
97 /* Public interface | |
98 */ | |
99 | |
100 GtkWidget * | |
101 gtk_form_new(void) | |
102 { | |
103 GtkForm *form; | |
104 | |
105 form = gtk_type_new(gtk_form_get_type()); | |
106 | |
107 return GTK_WIDGET(form); | |
108 } | |
109 | |
110 void | |
111 gtk_form_put(GtkForm *form, | |
112 GtkWidget *child_widget, | |
113 gint x, | |
114 gint y) | |
115 { | |
116 GtkFormChild *child; | |
117 | |
118 g_return_if_fail(GTK_IS_FORM(form)); | |
119 | |
129 | 120 /* LINTED: avoid warning: conversion to 'unsigned long' */ |
7 | 121 child = g_new(GtkFormChild, 1); |
122 | |
123 child->widget = child_widget; | |
124 child->window = NULL; | |
125 child->x = x; | |
126 child->y = y; | |
127 child->widget->requisition.width = 0; | |
128 child->widget->requisition.height = 0; | |
129 child->mapped = FALSE; | |
130 | |
131 form->children = g_list_append(form->children, child); | |
132 | |
133 /* child->window must be created and attached to the widget _before_ | |
134 * it has been realized, or else things will break with GTK2. Note | |
135 * that gtk_widget_set_parent() realizes the widget if it's visible | |
136 * and its parent is mapped. | |
137 */ | |
138 if (GTK_WIDGET_REALIZED(form)) | |
139 gtk_form_attach_child_window(form, child); | |
140 | |
141 gtk_widget_set_parent(child_widget, GTK_WIDGET(form)); | |
142 gtk_widget_size_request(child->widget, NULL); | |
143 | |
144 if (GTK_WIDGET_REALIZED(form) && !GTK_WIDGET_REALIZED(child_widget)) | |
145 gtk_form_realize_child(form, child); | |
146 | |
147 gtk_form_position_child(form, child, TRUE); | |
148 } | |
149 | |
150 void | |
151 gtk_form_move(GtkForm *form, | |
152 GtkWidget *child_widget, | |
153 gint x, | |
154 gint y) | |
155 { | |
156 GList *tmp_list; | |
157 GtkFormChild *child; | |
158 | |
159 g_return_if_fail(GTK_IS_FORM(form)); | |
160 | |
161 for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next) | |
162 { | |
163 child = tmp_list->data; | |
164 if (child->widget == child_widget) | |
165 { | |
166 child->x = x; | |
167 child->y = y; | |
168 | |
169 gtk_form_position_child(form, child, TRUE); | |
170 return; | |
171 } | |
172 } | |
173 } | |
174 | |
2237
770485470e59
Add a few #ifdefs to exclude functions that are not used. (Domnique Pelle)
Bram Moolenaar <bram@vim.org>
parents:
1960
diff
changeset
|
175 #if !defined(HAVE_GTK2) || defined(PROTO) |
7 | 176 void |
177 gtk_form_set_size(GtkForm *form, guint width, guint height) | |
178 { | |
179 g_return_if_fail(GTK_IS_FORM(form)); | |
180 | |
2237
770485470e59
Add a few #ifdefs to exclude functions that are not used. (Domnique Pelle)
Bram Moolenaar <bram@vim.org>
parents:
1960
diff
changeset
|
181 /* prevent useless calls */ |
7 | 182 if (form->width == width && form->height == height) |
183 return; | |
184 form->width = width; | |
185 form->height = height; | |
186 | |
187 /* signal the change */ | |
188 #ifdef HAVE_GTK2 | |
189 gtk_widget_queue_resize(gtk_widget_get_parent(GTK_WIDGET(form))); | |
190 #else | |
191 gtk_container_queue_resize(GTK_CONTAINER(GTK_WIDGET(form)->parent)); | |
192 #endif | |
193 } | |
2237
770485470e59
Add a few #ifdefs to exclude functions that are not used. (Domnique Pelle)
Bram Moolenaar <bram@vim.org>
parents:
1960
diff
changeset
|
194 #endif |
7 | 195 |
196 void | |
197 gtk_form_freeze(GtkForm *form) | |
198 { | |
199 g_return_if_fail(GTK_IS_FORM(form)); | |
200 | |
201 ++form->freeze_count; | |
202 } | |
203 | |
204 void | |
205 gtk_form_thaw(GtkForm *form) | |
206 { | |
207 g_return_if_fail(GTK_IS_FORM(form)); | |
208 | |
209 if (form->freeze_count) | |
210 { | |
211 if (!(--form->freeze_count)) | |
212 { | |
213 gtk_form_position_children(form); | |
214 #ifdef HAVE_GTK2 | |
215 gtk_widget_queue_draw(GTK_WIDGET(form)); | |
216 #else | |
217 gtk_widget_draw(GTK_WIDGET(form), NULL); | |
218 #endif | |
219 } | |
220 } | |
221 } | |
222 | |
223 /* Basic Object handling procedures | |
224 */ | |
225 GtkType | |
226 gtk_form_get_type(void) | |
227 { | |
228 static GtkType form_type = 0; | |
229 | |
230 if (!form_type) | |
231 { | |
1884 | 232 GtkTypeInfo form_info; |
233 | |
1885 | 234 vim_memset(&form_info, 0, sizeof(form_info)); |
1884 | 235 form_info.type_name = "GtkForm"; |
236 form_info.object_size = sizeof(GtkForm); | |
237 form_info.class_size = sizeof(GtkFormClass); | |
238 form_info.class_init_func = (GtkClassInitFunc)gtk_form_class_init; | |
239 form_info.object_init_func = (GtkObjectInitFunc)gtk_form_init; | |
7 | 240 |
241 form_type = gtk_type_unique(GTK_TYPE_CONTAINER, &form_info); | |
242 } | |
243 return form_type; | |
244 } | |
245 | |
246 static void | |
247 gtk_form_class_init(GtkFormClass *klass) | |
248 { | |
249 GtkWidgetClass *widget_class; | |
250 GtkContainerClass *container_class; | |
251 | |
252 widget_class = (GtkWidgetClass *) klass; | |
253 container_class = (GtkContainerClass *) klass; | |
254 | |
255 parent_class = gtk_type_class(gtk_container_get_type()); | |
256 | |
257 widget_class->realize = gtk_form_realize; | |
258 widget_class->unrealize = gtk_form_unrealize; | |
259 widget_class->map = gtk_form_map; | |
260 widget_class->size_request = gtk_form_size_request; | |
261 widget_class->size_allocate = gtk_form_size_allocate; | |
262 #ifndef HAVE_GTK2 /* not needed for GTK2 */ | |
263 widget_class->draw = gtk_form_draw; | |
264 #endif | |
265 widget_class->expose_event = gtk_form_expose; | |
266 | |
267 container_class->remove = gtk_form_remove; | |
268 container_class->forall = gtk_form_forall; | |
269 } | |
270 | |
271 static void | |
272 gtk_form_init(GtkForm *form) | |
273 { | |
274 form->children = NULL; | |
275 | |
276 form->width = 1; | |
277 form->height = 1; | |
278 | |
279 form->bin_window = NULL; | |
280 | |
281 form->configure_serial = 0; | |
282 form->visibility = GDK_VISIBILITY_PARTIAL; | |
283 | |
284 form->freeze_count = 0; | |
285 } | |
286 | |
287 /* | |
288 * Widget methods | |
289 */ | |
290 | |
291 static void | |
292 gtk_form_realize(GtkWidget *widget) | |
293 { | |
294 GList *tmp_list; | |
295 GtkForm *form; | |
296 GdkWindowAttr attributes; | |
297 gint attributes_mask; | |
298 | |
299 g_return_if_fail(GTK_IS_FORM(widget)); | |
300 | |
301 form = GTK_FORM(widget); | |
302 GTK_WIDGET_SET_FLAGS(form, GTK_REALIZED); | |
303 | |
304 attributes.window_type = GDK_WINDOW_CHILD; | |
305 attributes.x = widget->allocation.x; | |
306 attributes.y = widget->allocation.y; | |
307 attributes.width = widget->allocation.width; | |
308 attributes.height = widget->allocation.height; | |
309 attributes.wclass = GDK_INPUT_OUTPUT; | |
310 attributes.visual = gtk_widget_get_visual(widget); | |
311 attributes.colormap = gtk_widget_get_colormap(widget); | |
312 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK; | |
313 | |
314 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; | |
315 | |
316 widget->window = gdk_window_new(gtk_widget_get_parent_window(widget), | |
317 &attributes, attributes_mask); | |
318 gdk_window_set_user_data(widget->window, widget); | |
319 | |
320 attributes.x = 0; | |
321 attributes.y = 0; | |
322 attributes.event_mask = gtk_widget_get_events(widget); | |
323 | |
324 form->bin_window = gdk_window_new(widget->window, | |
325 &attributes, attributes_mask); | |
326 gdk_window_set_user_data(form->bin_window, widget); | |
327 | |
328 gtk_form_set_static_gravity(form->bin_window, TRUE); | |
329 | |
330 widget->style = gtk_style_attach(widget->style, widget->window); | |
331 gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL); | |
332 gtk_style_set_background(widget->style, form->bin_window, GTK_STATE_NORMAL); | |
333 | |
334 gdk_window_add_filter(widget->window, gtk_form_main_filter, form); | |
335 gdk_window_add_filter(form->bin_window, gtk_form_filter, form); | |
336 | |
337 for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next) | |
338 { | |
339 GtkFormChild *child = tmp_list->data; | |
340 | |
341 gtk_form_attach_child_window(form, child); | |
342 | |
343 if (GTK_WIDGET_VISIBLE(child->widget)) | |
344 gtk_form_realize_child(form, child); | |
345 } | |
346 } | |
347 | |
348 | |
349 /* After reading the documentation at | |
350 * http://developer.gnome.org/doc/API/2.0/gtk/gtk-changes-2-0.html | |
351 * I think it should be possible to remove this function when compiling | |
352 * against gtk-2.0. It doesn't seem to cause problems, though. | |
353 * | |
354 * Well, I reckon at least the gdk_window_show(form->bin_window) | |
355 * is necessary. GtkForm is anything but a usual container widget. | |
356 */ | |
357 static void | |
358 gtk_form_map(GtkWidget *widget) | |
359 { | |
360 GList *tmp_list; | |
361 GtkForm *form; | |
362 | |
363 g_return_if_fail(GTK_IS_FORM(widget)); | |
364 | |
365 form = GTK_FORM(widget); | |
366 | |
367 GTK_WIDGET_SET_FLAGS(widget, GTK_MAPPED); | |
368 | |
369 gdk_window_show(widget->window); | |
370 gdk_window_show(form->bin_window); | |
371 | |
372 for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next) | |
373 { | |
374 GtkFormChild *child = tmp_list->data; | |
375 | |
376 if (GTK_WIDGET_VISIBLE(child->widget) | |
377 && !GTK_WIDGET_MAPPED(child->widget)) | |
378 gtk_widget_map(child->widget); | |
379 } | |
380 } | |
381 | |
382 static void | |
383 gtk_form_unrealize(GtkWidget *widget) | |
384 { | |
385 GList *tmp_list; | |
386 GtkForm *form; | |
387 | |
388 g_return_if_fail(GTK_IS_FORM(widget)); | |
389 | |
390 form = GTK_FORM(widget); | |
391 | |
392 tmp_list = form->children; | |
393 | |
394 gdk_window_set_user_data(form->bin_window, NULL); | |
395 gdk_window_destroy(form->bin_window); | |
396 form->bin_window = NULL; | |
397 | |
398 while (tmp_list) | |
399 { | |
400 GtkFormChild *child = tmp_list->data; | |
401 | |
402 if (child->window != NULL) | |
403 { | |
404 gtk_signal_disconnect_by_func(GTK_OBJECT(child->widget), | |
405 GTK_SIGNAL_FUNC(gtk_form_child_map), | |
406 child); | |
407 gtk_signal_disconnect_by_func(GTK_OBJECT(child->widget), | |
408 GTK_SIGNAL_FUNC(gtk_form_child_unmap), | |
409 child); | |
410 | |
411 gdk_window_set_user_data(child->window, NULL); | |
412 gdk_window_destroy(child->window); | |
413 | |
414 child->window = NULL; | |
415 } | |
416 | |
417 tmp_list = tmp_list->next; | |
418 } | |
419 | |
420 if (GTK_WIDGET_CLASS (parent_class)->unrealize) | |
421 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); | |
422 } | |
423 | |
424 #ifndef HAVE_GTK2 | |
425 static void | |
426 gtk_form_draw(GtkWidget *widget, GdkRectangle *area) | |
427 { | |
428 GtkForm *form; | |
429 GList *children; | |
430 GtkFormChild *child; | |
431 GdkRectangle child_area; | |
432 | |
433 g_return_if_fail(GTK_IS_FORM(widget)); | |
434 | |
435 if (GTK_WIDGET_DRAWABLE(widget)) | |
436 { | |
437 form = GTK_FORM(widget); | |
438 | |
439 children = form->children; | |
440 | |
441 while (children) | |
442 { | |
443 child = children->data; | |
444 | |
445 if (GTK_WIDGET_DRAWABLE(child->widget) | |
446 && gtk_widget_intersect(child->widget, area, &child_area)) | |
447 gtk_widget_draw(child->widget, &child_area); | |
448 | |
449 children = children->next; | |
450 } | |
451 } | |
452 } | |
453 #endif /* !HAVE_GTK2 */ | |
454 | |
455 static void | |
456 gtk_form_size_request(GtkWidget *widget, GtkRequisition *requisition) | |
457 { | |
458 GList *tmp_list; | |
459 GtkForm *form; | |
460 | |
461 g_return_if_fail(GTK_IS_FORM(widget)); | |
462 | |
463 form = GTK_FORM(widget); | |
464 | |
465 requisition->width = form->width; | |
466 requisition->height = form->height; | |
467 | |
468 tmp_list = form->children; | |
469 | |
470 while (tmp_list) | |
471 { | |
472 GtkFormChild *child = tmp_list->data; | |
473 gtk_widget_size_request(child->widget, NULL); | |
474 tmp_list = tmp_list->next; | |
475 } | |
476 } | |
477 | |
478 static void | |
479 gtk_form_size_allocate(GtkWidget *widget, GtkAllocation *allocation) | |
480 { | |
481 GList *tmp_list; | |
482 GtkForm *form; | |
483 gboolean need_reposition; | |
484 | |
485 g_return_if_fail(GTK_IS_FORM(widget)); | |
486 | |
487 if (widget->allocation.x == allocation->x | |
488 && widget->allocation.y == allocation->y | |
489 && widget->allocation.width == allocation->width | |
490 && widget->allocation.height == allocation->height) | |
491 return; | |
492 | |
493 need_reposition = widget->allocation.width != allocation->width | |
494 || widget->allocation.height != allocation->height; | |
495 form = GTK_FORM(widget); | |
496 | |
497 if (need_reposition) | |
498 { | |
499 tmp_list = form->children; | |
500 | |
501 while (tmp_list) | |
502 { | |
503 GtkFormChild *child = tmp_list->data; | |
504 gtk_form_position_child(form, child, TRUE); | |
505 | |
506 tmp_list = tmp_list->next; | |
507 } | |
508 } | |
509 | |
510 if (GTK_WIDGET_REALIZED(widget)) | |
511 { | |
512 gdk_window_move_resize(widget->window, | |
513 allocation->x, allocation->y, | |
514 allocation->width, allocation->height); | |
515 gdk_window_move_resize(GTK_FORM(widget)->bin_window, | |
516 0, 0, | |
517 allocation->width, allocation->height); | |
518 } | |
519 widget->allocation = *allocation; | |
520 if (need_reposition) | |
521 gtk_form_send_configure(form); | |
522 } | |
523 | |
524 static gint | |
525 gtk_form_expose(GtkWidget *widget, GdkEventExpose *event) | |
526 { | |
527 GList *tmp_list; | |
528 GtkForm *form; | |
529 | |
530 g_return_val_if_fail(GTK_IS_FORM(widget), FALSE); | |
531 | |
532 form = GTK_FORM(widget); | |
533 | |
534 if (event->window == form->bin_window) | |
535 return FALSE; | |
536 | |
537 for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next) | |
538 { | |
539 #ifdef HAVE_GTK2 | |
540 GtkFormChild *formchild = tmp_list->data; | |
541 GtkWidget *child = formchild->widget; | |
542 /* | |
543 * The following chunk of code is taken from gtkcontainer.c. The | |
544 * gtk1.x code synthesized expose events directly on the child widgets, | |
545 * which can't be done in gtk2 | |
546 */ | |
547 if (GTK_WIDGET_DRAWABLE(child) && GTK_WIDGET_NO_WINDOW(child) | |
548 && child->window == event->window) | |
549 { | |
550 GdkEventExpose child_event; | |
551 child_event = *event; | |
552 | |
553 child_event.region = gtk_widget_region_intersect(child, event->region); | |
554 if (!gdk_region_empty(child_event.region)) | |
555 { | |
556 gdk_region_get_clipbox(child_event.region, &child_event.area); | |
557 gtk_widget_send_expose(child, (GdkEvent *)&child_event); | |
558 } | |
559 } | |
560 #else /* !HAVE_GTK2 */ | |
561 GtkFormChild *child = tmp_list->data; | |
562 | |
563 if (event->window == child->window) | |
564 return gtk_widget_event(child->widget, (GdkEvent *) event); | |
565 #endif /* !HAVE_GTK2 */ | |
566 } | |
567 | |
568 return FALSE; | |
569 } | |
570 | |
571 /* Container method | |
572 */ | |
573 static void | |
574 gtk_form_remove(GtkContainer *container, GtkWidget *widget) | |
575 { | |
576 GList *tmp_list; | |
577 GtkForm *form; | |
578 GtkFormChild *child = NULL; /* init for gcc */ | |
579 | |
580 g_return_if_fail(GTK_IS_FORM(container)); | |
581 | |
582 form = GTK_FORM(container); | |
583 | |
584 tmp_list = form->children; | |
585 while (tmp_list) | |
586 { | |
587 child = tmp_list->data; | |
588 if (child->widget == widget) | |
589 break; | |
590 tmp_list = tmp_list->next; | |
591 } | |
592 | |
593 if (tmp_list) | |
594 { | |
595 if (child->window) | |
596 { | |
597 gtk_signal_disconnect_by_func(GTK_OBJECT(child->widget), | |
598 GTK_SIGNAL_FUNC(>k_form_child_map), child); | |
599 gtk_signal_disconnect_by_func(GTK_OBJECT(child->widget), | |
600 GTK_SIGNAL_FUNC(>k_form_child_unmap), child); | |
601 | |
602 /* FIXME: This will cause problems for reparenting NO_WINDOW | |
603 * widgets out of a GtkForm | |
604 */ | |
605 gdk_window_set_user_data(child->window, NULL); | |
606 gdk_window_destroy(child->window); | |
607 } | |
608 gtk_widget_unparent(widget); | |
609 | |
610 form->children = g_list_remove_link(form->children, tmp_list); | |
611 g_list_free_1(tmp_list); | |
612 g_free(child); | |
613 } | |
614 } | |
615 | |
616 static void | |
617 gtk_form_forall(GtkContainer *container, | |
1884 | 618 gboolean include_internals UNUSED, |
7 | 619 GtkCallback callback, |
620 gpointer callback_data) | |
621 { | |
622 GtkForm *form; | |
623 GtkFormChild *child; | |
624 GList *tmp_list; | |
625 | |
626 g_return_if_fail(GTK_IS_FORM(container)); | |
627 g_return_if_fail(callback != NULL); | |
628 | |
629 form = GTK_FORM(container); | |
630 | |
631 tmp_list = form->children; | |
632 while (tmp_list) | |
633 { | |
634 child = tmp_list->data; | |
635 tmp_list = tmp_list->next; | |
636 | |
637 (*callback) (child->widget, callback_data); | |
638 } | |
639 } | |
640 | |
641 /* Operations on children | |
642 */ | |
643 | |
644 static void | |
645 gtk_form_attach_child_window(GtkForm *form, GtkFormChild *child) | |
646 { | |
647 if (child->window != NULL) | |
648 return; /* been there, done that */ | |
649 | |
650 if (GTK_WIDGET_NO_WINDOW(child->widget)) | |
651 { | |
652 GtkWidget *widget; | |
653 GdkWindowAttr attributes; | |
654 gint attributes_mask; | |
655 | |
656 widget = GTK_WIDGET(form); | |
657 | |
658 attributes.window_type = GDK_WINDOW_CHILD; | |
659 attributes.x = child->x; | |
660 attributes.y = child->y; | |
661 attributes.width = child->widget->requisition.width; | |
662 attributes.height = child->widget->requisition.height; | |
663 attributes.wclass = GDK_INPUT_OUTPUT; | |
664 attributes.visual = gtk_widget_get_visual(widget); | |
665 attributes.colormap = gtk_widget_get_colormap(widget); | |
666 attributes.event_mask = GDK_EXPOSURE_MASK; | |
667 | |
668 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; | |
669 child->window = gdk_window_new(form->bin_window, | |
670 &attributes, attributes_mask); | |
671 gdk_window_set_user_data(child->window, widget); | |
672 | |
673 gtk_style_set_background(widget->style, | |
674 child->window, | |
675 GTK_STATE_NORMAL); | |
676 | |
677 gtk_widget_set_parent_window(child->widget, child->window); | |
678 gtk_form_set_static_gravity(child->window, TRUE); | |
679 /* | |
680 * Install signal handlers to map/unmap child->window | |
681 * alongside with the actual widget. | |
682 */ | |
683 gtk_signal_connect(GTK_OBJECT(child->widget), "map", | |
684 GTK_SIGNAL_FUNC(>k_form_child_map), child); | |
685 gtk_signal_connect(GTK_OBJECT(child->widget), "unmap", | |
686 GTK_SIGNAL_FUNC(>k_form_child_unmap), child); | |
687 } | |
688 else if (!GTK_WIDGET_REALIZED(child->widget)) | |
689 { | |
690 gtk_widget_set_parent_window(child->widget, form->bin_window); | |
691 } | |
692 } | |
693 | |
694 static void | |
695 gtk_form_realize_child(GtkForm *form, GtkFormChild *child) | |
696 { | |
697 gtk_form_attach_child_window(form, child); | |
698 gtk_widget_realize(child->widget); | |
699 | |
700 if (child->window == NULL) /* might be already set, see above */ | |
701 gtk_form_set_static_gravity(child->widget->window, TRUE); | |
702 } | |
703 | |
704 static void | |
705 gtk_form_position_child(GtkForm *form, GtkFormChild *child, | |
706 gboolean force_allocate) | |
707 { | |
708 gint x; | |
709 gint y; | |
710 | |
711 x = child->x; | |
712 y = child->y; | |
713 | |
714 if ((x >= G_MINSHORT) && (x <= G_MAXSHORT) && | |
715 (y >= G_MINSHORT) && (y <= G_MAXSHORT)) | |
716 { | |
717 if (!child->mapped) | |
718 { | |
719 if (GTK_WIDGET_MAPPED(form) && GTK_WIDGET_VISIBLE(child->widget)) | |
720 { | |
721 if (!GTK_WIDGET_MAPPED(child->widget)) | |
722 gtk_widget_map(child->widget); | |
723 | |
724 child->mapped = TRUE; | |
725 force_allocate = TRUE; | |
726 } | |
727 } | |
728 | |
729 if (force_allocate) | |
730 { | |
731 GtkAllocation allocation; | |
732 | |
733 if (GTK_WIDGET_NO_WINDOW(child->widget)) | |
734 { | |
735 if (child->window) | |
736 { | |
737 gdk_window_move_resize(child->window, | |
738 x, y, | |
739 child->widget->requisition.width, | |
740 child->widget->requisition.height); | |
741 } | |
742 | |
743 allocation.x = 0; | |
744 allocation.y = 0; | |
745 } | |
746 else | |
747 { | |
748 allocation.x = x; | |
749 allocation.y = y; | |
750 } | |
751 | |
752 allocation.width = child->widget->requisition.width; | |
753 allocation.height = child->widget->requisition.height; | |
754 | |
755 gtk_widget_size_allocate(child->widget, &allocation); | |
756 } | |
757 } | |
758 else | |
759 { | |
760 if (child->mapped) | |
761 { | |
762 child->mapped = FALSE; | |
763 | |
764 if (GTK_WIDGET_MAPPED(child->widget)) | |
765 gtk_widget_unmap(child->widget); | |
766 } | |
767 } | |
768 } | |
769 | |
770 static void | |
771 gtk_form_position_children(GtkForm *form) | |
772 { | |
773 GList *tmp_list; | |
774 | |
775 for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next) | |
776 gtk_form_position_child(form, tmp_list->data, FALSE); | |
777 } | |
778 | |
779 /* Callbacks */ | |
780 | |
781 /* The main event filter. Actually, we probably don't really need | |
782 * to install this as a filter at all, since we are calling it | |
783 * directly above in the expose-handling hack. | |
784 * | |
785 * This routine identifies expose events that are generated when | |
786 * we've temporarily moved the bin_window_origin, and translates | |
787 * them or discards them, depending on whether we are obscured | |
788 * or not. | |
789 */ | |
790 static GdkFilterReturn | |
1884 | 791 gtk_form_filter(GdkXEvent *gdk_xevent, GdkEvent *event UNUSED, gpointer data) |
7 | 792 { |
793 XEvent *xevent; | |
794 GtkForm *form; | |
795 | |
796 xevent = (XEvent *) gdk_xevent; | |
797 form = GTK_FORM(data); | |
798 | |
799 switch (xevent->type) | |
800 { | |
801 case Expose: | |
802 if (xevent->xexpose.serial == form->configure_serial) | |
803 { | |
804 if (form->visibility == GDK_VISIBILITY_UNOBSCURED) | |
805 return GDK_FILTER_REMOVE; | |
806 else | |
807 break; | |
808 } | |
809 break; | |
810 | |
811 case ConfigureNotify: | |
812 if ((xevent->xconfigure.x != 0) || (xevent->xconfigure.y != 0)) | |
813 form->configure_serial = xevent->xconfigure.serial; | |
814 break; | |
815 } | |
816 | |
817 return GDK_FILTER_CONTINUE; | |
818 } | |
819 | |
820 /* Although GDK does have a GDK_VISIBILITY_NOTIFY event, | |
821 * there is no corresponding event in GTK, so we have | |
822 * to get the events from a filter | |
823 */ | |
824 static GdkFilterReturn | |
1884 | 825 gtk_form_main_filter(GdkXEvent *gdk_xevent, |
826 GdkEvent *event UNUSED, | |
827 gpointer data) | |
7 | 828 { |
829 XEvent *xevent; | |
830 GtkForm *form; | |
831 | |
832 xevent = (XEvent *) gdk_xevent; | |
833 form = GTK_FORM(data); | |
834 | |
835 if (xevent->type == VisibilityNotify) | |
836 { | |
837 switch (xevent->xvisibility.state) | |
838 { | |
839 case VisibilityFullyObscured: | |
840 form->visibility = GDK_VISIBILITY_FULLY_OBSCURED; | |
841 break; | |
842 | |
843 case VisibilityPartiallyObscured: | |
844 form->visibility = GDK_VISIBILITY_PARTIAL; | |
845 break; | |
846 | |
847 case VisibilityUnobscured: | |
848 form->visibility = GDK_VISIBILITY_UNOBSCURED; | |
849 break; | |
850 } | |
851 | |
852 return GDK_FILTER_REMOVE; | |
853 } | |
854 return GDK_FILTER_CONTINUE; | |
855 } | |
856 | |
857 /* Routines to set the window gravity, and check whether it is | |
858 * functional. Extra capabilities need to be added to GDK, so | |
859 * we don't have to use Xlib here. | |
860 */ | |
861 static void | |
862 gtk_form_set_static_gravity(GdkWindow *window, gboolean use_static) | |
863 { | |
864 #ifdef HAVE_GTK2 | |
1960 | 865 /* We don't check if static gravity is actually supported, because it |
866 * results in an annoying assertion error message. */ | |
867 gdk_window_set_static_gravities(window, use_static); | |
7 | 868 #else |
869 XSetWindowAttributes xattributes; | |
870 | |
871 xattributes.win_gravity = (use_static) ? StaticGravity : NorthWestGravity; | |
872 xattributes.bit_gravity = (use_static) ? StaticGravity : NorthWestGravity; | |
873 | |
874 XChangeWindowAttributes(GDK_WINDOW_XDISPLAY(window), | |
875 GDK_WINDOW_XWINDOW(window), | |
876 CWBitGravity | CWWinGravity, | |
877 &xattributes); | |
878 #endif | |
879 } | |
880 | |
881 void | |
882 gtk_form_move_resize(GtkForm *form, GtkWidget *widget, | |
883 gint x, gint y, gint w, gint h) | |
884 { | |
885 widget->requisition.width = w; | |
886 widget->requisition.height = h; | |
887 | |
888 gtk_form_move(form, widget, x, y); | |
889 } | |
890 | |
891 static void | |
892 gtk_form_send_configure(GtkForm *form) | |
893 { | |
894 GtkWidget *widget; | |
895 GdkEventConfigure event; | |
896 | |
897 widget = GTK_WIDGET(form); | |
898 | |
899 event.type = GDK_CONFIGURE; | |
900 event.window = widget->window; | |
901 event.x = widget->allocation.x; | |
902 event.y = widget->allocation.y; | |
903 event.width = widget->allocation.width; | |
904 event.height = widget->allocation.height; | |
905 | |
906 #ifdef HAVE_GTK2 | |
907 gtk_main_do_event((GdkEvent*)&event); | |
908 #else | |
909 gtk_widget_event(widget, (GdkEvent*)&event); | |
910 #endif | |
911 } | |
912 | |
913 static void | |
1884 | 914 gtk_form_child_map(GtkWidget *widget UNUSED, gpointer user_data) |
7 | 915 { |
916 GtkFormChild *child; | |
917 | |
918 child = (GtkFormChild *)user_data; | |
919 | |
920 child->mapped = TRUE; | |
921 gdk_window_show(child->window); | |
922 } | |
923 | |
924 static void | |
1884 | 925 gtk_form_child_unmap(GtkWidget *widget UNUSED, gpointer user_data) |
7 | 926 { |
927 GtkFormChild *child; | |
928 | |
929 child = (GtkFormChild *)user_data; | |
930 | |
931 child->mapped = FALSE; | |
932 gdk_window_hide(child->window); | |
933 } | |
934 |