gdk_event_new() already returns a struct filled with zeros
[hildon] / hildon / hildon-gtk.c
1 /*
2  * This file is a part of hildon
3  *
4  * Copyright (C) 2008 Nokia Corporation, all rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser Public License as published by
8  * the Free Software Foundation; version 2 of the license.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser Public License for more details.
14  *
15  */
16
17 /**
18  * SECTION:hildon-gtk
19  * @short_description: Additional functions for Gtk widgets
20  * @see_also: #HildonButton, #HildonCheckButton
21  *
22  * Hildon provides some functions to extend the functionality of
23  * existing Gtk widgets. This also includes convenience functions to
24  * easily perform frequent tasks.
25  */
26
27 #include <X11/Xatom.h>
28 #include <gdk/gdkx.h>
29
30 #include "hildon-gtk.h"
31
32 typedef void (*HildonFlagFunc) (GtkWindow *window, gpointer userdata);
33
34 static void
35 image_visible_changed_cb                        (GtkWidget  *image,
36                                                  GParamSpec *arg1,
37                                                  gpointer   oldparent)
38 {
39     if (!GTK_WIDGET_VISIBLE (image))
40         gtk_widget_show (image);
41 }
42
43 static void
44 parent_changed_cb                               (GtkWidget  *image,
45                                                  GParamSpec *arg1,
46                                                  gpointer   oldparent)
47 {
48     /* If the parent has really changed, remove the old signal handlers */
49     if (image->parent != oldparent) {
50         g_signal_handlers_disconnect_by_func (image, parent_changed_cb, oldparent);
51         g_signal_handlers_disconnect_by_func (image, image_visible_changed_cb, NULL);
52     }
53 }
54
55 static void
56 image_changed_cb                                (GtkButton  *button,
57                                                  GParamSpec *arg1,
58                                                  gpointer    user_data)
59 {
60     GtkWidget *image = gtk_button_get_image (button);
61
62     g_return_if_fail (image == NULL || GTK_IS_WIDGET (image));
63
64     if (image != NULL) {
65         /* If the button has a new image, show it */
66         gtk_widget_show (image);
67         /* Show the image no matter the value of gtk-button-images */
68         g_signal_connect (image, "notify::visible", G_CALLBACK (image_visible_changed_cb), NULL);
69         /* If the image is removed from the button, disconnect these handlers */
70         g_signal_connect (image, "notify::parent", G_CALLBACK (parent_changed_cb), image->parent);
71     }
72 }
73
74 static void
75 button_common_init                              (GtkWidget      *button,
76                                                  HildonSizeType  size)
77 {
78     /* Set requested size */
79     hildon_gtk_widget_set_theme_size (button, size);
80
81     /* Set focus-on-click to FALSE by default */
82     gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
83
84     /* Make sure that all images in this button are always shown */
85     g_signal_connect (button, "notify::image", G_CALLBACK (image_changed_cb), NULL);
86 }
87
88 /**
89  * hildon_gtk_menu_new:
90  *
91  * This is a convenience function to create a #GtkMenu setting its
92  * widget name to allow Hildon specific styling.
93  *
94  * Return value: A newly created #GtkMenu widget.
95  *
96  * Since: 2.2
97  **/
98 GtkWidget *
99 hildon_gtk_menu_new                             (void)
100 {
101     GtkWidget *menu = gtk_menu_new ();
102     gtk_widget_set_name (menu, "hildon-context-sensitive-menu");
103     return menu;
104 }
105
106 /**
107  * hildon_gtk_button_new:
108  * @size: Flags indicating the size of the new button
109  *
110  * This is a convenience function to create a #GtkButton setting its
111  * size to one of the pre-defined Hildon sizes.
112  *
113  * Buttons created with this function also override the
114  * "gtk-button-images" setting. Images set using
115  * gtk_button_set_image() are always shown.
116  *
117  * Buttons created using this function have #GtkButton:focus-on-click
118  * set to %FALSE by default.
119  *
120  * Return value: A newly created #GtkButton widget.
121  *
122  * Since: 2.2
123  **/
124 GtkWidget *
125 hildon_gtk_button_new                           (HildonSizeType size)
126 {
127     GtkWidget *button = gtk_button_new ();
128     button_common_init (button, size);
129     return button;
130 }
131
132 /**
133  * hildon_gtk_toggle_button_new:
134  * @size: Flags indicating the size of the new button
135  *
136  * This is a convenience function to create a #GtkToggleButton setting
137  * its size to one of the pre-defined Hildon sizes.
138  *
139  * Buttons created with this function also override the
140  * "gtk-button-images" setting. Images set using
141  * gtk_button_set_image() are always shown.
142  *
143  * Buttons created using this function have #GtkButton:focus-on-click
144  * set to %FALSE by default.
145  *
146  * Return value: A newly created #GtkToggleButton widget.
147  *
148  * Since: 2.2
149  **/
150 GtkWidget *
151 hildon_gtk_toggle_button_new                    (HildonSizeType size)
152 {
153     GtkWidget *button = gtk_toggle_button_new ();
154     button_common_init (button, size);
155     return button;
156 }
157
158 /**
159  * hildon_gtk_radio_button_new:
160  * @size: Flags indicating the size of the new button
161  * @group: An existing radio button group, or %NULL if you are
162  * creating a new group
163  *
164  * This is a convenience function to create a #GtkRadioButton setting
165  * its size to one of the pre-defined Hildon sizes.
166  *
167  * Buttons created with this function also override the
168  * "gtk-button-images" setting. Images set using
169  * gtk_button_set_image() are always shown.
170  *
171  * Buttons created using this function have #GtkButton:focus-on-click
172  * set to %FALSE by default.
173  *
174  * Return value: A newly created #GtkRadioButton widget.
175  *
176  * Since: 2.2
177  **/
178 GtkWidget *
179 hildon_gtk_radio_button_new                     (HildonSizeType  size,
180                                                  GSList         *group)
181 {
182     GtkWidget *button = gtk_radio_button_new (group);
183     button_common_init (button, size);
184     return button;
185 }
186
187 /**
188  * hildon_gtk_radio_button_new_from_widget:
189  * @size: Flags indicating the size of the new button
190  * @radio_group_member: widget to get radio group from or %NULL
191  *
192  * This is a convenience function to create a #GtkRadioButton setting
193  * its size to one of the pre-defined Hildon sizes.
194  *
195  * Buttons created with this function also override the
196  * "gtk-button-images" setting. Images set using
197  * gtk_button_set_image() are always shown.
198  *
199  * Buttons created using this function have #GtkButton:focus-on-click
200  * set to %FALSE by default.
201  *
202  * Return value: A newly created #GtkRadioButton widget.
203  *
204  * Since: 2.2
205  **/
206 GtkWidget *
207 hildon_gtk_radio_button_new_from_widget         (HildonSizeType  size,
208                                                  GtkRadioButton *radio_group_member)
209 {
210     GtkWidget *button = gtk_radio_button_new_from_widget (radio_group_member);
211     button_common_init (button, size);
212     return button;
213 }
214
215 #ifdef MAEMO_GTK
216 /**
217  * hildon_gtk_tree_view_new:
218  * @mode: the Hildon UI mode
219  *
220  * Creates a new #GtkTreeView widget with the Hildon UI mode set to
221  * @mode
222  *
223  * Return value: A newly created #GtkTreeView widget.
224  *
225  * Since: 2.2
226  **/
227 GtkWidget *
228 hildon_gtk_tree_view_new                        (HildonUIMode mode)
229 {
230     return g_object_new (GTK_TYPE_TREE_VIEW, "hildon-ui-mode", mode,
231                          "enable-search", FALSE, NULL);
232 }
233
234 /**
235  * hildon_gtk_tree_view_new_with_model:
236  * @mode: the Hildon UI mode
237  * @model: the model.
238  *
239  * Creates a new #GtkTreeView widget with the Hildon UI mode set to
240  * @mode and the model initialized to @model.
241  *
242  * Return value: A newly created #GtkTreeView widget.
243  *
244  * Since: 2.2
245  **/
246 GtkWidget *
247 hildon_gtk_tree_view_new_with_model             (HildonUIMode  mode,
248                                                  GtkTreeModel *model)
249 {
250     return g_object_new (GTK_TYPE_TREE_VIEW, "hildon-ui-mode", mode, "model", model, NULL);
251 }
252
253 /**
254  * hildon_gtk_tree_view_set_ui_mode:
255  * @treeview: A #GtkTreeView
256  * @mode: The new #HildonUIMode
257  *
258  * Sets the UI mode of @treeview to @mode.
259  *
260  * Since: 2.2
261  **/
262 void
263 hildon_gtk_tree_view_set_ui_mode                (GtkTreeView  *treeview,
264                                                  HildonUIMode  mode)
265 {
266     g_return_if_fail (GTK_IS_TREE_VIEW (treeview));
267     g_object_set (treeview, "hildon-ui-mode", mode, NULL);
268 }
269
270 /**
271  * hildon_gtk_icon_view_new:
272  * @mode: the Hildon UI mode
273  *
274  * Creates a new #GtkIconView widget with the Hildon UI mode set to
275  * @mode
276  *
277  * Return value: A newly created #GtkIconView widget
278  *
279  * Since: 2.2
280  **/
281 GtkWidget *
282 hildon_gtk_icon_view_new                        (HildonUIMode mode)
283 {
284     return g_object_new (GTK_TYPE_ICON_VIEW, "hildon-ui-mode", mode, NULL);
285 }
286
287 /**
288  * hildon_gtk_icon_view_new_with_model:
289  * @mode: the Hildon UI mode
290  * @model: The model.
291  *
292  * Creates a new #GtkIconView widget with the Hildon UI mode set to
293  * @mode and the model intitialized to @model.
294  *
295  * Return value: A newly created #GtkIconView widget.
296  *
297  * Since: 2.2
298  **/
299 GtkWidget *
300 hildon_gtk_icon_view_new_with_model             (HildonUIMode  mode,
301                                                  GtkTreeModel *model)
302 {
303     return g_object_new (GTK_TYPE_ICON_VIEW, "hildon-ui-mode", mode, "model", model, NULL);
304 }
305
306 /**
307  * hildon_gtk_icon_view_set_ui_mode:
308  * @iconview: A #GtkIconView
309  * @mode: The new #HildonUIMode
310  *
311  * Sets the UI mode of @iconview to @mode.
312  *
313  * Since: 2.2
314  **/
315 void
316 hildon_gtk_icon_view_set_ui_mode                (GtkIconView  *iconview,
317                                                  HildonUIMode  mode)
318 {
319     g_return_if_fail (GTK_IS_ICON_VIEW (iconview));
320     g_object_set (iconview, "hildon-ui-mode", mode, NULL);
321 }
322 #endif /* MAEMO_GTK */
323
324 static void
325 set_clear_window_flag                           (GtkWindow   *window,
326                                                  const gchar *atomname,
327                                                  Atom         xatom,
328                                                  gboolean     flag)
329 {
330     GdkWindow *gdkwin = GTK_WIDGET (window)->window;
331     GdkAtom atom = gdk_atom_intern (atomname, FALSE);
332
333     if (flag) {
334         guint32 set = 1;
335         gdk_property_change (gdkwin, atom, gdk_x11_xatom_to_atom (xatom),
336                              32, GDK_PROP_MODE_REPLACE, (const guchar *) &set, 1);
337     } else {
338         gdk_property_delete (gdkwin, atom);
339     }
340 }
341
342 static void
343 do_set_progress_indicator                       (GtkWindow *window,
344                                                  gpointer   stateptr)
345 {
346     guint state = GPOINTER_TO_UINT (stateptr);
347     set_clear_window_flag (window, "_HILDON_WM_WINDOW_PROGRESS_INDICATOR", XA_INTEGER, state);
348     g_signal_handlers_disconnect_matched (window, G_SIGNAL_MATCH_FUNC,
349                                           0, 0, NULL, do_set_progress_indicator, NULL);
350 }
351
352 static void
353 do_set_do_not_disturb                           (GtkWindow *window,
354                                                  gpointer   dndptr)
355 {
356     gboolean dndflag = GPOINTER_TO_INT (dndptr);
357     set_clear_window_flag (window, "_HILDON_DO_NOT_DISTURB", XA_INTEGER, dndflag);
358     g_signal_handlers_disconnect_matched (window, G_SIGNAL_MATCH_FUNC,
359                                           0, 0, NULL, do_set_do_not_disturb, NULL);
360 }
361
362 static void
363 do_set_portrait_flags                           (GtkWindow *window,
364                                                  gpointer   flagsptr)
365 {
366     HildonPortraitFlags flags = GPOINTER_TO_INT (flagsptr);
367
368     set_clear_window_flag (window, "_HILDON_PORTRAIT_MODE_REQUEST", XA_CARDINAL,
369                            flags & HILDON_PORTRAIT_MODE_REQUEST);
370     set_clear_window_flag (window, "_HILDON_PORTRAIT_MODE_SUPPORT", XA_CARDINAL,
371                            flags & HILDON_PORTRAIT_MODE_SUPPORT);
372
373     g_signal_handlers_disconnect_matched (window, G_SIGNAL_MATCH_FUNC,
374                                           0, 0, NULL, do_set_portrait_flags, NULL);
375 }
376
377 static void
378 set_flag                                        (GtkWindow      *window,
379                                                  HildonFlagFunc  func,
380                                                  gpointer        userdata)
381 {
382      g_return_if_fail (GTK_IS_WINDOW (window));
383      if (GTK_WIDGET_REALIZED (window)) {
384         (*func) (window, userdata);
385      } else {
386          g_signal_handlers_disconnect_matched (window, G_SIGNAL_MATCH_FUNC,
387                                                0, 0, NULL, func, NULL);
388          g_signal_connect (window, "realize", G_CALLBACK (func), userdata);
389      }
390 }
391
392 /**
393  * hildon_gtk_window_set_progress_indicator:
394  * @window: a #GtkWindow.
395  * @state: The state we want to set: 1 -> show progress indicator, 0
396  *          -> hide progress indicator.
397  *
398  * This functions tells the window manager to show/hide a progress
399  * indicator in the window title. It applies to #HildonDialog and
400  * #HildonWindow (including subclasses).
401  *
402  * Since: 2.2
403  **/
404 void
405 hildon_gtk_window_set_progress_indicator        (GtkWindow *window,
406                                                  guint      state)
407 {
408     set_flag (window, (HildonFlagFunc) do_set_progress_indicator, GUINT_TO_POINTER (state));
409 }
410
411 /**
412  * hildon_gtk_window_set_do_not_disturb:
413  * @window: a #GtkWindow
414  * @dndflag: %TRUE to set the "do-not-disturb" flag, %FALSE to clear it
415  *
416  * This function tells the window manager to set (or clear) the
417  * "do-not-disturb" flag on @window.
418  *
419  * Since: 2.2
420  **/
421 void
422 hildon_gtk_window_set_do_not_disturb            (GtkWindow *window,
423                                                  gboolean   dndflag)
424 {
425     set_flag (window, (HildonFlagFunc) do_set_do_not_disturb, GUINT_TO_POINTER (dndflag));
426 }
427
428 /**
429  * hildon_gtk_window_set_portrait_flags:
430  * @window: a #GtkWindow
431  * @portrait_flags: a combination of #HildonPortraitFlags
432  *
433  * Sets the portrait flags for @window.
434  *
435  * Since: 2.2
436  **/
437 void
438 hildon_gtk_window_set_portrait_flags            (GtkWindow           *window,
439                                                  HildonPortraitFlags  portrait_flags)
440 {
441     set_flag (window, (HildonFlagFunc) do_set_portrait_flags, GUINT_TO_POINTER (portrait_flags));
442 }
443
444 /**
445  * hildon_gtk_window_take_screenshot:
446  * @window: a #GtkWindow
447  * @take: %TRUE to take a screenshot, %FALSE to destroy the existing one.
448  *
449  * Tells the window manager to take a screenshot of @window, or to
450  * destroy the existing one. @window must be mapped.
451  **/
452 void
453 hildon_gtk_window_take_screenshot               (GtkWindow *window,
454                                                  gboolean   take)
455 {
456     GdkEventClient *ev;
457     GdkWindow *rootwin;
458
459     g_return_if_fail (GTK_IS_WINDOW (window));
460     g_return_if_fail (GTK_WIDGET_MAPPED (window));
461
462     rootwin = gdk_screen_get_root_window (gtk_window_get_screen (window));
463
464     ev = (GdkEventClient *) gdk_event_new (GDK_CLIENT_EVENT);
465     ev->window = g_object_ref (rootwin);
466     ev->send_event = TRUE;
467     ev->message_type = gdk_atom_intern ("_HILDON_LOADING_SCREENSHOT", FALSE);
468     ev->data_format = 32;
469     ev->data.l[0] = take ? 1 : 0;
470     ev->data.l[1] = GDK_WINDOW_XID (GTK_WIDGET (window)->window);
471
472     gdk_event_send_client_message ((GdkEvent *) ev, GDK_WINDOW_XWINDOW (rootwin));
473
474     gdk_event_free ((GdkEvent *) ev);
475 }
476
477
478 /**
479  * hildon_gtk_hscale_new:
480  *
481  * Creates a new horizontal scale widget that lets the user select
482  * a value. The value is technically a double between 0.0 and 1.0.
483  * See gtk_adjustment_configure() for reconfiguring the adjustment.
484  *
485  * The scale is hildonized, which means that a click or tap immediately
486  * jumps to the desired position, see gtk_range_set_jump_to_position().
487  * Further more the value is not displayed, see gtk_scale_set_draw_value().
488  *
489  * Returns: a new hildonized #GtkHScale
490  *
491  * Since: 2.2
492  **/
493 GtkWidget*
494 hildon_gtk_hscale_new                           (void)
495 {
496   GtkWidget *scale = gtk_hscale_new_with_range (0.0, 1.0, 0.1);
497   g_object_set (scale,
498                 "draw-value", FALSE,
499 #ifdef MAEMO_GTK
500                 "jump-to-position", TRUE,
501 #endif
502                 NULL);
503
504   return scale;
505 }
506
507 /**
508  * hildon_gtk_vscale_new:
509  *
510  * Creates a new vertical scale widget that lets the user select
511  * a value. The value is technically a double between 0.0 and 1.0.
512  * See gtk_adjustment_configure() for reconfiguring the adjustment.
513  *
514  * The scale is hildonized, which means that a click or tap immediately
515  * jumps to the desired position, see gtk_range_set_jump_to_position().
516  * Further more the value is not displayed, see gtk_scale_set_draw_value().
517  *
518  * Returns: a new hildonized #GtkVScale
519  *
520  * Since: 2.2
521  **/
522 GtkWidget*
523 hildon_gtk_vscale_new                           (void)
524 {
525   GtkWidget *scale = gtk_vscale_new_with_range (0.0, 1.0, 0.1);
526   g_object_set (scale,
527                 "draw-value", FALSE,
528 #ifdef MAEMO_GTK
529                 "jump-to-position", TRUE,
530 #endif
531                 NULL);
532
533   return scale;
534 }