~ubuntu-branches/ubuntu/dapper/gnome-screensaver/dapper

« back to all changes in this revision

Viewing changes to src/gs-window-x11.c

  • Committer: Bazaar Package Importer
  • Author(s): Oliver Grawert
  • Date: 2005-10-10 00:18:18 UTC
  • Revision ID: james.westby@ubuntu.com-20051010001818-3mujs05r8rht7xi1
Tags: upstream-0.0.15
ImportĀ upstreamĀ versionĀ 0.0.15

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-2005 William Jon McCann <mccann@jhu.edu>
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
18
 *
 
19
 * Authors: William Jon McCann <mccann@jhu.edu>
 
20
 *
 
21
 */
 
22
 
 
23
#include "config.h"
 
24
 
 
25
#include <sys/types.h>
 
26
#include <errno.h>
 
27
#include <sys/wait.h>
 
28
#include <string.h>
 
29
 
 
30
#include <gdk/gdkx.h>
 
31
#include <gdk/gdkkeysyms.h>
 
32
#include <gtk/gtk.h>
 
33
 
 
34
#include "gs-window.h"
 
35
#include "subprocs.h"
 
36
 
 
37
static void gs_window_class_init (GSWindowClass *klass);
 
38
static void gs_window_init       (GSWindow      *window);
 
39
static void gs_window_finalize   (GObject       *object);
 
40
 
 
41
enum {
 
42
        DIALOG_RESPONSE_CANCEL,
 
43
        DIALOG_RESPONSE_OK
 
44
};
 
45
 
 
46
#define GS_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_WINDOW, GSWindowPrivate))
 
47
 
 
48
struct GSWindowPrivate
 
49
{
 
50
        int        monitor;
 
51
 
 
52
        GdkRectangle geometry;
 
53
 
 
54
        guint      lock_enabled : 1;
 
55
        guint      logout_enabled : 1;
 
56
        guint      user_switch_enabled : 1;
 
57
        guint64    logout_timeout;
 
58
 
 
59
        GtkWidget *box;
 
60
        GtkWidget *socket;
 
61
 
 
62
        guint      request_unlock_idle_id;
 
63
        guint      popup_dialog_idle_id;
 
64
 
 
65
        guint      dialog_map_signal_id;
 
66
        guint      dialog_unmap_signal_id;
 
67
        guint      dialog_response_signal_id;
 
68
 
 
69
        gint       pid;
 
70
        gint       watch_id;
 
71
        gint       dialog_response;
 
72
 
 
73
        GList     *key_events;
 
74
 
 
75
        GTimer    *timer;
 
76
};
 
77
 
 
78
enum {
 
79
        UNBLANKED,
 
80
        DIALOG_UP,
 
81
        DIALOG_DOWN,
 
82
        LAST_SIGNAL
 
83
};
 
84
 
 
85
enum {
 
86
        PROP_0,
 
87
        PROP_LOCK_ENABLED,
 
88
        PROP_LOGOUT_ENABLED,
 
89
        PROP_LOGOUT_TIMEOUT,
 
90
        PROP_MONITOR
 
91
};
 
92
 
 
93
static GObjectClass   *parent_class = NULL;
 
94
static guint           signals [LAST_SIGNAL] = { 0, };
 
95
 
 
96
G_DEFINE_TYPE (GSWindow, gs_window, GTK_TYPE_WINDOW);
 
97
 
 
98
static void
 
99
set_invisible_cursor (GdkWindow *window,
 
100
                      gboolean   invisible)
 
101
{
 
102
        GdkBitmap *empty_bitmap;
 
103
        GdkCursor *cursor = NULL;
 
104
        GdkColor   useless;
 
105
        char       invisible_cursor_bits [] = { 0x0 };
 
106
 
 
107
        if (invisible) {
 
108
                useless.red = useless.green = useless.blue = 0;
 
109
                useless.pixel = 0;
 
110
 
 
111
                empty_bitmap = gdk_bitmap_create_from_data (window,
 
112
                                                            invisible_cursor_bits,
 
113
                                                            1, 1);
 
114
 
 
115
                cursor = gdk_cursor_new_from_pixmap (empty_bitmap,
 
116
                                                     empty_bitmap,
 
117
                                                     &useless,
 
118
                                                     &useless, 0, 0);
 
119
 
 
120
                g_object_unref (empty_bitmap);
 
121
        }
 
122
 
 
123
        gdk_window_set_cursor (window, cursor);
 
124
 
 
125
        if (cursor)
 
126
                gdk_cursor_unref (cursor);
 
127
}
 
128
 
 
129
/* derived from tomboy */
 
130
static void
 
131
gs_window_override_user_time (GSWindow *window)
 
132
{
 
133
        guint32 ev_time = gtk_get_current_event_time ();
 
134
 
 
135
        if (ev_time == 0) {
 
136
                gint ev_mask = gtk_widget_get_events (GTK_WIDGET (window));
 
137
                if (!(ev_mask & GDK_PROPERTY_CHANGE_MASK)) {
 
138
                        gtk_widget_add_events (GTK_WIDGET (window),
 
139
                                               GDK_PROPERTY_CHANGE_MASK);
 
140
                }
 
141
 
 
142
                /* 
 
143
                 * NOTE: Last resort for D-BUS or other non-interactive
 
144
                 *       openings.  Causes roundtrip to server.  Lame. 
 
145
                 */
 
146
                ev_time = gdk_x11_get_server_time (GTK_WIDGET (window)->window);
 
147
        }
 
148
 
 
149
        gdk_x11_window_set_user_time (GTK_WIDGET (window)->window, ev_time);
 
150
}
 
