~cjcurran/gnome-control-center/expose-card-ports

« back to all changes in this revision

Viewing changes to typing-break/drwright.c

  • Committer: Bazaar Package Importer
  • Author(s): Rodrigo Moya
  • Date: 2011-05-17 10:47:27 UTC
  • mfrom: (0.1.11 experimental) (1.1.45 upstream)
  • Revision ID: james.westby@ubuntu.com-20110517104727-lqel6m8vhfw5jby1
Tags: 1:3.0.1.1-1ubuntu1
* Rebase on Debian, remaining Ubuntu changes:
* debian/control:
  - Build-Depend on hardening-wrapper, dpkg-dev and dh-autoreconf
  - Add dependency on ubuntu-system-service
  - Remove dependency on gnome-icon-theme-symbolic
  - Move dependency on apg, gnome-icon-theme-symbolic and accountsservice to
    be a Recommends: until we get them in main
* debian/rules:
  - Use autoreconf
  - Add binary-post-install rule for gnome-control-center-data
  - Run dh-autoreconf
* debian/gnome-control-center.dirs:
* debian/gnome-control-center.links:
  - Add a link to the control center shell for indicators
* debian/patches/00_disable-nm.patch:
  - Temporary patch to disable building with NetworkManager until we get
    the new one in the archive
* debian/patches/01_git_remove_gettext_calls.patch:
  - Remove calls to AM_GNU_GETTEXT, IT_PROG_INTLTOOL should be enough
* debian/patches/01_git_kill_warning.patch:
  - Kill warning
* debian/patches/50_ubuntu_systemwide_prefs.patch:
  - Ubuntu specific proxy preferences
* debian/patches/51_ubuntu_system_keyboard.patch:
  - Implement the global keyboard spec at https://wiki.ubuntu.com/DefaultKeyboardSettings

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
 
/*
3
 
 * Copyright (C) 2003-2005 Imendio HB
4
 
 * Copyright (C) 2002-2003 Richard Hult <richard@imendio.com>
5
 
 * Copyright (C) 2002 CodeFactory AB
6
 
 *
7
 
 * This program is free software; you can redistribute it and/or
8
 
 * modify it under the terms of the GNU General Public License as
9
 
 * published by the Free Software Foundation; either version 2 of the
10
 
 * License, or (at your option) any later version.
11
 
 *
12
 
 * This program is distributed in the hope that it will be useful,
13
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 
 * General Public License for more details.
16
 
 *
17
 
 * You should have received a copy of the GNU General Public
18
 
 * License along with this program; if not, write to the
19
 
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20
 
 * Boston, MA 02111-1307, USA.
21
 
 */
22
 
 
23
 
#include <config.h>
24
 
#include <string.h>
25
 
#include <math.h>
26
 
#include <glib/gi18n.h>
27
 
#include <gdk/gdk.h>
28
 
#include <gdk/gdkkeysyms.h>
29
 
#include <gtk/gtk.h>
30
 
#include <gconf/gconf-client.h>
31
 
 
32
 
#ifdef HAVE_APP_INDICATOR
33
 
#include <libappindicator/app-indicator.h>
34
 
#endif /* HAVE_APP_INDICATOR */
35
 
 
36
 
#include "drwright.h"
37
 
#include "drw-break-window.h"
38
 
#include "drw-monitor.h"
39
 
#include "drw-utils.h"
40
 
#include "drw-timer.h"
41
 
 
42
 
#ifndef HAVE_APP_INDICATOR
43
 
#define BLINK_TIMEOUT        200
44
 
#define BLINK_TIMEOUT_MIN    120
45
 
#define BLINK_TIMEOUT_FACTOR 100
46
 
#endif /* HAVE_APP_INDICATOR */
47
 
 
48
 
#define POPUP_ITEM_ENABLED 1
49
 
#define POPUP_ITEM_BREAK   2
50
 
 
51
 
typedef enum {
52
 
        STATE_START,
53
 
        STATE_RUNNING,
54
 
        STATE_WARN,
55
 
        STATE_BREAK_SETUP,
56
 
        STATE_BREAK,
57
 
        STATE_BREAK_DONE_SETUP,
58
 
        STATE_BREAK_DONE
59
 
} DrwState;
60
 
 
61
 
#ifdef HAVE_APP_INDICATOR
62
 
#define TYPING_MONITOR_ACTIVE_ICON "bar-green"
63
 
#define TYPING_MONITOR_ATTENTION_ICON "bar-red"
64
 
#endif /* HAVE_APP_INDICATOR */
65
 
 
66
 
struct _DrWright {
67
 
        /* Widgets. */
68
 
        GtkWidget      *break_window;
69
 
        GList          *secondary_break_windows;
70
 
 
71
 
        DrwMonitor     *monitor;
72
 
 
73
 
        GtkUIManager *ui_manager;
74
 
 
75
 
