~charlesk/indicator-datetime/fix-833337

« back to all changes in this revision

Viewing changes to libmap/cc-timezone-map.c

  • Committer: Charles Kerr
  • Date: 2012-02-15 19:25:19 UTC
  • mfrom: (144.2.4 indicator-datetime)
  • Revision ID: charles.kerr@canonical.com-20120215192519-288t3bik3u0u5zyc
lp:~mterry/indicator-datetime/libtimezonemap

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2010 Intel, Inc
3
 
 * Copyright (C) 2011 Canonical Ltd.
4
 
 *
5
 
 * Portions from Ubiquity, Copyright (C) 2009 Canonical Ltd.
6
 
 * Written by Evan Dandrea <evand@ubuntu.com>
7
 
 *
8
 
 * This program is free software; you can redistribute it and/or modify
9
 
 * it under the terms of the GNU General Public License as published by
10
 
 * the Free Software Foundation; either version 2 of the License, or
11
 
 * (at your option) any later version.
12
 
 *
13
 
 * This program is distributed in the hope that it will be useful,
14
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
 * GNU General Public License for more details.
17
 
 *
18
 
 * You should have received a copy of the GNU General Public License
19
 
 * along with this program; if not, write to the Free Software
20
 
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
 
 *
22
 
 * Author: Thomas Wood <thomas.wood@intel.com>
23
 
 *
24
 
 */
25
 
 
26
 
#include "cc-timezone-map.h"
27
 
#include <math.h>
28
 
#include "tz.h"
29
 
 
30
 
G_DEFINE_TYPE (CcTimezoneMap, cc_timezone_map, GTK_TYPE_WIDGET)
31
 
 
32
 
#define TIMEZONE_MAP_PRIVATE(o) \
33
 
  (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_TIMEZONE_MAP, CcTimezoneMapPrivate))
34
 
 
35
 
 
36
 
typedef struct
37
 
{
38
 
  gdouble offset;
39
 
  guchar red;
40
 
  guchar green;
41
 
  guchar blue;
42
 
  guchar alpha;
43
 
} CcTimezoneMapOffset;
44
 
 
45
 
struct _CcTimezoneMapPrivate
46
 
{
47
 
  GdkPixbuf *orig_background;
48
 
  GdkPixbuf *orig_color_map;
49
 
 
50
 
  GdkPixbuf *background;
51
 
  GdkPixbuf *color_map;
52
 
  GdkPixbuf *olsen_map;
53
 
 
54
 
  guchar *visible_map_pixels;
55
 
  gint visible_map_rowstride;
56
 
 
57
 
  gint olsen_map_channels;
58
 
  guchar *olsen_map_pixels;
59
 
  gint olsen_map_rowstride;
60
 
 
61
 
  gdouble selected_offset;
62
 
 
63
 
  gchar *watermark;
64
 
 
65
 
  TzDB *tzdb;
66
 
  TzLocation *location;
67
 
  GHashTable *alias_db;
68
 
};
69
 
 
70
 
enum
71
 
{
72
 
  LOCATION_CHANGED,
73
 
  LAST_SIGNAL
74
 
};
75
 
 
76
 
static guint signals[LAST_SIGNAL];
77
 
 
78
 
 
79
 
static CcTimezoneMapOffset color_codes[] =
80
 
{
81
 
    {-11.0, 43, 0, 0, 255 },
82
 
    {-10.0, 85, 0, 0, 255 },
83
 
    {-9.5, 102, 255, 0, 255 },
84
 
    {-9.0, 128, 0, 0, 255 },
85
 
    {-8.0, 170, 0, 0, 255 },
86
 
    {-7.0, 212, 0, 0, 255 },
87
 
    {-6.0, 255, 0, 1, 255 }, // north
88
 
    {-6.0, 255, 0, 0, 255 }, // south
89
 
    {-5.0, 255, 42, 42, 255 },
90
 
    {-4.5, 192, 255, 0, 255 },
91
 
    {-4.0, 255, 85, 85, 255 },
92
 
    {-3.5, 0, 255, 0, 255 },
93
 
    {-3.0, 255, 128, 128, 255 },
94
 
    {-2.0, 255, 170, 170, 255 },
95
 
    {-1.0, 255, 213, 213, 255 },
96
 
    {0.0, 43, 17, 0, 255 },
97
 
    {1.0, 85, 34, 0, 255 },
98
 
    {2.0, 128, 51, 0, 255 },
99
 
    {3.0, 170, 68, 0, 255 },
100
 
    {3.5, 0, 255, 102, 255 },
101
 
    {4.0, 212, 85, 0, 255 },
102
 
    {4.5, 0, 204, 255, 255 },
103
 
    {5.0, 255, 102, 0, 255 },
104
 
    {5.5, 0, 102, 255, 255 },
105
 
    {5.75, 0, 238, 207, 247 },
106
 
    {6.0, 255, 127, 42, 255 },
107
 
    {6.5, 204, 0, 254, 254 },
108
 
    {7.0, 255, 153, 85, 255 },
109
 
    {8.0, 255, 179, 128, 255 },
110
 
    {9.0, 255, 204, 170, 255 },
111
 
    {9.5, 170, 0, 68, 250 },
112
 
    {10.0, 255, 230, 213, 255 },
113
 
    {10.5, 212, 124, 21, 250 },
114
 
    {11.0, 212, 170, 0, 255 },
115
 
    {11.5, 249, 25, 87, 253 },
116
 
    {12.0, 255, 204, 0, 255 },
117
 
    {12.75, 254, 74, 100, 248 },
118
 
    {13.0, 255, 85, 153, 250 },
119
 
    {-100, 0, 0, 0, 0 }
120
 
};
121
 
 
122
 
