~ubuntu-branches/ubuntu/oneiric/awn-extras/oneiric

« back to all changes in this revision

Viewing changes to .pc/03-libnotify07.patch/applets/maintained/notification-daemon/daemon.c

  • Committer: Bazaar Package Importer
  • Author(s): Julien Lavergne
  • Date: 2011-08-19 16:41:05 UTC
  • Revision ID: james.westby@ubuntu.com-20110819164105-1xwagz8ad88w4tq6
Tags: 0.4.1~bzr1507-0ubuntu2
* debian/patches:
 - 04-fix-indicator-API-detection.patch: Build against lastest indicators
   version (LP: #810817)
 - 03-libnotify07.patch: Transition to libnotify 0.7, thanks to Laurent
   Bigonville.
* debian/rules:
 - Use --with autoreconf, needed by 04-fix-indicator-API-detection.patch.
* debian/control:
 - Build-depends on dh-autoreconf.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* daemon.c - Implementation of the destop notification spec
 
2
 *
 
3
 * Awn related modifications by Rodney Cryderman <rcryderman@gmail.com>
 
4
 *
 
5
 * Base gnome-notification-daemon by
 
6
 * Copyright (C) 2006 Christian Hammond <chipx86@chipx86.com>
 
7
 * Copyright (C) 2005 John (J5) Palmieri <johnp@redhat.com>
 
8
 *
 
9
 * This program is free software; you can redistribute it and/or modify
 
10
 * it under the terms of the GNU General Public License as published by
 
11
 * the Free Software Foundation; either version 2, or (at your option)
 
12
 * any later version.
 
13
 *
 
14
 * This program is distributed in the hope that it will be useful,
 
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
 * GNU General Public License for more details.
 
18
 *
 
19
 * You should have received a copy of the GNU General Public License
 
20
 * along with this program; if not, write to the Free Software
 
21
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
22
 * 02111-1307, USA.
 
23
 */
 
24
 
 
25
 
 
26
/*tabsize =4*/
 
27
 
 
28
#ifdef HAVE_CONFIG_H
 
29
#include "config.h"
 
30
#endif
 
31
 
 
32
#include <stdlib.h>
 
33
#include <errno.h>
 
34
#include <string.h>
 
35
#include <stdio.h>
 
36
#include <signal.h>
 
37
#include <sys/types.h>
 
38
 
 
39
#ifdef HAVE_UNISTD_H
 
40
#include <unistd.h>
 
41
#endif
 
42
 
 
43
#include <dbus/dbus.h>
 
44
#include <dbus/dbus-glib.h>
 
45
#include <glib/gi18n.h>
 
46
#include <glib.h>
 
47
#include <glib-object.h>
 
48
#include <gtk/gtk.h>
 
49
#include <glib/gprintf.h>
 
50
 
 
51
#include <libnotify/notify.h>
 
52
 
 
53
#include <glib/gprintf.h>
 
54
 
 
55
#include <X11/Xproto.h>
 
56
 
 
57
#include <X11/Xlib.h>
 
58
#include <X11/Xutil.h>
 
59
#include <X11/Xatom.h>
 
60
#include <gdk/gdkx.h>
 
61
 
 
62
#undef NDEBUG
 
63
#include <assert.h>
 
64
 
 
65
#define WNCK_I_KNOW_THIS_IS_UNSTABLE
 
66
#include <libwnck/libwnck.h>
 
67
 
 
68
#include <sys/types.h>
 
69
#include <sys/wait.h>
 
70
#include <libawn/libawn.h>
 
71
 
 
72
#include "daemon.h"
 
73
#include "engines.h"
 
74
#include "stack.h"
 
75
#include "sound.h"
 
76
#include "notificationdaemon-dbus-glue.h"
 
77
 
 
78
#define IMAGE_SIZE 48
 
79
 
 
80
#define NW_GET_NOTIFY_ID(nw) \
 
81
  (GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(nw), "_notify_id")))
 
82
#define NW_GET_NOTIFY_SENDER(nw) \
 
83
  (g_object_get_data(G_OBJECT(nw), "_notify_sender"))
 
84
#define NW_GET_DAEMON(nw) \
 
85
  (g_object_get_data(G_OBJECT(nw), "_notify_daemon"))
 
86
 
 
87
typedef struct
 
88
{
 
89
  NotifyStackLocation type;
 
90
  const gchar *identifier;
 
91
 
 
92
} PopupNotifyStackLocation;
 
93
 
 
94
typedef struct
 
95
{
 
96
  AwnApplet *applet;
 
97
 
 
98
}AwnNotificationDaemon;
 
99
 
 
100
 
 
101
Notification_Daemon G_daemon_config;
 
102
 
 
103
 
 
104
const PopupNotifyStackLocation popup_stack_locations[] =
 
105
{
 
106
  { NOTIFY_STACK_LOCATION_TOP_LEFT,     "top_left"     },
 
107
  { NOTIFY_STACK_LOCATION_TOP_RIGHT,    "top_right"    },
 
108
  { NOTIFY_STACK_LOCATION_BOTTOM_LEFT,  "bottom_left"  },
 
109
  { NOTIFY_STACK_LOCATION_BOTTOM_RIGHT, "bottom_right" },
 
110
  { NOTIFY_STACK_LOCATION_AWN,          "awn-dynamic" },
 
111
  { NOTIFY_STACK_LOCATION_UNKNOWN,      NULL }
 
112
};
 
113
 
 
114
#define POPUP_STACK_DEFAULT_INDEX 4 /* XXX Hack! */
 
115
 
 
116
typedef struct
 
117
{
 
118
  NotifyDaemon *daemon;
 
119
  GTimeVal expiration;
 
120
  GTimeVal paused_diff;
 
121
  gboolean has_timeout;
 
122
  gboolean paused;
 
123
  guint id;
 
124
  GtkWindow *nw;
 
125
  Window src_window_xid;
 
126
} NotifyTimeout;
 
127
 
 
128
struct _NotifyDaemonPrivate
 
129
{
 
130
  guint next_id;
 
131
  guint timeout_source;
 
132
  GHashTable *idle_reposition_notify_ids;
 
133
  GHashTable *monitored_window_hash;
 
134
  GHashTable *notification_hash;
 
135
  gboolean url_clicked_lock;
 
136
  NotifyStack **stacks;
 
137
  gint stacks_size;
 
138
};
 
139
 
 
140
static DesktopAgnosticConfigClient  *conf_client = NULL;
 
141
 
 
142
static DBusConnection *dbus_conn = NULL;
 
143
 
 
144
#define CHECK_DBUS_VERSION(major, minor) \
 
145
  (DBUS_MAJOR_VER > (major) || \
 
146
   (DBUS_MAJOR_VER == (major) && DBUS_MINOR_VER >= (minor)))
 
147
 
 
148
#if !CHECK_DBUS_VERSION(0, 60)
 
149
/* This is a hack that will go away in time. For now, it's fairly safe. */
 
150
 
 
151
struct _DBusGMethodInvocation
 
152
{
 
153
  DBusGConnection *connection;
 
154
  DBusGMessage *message;
 
155
  const DBusGObjectInfo *object;
 
156
  const DBusGMethodInfo *method;
 
157
};
 
158
 
 
159
#endif /* D-BUS < 0.60 */
 
160
 
 
161
static void notify_daemon_finalize(GObject *object);
 
162
static void _notification_destroyed_cb(GtkWindow *nw, NotifyDaemon *daemon);
 
163
static void _close_notification(NotifyDaemon *daemon, guint id,
 
164
                                gboolean hide_notification,
 
165
                                NotifydClosedReason reason);
 
166
static GdkFilterReturn _notify_x11_filter(GdkXEvent *xevent,
 
167
                                          GdkEvent *event,
 
168
                                          gpointer user_data);
 
169
static void _emit_closed_signal(GtkWindow *nw, NotifydClosedReason reason);
 
170
static void _action_invoked_cb(GtkWindow *nw, const char *key);
 
171
static NotifyStackLocation get_stack_location_from_string(const char *slocation);
 
172
static void sync_notification_position(NotifyDaemon *daemon, GtkWindow *nw,
 
173
                                       Window source);
 
174
static void monitor_notification_source_windows(NotifyDaemon *daemon,
 
175
                                                NotifyTimeout *nt,
 
176
                                                Window source);
 
177
 
 
178
G_DEFINE_TYPE(NotifyDaemon, notify_daemon, G_TYPE_OBJECT);
 
179
 
 
180
static void
 
181
notify_daemon_class_init(NotifyDaemonClass *daemon_class)
 
182
{
 
183
  GObjectClass *object_class = G_OBJECT_CLASS(daemon_class);
 
184
 
 
185
  object_class->finalize = notify_daemon_finalize;
 
186
 
 
187
  g_type_class_add_private(daemon_class, sizeof(NotifyDaemonPrivate));
 
188
}
 
189
 
 
190
static void
 
191
_notify_timeout_destroy(NotifyTimeout *nt)
 
192
{
 
193
  /*
 
194
   * Disconnect the destroy handler to avoid a loop since the id
 
195
   * won't be removed from the hash table before the widget is
 
196
   * destroyed.
 
197
   */
 
198
  g_signal_handlers_disconnect_by_func(nt->nw, _notification_destroyed_cb,
 
199
                                       nt->daemon);
 
200
 
 
201
  gtk_widget_destroy(GTK_WIDGET(nt->nw));
 
202
  g_free(nt);
 
203
}
 
204
 
 
205
static void
 
206
notify_daemon_init(NotifyDaemon *daemon)
 
207
{
 
208
  NotifyStackLocation location;
 
209
DesktopAgnosticConfigClient  *client = get_conf_client();
 
210
  GdkDisplay *display;
 
211
  GdkScreen *screen;
 
212
  gchar *slocation;
 
213
  gint i;
 
214
 
 
215
  daemon->priv = G_TYPE_INSTANCE_GET_PRIVATE(daemon, NOTIFY_TYPE_DAEMON,
 
216
                 NotifyDaemonPrivate);
 
217
 
 
218
  daemon->priv->next_id = 1;
 
219
  daemon->priv->timeout_source = 0;
 
220
 
 
221
//  slocation = gconf_client_get_string(client, GCONF_KEY_POPUP_LOCATION, NULL);
 
222
  slocation = g_strdup ("bottom_right");
 
223
 
 
224
  location = get_stack_location_from_string(slocation);
 
225
  g_free(slocation);
 
226
 
 
227
  display = gdk_display_get_default();
 
228
  screen = gdk_display_get_default_screen(display);
 
229
  daemon->priv->stacks_size = gdk_screen_get_n_monitors(screen);
 
230
  daemon->priv->stacks = g_new0(NotifyStack *, daemon->priv->stacks_size);
 
231
 
 
232
  daemon->priv->idle_reposition_notify_ids = g_hash_table_new(NULL, NULL);
 
233
  daemon->priv->monitored_window_hash = g_hash_table_new(NULL, NULL);
 
234
  gdk_window_add_filter(NULL, _notify_x11_filter, daemon);
 
235
 
 
236
  for (i = 0; i < daemon->priv->stacks_size; i++)
 
237
  {
 
238
    daemon->priv->stacks[i] = notify_stack_new(daemon, screen,
 
239
                              i, location);
 
240
  }
 
241
 
 
242
  daemon->priv->notification_hash =
 
243
 
 
244
    g_hash_table_new_full(g_int_hash, g_int_equal, g_free,
 
245
                          (GDestroyNotify)_notify_timeout_destroy);
 
246
 
 
247
 
 
248
  /*awn daemon specific initialization follows*/
 
249
}
 
