~ubuntu-branches/ubuntu/wily/gnome-screensaver/wily-proposed

« back to all changes in this revision

Viewing changes to .pc/22_dont_show_numlock_warning.patch/src/gs-lock-plug.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2012-04-16 09:02:26 UTC
  • mfrom: (1.3.11)
  • Revision ID: package-import@ubuntu.com-20120416090226-9pvsdbefuj2girbi
Tags: 3.4.1-0ubuntu1
* New upstream bug fix release:
  - Drop num lock warning
  - Translation updates.
* Drop 22_dont_show_numlock_warning.patch, applied upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2
 
 *
3
 
 * Copyright (C) 2004-2008 William Jon McCann <mccann@jhu.edu>
4
 
 * Copyright (C) 2008-2011 Red Hat, Inc.
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 of the License, or
9
 
 * (at your option) 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
 
 *
20
 
 */
21
 
 
22
 
#include "config.h"
23
 
 
24
 
#include <stdlib.h>
25
 
#include <unistd.h>
26
 
#include <string.h>
27
 
#include <errno.h>
28
 
#include <time.h>
29
 
#include <unistd.h>
30
 
#include <sys/utsname.h>
31
 
 
32
 
#include <glib/gprintf.h>
33
 
#include <glib/gstdio.h>
34
 
#include <glib/gi18n.h>
35
 
#include <gdk/gdkkeysyms.h>
36
 
#include <gdk/gdkx.h>
37
 
#include <gtk/gtk.h>
38
 
 
39
 
#ifdef WITH_KBD_LAYOUT_INDICATOR
40
 
#include <libgnomekbd/gkbd-indicator.h>
41
 
#endif
42
 
 
43
 
#include "gs-lock-plug.h"
44
 
 
45
 
#include "gs-debug.h"
46
 
 
47
 
#define GDM_FLEXISERVER_COMMAND "gdmflexiserver"
48
 
#define GDM_FLEXISERVER_ARGS    "--startnew Standard"
49
 
 
50
 
enum {
51
 
        AUTH_PAGE = 0,
52
 
};
53
 
 
54
 
enum {
55
 
        LOCK_NONE = 0,
56
 
        LOCK_CAPS = 1 << 0,
57
 
        LOCK_NUM = 1 << 1,
58
 
};
59
 
 
60
 
#define FACE_ICON_SIZE 48
61
 
#define DIALOG_TIMEOUT_MSEC 60000
62
 
 
63
 
static void gs_lock_plug_finalize   (GObject         *object);
64
 
 
65
 
#define GS_LOCK_PLUG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_LOCK_PLUG, GSLockPlugPrivate))
66
 
 
67
 
struct GSLockPlugPrivate
68
 
{
69
 
        GtkWidget   *frame;
70
 
        GtkWidget   *vbox;
71
 
        GtkWidget   *auth_action_area;
72
 
 
73
 
        GtkWidget   *notebook;
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;
82
 
 
83
 
        GtkWidget   *auth_unlock_button;
84
 
        GtkWidget   *auth_switch_button;
85
 
        GtkWidget   *auth_logout_button;
86
 
 
87
 
        GtkWidget   *auth_prompt_kbd_layout_indicator;
88
 
 
89
 
        int          kbd_lock_mode;
90
 
        gboolean     switch_enabled;
91
 
        gboolean     logout_enabled;
92
 
        char        *logout_command;
93
 
        char        *status_message;
94
 
 
95
 
        guint        timeout;
96
 
 
97
 
        guint        cancel_timeout_id;
98
 
        guint        auth_check_idle_id;
99
 
        guint        response_idle_id;
100
 
 
101
 
        GList       *key_events;
102
 
};
103
 
 
104
 
typedef struct _ResponseData ResponseData;
105
 
 
106
 
struct _ResponseData
107
 
{
108
 
        gint response_id;
109
 
};
110
 
 
111
 
 
112
 
enum {
113
 
        RESPONSE,
114
 
        CLOSE,
115
 
        LAST_SIGNAL
116
 
};
117
 
 
118
 
enum {
119
 
        PROP_0,
120
 
        PROP_LOGOUT_ENABLED,
121
 
        PROP_LOGOUT_COMMAND,
122
 
        PROP_SWITCH_ENABLED,
123
 
        PROP_STATUS_MESSAGE
124
 
};
125
 
 
126
 
static guint lock_plug_signals [LAST_SIGNAL];
127
 
 
128
 
G_DEFINE_TYPE (GSLockPlug, gs_lock_plug, GTK_TYPE_PLUG)
129
 
 
130
 
static void
131
 
gs_lock_plug_style_set (GtkWidget *widget,
132
 
                        GtkStyle  *previous_style)
133
 
{
134
 
        GSLockPlug *plug;
135
 
 
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);
138
 
        }
139
 
 
140
 
        plug = GS_LOCK_PLUG (widget);
141
 
 
142
 
        gtk_container_set_border_width (GTK_CONTAINER (plug->priv->vbox), 24);
143
 
        gtk_box_set_spacing (GTK_BOX (plug->priv->vbox), 12);
144
 
 
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);
147
 
}
148
 
 
149
 
static void
150
 
do_user_switch (GSLockPlug *plug)
151
 
{
152
 
        GAppInfo *app;
153
 
        GAppLaunchContext *context;
154
 
        GError  *error;
155
 
        char    *command;
156
 
 
157
 
        command = g_strdup_printf ("%s %s",
158
 
                                   GDM_FLEXISERVER_COMMAND,
159
 
                                   GDM_FLEXISERVER_ARGS);
160
 
 
161
 
        error = NULL;
162
 
        context = (GAppLaunchContext*)gdk_app_launch_context_new ();
163
 
        app = g_app_info_create_from_commandline (command, "gdmflexiserver", 0, &error);
164
 
        if (app)
165
 
                g_app_info_launch (app, NULL, context, &error);
166
 
 
167
 
        g_free (command);
168
 
        g_object_unref (context);
169
 
        g_object_unref (app);
170
 
 
171
 
        if (error != NULL) {
172
 
                gs_debug ("Unable to start GDM greeter: %s", error->message);
173
 
                g_error_free (error);
174
 
        }
175
 
}
176
 
 
177
 
static void
178
 
set_status_text (GSLockPlug *plug,
179
 
                 const char *text)
180
 
{
181
 
        if (plug->priv->auth_message_label != NULL) {
182
 
                gtk_label_set_text (GTK_LABEL (plug->priv->auth_message_label), text);
183
 
        }
184
 
}
185
 
 
186
 
void
187
 
gs_lock_plug_set_sensitive (GSLockPlug *plug,
188
 
                            gboolean    sensitive)
189
 
{
190
 
        g_return_if_fail (GS_IS_LOCK_PLUG (plug));
191
 
 
192
 
        gtk_widget_set_sensitive (plug->priv->auth_prompt_entry, sensitive);
193
 
        gtk_widget_set_sensitive (plug->priv->auth_action_area, sensitive);
194
 
}
195
 
 
196
 
static void
197
 
remove_cancel_timeout (GSLockPlug *plug)
198
 