static const gchar * olsen_map_timezones[] = {
123
 
    "Africa/Abidjan",
124
 
    "Africa/Accra",
125
 
    "Africa/Addis_Ababa",
126
 
    "Africa/Algiers",
127
 
    "Africa/Asmara",
128
 
    "Africa/Bamako",
129
 
    "Africa/Bangui",
130
 
    "Africa/Banjul",
131
 
    "Africa/Bissau",
132
 
    "Africa/Blantyre",
133
 
    "Africa/Brazzaville",
134
 
    "Africa/Bujumbura",
135
 
    "Africa/Cairo",
136
 
    "Africa/Casablanca",
137
 
    "Africa/Conakry",
138
 
    "Africa/Dakar",
139
 
    "Africa/Dar_es_Salaam",
140
 
    "Africa/Djibouti",
141
 
    "Africa/Douala",
142
 
    "Africa/El_Aaiun",
143
 
    "Africa/Freetown",
144
 
    "Africa/Gaborone",
145
 
    "Africa/Harare",
146
 
    "Africa/Johannesburg",
147
 
    "Africa/Kampala",
148
 
    "Africa/Khartoum",
149
 
    "Africa/Kigali",
150
 
    "Africa/Kinshasa",
151
 
    "Africa/Lagos",
152
 
    "Africa/Libreville",
153
 
    "Africa/Lome",
154
 
    "Africa/Luanda",
155
 
    "Africa/Lubumbashi",
156
 
    "Africa/Lusaka",
157
 
    "Africa/Malabo",
158
 
    "Africa/Maputo",
159
 
    "Africa/Maseru",
160
 
    "Africa/Mbabane",
161
 
    "Africa/Mogadishu",
162
 
    "Africa/Monrovia",
163
 
    "Africa/Nairobi",
164
 
    "Africa/Ndjamena",
165
 
    "Africa/Niamey",
166
 
    "Africa/Nouakchott",
167
 
    "Africa/Ouagadougou",
168
 
    "Africa/Porto-Novo",
169
 
    "Africa/Sao_Tome",
170
 
    "Africa/Tripoli",
171
 
    "Africa/Tunis",
172
 
    "Africa/Windhoek",
173
 
    "America/Adak",
174
 
    "America/Anguilla",
175
 
    "America/Antigua",
176
 
    "America/Araguaina",
177
 
    "America/Argentina/Buenos_Aires",
178
 
    "America/Argentina/Catamarca",
179
 
    "America/Argentina/Cordoba",
180
 
    "America/Argentina/Jujuy",
181
 
    "America/Argentina/La_Rioja",
182
 
    "America/Argentina/Mendoza",
183
 
    "America/Argentina/Rio_Gallegos",
184
 
    "America/Argentina/San_Juan",
185
 
    "America/Argentina/San_Luis",
186
 
    "America/Argentina/Tucuman",
187
 
    "America/Argentina/Ushuaia",
188
 
    "America/Aruba",
189
 
    "America/Asuncion",
190
 
    "America/Atikokan",
191
 
    "America/Bahia",
192
 
    "America/Barbados",
193
 
    "America/Belem",
194
 
    "America/Belize",
195
 
    "America/Blanc-Sablon",
196
 
    "America/Boa_Vista",
197
 
    "America/Bogota",
198
 
    "America/Boise",
199
 
    "America/Cambridge_Bay",
200
 
    "America/Campo_Grande",
201
 
    "America/Cancun",
202
 
    "America/Caracas",
203
 
    "America/Cayenne",
204
 
    "America/Cayman",
205
 
    "America/Chicago",
206
 
    "America/Chihuahua",
207
 
    "America/Coral_Harbour",
208
 
    "America/Costa_Rica",
209
 
    "America/Cuiaba",
210
 
    "America/Curacao",
211
 
    "America/Dawson",
212
 
    "America/Dawson_Creek",
213
 
    "America/Denver",
214
 
    "America/Dominica",
215
 
    "America/Edmonton",
216
 
    "America/Eirunepe",
217
 
    "America/El_Salvador",
218
 
    "America/Fortaleza",
219
 
    "America/Glace_Bay",
220
 
    "America/Goose_Bay",
221
 
    "America/Grand_Turk",
222
 
    "America/Grenada",
223
 
    "America/Guadeloupe",
224
 
    "America/Guatemala",
225
 
    "America/Guayaquil",
226
 
    "America/Guyana",
227
 
    "America/Halifax",
228
 
    "America/Havana",
229
 
    "America/Hermosillo",
230
 
    "America/Indiana/Indianapolis",
231
 
    "America/Indiana/Knox",
232
 
    "America/Indiana/Marengo",
233
 
    "America/Indiana/Petersburg",
234
 
    "America/Indiana/Vevay",
235
 
    "America/Indiana/Vincennes",
236
 
    "America/Indiana/Winamac",
237
 
    "America/Inuvik",
238
 
    "America/Iqaluit",
239
 
    "America/Jamaica",
240
 
    "America/Juneau",
241
 
    "America/Kentucky/Louisville",
242
 
    "America/Kentucky/Monticello",
243
 
    "America/La_Paz",
244
 
    "America/Lima",
245
 
    "America/Los_Angeles",
246
 
    "America/Maceio",
247
 
    "America/Managua",
248
 
    "America/Manaus",
249
 
    "America/Marigot",
250
 
    "America/Martinique",
251
 
    "America/Mazatlan",
252
 
    "America/Menominee",
253
 
    "America/Merida",
254
 
    "America/Mexico_City",
255
 
    "America/Miquelon",
256
 
    "America/Moncton",
257
 
    "America/Monterrey",
258
 
    "America/Montevideo",
259
 
    "America/Montreal",
260
 
    "America/Montserrat",
261
 
    "America/Nassau",
262
 
    "America/New_York",
263
 
    "America/Nipigon",
264
 
    "America/Noronha",
265
 
    "America/North_Dakota/Center",
266
 
    "America/North_Dakota/Salem",
267
 
    "America/Panama",
268
 
    "America/Pangnirtung",
269
 
    "America/Paramaribo",
270
 
    "America/Phoenix",
271
 
    "America/Port-au-Prince",
272
 
    "America/Port_of_Spain",
273
 
    "America/Porto_Velho",
274
 
    "America/Puerto_Rico",
275
 
    "America/Rainy_River",
276
 
    "America/Rankin_Inlet",
277
 
    "America/Recife",
278
 
    "America/Regina",
279
 
    "America/Resolute",
280
 
    "America/Rio_Branco",
281
 
    "America/Santarem",
282
 
    "America/Santiago",
283
 
    "America/Santo_Domingo",
284
 
    "America/Sao_Paulo",
285
 
    "America/St_Barthelemy",
286
 
    "America/St_Johns",
287
 
    "America/St_Kitts",
288
 
    "America/St_Lucia",
289
 
    "America/St_Thomas",
290
 
    "America/St_Vincent",
291
 
    "America/Tegucigalpa",
292
 
    "America/Thunder_Bay",
293
 
    "America/Tijuana",
294
 
    "America/Toronto",
295
 
    "America/Tortola",
296
 
    "America/Vancouver",
297
 
    "America/Whitehorse",
298
 
    "America/Winnipeg",
299
 
    "America/Yellowknife",
300
 
    "Ameriica/Swift_Current",
301
 
    "Arctic/Longyearbyen",
302
 
    "Asia/Aden",
303
 
    "Asia/Almaty",
304
 
    "Asia/Amman",
305
 
    "Asia/Anadyr",
306
 
    "Asia/Aqtau",
307
 
    "Asia/Aqtobe",
308
 
    "Asia/Ashgabat",
309
 
    "Asia/Baghdad",
310
 
    "Asia/Bahrain",
311
 
    "Asia/Baku",
312
 
    "Asia/Bangkok",
313
 
    "Asia/Beirut",
314
 
    "Asia/Bishkek",
315
 
    "Asia/Brunei",
316
 
    "Asia/Choibalsan",
317
 
    "Asia/Chongqing",
318
 
    "Asia/Colombo",
319
 
    "Asia/Damascus",
320
 
    "Asia/Dhaka",
321
 
    "Asia/Dili",
322
 
    "Asia/Dubai",
323
 
    "Asia/Dushanbe",
324
 
    "Asia/Gaza",
325
 
    "Asia/Harbin",
326
 
    "Asia/Ho_Chi_Minh",
327
 
    "Asia/Hong_Kong",
328
 
    "Asia/Hovd",
329
 
    "Asia/Irkutsk",
330
 
    "Asia/Jakarta",
331
 
    "Asia/Jayapura",
332
 
    "Asia/Jerusalem",
333
 
    "Asia/Kabul",
334
 
    "Asia/Kamchatka",
335
 
    "Asia/Karachi",
336
 
    "Asia/Kashgar",
337
 
    "Asia/Katmandu",
338
 
    "Asia/Kolkata",
339
 
    "Asia/Krasnoyarsk",
340
 
    "Asia/Kuala_Lumpur",
341
 
    "Asia/Kuching",
342
 
    "Asia/Kuwait",
343
 
    "Asia/Macau",
344
 
    "Asia/Magadan",
345
 
    "Asia/Makassar",
346
 
    "Asia/Manila",
347
 
    "Asia/Muscat",
348
 
    "Asia/Nicosia",
349
 
    "Asia/Novosibirsk",
350
 
    "Asia/Omsk",
351
 
    "Asia/Oral",
352
 
    "Asia/Phnom_Penh",
353
 
    "Asia/Pontianak",
354
 
    "Asia/Pyongyang",
355
 
    "Asia/Qatar",
356
 
    "Asia/Qyzylorda",
357
 
    "Asia/Rangoon",
358
 
    "Asia/Riyadh",
359
 
    "Asia/Sakhalin",
360
 
    "Asia/Samarkand",
361
 
    "Asia/Seoul",
362
 
    "Asia/Shanghai",
363
 
    "Asia/Singapore",
364
 
    "Asia/Taipei",
365
 
    "Asia/Tashkent",
366
 
    "Asia/Tbilisi",
367
 
    "Asia/Tehran",
368
 
    "Asia/Thimphu",
369
 
    "Asia/Tokyo",
370
 
    "Asia/Ulaanbaatar",
371
 
    "Asia/Urumqi",
372
 
    "Asia/Vientiane",
373
 
    "Asia/Vladivostok",
374
 
    "Asia/Yakutsk",
375
 
    "Asia/Yekaterinburg",
376
 
    "Asia/Yerevan",
377
 
    "Atlantic/Azores",
378
 
    "Atlantic/Bermuda",
379
 
    "Atlantic/Canary",
380
 
    "Atlantic/Cape_Verde",
381
 
    "Atlantic/Faroe",
382
 
    "Atlantic/Madeira",
383
 
    "Atlantic/Reykjavik",
384
 
    "Atlantic/South_Georgia",
385
 
    "Atlantic/St_Helena",
386
 
    "Atlantic/Stanley",
387
 
    "Australia/Adelaide",
388
 
    "Australia/Brisbane",
389
 
    "Australia/Broken_Hill",
390
 
    "Australia/Currie",
391
 
    "Australia/Darwin",
392
 
    "Australia/Eucla",
393
 
    "Australia/Hobart",
394
 
    "Australia/Lindeman",
395
 
    "Australia/Lord_Howe",
396
 
    "Australia/Melbourne",
397
 
    "Australia/Perth",
398
 
    "Australia/Sydney",
399
 
    "Europe/Amsterdam",
400
 
    "Europe/Andorra",
401
 
    "Europe/Athens",
402
 
    "Europe/Belgrade",
403
 
    "Europe/Berlin",
404
 
    "Europe/Bratislava",
405
 
    "Europe/Brussels",
406
 
    "Europe/Bucharest",
407
 
    "Europe/Budapest",
408
 
    "Europe/Chisinau",
409
 
    "Europe/Copenhagen",
410
 
    "Europe/Dublin",
411
 
    "Europe/Gibraltar",
412
 
    "Europe/Guernsey",
413
 
    "Europe/Helsinki",
414
 
    "Europe/Isle_of_Man",
415
 
    "Europe/Istanbul",
416
 
    "Europe/Jersey",
417
 
    "Europe/Kaliningrad",
418
 
    "Europe/Kiev",
419
 
    "Europe/Lisbon",
420
 
    "Europe/Ljubljana",
421
 
    "Europe/London",
422
 
    "Europe/Luxembourg",
423
 
    "Europe/Madrid",
424
 
    "Europe/Malta",
425
 
    "Europe/Marienhamn",
426
 
    "Europe/Minsk",
427
 
    "Europe/Monaco",
428
 
    "Europe/Moscow",
429
 
    "Europe/Oslo",
430
 
    "Europe/Paris",
431
 
    "Europe/Podgorica",
432
 
    "Europe/Prague",
433
 
    "Europe/Riga",
434
 
    "Europe/Rome",
435
 
    "Europe/Samara",
436
 
    "Europe/San_Marino",
437
 
    "Europe/Sarajevo",
438
 
    "Europe/Simferopol",
439
 
    "Europe/Skopje",
440
 
    "Europe/Sofia",
441
 
    "Europe/Stockholm",
442
 
    "Europe/Tallinn",
443
 
    "Europe/Tirane",
444
 
    "Europe/Uzhgorod",
445
 
    "Europe/Vaduz",
446
 
    "Europe/Vatican",
447
 
    "Europe/Vienna",
448
 
    "Europe/Vilnius",
449
 
    "Europe/Volgograd",
450
 
    "Europe/Warsaw",
451
 
    "Europe/Zagreb",
452
 
    "Europe/Zaporozhye",
453
 
    "Europe/Zurich",
454
 
    "Indian/Antananarivo",
455
 
    "Indian/Chagos",
456
 
    "Indian/Christmas",
457
 
    "Indian/Cocos",
458
 
    "Indian/Comoro",
459
 
    "Indian/Kerguelen",
460
 
    "Indian/Mahe",
461
 
    "Indian/Maldives",
462
 
    "Indian/Mauritius",
463
 
    "Indian/Mayotte",
464
 
    "Indian/Reunion",
465
 
    "Pacific/Apia",
466
 
    "Pacific/Auckland",
467
 
    "Pacific/Chatham",
468
 
    "Pacific/Easter",
469
 
    "Pacific/Efate",
470
 
    "Pacific/Enderbury",
471
 
    "Pacific/Fakaofo",
472
 
    "Pacific/Fiji",
473
 
    "Pacific/Funafuti",
474
 
    "Pacific/Galapagos",
475
 
    "Pacific/Gambier",
476
 
    "Pacific/Guadalcanal",
477
 
    "Pacific/Guam",
478
 
    "Pacific/Honolulu",
479
 
    "Pacific/Johnston",
480
 
    "Pacific/Kiritimati",
481
 
    "Pacific/Kosrae",
482
 
    "Pacific/Kwajalein",
483
 
    "Pacific/Majuro",
484
 
    "Pacific/Marquesas",
485
 
    "Pacific/Midway",
486
 
    "Pacific/Nauru",
487
 
    "Pacific/Niue",
488
 
    "Pacific/Norfolk",
489
 
    "Pacific/Noumea",
490
 
    "Pacific/Pago_Pago",
491
 
    "Pacific/Palau",
492
 
    "Pacific/Pitcairn",
493
 
    "Pacific/Ponape",
494
 
    "Pacific/Port_Moresby",
495
 
    "Pacific/Rarotonga",
496
 
    "Pacific/Saipan",
497
 
    "Pacific/Tahiti",
498
 
    "Pacific/Tarawa",
499
 
    "Pacific/Tongatapu",
500
 
    "Pacific/Truk",
501
 
    "Pacific/Wake",
502
 
    "Pacific/Wallis"
503
 
};
504
 
 
505
 
