Use the Xlib API to take window screenshots
[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 "hildon-gtk.h"
28 #include "hildon-window.h"
29 #include "hildon-window-private.h"
30 #include "hildon-edit-toolbar.h"
31 #include "hildon-edit-toolbar-private.h"
32 #include "hildon-private.h"
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
114  * #GtkSettings:gtk-button-images. 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
140  * #GtkSettings:gtk-button-images. 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
168  * #GtkSettings:gtk-button-images. 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
196  * #GtkSettings:gtk-button-images. 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 do_set_progress_indicator                       (GtkWindow *window,
326                                                  gpointer   stateptr)
327 {
328     guint state = GPOINTER_TO_UINT (stateptr);
329     hildon_gtk_window_set_clear_window_flag (window, "_HILDON_WM_WINDOW_PROGRESS_INDICATOR",
330                                              XA_INTEGER, state);
331     g_signal_handlers_disconnect_matched (window, G_SIGNAL_MATCH_FUNC,
332                                           0, 0, NULL, do_set_progress_indicator, NULL);
333 }
334
335 static void
336 do_set_do_not_disturb                           (GtkWindow *window,
337                                                  gpointer   dndptr)
338 {
339     gboolean dndflag = GPOINTER_TO_INT (dndptr);
340     hildon_gtk_window_set_clear_window_flag (window, "_HILDON_DO_NOT_DISTURB",
341                                              XA_INTEGER, dndflag);
342     g_signal_handlers_disconnect_matched (window, G_SIGNAL_MATCH_FUNC,
343                                           0, 0, NULL, do_set_do_not_disturb, NULL);
344 }
345
346 static void
347 do_set_portrait_flags                           (GtkWindow *window,
348                                                  gpointer   flagsptr)
349 {
350     HildonPortraitFlags flags = GPOINTER_TO_INT (flagsptr);
351
352     hildon_gtk_window_set_clear_window_flag (window, "_HILDON_PORTRAIT_MODE_REQUEST",
353                                              XA_CARDINAL,
354                                              flags & HILDON_PORTRAIT_MODE_REQUEST);
355     hildon_gtk_window_set_clear_window_flag (window, "_HILDON_PORTRAIT_MODE_SUPPORT",
356                                              XA_CARDINAL,
357                                              flags & HILDON_PORTRAIT_MODE_SUPPORT);
358
359     g_signal_handlers_disconnect_matched (window, G_SIGNAL_MATCH_FUNC,
360                                           0, 0, NULL, do_set_portrait_flags, NULL);
361 }
362
363 /**
364  * hildon_gtk_window_set_progress_indicator:
365  * @window: a #GtkWindow.
366  * @state: The state we want to set: 1 -> show progress indicator, 0
367  *          -> hide progress indicator.
368  *
369  * This functions tells the window manager to show/hide a progress
370  * indicator in the window title. It applies to #HildonDialog and
371  * #HildonWindow (including subclasses).
372  *
373  * Since: 2.2
374  **/
375 void
376 hildon_gtk_window_set_progress_indicator        (GtkWindow *window,
377                                                  guint      state)
378 {
379     hildon_gtk_window_set_flag (window, (HildonFlagFunc) do_set_progress_indicator, GUINT_TO_POINTER (state));
380     if (HILDON_IS_WINDOW (window)) {
381         HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (window);
382         if (priv->edit_toolbar) {
383             HildonEditToolbar *tb = HILDON_EDIT_TOOLBAR (priv->edit_toolbar);
384             hildon_edit_toolbar_set_progress_indicator (tb, state);
385         }
386     }
387 }
388
389 /**
390  * hildon_gtk_window_set_do_not_disturb:
391  * @window: a #GtkWindow
392  * @dndflag: %TRUE to set the "do-not-disturb" flag, %FALSE to clear it
393  *
394  * This function tells the window manager to set (or clear) the
395  * "do-not-disturb" flag on @window.
396  *
397  * Since: 2.2
398  **/
399 void
400 hildon_gtk_window_set_do_not_disturb            (GtkWindow *window,
401                                                  gboolean   dndflag)
402 {
403     hildon_gtk_window_set_flag (window, (HildonFlagFunc) do_set_do_not_disturb, GUINT_TO_POINTER (dndflag));
404 }
405
406 /**
407  * hildon_gtk_window_set_portrait_flags:
408  * @window: a #GtkWindow
409  * @portrait_flags: a combination of #HildonPortraitFlags
410  *
411  * Sets the portrait flags for @window.
412  *
413  * Since: 2.2
414  **/
415 void
416 hildon_gtk_window_set_portrait_flags            (GtkWindow           *window,
417                                                  HildonPortraitFlags  portrait_flags)
418 {
419     hildon_gtk_window_set_flag (window, (HildonFlagFunc) do_set_portrait_flags, GUINT_TO_POINTER (portrait_flags));
420 }
421
422 /**
423  * hildon_gtk_window_take_screenshot:
424  * @window: a #GtkWindow
425  * @take: %TRUE to take a screenshot, %FALSE to destroy the existing one.
426  *
427  * Tells the window manager to take a screenshot of @window, or to
428  * destroy the existing one. @window must be mapped.
429  **/
430 void
431 hildon_gtk_window_take_screenshot               (GtkWindow *window,
432                                                  gboolean   take)
433 {
434     XEvent xev = { 0 };
435
436     g_return_if_fail (GTK_IS_WINDOW (window));
437     g_return_if_fail (GTK_WIDGET_MAPPED (window));
438
439     xev.xclient.type = ClientMessage;
440     xev.xclient.serial = 0;
441     xev.xclient.send_event = True;
442     xev.xclient.display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (window)));
443     xev.xclient.window = XDefaultRootWindow (xev.xclient.display);
444     xev.xclient.message_type = XInternAtom (xev.xclient.display, "_HILDON_LOADING_SCREENSHOT", False);
445     xev.xclient.format = 32;
446     xev.xclient.data.l[0] = take ? 0 : 1;
447     xev.xclient.data.l[1] = GDK_WINDOW_XID (GTK_WIDGET (window)->window);
448
449     XSendEvent (xev.xclient.display,
450                 xev.xclient.window,
451                 False,
452                 SubstructureRedirectMask | SubstructureNotifyMask,
453                 &xev);
454
455     XFlush (xev.xclient.display);
456     XSync (xev.xclient.display, False);
457 }
458
459
460 /**
461  * hildon_gtk_hscale_new:
462  *
463  * Creates a new horizontal scale widget that lets the user select
464  * a value. The value is technically a double between 0.0 and 1.0.
465  * See gtk_adjustment_configure() for reconfiguring the adjustment.
466  *
467  * The scale is hildonized, which means that a click or tap immediately
468  * jumps to the desired position, see gtk_range_set_jump_to_position().
469  * Further more the value is not displayed, see gtk_scale_set_draw_value().
470  *
471  * Returns: a new hildonized #GtkHScale
472  *
473  * Since: 2.2
474  **/
475 GtkWidget*
476 hildon_gtk_hscale_new                           (void)
477 {
478   GtkWidget *scale = gtk_hscale_new_with_range (0.0, 1.0, 0.1);
479   g_object_set (scale,
480                 "draw-value", FALSE,
481 #ifdef MAEMO_GTK
482                 "jump-to-position", TRUE,
483 #endif
484                 NULL);
485
486   return scale;
487 }
488
489 /**
490  * hildon_gtk_vscale_new:
491  *
492  * Creates a new vertical 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 #GtkVScale
501  *
502  * Since: 2.2
503  **/
504 GtkWidget*
505 hildon_gtk_vscale_new                           (void)
506 {
507   GtkWidget *scale = gtk_vscale_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 }