151
 
 
152
void
 
153
gs_window_clear (GSWindow *window)
 
154
{
 
155
        GdkColor     color = { 0, 0, 0 };
 
156
        GdkColormap *colormap;
 
157
 
 
158
        gtk_widget_modify_bg (GTK_WIDGET (window), GTK_STATE_NORMAL, &color);
 
159
        colormap = gdk_drawable_get_colormap (GTK_WIDGET (window)->window);
 
160
        gdk_colormap_alloc_color (colormap, &color, FALSE, TRUE);
 
161
        gdk_window_set_background (GTK_WIDGET (window)->window, &color);
 
162
        gdk_window_clear (GTK_WIDGET (window)->window);
 
163
        gdk_flush ();
 
164
}
 
165
 
 
166
static void
 
167
update_geometry (GSWindow *window)
 
168
{
 
169
        GdkRectangle geometry;
 
170
 
 
171
        gdk_screen_get_monitor_geometry (GTK_WINDOW (window)->screen,
 
172
                                         window->priv->monitor,
 
173
                                         &geometry);
 
174
 
 
175
        window->priv->geometry.x = geometry.x;
 
176
        window->priv->geometry.y = geometry.y;
 
177
        window->priv->geometry.width = geometry.width;
 
178
        window->priv->geometry.height = geometry.height;
 
179
}
 
180
 
 
181
static void
 
182
screen_size_changed (GdkScreen *screen,
 
183
                     GSWindow  *window)
 
184
{
 
185
        gtk_widget_queue_resize (GTK_WIDGET (window));
 
186
}
 
187
 
 
188
/* copied from panel-toplevel.c */
 
189
static void
 
190
gs_window_move_resize_window (GSWindow *window,
 
191
                              gboolean  move,
 
192
                              gboolean  resize)
 
193
{
 
194
        GtkWidget *widget;
 
195
 
 
196
        widget = GTK_WIDGET (window);
 
197
 
 
198
        g_assert (GTK_WIDGET_REALIZED (widget));
 
199
 
 
200
        if (move && resize)
 
201
                gdk_window_move_resize (widget->window,
 
202
                                        window->priv->geometry.x,
 
203
                                        window->priv->geometry.y,
 
204
                                        window->priv->geometry.width,
 
205
                                        window->priv->geometry.height);
 
206
        else if (move)
 
207
                gdk_window_move (widget->window,
 
208
                                 window->priv->geometry.x,
 
209
                                 window->priv->geometry.y);
 
210
        else if (resize)
 
211
                gdk_window_resize (widget->window,
 
212
                                   window->priv->geometry.width,
 
213
                                   window->priv->geometry.height);
 
214
}
 
215
 
 
216
static void
 
217
gs_window_real_realize (GtkWidget *widget)
 
218
{
 
219
        if (GTK_WIDGET_CLASS (parent_class)->realize)
 
220
                GTK_WIDGET_CLASS (parent_class)->realize (widget);
 
221
 
 
222
        gs_window_override_user_time (GS_WINDOW (widget));
 
223
        gs_window_clear (GS_WINDOW (widget));
 
224
 
 
225
        gs_window_move_resize_window (GS_WINDOW (widget), TRUE, TRUE);
 
226
 
 
227
        g_signal_connect (gtk_window_get_screen (GTK_WINDOW (widget)),
 
228
                          "size_changed",
 
229
                          G_CALLBACK (screen_size_changed),
 
230
                          widget);
 
231
}
 
232
 
 
233
static void
 
234
gs_window_real_show (GtkWidget *widget)
 
235
{
 
236
        GSWindow *window;
 
237
 
 
238
        if (GTK_WIDGET_CLASS (parent_class)->show)
 
239
                GTK_WIDGET_CLASS (parent_class)->show (widget);
 
240
 
 
241
        set_invisible_cursor (widget->window, TRUE);
 
242
 
 
243
        window = GS_WINDOW (widget);
 
244
        if (window->priv->timer)
 
245
                g_timer_destroy (window->priv->timer);
 
246
        window->priv->timer = g_timer_new ();
 
247
}
 
248
 
 
249
void
 
250
gs_window_show (GSWindow *window)
 
251
{
 
252
        g_return_if_fail (GS_IS_WINDOW (window));
 
253
 
 
254
        gtk_widget_show (GTK_WIDGET (window));
 
255
}
 
256
 
 
257
void
 
258
gs_window_destroy (GSWindow *window)
 
259
{
 
260
        g_return_if_fail (GS_IS_WINDOW (window));
 
261
 
 
262
        gtk_widget_destroy (GTK_WIDGET (window));
 
263
}
 
264
 
 
265
GdkWindow *
 
266
gs_window_get_gdk_window (GSWindow *window)
 