static void
506
 
cc_timezone_map_get_property (GObject    *object,
507
 
                              guint       property_id,
508
 
                              GValue     *value,
509
 
                              GParamSpec *pspec)
510
 
{
511
 
  switch (property_id)
512
 
    {
513
 
    default:
514
 
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
515
 
    }
516
 
}
517
 
 
518
 
static void
519
 
cc_timezone_map_set_property (GObject      *object,
520
 
                              guint         property_id,
521
 
                              const GValue *value,
522
 
                              GParamSpec   *pspec)
523
 
{
524
 
  switch (property_id)
525
 
    {
526
 
    default:
527
 
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
528
 
    }
529
 
}
530
 
 
531
 
static void
532
 
cc_timezone_map_dispose (GObject *object)
533
 
{
534
 
  CcTimezoneMapPrivate *priv = CC_TIMEZONE_MAP (object)->priv;
535
 
 
536
 
  if (priv->orig_background)
537
 
    {
538
 
      g_object_unref (priv->orig_background);
539
 
      priv->orig_background = NULL;
540
 
    }
541
 
 
542
 
  if (priv->orig_color_map)
543
 
    {
544
 
      g_object_unref (priv->orig_color_map);
545
 
      priv->orig_color_map = NULL;
546
 
    }
547
 
 
548
 
  if (priv->olsen_map)
549
 
    {
550
 
      g_object_unref (priv->olsen_map);
551
 
      priv->olsen_map = NULL;
552
 
 
553
 
      priv->olsen_map_channels = 0;
554
 
      priv->olsen_map_pixels = NULL;
555
 
      priv->olsen_map_rowstride = 0;
556
 
    }
557
 
 
558
 
  if (priv->background)
559
 
    {
560
 
      g_object_unref (priv->background);
561
 
      priv->background = NULL;
562
 
    }
563
 
 
564
 
  if (priv->color_map)
565
 
    {
566
 
      g_object_unref (priv->color_map);
567
 
      priv->color_map = NULL;
568
 
 
569
 
      priv->visible_map_pixels = NULL;
570
 
      priv->visible_map_rowstride = 0;
571
 
    }
572
 
 
573
 
  if (priv->alias_db)
574
 
    {
575
 
      g_hash_table_destroy (priv->alias_db);
576
 
      priv->alias_db = NULL;
577
 
    }
578
 
 
579
 
  if (priv->watermark)
580
 
    {
581
 
      g_free (priv->watermark);
582
 
      priv->watermark = NULL;
583
 
    }
584
 
 
585
 
  G_OBJECT_CLASS (cc_timezone_map_parent_class)->dispose (object);
586
 
}
587
 
 
588
 
