From 33d4eef0b9f61adad1f42ace436225ff508c6ea3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?V=C3=A1clav=20Slav=C3=ADk?= Date: Mon, 31 May 2004 22:17:09 +0000 Subject: [PATCH] implemented freedesktop.org spec support for GTK version of wxTaskBarIcon git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@27544 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- Makefile.in | 61 +++++- build/bakefiles/files.bkl | 7 +- docs/changes.txt | 10 + docs/latex/wx/taskbar.tex | 24 ++- include/wx/gtk/taskbarpriv.h | 31 +++ include/wx/gtk1/taskbarpriv.h | 31 +++ src/gtk/eggtrayicon.c | 345 ++++++++++++++++++++++++++++++++++ src/gtk/eggtrayicon.h | 74 ++++++++ src/gtk/taskbar.cpp | 65 +++++++ src/gtk1/eggtrayicon.c | 345 ++++++++++++++++++++++++++++++++++ src/gtk1/eggtrayicon.h | 74 ++++++++ src/gtk1/taskbar.cpp | 65 +++++++ src/unix/taskbarx11.cpp | 161 +++++++++++----- 13 files changed, 1233 insertions(+), 60 deletions(-) create mode 100644 include/wx/gtk/taskbarpriv.h create mode 100644 include/wx/gtk1/taskbarpriv.h create mode 100644 src/gtk/eggtrayicon.c create mode 100644 src/gtk/eggtrayicon.h create mode 100644 src/gtk/taskbar.cpp create mode 100644 src/gtk1/eggtrayicon.c create mode 100644 src/gtk1/eggtrayicon.h create mode 100644 src/gtk1/taskbar.cpp diff --git a/Makefile.in b/Makefile.in index 8e5eec404d..fa5905460d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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) $< diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index 6cf2c5159d..bbf0ec23ee 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -2196,6 +2196,11 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! wx/unix/taskbarx11.h + + src/gtk/taskbar.cpp + src/gtk/eggtrayicon.c + + @@ -2450,7 +2455,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! $(ADVANCED_MSW_SRC) $(ADVANCED_MAC_SRC) $(ADVANCED_UNIX_SRC) - $(ADVANCED_UNIX_SRC) + $(ADVANCED_UNIX_SRC) $(ADVANCED_GTK_SRC) $(ADVANCED_UNIX_SRC) $(ADVANCED_OS2_SRC) diff --git a/docs/changes.txt b/docs/changes.txt index 3db3c9ce6a..ff33354dd8 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -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: -
handling fix (Xavier Nodet) Unix: + - fixed priorities of mailcap entries (David Hart) - added "wx-config --libs=std," syntax (i.e. support for "std") wxODBC: + - Full Unicode support is now available - BLOB support is working diff --git a/docs/latex/wx/taskbar.tex b/docs/latex/wx/taskbar.tex index 2e63b1e38a..c560b0297c 100644 --- a/docs/latex/wx/taskbar.tex +++ b/docs/latex/wx/taskbar.tex @@ -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 index 0000000000..117e4cd04b --- /dev/null +++ b/include/wx/gtk/taskbarpriv.h @@ -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 index 0000000000..117e4cd04b --- /dev/null +++ b/include/wx/gtk1/taskbarpriv.h @@ -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 index 0000000000..416a6481ea --- /dev/null +++ b/src/gtk/eggtrayicon.c @@ -0,0 +1,345 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* eggtrayicon.c + * Copyright (C) 2002 Anders Carlsson + * + * 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 +#include +#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 index 0000000000..df604dfeb9 --- /dev/null +++ b/src/gtk/eggtrayicon.h @@ -0,0 +1,74 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* eggtrayicon.h + * Copyright (C) 2002 Anders Carlsson + * + * 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 +#include + +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 index 0000000000..fe4c00d4af --- /dev/null +++ b/src/gtk/taskbar.cpp @@ -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 index 0000000000..416a6481ea --- /dev/null +++ b/src/gtk1/eggtrayicon.c @@ -0,0 +1,345 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* eggtrayicon.c + * Copyright (C) 2002 Anders Carlsson + * + * 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 +#include +#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 index 0000000000..df604dfeb9 --- /dev/null +++ b/src/gtk1/eggtrayicon.h @@ -0,0 +1,74 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* eggtrayicon.h + * Copyright (C) 2002 Anders Carlsson + * + * 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 +#include + +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 index 0000000000..fe4c00d4af --- /dev/null +++ b/src/gtk1/taskbar.cpp @@ -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/unix/taskbarx11.cpp b/src/unix/taskbarx11.cpp index 3611d4dc12..5b4704bc53 100644 --- a/src/unix/taskbarx11.cpp +++ b/src/unix/taskbarx11.cpp @@ -14,13 +14,9 @@ #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 @@ -45,6 +42,27 @@ #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: // ---------------------------------------------------------------------------- @@ -68,46 +86,85 @@ // 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() -- 2.45.2