{
199
 
        if (plug->priv->cancel_timeout_id > 0) {
200
 
                g_source_remove (plug->priv->cancel_timeout_id);
201
 
                plug->priv->cancel_timeout_id = 0;
202
 
        }
203
 
}
204
 
 
205
 
static void
206
 
remove_response_idle (GSLockPlug *plug)
207
 
{
208
 
        if (plug->priv->response_idle_id > 0) {
209
 
                g_source_remove (plug->priv->response_idle_id);
210
 
                plug->priv->response_idle_id = 0;
211
 
        }
212
 
}
213
 
 
214
 
static void
215
 
gs_lock_plug_response (GSLockPlug *plug,
216
 
                       gint        response_id)
217
 
{
218
 
        int new_response;
219
 
 
220
 
        new_response = response_id;
221
 
 
222
 
        g_return_if_fail (GS_IS_LOCK_PLUG (plug));
223
 
 
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)) {
227
 
                return;
228
 
        }
229
 
 
230
 
        remove_cancel_timeout (plug);
231
 
        remove_response_idle (plug);
232
 
 
233
 
        if (response_id == GS_LOCK_PLUG_RESPONSE_CANCEL) {
234
 
                gtk_entry_set_text (GTK_ENTRY (plug->priv->auth_prompt_entry), "");
235
 
        }
236
 
 
237
 
        g_signal_emit (plug,
238
 
                       lock_plug_signals [RESPONSE],
239
 
                       0,
240
 
                       new_response);
241
 
}
242
 
 
243
 
static gboolean
244
 
response_cancel_idle_cb (GSLockPlug *plug)
245
 
{
246
 
        plug->priv->response_idle_id = 0;
247
 
 
248
 
        gs_lock_plug_response (plug, GS_LOCK_PLUG_RESPONSE_CANCEL);
249
 
 
250
 
        return FALSE;
251
 
}
252
 
 
253
 
static gboolean
254
 
dialog_timed_out (GSLockPlug *plug)
255
 
{
256
 
        gs_lock_plug_set_sensitive (plug, FALSE);
257
 
        set_status_text (plug, _("Time has expired."));
258
 
 
259
 
        if (plug->priv->response_idle_id != 0) {
260
 
                g_warning ("Response idle ID already set but shouldn't be");
261
 
        }
262
 
 
263
 
        remove_response_idle (plug);
264
 
 
265
 
        plug->priv->response_idle_id = g_timeout_add (2000,
266
 
                                                      (GSourceFunc)response_cancel_idle_cb,
267
 
                                                      plug);
268
 
        return FALSE;
269
 
}
270
 
 
271
 
 
272
 
static void
273
 
kbd_lock_mode_update (GSLockPlug *plug,
274
 
                      int         mode)
275
 
{
276
 
        if (plug->priv->kbd_lock_mode == mode) {
277
 
                return;
278
 
        }
279
 
 
280
 
        plug->priv->kbd_lock_mode = mode;
281
 
 
282
 
        if (plug->priv->auth_capslock_label == NULL) {
283
 
                return;
284
 
        }
285
 
 
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."));
295
 
        } else {
296
 
                gtk_label_set_text (GTK_LABEL (plug->priv->auth_capslock_label),
297
 
                                    "");
298
 
        }
299
 
}
300
 
 
301
 
static int
302
 
get_kbd_lock_mode (void)
303
 
{
304
 
        GdkKeymap *keymap;
305
 
        int        mode;
306
 
 
307
 
        mode = LOCK_NONE;
308
 
 
309
 
        keymap = gdk_keymap_get_default ();
310
 
        if (keymap != NULL) {
311
 
                gboolean res;
312
 
 
313
 
                res = gdk_keymap_get_caps_lock_state (keymap);
314
 
                if (res) {
315
 
                        mode |= LOCK_CAPS;
316
 
                }
317
 
#if GTK_CHECK_VERSION(2,90,6)
318
 
                res = gdk_keymap_get_num_lock_state (keymap);
319
 
                if (res) {
320
 
                        mode |= LOCK_NUM;
321
 
                }
322
 
#endif
323
 
        }
324
 
 
325
 
        return mode;
326
 
}
327
 
 
328
 
static void
329
 
restart_cancel_timeout (GSLockPlug *plug)
330
 
{
331
 
        remove_cancel_timeout (plug);
332
 
 
333
 
        plug->priv->cancel_timeout_id = g_timeout_add (plug->priv->timeout,
334
 
                                                       (GSourceFunc)dialog_timed_out,
335
 
                                                       plug);
336
 
}
337
 
 
338
 
void
339
 
gs_lock_plug_get_text (GSLockPlug *plug,
340
 
                       char      **text)
341
 
{
342
 
        const char *typed_text;
343
 
        char       *null_text;
344
 
        char       *local_text;
345
 
 
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);
348
 
 
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), "");
352
 
        g_free (null_text);
353
 
 
354
 
        if (text != NULL) {
355
 
                *text = local_text;
356
 
        }
357
 
}
358
 
 
359
 
typedef struct
360
 
{
361
 
        GSLockPlug *plug;
362
 
        gint response_id;
363
 
        GMainLoop *loop;
364
 
        gboolean destroyed;
365
 
} RunInfo;
366
 
 
367
 
static void
368
 
shutdown_loop (RunInfo *ri)
369
 
{
370
 
        if (g_main_loop_is_running (ri->loop))
371
 
                g_main_loop_quit (ri->loop);
372
 
}
373
 
 
374
 
static void
375
 
run_unmap_handler (GSLockPlug *plug,
376
 
                   gpointer data)
377
 
{
378
 
        RunInfo *ri = data;
379
 
 
380
 
        shutdown_loop (ri);
381
 
}
382
 
 
383
 
static void
384
 
run_response_handler (GSLockPlug *plug,
385
 
                      gint response_id,
386
 
                      gpointer data)
387
 
{
388
 
        RunInfo *ri;
389
 
 
390
 
        ri = data;
391
 
 
392
 
        ri->response_id = response_id;
393
 
 
394
 
        shutdown_loop (ri);
395
 
}
396
 
 
397
 
static gint
398
 
run_delete_handler (GSLockPlug *plug,
399
 
                    GdkEventAny *event,
400
 
                    gpointer data)
401
 
{
402
 
        RunInfo *ri = data;
403
 
 
404
 
        shutdown_loop (ri);
405
 
 
406
 
        return TRUE; /* Do not destroy */
407
 
}
408
 
 
409
 
static void
410
 
run_destroy_handler (GSLockPlug *plug,
411
 
                     gpointer data)
412
 
{
413
 
        RunInfo *ri = data;
414
 
 
415
 
        /* shutdown_loop will be called by run_unmap_handler */
416
 
        ri->destroyed = TRUE;
417
 
}
418
 
 
419
 
static void
420
 
run_keymap_handler (GdkKeymap *keymap,
421
 
                    GSLockPlug *plug)
422
 
{
423
 
        kbd_lock_mode_update (plug, get_kbd_lock_mode ());
424
 
}
425
 
 
426
 
/* adapted from GTK+ gtkdialog.c */
427
 
int
428
 
gs_lock_plug_run (GSLockPlug *plug)
429
 