267
{
 
268
        g_return_val_if_fail (GS_IS_WINDOW (window), NULL);
 
269
 
 
270
        return GTK_WIDGET (window)->window;
 
271
}
 
272
 
 
273
static gboolean
 
274
emit_unblanked_idle (GSWindow *window)
 
275
{
 
276
        g_signal_emit (window, signals [UNBLANKED], 0);
 
277
 
 
278
        return FALSE;
 
279
}
 
280
 
 
281
static gboolean
 
282
spawn_on_window (GSWindow *window,
 
283
                 char     *command,
 
284
                 int      *pid,
 
285
                 GIOFunc   watch_func,
 
286
                 gpointer  user_data,
 
287
                 gint     *watch_id)
 
288
{
 
289
        int         argc;
 
290
        char      **argv;
 
291
        char       *str;
 
292
        GPtrArray  *env;
 
293
        gboolean    result;
 
294
        GIOChannel *channel;
 
295
        int         standard_output;
 
296
        int         child_pid;
 
297
        int         id;
 
298
        int         i;
 
299
 
 
300
        if (!g_shell_parse_argv (command, &argc, &argv, NULL))
 
301
                return FALSE;
 
302
 
 
303
        env = g_ptr_array_new ();
 
304
 
 
305
        str = gdk_screen_make_display_name (GTK_WINDOW (window)->screen);
 
306
        g_ptr_array_add (env, g_strdup_printf ("DISPLAY=%s", str));
 
307
        g_free (str);
 
308
 
 
309
        g_ptr_array_add (env, g_strdup_printf ("HOME=%s",
 
310
                                               g_get_home_dir ()));
 
311
        if (g_getenv ("PATH"))
 
312
                g_ptr_array_add (env, g_strdup_printf ("PATH=%s",
 
313
                                                       g_getenv ("PATH")));
 
314
        if (g_getenv ("SESSION_MANAGER"))
 
315
                g_ptr_array_add (env, g_strdup_printf ("SESSION_MANAGER=%s",
 
316
                                                       g_getenv ("SESSION_MANAGER")));
 
317
        if (g_getenv ("XAUTHORITY"))
 
318
                g_ptr_array_add (env, g_strdup_printf ("XAUTHORITY=%s",
 
319
                                                       g_getenv ("XAUTHORITY")));
 
320
        if (g_getenv ("XAUTHLOCALHOSTNAME"))
 
321
                g_ptr_array_add (env, g_strdup_printf ("XAUTHLOCALHOSTNAME=%s",
 
322
                                                       g_getenv ("XAUTHLOCALHOSTNAME")));
 
323
        if (g_getenv ("LANG"))
 
324
                g_ptr_array_add (env, g_strdup_printf ("LANG=%s",
 
325
                                                       g_getenv ("LANG")));
 
326
        if (g_getenv ("LANGUAGE"))
 
327
                g_ptr_array_add (env, g_strdup_printf ("LANGUAGE=%s",
 
328
                                                       g_getenv ("LANGUAGE")));
 
329
        g_ptr_array_add (env, NULL);
 
330
 
 
331
        result = gdk_spawn_on_screen_with_pipes (GTK_WINDOW (window)->screen,
 
332
                                                 g_get_home_dir (),
 
333
                                                 argv,
 
334
                                                 (char **)env->pdata,
 
335
                                                 G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
 
336
                                                 NULL,
 
337
                                                 NULL,
 
338
                                                 &child_pid,
 
339
                                                 NULL,
 
340
                                                 &standard_output,
 
341
                                                 NULL,
 
342
                                                 NULL);
 
343
 
 
344
        for (i = 0; i < env->len; i++)
 
345
                g_free (g_ptr_array_index (env, i));
 
346
        g_ptr_array_free (env, TRUE);
 
347
 
 
348
        if (!result)
 
349
                return FALSE;
 
350
 
 
351
        if (pid)
 
352
                *pid = child_pid;
 
353
        else
 
354
                g_spawn_close_pid (child_pid);
 
355
 
 
356
        channel = g_io_channel_unix_new (standard_output);
 
357
        g_io_channel_set_close_on_unref (channel, TRUE);
 
358
        g_io_channel_set_flags (channel,
 
359
                                g_io_channel_get_flags (channel) | G_IO_FLAG_NONBLOCK,
 
360
                                NULL);
 
361
        id = g_io_add_watch (channel,
 
362
                             G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
 
363
                             watch_func,
 
364
                             user_data);
 
365
        if (watch_id)
 
366
                *watch_id = id;
 
367
 
 
368
        g_io_channel_unref (channel);
 
369
 
 
370
        g_strfreev (argv);
 
371
 
 
372
        return result;
 
373
}
 
374
 
 
375
static void
 
376
plug_added (GtkWidget *widget,
 
377
            GSWindow  *window)
 
378
{
 
379
        gtk_widget_show (window->priv->socket);
 
380
}
 
381
 
 
382
static gboolean
 
383
plug_removed (GtkWidget *widget,
 
384
              GSWindow  *window)
 
385
{
 
386
        gtk_widget_hide (window->priv->socket);
 
387
        gtk_container_remove (GTK_CONTAINER (window), GTK_WIDGET (window->priv->box));
 
388
 
 
389
        return TRUE;
 
390
}
 
