~mdz/network-manager/ubuntu.0.7

« back to all changes in this revision

Viewing changes to examples/python/systray/eggtrayicon.c

  • Committer: clarkbw
  • Date: 2004-08-27 20:48:04 UTC
  • Revision ID: vcs-imports@canonical.com-20040827204804-17ed195edeb66422
004-08-27  Bryan Clark  <bclark@redhat.com>

        * examples/python/systray/trayiconmodule.c:
        * examples/python/systray/trayicon.override:
        * examples/python/systray/network_tray.py:
        * examples/python/systray/eggtrayicon.h:
        * examples/python/systray/eggtrayicon.c:
        * examples/python/systray/Makefile:
        * examples/python/README:
        * examples/python/NetworkManager.py:
        * examples/python/NMTester.py:

        Initial commit of these python example files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 
2
/* eggtrayicon.c
 
3
 * Copyright (C) 2002 Anders Carlsson <andersca@gnu.org>
 
4
 *
 
5
 * This library is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU Lesser General Public
 
7
 * License as published by the Free Software Foundation; either
 
8
 * version 2 of the License, or (at your option) any later version.
 
9
 *
 
10
 * This library is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
 * Lesser General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU Lesser General Public
 
16
 * License along with this library; if not, write to the
 
17
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
18
 * Boston, MA 02111-1307, USA.
 
19
 */
 
20
 
 
21
#include <config.h>
 
22
#include <string.h>
 
23
#include <libintl.h>
 
24
 
 
25
#include "eggtrayicon.h"
 
26
 
 
27
#include <gdk/gdkx.h>
 
28
#include <X11/Xatom.h>
 
29
 
 
30
#define _(x) x
 
31
#define N_(x) x
 
32
 
 
33
#define SYSTEM_TRAY_REQUEST_DOCK    0
 
34
#define SYSTEM_TRAY_BEGIN_MESSAGE   1
 
35
#define SYSTEM_TRAY_CANCEL_MESSAGE  2
 
36
 
 
37
#define SYSTEM_TRAY_ORIENTATION_HORZ 0
 
38
#define SYSTEM_TRAY_ORIENTATION_VERT 1
 
39
 
 
40
enum {
 
41
  PROP_0,
 
42
  PROP_ORIENTATION
 
43
};
 
44
         
 
45
static GtkPlugClass *parent_class = NULL;
 
46
 
 
47
static void egg_tray_icon_init (EggTrayIcon *icon);
 
48
static void egg_tray_icon_class_init (EggTrayIconClass *klass);
 
49
 
 
50
static void egg_tray_icon_get_property (GObject    *object,
 
51
                                        guint       prop_id,
 
52
                                        GValue     *value,
 
53
                                        GParamSpec *pspec);
 
54
 
 
55
static void egg_tray_icon_realize   (GtkWidget *widget);
 
56
static void egg_tray_icon_unrealize (GtkWidget *widget);
 
57
 
 
58
static void egg_tray_icon_update_manager_window (EggTrayIcon *icon);
 
59
 
 
60
GType
 
61
egg_tray_icon_get_type (void)
 
62
{
 
63
  static GType our_type = 0;
 
64
 
 
65
  if (our_type == 0)
 
66
    {
 
67
      static const GTypeInfo our_info =
 
68
      {
 
69
        sizeof (EggTrayIconClass),
 
70
        (GBaseInitFunc) NULL,
 
71
        (GBaseFinalizeFunc) NULL,
 
72
        (GClassInitFunc) egg_tray_icon_class_init,
 
73
        NULL, /* class_finalize */
 
74
        NULL, /* class_data */
 
75
        sizeof (EggTrayIcon),
 
76
        0,    /* n_preallocs */
 
77
        (GInstanceInitFunc) egg_tray_icon_init
 
78
      };
 
79
 
 
80
      our_type = g_type_register_static (GTK_TYPE_PLUG, "EggTrayIcon", &our_info, 0);
 
81
    }
 
82
 
 
83
  return our_type;
 
84
}
 
85
 
 
86
static void
 
87
egg_tray_icon_init (EggTrayIcon *icon)
 
88
{
 
89
  icon->stamp = 1;
 
90
  icon->orientation = GTK_ORIENTATION_HORIZONTAL;
 
91
  
 
92
  gtk_widget_add_events (GTK_WIDGET (icon), GDK_PROPERTY_CHANGE_MASK);
 
93
}
 
94
 
 
95
static void
 
96
egg_tray_icon_class_init (EggTrayIconClass *klass)
 
