1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3
* Copyright (C) 2004-2008 William Jon McCann <mccann@jhu.edu>
4
* Copyright (C) 2008-2011 Red Hat, Inc.
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 of the License, or
9
* (at your option) any later version.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30
#include <sys/utsname.h>
32
#include <glib/gprintf.h>
33
#include <glib/gstdio.h>
34
#include <glib/gi18n.h>
35
#include <gdk/gdkkeysyms.h>
39
#ifdef WITH_KBD_LAYOUT_INDICATOR
40
#include <libgnomekbd/gkbd-indicator.h>
43
#include "gs-lock-plug.h"
47
#define GDM_FLEXISERVER_COMMAND "gdmflexiserver"
48
#define GDM_FLEXISERVER_ARGS "--startnew Standard"
60
#define FACE_ICON_SIZE 48
61
#define DIALOG_TIMEOUT_MSEC 60000
63
static void gs_lock_plug_finalize (GObject *object);
65
#define GS_LOCK_PLUG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_LOCK_PLUG, GSLockPlugPrivate))
67
struct GSLockPlugPrivate
71
GtkWidget *auth_action_area;
74
GtkWidget *auth_face_image;
75
GtkWidget *auth_realname_label;
76
GtkWidget *auth_prompt_label;
77
GtkWidget *auth_prompt_entry;
78
GtkWidget *auth_prompt_box;
79
GtkWidget *auth_capslock_label;
80
GtkWidget *auth_message_label;
81
GtkWidget *status_message_label;
83
GtkWidget *auth_unlock_button;
84
GtkWidget *auth_switch_button;
85
GtkWidget *auth_logout_button;
87
GtkWidget *auth_prompt_kbd_layout_indicator;
90
gboolean switch_enabled;
91
gboolean logout_enabled;
97
guint cancel_timeout_id;
98
guint auth_check_idle_id;
99
guint response_idle_id;
104
typedef struct _ResponseData ResponseData;
126
static guint lock_plug_signals [LAST_SIGNAL];
128
G_DEFINE_TYPE (GSLockPlug, gs_lock_plug, GTK_TYPE_PLUG)
131
gs_lock_plug_style_set (GtkWidget *widget,
132
GtkStyle *previous_style)
136
if (GTK_WIDGET_CLASS (gs_lock_plug_parent_class)->style_set) {
137
GTK_WIDGET_CLASS (gs_lock_plug_parent_class)->style_set (widget, previous_style);
140
plug = GS_LOCK_PLUG (widget);
142
gtk_container_set_border_width (GTK_CONTAINER (plug->priv->vbox), 24);
143
gtk_box_set_spacing (GTK_BOX (plug->priv->vbox), 12);
145
gtk_container_set_border_width (GTK_CONTAINER (plug->priv->auth_action_area), 0);
146
gtk_box_set_spacing (GTK_BOX (plug->priv->auth_action_area), 5);
150
do_user_switch (GSLockPlug *plug)
153
GAppLaunchContext *context;
157
command = g_strdup_printf ("%s %s",
158
GDM_FLEXISERVER_COMMAND,
159
GDM_FLEXISERVER_ARGS);
162
context = (GAppLaunchContext*)gdk_app_launch_context_new ();
163
app = g_app_info_create_from_commandline (command, "gdmflexiserver", 0, &error);
165
g_app_info_launch (app, NULL, context, &error);
168
g_object_unref (context);
169
g_object_unref (app);
172
gs_debug ("Unable to start GDM greeter: %s", error->message);
173
g_error_free (error);
178
set_status_text (GSLockPlug *plug,
181
if (plug->priv->auth_message_label != NULL) {
182
gtk_label_set_text (GTK_LABEL (plug->priv->auth_message_label), text);
187
gs_lock_plug_set_sensitive (GSLockPlug *plug,
190
g_return_if_fail (GS_IS_LOCK_PLUG (plug));
192
gtk_widget_set_sensitive (plug->priv->auth_prompt_entry, sensitive);
193
gtk_widget_set_sensitive (plug->priv->auth_action_area, sensitive);
197
remove_cancel_timeout (GSLockPlug *plug)
199
if (plug->priv->cancel_timeout_id > 0) {
200
g_source_remove (plug->priv->cancel_timeout_id);
201
plug->priv->cancel_timeout_id = 0;
206
remove_response_idle (GSLockPlug *plug)
208
if (plug->priv->response_idle_id > 0) {
209
g_source_remove (plug->priv->response_idle_id);
210
plug->priv->response_idle_id = 0;
215
gs_lock_plug_response (GSLockPlug *plug,
220
new_response = response_id;
222
g_return_if_fail (GS_IS_LOCK_PLUG (plug));
224
/* Act only on response IDs we recognize */
225
if (!(response_id == GS_LOCK_PLUG_RESPONSE_OK
226
|| response_id == GS_LOCK_PLUG_RESPONSE_CANCEL)) {
230
remove_cancel_timeout (plug);
231
remove_response_idle (plug);
233
if (response_id == GS_LOCK_PLUG_RESPONSE_CANCEL) {
234
gtk_entry_set_text (GTK_ENTRY (plug->priv->auth_prompt_entry), "");
238
lock_plug_signals [RESPONSE],
244
response_cancel_idle_cb (GSLockPlug *plug)
246
plug->priv->response_idle_id = 0;
248
gs_lock_plug_response (plug, GS_LOCK_PLUG_RESPONSE_CANCEL);
254
dialog_timed_out (GSLockPlug *plug)
256
gs_lock_plug_set_sensitive (plug, FALSE);
257
set_status_text (plug, _("Time has expired."));
259
if (plug->priv->response_idle_id != 0) {
260
g_warning ("Response idle ID already set but shouldn't be");
263
remove_response_idle (plug);
265
plug->priv->response_idle_id = g_timeout_add (2000,
266
(GSourceFunc)response_cancel_idle_cb,
273
kbd_lock_mode_update (GSLockPlug *plug,
276
if (plug->priv->kbd_lock_mode == mode) {
280
plug->priv->kbd_lock_mode = mode;
282
if (plug->priv->auth_capslock_label == NULL) {
286
if ((mode & LOCK_CAPS) != 0 && (mode & LOCK_NUM) != 0) {
287
gtk_label_set_text (GTK_LABEL (plug->priv->auth_capslock_label),
288
_("You have the Caps & Num Lock keys on."));
289
} else if ((mode & LOCK_CAPS) != 0) {
290
gtk_label_set_text (GTK_LABEL (plug->priv->auth_capslock_label),
291
_("You have the Caps Lock key on."));
292
} else if ((mode & LOCK_NUM) != 0) {
293
gtk_label_set_text (GTK_LABEL (plug->priv->auth_capslock_label),
294
_("You have the Num Lock key on."));
296
gtk_label_set_text (GTK_LABEL (plug->priv->auth_capslock_label),
302
get_kbd_lock_mode (void)
309
keymap = gdk_keymap_get_default ();
310
if (keymap != NULL) {
313
res = gdk_keymap_get_caps_lock_state (keymap);
317
#if GTK_CHECK_VERSION(2,90,6)
318
res = gdk_keymap_get_num_lock_state (keymap);
329
restart_cancel_timeout (GSLockPlug *plug)
331
remove_cancel_timeout (plug);
333
plug->priv->cancel_timeout_id = g_timeout_add (plug->priv->timeout,
334
(GSourceFunc)dialog_timed_out,
339
gs_lock_plug_get_text (GSLockPlug *plug,
342
const char *typed_text;
346
typed_text = gtk_entry_get_text (GTK_ENTRY (plug->priv->auth_prompt_entry));
347
local_text = g_locale_from_utf8 (typed_text, strlen (typed_text), NULL, NULL, NULL);
349
null_text = g_strnfill (strlen (typed_text) + 1, '\b');
350
gtk_entry_set_text (GTK_ENTRY (plug->priv->auth_prompt_entry), null_text);
351
gtk_entry_set_text (GTK_ENTRY (plug->priv->auth_prompt_entry), "");
368
shutdown_loop (RunInfo *ri)
370
if (g_main_loop_is_running (ri->loop))
371
g_main_loop_quit (ri->loop);
375
run_unmap_handler (GSLockPlug *plug,
384
run_response_handler (GSLockPlug *plug,
392
ri->response_id = response_id;
398
run_delete_handler (GSLockPlug *plug,
406
return TRUE; /* Do not destroy */
410
run_destroy_handler (GSLockPlug *plug,
415
/* shutdown_loop will be called by run_unmap_handler */
416
ri->destroyed = TRUE;
420
run_keymap_handler (GdkKeymap *keymap,
423
kbd_lock_mode_update (plug, get_kbd_lock_mode ());
426
/* adapted from GTK+ gtkdialog.c */
428
gs_lock_plug_run (GSLockPlug *plug)
430
RunInfo ri = { NULL, GTK_RESPONSE_NONE, NULL, FALSE };
432
gulong response_handler;
433
gulong unmap_handler;
434
gulong destroy_handler;
435
gulong delete_handler;
436
gulong keymap_handler;
439
g_return_val_if_fail (GS_IS_LOCK_PLUG (plug), -1);
443
was_modal = gtk_window_get_modal (GTK_WINDOW (plug));
445
gtk_window_set_modal (GTK_WINDOW (plug), TRUE);
448
if (!gtk_widget_get_visible (GTK_WIDGET (plug))) {
449
gtk_widget_show (GTK_WIDGET (plug));
452
keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (plug)));
455
g_signal_connect (keymap,
457
G_CALLBACK (run_keymap_handler),
461
g_signal_connect (plug,
463
G_CALLBACK (run_response_handler),
467
g_signal_connect (plug,
469
G_CALLBACK (run_unmap_handler),
473
g_signal_connect (plug,
475
G_CALLBACK (run_delete_handler),
479
g_signal_connect (plug,
481
G_CALLBACK (run_destroy_handler),
484
ri.loop = g_main_loop_new (NULL, FALSE);
486
GDK_THREADS_LEAVE ();
487
g_main_loop_run (ri.loop);
488
GDK_THREADS_ENTER ();
490
g_main_loop_unref (ri.loop);
496
gtk_window_set_modal (GTK_WINDOW (plug), FALSE);
499
g_signal_handler_disconnect (plug, response_handler);
500
g_signal_handler_disconnect (plug, unmap_handler);
501
g_signal_handler_disconnect (plug, delete_handler);
502
g_signal_handler_disconnect (plug, destroy_handler);
503
g_signal_handler_disconnect (plug, keymap_handler);
506
g_object_unref (plug);
508
return ri.response_id;
512
static cairo_surface_t *
513
surface_from_pixbuf (GdkPixbuf *pixbuf)
515
cairo_surface_t *surface;
518
surface = cairo_image_surface_create (gdk_pixbuf_get_has_alpha (pixbuf) ?
519
CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
520
gdk_pixbuf_get_width (pixbuf),
521
gdk_pixbuf_get_height (pixbuf));
522
cr = cairo_create (surface);
523
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
531
rounded_rectangle (cairo_t *cr,
535
gdouble corner_radius,
542
radius = corner_radius / aspect;
543
degrees = G_PI / 180.0;
545
cairo_new_sub_path (cr);
570
cairo_close_path (cr);
573
/* copied from gdm-user.c */
576
* go_cairo_convert_data_to_pixbuf:
577
* @src: a pointer to pixel data in cairo format
578
* @dst: a pointer to pixel data in pixbuf format
579
* @width: image width
580
* @height: image height
581
* @rowstride: data rowstride
583
* Converts the pixel data stored in @src in CAIRO_FORMAT_ARGB32 cairo format
584
* to GDK_COLORSPACE_RGB pixbuf format and move them
585
* to @dst. If @src == @dst, pixel are converted in place.
589
go_cairo_convert_data_to_pixbuf (unsigned char *dst,
590
unsigned char const *src,
597
unsigned char a, b, c;
599
g_return_if_fail (dst != NULL);
601
#define MULT(d,c,a,t) G_STMT_START { t = (a)? c * 255 / a: 0; d = t;} G_STMT_END
603
if (src == dst || src == NULL) {
604
for (i = 0; i < height; i++) {
605
for (j = 0; j < width; j++) {
606
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
607
MULT(a, dst[2], dst[3], t);
608
MULT(b, dst[1], dst[3], t);
609
MULT(c, dst[0], dst[3], t);
614
MULT(a, dst[1], dst[0], t);
615
MULT(b, dst[2], dst[0], t);
616
MULT(c, dst[3], dst[0], t);
624
dst += rowstride - width * 4;
627
for (i = 0; i < height; i++) {
628
for (j = 0; j < width; j++) {
629
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
630
MULT(dst[0], src[2], src[3], t);
631
MULT(dst[1], src[1], src[3], t);
632
MULT(dst[2], src[0], src[3], t);
635
MULT(dst[0], src[1], src[0], t);
636
MULT(dst[1], src[2], src[0], t);
637
MULT(dst[2], src[3], src[0], t);
643
src += rowstride - width * 4;
644
dst += rowstride - width * 4;
651
cairo_to_pixbuf (guint8 *src_data,
652
GdkPixbuf *dst_pixbuf)
660
w = gdk_pixbuf_get_width (dst_pixbuf);
661
h = gdk_pixbuf_get_height (dst_pixbuf);
662
rowstride = gdk_pixbuf_get_rowstride (dst_pixbuf);
664
dst = gdk_pixbuf_get_pixels (dst_pixbuf);
667
go_cairo_convert_data_to_pixbuf (dst, src, w, h, rowstride);
671
frame_pixbuf (GdkPixbuf *source)
675
cairo_surface_t *surface;
685
w = gdk_pixbuf_get_width (source) + frame_width * 2;
686
h = gdk_pixbuf_get_height (source) + frame_width * 2;
689
dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
694
rowstride = gdk_pixbuf_get_rowstride (dest);
697
data = g_new0 (guint8, h * rowstride);
699
surface = cairo_image_surface_create_for_data (data,
704
cr = cairo_create (surface);
705
cairo_surface_destroy (surface);
708
cairo_rectangle (cr, 0, 0, w, h);
709
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0);
712
rounded_rectangle (cr,
717
w - frame_width * 2 - 1,
718
h - frame_width * 2 - 1);
719
cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.3);
720
cairo_fill_preserve (cr);
722
surface = surface_from_pixbuf (source);
723
cairo_set_source_surface (cr, surface, frame_width, frame_width);
725
cairo_surface_destroy (surface);
727
cairo_to_pixbuf (data, dest);
735
/* end copied from gdm-user.c */
738
image_set_from_pixbuf (GtkImage *image,
743
pixbuf = frame_pixbuf (source);
744
gtk_image_set_from_pixbuf (image, pixbuf);
745
g_object_unref (pixbuf);
749
get_pixbuf_of_user_icon (GSLockPlug *plug)
752
GDBusConnection *system_bus;
753
GVariant *find_user_by_name_reply;
755
GVariant *get_icon_file_reply;
756
GVariant *icon_file_variant;
757
const char *icon_file;
761
system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
764
g_warning ("Unable to get system bus: %s", error->message);
765
g_error_free (error);
769
find_user_by_name_reply = g_dbus_connection_call_sync (system_bus,
770
"org.freedesktop.Accounts",
771
"/org/freedesktop/Accounts",
772
"org.freedesktop.Accounts",
774
g_variant_new ("(s)",
776
G_VARIANT_TYPE ("(o)"),
777
G_DBUS_CALL_FLAGS_NONE,
782
g_warning ("Couldn't find user in accounts service: %s", error->message);
783
g_error_free (error);
787
user = g_variant_get_string (g_variant_get_child_value (find_user_by_name_reply,
791
get_icon_file_reply = g_dbus_connection_call_sync (system_bus,
792
"org.freedesktop.Accounts",
794
"org.freedesktop.DBus.Properties",
796
g_variant_new ("(ss)",
797
"org.freedesktop.Accounts.User",
799
G_VARIANT_TYPE ("(v)"),
800
G_DBUS_CALL_FLAGS_NONE,
804
g_variant_unref (find_user_by_name_reply);
807
g_warning ("Couldn't find user icon in accounts service: %s", error->message);
808
g_error_free (error);
812
g_variant_get_child (get_icon_file_reply, 0, "v", &icon_file_variant);
814
icon_file = g_variant_get_string (icon_file_variant, NULL);
816
if (icon_file == NULL) {
819
string = g_variant_print (get_icon_file_reply, TRUE);
820
g_warning ("reply for user icon path returned invalid response '%s'", string);
825
pixbuf = gdk_pixbuf_new_from_file_at_size (icon_file,
830
g_variant_unref (icon_file_variant);
831
g_variant_unref (get_icon_file_reply);
834
g_warning ("Couldn't load user icon: %s", error->message);
835
g_error_free (error);
843
set_face_image (GSLockPlug *plug)
847
pixbuf = get_pixbuf_of_user_icon (plug);
849
if (pixbuf == NULL) {
853
image_set_from_pixbuf (GTK_IMAGE (plug->priv->auth_face_image), pixbuf);
855
g_object_unref (pixbuf);
861
gs_lock_plug_show (GtkWidget *widget)
863
GSLockPlug *plug = GS_LOCK_PLUG (widget);
865
gs_profile_start (NULL);
867
gs_profile_start ("parent");
868
if (GTK_WIDGET_CLASS (gs_lock_plug_parent_class)->show) {
869
GTK_WIDGET_CLASS (gs_lock_plug_parent_class)->show (widget);
872
gs_profile_end ("parent");
875
if (plug->priv->auth_face_image) {
876
set_face_image (plug);
879
kbd_lock_mode_update (plug, get_kbd_lock_mode ());
881
restart_cancel_timeout (plug);
883
gs_profile_end (NULL);
887
gs_lock_plug_hide (GtkWidget *widget)
889
if (GTK_WIDGET_CLASS (gs_lock_plug_parent_class)->hide) {
890
GTK_WIDGET_CLASS (gs_lock_plug_parent_class)->hide (widget);
895
queue_key_event (GSLockPlug *plug,
898
GdkEvent *saved_event;
900
saved_event = gdk_event_copy ((GdkEvent *)event);
901
plug->priv->key_events = g_list_prepend (plug->priv->key_events,
906
forward_key_events (GSLockPlug *plug)
908
plug->priv->key_events = g_list_reverse (plug->priv->key_events);
909
while (plug->priv->key_events != NULL) {
910
GdkEventKey *event = plug->priv->key_events->data;
912
gtk_window_propagate_key_event (GTK_WINDOW (plug), event);
914
gdk_event_free ((GdkEvent *)event);
916
plug->priv->key_events = g_list_delete_link (plug->priv->key_events,
917
plug->priv->key_events);
922
gs_lock_plug_set_logout_enabled (GSLockPlug *plug,
923
gboolean logout_enabled)
925
g_return_if_fail (GS_LOCK_PLUG (plug));
927
if (plug->priv->logout_enabled == logout_enabled) {
931
plug->priv->logout_enabled = logout_enabled;
932
g_object_notify (G_OBJECT (plug), "logout-enabled");
934
if (plug->priv->auth_logout_button == NULL) {
938
if (logout_enabled) {
939
gtk_widget_show (plug->priv->auth_logout_button);
941
gtk_widget_hide (plug->priv->auth_logout_button);
946
gs_lock_plug_set_logout_command (GSLockPlug *plug,
949
g_return_if_fail (GS_LOCK_PLUG (plug));
951
g_free (plug->priv->logout_command);
954
plug->priv->logout_command = g_strdup (command);
956
plug->priv->logout_command = NULL;
961
is_program_in_path (const char *program)
963
char *tmp = g_find_program_in_path (program);
973
gs_lock_plug_set_status_message (GSLockPlug *plug,
974
const char *status_message)
976
g_return_if_fail (GS_LOCK_PLUG (plug));
978
g_free (plug->priv->status_message);
979
plug->priv->status_message = g_strdup (status_message);
981
if (plug->priv->status_message_label) {
982
if (plug->priv->status_message) {
983
gtk_label_set_text (GTK_LABEL (plug->priv->status_message_label),
984
plug->priv->status_message);
985
gtk_widget_show (plug->priv->status_message_label);
988
gtk_widget_hide (plug->priv->status_message_label);
994
gs_lock_plug_get_property (GObject *object,
1001
self = GS_LOCK_PLUG (object);
1004
case PROP_LOGOUT_ENABLED:
1005
g_value_set_boolean (value, self->priv->logout_enabled);
1007
case PROP_LOGOUT_COMMAND:
1008
g_value_set_string (value, self->priv->logout_command);
1010
case PROP_SWITCH_ENABLED:
1011
g_value_set_boolean (value, self->priv->switch_enabled);
1013
case PROP_STATUS_MESSAGE:
1014
g_value_set_string (value, self->priv->status_message);
1017
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1023
gs_lock_plug_set_switch_enabled (GSLockPlug *plug,
1024
gboolean switch_enabled)
1026
g_return_if_fail (GS_LOCK_PLUG (plug));
1028
if (plug->priv->switch_enabled == switch_enabled) {
1032
plug->priv->switch_enabled = switch_enabled;
1033
g_object_notify (G_OBJECT (plug), "switch-enabled");
1035
if (plug->priv->auth_switch_button == NULL) {
1039
if (switch_enabled) {
1041
found = is_program_in_path (GDM_FLEXISERVER_COMMAND);
1043
gtk_widget_show (plug->priv->auth_switch_button);
1045
gs_debug ("Waring: GDM flexiserver command not found: %s", GDM_FLEXISERVER_COMMAND);
1046
gtk_widget_hide (plug->priv->auth_switch_button);
1049
gtk_widget_hide (plug->priv->auth_switch_button);
1054
gs_lock_plug_set_property (GObject *object,
1056
const GValue *value,
1061
self = GS_LOCK_PLUG (object);
1064
case PROP_LOGOUT_ENABLED:
1065
gs_lock_plug_set_logout_enabled (self, g_value_get_boolean (value));
1067
case PROP_LOGOUT_COMMAND:
1068
gs_lock_plug_set_logout_command (self, g_value_get_string (value));
1070
case PROP_STATUS_MESSAGE:
1071
gs_lock_plug_set_status_message (self, g_value_get_string (value));
1073
case PROP_SWITCH_ENABLED:
1074
gs_lock_plug_set_switch_enabled (self, g_value_get_boolean (value));
1077
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1083
gs_lock_plug_close (GSLockPlug *plug)
1085
/* Synthesize delete_event to close dialog. */
1087
GtkWidget *widget = GTK_WIDGET (plug);
1090
event = gdk_event_new (GDK_DELETE);
1091
event->any.window = g_object_ref (gtk_widget_get_window (widget));
1092
event->any.send_event = TRUE;
1094
gtk_main_do_event (event);
1095
gdk_event_free (event);
1099
gs_lock_plug_class_init (GSLockPlugClass *klass)
1101
GObjectClass *object_class = G_OBJECT_CLASS (klass);
1102
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
1103
GtkBindingSet *binding_set;
1105
object_class->finalize = gs_lock_plug_finalize;
1106
object_class->get_property = gs_lock_plug_get_property;
1107
object_class->set_property = gs_lock_plug_set_property;
1109
widget_class->style_set = gs_lock_plug_style_set;
1110
widget_class->show = gs_lock_plug_show;
1111
widget_class->hide = gs_lock_plug_hide;
1113
klass->close = gs_lock_plug_close;
1115
g_type_class_add_private (klass, sizeof (GSLockPlugPrivate));
1117
lock_plug_signals [RESPONSE] = g_signal_new ("response",
1118
G_OBJECT_CLASS_TYPE (klass),
1120
G_STRUCT_OFFSET (GSLockPlugClass, response),
1122
g_cclosure_marshal_VOID__INT,
1125
lock_plug_signals [CLOSE] = g_signal_new ("close",
1126
G_OBJECT_CLASS_TYPE (klass),
1127
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1128
G_STRUCT_OFFSET (GSLockPlugClass, close),
1130
g_cclosure_marshal_VOID__VOID,
1133
g_object_class_install_property (object_class,
1134
PROP_LOGOUT_ENABLED,
1135
g_param_spec_boolean ("logout-enabled",
1139
G_PARAM_READWRITE));
1140
g_object_class_install_property (object_class,
1141
PROP_LOGOUT_COMMAND,
1142
g_param_spec_string ("logout-command",
1146
G_PARAM_READWRITE));
1147
g_object_class_install_property (object_class,
1148
PROP_STATUS_MESSAGE,
1149
g_param_spec_string ("status-message",
1153
G_PARAM_READWRITE));
1154
g_object_class_install_property (object_class,
1155
PROP_SWITCH_ENABLED,
1156
g_param_spec_boolean ("switch-enabled",
1160
G_PARAM_READWRITE));
1162
binding_set = gtk_binding_set_by_class (klass);
1164
gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0,
1169
clear_clipboards (GSLockPlug *plug)
1171
GtkClipboard *clipboard;
1173
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (plug), GDK_SELECTION_PRIMARY);
1174
gtk_clipboard_clear (clipboard);
1175
gtk_clipboard_set_text (clipboard, "", -1);
1176
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (plug), GDK_SELECTION_CLIPBOARD);
1177
gtk_clipboard_clear (clipboard);
1178
gtk_clipboard_set_text (clipboard, "", -1);
1182
logout_button_clicked (GtkButton *button,
1186
GError *error = NULL;
1189
if (! plug->priv->logout_command) {
1193
res = g_shell_parse_argv (plug->priv->logout_command, NULL, &argv, &error);
1196
g_warning ("Could not parse logout command: %s", error->message);
1197
g_error_free (error);
1201
g_spawn_async (g_get_home_dir (),
1204
G_SPAWN_SEARCH_PATH,
1213
g_warning ("Could not run logout command: %s", error->message);
1214
g_error_free (error);
1219
gs_lock_plug_set_busy (GSLockPlug *plug)
1222
GtkWidget *top_level;
1224
top_level = gtk_widget_get_toplevel (GTK_WIDGET (plug));
1226
cursor = gdk_cursor_new (GDK_WATCH);
1227
gdk_window_set_cursor (gtk_widget_get_window (top_level), cursor);
1228
gdk_cursor_unref (cursor);
1232
gs_lock_plug_set_ready (GSLockPlug *plug)
1235
GtkWidget *top_level;
1237
top_level = gtk_widget_get_toplevel (GTK_WIDGET (plug));
1239
cursor = gdk_cursor_new (GDK_LEFT_PTR);
1240
gdk_window_set_cursor (gtk_widget_get_window (top_level), cursor);
1241
gdk_cursor_unref (cursor);
1245
gs_lock_plug_enable_prompt (GSLockPlug *plug,
1246
const char *message,
1251
g_return_if_fail (GS_IS_LOCK_PLUG (plug));
1253
gs_debug ("Setting prompt to: %s", message);
1255
gtk_widget_set_sensitive (plug->priv->auth_unlock_button, TRUE);
1256
gtk_widget_show (plug->priv->auth_unlock_button);
1257
gtk_widget_grab_default (plug->priv->auth_unlock_button);
1259
/* Change appearance if we're running under Unity */
1260
if (g_getenv ("XDG_CURRENT_DESKTOP") &&
1261
strcmp (g_getenv ("XDG_CURRENT_DESKTOP"), "Unity") == 0) {
1262
markup = g_strdup_printf ("<span font_desc=\"Ubuntu 10\">%s</span>", message);
1264
markup = g_strdup_printf ("<b><big>%s</big></b>", message);
1267
gtk_label_set_markup (GTK_LABEL (plug->priv->auth_prompt_label), markup);
1270
gtk_widget_show (plug->priv->auth_prompt_label);
1271
gtk_entry_set_visibility (GTK_ENTRY (plug->priv->auth_prompt_entry), visible);
1272
gtk_widget_set_sensitive (plug->priv->auth_prompt_entry, TRUE);
1273
gtk_widget_show (plug->priv->auth_prompt_entry);
1275
if (!gtk_widget_has_focus (plug->priv->auth_prompt_entry)) {
1276
gtk_widget_grab_focus (plug->priv->auth_prompt_entry);
1279
/* were there any key events sent to the plug while the
1280
* entry wasnt ready? If so, forward them along
1282
forward_key_events (plug);
1284
restart_cancel_timeout (plug);
1288
gs_lock_plug_disable_prompt (GSLockPlug *plug)
1290
g_return_if_fail (GS_IS_LOCK_PLUG (plug));
1292
/* gtk_widget_hide (plug->priv->auth_prompt_entry); */
1293
/* gtk_widget_hide (plug->priv->auth_prompt_label); */
1294
gtk_widget_set_sensitive (plug->priv->auth_unlock_button, FALSE);
1295
gtk_widget_set_sensitive (plug->priv->auth_prompt_entry, FALSE);
1296
/* gtk_widget_hide (plug->priv->auth_unlock_button); */
1300
gs_lock_plug_show_message (GSLockPlug *plug,
1301
const char *message)
1303
g_return_if_fail (GS_IS_LOCK_PLUG (plug));
1305
set_status_text (plug, message ? message : "");
1308
/* button press handler used to inhibit popup menu */
1310
entry_button_press (GtkWidget *widget,
1311
GdkEventButton *event)
1313
if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
1321
entry_key_press (GtkWidget *widget,
1325
restart_cancel_timeout (plug);
1327
/* if the input widget is visible and ready for input
1328
* then just carry on as usual
1330
if (gtk_widget_get_visible (plug->priv->auth_prompt_entry) &&
1331
gtk_widget_get_sensitive (plug->priv->auth_prompt_entry)) {
1335
if (strcmp (event->string, "") == 0) {
1339
queue_key_event (plug, event);
1344
/* adapted from gtk_dialog_add_button */
1346
gs_lock_plug_add_button (GSLockPlug *plug,
1347
GtkWidget *action_area,
1348
const gchar *button_text)
1352
g_return_val_if_fail (GS_IS_LOCK_PLUG (plug), NULL);
1353
g_return_val_if_fail (button_text != NULL, NULL);
1355
button = gtk_button_new_from_stock (button_text);
1357
gtk_widget_set_can_default (button, TRUE);
1359
gtk_widget_show (button);
1361
gtk_box_pack_end (GTK_BOX (action_area),
1369
create_page_one_buttons (GSLockPlug *plug)
1372
gs_profile_start ("page one buttons");
1374
plug->priv->auth_switch_button = gs_lock_plug_add_button (GS_LOCK_PLUG (plug),
1375
plug->priv->auth_action_area,
1376
_("S_witch User…"));
1377
gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (plug->priv->auth_action_area),
1378
plug->priv->auth_switch_button,
1380
gtk_button_set_focus_on_click (GTK_BUTTON (plug->priv->auth_switch_button), FALSE);
1381
gtk_widget_set_no_show_all (plug->priv->auth_switch_button, TRUE);
1383
plug->priv->auth_logout_button = gs_lock_plug_add_button (GS_LOCK_PLUG (plug),
1384
plug->priv->auth_action_area,
1386
gtk_button_set_focus_on_click (GTK_BUTTON (plug->priv->auth_logout_button), FALSE);
1387
gtk_widget_set_no_show_all (plug->priv->auth_logout_button, TRUE);
1390
plug->priv->auth_unlock_button = gs_lock_plug_add_button (GS_LOCK_PLUG (plug),
1391
plug->priv->auth_action_area,
1393
gtk_button_set_focus_on_click (GTK_BUTTON (plug->priv->auth_unlock_button), FALSE);
1395
gtk_window_set_default (GTK_WINDOW (plug), plug->priv->auth_unlock_button);
1397
gs_profile_end ("page one buttons");
1401
get_user_display_name (void)
1406
name = g_get_real_name ();
1408
if (name == NULL || strcmp (name, "Unknown") == 0) {
1409
name = g_get_user_name ();
1415
utf8_name = g_locale_to_utf8 (name, -1, NULL, NULL, NULL);
1422
update_realname_label (GSLockPlug *plug)
1426
name = get_user_display_name ();
1427
markup = g_strdup_printf ("<span font_desc=\"Ubuntu 16\">%s</span>", name);
1428
gtk_label_set_markup (GTK_LABEL (plug->priv->auth_realname_label), markup);
1434
create_page_one (GSLockPlug *plug)
1441
gs_profile_start ("page one");
1443
align = gtk_alignment_new (0.5, 0.5, 1, 1);
1444
gtk_notebook_append_page (GTK_NOTEBOOK (plug->priv->notebook), align, NULL);
1446
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
1447
gtk_container_add (GTK_CONTAINER (align), vbox);
1449
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1450
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1452
plug->priv->auth_face_image = gtk_image_new ();
1453
gtk_box_pack_start (GTK_BOX (hbox), plug->priv->auth_face_image, FALSE, FALSE, 0);
1454
gtk_misc_set_alignment (GTK_MISC (plug->priv->auth_face_image), 0, 0);
1456
vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
1457
gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 0);
1458
gtk_container_set_border_width (GTK_CONTAINER (vbox2), 10);
1460
#ifdef WITH_KBD_LAYOUT_INDICATOR
1461
gtk_box_pack_start (GTK_BOX (hbox), plug->priv->auth_prompt_kbd_layout_indicator, FALSE, FALSE, 0);
1464
/* Change appearance if we're running under Unity */
1465
if (g_getenv ("XDG_CURRENT_DESKTOP") &&
1466
strcmp (g_getenv ("XDG_CURRENT_DESKTOP"), "Unity") == 0) {
1467
gtk_box_set_spacing (vbox2, 0);
1468
gtk_misc_set_alignment (GTK_MISC (plug->priv->auth_face_image), 0, 0.5);
1469
plug->priv->auth_realname_label = gtk_label_new (NULL);
1470
update_realname_label (plug);
1471
gtk_misc_set_alignment (GTK_MISC (plug->priv->auth_realname_label), 0, 1);
1472
gtk_box_pack_start (GTK_BOX (vbox2), plug->priv->auth_realname_label, FALSE, FALSE, 0);
1474
plug->priv->auth_prompt_label = gtk_label_new_with_mnemonic (_("_Password:"));
1475
gtk_misc_set_alignment (GTK_MISC (plug->priv->auth_prompt_label), 0, 0);
1476
gtk_box_pack_start (GTK_BOX (vbox2), plug->priv->auth_prompt_label, FALSE, FALSE, 0);
1478
plug->priv->auth_prompt_entry = gtk_entry_new ();
1479
gtk_box_pack_start (GTK_BOX (vbox2), plug->priv->auth_prompt_entry, TRUE, TRUE, 6);
1481
gtk_label_set_mnemonic_widget (GTK_LABEL (plug->priv->auth_prompt_label),
1482
plug->priv->auth_prompt_entry);
1484
plug->priv->auth_capslock_label = gtk_label_new ("");
1485
gtk_misc_set_alignment (GTK_MISC (plug->priv->auth_capslock_label), 0, 0.5);
1486
gtk_box_pack_start (GTK_BOX (vbox2), plug->priv->auth_capslock_label, FALSE, FALSE, 0);
1490
plug->priv->auth_message_label = gtk_label_new (NULL);
1491
gtk_misc_set_alignment (GTK_MISC (plug->priv->auth_message_label), 0, 0.5);
1492
gtk_box_pack_start (GTK_BOX (vbox2), plug->priv->auth_message_label,
1497
plug->priv->auth_prompt_label = gtk_label_new_with_mnemonic (_("_Password:"));
1498
gtk_misc_set_alignment (GTK_MISC (plug->priv->auth_prompt_label), 0, 0.5);
1499
gtk_box_pack_start (GTK_BOX (vbox2), plug->priv->auth_prompt_label, FALSE, FALSE, 0);
1501
plug->priv->auth_prompt_entry = gtk_entry_new ();
1502
gtk_box_pack_start (GTK_BOX (vbox2), plug->priv->auth_prompt_entry, TRUE, TRUE, 0);
1504
gtk_label_set_mnemonic_widget (GTK_LABEL (plug->priv->auth_prompt_label),
1505
plug->priv->auth_prompt_entry);
1507
plug->priv->auth_capslock_label = gtk_label_new ("");
1508
gtk_misc_set_alignment (GTK_MISC (plug->priv->auth_capslock_label), 0.5, 0.5);
1509
gtk_box_pack_start (GTK_BOX (vbox2), plug->priv->auth_capslock_label, FALSE, FALSE, 0);
1513
plug->priv->auth_message_label = gtk_label_new (NULL);
1514
gtk_box_pack_start (GTK_BOX (vbox), plug->priv->auth_message_label,
1518
plug->priv->auth_action_area = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
1520
gtk_button_box_set_layout (GTK_BUTTON_BOX (plug->priv->auth_action_area),
1523
gtk_box_pack_end (GTK_BOX (vbox), plug->priv->auth_action_area,
1525
gtk_widget_show (plug->priv->auth_action_area);
1527
create_page_one_buttons (plug);
1529
gs_profile_end ("page one");
1533
unlock_button_clicked (GtkButton *button,
1536
gs_lock_plug_response (plug, GS_LOCK_PLUG_RESPONSE_OK);
1540
switch_user_button_clicked (GtkButton *button,
1544
remove_response_idle (plug);
1546
gs_lock_plug_set_sensitive (plug, FALSE);
1548
plug->priv->response_idle_id = g_timeout_add (2000,
1549
(GSourceFunc)response_cancel_idle_cb,
1552
gs_lock_plug_set_busy (plug);
1553
do_user_switch (plug);
1557
delete_handler (GSLockPlug *plug,
1561
gs_lock_plug_response (plug, GS_LOCK_PLUG_RESPONSE_CANCEL);
1563
return TRUE; /* Do not destroy */
1567
gs_lock_plug_init (GSLockPlug *plug)
1569
gs_profile_start (NULL);
1571
plug->priv = GS_LOCK_PLUG_GET_PRIVATE (plug);
1573
clear_clipboards (plug);
1575
plug->priv->frame = gtk_frame_new (NULL);
1576
gtk_frame_set_shadow_type (GTK_FRAME (plug->priv->frame), GTK_SHADOW_OUT);
1577
gtk_container_add (GTK_CONTAINER (plug), plug->priv->frame);
1579
plug->priv->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1580
gtk_container_add (GTK_CONTAINER (plug->priv->frame), plug->priv->vbox);
1582
plug->priv->auth_prompt_kbd_layout_indicator = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1585
plug->priv->notebook = gtk_notebook_new ();
1586
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (plug->priv->notebook), FALSE);
1587
gtk_notebook_set_show_border (GTK_NOTEBOOK (plug->priv->notebook), FALSE);
1588
gtk_box_pack_start (GTK_BOX (plug->priv->vbox), plug->priv->notebook, TRUE, TRUE, 0);
1592
create_page_one (plug);
1594
gtk_widget_show_all (plug->priv->frame);
1596
/* Layout indicator */
1597
#ifdef WITH_KBD_LAYOUT_INDICATOR
1598
if (plug->priv->auth_prompt_kbd_layout_indicator != NULL) {
1601
engine = xkl_engine_get_instance (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
1602
if (xkl_engine_get_num_groups (engine) > 1) {
1603
GtkWidget *layout_indicator;
1605
layout_indicator = gkbd_indicator_new ();
1606
gkbd_indicator_set_parent_tooltips (GKBD_INDICATOR (layout_indicator), TRUE);
1607
gtk_box_pack_start (GTK_BOX (plug->priv->auth_prompt_kbd_layout_indicator),
1613
gtk_widget_show_all (layout_indicator);
1614
gtk_widget_show (plug->priv->auth_prompt_kbd_layout_indicator);
1616
gtk_widget_hide (plug->priv->auth_prompt_kbd_layout_indicator);
1619
g_object_unref (engine);
1623
if (plug->priv->auth_switch_button != NULL) {
1624
if (plug->priv->switch_enabled) {
1625
gtk_widget_show_all (plug->priv->auth_switch_button);
1627
gtk_widget_hide (plug->priv->auth_switch_button);
1631
gtk_widget_grab_default (plug->priv->auth_unlock_button);
1633
if (! plug->priv->logout_enabled || ! plug->priv->logout_command) {
1634
if (plug->priv->auth_logout_button != NULL) {
1635
gtk_widget_hide (plug->priv->auth_logout_button);
1639
plug->priv->timeout = DIALOG_TIMEOUT_MSEC;
1641
g_signal_connect (plug, "key_press_event",
1642
G_CALLBACK (entry_key_press), plug);
1644
/* button press handler used to inhibit popup menu */
1645
g_signal_connect (plug->priv->auth_prompt_entry, "button_press_event",
1646
G_CALLBACK (entry_button_press), NULL);
1647
gtk_entry_set_activates_default (GTK_ENTRY (plug->priv->auth_prompt_entry), TRUE);
1648
gtk_entry_set_visibility (GTK_ENTRY (plug->priv->auth_prompt_entry), FALSE);
1650
g_signal_connect (plug->priv->auth_unlock_button, "clicked",
1651
G_CALLBACK (unlock_button_clicked), plug);
1653
if (plug->priv->status_message_label) {
1654
if (plug->priv->status_message) {
1655
gtk_label_set_text (GTK_LABEL (plug->priv->status_message_label),
1656
plug->priv->status_message);
1659
gtk_widget_hide (plug->priv->status_message_label);
1663
if (plug->priv->auth_switch_button != NULL) {
1664
g_signal_connect (plug->priv->auth_switch_button, "clicked",
1665
G_CALLBACK (switch_user_button_clicked), plug);
1668
if (plug->priv->auth_logout_button != NULL) {
1669
g_signal_connect (plug->priv->auth_logout_button, "clicked",
1670
G_CALLBACK (logout_button_clicked), plug);
1673
g_signal_connect (plug, "delete_event", G_CALLBACK (delete_handler), NULL);
1675
gtk_widget_set_size_request (GTK_WIDGET (plug), 450, -1);
1677
gs_profile_end (NULL);
1681
gs_lock_plug_finalize (GObject *object)
1685
g_return_if_fail (object != NULL);
1686
g_return_if_fail (GS_IS_LOCK_PLUG (object));
1688
plug = GS_LOCK_PLUG (object);
1690
g_return_if_fail (plug->priv != NULL);
1692
g_free (plug->priv->logout_command);
1694
remove_response_idle (plug);
1695
remove_cancel_timeout (plug);
1697
G_OBJECT_CLASS (gs_lock_plug_parent_class)->finalize (object);
1701
gs_lock_plug_new (void)
1705
result = g_object_new (GS_TYPE_LOCK_PLUG, NULL);
1707
gtk_window_set_focus_on_map (GTK_WINDOW (result), TRUE);