391
 
 
392
static void
 
393
forward_key_events (GSWindow *window)
 
394
{
 
395
        window->priv->key_events = g_list_reverse (window->priv->key_events);
 
396
 
 
397
        while (window->priv->key_events) {
 
398
                GdkEventKey *event = window->priv->key_events->data;
 
399
 
 
400
                gtk_window_propagate_key_event (GTK_WINDOW (window), event);
 
401
 
 
402
                gdk_event_free ((GdkEvent *)event);
 
403
                window->priv->key_events = g_list_delete_link (window->priv->key_events,
 
404
                                                               window->priv->key_events);
 
405
        }
 
406
}
 
407
 
 
408
static void
 
409
remove_key_events (GSWindow *window)
 
410
{
 
411
        window->priv->key_events = g_list_reverse (window->priv->key_events);
 
412
 
 
413
        while (window->priv->key_events) {
 
414
                GdkEventKey *event = window->priv->key_events->data;
 
415
 
 
416
                gdk_event_free ((GdkEvent *)event);
 
417
                window->priv->key_events = g_list_delete_link (window->priv->key_events,
 
418
                                                               window->priv->key_events);
 
419
        }
 
420
}
 
421
 
 
422
static void
 
423
socket_show (GtkWidget *widget,
 
424
             GSWindow  *window)
 
425
{
 
426
        gtk_widget_child_focus (window->priv->socket, GTK_DIR_TAB_FORWARD);
 
427
 
 
428
        /* send queued events to the dialog */
 
429
        forward_key_events (window);
 
430
}
 
431
 
 
432
static void
 
433
socket_destroyed (GtkWidget *widget,
 
434
                  GSWindow  *window)
 
435
{
 
436
        window->priv->socket = NULL;
 
437
}
 
438
 
 
439
static void
 
440
create_socket (GSWindow *window,
 
441
               guint32   id)
 
442
{
 
443
        window->priv->socket = gtk_socket_new ();
 
444
        window->priv->box = gtk_alignment_new (0.5, 0.5, 0, 0);
 
445
        gtk_widget_show (window->priv->box);
 
446
 
 
447
        gtk_container_add (GTK_CONTAINER (window), window->priv->box);
 
448
 
 
449
        gtk_container_add (GTK_CONTAINER (window->priv->box), window->priv->socket);
 
450
 
 
451
        g_signal_connect (window->priv->socket, "show",
 
452
                          G_CALLBACK (socket_show), window);
 
453
        g_signal_connect (window->priv->socket, "destroy",
 
454
                          G_CALLBACK (socket_destroyed), window);
 
455
        g_signal_connect (window->priv->socket, "plug_added",
 
456
                          G_CALLBACK (plug_added), window);
 
457
        g_signal_connect (window->priv->socket, "plug_removed",
 
458
                          G_CALLBACK (plug_removed), window);
 
459
 
 
460
        gtk_socket_add_id (GTK_SOCKET (window->priv->socket), id);
 
461
}
 
462
 
 
463
/* adapted from gspawn.c */
 
464
static int
 
465
wait_on_child (int pid)
 
466
{
 
467
        int status;
 
468
 
 
469
 wait_again:
 
470
        if (waitpid (pid, &status, 0) < 0) {
 
471
                if (errno == EINTR)
 
472
                        goto wait_again;
 
473
                else if (errno == ECHILD)
 
474
                        ; /* do nothing, child already reaped */
 
475
                else
 
476
                        g_warning ("waitpid () should not fail in 'GSWindow'");
 
477
        }
 
478
 
 
479
        return status;
 
480
}
 
481
 
 
482
static void
 
483
gs_window_dialog_finish (GSWindow *window)
 
484
{
 
485
        g_return_if_fail (GS_IS_WINDOW (window));
 
486
 
 
487
        if (window->priv->pid > 0) {
 
488
                int exit_status;
 
489
                        
 
490
                exit_status = wait_on_child (window->priv->pid);
 
491
        }
 
492
 
 
493
        g_spawn_close_pid (window->priv->pid);
 
494
        window->priv->pid = 0;
 
495
 
 
496
        /* remove events for the case were we failed to show socket */
 
497
        remove_key_events (window);
 
498
}
 
499
 
 
500
static gboolean
 
501
command_watch (GIOChannel   *source,
 
502
               GIOCondition  condition,
 
503
               GSWindow     *window)
 
