~ubuntu-dev/wxwidgets2.6/upstream-debian

« back to all changes in this revision

Viewing changes to src/gtk/eggtrayicon.c

  • Committer: Daniel T Chen
  • Date: 2006-06-26 10:15:11 UTC
  • Revision ID: crimsun@ubuntu.com-20060626101511-a4436cec4c6d9b35
ImportĀ DebianĀ 2.6.3.2.1

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
/* 
 
22
 
 
23
Permission to use this file under wxWindows license given by
 
24
copyright holder:
 
25
--------
 
26
From andersca@gnu.org Tue Dec  9 13:01:56 2003
 
27
Return-path: <andersca@gnu.org>
 
28
Envelope-to: vasek@localhost
 
29
Delivery-date: Tue, 09 Dec 2003 13:04:35 +0100
 
30
Received: from localhost
 
31
        ([127.0.0.1] helo=amavis ident=amavis)
 
32
        by armitage with esmtp (Exim 3.35 #1)
 
33
        id 1ATgbS-0001Gs-00
 
34
        for vasek@localhost; Tue, 09 Dec 2003 13:04:35 +0100
 
35
Received: from armitage ([127.0.0.1])
 
36
        by amavis (armitage [127.0.0.1]) (amavisd-new, port 10024) with ESMTP
 
37
        id 04227-09 for <vasek@localhost>;
 
38
        Tue, 9 Dec 2003 13:04:11 +0100 (CET)
 
39
Received: from localhost ([127.0.0.1] ident=fetchmail)
 
40
        by armitage with esmtp (Exim 3.35 #1)
 
41
        id 1ATgb5-0001GY-00
 
42
        for vasek@localhost; Tue, 09 Dec 2003 13:04:11 +0100
 
43
Delivered-To: alias-email-slavikvaclav@seznam.cz
 
44
Received: from pop3.seznam.cz [212.80.76.45]
 
45
        by localhost with POP3 (fetchmail-5.9.11)
 
46
        for vasek@localhost (single-drop); Tue, 09 Dec 2003 13:04:11 +0100 (CET)
 
47
Received: (qmail 9861 invoked from network); 9 Dec 2003 12:02:17 -0000
 
48
Received: from unknown (HELO maxipes.logix.cz) (81.0.234.97)
 
49
  by buster.go.seznam.cz with SMTP; 9 Dec 2003 12:02:17 -0000
 
50
Received: by maxipes.logix.cz (Postfix, from userid 604)
 
51
        id 37E6D29A51; Tue,  9 Dec 2003 13:02:16 +0100 (CET)
 
52
X-Original-To: vaclav.slavik@matfyz.cz
 
53
Received: from mail.csbnet.se (glutus.csbnet.se [193.11.248.2])
 
54
        by maxipes.logix.cz (Postfix) with ESMTP id 90D6A29A51
 
55
        for <vaclav.slavik@matfyz.cz>; Tue,  9 Dec 2003 13:02:15 +0100 (CET)
 
56
Received: by mail.csbnet.se (Postfix, from userid 8)
 
57
        id 7AA7F10A6D7; Tue,  9 Dec 2003 13:02:14 +0100 (CET)
 
58
Received: from carbon.csbnet.se (carbon.csbnet.se [193.11.248.180])
 
59
        by mail.csbnet.se (Postfix) with ESMTP id A190F10A71D
 
60
        for <vaclav.slavik@matfyz.cz>; Tue,  9 Dec 2003 13:01:56 +0100 (CET)
 
61
Subject: Re: eggtrayicon.{c,h} licensing
 
62
From: Anders Carlsson <andersca@gnu.org>
 
63
To: Vaclav Slavik <vaclav.slavik@matfyz.cz>
 
64
In-Reply-To: <200312091142.54542.vaclav.slavik@matfyz.cz>
 
65
References: <200312091142.54542.vaclav.slavik@matfyz.cz>
 
66
Content-Type: text/plain
 
67
Message-Id: <1070971316.30989.0.camel@carbon.csbnet.se>
 
68
Mime-Version: 1.0
 
69
X-Mailer: Ximian Evolution 1.5 
 
70
Date: Tue, 09 Dec 2003 13:01:56 +0100
 
71
Content-Transfer-Encoding: 7bit
 
72
X-Scanned-By: CLAM (openantivirus DB) antivirus scanner at mail.csbnet.se
 
73
X-Virus-Scanned: by amavisd-new-20030616-p5 (Debian) at armitage
 
74
X-Spam-Status: No, hits=-4.9 tagged_above=-999.0 required=6.3 tests=BAYES_00
 
75
X-Spam-Level: 
 
76
Status: R 
 
77
X-Status: N
 
78
X-KMail-EncryptionState:  
 
79
X-KMail-SignatureState:  
 
80
 
 
81
On tis, 2003-12-09 at 11:42 +0100, Vaclav Slavik wrote:
 
82
> Hi,
 
83
 
84
> I'm working on the wxWindows cross-platform GUI toolkit 
 
85
> (http://www.wxwindows.org) which uses GTK+ and it would save me a lot 
 
86
> of time if I could use your eggtrayicon code to implement tray icons 
 
87
> on X11. Unfortunately I can't use it right now because it is not part 
 
88
> of any library we could depend on (as we do depend on GTK+) and would 
 
89
> have to be included in our sources and it is under the LGPL license. 
 
90
> The problem is that wxWindows' license is more permissive (see 
 
91
> http://www.opensource.org/licenses/wxwindows.php for details) and so 
 
92
> I can't take your code and put it under wxWindows License. And I 
 
93
> can't put code that can't be used under the terms of wxWindows 
 
94
> License into wxWindows either. Do you think it would be possible to 
 
95
> get permission to include eggtrayicon under wxWindows license?
 
96
 
97
> Thanks,
 
98
> Vaclav
 
99
 
100
 
 
101
Sure, that's fine by me.
 
102
 
 
103
Anders
 
104
--------
 
105
*/
 