static void
589
 
cc_timezone_map_finalize (GObject *object)
590
 
{
591
 
  CcTimezoneMapPrivate *priv = CC_TIMEZONE_MAP (object)->priv;
592
 
 
593
 
  if (priv->tzdb)
594
 
    {
595
 
      tz_db_free (priv->tzdb);
596
 
      priv->tzdb = NULL;
597
 
    }
598
 
 
599
 
 
600
 
  G_OBJECT_CLASS (cc_timezone_map_parent_class)->finalize (object);
601
 
}
602
 
 
603
 
/* GtkWidget functions */
604
 
static void
605
 
cc_timezone_map_get_preferred_width (GtkWidget *widget,
606
 
                                     gint      *minimum,
607
 
                                     gint      *natural)
608
 
{
609
 
  /* choose a minimum size small enough to prevent the window
610
 
   * from growing horizontally
611
 
   */
612
 
  if (minimum != NULL)
613
 
    *minimum = 300;
614
 
  if (natural != NULL)
615
 
    *natural = 300;
616
 
}
617
 
 
618
 
static void
619
 
cc_timezone_map_get_preferred_height (GtkWidget *widget,
620
 
                                      gint      *minimum,
621
 
                                      gint      *natural)
622
 
{
623
 
  CcTimezoneMapPrivate *priv = CC_TIMEZONE_MAP (widget)->priv;
624
 
  gint size;
625
 
 
626
 
  /* The + 20 here is a slight tweak to make the map fill the
627
 
   * panel better without causing horizontal growing
628
 
   */
629
 
  size = 300 * gdk_pixbuf_get_height (priv->orig_background) / gdk_pixbuf_get_width (priv->orig_background) + 20;
630
 
  if (minimum != NULL)
631
 
    *minimum = size;
632
 
  if (natural != NULL)
633
 
    *natural = size;
634
 
}
635
 
 
636
 