504
{
 
505
        gboolean finished = FALSE;
 
506
 
 
507
        g_return_val_if_fail (GS_IS_WINDOW (window), FALSE);
 
508
 
 
509
        if (condition & G_IO_IN) {
 
510
                GIOStatus status;
 
511
                GError   *error = NULL;
 
512
                char     *line;
 
513
 
 
514
                status = g_io_channel_read_line (source, &line, NULL, NULL, &error);
 
515
 
 
516
                switch (status) {
 
517
                case G_IO_STATUS_NORMAL:
 
518
                        /*g_message ("LINE: %s", line);*/
 
519
 
 
520
                        if (strstr (line, "WINDOW ID=")) {
 
521
                                guint32 id;
 
522
                                char    c;
 
523
                                if (1 == sscanf (line, " WINDOW ID= 0x%x %c", &id, &c)) {
 
524
                                        create_socket (window, id);
 
525
                                }
 
526
                        } else if (strstr (line, "RESPONSE=")) {
 
527
                                if (strstr (line, "RESPONSE=OK")) {
 
528
                                        window->priv->dialog_response = DIALOG_RESPONSE_OK;
 
529
                                } else {
 
530
                                        window->priv->dialog_response = DIALOG_RESPONSE_CANCEL;
 
531
                                }
 
532
                                finished = TRUE;
 
533
                        }
 
534
 
 
535
                        g_free (line);
 
536
                        break;
 
537
                case G_IO_STATUS_EOF:
 
538
                        finished = TRUE;
 
539
                        break;
 
540
                case G_IO_STATUS_ERROR:
 
541
                        finished = TRUE;
 
542
                        fprintf (stderr, "Error reading fd from child: %s\n", error->message);
 
543
                        return FALSE;
 
544
                case G_IO_STATUS_AGAIN:
 
545
                default:
 
546
                        break;
 
547
                }
 
548
 
 
549
        } else if (condition & G_IO_HUP)
 
550
                finished = TRUE;
 
551
 
 
552
        if (finished) {
 
553
                gs_window_dialog_finish (window);
 
554
 
 
555
                if (window->priv->dialog_response == DIALOG_RESPONSE_OK) {
 
556
                        g_idle_add ((GSourceFunc)emit_unblanked_idle, window);
 
557
                }
 
558
 
 
559
                gs_window_clear (window);
 
560
                set_invisible_cursor (GTK_WIDGET (window)->window, TRUE);
 
561
                g_signal_emit (window, signals [DIALOG_DOWN], 0);
 
562
 
 
563
                window->priv->watch_id = 0;
 
564
                return FALSE;
 
565
        }
 
566
 
 
567
        return TRUE;
 
568
}
 
569
 
 
570
static gboolean
 
571
is_logout_enabled (GSWindow *window)
 
572
{
 
573
        double elapsed;
 
574
 
 
575
        if (! window->priv->logout_enabled)
 
576
                return FALSE;
 
577
 
 
578
        elapsed = g_timer_elapsed (window->priv->timer, NULL);
 
579
 
 
580
        if (window->priv->logout_timeout < (elapsed * 1000))
 
581
                return TRUE;
 
582
 
 
583
        return FALSE;
 
584
}
 
585
 
 
586
static gboolean
 
587
is_user_switch_enabled (GSWindow *window)
 
588
{
 
589
        return window->priv->user_switch_enabled;
 
590
}
 
591
 
 
592
static gboolean
 
593
popup_dialog_idle (GSWindow *window)
 
594
{
 
595
        gboolean  result;
 
596
        char     *tmp;
 
597
        GString  *command;
 
598
 
 
599
        tmp = g_build_filename (LIBEXECDIR, "gnome-screensaver-dialog", NULL);
 
600
        command = g_string_new (tmp);
 
601
        g_free (tmp);
 
602
 
 
603
        if (is_logout_enabled (window)) {
 
604
                command = g_string_append (command, " --enable-logout");
 
605
        }
 
606
        if (is_user_switch_enabled (window)) {
 
607
                command = g_string_append (command, " --enable-switch");
 
608
        }
 
609
 
 
610
        gs_window_clear (window);
 
611
        set_invisible_cursor (GTK_WIDGET (window)->window, FALSE);
 
612
 
 
613
        result = spawn_on_window (window,
 
614
                                  command->str,
 
615
                                  &window->priv->pid,
 
616
                                  (GIOFunc)command_watch,
 
617
                                  window,
 
618
                                  &window->priv->watch_id);
 
619
        if (!result)
 
620
                g_warning ("Could not start command: %s", command->str);
 
621
 
 
622
        g_string_free (command, TRUE);
 
623
 
 
624
        window->priv->popup_dialog_idle_id = 0;
 
625
 
 
626
        return FALSE;
 
627
}
 
628
 
 
629
void
 
630
gs_window_request_unlock (GSWindow *window)
 
631
{
 
632
        g_return_if_fail (GS_IS_WINDOW (window));
 
633
 
 
634
        if (window->priv->watch_id)
 
635
                return;
 
636
 
 
637
        if (! window->priv->lock_enabled) {
 
638
                g_idle_add ((GSourceFunc)emit_unblanked_idle, window);
 
639
                return;
 
640
        }
 
641
 
 
642
        if (window->priv->popup_dialog_idle_id == 0) {
 
643
                window->priv->popup_dialog_idle_id = g_idle_add ((GSourceFunc)popup_dialog_idle, window);
 
644
        }
 
645
 
 
646
        g_signal_emit (window, signals [DIALOG_UP], 0);
 
647
}
 
648
 
 
649
void
 
650
gs_window_set_lock_enabled (GSWindow *window,
 
651
                            gboolean  lock_enabled)
 
652
{
 
653
        g_return_if_fail (GS_IS_WINDOW (window));
 
654
 
 
655
        if (window->priv->lock_enabled == lock_enabled)
 
656
                return;
 
657
 
 
658
        window->priv->lock_enabled = lock_enabled;
 
659
        g_object_notify (G_OBJECT (window), "lock-enabled");
 
660
}
 
