| 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 |
|
| 24 #include "eggtrayicon.h" |
|
| 25 |
|
| 26 #include <gdk/gdkx.h> |
|
| 27 #include <X11/Xatom.h> |
|
| 28 |
|
| 29 #define _(x) x |
|
| 30 #define N_(x) x |
|
| 31 |
|
| 32 #define SYSTEM_TRAY_REQUEST_DOCK 0 |
|
| 33 #define SYSTEM_TRAY_BEGIN_MESSAGE 1 |
|
| 34 #define SYSTEM_TRAY_CANCEL_MESSAGE 2 |
|
| 35 |
|
| 36 #define SYSTEM_TRAY_ORIENTATION_HORZ 0 |
|
| 37 #define SYSTEM_TRAY_ORIENTATION_VERT 1 |
|
| 38 |
|
| 39 enum { |
|
| 40 PROP_0, |
|
| 41 PROP_ORIENTATION |
|
| 42 }; |
|
| 43 |
|
| 44 static GtkPlugClass *parent_class = NULL; |
|
| 45 |
|
| 46 static void egg_tray_icon_init (EggTrayIcon *icon); |
|
| 47 static void egg_tray_icon_class_init (EggTrayIconClass *klass); |
|
| 48 |
|
| 49 static void egg_tray_icon_get_property (GObject *object, |
|
| 50 guint prop_id, |
|
| 51 GValue *value, |
|
| 52 GParamSpec *pspec); |
|
| 53 |
|
| 54 static void egg_tray_icon_realize (GtkWidget *widget); |
|
| 55 static void egg_tray_icon_unrealize (GtkWidget *widget); |
|
| 56 |
|
| 57 static void egg_tray_icon_add (GtkContainer *container, |
|
| 58 GtkWidget *widget); |
|
| 59 |
|
| 60 static void egg_tray_icon_update_manager_window (EggTrayIcon *icon, |
|
| 61 gboolean dock_if_realized); |
|
| 62 static void egg_tray_icon_manager_window_destroyed (EggTrayIcon *icon); |
|
| 63 |
|
| 64 GType |
|
| 65 egg_tray_icon_get_type (void) |
|
| 66 { |
|
| 67 static GType our_type = 0; |
|
| 68 |
|
| 69 if (our_type == 0) |
|
| 70 { |
|
| 71 our_type = g_type_from_name("EggTrayIcon"); |
|
| 72 |
|
| 73 if (our_type == 0) |
|
| 74 { |
|
| 75 static const GTypeInfo our_info = |
|
| 76 { |
|
| 77 sizeof (EggTrayIconClass), |
|
| 78 (GBaseInitFunc) NULL, |
|
| 79 (GBaseFinalizeFunc) NULL, |
|
| 80 (GClassInitFunc) egg_tray_icon_class_init, |
|
| 81 NULL, /* class_finalize */ |
|
| 82 NULL, /* class_data */ |
|
| 83 sizeof (EggTrayIcon), |
|
| 84 0, /* n_preallocs */ |
|
| 85 (GInstanceInitFunc) egg_tray_icon_init, |
|
| 86 NULL /* value_table */ |
|
| 87 }; |
|
| 88 |
|
| 89 our_type = g_type_register_static (GTK_TYPE_PLUG, "EggTrayIcon", &our_info, 0); |
|
| 90 } |
|
| 91 else if (parent_class == NULL) |
|
| 92 { |
|
| 93 /* we're reheating the old class from a previous instance - engage ugly hack =( */ |
|
| 94 egg_tray_icon_class_init((EggTrayIconClass *)g_type_class_peek(our_type)); |
|
| 95 } |
|
| 96 } |
|
| 97 |
|
| 98 return our_type; |
|
| 99 } |
|
| 100 |
|
| 101 static void |
|
| 102 egg_tray_icon_init (EggTrayIcon *icon) |
|
| 103 { |
|
| 104 icon->stamp = 1; |
|
| 105 icon->orientation = GTK_ORIENTATION_HORIZONTAL; |
|
| 106 |
|
| 107 gtk_widget_add_events (GTK_WIDGET (icon), GDK_PROPERTY_CHANGE_MASK); |
|
| 108 } |
|
| 109 |
|
| 110 static void |
|
| 111 egg_tray_icon_class_init (EggTrayIconClass *klass) |
|
| 112 { |
|
| 113 GObjectClass *gobject_class = (GObjectClass *)klass; |
|
| 114 GtkWidgetClass *widget_class = (GtkWidgetClass *)klass; |
|
| 115 GtkContainerClass *container_class = (GtkContainerClass *)klass; |
|
| 116 |
|
| 117 parent_class = g_type_class_peek_parent (klass); |
|
| 118 |
|
| 119 gobject_class->get_property = egg_tray_icon_get_property; |
|
| 120 |
|
| 121 widget_class->realize = egg_tray_icon_realize; |
|
| 122 widget_class->unrealize = egg_tray_icon_unrealize; |
|
| 123 |
|
| 124 container_class->add = egg_tray_icon_add; |
|
| 125 |
|
| 126 g_object_class_install_property (gobject_class, |
|
| 127 PROP_ORIENTATION, |
|
| 128 g_param_spec_enum ("orientation", |
|
| 129 _("Orientation"), |
|
| 130 _("The orientation of the tray."), |
|
| 131 GTK_TYPE_ORIENTATION, |
|
| 132 GTK_ORIENTATION_HORIZONTAL, |
|
| 133 G_PARAM_READABLE)); |
|
| 134 } |
|
| 135 |
|
| 136 static void |
|
| 137 egg_tray_icon_get_property (GObject *object, |
|
| 138 guint prop_id, |
|
| 139 GValue *value, |
|
| 140 GParamSpec *pspec) |
|
| 141 { |
|
| 142 EggTrayIcon *icon = EGG_TRAY_ICON (object); |
|
| 143 |
|
| 144 switch (prop_id) |
|
| 145 { |
|
| 146 case PROP_ORIENTATION: |
|
| 147 g_value_set_enum (value, icon->orientation); |
|
| 148 break; |
|
| 149 default: |
|
| 150 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
|
| 151 break; |
|
| 152 } |
|
| 153 } |
|
| 154 |
|
| 155 static void |
|
| 156 egg_tray_icon_get_orientation_property (EggTrayIcon *icon) |
|
| 157 { |
|
| 158 Display *xdisplay; |
|
| 159 Atom type; |
|
| 160 int format; |
|
| 161 union { |
|
| 162 gulong *prop; |
|
| 163 guchar *prop_ch; |
|
| 164 } prop = { NULL }; |
|
| 165 gulong nitems; |
|
| 166 gulong bytes_after; |
|
| 167 int error, result; |
|
| 168 |
|
| 169 g_return_if_fail(icon->manager_window != None); |
|
| 170 |
|
| 171 #if GTK_CHECK_VERSION(2,1,0) |
|
| 172 xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); |
|
| 173 #else |
|
| 174 xdisplay = gdk_display; |
|
| 175 #endif |
|
| 176 |
|
| 177 gdk_error_trap_push (); |
|
| 178 type = None; |
|
| 179 result = XGetWindowProperty (xdisplay, |
|
| 180 icon->manager_window, |
|
| 181 icon->orientation_atom, |
|
| 182 0, G_MAXLONG, FALSE, |
|
| 183 XA_CARDINAL, |
|
| 184 &type, &format, &nitems, |
|
| 185 &bytes_after, &(prop.prop_ch)); |
|
| 186 error = gdk_error_trap_pop (); |
|
| 187 |
|
| 188 if (error || result != Success) |
|
| 189 return; |
|
| 190 |
|
| 191 if (type == XA_CARDINAL) |
|
| 192 { |
|
| 193 GtkOrientation orientation; |
|
| 194 |
|
| 195 orientation = (prop.prop [0] == SYSTEM_TRAY_ORIENTATION_HORZ) ? |
|
| 196 GTK_ORIENTATION_HORIZONTAL : |
|
| 197 GTK_ORIENTATION_VERTICAL; |
|
| 198 |
|
| 199 if (icon->orientation != orientation) |
|
| 200 { |
|
| 201 icon->orientation = orientation; |
|
| 202 |
|
| 203 g_object_notify (G_OBJECT (icon), "orientation"); |
|
| 204 } |
|
| 205 } |
|
| 206 |
|
| 207 if (prop.prop) |
|
| 208 XFree (prop.prop); |
|
| 209 } |
|
| 210 |
|
| 211 static GdkFilterReturn |
|
| 212 egg_tray_icon_manager_filter (GdkXEvent *xevent, GdkEvent *event, gpointer user_data) |
|
| 213 { |
|
| 214 EggTrayIcon *icon = user_data; |
|
| 215 XEvent *xev = (XEvent *)xevent; |
|
| 216 |
|
| 217 if (xev->xany.type == ClientMessage && |
|
| 218 xev->xclient.message_type == icon->manager_atom && |
|
| 219 xev->xclient.data.l[1] == icon->selection_atom) |
|
| 220 { |
|
| 221 egg_tray_icon_update_manager_window (icon, TRUE); |
|
| 222 } |
|
| 223 else if (xev->xany.window == icon->manager_window) |
|
| 224 { |
|
| 225 if (xev->xany.type == PropertyNotify && |
|
| 226 xev->xproperty.atom == icon->orientation_atom) |
|
| 227 { |
|
| 228 egg_tray_icon_get_orientation_property (icon); |
|
| 229 } |
|
| 230 if (xev->xany.type == DestroyNotify) |
|
| 231 { |
|
| 232 egg_tray_icon_manager_window_destroyed (icon); |
|
| 233 } |
|
| 234 } |
|
| 235 |
|
| 236 return GDK_FILTER_CONTINUE; |
|
| 237 } |
|
| 238 |
|
| 239 static void |
|
| 240 egg_tray_icon_unrealize (GtkWidget *widget) |
|
| 241 { |
|
| 242 EggTrayIcon *icon = EGG_TRAY_ICON (widget); |
|
| 243 GdkWindow *root_window; |
|
| 244 |
|
| 245 if (icon->manager_window != None) |
|
| 246 { |
|
| 247 GdkWindow *gdkwin; |
|
| 248 |
|
| 249 #if GTK_CHECK_VERSION(2,1,0) |
|
| 250 gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (widget), |
|
| 251 icon->manager_window); |
|
| 252 #else |
|
| 253 gdkwin = gdk_window_lookup (icon->manager_window); |
|
| 254 #endif |
|
| 255 |
|
| 256 gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon); |
|
| 257 } |
|
| 258 |
|
| 259 #if GTK_CHECK_VERSION(2,1,0) |
|
| 260 root_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget)); |
|
| 261 #else |
|
| 262 root_window = gdk_window_lookup (gdk_x11_get_default_root_xwindow ()); |
|
| 263 #endif |
|
| 264 |
|
| 265 gdk_window_remove_filter (root_window, egg_tray_icon_manager_filter, icon); |
|
| 266 |
|
| 267 if (GTK_WIDGET_CLASS (parent_class)->unrealize) |
|
| 268 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); |
|
| 269 } |
|
| 270 |
|
| 271 static void |
|
| 272 egg_tray_icon_send_manager_message (EggTrayIcon *icon, |
|
| 273 long message, |
|
| 274 Window window, |
|
| 275 long data1, |
|
| 276 long data2, |
|
| 277 long data3) |
|
| 278 { |
|
| 279 XClientMessageEvent ev; |
|
| 280 Display *display; |
|
| 281 |
|
| 282 ev.type = ClientMessage; |
|
| 283 ev.window = window; |
|
| 284 ev.message_type = icon->system_tray_opcode_atom; |
|
| 285 ev.format = 32; |
|
| 286 ev.data.l[0] = gdk_x11_get_server_time (GTK_WIDGET (icon)->window); |
|
| 287 ev.data.l[1] = message; |
|
| 288 ev.data.l[2] = data1; |
|
| 289 ev.data.l[3] = data2; |
|
| 290 ev.data.l[4] = data3; |
|
| 291 |
|
| 292 #if GTK_CHECK_VERSION(2,1,0) |
|
| 293 display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); |
|
| 294 #else |
|
| 295 display = gdk_display; |
|
| 296 #endif |
|
| 297 |
|
| 298 gdk_error_trap_push (); |
|
| 299 XSendEvent (display, |
|
| 300 icon->manager_window, False, NoEventMask, (XEvent *)&ev); |
|
| 301 XSync (display, False); |
|
| 302 gdk_error_trap_pop (); |
|
| 303 } |
|
| 304 |
|
| 305 static void |
|
| 306 egg_tray_icon_send_dock_request (EggTrayIcon *icon) |
|
| 307 { |
|
| 308 egg_tray_icon_send_manager_message (icon, |
|
| 309 SYSTEM_TRAY_REQUEST_DOCK, |
|
| 310 icon->manager_window, |
|
| 311 gtk_plug_get_id (GTK_PLUG (icon)), |
|
| 312 0, 0); |
|
| 313 } |
|
| 314 |
|
| 315 static void |
|
| 316 egg_tray_icon_update_manager_window (EggTrayIcon *icon, |
|
| 317 gboolean dock_if_realized) |
|
| 318 { |
|
| 319 Display *xdisplay; |
|
| 320 |
|
| 321 if (icon->manager_window != None) |
|
| 322 return; |
|
| 323 |
|
| 324 #if GTK_CHECK_VERSION(2,1,0) |
|
| 325 xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); |
|
| 326 #else |
|
| 327 xdisplay = gdk_display; |
|
| 328 #endif |
|
| 329 |
|
| 330 XGrabServer (xdisplay); |
|
| 331 |
|
| 332 icon->manager_window = XGetSelectionOwner (xdisplay, |
|
| 333 icon->selection_atom); |
|
| 334 |
|
| 335 if (icon->manager_window != None) |
|
| 336 XSelectInput (xdisplay, |
|
| 337 icon->manager_window, StructureNotifyMask|PropertyChangeMask); |
|
| 338 |
|
| 339 XUngrabServer (xdisplay); |
|
| 340 XFlush (xdisplay); |
|
| 341 |
|
| 342 if (icon->manager_window != None) |
|
| 343 { |
|
| 344 GdkWindow *gdkwin; |
|
| 345 |
|
| 346 #if GTK_CHECK_VERSION(2,1,0) |
|
| 347 gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)), |
|
| 348 icon->manager_window); |
|
| 349 #else |
|
| 350 gdkwin = gdk_window_lookup (icon->manager_window); |
|
| 351 #endif |
|
| 352 |
|
| 353 gdk_window_add_filter (gdkwin, egg_tray_icon_manager_filter, icon); |
|
| 354 |
|
| 355 if (dock_if_realized && GTK_WIDGET_REALIZED (icon)) |
|
| 356 egg_tray_icon_send_dock_request (icon); |
|
| 357 |
|
| 358 egg_tray_icon_get_orientation_property (icon); |
|
| 359 } |
|
| 360 } |
|
| 361 |
|
| 362 static void |
|
| 363 egg_tray_icon_manager_window_destroyed (EggTrayIcon *icon) |
|
| 364 { |
|
| 365 GdkWindow *gdkwin; |
|
| 366 |
|
| 367 g_return_if_fail (icon->manager_window != None); |
|
| 368 |
|
| 369 #if GTK_CHECK_VERSION(2,1,0) |
|
| 370 gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)), |
|
| 371 icon->manager_window); |
|
| 372 #else |
|
| 373 gdkwin = gdk_window_lookup (icon->manager_window); |
|
| 374 #endif |
|
| 375 |
|
| 376 gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon); |
|
| 377 |
|
| 378 icon->manager_window = None; |
|
| 379 |
|
| 380 egg_tray_icon_update_manager_window (icon, TRUE); |
|
| 381 } |
|
| 382 |
|
| 383 static gboolean |
|
| 384 transparent_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) |
|
| 385 { |
|
| 386 gdk_window_clear_area (widget->window, event->area.x, event->area.y, |
|
| 387 event->area.width, event->area.height); |
|
| 388 return FALSE; |
|
| 389 } |
|
| 390 |
|
| 391 static void |
|
| 392 make_transparent_again (GtkWidget *widget, GtkStyle *previous_style, |
|
| 393 gpointer user_data) |
|
| 394 { |
|
| 395 gdk_window_set_back_pixmap(widget->window, NULL, TRUE); |
|
| 396 } |
|
| 397 |
|
| 398 static void |
|
| 399 make_transparent (GtkWidget *widget, gpointer user_data) |
|
| 400 { |
|
| 401 if (GTK_WIDGET_NO_WINDOW (widget) || GTK_WIDGET_APP_PAINTABLE (widget)) |
|
| 402 return; |
|
| 403 |
|
| 404 gtk_widget_set_app_paintable (widget, TRUE); |
|
| 405 gtk_widget_set_double_buffered (widget, FALSE); |
|
| 406 gdk_window_set_back_pixmap (widget->window, NULL, TRUE); |
|
| 407 g_signal_connect (widget, "expose_event", |
|
| 408 G_CALLBACK (transparent_expose_event), NULL); |
|
| 409 g_signal_connect_after (widget, "style_set", |
|
| 410 G_CALLBACK (make_transparent_again), NULL); |
|
| 411 } |
|
| 412 |
|
| 413 static void |
|
| 414 egg_tray_icon_realize (GtkWidget *widget) |
|
| 415 { |
|
| 416 EggTrayIcon *icon = EGG_TRAY_ICON (widget); |
|
| 417 gint screen; |
|
| 418 Display *xdisplay; |
|
| 419 char buffer[256]; |
|
| 420 GdkWindow *root_window; |
|
| 421 |
|
| 422 if (GTK_WIDGET_CLASS (parent_class)->realize) |
|
| 423 GTK_WIDGET_CLASS (parent_class)->realize (widget); |
|
| 424 |
|
| 425 make_transparent (widget, NULL); |
|
| 426 |
|
| 427 #if GTK_CHECK_VERSION(2,1,0) |
|
| 428 screen = gdk_screen_get_number (gtk_widget_get_screen (widget)); |
|
| 429 xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget)); |
|
| 430 #else |
|
| 431 screen = XScreenNumberOfScreen (DefaultScreenOfDisplay (gdk_display)); |
|
| 432 xdisplay = gdk_display; |
|
| 433 #endif |
|
| 434 |
|
| 435 /* Now see if there's a manager window around */ |
|
| 436 g_snprintf (buffer, sizeof (buffer), |
|
| 437 "_NET_SYSTEM_TRAY_S%d", |
|
| 438 screen); |
|
| 439 |
|
| 440 icon->selection_atom = XInternAtom (xdisplay, buffer, False); |
|
| 441 |
|
| 442 icon->manager_atom = XInternAtom (xdisplay, "MANAGER", False); |
|
| 443 |
|
| 444 icon->system_tray_opcode_atom = XInternAtom (xdisplay, |
|
| 445 "_NET_SYSTEM_TRAY_OPCODE", |
|
| 446 False); |
|
| 447 |
|
| 448 icon->orientation_atom = XInternAtom (xdisplay, |
|
| 449 "_NET_SYSTEM_TRAY_ORIENTATION", |
|
| 450 False); |
|
| 451 |
|
| 452 egg_tray_icon_update_manager_window (icon, FALSE); |
|
| 453 egg_tray_icon_send_dock_request (icon); |
|
| 454 |
|
| 455 #if GTK_CHECK_VERSION(2,1,0) |
|
| 456 root_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget)); |
|
| 457 #else |
|
| 458 root_window = gdk_window_lookup (gdk_x11_get_default_root_xwindow ()); |
|
| 459 #endif |
|
| 460 |
|
| 461 /* Add a root window filter so that we get changes on MANAGER */ |
|
| 462 gdk_window_add_filter (root_window, |
|
| 463 egg_tray_icon_manager_filter, icon); |
|
| 464 } |
|
| 465 |
|
| 466 static void |
|
| 467 egg_tray_icon_add (GtkContainer *container, GtkWidget *widget) |
|
| 468 { |
|
| 469 g_signal_connect (widget, "realize", |
|
| 470 G_CALLBACK (make_transparent), NULL); |
|
| 471 GTK_CONTAINER_CLASS (parent_class)->add (container, widget); |
|
| 472 } |
|
| 473 |
|
| 474 #if GTK_CHECK_VERSION(2,1,0) |
|
| 475 EggTrayIcon * |
|
| 476 egg_tray_icon_new_for_screen (GdkScreen *screen, const char *name) |
|
| 477 { |
|
| 478 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); |
|
| 479 |
|
| 480 return g_object_new (EGG_TYPE_TRAY_ICON, "screen", screen, "title", name, NULL); |
|
| 481 } |
|
| 482 #endif |
|
| 483 |
|
| 484 EggTrayIcon* |
|
| 485 egg_tray_icon_new (const gchar *name) |
|
| 486 { |
|
| 487 return g_object_new (EGG_TYPE_TRAY_ICON, "title", name, NULL); |
|
| 488 } |
|
| 489 |
|
| 490 guint |
|
| 491 egg_tray_icon_send_message (EggTrayIcon *icon, |
|
| 492 gint timeout, |
|
| 493 const gchar *message, |
|
| 494 gint len) |
|
| 495 { |
|
| 496 guint stamp; |
|
| 497 |
|
| 498 g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), 0); |
|
| 499 g_return_val_if_fail (timeout >= 0, 0); |
|
| 500 g_return_val_if_fail (message != NULL, 0); |
|
| 501 |
|
| 502 if (icon->manager_window == None) |
|
| 503 return 0; |
|
| 504 |
|
| 505 if (len < 0) |
|
| 506 len = strlen (message); |
|
| 507 |
|
| 508 stamp = icon->stamp++; |
|
| 509 |
|
| 510 /* Get ready to send the message */ |
|
| 511 egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_BEGIN_MESSAGE, |
|
| 512 (Window)gtk_plug_get_id (GTK_PLUG (icon)), |
|
| 513 timeout, len, stamp); |
|
| 514 |
|
| 515 /* Now to send the actual message */ |
|
| 516 gdk_error_trap_push (); |
|
| 517 while (len > 0) |
|
| 518 { |
|
| 519 XClientMessageEvent ev; |
|
| 520 Display *xdisplay; |
|
| 521 |
|
| 522 #if GTK_CHECK_VERSION(2,1,0) |
|
| 523 xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon))); |
|
| 524 #else |
|
| 525 xdisplay = gdk_display; |
|
| 526 #endif |
|
| 527 |
|
| 528 ev.type = ClientMessage; |
|
| 529 ev.window = (Window)gtk_plug_get_id (GTK_PLUG (icon)); |
|
| 530 ev.format = 8; |
|
| 531 ev.message_type = XInternAtom (xdisplay, |
|
| 532 "_NET_SYSTEM_TRAY_MESSAGE_DATA", False); |
|
| 533 if (len > 20) |
|
| 534 { |
|
| 535 memcpy (&ev.data, message, 20); |
|
| 536 len -= 20; |
|
| 537 message += 20; |
|
| 538 } |
|
| 539 else |
|
| 540 { |
|
| 541 memcpy (&ev.data, message, len); |
|
| 542 len = 0; |
|
| 543 } |
|
| 544 |
|
| 545 XSendEvent (xdisplay, |
|
| 546 icon->manager_window, False, StructureNotifyMask, (XEvent *)&ev); |
|
| 547 XSync (xdisplay, False); |
|
| 548 } |
|
| 549 gdk_error_trap_pop (); |
|
| 550 |
|
| 551 return stamp; |
|
| 552 } |
|
| 553 |
|
| 554 void |
|
| 555 egg_tray_icon_cancel_message (EggTrayIcon *icon, |
|
| 556 guint id) |
|
| 557 { |
|
| 558 g_return_if_fail (EGG_IS_TRAY_ICON (icon)); |
|
| 559 g_return_if_fail (id > 0); |
|
| 560 |
|
| 561 egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_CANCEL_MESSAGE, |
|
| 562 (Window)gtk_plug_get_id (GTK_PLUG (icon)), |
|
| 563 id, 0, 0); |
|
| 564 } |
|
| 565 |
|
| 566 GtkOrientation |
|
| 567 egg_tray_icon_get_orientation (EggTrayIcon *icon) |
|
| 568 { |
|
| 569 g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), GTK_ORIENTATION_HORIZONTAL); |
|
| 570 |
|
| 571 return icon->orientation; |
|
| 572 } |
|