106
 
 
107
#include "wx/platform.h"
 
108
 
 
109
#include <gdk/gdkx.h>
 
110
 
 
111
#ifdef __WXGTK20__
 
112
#include <gtk/gtkversion.h>
 
113
#if GTK_CHECK_VERSION(2, 1, 0)
 
114
 
 
115
#include <string.h>
 
116
#include "eggtrayicon.h"
 
117
 
 
118
#define SYSTEM_TRAY_REQUEST_DOCK    0
 
119
#define SYSTEM_TRAY_BEGIN_MESSAGE   1
 
120
#define SYSTEM_TRAY_CANCEL_MESSAGE  2
 
121
         
 
122
static GtkPlugClass *parent_class = NULL;
 
123
 
 
124
static void egg_tray_icon_init (EggTrayIcon *icon);
 
125
static void egg_tray_icon_class_init (EggTrayIconClass *klass);
 
126
 
 
127
static void egg_tray_icon_unrealize (GtkWidget *widget);
 
128
 
 
129
static void egg_tray_icon_update_manager_window (EggTrayIcon *icon);
 
130
 
 
131
GType
 
132
egg_tray_icon_get_type (void)
 
133
{
 
134
  static GType our_type = 0;
 
135
 
 
136
  if (our_type == 0)
 
137
    {
 
138
      static const GTypeInfo our_info =
 
139
      {
 
140
        sizeof (EggTrayIconClass),
 
141
        (GBaseInitFunc) NULL,
 
142
        (GBaseFinalizeFunc) NULL,
 
143
        (GClassInitFunc) egg_tray_icon_class_init,
 
144
        NULL, /* class_finalize */
 
145
        NULL, /* class_data */
 
146
        sizeof (EggTrayIcon),
 
147
        0,    /* n_preallocs */
 
148
        (GInstanceInitFunc) egg_tray_icon_init
 
149
      };
 
150
 
 
151
      our_type = g_type_register_static (GTK_TYPE_PLUG, "EggTrayIcon", &our_info, 0);
 
152
    }
 
153
 
 
154
  return our_type;
 
155
}
 
156
 
 
157
static void
 
158
egg_tray_icon_init (EggTrayIcon *icon)
 
159
{
 
160
  icon->stamp = 1;
 
161
  
 
162
  gtk_widget_add_events (GTK_WIDGET (icon), GDK_PROPERTY_CHANGE_MASK);
 
163
}
 
164
 
 
165
static void
 
166
egg_tray_icon_class_init (EggTrayIconClass *klass)
 
167
{
 
168
  GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
 
169
 
 
170
  parent_class = g_type_class_peek_parent (klass);
 
171
 
 
172
  widget_class->unrealize = egg_tray_icon_unrealize;
 
173
}
 
174
 
 
175
static GdkFilterReturn
 
176
egg_tray_icon_manager_filter (GdkXEvent *xevent, GdkEvent *event, gpointer user_data)
 
177
{
 
178
  EggTrayIcon *icon = user_data;
 
179
  XEvent *xev = (XEvent *)xevent;
 
180
 
 
181
  if (xev->xany.type == ClientMessage &&
 
182
      xev->xclient.message_type == icon->manager_atom &&
 
183
      xev->xclient.data.l[1] == icon->selection_atom)
 
184
    {
 
185
      egg_tray_icon_update_manager_window (icon);
 
186
    }
 
187
  else if (xev->xany.window == icon->manager_window)
 
188
    {
 
189
      if (xev->xany.type == DestroyNotify)
 
190
        {
 
191
          egg_tray_icon_update_manager_window (icon);
 
192
        }
 
193
    }
 
194
  
 
195
  return GDK_FILTER_CONTINUE;
 
196
}
 