97
{
 
98
  GObjectClass *gobject_class = (GObjectClass *)klass;
 
99
  GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
 
100
 
 
101
  parent_class = g_type_class_peek_parent (klass);
 
102
 
 
103
  gobject_class->get_property = egg_tray_icon_get_property;
 
104
 
 
105
  widget_class->realize   = egg_tray_icon_realize;
 
106
  widget_class->unrealize = egg_tray_icon_unrealize;
 
107
 
 
108
  g_object_class_install_property (gobject_class,
 
109
                                   PROP_ORIENTATION,
 
110
                                   g_param_spec_enum ("orientation",
 
111
                                                      _("Orientation"),
 
112
                                                      _("The orientation of the tray."),
 
113
                                                      GTK_TYPE_ORIENTATION,
 
114
                                                      GTK_ORIENTATION_HORIZONTAL,
 
115
                                                      G_PARAM_READABLE));
 
116
}
 
117
 
 
118
static void
 
119
egg_tray_icon_get_property (GObject    *object,
 
120
                            guint       prop_id,
 
121
                            GValue     *value,
 
122
                            GParamSpec *pspec)
 
123
{
 
124
  EggTrayIcon *icon = EGG_TRAY_ICON (object);
 
125
 
 
126
  switch (prop_id)
 
127
    {
 
128
    case PROP_ORIENTATION:
 
129
      g_value_set_enum (value, icon->orientation);
 
130
      break;
 
131
    default:
 
132
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
133
      break;
 
134
    }
 
135
}
 
136
 
 
137
static void
 
138
egg_tray_icon_get_orientation_property (EggTrayIcon *icon)
 
139
{
 
140
  Display *xdisplay;
 
141
  Atom type;
 
142
  int format;
 
143
  union {
 
144
        gulong *prop;
 
145
        guchar *prop_ch;
 
146
  } prop = { NULL };
 
147
  gulong nitems;
 
148
  gulong bytes_after;
 
149
  int error, result;
 
150
 
 
151
  g_assert (icon->manager_window != None);
 
152
  
 
153
  xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
 
154
 
 
155
  gdk_error_trap_push ();
 
156
  type = None;
 
157
  result = XGetWindowProperty (xdisplay,
 
158
                               icon->manager_window,
 
159
                               icon->orientation_atom,
 
160
                               0, G_MAXLONG, FALSE,
 
161
                               XA_CARDINAL,
 
162
                               &type, &format, &nitems,
 
163
                               &bytes_after, &(prop.prop_ch));
 
164
  error = gdk_error_trap_pop ();
 
165
 
 
166
  if (error || result != Success)
 
167
    return;
 
168
 
 
169
  if (type == XA_CARDINAL)
 
170
    {
 
171
      GtkOrientation orientation;
 
172
 
 
173
      orientation = (prop.prop [0] == SYSTEM_TRAY_ORIENTATION_HORZ) ?
 
174
                                        GTK_ORIENTATION_HORIZONTAL :
 
175
                                        GTK_ORIENTATION_VERTICAL;
 
176
 
 
177
      if (icon->orientation != orientation)
 
178
        {
 
179
          icon->orientation = orientation;
 
180
 
 
181
          g_object_notify (G_OBJECT (icon), "orientation");
 
182
        }
 
183
    }
 
184
 
 
185
  if (prop.prop)
 
186
    XFree (prop.prop);
 
187
}
 
188
 
 
189
static GdkFilterReturn
 
190
egg_tray_icon_manager_filter (GdkXEvent *xevent, GdkEvent *event, gpointer user_data)
 
191
{
 
192
  EggTrayIcon *icon = user_data;
 
193
  XEvent *xev = (XEvent *)xevent;
 
194
 
 
195
  if (xev->xany.type == ClientMessage &&
 
196
      xev->xclient.message_type == icon->manager_atom &&
 
197
      xev->xclient.data.l[1] == icon->selection_atom)
 
198
    {
 
199
      egg_tray_icon_update_manager_window (icon);
 
200
    }
 
201
  else if (xev->xany.window == icon->manager_window)
 
202
    {
 
203
      if (xev->xany.type == PropertyNotify &&
 
204
          xev->xproperty.atom == icon->orientation_atom)
 
205
        {
 
206
          egg_tray_icon_get_orientation_property (icon);
 
207
        }
 
208
      if (xev->xany.type == DestroyNotify)
 
209
        {
 
210
          egg_tray_icon_update_manager_window (icon);
 
211
        }
 
212
    }
 
213
  
 
214
  return GDK_FILTER_CONTINUE;
 
215
}
 
216
 
 
217
static void
 
218
egg_tray_icon_unrealize (GtkWidget *widget)
 
219
{
 
220
  EggTrayIcon *icon = EGG_TRAY_ICON (widget);
 
221
  GdkWindow *root_window;
 
222
 
 
223
  if (icon->manager_window != None)
 
224
    {
 
225
      GdkWindow *gdkwin;
 
226
 
 
227
      gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (widget),
 
228
                                              icon->manager_window);
 
229
 
 
230
      gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon);
 
