]> Pileus Git - ~andy/gtk/blob - gtk/gtkpaned.c
do not avoid to queue for a resize if the container is not visible, we
[~andy/gtk] / gtk / gtkpaned.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 #include "gtkpaned.h"
20
21
22 static void gtk_paned_class_init (GtkPanedClass    *klass);
23 static void gtk_paned_init       (GtkPaned         *paned);
24 static void gtk_paned_realize    (GtkWidget *widget);
25 static void gtk_paned_map        (GtkWidget      *widget);
26 static void gtk_paned_unmap      (GtkWidget      *widget);
27 static void gtk_paned_unrealize  (GtkWidget *widget);
28 static gint gtk_paned_expose     (GtkWidget      *widget,
29                                 GdkEventExpose *event);
30 static void gtk_paned_add        (GtkContainer   *container,
31                                 GtkWidget      *widget);
32 static void gtk_paned_remove     (GtkContainer   *container,
33                                 GtkWidget      *widget);
34 static void gtk_paned_foreach    (GtkContainer   *container,
35                                 GtkCallback     callback,
36                                 gpointer        callback_data);
37 static GtkType gtk_paned_child_type (GtkContainer *container);
38
39
40 static GtkContainerClass *parent_class = NULL;
41
42
43 guint
44 gtk_paned_get_type (void)
45 {
46   static guint paned_type = 0;
47
48   if (!paned_type)
49     {
50       GtkTypeInfo paned_info =
51       {
52         "GtkPaned",
53         sizeof (GtkPaned),
54         sizeof (GtkPanedClass),
55         (GtkClassInitFunc) gtk_paned_class_init,
56         (GtkObjectInitFunc) gtk_paned_init,
57         (GtkArgSetFunc) NULL,
58         (GtkArgGetFunc) NULL,
59       };
60
61       paned_type = gtk_type_unique (gtk_container_get_type (), &paned_info);
62     }
63
64   return paned_type;
65 }
66
67 static void
68 gtk_paned_class_init (GtkPanedClass *class)
69 {
70   GtkObjectClass *object_class;
71   GtkWidgetClass *widget_class;
72   GtkContainerClass *container_class;
73
74   object_class = (GtkObjectClass*) class;
75   widget_class = (GtkWidgetClass*) class;
76   container_class = (GtkContainerClass*) class;
77
78   parent_class = gtk_type_class (gtk_container_get_type ());
79
80   widget_class->realize = gtk_paned_realize;
81   widget_class->map = gtk_paned_map;
82   widget_class->unmap = gtk_paned_unmap;
83   widget_class->unrealize = gtk_paned_unrealize;
84   widget_class->expose_event = gtk_paned_expose;
85
86   container_class->add = gtk_paned_add;
87   container_class->remove = gtk_paned_remove;
88   container_class->foreach = gtk_paned_foreach;
89   container_class->child_type = gtk_paned_child_type;
90 }
91
92 static GtkType
93 gtk_paned_child_type (GtkContainer *container)
94 {
95   if (!GTK_PANED (container)->child1 || !GTK_PANED (container)->child2)
96     return GTK_TYPE_WIDGET;
97   else
98     return GTK_TYPE_NONE;
99 }
100
101 static void
102 gtk_paned_init (GtkPaned *paned)
103 {
104   GTK_WIDGET_UNSET_FLAGS (paned, GTK_NO_WINDOW);
105
106   paned->child1 = NULL;
107   paned->child2 = NULL;
108   paned->handle = NULL;
109   paned->xor_gc = NULL;
110
111   paned->handle_size = 10;
112   paned->gutter_size = 6;
113   paned->position_set = FALSE;
114   paned->in_drag = FALSE;
115
116   paned->handle_xpos = -1;
117   paned->handle_ypos = -1;
118 }
119
120
121 static void
122 gtk_paned_realize (GtkWidget *widget)
123 {
124   GtkPaned *paned;
125   GdkWindowAttr attributes;
126   gint attributes_mask;
127
128   g_return_if_fail (widget != NULL);
129   g_return_if_fail (GTK_IS_PANED (widget));
130
131   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
132   paned = GTK_PANED (widget);
133
134   attributes.x = widget->allocation.x;
135   attributes.y = widget->allocation.y;
136   attributes.width = widget->allocation.width;
137   attributes.height = widget->allocation.height;
138   attributes.window_type = GDK_WINDOW_CHILD;
139   attributes.wclass = GDK_INPUT_OUTPUT;
140   attributes.visual = gtk_widget_get_visual (widget);
141   attributes.colormap = gtk_widget_get_colormap (widget);
142   attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
143   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
144
145   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
146                                    &attributes, attributes_mask);
147   gdk_window_set_user_data (widget->window, paned);
148
149   attributes.x = paned->handle_xpos;
150   attributes.y = paned->handle_ypos;
151   attributes.width = paned->handle_size;
152   attributes.height = paned->handle_size;
153   attributes.cursor = paned->cursor = gdk_cursor_new (GDK_CROSS);
154   attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
155                             GDK_BUTTON_RELEASE_MASK |
156                             GDK_POINTER_MOTION_MASK |
157                             GDK_POINTER_MOTION_HINT_MASK);
158   attributes_mask |= GDK_WA_CURSOR;
159
160   paned->handle = gdk_window_new (widget->window,
161                                   &attributes, attributes_mask);
162   gdk_window_set_user_data (paned->handle, paned);
163
164   widget->style = gtk_style_attach (widget->style, widget->window);
165
166   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
167   gtk_style_set_background (widget->style, paned->handle, GTK_STATE_NORMAL);
168
169   gdk_window_show (paned->handle);
170 }
171   
172 static void
173 gtk_paned_map (GtkWidget *widget)
174 {
175   GtkPaned *paned;
176
177   g_return_if_fail (widget != NULL);
178   g_return_if_fail (GTK_IS_PANED (widget));
179
180   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
181   paned = GTK_PANED (widget);
182
183   gdk_window_show (widget->window);
184
185   if (paned->child1 &&
186       GTK_WIDGET_VISIBLE (paned->child1) &&
187       !GTK_WIDGET_MAPPED (paned->child1))
188     gtk_widget_map (paned->child1);
189   if (paned->child2 &&
190       GTK_WIDGET_VISIBLE (paned->child2) &&
191       !GTK_WIDGET_MAPPED (paned->child2))
192     gtk_widget_map (paned->child2);
193 }
194
195 static void
196 gtk_paned_unmap (GtkWidget *widget)
197 {
198   g_return_if_fail (widget != NULL);
199   g_return_if_fail (GTK_IS_PANED (widget));
200
201   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
202
203   gdk_window_hide (widget->window);
204 }
205
206 static void
207 gtk_paned_unrealize (GtkWidget *widget)
208 {
209   GtkPaned *paned;
210
211   g_return_if_fail (widget != NULL);
212   g_return_if_fail (GTK_IS_PANED (widget));
213
214   paned = GTK_PANED (widget);
215
216   if (paned->xor_gc)
217     {
218       gdk_gc_destroy (paned->xor_gc);
219       paned->xor_gc = NULL;
220     }
221
222   if (paned->handle)
223     {
224       gdk_window_set_user_data (paned->handle, NULL);
225       gdk_window_destroy (paned->handle);
226       paned->handle = NULL;
227       gdk_cursor_destroy (paned->cursor);
228       paned->cursor = NULL;
229     }
230
231   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
232     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
233 }
234
235 static gint
236 gtk_paned_expose (GtkWidget      *widget,
237                   GdkEventExpose *event)
238 {
239   GtkPaned *paned;
240   GdkEventExpose child_event;
241
242   g_return_val_if_fail (widget != NULL, FALSE);
243   g_return_val_if_fail (GTK_IS_PANED (widget), FALSE);
244   g_return_val_if_fail (event != NULL, FALSE);
245
246   if (GTK_WIDGET_DRAWABLE (widget))
247     {
248       paned = GTK_PANED (widget);
249
250       /* An expose event for the handle */
251       if (event->window == paned->handle)
252         {
253           gdk_window_set_background (paned->handle,
254                                      &widget->style->bg[widget->state]);
255           gdk_window_clear (paned->handle);
256           gtk_draw_shadow (widget->style, paned->handle,
257                            GTK_WIDGET_STATE(widget),
258                            GTK_SHADOW_OUT, 0, 0,
259                            paned->handle_size, paned->handle_size);
260         }
261       else
262         {
263           child_event = *event;
264           if (paned->child1 &&
265               GTK_WIDGET_NO_WINDOW (paned->child1) &&
266               gtk_widget_intersect (paned->child1, &event->area, &child_event.area))
267             gtk_widget_event (paned->child1, (GdkEvent*) &child_event);
268
269           if (paned->child2 &&
270               GTK_WIDGET_NO_WINDOW (paned->child2) &&
271               gtk_widget_intersect (paned->child2, &event->area, &child_event.area))
272             gtk_widget_event (paned->child2, (GdkEvent*) &child_event);
273
274           /* redraw the groove if necessary */
275           if (gdk_rectangle_intersect (&paned->groove_rectangle, 
276                                        &event->area, 
277                                        &child_event.area))
278             gtk_widget_draw (widget, &child_event.area);
279         }
280     }
281   return FALSE;
282 }
283
284 void
285 gtk_paned_add1 (GtkPaned     *paned,
286                 GtkWidget    *widget)
287 {
288   g_return_if_fail (widget != NULL);
289
290   if (!paned->child1)
291     {
292       gtk_widget_set_parent (widget, GTK_WIDGET (paned));
293
294       if (GTK_WIDGET_VISIBLE (widget->parent))
295         {
296           if (GTK_WIDGET_REALIZED (widget->parent) &&
297               !GTK_WIDGET_REALIZED (widget))
298             gtk_widget_realize (widget);
299           
300           if (GTK_WIDGET_MAPPED (widget->parent) &&
301               !GTK_WIDGET_MAPPED (widget))
302             gtk_widget_map (widget);
303         }
304
305       paned->child1 = widget;
306
307       if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (paned))
308         gtk_widget_queue_resize (widget);
309     }
310 }
311
312 void
313 gtk_paned_add2 (GtkPaned  *paned,
314                 GtkWidget *widget)
315 {
316   g_return_if_fail (widget != NULL);
317
318   if (!paned->child2)
319     {
320       gtk_widget_set_parent (widget, GTK_WIDGET (paned));
321
322       if (GTK_WIDGET_VISIBLE (widget->parent))
323         {
324           if (GTK_WIDGET_REALIZED (widget->parent) &&
325               !GTK_WIDGET_REALIZED (widget))
326             gtk_widget_realize (widget);
327           
328           if (GTK_WIDGET_MAPPED (widget->parent) &&
329               !GTK_WIDGET_MAPPED (widget))
330             gtk_widget_map (widget);
331         }
332
333       paned->child2 = widget;
334
335       if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (paned))
336         gtk_widget_queue_resize (widget);
337     }
338 }
339
340 static void
341 gtk_paned_add (GtkContainer *container,
342                GtkWidget    *widget)
343 {
344   GtkPaned *paned;
345
346   g_return_if_fail (container != NULL);
347   g_return_if_fail (GTK_IS_PANED (container));
348   g_return_if_fail (widget != NULL);
349
350   paned = GTK_PANED (container);
351
352   if (!paned->child1)
353     gtk_paned_add1 (GTK_PANED (container),widget);
354   else if (!paned->child2)
355     gtk_paned_add2 (GTK_PANED (container),widget);
356 }
357
358 static void
359 gtk_paned_remove (GtkContainer *container,
360                   GtkWidget    *widget)
361 {
362   GtkPaned *paned;
363   gboolean was_visible;
364
365   g_return_if_fail (container != NULL);
366   g_return_if_fail (GTK_IS_PANED (container));
367   g_return_if_fail (widget != NULL);
368
369   paned = GTK_PANED (container);
370   was_visible = GTK_WIDGET_VISIBLE (widget);
371   
372   if (paned->child1 == widget)
373     {
374       gtk_widget_unparent (widget);
375
376       paned->child1 = NULL;
377
378       if (was_visible && GTK_WIDGET_VISIBLE (container))
379         gtk_widget_queue_resize (GTK_WIDGET (container));
380     }
381   else if (paned->child2 == widget)
382     {
383       gtk_widget_unparent (widget);
384
385       paned->child2 = NULL;
386
387       if (was_visible && GTK_WIDGET_VISIBLE (container))
388         gtk_widget_queue_resize (GTK_WIDGET (container));
389     }
390 }
391
392 static void
393 gtk_paned_foreach (GtkContainer *container,
394                  GtkCallback   callback,
395                  gpointer      callback_data)
396 {
397   GtkPaned *paned;
398
399   g_return_if_fail (container != NULL);
400   g_return_if_fail (GTK_IS_PANED (container));
401   g_return_if_fail (callback != NULL);
402
403   paned = GTK_PANED (container);
404
405   if (paned->child1)
406     (* callback) (paned->child1, callback_data);
407   if (paned->child2)
408     (* callback) (paned->child2, callback_data);
409 }
410
411 void
412 gtk_paned_handle_size (GtkPaned *paned, guint16 size)
413 {
414   gint x,y;
415
416   if (paned->handle)
417     {
418       gdk_window_get_geometry (paned->handle, &x, &y, NULL, NULL, NULL);
419       gdk_window_move_resize (paned->handle,
420                               x + paned->handle_size / 2 - size / 2,
421                               y + paned->handle_size / 2 - size / 2,
422                               size, size);
423     }
424   
425   paned->handle_size = size;
426 }
427
428 void
429 gtk_paned_gutter_size (GtkPaned *paned, guint16 size)
430 {
431   paned->gutter_size = size;
432
433   if (GTK_WIDGET_VISIBLE (GTK_WIDGET (paned)))
434     gtk_widget_queue_resize (GTK_WIDGET (paned));
435 }
436