1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3
* Copyright (C) 2002 Anders Carlsson <andersca@gnu.org>
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.
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.
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.
23
#include "eggtrayicon.h"
25
#define SYSTEM_TRAY_REQUEST_DOCK 0
26
#define SYSTEM_TRAY_BEGIN_MESSAGE 1
27
#define SYSTEM_TRAY_CANCEL_MESSAGE 2
29
static GtkPlugClass *parent_class = NULL;
31
static void egg_tray_icon_init (EggTrayIcon *icon);
32
static void egg_tray_icon_class_init (EggTrayIconClass *klass);
34
static void egg_tray_icon_update_manager_window (EggTrayIcon *icon);
37
egg_tray_icon_get_type (void)
39
static GType our_type = 0;
43
static const GTypeInfo our_info =
45
sizeof (EggTrayIconClass),
47
(GBaseFinalizeFunc) NULL,
48
(GClassInitFunc) egg_tray_icon_class_init,
49
NULL, /* class_finalize */
50
NULL, /* class_data */
53
(GInstanceInitFunc) egg_tray_icon_init
56
our_type = g_type_register_static (GTK_TYPE_PLUG, "EggTrayIcon", &our_info, 0);
63
egg_tray_icon_init (EggTrayIcon *icon)
67
gtk_widget_add_events (GTK_WIDGET (icon), GDK_PROPERTY_CHANGE_MASK);
71
egg_tray_icon_class_init (EggTrayIconClass *klass)
73
parent_class = g_type_class_peek_parent (klass);
76
static GdkFilterReturn
77
egg_tray_icon_manager_filter (GdkXEvent *xevent, GdkEvent *event, gpointer user_data)
79
EggTrayIcon *icon = user_data;
80
XEvent *xev = (XEvent *)xevent;
82
if (xev->xany.type == ClientMessage &&
83
xev->xclient.message_type == icon->manager_atom &&
84
xev->xclient.data.l[1] == icon->selection_atom)
86
egg_tray_icon_update_manager_window (icon);
88
else if (xev->xany.window == icon->manager_window)
90
if (xev->xany.type == DestroyNotify)
92
egg_tray_icon_update_manager_window (icon);
96
return GDK_FILTER_CONTINUE;
100
egg_tray_icon_send_manager_message (EggTrayIcon *icon,
107
XClientMessageEvent ev;
110
ev.type = ClientMessage;
112
ev.message_type = icon->system_tray_opcode_atom;
114
ev.data.l[0] = gdk_x11_get_server_time (GTK_WIDGET (icon)->window);
115
ev.data.l[1] = message;
116
ev.data.l[2] = data1;
117
ev.data.l[3] = data2;
118
ev.data.l[4] = data3;
120
#if HAVE_GTK_MULTIHEAD
121
display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
123
display = gdk_display;
126
gdk_error_trap_push ();
128
icon->manager_window, False, NoEventMask, (XEvent *)&ev);
129
XSync (display, False);
130
gdk_error_trap_pop ();
134
egg_tray_icon_send_dock_request (EggTrayIcon *icon)
136
egg_tray_icon_send_manager_message (icon,
137
SYSTEM_TRAY_REQUEST_DOCK,
138
icon->manager_window,
139
gtk_plug_get_id (GTK_PLUG (icon)),
144
egg_tray_icon_update_manager_window (EggTrayIcon *icon)
148
#if HAVE_GTK_MULTIHEAD
149
xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
151
xdisplay = gdk_display;
154
if (icon->manager_window != None)
158
#if HAVE_GTK_MULTIHEAD
159
gdkwin = gdk_window_lookup_for_display (display,
160
icon->manager_window);
162
gdkwin = gdk_window_lookup (icon->manager_window);
165
gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon);
168
XGrabServer (xdisplay);
170
icon->manager_window = XGetSelectionOwner (xdisplay,
171
icon->selection_atom);
173
if (icon->manager_window != None)
174
XSelectInput (xdisplay,
175
icon->manager_window, StructureNotifyMask);
177
XUngrabServer (xdisplay);
180
if (icon->manager_window != None)
184
#if HAVE_GTK_MULTIHEAD
185
gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)),
186
icon->manager_window);
188
gdkwin = gdk_window_lookup (icon->manager_window);
191
gdk_window_add_filter (gdkwin, egg_tray_icon_manager_filter, icon);
193
/* Send a request that we'd like to dock */
194
egg_tray_icon_send_dock_request (icon);
199
egg_tray_icon_new_for_xscreen (Screen *xscreen, const char *name)
203
GdkWindow *root_window;
205
g_return_val_if_fail (xscreen != NULL, NULL);
207
icon = g_object_new (EGG_TYPE_TRAY_ICON, NULL);
208
gtk_window_set_title (GTK_WINDOW (icon), name);
210
#if HAVE_GTK_MULTIHEAD
211
gtk_plug_construct_for_display (GTK_PLUG (icon),
212
gdk_screen_get_display (screen), 0);
214
gtk_plug_construct (GTK_PLUG (icon), 0);
217
gtk_widget_realize (GTK_WIDGET (icon));
219
/* Now see if there's a manager window around */
220
g_snprintf (buffer, sizeof (buffer),
221
"_NET_SYSTEM_TRAY_S%d",
222
XScreenNumberOfScreen (xscreen));
224
icon->selection_atom = XInternAtom (DisplayOfScreen (xscreen),
227
icon->manager_atom = XInternAtom (DisplayOfScreen (xscreen),
230
icon->system_tray_opcode_atom = XInternAtom (DisplayOfScreen (xscreen),
231
"_NET_SYSTEM_TRAY_OPCODE", False);
233
egg_tray_icon_update_manager_window (icon);
235
#if HAVE_GTK_MULTIHEAD
236
root_window = gdk_screen_get_root_window (screen);
238
root_window = gdk_window_lookup (gdk_x11_get_default_root_xwindow ());
241
/* Add a root window filter so that we get changes on MANAGER */
242
gdk_window_add_filter (root_window,
243
egg_tray_icon_manager_filter, icon);
248
#if HAVE_GTK_MULTIHEAD
250
egg_tray_icon_new_for_screen (GdkScreen *screen, const char *name)
255
g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
257
return egg_tray_icon_new_for_xscreen (GDK_SCREEN_XSCREEN (screen), name);
262
egg_tray_icon_new (const gchar *name)
264
return egg_tray_icon_new_for_xscreen (DefaultScreenOfDisplay (gdk_display), name);
268
egg_tray_icon_send_message (EggTrayIcon *icon,
270
const gchar *message,
275
g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), 0);
276
g_return_val_if_fail (timeout >= 0, 0);
277
g_return_val_if_fail (message != NULL, 0);
279
if (icon->manager_window == None)
283
len = strlen (message);
285
stamp = icon->stamp++;
287
/* Get ready to send the message */
288
egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_BEGIN_MESSAGE,
289
(Window)gtk_plug_get_id (GTK_PLUG (icon)),
290
timeout, len, stamp);
292
/* Now to send the actual message */
293
gdk_error_trap_push ();
296
XClientMessageEvent ev;
299
#if HAVE_GTK_MULTIHEAD
300
xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
302
xdisplay = gdk_display;
305
ev.type = ClientMessage;
306
ev.window = (Window)gtk_plug_get_id (GTK_PLUG (icon));
308
ev.message_type = XInternAtom (xdisplay,
309
"_NET_SYSTEM_TRAY_MESSAGE_DATA", False);
312
memcpy (&ev.data, message, 20);
318
memcpy (&ev.data, message, len);
322
XSendEvent (xdisplay,
323
icon->manager_window, False, StructureNotifyMask, (XEvent *)&ev);
324
XSync (xdisplay, False);
326
gdk_error_trap_pop ();
332
egg_tray_icon_cancel_message (EggTrayIcon *icon,
335
g_return_if_fail (EGG_IS_TRAY_ICON (icon));
336
g_return_if_fail (id > 0);
338
egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_CANCEL_MESSAGE,
339
(Window)gtk_plug_get_id (GTK_PLUG (icon)),