static void
637
 
cc_timezone_map_size_allocate (GtkWidget     *widget,
638
 
                               GtkAllocation *allocation)
639
 
{
640
 
  CcTimezoneMapPrivate *priv = CC_TIMEZONE_MAP (widget)->priv;
641
 
 
642
 
  if (priv->background)
643
 
    g_object_unref (priv->background);
644
 
 
645
 
  priv->background = gdk_pixbuf_scale_simple (priv->orig_background,
646
 
                                              allocation->width,
647
 
                                              allocation->height,
648
 
                                              GDK_INTERP_BILINEAR);
649
 
 
650
 
  if (priv->color_map)
651
 
    g_object_unref (priv->color_map);
652
 
 
653
 
  priv->color_map = gdk_pixbuf_scale_simple (priv->orig_color_map,
654
 
                                             allocation->width,
655
 
                                             allocation->height,
656
 
                                             GDK_INTERP_BILINEAR);
657
 
 
658
 
  priv->visible_map_pixels = gdk_pixbuf_get_pixels (priv->color_map);
659
 
  priv->visible_map_rowstride = gdk_pixbuf_get_rowstride (priv->color_map);
660
 
 
661
 
  GTK_WIDGET_CLASS (cc_timezone_map_parent_class)->size_allocate (widget,
662
 
                                                                  allocation);
663
 
}
664
 
 
665
 
static void
666
 
cc_timezone_map_realize (GtkWidget *widget)
667
 
{
668
 
  GdkWindowAttr attr = { 0, };
669
 
  GtkAllocation allocation;
670
 
  GdkCursor *cursor;
671
 
  GdkWindow *window;
672
 
 
673
 
  gtk_widget_get_allocation (widget, &allocation);
674
 
 
675
 
  gtk_widget_set_realized (widget, TRUE);
676
 
 
677
 
  attr.window_type = GDK_WINDOW_CHILD;
678
 
  attr.wclass = GDK_INPUT_OUTPUT;
679
 
  attr.width = allocation.width;
680
 
  attr.height = allocation.height;
681
 
  attr.x = allocation.x;
682
 
  attr.y = allocation.y;
683
 
  attr.event_mask = gtk_widget_get_events (widget)
684
 
                                 | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK;
685
 
 
686
 
  window = gdk_window_new (gtk_widget_get_parent_window (widget), &attr,
687
 
                           GDK_WA_X | GDK_WA_Y);
688
 
 
689
 
  gdk_window_set_user_data (window, widget);
690
 
 
691
 
  cursor = gdk_cursor_new (GDK_HAND2);
692
 
  gdk_window_set_cursor (window, cursor);
693
 
 
694
 
  gtk_widget_set_window (widget, window);
695
 
}
696
 
 
697
 
 
698
 
static gdouble
699
 
convert_longtitude_to_x (gdouble longitude, gint map_width)
700
 
{
701
 
  const gdouble xdeg_offset = -6;
702
 
  gdouble x;
703
 
 
704
 
  x = (map_width * (180.0 + longitude) / 360.0)
705
 
    + (map_width * xdeg_offset / 180.0);
706
 
 
707
 
  return x;
708
 
}
709
 
 
710
 
static gdouble
711
 
radians (gdouble degrees)
712
 
{
713
 
  return (degrees / 360.0) * G_PI * 2;
714
 
}
715
 
 
716
 
static gdouble
717
 
convert_latitude_to_y (gdouble latitude, gdouble map_height)
718
 
{
719
 
  gdouble bottom_lat = -59;
720
 
  gdouble top_lat = 81;
721
 
  gdouble top_per, y, full_range, top_offset, map_range;
722
 
 
723
 
  top_per = top_lat / 180.0;
724
 
  y = 1.25 * log (tan (G_PI_4 + 0.4 * radians (latitude)));
725
 
  full_range = 4.6068250867599998;
726
 
  top_offset = full_range * top_per;
727
 
  map_range = fabs (1.25 * log (tan (G_PI_4 + 0.4 * radians (bottom_lat))) - top_offset);
728
 
  y = fabs (y - top_offset);
729
 
  y = y / map_range;
730
 
  y = y * map_height;
731
 
  return y;
732
 
}
733
 
 
734
 
 
735
 
static gboolean
736
 
cc_timezone_map_draw (GtkWidget *widget,
737
 
                      cairo_t   *cr)
