~ubuntu-branches/debian/lenny/gworldclock/lenny

« back to all changes in this revision

Viewing changes to main.c

  • Committer: Bazaar Package Importer
  • Author(s): Drew Parsons
  • Date: 2005-03-28 13:50:18 UTC
  • mfrom: (1.2.1 upstream) (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050328135018-jk2szisqaovghn3s
Tags: 1.4.4-1
* New upstream version.
  - modernised design of AddZone dialog. Closes: #193952.
  - removed use of deprecated GTK functions and objects.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  gworldclock
 
2
 
 
3
This program is designed to keep track of the time and date in various 
 
4
time zones around the world.  
 
5
 
 
6
The zones are kept in a configuration file (default ~/.tzlist), one zone 
 
7
per line.  Each line has one or two entries: the first is the TZ value 
 
8
corresponding, the second is an optional description string enclosed in 
 
9
inverted commas ('"').
 
10
 
 
11
The config file is compatible for use with tzwatch, a shell script 
 
12
writing the time in the given zones to stdout.
 
13
 
 
14
Note, time_t is evil.  It apparently resolves to a 32bit integer (on x86 at 
 
15
least), which only lets the clocks go back to 8:48pm, 13 Dec 1901 (GMT)
 
16
(2147483648 seconds before 1 Jan 1970).
 
17
On the other side, the limit is 19 January 2038, 3:13am.
 
18
There appears to be no simple way around this limitation.  If we use struct tm
 
19
throughout, then on printing to display for each time zone, asctime does not
 
20
update the display for the zone in the way that ctime does.
 
21
(curiously, asctime *is* updated if preceded by ctime in the same line, e.g.
 
22
asprintf( &text, "%.0s%s", ctime(&t), asctime( tp ) );  
 
23
but in this case we still suffer the limitation of the 32bit counter).
 
24
So it's all very silly really.  You'll just have to put up with not syncing
 
25
earlier than 1902.  Too bad for your time machine.
 
26
The alternative is to do some dreadful dreadful frigging around with the
 
27
daylight savings and time difference fields in struct tm, which I'm
 
28
certainly not going to do right now.
 
29
  
 
30
 
 
31
To do:  
 
32
- change CLists (add zone) to TreeViews
 
33
- rewrite "About" text using neater GTK text formatting capabilities.
 
34
- update list of days in month to be correct for the given month 
 
35
- convert time_t references to struct tm and tweak time difference
 
36
by hand to allow years beyond the 2^32 sec limit (?)
 
37
- have someone compile it for Win32 so I can give it to Kostya & Andrei
 
38
*/
 
39
 
 
40
 
 
41
/* Copyright (C) 2000-2005 Drew F. Parsons
 
42
 *
 
43
 *     This program is free software; you can redistribute it and/or modify
 
44
 *     it under the terms of the GNU General Public License as published by
 
45
 *     the Free Software Foundation; ( version 2 of the License at time of 
 
46
 *     writing).
 
47
 *
 
48
 *     This program is distributed in the hope that it will be useful,
 
49
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 
50
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
51
 *     GNU General Public License for more details.
 
52
 *
 
53
 *     You should have received a copy of the GNU General Public License
 
54
 *     along with this program; if not, write to the Free Software
 
55
 *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
56
 */
 
57
 
 
58
#include <config.h>
 
59
#include <errno.h>
 
60
#include <gtk/gtk.h>
 
61
#include <stdlib.h>
 
62
#include <locale.h>
 
63
#include <libintl.h>
 
64
#define _(A) gettext(A)
 
65
 
 
66
#include "main.h"
 
67
#include "options.h"
 
68
#include "zones.h"
 
69
#include "resize.h"
 
70
 
 
71
/* so many global variables....how naughty! 
 
72
collect them in a structure to be passed around? */
 
73
gint changed=0;
 
74
gint OKtoQuit=1;
 
75
GString *configfile;
 
76
GString *optionFile;
 
77
 
 
78
/* id of second timer.
 
79
   Set to -1 during synchronisation.
 
80
*/
 
81
gint timer;
 
82
 
 
83
GtkBox *syncBox;
 
84
 
 
85
const gchar* translate_func (const gchar * s, gpointer p)
 
86
{
 
87
  /* 
 
88
     translation function used for itemfactory
 
89
     added by dancerj, Junichi Uekawa, 26 Jul 2003.
 
90
   */
 
91
  return gettext(s);
 
92
}
 
93
 
 
94
 
 
95
void AboutDialog( GtkWidget *w, gpointer clocklist )
 
96
{
 
97
    GtkWidget *dialog;
 
98
 
 
99
    GString *copyright, *comments, *licence;
 
100
 
 
101
    /* set up strings */
 
102
    copyright = g_string_new( "Drew Parsons <dparsons@emerall.com>  " );
 
103
#ifdef RELEASE_DATE
 
104
    g_string_append(copyright, RELEASE_DATE);
 
105
#endif
 
106
 
 
107
    licence = g_string_new( _("Released under the General Public License (GPL) v2.0") );
 
108
 
 
109
    comments = g_string_new(  _( "gworldclock allows you to keep track of the current time"
 
110
                                 " in time zones all round the world.  You may also \"rendezvous\""
 
111
                                 " your time zones to a specified time and date.") );
 
112
    
 
113
 
 
114
    /* build the about dialog */
 
115
    
 
116
    dialog = gtk_about_dialog_new();
 
117
    
 
118
#ifdef PACKAGE_VERSION
 
119
    gtk_about_dialog_set_version( GTK_ABOUT_DIALOG(dialog), PACKAGE_VERSION );
 
120
#endif
 
121
    gtk_about_dialog_set_copyright( GTK_ABOUT_DIALOG(dialog), copyright->str );
 
122
    gtk_about_dialog_set_comments( GTK_ABOUT_DIALOG(dialog), comments->str );
 
123
    gtk_about_dialog_set_license( GTK_ABOUT_DIALOG(dialog) , licence->str );
 
124
    gtk_about_dialog_set_translator_credits( GTK_ABOUT_DIALOG(dialog), _("translator-credits") );
 
125
 
 
126
    gtk_show_about_dialog( NULL,
 
127
       "copyright", gtk_about_dialog_get_copyright( GTK_ABOUT_DIALOG(dialog) ),
 
128
       "license", gtk_about_dialog_get_license( GTK_ABOUT_DIALOG(dialog) ),
 
129
       "comments", gtk_about_dialog_get_comments( GTK_ABOUT_DIALOG(dialog) ),
 
130
                 NULL );
 
131
 
 
132
    g_string_free(copyright,TRUE);
 
133
    g_string_free(comments,TRUE);
 
134
    g_string_free(licence,TRUE);
 
135
 
 
136
}
 
137
 
 
138
 
 
139
/* ensure we go through the same save routine when quitting from the menu (C-Q)
 
140
   or by pressing the window's 'close' button */
 
141
void send_clock_quit( GtkWidget *w, gpointer clocklist )
 
142
{
 
143
  GdkEvent event;
 
144
  gint return_val;
 
145
  extern gint OKtoQuit;
 
146
 
 
147
  g_signal_emit_by_name((GObject *) gtk_widget_get_toplevel(
 
148
                             (GtkWidget *)g_object_get_data(clocklist, MAIN_WINDOW)), 
 
149
                          "delete_event", &event, &return_val);
 
150
 
 
151
  /* why didn't the above send "delete", which then sends "destroy"??
 
152
     Have to "destroy" by hand...   */
 
153
  if(OKtoQuit)
 
154
    gtk_main_quit();
 
155
  else
 
156
    OKtoQuit=1;
 
157
}
 
158
 
 
159
/* save the config data when quitting, if necessary */
 
160
gint worldclock_quit(GtkWidget *widget,
 
161
                     GdkEvent  *event,
 
162
                     gpointer   clocklist )
 
163
{
 
164
  extern gint changed;
 
165
  extern gint OKtoQuit;
 
166
  extern GString *configfile;
 
167
  gint choice;
 
168
  GtkWidget *dialog;
 
169
 
 
170
  gchar *title="Save Zones";
 
171
  GString *msg;
 
172
  gchar *buttons3[] =  { "Yes", "No", "Cancel" };
 
173
  gchar *buttons2[] =  { "Yes", "No" };
 
174
 
 
175
  SaveOptions();
 
176
 
 
177
  if(changed) 
 
178
  {
 
179
     msg = g_string_new(NULL);
 
180
     g_string_sprintf(msg," Do you want to save your modified zone list? ");
 
181
     dialog = gtk_message_dialog_new( NULL,
 
182
                                      0,
 
183
                                      GTK_MESSAGE_QUESTION,
 
184
                                      GTK_BUTTONS_YES_NO,
 
185
                                      msg->str);
 
186
     gtk_dialog_add_buttons( GTK_DIALOG(dialog), 
 
187
                             "Cancel", GTK_RESPONSE_CANCEL,
 
188
                             NULL);
 
189
     choice = gtk_dialog_run( GTK_DIALOG(dialog) );
 
190
     gtk_widget_destroy (dialog);
 
191
     g_string_free(msg,TRUE);
 
192
     if(choice==GTK_RESPONSE_YES)   /* yes, save */
 
193
     {
 
194
        if (!SaveZones(widget, clocklist)) 
 
195
        {
 
196
           msg = g_string_new(NULL);
 
197
           g_string_sprintf(msg," Error saving zone file \"%s\": \n %s \n\n Continue quitting? ",
 
198
                            configfile->str, g_strerror(errno));
 
199
           dialog = gtk_message_dialog_new( NULL,
 
200
                                            0,
 
201
                                            GTK_MESSAGE_QUESTION,
 
202
                                            GTK_BUTTONS_YES_NO,
 
203
                                            msg->str);
 
204
 
 
205
           choice = gtk_dialog_run (GTK_DIALOG (dialog));
 
206
           gtk_widget_destroy (dialog);
 
207
 
 
208
           g_string_free(msg,TRUE);
 
209
           if(choice==GTK_RESPONSE_NO) /* no, don't quit if there was an error */
 
210
           {
 
211
              OKtoQuit=0;    
 
212
              return TRUE;
 
213
           }
 
214
        }
 
215
        OKtoQuit=1;
 
216
        return FALSE;
 
217
     }
 
218
     else if (choice==GTK_RESPONSE_NO) /* no, don't save */
 
219
     {
 
220
        OKtoQuit=1;
 
221
        return FALSE;
 
222
     }
 
223
     else /* cancel from quitting */
 
224
     {
 
225
        OKtoQuit=0;    
 
226
        return TRUE;
 
227
     }
 
228
  }
 
229
 
 
230
  return FALSE;
 
231
}
 
232
 
 
233
 
 
234
/* Process mouse click when a zone in the list is selected.
 
235
   Double-click with left mouse button (button 1) pops up the 
 
236
   "Change Description" dialog box.
 
237
   Single-click with right button (button 3) pops up the menu of actions.
 
238
*/
 
239
static gboolean ButtonPressedInList (GtkWidget *clocklist, 
 
240
                                     GdkEventButton *event,
 
241
                                     gpointer selection)
 
242
{
 
243
   GtkTreeModel *clocklistModel;
 
244
 
 
245
   static GtkWidget *popup;
 
246
 
 
247
   gboolean returnVal = FALSE;
 
248
 
 
249
   if( (event->button==1) && ( event->type==GDK_2BUTTON_PRESS))
 
250
   {
 
251
      ChangeZoneDescription(clocklist, (gpointer)clocklist);
 
252
      returnVal = TRUE;
 
253
   }
 
254
   /* attempting to identify when reorder has occurred
 
255
      Will probably have to wipe this code 
 
256
      else if ( (event->type==GDK_BUTTON_RELEASE) && (event->button==1)) 
 
257
      {
 
258
      g_print("released button 1 for row %d\n", selectedRow);
 
259
      returnVal = TRUE;
 
260
      }    
 
261
      else if (event->button==1) 
 
262
      {
 
263
      g_print("pressed button 1 for row %d\n", selectedRow);
 
264
      returnVal = FALSE;
 
265
      }
 
266
   */   
 
267
   else if (event->button==3) 
 
268
   {
 
269
      if(!popup) { /* create only once! */
 
270
          popup = gtk_ui_manager_get_widget (g_object_get_data(G_OBJECT(clocklist), UI_MANAGER), "/PopupMenu");
 
271
      }
 
272
      gtk_menu_popup (GTK_MENU(popup), NULL, NULL, NULL, NULL,
 
273
                      event->button, event->time);   
 
274
      returnVal = TRUE;
 
275
   }
 
276
 
 
277
   return returnVal;
 
278
}
 
279
 
 
280
 
 
281
int main( int argc, char *argv[] )
 
282
{
 
283
  GtkWidget *window, *scrolled_window;
 
284
  GtkWidget *main_vbox;
 
285
  GtkWidget *menubar;
 
286
  GtkListStore *clocklistModel;
 
287
  GtkWidget *clocklist;
 
288
  gchar *titles[2] = { N_("Time Zone"), N_("Time&Date") };
 
289
  GtkCellRenderer *renderer;
 
290
  GtkTreeViewColumn *column;
 
291
  GtkTreeSelection *select;
 
292
  GdkRectangle cell;
 
293
  gint cellHeight;
 
294
 
 
295
  GtkActionGroup *action_group;
 
296
  GtkUIManager *ui_manager;
 
297
  GtkAccelGroup *accel_group;
 
298
  GError *error;
 
299
 
 
300
  gint xoff, yoff, h, w;
 
301
  GSignalQuery query;
 
302
 
 
303
  gtk_init (&argc, &argv);
 
304
  GetOptions(argc,argv);
 
305
  bindtextdomain(PACKAGE_NAME, LOCALEDIR);
 
306
  bind_textdomain_codeset (PACKAGE_NAME, "UTF-8");
 
307
  textdomain(PACKAGE_NAME);
 
308
 
 
309
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
310
  g_signal_connect (G_OBJECT (window), "destroy", 
 
311
                      G_CALLBACK (gtk_main_quit), 
 
312
                      "WM destroy");
 
313
  gtk_window_set_title (GTK_WINDOW(window), "gworldclock");
 
314
 
 
315
  main_vbox = gtk_vbox_new (FALSE, 5);
 
316
  gtk_container_border_width (GTK_CONTAINER (main_vbox), 1);
 
317
  gtk_container_add (GTK_CONTAINER (window), main_vbox);
 
318
  gtk_widget_show (main_vbox);
 
319
 
 
320
  /* Create a scrolled window to pack the list widget into */
 
321
  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
 
322
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
 
323
                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
 
324
  
 
325
  gtk_box_pack_end(GTK_BOX(main_vbox), scrolled_window, TRUE, TRUE, 0);
 
326
  gtk_widget_show (scrolled_window);
 
327
 
 
328
 
 
329
  /* the main clock object is created here */
 
330
  clocklistModel = gtk_list_store_new (LIST_COLUMNS, 
 
331
                                  G_TYPE_STRING, /* TZ name */
 
332
                                  G_TYPE_STRING, /* TZ description */
 
333
                                  G_TYPE_STRING  /* time/date */
 
334
     );
 
335
 
 
336
  clocklist = gtk_tree_view_new_with_model (GTK_TREE_MODEL (clocklistModel));  
 
337
  gtk_tree_view_set_reorderable( GTK_TREE_VIEW(clocklist), TRUE );
 
338
  g_signal_connect(G_OBJECT(clocklistModel), "rows_reordered", 
 
339
                   G_CALLBACK(registerReorderedRows), NULL);
 
340
 
 
341
  renderer = gtk_cell_renderer_text_new ();
 
342
  column = gtk_tree_view_column_new_with_attributes (gettext(titles[0]),
 
343
                                                     renderer,
 
344
                                                     "text", TZ_DESCRIPTION,
 
345
                                                     NULL);
 
346
  gtk_tree_view_column_set_sizing( column, GTK_TREE_VIEW_COLUMN_AUTOSIZE );
 
347
 
 
348
  g_signal_connect(G_OBJECT(column), "notify::width", 
 
349
                   G_CALLBACK(updateColumnWidth), clocklist);
 
350
  gtk_tree_view_append_column (GTK_TREE_VIEW (clocklist), column);
 
351
 
 
352
  renderer = gtk_cell_renderer_text_new ();
 
353
  column = gtk_tree_view_column_new_with_attributes (gettext(titles[1]),
 
354
                                                     renderer,
 
355
                                                     "text", TZ_TIMEDATE,
 
356
                                                     NULL);
 
357
  gtk_tree_view_column_set_sizing( column, GTK_TREE_VIEW_COLUMN_AUTOSIZE );
 
358
  gtk_tree_view_append_column (GTK_TREE_VIEW (clocklist), column);
 
359
 
 
360
  select = gtk_tree_view_get_selection (GTK_TREE_VIEW (clocklist));
 
361
  gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
 
362
  
 
363
  g_signal_connect(G_OBJECT(clocklist),
 
364
                   "button_press_event",
 
365
                   G_CALLBACK(ButtonPressedInList),
 
366
                   (gpointer)select);
 
367
 
 
368
  gtk_container_add(GTK_CONTAINER(scrolled_window), clocklist);
 
369
  start_clocks((gpointer)clocklist);
 
370
  gtk_widget_show (clocklist);
 
371
 
 
372
  g_object_set_data(G_OBJECT(clocklist), MAIN_WINDOW, window);
 
373
  g_signal_connect (G_OBJECT (window), "delete_event", 
 
374
                      G_CALLBACK (worldclock_quit), (gpointer)clocklist);
 
375
 
 
376
  /* set up menu */
 
377
  action_group = gtk_action_group_new ("UIActions");
 
378
  gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), clocklist);  
 