{
430
 
        RunInfo ri = { NULL, GTK_RESPONSE_NONE, NULL, FALSE };
431
 
        gboolean was_modal;
432
 
        gulong response_handler;
433
 
        gulong unmap_handler;
434
 
        gulong destroy_handler;
435
 
        gulong delete_handler;
436
 
        gulong keymap_handler;
437
 
        GdkKeymap *keymap;
438
 
 
439
 
        g_return_val_if_fail (GS_IS_LOCK_PLUG (plug), -1);
440
 
 
441
 
        g_object_ref (plug);
442
 
 
443
 
        was_modal = gtk_window_get_modal (GTK_WINDOW (plug));
444
 
        if (!was_modal) {
445
 
                gtk_window_set_modal (GTK_WINDOW (plug), TRUE);
446
 
        }
447
 
 
448
 
        if (!gtk_widget_get_visible (GTK_WIDGET (plug))) {
449
 
                gtk_widget_show (GTK_WIDGET (plug));
450
 
        }
451
 
 
452
 
        keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (plug)));
453
 
 
454
 
        keymap_handler =
455
 
                g_signal_connect (keymap,
456
 
                                  "state-changed",
457
 
                                  G_CALLBACK (run_keymap_handler),
458
 
                                  plug);
459
 
 
460
 
        response_handler =
461
 
                g_signal_connect (plug,
462
 
                                  "response",
463
 
                                  G_CALLBACK (run_response_handler),
464
 
                                  &ri);
465
 
 
466
 
        unmap_handler =
467
 
                g_signal_connect (plug,
468
 
                                  "unmap",
469
 
                                  G_CALLBACK (run_unmap_handler),
470
 
                                  &ri);
471
 
 
472
 
        delete_handler =
473
 
                g_signal_connect (plug,
474
 
                                  "delete_event",
475
 
                                  G_CALLBACK (run_delete_handler),
476
 
                                  &ri);
477
 
 
478
 
        destroy_handler =
479
 
                g_signal_connect (plug,
480
 
                                  "destroy",
481
 
                                  G_CALLBACK (run_destroy_handler),
482
 
                                  &ri);
483
 
 
484
 
        ri.loop = g_main_loop_new (NULL, FALSE);
485
 
 
486
 
        GDK_THREADS_LEAVE ();
487
 
        g_main_loop_run (ri.loop);
488
 
        GDK_THREADS_ENTER ();
489
 
 
490
 
        g_main_loop_unref (ri.loop);
491
 
 
492
 
        ri.loop = NULL;
493
 
 
494
 
        if (!ri.destroyed) {
495
 
                if (! was_modal) {
496
 
                        gtk_window_set_modal (GTK_WINDOW (plug), FALSE);
497
 
                }
498
 
 
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);
504
 
        }
505
 
 
506
 
        g_object_unref (plug);
507
 
 
508
 
        return ri.response_id;
509
 
}
510
 
 
511
 
 
512
 
static cairo_surface_t *
513
 
surface_from_pixbuf (GdkPixbuf *pixbuf)
514
 
{
515
 
        cairo_surface_t *surface;
516
 
        cairo_t         *cr;
517
 
 
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);
524
 
        cairo_paint (cr);
525
 
        cairo_destroy (cr);
526
 
 
527
 
        return surface;
528
 
}
529
 
 
530
 
static void
531
 
rounded_rectangle (cairo_t *cr,
532
 
                   gdouble  aspect,
533
 
                   gdouble  x,
534
 
                   gdouble  y,
535
 
                   gdouble  corner_radius,
536
 
                   gdouble  width,
537
 
                   gdouble  height)
538
 
{
539
 
        gdouble radius;
540
 
        gdouble degrees;
541
 
 
542
 
        radius = corner_radius / aspect;
543
 
        degrees = G_PI / 180.0;
544
 
 
545
 
        cairo_new_sub_path (cr);
546
 
        cairo_arc (cr,
547
 
                   x + width - radius,
548
 
                   y + radius,
549
 
                   radius,
550
 
                   -90 * degrees,
551
 
                   0 * degrees);
552
 
        cairo_arc (cr,
553
 
                   x + width - radius,
554
 
                   y + height - radius,
555
 
                   radius,
556
 
                   0 * degrees,
557
 
                   90 * degrees);
558
 
        cairo_arc (cr,
559
 
                   x + radius,
560
 
                   y + height - radius,
561
 
                   radius,
562
 
                   90 * degrees,
563
 
                   180 * degrees);
564
 
        cairo_arc (cr,
565
 
                   x + radius,
566
 
                   y + radius,
567
 
                   radius,
568
 
                   180 * degrees,
569
 
                   270 * degrees);
570
 
        cairo_close_path (cr);
571
 
}
572
 
 
573
 
/* copied from gdm-user.c */
574
 
 
575
 
/**
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
582
 
 *
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.
586
 
 **/
587
 
 
588
 
static void
589
 
go_cairo_convert_data_to_pixbuf (unsigned char *dst,
590
 
                                 unsigned char const *src,
591
 
                                 int width,
592
 
                                 int height,
593
 
                                 int rowstride)
594
 
{
595
 
        int i,j;
596
 
        unsigned int t;
597
 
        unsigned char a, b, c;
598
 
 
599
 
        g_return_if_fail (dst != NULL);
600
 
 
601
 
#define MULT(d,c,a,t) G_STMT_START { t = (a)? c * 255 / a: 0; d = t;} G_STMT_END
602
 
 
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);
610
 
                                dst[0] = a;
611
 
                                dst[1] = b;
612
 
                                dst[2] = c;
613
 
#else
614
 
                                MULT(a, dst[1], dst[0], t);
615
 
                                MULT(b, dst[2], dst[0], t);
616
 
                                MULT(c, dst[3], dst[0], t);
617
 
                                dst[3] = dst[0];
618
 
                                dst[0] = a;
619
 
                                dst[1] = b;
620
 
                                dst[2] = c;
621
 
#endif
622
 
                                dst += 4;
623
 
                        }
624
 
                        dst += rowstride - width * 4;
625
 
                }
626
 
        } else {
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);
633
 
                                dst[3] = src[3];
634
 
#else
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);
638
 
                                dst[3] = src[0];
639
 
#endif
640
 
                                src += 4;
641
 
                                dst += 4;
642
 
                        }
643
 
                        src += rowstride - width * 4;
644
 
                        dst += rowstride - width * 4;
645
 
                }
646
 
        }
647
 
#undef MULT
648
 
}
649
 
 
650
 
static void
651
 
cairo_to_pixbuf (guint8    *src_data,
652
 
                 GdkPixbuf *dst_pixbuf)
653
 
{
654
 
        unsigned char *src;
655
 
        unsigned char *dst;
656
 
        guint          w;
657
 
        guint          h;
658
 
        guint          rowstride;
659
 
 
660
 
        w = gdk_pixbuf_get_width (dst_pixbuf);
661
 
        h = gdk_pixbuf_get_height (dst_pixbuf);
662
 
        rowstride = gdk_pixbuf_get_rowstride (dst_pixbuf);
663
 
 
664
 
        dst = gdk_pixbuf_get_pixels (dst_pixbuf);
665
 
        src = src_data;
666
 
 
667
 
        go_cairo_convert_data_to_pixbuf (dst, src, w, h, rowstride);
668
 
}
669
 
 
670
 
