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 Permission to use this file under wxWindows licence given by 
  26 From andersca@gnu.org Tue Dec  9 13:01:56 2003 
  27 Return-path: <andersca@gnu.org> 
  28 Envelope-to: vasek@localhost 
  29 Delivery-date: Tue, 09 Dec 2003 13:04:35 +0100 
  30 Received: from localhost 
  31         ([127.0.0.1] helo=amavis ident=amavis) 
  32         by armitage with esmtp (Exim 3.35 #1) 
  34         for vasek@localhost; Tue, 09 Dec 2003 13:04:35 +0100 
  35 Received: from armitage ([127.0.0.1]) 
  36         by amavis (armitage [127.0.0.1]) (amavisd-new, port 10024) with ESMTP 
  37         id 04227-09 for <vasek@localhost>; 
  38         Tue, 9 Dec 2003 13:04:11 +0100 (CET) 
  39 Received: from localhost ([127.0.0.1] ident=fetchmail) 
  40         by armitage with esmtp (Exim 3.35 #1) 
  42         for vasek@localhost; Tue, 09 Dec 2003 13:04:11 +0100 
  43 Delivered-To: alias-email-slavikvaclav@seznam.cz 
  44 Received: from pop3.seznam.cz [212.80.76.45] 
  45         by localhost with POP3 (fetchmail-5.9.11) 
  46         for vasek@localhost (single-drop); Tue, 09 Dec 2003 13:04:11 +0100 (CET) 
  47 Received: (qmail 9861 invoked from network); 9 Dec 2003 12:02:17 -0000 
  48 Received: from unknown (HELO maxipes.logix.cz) (81.0.234.97) 
  49   by buster.go.seznam.cz with SMTP; 9 Dec 2003 12:02:17 -0000 
  50 Received: by maxipes.logix.cz (Postfix, from userid 604) 
  51         id 37E6D29A51; Tue,  9 Dec 2003 13:02:16 +0100 (CET) 
  52 X-Original-To: vaclav.slavik@matfyz.cz 
  53 Received: from mail.csbnet.se (glutus.csbnet.se [193.11.248.2]) 
  54         by maxipes.logix.cz (Postfix) with ESMTP id 90D6A29A51 
  55         for <vaclav.slavik@matfyz.cz>; Tue,  9 Dec 2003 13:02:15 +0100 (CET) 
  56 Received: by mail.csbnet.se (Postfix, from userid 8) 
  57         id 7AA7F10A6D7; Tue,  9 Dec 2003 13:02:14 +0100 (CET) 
  58 Received: from carbon.csbnet.se (carbon.csbnet.se [193.11.248.180]) 
  59         by mail.csbnet.se (Postfix) with ESMTP id A190F10A71D 
  60         for <vaclav.slavik@matfyz.cz>; Tue,  9 Dec 2003 13:01:56 +0100 (CET) 
  61 Subject: Re: eggtrayicon.{c,h} licensing 
  62 From: Anders Carlsson <andersca@gnu.org> 
  63 To: Vaclav Slavik <vaclav.slavik@matfyz.cz> 
  64 In-Reply-To: <200312091142.54542.vaclav.slavik@matfyz.cz> 
  65 References: <200312091142.54542.vaclav.slavik@matfyz.cz> 
  66 Content-Type: text/plain 
  67 Message-Id: <1070971316.30989.0.camel@carbon.csbnet.se> 
  69 X-Mailer: Ximian Evolution 1.5  
  70 Date: Tue, 09 Dec 2003 13:01:56 +0100 
  71 Content-Transfer-Encoding: 7bit 
  72 X-Scanned-By: CLAM (openantivirus DB) antivirus scanner at mail.csbnet.se 
  73 X-Virus-Scanned: by amavisd-new-20030616-p5 (Debian) at armitage 
  74 X-Spam-Status: No, hits=-4.9 tagged_above=-999.0 required=6.3 tests=BAYES_00 
  78 X-KMail-EncryptionState:   
  79 X-KMail-SignatureState:   
  81 On tis, 2003-12-09 at 11:42 +0100, Vaclav Slavik wrote: 
  84 > I'm working on the wxWindows cross-platform GUI toolkit  
  85 > (http://www.wxwindows.org) which uses GTK+ and it would save me a lot  
  86 > of time if I could use your eggtrayicon code to implement tray icons  
  87 > on X11. Unfortunately I can't use it right now because it is not part  
  88 > of any library we could depend on (as we do depend on GTK+) and would  
  89 > have to be included in our sources and it is under the LGPL license.  
  90 > The problem is that wxWindows' license is more permissive (see  
  91 > http://www.opensource.org/licenses/wxwindows.php for details) and so  
  92 > I can't take your code and put it under wxWindows licence. And I 
  93 > can't put code that can't be used under the terms of wxWindows  
  94 > License into wxWindows either. Do you think it would be possible to  
  95 > get permission to include eggtrayicon under wxWindows licence? 
 101 Sure, that's fine by me. 
 107 #include "wx/platform.h" 
 109 #include <gdk/gdkx.h> 
 112 #include <gtk/gtkversion.h> 
 113 #if GTK_CHECK_VERSION(2, 1, 0) 
 116 #include "eggtrayicon.h" 
 118 #define SYSTEM_TRAY_REQUEST_DOCK    0 
 119 #define SYSTEM_TRAY_BEGIN_MESSAGE   1 
 120 #define SYSTEM_TRAY_CANCEL_MESSAGE  2 
 122 static GtkPlugClass 
*parent_class 
= NULL
; 
 124 static void egg_tray_icon_init (EggTrayIcon 
*icon
); 
 125 static void egg_tray_icon_class_init (EggTrayIconClass 
*klass
); 
 127 static void egg_tray_icon_unrealize (GtkWidget 
*widget
); 
 129 static void egg_tray_icon_update_manager_window (EggTrayIcon 
*icon
); 
 132 egg_tray_icon_get_type (void) 
 134   static GType our_type 
= 0; 
 138       const GTypeInfo our_info 
= 
 140         sizeof (EggTrayIconClass
), 
 141         (GBaseInitFunc
) NULL
, 
 142         (GBaseFinalizeFunc
) NULL
, 
 143         (GClassInitFunc
) egg_tray_icon_class_init
, 
 144         NULL
, /* class_finalize */ 
 145         NULL
, /* class_data */ 
 146         sizeof (EggTrayIcon
), 
 148         (GInstanceInitFunc
) egg_tray_icon_init
 
 151       our_type 
= g_type_register_static (GTK_TYPE_PLUG
, "EggTrayIcon", 
 152                                           &our_info
, (GTypeFlags
)0); 
 159 egg_tray_icon_init (EggTrayIcon 
*icon
) 
 163   gtk_widget_add_events (GTK_WIDGET (icon
), GDK_PROPERTY_CHANGE_MASK
); 
 167 egg_tray_icon_class_init (EggTrayIconClass 
*klass
) 
 169   GtkWidgetClass 
*widget_class 
= (GtkWidgetClass 
*)klass
; 
 171   parent_class 
= g_type_class_peek_parent (klass
); 
 173   widget_class
->unrealize 
= egg_tray_icon_unrealize
; 
 176 static GdkFilterReturn
 
 177 egg_tray_icon_manager_filter (GdkXEvent 
*xevent
, GdkEvent 
*event
, gpointer user_data
) 
 179   EggTrayIcon 
*icon 
= user_data
; 
 180   XEvent 
*xev 
= (XEvent 
*)xevent
; 
 182   if (xev
->xany
.type 
== ClientMessage 
&& 
 183       xev
->xclient
.message_type 
== icon
->manager_atom 
&& 
 184       xev
->xclient
.data
.l
[1] == icon
->selection_atom
) 
 186       egg_tray_icon_update_manager_window (icon
); 
 188   else if (xev
->xany
.window 
== icon
->manager_window
) 
 190       if (xev
->xany
.type 
== DestroyNotify
) 
 192           egg_tray_icon_update_manager_window (icon
); 
 196   return GDK_FILTER_CONTINUE
; 
 200 egg_tray_icon_unrealize (GtkWidget 
*widget
) 
 202   EggTrayIcon 
*icon 
= EGG_TRAY_ICON (widget
); 
 203   GdkWindow 
*root_window
; 
 205   if (icon
->manager_window 
!= None
) 
 209       gdkwin 
= gdk_window_lookup_for_display (gtk_widget_get_display (widget
), 
 210                                               icon
->manager_window
); 
 212       gdk_window_remove_filter (gdkwin
, egg_tray_icon_manager_filter
, icon
); 
 215   root_window 
= gdk_screen_get_root_window (gtk_widget_get_screen (widget
)); 
 217   gdk_window_remove_filter (root_window
, egg_tray_icon_manager_filter
, icon
); 
 219   if (GTK_WIDGET_CLASS (parent_class
)->unrealize
) 
 220     (* GTK_WIDGET_CLASS (parent_class
)->unrealize
) (widget
); 
 224 egg_tray_icon_send_manager_message (EggTrayIcon 
*icon
, 
 231   XClientMessageEvent ev
; 
 234   ev
.type 
= ClientMessage
; 
 236   ev
.message_type 
= icon
->system_tray_opcode_atom
; 
 238   ev
.data
.l
[0] = gdk_x11_get_server_time (GTK_WIDGET (icon
)->window
); 
 239   ev
.data
.l
[1] = message
; 
 240   ev
.data
.l
[2] = data1
; 
 241   ev
.data
.l
[3] = data2
; 
 242   ev
.data
.l
[4] = data3
; 
 244   display 
= GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon
))); 
 246   gdk_error_trap_push (); 
 248               icon
->manager_window
, False
, NoEventMask
, (XEvent 
*)&ev
); 
 249   XSync (display
, False
); 
 250   gdk_error_trap_pop (); 
 254 egg_tray_icon_send_dock_request (EggTrayIcon 
*icon
) 
 256   egg_tray_icon_send_manager_message (icon
, 
 257                                       SYSTEM_TRAY_REQUEST_DOCK
, 
 258                                       icon
->manager_window
, 
 259                                       gtk_plug_get_id (GTK_PLUG (icon
)), 
 264 egg_tray_icon_update_manager_window (EggTrayIcon 
*icon
) 
 268   xdisplay 
= GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon
))); 
 270   if (icon
->manager_window 
!= None
) 
 274       gdkwin 
= gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon
)), 
 275                                               icon
->manager_window
); 
 277       gdk_window_remove_filter (gdkwin
, egg_tray_icon_manager_filter
, icon
); 
 280   XGrabServer (xdisplay
); 
 282   icon
->manager_window 
= XGetSelectionOwner (xdisplay
, 
 283                                              icon
->selection_atom
); 
 285   if (icon
->manager_window 
!= None
) 
 286     XSelectInput (xdisplay
, 
 287                   icon
->manager_window
, StructureNotifyMask
); 
 289   XUngrabServer (xdisplay
); 
 292   if (icon
->manager_window 
!= None
) 
 296       gdkwin 
= gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon
)), 
 297                                               icon
->manager_window
); 
 299       gdk_window_add_filter (gdkwin
, egg_tray_icon_manager_filter
, icon
); 
 301       /* Send a request that we'd like to dock */ 
 302       egg_tray_icon_send_dock_request (icon
); 
 307 egg_tray_icon_new_for_xscreen (Screen 
*xscreen
, const char *name
) 
 311   GdkWindow 
*root_window
; 
 315   g_return_val_if_fail (xscreen 
!= NULL
, NULL
); 
 317   icon 
= g_object_new (EGG_TYPE_TRAY_ICON
, NULL
); 
 318   gtk_window_set_title (GTK_WINDOW (icon
), name
); 
 320   display 