250
 
 
251
static void
 
252
notify_daemon_finalize(GObject *object)
 
253
{
 
254
  NotifyDaemon *daemon       = NOTIFY_DAEMON(object);
 
255
  GObjectClass *parent_class = G_OBJECT_CLASS(notify_daemon_parent_class);
 
256
 
 
257
  g_hash_table_destroy(daemon->priv->monitored_window_hash);
 
258
  g_hash_table_destroy(daemon->priv->idle_reposition_notify_ids);
 
259
  g_hash_table_destroy(daemon->priv->notification_hash);
 
260
  g_free(daemon->priv);
 
261
 
 
262
  if (parent_class->finalize != NULL)
 
263
    parent_class->finalize(object);
 
264
}
 
265
 
 
266
static NotifyStackLocation
 
267
get_stack_location_from_string(const char *slocation)
 
268
{
 
269
  NotifyStackLocation stack_location = NOTIFY_STACK_LOCATION_DEFAULT;
 
270
 
 
271
  if (slocation == NULL || *slocation == '\0')
 
272
    return NOTIFY_STACK_LOCATION_DEFAULT;
 
273
  else
 
274
  {
 
275
    const PopupNotifyStackLocation *l;
 
276
 
 
277
    for (l = popup_stack_locations;
 
278
         l->type != NOTIFY_STACK_LOCATION_UNKNOWN;
 
279
         l++)
 
280
    {
 
281
      if (!strcmp(slocation, l->identifier))
 
282
        stack_location = l->type;
 
283
    }
 
284
  }
 
285
 
 
286
  return stack_location;
 
287
}
 
288
 
 
289
static DBusMessage *
 
290
create_signal(GtkWindow *nw, const char *signal_name)
 
291
{
 
292
  guint id = NW_GET_NOTIFY_ID(nw);
 
293
  gchar *dest = NW_GET_NOTIFY_SENDER(nw);
 
294
  DBusMessage *message;
 
295
 
 
296
  g_assert(dest != NULL);
 
297
 
 
298
  message = dbus_message_new_signal("/org/freedesktop/Notifications",
 
299
                                    "org.freedesktop.Notifications",
 
300
                                    signal_name);
 
301
 
 
302
  dbus_message_set_destination(message, dest);
 
303
  dbus_message_append_args(message,
 
304
                           DBUS_TYPE_UINT32, &id,
 
305
                           DBUS_TYPE_INVALID);
 
306
 
 
307
  return message;
 
308
}
 
309
 
 
310
static void
 
311
_action_invoked_cb(GtkWindow *nw, const char *key)
 
312
{
 
313
  NotifyDaemon *daemon = NW_GET_DAEMON(nw);
 
314
  guint id = NW_GET_NOTIFY_ID(nw);
 
315
  DBusMessage *message;
 
316
 
 
317
  message = create_signal(nw, "ActionInvoked");
 
318
  dbus_message_append_args(message,
 
319
                           DBUS_TYPE_STRING, &key,
 
320
                           DBUS_TYPE_INVALID);
 
321
 
 
322
  dbus_connection_send(dbus_conn, message, NULL);
 
323
  dbus_message_unref(message);
 
324
 
 
325
  _close_notification(daemon, id, TRUE, NOTIFYD_CLOSED_USER);
 
326
}
 
327
 
 
328
static void
 
329
_emit_closed_signal(GtkWindow *nw, NotifydClosedReason reason)
 
330
{
 
331
  DBusMessage *message = create_signal(nw, "NotificationClosed");
 
332
  dbus_message_append_args(message,
 
333
                           DBUS_TYPE_UINT32, &reason,
 
334
                           DBUS_TYPE_INVALID);
 
335
  dbus_connection_send(dbus_conn, message, NULL);
 
336
  dbus_message_unref(message);
 
337
}
 
338
 
 
339
static void
 
340
_close_notification(NotifyDaemon *daemon, guint id,
 
341
                    gboolean bhide_notification, NotifydClosedReason reason)
 
342
{
 
343
  NotifyDaemonPrivate *priv = daemon->priv;
 
344
  NotifyTimeout *nt;
 
345
 
 
346
  nt = (NotifyTimeout *)g_hash_table_lookup(priv->notification_hash, &id);
 
347
 
 
348
  if (nt != NULL)
 
349
  {
 
350
    _emit_closed_signal(nt->nw, reason);
 
351
 
 
352
    if (bhide_notification)
 
353
      hide_notification(nt->nw);
 
354
 
 
355
    g_hash_table_remove(priv->notification_hash, &id);
 
356
  }
 
357
}
 
358
 
 
359
static void
 
360
_notification_destroyed_cb(GtkWindow *nw, NotifyDaemon *daemon)
 
361
{
 
362
  /*
 
363
   * This usually won't happen, but can if notification-daemon dies before
 
364
   * all notifications are closed. Mark them as expired.
 
365
   */
 
366
  _close_notification(daemon, NW_GET_NOTIFY_ID(nw), FALSE,
 
367
                      NOTIFYD_CLOSED_EXPIRED);
 
368
}
 
369
 
 
370
typedef struct
 
371
{
 
372
  NotifyDaemon *daemon;
 
373
  gint id;
 
374
} IdleRepositionData;
 
375
 
 
376
static gboolean
 
377
idle_reposition_notification(gpointer datap)
 
378
{
 
379
  IdleRepositionData *data = (IdleRepositionData *)datap;
 
380
  NotifyDaemon *daemon = data->daemon;
 
381
  NotifyTimeout *nt;
 
382
  gint notify_id;
 
383
 
 
384
  notify_id = data->id;
 
385
 
 
386
  /* Look up the timeout, if it's completed we don't need to do anything */
 
387
  nt = (NotifyTimeout *)g_hash_table_lookup(daemon->priv->notification_hash,
 
388
                        &notify_id);
 
389
  if (nt != NULL) {
 
390
    sync_notification_position(daemon, nt->nw, nt->src_window_xid);
 
391
  }
 
392
 
 
393
  g_hash_table_remove(daemon->priv->idle_reposition_notify_ids,
 
394
            GINT_TO_POINTER(notify_id));
 
395
  g_object_unref(daemon);
 
396
  g_free(data);
 
397
 
 
398
  return FALSE;
 
399
}
 
400
 
 
401
static void
 
402
_queue_idle_reposition_notification(NotifyDaemon *daemon, gint notify_id)
 
403
{
 
404
  IdleRepositionData *data;
 
405
  gpointer orig_key;
 
406
  gpointer value;
 
407
  guint idle_id;
 
408
 
 
409
  /* Do we already have an idle update pending? */
 
410
  if (g_hash_table_lookup_extended(daemon->priv->idle_reposition_notify_ids,
 
411
                   GINT_TO_POINTER(notify_id),
 
412
                   &orig_key, &value))
 
413
  {
 
414
    return;
 
415
  }
 
416
 
 
417
  data = g_new0(IdleRepositionData, 1);
 
418
  data->daemon = g_object_ref(daemon);
 
419
  data->id = notify_id;
 
420
 
 
421
  /* We do this as a short timeout to avoid repositioning spam */
 
422
  idle_id = g_timeout_add_full(G_PRIORITY_LOW, 50,
 
423
                 idle_reposition_notification, data, NULL);
 
424
  g_hash_table_insert(daemon->priv->idle_reposition_notify_ids,
 
425
            GINT_TO_POINTER(notify_id), GUINT_TO_POINTER(idle_id));
 
426
}
 
427
 
 
428
static GdkFilterReturn
 
429
_notify_x11_filter(GdkXEvent *xevent,
 
430
           GdkEvent *event,
 
431
           gpointer user_data)
 
432
{
 
433
  NotifyDaemon *daemon = NOTIFY_DAEMON(user_data);
 
434
  XEvent *xev = (XEvent *)xevent;
 
435
  gpointer orig_key;
 
436
  gpointer value;
 
437
  gint notify_id;
 
438
  NotifyTimeout *nt;
 
439
 
 
440
  if (xev->xany.type == DestroyNotify)
 
441
  {
 
442
    g_hash_table_remove(daemon->priv->monitored_window_hash,
 
443
              GUINT_TO_POINTER(xev->xany.window));
 
444
    return GDK_FILTER_CONTINUE;
 
445
  }
 
446
 
 
447
  if (!g_hash_table_lookup_extended(daemon->priv->monitored_window_hash,
 
448
           GUINT_TO_POINTER(xev->xany.window), &orig_key, &value))
 
449
    return GDK_FILTER_CONTINUE;
 
450
 
 
451
  notify_id = GPOINTER_TO_INT(value);
 
452
 
 
453
  if (xev->xany.type == ConfigureNotify || xev->xany.type == MapNotify)
 
454
  {
 
455
    _queue_idle_reposition_notification(daemon, notify_id);
 
456
  }
 
457
  else if (xev->xany.type == ReparentNotify)
 
458
  {
 
459
    nt = (NotifyTimeout *)g_hash_table_lookup(
 
460
      daemon->priv->notification_hash, &notify_id);
 
461
 
 
462
    if (nt == NULL)
 
463
      return GDK_FILTER_CONTINUE;
 
464
 
 
465
    /*
 
466
     * If the window got reparented, we need to start monitoring the
 
467
     * new parents.
 
468
     */
 
469
    monitor_notification_source_windows(daemon, nt, nt->src_window_xid);
 
470
    sync_notification_position(daemon, nt->nw, nt->src_window_xid);
 
471
  }
 
472
 
 
473
  return GDK_FILTER_CONTINUE;
 
474
}
 
475
 
 
476
static void
 
477
_mouse_entered_cb(GtkWindow *nw, GdkEventCrossing *event, NotifyDaemon *daemon)
 