197
 
 
198
static void
 
199
egg_tray_icon_unrealize (GtkWidget *widget)
 
200
{
 
201
  EggTrayIcon *icon = EGG_TRAY_ICON (widget);
 
202
  GdkWindow *root_window;
 
203
 
 
204
  if (icon->manager_window != None)
 
205
    {
 
206
      GdkWindow *gdkwin;
 
207
 
 
208
      gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (widget),
 
209
                                              icon->manager_window);
 
210
 
 
211
      gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon);
 
212
    }
 
213
 
 
214
  root_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget));
 
215
 
 
216
  gdk_window_remove_filter (root_window, egg_tray_icon_manager_filter, icon);
 
217
 
 
218
  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
 
219
    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
 
220
}
 
221
 
 
222
static void
 
223
egg_tray_icon_send_manager_message (EggTrayIcon *icon,
 
224
                                    long         message,
 
225
                                    Window       window,
 
226
                                    long         data1,
 
227
                                    long         data2,
 
228
                                    long         data3)
 
229
{
 
230
  XClientMessageEvent ev;
 
231
  Display *display;
 
232
  
 
233
  ev.type = ClientMessage;
 
234
  ev.window = window;
 
235
  ev.message_type = icon->system_tray_opcode_atom;
 
236
  ev.format = 32;
 
237
  ev.data.l[0] = gdk_x11_get_server_time (GTK_WIDGET (icon)->window);
 
238
  ev.data.l[1] = message;
 
239
  ev.data.l[2] = data1;
 
240
  ev.data.l[3] = data2;
 
241
  ev.data.l[4] = data3;
 
242
 
 
243
  display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
 
244
  
 
245
  gdk_error_trap_push ();
 
246
  XSendEvent (display,
 
247
              icon->manager_window, False, NoEventMask, (XEvent *)&ev);
 
248
  XSync (display, False);
 
249
  gdk_error_trap_pop ();
 
250
}
 
251
 
 
252
static void
 
253
egg_tray_icon_send_dock_request (EggTrayIcon *icon)
 
254
{
 
255
  egg_tray_icon_send_manager_message (icon,
 
256
                                      SYSTEM_TRAY_REQUEST_DOCK,
 
257
                                      icon->manager_window,
 
258
                                      gtk_plug_get_id (GTK_PLUG (icon)),
 
259
                                      0, 0);
 
260
}
 
261
 
 
262
static void
 
263
egg_tray_icon_update_manager_window (EggTrayIcon *icon)
 
264
{
 
265
  Display *xdisplay;
 
266
  
 
267
  xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
 
268
  
 
269
  if (icon->manager_window != None)
 
270
    {
 
271
      GdkWindow *gdkwin;
 
272
 
 
273
      gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)),
 
274
                                              icon->manager_window);
 
275
      
 
276
      gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon);
 
277
    }
 
278
  
 
279
  XGrabServer (xdisplay);
 
280
  
 
281
  icon->manager_window = XGetSelectionOwner (xdisplay,
 
282
                                             icon->selection_atom);
 
283
 
 
284
  if (icon->manager_window != None)
 
285
    XSelectInput (xdisplay,
 
286
                  icon->manager_window, StructureNotifyMask);
 
287
 
 
288
  XUngrabServer (xdisplay);
 
289
  XFlush (xdisplay);
 
290
  
 
291
  if (icon->manager_window != None)
 
292
    {
 
293
      GdkWindow *gdkwin;
 
294
 
 
295
      gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)),
 
296
                                              icon->manager_window);
 
297
      
 
298
      gdk_window_add_filter (gdkwin, egg_tray_icon_manager_filter, icon);
 
299
 
 
300
      /* Send a request that we'd like to dock */
 
301
      egg_tray_icon_send_dock_request (icon);
 
302
    }
 
303
}
 
304
 
 
305
EggTrayIcon *
 
306
egg_tray_icon_new_for_xscreen (Screen *xscreen, const char *name)
 