738
 
{
739
 
  CcTimezoneMapPrivate *priv = CC_TIMEZONE_MAP (widget)->priv;
740
 
  GdkPixbuf *hilight, *orig_hilight, *pin;
741
 
  GtkAllocation alloc;
742
 
  gchar *file;
743
 
  GError *err = NULL;
744
 
  gdouble pointx, pointy;
745
 
  gdouble alpha = 1.0;
746
 
  char buf[16];
747
 
 
748
 
  gtk_widget_get_allocation (widget, &alloc);
749
 
 
750
 
  /* Check if insensitive */
751
 
  if (gtk_widget_get_sensitive (widget))
752
 
    alpha = 0.5;
753
 
 
754
 
  /* paint background */
755
 
#if GTK_CHECK_VERSION(3,0,0)
756
 
  GdkRGBA rgba;
757
 
  gtk_style_context_get_background_color (gtk_widget_get_style_context (widget),
758
 
                                          gtk_widget_get_state_flags (widget),
759
 
                                          &rgba);
760
 
  gdk_cairo_set_source_rgba (cr, &rgba);
761
 
#else
762
 
  GtkStyle * style = gtk_widget_get_style (widget);
763
 
  gdk_cairo_set_source_color (cr, &style->bg[gtk_widget_get_state (widget)]);
764
 
#endif
765
 
  cairo_paint (cr);
766
 
  gdk_cairo_set_source_pixbuf (cr, priv->background, 0, 0);
767
 
  cairo_paint_with_alpha (cr, alpha);
768
 
 
769
 
  /* paint watermark */
770
 
  if (priv->watermark) {
771
 
    cairo_text_extents_t extent;
772
 
    cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
773
 
    cairo_set_font_size(cr, 12.0);
774
 
    cairo_set_source_rgba(cr, 1, 1, 1, 0.5);
775
 
    cairo_text_extents(cr, priv->watermark, &extent);
776
 
    cairo_move_to(cr, alloc.width - extent.x_advance + extent.x_bearing - 5,
777
 
                      alloc.height - extent.height - extent.y_bearing - 5);
778
 
    cairo_show_text(cr, priv->watermark);
779
 
    cairo_stroke(cr);
780
 
  }
781
 
 
782
 
  if (!priv->location) {
783
 
    return TRUE;
784
 
  }
785
 
 
786
 
  /* paint hilight */
787
 
  file = g_strdup_printf (DATADIR "/timezone_%s.png",
788
 
                          g_ascii_formatd (buf, sizeof (buf),
789
 
                                           "%g", priv->selected_offset));
790
 
  orig_hilight = gdk_pixbuf_new_from_file (file, &err);
791
 
  g_free (file);
792
 
  file = NULL;
793
 
 
794
 
  if (!orig_hilight)
795
 
    {
796
 
      g_warning ("Could not load hilight: %s",
797
 
                 (err) ? err->message : "Unknown Error");
798
 
      if (err)
799
 
        g_clear_error (&err);
800
 
    }
801
 
  else
802
 
    {
803
 
 
804
 
      hilight = gdk_pixbuf_scale_simple (orig_hilight, alloc.width,
805
 
                                         alloc.height, GDK_INTERP_BILINEAR);
806
 
      gdk_cairo_set_source_pixbuf (cr, hilight, 0, 0);
807
 
 
808
 
      cairo_paint_with_alpha (cr, alpha);
809
 
      g_object_unref (hilight);
810
 
      g_object_unref (orig_hilight);
811
 
    }
812
 
 
813
 
  /* load pin icon */
814
 
  pin = gdk_pixbuf_new_from_file (DATADIR "/pin.png", &err);
815
 
 
816
 
  if (err)
817
 
    {
818
 
      g_warning ("Could not load pin icon: %s", err->message);
819
 
      g_clear_error (&err);
820
 
    }
821
 
 
822
 
  pointx = convert_longtitude_to_x (priv->location->longitude, alloc.width);
823
 
  pointy = convert_latitude_to_y (priv->location->latitude, alloc.height);
824
 
 
825
 
  if (pointy > alloc.height)
826
 
    pointy = alloc.height;
827
 
 
828
 
  if (pin)
829
 
    {
830
 
      gdk_cairo_set_source_pixbuf (cr, pin, pointx - 8, pointy - 14);
831
 
      cairo_paint_with_alpha (cr, alpha);
832
 
      g_object_unref (pin);
833
 
    }
834
 
 
835
 
  return TRUE;
836
 
}
837
 
 
838
 
static void
839
 
cc_timezone_map_class_init (CcTimezoneMapClass *klass)
840
 
{
841
 
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
842
 
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
843
 
 
844
 
  g_type_class_add_private (klass, sizeof (CcTimezoneMapPrivate));
845
 
 
846
 
  object_class->get_property = cc_timezone_map_get_property;
847
 
  object_class->set_property = cc_timezone_map_set_property;
848
 
  object_class->dispose = cc_timezone_map_dispose;
849
 
  object_class->finalize = cc_timezone_map_finalize;
850
 
 
851
 
  widget_class->get_preferred_width = cc_timezone_map_get_preferred_width;
852
 
  widget_class->get_preferred_height = cc_timezone_map_get_preferred_height;
853
 
  widget_class->size_allocate = cc_timezone_map_size_allocate;
854
 
  widget_class->realize = cc_timezone_map_realize;
855
 
  widget_class->draw = cc_timezone_map_draw;
856
 
 
857
 
  signals[LOCATION_CHANGED] = g_signal_new ("location-changed",
858
 
                                            CC_TYPE_TIMEZONE_MAP,
859
 
                                            G_SIGNAL_RUN_FIRST,
860
 
                                            0,
861
 
                                            NULL,
862
 
                                            NULL,
863
 
                                            g_cclosure_marshal_VOID__POINTER,
864
 
                                            G_TYPE_NONE, 1,
865
 
                                            G_TYPE_POINTER);
866
 
}
867
 
 
868
 
 
869
 
static gint
870
 
sort_locations (TzLocation *a,
871
 
                TzLocation *b)
872
 
