Mercurial > pidgin
annotate plugins/docklet/eggtrayicon.c @ 7433:6fdc55dd636a
[gaim-migrate @ 8038]
Because all the log reading and writing is abstracted, it makes it real easy
to tell Gaim, "give me entire contents of the last conversation," which is
useful for, say, a history.c plugin. This code is now much simpler, and it
took no time at all to port it.
Sort-by-log will be a bit harder.
And because two people asked me within a minute of me committing it, there
exists an "old log" GaimLogLogger that doesn't write logs, but can list and
read them. So, you'll be able to seamlessly see your old logs along with
your new logs together in the log viewer.
committer: Tailor Script <tailor@pidgin.im>
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Wed, 05 Nov 2003 06:39:05 +0000 |
parents | e252238f99df |
children | 92cbf9713795 |
rev | line source |
---|---|
3510 | 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 <string.h> | |
22 #include <gdk/gdkx.h> | |
23 #include "eggtrayicon.h" | |
24 | |
25 #define SYSTEM_TRAY_REQUEST_DOCK 0 | |
26 #define SYSTEM_TRAY_BEGIN_MESSAGE 1 | |
27 #define SYSTEM_TRAY_CANCEL_MESSAGE 2 | |
28 | |
29 static GtkPlugClass *parent_class = NULL; | |
30 | |
31 static void egg_tray_icon_init (EggTrayIcon *icon); | |
32 static void egg_tray_icon_class_init (EggTrayIconClass *klass); | |
33 | |
4261
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
34 static void egg_tray_icon_unrealize (GtkWidget *widget); |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
35 |
3510 | 36 static void egg_tray_icon_update_manager_window (EggTrayIcon *icon); |
37 | |
38 GType | |
39 egg_tray_icon_get_type (void) | |
40 { | |
41 static GType our_type = 0; | |
42 | |
43 our_type = g_type_from_name("EggTrayIcon"); | |
44 | |
45 if (our_type == 0) | |
46 { | |
47 static const GTypeInfo our_info = | |
48 { | |
49 sizeof (EggTrayIconClass), | |
50 (GBaseInitFunc) NULL, | |
51 (GBaseFinalizeFunc) NULL, | |
52 (GClassInitFunc) egg_tray_icon_class_init, | |
53 NULL, /* class_finalize */ | |
54 NULL, /* class_data */ | |
55 sizeof (EggTrayIcon), | |
56 0, /* n_preallocs */ | |
57 (GInstanceInitFunc) egg_tray_icon_init | |
58 }; | |
59 | |
60 our_type = g_type_register_static (GTK_TYPE_PLUG, "EggTrayIcon", &our_info, 0); | |
61 } | |
4261
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
62 else if (parent_class == NULL) { |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
63 /* we're reheating the old class from a previous instance - engage ugly hack =( */ |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
64 egg_tray_icon_class_init((EggTrayIconClass *)g_type_class_peek(our_type)); |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
65 } |
3510 | 66 |
67 return our_type; | |
68 } | |
69 | |
70 static void | |
71 egg_tray_icon_init (EggTrayIcon *icon) | |
72 { | |
73 icon->stamp = 1; | |
74 | |
75 gtk_widget_add_events (GTK_WIDGET (icon), GDK_PROPERTY_CHANGE_MASK); | |
76 } | |
77 | |
78 static void | |
79 egg_tray_icon_class_init (EggTrayIconClass *klass) | |
80 { | |
4261
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
81 GtkWidgetClass *widget_class = (GtkWidgetClass *)klass; |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
82 |
3510 | 83 parent_class = g_type_class_peek_parent (klass); |
4261
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
84 |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
85 widget_class->unrealize = egg_tray_icon_unrealize; |
3510 | 86 } |
87 | |
88 static GdkFilterReturn | |
89 egg_tray_icon_manager_filter (GdkXEvent *xevent, GdkEvent *event, gpointer user_data) | |
90 { | |
91 EggTrayIcon *icon = user_data; | |
92 XEvent *xev = (XEvent *)xevent; | |
93 | |
94 if (xev->xany.type == ClientMessage && | |
95 xev->xclient.message_type == icon->manager_atom && | |
96 xev->xclient.data.l[1] == icon->selection_atom) | |
97 { | |
98 egg_tray_icon_update_manager_window (icon); | |
99 } | |
100 else if (xev->xany.window == icon->manager_window) | |
101 { | |
102 if (xev->xany.type == DestroyNotify) | |
103 { | |
104 egg_tray_icon_update_manager_window (icon); | |
105 } | |
106 } | |
107 | |
108 return GDK_FILTER_CONTINUE; | |
109 } | |
110 | |
111 static void | |
4261
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
112 egg_tray_icon_unrealize (GtkWidget *widget) |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
113 { |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
114 EggTrayIcon *icon = EGG_TRAY_ICON (widget); |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
115 GdkWindow *root_window; |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
116 |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
117 if (icon->manager_window != None) |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
118 { |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
119 GdkWindow *gdkwin; |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
120 |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
121 #if HAVE_GTK_MULTIHEAD |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
122 gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (widget), |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
123 icon->manager_window); |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
124 #else |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
125 gdkwin = gdk_window_lookup (icon->manager_window); |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
126 #endif |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
127 |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
128 gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon); |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
129 } |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
130 |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
131 #if HAVE_GTK_MULTIHEAD |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
132 root_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget)); |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
133 #else |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
134 root_window = gdk_window_lookup (gdk_x11_get_default_root_xwindow ()); |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
135 #endif |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
136 |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
137 gdk_window_remove_filter (root_window, egg_tray_icon_manager_filter, icon); |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
138 |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
139 if (GTK_WIDGET_CLASS (parent_class)->unrealize) |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
140 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
141 } |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
142 |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
143 static void |
3510 | 144 egg_tray_icon_send_manager_message (EggTrayIcon *icon, |
145 long message, | |
146 Window window, | |
147 long data1, | |
148 long data2, | |
149 long data3) | |
150 { | |
151 XClientMessageEvent ev; | |
152 Display *display; | |
153 | |
154 ev.type = ClientMessage; | |
155 ev.window = window; | |
156 ev.message_type = icon->system_tray_opcode_atom; | |
157 ev.format = 32; | |
158 ev.data.l[0] = gdk_x11_get_server_time (GTK_WIDGET (icon)->window); | |
159 ev.data.l[1] = message; | |
160 ev.data.l[2] = data1; | |
161 ev.data.l[3] = data2; | |
162 ev.data.l[4] = data3; | |
163 | |
164 #if HAVE_GTK_MULTIHEAD | |
165 display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); | |
166 #else | |
167 display = gdk_display; | |
168 #endif | |
169 | |
170 gdk_error_trap_push (); | |
171 XSendEvent (display, | |
172 icon->manager_window, False, NoEventMask, (XEvent *)&ev); | |
173 XSync (display, False); | |
174 gdk_error_trap_pop (); | |
175 } | |
176 | |
177 static void | |
178 egg_tray_icon_send_dock_request (EggTrayIcon *icon) | |
179 { | |
180 egg_tray_icon_send_manager_message (icon, | |
181 SYSTEM_TRAY_REQUEST_DOCK, | |
182 icon->manager_window, | |
183 gtk_plug_get_id (GTK_PLUG (icon)), | |
184 0, 0); | |
185 } | |
186 | |
187 static void | |
188 egg_tray_icon_update_manager_window (EggTrayIcon *icon) | |
189 { | |
190 Display *xdisplay; | |
191 | |
192 #if HAVE_GTK_MULTIHEAD | |
193 xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); | |
194 #else | |
195 xdisplay = gdk_display; | |
196 #endif | |
197 | |
198 if (icon->manager_window != None) | |
199 { | |
200 GdkWindow *gdkwin; | |
201 | |
202 #if HAVE_GTK_MULTIHEAD | |
4261
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
203 gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)), |
3510 | 204 icon->manager_window); |
205 #else | |
206 gdkwin = gdk_window_lookup (icon->manager_window); | |
207 #endif | |
208 | |
209 gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon); | |
210 } | |
211 | |
212 XGrabServer (xdisplay); | |
213 | |
214 icon->manager_window = XGetSelectionOwner (xdisplay, | |
215 icon->selection_atom); | |
216 | |
217 if (icon->manager_window != None) | |
218 XSelectInput (xdisplay, | |
219 icon->manager_window, StructureNotifyMask); | |
220 | |
221 XUngrabServer (xdisplay); | |
222 XFlush (xdisplay); | |
223 | |
224 if (icon->manager_window != None) | |
225 { | |
226 GdkWindow *gdkwin; | |
227 | |
228 #if HAVE_GTK_MULTIHEAD | |
229 gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)), | |
230 icon->manager_window); | |
231 #else | |
232 gdkwin = gdk_window_lookup (icon->manager_window); | |
233 #endif | |
234 | |
235 gdk_window_add_filter (gdkwin, egg_tray_icon_manager_filter, icon); | |
236 | |
237 /* Send a request that we'd like to dock */ | |
238 egg_tray_icon_send_dock_request (icon); | |
239 } | |
240 } | |
241 | |
242 EggTrayIcon * | |
243 egg_tray_icon_new_for_xscreen (Screen *xscreen, const char *name) | |
244 { | |
245 EggTrayIcon *icon; | |
246 char buffer[256]; | |
247 GdkWindow *root_window; | |
248 | |
249 g_return_val_if_fail (xscreen != NULL, NULL); | |
250 | |
251 icon = g_object_new (EGG_TYPE_TRAY_ICON, NULL); | |
252 gtk_window_set_title (GTK_WINDOW (icon), name); | |
253 | |
254 #if HAVE_GTK_MULTIHEAD | |
4261
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
255 /* FIXME: this code does not compile, screen is undefined. Now try |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
256 * getting the GdkScreen from xscreen (:. Dunno how to solve this |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
257 * (there is prolly some easy way I cant think of right now) |
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
258 */ |
3510 | 259 gtk_plug_construct_for_display (GTK_PLUG (icon), |
260 gdk_screen_get_display (screen), 0); | |
261 #else | |
262 gtk_plug_construct (GTK_PLUG (icon), 0); | |
263 #endif | |
264 | |
265 gtk_widget_realize (GTK_WIDGET (icon)); | |
266 | |
267 /* Now see if there's a manager window around */ | |
268 g_snprintf (buffer, sizeof (buffer), | |
269 "_NET_SYSTEM_TRAY_S%d", | |
270 XScreenNumberOfScreen (xscreen)); | |
271 | |
272 icon->selection_atom = XInternAtom (DisplayOfScreen (xscreen), | |
273 buffer, False); | |
274 | |
275 icon->manager_atom = XInternAtom (DisplayOfScreen (xscreen), | |
276 "MANAGER", False); | |
277 | |
278 icon->system_tray_opcode_atom = XInternAtom (DisplayOfScreen (xscreen), | |
279 "_NET_SYSTEM_TRAY_OPCODE", False); | |
280 | |
281 egg_tray_icon_update_manager_window (icon); | |
282 | |
283 #if HAVE_GTK_MULTIHEAD | |
4261
e252238f99df
[gaim-migrate @ 4512]
Christian Hammond <chipx86@chipx86.com>
parents:
3510
diff
changeset
|
284 root_window = gdk_screen_get_root_window (gtk_widget_get_screen (screen)); |
3510 | 285 #else |
286 root_window = gdk_window_lookup (gdk_x11_get_default_root_xwindow ()); | |
287 #endif | |
288 | |
289 /* Add a root window filter so that we get changes on MANAGER */ | |
290 gdk_window_add_filter (root_window, | |
291 egg_tray_icon_manager_filter, icon); | |
292 | |
293 return icon; | |
294 } | |
295 | |
296 #if HAVE_GTK_MULTIHEAD | |
297 EggTrayIcon * | |
298 egg_tray_icon_new_for_screen (GdkScreen *screen, const char *name) | |
299 { | |
300 EggTrayIcon *icon; | |
301 char buffer[256]; | |
302 | |
303 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); | |
304 | |
305 return egg_tray_icon_new_for_xscreen (GDK_SCREEN_XSCREEN (screen), name); | |
306 } | |
307 #endif | |
308 | |
309 EggTrayIcon* | |
310 egg_tray_icon_new (const gchar *name) | |
311 { | |
312 return egg_tray_icon_new_for_xscreen (DefaultScreenOfDisplay (gdk_display), name); | |
313 } | |
314 | |
315 guint | |
316 egg_tray_icon_send_message (EggTrayIcon *icon, | |
317 gint timeout, | |
318 const gchar *message, | |
319 gint len) | |
320 { | |
321 guint stamp; | |
322 | |
323 g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), 0); | |
324 g_return_val_if_fail (timeout >= 0, 0); | |
325 g_return_val_if_fail (message != NULL, 0); | |
326 | |
327 if (icon->manager_window == None) | |
328 return 0; | |
329 | |
330 if (len < 0) | |
331 len = strlen (message); | |
332 | |
333 stamp = icon->stamp++; | |
334 | |
335 /* Get ready to send the message */ | |
336 egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_BEGIN_MESSAGE, | |
337 (Window)gtk_plug_get_id (GTK_PLUG (icon)), | |
338 timeout, len, stamp); | |
339 | |
340 /* Now to send the actual message */ | |
341 gdk_error_trap_push (); | |
342 while (len > 0) | |
343 { | |
344 XClientMessageEvent ev; | |
345 Display *xdisplay; | |
346 | |
347 #if HAVE_GTK_MULTIHEAD | |
348 xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); | |
349 #else | |
350 xdisplay = gdk_display; | |
351 #endif | |
352 | |
353 ev.type = ClientMessage; | |
354 ev.window = (Window)gtk_plug_get_id (GTK_PLUG (icon)); | |
355 ev.format = 8; | |
356 ev.message_type = XInternAtom (xdisplay, | |
357 "_NET_SYSTEM_TRAY_MESSAGE_DATA", False); | |
358 if (len > 20) | |
359 { | |
360 memcpy (&ev.data, message, 20); | |
361 len -= 20; | |
362 message += 20; | |
363 } | |
364 else | |
365 { | |
366 memcpy (&ev.data, message, len); | |
367 len = 0; | |
368 } | |
369 | |
370 XSendEvent (xdisplay, | |
371 icon->manager_window, False, StructureNotifyMask, (XEvent *)&ev); | |
372 XSync (xdisplay, False); | |
373 } | |
374 gdk_error_trap_pop (); | |
375 | |
376 return stamp; | |
377 } | |
378 | |
379 void | |
380 egg_tray_icon_cancel_message (EggTrayIcon *icon, | |
381 guint id) | |
382 { | |
383 g_return_if_fail (EGG_IS_TRAY_ICON (icon)); | |
384 g_return_if_fail (id > 0); | |
385 | |
386 egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_CANCEL_MESSAGE, | |
387 (Window)gtk_plug_get_id (GTK_PLUG (icon)), | |
388 id, 0, 0); | |
389 } |