]>
Commit | Line | Data |
---|---|---|
1 | /* /////////////////////////////////////////////////////////////////////////// | |
2 | // Name: src/gtk/win_gtk.c | |
3 | // Purpose: Native GTK+ widget for wxWidgets, based on GtkLayout and | |
4 | // GtkFixed. It makes use of the gravity window property and | |
5 | // therefore does not work with GTK 1.0. | |
6 | // Author: Robert Roebling | |
7 | // Id: $Id$ | |
8 | // Copyright: (c) 1998 Robert Roebling | |
9 | // Licence: wxWidgets licence | |
10 | /////////////////////////////////////////////////////////////////////////// */ | |
11 | ||
12 | #ifdef VMS | |
13 | #define XCheckIfEvent XCHECKIFEVENT | |
14 | #endif | |
15 | ||
16 | #include "wx/platform.h" | |
17 | #include "wx/gtk/win_gtk.h" | |
18 | #include "gtk/gtksignal.h" | |
19 | #include "gtk/gtkprivate.h" | |
20 | #include "gdk/gdkx.h" | |
21 | ||
22 | #ifdef __cplusplus | |
23 | extern "C" { | |
24 | #endif /* __cplusplus */ | |
25 | ||
26 | typedef struct _GtkPizzaAdjData GtkPizzaAdjData; | |
27 | ||
28 | struct _GtkPizzaAdjData | |
29 | { | |
30 | gint dx; | |
31 | gint dy; | |
32 | }; | |
33 | ||
34 | static void gtk_pizza_class_init (GtkPizzaClass *klass); | |
35 | static void gtk_pizza_init (GtkPizza *pizza); | |
36 | ||
37 | static void gtk_pizza_realize (GtkWidget *widget); | |
38 | static void gtk_pizza_unrealize (GtkWidget *widget); | |
39 | ||
40 | static void gtk_pizza_map (GtkWidget *widget); | |
41 | ||
42 | static void gtk_pizza_size_request (GtkWidget *widget, | |
43 | GtkRequisition *requisition); | |
44 | static void gtk_pizza_size_allocate (GtkWidget *widget, | |
45 | GtkAllocation *allocation); | |
46 | static gint gtk_pizza_expose (GtkWidget *widget, | |
47 | GdkEventExpose *event); | |
48 | static void gtk_pizza_style_set (GtkWidget *widget, | |
49 | GtkStyle *previous_style); | |
50 | static void gtk_pizza_add (GtkContainer *container, | |
51 | GtkWidget *widget); | |
52 | static void gtk_pizza_remove (GtkContainer *container, | |
53 | GtkWidget *widget); | |
54 | static void gtk_pizza_forall (GtkContainer *container, | |
55 | gboolean include_internals, | |
56 | GtkCallback callback, | |
57 | gpointer callback_data); | |
58 | ||
59 | static void gtk_pizza_allocate_child (GtkPizza *pizza, | |
60 | GtkPizzaChild *child); | |
61 | static void gtk_pizza_adjust_allocations_recurse (GtkWidget *widget, | |
62 | gpointer cb_data); | |
63 | ||
64 | static GtkType gtk_pizza_child_type (GtkContainer *container); | |
65 | ||
66 | static void gtk_pizza_scroll_set_adjustments (GtkPizza *pizza, | |
67 | GtkAdjustment *hadj, | |
68 | GtkAdjustment *vadj); | |
69 | ||
70 | /* static */ | |
71 | GtkContainerClass *pizza_parent_class = NULL; | |
72 | ||
73 | GtkType | |
74 | gtk_pizza_get_type () | |
75 | { | |
76 | static GtkType pizza_type = 0; | |
77 | ||
78 | if (!pizza_type) | |
79 | { | |
80 | static const GTypeInfo pizza_info = | |
81 | { | |
82 | sizeof (GtkPizzaClass), | |
83 | NULL, /* base_init */ | |
84 | NULL, /* base_finalize */ | |
85 | (GClassInitFunc) gtk_pizza_class_init, | |
86 | NULL, /* class_finalize */ | |
87 | NULL, /* class_data */ | |
88 | sizeof (GtkPizza), | |
89 | 16, /* n_preallocs */ | |
90 | (GInstanceInitFunc) gtk_pizza_init, | |
91 | }; | |
92 | pizza_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkPizza", &pizza_info, (GTypeFlags)0); | |
93 | } | |
94 | ||
95 | return pizza_type; | |
96 | } | |
97 | ||
98 | /* Marshaller needed for set_scroll_adjustments signal, | |
99 | generated with GLib-2.4.6 glib-genmarshal */ | |
100 | #define g_marshal_value_peek_object(v) g_value_get_object (v) | |
101 | static void | |
102 | g_cclosure_user_marshal_VOID__OBJECT_OBJECT (GClosure *closure, | |
103 | GValue *return_value, | |
104 | guint n_param_values, | |
105 | const GValue *param_values, | |
106 | gpointer invocation_hint, | |
107 | gpointer marshal_data) | |
108 | { | |
109 | typedef void (*GMarshalFunc_VOID__OBJECT_OBJECT) (gpointer data1, | |
110 | gpointer arg_1, | |
111 | gpointer arg_2, | |
112 | gpointer data2); | |
113 | register GMarshalFunc_VOID__OBJECT_OBJECT callback; | |
114 | register GCClosure *cc = (GCClosure*) closure; | |
115 | register gpointer data1, data2; | |
116 | ||
117 | g_return_if_fail (n_param_values == 3); | |
118 | ||
119 | if (G_CCLOSURE_SWAP_DATA (closure)) | |
120 | { | |
121 | data1 = closure->data; | |
122 | data2 = g_value_peek_pointer (param_values + 0); | |
123 | } | |
124 | else | |
125 | { | |
126 | data1 = g_value_peek_pointer (param_values + 0); | |
127 | data2 = closure->data; | |
128 | } | |
129 | callback = (GMarshalFunc_VOID__OBJECT_OBJECT) (marshal_data ? marshal_data : cc->callback); | |
130 | ||
131 | callback (data1, | |
132 | g_marshal_value_peek_object (param_values + 1), | |
133 | g_marshal_value_peek_object (param_values + 2), | |
134 | data2); | |
135 | } | |
136 | ||
137 | static void | |
138 | gtk_pizza_class_init (GtkPizzaClass *klass) | |
139 | { | |
140 | GtkObjectClass *object_class; | |
141 | GtkWidgetClass *widget_class; | |
142 | GtkContainerClass *container_class; | |
143 | ||
144 | object_class = (GtkObjectClass*) klass; | |
145 | widget_class = (GtkWidgetClass*) klass; | |
146 | container_class = (GtkContainerClass*) klass; | |
147 | pizza_parent_class = gtk_type_class (GTK_TYPE_CONTAINER); | |
148 | ||
149 | widget_class->map = gtk_pizza_map; | |
150 | widget_class->realize = gtk_pizza_realize; | |
151 | widget_class->unrealize = gtk_pizza_unrealize; | |
152 | widget_class->size_request = gtk_pizza_size_request; | |
153 | widget_class->size_allocate = gtk_pizza_size_allocate; | |
154 | widget_class->expose_event = gtk_pizza_expose; | |
155 | widget_class->style_set = gtk_pizza_style_set; | |
156 | ||
157 | container_class->add = gtk_pizza_add; | |
158 | container_class->remove = gtk_pizza_remove; | |
159 | container_class->forall = gtk_pizza_forall; | |
160 | ||
161 | container_class->child_type = gtk_pizza_child_type; | |
162 | ||
163 | klass->set_scroll_adjustments = gtk_pizza_scroll_set_adjustments; | |
164 | ||
165 | widget_class->set_scroll_adjustments_signal = | |
166 | g_signal_new( | |
167 | "set_scroll_adjustments", | |
168 | G_TYPE_FROM_CLASS(object_class), | |
169 | G_SIGNAL_RUN_LAST, | |
170 | G_STRUCT_OFFSET(GtkPizzaClass, set_scroll_adjustments), | |
171 | NULL, | |
172 | NULL, | |
173 | g_cclosure_user_marshal_VOID__OBJECT_OBJECT, | |
174 | G_TYPE_NONE, | |
175 | 2, | |
176 | GTK_TYPE_ADJUSTMENT, | |
177 | GTK_TYPE_ADJUSTMENT); | |
178 | } | |
179 | ||
180 | static GtkType | |
181 | gtk_pizza_child_type (GtkContainer *container) | |
182 | { | |
183 | return GTK_TYPE_WIDGET; | |
184 | } | |
185 | ||
186 | static void | |
187 | gtk_pizza_init (GtkPizza *pizza) | |
188 | { | |
189 | GTK_WIDGET_UNSET_FLAGS (pizza, GTK_NO_WINDOW); | |
190 | ||
191 | pizza->shadow_type = GTK_MYSHADOW_NONE; | |
192 | ||
193 | pizza->children = NULL; | |
194 | ||
195 | pizza->width = 20; | |
196 | pizza->height = 20; | |
197 | ||
198 | pizza->bin_window = NULL; | |
199 | ||
200 | pizza->xoffset = 0; | |
201 | pizza->yoffset = 0; | |
202 | ||
203 | pizza->configure_serial = 0; | |
204 | pizza->scroll_x = 0; | |
205 | pizza->scroll_y = 0; | |
206 | pizza->visibility = GDK_VISIBILITY_PARTIAL; | |
207 | ||
208 | pizza->clear_on_draw = TRUE; | |
209 | pizza->use_filter = TRUE; | |
210 | pizza->external_expose = FALSE; | |
211 | } | |
212 | ||
213 | GtkWidget* | |
214 | gtk_pizza_new () | |
215 | { | |
216 | GtkPizza *pizza; | |
217 | ||
218 | pizza = gtk_type_new (gtk_pizza_get_type ()); | |
219 | ||
220 | return GTK_WIDGET (pizza); | |
221 | } | |
222 | ||
223 | static void | |
224 | gtk_pizza_scroll_set_adjustments (GtkPizza *pizza, | |
225 | GtkAdjustment *hadj, | |
226 | GtkAdjustment *vadj) | |
227 | { | |
228 | /* We handle scrolling in the wxScrolledWindow, not here. */ | |
229 | } | |
230 | ||
231 | void | |
232 | gtk_pizza_set_shadow_type (GtkPizza *pizza, | |
233 | GtkMyShadowType type) | |
234 | { | |
235 | g_return_if_fail (pizza != NULL); | |
236 | g_return_if_fail (GTK_IS_PIZZA (pizza)); | |
237 | ||
238 | if ((GtkMyShadowType) pizza->shadow_type != type) | |
239 | { | |
240 | pizza->shadow_type = type; | |
241 | ||
242 | if (GTK_WIDGET_VISIBLE (pizza)) | |
243 | { | |
244 | gtk_widget_size_allocate (GTK_WIDGET (pizza), &(GTK_WIDGET (pizza)->allocation)); | |
245 | gtk_widget_queue_draw (GTK_WIDGET (pizza)); | |
246 | } | |
247 | } | |
248 | } | |
249 | ||
250 | void | |
251 | gtk_pizza_set_clear (GtkPizza *pizza, | |
252 | gboolean clear) | |
253 | { | |
254 | g_return_if_fail (pizza != NULL); | |
255 | g_return_if_fail (GTK_IS_PIZZA (pizza)); | |
256 | ||
257 | pizza->clear_on_draw = clear; | |
258 | } | |
259 | ||
260 | void | |
261 | gtk_pizza_set_filter (GtkPizza *pizza, | |
262 | gboolean use) | |
263 | { | |
264 | g_return_if_fail (pizza != NULL); | |
265 | g_return_if_fail (GTK_IS_PIZZA (pizza)); | |
266 | ||
267 | pizza->use_filter = use; | |
268 | } | |
269 | ||
270 | void | |
271 | gtk_pizza_set_external (GtkPizza *pizza, | |
272 | gboolean expose) | |
273 | { | |
274 | g_return_if_fail (pizza != NULL); | |
275 | g_return_if_fail (GTK_IS_PIZZA (pizza)); | |
276 | ||
277 | pizza->external_expose = expose; | |
278 | } | |
279 | ||
280 | void | |
281 | gtk_pizza_put (GtkPizza *pizza, | |
282 | GtkWidget *widget, | |
283 | gint x, | |
284 | gint y, | |
285 | gint width, | |
286 | gint height) | |
287 | { | |
288 | GtkPizzaChild *child_info; | |
289 | ||
290 | g_return_if_fail (pizza != NULL); | |
291 | g_return_if_fail (GTK_IS_PIZZA (pizza)); | |
292 | g_return_if_fail (widget != NULL); | |
293 | ||
294 | child_info = g_new (GtkPizzaChild, 1); | |
295 | ||
296 | child_info->widget = widget; | |
297 | child_info->x = x; | |
298 | child_info->y = y; | |
299 | child_info->width = width; | |
300 | child_info->height = height; | |
301 | ||
302 | pizza->children = g_list_append (pizza->children, child_info); | |
303 | ||
304 | if (GTK_WIDGET_REALIZED (pizza)) | |
305 | gtk_widget_set_parent_window (widget, pizza->bin_window); | |
306 | ||
307 | gtk_widget_set_parent (widget, GTK_WIDGET (pizza)); | |
308 | ||
309 | gtk_widget_set_size_request (widget, width, height); | |
310 | } | |
311 | ||
312 | void | |
313 | gtk_pizza_move (GtkPizza *pizza, | |
314 | GtkWidget *widget, | |
315 | gint x, | |
316 | gint y) | |
317 | { | |
318 | GtkPizzaChild *child; | |
319 | GList *children; | |
320 | ||
321 | g_return_if_fail (pizza != NULL); | |
322 | g_return_if_fail (GTK_IS_PIZZA (pizza)); | |
323 | g_return_if_fail (widget != NULL); | |
324 | ||
325 | children = pizza->children; | |
326 | while (children) | |
327 | { | |
328 | child = children->data; | |
329 | children = children->next; | |
330 | ||
331 | if (child->widget == widget) | |
332 | { | |
333 | if ((child->x == x) && (child->y == y)) | |
334 | break; | |
335 | ||
336 | child->x = x; | |
337 | child->y = y; | |
338 | ||
339 | if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (pizza)) | |
340 | gtk_widget_queue_resize (widget); | |
341 | break; | |
342 | } | |
343 | } | |
344 | } | |
345 | ||
346 | void | |
347 | gtk_pizza_resize (GtkPizza *pizza, | |
348 | GtkWidget *widget, | |
349 | gint width, | |
350 | gint height) | |
351 | { | |
352 | GtkPizzaChild *child; | |
353 | GList *children; | |
354 | ||
355 | g_return_if_fail (pizza != NULL); | |
356 | g_return_if_fail (GTK_IS_PIZZA (pizza)); | |
357 | g_return_if_fail (widget != NULL); | |
358 | ||
359 | children = pizza->children; | |
360 | while (children) | |
361 | { | |
362 | child = children->data; | |
363 | children = children->next; | |
364 | ||
365 | if (child->widget == widget) | |
366 | { | |
367 | if ((child->width == width) && (child->height == height)) | |
368 | break; | |
369 | ||
370 | child->width = width; | |
371 | child->height = height; | |
372 | ||
373 | gtk_widget_set_size_request (widget, width, height); | |
374 | ||
375 | if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (pizza)) | |
376 | gtk_widget_queue_resize (widget); | |
377 | break; | |
378 | } | |
379 | } | |
380 | } | |
381 | ||
382 | void | |
383 | gtk_pizza_set_size (GtkPizza *pizza, | |
384 | GtkWidget *widget, | |
385 | gint x, | |
386 | gint y, | |
387 | gint width, | |
388 | gint height) | |
389 | { | |
390 | GtkPizzaChild *child; | |
391 | GList *children; | |
392 | ||
393 | g_return_if_fail (pizza != NULL); | |
394 | g_return_if_fail (GTK_IS_PIZZA (pizza)); | |
395 | g_return_if_fail (widget != NULL); | |
396 | ||
397 | #ifndef WX_WARN_ILLEGAL_SETSIZE | |
398 | /* this really shouldn't happen -- but it does, a lot, right now and we | |
399 | can't pass negative values to gtk_widget_set_size_request() without getting | |
400 | a warning printed out, so filter them out here */ | |
401 | if ( width < 0 ) | |
402 | width = 0; | |
403 | if ( height < 0 ) | |
404 | height = 0; | |
405 | #endif | |
406 | ||
407 | children = pizza->children; | |
408 | while (children) | |
409 | { | |
410 | child = children->data; | |
411 | children = children->next; | |
412 | ||
413 | if (child->widget == widget) | |
414 | { | |
415 | if ((child->x == x) && | |
416 | (child->y == y) && | |
417 | (child->width == width) && | |
418 | (child->height == height)) return; | |
419 | ||
420 | child->x = x; | |
421 | child->y = y; | |
422 | child->width = width; | |
423 | child->height = height; | |
424 | ||
425 | gtk_widget_set_size_request (widget, width, height); | |
426 | ||
427 | if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (pizza)) | |
428 | gtk_widget_queue_resize (widget); | |
429 | ||
430 | return; | |
431 | } | |
432 | } | |
433 | } | |
434 | ||
435 | gint | |
436 | gtk_pizza_child_resized (GtkPizza *pizza, | |
437 | GtkWidget *widget) | |
438 | { | |
439 | GtkPizzaChild *child; | |
440 | GList *children; | |
441 | ||
442 | g_return_val_if_fail (pizza != NULL, FALSE); | |
443 | g_return_val_if_fail (GTK_IS_PIZZA (pizza), FALSE); | |
444 | g_return_val_if_fail (widget != NULL, FALSE); | |
445 | ||
446 | children = pizza->children; | |
447 | while (children) | |
448 | { | |
449 | child = children->data; | |
450 | children = children->next; | |
451 | ||
452 | if (child->widget == widget) | |
453 | { | |
454 | return ((child->width == widget->allocation.width) && | |
455 | (child->height == widget->allocation.height)); | |
456 | } | |
457 | } | |
458 | ||
459 | return FALSE; | |
460 | } | |
461 | ||
462 | static void | |
463 | gtk_pizza_map (GtkWidget *widget) | |
464 | { | |
465 | GtkPizza *pizza; | |
466 | GtkPizzaChild *child; | |
467 | GList *children; | |
468 | ||
469 | g_return_if_fail (widget != NULL); | |
470 | g_return_if_fail (GTK_IS_PIZZA (widget)); | |
471 | ||
472 | GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); | |
473 | pizza = GTK_PIZZA (widget); | |
474 | ||
475 | children = pizza->children; | |
476 | while (children) | |
477 | { | |
478 | child = children->data; | |
479 | children = children->next; | |
480 | ||
481 | if ( GTK_WIDGET_VISIBLE (child->widget) && | |
482 | !GTK_WIDGET_MAPPED (child->widget) && | |
483 | TRUE) | |
484 | { | |
485 | gtk_widget_map (child->widget); | |
486 | } | |
487 | } | |
488 | ||
489 | gdk_window_show (widget->window); | |
490 | gdk_window_show (pizza->bin_window); | |
491 | } | |
492 | ||
493 | static void | |
494 | gtk_pizza_realize (GtkWidget *widget) | |
495 | { | |
496 | GtkPizza *pizza; | |
497 | GdkWindowAttr attributes; | |
498 | gint attributes_mask; | |
499 | GtkPizzaChild *child; | |
500 | GList *children; | |
501 | ||
502 | g_return_if_fail (widget != NULL); | |
503 | g_return_if_fail (GTK_IS_PIZZA (widget)); | |
504 | ||
505 | pizza = GTK_PIZZA (widget); | |
506 | GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); | |
507 | ||
508 | attributes.window_type = GDK_WINDOW_CHILD; | |
509 | ||
510 | attributes.x = widget->allocation.x; | |
511 | attributes.y = widget->allocation.y; | |
512 | attributes.width = widget->allocation.width; | |
513 | attributes.height = widget->allocation.height; | |
514 | ||
515 | #ifndef __WXUNIVERSAL__ | |
516 | if (pizza->shadow_type == GTK_MYSHADOW_NONE) | |
517 | { | |
518 | /* no border, no changes to sizes */ | |
519 | } | |
520 | else if (pizza->shadow_type == GTK_MYSHADOW_THIN) | |
521 | { | |
522 | /* GTK_MYSHADOW_THIN == wxSIMPLE_BORDER */ | |
523 | attributes.x += 1; | |
524 | attributes.y += 1; | |
525 | attributes.width -= 2; | |
526 | attributes.height -= 2; | |
527 | } | |
528 | else | |
529 | { | |
530 | /* GTK_MYSHADOW_IN == wxSUNKEN_BORDER */ | |
531 | /* GTK_MYSHADOW_OUT == wxRAISED_BORDER */ | |
532 | attributes.x += 2; | |
533 | attributes.y += 2; | |
534 | attributes.width -= 4; | |
535 | attributes.height -= 4; | |
536 | } | |
537 | #endif /* __WXUNIVERSAL__ */ | |
538 | ||
539 | /* minimal size */ | |
540 | if (attributes.width < 2) attributes.width = 2; | |
541 | if (attributes.height < 2) attributes.height = 2; | |
542 | ||
543 | attributes.wclass = GDK_INPUT_OUTPUT; | |
544 | attributes.visual = gtk_widget_get_visual (widget); | |
545 | attributes.colormap = gtk_widget_get_colormap (widget); | |
546 | attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK; | |
547 | attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; | |
548 | ||
549 | widget->window = gdk_window_new(gtk_widget_get_parent_window (widget), | |
550 | &attributes, attributes_mask); | |
551 | gdk_window_set_user_data (widget->window, widget); | |
552 | ||
553 | attributes.x = 0; | |
554 | attributes.y = 0; | |
555 | ||
556 | attributes.event_mask = gtk_widget_get_events (widget); | |
557 | attributes.event_mask |= GDK_EXPOSURE_MASK | | |
558 | GDK_SCROLL_MASK | | |
559 | GDK_POINTER_MOTION_MASK | | |
560 | GDK_POINTER_MOTION_HINT_MASK | | |
561 | GDK_BUTTON_MOTION_MASK | | |
562 | GDK_BUTTON1_MOTION_MASK | | |
563 | GDK_BUTTON2_MOTION_MASK | | |
564 | GDK_BUTTON3_MOTION_MASK | | |
565 | GDK_BUTTON_PRESS_MASK | | |
566 | GDK_BUTTON_RELEASE_MASK | | |
567 | GDK_KEY_PRESS_MASK | | |
568 | GDK_KEY_RELEASE_MASK | | |
569 | GDK_ENTER_NOTIFY_MASK | | |
570 | GDK_LEAVE_NOTIFY_MASK | | |
571 | GDK_FOCUS_CHANGE_MASK; | |
572 | ||
573 | pizza->bin_window = gdk_window_new(widget->window, | |
574 | &attributes, attributes_mask); | |
575 | gdk_window_set_user_data (pizza->bin_window, widget); | |
576 | ||
577 | widget->style = gtk_style_attach (widget->style, widget->window); | |
578 | gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); | |
579 | gtk_style_set_background (widget->style, pizza->bin_window, GTK_STATE_NORMAL ); | |
580 | ||
581 | /* | |
582 | gdk_window_set_back_pixmap( widget->window, NULL, FALSE ); | |
583 | gdk_window_set_back_pixmap( pizza->bin_window, NULL, FALSE ); | |
584 | */ | |
585 | ||
586 | /* cannot be done before realisation */ | |
587 | children = pizza->children; | |
588 | while (children) | |
589 | { | |
590 | child = children->data; | |
591 | children = children->next; | |
592 | ||
593 | gtk_widget_set_parent_window (child->widget, pizza->bin_window); | |
594 | } | |
595 | } | |
596 | ||
597 | static void | |
598 | gtk_pizza_unrealize (GtkWidget *widget) | |
599 | { | |
600 | GtkPizza *pizza; | |
601 | ||
602 | g_return_if_fail (widget != NULL); | |
603 | g_return_if_fail (GTK_IS_PIZZA (widget)); | |
604 | ||
605 | pizza = GTK_PIZZA (widget); | |
606 | ||
607 | gdk_window_set_user_data (pizza->bin_window, NULL); | |
608 | gdk_window_destroy (pizza->bin_window); | |
609 | pizza->bin_window = NULL; | |
610 | ||
611 | if (GTK_WIDGET_CLASS (pizza_parent_class)->unrealize) | |
612 | (* GTK_WIDGET_CLASS (pizza_parent_class)->unrealize) (widget); | |
613 | } | |
614 | ||
615 | static void | |
616 | gtk_pizza_size_request (GtkWidget *widget, | |
617 | GtkRequisition *requisition) | |
618 | { | |
619 | GtkPizza *pizza; | |
620 | GtkPizzaChild *child; | |
621 | GList *children; | |
622 | GtkRequisition child_requisition; | |
623 | ||
624 | g_return_if_fail (widget != NULL); | |
625 | g_return_if_fail (GTK_IS_PIZZA (widget)); | |
626 | g_return_if_fail (requisition != NULL); | |
627 | ||
628 | pizza = GTK_PIZZA (widget); | |
629 | ||
630 | children = pizza->children; | |
631 | while (children) | |
632 | { | |
633 | child = children->data; | |
634 | children = children->next; | |
635 | ||
636 | if (GTK_WIDGET_VISIBLE (child->widget)) | |
637 | { | |
638 | gtk_widget_size_request (child->widget, &child_requisition); | |
639 | } | |
640 | } | |
641 | ||
642 | /* request very little, I'm not sure if requesting nothing | |
643 | will always have positive effects on stability... */ | |
644 | requisition->width = 2; | |
645 | requisition->height = 2; | |
646 | } | |
647 | ||
648 | static void | |
649 | gtk_pizza_size_allocate (GtkWidget *widget, | |
650 | GtkAllocation *allocation) | |
651 | { | |
652 | GtkPizza *pizza; | |
653 | gint border; | |
654 | gint x,y,w,h; | |
655 | GtkPizzaChild *child; | |
656 | GList *children; | |
657 | ||
658 | g_return_if_fail (widget != NULL); | |
659 | g_return_if_fail (GTK_IS_PIZZA(widget)); | |
660 | g_return_if_fail (allocation != NULL); | |
661 | ||
662 | pizza = GTK_PIZZA (widget); | |
663 | ||
664 | widget->allocation = *allocation; | |
665 | ||
666 | if (pizza->shadow_type == GTK_MYSHADOW_NONE) | |
667 | border = 0; | |
668 | else | |
669 | if (pizza->shadow_type == GTK_MYSHADOW_THIN) | |
670 | border = 1; | |
671 | else | |
672 | border = 2; | |
673 | ||
674 | x = allocation->x + border; | |
675 | y = allocation->y + border; | |
676 | w = allocation->width - border*2; | |
677 | h = allocation->height - border*2; | |
678 | ||
679 | if (GTK_WIDGET_REALIZED (widget)) | |
680 | { | |
681 | gdk_window_move_resize( widget->window, x, y, w, h ); | |
682 | gdk_window_move_resize( pizza->bin_window, 0, 0, w, h ); | |
683 | } | |
684 | ||
685 | children = pizza->children; | |
686 | while (children) | |
687 | { | |
688 | child = children->data; | |
689 | children = children->next; | |
690 | ||
691 | gtk_pizza_allocate_child (pizza, child); | |
692 | } | |
693 | } | |
694 | ||
695 | static gint | |
696 | gtk_pizza_expose (GtkWidget *widget, | |
697 | GdkEventExpose *event) | |
698 | { | |
699 | GtkPizza *pizza; | |
700 | ||
701 | g_return_val_if_fail (widget != NULL, FALSE); | |
702 | g_return_val_if_fail (GTK_IS_PIZZA (widget), FALSE); | |
703 | g_return_val_if_fail (event != NULL, FALSE); | |
704 | ||
705 | pizza = GTK_PIZZA (widget); | |
706 | ||
707 | if (event->window != pizza->bin_window) | |
708 | return FALSE; | |
709 | ||
710 | /* We handle all expose events in window.cpp now. */ | |
711 | if (pizza->external_expose) | |
712 | return FALSE; | |
713 | ||
714 | (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, event); | |
715 | ||
716 | return FALSE; | |
717 | } | |
718 | ||
719 | static void | |
720 | gtk_pizza_style_set(GtkWidget *widget, GtkStyle *previous_style) | |
721 | { | |
722 | if (GTK_WIDGET_REALIZED(widget)) | |
723 | { | |
724 | gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL); | |
725 | gtk_style_set_background(widget->style, GTK_PIZZA(widget)->bin_window, GTK_STATE_NORMAL ); | |
726 | } | |
727 | ||
728 | (* GTK_WIDGET_CLASS (pizza_parent_class)->style_set) (widget, previous_style); | |
729 | } | |
730 | ||
731 | static void | |
732 | gtk_pizza_add (GtkContainer *container, | |
733 | GtkWidget *widget) | |
734 | { | |
735 | g_return_if_fail (container != NULL); | |
736 | g_return_if_fail (GTK_IS_PIZZA (container)); | |
737 | g_return_if_fail (widget != NULL); | |
738 | ||
739 | gtk_pizza_put (GTK_PIZZA (container), widget, 0, 0, 20, 20 ); | |
740 | } | |
741 | ||
742 | static void | |
743 | gtk_pizza_remove (GtkContainer *container, | |
744 | GtkWidget *widget) | |
745 | { | |
746 | GtkPizza *pizza; | |
747 | GtkPizzaChild *child; | |
748 | GList *children; | |
749 | ||
750 | g_return_if_fail (container != NULL); | |
751 | g_return_if_fail (GTK_IS_PIZZA (container)); | |
752 | g_return_if_fail (widget != NULL); | |
753 | ||
754 | pizza = GTK_PIZZA (container); | |
755 | ||
756 | children = pizza->children; | |
757 | while (children) | |
758 | { | |
759 | child = children->data; | |
760 | ||
761 | if (child->widget == widget) | |
762 | { | |
763 | gtk_widget_unparent (widget); | |
764 | ||
765 | /* security checks */ | |
766 | g_return_if_fail (GTK_IS_WIDGET (widget)); | |
767 | ||
768 | pizza->children = g_list_remove_link (pizza->children, children); | |
769 | g_list_free (children); | |
770 | g_free (child); | |
771 | ||
772 | /* security checks */ | |
773 | g_return_if_fail (GTK_IS_WIDGET (widget)); | |
774 | ||
775 | break; | |
776 | } | |
777 | ||
778 | children = children->next; | |
779 | } | |
780 | } | |
781 | ||
782 | static void | |
783 | gtk_pizza_forall (GtkContainer *container, | |
784 | gboolean include_internals, | |
785 | GtkCallback callback, | |
786 | gpointer callback_data) | |
787 | { | |
788 | GtkPizza *pizza; | |
789 | GtkPizzaChild *child; | |
790 | GList *children; | |
791 | ||
792 | g_return_if_fail (container != NULL); | |
793 | g_return_if_fail (GTK_IS_PIZZA (container)); | |
794 | g_return_if_fail (callback != (GtkCallback)NULL); | |
795 | ||
796 | pizza = GTK_PIZZA (container); | |
797 | ||
798 | children = pizza->children; | |
799 | while (children) | |
800 | { | |
801 | child = children->data; | |
802 | children = children->next; | |
803 | ||
804 | (* callback) (child->widget, callback_data); | |
805 | } | |
806 | } | |
807 | ||
808 | static void | |
809 | gtk_pizza_allocate_child (GtkPizza *pizza, | |
810 | GtkPizzaChild *child) | |
811 | { | |
812 | GtkAllocation allocation; | |
813 | GtkRequisition requisition; | |
814 | ||
815 | allocation.x = child->x - pizza->xoffset; | |
816 | allocation.y = child->y - pizza->yoffset; | |
817 | gtk_widget_get_child_requisition (child->widget, &requisition); | |
818 | allocation.width = requisition.width; | |
819 | allocation.height = requisition.height; | |
820 | ||
821 | gtk_widget_size_allocate (child->widget, &allocation); | |
822 | } | |
823 | ||
824 | static void | |
825 | gtk_pizza_adjust_allocations_recurse (GtkWidget *widget, | |
826 | gpointer cb_data) | |
827 | { | |
828 | GtkPizzaAdjData *data = cb_data; | |
829 | ||
830 | widget->allocation.x += data->dx; | |
831 | widget->allocation.y += data->dy; | |
832 | ||
833 | if (GTK_WIDGET_NO_WINDOW (widget) && GTK_IS_CONTAINER (widget)) | |
834 | { | |
835 | gtk_container_forall (GTK_CONTAINER (widget), | |
836 | gtk_pizza_adjust_allocations_recurse, | |
837 | cb_data); | |
838 | } | |
839 | } | |
840 | ||
841 | static void | |
842 | gtk_pizza_adjust_allocations (GtkPizza *pizza, | |
843 | gint dx, | |
844 | gint dy) | |
845 | { | |
846 | GList *tmp_list; | |
847 | GtkPizzaAdjData data; | |
848 | ||
849 | data.dx = dx; | |
850 | data.dy = dy; | |
851 | ||
852 | tmp_list = pizza->children; | |
853 | while (tmp_list) | |
854 | { | |
855 | GtkPizzaChild *child = tmp_list->data; | |
856 | tmp_list = tmp_list->next; | |
857 | ||
858 | child->widget->allocation.x += dx; | |
859 | child->widget->allocation.y += dy; | |
860 | ||
861 | if (GTK_WIDGET_NO_WINDOW (child->widget) && | |
862 | GTK_IS_CONTAINER (child->widget)) | |
863 | { | |
864 | gtk_container_forall (GTK_CONTAINER (child->widget), | |
865 | gtk_pizza_adjust_allocations_recurse, | |
866 | &data); | |
867 | } | |
868 | } | |
869 | } | |
870 | ||
871 | ||
872 | /* This is the main routine to do the scrolling. Scrolling is | |
873 | * done by "Guffaw" scrolling, as in the Mozilla XFE, with | |
874 | * a few modifications. | |
875 | * | |
876 | * The main improvement is that we keep track of whether we | |
877 | * are obscured or not. If not, we ignore the generated expose | |
878 | * events and instead do the exposes ourself, without having | |
879 | * to wait for a roundtrip to the server. This also provides | |
880 | * a limited form of expose-event compression, since we do | |
881 | * the affected area as one big chunk. | |
882 | */ | |
883 | ||
884 | void | |
885 | gtk_pizza_scroll (GtkPizza *pizza, gint dx, gint dy) | |
886 | { | |
887 | pizza->xoffset += dx; | |
888 | pizza->yoffset += dy; | |
889 | ||
890 | gtk_pizza_adjust_allocations (pizza, -dx, -dy); | |
891 | ||
892 | if (pizza->bin_window) | |
893 | gdk_window_scroll( pizza->bin_window, -dx, -dy ); | |
894 | } | |
895 | ||
896 | #ifdef __cplusplus | |
897 | } | |
898 | #endif /* __cplusplus */ |