478
{
 
479
  NotifyTimeout *nt;
 
480
  guint id;
 
481
  GTimeVal now;
 
482
 
 
483
  if (event->detail == GDK_NOTIFY_INFERIOR)
 
484
    return;
 
485
 
 
486
  id = NW_GET_NOTIFY_ID(nw);
 
487
 
 
488
  nt = (NotifyTimeout *)g_hash_table_lookup(daemon->priv->notification_hash,
 
489
       &id);
 
490
 
 
491
  nt->paused = TRUE;
 
492
 
 
493
  g_get_current_time(&now);
 
494
 
 
495
  nt->paused_diff.tv_usec = nt->expiration.tv_usec - now.tv_usec;
 
496
 
 
497
  nt->paused_diff.tv_sec  = nt->expiration.tv_sec  - now.tv_sec;
 
498
 
 
499
  if (nt->paused_diff.tv_usec < 0)
 
500
  {
 
501
    nt->paused_diff.tv_usec += G_USEC_PER_SEC;
 
502
    nt->paused_diff.tv_sec--;
 
503
  }
 
504
}
 
505
 
 
506
static void
 
507
_mouse_exitted_cb(GtkWindow *nw, GdkEventCrossing *event,
 
508
                  NotifyDaemon *daemon)
 
509
{
 
510
  NotifyTimeout *nt;
 
511
  guint id;
 
512
 
 
513
  if (event->detail == GDK_NOTIFY_INFERIOR)
 
514
    return;
 
515
 
 
516
  id = NW_GET_NOTIFY_ID(nw);
 
517
 
 
518
  nt = (NotifyTimeout *)g_hash_table_lookup(daemon->priv->notification_hash,
 
519
       &id);
 
520
 
 
521
  nt->paused = FALSE;
 
522
}
 
523
 
 
524
static gboolean
 
525
_is_expired(gpointer key, gpointer value, gpointer data)
 
526
{
 
527
  NotifyTimeout *nt = (NotifyTimeout *)value;
 
528
  gboolean *phas_more_timeouts = (gboolean *)data;
 
529
  time_t now_time;
 
530
  time_t expiration_time;
 
531
  GTimeVal now;
 
532
 
 
533
  if (!nt->has_timeout)
 
534
    return FALSE;
 
535
 
 
536
  g_get_current_time(&now);
 
537
 
 
538
  expiration_time = (nt->expiration.tv_sec * 1000) +
 
539
                    (nt->expiration.tv_usec / 1000);
 
540
 
 
541
  now_time = (now.tv_sec * 1000) + (now.tv_usec / 1000);
 
542
 
 
543
  if (now_time > expiration_time)
 
544
  {
 
545
    notification_tick(nt->nw, 0);
 
546
    _emit_closed_signal(nt->nw, NOTIFYD_CLOSED_EXPIRED);
 
547
    return TRUE;
 
548
  }
 
549
  else if (nt->paused)
 
550
  {
 
551
    nt->expiration.tv_usec = nt->paused_diff.tv_usec + now.tv_usec;
 
552
    nt->expiration.tv_sec  = nt->paused_diff.tv_sec  + now.tv_sec;
 
553
 
 
554
    if (nt->expiration.tv_usec >= G_USEC_PER_SEC)
 
555
    {
 
556
      nt->expiration.tv_usec -= G_USEC_PER_SEC;
 
557
      nt->expiration.tv_sec++;
 
558
    }
 
559
  }
 
560
  else
 
561
  {
 
562
    notification_tick(nt->nw, expiration_time - now_time);
 
563
  }
 
564
 
 
565
  *phas_more_timeouts = TRUE;
 
566
 
 
567
  return FALSE;
 
568
}
 
569
 
 
570
static gboolean
 
571
_check_expiration(gpointer data)
 
572
{
 
573
  NotifyDaemon *daemon = (NotifyDaemon *)data;
 
574
  gboolean has_more_timeouts = FALSE;
 
575
 
 
576
  g_hash_table_foreach_remove(daemon->priv->notification_hash,
 
577
                              _is_expired, (gpointer)&has_more_timeouts);
 
578
 
 
579
  if (!has_more_timeouts)
 
580
    daemon->priv->timeout_source = 0;
 
581
 
 
582
  return has_more_timeouts;
 
583
}
 
584
 
 
585
static void
 
586
_calculate_timeout(NotifyDaemon *daemon, NotifyTimeout *nt, int timeout)
 
587
{
 
588
  if (timeout == 0)
 
589
    nt->has_timeout = FALSE;
 
590
  else
 
591
  {
 
592
    glong usec;
 
593
 
 
594
    if (G_daemon_config.timeout > 0)
 
595
      timeout = G_daemon_config.timeout;
 
596
 
 
597
    nt->has_timeout = TRUE;
 
598
 
 
599
    if (timeout == -1)
 
600
      timeout = NOTIFY_DAEMON_DEFAULT_TIMEOUT;
 
601
 
 
602
    set_notification_timeout(nt->nw, timeout);
 
603
 
 
604
    usec = timeout * 1000; /* convert from msec to usec */
 
605
 
 
606
    /*
 
607
     * If it's less than 0, wrap around back to MAXLONG.
 
608
     * g_time_val_add() requires a glong, and anything larger than
 
609
     * MAXLONG will be treated as a negative value.
 
610
     */
 
611
    if (usec < 0)
 
612
      usec = G_MAXLONG;
 
613
 
 
614
    g_get_current_time(&nt->expiration);
 
615
 
 
616
    g_time_val_add(&nt->expiration, usec);
 
617
 
 
618
    if (daemon->priv->timeout_source == 0)
 
619
    {
 
620
      daemon->priv->timeout_source =
 
621
        g_timeout_add(100, _check_expiration, daemon);
 
622
    }
 
623
  }
 
624
}
 
625
 
 
626
static NotifyTimeout *
 
627
_store_notification(NotifyDaemon *daemon, GtkWindow *nw, int timeout)
 
628
{
 
629
  NotifyDaemonPrivate *priv = daemon->priv;
 
630
  NotifyTimeout *nt;
 
631
  guint id = 0;
 
632
 
 
633
  do
 
634
  {
 
635
    id = priv->next_id;
 
636
 
 
637
    if (id != UINT_MAX)
 
638
      priv->next_id++;
 
639
    else
 
640
      priv->next_id = 1;
 
641
 
 
642
    if (g_hash_table_lookup(priv->notification_hash, &id) != NULL)
 
643
      id = 0;
 
644
 
 
645
  }
 
646
  while (id == 0);
 
647
 
 
648
  nt = g_new0(NotifyTimeout, 1);
 
649
  nt->id = id;
 
650
  nt->nw = nw;
 
651
  nt->daemon = daemon;
 
652
 
 
653
  _calculate_timeout(daemon, nt, timeout);
 
654
 
 
655
  g_hash_table_insert(priv->notification_hash,
 
656
                      g_memdup(&id, sizeof(guint)), nt);
 
657
 
 
658
  return nt;
 
659
}
 
660
 
 
661
static gboolean
 
662
_notify_daemon_process_icon_data(NotifyDaemon *daemon, GtkWindow *nw,
 
663
                                 GValue *icon_data)
 
664
{
 
665
  const guchar *data = NULL;
 
666
  gboolean has_alpha;
 
667
  int bits_per_sample;
 
668
  int width;
 
669
  int height;
 
670
  int rowstride;
 
671
  int n_channels;
 
672
  gsize expected_len;
 
673
  GdkPixbuf *pixbuf;
 
674
  GValueArray *image_struct;
 
675
  GValue *value;
 
676
  GArray *tmp_array;
 
677
#if CHECK_DBUS_VERSION(0, 61)
 
678
  GType struct_type;
 
679
 
 
680
  struct_type = dbus_g_type_get_struct(
 
681
                  "GValueArray",
 
682
                  G_TYPE_INT,
 
683
                  G_TYPE_INT,
 
684
                  G_TYPE_INT,
 
685
                  G_TYPE_BOOLEAN,
 
686
                  G_TYPE_INT,
 
687
                  G_TYPE_INT,
 
688
                  dbus_g_type_get_collection("GArray", G_TYPE_UCHAR),
 
689
                  G_TYPE_INVALID);
 
690
 
 
691
  if (!G_VALUE_HOLDS(icon_data, struct_type))
 
692
  {
 
693
    g_warning("_notify_daemon_process_icon_data expected a "
 
694
              "GValue of type GValueArray");
 
695
    return FALSE;
 
696
  }
 
697
 
 
698
#endif /* D-BUS >= 0.61 */
 
699
 
 
700
  image_struct = (GValueArray *)g_value_get_boxed(icon_data);
 
701
 
 
702
  value = g_value_array_get_nth(image_struct, 0);
 
703
 
 
704
  if (value == NULL)
 
705
  {
 
706
    g_warning("_notify_daemon_process_icon_data expected position "
 
707
              "0 of the GValueArray to exist");
 
708
    return FALSE;
 
709
  }
 
710
 
 
711
  if (!G_VALUE_HOLDS(value, G_TYPE_INT))
 
712
  {
 
713
    g_warning("_notify_daemon_process_icon_data expected "
 
714
              "position 0 of the GValueArray to be of type int");
 
715
    return FALSE;
 
716
  }
 
717
 
 
718
  width = g_value_get_int(value);
 
719
 
 
720
  value = g_value_array_get_nth(image_struct, 1);
 
721
 
 
722
  if (value == NULL)
 
723
  {
 
724
    g_warning("_notify_daemon_process_icon_data expected "
 
725
              "position 1 of the GValueArray to exist");
 
726
    return FALSE;
 
727
  }
 
728
 
 
729
  if (!G_VALUE_HOLDS(value, G_TYPE_INT))
 
730
  {
 
731
    g_warning("_notify_daemon_process_icon_data expected "
 
732
              "position 1 of the GValueArray to be of type int");
 
733
    return FALSE;
 
734
  }
 
735
 
 
736
  height = g_value_get_int(value);
 
737
 
 
738
  value = g_value_array_get_nth(image_struct, 2);
 
739
 
 
740
  if (value == NULL)
 
741
  {
 
742
    g_warning("_notify_daemon_process_icon_data expected "
 
743
              "position 2 of the GValueArray to exist");
 
744
    return FALSE;
 
745
  }
 
746
 
 
747
  if (!G_VALUE_HOLDS(value, G_TYPE_INT))
 
748
  {
 
749
    g_warning("_notify_daemon_process_icon_data expected "
 
750
              "position 2 of the GValueArray to be of type int");
 
751
    return FALSE;
 
752
  }
 
753
 
 
754
  rowstride = g_value_get_int(value);
 
755
 
 
756
  value = g_value_array_get_nth(image_struct, 3);
 
757
 
 
758
  if (value == NULL)
 
759
  {
 
760
    g_warning("_notify_daemon_process_icon_data expected "
 
761
              "position 3 of the GValueArray to exist");
 
762
    return FALSE;
 
763
  }
 
764
 
 
765
  if (!G_VALUE_HOLDS(value, G_TYPE_BOOLEAN))
 
766
  {
 
767
    g_warning("_notify_daemon_process_icon_data expected "
 
768
              "position 3 of the GValueArray to be of type gboolean");
 
769
    return FALSE;
 
770
  }
 
771
 
 
772
  has_alpha = g_value_get_boolean(value);
 
773
 
 
774
  value = g_value_array_get_nth(image_struct, 4);
 
775
 
 
776
  if (value == NULL)
 
777
  {
 
778
    g_warning("_notify_daemon_process_icon_data expected "
 
779
              "position 4 of the GValueArray to exist");
 
780
    return FALSE;
 
781
  }
 
782
 
 
783
  if (!G_VALUE_HOLDS(value, G_TYPE_INT))
 
784
  {
 
785
    g_warning("_notify_daemon_process_icon_data expected "
 
786
              "position 4 of the GValueArray to be of type int");
 
787
    return FALSE;
 
788
  }
 
789
 
 
790
  bits_per_sample = g_value_get_int(value);
 
791
 
 
792
  value = g_value_array_get_nth(image_struct, 5);
 
793
 
 
794
  if (value == NULL)
 
795
  {
 
796
    g_warning("_notify_daemon_process_icon_data expected "
 
797
              "position 5 of the GValueArray to exist");
 
798
    return FALSE;
 
799
  }
 
800
 
 
801
  if (!G_VALUE_HOLDS(value, G_TYPE_INT))
 
802
  {
 
803
    g_warning("_notify_daemon_process_icon_data expected "
 
804
              "position 5 of the GValueArray to be of type int");
 
805
    return FALSE;
 
806
  }
 
807
 
 
808
  n_channels = g_value_get_int(value);
 
809
 
 
810
  value = g_value_array_get_nth(image_struct, 6);
 
811
 
 
812
  if (value == NULL)
 
813
  {
 
814
    g_warning("_notify_daemon_process_icon_data expected "
 
815
              "position 6 of the GValueArray to exist");
 
816
    return FALSE;
 
817
  }
 
818
 
 
819
  if (!G_VALUE_HOLDS(value,
 
820
                     dbus_g_type_get_collection("GArray", G_TYPE_UCHAR)))
 
821
  {
 
822
    g_warning("_notify_daemon_process_icon_data expected "
 
823
              "position 6 of the GValueArray to be of type GArray");
 
824
    return FALSE;
 
825
  }
 
826
 
 
827
  tmp_array = (GArray *)g_value_get_boxed(value);
 
828
 
 
829
  expected_len = (height - 1) * rowstride + width *
 
830
                 ((n_channels * bits_per_sample + 7) / 8);
 
831
 
 
832
  if (expected_len != tmp_array->len)
 
833
  {
 
834
    g_warning("_notify_daemon_process_icon_data expected image "
 
835
              "data to be of length %" G_GSIZE_FORMAT " but got a "
 
836
              "length of %u",
 
837
              expected_len, tmp_array->len);
 
838
    return FALSE;
 
839
  }
 
840
 
 
841
  data = (guchar *)g_memdup(tmp_array->data, tmp_array->len);
 
842
 
 
843
  pixbuf = gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, has_alpha,
 
844
                                    bits_per_sample, width, height,
 
845
                                    rowstride,
 
846
                                    (GdkPixbufDestroyNotify)g_free,
 
847
                                    NULL);
 