= gdk_x11_lookup_xdisplay (DisplayOfScreen (xscreen
)); 
 321   screen 
= gdk_display_get_screen (display
, XScreenNumberOfScreen (xscreen
)); 
 323   gtk_plug_construct_for_display (GTK_PLUG (icon
), 
 326   gtk_window_set_screen (GTK_WINDOW (icon
), screen
);      
 328   gtk_widget_realize (GTK_WIDGET (icon
)); 
 330   /* Now see if there's a manager window around */ 
 331   g_snprintf (buffer
, sizeof (buffer
), 
 332               "_NET_SYSTEM_TRAY_S%d", 
 333               XScreenNumberOfScreen (xscreen
)); 
 335   icon
->selection_atom 
= XInternAtom (DisplayOfScreen (xscreen
), 
 338   icon
->manager_atom 
= XInternAtom (DisplayOfScreen (xscreen
), 
 341   icon
->system_tray_opcode_atom 
= XInternAtom (DisplayOfScreen (xscreen
), 
 342                                                "_NET_SYSTEM_TRAY_OPCODE", False
); 
 344   egg_tray_icon_update_manager_window (icon
); 
 346   root_window 
= gdk_screen_get_root_window (gtk_widget_get_screen (GTK_WIDGET (icon
))); 
 348   /* Add a root window filter so that we get changes on MANAGER */ 
 349   gdk_window_add_filter (root_window
, 
 350                          egg_tray_icon_manager_filter
, icon
); 
 356 egg_tray_icon_new_for_screen (GdkScreen 
*screen
, const char *name
) 
 358   g_return_val_if_fail (GDK_IS_SCREEN (screen
), NULL
); 
 360   return egg_tray_icon_new_for_xscreen (GDK_SCREEN_XSCREEN (screen
), name
); 
 364 egg_tray_icon_new (const gchar 
*name
) 
 366   return egg_tray_icon_new_for_xscreen (DefaultScreenOfDisplay (gdk_display
), name
); 
 370 egg_tray_icon_send_message (EggTrayIcon 
*icon
, 
 372                             const gchar 
*message
, 
 377   g_return_val_if_fail (EGG_IS_TRAY_ICON (icon
), 0); 
 378   g_return_val_if_fail (timeout 
>= 0, 0); 
 379   g_return_val_if_fail (message 
!= NULL
, 0); 
 381   if (icon
->manager_window 
== None
) 
 385     len 
= strlen (message
); 
 387   stamp 
= icon
->stamp
++; 
 389   /* Get ready to send the message */ 
 390   egg_tray_icon_send_manager_message (icon
, SYSTEM_TRAY_BEGIN_MESSAGE
, 
 391                                       (Window
)gtk_plug_get_id (GTK_PLUG (icon
)), 
 392                                       timeout
, len
, stamp
); 
 394   /* Now to send the actual message */ 
 395   gdk_error_trap_push (); 
 398       XClientMessageEvent ev
; 
 401       xdisplay 
= GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon
))); 
 403       ev
.type 
= ClientMessage
; 
 404       ev
.window 
= (Window
)gtk_plug_get_id (GTK_PLUG (icon
)); 
 406       ev
.message_type 
= XInternAtom (xdisplay
, 
 407                                      "_NET_SYSTEM_TRAY_MESSAGE_DATA", False
); 
 410           memcpy (&ev
.data
, message
, 20); 
 416           memcpy (&ev
.data
, message
, len
); 
 420       XSendEvent (xdisplay
, 
 421                   icon
->manager_window
, False
, StructureNotifyMask
, (XEvent 
*)&ev
); 
 422       XSync (xdisplay
, False
); 
 424   gdk_error_trap_pop (); 
 430 egg_tray_icon_cancel_message (EggTrayIcon 
*icon
, 
 433   g_return_if_fail (EGG_IS_TRAY_ICON (icon
)); 
 434   g_return_if_fail (id 
> 0); 
 436   egg_tray_icon_send_manager_message (icon
, SYSTEM_TRAY_CANCEL_MESSAGE
, 
 437                                       (Window
)gtk_plug_get_id (GTK_PLUG (icon
)), 
 441 #endif /* __WXGTK20__ */ 
 442 #endif /* GTK_CHECK_VERSION(2, 1, 0) */