]> git.saurik.com Git - wxWidgets.git/commitdiff
implemented freedesktop.org spec support for GTK version of wxTaskBarIcon
authorVáclav Slavík <vslavik@fastmail.fm>
Mon, 31 May 2004 22:17:09 +0000 (22:17 +0000)
committerVáclav Slavík <vslavik@fastmail.fm>
Mon, 31 May 2004 22:17:09 +0000 (22:17 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@27544 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

13 files changed:
Makefile.in
build/bakefiles/files.bkl
docs/changes.txt
docs/latex/wx/taskbar.tex
include/wx/gtk/taskbarpriv.h [new file with mode: 0644]
include/wx/gtk1/taskbarpriv.h [new file with mode: 0644]
src/gtk/eggtrayicon.c [new file with mode: 0644]
src/gtk/eggtrayicon.h [new file with mode: 0644]
src/gtk/taskbar.cpp [new file with mode: 0644]
src/gtk1/eggtrayicon.c [new file with mode: 0644]
src/gtk1/eggtrayicon.h [new file with mode: 0644]
src/gtk1/taskbar.cpp [new file with mode: 0644]
src/unix/taskbarx11.cpp

index 8e5eec404d354009ef66a91991c5645d193a82f6..fa5905460dde71953568d5900e9d0b7e7fa1204d 100644 (file)
@@ -822,6 +822,10 @@ CORELIB_OBJECTS =  \
        $(__BASE_AND_GUI_TOOLKIT_SRC_OBJECTS_5) \
        $(__CORE_SRC_OBJECTS_3)
 CORELIB_ODEP =  $(___pch_wxprec_corelib_wx_wxprec_h_gch___depname)
+ADVDLL_CFLAGS = $(__advdll_PCH_INC) -D__WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p) \
+       $(__INC_TIFF_p) $(__INC_JPEG_p) $(__INC_PNG_p) $(__INC_ZLIB_p) \
+       $(__INC_ODBC_p) $(__INC_REGEX_p) $(__INC_EXPAT_p) -DWXUSINGDLL \
+       -DWXMAKINGDLL_ADV $(PIC_FLAG) $(CPPFLAGS) $(CFLAGS)
 ADVDLL_CXXFLAGS = $(__advdll_PCH_INC) -D__WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p) \
        $(__INC_TIFF_p) $(__INC_JPEG_p) $(__INC_PNG_p) $(__INC_ZLIB_p) \
        $(__INC_ODBC_p) $(__INC_REGEX_p) $(__INC_EXPAT_p) -DWXUSINGDLL \
@@ -840,6 +844,9 @@ ADVDLL_OBJECTS =  \
        $(__ADVANCED_PLATFORM_SRC_OBJECTS_2) \
        $(__PLUGIN_ADV_SRC_OBJECTS_2)
 ADVDLL_ODEP =  $(___pch_wxprec_advdll_wx_wxprec_h_gch___depname)
+ADVLIB_CFLAGS = $(__advlib_PCH_INC) -D__WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p) \
+       $(__INC_TIFF_p) $(__INC_JPEG_p) $(__INC_PNG_p) $(__INC_ZLIB_p) \
+       $(__INC_ODBC_p) $(__INC_REGEX_p) $(__INC_EXPAT_p) $(CPPFLAGS) $(CFLAGS)
 ADVLIB_CXXFLAGS = $(__advlib_PCH_INC) -D__WX$(TOOLKIT)__ $(__WXUNIV_DEFINE_p) \
        $(__INC_TIFF_p) $(__INC_JPEG_p) $(__INC_PNG_p) $(__INC_ZLIB_p) \
        $(__INC_ODBC_p) $(__INC_REGEX_p) $(__INC_EXPAT_p) $(CPPFLAGS) $(CXXFLAGS)
@@ -3021,7 +3028,9 @@ COND_TOOLKIT_GTK___ADVANCED_PLATFORM_SRC_OBJECTS =  \
        monodll_taskbarcmn.o \
        monodll_joystick.o \
        monodll_sound.o \
-       monodll_taskbarx11.o
+       monodll_taskbarx11.o \
+       monodll_taskbar.o \
+       monodll_eggtrayicon.o
 @COND_TOOLKIT_GTK@__ADVANCED_PLATFORM_SRC_OBJECTS = $(COND_TOOLKIT_GTK___ADVANCED_PLATFORM_SRC_OBJECTS)
 @COND_TOOLKIT_MAC@__ADVANCED_PLATFORM_SRC_OBJECTS = \
 @COND_TOOLKIT_MAC@     monodll_joystick.o monodll_sound.o
@@ -3877,7 +3886,9 @@ COND_TOOLKIT_GTK___ADVANCED_PLATFORM_SRC_OBJECTS_1 =  \
        monolib_taskbarcmn.o \
        monolib_joystick.o \
        monolib_sound.o \
-       monolib_taskbarx11.o
+       monolib_taskbarx11.o \
+       monolib_taskbar.o \
+       monolib_eggtrayicon.o
 @COND_TOOLKIT_GTK@__ADVANCED_PLATFORM_SRC_OBJECTS_1 = $(COND_TOOLKIT_GTK___ADVANCED_PLATFORM_SRC_OBJECTS_1)
 @COND_TOOLKIT_MAC@__ADVANCED_PLATFORM_SRC_OBJECTS_1 = \
 @COND_TOOLKIT_MAC@     monolib_joystick.o monolib_sound.o
@@ -5669,9 +5680,14 @@ COND_USE_SOSYMLINKS_1___advdll___so_symlinks_inst_cmd = rm -f \
        $(DLLPREFIX)$(WXDLLNAMEPREFIXGUI)$(WXUNICODEFLAG)$(WXDEBUGFLAG)_adv$(WXCOMPILER)$(VENDORTAG)$(WXDLLVERSIONTAG)$(dll___targetsuf2) \
        $(LIBPREFIX)wx_$(PORTNAME)$(WXUNIVNAME)$(WXUNICODEFLAG)$(WXDEBUGFLAG)_adv-2.5$(HOST_SUFFIX).$(DLLIMP_SUFFIX)
 @COND_USE_SOSYMLINKS_1@__advdll___so_symlinks_inst_cmd = $(COND_USE_SOSYMLINKS_1___advdll___so_symlinks_inst_cmd)
-@COND_TOOLKIT_GTK@__ADVANCED_PLATFORM_SRC_OBJECTS_2 = \
-@COND_TOOLKIT_GTK@     advdll_taskbarcmn.o advdll_joystick.o advdll_sound.o \
-@COND_TOOLKIT_GTK@     advdll_taskbarx11.o
+COND_TOOLKIT_GTK___ADVANCED_PLATFORM_SRC_OBJECTS_2 =  \
+       advdll_taskbarcmn.o \
+       advdll_joystick.o \
+       advdll_sound.o \
+       advdll_taskbarx11.o \
+       advdll_taskbar.o \
+       advdll_eggtrayicon.o
+@COND_TOOLKIT_GTK@__ADVANCED_PLATFORM_SRC_OBJECTS_2 = $(COND_TOOLKIT_GTK___ADVANCED_PLATFORM_SRC_OBJECTS_2)
 @COND_TOOLKIT_MAC@__ADVANCED_PLATFORM_SRC_OBJECTS_2 = \
 @COND_TOOLKIT_MAC@     advdll_joystick.o advdll_sound.o
 @COND_TOOLKIT_MOTIF@__ADVANCED_PLATFORM_SRC_OBJECTS_2 = \