848
  set_notification_icon(nw, pixbuf);
 
849
  g_object_unref(G_OBJECT(pixbuf));
 
850
 
 
851
  return TRUE;
 
852
}
 
853
 
 
854
static void
 
855
window_clicked_cb(GtkWindow *nw, GdkEventButton *button, NotifyDaemon *daemon)
 
856
{
 
857
  if (daemon->priv->url_clicked_lock)
 
858
  {
 
859
    daemon->priv->url_clicked_lock = FALSE;
 
860
    return;
 
861
  }
 
862
 
 
863
  _action_invoked_cb(nw, "default");
 
864
 
 
865
  _close_notification(daemon, NW_GET_NOTIFY_ID(nw), TRUE,
 
866
                      NOTIFYD_CLOSED_USER);
 
867
}
 
868
 
 
869
static void
 
870
popup_location_changed_cb(DesktopAgnosticConfigClient  *client, guint cnxn_id,
 
871
                          gpointer *entry, gpointer user_data)
 
872
{
 
873
  NotifyDaemon *daemon = (NotifyDaemon*)user_data;
 
874
  NotifyStackLocation stack_location;
 
875
  const char *slocation;
 
876
  gint i;
 
877
 
 
878
  if (daemon == NULL)
 
879
    return;
 
880
 
 
881
  stack_location = NOTIFY_STACK_LOCATION_DEFAULT;
 
882
 
 
883
  for (i = 0; i < daemon->priv->stacks_size; i++)
 
884
    notify_stack_set_location(daemon->priv->stacks[i], stack_location);
 
885
}
 
886
 
 
887
static void
 
888
url_clicked_cb(GtkWindow *nw, const char *url)
 
889
{
 
890
  NotifyDaemon *daemon = NW_GET_DAEMON(nw);
 
891
  char *escaped_url;
 
892
  char *cmd = NULL;
 
893
 
 
894
  /* Somewhat of a hack.. */
 
895
  daemon->priv->url_clicked_lock = TRUE;
 
896
 
 
897
  escaped_url = g_shell_quote(url);
 
898
 
 
899
  /*
 
900
   * We can't actually check for GNOME_DESKTOP_SESSION_ID, because it's
 
901
   * not in the environment for this program :(
 
902
   */
 
903
 
 
904
  if (/*g_getenv("GNOME_DESKTOP_SESSION_ID") != NULL &&*/
 
905
    g_find_program_in_path("gnome-open") != NULL)
 
906
  {
 
907
    cmd = g_strdup_printf("gnome-open %s", escaped_url);
 
908
  }
 
909
  else if (g_find_program_in_path("mozilla-firefox") != NULL)
 
910
  {
 
911
    cmd = g_strdup_printf("mozilla-firefox %s", escaped_url);
 
912
  }
 
913
  else if (g_find_program_in_path("firefox") != NULL)
 
914
  {
 
915
    cmd = g_strdup_printf("firefox %s", escaped_url);
 
916
  }
 
917
  else if (g_find_program_in_path("mozilla") != NULL)
 
918
  {
 
919
    cmd = g_strdup_printf("mozilla %s", escaped_url);
 
920
  }
 
921
  else
 
922
  {
 
923
    g_warning("Unable to find a browser.");
 
924
  }
 
925
 
 
926
  g_free(escaped_url);
 
927
 
 
928
  if (cmd != NULL)
 
929
  {
 
930
    g_spawn_command_line_async(cmd, NULL);
 
931
    g_free(cmd);
 
932
  }
 
933
}
 
934
 
 
935
static gboolean
 
936
screensaver_active(GtkWidget *nw)
 
937
{
 
938
  GdkDisplay *display = gdk_drawable_get_display(GDK_DRAWABLE(nw->window));
 
939
  Atom type;
 
940
  int format;
 
941
  unsigned long nitems, bytes_after;
 
942
  unsigned char *temp_data;
 
943
  gboolean active = FALSE;
 
944
  Atom XA_BLANK = gdk_x11_get_xatom_by_name_for_display(display, "BLANK");
 
945
  Atom XA_LOCK = gdk_x11_get_xatom_by_name_for_display(display, "LOCK");
 
946
 
 
947
  /* Check for a screensaver first. */
 
948
 
 
949
  if (XGetWindowProperty(
 
950
        GDK_DISPLAY_XDISPLAY(display),
 
951
        GDK_ROOT_WINDOW(),
 
952
        gdk_x11_get_xatom_by_name_for_display(display, "_SCREENSAVER_STATUS"),
 
953
        0, G_MAXLONG, False, XA_INTEGER, &type, &format, &nitems,
 
954
        &bytes_after, &temp_data) == Success &&
 
955
      type && temp_data != NULL)
 
956
  {
 
957
    CARD32 *data = (CARD32 *)temp_data;
 
958
 
 
959
    active = (type == XA_INTEGER && nitems >= 3 &&
 
960
              (time_t)data[1] > (time_t)666000000L &&
 
961
              (data[0] == XA_BLANK || data[0] == XA_LOCK));
 
962
  }
 
963
 
 
964
  if (temp_data != NULL)
 
965
    XFree(temp_data);
 
966
  return active;
 
967
}
 
968
 
 
969
static gboolean
 
970
fullscreen_window_exists(GtkWidget *nw)
 
971
{
 
972
  WnckScreen *wnck_screen;
 
973
  WnckWorkspace *wnck_workspace;
 
974
  GList *l;
 
975
 
 
976
  wnck_screen = wnck_screen_get(GDK_SCREEN_XNUMBER(
 
977
                                  gdk_drawable_get_screen(GDK_DRAWABLE(GTK_WIDGET(nw)->window))));
 
978
  wnck_screen_force_update(wnck_screen);
 
979
 
 
980
  wnck_workspace = wnck_screen_get_active_workspace(wnck_screen);
 
981
 
 
982
  for (l = wnck_screen_get_windows_stacked(wnck_screen);
 
983
       l != NULL;
 
984
       l = l->next)
 
985
  {
 
986
    WnckWindow *wnck_win = (WnckWindow *)l->data;
 
987
 
 
988
    if (wnck_window_is_on_workspace(wnck_win, wnck_workspace) &&
 
989
        wnck_window_is_fullscreen(wnck_win) &&
 
990
        wnck_window_is_active(wnck_win))
 
991
    {
 
992
      /*
 
993
       * Sanity check if the window is _really_ fullscreen to
 
994
       * work around a bug in libwnck that doesn't get all
 
995
       * unfullscreen events.
 
996
       */
 
997
      int sw = wnck_screen_get_width(wnck_screen);
 
998
      int sh = wnck_screen_get_height(wnck_screen);
 
999
      int x, y, w, h;
 
1000
 
 
1001
      wnck_window_get_geometry(wnck_win, &x, &y, &w, &h);
 
1002
 
 
1003
      if (sw == w && sh == h)
 
1004
        return TRUE;
 
1005
    }
 
1006
  }
 
1007
 
 
1008
  return FALSE;
 
1009
}
 
1010
 
 
1011
static Window
 
1012
get_window_parent(Display *display,
 
1013
          Window window,
 
1014
          Window *root)
 