static GdkPixbuf *
671
 
frame_pixbuf (GdkPixbuf *source)
672
 
{
673
 
        GdkPixbuf       *dest;
674
 
        cairo_t         *cr;
675
 
        cairo_surface_t *surface;
676
 
        guint            w;
677
 
        guint            h;
678
 
        guint            rowstride;
679
 
        int              frame_width;
680
 
        double           radius;
681
 
        guint8          *data;
682
 
 
683
 
        frame_width = 5;
684
 
 
685
 
        w = gdk_pixbuf_get_width (source) + frame_width * 2;
686
 
        h = gdk_pixbuf_get_height (source) + frame_width * 2;
687
 
        radius = w / 10;
688
 
 
689
 
        dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
690
 
                               TRUE,
691
 
                               8,
692
 
                               w,
693
 
                               h);
694
 
        rowstride = gdk_pixbuf_get_rowstride (dest);
695
 
 
696
 
 
697
 
        data = g_new0 (guint8, h * rowstride);
698
 
 
699
 
        surface = cairo_image_surface_create_for_data (data,
700
 
                                                       CAIRO_FORMAT_ARGB32,
701
 
                                                       w,
702
 
                                                       h,
703
 
                                                       rowstride);
704
 
        cr = cairo_create (surface);
705
 
        cairo_surface_destroy (surface);
706
 
 
707
 
        /* set up image */
708
 
        cairo_rectangle (cr, 0, 0, w, h);
709
 
        cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0);
710
 
        cairo_fill (cr);
711
 
 
712
 
        rounded_rectangle (cr,
713
 
                           1.0,
714
 
                           frame_width + 0.5,
715
 
                           frame_width + 0.5,
716
 
                           radius,
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);
721
 
 
722
 
        surface = surface_from_pixbuf (source);
723
 
        cairo_set_source_surface (cr, surface, frame_width, frame_width);
724
 
        cairo_fill (cr);
725
 
        cairo_surface_destroy (surface);
726
 
 
727
 
        cairo_to_pixbuf (data, dest);
728
 
 
729
 
        cairo_destroy (cr);
730
 
        g_free (data);
731
 
 
732
 
        return dest;
733
 
}
734
 
 
735
 
/* end copied from gdm-user.c */
736
 
 
737
 
static void
738
 
image_set_from_pixbuf (GtkImage  *image,
739
 
                       GdkPixbuf *source)
740
 
{
741
 
        GdkPixbuf *pixbuf;
742
 
 
743
 
        pixbuf = frame_pixbuf (source);
744
 
        gtk_image_set_from_pixbuf (image, pixbuf);
745
 
        g_object_unref (pixbuf);
746
 
}
747
 
 
748
 
static GdkPixbuf *
749
 
get_pixbuf_of_user_icon (GSLockPlug *plug)
750
 
{
751
 
        GError          *error;
752
 
        GDBusConnection *system_bus;
753
 
        GVariant        *find_user_by_name_reply;
754
 
        const char      *user;
755
 
        GVariant        *get_icon_file_reply;
756
 
        GVariant        *icon_file_variant;
757
 
        const char      *icon_file;
758
 
        GdkPixbuf       *pixbuf;
759
 
 
760
 
        error = NULL;
761
 
        system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
762
 
 
763
 
        if (error != NULL) {
764
 
                g_warning ("Unable to get system bus: %s", error->message);
765
 
                g_error_free (error);
766
 
                return NULL;
767
 
        }
768
 
 
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",
773
 
                                                               "FindUserByName",
774
 
                                                               g_variant_new ("(s)",
775
 
                                                                              g_get_user_name ()),
776
 
                                                               G_VARIANT_TYPE ("(o)"),
777
 
                                                               G_DBUS_CALL_FLAGS_NONE,
778
 
                                                               -1,
779
 
                                                               NULL,
780
 
                                                               &error);
781
 
        if (error != NULL) {
782
 
                g_warning ("Couldn't find user in accounts service: %s", error->message);
783
 
                g_error_free (error);
784
 
                return NULL;
785
 
        }
786
 
 
787
 
        user = g_variant_get_string (g_variant_get_child_value (find_user_by_name_reply,
788
 
                                                                0),
789
 
                                     NULL);
790
 
 
791
 
        get_icon_file_reply = g_dbus_connection_call_sync (system_bus,
792
 
                                                           "org.freedesktop.Accounts",
793
 
                                                           user,
794
 
                                                           "org.freedesktop.DBus.Properties",
795
 
                                                           "Get",
796
 
                                                           g_variant_new ("(ss)",
797
 
                                                                          "org.freedesktop.Accounts.User",
798
 
                                                                          "IconFile"),
799
 
                                                           G_VARIANT_TYPE ("(v)"),
800
 
                                                           G_DBUS_CALL_FLAGS_NONE,
801
 
                                                           -1,
802
 
                                                           NULL,
803
 
                                                           &error);
804
 
        g_variant_unref (find_user_by_name_reply);
805
 
 
806
 
        if (error != NULL) {
807
 
                g_warning ("Couldn't find user icon in accounts service: %s", error->message);
808
 
                g_error_free (error);
809
 
                return NULL;
810
 
        }
811
 
 
812
 
        g_variant_get_child (get_icon_file_reply, 0, "v", &icon_file_variant);
813
 
 
814
 
        icon_file = g_variant_get_string (icon_file_variant, NULL);
815
 
 
816
 
        if (icon_file == NULL) {
817
 
                char *string;
818
 
 
819
 
                string = g_variant_print (get_icon_file_reply, TRUE);
820
 
                g_warning ("reply for user icon path returned invalid response '%s'", string);
821
 
                g_free (string);
822
 
 
823
 
                pixbuf = NULL;
824
 
        } else {
825
 
                pixbuf = gdk_pixbuf_new_from_file_at_size (icon_file,
826
 
                                                           64,
827
 
                                                           64,
828
 
                                                           &error);
829
 
        }
830
 
        g_variant_unref (icon_file_variant);
831
 
        g_variant_unref (get_icon_file_reply);
832
 
 
833
 
        if (error != NULL) {
834
 
                g_warning ("Couldn't load user icon: %s", error->message);
835
 
                g_error_free (error);
836
 
                return NULL;
837
 
        }
838
 
 
839
 
        return pixbuf;
840
 
}
841
 
 
842
 
static gboolean
843
 
set_face_image (GSLockPlug *plug)
844
 
{
845
 
        GdkPixbuf    *pixbuf;
846
 
 
847
 
        pixbuf = get_pixbuf_of_user_icon (plug);
848
 
 
849
 
        if (pixbuf == NULL) {
850
 
                return FALSE;
851
 
        }
852
 
 
853
 
        image_set_from_pixbuf (GTK_IMAGE (plug->priv->auth_face_image), pixbuf);
854
 
 
855
 
        g_object_unref (pixbuf);
856
 
 
857
 
        return TRUE;
858
 
}
859
 
 
860
 
static void
861
 
gs_lock_plug_show (GtkWidget *widget)
862
 