@@ -5697,9 +5713,14 @@ COND_MONOLITHIC_0_SHARED_0_USE_GUI_1___advlib___depname = \
 @COND_GCC_PCH_1@__advlib_PCH_INC = -I.pch/wxprec_advlib
 @COND_GCC_PCH_1@___pch_wxprec_advlib_wx_wxprec_h_gch___depname \
 @COND_GCC_PCH_1@       = .pch/wxprec_advlib/wx/wxprec.h.gch
-@COND_TOOLKIT_GTK@__ADVANCED_PLATFORM_SRC_OBJECTS_3 = \
-@COND_TOOLKIT_GTK@     advlib_taskbarcmn.o advlib_joystick.o advlib_sound.o \
-@COND_TOOLKIT_GTK@     advlib_taskbarx11.o
+COND_TOOLKIT_GTK___ADVANCED_PLATFORM_SRC_OBJECTS_3 =  \
+       advlib_taskbarcmn.o \
+       advlib_joystick.o \
+       advlib_sound.o \
+       advlib_taskbarx11.o \
+       advlib_taskbar.o \
+       advlib_eggtrayicon.o
+@COND_TOOLKIT_GTK@__ADVANCED_PLATFORM_SRC_OBJECTS_3 = $(COND_TOOLKIT_GTK___ADVANCED_PLATFORM_SRC_OBJECTS_3)
 @COND_TOOLKIT_MAC@__ADVANCED_PLATFORM_SRC_OBJECTS_3 = \
 @COND_TOOLKIT_MAC@     advlib_joystick.o advlib_sound.o
 @COND_TOOLKIT_MOTIF@__ADVANCED_PLATFORM_SRC_OBJECTS_3 = \
@@ -8213,6 +8234,9 @@ monodll_tipdlg.o: $(srcdir)/src/generic/tipdlg.cpp $(MONODLL_ODEP)
 monodll_wizard.o: $(srcdir)/src/generic/wizard.cpp $(MONODLL_ODEP)
        $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $<
 
+monodll_eggtrayicon.o: $(srcdir)/src/gtk/eggtrayicon.c $(MONODLL_ODEP)
+       $(CCC) -c -o $@ $(MONODLL_CFLAGS) $<
+
 monodll_helpbest.o: $(srcdir)/src/msw/helpbest.cpp $(MONODLL_ODEP)
        $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $<
 
@@ -10697,6 +10721,9 @@ monodll_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(MONODLL_ODEP)
 @COND_TOOLKIT_WINCE_USE_GUI_1@monodll_taskbar.o: $(srcdir)/src/msw/taskbar.cpp $(MONODLL_ODEP)
 @COND_TOOLKIT_WINCE_USE_GUI_1@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $<
 
+@COND_TOOLKIT_GTK_USE_GUI_1@monodll_taskbar.o: $(srcdir)/src/gtk/taskbar.cpp $(MONODLL_ODEP)
+@COND_TOOLKIT_GTK_USE_GUI_1@   $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $<
+
 @COND_TOOLKIT_MSW_USE_GUI_1@monodll_joystick.o: $(srcdir)/src/msw/joystick.cpp $(MONODLL_ODEP)
 @COND_TOOLKIT_MSW_USE_GUI_1@   $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $<
 
@@ -11144,6 +11171,9 @@ monolib_tipdlg.o: $(srcdir)/src/generic/tipdlg.cpp $(MONOLIB_ODEP)
 monolib_wizard.o: $(srcdir)/src/generic/wizard.cpp $(MONOLIB_ODEP)
        $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $<
 
+monolib_eggtrayicon.o: $(srcdir)/src/gtk/eggtrayicon.c $(MONOLIB_ODEP)
+       $(CCC) -c -o $@ $(MONOLIB_CFLAGS) $<
+
 monolib_helpbest.o: $(srcdir)/src/msw/helpbest.cpp $(MONOLIB_ODEP)
        $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $<
 
@@ -13628,6 +13658,9 @@ monolib_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(MONOLIB_ODEP)
 @COND_TOOLKIT_WINCE_USE_GUI_1@monolib_taskbar.o: $(srcdir)/src/msw/taskbar.cpp $(MONOLIB_ODEP)
 @COND_TOOLKIT_WINCE_USE_GUI_1@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $<
 
+@COND_TOOLKIT_GTK_USE_GUI_1@monolib_taskbar.o: $(srcdir)/src/gtk/taskbar.cpp $(MONOLIB_ODEP)
+@COND_TOOLKIT_GTK_USE_GUI_1@   $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $<
+
 @COND_TOOLKIT_MSW_USE_GUI_1@monolib_joystick.o: $(srcdir)/src/msw/joystick.cpp $(MONOLIB_ODEP)
 @COND_TOOLKIT_MSW_USE_GUI_1@   $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $<
 
@@ -19241,6 +19274,9 @@ advdll_tipdlg.o: $(srcdir)/src/generic/tipdlg.cpp $(ADVDLL_ODEP)
 advdll_wizard.o: $(srcdir)/src/generic/wizard.cpp $(ADVDLL_ODEP)
        $(CXXC) -c -o $@ $(ADVDLL_CXXFLAGS) $<
 
+advdll_eggtrayicon.o: $(srcdir)/src/gtk/eggtrayicon.c $(ADVDLL_ODEP)
+       $(CCC) -c -o $@ $(ADVDLL_CFLAGS) $<
+
 advdll_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(ADVDLL_ODEP)
        $(CXXC) -c -o $@ $(ADVDLL_CXXFLAGS) $<
 
@@ -19286,6 +19322,9 @@ advdll_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(ADVDLL_ODEP)
 @COND_TOOLKIT_WINCE@advdll_taskbar.o: $(srcdir)/src/msw/taskbar.cpp $(ADVDLL_ODEP)
 @COND_TOOLKIT_WINCE@   $(CXXC) -c -o $@ $(ADVDLL_CXXFLAGS) $<
 
+@COND_TOOLKIT_GTK@advdll_taskbar.o: $(srcdir)/src/gtk/taskbar.cpp $(ADVDLL_ODEP)
+@COND_TOOLKIT_GTK@     $(CXXC) -c -o $@ $(ADVDLL_CXXFLAGS) $<
+
 @COND_TOOLKIT_MSW@advdll_joystick.o: $(srcdir)/src/msw/joystick.cpp $(ADVDLL_ODEP)
 @COND_TOOLKIT_MSW@     $(CXXC) -c -o $@ $(ADVDLL_CXXFLAGS) $<
 
@@ -19343,6 +19382,9 @@ advlib_tipdlg.o: $(srcdir)/src/generic/tipdlg.cpp $(ADVLIB_ODEP)
 advlib_wizard.o: $(srcdir)/src/generic/wizard.cpp $(ADVLIB_ODEP)
        $(CXXC) -c -o $@ $(ADVLIB_CXXFLAGS) $<
 
+advlib_eggtrayicon.o: $(srcdir)/src/gtk/eggtrayicon.c $(ADVLIB_ODEP)
+       $(CCC) -c -o $@ $(ADVLIB_CFLAGS) $<
+
 advlib_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(ADVLIB_ODEP)
        $(CXXC) -c -o $@ $(ADVLIB_CXXFLAGS) $<
 
@@ -19388,6 +19430,9 @@ advlib_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(ADVLIB_ODEP)
 @COND_TOOLKIT_WINCE@advlib_taskbar.o: $(srcdir)/src/msw/taskbar.cpp $(ADVLIB_ODEP)
 @COND_TOOLKIT_WINCE@   $(CXXC) -c -o $@ $(ADVLIB_CXXFLAGS) $<
 