1015
{
 
1016
  Window parent;
 
1017
  Window *children = NULL;
 
1018
  guint nchildren;
 
1019
  gboolean result;
 
1020
 
 
1021
  gdk_error_trap_push();
 
1022
  result = XQueryTree(display, window, root, &parent, &children, &nchildren);
 
1023
  if (gdk_error_trap_pop() || !result)
 
1024
    return None;
 
1025
 
 
1026
  if (children)
 
1027
    XFree(children);
 
1028
 
 
1029
  return parent;
 
1030
}
 
1031
 
 
1032
/*
 
1033
 * Recurse over X Window and parents, up to root, and start watching them
 
1034
 * for position changes.
 
1035
 */
 
1036
static void
 
1037
monitor_notification_source_windows(NotifyDaemon *daemon,
 
1038
                  NotifyTimeout *nt,
 
1039
                  Window source)
 
1040
{
 
1041
  Display *display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
 
1042
  Window root = None;
 
1043
  Window parent;
 
1044
 
 
1045
  /* Store the window in the timeout */
 
1046
  g_assert(nt != NULL);
 
1047
  nt->src_window_xid = source;
 
1048
 
 
1049
  for (parent = get_window_parent(display, source, &root);
 
1050
     parent != None && root != parent;
 
1051
     parent = get_window_parent(display, parent, &root)) {
 
1052
 
 
1053
    XSelectInput(display, parent, StructureNotifyMask);
 
1054
    g_hash_table_insert(daemon->priv->monitored_window_hash,
 
1055
              GUINT_TO_POINTER(parent), GINT_TO_POINTER(nt->id));
 
1056
  }
 
1057
}
 
1058
 
 
1059
/* Use a source X Window ID to reposition a notification. */
 
1060
static void
 
1061
sync_notification_position(NotifyDaemon *daemon,
 
1062
               GtkWindow *nw,
 
1063
               Window source)
 
1064
{
 
1065
  Display *display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
 
1066
  Status result;
 
1067
  Window root;
 
1068
  Window child;
 
1069
  int x, y;
 
1070
  unsigned int width, height;
 
1071
  unsigned int border_width, depth;
 
1072
 
 
1073
  gdk_error_trap_push();
 
1074
 
 
1075
  /* Get the root for this window */
 
1076
  result = XGetGeometry(display, source, &root, &x, &y,
 
1077
              &width, &height, &border_width, &depth);
 
1078
  if (gdk_error_trap_pop() || !result)
 
1079
    return;
 
1080
 
 
1081
  /*
 
1082
   * Now calculate the offset coordinates for the source window from
 
1083
   * the root.
 
1084
   */
 
1085
  gdk_error_trap_push ();
 
1086
  result = XTranslateCoordinates(display, source, root, 0, 0,
 
1087
                   &x, &y, &child);
 
1088
  if (gdk_error_trap_pop() || !result)
 
1089
    return;
 
1090
 
 
1091
  x += width  / 2;
 
1092
  y += height / 2;
 
1093
 
 
1094
  /*
 
1095
   * We need to manually queue a draw here as the default theme recalculates
 
1096
   * its position in the draw handler and moves the window (which seems
 
1097
   * fairly broken), so just calling move/show above isn't enough to cause
 
1098
   * its position to be calculated.
 
1099
   */
 
1100
  gtk_widget_queue_draw(GTK_WIDGET(nw));
 
1101
}
 
1102
 
 
1103
GQuark
 
1104
notify_daemon_error_quark(void)
 
1105
{
 
1106
  static GQuark q = 0;
 
1107
 
 
1108
  if (q == 0)
 
1109
    q = g_quark_from_static_string("notification-daemon-error-quark");
 
1110
 
 
1111
  return q;
 
1112
}
 
1113
 
 
1114
gboolean
 
1115
notify_daemon_notify_handler(NotifyDaemon *daemon,
 
1116
                             const gchar *app_name,
 
1117
                             guint id,
 
1118
                             const gchar *icon,
 
1119
                             const gchar *summary,
 
1120
                             const gchar *body,
 
1121
                             gchar **actions,
 
1122
                             GHashTable *hints,
 
1123
                             int timeout, DBusGMethodInvocation *context)
 
1124
{
 
1125
  NotifyDaemonPrivate *priv = daemon->priv;
 
1126
  NotifyTimeout *nt = NULL;
 
1127
  GtkWindow *nw = NULL;
 
1128
  GValue *data;
 
1129
  gboolean use_pos_data = FALSE;
 
1130
  gboolean new_notification = FALSE;
 
1131
  gint x = 0;
 
1132
  gint y = 0;
 
1133
  Window window_xid = None;
 
1134
  guint return_id;
 
1135
  gchar *sender;
 
1136
  gchar *sound_file = NULL;
 
1137
  gboolean sound_enabled;
 
1138
  gint i;
 
1139
 
 
1140
  if (id > 0)
 
1141
  {
 
1142
    nt = (NotifyTimeout *)g_hash_table_lookup(priv->notification_hash,
 
1143
         &id);
 
1144
 
 
1145
    if (nt != NULL)
 
1146
      nw = nt->nw;
 
1147
    else
 
1148
      id = 0;
 
1149
  }
 
1150
 
 
1151
  if (nw == NULL)
 
1152
  {
 
1153
    nw = create_notification(url_clicked_cb);
 
1154
    g_object_set_data(G_OBJECT(nw), "_notify_daemon", daemon);
 
1155
    gtk_widget_realize(GTK_WIDGET(nw));
 
1156
    new_notification = TRUE;
 
1157
 
 
1158
    g_signal_connect(G_OBJECT(nw), "button-release-event",
 
1159
                     G_CALLBACK(window_clicked_cb), daemon);
 
1160
    g_signal_connect(G_OBJECT(nw), "destroy",
 
1161
                     G_CALLBACK(_notification_destroyed_cb), daemon);
 
1162
    g_signal_connect(G_OBJECT(nw), "enter-notify-event",
 
1163
                     G_CALLBACK(_mouse_entered_cb), daemon);
 
1164
    g_signal_connect(G_OBJECT(nw), "leave-notify-event",
 
1165
                     G_CALLBACK(_mouse_exitted_cb), daemon);
 
1166
  }
 
1167
  else
 
1168
  {
 
1169
    clear_notification_actions(nw);
 
1170
  }
 
1171
 
 
1172
  set_notification_text(nw, summary, body);
 
1173
 
 
1174
  set_notification_hints(nw, hints);
 
1175
 
 
1176
  /*
 
1177
   *XXX This needs to handle file URIs and all that.
 
1178
   */
 
1179
 
 
1180
 
 
1181
  if ((data = (GValue *)g_hash_table_lookup(hints, "window-xid")) != NULL)
 
1182
  {
 
1183
    window_xid = (Window)g_value_get_uint(data);
 
1184
  }
 
1185
  /* deal with x, and y hints */
 
1186
  else if ((data = (GValue *)g_hash_table_lookup(hints, "x")) != NULL)
 
1187
  {
 
1188
    x = g_value_get_int(data);
 
1189
 
 
1190
    if ((data = (GValue *)g_hash_table_lookup(hints, "y")) != NULL)
 
1191
    {
 
1192
      y = g_value_get_int(data);
 
1193
      use_pos_data = TRUE;
 
1194
    }
 
1195
  }
 
1196
 
 
1197
  /* Deal with sound hints */
 
1198
 
 
1199
  sound_enabled = desktop_agnostic_config_client_get_bool (conf_client,  DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,"sound_enabled",NULL);
 
1200
 
 
1201
  data = (GValue *)g_hash_table_lookup(hints, "suppress-sound");
 
1202
 
 
1203
  if (data != NULL)
 
1204
  {
 
1205
    if (G_VALUE_HOLDS_BOOLEAN(data))
 
1206
      sound_enabled = !g_value_get_boolean(data);
 
1207
    else if (G_VALUE_HOLDS_INT(data))
 
1208
      sound_enabled = (g_value_get_int(data) != 0);
 
1209
    else
 
1210
    {
 
1211
      g_warning("suppress-sound is of type %s (expected bool or int)\n",
 
1212
                g_type_name(G_VALUE_TYPE(data)));
 
1213
    }
 
1214
  }
 
1215
 
 
1216
  if (sound_enabled)
 
1217
  {
 
1218
    data = (GValue *)g_hash_table_lookup(hints, "sound-file");
 
1219
 
 
1220
    if (data != NULL)
 
1221
    {
 
1222
      sound_file = g_value_dup_string(data);
 
1223
 
 
1224
      if (*sound_file == '\0' ||
 
1225
          !g_file_test(sound_file, G_FILE_TEST_EXISTS))
 
1226
      {
 
1227
        g_free(sound_file);
 
1228
        sound_file = NULL;
 
1229
      }
 
1230
    }
 
1231
 
 
1232
    /*
 
1233
     * TODO: If we don't have a sound_file yet, get the urgency hint, then
 
1234
     *       get the corresponding system event sound
 
1235
     *
 
1236
     *       We will need to parse /etc/sound/events/gnome-2.soundlist
 
1237
     *       and ~/.gnome2/sound/events/gnome-2.soundlist.
 
1238
     */
 
1239
 
 
1240
    /* If we don't have a sound file yet, use our gconf default */
 
1241
    if (sound_file == NULL)
 
1242
    {
 
1243
      sound_file = desktop_agnostic_config_client_get_string (conf_client,  DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,"default_sound",NULL);
 
1244
      if (sound_file != NULL &&
 
1245
          (*sound_file == '\0' ||
 
1246
           !g_file_test(sound_file, G_FILE_TEST_EXISTS)))
 
1247
      {
 
1248
        g_free(sound_file);
 
1249
        sound_file = NULL;
 
1250
      }
 
1251
    }
 
1252
  }
 
1253
 
 
1254
  /* set up action buttons */
 
1255
  for (i = 0; actions[i] != NULL; i += 2)
 
1256
  {
 
1257
    gchar *l = actions[i + 1];
 
1258
 
 
1259
    if (l == NULL)
 
1260
    {
 
1261
      g_warning("Label not found for action %s. "
 
1262
                "The protocol specifies that a label must "
 
1263
                "follow an action in the actions array", actions[i]);
 
1264
 
 
1265
      break;
 
1266
    }
 
1267
 
 
1268
    if (strcasecmp(actions[i], "default"))
 
1269
    {
 
1270
      add_notification_action(nw, l, actions[i],
 
1271
                              G_CALLBACK(_action_invoked_cb));
 
1272
    }
 
1273
  }
 
1274
 
 
1275
  /* check for icon_data if icon == "" */
 
1276
  if (*icon == '\0')
 
1277
  {
 
1278
    data = (GValue *)g_hash_table_lookup(hints, "icon_data");
 
1279
 
 
1280
    if (data)
 
1281
      _notify_daemon_process_icon_data(daemon, nw, data);
 
1282
  }
 
1283
  else
 
1284
  {
 
1285
    GdkPixbuf *pixbuf = NULL;
 
1286
 
 
1287
    if (!strncmp(icon, "file://", 7) || *icon == '/')
 
1288
    {
 
1289
      if (!strncmp(icon, "file://", 7))
 
1290
        icon += 7;
 
1291
 
 
1292
      /* Load file */
 
1293
      pixbuf = gdk_pixbuf_new_from_file(icon, NULL);
 
1294
    }
 
1295
    else
 
1296
    {
 
1297
      /* Load icon theme icon */
 
1298
      GtkIconTheme *theme = gtk_icon_theme_get_default();
 
1299
      GtkIconInfo *icon_info =
 
1300
        gtk_icon_theme_lookup_icon(theme, icon, IMAGE_SIZE,
 
1301
                                   GTK_ICON_LOOKUP_USE_BUILTIN);
 
1302
 
 
1303
      if (icon_info != NULL)
 
1304
      {
 
1305
        gint icon_size = MIN(IMAGE_SIZE,
 
1306
                             gtk_icon_info_get_base_size(icon_info));
 
1307
 
 
1308
        if (icon_size == 0)
 
1309
          icon_size = IMAGE_SIZE;
 
1310
 
 
1311
        pixbuf = gtk_icon_theme_load_icon(theme, icon, icon_size,
 
1312
                                          GTK_ICON_LOOKUP_USE_BUILTIN,
 
1313
                                          NULL);
 
1314
 
 
1315
        gtk_icon_info_free(icon_info);
 
1316
      }
 
1317
 
 
1318
      if (pixbuf == NULL)
 
1319
      {
 
1320
        /* Well... maybe this is a file afterall. */
 
1321
        pixbuf = gdk_pixbuf_new_from_file(icon, NULL);
 
1322
      }
 
1323
    }
 
1324
 
 
1325
    if (pixbuf != NULL)
 
1326
    {
 
1327
      set_notification_icon(nw, pixbuf);
 
1328
      g_object_unref(G_OBJECT(pixbuf));
 
1329
    }
 
1330
  }
 
1331
 
 
1332
  if (window_xid != None && G_daemon_config.awn_client_pos)
 
1333
  {
 
1334
    /*
 
1335
     * Do nothing here if we were passed an XID; we'll call
 
1336
     * sync_notification_position later.
 
1337
     */
 
1338
  }
 
1339
  else if (use_pos_data && G_daemon_config.awn_client_pos)
 
1340
  {
 
1341
    /*
 
1342
     * Typically, the theme engine will set its own position based on
 
1343
     * the arrow X, Y hints. However, in case, move the notification to
 
1344
     * that position.
 
1345
     */
 
1346
    set_notification_arrow(GTK_WIDGET(nw), TRUE, x, y);
 
1347
    move_notification(GTK_WIDGET(nw), x, y);
 
1348
  }
 
1349
  else
 
1350
  {
 
1351
    gint monitor;
 
1352
    GdkScreen *screen;
 
1353
    gint x, y;
 
1354
    set_notification_arrow(GTK_WIDGET(nw), FALSE, 0, 0);
 
1355
 
 
1356
    gdk_display_get_pointer(gdk_display_get_default(),
 
1357
                            &screen, &x, &y, NULL);
 
1358
    monitor = gdk_screen_get_monitor_at_point(screen, x, y);
 
1359
    g_assert(monitor >= 0 && monitor < priv->stacks_size);
 
1360
 
 
1361
    notify_stack_add_window(priv->stacks[monitor], nw, new_notification);
 
1362
  }
 
1363
 
 
1364
  if (id == 0)
 
1365
  {
 
1366
    nt = _store_notification(daemon, nw, timeout);
 
1367
    return_id = nt->id;
 
1368
  }
 
1369
  else
 
1370
    return_id = id;
 
1371
 
 
1372
  /*
 
1373
   * If we have a source Window XID, start monitoring the tree
 
1374
   * for changes, and reposition the window based on the source
 
1375
   * window.  We need to do this after return_id is calculated.
 
1376
   */
 
1377
  if (window_xid != None && G_daemon_config.awn_client_pos)
 
1378
  {
 
1379
    monitor_notification_source_windows(daemon, nt, window_xid);
 
1380
    sync_notification_position(daemon, nw, window_xid);
 
1381
  }
 
1382
 
 
1383
  if (!screensaver_active(GTK_WIDGET(nw)) &&
 
1384
      !fullscreen_window_exists(GTK_WIDGET(nw)))
 
1385
  {
 
1386
    show_notification(nw);
 
1387
 
 
1388
    if (sound_file != NULL)
 
1389
      sound_play(sound_file);
 
1390
  }
 
1391
 
 
1392
  g_free(sound_file);
 
1393
 
 
1394
#if CHECK_DBUS_VERSION(0, 60)
 
1395
  sender = dbus_g_method_get_sender(context);
 
1396
#else
 
1397
  sender = g_strdup(dbus_message_get_sender(
 
1398
                      dbus_g_message_get_message(context->message)));
 
1399
#endif
 
1400
 
 
1401
  g_object_set_data(G_OBJECT(nw), "_notify_id",
 
1402
                    GUINT_TO_POINTER(return_id));
 
1403
  g_object_set_data_full(G_OBJECT(nw), "_notify_sender", sender,
 
1404
                         (GDestroyNotify)g_free);
 
1405
 
 
1406
  if (nt)
 
1407
    _calculate_timeout(daemon, nt, timeout);
 
1408
 
 
1409
  dbus_g_method_return(context, return_id);
 
1410
 
 
1411
  return TRUE;
 
1412
}
 