307
{
 
308
  EggTrayIcon *icon;
 
309
  char buffer[256];
 
310
  GdkWindow *root_window;
 
311
  GdkDisplay *display;
 
312
  GdkScreen *screen;
 
313
  
 
314
  g_return_val_if_fail (xscreen != NULL, NULL);
 
315
  
 
316
  icon = g_object_new (EGG_TYPE_TRAY_ICON, NULL);
 
317
  gtk_window_set_title (GTK_WINDOW (icon), name);
 
318
 
 
319
  display = gdk_x11_lookup_xdisplay (DisplayOfScreen (xscreen));
 
320
  screen = gdk_display_get_screen (display, XScreenNumberOfScreen (xscreen));
 
321
  
 
322
  gtk_plug_construct_for_display (GTK_PLUG (icon),
 
323
                                  display, 0);
 
324
 
 
325
  gtk_window_set_screen (GTK_WINDOW (icon), screen);     
 
326
  
 
327
  gtk_widget_realize (GTK_WIDGET (icon));
 
328
 
 
329
  /* Now see if there's a manager window around */
 
330
  g_snprintf (buffer, sizeof (buffer),
 
331
              "_NET_SYSTEM_TRAY_S%d",
 
332
              XScreenNumberOfScreen (xscreen));
 
333
  
 
334
  icon->selection_atom = XInternAtom (DisplayOfScreen (xscreen),
 
335
                                      buffer, False);
 
336
  
 
337
  icon->manager_atom = XInternAtom (DisplayOfScreen (xscreen),
 
338
                                    "MANAGER", False);
 
339
  
 
340
  icon->system_tray_opcode_atom = XInternAtom (DisplayOfScreen (xscreen),
 
341
                                               "_NET_SYSTEM_TRAY_OPCODE", False);
 
342
 
 
343
  egg_tray_icon_update_manager_window (icon);
 
344
 
 
345
  root_window = gdk_screen_get_root_window (gtk_widget_get_screen (GTK_WIDGET (icon)));
 
346
  
 
347
  /* Add a root window filter so that we get changes on MANAGER */
 
348
  gdk_window_add_filter (root_window,
 
349
                         egg_tray_icon_manager_filter, icon);
 
350
                      
 
351
  return icon;
 
352
}
 
353
 
 
354
EggTrayIcon *
 
355
egg_tray_icon_new_for_screen (GdkScreen *screen, const char *name)
 
356
{
 
357
  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
 
358
 
 
359
  return egg_tray_icon_new_for_xscreen (GDK_SCREEN_XSCREEN (screen), name);
 
360
}
 
361
 
 
362
EggTrayIcon*
 
363
egg_tray_icon_new (const gchar *name)
 
364
{
 
365
  return egg_tray_icon_new_for_xscreen (DefaultScreenOfDisplay (gdk_display), name);
 
366
}
 
367
 
 
368
guint
 
369
egg_tray_icon_send_message (EggTrayIcon *icon,
 
370
                            gint         timeout,
 
371
                            const gchar *message,
 
372
                            gint         len)
 
373
{
 
374
  guint stamp;
 
375
  
 
376
  g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), 0);
 
377
  g_return_val_if_fail (timeout >= 0, 0);
 
378
  g_return_val_if_fail (message != NULL, 0);
 
379
                     
 
380
  if (icon->manager_window == None)
 
381
    return 0;
 
382
 
 
383
  if (len < 0)
 
384
    len = strlen (message);
 
385
 
 
386
  stamp = icon->stamp++;
 
387
  
 
388
  /* Get ready to send the message */
 
389
  egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_BEGIN_MESSAGE,
 
390
                                      (Window)gtk_plug_get_id (GTK_PLUG (icon)),
 
391
                                      timeout, len, stamp);
 
392
 
 
393
  /* Now to send the actual message */
 
394
  gdk_error_trap_push ();
 
395
  while (len > 0)
 
396
    {
 
397
      XClientMessageEvent ev;
 
398
      Display *xdisplay;
 
399
 
 
400
      xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
 
401
      
 
402
      ev.type = ClientMessage;
 
403
      ev.window = (Window)gtk_plug_get_id (GTK_PLUG (icon));
 
404
      ev.format = 8;
 
405
      ev.message_type = XInternAtom (xdisplay,
 
406
                                     "_NET_SYSTEM_TRAY_MESSAGE_DATA", False);
 
407
      if (len > 20)
 
408
        {
 
409
          memcpy (&ev.data, message, 20);
 
410
          len -= 20;
 
411
          message += 20;
 
412
        }
 
413
      else
 
414
        {
 
415
          memcpy (&ev.data, message, len);
 
416
          len = 0;
 
417
        }
 
418
 
 
419
      XSendEvent (xdisplay,
 
420
                  icon->manager_window, False, StructureNotifyMask, (XEvent *)&ev);
 
421
      XSync (xdisplay, False);
 
422
    }
 
423
  gdk_error_trap_pop ();
 
424
 
 
425
  return stamp;
 
426
}
 
427
 
 
428
void
 
429
egg_tray_icon_cancel_message (EggTrayIcon *icon,
 
430
                              guint        id)
 
431
{
 
432
  g_return_if_fail (EGG_IS_TRAY_ICON (icon));
 
433
  g_return_if_fail (id > 0);
 
434
  
 
435
  egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_CANCEL_MESSAGE,
 
436
                                      (Window)gtk_plug_get_id (GTK_PLUG (icon)),
 
437
                                      id, 0, 0);
 
438
}
 
439
 
 
440
#endif /* __WXGTK20__ */
 
441
#endif /* GTK_CHECK_VERSION(2, 1, 0) */