+@COND_TOOLKIT_GTK@advlib_taskbar.o: $(srcdir)/src/gtk/taskbar.cpp $(ADVLIB_ODEP)
+@COND_TOOLKIT_GTK@     $(CXXC) -c -o $@ $(ADVLIB_CXXFLAGS) $<
+
 @COND_TOOLKIT_MSW@advlib_joystick.o: $(srcdir)/src/msw/joystick.cpp $(ADVLIB_ODEP)
 @COND_TOOLKIT_MSW@     $(CXXC) -c -o $@ $(ADVLIB_CXXFLAGS) $<
 
index 6cf2c5159d4b3db1e013212d2dab840e9c9bedd4..bbf0ec23eebda61fdebf7c9b1bfb75f79df895b3 100644 (file)
@@ -2196,6 +2196,11 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file!
     wx/unix/taskbarx11.h
 </set>
 
+<set var="ADVANCED_GTK_SRC" hints="files">
+    src/gtk/taskbar.cpp
+    src/gtk/eggtrayicon.c
+</set>
+
 
 <!-- ====================================================================== -->
 <!--                               wxHTML                                   -->
@@ -2450,7 +2455,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file!
         <if cond="TOOLKIT=='WINCE'">$(ADVANCED_MSW_SRC)</if>
         <if cond="TOOLKIT=='MAC'">$(ADVANCED_MAC_SRC)</if>
         <if cond="TOOLKIT=='MOTIF'">$(ADVANCED_UNIX_SRC)</if>
-        <if cond="TOOLKIT=='GTK'">$(ADVANCED_UNIX_SRC)</if>
+        <if cond="TOOLKIT=='GTK'">$(ADVANCED_UNIX_SRC) $(ADVANCED_GTK_SRC)</if>
         <if cond="TOOLKIT=='X11'">$(ADVANCED_UNIX_SRC)</if>
         <if cond="TOOLKIT=='PM'">$(ADVANCED_OS2_SRC)</if>
     </set>
index 3db3c9ce6a000464948bfecb59c50ccc4606c3b4..ff33354dd864b0d8842678e78a6666077702219e 100644 (file)
@@ -94,6 +94,14 @@ versions, please update your code to not use them.
 OTHER CHANGES
 =============
 
+2.5.3
+-----
+
+Unix:
+
+- wxTaskBarIcon now supports freedesktop.org System Tray protocol
+
+
 2.5.2
 -----
 
@@ -162,10 +170,12 @@ wxHTML:
 - <div> handling fix (Xavier Nodet)
 
 Unix:
+
 - fixed priorities of mailcap entries (David Hart)
 - added "wx-config --libs=std,<extra>" syntax (i.e. support for "std")
 
 wxODBC:
+
 - Full Unicode support is now available
 - BLOB support is working
 
index 2e63b1e38a936fb01a9808e64dae18c3769b5a1e..c560b0297c0ed7ad29fe14e150a915f879437181 100644 (file)
@@ -1,9 +1,25 @@
 \section{\class{wxTaskBarIcon}}\label{wxtaskbaricon}
 