        DrwState        state;
76
 
        DrwTimer       *timer;
77
 
        DrwTimer       *idle_timer;
78
 
 
79
 
        gint            last_elapsed_time;
80
 
        gint            save_last_time;
81
 
 
82
 
        /* Time settings. */
83
 
        gint            type_time;
84
 
        gint            break_time;
85
 
        gint            warn_time;
86
 
 
87
 
        gboolean        enabled;
88
 
 
89
 
        guint           clock_timeout_id;
90
 
#ifdef HAVE_APP_INDICATOR
91
 
        AppIndicator   *indicator;
92
 
#else
93
 
        guint           blink_timeout_id;
94
 
 
95
 
        gboolean        blink_on;
96
 
 
97
 
        GtkStatusIcon  *icon;
98
 
 
99
 
        GdkPixbuf      *neutral_bar;
100
 
        GdkPixbuf      *red_bar;
101
 
        GdkPixbuf      *green_bar;
102
 
        GdkPixbuf      *disabled_bar;
103
 
        GdkPixbuf      *composite_bar;
104
 
#endif /* HAVE_APP_INDICATOR */
105
 
 
106
 
        GtkWidget      *warn_dialog;
107
 
};
108
 
 
109
 
static void     activity_detected_cb           (DrwMonitor     *monitor,
110
 
                                                DrWright       *drwright);
111
 
static gboolean maybe_change_state             (DrWright       *drwright);
112
 
static gint     get_time_left                  (DrWright       *drwright);
113
 
static gboolean update_status                  (DrWright       *drwright);
114
 
static void     break_window_done_cb           (GtkWidget      *window,
115
 
                                                DrWright       *dr);
116
 
static void     break_window_postpone_cb       (GtkWidget      *window,
117
 
                                                DrWright       *dr);
118
 
static void     break_window_destroy_cb        (GtkWidget      *window,
119
 
                                                DrWright       *dr);
120
 
static void     popup_break_cb                 (GtkAction      *action,
121
 
                                                DrWright       *dr);
122
 
static void     popup_preferences_cb           (GtkAction      *action,
123
 
                                                DrWright       *dr);
124
 
static void     popup_about_cb                 (GtkAction      *action,
125
 
                                                DrWright       *dr);
126
 
#ifdef HAVE_APP_INDICATOR
127
 
static void     init_app_indicator             (DrWright       *dr);
128
 
#else
129
 
static void     init_tray_icon                 (DrWright       *dr);
130
 
#endif /* HAVE_APP_INDICATOR */
131
 
static GList *  create_secondary_break_windows (void);
132
 
 
133
 