{
873
 
  if (a->dist > b->dist)
874
 
    return 1;
875
 
 
876
 
  if (a->dist < b->dist)
877
 
    return -1;
878
 
 
879
 
  return 0;
880
 
}
881
 
 
882
 
static void
883
 
set_location (CcTimezoneMap *map,
884
 
              TzLocation    *location)
885
 
{
886
 
  CcTimezoneMapPrivate *priv = map->priv;
887
 
  TzInfo *info;
888
 
 
889
 
  priv->location = location;
890
 
 
891
 
  info = tz_info_from_location (priv->location);
892
 
 
893
 
  priv->selected_offset = tz_location_get_utc_offset (priv->location)
894
 
    / (60.0*60.0) + ((info->daylight) ? -1.0 : 0.0);
895
 
 
896
 
  g_signal_emit (map, signals[LOCATION_CHANGED], 0, priv->location);
897
 
 
898
 
  tz_info_free (info);
899
 
}
900
 
 
901
 
static TzLocation *
902
 
get_loc_for_xy (GtkWidget * widget, gint x, gint y)
903
 
{
904
 
  CcTimezoneMapPrivate *priv = CC_TIMEZONE_MAP (widget)->priv;
905
 
  guchar r, g, b, a;
906
 
  guchar *pixels;
907
 
  gint rowstride;
908
 
  gint i;
909
 
 
910
 
  const GPtrArray *array;
911
 
  gint width, height;
912
 
  GList *distances = NULL;
913
 
  GtkAllocation alloc;
914
 
 
915
 
  rowstride = priv->visible_map_rowstride;
916
 
  pixels = priv->visible_map_pixels;
917
 
 
918
 
  r = pixels[(rowstride * y + x * 4)];
919
 
  g = pixels[(rowstride * y + x * 4) + 1];
920
 
  b = pixels[(rowstride * y + x * 4) + 2];
921
 
  a = pixels[(rowstride * y + x * 4) + 3];
922
 
 
923
 
 
924
 
  for (i = 0; color_codes[i].offset != -100; i++)
925
 
    {
926
 
       if (color_codes[i].red == r && color_codes[i].green == g
927
 
           && color_codes[i].blue == b && color_codes[i].alpha == a)
928
 
         {
929
 
           priv->selected_offset = color_codes[i].offset;
930
 
         }
931
 
    }
932
 
 
933
 
  gtk_widget_queue_draw (widget);
934
 
 
935
 
  /* work out the co-ordinates */
936
 
 
937
 
  array = tz_get_locations (priv->tzdb);
938
 
 
939
 
  gtk_widget_get_allocation (widget, &alloc);
940
 
  width = alloc.width;
941
 
  height = alloc.height;
942
 
 
943
 
  for (i = 0; i < array->len; i++)
944
 
    {
945
 
      gdouble pointx, pointy, dx, dy;
946
 
      TzLocation *loc = array->pdata[i];
947
 
 
948
 
      pointx = convert_longtitude_to_x (loc->longitude, width);
949
 
      pointy = convert_latitude_to_y (loc->latitude, height);
950
 
 
951
 
      dx = pointx - x;
952
 
      dy = pointy - y;
953
 
 
954
 
      loc->dist = dx * dx + dy * dy;
955
 
      distances = g_list_prepend (distances, loc);
956
 
 
957
 
    }
958
 
  distances = g_list_sort (distances, (GCompareFunc) sort_locations);
959
 
 
960
 
  TzLocation * loc = (TzLocation*) distances->data;
961
 
 
962
 
  g_list_free (distances);
963
 
 
964
 
  return loc;
965
 
}
966
 
 
967
 
static gboolean
968
 
button_press_event (GtkWidget      *widget,
969
 
                    GdkEventButton *event)
970
 
{
971
 
  TzLocation * loc = get_loc_for_xy (widget, event->x, event->y);
972
 
  set_location (CC_TIMEZONE_MAP (widget), loc);
973
 
  return TRUE;
974
 
}
975
 
 
976
 
static void
977
 
state_flags_changed (GtkWidget *widget)
978
 
{
979
 
  // To catch sensitivity changes
980
 
  gtk_widget_queue_draw (widget);
981
 
}
982
 
 
983
 
static void
984
 
load_backward_tz (CcTimezoneMap *self)
985
 
{
986
 
  GError *error = NULL;
987
 
  char **lines, *contents;
988
 
  guint i;
989
 
 
990
 
  self->priv->alias_db = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
991
 
 
992
 
  if (g_file_get_contents (GNOMECC_DATA_DIR "/datetime/backward", &contents, NULL, &error) == FALSE)
993
 
    {
994
 
      g_warning ("Failed to load 'backward' file: %s", error->message);
995
 
      return;
996
 
    }
997
 
  lines = g_strsplit (contents, "\n", -1);
998
 
  g_free (contents);
999
 
  for (i = 0; lines[i] != NULL; i++)
1000
 
    {
1001
 
      char **items;
1002
 
      guint j;
1003
 
      char *real, *alias;
1004
 
 
1005
 
      if (g_ascii_strncasecmp (lines[i], "Link\t", 5) != 0)
1006
 
        continue;
1007
 
 
1008
 
      items = g_strsplit (lines[i], "\t", -1);
1009
 
      real = NULL;
1010
 
      alias = NULL;
1011
 
      /* Skip the "Link<tab>" part */
1012
 
      for (j = 1; items[j] != NULL; j++)
1013
 
        {
1014
 
          if (items[j][0] == '\0')
1015
 
            continue;
1016
 
          if (real == NULL)
1017
 
            {
1018
 
              real = items[j];
1019
 
              continue;
1020
 
            }
1021
 
          alias = items[j];
1022
 
          break;
1023
 
        }
1024
 
 
1025
 
      if (real == NULL || alias == NULL)
1026
 
        g_warning ("Could not parse line: %s", lines[i]);
1027
 
 
1028
 
      g_hash_table_insert (self->priv->alias_db, g_strdup (alias), g_strdup (real));
1029
 
      g_strfreev (items);
1030
 
    }
1031
 
  g_strfreev (lines);
1032
 
}
1033
 
 
1034
 