-This class represents a taskbar icon, appearing in the `system tray' and responding to
-mouse clicks. An icon has an optional tooltip. This class is only supported for Windows 95/NT and for
-X Window System ports (wxGTK, wxMotif, wxX11), assuming the window manager supports KDE and GNOME 1.2
-systray methods.
+This class represents a taskbar icon, appearing in the `system tray' and
+responding to mouse clicks. An icon has an optional tooltip. This class is only
+supported under Windows 95/NT and in X Window System ports (wxGTK, wxMotif,
+wxX11). 
+
+\wxheading{X Window System Note}
+
+Under X Window System, the window manager must support either
+the \urlref{System Tray Protocol by freedesktop.org}{http://freedesktop.org/Standards/systemtray-spec}
+(WMs used by modern desktop environments such as GNOME >= 2, KDE
+>= 3 and XFCE >= 4 all do) or the older methods used in GNOME 1.2 and
+KDE 1 and 2. If it doesn't, the icon will appear as a toplevel window on
+user's desktop.
+
+Because not all window managers have system tray, there's no guarantee that
+wxTaskBarIcon will work correctly under X Window System and so the applications
+should use it only as an optional component of their user interface. The user
+should be required to explicitly enable the taskbar icon on Unix, it shouldn't
+be on by default.
+
 
 \wxheading{Derived from}
 
diff --git a/include/wx/gtk/taskbarpriv.h b/include/wx/gtk/taskbarpriv.h
new file mode 100644 (file)
index 0000000..117e4cd
--- /dev/null
@@ -0,0 +1,31 @@
+/////////////////////////////////////////////////////////////////////////
+// File:        wx/gtk/taskbarpriv.h
+// Purpose:     wxTaskBarIcon (src/unix/taskbarx11.cpp) helper for GTK2
+// Author:      Vaclav Slavik
+// Modified by:
+// Created:     2004/05/29
+// RCS-ID:      $Id$
+// Copyright:   (c) Vaclav Slavik, 2004
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_TASKBARPRIV_H_
+#define _WX_TASKBARPRIV_H_
+
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
+#pragma interface "taskbarpriv.h"
+#endif
+
+#include "wx/toplevel.h"
+#include "wx/bitmap.h"
+
+class WXDLLIMPEXP_ADV wxTaskBarIconAreaBase : public wxTopLevelWindow
+{
+public:
+    wxTaskBarIconAreaBase();
+
+    // Returns true if SYSTRAY protocol is supported by the desktop
+    bool IsProtocolSupported();
+};
+
+#endif // _WX_TASKBARPRIV_H_
diff --git a/include/wx/gtk1/taskbarpriv.h b/include/wx/gtk1/taskbarpriv.h
new file mode 100644 (file)
index 0000000..117e4cd
--- /dev/null
@@ -0,0 +1,31 @@
+/////////////////////////////////////////////////////////////////////////
+// File:        wx/gtk/taskbarpriv.h
+// Purpose:     wxTaskBarIcon (src/unix/taskbarx11.cpp) helper for GTK2
+// Author:      Vaclav Slavik
+// Modified by:
+// Created:     2004/05/29
+// RCS-ID:      $Id$
+// Copyright:   (c) Vaclav Slavik, 2004
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_TASKBARPRIV_H_
+#define _WX_TASKBARPRIV_H_
+
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
+#pragma interface "taskbarpriv.h"
+#endif
+
+#include "wx/toplevel.h"
+#include "wx/bitmap.h"
+
+class WXDLLIMPEXP_ADV wxTaskBarIconAreaBase : public wxTopLevelWindow
+{
+public:
+    wxTaskBarIconAreaBase();
+
+    // Returns true if SYSTRAY protocol is supported by the desktop
+    bool IsProtocolSupported();
+};
+
+#endif // _WX_TASKBARPRIV_H_
diff --git a/src/gtk/eggtrayicon.c b/src/gtk/eggtrayicon.c
new file mode 100644 (file)
index 0000000..416a648
--- /dev/null
@@ -0,0 +1,345 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* eggtrayicon.c
+ * Copyright (C) 2002 Anders Carlsson <andersca@gnu.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <gdk/gdkx.h>
+#include "eggtrayicon.h"
+
+#define SYSTEM_TRAY_REQUEST_DOCK    0
+#define SYSTEM_TRAY_BEGIN_MESSAGE   1
+#define SYSTEM_TRAY_CANCEL_MESSAGE  2
+         
+static GtkPlugClass *parent_class = NULL;
+
+static void egg_tray_icon_init (EggTrayIcon *icon);
+static void egg_tray_icon_class_init (EggTrayIconClass *klass);
+
+static void egg_tray_icon_unrealize (GtkWidget *widget);
+
+static void egg_tray_icon_update_manager_window (EggTrayIcon *icon);
+
+GType
+egg_tray_icon_get_type (void)
+{
+  static GType our_type = 0;
+
+  if (our_type == 0)
+    {
+      static const GTypeInfo our_info =
+      {
+       sizeof (EggTrayIconClass),
+       (GBaseInitFunc) NULL,
+       (GBaseFinalizeFunc) NULL,
+       (GClassInitFunc) egg_tray_icon_class_init,
+       NULL, /* class_finalize */
+       NULL, /* class_data */
+       sizeof (EggTrayIcon),
+       0,    /* n_preallocs */
+       (GInstanceInitFunc) egg_tray_icon_init
+      };
+
+      our_type = g_type_register_static (GTK_TYPE_PLUG, "EggTrayIcon", &our_info, 0);
+    }
+
+  return our_type;
+}
+
+static void
+egg_tray_icon_init (EggTrayIcon *icon)
+{
+  icon->stamp = 1;
+  
+  gtk_widget_add_events (GTK_WIDGET (icon), GDK_PROPERTY_CHANGE_MASK);
+}
+
+static void
+egg_tray_icon_class_init (EggTrayIconClass *klass)
+{
+  GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  widget_class->unrealize = egg_tray_icon_unrealize;
+}
+
+static GdkFilterReturn
+egg_tray_icon_manager_filter (GdkXEvent *xevent, GdkEvent *event, gpointer user_data)
+{
+  EggTrayIcon *icon = user_data;
+  XEvent *xev = (XEvent *)xevent;
+
+  if (xev->xany.type == ClientMessage &&
+      xev->xclient.message_type == icon->manager_atom &&
+      xev->xclient.data.l[1] == icon->selection_atom)
+    {
+      egg_tray_icon_update_manager_window (icon);
+    }
+  else if (xev->xany.window == icon->manager_window)
+    {
+      if (xev->xany.type == DestroyNotify)
+       {
+         egg_tray_icon_update_manager_window (icon);
+       }
+    }
+  
+  return GDK_FILTER_CONTINUE;
+}
+
+static void
+egg_tray_icon_unrealize (GtkWidget *widget)
+{
+  EggTrayIcon *icon = EGG_TRAY_ICON (widget);
+  GdkWindow *root_window;
+
+  if (icon->manager_window != None)
+    {
+      GdkWindow *gdkwin;
+
+      gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (widget),
+                                              icon->manager_window);
+
+      gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon);
+    }
+
+  root_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget));
+
+  gdk_window_remove_filter (root_window, egg_tray_icon_manager_filter, icon);
+
+  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
+    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+}
+
+static void
+egg_tray_icon_send_manager_message (EggTrayIcon *icon,
+                                   long         message,
+                                   Window       window,
+                                   long         data1,
+                                   long         data2,
+                                   long         data3)
+{
+  XClientMessageEvent ev;
+  Display *display;
+  
+  ev.type = ClientMessage;
+  ev.window = window;
+  ev.message_type = icon->system_tray_opcode_atom;
+  ev.format = 32;
+  ev.data.l[0] = gdk_x11_get_server_time (GTK_WIDGET (icon)->window);
+  ev.data.l[1] = message;
+  ev.data.l[2] = data1;
+  ev.data.l[3] = data2;
+  ev.data.l[4] = data3;
+
+  display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
+  
+  gdk_error_trap_push ();
+  XSendEvent (display,
+             icon->manager_window, False, NoEventMask, (XEvent *)&ev);
+  XSync (display, False);
+  gdk_error_trap_pop ();
+}
+
+static void
+egg_tray_icon_send_dock_request (EggTrayIcon *icon)
+{
+  egg_tray_icon_send_manager_message (icon,
+                                     SYSTEM_TRAY_REQUEST_DOCK,
+                                     icon->manager_window,
+                                     gtk_plug_get_id (GTK_PLUG (icon)),
+                                     0, 0);
+}
+
+static void
+egg_tray_icon_update_manager_window (EggTrayIcon *icon)
+{
+  Display *xdisplay;
+  
+  xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
+  
+  if (icon->manager_window != None)
+    {
+      GdkWindow *gdkwin;
+
+      gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)),
+                                             icon->manager_window);
+      
+      gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon);
+    }
+  
+  XGrabServer (xdisplay);
+  
+  icon->manager_window = XGetSelectionOwner (xdisplay,
+                                            icon->selection_atom);
+
+  if (icon->manager_window != None)
+    XSelectInput (xdisplay,
+                 icon->manager_window, StructureNotifyMask);
+
+  XUngrabServer (xdisplay);
+  XFlush (xdisplay);
+  
+  if (icon->manager_window != None)
+    {
+      GdkWindow *gdkwin;
+
+      gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)),
+                                             icon->manager_window);
+      
+      gdk_window_add_filter (gdkwin, egg_tray_icon_manager_filter, icon);
+
+      /* Send a request that we'd like to dock */
+      egg_tray_icon_send_dock_request (icon);
+    }
+}
+
+EggTrayIcon *
+egg_tray_icon_new_for_xscreen (Screen *xscreen, const char *name)
+{
+  EggTrayIcon *icon;
+  char buffer[256];
+  GdkWindow *root_window;
+  GdkDisplay *display;
+  GdkScreen *screen;
+  
+  g_return_val_if_fail (xscreen != NULL, NULL);
+  
+  icon = g_object_new (EGG_TYPE_TRAY_ICON, NULL);
+  gtk_window_set_title (GTK_WINDOW (icon), name);
+
+  display = gdk_x11_lookup_xdisplay (DisplayOfScreen (xscreen));
+  screen = gdk_display_get_screen (display, XScreenNumberOfScreen (xscreen));
+  
+  gtk_plug_construct_for_display (GTK_PLUG (icon),
+                                 display, 0);
+
+  gtk_window_set_screen (GTK_WINDOW (icon), screen);    
+  
+  gtk_widget_realize (GTK_WIDGET (icon));
+
+  /* Now see if there's a manager window around */
+  g_snprintf (buffer, sizeof (buffer),
+             "_NET_SYSTEM_TRAY_S%d",
+             XScreenNumberOfScreen (xscreen));
+  
+  icon->selection_atom = XInternAtom (DisplayOfScreen (xscreen),
+                                     buffer, False);
+  
+  icon->manager_atom = XInternAtom (DisplayOfScreen (xscreen),
+                                   "MANAGER", False);
+  
+  icon->system_tray_opcode_atom = XInternAtom (DisplayOfScreen (xscreen),
+                                              "_NET_SYSTEM_TRAY_OPCODE", False);
+
+  egg_tray_icon_update_manager_window (icon);
+
+  root_window = gdk_screen_get_root_window (gtk_widget_get_screen (GTK_WIDGET (icon)));
+  
+  /* Add a root window filter so that we get changes on MANAGER */
+  gdk_window_add_filter (root_window,
+                        egg_tray_icon_manager_filter, icon);
+                     
+  return icon;
+}
+
+EggTrayIcon *
+egg_tray_icon_new_for_screen (GdkScreen *screen, const char *name)
+{
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+  return egg_tray_icon_new_for_xscreen (GDK_SCREEN_XSCREEN (screen), name);
+}
+
+EggTrayIcon*
+egg_tray_icon_new (const gchar *name)
+{
+  return egg_tray_icon_new_for_xscreen (DefaultScreenOfDisplay (gdk_display), name);
+}
+
+guint
+egg_tray_icon_send_message (EggTrayIcon *icon,
+                           gint         timeout,
+                           const gchar *message,
+                           gint         len)
+{
+  guint stamp;
+  
+  g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), 0);
+  g_return_val_if_fail (timeout >= 0, 0);
+  g_return_val_if_fail (message != NULL, 0);
+                    
+  if (icon->manager_window == None)
+    return 0;
+
+  if (len < 0)
+    len = strlen (message);
+
+  stamp = icon->stamp++;
+  
+  /* Get ready to send the message */
+  egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_BEGIN_MESSAGE,
+                                     (Window)gtk_plug_get_id (GTK_PLUG (icon)),
+                                     timeout, len, stamp);
+
+  /* Now to send the actual message */
+  gdk_error_trap_push ();
+  while (len > 0)
+    {
+      XClientMessageEvent ev;
+      Display *xdisplay;
+
+      xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
+      
+      ev.type = ClientMessage;
+      ev.window = (Window)gtk_plug_get_id (GTK_PLUG (icon));
+      ev.format = 8;
+      ev.message_type = XInternAtom (xdisplay,
+                                    "_NET_SYSTEM_TRAY_MESSAGE_DATA", False);
+      if (len > 20)
+       {
+         memcpy (&ev.data, message, 20);
+         len -= 20;
+         message += 20;
+       }
+      else
+       {
+         memcpy (&ev.data, message, len);
+         len = 0;
+       }
+
+      XSendEvent (xdisplay,
+                 icon->manager_window, False, StructureNotifyMask, (XEvent *)&ev);
+      XSync (xdisplay, False);
+    }
+  gdk_error_trap_pop ();
+
+  return stamp;
+}
+
+void
+egg_tray_icon_cancel_message (EggTrayIcon *icon,
+                             guint        id)
+{
+  g_return_if_fail (EGG_IS_TRAY_ICON (icon));
+  g_return_if_fail (id > 0);
+  
+  egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_CANCEL_MESSAGE,
+                                     (Window)gtk_plug_get_id (GTK_PLUG (icon)),
+                                     id, 0, 0);
+}
diff --git a/src/gtk/eggtrayicon.h b/src/gtk/eggtrayicon.h
new file mode 100644 (file)
index 0000000..df604df
--- /dev/null
@@ -0,0 +1,74 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* eggtrayicon.h
+ * Copyright (C) 2002 Anders Carlsson <andersca@gnu.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EGG_TRAY_ICON_H__
+#define __EGG_TRAY_ICON_H__
+
+#include <gtk/gtkplug.h>
+#include <gdk/gdkx.h>
+
+G_BEGIN_DECLS
+
+#define EGG_TYPE_TRAY_ICON             (egg_tray_icon_get_type ())
+#define EGG_TRAY_ICON(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TRAY_ICON, EggTrayIcon))
+#define EGG_TRAY_ICON_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_TRAY_ICON, EggTrayIconClass))
+#define EGG_IS_TRAY_ICON(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TRAY_ICON))
+#define EGG_IS_TRAY_ICON_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_TRAY_ICON))
+#define EGG_TRAY_ICON_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_TRAY_ICON, EggTrayIconClass))
+       
+typedef struct _EggTrayIcon      EggTrayIcon;
+typedef struct _EggTrayIconClass  EggTrayIconClass;
+
+struct _EggTrayIcon
+{
+  GtkPlug parent_instance;
+
+  guint stamp;
+  
+  Atom selection_atom;
+  Atom manager_atom;
+  Atom system_tray_opcode_atom;
+  Window manager_window;
+};
+
+struct _EggTrayIconClass
+{
+  GtkPlugClass parent_class;
+};
+
+GType        egg_tray_icon_get_type       (void);
+
+EggTrayIcon *egg_tray_icon_new_for_screen (GdkScreen   *screen,
+                                          const gchar *name);
+
+EggTrayIcon *egg_tray_icon_new            (const gchar *name);
+
+guint        egg_tray_icon_send_message   (EggTrayIcon *icon,
+                                          gint         timeout,
+                                          const char  *message,
+                                          gint         len);
+void         egg_tray_icon_cancel_message (EggTrayIcon *icon,
+                                          guint        id);
+
+
+                                           
+G_END_DECLS
+
+#endif /* __EGG_TRAY_ICON_H__ */
diff --git a/src/gtk/taskbar.cpp b/src/gtk/taskbar.cpp
new file mode 100644 (file)
index 0000000..fe4c00d
--- /dev/null
@@ -0,0 +1,65 @@
+/////////////////////////////////////////////////////////////////////////
+// File:        taskbar.cpp
+// Purpose:     wxTaskBarIcon (src/unix/taskbarx11.cpp) helper for GTK2
+// Author:      Vaclav Slavik
+// Modified by:
+// Created:     2004/05/29
+// RCS-ID:      $Id$
+// Copyright:   (c) Vaclav Slavik, 2004
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////
+
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
+#pragma implementation "taskbarpriv.h"
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#include "wx/log.h"
+#include "wx/frame.h"
+
+#ifdef __WXGTK20__
+
+#include "wx/gtk/taskbarpriv.h"
+#include "eggtrayicon.h"
+
+wxTaskBarIconAreaBase::wxTaskBarIconAreaBase()
+{
+    if (IsProtocolSupported())
+    {
+        m_widget = GTK_WIDGET(egg_tray_icon_new("systray icon"));
+        gtk_window_set_resizable(GTK_WINDOW(m_widget), false);
+        
+        wxLogTrace(_T("systray"), _T("using freedesktop.org systray spec"));
+    }
+    
+    wxTopLevelWindow::Create(
+            NULL, wxID_ANY, _T("systray icon"),
+            wxDefaultPosition, wxDefaultSize,
+            wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR | wxSIMPLE_BORDER |
+            wxFRAME_SHAPED,
+            wxEmptyString /*eggtray doesn't like setting wmclass*/);
+}
+
+bool wxTaskBarIconAreaBase::IsProtocolSupported()
+{
+    static int s_supported = -1;
+    if (s_supported == -1)
+    {
+        Display *display = GDK_DISPLAY();
+        Screen *screen = DefaultScreenOfDisplay(display);
+    
+        wxString name;
+        name.Printf(_T("_NET_SYSTEM_TRAY_S%d"), XScreenNumberOfScreen(screen));
+        Atom atom = XInternAtom(display, name.ToAscii(), False);
+        
+        Window manager = XGetSelectionOwner(display, atom);
+        
+        s_supported = (manager != None);
+    }
+    
+    return (bool)s_supported;
+}
+
+#endif // __WXGTK20__
diff --git a/src/gtk1/eggtrayicon.c b/src/gtk1/eggtrayicon.c
new file mode 100644 (file)
index 0000000..416a648
--- /dev/null
@@ -0,0 +1,345 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* eggtrayicon.c
+ * Copyright (C) 2002 Anders Carlsson <andersca@gnu.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <gdk/gdkx.h>
+#include "eggtrayicon.h"
+
+#define SYSTEM_TRAY_REQUEST_DOCK    0
+#define SYSTEM_TRAY_BEGIN_MESSAGE   1
+#define SYSTEM_TRAY_CANCEL_MESSAGE  2
+         
+static GtkPlugClass *parent_class = NULL;
+
+static void egg_tray_icon_init (EggTrayIcon *icon);
+static void egg_tray_icon_class_init (EggTrayIconClass *klass);
+
+static void egg_tray_icon_unrealize (GtkWidget *widget);
+
+static void egg_tray_icon_update_manager_window (EggTrayIcon *icon);
+
+GType
+egg_tray_icon_get_type (void)
+{
+  static GType our_type = 0;
+
+  if (our_type == 0)
+    {
+      static const GTypeInfo our_info =
+      {
+       sizeof (EggTrayIconClass),
+       (GBaseInitFunc) NULL,
+       (GBaseFinalizeFunc) NULL,
+       (GClassInitFunc) egg_tray_icon_class_init,
+       NULL, /* class_finalize */
+       NULL, /* class_data */
+       sizeof (EggTrayIcon),
+       0,    /* n_preallocs */
+       (GInstanceInitFunc) egg_tray_icon_init
+      };
+
+      our_type = g_type_register_static (GTK_TYPE_PLUG, "EggTrayIcon", &our_info, 0);
+    }
+
+  return our_type;
+}
+
+static void
+egg_tray_icon_init (EggTrayIcon *icon)
+{
+  icon->stamp = 1;
+  
+  gtk_widget_add_events (GTK_WIDGET (icon), GDK_PROPERTY_CHANGE_MASK);
+}
+
+static void
+egg_tray_icon_class_init (EggTrayIconClass *klass)
+{
+  GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  widget_class->unrealize = egg_tray_icon_unrealize;
+}
+
+static GdkFilterReturn
+egg_tray_icon_manager_filter (GdkXEvent *xevent, GdkEvent *event, gpointer user_data)
+{
+  EggTrayIcon *icon = user_data;
+  XEvent *xev = (XEvent *)xevent;
+
+  if (xev->xany.type == ClientMessage &&
+      xev->xclient.message_type == icon->manager_atom &&
+      xev->xclient.data.l[1] == icon->selection_atom)
+    {
+      egg_tray_icon_update_manager_window (icon);
+    }
+  else if (xev->xany.window == icon->manager_window)
+    {
+      if (xev->xany.type == DestroyNotify)
+       {
+         egg_tray_icon_update_manager_window (icon);
+       }
+    }
+  
+  return GDK_FILTER_CONTINUE;
+}
+
+static void
+egg_tray_icon_unrealize (GtkWidget *widget)
+{
+  EggTrayIcon *icon = EGG_TRAY_ICON (widget);
+  GdkWindow *root_window;
+
+  if (icon->manager_window != None)
+    {
+      GdkWindow *gdkwin;
+
+      gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (widget),
+                                              icon->manager_window);
+
+      gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon);
+    }
+
+  root_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget));
+
+  gdk_window_remove_filter (root_window, egg_tray_icon_manager_filter, icon);
+
+  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
+    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+}
+
+static void
+egg_tray_icon_send_manager_message (EggTrayIcon *icon,
+                                   long         message,
+                                   Window       window,
+                                   long         data1,
+                                   long         data2,
+                                   long         data3)
+{
+  XClientMessageEvent ev;
+  Display *display;
+  
+  ev.type = ClientMessage;
+  ev.window = window;
+  ev.message_type = icon->system_tray_opcode_atom;
+  ev.format = 32;
+  ev.data.l[0] = gdk_x11_get_server_time (GTK_WIDGET (icon)->window);
+  ev.data.l[1] = message;
+  ev.data.l[2] = data1;
+  ev.data.l[3] = data2;
+  ev.data.l[4] = data3;
+
+  display = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
+  
+  gdk_error_trap_push ();
+  XSendEvent (display,
+             icon->manager_window, False, NoEventMask, (XEvent *)&ev);
+  XSync (display, False);
+  gdk_error_trap_pop ();
+}
+
+static void
+egg_tray_icon_send_dock_request (EggTrayIcon *icon)
+{
+  egg_tray_icon_send_manager_message (icon,
+                                     SYSTEM_TRAY_REQUEST_DOCK,
+                                     icon->manager_window,
+                                     gtk_plug_get_id (GTK_PLUG (icon)),
+                                     0, 0);
+}
+
+static void
+egg_tray_icon_update_manager_window (EggTrayIcon *icon)
+{
+  Display *xdisplay;
+  
+  xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
+  
+  if (icon->manager_window != None)
+    {
+      GdkWindow *gdkwin;
+
+      gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)),
+                                             icon->manager_window);
+      
+      gdk_window_remove_filter (gdkwin, egg_tray_icon_manager_filter, icon);
+    }
+  
+  XGrabServer (xdisplay);
+  
+  icon->manager_window = XGetSelectionOwner (xdisplay,
+                                            icon->selection_atom);
+
+  if (icon->manager_window != None)
+    XSelectInput (xdisplay,
+                 icon->manager_window, StructureNotifyMask);
+
+  XUngrabServer (xdisplay);
+  XFlush (xdisplay);
+  
+  if (icon->manager_window != None)
+    {
+      GdkWindow *gdkwin;
+
+      gdkwin = gdk_window_lookup_for_display (gtk_widget_get_display (GTK_WIDGET (icon)),
+                                             icon->manager_window);
+      
+      gdk_window_add_filter (gdkwin, egg_tray_icon_manager_filter, icon);
+
+      /* Send a request that we'd like to dock */
+      egg_tray_icon_send_dock_request (icon);
+    }
+}
+
+EggTrayIcon *
+egg_tray_icon_new_for_xscreen (Screen *xscreen, const char *name)
+{
+  EggTrayIcon *icon;
+  char buffer[256];
+  GdkWindow *root_window;
+  GdkDisplay *display;
+  GdkScreen *screen;
+  
+  g_return_val_if_fail (xscreen != NULL, NULL);
+  
+  icon = g_object_new (EGG_TYPE_TRAY_ICON, NULL);
+  gtk_window_set_title (GTK_WINDOW (icon), name);
+
+  display = gdk_x11_lookup_xdisplay (DisplayOfScreen (xscreen));
+  screen = gdk_display_get_screen (display, XScreenNumberOfScreen (xscreen));
+  
+  gtk_plug_construct_for_display (GTK_PLUG (icon),
+                                 display, 0);
+
+  gtk_window_set_screen (GTK_WINDOW (icon), screen);    
+  
+  gtk_widget_realize (GTK_WIDGET (icon));
+
+  /* Now see if there's a manager window around */
+  g_snprintf (buffer, sizeof (buffer),
+             "_NET_SYSTEM_TRAY_S%d",
+             XScreenNumberOfScreen (xscreen));
+  
+  icon->selection_atom = XInternAtom (DisplayOfScreen (xscreen),
+                                     buffer, False);
+  
+  icon->manager_atom = XInternAtom (DisplayOfScreen (xscreen),
+                                   "MANAGER", False);
+  
+  icon->system_tray_opcode_atom = XInternAtom (DisplayOfScreen (xscreen),
+                                              "_NET_SYSTEM_TRAY_OPCODE", False);
+
+  egg_tray_icon_update_manager_window (icon);
+
+  root_window = gdk_screen_get_root_window (gtk_widget_get_screen (GTK_WIDGET (icon)));
+  
+  /* Add a root window filter so that we get changes on MANAGER */
+  gdk_window_add_filter (root_window,
+                        egg_tray_icon_manager_filter, icon);
+                     
+  return icon;
+}
+
+EggTrayIcon *
+egg_tray_icon_new_for_screen (GdkScreen *screen, const char *name)
+{
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+  return egg_tray_icon_new_for_xscreen (GDK_SCREEN_XSCREEN (screen), name);
+}
+
+EggTrayIcon*
+egg_tray_icon_new (const gchar *name)
+{
+  return egg_tray_icon_new_for_xscreen (DefaultScreenOfDisplay (gdk_display), name);
+}
+
+guint
+egg_tray_icon_send_message (EggTrayIcon *icon,
+                           gint         timeout,
+                           const gchar *message,
+                           gint         len)
+{
+  guint stamp;
+  
+  g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), 0);
+  g_return_val_if_fail (timeout >= 0, 0);
+  g_return_val_if_fail (message != NULL, 0);
+                    
+  if (icon->manager_window == None)
+    return 0;
+
+  if (len < 0)
+    len = strlen (message);
+
+  stamp = icon->stamp++;
+  
+  /* Get ready to send the message */
+  egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_BEGIN_MESSAGE,
+                                     (Window)gtk_plug_get_id (GTK_PLUG (icon)),
+                                     timeout, len, stamp);
+
+  /* Now to send the actual message */
+  gdk_error_trap_push ();
+  while (len > 0)
+    {
+      XClientMessageEvent ev;
+      Display *xdisplay;
+
+      xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));
+      
+      ev.type = ClientMessage;
+      ev.window = (Window)gtk_plug_get_id (GTK_PLUG (icon));
+      ev.format = 8;
+      ev.message_type = XInternAtom (xdisplay,
+                                    "_NET_SYSTEM_TRAY_MESSAGE_DATA", False);
+      if (len > 20)
+       {
+         memcpy (&ev.data, message, 20);
+         len -= 20;
+         message += 20;
+       }
+      else
+       {
+         memcpy (&ev.data, message, len);
+         len = 0;
+       }
+
+      XSendEvent (xdisplay,
+                 icon->manager_window, False, StructureNotifyMask, (XEvent *)&ev);
+      XSync (xdisplay, False);
+    }
+  gdk_error_trap_pop ();
+
+  return stamp;
+}
+
+void
+egg_tray_icon_cancel_message (EggTrayIcon *icon,
+                             guint        id)
+{
+  g_return_if_fail (EGG_IS_TRAY_ICON (icon));
+  g_return_if_fail (id > 0);
+  
+  egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_CANCEL_MESSAGE,
+                                     (Window)gtk_plug_get_id (GTK_PLUG (icon)),
+                                     id, 0, 0);
+}
diff --git a/src/gtk1/eggtrayicon.h b/src/gtk1/eggtrayicon.h
new file mode 100644 (file)
index 0000000..df604df
--- /dev/null
@@ -0,0 +1,74 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* eggtrayicon.h
+ * Copyright (C) 2002 Anders Carlsson <andersca@gnu.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EGG_TRAY_ICON_H__
+#define __EGG_TRAY_ICON_H__
+
+#include <gtk/gtkplug.h>
+#include <gdk/gdkx.h>
+
+G_BEGIN_DECLS
+
+#define EGG_TYPE_TRAY_ICON             (egg_tray_icon_get_type ())
+#define EGG_TRAY_ICON(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TRAY_ICON, EggTrayIcon))
+#define EGG_TRAY_ICON_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_TRAY_ICON, EggTrayIconClass))
+#define EGG_IS_TRAY_ICON(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TRAY_ICON))
+#define EGG_IS_TRAY_ICON_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_TRAY_ICON))
+#define EGG_TRAY_ICON_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_TRAY_ICON, EggTrayIconClass))
+       
+typedef struct _EggTrayIcon      EggTrayIcon;
+typedef struct _EggTrayIconClass  EggTrayIconClass;
+
+struct _EggTrayIcon
+{
+  GtkPlug parent_instance;
+
+  guint stamp;
+  
+  Atom selection_atom;
+  Atom manager_atom;
+  Atom system_tray_opcode_atom;
+  Window manager_window;
+};
+
+struct _EggTrayIconClass
+{
+  GtkPlugClass parent_class;
+};
+
+GType        egg_tray_icon_get_type       (void);
+
+EggTrayIcon *egg_tray_icon_new_for_screen (GdkScreen   *screen,
+                                          const gchar *name);
+
+EggTrayIcon *egg_tray_icon_new            (const gchar *name);
+
+guint        egg_tray_icon_send_message   (EggTrayIcon *icon,
+                                          gint         timeout,
+                                          const char  *message,
+                                          gint         len);
+void         egg_tray_icon_cancel_message (EggTrayIcon *icon,
+                                          guint        id);
+
+
+                                           
+G_END_DECLS
+
+#endif /* __EGG_TRAY_ICON_H__ */
diff --git a/src/gtk1/taskbar.cpp b/src/gtk1/taskbar.cpp
new file mode 100644 (file)
index 0000000..fe4c00d
--- /dev/null
@@ -0,0 +1,65 @@
+/////////////////////////////////////////////////////////////////////////
+// File:        taskbar.cpp
+// Purpose:     wxTaskBarIcon (src/unix/taskbarx11.cpp) helper for GTK2
+// Author:      Vaclav Slavik
+// Modified by:
+// Created:     2004/05/29
+// RCS-ID:      $Id$
+// Copyright:   (c) Vaclav Slavik, 2004
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////
+
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
+#pragma implementation "taskbarpriv.h"
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#include "wx/log.h"
+#include "wx/frame.h"
+
+#ifdef __WXGTK20__
+
+#include "wx/gtk/taskbarpriv.h"
+#include "eggtrayicon.h"
+
+wxTaskBarIconAreaBase::wxTaskBarIconAreaBase()
+{
+    if (IsProtocolSupported())
+    {
+        m_widget = GTK_WIDGET(egg_tray_icon_new("systray icon"));
+        gtk_window_set_resizable(GTK_WINDOW(m_widget), false);
+        
+        wxLogTrace(_T("systray"), _T("using freedesktop.org systray spec"));
+    }
+    
+    wxTopLevelWindow::Create(
+            NULL, wxID_ANY, _T("systray icon"),
+            wxDefaultPosition, wxDefaultSize,
+            wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR | wxSIMPLE_BORDER |
+            wxFRAME_SHAPED,
+            wxEmptyString /*eggtray doesn't like setting wmclass*/);
+}
+
+bool wxTaskBarIconAreaBase::IsProtocolSupported()
+{
+    static int s_supported = -1;
+    if (s_supported == -1)
+    {
+        Display *display = GDK_DISPLAY();
+        Screen *screen = DefaultScreenOfDisplay(display);
+    
+        wxString name;
+        name.Printf(_T("_NET_SYSTEM_TRAY_S%d"), XScreenNumberOfScreen(screen));
+        Atom atom = XInternAtom(display, name.ToAscii(), False);
+        
+        Window manager = XGetSelectionOwner(display, atom);
+        
+        s_supported = (manager != None);
+    }
+    
+    return (bool)s_supported;
+}
+
+#endif // __WXGTK20__
index 3611d4dc129edc0cef18b21d133a39aac13c54b3..5b4704bc537a1d8b3cbdcd11d1aa62597a2223d2 100644 (file)
 #endif
 
 // NB: This implementation does *not* work with every X11 window manager.