661
 
 
662
void
 
663
gs_window_set_screen (GSWindow  *window,
 
664
                      GdkScreen *screen)
 
665
{
 
666
 
 
667
        g_return_if_fail (GS_IS_WINDOW (window));
 
668
        g_return_if_fail (GDK_IS_SCREEN (screen));
 
669
 
 
670
        gtk_window_set_screen (GTK_WINDOW (window), screen);
 
671
}
 
672
 
 
673
GdkScreen *
 
674
gs_window_get_screen (GSWindow  *window)
 
675
{
 
676
        g_return_val_if_fail (GS_IS_WINDOW (window), NULL);
 
677
 
 
678
        return GTK_WINDOW (window)->screen;
 
679
}
 
680
 
 
681
void
 
682
gs_window_set_logout_enabled (GSWindow *window,
 
683
                              gboolean  logout_enabled)
 
684
{
 
685
        g_return_if_fail (GS_IS_WINDOW (window));
 
686
 
 
687
        window->priv->logout_enabled = logout_enabled;
 
688
}
 
689
 
 
690
void
 
691
gs_window_set_user_switch_enabled (GSWindow *window,
 
692
                                   gboolean  user_switch_enabled)
 
693
{
 
694
        g_return_if_fail (GS_IS_WINDOW (window));
 
695
 
 
696
        window->priv->user_switch_enabled = user_switch_enabled;
 
697
}
 
698
 
 
699
void
 
700
gs_window_set_logout_timeout (GSWindow *window,
 
701
                              glong     logout_timeout)
 
702
{
 
703
        g_return_if_fail (GS_IS_WINDOW (window));
 
704
 
 
705
        if (logout_timeout < 0)
 
706
                window->priv->logout_timeout = 0;
 
707
        else
 
708
                window->priv->logout_timeout = logout_timeout;
 
709
}
 
710
 
 
711
void
 
712
gs_window_set_monitor (GSWindow *window,
 
713
                       int       monitor)
 
714
{
 
715
        g_return_if_fail (GS_IS_WINDOW (window));
 
716
 
 
717
        if (window->priv->monitor == monitor)
 
718
                return;
 
719
 
 
720
        window->priv->monitor = monitor;
 
721
 
 
722
        gtk_widget_queue_resize (GTK_WIDGET (window));
 
723
 
 
724
        g_object_notify (G_OBJECT (window), "monitor");
 
725
}
 
726
 
 
727
int
 
728
gs_window_get_monitor (GSWindow *window)
 
729
{
 
730
        g_return_val_if_fail (GS_IS_WINDOW (window), -1);
 
731
 
 
732
        return window->priv->monitor;
 
733
}
 
734
 
 
735
static void
 
736
gs_window_set_property (GObject            *object,
 
737
                        guint               prop_id,
 
738
                        const GValue       *value,
 
739
                        GParamSpec         *pspec)
 
740
{
 
741
        GSWindow *self;
 
742
 
 
743
        self = GS_WINDOW (object);
 
744
 
 
745
        switch (prop_id) {
 
746
        case PROP_LOCK_ENABLED:
 
747
                gs_window_set_lock_enabled (self, g_value_get_boolean (value));
 
748
                break;
 
749
        case PROP_LOGOUT_ENABLED:
 
750
                gs_window_set_logout_enabled (self, g_value_get_boolean (value));
 
751
                break;
 
752
        case PROP_LOGOUT_TIMEOUT:
 
753
                gs_window_set_logout_timeout (self, g_value_get_long (value));
 
754
                break;
 
755
        case PROP_MONITOR:
 
756
                gs_window_set_monitor (self, g_value_get_int (value));
 
757
                break;
 
758
        default:
 
759
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
760
                break;
 
761
        }
 
762
}
 
763
 
 
764
static void
 
765
gs_window_get_property (GObject    *object,
 
766
                        guint       prop_id,
 
767
                        GValue     *value,
 
768
                        GParamSpec *pspec)
 
769
{
 
770
        GSWindow *self;
 
771
 
 
772
        self = GS_WINDOW (object);
 
773
 
 
774
        switch (prop_id) {
 
775
        case PROP_LOCK_ENABLED:
 
776
                g_value_set_boolean (value, self->priv->lock_enabled);
 
777
                break;
 
778
        case PROP_LOGOUT_ENABLED:
 
779
                g_value_set_boolean (value, self->priv->logout_enabled);
 
780
                break;
 
781
        case PROP_LOGOUT_TIMEOUT:
 
782
                g_value_set_long (value, self->priv->logout_timeout);
 
783
                break;
 
784
        case PROP_MONITOR:
 
785
                g_value_set_int (value, self->priv->monitor);
 
786
                break;
 
787
        default:
 
788
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
789
                break;
 
790
        }
 
791
}
 
792
 
 
793
static gboolean
 
794
gs_window_request_unlock_idle (GSWindow *window)
 
795
{
 
796
        gs_window_request_unlock (window);
 
797
 
 
798
        window->priv->request_unlock_idle_id = 0;
 
799
 
 
800
        return FALSE;
 
801
}
 
