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