231
    }
 
232
 
 
233
  root_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget));
 
234
 
 
235
  gdk_window_remove_filter (root_window, egg_tray_icon_manager_filter, icon);
 
236
 
 
237
  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
 
238
    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
 
239
}
 
240
 
 
241
static void
 
242
egg_tray_icon_send_manager_message (EggTrayIcon *icon,
 
243
                                    long         message,
 
244
                                    Window       window,
 
245
                                    long         data1,
 
246
                                    long         data2,
 
247
                                    long         data3)
 
248
{
 
249
  XClientMessageEvent ev;
 
250
  Display *display;
 
251
  
 
252
  ev.type = ClientMessage;
 
253
  ev.window = window;
 
254
  ev.message_type = icon->system_tray_opcode_atom;
 
255
  ev.format = 32;
 
256
  ev.data.l[0] = gdk_x11_get_server_time (GTK_WIDGET (icon)->window);
 
257
  ev.data.l[1] = message;
 
258
  ev.data.l[2] = data1;
 
259
  ev.data.l[3] = data2;
 
260
  ev.data.l[4] = data3;
 
261
 
 
262
  display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
 
263
  
 
264
  gdk_error_trap_push ();
 
265
  XSendEvent (display,
 
266
              icon->manager_window, False, NoEventMask, (XEvent *)&ev);
 
267
  XSync (display, False);
 
268
  gdk_error_trap_pop ();
 
269
}
 
270
 
 
271
static void
 
272
egg_tray_icon_send_dock_request (EggTrayIcon *icon)
 
273
{
 
274
  egg_tray_icon_send_manager_message (icon,
 
275
                                      SYSTEM_TRAY_REQUEST_DOCK,
 
276
                                      icon->manager_window,
 
277
                                      gtk_plug_get_id (GTK_PLUG (icon)),
 
278
                                      0, 0);
 
279
}
 
280
 
 
281
static void
 
282
egg_tray_icon_update_manager_window (EggTrayIcon *icon)
 
283
{
 
284
  Display *xdisplay;
 
285
  
 
286
  xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
 
287
  
 
288
  if (icon->manager_window != None)
 
289
    {
 
290
      GdkWindow *gdkwin;
 
291
 
 
292
      gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)),
 
293
                                              icon->manager_window);
 
294
      
 
295
      gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon);
 
296
    }
 
297
  
 
298
  XGrabServer (xdisplay);
 
299
  
 
300
  icon->manager_window = XGetSelectionOwner (xdisplay,
 
301
                                             icon->selection_atom);
 
302
 
 
303
  if (icon->manager_window != None)
 
304
    XSelectInput (xdisplay,
 
305
                  icon->manager_window, StructureNotifyMask|PropertyChangeMask);
 
306
 
 
307
  XUngrabServer (xdisplay);
 
308
  XFlush (xdisplay);
 
309
  
 
310
  if (icon->manager_window != None)
 
311
    {
 
312
      GdkWindow *gdkwin;
 
313
 
 
314
      gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)),
 
315
                                              icon->manager_window);
 
316
      
 
317
      gdk_window_add_filter (gdkwin, egg_tray_icon_manager_filter, icon);
 
318
 
 
319
      /* Send a request that we'd like to dock */
 
320
      egg_tray_icon_send_dock_request (icon);
 
321
 
 
322
      egg_tray_icon_get_orientation_property (icon);
 
323
    }
 
324
}
 
325
 
 
326
static void
 
327
egg_tray_icon_realize (GtkWidget *widget)
 
328
{
 
329
  EggTrayIcon *icon = EGG_TRAY_ICON (widget);
 
330
  GdkScreen *screen;
 
331
  GdkDisplay *display;
 
332
  Display *xdisplay;
 
333
  char buffer[256];
 
334
  GdkWindow *root_window;
 
335
 
 
336
  if (GTK_WIDGET_CLASS (parent_class)->realize)
 
337
    GTK_WIDGET_CLASS (parent_class)->realize (widget);
 
338
 
 
339
  screen = gtk_widget_get_screen (widget);
 
340
  display = gdk_screen_get_display (screen);
 
341
  xdisplay = gdk_x11_display_get_xdisplay (display);
 
342
 
 
343
  /* Now see if there's a manager window around */
 
344
  g_snprintf (buffer, sizeof (buffer),
 
345
              "_NET_SYSTEM_TRAY_S%d",
 
346
              gdk_screen_get_number (screen));
 
347
 
 
348
  icon->selection_atom = XInternAtom (xdisplay, buffer, False);
 
349
  
 
350
  icon->manager_atom = XInternAtom (xdisplay, "MANAGER", False);
 
351
  
 
352
  icon->system_tray_opcode_atom = XInternAtom (xdisplay,
 
353
                                                   "_NET_SYSTEM_TRAY_OPCODE",
 
354
                                                   False);
 
355
 
 
356
  icon->orientation_atom = XInternAtom (xdisplay,
 
357
                                        "_NET_SYSTEM_TRAY_ORIENTATION",
 
358
                                        False);
 
359
 
 
360
  egg_tray_icon_update_manager_window (icon);
 
361
 
 
362
  root_window = gdk_screen_get_root_window (screen);
 
363
  
 
364
  /* Add a root window filter so that we get changes on MANAGER */
 
365
  gdk_window_add_filter (root_window,
 
366
                         egg_tray_icon_manager_filter, icon);
 
367
}
 