802
 
 
803
static void
 
804
queue_key_event (GSWindow    *window,
 
805
                 GdkEventKey *event)
 
806
{
 
807
        /* Eat the first return or space */
 
808
        if (window->priv->key_events == NULL
 
809
            && (event->keyval == GDK_Return
 
810
                || event->keyval == GDK_space)) {
 
811
                return;
 
812
        }
 
813
 
 
814
        window->priv->key_events = g_list_prepend (window->priv->key_events,
 
815
                                                   gdk_event_copy ((GdkEvent *)event));
 
816
}
 
817
 
 
818
static gboolean
 
819
gs_window_real_key_press_event (GtkWidget   *widget,
 
820
                                GdkEventKey *event)
 
821
{
 
822
        gboolean catch_events = FALSE;
 
823
 
 
824
        /*g_message ("KEY PRESS state: %u keyval %u", event->state, event->keyval);*/
 
825
 
 
826
        /* if we don't already have a socket then request an unlock */
 
827
        if (! GS_WINDOW (widget)->priv->socket) {
 
828
                if (GS_WINDOW (widget)->priv->request_unlock_idle_id == 0) {
 
829
                        GS_WINDOW (widget)->priv->request_unlock_idle_id = g_idle_add ((GSourceFunc)gs_window_request_unlock_idle, widget);
 
830
                }
 
831
 
 
832
                catch_events = TRUE;
 
833
        } else {
 
834
                if (! GTK_WIDGET_VISIBLE (GS_WINDOW (widget)->priv->socket)) {
 
835
                        catch_events = TRUE;
 
836
                }
 
837
        }
 
838
 
 
839
        /* Catch all keypresses up until the lock dialog is shown */
 
840
        if (catch_events) {
 
841
                queue_key_event (GS_WINDOW (widget), event);
 
842
        }
 
843
 
 
844
        if (GTK_WIDGET_CLASS (parent_class)->key_press_event)
 
845
                GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
 
846
 
 
847
        return TRUE;
 
848
}
 
849
 
 
850
static gboolean
 
851
gs_window_real_motion_notify_event (GtkWidget      *widget,
 
852
                                    GdkEventMotion *event)
 
853
{
 
854
 
 
855
        /* if we don't already have a socket then request an unlock */
 
856
        if (! GS_WINDOW (widget)->priv->socket
 
857
            && (GS_WINDOW (widget)->priv->request_unlock_idle_id == 0)) {
 
858
                GS_WINDOW (widget)->priv->request_unlock_idle_id = g_idle_add ((GSourceFunc)gs_window_request_unlock_idle, widget);
 
859
        }
 
860
 
 
861
        return FALSE;
 
862
}
 
863
 
 
864
static void
 
865
gs_window_real_size_request (GtkWidget      *widget,
 
866
                             GtkRequisition *requisition)
 
867
{
 
868
        GSWindow      *window;
 
869
        GtkBin        *bin;
 
870
        GdkRectangle   old_geometry;
 
871
        int            position_changed = FALSE;
 
872
        int            size_changed = FALSE;
 
873
 
 
874
        window = GS_WINDOW (widget);
 
875
        bin = GTK_BIN (widget);
 
876
 
 
877
        if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
 
878
                gtk_widget_size_request (bin->child, requisition);
 
879
 
 
880
        old_geometry = window->priv->geometry;
 
881
 
 
882
        update_geometry (window);
 
883
 
 
884
        requisition->width  = window->priv->geometry.width;
 
885
        requisition->height = window->priv->geometry.height;
 
886
 
 
887
        if (! GTK_WIDGET_REALIZED (widget))
 
888
                return;
 
889
 
 
890
        if (old_geometry.width  != window->priv->geometry.width ||
 
891
            old_geometry.height != window->priv->geometry.height)
 
892
                size_changed = TRUE;
 
893
 
 
894
        if (old_geometry.x != window->priv->geometry.x ||
 
895
            old_geometry.y != window->priv->geometry.y)
 
896
                position_changed = TRUE;
 
897
 
 
898
        gs_window_move_resize_window (window, position_changed, size_changed);
 
899
}
 
900
 
 
901
static void
 
902
gs_window_class_init (GSWindowClass *klass)
 
