eggtrayicon.c
上传用户:ledjyj
上传日期:2014-08-27
资源大小:2639k
文件大小:9k
源码类别:

驱动编程

开发平台:

Unix_Linux

  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. #include <string.h>
  21. #include <gdk/gdkx.h>
  22. #include "eggtrayicon.h"
  23. #define SYSTEM_TRAY_REQUEST_DOCK    0
  24. #define SYSTEM_TRAY_BEGIN_MESSAGE   1
  25. #define SYSTEM_TRAY_CANCEL_MESSAGE  2
  26.          
  27. static GtkPlugClass *parent_class = NULL;
  28. static void egg_tray_icon_init (EggTrayIcon *icon);
  29. static void egg_tray_icon_class_init (EggTrayIconClass *klass);
  30. static void egg_tray_icon_update_manager_window (EggTrayIcon *icon);
  31. GType
  32. egg_tray_icon_get_type (void)
  33. {
  34.   static GType our_type = 0;
  35.   if (our_type == 0)
  36.     {
  37.       static const GTypeInfo our_info =
  38.       {
  39. sizeof (EggTrayIconClass),
  40. (GBaseInitFunc) NULL,
  41. (GBaseFinalizeFunc) NULL,
  42. (GClassInitFunc) egg_tray_icon_class_init,
  43. NULL, /* class_finalize */
  44. NULL, /* class_data */
  45. sizeof (EggTrayIcon),
  46. 0,    /* n_preallocs */
  47. (GInstanceInitFunc) egg_tray_icon_init
  48.       };
  49.       our_type = g_type_register_static (GTK_TYPE_PLUG, "EggTrayIcon", &our_info, 0);
  50.     }
  51.   return our_type;
  52. }
  53. static void
  54. egg_tray_icon_init (EggTrayIcon *icon)
  55. {
  56.   icon->stamp = 1;
  57.   
  58.   gtk_widget_add_events (GTK_WIDGET (icon), GDK_PROPERTY_CHANGE_MASK);
  59. }
  60. static void
  61. egg_tray_icon_class_init (EggTrayIconClass *klass)
  62. {
  63.   parent_class = g_type_class_peek_parent (klass);
  64. }
  65. static GdkFilterReturn
  66. egg_tray_icon_manager_filter (GdkXEvent *xevent, GdkEvent *event, gpointer user_data)
  67. {
  68.   EggTrayIcon *icon = user_data;
  69.   XEvent *xev = (XEvent *)xevent;
  70.   if (xev->xany.type == ClientMessage &&
  71.       xev->xclient.message_type == icon->manager_atom &&
  72.       xev->xclient.data.l[1] == icon->selection_atom)
  73.     {
  74.       egg_tray_icon_update_manager_window (icon);
  75.     }
  76.   else if (xev->xany.window == icon->manager_window)
  77.     {
  78.       if (xev->xany.type == DestroyNotify)
  79. {
  80.   egg_tray_icon_update_manager_window (icon);
  81. }
  82.     }
  83.   
  84.   return GDK_FILTER_CONTINUE;
  85. }
  86. static void
  87. egg_tray_icon_send_manager_message (EggTrayIcon *icon,
  88.     long         message,
  89.     Window       window,
  90.     long         data1,
  91.     long         data2,
  92.     long         data3)
  93. {
  94.   XClientMessageEvent ev;
  95.   Display *display;
  96.   
  97.   ev.type = ClientMessage;
  98.   ev.window = window;
  99.   ev.message_type = icon->system_tray_opcode_atom;
  100.   ev.format = 32;
  101.   ev.data.l[0] = gdk_x11_get_server_time (GTK_WIDGET (icon)->window);
  102.   ev.data.l[1] = message;
  103.   ev.data.l[2] = data1;
  104.   ev.data.l[3] = data2;
  105.   ev.data.l[4] = data3;
  106. #if HAVE_GTK_MULTIHEAD
  107.   display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
  108. #else
  109.   display = gdk_display;
  110. #endif
  111.   
  112.   gdk_error_trap_push ();
  113.   XSendEvent (display,
  114.       icon->manager_window, False, NoEventMask, (XEvent *)&ev);
  115.   XSync (display, False);
  116.   gdk_error_trap_pop ();
  117. }
  118. static void
  119. egg_tray_icon_send_dock_request (EggTrayIcon *icon)
  120. {
  121.   egg_tray_icon_send_manager_message (icon,
  122.       SYSTEM_TRAY_REQUEST_DOCK,
  123.       icon->manager_window,
  124.       gtk_plug_get_id (GTK_PLUG (icon)),
  125.       0, 0);
  126. }
  127. static void
  128. egg_tray_icon_update_manager_window (EggTrayIcon *icon)
  129. {
  130.   Display *xdisplay;
  131.   
  132. #if HAVE_GTK_MULTIHEAD
  133.   xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
  134. #else
  135.   xdisplay = gdk_display;
  136. #endif
  137.   
  138.   if (icon->manager_window != None)
  139.     {
  140.       GdkWindow *gdkwin;
  141. #if HAVE_GTK_MULTIHEAD
  142.       gdkwin = gdk_window_lookup_for_display (display,
  143.       icon->manager_window);
  144. #else
  145.       gdkwin = gdk_window_lookup (icon->manager_window);
  146. #endif
  147.       
  148.       gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon);
  149.     }
  150.   
  151.   XGrabServer (xdisplay);
  152.   
  153.   icon->manager_window = XGetSelectionOwner (xdisplay,
  154.      icon->selection_atom);
  155.   if (icon->manager_window != None)
  156.     XSelectInput (xdisplay,
  157.   icon->manager_window, StructureNotifyMask);
  158.   XUngrabServer (xdisplay);
  159.   XFlush (xdisplay);
  160.   
  161.   if (icon->manager_window != None)
  162.     {
  163.       GdkWindow *gdkwin;
  164. #if HAVE_GTK_MULTIHEAD
  165.       gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)),
  166.       icon->manager_window);
  167. #else
  168.       gdkwin = gdk_window_lookup (icon->manager_window);
  169. #endif
  170.       
  171.       gdk_window_add_filter (gdkwin, egg_tray_icon_manager_filter, icon);
  172.       /* Send a request that we'd like to dock */
  173.       egg_tray_icon_send_dock_request (icon);
  174.     }
  175. }
  176. EggTrayIcon *
  177. egg_tray_icon_new_for_xscreen (Screen *xscreen, const char *name)
  178. {
  179.   EggTrayIcon *icon;
  180.   char buffer[256];
  181.   GdkWindow *root_window;
  182.   g_return_val_if_fail (xscreen != NULL, NULL);
  183.   
  184.   icon = g_object_new (EGG_TYPE_TRAY_ICON, NULL);
  185.   gtk_window_set_title (GTK_WINDOW (icon), name);
  186. #if HAVE_GTK_MULTIHEAD
  187.   gtk_plug_construct_for_display (GTK_PLUG (icon),
  188.   gdk_screen_get_display (screen), 0);
  189. #else
  190.   gtk_plug_construct (GTK_PLUG (icon), 0);
  191. #endif
  192.   
  193.   gtk_widget_realize (GTK_WIDGET (icon));
  194.   /* Now see if there's a manager window around */
  195.   g_snprintf (buffer, sizeof (buffer),
  196.       "_NET_SYSTEM_TRAY_S%d",
  197.       XScreenNumberOfScreen (xscreen));
  198.   
  199.   icon->selection_atom = XInternAtom (DisplayOfScreen (xscreen),
  200.       buffer, False);
  201.   
  202.   icon->manager_atom = XInternAtom (DisplayOfScreen (xscreen),
  203.     "MANAGER", False);
  204.   
  205.   icon->system_tray_opcode_atom = XInternAtom (DisplayOfScreen (xscreen),
  206.        "_NET_SYSTEM_TRAY_OPCODE", False);
  207.   egg_tray_icon_update_manager_window (icon);
  208. #if HAVE_GTK_MULTIHEAD
  209.   root_window = gdk_screen_get_root_window (screen);
  210. #else
  211.   root_window = gdk_window_lookup (gdk_x11_get_default_root_xwindow ());
  212. #endif
  213.   
  214.   /* Add a root window filter so that we get changes on MANAGER */
  215.   gdk_window_add_filter (root_window,
  216.  egg_tray_icon_manager_filter, icon);
  217.       
  218.   return icon;
  219. }
  220. #if HAVE_GTK_MULTIHEAD
  221. EggTrayIcon *
  222. egg_tray_icon_new_for_screen (GdkScreen *screen, const char *name)
  223. {
  224.   EggTrayIcon *icon;
  225.   char buffer[256];
  226.   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
  227.   return egg_tray_icon_new_for_xscreen (GDK_SCREEN_XSCREEN (screen), name);
  228. }
  229. #endif
  230. EggTrayIcon*
  231. egg_tray_icon_new (const gchar *name)
  232. {
  233.   return egg_tray_icon_new_for_xscreen (DefaultScreenOfDisplay (gdk_display), name);
  234. }
  235. guint
  236. egg_tray_icon_send_message (EggTrayIcon *icon,
  237.     gint         timeout,
  238.     const gchar *message,
  239.     gint         len)
  240. {
  241.   guint stamp;
  242.   
  243.   g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), 0);
  244.   g_return_val_if_fail (timeout >= 0, 0);
  245.   g_return_val_if_fail (message != NULL, 0);
  246.      
  247.   if (icon->manager_window == None)
  248.     return 0;
  249.   if (len < 0)
  250.     len = strlen (message);
  251.   stamp = icon->stamp++;
  252.   
  253.   /* Get ready to send the message */
  254.   egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_BEGIN_MESSAGE,
  255.       (Window)gtk_plug_get_id (GTK_PLUG (icon)),
  256.       timeout, len, stamp);
  257.   /* Now to send the actual message */
  258.   gdk_error_trap_push ();
  259.   while (len > 0)
  260.     {
  261.       XClientMessageEvent ev;
  262.       Display *xdisplay;
  263. #if HAVE_GTK_MULTIHEAD
  264.       xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
  265. #else
  266.       xdisplay = gdk_display;
  267. #endif
  268.       
  269.       ev.type = ClientMessage;
  270.       ev.window = (Window)gtk_plug_get_id (GTK_PLUG (icon));
  271.       ev.format = 8;
  272.       ev.message_type = XInternAtom (xdisplay,
  273.      "_NET_SYSTEM_TRAY_MESSAGE_DATA", False);
  274.       if (len > 20)
  275. {
  276.   memcpy (&ev.data, message, 20);
  277.   len -= 20;
  278.   message += 20;
  279. }
  280.       else
  281. {
  282.   memcpy (&ev.data, message, len);
  283.   len = 0;
  284. }
  285.       XSendEvent (xdisplay,
  286.   icon->manager_window, False, StructureNotifyMask, (XEvent *)&ev);
  287.       XSync (xdisplay, False);
  288.     }
  289.   gdk_error_trap_pop ();
  290.   return stamp;
  291. }
  292. void
  293. egg_tray_icon_cancel_message (EggTrayIcon *icon,
  294.       guint        id)
  295. {
  296.   g_return_if_fail (EGG_IS_TRAY_ICON (icon));
  297.   g_return_if_fail (id > 0);
  298.   
  299.   egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_CANCEL_MESSAGE,
  300.       (Window)gtk_plug_get_id (GTK_PLUG (icon)),
  301.       id, 0, 0);
  302. }