~ubuntu-branches/ubuntu/lucid/awn-extras-applets/lucid

« back to all changes in this revision

Viewing changes to applets/maintained/digital-clock/digital-clock.vala

  • Committer: Bazaar Package Importer
  • Author(s): Julien Lavergne
  • Date: 2010-03-30 20:26:40 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20100330202640-vza3bdnv9gc9bg5z
Tags: 0.4.0~rc1-0ubuntu1
* New upstream release (rc1) (LP: #551309)
 - Stack applet close on click (LP: #261520)
* debian/patches/
 - 03-remove-cairo-menu-pref.patch: From upstream (r1244 + r1245 + r1252),
   remove menu entry for cairo-menu preferences, it's not implemented
   (LP: #511254)
 - 04-tomboy-threading-free.patch: From upstream (r1246), remove threading to
   make the applet working. 
* debian/*.install: Update installation location of comics and digital 
  applets.
* debian/control: 
 - Move digital applet from python to C, and add proper Replaces.
 - Add Replaces for awn-applets-c-core to handle migration from 0.3.2.2.
   (LP: #524559)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Digital-clock applet for Awn (based on applet by Ryan Rushton)
 
3
 *
 
4
 * Copyright (C) 2010 Michal Hruby <michal.mhr@gmail.com>
 
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
 
19
 *
 
20
 * Author : Michal Hruby <michal.mhr@gmail.com>
 
21
 */
 
22
 
 
23
using Awn;
 
24
using DesktopAgnostic.Config;
 
25
 
 
26
class DigitalClock : AppletSimple
 
27
{
 
28
  private const string EVOLUTION_COMMAND =
 
29
    "evolution calendar:///?startdate=%(year)02d%(month)02d%(day)02dT120000";
 
30
  private const string TIME_ADMIN_COMMAND = "gksudo time-admin";
 
31
  private const string[] authors = {
 
32
    "Michal Hruby <michal.mhr@gmail.com>"
 
33
  };
 
34
 
 
35
  private Gtk.Menu _menu;
 
36
  private Awn.Dialog dialog;
 
37
  private OverlayText time_overlay;
 
38
  private OverlayText am_pm_overlay;
 
39
  private OverlayText day_overlay;
 
40
  private OverlayText date_overlay;
 
41
 
 
42
  private DesktopAgnostic.Config.Client client;
 
43
  private string[] current_time = null;
 
44
 
 
45
  private DigitalClockPrefs? prefs = null;
 
46
 
 
47
  public bool is_12_hour { get; set; }
 
48
  public bool show_date { get; set; default = true; }
 
49
  public bool date_before_time { get; set; }
 
50
  public string calendar_command { get; set; default = EVOLUTION_COMMAND; }
 
51
  public string datetime_command { get; set; default = TIME_ADMIN_COMMAND; }
 
52
 
 
53
  public DigitalClock (string canonical_name, string uid, int panel_id)
 
54
  {
 
55
    Object(canonical_name: canonical_name, uid: uid, panel_id: panel_id);
 
56
 
 
57
    this.display_name = Gettext._ ("Digital Clock");
 
58
    this.clicked.connect (this.on_clicked);
 
59
    this.context_menu_popup.connect (this.on_context_menu_popup);
 
60
 
 
61
    this.client = Awn.Config.get_default_for_applet (this);
 
62
    this.client.bind (GROUP_DEFAULT, "hour12", this, "is_12_hour",
 
63
                      true, BindMethod.FALLBACK);
 
64
    this.client.bind (GROUP_DEFAULT, "show_date", this, "show_date",
 
65
                      true, BindMethod.FALLBACK);
 
66
    this.client.bind (GROUP_DEFAULT, "dbt", this, "date_before_time",
 
67
                      true, BindMethod.FALLBACK);
 
68
    this.client.bind ("commands", "calendar", this, "calendar_command",
 
69
                      true, BindMethod.FALLBACK);
 
70
    this.client.bind ("commands", "adjust_datetime", this, "datetime_command",
 
71
                      true, BindMethod.FALLBACK);
 
72
 
 
73
    this.time_overlay = new OverlayText ();
 
74
    this.time_overlay.apply_effects = true;
 
75
    this.add_overlay(this.time_overlay);
 
76
 
 
77
    this.am_pm_overlay = new OverlayText();
 
78
    this.am_pm_overlay.apply_effects = true;
 
79
    this.add_overlay(this.am_pm_overlay);
 
80
 
 
81
    this.day_overlay = new OverlayText();
 
82
    this.day_overlay.apply_effects = true;
 
83
    this.add_overlay(this.day_overlay);
 
84
 
 
85
    this.date_overlay = new OverlayText();
 
86
    this.date_overlay.apply_effects = true;
 
87
    this.add_overlay(this.date_overlay);
 
88
 
 
89
    // we'll just use overlays, but AwnIcon doesn't like not having icon set,
 
90
    // so we'll give it 1x1 transparent pixbuf
 
91
    Gdk.Pixbuf pixbuf = new Gdk.Pixbuf (Gdk.Colorspace.RGB, true, 8, 1, 1);
 
92
    pixbuf.fill (0);
 
93
    this.set_icon_pixbuf (pixbuf);
 
94
 
 
95
    this.position_changed.connect (this.refresh_overlays);
 
96
    this.size_changed.connect (this.refresh_overlays);
 
97
    this.notify.connect (this.force_refresh);
 
98
 
 
99
    this.refresh_overlays ();
 
100
    this.update_clock ();
 
101
 
 
102
    Timeout.add_seconds (1, () => { this.update_clock (); return true; });
 
103
 
 
104
    this.init_calendar ();
 
105
  }
 
106
 
 
107
  private void
 
108
  init_calendar ()
 
109
  {
 
110
    this.dialog = new Awn.Dialog.for_widget (this);
 
111
    this.dialog.hide_on_unfocus = true;
 
112
 
 
113
    Gtk.Calendar calendar = new Gtk.Calendar ();
 
114
    calendar.set_display_options (Gtk.CalendarDisplayOptions.SHOW_HEADING |
 
115
                                  Gtk.CalendarDisplayOptions.SHOW_DAY_NAMES |
 
116
                                  Gtk.CalendarDisplayOptions.SHOW_WEEK_NUMBERS);
 
117
    calendar.day_selected_double_click.connect (this.start_external_calendar);
 
118
 
 
119
    this.dialog.set_title (_ ("Calendar"));
 
120
    this.dialog.add (calendar);
 
121
  }
 
122
 
 
123
  private void
 
124
  start_external_calendar (Gtk.Calendar calendar)
 
125
  {
 
126
    uint year, month, day;
 
127
    calendar.get_date (out year, out month, out day);
 
128
 
 
129
    month++;
 
130
    // damn, this one is pretty complicated to do in Vala
 
131
    string python_cmd =
 
132
      "python -c \"" +
 
133
      "import subprocess;" +
 
134
      "data = {'year': %u, 'month': %u, 'day': %u};".printf (year, month, day) +
 
135
      "command = '%s';".printf (this.calendar_command) +
 
136
      "subprocess.Popen(command % data, shell=True);" +
 
137
      "\"";
 
138
 
 
139
    Process.spawn_command_line_async (python_cmd);
 
140
  }
 
141
 
 
142
  private void
 
143
  force_refresh ()
 
144
  {
 
145
    this.current_time = null;
 
146
    this.refresh_overlays ();
 
147
    this.update_clock ();
 
148
  }
 
149
 
 
150
  private void
 
151
  refresh_overlays ()
 
152
  {
 
153
    Gtk.PositionType position = this.get_pos_type ();
 
154
    int size = this.get_size ();
 
155
 
 
156
    this.am_pm_overlay.active = false;
 
157
    this.day_overlay.active = this.show_date;
 
158
    this.date_overlay.active = this.show_date;
 
159
 
 
160
    if (position == Gtk.PositionType.TOP || position == Gtk.PositionType.BOTTOM)
 
161
    {
 
162
      // horizontal orientation
 
163
      if (this.date_before_time || !this.show_date)
 
164
      {
 
165
        // date on left of time / no date
 
166
        int width = this.show_date ? size * 11 / 5 : size * 3 / 2;
 
167
 
 
168
        this.get_icon ().set_custom_paint (width, size);
 
169
 
 
170
        this.time_overlay.font_sizing = this.show_date ? 22 : 25;
 
171
        this.time_overlay.gravity = this.show_date || this.is_12_hour ?
 
172
            Gdk.Gravity.NORTH_EAST : Gdk.Gravity.CENTER;
 
173
 
 
174
        this.day_overlay.font_sizing = 14;
 
175
        this.day_overlay.gravity = Gdk.Gravity.WEST;
 
176
        this.day_overlay.y_adj = 0;
 
177
 
 
178
        this.date_overlay.font_sizing = 14;
 
179
        this.date_overlay.gravity = Gdk.Gravity.SOUTH_WEST;
 
180
 
 
181
        if (this.is_12_hour)
 
182
        {
 
183
          this.am_pm_overlay.active = true;
 
184
          this.am_pm_overlay.font_sizing = 14;
 
185
          this.am_pm_overlay.gravity = Gdk.Gravity.SOUTH_EAST;
 
186
        }
 
187
      }
 
188
      else
 
189
      {
 
190
        // date below time
 
191
        int width = this.is_12_hour ? size * 17 / 10 : size * 6 / 5;
 
192
 
 
193
        this.get_icon ().set_custom_paint (width, size);
 
194
 
 
195
        this.time_overlay.font_sizing = this.is_12_hour ? 17 : 18;
 
196
        this.time_overlay.gravity = Gdk.Gravity.NORTH;
 
197
 
 
198
        this.day_overlay.font_sizing = 14;
 
199
        this.day_overlay.gravity = Gdk.Gravity.CENTER;
 
200
        this.day_overlay.y_adj = 0.05;
 
201
 
 
202
        this.date_overlay.font_sizing = 14;
 
203
        this.date_overlay.gravity = Gdk.Gravity.SOUTH;
 
204
      }
 
205
    }
 
206
    else
 
207
    {
 
208
      // side orientation, no support for "Date before time"
 
209
      int height;
 
210
      if (this.show_date)
 
211
      {
 
212
        height = size;
 
213
      }
 
214
      else
 
215
      {
 
216
        height = size / 2;
 
217
      }
 
218
 
 
219
      this.get_icon ().set_custom_paint (size, height);
 
220
 
 
221
      this.time_overlay.font_sizing = this.is_12_hour ? 10 : 15;
 
222
      if (!this.show_date) this.time_overlay.font_sizing *= 2;
 
223
      this.time_overlay.gravity = this.show_date ?
 
224
          Gdk.Gravity.NORTH : Gdk.Gravity.CENTER;
 
225
 
 
226
      this.day_overlay.font_sizing = 12;
 
227
      this.day_overlay.gravity = Gdk.Gravity.CENTER;
 
228
      this.day_overlay.y_adj = 0.05;
 
229
 
 
230
      this.date_overlay.font_sizing = 12;
 
231
      this.date_overlay.gravity = Gdk.Gravity.SOUTH;
 
232
    }
 
233
  }
 
234
 
 
235
  private void
 
236
  update_clock ()
 
237
  {
 
238
    if (!this.time_string_changed ()) return;
 
239
 
 
240
    if (!this.is_12_hour || this.am_pm_overlay.active)
 
241
    {
 
242
      this.time_overlay.text = current_time[0];
 
243
      this.am_pm_overlay.text = current_time[1];
 
244
    }
 
245
    else
 
246
    {
 
247
      this.time_overlay.text = "%s %s".printf (current_time[0],
 
248
                                               current_time[1]);
 
249
    }
 
250
 
 
251
    this.day_overlay.text = current_time[2];
 
252
    this.date_overlay.text = current_time[3];
 
253
  }
 
254
 
 
255
  private bool time_string_changed ()
 
256
  {
 
257
    string[] cur_time = this.get_time_string ();
 
258
 
 
259
    if (this.current_time == null)
 
260
    {
 
261
      this.current_time = cur_time;
 
262
      return true;
 
263
    }
 
264
 
 
265
    for (int i=0; i<this.current_time.length; i++)
 
266
    {
 
267
      if (this.current_time[i] != cur_time[i])
 
268
      {
 
269
        this.current_time = cur_time;
 
270
        return true;
 
271
      }
 
272
    }
 
273
 
 
274
    return false;
 
275
  }
 
276
 
 
277
  private static string format_current_time (string format)
 
278
  {
 
279
    time_t cur_time_t = time_t ();
 
280
    Time cur_time = Time.local (cur_time_t);
 
281
 
 
282
    return cur_time.format (format);
 
283
  }
 
284
 
 
285
  private string[] get_time_string ()
 
286
  {
 
287
    string[] full_date = new string[4];
 
288
 
 
289
    time_t cur_time_t = time_t ();
 
290
    Time cur_time = Time.local (cur_time_t);
 
291
 
 
292
    if (this.is_12_hour)
 
293
    {
 
294
      full_date[0] = cur_time.format ("%I:%M");
 
295
      full_date[1] = cur_time.format ("%p");
 
296
    }
 
297
    else
 
298
    {
 
299
      full_date[0] = cur_time.format ("%H:%M");
 
300
      full_date[1] = "";
 
301
    }
 
302
 
 
303
    full_date[2] = cur_time.format ("%a");
 
304
    full_date[3] = cur_time.format ("%b %d");
 
305
 
 
306
    return full_date;
 
307
  }
 
308
 
 
309
  private void
 
310
  on_clicked ()
 
311
  {
 
312
    Gtk.WidgetFlags flags = this.dialog.get_flags () & Gtk.WidgetFlags.VISIBLE;
 
313
    if (flags != Gtk.WidgetFlags.VISIBLE)
 
314
    {
 
315
      this.dialog.show_all ();
 
316
    }
 
317
    else
 
318
    {
 
319
      this.dialog.hide ();
 
320
    }
 
321
  }
 
322
 
 
323
  private void
 
324
  on_context_menu_popup (Gdk.EventButton event)
 
325
  {
 
326
    if (this._menu == null)
 
327
    {
 
328
      Gtk.ImageMenuItem image_item;
 
329
      Gtk.MenuItem menu_item;
 
330
      Gtk.Widget about_item;
 
331
 
 
332
      this._menu = this.create_default_menu () as Gtk.Menu;
 
333
 
 
334
      // "Copy Time" menu item
 
335
      image_item = new Gtk.ImageMenuItem.with_label (_ ("Copy Time"));
 
336
      image_item.set_image (new Gtk.Image.from_stock (Gtk.STOCK_COPY,
 
337
                                                      Gtk.IconSize.MENU));
 
338
      image_item.activate.connect ((w) =>
 
339
      {
 
340
        unowned Gtk.Clipboard cb = Gtk.Clipboard.get (Gdk.SELECTION_CLIPBOARD);
 
341
        if (this.is_12_hour)
 
342
        {
 
343
          cb.set_text (format_current_time ("%I:%M %p"), -1);
 
344
        }
 
345
        else
 
346
        {
 
347
          cb.set_text (format_current_time ("%H:%M"), -1);
 
348
        }
 
349
      });
 
350
      image_item.show ();
 
351
      this._menu.append (image_item);
 
352
 
 
353
      // "Copy Date" menu item
 
354
      image_item = new Gtk.ImageMenuItem.with_label (_ ("Copy Date"));
 
355
      image_item.set_image (new Gtk.Image.from_stock (Gtk.STOCK_COPY,
 
356
                                                      Gtk.IconSize.MENU));
 
357
      image_item.activate.connect ((w) =>
 
358
      {
 
359
        unowned Gtk.Clipboard cb = Gtk.Clipboard.get (Gdk.SELECTION_CLIPBOARD);
 
360
        cb.set_text (format_current_time ("%A, %B %d %Y"), -1);
 
361
      });
 
362
      image_item.show ();
 
363
      this._menu.append (image_item);
 
364
 
 
365
      // "Adjust Date & Time" menu item
 
366
      image_item = new Gtk.ImageMenuItem.with_label (_ ("Adjust Date & Time"));
 
367
      image_item.set_image (new Gtk.Image.from_stock (Gtk.STOCK_EDIT,
 
368
                                                      Gtk.IconSize.MENU));
 
369
      image_item.activate.connect ((w) =>
 
370
      {
 
371
        if (this.datetime_command.length > 0)
 
372
        {
 
373
          Process.spawn_command_line_async (this.datetime_command);
 
374
        }
 
375
      });
 
376
      image_item.show ();
 
377
      this._menu.append (image_item);
 
378
 
 
379
      // Separator
 
380
      menu_item = new Gtk.SeparatorMenuItem ();
 
381
      menu_item.show ();
 
382
      this._menu.append (menu_item);
 
383
 
 
384
      image_item = new Gtk.ImageMenuItem.from_stock (Gtk.STOCK_PREFERENCES, null);
 
385
      image_item.activate.connect ((w) =>
 
386
      {
 
387
        if (this.prefs == null)
 
388
        {
 
389
          this.prefs = new DigitalClockPrefs (this);
 
390
 
 
391
          this.prefs.get_dialog ().run ();
 
392
          this.prefs.get_dialog ().destroy ();
 
393
 
 
394
          this.prefs = null;
 
395
        }
 
396
        else
 
397
        {
 
398
          var dialog = this.prefs.get_dialog ();
 
399
          dialog.present_with_time (Gtk.get_current_event_time ());
 
400
        }
 
401
      });
 
402
      image_item.show ();
 
403
      this._menu.append (image_item);
 
404
 
 
405
      // Separator
 
406
      Gtk.MenuItem separator = new Gtk.SeparatorMenuItem ();
 
407
      separator.show ();
 
408
      this._menu.append (separator);
 
409
 
 
410
      about_item = this.create_about_item ("Copyright © 2010 Michal Hruby",
 
411
                                           AppletLicense.GPLV2, Build.VERSION,
 
412
                                           Gettext._ ("Displays digital clock."),
 
413
                                           null, null, "awn-applet-digital-clock",
 
414
                                           null, authors, null, null);
 
415
      about_item.show ();
 
416
      this._menu.append (about_item as Gtk.MenuItem);
 
417
    }
 
418
    this._menu.set_screen (null);
 
419
    this._menu.popup (null, null, null, event.button, event.time);
 
420
  }
 
421
}
 
422
 
 
423
public Applet
 
424
awn_applet_factory_initp (string canonical_name, string uid, int panel_id)
 
425
{
 
426
  // i18n support
 
427
  Gettext.bindtextdomain (Build.GETTEXT_PACKAGE, Build.LOCALEDIR);
 
428
  Gettext.textdomain (Build.GETTEXT_PACKAGE);
 
429
 
 
430
  return new DigitalClock (canonical_name, uid, panel_id);
 
431
}
 
432
 
 
433
// vim:ft=vala:et:ts=2 sts=2 sw=2:ai:cindent