{
863
 
        GSLockPlug *plug = GS_LOCK_PLUG (widget);
864
 
 
865
 
        gs_profile_start (NULL);
866
 
 
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);
870
 
        }
871
 
 
872
 
        gs_profile_end ("parent");
873
 
 
874
 
 
875
 
        if (plug->priv->auth_face_image) {
876
 
                set_face_image (plug);
877
 
        }
878
 
 
879
 
        kbd_lock_mode_update (plug, get_kbd_lock_mode ());
880
 
 
881
 
        restart_cancel_timeout (plug);
882
 
 
883
 
        gs_profile_end (NULL);
884
 
}
885
 
 
886
 
static void
887
 
gs_lock_plug_hide (GtkWidget *widget)
888
 
{
889
 
        if (GTK_WIDGET_CLASS (gs_lock_plug_parent_class)->hide) {
890
 
                GTK_WIDGET_CLASS (gs_lock_plug_parent_class)->hide (widget);
891
 
        }
892
 
}
893
 
 
894
 
static void
895
 
queue_key_event (GSLockPlug  *plug,
896
 
                 GdkEventKey *event)
897
 
{
898
 
        GdkEvent *saved_event;
899
 
 
900
 
        saved_event = gdk_event_copy ((GdkEvent *)event);
901
 
        plug->priv->key_events = g_list_prepend (plug->priv->key_events,
902
 
                                                 saved_event);
903
 
}
904
 
 
905
 
static void
906
 
forward_key_events (GSLockPlug *plug)
907
 
{
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;
911
 
 
912
 
                gtk_window_propagate_key_event (GTK_WINDOW (plug), event);
913
 
 
914
 
                gdk_event_free ((GdkEvent *)event);
915
 
 
916
 
                plug->priv->key_events = g_list_delete_link (plug->priv->key_events,
917
 
                                                             plug->priv->key_events);
918
 
        }
919
 
}
920
 
 
921
 
static void
922
 
gs_lock_plug_set_logout_enabled (GSLockPlug *plug,
923
 
                                 gboolean    logout_enabled)
924
 
{
925
 
        g_return_if_fail (GS_LOCK_PLUG (plug));
926
 
 
927
 
        if (plug->priv->logout_enabled == logout_enabled) {
928
 
                return;
929
 
        }
930
 
 
931
 
        plug->priv->logout_enabled = logout_enabled;
932
 
        g_object_notify (G_OBJECT (plug), "logout-enabled");
933
 
 
934
 
        if (plug->priv->auth_logout_button == NULL) {
935
 
                return;
936
 
        }
937
 
 
938
 
        if (logout_enabled) {
939
 
                gtk_widget_show (plug->priv->auth_logout_button);
940
 
        } else {
941
 
                gtk_widget_hide (plug->priv->auth_logout_button);
942
 
        }
943
 
}
944
 
 
945
 
static void
946
 
gs_lock_plug_set_logout_command (GSLockPlug *plug,
947
 
                                 const char *command)
948
 
{
949
 
        g_return_if_fail (GS_LOCK_PLUG (plug));
950
 
 
951
 
        g_free (plug->priv->logout_command);
952
 
 
953
 
        if (command) {
954
 
                plug->priv->logout_command = g_strdup (command);
955
 
        } else {
956
 
                plug->priv->logout_command = NULL;
957
 
        }
958
 
}
959
 
 
960
 
static gboolean
961
 
is_program_in_path (const char *program)
962
 
{
963
 
        char *tmp = g_find_program_in_path (program);
964
 
        if (tmp != NULL) {
965
 
                g_free (tmp);
966
 
                return TRUE;
967
 
        } else {
968
 
                return FALSE;
969
 
        }
970
 
}
971
 
 
972
 
static void
973
 
gs_lock_plug_set_status_message (GSLockPlug *plug,
974
 
                                 const char *status_message)
975
 
{
976
 
        g_return_if_fail (GS_LOCK_PLUG (plug));
977
 
 
978
 
        g_free (plug->priv->status_message);
979
 
        plug->priv->status_message = g_strdup (status_message);
980
 
 
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);
986
 
                }
987
 
                else {
988
 
                        gtk_widget_hide (plug->priv->status_message_label);
989
 
                }
990
 
        }
991
 
}
992
 
 
993
 
static void
994
 
gs_lock_plug_get_property (GObject    *object,
995
 
                           guint       prop_id,
996
 
                           GValue     *value,
997
 
                           GParamSpec *pspec)
998
 
{
999
 
        GSLockPlug *self;
1000
 
 
1001
 
        self = GS_LOCK_PLUG (object);
1002
 
 
1003
 
        switch (prop_id) {
1004
 
        case PROP_LOGOUT_ENABLED:
1005
 
                g_value_set_boolean (value, self->priv->logout_enabled);
1006
 
                break;
1007
 
        case PROP_LOGOUT_COMMAND:
1008
 
                g_value_set_string (value, self->priv->logout_command);
1009
 
                break;
1010
 
        case PROP_SWITCH_ENABLED:
1011
 
                g_value_set_boolean (value, self->priv->switch_enabled);
1012
 
                break;
1013
 
        case PROP_STATUS_MESSAGE:
1014
 
                g_value_set_string (value, self->priv->status_message);
1015
 
                break;
1016
 
        default:
1017
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1018
 
                break;
1019
 
        }
1020
 
}
1021
 
 
1022
 
static void
1023
 
gs_lock_plug_set_switch_enabled (GSLockPlug *plug,
1024
 
                                 gboolean    switch_enabled)
1025
 
{
1026
 
        g_return_if_fail (GS_LOCK_PLUG (plug));
1027
 
 
1028
 
        if (plug->priv->switch_enabled == switch_enabled) {
1029
 
                return;
1030
 
        }
1031
 
 
1032
 
        plug->priv->switch_enabled = switch_enabled;
1033
 
        g_object_notify (G_OBJECT (plug), "switch-enabled");
1034
 
 
1035
 
        if (plug->priv->auth_switch_button == NULL) {
1036
 
                return;
1037
 
        }
1038
 
 
1039
 
        if (switch_enabled) {
1040
 
                gboolean found;
1041
 
                found = is_program_in_path (GDM_FLEXISERVER_COMMAND);
1042
 
                if (found) {
1043
 
                        gtk_widget_show (plug->priv->auth_switch_button);
1044
 
                } else {
1045
 
                        gs_debug ("Waring: GDM flexiserver command not found: %s", GDM_FLEXISERVER_COMMAND);
1046
 
                        gtk_widget_hide (plug->priv->auth_switch_button);
1047
 
                }
1048
 
        } else {
1049
 
                gtk_widget_hide (plug->priv->auth_switch_button);
1050
 
        }
1051
 
}
1052
 
 
1053
 
static void
1054
 
gs_lock_plug_set_property (GObject            *object,
1055
 
                           guint               prop_id,
1056
 
                           const GValue       *value,
1057
 
                           GParamSpec         *pspec)
1058
 