-//     Currently only GNOME 1.2 and KDE 1,2,3 methods are implemented.
-//
-//     FIXME: implement:
-//               - GNOME 2 support (see www.freedesktop.org for specification;
-//                 KDE 3 uses this method as well, even though legacy KDE
-//                 method we implement works as well)
-//               - IceWM support (?)
+//     Currently only GNOME 1.2 and KDE 1,2,3 methods are implemented here.
+//     Freedesktop.org's System Tray specification is implemented in
+//     src/gtk/taskbar.cpp and used from here under wxGTK.
 //
 //     Thanks to Ian Campbell, author of XMMS Status Docklet, for publishing
 //     KDE and GNOME 1.2 methods.
@@ -35,6 +31,7 @@
 #include "wx/statbmp.h"
 #include "wx/sizer.h"
 #include "wx/dcclient.h"
+#include "wx/log.h"
 
 #ifdef __VMS
 #pragma message disable nosimpint
 #pragma message enable nosimpint
 #endif
 
+// ----------------------------------------------------------------------------
+// base class that implements toolkit-specific method:
+// ----------------------------------------------------------------------------
+
+#ifdef __WXGTK20__
+    #include "wx/gtk/taskbarpriv.h"
+#else
+    class WXDLLIMPEXP_ADV wxTaskBarIconAreaBase : public wxFrame
+    {
+    public:
+        wxTaskBarIconAreaBase()
+            : wxFrame(NULL, wxID_ANY, _T("systray icon"),
+                      wxDefaultPosition, wxDefaultSize,
+                      wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR |
+                      wxSIMPLE_BORDER | wxFRAME_SHAPED) {}
+
+        bool IsProtocolSupported() const { return false; }
+    };
+#endif
+
+
 // ----------------------------------------------------------------------------
 // toolkit dependent methods to set properties on helper window:
 // ----------------------------------------------------------------------------
 // wxTaskBarIconArea is the real window that shows the icon:
 // ----------------------------------------------------------------------------
 