static void
1035
 
cc_timezone_map_init (CcTimezoneMap *self)
1036
 
{
1037
 
  CcTimezoneMapPrivate *priv;
1038
 
  GError *err = NULL;
1039
 
 
1040
 
  priv = self->priv = TIMEZONE_MAP_PRIVATE (self);
1041
 
 
1042
 
  priv->orig_background = gdk_pixbuf_new_from_file (DATADIR "/bg.png",
1043
 
                                                    &err);
1044
 
 
1045
 
  if (!priv->orig_background)
1046
 
    {
1047
 
      g_warning ("Could not load background image: %s",
1048
 
                 (err) ? err->message : "Unknown error");
1049
 
      g_clear_error (&err);
1050
 
    }
1051
 
 
1052
 
  priv->orig_color_map = gdk_pixbuf_new_from_file (DATADIR "/cc.png",
1053
 
                                                   &err);
1054
 
  if (!priv->orig_color_map)
1055
 
    {
1056
 
      g_warning ("Could not load background image: %s",
1057
 
                 (err) ? err->message : "Unknown error");
1058
 
      g_clear_error (&err);
1059
 
    }
1060
 
 
1061
 
  priv->olsen_map = gdk_pixbuf_new_from_file (DATADIR "/olsen_map.png",
1062
 
                                              &err);
1063
 
  if (!priv->olsen_map)
1064
 
    {
1065
 
      g_warning ("Could not load olsen map: %s",
1066
 
                 (err) ? err->message : "Unknown error");
1067
 
      g_clear_error (&err);
1068
 
    }
1069
 
  priv->olsen_map_channels = gdk_pixbuf_get_n_channels (priv->olsen_map);
1070
 
  priv->olsen_map_pixels = gdk_pixbuf_get_pixels (priv->olsen_map);
1071
 
  priv->olsen_map_rowstride = gdk_pixbuf_get_rowstride (priv->olsen_map);
1072
 
 
1073
 
  priv->tzdb = tz_load_db ();
1074
 
 
1075
 
  g_signal_connect (self, "button-press-event", G_CALLBACK (button_press_event),
1076
 
                    NULL);
1077
 
  g_signal_connect (self, "state-flags-changed", G_CALLBACK (state_flags_changed),
1078
 
                    NULL);
1079
 
 
1080
 
  load_backward_tz (self);
1081
 
}
1082
 
 
1083
 
CcTimezoneMap *
1084
 
cc_timezone_map_new (void)
1085
 
{
1086
 
  return g_object_new (CC_TYPE_TIMEZONE_MAP, NULL);
1087
 
}
1088
 
 
1089
 
void
1090
 
cc_timezone_map_set_timezone (CcTimezoneMap *map,
1091
 
                              const gchar   *timezone)
1092
 
{
1093
 
  GPtrArray *locations;
1094
 
  guint i;
1095
 
  char *real_tz;
1096
 
 
1097
 
  real_tz = g_hash_table_lookup (map->priv->alias_db, timezone);
1098
 
 
1099
 
  locations = tz_get_locations (map->priv->tzdb);
1100
 
 
1101
 
  for (i = 0; i < locations->len; i++)
1102
 
    {
1103
 
      TzLocation *loc = locations->pdata[i];
1104
 
 
1105
 
      if (!g_strcmp0 (loc->zone, real_tz ? real_tz : timezone))
1106
 
        {
1107
 
          set_location (map, loc);
1108
 
          break;
1109
 
        }
1110
 
    }
1111
 
 
1112
 
  gtk_widget_queue_draw (GTK_WIDGET (map));
1113
 
}
1114
 
 
1115
 
void
1116
 
cc_timezone_map_set_coords (CcTimezoneMap *map, gdouble lon, gdouble lat)
1117
 
{
1118
 
  const gchar * zone = cc_timezone_map_get_timezone_at_coords (map, lon, lat);
1119
 
  cc_timezone_map_set_timezone (map, zone);
1120
 
}
1121
 
 
1122
 
const gchar *
1123
 
cc_timezone_map_get_timezone_at_coords (CcTimezoneMap *map, gdouble lon, gdouble lat)
1124
 
{
1125
 
  gint x = (int)(2048.0 / 360.0 * (180.0 + lon));
1126
 
  gint y = (int)(1024.0 / 180.0 * (90.0 - lat));
1127
 
  gint offset = map->priv->olsen_map_rowstride * y + x * map->priv->olsen_map_channels;
1128
 
  guchar color0 = map->priv->olsen_map_pixels[offset];
1129
 
  guchar color1 = map->priv->olsen_map_pixels[offset + 1];
1130
 
  gint zone = ((color0 & 248) << 1) + ((color1 >>4) & 15);
1131
 
 
1132
 
  const gchar * city = NULL;
1133
 
  if (zone < G_N_ELEMENTS(olsen_map_timezones))
1134
 
    city = olsen_map_timezones[zone];
1135
 
 
1136
 
  if (city != NULL) {
1137
 
    return city;
1138
 
  }
1139
 
  else {
1140
 
    GtkAllocation alloc;
1141
 
    gtk_widget_get_allocation (GTK_WIDGET (map), &alloc);
1142
 
    x = convert_longtitude_to_x(lon, alloc.width);
1143
 
    y = convert_latitude_to_y(lat, alloc.height);
1144
 
    TzLocation * loc = get_loc_for_xy(GTK_WIDGET (map), x, y);
1145
 
    return loc->zone;
1146
 
  }
1147
 
}
1148
 
 
1149
 
void
1150
 
cc_timezone_map_set_watermark (CcTimezoneMap *map, const gchar * watermark)
1151
 
{
1152
 
  if (map->priv->watermark)
1153
 
    g_free (map->priv->watermark);
1154
 
 
1155
 
  map->priv->watermark = g_strdup (watermark);
1156
 
  gtk_widget_queue_draw (GTK_WIDGET (map));
1157
 
}
1158
 
 
1159
 
TzLocation *
1160
 
cc_timezone_map_get_location (CcTimezoneMap *map)
1161
 
{
1162
 
  return map->priv->location;
1163
 
}