903
{
 
904
        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
 
905
        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
906
 
 
907
        parent_class = g_type_class_peek_parent (klass);
 
908
 
 
909
        object_class->finalize     = gs_window_finalize;
 
910
        object_class->get_property = gs_window_get_property;
 
911
        object_class->set_property = gs_window_set_property;
 
912
 
 
913
        widget_class->show                = gs_window_real_show;
 
914
        widget_class->realize             = gs_window_real_realize;
 
915
        widget_class->key_press_event     = gs_window_real_key_press_event;
 
916
        widget_class->motion_notify_event = gs_window_real_motion_notify_event;
 
917
        widget_class->size_request        = gs_window_real_size_request;
 
918
 
 
919
        g_type_class_add_private (klass, sizeof (GSWindowPrivate));
 
920
 
 
921
        signals [UNBLANKED] =
 
922
                g_signal_new ("unblanked",
 
923
                              G_TYPE_FROM_CLASS (object_class),
 
924
                              G_SIGNAL_RUN_LAST,
 
925
                              G_STRUCT_OFFSET (GSWindowClass, unblanked),
 
926
                              NULL,
 
927
                              NULL,
 
928
                              g_cclosure_marshal_VOID__VOID,
 
929
                              G_TYPE_NONE,
 
930
                              0);
 
931
        signals [DIALOG_UP] =
 
932
                g_signal_new ("dialog-up",
 
933
                              G_TYPE_FROM_CLASS (object_class),
 
934
                              G_SIGNAL_RUN_LAST,
 
935
                              G_STRUCT_OFFSET (GSWindowClass, dialog_up),
 
936
                              NULL,
 
937
                              NULL,
 
938
                              g_cclosure_marshal_VOID__VOID,
 
939
                              G_TYPE_NONE,
 
940
                              0);
 
941
        signals [DIALOG_DOWN] =
 
942
                g_signal_new ("dialog-down",
 
943
                              G_TYPE_FROM_CLASS (object_class),
 
944
                              G_SIGNAL_RUN_LAST,
 
945
                              G_STRUCT_OFFSET (GSWindowClass, dialog_down),
 
946
                              NULL,
 
947
                              NULL,
 
948
                              g_cclosure_marshal_VOID__VOID,
 
949
                              G_TYPE_NONE,
 
950
                              0);
 
951
 
 
952
        g_object_class_install_property (object_class,
 
953
                                         PROP_LOCK_ENABLED,
 
954
                                         g_param_spec_boolean ("lock-enabled",
 
955
                                                               NULL,
 
956
                                                               NULL,
 
957
                                                               FALSE,
 
958
                                                               G_PARAM_READWRITE));
 
959
        g_object_class_install_property (object_class,
 
960
                                         PROP_MONITOR,
 
961
                                         g_param_spec_int ("monitor",
 
962
                                                           "Xinerama monitor",
 
963
                                                           "The monitor (in terms of Xinerama) which the panel is on",
 
964
                                                           0,
 
965
                                                           G_MAXINT,
 
966
                                                           0,
 
967
                                                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
968
 
 
969
}
 
970
 
 
971
static void
 
972
gs_window_init (GSWindow *window)
 
973
{
 
974
        window->priv = GS_WINDOW_GET_PRIVATE (window);
 
975
 
 
976
        window->priv->geometry.x      = -1;
 
977
        window->priv->geometry.y      = -1;
 
978
        window->priv->geometry.width  = -1;
 
979
        window->priv->geometry.height = -1;
 
980
 
 
981
        gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
 
982
 
 
983
        gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), TRUE);
 
984
        gtk_window_set_skip_pager_hint (GTK_WINDOW (window), TRUE);
 
985
 
 
986
        gtk_window_set_keep_above (GTK_WINDOW (window), TRUE);
 
987
 
 
988
        gtk_window_fullscreen (GTK_WINDOW (window));
 
989
 
 
990
        gtk_widget_set_events (GTK_WIDGET (window),
 
991
                               gtk_widget_get_events (GTK_WIDGET (window))
 
992
                               | GDK_POINTER_MOTION_MASK
 
993
                               | GDK_BUTTON_PRESS_MASK
 
994
                               | GDK_BUTTON_RELEASE_MASK
 
995
                               | GDK_KEY_PRESS_MASK
 
996
                               | GDK_KEY_RELEASE_MASK
 
997
                               | GDK_EXPOSURE_MASK
 
998
                               | GDK_ENTER_NOTIFY_MASK
 
999
                               | GDK_LEAVE_NOTIFY_MASK);
 
1000
}
 
1001
 
 
1002
static void
 
1003
gs_window_finalize (GObject *object)
 
1004
{
 
1005
        GSWindow *window;
 
1006
 
 
1007
        g_return_if_fail (object != NULL);
 
1008
        g_return_if_fail (GS_IS_WINDOW (object));
 
1009
 
 
1010
        window = GS_WINDOW (object);
 
1011
 
 
1012
        g_return_if_fail (window->priv != NULL);
 
1013
 
 
1014
        if (window->priv->request_unlock_idle_id)
 
1015
                g_source_remove (window->priv->request_unlock_idle_id);
 
1016
        if (window->priv->popup_dialog_idle_id)
 
1017
                g_source_remove (window->priv->popup_dialog_idle_id);
 
1018
 
 
1019
        if (window->priv->timer)
 
1020
                g_timer_destroy (window->priv->timer);
 
1021
 
 
1022
        /* just in case they weren't removed */
 
1023
        remove_key_events (window);
 
1024
 
 
1025
        G_OBJECT_CLASS (parent_class)->finalize (object);
 
1026
}
 
1027
 
 
1028
GSWindow *
 
1029
gs_window_new (GdkScreen *screen,
 
1030
               int        monitor,
 
1031
               gboolean   lock_enabled)
 
1032
{
 
1033
        GObject     *result;
 
1034
 
 
1035
        result = g_object_new (GS_TYPE_WINDOW,
 
1036
                               "screen", screen,
 
1037
                               "monitor", monitor,
 
1038
                               "lock-enabled", lock_enabled,
 
1039
                               NULL);
 
1040
 
 
1041
        return GS_WINDOW (result);
 
1042
}