-class WXDLLIMPEXP_ADV wxTaskBarIconArea : public wxFrame
+class WXDLLIMPEXP_ADV wxTaskBarIconArea : public wxTaskBarIconAreaBase
 {
 public:
-    wxTaskBarIconArea(wxTaskBarIcon *icon, const wxBitmap &bmp)
-        : wxFrame(NULL, -1, wxT("taskbar icon"),
-                  wxDefaultPosition, wxDefaultSize,
-                  wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR |
-                  wxSIMPLE_BORDER | wxFRAME_SHAPED),
-          m_icon(icon), m_bmp(bmp)
-    {
-        SetWMProperties();
-        SetSize(wxSize(bmp.GetWidth(), bmp.GetHeight()));
-    }
-
+    wxTaskBarIconArea(wxTaskBarIcon *icon, const wxBitmap &bmp);
+    void SetTrayIcon(const wxBitmap& bmp);
     bool IsOk() { return true; }
     
 protected:
-    void SetWMProperties();
+    void SetLegacyWMProperties();
     
+    void OnSizeChange(wxSizeEvent& event);
     void OnPaint(wxPaintEvent& evt);
-    void OnWindowCreate(wxWindowCreateEvent& event);
     void OnMouseEvent(wxMouseEvent& event);
     void OnMenuEvent(wxCommandEvent& event);
 
     wxTaskBarIcon *m_icon;
-    wxBitmap m_bmp;
+    wxPoint        m_pos;
+    wxBitmap       m_bmp;
     
     DECLARE_EVENT_TABLE()
 };
 
