]> Pileus Git - ~andy/gtk/blob - gtk/gtkpaned.c
I submitted this patch twice to gtk-devel-list, and received no comments,
[~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_forall     (GtkContainer   *container,
35                                   gboolean        include_internals,
36                                   GtkCallback     callback,
37                                   gpointer        callback_data);
38 static GtkType gtk_paned_child_type (GtkContainer *container);
39
40
41 static GtkContainerClass *parent_class = NULL;
42
43
44 GtkType
45 gtk_paned_get_type (void)
46 {
47   static GtkType paned_type = 0;
48   
49   if (!paned_type)
50     {
51       static const GtkTypeInfo paned_info =
52       {
53         "GtkPaned",
54         sizeof (GtkPaned),
55         sizeof (GtkPanedClass),
56         (GtkClassInitFunc) gtk_paned_class_init,
57         (GtkObjectInitFunc) gtk_paned_init,
58         /* reserved_1 */ NULL,
59         /* reserved_2 */ NULL,
60         (GtkClassInitFunc) NULL,
61       };
62       
63       paned_type = gtk_type_unique (GTK_TYPE_CONTAINER, &paned_info);
64     }
65   
66   return paned_type;
67 }
68
69 static void
70 gtk_paned_class_init (GtkPanedClass *class)
71 {
72   GtkObjectClass *object_class;
73   GtkWidgetClass *widget_class;
74   GtkContainerClass *container_class;
75   
76   object_class = (GtkObjectClass*) class;
77   widget_class = (GtkWidgetClass*) class;
78   container_class = (GtkContainerClass*) class;
79   
80   parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
81   
82   widget_class->realize = gtk_paned_realize;
83   widget_class->map = gtk_paned_map;
84   widget_class->unmap = gtk_paned_unmap;
85   widget_class->unrealize = gtk_paned_unrealize;
86   widget_class->expose_event = gtk_paned_expose;
87   
88   container_class->add = gtk_paned_add;
89   container_class->remove = gtk_paned_remove;
90   container_class->forall = gtk_paned_forall;
91   container_class->child_type = gtk_paned_child_type;
92 }
93
94 static GtkType
95 gtk_paned_child_type (GtkContainer *container)
96 {
97   if (!GTK_PANED (container)->child1 || !GTK_PANED (container)->child2)
98     return GTK_TYPE_WIDGET;
99   else
100     return GTK_TYPE_NONE;
101 }
102
103 static void
104 gtk_paned_init (GtkPaned *paned)
105 {
106   GTK_WIDGET_UNSET_FLAGS (paned, GTK_NO_WINDOW);
107   
108   paned->child1 = NULL;
109   paned->child2 = NULL;
110   paned->handle = NULL;
111   paned->xor_gc = NULL;
112   
113   paned->handle_size = 10;
114   paned->gutter_size = 6;
115   paned->position_set = FALSE;
116   paned->in_drag = FALSE;
117   
118   paned->handle_xpos = -1;
119   paned->handle_ypos = -1;
120 }
121
122
123 static void
124 gtk_paned_realize (GtkWidget *widget)
125 {
126   GtkPaned *paned;
127   GdkWindowAttr attributes;
128   gint attributes_mask;
129   
130   g_return_if_fail (widget != NULL);
131   g_return_if_fail (GTK_IS_PANED (widget));
132   
133   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
134   paned = GTK_PANED (widget);
135   
136   attributes.x = widget->allocation.x;
137   attributes.y = widget->allocation.y;
138   attributes.width = widget->allocation.width;
139   attributes.height = widget->allocation.height;
140   attributes.window_type = GDK_WINDOW_CHILD;
141   attributes.wclass = GDK_INPUT_OUTPUT;
142   attributes.visual = gtk_widget_get_visual (widget);
143   attributes.colormap = gtk_widget_get_colormap (widget);
144   attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
145   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
146   
147   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
148                                    &attributes, attributes_mask);
149   gdk_window_set_user_data (widget->window, paned);
150   
151   attributes.x = paned->handle_xpos;
152   attributes.y = paned->handle_ypos;
153   attributes.width = paned->handle_size;
154   attributes.height = paned->handle_size;
155   attributes.cursor = gdk_cursor_new (GDK_CROSS);
156   attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
157                             GDK_BUTTON_RELEASE_MASK |
158                             GDK_POINTER_MOTION_MASK |
159                             GDK_POINTER_MOTION_HINT_MASK);
160   attributes_mask |= GDK_WA_CURSOR;
161   
162   paned->handle = gdk_window_new (widget->window,
163                                   &attributes, attributes_mask);
164   gdk_window_set_user_data (paned->handle, paned);
165   gdk_cursor_destroy (attributes.cursor);
166   
167   widget->style = gtk_style_attach (widget->style, widget->window);
168   
169   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
170   gtk_style_set_background (widget->style, paned->handle, GTK_STATE_NORMAL);
171
172   gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
173   
174   gdk_window_show (paned->handle);
175 }
176
177 static void
178 gtk_paned_map (GtkWidget *widget)
179 {
180   GtkPaned *paned;
181   
182   g_return_if_fail (widget != NULL);
183   g_return_if_fail (GTK_IS_PANED (widget));
184   
185   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
186   paned = GTK_PANED (widget);
187   
188   gdk_window_show (widget->window);
189   
190   if (paned->child1 &&
191       GTK_WIDGET_VISIBLE (paned->child1) &&
192       !GTK_WIDGET_MAPPED (paned->child1))
193     gtk_widget_map (paned->child1);
194   if (paned->child2 &&
195       GTK_WIDGET_VISIBLE (paned->child2) &&
196       !GTK_WIDGET_MAPPED (paned->child2))
197     gtk_widget_map (paned->child2);
198 }
199
200 static void
201 gtk_paned_unmap (GtkWidget *widget)
202 {
203   g_return_if_fail (widget != NULL);
204   g_return_if_fail (GTK_IS_PANED (widget));
205   
206   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
207   
208   gdk_window_hide (widget->window);
209 }
210
211 static void
212 gtk_paned_unrealize (GtkWidget *widget)
213 {
214   GtkPaned *paned;
215   
216   g_return_if_fail (widget != NULL);
217   g_return_if_fail (GTK_IS_PANED (widget));
218   
219   paned = GTK_PANED (widget);
220   
221   if (paned->xor_gc)
222     {
223       gdk_gc_destroy (paned->xor_gc);
224       paned->xor_gc = NULL;
225     }
226   
227   if (paned->handle)
228     {
229       gdk_window_set_user_data (paned->handle, NULL);
230       gdk_window_destroy (paned->handle);
231       paned->handle = NULL;
232     }
233   
234   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
235     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
236 }
237
238 static gint
239 gtk_paned_expose (GtkWidget      *widget,
240                   GdkEventExpose *event)
241 {
242   GtkPaned *paned;
243   GdkEventExpose child_event;
244   
245   g_return_val_if_fail (widget != NULL, FALSE);
246   g_return_val_if_fail (GTK_IS_PANED (widget), FALSE);
247   g_return_val_if_fail (event != NULL, FALSE);
248   
249   if (GTK_WIDGET_DRAWABLE (widget))
250     {
251       paned = GTK_PANED (widget);
252       
253       /* An expose event for the handle */
254       if (event->window == paned->handle)
255         {
256            gtk_paint_box (widget->style, paned->handle,
257                           GTK_WIDGET_STATE(widget),
258                           GTK_SHADOW_OUT, 
259                           &event->area, widget, "paned",
260                           0, 0,
261                           paned->handle_size, paned->handle_size);
262         }
263       else
264         {
265           child_event = *event;
266           if (paned->child1 &&
267               GTK_WIDGET_NO_WINDOW (paned->child1) &&
268               gtk_widget_intersect (paned->child1, &event->area, &child_event.area))
269             gtk_widget_event (paned->child1, (GdkEvent*) &child_event);
270           
271           if (paned->child2 &&
272               GTK_WIDGET_NO_WINDOW (paned->child2) &&
273               gtk_widget_intersect (paned->child2, &event->area, &child_event.area))
274             gtk_widget_event (paned->child2, (GdkEvent*) &child_event);
275           
276           /* redraw the groove if necessary */
277           if (gdk_rectangle_intersect (&paned->groove_rectangle, 
278                                        &event->area, 
279                                        &child_event.area))
280             gtk_widget_draw (widget, &child_event.area);
281         }
282     }
283   return FALSE;
284 }
285
286 void
287 gtk_paned_add1 (GtkPaned     *paned,
288                 GtkWidget    *widget)
289 {
290   g_return_if_fail (widget != NULL);
291   
292   if (!paned->child1)
293     {
294       gtk_widget_set_parent (widget, GTK_WIDGET (paned));
295       
296       if (GTK_WIDGET_VISIBLE (widget->parent))
297         {
298           if (GTK_WIDGET_REALIZED (widget->parent) &&
299               !GTK_WIDGET_REALIZED (widget))
300             gtk_widget_realize (widget);
301           
302           if (GTK_WIDGET_MAPPED (widget->parent) &&
303               !GTK_WIDGET_MAPPED (widget))
304             gtk_widget_map (widget);
305         }
306       
307       paned->child1 = widget;
308       
309       if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (paned))
310         gtk_widget_queue_resize (widget);
311     }
312 }
313
314 void
315 gtk_paned_add2 (GtkPaned  *paned,
316                 GtkWidget *widget)
317 {
318   g_return_if_fail (widget != NULL);
319   
320   if (!paned->child2)
321     {
322       gtk_widget_set_parent (widget, GTK_WIDGET (paned));
323       
324       if (GTK_WIDGET_VISIBLE (widget->parent))
325         {
326           if (GTK_WIDGET_REALIZED (widget->parent) &&
327               !GTK_WIDGET_REALIZED (widget))
328             gtk_widget_realize (widget);
329           
330           if (GTK_WIDGET_MAPPED (widget->parent) &&
331               !GTK_WIDGET_MAPPED (widget))
332             gtk_widget_map (widget);
333         }
334       
335       paned->child2 = widget;
336       
337       if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (paned))
338         gtk_widget_queue_resize (widget);
339     }
340 }
341
342 static void
343 gtk_paned_add (GtkContainer *container,
344                GtkWidget    *widget)
345 {
346   GtkPaned *paned;
347   
348   g_return_if_fail (container != NULL);
349   g_return_if_fail (GTK_IS_PANED (container));
350   g_return_if_fail (widget != NULL);
351   
352   paned = GTK_PANED (container);
353   
354   if (!paned->child1)
355     gtk_paned_add1 (GTK_PANED (container),widget);
356   else if (!paned->child2)
357     gtk_paned_add2 (GTK_PANED (container),widget);
358 }
359
360 static void
361 gtk_paned_remove (GtkContainer *container,
362                   GtkWidget    *widget)
363 {
364   GtkPaned *paned;
365   gboolean was_visible;
366   
367   g_return_if_fail (container != NULL);
368   g_return_if_fail (GTK_IS_PANED (container));
369   g_return_if_fail (widget != NULL);
370   
371   paned = GTK_PANED (container);
372   was_visible = GTK_WIDGET_VISIBLE (widget);
373   
374   if (paned->child1 == widget)
375     {
376       gtk_widget_unparent (widget);
377       
378       paned->child1 = NULL;
379       
380       if (was_visible && GTK_WIDGET_VISIBLE (container))
381         gtk_widget_queue_resize (GTK_WIDGET (container));
382     }
383   else if (paned->child2 == widget)
384     {
385       gtk_widget_unparent (widget);
386       
387       paned->child2 = NULL;
388       
389       if (was_visible && GTK_WIDGET_VISIBLE (container))
390         gtk_widget_queue_resize (GTK_WIDGET (container));
391     }
392 }
393
394 static void
395 gtk_paned_forall (GtkContainer *container,
396                   gboolean      include_internals,
397                   GtkCallback   callback,
398                   gpointer      callback_data)
399 {
400   GtkPaned *paned;
401   
402   g_return_if_fail (container != NULL);
403   g_return_if_fail (GTK_IS_PANED (container));
404   g_return_if_fail (callback != NULL);
405   
406   paned = GTK_PANED (container);
407   
408   if (paned->child1)
409     (* callback) (paned->child1, callback_data);
410   if (paned->child2)
411     (* callback) (paned->child2, callback_data);
412 }
413
414 void
415 gtk_paned_set_handle_size (GtkPaned *paned,
416                            guint16   size)
417 {
418   gint x,y;
419   
420   g_return_if_fail (paned != NULL);
421   g_return_if_fail (GTK_IS_PANED (paned));
422
423   if (paned->handle)
424     {
425       gdk_window_get_geometry (paned->handle, &x, &y, NULL, NULL, NULL);
426       gdk_window_move_resize (paned->handle,
427                               x + paned->handle_size / 2 - size / 2,
428                               y + paned->handle_size / 2 - size / 2,
429                               size, size);
430     }
431   paned->handle_size = size;
432 }
433
434 void
435 gtk_paned_set_gutter_size (GtkPaned *paned,
436                            guint16   size)
437 {
438   g_return_if_fail (paned != NULL);
439   g_return_if_fail (GTK_IS_PANED (paned));
440
441   paned->gutter_size = size;
442   
443   if (GTK_WIDGET_VISIBLE (GTK_WIDGET (paned)))
444     gtk_widget_queue_resize (GTK_WIDGET (paned));
445 }