1413
 
 
1414
gboolean
 
1415
notify_daemon_close_notification_handler(NotifyDaemon *daemon,
 
1416
    guint id, GError **error)
 
1417
{
 
1418
  if (id == 0)
 
1419
  {
 
1420
    g_set_error(error, notify_daemon_error_quark(), 100,
 
1421
                _("%u is not a valid notification ID"), id);
 
1422
    return FALSE;
 
1423
  }
 
1424
  else
 
1425
  {
 
1426
    _close_notification(daemon, id, TRUE, NOTIFYD_CLOSED_API);
 
1427
    return TRUE;
 
1428
  }
 
1429
}
 
1430
 
 
1431
gboolean
 
1432
notify_daemon_get_capabilities(NotifyDaemon *daemon, char ***caps)
 
1433
{
 
1434
  *caps = g_new0(char *, 6);
 
1435
 
 
1436
  (*caps)[0] = g_strdup("actions");
 
1437
  (*caps)[1] = g_strdup("body");
 
1438
  (*caps)[2] = g_strdup("body-hyperlinks");
 
1439
  (*caps)[3] = g_strdup("body-markup");
 
1440
  (*caps)[4] = g_strdup("icon-static");
 
1441
  (*caps)[5] = NULL;
 
1442
 
 
1443
  return TRUE;
 
1444
}
 
1445
 
 
1446
gboolean
 
1447
notify_daemon_get_server_information(NotifyDaemon *daemon,
 
1448
                                     char **out_name,
 
1449
                                     char **out_vendor,
 
1450
                                     char **out_version,
 
1451
                                     char **out_spec_ver)
 
1452
{
 
1453
  *out_name     = g_strdup("Notification Daemon");
 
1454
  *out_vendor   = g_strdup("Galago Project");
 
1455
  *out_version  = g_strdup(VERSION);
 
1456
  *out_spec_ver = g_strdup("1.0");
 
1457
 
 
1458
  return TRUE;
 
1459
}
 
1460
 
 
1461
DesktopAgnosticConfigClient  *
 
1462
get_conf_client(void)
 
1463
{
 
1464
  return conf_client;
 
1465
}
 
1466
 
 
1467
static void
 
1468
_height_changed(AwnApplet *app, guint height, gpointer *data)
 
1469
{
 
1470
}
 
1471
 
 
1472
gboolean _do_wait(gpointer null)
 
1473
{
 
1474
  return (waitpid(-1, NULL,  WNOHANG) <= 0) ;
 
1475
 
 
1476
}
 
1477
 
 
1478
gboolean send_message(gchar *body)
 
1479
{
 
1480
  NotifyNotification *notify;
 
1481
  gchar *summary = "Awn Notification Daemon Message";
 
1482
  gchar *type = NULL;
 
1483
  gchar *icon_str = NULL;
 
1484
  glong expire_timeout = NOTIFY_EXPIRES_DEFAULT;
 
1485
  NotifyUrgency urgency = NOTIFY_URGENCY_NORMAL;
 
1486
 
 
1487
  if (fork() == 0)
 
1488
  {
 
1489
    notify_init("notify-send");
 
1490
    notify = notify_notification_new(summary, body, icon_str, NULL);
 
1491
    notify_notification_set_category(notify, type);
 
1492
    notify_notification_set_urgency(notify, urgency);
 
1493
    notify_notification_set_timeout(notify, expire_timeout);
 
1494
    notify_notification_show(notify, NULL);
 
1495
 
 
1496
    g_object_unref(G_OBJECT(notify));
 
1497
    notify_uninit();
 
1498
    exit(0);
 
1499
  }
 
1500
 
 
1501
  g_timeout_add(3000, (GSourceFunc)_do_wait, NULL);
 
1502
 
 
1503
  return FALSE;
 
1504
}
 
1505
 
 
1506
gboolean hide_icon(gpointer data)
 
1507
{
 
1508
 
 
1509
  gtk_widget_set_size_request(GTK_WIDGET(G_daemon_config.awn_app), 1, 1);
 
1510
  gtk_widget_hide(GTK_WIDGET(G_daemon_config.awn_app));
 
1511
//  g_object_unref(G_daemon_config.awn_icon);
 
1512
 
 
1513
  G_daemon_config.awn_icon = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 1, 1);
 
1514
  gdk_pixbuf_fill(G_daemon_config.awn_icon, 0x00000000);
 
1515
  awn_applet_simple_set_icon_pixbuf(AWN_APPLET_SIMPLE(G_daemon_config.awn_app), G_daemon_config.awn_icon);
 
1516
//  g_object_unref(G_daemon_config.awn_icon);  
 
1517
  G_daemon_config.awn_icon = NULL;
 
1518
 
 
1519
  return FALSE;
 
1520
}
 
1521
 
 
1522
static void 
 
1523
config_get_color(DesktopAgnosticConfigClient *client, gchar * group,const gchar *key, DesktopAgnosticColor **color)
 