{
1059
 
        GSLockPlug *self;
1060
 
 
1061
 
        self = GS_LOCK_PLUG (object);
1062
 
 
1063
 
        switch (prop_id) {
1064
 
        case PROP_LOGOUT_ENABLED:
1065
 
                gs_lock_plug_set_logout_enabled (self, g_value_get_boolean (value));
1066
 
                break;
1067
 
        case PROP_LOGOUT_COMMAND:
1068
 
                gs_lock_plug_set_logout_command (self, g_value_get_string (value));
1069
 
                break;
1070
 
        case PROP_STATUS_MESSAGE:
1071
 
                gs_lock_plug_set_status_message (self, g_value_get_string (value));
1072
 
                break;
1073
 
        case PROP_SWITCH_ENABLED:
1074
 
                gs_lock_plug_set_switch_enabled (self, g_value_get_boolean (value));
1075
 
                break;
1076
 
        default:
1077
 
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1078
 
                break;
1079
 
        }
1080
 
}
1081
 
 
1082
 
static void
1083
 
gs_lock_plug_close (GSLockPlug *plug)
1084
 
{
1085
 
        /* Synthesize delete_event to close dialog. */
1086
 
 
1087
 
        GtkWidget *widget = GTK_WIDGET (plug);
1088
 
        GdkEvent  *event;
1089
 
 
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;
1093
 
 
1094
 
        gtk_main_do_event (event);
1095
 
        gdk_event_free (event);
1096
 
}
1097
 
 
1098
 
static void
1099
 
gs_lock_plug_class_init (GSLockPlugClass *klass)
1100
 
{
1101
 
        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
1102
 
        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
1103
 
        GtkBindingSet  *binding_set;
1104
 
 
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;
1108
 
 
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;
1112
 
 
1113
 
        klass->close = gs_lock_plug_close;
1114
 
 
1115
 
        g_type_class_add_private (klass, sizeof (GSLockPlugPrivate));
1116
 
 
1117
 
        lock_plug_signals [RESPONSE] = g_signal_new ("response",
1118
 
                                                     G_OBJECT_CLASS_TYPE (klass),
1119
 
                                                     G_SIGNAL_RUN_LAST,
1120
 
                                                     G_STRUCT_OFFSET (GSLockPlugClass, response),
1121
 
                                                     NULL, NULL,
1122
 
                                                     g_cclosure_marshal_VOID__INT,
1123
 
                                                     G_TYPE_NONE, 1,
1124
 
                                                     G_TYPE_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),
1129
 
                                                  NULL, NULL,
1130
 
                                                  g_cclosure_marshal_VOID__VOID,
1131
 
                                                  G_TYPE_NONE, 0);
1132
 
 
1133
 
        g_object_class_install_property (object_class,
1134
 
                                         PROP_LOGOUT_ENABLED,
1135
 
                                         g_param_spec_boolean ("logout-enabled",
1136
 
                                                               NULL,
1137
 
                                                               NULL,
1138
 
                                                               FALSE,
1139
 
                                                               G_PARAM_READWRITE));
1140
 
        g_object_class_install_property (object_class,
1141
 
                                         PROP_LOGOUT_COMMAND,
1142
 
                                         g_param_spec_string ("logout-command",
1143
 
                                                              NULL,
1144
 
                                                              NULL,
1145
 
                                                              NULL,
1146
 
                                                              G_PARAM_READWRITE));
1147
 
        g_object_class_install_property (object_class,
1148
 
                                         PROP_STATUS_MESSAGE,
1149
 
                                         g_param_spec_string ("status-message",
1150
 
                                                              NULL,
1151
 
                                                              NULL,
1152
 
                                                              NULL,
1153
 
                                                              G_PARAM_READWRITE));
1154
 
        g_object_class_install_property (object_class,
1155
 
                                         PROP_SWITCH_ENABLED,
1156
 
                                         g_param_spec_boolean ("switch-enabled",
1157
 
                                                               NULL,
1158
 
                                                               NULL,
1159
 
                                                               FALSE,
1160
 
                                                               G_PARAM_READWRITE));
1161
 
 
1162
 
        binding_set = gtk_binding_set_by_class (klass);
1163
 
 
1164
 
        gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0,
1165
 
                                      "close", 0);
1166
 
}
1167
 
 
1168
 
static void
1169
 
clear_clipboards (GSLockPlug *plug)
1170
 
{
1171
 
        GtkClipboard *clipboard;
1172
 
 
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);
1179
 
}
1180
 
 
1181
 
static void
1182
 
logout_button_clicked (GtkButton  *button,
1183
 
                       GSLockPlug *plug)
1184
 
{
1185
 
        char   **argv  = NULL;
1186
 
        GError  *error = NULL;
1187
 
        gboolean res;
1188
 
 
1189
 
        if (! plug->priv->logout_command) {
1190
 
                return;
1191
 
        }
1192
 
 
1193
 
        res = g_shell_parse_argv (plug->priv->logout_command, NULL, &argv, &error);
1194
 
 
1195
 
        if (! res) {
1196
 
                g_warning ("Could not parse logout command: %s", error->message);
1197
 
                g_error_free (error);
1198
 
                return;
1199
 
        }
1200
 
 
1201
 
        g_spawn_async (g_get_home_dir (),
1202
 
                       argv,
1203
 
                       NULL,
1204
 
                       G_SPAWN_SEARCH_PATH,
1205
 
                       NULL,
1206
 
                       NULL,
1207
 
                       NULL,
1208
 
                       &error);
1209
 
 
1210
 
        g_strfreev (argv);
1211
 
 
1212
 
        if (error) {
1213
 
                g_warning ("Could not run logout command: %s", error->message);
1214
 
                g_error_free (error);
1215
 
        }
1216
 
}
1217
 
 
1218
 
void
1219
 
gs_lock_plug_set_busy (GSLockPlug *plug)
1220
 
{
1221
 
        GdkCursor *cursor;
1222
 
        GtkWidget *top_level;
1223
 
 
1224
 
        top_level = gtk_widget_get_toplevel (GTK_WIDGET (plug));
1225
 
 
1226
 
        cursor = gdk_cursor_new (GDK_WATCH);
1227
 
        gdk_window_set_cursor (gtk_widget_get_window (top_level), cursor);
1228
 
        gdk_cursor_unref (cursor);
1229
 
}
1230
 
 
1231
 
void
1232
 
gs_lock_plug_set_ready (GSLockPlug *plug)
1233
 
{
1234
 
        GdkCursor *cursor;
1235
 
        GtkWidget *top_level;
1236
 
 
1237
 
        top_level = gtk_widget_get_toplevel (GTK_WIDGET (plug));
1238
 
 
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);
1242
 
}
1243
 
 
1244
 
void
1245
 
gs_lock_plug_enable_prompt (GSLockPlug *plug,
1246
 
                            const char *message,
1247
 
                            gboolean    visible)
1248
 
{
1249
 
        char *markup;
1250
 
 
1251
 
        g_return_if_fail (GS_IS_LOCK_PLUG (plug));
1252
 
 
1253
 
        gs_debug ("Setting prompt to: %s", message);
1254
 
 
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);
1258
 
 
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);
1263
 
        } else {
1264
 
                markup = g_strdup_printf ("<b><big>%s</big></b>", message);
1265
 
        }
1266
 
 
1267
 
        gtk_label_set_markup (GTK_LABEL (plug->priv->auth_prompt_label), markup);
1268
 
        g_free (markup);
