/home/fernape/Projects/lkmonitor/src/eggtrayicon.c

Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
00002 /* eggtrayicon.c
00003  * Copyright (C) 2002 Anders Carlsson <andersca@gnu.org>
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Lesser General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Lesser General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public
00016  * License along with this library; if not, write to the
00017  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018  * Boston, MA 02111-1307, USA.
00019  */
00020 
00021 #include <string.h>
00022 #include <gdk/gdkx.h>
00023 #include "eggtrayicon.h"
00024 
00025 #define SYSTEM_TRAY_REQUEST_DOCK    0
00026 #define SYSTEM_TRAY_BEGIN_MESSAGE   1
00027 #define SYSTEM_TRAY_CANCEL_MESSAGE  2
00028          
00029 static GtkPlugClass *parent_class = NULL;
00030 
00031 static void egg_tray_icon_init (EggTrayIcon *icon);
00032 static void egg_tray_icon_class_init (EggTrayIconClass *klass);
00033 
00034 static void egg_tray_icon_update_manager_window (EggTrayIcon *icon);
00035 
00036 GType
00037 egg_tray_icon_get_type (void)
00038 {
00039   static GType our_type = 0;
00040 
00041   if (our_type == 0)
00042     {
00043       static const GTypeInfo our_info =
00044       {
00045         sizeof (EggTrayIconClass),
00046         (GBaseInitFunc) NULL,
00047         (GBaseFinalizeFunc) NULL,
00048         (GClassInitFunc) egg_tray_icon_class_init,
00049         NULL, /* class_finalize */
00050         NULL, /* class_data */
00051         sizeof (EggTrayIcon),
00052         0,    /* n_preallocs */
00053         (GInstanceInitFunc) egg_tray_icon_init
00054       };
00055 
00056       our_type = g_type_register_static (GTK_TYPE_PLUG, "EggTrayIcon", &our_info, 0);
00057     }
00058 
00059   return our_type;
00060 }
00061 
00062 static void
00063 egg_tray_icon_init (EggTrayIcon *icon)
00064 {
00065   icon->stamp = 1;
00066   
00067   gtk_widget_add_events (GTK_WIDGET (icon), GDK_PROPERTY_CHANGE_MASK);
00068 }
00069 
00070 static void
00071 egg_tray_icon_class_init (EggTrayIconClass *klass)
00072 {
00073   parent_class = g_type_class_peek_parent (klass);
00074 }
00075 
00076 static GdkFilterReturn
00077 egg_tray_icon_manager_filter (GdkXEvent *xevent, GdkEvent *event, gpointer user_data)
00078 {
00079   EggTrayIcon *icon = user_data;
00080   XEvent *xev = (XEvent *)xevent;
00081 
00082   if (xev->xany.type == ClientMessage &&
00083       xev->xclient.message_type == icon->manager_atom &&
00084       xev->xclient.data.l[1] == icon->selection_atom)
00085     {
00086       egg_tray_icon_update_manager_window (icon);
00087     }
00088   else if (xev->xany.window == icon->manager_window)
00089     {
00090       if (xev->xany.type == DestroyNotify)
00091         {
00092           egg_tray_icon_update_manager_window (icon);
00093         }
00094     }
00095   
00096   return GDK_FILTER_CONTINUE;
00097 }
00098 
00099 static void
00100 egg_tray_icon_send_manager_message (EggTrayIcon *icon,
00101                                     long         message,
00102                                     Window       window,
00103                                     long         data1,
00104                                     long         data2,
00105                                     long         data3)
00106 {
00107   XClientMessageEvent ev;
00108   Display *display;
00109   
00110   ev.type = ClientMessage;
00111   ev.window = window;
00112   ev.message_type = icon->system_tray_opcode_atom;
00113   ev.format = 32;
00114   ev.data.l[0] = gdk_x11_get_server_time (GTK_WIDGET (icon)->window);
00115   ev.data.l[1] = message;
00116   ev.data.l[2] = data1;
00117   ev.data.l[3] = data2;
00118   ev.data.l[4] = data3;
00119 
00120 #if HAVE_GTK_MULTIHEAD
00121   display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
00122 #else
00123   display = gdk_display;
00124 #endif
00125   
00126   gdk_error_trap_push ();
00127   XSendEvent (display,
00128               icon->manager_window, False, NoEventMask, (XEvent *)&ev);
00129   XSync (display, False);
00130   gdk_error_trap_pop ();
00131 }
00132 
00133 static void
00134 egg_tray_icon_send_dock_request (EggTrayIcon *icon)
00135 {
00136   egg_tray_icon_send_manager_message (icon,
00137                                       SYSTEM_TRAY_REQUEST_DOCK,
00138                                       icon->manager_window,
00139                                       gtk_plug_get_id (GTK_PLUG (icon)),
00140                                       0, 0);
00141 }
00142 
00143 static void
00144 egg_tray_icon_update_manager_window (EggTrayIcon *icon)
00145 {
00146   Display *xdisplay;
00147   
00148 #if HAVE_GTK_MULTIHEAD
00149   xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
00150 #else
00151   xdisplay = gdk_display;
00152 #endif
00153   
00154   if (icon->manager_window != None)
00155     {
00156       GdkWindow *gdkwin;
00157 
00158 #if HAVE_GTK_MULTIHEAD
00159       gdkwin = gdk_window_lookup_for_display (display,
00160                                               icon->manager_window);
00161 #else
00162       gdkwin = gdk_window_lookup (icon->manager_window);
00163 #endif
00164       
00165       gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon);
00166     }
00167   
00168   XGrabServer (xdisplay);
00169   
00170   icon->manager_window = XGetSelectionOwner (xdisplay,
00171                                              icon->selection_atom);
00172 
00173   if (icon->manager_window != None)
00174     XSelectInput (xdisplay,
00175                   icon->manager_window, StructureNotifyMask);
00176 
00177   XUngrabServer (xdisplay);
00178   XFlush (xdisplay);
00179   
00180   if (icon->manager_window != None)
00181     {
00182       GdkWindow *gdkwin;
00183 
00184 #if HAVE_GTK_MULTIHEAD
00185       gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)),
00186                                               icon->manager_window);
00187 #else
00188       gdkwin = gdk_window_lookup (icon->manager_window);
00189 #endif
00190       
00191       gdk_window_add_filter (gdkwin, egg_tray_icon_manager_filter, icon);
00192 
00193       /* Send a request that we'd like to dock */
00194       egg_tray_icon_send_dock_request (icon);
00195     }
00196 }
00197 
00198 EggTrayIcon *
00199 egg_tray_icon_new_for_xscreen (Screen *xscreen, const char *name)
00200 {
00201   EggTrayIcon *icon;
00202   char buffer[256];
00203   GdkWindow *root_window;
00204 
00205   g_return_val_if_fail (xscreen != NULL, NULL);
00206   
00207   icon = g_object_new (EGG_TYPE_TRAY_ICON, NULL);
00208   gtk_window_set_title (GTK_WINDOW (icon), name);
00209 
00210 #if HAVE_GTK_MULTIHEAD
00211   gtk_plug_construct_for_display (GTK_PLUG (icon),
00212                                   gdk_screen_get_display (screen), 0);
00213 #else
00214   gtk_plug_construct (GTK_PLUG (icon), 0);
00215 #endif
00216   
00217   gtk_widget_realize (GTK_WIDGET (icon));
00218 
00219   /* Now see if there's a manager window around */
00220   g_snprintf (buffer, sizeof (buffer),
00221               "_NET_SYSTEM_TRAY_S%d",
00222               XScreenNumberOfScreen (xscreen));
00223   
00224   icon->selection_atom = XInternAtom (DisplayOfScreen (xscreen),
00225                                       buffer, False);
00226   
00227   icon->manager_atom = XInternAtom (DisplayOfScreen (xscreen),
00228                                     "MANAGER", False);
00229   
00230   icon->system_tray_opcode_atom = XInternAtom (DisplayOfScreen (xscreen),
00231                                                "_NET_SYSTEM_TRAY_OPCODE", False);
00232 
00233   egg_tray_icon_update_manager_window (icon);
00234 
00235 #if HAVE_GTK_MULTIHEAD
00236   root_window = gdk_screen_get_root_window (screen);
00237 #else
00238   root_window = gdk_window_lookup (gdk_x11_get_default_root_xwindow ());
00239 #endif
00240   
00241   /* Add a root window filter so that we get changes on MANAGER */
00242   gdk_window_add_filter (root_window,
00243                          egg_tray_icon_manager_filter, icon);
00244                       
00245   return icon;
00246 }
00247 
00248 #if HAVE_GTK_MULTIHEAD
00249 EggTrayIcon *
00250 egg_tray_icon_new_for_screen (GdkScreen *screen, const char *name)
00251 {
00252   EggTrayIcon *icon;
00253   char buffer[256];
00254 
00255   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
00256 
00257   return egg_tray_icon_new_for_xscreen (GDK_SCREEN_XSCREEN (screen), name);
00258 }
00259 #endif
00260 
00261 EggTrayIcon*
00262 egg_tray_icon_new (const gchar *name)
00263 {
00264   return egg_tray_icon_new_for_xscreen (DefaultScreenOfDisplay (gdk_display), name);
00265 }
00266 
00267 guint
00268 egg_tray_icon_send_message (EggTrayIcon *icon,
00269                             gint         timeout,
00270                             const gchar *message,
00271                             gint         len)
00272 {
00273   guint stamp;
00274   
00275   g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), 0);
00276   g_return_val_if_fail (timeout >= 0, 0);
00277   g_return_val_if_fail (message != NULL, 0);
00278                      
00279   if (icon->manager_window == None)
00280     return 0;
00281 
00282   if (len < 0)
00283     len = strlen (message);
00284 
00285   stamp = icon->stamp++;
00286   
00287   /* Get ready to send the message */
00288   egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_BEGIN_MESSAGE,
00289                                       (Window)gtk_plug_get_id (GTK_PLUG (icon)),
00290                                       timeout, len, stamp);
00291 
00292   /* Now to send the actual message */
00293   gdk_error_trap_push ();
00294   while (len > 0)
00295     {
00296       XClientMessageEvent ev;
00297       Display *xdisplay;
00298 
00299 #if HAVE_GTK_MULTIHEAD
00300       xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
00301 #else
00302       xdisplay = gdk_display;
00303 #endif
00304       
00305       ev.type = ClientMessage;
00306       ev.window = (Window)gtk_plug_get_id (GTK_PLUG (icon));
00307       ev.format = 8;
00308       ev.message_type = XInternAtom (xdisplay,
00309                                      "_NET_SYSTEM_TRAY_MESSAGE_DATA", False);
00310       if (len > 20)
00311         {
00312           memcpy (&ev.data, message, 20);
00313           len -= 20;
00314           message += 20;
00315         }
00316       else
00317         {
00318           memcpy (&ev.data, message, len);
00319           len = 0;
00320         }
00321 
00322       XSendEvent (xdisplay,
00323                   icon->manager_window, False, StructureNotifyMask, (XEvent *)&ev);
00324       XSync (xdisplay, False);
00325     }
00326   gdk_error_trap_pop ();
00327 
00328   return stamp;
00329 }
00330 
00331 void
00332 egg_tray_icon_cancel_message (EggTrayIcon *icon,
00333                               guint        id)
00334 {
00335   g_return_if_fail (EGG_IS_TRAY_ICON (icon));
00336   g_return_if_fail (id > 0);
00337   
00338   egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_CANCEL_MESSAGE,
00339                                       (Window)gtk_plug_get_id (GTK_PLUG (icon)),
00340                                       id, 0, 0);
00341 }

Generated on Tue Apr 1 22:52:51 2008 for lkmonitor by  doxygen 1.5.1