]> Pileus Git - ~andy/gtk/blob - gtk/gtkseparatortoolitem.c
separatortoolitem: Port to draw vfunc
[~andy/gtk] / gtk / gtkseparatortoolitem.c
1 /* gtkseparatortoolitem.c
2  *
3  * Copyright (C) 2002 Anders Carlsson <andersca@gnome.org>
4  * Copyright (C) 2002 James Henstridge <james@daa.com.au>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include "config.h"
23 #include "gtkseparatormenuitem.h"
24 #include "gtkseparatortoolitem.h"
25 #include "gtkintl.h"
26 #include "gtktoolbar.h"
27 #include "gtkprivate.h"
28
29 /**
30  * SECTION:gtkseparatortoolitem
31  * @Short_description: A toolbar item that separates groups of other
32  *   toolbar items
33  * @Title: GtkSeparatorToolItem
34  * @See_also: #GtkToolbar, #GtkRadioToolButton
35  *
36  * A #GtkSeparatorItem is a #GtkToolItem that separates groups of other
37  * #GtkToolItems. Depending on the theme, a #GtkSeparatorToolItem will
38  * often look like a vertical line on horizontally docked toolbars.
39  *
40  * If the #GtkToolbar child property "expand" is %TRUE and the property
41  * #GtkSeparatorToolItem:draw is %FALSE, a #GtkSeparatorToolItem will act as
42  * a "spring" that forces other items to the ends of the toolbar.
43  *
44  * Use gtk_separator_tool_item_new() to create a new #GtkSeparatorToolItem.
45  */
46
47 #define MENU_ID "gtk-separator-tool-item-menu-id"
48
49 struct _GtkSeparatorToolItemPrivate
50 {
51   GdkWindow *event_window;
52   guint draw : 1;
53 };
54
55 enum {
56   PROP_0,
57   PROP_DRAW
58 };
59
60 static gboolean gtk_separator_tool_item_create_menu_proxy (GtkToolItem               *item);
61 static void     gtk_separator_tool_item_set_property      (GObject                   *object,
62                                                            guint                      prop_id,
63                                                            const GValue              *value,
64                                                            GParamSpec                *pspec);
65 static void     gtk_separator_tool_item_get_property      (GObject                   *object,
66                                                            guint                      prop_id,
67                                                            GValue                    *value,
68                                                            GParamSpec                *pspec);
69 static void     gtk_separator_tool_item_size_request      (GtkWidget                 *widget,
70                                                            GtkRequisition            *requisition);
71 static void     gtk_separator_tool_item_size_allocate     (GtkWidget                 *widget,
72                                                            GtkAllocation             *allocation);
73 static gboolean gtk_separator_tool_item_draw              (GtkWidget                 *widget,
74                                                            cairo_t                   *cr);
75 static void     gtk_separator_tool_item_add               (GtkContainer              *container,
76                                                            GtkWidget                 *child);
77 static gint     get_space_size                            (GtkToolItem               *tool_item);
78 static void     gtk_separator_tool_item_realize           (GtkWidget                 *widget);
79 static void     gtk_separator_tool_item_unrealize         (GtkWidget                 *widget);
80 static void     gtk_separator_tool_item_map               (GtkWidget                 *widget);
81 static void     gtk_separator_tool_item_unmap             (GtkWidget                 *widget);
82 static gboolean gtk_separator_tool_item_button_event      (GtkWidget                 *widget,
83                                                            GdkEventButton            *event);
84
85
86 G_DEFINE_TYPE (GtkSeparatorToolItem, gtk_separator_tool_item, GTK_TYPE_TOOL_ITEM)
87
88 static gint
89 get_space_size (GtkToolItem *tool_item)
90 {
91   gint space_size = _gtk_toolbar_get_default_space_size();
92   GtkWidget *parent;
93
94   parent = gtk_widget_get_parent (GTK_WIDGET (tool_item));
95
96   if (GTK_IS_TOOLBAR (parent))
97     {
98       gtk_widget_style_get (parent,
99                             "space-size", &space_size,
100                             NULL);
101     }
102   
103   return space_size;
104 }
105
106 static void
107 gtk_separator_tool_item_class_init (GtkSeparatorToolItemClass *class)
108 {
109   GObjectClass *object_class;
110   GtkContainerClass *container_class;
111   GtkToolItemClass *toolitem_class;
112   GtkWidgetClass *widget_class;
113   
114   object_class = (GObjectClass *)class;
115   container_class = (GtkContainerClass *)class;
116   toolitem_class = (GtkToolItemClass *)class;
117   widget_class = (GtkWidgetClass *)class;
118
119   object_class->set_property = gtk_separator_tool_item_set_property;
120   object_class->get_property = gtk_separator_tool_item_get_property;
121   widget_class->size_request = gtk_separator_tool_item_size_request;
122   widget_class->size_allocate = gtk_separator_tool_item_size_allocate;
123   widget_class->draw = gtk_separator_tool_item_draw;
124   widget_class->realize = gtk_separator_tool_item_realize;
125   widget_class->unrealize = gtk_separator_tool_item_unrealize;
126   widget_class->map = gtk_separator_tool_item_map;
127   widget_class->unmap = gtk_separator_tool_item_unmap;
128   widget_class->button_press_event = gtk_separator_tool_item_button_event;
129   widget_class->button_release_event = gtk_separator_tool_item_button_event;
130
131   toolitem_class->create_menu_proxy = gtk_separator_tool_item_create_menu_proxy;
132   
133   container_class->add = gtk_separator_tool_item_add;
134   
135   g_object_class_install_property (object_class,
136                                    PROP_DRAW,
137                                    g_param_spec_boolean ("draw",
138                                                          P_("Draw"),
139                                                          P_("Whether the separator is drawn, or just blank"),
140                                                          TRUE,
141                                                          GTK_PARAM_READWRITE));
142   
143
144   g_type_class_add_private (object_class, sizeof (GtkSeparatorToolItemPrivate));
145 }
146
147 static void
148 gtk_separator_tool_item_init (GtkSeparatorToolItem *separator_item)
149 {
150   separator_item->priv = G_TYPE_INSTANCE_GET_PRIVATE (separator_item,
151                                                       GTK_TYPE_SEPARATOR_TOOL_ITEM,
152                                                       GtkSeparatorToolItemPrivate);
153   separator_item->priv->draw = TRUE;
154
155   gtk_widget_set_has_window (GTK_WIDGET (separator_item), FALSE);
156 }
157
158 static void
159 gtk_separator_tool_item_add (GtkContainer *container,
160                              GtkWidget    *child)
161 {
162   g_warning ("attempt to add a child to an GtkSeparatorToolItem");
163 }
164
165 static gboolean
166 gtk_separator_tool_item_create_menu_proxy (GtkToolItem *item)
167 {
168   GtkWidget *menu_item = NULL;
169   
170   menu_item = gtk_separator_menu_item_new();
171   
172   gtk_tool_item_set_proxy_menu_item (item, MENU_ID, menu_item);
173   
174   return TRUE;
175 }
176
177 static void
178 gtk_separator_tool_item_set_property (GObject      *object,
179                                       guint         prop_id,
180                                       const GValue *value,
181                                       GParamSpec   *pspec)
182 {
183   GtkSeparatorToolItem *item = GTK_SEPARATOR_TOOL_ITEM (object);
184   
185   switch (prop_id)
186     {
187     case PROP_DRAW:
188       gtk_separator_tool_item_set_draw (item, g_value_get_boolean (value));
189       break;
190     default:
191       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
192       break;
193     }
194 }
195
196 static void
197 gtk_separator_tool_item_get_property (GObject      *object,
198                                       guint         prop_id,
199                                       GValue       *value,
200                                       GParamSpec   *pspec)
201 {
202   GtkSeparatorToolItem *item = GTK_SEPARATOR_TOOL_ITEM (object);
203   
204   switch (prop_id)
205     {
206     case PROP_DRAW:
207       g_value_set_boolean (value, gtk_separator_tool_item_get_draw (item));
208       break;
209     default:
210       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
211       break;
212     }
213 }
214
215 static void
216 gtk_separator_tool_item_size_request (GtkWidget      *widget,
217                                       GtkRequisition *requisition)
218 {
219   GtkToolItem *item = GTK_TOOL_ITEM (widget);
220   GtkOrientation orientation = gtk_tool_item_get_orientation (item);
221   
222   if (orientation == GTK_ORIENTATION_HORIZONTAL)
223     {
224       requisition->width = get_space_size (item);
225       requisition->height = 1;
226     }
227   else
228     {
229       requisition->height = get_space_size (item);
230       requisition->width = 1;
231     }
232 }
233
234 static void
235 gtk_separator_tool_item_size_allocate (GtkWidget     *widget,
236                                        GtkAllocation *allocation)
237 {
238   GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
239   GtkSeparatorToolItemPrivate *priv = separator->priv;
240
241   gtk_widget_set_allocation (widget, allocation);
242
243   if (gtk_widget_get_realized (widget))
244     gdk_window_move_resize (priv->event_window,
245                             allocation->x,
246                             allocation->y,
247                             allocation->width,
248                             allocation->height);
249
250 }
251
252 static void
253 gtk_separator_tool_item_realize (GtkWidget *widget)
254 {
255   GtkAllocation allocation;
256   GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
257   GtkSeparatorToolItemPrivate *priv = separator->priv;
258   GdkWindow *window;
259   GdkWindowAttr attributes;
260   gint attributes_mask;
261
262   gtk_widget_set_realized (widget, TRUE);
263
264   gtk_widget_get_allocation (widget, &allocation);
265
266   attributes.window_type = GDK_WINDOW_CHILD;
267   attributes.x = allocation.x;
268   attributes.y = allocation.y;
269   attributes.width = allocation.width;
270   attributes.height = allocation.height;
271   attributes.wclass = GDK_INPUT_ONLY;
272   attributes.visual = gtk_widget_get_visual (widget);
273   attributes.event_mask = gtk_widget_get_events (widget) |
274                           GDK_BUTTON_PRESS_MASK |
275                           GDK_BUTTON_RELEASE_MASK;
276   attributes_mask = GDK_WA_X | GDK_WA_Y;
277
278   window = gtk_widget_get_parent_window (widget);
279   gtk_widget_set_window (widget, window);
280   g_object_ref (window);
281
282   priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
283                                        &attributes, attributes_mask);
284   gdk_window_set_user_data (priv->event_window, widget);
285
286   gtk_widget_style_attach (widget);
287 }
288
289 static void
290 gtk_separator_tool_item_unrealize (GtkWidget *widget)
291 {
292   GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
293   GtkSeparatorToolItemPrivate *priv = separator->priv;
294
295   if (priv->event_window)
296     {
297       gdk_window_set_user_data (priv->event_window, NULL);
298       gdk_window_destroy (priv->event_window);
299       priv->event_window = NULL;
300     }
301
302   GTK_WIDGET_CLASS (gtk_separator_tool_item_parent_class)->unrealize (widget);
303 }
304
305 static void
306 gtk_separator_tool_item_map (GtkWidget *widget)
307 {
308   GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
309   GtkSeparatorToolItemPrivate *priv = separator->priv;
310
311   GTK_WIDGET_CLASS (gtk_separator_tool_item_parent_class)->map (widget);
312
313   if (priv->event_window)
314     gdk_window_show (priv->event_window);
315 }
316
317 static void
318 gtk_separator_tool_item_unmap (GtkWidget *widget)
319 {
320   GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
321   GtkSeparatorToolItemPrivate *priv = separator->priv;
322
323   if (priv->event_window)
324     gdk_window_hide (priv->event_window);
325
326   GTK_WIDGET_CLASS (gtk_separator_tool_item_parent_class)->unmap (widget);
327 }
328
329 static gboolean
330 gtk_separator_tool_item_button_event (GtkWidget      *widget,
331                                       GdkEventButton *event)
332 {
333   GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
334   GtkSeparatorToolItemPrivate *priv = separator->priv;
335
336   /* We want window dragging to work on empty toolbar areas,
337    * so we only eat button events on visible separators
338    */
339   return priv->draw;
340 }
341
342 static gboolean
343 gtk_separator_tool_item_draw (GtkWidget *widget,
344                               cairo_t   *cr)
345 {
346   GtkAllocation allocation;
347   GtkToolbar *toolbar = NULL;
348   GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
349   GtkSeparatorToolItemPrivate *priv = separator->priv;
350   GtkWidget *parent;
351
352   if (priv->draw)
353     {
354       parent = gtk_widget_get_parent (widget);
355       if (GTK_IS_TOOLBAR (parent))
356         toolbar = GTK_TOOLBAR (parent);
357
358       gtk_widget_get_allocation (widget, &allocation);
359       _gtk_toolbar_paint_space_line (widget, toolbar, cr);
360     }
361
362   return FALSE;
363 }
364
365 /**
366  * gtk_separator_tool_item_new:
367  * 
368  * Create a new #GtkSeparatorToolItem
369  * 
370  * Return value: the new #GtkSeparatorToolItem
371  * 
372  * Since: 2.4
373  */
374 GtkToolItem *
375 gtk_separator_tool_item_new (void)
376 {
377   GtkToolItem *self;
378   
379   self = g_object_new (GTK_TYPE_SEPARATOR_TOOL_ITEM,
380                        NULL);
381   
382   return self;
383 }
384
385 /**
386  * gtk_separator_tool_item_get_draw:
387  * @item: a #GtkSeparatorToolItem 
388  * 
389  * Returns whether @item is drawn as a line, or just blank. 
390  * See gtk_separator_tool_item_set_draw().
391  * 
392  * Return value: %TRUE if @item is drawn as a line, or just blank.
393  * 
394  * Since: 2.4
395  */
396 gboolean
397 gtk_separator_tool_item_get_draw (GtkSeparatorToolItem *item)
398 {
399   g_return_val_if_fail (GTK_IS_SEPARATOR_TOOL_ITEM (item), FALSE);
400   
401   return item->priv->draw;
402 }
403
404 /**
405  * gtk_separator_tool_item_set_draw:
406  * @item: a #GtkSeparatorToolItem
407  * @draw: whether @item is drawn as a vertical line
408  * 
409  * Whether @item is drawn as a vertical line, or just blank.
410  * Setting this to %FALSE along with gtk_tool_item_set_expand() is useful
411  * to create an item that forces following items to the end of the toolbar.
412  * 
413  * Since: 2.4
414  */
415 void
416 gtk_separator_tool_item_set_draw (GtkSeparatorToolItem *item,
417                                   gboolean              draw)
418 {
419   g_return_if_fail (GTK_IS_SEPARATOR_TOOL_ITEM (item));
420
421   draw = draw != FALSE;
422
423   if (draw != item->priv->draw)
424     {
425       item->priv->draw = draw;
426
427       gtk_widget_queue_draw (GTK_WIDGET (item));
428
429       g_object_notify (G_OBJECT (item), "draw");
430     }
431 }