-BEGIN_EVENT_TABLE(wxTaskBarIconArea, wxFrame)
+BEGIN_EVENT_TABLE(wxTaskBarIconArea, wxTaskBarIconAreaBase)
+    EVT_SIZE(wxTaskBarIconArea::OnSizeChange)
     EVT_MOUSE_EVENTS(wxTaskBarIconArea::OnMouseEvent)
     EVT_MENU(-1, wxTaskBarIconArea::OnMenuEvent)
     EVT_PAINT(wxTaskBarIconArea::OnPaint)
-#ifdef __WXGTK__
-    EVT_WINDOW_CREATE(wxTaskBarIconArea::OnWindowCreate)
-#endif
 END_EVENT_TABLE()
+        
+wxTaskBarIconArea::wxTaskBarIconArea(wxTaskBarIcon *icon, const wxBitmap &bmp)
+    : wxTaskBarIconAreaBase(), m_icon(icon), m_pos(0,0)
+{
+    if (!IsProtocolSupported())
+    {
+        wxLogTrace(_T("systray"),
+                   _T("using legacy KDE1,2 and GNOME 1.2 methods"));
+        SetLegacyWMProperties();
+    }
+   
+    // Set initial size to bitmap size (tray manager may and often will
+    // change it):
+    SetSize(wxSize(bmp.GetWidth(), bmp.GetHeight()));
+    
+    SetTrayIcon(bmp);
+}
+
+void wxTaskBarIconArea::SetTrayIcon(const wxBitmap& bmp)
+{
+    m_bmp = bmp;
+    
+    // determine suitable bitmap size:
+    wxSize winsize(GetSize());
+    wxSize bmpsize(m_bmp.GetWidth(), m_bmp.GetHeight());
+    wxSize iconsize(wxMin(winsize.x, bmpsize.x), wxMin(winsize.y, bmpsize.y));
+
+    // rescale the bitmap to fit into the tray icon window:
+    if (bmpsize != iconsize)
+    {
+        wxImage img = m_bmp.ConvertToImage();
+        img.Rescale(iconsize.x, iconsize.y);
+        m_bmp = wxBitmap(img);
+    }
 
-void wxTaskBarIconArea::SetWMProperties()
+    wxRegion region(m_bmp);
+
+    // if the bitmap is smaller than the window, offset it:
+    if (winsize != iconsize)
+    {
+        m_pos.x = (winsize.x - iconsize.x) / 2;
+        m_pos.y = (winsize.y - iconsize.y) / 2;
+        region.Offset(m_pos.x, m_pos.y);
+    }
+
+    // set frame's shape to correct value and redraw:
+    SetShape(region);
+    Refresh();
+}
+
+void wxTaskBarIconArea::SetLegacyWMProperties()
 { 
 #ifdef __WXGTK__
     gtk_widget_realize(m_widget);
@@ -134,22 +191,26 @@ void wxTaskBarIconArea::SetWMProperties()
                     PropModeReplace, (unsigned char*)data, 1);
 }
     