1524
{
 
1525
  GError *error = NULL;
 
1526
  GValue value = {0,};
 
1527
 
 
1528
  desktop_agnostic_config_client_get_value(client, group, key, &value, &error);
 
1529
 
 
1530
  if (error)
 
1531
  {
 
1532
    g_warning("Notification Daemon: error reading config string (%s): %s", key, error->message);
 
1533
    g_error_free(error);
 
1534
    *color = desktop_agnostic_color_new_from_string("#000", NULL);
 
1535
  }
 
1536
  else
 
1537
  {
 
1538
    *color = (DesktopAgnosticColor*)g_value_dup_object(&value);
 
1539
    g_value_unset(&value);
 
1540
  }
 
1541
}
 
1542
 
 
1543
static void read_config(void)
 
1544
{
 
1545
  static gboolean done_once = FALSE;
 
1546
  gchar * svalue;
 
1547
  static DesktopAgnosticConfigClient * theme_client = NULL;
 
1548
  GError * error = NULL;
 
1549
 
 
1550
  if (!theme_client)
 
1551
  {
 
1552
    theme_client = awn_config_get_default (AWN_PANEL_ID_DEFAULT,NULL);
 
1553
  }
 
1554
 
 
1555
  if (desktop_agnostic_config_client_get_bool (conf_client,  DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,GCONF_KEY_AWN_KILL_ND,NULL))
 
1556
  {
 
1557
    if (!done_once)
 
1558
    {
 
1559
      DBusGConnection *connection;
 
1560
      DBusGProxy *proxy;
 
1561
      connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
 
1562
      if (error)
 
1563
      {
 
1564
        g_warning ("Unable to make connection to the D-Bus session bus: %s",
 
1565
                   error->message);
 
1566
        g_error_free (error);
 
1567
      }
 
1568
      if (connection)
 
1569
      {
 
1570
        unsigned int pid=0;
 
1571
        proxy = dbus_g_proxy_new_for_name (connection,
 
1572
                                             "org.freedesktop.DBus", 
 
1573
                                             "/org/freedesktop/DBus",
 
1574
                                             "org.freedesktop.DBus");
 
1575
 
 
1576
        dbus_g_proxy_call (proxy, "GetConnectionUnixProcessID", &error,
 
1577
                           G_TYPE_STRING, "org.freedesktop.Notifications",
 
1578
                           G_TYPE_INVALID,
 
1579
                           G_TYPE_UINT, &pid,
 
1580
                           G_TYPE_INVALID);
 
1581
 
 
1582
        if (pid)
 
1583
        {
 
1584
          kill ((pid_t)pid,SIGTERM);
 
1585
        }
 
1586
        dbus_g_connection_unref(connection);
 
1587
      }
 
1588
      if (proxy)
 
1589
      {
 
1590
        g_object_unref (proxy);
 
1591
      }
 
1592
    }
 
1593
  }
 
1594
 
 
1595
  G_daemon_config.awn_client_pos = desktop_agnostic_config_client_get_bool (conf_client,  DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,GCONF_KEY_AWN_CLIENT_POS,NULL);
 
1596
 
 
1597
  G_daemon_config.awn_use_theme = desktop_agnostic_config_client_get_bool (conf_client,  DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,GCONF_KEY_AWN_HONOUR_GTK,NULL);
 
1598
 
 
1599
  if (G_daemon_config.awn_use_theme)
 
1600
  {
 
1601
    config_get_color (theme_client, "theme","gstep2",&G_daemon_config.awn_bg);
 
1602
    if ( (double)desktop_agnostic_color_get_alpha (G_daemon_config.awn_bg)/(double)0xFFFF < 0.80)
 
1603
    {
 
1604
      desktop_agnostic_color_set_alpha (G_daemon_config.awn_bg, 0xFFFF * 0.8);
 
1605
    }
 
1606
 
 
1607
    if ( desktop_agnostic_config_client_get_int (theme_client,"theme","icon_font_mode",NULL) == 2)
 
1608
    {
 
1609
      config_get_color (theme_client, "theme","icon_text_outline_color",&G_daemon_config.awn_text);
 
1610
    }
 
1611
    else
 
1612
    {
 
1613
      config_get_color (theme_client, "theme","icon_text_color",&G_daemon_config.awn_text);
 
1614
    }
 
1615
    if (!G_daemon_config.awn_text)
 
1616
    {
 
1617
      G_daemon_config.awn_text = desktop_agnostic_color_new_from_string ("white",NULL);
 
1618
    }
 
1619
    G_daemon_config.awn_text_str = desktop_agnostic_color_to_string (G_daemon_config.awn_text);
 
1620
 
 
1621
    gchar * tmp = g_strdup (G_daemon_config.awn_text_str+1);
 
1622
    g_free (G_daemon_config.awn_text_str);
 
1623
    G_daemon_config.awn_text_str = tmp;
 
1624
 
 
1625
    if (strlen(G_daemon_config.awn_text_str) > 6)
 
1626
      G_daemon_config.awn_text_str[6] = '\0';
 
1627
 
 
1628
    config_get_color (theme_client, "theme","ghistep2",&G_daemon_config.awn_border);
 
1629
  }
 
1630
  else
 
1631
  {
 
1632
    config_get_color (conf_client, DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,GCONF_KEY_AWN_BG,&G_daemon_config.awn_bg);
 
1633
 
 
1634
    config_get_color (conf_client, DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,GCONF_KEY_AWN_TEXT_COLOUR,&G_daemon_config.awn_text);
 
1635
 
 
1636
    G_daemon_config.awn_text_str = desktop_agnostic_color_to_string (G_daemon_config.awn_text);
 
1637
 
 
1638
    gchar * tmp = g_strdup (G_daemon_config.awn_text_str+1);
 
1639
    g_free (G_daemon_config.awn_text_str);
 
1640
    G_daemon_config.awn_text_str = tmp;
 
1641
 
 
1642
    if (strlen(G_daemon_config.awn_text_str) > 6)
 
1643
      G_daemon_config.awn_text_str[6] = '\0';
 
1644
 
 
1645
    config_get_color (conf_client, DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,GCONF_KEY_AWN_BG,&G_daemon_config.awn_border);
 
1646
  }    
 
1647
  G_daemon_config.awn_border_width = desktop_agnostic_config_client_get_int (conf_client,  DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,GCONF_KEY_AWN_BORDER_WIDTH,NULL);
 
1648
 
 
1649
  G_daemon_config.awn_gradient_factor = desktop_agnostic_config_client_get_float (conf_client,  DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,GCONF_KEY_AWN_GRADIENT_FACTOR,NULL);
 
1650
 
 
1651
  G_daemon_config.awn_override_x = desktop_agnostic_config_client_get_int (conf_client,  DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,GCONF_KEY_AWN_OVERRIDE_X,NULL);
 
1652
    
 
1653
  G_daemon_config.awn_override_y = desktop_agnostic_config_client_get_int (conf_client,  DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,GCONF_KEY_AWN_OVERRIDE_Y,NULL);
 
1654
 
 
1655
  G_daemon_config.timeout = desktop_agnostic_config_client_get_int (conf_client,  DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,GCONF_KEY_AWN_TIMEOUT,NULL);
 
1656
 
 
1657
  G_daemon_config.bold_text_body = desktop_agnostic_config_client_get_bool (conf_client,  DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,GCONF_KEY_AWN_BOLD_BODY,NULL);
 
1658
 
 
1659
  G_daemon_config.show_icon = desktop_agnostic_config_client_get_bool (conf_client,  DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,GCONF_KEY_AWN_SHOW_ICON,NULL);
 
1660
 
 
1661
  G_daemon_config.hide_opacity = desktop_agnostic_config_client_get_float (conf_client,  DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,GCONF_KEY_AWN_HIDE_OPACITY,NULL);
 
1662
  done_once = TRUE;
 
1663
}
 
1664
 
 
1665
static void 
 
1666
_change_config_cb(const gchar *group, const gchar *key, const GValue *value, gpointer user_data)
 
1667
{
 
1668
  read_config ();  
 
1669
  g_debug ("%s",__func__);
 
1670
}
 
1671
 
 
1672
static gboolean _button_clicked_event(GtkWidget *widget, GdkEventButton *event, void * null)
 
1673
{
 
1674
  static GtkWidget *menu=NULL;  
 
1675
  G_daemon_config.show_status = !G_daemon_config.show_status;
 
1676
  if (event->button == 1)
 
1677
  {
 
1678
    if (G_daemon_config.show_status)
 
1679
    {
 
1680
//      gdk_pixbuf_fill(G_daemon_config.awn_icon, 0xdddddd33);
 
1681
      awn_applet_simple_set_icon_state(AWN_APPLET_SIMPLE(G_daemon_config.awn_app),"On");
 
1682
    }
 
1683
    else
 
1684
    {
 
1685
//      gdk_pixbuf_fill(G_daemon_config.awn_icon, 0x00000033);
 
1686
      awn_applet_simple_set_icon_state(AWN_APPLET_SIMPLE(G_daemon_config.awn_app),"Off");      
 
1687
    }
 
1688
 
 
1689
//    awn_applet_simple_set_icon(AWN_APPLET_SIMPLE(G_daemon_config.awn_app), G_daemon_config.awn_icon);
 
1690
  }
 
1691
  else if (event->button == 3)
 
1692
  {
 
1693
    if (!menu)
 
1694
    {
 
1695
      menu = awn_applet_create_default_menu (G_daemon_config.awn_app);
 
1696
      gtk_menu_set_screen (GTK_MENU (menu), NULL);
 
1697
    }
 
1698
    gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
 
1699
                    event->button, event->time);    
 
1700
  }
 
1701
  return TRUE;
 
1702
}
 
1703
 
 
1704
AwnApplet* awn_applet_factory_initp(const gchar *name,
 
1705
                                    const gchar *uid, gint panel_id)
 
1706
{
 
1707
  NotifyDaemon *daemon;
 
1708
  DBusGConnection *connection;
 
1709
  DBusGProxy *bus_proxy;
 
1710
  GError *error;
 
1711
  guint request_name_result;
 
1712
  AwnApplet *applet;
 
1713
  DesktopAgnosticConfigClient * theme_client = NULL;
 
1714
 
 
1715
  G_daemon_config.awn_app = applet = AWN_APPLET(awn_applet_simple_new(name, uid, panel_id));
 
1716
  theme_client = awn_config_get_default (AWN_PANEL_ID_DEFAULT, &error);
 
1717
  
 
1718
  gint height = awn_applet_get_size(applet);
 
1719
 
 
1720
  G_daemon_config.awn_app_height = height;
 
1721
  G_daemon_config.show_status = TRUE;
 
1722
  
 
1723
  g_object_set (applet,
 
1724
                "display-name","Awn Notification Daemon",
 
1725
                NULL);
 
1726
 
 
1727
  g_signal_connect(G_OBJECT(applet), "size-changed", G_CALLBACK(_height_changed), (gpointer)applet);
 
1728
  gtk_widget_set_size_request(GTK_WIDGET(applet), height, height);
 
1729
 
 
1730
#if 0
 
1731
  G_daemon_config.awn_icon = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, height, height);
 
