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