1269
 
 
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);
1274
 
 
1275
 
        if (!gtk_widget_has_focus (plug->priv->auth_prompt_entry)) {
1276
 
                gtk_widget_grab_focus (plug->priv->auth_prompt_entry);
1277
 
        }
1278
 
 
1279
 
        /* were there any key events sent to the plug while the
1280
 
         * entry wasnt ready? If so, forward them along
1281
 
         */
1282
 
        forward_key_events (plug);
1283
 
 
1284
 
        restart_cancel_timeout (plug);
1285
 
}
1286
 
 
1287
 
void
1288
 
gs_lock_plug_disable_prompt (GSLockPlug *plug)
1289
 
{
1290
 
        g_return_if_fail (GS_IS_LOCK_PLUG (plug));
1291
 
 
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); */
1297
 
}
1298
 
 
1299
 
void
1300
 
gs_lock_plug_show_message (GSLockPlug *plug,
1301
 
                           const char *message)
1302
 
{
1303
 
        g_return_if_fail (GS_IS_LOCK_PLUG (plug));
1304
 
 
1305
 
        set_status_text (plug, message ? message : "");
1306
 
}
1307
 
 
1308
 
/* button press handler used to inhibit popup menu */
1309
 
static gint
1310
 
entry_button_press (GtkWidget      *widget,
1311
 
                    GdkEventButton *event)
1312
 
{
1313
 
        if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
1314
 
                return TRUE;
1315
 
        }
1316
 
 
1317
 
        return FALSE;
1318
 
}
1319
 
 
1320
 
static gint
1321
 
entry_key_press (GtkWidget   *widget,
1322
 
                 GdkEventKey *event,
1323
 
                 GSLockPlug  *plug)
1324
 
{
1325
 
        restart_cancel_timeout (plug);
1326
 
 
1327
 
        /* if the input widget is visible and ready for input
1328
 
         * then just carry on as usual
1329
 
         */
1330
 
        if (gtk_widget_get_visible (plug->priv->auth_prompt_entry) &&
1331
 
            gtk_widget_get_sensitive (plug->priv->auth_prompt_entry)) {
1332
 
                return FALSE;
1333
 
        }
1334
 
 
1335
 
        if (strcmp (event->string, "") == 0) {
1336
 
                return FALSE;
1337
 
        }
1338
 
 
1339
 
        queue_key_event (plug, event);
1340
 
 
1341
 
        return TRUE;
1342
 
}
1343
 
 
1344
 
/* adapted from gtk_dialog_add_button */
1345
 
static GtkWidget *
1346
 
gs_lock_plug_add_button (GSLockPlug  *plug,
1347
 
                         GtkWidget   *action_area,
1348
 
                         const gchar *button_text)
1349
 
{
1350
 
        GtkWidget *button;
1351
 
 
1352
 
        g_return_val_if_fail (GS_IS_LOCK_PLUG (plug), NULL);
1353
 
        g_return_val_if_fail (button_text != NULL, NULL);
1354
 
 
1355
 
        button = gtk_button_new_from_stock (button_text);
1356
 
 
1357
 
        gtk_widget_set_can_default (button, TRUE);
1358
 
 
1359
 
        gtk_widget_show (button);
1360
 
 
1361
 
        gtk_box_pack_end (GTK_BOX (action_area),
1362
 
                          button,
1363
 
                          FALSE, TRUE, 0);
1364
 
 
1365
 
        return button;
1366
 
}
1367
 
 
1368
 
static void
1369
 
create_page_one_buttons (GSLockPlug *plug)
1370
 
{
1371
 
 
1372
 
        gs_profile_start ("page one buttons");
1373
 
 
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,
1379
 
                                            TRUE);
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);
1382
 
 
1383
 
        plug->priv->auth_logout_button =  gs_lock_plug_add_button (GS_LOCK_PLUG (plug),
1384
 
                                                                   plug->priv->auth_action_area,
1385
 
                                                                   _("Log _Out"));
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);
1388
 
 
1389
 
 
1390
 
        plug->priv->auth_unlock_button =  gs_lock_plug_add_button (GS_LOCK_PLUG (plug),
1391
 
                                                                   plug->priv->auth_action_area,
1392
 
                                                                   _("_Unlock"));
1393
 
        gtk_button_set_focus_on_click (GTK_BUTTON (plug->priv->auth_unlock_button), FALSE);
1394
 
 
1395
 
        gtk_window_set_default (GTK_WINDOW (plug), plug->priv->auth_unlock_button);
1396
 
 
1397
 
        gs_profile_end ("page one buttons");
1398
 
}
1399
 
 
1400
 
static char *
1401
 
get_user_display_name (void)
1402
 
{
1403
 
        const char *name;
1404
 
        char       *utf8_name;
1405
 
 
1406
 
        name = g_get_real_name ();
1407
 
 
1408
 
        if (name == NULL || strcmp (name, "Unknown") == 0) {
1409
 
                name = g_get_user_name ();
1410
 
        }
1411
 
 
1412
 
        utf8_name = NULL;
1413
 
 
1414
 
        if (name != NULL) {
1415
 
                utf8_name = g_locale_to_utf8 (name, -1, NULL, NULL, NULL);
1416
 
        }
1417
 
 
1418
 
        return utf8_name;
1419
 
}
1420
 
 
1421
 
static void
1422
 
update_realname_label (GSLockPlug *plug)
1423
 
{
1424
 
        char *name;
1425
 
        char *markup;
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);
1429
 
        g_free (markup);
1430
 
        g_free (name);
1431
 
}
1432
 
 
1433
 
static void
1434
 
create_page_one (GSLockPlug *plug)
1435
 
{
1436
 
        GtkWidget            *align;
1437
 
        GtkWidget            *vbox;
1438
 
        GtkWidget            *vbox2;
1439
 
        GtkWidget            *hbox;
1440
 
 
1441
 
        gs_profile_start ("page one");
1442
 
 
1443
 
        align = gtk_alignment_new (0.5, 0.5, 1, 1);
1444
 
        gtk_notebook_append_page (GTK_NOTEBOOK (plug->priv->notebook), align, NULL);
1445
 
 
1446
 
        vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
1447
 
        gtk_container_add (GTK_CONTAINER (align), vbox);
1448
 
 
1449
 
        hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1450
 
        gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1451
 
 
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);
1455
 
 
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);
1459
 
 
1460
 
#ifdef WITH_KBD_LAYOUT_INDICATOR
1461
 
        gtk_box_pack_start (GTK_BOX (hbox), plug->priv->auth_prompt_kbd_layout_indicator, FALSE, FALSE, 0);
1462
 
#endif
1463
 
 
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);
1473
 
 
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);
1477
 
 
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);
1480
 
 
1481
 
                gtk_label_set_mnemonic_widget (GTK_LABEL (plug->priv->auth_prompt_label),
1482
 
                                               plug->priv->auth_prompt_entry);
1483
 
 
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);
1487
 
 
1488
 
                /* Status text */
1489
 
 
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,
1493
 
                                    FALSE, FALSE, 0);