1732
  gdk_pixbuf_fill(G_daemon_config.awn_icon, 0xdddddd33);
 
1733
  awn_applet_simple_set_icon(AWN_APPLET_SIMPLE(applet), G_daemon_config.awn_icon);
 
1734
#endif
 
1735
 
 
1736
  gchar * states[]={"On","Off",NULL};
 
1737
  gchar * icon_names[]={"stock_up","stock_down",NULL};
 
1738
  awn_applet_simple_set_icon_info(AWN_APPLET_SIMPLE(applet),
 
1739
                                    states,
 
1740
                                    icon_names
 
1741
                                    );
 
1742
  awn_applet_simple_set_icon_state (AWN_APPLET_SIMPLE(applet),"On");
 
1743
/*  awn_applet_simple_set_icon_name (AWN_APPLET_SIMPLE(applet),
 
1744
                                    "Awn Notification Daemon",
 
1745
                                    "Off");*/
 
1746
/*  gtk_widget_show_all(GTK_WIDGET(applet));*/
 
1747
 
 
1748
 
 
1749
  g_log_set_always_fatal(G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
 
1750
 
 
1751
  sound_init();
 
1752
 
 
1753
  conf_client = awn_config_get_default_for_applet(AWN_APPLET(applet), NULL);
 
1754
 
 
1755
  error = NULL;
 
1756
 
 
1757
  read_config();
 
1758
  
 
1759
  connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
 
1760
 
 
1761
  while (connection == NULL)
 
1762
  {
 
1763
    printf("Failed to open connection to bus: %s. sleeping 5 s.\n",
 
1764
           error->message);
 
1765
    g_error_free(error);
 
1766
    connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
 
1767
    sleep(5);
 
1768
  }
 
1769
 
 
1770
  dbus_conn = dbus_g_connection_get_connection(connection);
 
1771
 
 
1772
  assert(dbus_conn);
 
1773
 
 
1774
  dbus_g_object_type_install_info(NOTIFY_TYPE_DAEMON,
 
1775
                                  &dbus_glib_notification_daemon_object_info);
 
1776
 
 
1777
  bus_proxy = dbus_g_proxy_new_for_name(connection,
 
1778
                                        "org.freedesktop.DBus",
 
1779
                                        "/org/freedesktop/DBus",
 
1780
                                        "org.freedesktop.DBus");
 
1781
  assert(bus_proxy);
 
1782
 
 
1783
  while (!dbus_g_proxy_call(bus_proxy, "RequestName", &error,
 
1784
                            G_TYPE_STRING, "org.freedesktop.Notifications",
 
1785
                            G_TYPE_UINT, 0,
 
1786
                            G_TYPE_INVALID,
 
1787
                            G_TYPE_UINT, &request_name_result,
 
1788
                            G_TYPE_INVALID))
 
1789
  {
 
1790
    printf("Could not aquire name: %s. sleeping 2 seconds", error->message);
 
1791
    sleep(2);
 
1792
  }
 
1793
 
 
1794
  daemon = g_object_new(NOTIFY_TYPE_DAEMON, NULL);
 
1795
 
 
1796
  assert(daemon);
 
1797
 
 
1798
  desktop_agnostic_config_client_notify_add(conf_client,
 
1799
                               DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,
 
1800
                               GCONF_KEY_AWN_KILL_ND,
 
1801
                               (DesktopAgnosticConfigNotifyFunc)_change_config_cb,
 
1802
                               applet, NULL);
 
1803
  
 
1804
  desktop_agnostic_config_client_notify_add(conf_client,
 
1805
                               DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,
 
1806
                               GCONF_KEY_AWN_BG,
 
1807
                               (DesktopAgnosticConfigNotifyFunc)_change_config_cb,
 
1808
                               applet, NULL);
 
1809
 
 
1810
  desktop_agnostic_config_client_notify_add(conf_client,
 
1811
                               DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,
 
1812
                               GCONF_KEY_AWN_BORDER,
 
1813
                               (DesktopAgnosticConfigNotifyFunc)_change_config_cb,
 
1814
                               applet, NULL);
 
1815
 
 
1816
  desktop_agnostic_config_client_notify_add(conf_client,
 
1817
                               DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,
 
1818
                               GCONF_KEY_AWN_BORDER_WIDTH,
 
1819
                               (DesktopAgnosticConfigNotifyFunc)_change_config_cb,
 
1820
                               applet, NULL);
 
1821
 
 
1822
  desktop_agnostic_config_client_notify_add(conf_client,
 
1823
                               DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,
 
1824
                               GCONF_KEY_AWN_GRADIENT_FACTOR,
 
1825
                               (DesktopAgnosticConfigNotifyFunc)_change_config_cb,
 
1826
                               applet, NULL);
 
1827
  
 
1828
  desktop_agnostic_config_client_notify_add(conf_client,
 
1829
                               DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,
 
1830
                               GCONF_KEY_AWN_TEXT_COLOUR,
 
1831
                               (DesktopAgnosticConfigNotifyFunc)_change_config_cb,
 
1832
                               applet, NULL);
 
1833
 
 
1834
  desktop_agnostic_config_client_notify_add(conf_client,
 
1835
                               DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,
 
1836
                               GCONF_KEY_AWN_CLIENT_POS,
 
1837
                               (DesktopAgnosticConfigNotifyFunc)_change_config_cb,
 
1838
                               applet, NULL);
 
1839
 
 
1840
  desktop_agnostic_config_client_notify_add(conf_client,
 
1841
                               DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,
 
1842
                               GCONF_KEY_AWN_HONOUR_GTK,
 
1843
                               (DesktopAgnosticConfigNotifyFunc)_change_config_cb,
 
1844
                               applet, NULL);
 
1845
 
 
1846
  desktop_agnostic_config_client_notify_add(conf_client,
 
1847
                               DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,
 
1848
                               GCONF_KEY_AWN_OVERRIDE_X,
 
1849
                               (DesktopAgnosticConfigNotifyFunc)_change_config_cb,
 
1850
                               applet, NULL);
 
1851
 
 
1852
  desktop_agnostic_config_client_notify_add(conf_client,
 
1853
                               DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,
 
1854
                               GCONF_KEY_AWN_OVERRIDE_Y,
 
1855
                               (DesktopAgnosticConfigNotifyFunc)_change_config_cb,
 
1856
                               applet, NULL);
 
1857
 
 
1858
  desktop_agnostic_config_client_notify_add(conf_client,
 
1859
                               DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,
 
1860
                               GCONF_KEY_AWN_TIMEOUT,
 
1861
                               (DesktopAgnosticConfigNotifyFunc)_change_config_cb,
 
1862
                               applet, NULL);
 
1863
 
 
1864
  desktop_agnostic_config_client_notify_add(conf_client,
 
1865
                               DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,
 
1866
                               GCONF_KEY_AWN_BOLD_BODY,
 
1867
                               (DesktopAgnosticConfigNotifyFunc)_change_config_cb,
 
1868
                               applet, NULL);
 
1869
 
 
1870
  desktop_agnostic_config_client_notify_add(conf_client,
 
1871
                               DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,
 
1872
                               GCONF_KEY_AWN_SHOW_ICON,
 
1873
                               (DesktopAgnosticConfigNotifyFunc)_change_config_cb,
 
1874
                               applet, NULL);
 
1875
 
 
1876
  desktop_agnostic_config_client_notify_add(conf_client,
 
1877
                               DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,
 
1878
                               GCONF_KEY_AWN_HIDE_OPACITY,
 
1879
                               (DesktopAgnosticConfigNotifyFunc)_change_config_cb,
 
1880
                               applet, NULL);
 
1881
 
 
1882
  desktop_agnostic_config_client_notify_add(conf_client,
 
1883
                               DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,
 
1884
                               "default_sound",
 
1885
                               (DesktopAgnosticConfigNotifyFunc)_change_config_cb,
 
1886
                               applet, NULL);
 
1887
 
 
1888
    desktop_agnostic_config_client_notify_add(conf_client,
 
1889
                               DESKTOP_AGNOSTIC_CONFIG_GROUP_DEFAULT,
 
1890
                               "sound_enabled",
 
1891
                               (DesktopAgnosticConfigNotifyFunc)_change_config_cb,
 
1892
                               applet, NULL);
 
1893
 
 
1894
    desktop_agnostic_config_client_notify_add(theme_client,
 
1895
                               "theme",
 
1896
                               "gtk_theme_mode",
 
1897
                               (DesktopAgnosticConfigNotifyFunc)_change_config_cb,
 
1898
                               applet, NULL);
 
1899
 
 
1900
    desktop_agnostic_config_client_notify_add(theme_client,
 
1901
                               "theme",
 
1902
                               "gstep2",
 
1903
                               (DesktopAgnosticConfigNotifyFunc)_change_config_cb,
 
1904
                               applet, NULL);
 
1905
 
 
1906
    desktop_agnostic_config_client_notify_add(theme_client,
 
1907
                               "theme",
 
1908
                               "icon_text_outline_color",
 
1909
                               (DesktopAgnosticConfigNotifyFunc)_change_config_cb,
 
1910
                               applet, NULL);
 
1911
 
 
1912
  desktop_agnostic_config_client_notify_add(theme_client,
 
1913
                               "theme",
 
1914
                               "icon_text_color",
 
1915
                               (DesktopAgnosticConfigNotifyFunc)_change_config_cb,
 
1916
                               applet, NULL);
 
1917
 
 
1918
  /* just chopping crap out converting to lda */
 
1919
  popup_location_changed_cb(conf_client, 0,NULL, daemon);
 
1920
 
 
1921
  dbus_g_connection_register_g_object(connection, "/org/freedesktop/Notifications", G_OBJECT(daemon));
 
1922
 
 
1923
//  g_timeout_add(5000, (GSourceFunc)send_message, g_strdup("Awn Notification Daemon has loaded Successfully.\nClick <a href=\"http://wiki.awn-project.org/index.php?title=Awn_Notification-Daemon\">Here</a> for online documentation."));
 
1924
 
 
1925
  if (! G_daemon_config.show_icon)
 
1926
  {
 
1927
    g_timeout_add(3000, (GSourceFunc)hide_icon, NULL);
 
1928
  }
 
1929
  else
 
1930
  {
 
1931
    g_signal_connect(G_OBJECT(G_daemon_config.awn_app), "button-press-event", G_CALLBACK(_button_clicked_event), NULL);
 
1932
  }
 
1933
 
 
1934
  return applet;
 
1935
 
 
1936
}