1 /*-
2 * Copyright (c) 2003-2004 Benedikt Meurer <benny@xfce.org>
3 * Copyright (c) 2011 Nick Schermer <nick@xfce.org>
4 * 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 General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This program 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
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301 USA.
20 *
21 * Parts of this file where taken from gnome-session/logout.c, which
22 * was written by Owen Taylor <otaylor@redhat.com>.
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #ifdef HAVE_SYS_WAIT_H
30 #include <sys/wait.h>
31 #endif
32
33 #ifdef HAVE_STDLIB_H
34 #include <stdlib.h>
35 #endif
36 #ifdef HAVE_STRING_H
37 #include <string.h>
38 #endif
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42 #ifdef HAVE_MATH_H
43 #include <math.h>
44 #endif
45
46 #include <libxfce4util/libxfce4util.h>
47 #include <gtk/gtk.h>
48
49 #include <libxfsm/xfsm-util.h>
50
51 #include <xfce4-session/xfsm-logout-dialog.h>
52 #include <xfce4-session/xfsm-fadeout.h>
53 #include <xfce4-session/xfsm-global.h>
54 #include <xfce4-session/xfsm-legacy.h>
55 #include <xfce4-session/xfsm-error.h>
56
57 #ifdef GDK_WINDOWING_X11
58 #include <X11/Xlib.h>
59 #include <gdk/gdkx.h>
60 #endif
61
62
63
64 #define BORDER 6
65 #define SHOTSIZE 64
66
67
68
69 static void xfsm_logout_dialog_finalize (GObject *object);
70 static GtkWidget *xfsm_logout_dialog_button (const gchar *title,
71 const gchar *icon_name,
72 const gchar *icon_name_fallback,
73 const gchar *icon_name_fallback2,
74 XfsmShutdownType type,
75 XfsmLogoutDialog *dialog);
76
77
78
79 enum
80 {
81 MODE_LOGOUT_BUTTONS,
82 MODE_SHOW_ERROR,
83 N_MODES
84 };
85
86 struct _XfsmLogoutDialogClass
87 {
88 GtkDialogClass __parent__;
89 };
90
91 struct _XfsmLogoutDialog
92 {
93 GtkDialog __parent__;
94
95 /* set when a button is clicked */
96 XfsmShutdownType type_clicked;
97
98 /* save session checkbox */
99 GtkWidget *save_session;
100
101 /* mode widgets */
102 GtkWidget *box[N_MODES];
103
104 /* dialog buttons */
105 GtkWidget *button_cancel;
106
107 /* error label */
108 GtkWidget *error_label;
109
110 /* pm instance */
111 XfsmShutdown *shutdown;
112 };
113
114
115
G_DEFINE_TYPE(XfsmLogoutDialog,xfsm_logout_dialog,GTK_TYPE_DIALOG)116 G_DEFINE_TYPE (XfsmLogoutDialog, xfsm_logout_dialog, GTK_TYPE_DIALOG)
117
118
119
120 static void
121 xfsm_logout_dialog_class_init (XfsmLogoutDialogClass *klass)
122 {
123 GObjectClass *gobject_class;
124
125 gobject_class = G_OBJECT_CLASS (klass);
126 gobject_class->finalize = xfsm_logout_dialog_finalize;
127 }
128
129
130
131 static void
xfsm_logout_dialog_init(XfsmLogoutDialog * dialog)132 xfsm_logout_dialog_init (XfsmLogoutDialog *dialog)
133 {
134 const gchar *username;
135 GtkWidget *label;
136 gchar *label_str;
137 PangoAttrList *attrs;
138 GtkWidget *vbox;
139 GtkWidget *button_vbox;
140 GtkWidget *main_vbox;
141 GtkWidget *hbox;
142 GtkWidget *button;
143 gboolean can_shutdown;
144 gboolean save_session = FALSE;
145 gboolean can_restart;
146 gboolean can_suspend = FALSE;
147 gboolean can_hibernate = FALSE;
148 gboolean can_hybrid_sleep = FALSE;
149 gboolean can_switch_user = FALSE;
150 gboolean auth_suspend = FALSE;
151 gboolean auth_hibernate = FALSE;
152 gboolean auth_hybrid_sleep = FALSE;
153 GError *error = NULL;
154 XfconfChannel *channel;
155 GtkWidget *image;
156 GtkWidget *separator;
157 gboolean upower_not_found = FALSE;
158 GtkCssProvider *provider;
159
160 dialog->type_clicked = XFSM_SHUTDOWN_LOGOUT;
161 dialog->shutdown = xfsm_shutdown_get ();
162
163 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
164 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
165 gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
166 /* Use Adwaita's keycap style to get a meaningful look out of the box */
167 gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (dialog)), "keycap");
168 gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (dialog)), "xfsm-logout-dialog");
169 provider = gtk_css_provider_new ();
170 gtk_css_provider_load_from_data (provider, ".xfsm-logout-dialog { font-size: initial; }", -1, NULL);
171 gtk_style_context_add_provider (gtk_widget_get_style_context (GTK_WIDGET (dialog)),
172 GTK_STYLE_PROVIDER (provider),
173 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
174 g_object_unref (provider);
175
176 /* load xfconf settings */
177 channel = xfsm_open_config ();
178 if (xfsm_shutdown_can_save_session (dialog->shutdown))
179 save_session = xfconf_channel_get_bool (channel, "/general/SaveOnExit", TRUE);
180
181 main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, BORDER);
182 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), main_vbox, TRUE, TRUE, 0);
183 gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
184 gtk_widget_show (main_vbox);
185
186 /* label showing the users' name */
187 username = g_get_real_name ();
188 if (username == NULL
189 || *username == '\0'
190 || strcmp ("Unknown", username) == 0)
191 username = g_get_user_name ();
192
193 label_str = g_strdup_printf (_("Log out %s"), username);
194 label = gtk_label_new (label_str);
195 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
196 gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (label)), "xfsm-logout-label");
197 gtk_box_pack_start (GTK_BOX (main_vbox), label, FALSE, TRUE, 0);
198 gtk_widget_show (label);
199 g_free (label_str);
200
201 attrs = pango_attr_list_new ();
202 pango_attr_list_insert (attrs, pango_attr_scale_new (PANGO_SCALE_LARGE));
203 pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
204 gtk_label_set_attributes (GTK_LABEL (label), attrs);
205 pango_attr_list_unref (attrs);
206
207 separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
208 gtk_box_pack_start (GTK_BOX (main_vbox), separator, FALSE, TRUE, 0);
209 gtk_widget_show (separator);
210
211 /**
212 * Start mode MODE_LOGOUT_BUTTONS
213 **/
214 dialog->box[MODE_LOGOUT_BUTTONS] = vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, BORDER);
215 gtk_box_pack_start (GTK_BOX (main_vbox), vbox, TRUE, TRUE, 0);
216
217 /**
218 * Cancel
219 **/
220 dialog->button_cancel = gtk_dialog_add_button (GTK_DIALOG (dialog),
221 _("_Cancel"),
222 GTK_RESPONSE_CANCEL);
223
224 button_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, BORDER);
225 gtk_box_pack_start (GTK_BOX (vbox), button_vbox, FALSE, TRUE, 0);
226 gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (button_vbox)), "xfsm-logout-buttons");
227 gtk_widget_show (button_vbox);
228
229 /* row for logout/shutdown and reboot */
230 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, BORDER);
231 gtk_box_pack_start (GTK_BOX (button_vbox), hbox, FALSE, TRUE, 0);
232 gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
233 gtk_widget_show (hbox);
234
235 /**
236 * Logout
237 **/
238 button = xfsm_logout_dialog_button (_("_Log Out"), "xfsm-logout",
239 "system-log-out", NULL,
240 XFSM_SHUTDOWN_LOGOUT, dialog);
241
242 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
243 gtk_widget_show (button);
244 gtk_widget_grab_focus (button);
245
246 /**
247 * Reboot
248 **/
249 if (!xfsm_shutdown_can_restart (dialog->shutdown, &can_restart, &error))
250 {
251 g_printerr ("%s: Querying CanRestart failed, %s\n\n",
252 PACKAGE_NAME, ERROR_MSG (error));
253 g_clear_error (&error);
254
255 can_restart = FALSE;
256 }
257
258 button = xfsm_logout_dialog_button (_("_Restart"), "xfsm-reboot",
259 "system-reboot", NULL,
260 XFSM_SHUTDOWN_RESTART, dialog);
261
262 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
263 gtk_widget_set_sensitive (button, can_restart);
264 gtk_widget_show (button);
265
266 /**
267 * Shutdown
268 **/
269 if (!xfsm_shutdown_can_shutdown (dialog->shutdown, &can_shutdown, &error))
270 {
271 g_printerr ("%s: Querying CanShutdown failed. %s\n\n",
272 PACKAGE_NAME, ERROR_MSG (error));
273 g_clear_error (&error);
274
275 can_shutdown = FALSE;
276 }
277
278 button = xfsm_logout_dialog_button (_("Shut _Down"), "xfsm-shutdown",
279 "system-shutdown", NULL,
280 XFSM_SHUTDOWN_SHUTDOWN, dialog);
281
282 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
283 gtk_widget_set_sensitive (button, can_shutdown);
284 gtk_widget_show (button);
285
286 /* new row for suspend/hibernate/hybrid sleep */
287 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, BORDER);
288 gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
289 gtk_box_pack_start (GTK_BOX (button_vbox), hbox, FALSE, TRUE, 0);
290
291 /**
292 * Suspend
293 *
294 * Hide the button if UPower is not installed or system cannot suspend
295 **/
296 if (xfconf_channel_get_bool (channel, "/shutdown/ShowSuspend", TRUE))
297 {
298 if (xfsm_shutdown_can_suspend (dialog->shutdown, &can_suspend, &auth_suspend, &error))
299 {
300 if (can_suspend)
301 {
302 button = xfsm_logout_dialog_button (_("Sus_pend"), "xfsm-suspend",
303 "system-suspend", NULL,
304 XFSM_SHUTDOWN_SUSPEND, dialog);
305
306 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
307 gtk_widget_set_sensitive (button, auth_suspend);
308 gtk_widget_show (button);
309
310 gtk_widget_show (hbox);
311 }
312 }
313 else
314 {
315 g_printerr ("%s: Querying suspend failed: %s\n\n",
316 PACKAGE_NAME, ERROR_MSG (error));
317 g_clear_error (&error);
318
319 /* don't try hibernate again */
320 upower_not_found = TRUE;
321 }
322 }
323
324 /**
325 * Hibernate
326 *
327 * Hide the button if UPower is not installed or system cannot suspend
328 **/
329 if (!upower_not_found
330 && xfconf_channel_get_bool (channel, "/shutdown/ShowHibernate", TRUE))
331 {
332 if (xfsm_shutdown_can_hibernate (dialog->shutdown, &can_hibernate, &auth_hibernate, &error))
333 {
334 if (can_hibernate)
335 {
336 button = xfsm_logout_dialog_button (_("_Hibernate"), "xfsm-hibernate",
337 "system-hibernate", NULL,
338 XFSM_SHUTDOWN_HIBERNATE, dialog);
339
340 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
341 gtk_widget_set_sensitive (button, auth_hibernate);
342 gtk_widget_show (button);
343
344 gtk_widget_show (hbox);
345 }
346 }
347 else
348 {
349 g_printerr ("%s: Querying hibernate failed: %s\n\n",
350 PACKAGE_NAME, ERROR_MSG (error));
351 g_clear_error (&error);
352 }
353 }
354
355 /**
356 * Hybrid Sleep
357 *
358 * Hide the button if UPower is not installed or system cannot suspend
359 **/
360 if (!upower_not_found
361 && xfconf_channel_get_bool (channel, "/shutdown/ShowHybridSleep", TRUE))
362 {
363 if (xfsm_shutdown_can_hybrid_sleep (dialog->shutdown, &can_hybrid_sleep, &auth_hybrid_sleep, &error))
364 {
365 if (can_hybrid_sleep)
366 {
367 button = xfsm_logout_dialog_button (_("H_ybrid Sleep"), "xfsm-hibernate",
368 "system-hibernate", "system-suspend-hibernate",
369 XFSM_SHUTDOWN_HYBRID_SLEEP, dialog);
370
371 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
372 gtk_widget_set_sensitive (button, auth_hybrid_sleep);
373 gtk_widget_show (button);
374
375 gtk_widget_show (hbox);
376 }
377 }
378 else
379 {
380 g_printerr ("%s: Querying hybrid-sleep failed: %s\n\n",
381 PACKAGE_NAME, ERROR_MSG (error));
382 g_clear_error (&error);
383 }
384 }
385
386 /**
387 * Switch User
388 *
389 * Hide the button if system cannot switch user, requires the display
390 * manager to provide the org.freedesktop.DisplayManager dbus API
391 **/
392 if (xfconf_channel_get_bool (channel, "/shutdown/ShowSwitchUser", TRUE))
393 {
394 if (xfsm_shutdown_can_switch_user (dialog->shutdown, &can_switch_user, &error))
395 {
396 if (can_switch_user)
397 {
398 button = xfsm_logout_dialog_button (_("Switch _User"), "xfsm-switch-user",
399 "system-users", "system-users-symbolic",
400 XFSM_SHUTDOWN_SWITCH_USER, dialog);
401
402 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
403 gtk_widget_set_sensitive (button, can_switch_user);
404 gtk_widget_show (button);
405
406 gtk_widget_show (hbox);
407 }
408 }
409 else
410 {
411 g_printerr ("%s: Querying switch user failed: %s\n\n",
412 PACKAGE_NAME, ERROR_MSG (error));
413 g_clear_error (&error);
414 }
415 }
416
417 /**
418 * Save session
419 **/
420 if (xfsm_shutdown_can_save_session (dialog->shutdown)
421 && !xfconf_channel_get_bool (channel, "/general/AutoSave", FALSE))
422 {
423 dialog->save_session = gtk_check_button_new_with_mnemonic (_("_Save session for future logins"));
424 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->save_session), save_session);
425 gtk_box_pack_start (GTK_BOX (vbox), dialog->save_session, FALSE, TRUE, BORDER);
426 gtk_widget_show (dialog->save_session);
427 }
428
429 attrs = pango_attr_list_new ();
430 pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
431
432
433 /**
434 * Start mode MODE_SHOW_ERROR
435 **/
436 dialog->box[MODE_SHOW_ERROR] = vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, BORDER);
437 gtk_box_pack_start (GTK_BOX (main_vbox), vbox, TRUE, TRUE, 0);
438
439 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, BORDER * 2);
440 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
441 gtk_widget_show (hbox);
442
443 image = gtk_image_new_from_icon_name ("dialog-error", GTK_ICON_SIZE_DIALOG);
444 gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
445 gtk_widget_show (image);
446
447 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, BORDER);
448 gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
449 gtk_widget_show (vbox);
450
451 label = gtk_label_new (_("An error occurred"));
452 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
453 gtk_label_set_xalign (GTK_LABEL (label), 0.00);
454 gtk_label_set_yalign (GTK_LABEL (label), 0.50);
455 gtk_label_set_attributes (GTK_LABEL (label), attrs);
456 gtk_widget_show (label);
457
458 pango_attr_list_unref (attrs);
459 }
460
461
462
463 static void
xfsm_logout_dialog_finalize(GObject * object)464 xfsm_logout_dialog_finalize (GObject *object)
465 {
466 XfsmLogoutDialog *dialog = XFSM_LOGOUT_DIALOG (object);
467
468 g_object_unref (G_OBJECT (dialog->shutdown));
469
470 (*G_OBJECT_CLASS (xfsm_logout_dialog_parent_class)->finalize) (object);
471 }
472
473
474
475 static void
xfsm_logout_dialog_set_mode(XfsmLogoutDialog * dialog,gint mode)476 xfsm_logout_dialog_set_mode (XfsmLogoutDialog *dialog,
477 gint mode)
478 {
479 gint i;
480
481 for (i = 0; i < N_MODES; i++)
482 gtk_widget_set_visible (dialog->box[i], i == mode);
483
484 gtk_widget_set_visible (dialog->button_cancel, mode != MODE_SHOW_ERROR);
485 }
486
487
488
489 static void
xfsm_logout_dialog_button_clicked(GtkWidget * button,XfsmLogoutDialog * dialog)490 xfsm_logout_dialog_button_clicked (GtkWidget *button,
491 XfsmLogoutDialog *dialog)
492 {
493 gint *val;
494
495 val = g_object_get_data (G_OBJECT (button), "shutdown-type");
496 g_assert (val != NULL);
497 dialog->type_clicked = *val;
498
499 gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
500 }
501
502
503
504 static GtkWidget *
xfsm_logout_dialog_button(const gchar * title,const gchar * icon_name,const gchar * icon_name_fallback,const gchar * icon_name_fallback2,XfsmShutdownType type,XfsmLogoutDialog * dialog)505 xfsm_logout_dialog_button (const gchar *title,
506 const gchar *icon_name,
507 const gchar *icon_name_fallback,
508 const gchar *icon_name_fallback2,
509 XfsmShutdownType type,
510 XfsmLogoutDialog *dialog)
511 {
512 GtkWidget *button;
513 GtkWidget *vbox;
514 GtkWidget *image;
515 GtkWidget *label;
516 gint *val;
517 GtkIconTheme *icon_theme;
518
519 g_return_val_if_fail (XFSM_IS_LOGOUT_DIALOG (dialog), NULL);
520
521 val = g_new0 (gint, 1);
522 *val = type;
523
524 button = gtk_button_new ();
525 g_object_set_data_full (G_OBJECT (button), "shutdown-type", val, g_free);
526 g_signal_connect (G_OBJECT (button), "clicked",
527 G_CALLBACK (xfsm_logout_dialog_button_clicked), dialog);
528
529 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, BORDER);
530 gtk_container_set_border_width (GTK_CONTAINER (vbox), BORDER);
531 gtk_container_add (GTK_CONTAINER (button), vbox);
532 gtk_widget_show (vbox);
533
534 icon_theme = gtk_icon_theme_get_default ();
535
536 image = gtk_image_new ();
537 if (gtk_icon_theme_has_icon (icon_theme, icon_name))
538 gtk_image_set_from_icon_name (GTK_IMAGE (image), icon_name, GTK_ICON_SIZE_DIALOG);
539 else if (gtk_icon_theme_has_icon (icon_theme, icon_name_fallback))
540 gtk_image_set_from_icon_name (GTK_IMAGE (image), icon_name_fallback, GTK_ICON_SIZE_DIALOG);
541 else if (gtk_icon_theme_has_icon (icon_theme, icon_name_fallback2))
542 gtk_image_set_from_icon_name (GTK_IMAGE (image), icon_name_fallback2, GTK_ICON_SIZE_DIALOG);
543
544 gtk_image_set_pixel_size (GTK_IMAGE (image), 48);
545 gtk_box_pack_start (GTK_BOX (vbox), image, FALSE, FALSE, 0);
546 gtk_widget_show (image);
547
548 label = gtk_label_new_with_mnemonic (title);
549 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
550 gtk_widget_show (label);
551
552 return button;
553 }
554
555
556
557 static GdkPixbuf *
xfsm_logout_dialog_screenshot_new(GdkScreen * screen)558 xfsm_logout_dialog_screenshot_new (GdkScreen *screen)
559 {
560 GdkRectangle rect, screen_rect;
561 GdkWindow *window;
562 GdkPixbuf *screenshot;
563 gint x, y;
564
565 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
566
567 screen_rect.x = 0;
568 screen_rect.y = 0;
569 screen_rect.width = gdk_screen_get_width (screen);
570 screen_rect.height = gdk_screen_get_height (screen);
571
572 window = gdk_screen_get_root_window (screen);
573
574 rect.width = gdk_window_get_width (window);
575 rect.height = gdk_window_get_height (window);
576
577 gdk_window_get_origin (window, &x, &y);
578
579 rect.x = x;
580 rect.y = y;
581
582 if (!gdk_rectangle_intersect (&rect, &screen_rect, &rect))
583 return NULL;
584
585 screenshot = gdk_pixbuf_get_from_window (window, 0, 0, rect.width, rect.height);
586
587 gdk_display_beep (gdk_screen_get_display (screen));
588
589 return screenshot;
590 }
591
592
593
594 static GdkPixbuf *
exo_gdk_pixbuf_scale_ratio(GdkPixbuf * source,gint dest_size)595 exo_gdk_pixbuf_scale_ratio (GdkPixbuf *source,
596 gint dest_size)
597 {
598 gdouble wratio;
599 gdouble hratio;
600 gint source_width;
601 gint source_height;
602 gint dest_width;
603 gint dest_height;
604
605 g_return_val_if_fail (GDK_IS_PIXBUF (source), NULL);
606 g_return_val_if_fail (dest_size > 0, NULL);
607
608 source_width = gdk_pixbuf_get_width (source);
609 source_height = gdk_pixbuf_get_height (source);
610
611 wratio = (gdouble) source_width / (gdouble) dest_size;
612 hratio = (gdouble) source_height / (gdouble) dest_size;
613
614 if (hratio > wratio)
615 {
616 dest_width = rint (source_width / hratio);
617 dest_height = dest_size;
618 }
619 else
620 {
621 dest_width = dest_size;
622 dest_height = rint (source_height / wratio);
623 }
624
625 return gdk_pixbuf_scale_simple (source, MAX (dest_width, 1),
626 MAX (dest_height, 1), GDK_INTERP_BILINEAR);
627 }
628
629
630
631 static void
xfsm_logout_dialog_screenshot_save(GdkPixbuf * screenshot,GdkScreen * screen,const gchar * session_name)632 xfsm_logout_dialog_screenshot_save (GdkPixbuf *screenshot,
633 GdkScreen *screen,
634 const gchar *session_name)
635 {
636 GdkPixbuf *scaled;
637 gchar *path;
638 gchar *display_name;
639 GdkDisplay *dpy;
640 GError *error = NULL;
641 gchar *filename;
642
643 g_return_if_fail (GDK_IS_PIXBUF (screenshot));
644 g_return_if_fail (GDK_IS_SCREEN (screen));
645
646 scaled = exo_gdk_pixbuf_scale_ratio (screenshot, SHOTSIZE);
647 if (G_LIKELY (scaled != NULL))
648 {
649 dpy = gdk_screen_get_display (screen);
650 display_name = xfsm_gdk_display_get_fullname (dpy);
651 path = g_strconcat ("sessions/thumbs-", display_name, "/", session_name, ".png", NULL);
652 filename = xfce_resource_save_location (XFCE_RESOURCE_CACHE, path, TRUE);
653 g_free (display_name);
654 g_free (path);
655
656 if (!filename)
657 {
658 g_warning ("Unable to save screenshot, "
659 "error calling xfce_resource_save_location with %s, "
660 "check your permissions", path);
661 return;
662 }
663
664 if (!gdk_pixbuf_save (scaled, filename, "png", &error, NULL))
665 {
666 g_warning ("Failed to save session screenshot: %s", error->message);
667 g_error_free (error);
668 }
669
670 g_free (filename);
671 g_object_unref (G_OBJECT (scaled));
672 }
673 }
674
675
676
677 static void
xfsm_logout_dialog_grab_callback(GdkSeat * seat,GdkWindow * window,gpointer user_data)678 xfsm_logout_dialog_grab_callback (GdkSeat *seat,
679 GdkWindow *window,
680 gpointer user_data)
681 {
682 /* ensure window is mapped to avoid unsuccessful grabs */
683 if (!gdk_window_is_visible (window))
684 gdk_window_show (window);
685 }
686
687
688
689 static gint
xfsm_logout_dialog_run(GtkDialog * dialog,gboolean grab_input)690 xfsm_logout_dialog_run (GtkDialog *dialog,
691 gboolean grab_input)
692 {
693 GdkWindow *window;
694 gint ret;
695 GdkDevice *device;
696 GdkSeat *seat;
697
698 if (grab_input)
699 {
700 gtk_widget_show_now (GTK_WIDGET (dialog));
701
702 window = gtk_widget_get_window (GTK_WIDGET (dialog));
703
704 device = gtk_get_current_event_device ();
705 seat = device != NULL
706 ? gdk_device_get_seat (device)
707 : gdk_display_get_default_seat (gtk_widget_get_display (GTK_WIDGET (dialog)));
708
709 if (gdk_seat_grab (seat, window,
710 GDK_SEAT_CAPABILITY_KEYBOARD,
711 FALSE, NULL, NULL,
712 xfsm_logout_dialog_grab_callback,
713 NULL) != GDK_GRAB_SUCCESS)
714 {
715 g_critical ("Failed to grab the keyboard for logout window");
716 }
717
718 #ifdef GDK_WINDOWING_X11
719 /* force input to the dialog */
720 gdk_error_trap_push ();
721 XSetInputFocus (gdk_x11_get_default_xdisplay (),
722 GDK_WINDOW_XID (window),
723 RevertToParent, CurrentTime);
724 gdk_error_trap_pop_ignored ();
725 #endif
726 }
727
728 ret = gtk_dialog_run (dialog);
729
730 if (grab_input)
731 gdk_seat_ungrab (seat);
732
733 return ret;
734 }
735
736
737
738 gboolean
xfsm_logout_dialog(const gchar * session_name,XfsmShutdownType * return_type,gboolean * return_save_session,gboolean accessibility)739 xfsm_logout_dialog (const gchar *session_name,
740 XfsmShutdownType *return_type,
741 gboolean *return_save_session,
742 gboolean accessibility)
743 {
744 gint result;
745 GtkWidget *hidden;
746 GtkWidget *dialog;
747 GdkScreen *screen;
748 gint monitor;
749 GdkPixbuf *screenshot = NULL;
750 XfsmFadeout *fadeout = NULL;
751 XfsmLogoutDialog *xfsm_dialog;
752 XfconfChannel *channel = xfsm_open_config ();
753 gboolean autosave;
754 XfsmShutdown *shutdown;
755 GdkDevice *device;
756 GdkSeat *seat;
757 gint grab_count = 0;
758
759 g_return_val_if_fail (return_type != NULL, FALSE);
760 g_return_val_if_fail (return_save_session != NULL, FALSE);
761
762 shutdown = xfsm_shutdown_get ();
763 if (xfsm_shutdown_can_save_session (shutdown))
764 autosave = xfconf_channel_get_bool (channel, "/general/AutoSave", FALSE);
765 else
766 autosave = FALSE;
767 g_object_unref (shutdown);
768
769 /* check if we need to bother the user */
770 if (!xfconf_channel_get_bool (channel, "/general/PromptOnLogout", TRUE))
771 {
772 *return_type = XFSM_SHUTDOWN_LOGOUT;
773 *return_save_session = autosave;
774
775 return TRUE;
776 }
777
778 /* decide on which screen we should show the dialog */
779 screen = xfce_gdk_screen_get_active (&monitor);
780 if (G_UNLIKELY (screen == NULL))
781 {
782 screen = gdk_screen_get_default ();
783 monitor = 0;
784 }
785
786 hidden = gtk_invisible_new_for_screen (screen);
787 gtk_widget_show (hidden);
788
789 /* check if accessibility is enabled */
790 if (G_LIKELY (!accessibility))
791 {
792 /* wait until we can grab the keyboard, we need this for
793 * the dialog when running it */
794 for (;;)
795 {
796 device = gtk_get_current_event_device ();
797 seat = device != NULL
798 ? gdk_device_get_seat (device)
799 : gdk_display_get_default_seat (gtk_widget_get_display (hidden));
800
801 if (gdk_seat_grab (seat, gtk_widget_get_window (hidden),
802 GDK_SEAT_CAPABILITY_KEYBOARD,
803 FALSE, NULL, NULL,
804 xfsm_logout_dialog_grab_callback,
805 NULL) == GDK_GRAB_SUCCESS)
806 {
807 gdk_seat_ungrab (seat);
808 break;
809 }
810
811 if (grab_count++ >= 40)
812 {
813 g_critical ("Failed to grab the keyboard for logout window");
814 break;
815 }
816
817 g_usleep (G_USEC_PER_SEC / 20);
818 }
819
820 /* make a screenshot */
821 if (xfconf_channel_get_bool (channel, "/general/ShowScreenshots", TRUE))
822 screenshot = xfsm_logout_dialog_screenshot_new (screen);
823
824 /* display fadeout */
825 fadeout = xfsm_fadeout_new (gdk_screen_get_display (screen));
826
827 dialog = g_object_new (XFSM_TYPE_LOGOUT_DIALOG,
828 "type", GTK_WINDOW_POPUP,
829 "screen", screen, NULL);
830
831 gtk_widget_realize (dialog);
832 gdk_window_set_override_redirect (gtk_widget_get_window (dialog), TRUE);
833 gdk_window_raise (gtk_widget_get_window (dialog));
834 }
835 else
836 {
837 dialog = g_object_new (XFSM_TYPE_LOGOUT_DIALOG,
838 "decorated", !accessibility,
839 "screen", screen, NULL);
840
841 gtk_window_set_keep_above (GTK_WINDOW (dialog), TRUE);
842 atk_object_set_role (gtk_widget_get_accessible (dialog), ATK_ROLE_ALERT);
843 }
844
845 gtk_widget_destroy (hidden);
846
847 xfsm_dialog = XFSM_LOGOUT_DIALOG (dialog);
848
849 /* set mode */
850 xfsm_logout_dialog_set_mode (xfsm_dialog, MODE_LOGOUT_BUTTONS);
851
852 result = xfsm_logout_dialog_run (GTK_DIALOG (dialog), !accessibility);
853
854 gtk_widget_hide (dialog);
855
856 if (result == GTK_RESPONSE_OK)
857 {
858 /* store autosave state */
859 if (autosave)
860 *return_save_session = TRUE;
861 else if (xfsm_dialog->save_session != NULL)
862 *return_save_session = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (xfsm_dialog->save_session));
863 else
864 *return_save_session = FALSE;
865
866 /* return the clicked action */
867 *return_type = xfsm_dialog->type_clicked;
868 }
869
870 if (fadeout != NULL)
871 xfsm_fadeout_destroy (fadeout);
872
873 gtk_widget_destroy (dialog);
874
875 /* store channel settings if everything worked fine */
876 if (result == GTK_RESPONSE_OK)
877 {
878 xfconf_channel_set_string (channel, "/general/SessionName", session_name);
879 xfconf_channel_set_bool (channel, "/general/SaveOnExit", *return_save_session);
880 }
881
882 /* save the screenshot */
883 if (screenshot != NULL)
884 {
885 if (result == GTK_RESPONSE_OK)
886 xfsm_logout_dialog_screenshot_save (screenshot, screen, session_name);
887 g_object_unref (G_OBJECT (screenshot));
888 }
889
890 return (result == GTK_RESPONSE_OK);
891 }
892