static const GtkActionEntry actions[] = {
134
 
  {"Preferences", GTK_STOCK_PREFERENCES, NULL, NULL, NULL, G_CALLBACK (popup_preferences_cb)},
135
 
  {"About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK (popup_about_cb)},
136
 
  {"TakeABreak", NULL, N_("_Take a Break"), NULL, NULL, G_CALLBACK (popup_break_cb)}
137
 
};
138
 
 
139
 
extern gboolean debug;
140
 
 
141
 
static void
142
 
setup_debug_values (DrWright *dr)
143
 
{
144
 
        dr->type_time = 5;
145
 
        dr->warn_time = 4;
146
 
        dr->break_time = 10;
147
 
}
148
 
 
149
 
#ifdef HAVE_APP_INDICATOR
150
 
static void
151
 
update_app_indicator (DrWright *dr)
152
 
{
153
 
        AppIndicatorStatus new_status;
154
 
 
155
 
        if (!dr->enabled) {
156
 
                app_indicator_set_status (dr->indicator,
157
 
                                          APP_INDICATOR_STATUS_PASSIVE);
158
 
                return;
159
 
        }
160
 
 
161
 
        switch (dr->state) {
162
 
        case STATE_WARN:
163
 
        case STATE_BREAK_SETUP:
164
 
        case STATE_BREAK:
165
 
                new_status = APP_INDICATOR_STATUS_ATTENTION;
166
 
                break;
167
 
        default:
168
 
                new_status = APP_INDICATOR_STATUS_ACTIVE;
169
 
        }
170
 
 
171
 
        app_indicator_set_status (dr->indicator, new_status);
172
 
}
173
 
#else
174
 
static void
175
 
update_icon (DrWright *dr)
176
 
{
177
 
        GdkPixbuf *pixbuf;
178
 
        GdkPixbuf *tmp_pixbuf;
179
 
        gint       width, height;
180
 
        gfloat     r;
181
 
        gint       offset;
182
 
        gboolean   set_pixbuf;
183
 
 
184
 
        if (!dr->enabled) {
185
 
                gtk_status_icon_set_from_pixbuf (dr->icon,
186
 
                                                 dr->disabled_bar);
187
 
                return;
188
 
        }
189
 
 
190
 
        tmp_pixbuf = gdk_pixbuf_copy (dr->neutral_bar);
191
 
 
192
 
        width = gdk_pixbuf_get_width (tmp_pixbuf);
193
 
        height = gdk_pixbuf_get_height (tmp_pixbuf);
194
 
 
195
 
        set_pixbuf = TRUE;
196
 
 
197
 
        switch (dr->state) {
198
 
        case STATE_BREAK:
199
 
        case STATE_BREAK_SETUP:
200
 
                r = 1;
201
 
                break;
202
 
 
203
 
        case STATE_BREAK_DONE:
204
 
        case STATE_BREAK_DONE_SETUP:
205
 
        case STATE_START:
206
 
                r = 0;
207
 
                break;
208
 
 
209
 
        default:
210
 
                r = (float) (drw_timer_elapsed (dr->timer) + dr->save_last_time) /
211
 
                    (float) dr->type_time;
212
 
                break;
213
 
        }
214
 
 
215
 
        offset = CLAMP ((height - 0) * (1.0 - r), 1, height - 0);
216
 
 
217
 
        switch (dr->state) {
218
 
        case STATE_WARN:
219
 
                pixbuf = dr->red_bar;
220
 
                set_pixbuf = FALSE;
221
 
                break;
222
 
 
223
 
        case STATE_BREAK_SETUP:
224
 
        case STATE_BREAK:
225
 
                pixbuf = dr->red_bar;
226
 
                break;
227
 
 
228
 
        default:
229
 
                pixbuf = dr->green_bar;
230
 
        }
231
 
 
232
 
        gdk_pixbuf_composite (pixbuf,
233
 
                              tmp_pixbuf,
234
 
                              0,
235
 
                              offset,
236
 
                              width,
237
 
                              height - offset,
238
 
                              0,
239
 
                              0,
240
 
                              1.0,
241
 
                              1.0,
242
 
                              GDK_INTERP_BILINEAR,
243
 
                              255);
244
 
 
245
 
        if (set_pixbuf) {
246
 
                gtk_status_icon_set_from_pixbuf (dr->icon,
247
 
                                                 tmp_pixbuf);
248
 
        }
249
 
 
250
 
        if (dr->composite_bar) {
251
 
                g_object_unref (dr->composite_bar);
252
 
        }
253
 
 
254
 
        dr->composite_bar = tmp_pixbuf;
255
 
}
256
 
 
257
 
static gboolean
258
 
blink_timeout_cb (DrWright *dr)
259
 
{
260
 
        gfloat r;
261
 
        gint   timeout;
262
 
 
263
 
        r = (dr->type_time - drw_timer_elapsed (dr->timer) - dr->save_last_time) / dr->warn_time;
264
 
        timeout = BLINK_TIMEOUT + BLINK_TIMEOUT_FACTOR * r;
265
 
 
266
 
        if (timeout < BLINK_TIMEOUT_MIN) {
267
 
                timeout = BLINK_TIMEOUT_MIN;
268
 
        }
269
 
 
270
 
        if (dr->blink_on || timeout == 0) {
271
 
                gtk_status_icon_set_from_pixbuf (dr->icon,
272
 
                                                 dr->composite_bar);
273
 
        } else {
274
 
                gtk_status_icon_set_from_pixbuf (dr->icon,
275
 
                                                 dr->neutral_bar);
276
 
        }
277
 
 
278
 
        dr->blink_on = !dr->blink_on;
279
 
 
280
 
        if (timeout) {
281
 
                dr->blink_timeout_id = g_timeout_add (timeout,
282
 
                                                      (GSourceFunc) blink_timeout_cb,
283
 
                                                      dr);
284
 
        } else {
285
 
                dr->blink_timeout_id = 0;
286
 
        }
287
 
 
288
 
        return FALSE;
289
 
}
290
 
#endif /* HAVE_APP_INDICATOR */
291
 
 
292
 
static void
293
 
start_blinking (DrWright *dr)
294
 
{
295
 
#ifndef HAVE_APP_INDICATOR
296
 
        if (!dr->blink_timeout_id) {
297
 
                dr->blink_on = TRUE;
298
 
                blink_timeout_cb (dr);
299
 
        }
300
 
 
301
 
        /*gtk_widget_show (GTK_WIDGET (dr->icon));*/
302
 
#endif /* HAVE_APP_INDICATOR */
303
 
}
304
 
 
305
 
static void
306
 
stop_blinking (DrWright *dr)
307
 
{
308
 
#ifndef HAVE_APP_INDICATOR
309
 
        if (dr->blink_timeout_id) {
310
 
                g_source_remove (dr->blink_timeout_id);
311
 
                dr->blink_timeout_id = 0;
312
 
        }
313
 
 
314
 
        /*gtk_widget_hide (GTK_WIDGET (dr->icon));*/
315
 
#endif /* HAVE_APP_INDICATOR */
316
 
}
317
 
 
318
 
static gboolean
319
 
grab_keyboard_on_window (GdkWindow *window,
320
 
                         guint32    activate_time)
321
 
{
322
 
        GdkGrabStatus status;
323
 
 
324
 
        status = gdk_keyboard_grab (window, TRUE, activate_time);
325
 
        if (status == GDK_GRAB_SUCCESS) {
326
 
                return TRUE;
327
 
        }
328
 
 
329
 
        return FALSE;
330
 
}
331
 
 
332
 
static gboolean
333
 
break_window_map_event_cb (GtkWidget *widget,
334
 
                           GdkEvent  *event,
335
 
                           DrWright  *dr)
336
 
{
337
 
        grab_keyboard_on_window (gtk_widget_get_window (dr->break_window), gtk_get_current_event_time ());
338
 
 
339
 
        return FALSE;
340
 
}
341
 
 
342
 
static gboolean
343
 
maybe_change_state (DrWright *dr)
344
 
{
345
 
        gint elapsed_time;
346
 
        gint elapsed_idle_time;
347
 
 
348
 
        if (debug) {
349
 
                drw_timer_start (dr->idle_timer);
350
 
        }
351
 
 
352
 
        elapsed_time = drw_timer_elapsed (dr->timer) + dr->save_last_time;
353
 
        elapsed_idle_time = drw_timer_elapsed (dr->idle_timer);
354
 
 
355
 
        if (elapsed_time > dr->last_elapsed_time + dr->warn_time) {
356
 
                /* If the timeout is delayed by the amount of warning time, then
357
 
                 * we must have been suspended or stopped, so we just start
358
 
                 * over.
359
 
                 */
360
 
                dr->state = STATE_START;
361
 
        }
362
 
 
363
 
        switch (dr->state) {
364
 
        case STATE_START:
365
 
                if (dr->break_window) {
366
 
                        gtk_widget_destroy (dr->break_window);
367
 
                        dr->break_window = NULL;
368
 
                }
369
 
 
370
 
#ifndef HAVE_APP_INDICATOR
371
 
                gtk_status_icon_set_from_pixbuf (dr->icon,
372
 
                                                 dr->neutral_bar);
373
 
#endif /* HAVE_APP_INDICATOR */
374
 
 
375
 
                dr->save_last_time = 0;
376
 
 
377
 
                drw_timer_start (dr->timer);
378
 
                drw_timer_start (dr->idle_timer);
379
 
 
380
 
                if (dr->enabled) {
381
 
                        dr->state = STATE_RUNNING;
382
 
                }
383
 
 
384
 
                update_status (dr);
385
 
                stop_blinking (dr);
386
 
                break;
387
 
 
388
 
        case STATE_RUNNING:
389
 
        case STATE_WARN:
390
 
                if (elapsed_idle_time >= dr->break_time) {
391
 
                        dr->state = STATE_BREAK_DONE_SETUP;
392
 
                } else if (elapsed_time >= dr->type_time) {
393
 
                        dr->state = STATE_BREAK_SETUP;
394
 
                } else if (dr->state != STATE_WARN
395
 
                           && elapsed_time >= dr->type_time - dr->warn_time) {
396
 
                        dr->state = STATE_WARN;
397
 
                        start_blinking (dr);
398
 
                }
399
 
                break;
400
 
 
401
 
        case STATE_BREAK_SETUP:
402
 
                /* Don't allow more than one break window to coexist, can happen
403
 
                 * if a break is manually enforced.
404
 
                 */
405
 
                if (dr->break_window) {
406
 
                        dr->state = STATE_BREAK;
407
 
                        break;
408
 
                }
409
 
 
410
 
                stop_blinking (dr);
411
 
#ifndef HAVE_APP_INDICATOR
412
 
                gtk_status_icon_set_from_pixbuf (dr->icon,
413
 
                                                 dr->red_bar);
414
 
#endif /* HAVE_APP_INDICATOR */
415
 
 
416
 
                drw_timer_start (dr->timer);
417
 
 
418
 
                dr->break_window = drw_break_window_new ();
419
 
 
420
 
                g_signal_connect (dr->break_window, "map_event",
421
 
                                  G_CALLBACK (break_window_map_event_cb),
422
 
                                  dr);
423
 
 
424
 
                g_signal_connect (dr->break_window,
425
 
                                  "done",
426
 
                                  G_CALLBACK (break_window_done_cb),
427
 
                                  dr);
428
 
 
429
 
                g_signal_connect (dr->break_window,
430
 
                                  "postpone",
431
 
                                  G_CALLBACK (break_window_postpone_cb),
432
 
                                  dr);
433
 
 
434
 
                g_signal_connect (dr->break_window,
435
 
                                  "destroy",
436
 
                                  G_CALLBACK (break_window_destroy_cb),
437
 
                                  dr);
438
 
 
439
 
                dr->secondary_break_windows = create_secondary_break_windows ();
440
 
 
441
 
                gtk_widget_show (dr->break_window);
442
 
 
443
 
                dr->save_last_time = elapsed_time;
444
 
                dr->state = STATE_BREAK;
445
 
                break;
446
 
 
447
 
        case STATE_BREAK:
448
 
                if (elapsed_time - dr->save_last_time >= dr->break_time) {
449
 
                        dr->state = STATE_BREAK_DONE_SETUP;
450
 
                }
451
 
                break;
452
 
 
453
 
        case STATE_BREAK_DONE_SETUP:
454
 
                stop_blinking (dr);
455
 
#ifndef HAVE_APP_INDICATOR
456
 
                gtk_status_icon_set_from_pixbuf (dr->icon,
457
 
                                                 dr->green_bar);
458
 
#endif /* HAVE_APP_INDICATOR */
459
 
 
460
 
                dr->state = STATE_BREAK_DONE;
461
 
                break;
462
 
 
463
 
        case STATE_BREAK_DONE:
464
 
                dr->state = STATE_START;
465
 
                if (dr->break_window) {
466
 
                        gtk_widget_destroy (dr->break_window);
467
 
                        dr->break_window = NULL;
468
 
                }
469
 
                break;
470
 
        }
471
 
 
472
 
        dr->last_elapsed_time = elapsed_time;
473
 
 
474
 
#ifdef HAVE_APP_INDICATOR
475
 
        update_app_indicator (dr);
476
 
#else
477
 
        update_icon (dr);
478
 
#endif /* HAVE_APP_INDICATOR */
479
 
 
480
 
        return TRUE;
481
 
}
482
 
 
483
 
static gboolean
484
 
update_status (DrWright *dr)
485
 
{
486
 
        gint       min;
487
 
        gchar     *str;
488
 
#ifdef HAVE_APP_INDICATOR
489
 
        GtkWidget *item;
490
 
#endif /* HAVE_APP_INDICATOR */
491
 
 
492
 
        if (!dr->enabled) {
493
 
#ifdef HAVE_APP_INDICATOR
494
 
                app_indicator_set_status (dr->indicator,
495
 
                                          APP_INDICATOR_STATUS_PASSIVE);
496
 
#else
497
 
                gtk_status_icon_set_tooltip_text (dr->icon,
498
 
                                                  _("Disabled"));
499
 
#endif /* HAVE_APP_INDICATOR */
500
 
                return TRUE;
501
 
        }
502
 
 
503
 
        min = get_time_left (dr);
504
 
 
505
 
        if (min >= 1) {
506
 
#ifdef HAVE_APP_INDICATOR
507
 
                str = g_strdup_printf (_("Take a break now (next in %dm)"), min);
508
 
#else
509
 
                str = g_strdup_printf (ngettext("%d minute until the next break",
510
 
                                                "%d minutes until the next break",
511
 
                                                min), min);
512
 
#endif /* HAVE_APP_INDICATOR */
513
 
        } else {
514
 
#ifdef HAVE_APP_INDICATOR
515
 
                str = g_strdup_printf (_("Take a break now (next in less than one minute)"));
516
 
#else
517
 
                str = g_strdup_printf (_("Less than one minute until the next break"));
518
 
#endif /* HAVE_APP_INDICATOR */
519
 
        }
520
 
 
521
 
#ifdef HAVE_APP_INDICATOR
522
 
        item = gtk_ui_manager_get_widget (dr->ui_manager, "/Pop/TakeABreak");
523
 
        gtk_menu_item_set_label (GTK_MENU_ITEM (item), str);
524
 
#else
525
 
        gtk_status_icon_set_tooltip_text (dr->icon, str);
526
 
#endif /* HAVE_APP_INDICATOR */
527
 
 
528
 
        g_free (str);
529
 
 
530
 
        return TRUE;
531
 
}
532
 
 
533
 
static gint
534
 
get_time_left (DrWright *dr)
535
 
{
536
 
        gint elapsed_time;
537
 
 
538
 
        elapsed_time = drw_timer_elapsed (dr->timer);
539
 
 
540
 
        return floor (0.5 + (dr->type_time - elapsed_time - dr->save_last_time) / 60.0);
541
 
}
542
 
 
543
 
static void
544
 
activity_detected_cb (DrwMonitor *monitor,
545
 
                      DrWright   *dr)
546
 
{
547
 
        drw_timer_start (dr->idle_timer);
548
 
}
549
 
 
550
 
static void
551
 
gconf_notify_cb (GConfClient *client,
552
 
                 guint        cnxn_id,
553
 
                 GConfEntry  *entry,
554
 
                 gpointer     user_data)
555
 
{
556
 
        DrWright  *dr = user_data;
557
 
        GtkWidget *item;
558
 
 
559
 
        if (!strcmp (entry->key, GCONF_PATH "/type_time")) {
560
 
                if (entry->value->type == GCONF_VALUE_INT) {
561
 
                        dr->type_time = 60 * gconf_value_get_int (entry->value);
562
 
                        dr->warn_time = MIN (dr->type_time / 10, 5*60);
563
 
 
564
 
                        dr->state = STATE_START;
565
 
                }
566
 
        }
567
 
        else if (!strcmp (entry->key, GCONF_PATH "/break_time")) {
568
 
                if (entry->value->type == GCONF_VALUE_INT) {
569
 
                        dr->break_time = 60 * gconf_value_get_int (entry->value);
570
 
                        dr->state = STATE_START;
571
 
                }
572
 
        }
573
 
        else if (!strcmp (entry->key, GCONF_PATH "/enabled")) {
574
 
                if (entry->value->type == GCONF_VALUE_BOOL) {
575
 
                        dr->enabled = gconf_value_get_bool (entry->value);
576
 
                        dr->state = STATE_START;
577
 
 
578
 
                        item = gtk_ui_manager_get_widget (dr->ui_manager,
579
 
                                                          "/Pop/TakeABreak");
580
 
                        gtk_widget_set_sensitive (item, dr->enabled);
581
 
 
582
 
                        update_status (dr);
583
 
                }
584
 
        }
585
 
 
586
 
        maybe_change_state (dr);
587
 
}
588
 
 
589
 
static void
590
 
popup_break_cb (GtkAction *action, DrWright *dr)
591
 
{
592
 
        if (dr->enabled) {
593
 
                dr->state = STATE_BREAK_SETUP;
594
 
                maybe_change_state (dr);
595
 
        }
596
 
}
597
 
 
598
 
static void
599
 
popup_preferences_cb (GtkAction *action, DrWright *dr)
600
 
{
601
 
        GdkScreen *screen;
602
 
        GError    *error = NULL;
603
 
        GtkWidget *menu;
604
 
 
605
 
        menu = gtk_ui_manager_get_widget (dr->ui_manager, "/Pop");
606
 
        screen = gtk_widget_get_screen (menu);
607
 
 
608
 
        if (!gdk_spawn_command_line_on_screen (screen, "gnome-keyboard-properties --typing-break", &error)) {
609
 
                GtkWidget *error_dialog;
610
 
 
611
 
                error_dialog = gtk_message_dialog_new (NULL, 0,
612
 
                                                       GTK_MESSAGE_ERROR,
613
 
                                                       GTK_BUTTONS_CLOSE,
614
 
                                                       _("Unable to bring up the typing break properties dialog with the following error: %s"),
615
 
                                                       error->message);
616
 
                g_signal_connect (error_dialog,
617
 
                                  "response",
618
 
                                  G_CALLBACK (gtk_widget_destroy), NULL);
619
 
                gtk_window_set_resizable (GTK_WINDOW (error_dialog), FALSE);
620
 
                gtk_widget_show (error_dialog);
621
 
 
622
 
                g_error_free (error);
623
 
        }
624
 
}
625
 
 
626
 
static void
627
 
popup_about_cb (GtkAction *action, DrWright *dr)
628
 
{
629
 
        gint   i;
630
 
        gchar *authors[] = {
631
 
                N_("Written by Richard Hult <richard@imendio.com>"),
632
 
                N_("Eye candy added by Anders Carlsson"),
633
 
                NULL
634
 
        };
635
 
 
636
 
        for (i = 0; authors [i]; i++)
637
 
                authors [i] = _(authors [i]);
638
 
 
639
 
        gtk_show_about_dialog (NULL,
640
 
                               "authors", authors,
641
 
                               "comments",  _("A computer break reminder."),
642
 
                               "logo-icon-name", "typing-monitor",
643
 
                               "translator-credits", _("translator-credits"),
644
 
                               "version", VERSION,
645
 
                               NULL);
646
 
}
647
 
 
648
 
#ifndef HAVE_APP_INDICATOR
649
 
static void
650
 
popup_menu_cb (GtkWidget *widget,
651
 
               guint      button,
652
 
               guint      activate_time,
653
 
               DrWright  *dr)
654
 
{
655
 
        GtkWidget *menu;
656
 
 
657
 
        menu = gtk_ui_manager_get_widget (dr->ui_manager, "/Pop");
658
 
 
659
 
        gtk_menu_popup (GTK_MENU (menu),
660
 
                        NULL,
661
 
                        NULL,
662
 
                        gtk_status_icon_position_menu,
663
 
                        dr->icon,
664
 
                        0,
665
 
                        gtk_get_current_event_time ());
666
 
}
667
 
#endif /* HAVE_APP_INDICATOR */
668
 
 
669
 
static void
670
 
break_window_done_cb (GtkWidget *window,
671
 
                      DrWright  *dr)
672
 
{
673
 
        gtk_widget_destroy (dr->break_window);
674
 
 
675
 
        dr->state = STATE_BREAK_DONE_SETUP;
676
 
        dr->break_window = NULL;
677
 
 
678
 
        update_status (dr);
679
 
        maybe_change_state (dr);
680
 
}
681
 
 
682
 
static void
683
 
break_window_postpone_cb (GtkWidget *window,
684
 
                          DrWright  *dr)
685
 
{
686
 
        gint elapsed_time;
687
 
 
688
 
        gtk_widget_destroy (dr->break_window);
689
 
 
690
 
        dr->state = STATE_RUNNING;
691
 
        dr->break_window = NULL;
692
 
 
693
 
        elapsed_time = drw_timer_elapsed (dr->timer);
694
 
 
695
 
        if (elapsed_time + dr->save_last_time >= dr->type_time) {
696
 
                /* Typing time has expired, but break was postponed.
697
 
                 * We'll warn again in (elapsed * sqrt (typing_time))^2 */
698
 
                gfloat postpone_time = (((float) elapsed_time) / dr->break_time)
699
 
                                        * sqrt (dr->type_time);
700
 
                postpone_time *= postpone_time;
701
 
                dr->save_last_time = dr->type_time - MAX (dr->warn_time, (gint) postpone_time);
702
 
        }
703
 
 
704
 
        drw_timer_start (dr->timer);
705
 
        maybe_change_state (dr);
706
 
        update_status (dr);
707
 
#ifdef HAVE_APP_INDICATOR
708
 
        update_app_indicator (dr);
709
 
#else
710
 
        update_icon (dr);
711
 
#endif /* HAVE_APP_INDICATOR */
712
 
}
713
 
 
714
 
static void
715
 
break_window_destroy_cb (GtkWidget *window,
716
 
                         DrWright  *dr)
717
 
{
718
 
        GList *l;
719
 
 
720
 
        for (l = dr->secondary_break_windows; l; l = l->next) {
721
 
                gtk_widget_destroy (l->data);
722
 
        }
723
 
 
724
 
        g_list_free (dr->secondary_break_windows);
725
 
        dr->secondary_break_windows = NULL;
726
 
}
727
 
 
728
 
#ifdef HAVE_APP_INDICATOR
729
 
static void
730
 
init_app_indicator (DrWright *dr)
731
 
{
732
 
        GtkWidget *indicator_menu;
733
 
 
734
 
        dr->indicator =
735
 
                app_indicator_new_with_path ("typing-break-indicator",
736
 
                                             TYPING_MONITOR_ACTIVE_ICON,
737
 
                                             APP_INDICATOR_CATEGORY_APPLICATION_STATUS,
738
 
                                             IMAGEDIR);
739
 
        if (dr->enabled) {
740
 
                app_indicator_set_status (dr->indicator,
741
 
                                          APP_INDICATOR_STATUS_ACTIVE);
742
 
        } else {
743
 
                app_indicator_set_status (dr->indicator,
744
 
                                          APP_INDICATOR_STATUS_PASSIVE);
745
 
        }
746
 
 
747
 
        indicator_menu = gtk_ui_manager_get_widget (dr->ui_manager, "/Pop");
748
 
        app_indicator_set_menu (dr->indicator, GTK_MENU (indicator_menu));
749
 
        app_indicator_set_attention_icon (dr->indicator, TYPING_MONITOR_ATTENTION_ICON);
750
 
 
751
 
        update_status (dr);
752
 
        update_app_indicator (dr);
753
 
}
754
 
#else
755
 
static void
756
 
init_tray_icon (DrWright *dr)
757
 
{
758
 
        dr->icon = gtk_status_icon_new_from_pixbuf (dr->neutral_bar);
759
 
 
760
 
        update_status (dr);
761
 
        update_icon (dr);
762
 
 
763
 
        g_signal_connect (dr->icon,
764
 
                          "popup_menu",
765
 
                          G_CALLBACK (popup_menu_cb),
766
 
                          dr);
767
 
}
768
 
#endif /* HAVE_APP_INDICATOR */
769
 
 
770
 
static GList *
771
 
create_secondary_break_windows (void)
772
 
{
773
 
        GdkDisplay *display;
774
 
        GdkScreen  *screen;
775
 
        GtkWidget  *window;
776
 
        gint        i;
777
 
        GList      *windows = NULL;
778
 
 
779
 
        display = gdk_display_get_default ();
780
 
 
781
 
        for (i = 0; i < gdk_display_get_n_screens (display); i++) {
782
 
                screen = gdk_display_get_screen (display, i);
783
 
 
784
 
                if (screen == gdk_screen_get_default ()) {
785
 
                        /* Handled by DrwBreakWindow. */
786
 
                        continue;
787
 
                }
788
 
 
789
 
                window = gtk_window_new (GTK_WINDOW_POPUP);
790
 
 
791
 
                windows = g_list_prepend (windows, window);
792
 
 
793
 
                gtk_window_set_screen (GTK_WINDOW (window), screen);
794
 
 
795
 
                gtk_window_set_default_size (GTK_WINDOW (window),
796
 
                                             gdk_screen_get_width (screen),
797
 
                                             gdk_screen_get_height (screen));
798
 
 
799
 
                gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
800
 
                drw_setup_background (GTK_WIDGET (window));
801
 
                gtk_window_stick (GTK_WINDOW (window));
802
 
                gtk_widget_show (window);
803
 
        }
804
 
 
805
 
        return windows;
806
 
}
807
 
 
808
 
DrWright *
809
 
drwright_new (void)
810
 
{
811
 
        DrWright  *dr;
812
 
        GtkWidget *item;
813
 
        GConfClient *client;
814
 
        GtkActionGroup *action_group;
815
 
 
816
 
        static const char ui_description[] =
817
 
          "<ui>"
818
 
          "  <popup name='Pop'>"
819
 
          "    <menuitem action='Preferences'/>"
820
 
          "    <menuitem action='About'/>"
821
 
          "    <separator/>"
822
 
          "    <menuitem action='TakeABreak'/>"
823
 
          "  </popup>"
824
 
          "</ui>";
825
 
 
826
 
        dr = g_new0 (DrWright, 1);
827
 
 
828
 
        client = gconf_client_get_default ();
829
 
 
830
 
        gconf_client_add_dir (client,
831
 
                              GCONF_PATH,
832
 
                              GCONF_CLIENT_PRELOAD_NONE,
833
 
                              NULL);
834
 
 
835
 
        gconf_client_notify_add (client, GCONF_PATH,
836
 
                                 gconf_notify_cb,
837
 
                                 dr,
838
 
                                 NULL,
839
 
                                 NULL);
840
 
 
841
 
        dr->type_time = 60 * gconf_client_get_int (
842
 
                client, GCONF_PATH "/type_time", NULL);
843
 
 
844
 
        dr->warn_time = MIN (dr->type_time / 12, 60*3);
845
 
 
846
 
        dr->break_time = 60 * gconf_client_get_int (
847
 
                client, GCONF_PATH "/break_time", NULL);
848
 
 
849
 
        dr->enabled = gconf_client_get_bool (
850
 
                client,
851
 
                GCONF_PATH "/enabled",
852
 
                NULL);
853
 
 
854
 
        g_object_unref (client);
855
 
 
856
 
        if (debug) {
857
 
                setup_debug_values (dr);
858
 
        }
859
 
 
860
 
        dr->ui_manager = gtk_ui_manager_new ();
861
 
 
862
 
        action_group = gtk_action_group_new ("MenuActions");
863
 
        gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
864
 
        gtk_action_group_add_actions (action_group, actions, G_N_ELEMENTS (actions), dr);
865
 
        gtk_ui_manager_insert_action_group (dr->ui_manager, action_group, 0);
866
 
        gtk_ui_manager_add_ui_from_string (dr->ui_manager, ui_description, -1, NULL);
867
 
 
868
 
        item = gtk_ui_manager_get_widget (dr->ui_manager, "/Pop/TakeABreak");
869
 
        gtk_widget_set_sensitive (item, dr->enabled);
870
 
 
871
 
        dr->timer = drw_timer_new ();
872
 
        dr->idle_timer = drw_timer_new ();
873
 
 
874
 
        dr->state = STATE_START;
875
 
 
876
 
        dr->monitor = drw_monitor_new ();
877
 
 
878
 
        g_signal_connect (dr->monitor,
879
 
                          "activity",
880
 
                          G_CALLBACK (activity_detected_cb),
881
 
                          dr);
882
 
 
883
 
#ifdef HAVE_APP_INDICATOR
884
 
        init_app_indicator (dr);
885
 
#else
886
 
        dr->neutral_bar = gdk_pixbuf_new_from_file (IMAGEDIR "/bar.png", NULL);
887
 
        dr->red_bar = gdk_pixbuf_new_from_file (IMAGEDIR "/bar-red.png", NULL);
888
 
        dr->green_bar = gdk_pixbuf_new_from_file (IMAGEDIR "/bar-green.png", NULL);
889
 
        dr->disabled_bar = gdk_pixbuf_new_from_file (IMAGEDIR "/bar-disabled.png", NULL);
890
 
 
891
 
        init_tray_icon (dr);
892
 
#endif /* HAVE_APP_INDICATOR */
893
 
 
894
 
        g_timeout_add_seconds (12,
895
 
                               (GSourceFunc) update_status,
896
 
                               dr);
897
 
 
898
 
        g_timeout_add_seconds (1,
899
 
                               (GSourceFunc) maybe_change_state,
900
 
                               dr);
901
 
 
902
 
        return dr;
903
 
}