379
  gtk_action_group_add_toggle_actions (action_group, toggle_entries, G_N_ELEMENTS (toggle_entries), clocklist);
 
380
  g_object_set_data(G_OBJECT(clocklist), ACTIONS, action_group);
 
381
 
 
382
 
 
383
  ui_manager = gtk_ui_manager_new ();
 
384
  gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
 
385
 
 
386
  accel_group = gtk_ui_manager_get_accel_group (ui_manager);
 
387
  gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
 
388
 
 
389
  error = NULL;
 
390
  if (!gtk_ui_manager_add_ui_from_string (ui_manager, ui_description, -1, &error))
 
391
  {
 
392
      g_message ("building menus failed: %s", error->message);
 
393
      g_error_free (error);
 
394
      exit (EXIT_FAILURE);
 
395
  }
 
396
 
 
397
  menubar = gtk_ui_manager_get_widget (ui_manager, "/MainMenu");
 
398
  gtk_box_pack_start (GTK_BOX (main_vbox), menubar, FALSE, FALSE, 0);
 
399
 
 
400
  g_object_set_data(G_OBJECT(clocklist), UI_MANAGER, ui_manager);
 
401
 
 
402
 
 
403
  /* stick the synchronise control panel at the top and hide it */
 
404
  syncBox = constructSyncBox((gpointer)clocklist);
 
405
  gtk_box_pack_start(GTK_BOX(main_vbox), (GtkWidget *)syncBox, FALSE, FALSE, 0);
 
406
  gtk_widget_hide((GtkWidget *) syncBox );
 
407
 
 
408
  /* calculate the time each second */
 
409
  timer = start_timer( (gpointer)clocklist );
 
410
 
 
411
  gtk_widget_show (window);
 
412
  resizeWindow( window, GTK_TREE_VIEW(clocklist) );
 
413
 
 
414
  gtk_main ();
 
415
         
 
416
  return(0);
 
417
}
 
418