368
 
 
369
EggTrayIcon *
 
370
egg_tray_icon_new_for_xscreen (Screen *xscreen, const char *name)
 
371
{
 
372
  GdkDisplay *display;
 
373
  GdkScreen *screen;
 
374
 
 
375
  display = gdk_x11_lookup_xdisplay (DisplayOfScreen (xscreen));
 
376
  screen = gdk_display_get_screen (display, XScreenNumberOfScreen (xscreen));
 
377
 
 
378
  return egg_tray_icon_new_for_screen (screen, name);
 
379
}
 
380
 
 
381
EggTrayIcon *
 
382
egg_tray_icon_new_for_screen (GdkScreen *screen, const char *name)
 
383
{
 
384
  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
 
385
 
 
386
  return g_object_new (EGG_TYPE_TRAY_ICON, "screen", screen, "title", name, NULL);
 
387
}
 
388
 
 
389
EggTrayIcon*
 
390
egg_tray_icon_new (const gchar *name)
 
391
{
 
392
  return g_object_new (EGG_TYPE_TRAY_ICON, "title", name, NULL);
 
393
}
 
394
 
 
395
guint
 
396
egg_tray_icon_send_message (EggTrayIcon *icon,
 
397
                            gint         timeout,
 
398
                            const gchar *message,
 
399
                            gint         len)
 
400
{
 
401
  guint stamp;
 
402
  
 
403
  g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), 0);
 
404
  g_return_val_if_fail (timeout >= 0, 0);
 
405
  g_return_val_if_fail (message != NULL, 0);
 
406
                     
 
407
  if (icon->manager_window == None)
 
408
    return 0;
 
409
 
 
410
  if (len < 0)
 
411
    len = strlen (message);
 
412
 
 
413
  stamp = icon->stamp++;
 
414
  
 
415
  /* Get ready to send the message */
 
416
  egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_BEGIN_MESSAGE,
 
417
                                      (Window)gtk_plug_get_id (GTK_PLUG (icon)),
 
418
                                      timeout, len, stamp);
 
419
 
 
420
  /* Now to send the actual message */
 
421
  gdk_error_trap_push ();
 
422
  while (len > 0)
 
423
    {
 
424
      XClientMessageEvent ev;
 
425
      Display *xdisplay;
 
426
 
 
427
      xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
 
428
      
 
429
      ev.type = ClientMessage;
 
430
      ev.window = (Window)gtk_plug_get_id (GTK_PLUG (icon));
 
431
      ev.format = 8;
 
432
      ev.message_type = XInternAtom (xdisplay,
 
433
                                     "_NET_SYSTEM_TRAY_MESSAGE_DATA", False);
 
434
      if (len > 20)
 
435
        {
 
436
          memcpy (&ev.data, message, 20);
 
437
          len -= 20;
 
438
          message += 20;
 
439
        }
 
440
      else
 
441
        {
 
442
          memcpy (&ev.data, message, len);
 
443
          len = 0;
 
444
        }
 
445
 
 
446
      XSendEvent (xdisplay,
 
447
                  icon->manager_window, False, StructureNotifyMask, (XEvent *)&ev);
 
448
      XSync (xdisplay, False);
 
449
    }
 
450
  gdk_error_trap_pop ();
 
451
 
 
452
  return stamp;
 
453
}
 
454
 
 
455
void
 
456
egg_tray_icon_cancel_message (EggTrayIcon *icon,
 
457
                              guint        id)
 
458
{
 
459
  g_return_if_fail (EGG_IS_TRAY_ICON (icon));
 
460
  g_return_if_fail (id > 0);
 
461
  
 
462
  egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_CANCEL_MESSAGE,
 
463
                                      (Window)gtk_plug_get_id (GTK_PLUG (icon)),
 
464
                                      id, 0, 0);
 
465
}
 
466
 
 
467
GtkOrientation
 
468
egg_tray_icon_get_orientation (EggTrayIcon *icon)
 
469
{
 
470
  g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), GTK_ORIENTATION_HORIZONTAL);
 
471
 
 
472
  return icon->orientation;
 
473
}