1494
 
 
1495
 
        } else {
1496
 
 
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);
1500
 
 
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);
1503
 
 
1504
 
                gtk_label_set_mnemonic_widget (GTK_LABEL (plug->priv->auth_prompt_label),
1505
 
                                           plug->priv->auth_prompt_entry);
1506
 
 
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);
1510
 
 
1511
 
                /* Status text */
1512
 
 
1513
 
                plug->priv->auth_message_label = gtk_label_new (NULL);
1514
 
                gtk_box_pack_start (GTK_BOX (vbox), plug->priv->auth_message_label,
1515
 
                                    FALSE, FALSE, 0);
1516
 
        }
1517
 
        /* Buttons */
1518
 
        plug->priv->auth_action_area = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
1519
 
 
1520
 
        gtk_button_box_set_layout (GTK_BUTTON_BOX (plug->priv->auth_action_area),
1521
 
                                   GTK_BUTTONBOX_END);
1522
 
 
1523
 
        gtk_box_pack_end (GTK_BOX (vbox), plug->priv->auth_action_area,
1524
 
                          FALSE, TRUE, 0);
1525
 
        gtk_widget_show (plug->priv->auth_action_area);
1526
 
 
1527
 
        create_page_one_buttons (plug);
1528
 
 
1529
 
        gs_profile_end ("page one");
1530
 
}
1531
 
 
1532
 
static void
1533
 
unlock_button_clicked (GtkButton  *button,
1534
 
                       GSLockPlug *plug)
1535
 
{
1536
 
        gs_lock_plug_response (plug, GS_LOCK_PLUG_RESPONSE_OK);
1537
 
}
1538
 
 
1539
 
static void
1540
 
switch_user_button_clicked (GtkButton  *button,
1541
 
                            GSLockPlug *plug)
1542
 
{
1543
 
 
1544
 
        remove_response_idle (plug);
1545
 
 
1546
 
        gs_lock_plug_set_sensitive (plug, FALSE);
1547
 
 
1548
 
        plug->priv->response_idle_id = g_timeout_add (2000,
1549
 
                                                      (GSourceFunc)response_cancel_idle_cb,
1550
 
                                                      plug);
1551
 
 
1552
 
        gs_lock_plug_set_busy (plug);
1553
 
        do_user_switch (plug);
1554
 
}
1555
 
 
1556
 
static int
1557
 
delete_handler (GSLockPlug  *plug,
1558
 
                GdkEventAny *event,
1559
 
                gpointer     data)
1560
 
{
1561
 
        gs_lock_plug_response (plug, GS_LOCK_PLUG_RESPONSE_CANCEL);
1562
 
 
1563
 
        return TRUE; /* Do not destroy */
1564
 
}
1565
 
 
1566
 
static void
1567
 
gs_lock_plug_init (GSLockPlug *plug)
1568
 
{
1569
 
        gs_profile_start (NULL);
1570
 
 
1571
 
        plug->priv = GS_LOCK_PLUG_GET_PRIVATE (plug);
1572
 
 
1573
 
        clear_clipboards (plug);
1574
 
 
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);
1578
 
 
1579
 
        plug->priv->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1580
 
        gtk_container_add (GTK_CONTAINER (plug->priv->frame), plug->priv->vbox);
1581
 
 
1582
 
        plug->priv->auth_prompt_kbd_layout_indicator = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1583
 
 
1584
 
        /* Notebook */
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);
1589
 
 
1590
 
        /* Page 1 */
1591
 
 
1592
 
        create_page_one (plug);
1593
 
 
1594
 
        gtk_widget_show_all (plug->priv->frame);
1595
 
 
1596
 
        /* Layout indicator */
1597
 
#ifdef WITH_KBD_LAYOUT_INDICATOR
1598
 
        if (plug->priv->auth_prompt_kbd_layout_indicator != NULL) {
1599
 
                XklEngine *engine;
1600
 
 
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;
1604
 
 
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),
1608
 
                                            layout_indicator,
1609
 
                                            FALSE,
1610
 
                                            FALSE,
1611
 
                                            6);
1612
 
 
1613
 
                        gtk_widget_show_all (layout_indicator);
1614
 
                        gtk_widget_show (plug->priv->auth_prompt_kbd_layout_indicator);
1615
 
                } else {
1616
 
                        gtk_widget_hide (plug->priv->auth_prompt_kbd_layout_indicator);
1617
 
                }
1618
 
 
1619
 
                g_object_unref (engine);
1620
 
        }
1621
 
#endif
1622
 
 
1623
 
        if (plug->priv->auth_switch_button != NULL) {
1624
 
                if (plug->priv->switch_enabled) {
1625
 
                        gtk_widget_show_all (plug->priv->auth_switch_button);
1626
 
                } else {
1627
 
                        gtk_widget_hide (plug->priv->auth_switch_button);
1628
 
                }
1629
 
        }
1630
 
 
1631
 
        gtk_widget_grab_default (plug->priv->auth_unlock_button);
1632
 
 
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);
1636
 
                }
1637
 
        }
1638
 
 
1639
 
        plug->priv->timeout = DIALOG_TIMEOUT_MSEC;
1640
 
 
1641
 
        g_signal_connect (plug, "key_press_event",
1642
 
                          G_CALLBACK (entry_key_press), plug);
1643
 
 
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);
1649
 
 
1650
 
        g_signal_connect (plug->priv->auth_unlock_button, "clicked",
1651
 
                          G_CALLBACK (unlock_button_clicked), plug);
1652
 
 
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);
1657
 
                }
1658
 
                else {
1659
 
                        gtk_widget_hide (plug->priv->status_message_label);
1660
 
                }
1661
 
        }
1662
 
 
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);
1666
 
        }
1667
 
 
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);
1671
 
        }
1672
 
 
1673
 
        g_signal_connect (plug, "delete_event", G_CALLBACK (delete_handler), NULL);
1674
 
 
1675
 
        gtk_widget_set_size_request (GTK_WIDGET (plug), 450, -1);
1676
 
 
1677
 
        gs_profile_end (NULL);
1678
 
}
1679
 
 
1680
 
static void
1681
 
gs_lock_plug_finalize (GObject *object)
1682
 
{
1683
 
        GSLockPlug *plug;
1684
 
 
1685
 
        g_return_if_fail (object != NULL);
1686
 
        g_return_if_fail (GS_IS_LOCK_PLUG (object));
1687
 
 
1688
 
        plug = GS_LOCK_PLUG (object);
1689
 
 
1690
 
        g_return_if_fail (plug->priv != NULL);
1691
 
 
1692
 
        g_free (plug->priv->logout_command);
1693
 
 
1694
 
        remove_response_idle (plug);
1695
 
        remove_cancel_timeout (plug);
1696
 
 
1697
 
        G_OBJECT_CLASS (gs_lock_plug_parent_class)->finalize (object);
1698
 
}
1699
 
 
1700
 
GtkWidget *
1701
 
gs_lock_plug_new (void)
1702
 
{
1703
 
        GtkWidget *result;
1704
 
 
1705
 
        result = g_object_new (GS_TYPE_LOCK_PLUG, NULL);
1706
 
 
1707
 
        gtk_window_set_focus_on_map (GTK_WINDOW (result), TRUE);
1708
 
 
1709
 
        return result;
1710
 
}