-void wxTaskBarIconArea::OnWindowCreate(wxWindowCreateEvent& WXUNUSED(event))
+void wxTaskBarIconArea::OnSizeChange(wxSizeEvent& event)
 {
-    SetShape(wxRegion(m_bmp));
+    wxLogTrace(_T("systray"), _T("icon size changed to %i x %i"),
+               GetSize().x, GetSize().y);
+    // rescale or reposition the icon as needed:
+    wxBitmap bmp(m_bmp);
+    SetTrayIcon(bmp);
 }
 
 void wxTaskBarIconArea::OnPaint(wxPaintEvent& WXUNUSED(event))
 {
     wxPaintDC dc(this);
-    dc.DrawBitmap(m_bmp, 0, 0, true);
+    dc.DrawBitmap(m_bmp, m_pos.x, m_pos.y, true);
 }
     
 void wxTaskBarIconArea::OnMouseEvent(wxMouseEvent& event)
 {
     wxEventType type = 0;
     wxEventType mtype = event.GetEventType();
-    
+
     if (mtype == wxEVT_LEFT_DOWN)
         type = wxEVT_TASKBAR_LEFT_DOWN;
     else if (mtype == wxEVT_LEFT_UP)
@@ -204,29 +265,35 @@ bool wxTaskBarIcon::IsIconInstalled() const
 
 bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip)
 {
-    if (m_iconWnd)
-        RemoveIcon();
-
     wxBitmap bmp;
     bmp.CopyFromIcon(icon);
-    
-    m_iconWnd = new wxTaskBarIconArea(this, bmp);
 
-#if wxUSE_TOOLTIPS
-    if (!tooltip.empty())
-        m_iconWnd->SetToolTip(tooltip);
-#endif
-    if (m_iconWnd->IsOk())
+    if (!m_iconWnd)
     {
-        m_iconWnd->Show();
-        return true;
+        m_iconWnd = new wxTaskBarIconArea(this, bmp);
+        if (m_iconWnd->IsOk())
+        {
+            m_iconWnd->Show();
+        }
+        else
+        {
+            m_iconWnd->Destroy();
+            m_iconWnd = NULL;
+            return false;
+        }
     }
     else
     {
-        m_iconWnd->Destroy();
-        m_iconWnd = NULL;
-        return false;
-    }
+        m_iconWnd->SetTrayIcon(bmp);
+    }    
+    
+#if wxUSE_TOOLTIPS
+    if (!tooltip.empty())
+        m_iconWnd->SetToolTip(tooltip);
+    else
+        m_iconWnd->SetToolTip(NULL);
+#endif
+    return true;
 }
 
 bool wxTaskBarIcon::RemoveIcon()