]> Pileus Git - ~andy/gtk/blob - gtk/gtkseparatortoolitem.c
Allow windows to be dragged by clicking on empty areas
[~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_expose            (GtkWidget                 *widget,
74                                                            GdkEventExpose            *event);
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 = GTK_WIDGET (tool_item)->parent;
93   
94   if (GTK_IS_TOOLBAR (parent))
95     {
96       gtk_widget_style_get (parent,
97                             "space-size", &space_size,
98                             NULL);
99     }
100   
101   return space_size;
102 }
103
104 static void
105 gtk_separator_tool_item_class_init (GtkSeparatorToolItemClass *class)
106 {
107   GObjectClass *object_class;
108   GtkContainerClass *container_class;
109   GtkToolItemClass *toolitem_class;
110   GtkWidgetClass *widget_class;
111   
112   object_class = (GObjectClass *)class;
113   container_class = (GtkContainerClass *)class;
114   toolitem_class = (GtkToolItemClass *)class;
115   widget_class = (GtkWidgetClass *)class;
116
117   object_class->set_property = gtk_separator_tool_item_set_property;
118   object_class->get_property = gtk_separator_tool_item_get_property;
119   widget_class->size_request = gtk_separator_tool_item_size_request;
120   widget_class->size_allocate = gtk_separator_tool_item_size_allocate;
121   widget_class->expose_event = gtk_separator_tool_item_expose;
122   widget_class->realize = gtk_separator_tool_item_realize;
123   widget_class->unrealize = gtk_separator_tool_item_unrealize;
124   widget_class->map = gtk_separator_tool_item_map;
125   widget_class->unmap = gtk_separator_tool_item_unmap;
126   widget_class->button_press_event = gtk_separator_tool_item_button_event;
127   widget_class->button_release_event = gtk_separator_tool_item_button_event;
128
129   toolitem_class->create_menu_proxy = gtk_separator_tool_item_create_menu_proxy;
130   
131   container_class->add = gtk_separator_tool_item_add;
132   
133   g_object_class_install_property (object_class,
134                                    PROP_DRAW,
135                                    g_param_spec_boolean ("draw",
136                                                          P_("Draw"),
137                                                          P_("Whether the separator is drawn, or just blank"),
138                                                          TRUE,
139                                                          GTK_PARAM_READWRITE));
140   
141
142   g_type_class_add_private (object_class, sizeof (GtkSeparatorToolItemPrivate));
143 }
144
145 static void
146 gtk_separator_tool_item_init (GtkSeparatorToolItem *separator_item)
147 {
148   separator_item->priv = G_TYPE_INSTANCE_GET_PRIVATE (separator_item,
149                                                       GTK_TYPE_SEPARATOR_TOOL_ITEM,
150                                                       GtkSeparatorToolItemPrivate);
151   separator_item->priv->draw = TRUE;
152
153   gtk_widget_set_has_window (GTK_WIDGET (separator_item), FALSE);
154 }
155
156 static void
157 gtk_separator_tool_item_add (GtkContainer *container,
158                              GtkWidget    *child)
159 {
160   g_warning ("attempt to add a child to an GtkSeparatorToolItem");
161 }
162
163 static gboolean
164 gtk_separator_tool_item_create_menu_proxy (GtkToolItem *item)
165 {
166   GtkWidget *menu_item = NULL;
167   
168   menu_item = gtk_separator_menu_item_new();
169   
170   gtk_tool_item_set_proxy_menu_item (item, MENU_ID, menu_item);
171   
172   return TRUE;
173 }
174
175 static void
176 gtk_separator_tool_item_set_property (GObject      *object,
177                                       guint         prop_id,
178                                       const GValue *value,
179                                       GParamSpec   *pspec)
180 {
181   GtkSeparatorToolItem *item = GTK_SEPARATOR_TOOL_ITEM (object);
182   
183   switch (prop_id)
184     {
185     case PROP_DRAW:
186       gtk_separator_tool_item_set_draw (item, g_value_get_boolean (value));
187       break;
188     default:
189       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
190       break;
191     }
192 }
193
194 static void
195 gtk_separator_tool_item_get_property (GObject      *object,
196                                       guint         prop_id,
197                                       GValue       *value,
198                                       GParamSpec   *pspec)
199 {
200   GtkSeparatorToolItem *item = GTK_SEPARATOR_TOOL_ITEM (object);
201   
202   switch (prop_id)
203     {
204     case PROP_DRAW:
205       g_value_set_boolean (value, gtk_separator_tool_item_get_draw (item));
206       break;
207     default:
208       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
209       break;
210     }
211 }
212
213 static void
214 gtk_separator_tool_item_size_request (GtkWidget      *widget,
215                                       GtkRequisition *requisition)
216 {
217   GtkToolItem *item = GTK_TOOL_ITEM (widget);
218   GtkOrientation orientation = gtk_tool_item_get_orientation (item);
219   
220   if (orientation == GTK_ORIENTATION_HORIZONTAL)
221     {
222       requisition->width = get_space_size (item);
223       requisition->height = 1;
224     }
225   else
226     {
227       requisition->height = get_space_size (item);
228       requisition->width = 1;
229     }
230 }
231
232 static void
233 gtk_separator_tool_item_size_allocate (GtkWidget     *widget,
234                                        GtkAllocation *allocation)
235 {
236   GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
237   GtkSeparatorToolItemPrivate *priv = separator->priv;
238
239   widget->allocation = *allocation;
240
241   if (gtk_widget_get_realized (widget))
242     gdk_window_move_resize (priv->event_window,
243                             widget->allocation.x,
244                             widget->allocation.y,
245                             widget->allocation.width,
246                             widget->allocation.height);
247
248 }
249
250 static void
251 gtk_separator_tool_item_realize (GtkWidget *widget)
252 {
253   GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
254   GtkSeparatorToolItemPrivate *priv = separator->priv;
255   GdkWindowAttr attributes;
256   gint attributes_mask;
257
258   gtk_widget_set_realized (widget, TRUE);
259
260   attributes.window_type = GDK_WINDOW_CHILD;
261   attributes.x = widget->allocation.x;
262   attributes.y = widget->allocation.y;
263   attributes.width = widget->allocation.width;
264   attributes.height = widget->allocation.height;
265   attributes.wclass = GDK_INPUT_ONLY;
266   attributes.visual = gtk_widget_get_visual (widget);
267   attributes.colormap = gtk_widget_get_colormap (widget);
268   attributes.event_mask = gtk_widget_get_events (widget) |
269                           GDK_BUTTON_PRESS_MASK |
270                           GDK_BUTTON_RELEASE_MASK;
271   attributes_mask = GDK_WA_X | GDK_WA_Y;
272
273   widget->window = gtk_widget_get_parent_window (widget);
274   g_object_ref (widget->window);
275
276   priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
277                                        &attributes, attributes_mask);
278   gdk_window_set_user_data (priv->event_window, widget);
279
280   widget->style = gtk_style_attach (widget->style, widget->window);
281 }
282
283 static void
284 gtk_separator_tool_item_unrealize (GtkWidget *widget)
285 {
286   GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
287   GtkSeparatorToolItemPrivate *priv = separator->priv;
288
289   if (priv->event_window)
290     {
291       gdk_window_set_user_data (priv->event_window, NULL);
292       gdk_window_destroy (priv->event_window);
293       priv->event_window = NULL;
294     }
295
296   GTK_WIDGET_CLASS (gtk_separator_tool_item_parent_class)->unrealize (widget);
297 }
298
299 static void
300 gtk_separator_tool_item_map (GtkWidget *widget)
301 {
302   GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
303   GtkSeparatorToolItemPrivate *priv = separator->priv;
304
305   GTK_WIDGET_CLASS (gtk_separator_tool_item_parent_class)->map (widget);
306
307   if (priv->event_window)
308     gdk_window_show (priv->event_window);
309 }
310
311 static void
312 gtk_separator_tool_item_unmap (GtkWidget *widget)
313 {
314   GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
315   GtkSeparatorToolItemPrivate *priv = separator->priv;
316
317   if (priv->event_window)
318     gdk_window_hide (priv->event_window);
319
320   GTK_WIDGET_CLASS (gtk_separator_tool_item_parent_class)->unmap (widget);
321 }
322
323 static gboolean
324 gtk_separator_tool_item_button_event (GtkWidget      *widget,
325                                       GdkEventButton *event)
326 {
327   GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
328   GtkSeparatorToolItemPrivate *priv = separator->priv;
329
330   /* We want window dragging to work on empty toolbar areas,
331    * so we only eat button events on visible separators
332    */
333   return priv->draw;
334 }
335
336 #define DEFAULT_SPACE_SIZE  12
337 #define DEFAULT_SPACE_STYLE GTK_TOOLBAR_SPACE_LINE
338 #define SPACE_LINE_DIVISION 10.0
339 #define SPACE_LINE_START    2.0
340 #define SPACE_LINE_END      8.0
341
342 static gboolean
343 gtk_separator_tool_item_expose (GtkWidget      *widget,
344                                 GdkEventExpose *event)
345 {
346   GtkToolbar *toolbar = NULL;
347   GtkSeparatorToolItem *separator = GTK_SEPARATOR_TOOL_ITEM (widget);
348   GtkSeparatorToolItemPrivate *priv = separator->priv;
349
350   if (priv->draw)
351     {
352       if (GTK_IS_TOOLBAR (widget->parent))
353         toolbar = GTK_TOOLBAR (widget->parent);
354
355       _gtk_toolbar_paint_space_line (widget, toolbar,
356                                      &(event->area), &widget->allocation);
357     }
358
359   return FALSE;
360 }
361
362 /**
363  * gtk_separator_tool_item_new:
364  * 
365  * Create a new #GtkSeparatorToolItem
366  * 
367  * Return value: the new #GtkSeparatorToolItem
368  * 
369  * Since: 2.4
370  */
371 GtkToolItem *
372 gtk_separator_tool_item_new (void)
373 {
374   GtkToolItem *self;
375   
376   self = g_object_new (GTK_TYPE_SEPARATOR_TOOL_ITEM,
377                        NULL);
378   
379   return self;
380 }
381
382 /**
383  * gtk_separator_tool_item_get_draw:
384  * @item: a #GtkSeparatorToolItem 
385  * 
386  * Returns whether @item is drawn as a line, or just blank. 
387  * See gtk_separator_tool_item_set_draw().
388  * 
389  * Return value: %TRUE if @item is drawn as a line, or just blank.
390  * 
391  * Since: 2.4
392  */
393 gboolean
394 gtk_separator_tool_item_get_draw (GtkSeparatorToolItem *item)
395 {
396   g_return_val_if_fail (GTK_IS_SEPARATOR_TOOL_ITEM (item), FALSE);
397   
398   return item->priv->draw;
399 }
400
401 /**
402  * gtk_separator_tool_item_set_draw:
403  * @item: a #GtkSeparatorToolItem
404  * @draw: whether @item is drawn as a vertical line
405  * 
406  * Whether @item is drawn as a vertical line, or just blank.
407  * Setting this to %FALSE along with gtk_tool_item_set_expand() is useful
408  * to create an item that forces following items to the end of the toolbar.
409  * 
410  * Since: 2.4
411  */
412 void
413 gtk_separator_tool_item_set_draw (GtkSeparatorToolItem *item,
414                                   gboolean              draw)
415 {
416   g_return_if_fail (GTK_IS_SEPARATOR_TOOL_ITEM (item));
417
418   draw = draw != FALSE;
419
420   if (draw != item->priv->draw)
421     {
422       item->priv->draw = draw;
423
424       gtk_widget_queue_draw (GTK_WIDGET (item));
425
426       g_object_notify (G_OBJECT (item), "draw");
427     }
428 }