diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl
index 29978103fc..49d6da1959 100644
--- a/build/bakefiles/files.bkl
+++ b/build/bakefiles/files.bkl
@@ -3007,6 +3007,7 @@ src/osx/iphone/window.mm
wx/gtk/hildon/notifmsg.h
+ wx/gtk/taskbar.h
diff --git a/include/wx/gtk/taskbar.h b/include/wx/gtk/taskbar.h
new file mode 100644
index 0000000000..b46758a7e6
--- /dev/null
+++ b/include/wx/gtk/taskbar.h
@@ -0,0 +1,34 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name: wx/gtk/taskbar.h
+// Purpose: wxTaskBarIcon class for GTK2
+// Author: Paul Cornett
+// Created: 2009-02-08
+// RCS-ID: $Id$
+// Copyright: (c) 2009 Paul Cornett
+// Licence: wxWindows licence
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_GTK_TASKBARICON_H_
+#define _WX_GTK_TASKBARICON_H_
+
+class WXDLLIMPEXP_ADV wxTaskBarIcon: public wxTaskBarIconBase
+{
+public:
+ wxTaskBarIcon();
+ ~wxTaskBarIcon();
+ virtual bool SetIcon(const wxIcon& icon, const wxString& tooltip = wxString());
+ virtual bool RemoveIcon();
+ virtual bool PopupMenu(wxMenu* menu);
+ bool IsOk() const { return true; }
+ bool IsIconInstalled() const;
+
+ class Private;
+
+private:
+ Private* m_priv;
+
+ DECLARE_DYNAMIC_CLASS(wxTaskBarIcon)
+ DECLARE_NO_COPY_CLASS(wxTaskBarIcon)
+};
+
+#endif // _WX_GTK_TASKBARICON_H_
diff --git a/include/wx/gtk/taskbarpriv.h b/include/wx/gtk/taskbarpriv.h
deleted file mode 100644
index 242d3c6a89..0000000000
--- a/include/wx/gtk/taskbarpriv.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/////////////////////////////////////////////////////////////////////////
-// 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_GTK_TASKBARPRIV_H_
-#define _WX_GTK_TASKBARPRIV_H_
-
-#include "wx/toplevel.h"
-
-class WXDLLIMPEXP_ADV wxTaskBarIconAreaBase : public wxTopLevelWindow
-{
-public:
- wxTaskBarIconAreaBase();
-
- // Returns true if SYSTRAY protocol is supported by the desktop
- static bool IsProtocolSupported();
-
- wxEvtHandler *m_invokingWindow;
-
-protected:
-#if wxUSE_MENUS_NATIVE
- virtual void DoPopupMenuUpdateUI(wxMenu* menu);
-#endif // wxUSE_MENUS_NATIVE
-};
-
-#endif // _WX_GTK_TASKBARPRIV_H_
diff --git a/include/wx/gtk/window.h b/include/wx/gtk/window.h
index 9f6a26f437..4cd39e93db 100644
--- a/include/wx/gtk/window.h
+++ b/include/wx/gtk/window.h
@@ -316,7 +316,6 @@ protected:
#if wxUSE_MENUS_NATIVE
virtual bool DoPopupMenu( wxMenu *menu, int x, int y );
- virtual void DoPopupMenuUpdateUI(wxMenu* menu);
#endif // wxUSE_MENUS_NATIVE
virtual void DoCaptureMouse();
diff --git a/include/wx/taskbar.h b/include/wx/taskbar.h
index 8c789f09f4..fdc2ea0f3a 100644
--- a/include/wx/taskbar.h
+++ b/include/wx/taskbar.h
@@ -65,6 +65,8 @@ private:
#include "wx/palmos/taskbar.h"
#elif defined(__WXMSW__)
#include "wx/msw/taskbar.h"
+#elif defined(__WXGTK20__)
+ #include "wx/gtk/taskbar.h"
#elif defined(__WXGTK__) || defined(__WXX11__) || defined(__WXMOTIF__)
#include "wx/unix/taskbarx11.h"
#elif defined (__WXMAC__)
diff --git a/src/gtk/taskbar.cpp b/src/gtk/taskbar.cpp
index ee192ae7b9..03bee569c7 100644
--- a/src/gtk/taskbar.cpp
+++ b/src/gtk/taskbar.cpp
@@ -1,8 +1,8 @@
/////////////////////////////////////////////////////////////////////////
// File: src/gtk/taskbar.cpp
-// Purpose: wxTaskBarIcon (src/unix/taskbarx11.cpp) helper for GTK2
+// Purpose: wxTaskBarIcon
// Author: Vaclav Slavik
-// Modified by:
+// Modified by: Paul Cornett
// Created: 2004/05/29
// RCS-ID: $Id$
// Copyright: (c) Vaclav Slavik, 2004
@@ -14,73 +14,283 @@
#if wxUSE_TASKBARICON
-#include "wx/gtk/taskbarpriv.h"
+#include "wx/taskbar.h"
#ifndef WX_PRECOMP
- #include "wx/log.h"
- #include "wx/frame.h"
+ #include "wx/toplevel.h"
#include "wx/menu.h"
+ #include "wx/icon.h"
#endif
-#include
-#include
-
#include "eggtrayicon.h"
+#include
-wxTaskBarIconAreaBase::wxTaskBarIconAreaBase()
+class wxTaskBarIcon::Private
{
- if (IsProtocolSupported())
- {
- m_widget = GTK_WIDGET(egg_tray_icon_new("systray icon"));
- g_object_ref(m_widget);
- gtk_window_set_resizable(GTK_WINDOW(m_widget), false);
+public:
+ Private(wxTaskBarIcon* taskBarIcon);
+ ~Private();
+ void SetIcon();
+ void size_allocate(int width, int height);
- wxLogTrace(_T("systray"), _T("using freedesktop.org systray spec"));
- }
+ // owning wxTaskBarIcon
+ wxTaskBarIcon* m_taskBarIcon;
+ // used when GTK+ >= 2.10
+ GtkStatusIcon* m_statusIcon;
+ // used when GTK+ < 2.10
+ GtkWidget* m_eggTrayIcon;
+ // for PopupMenu
+ wxWindow* m_win;
+ // for tooltip when GTK+ < 2.10
+ GtkTooltips* m_tooltips;
+ wxBitmap m_bitmap;
+ wxString m_tipText;
+ // width and height of available space, only used when GTK+ < 2.10
+ int m_size;
+};
+//-----------------------------------------------------------------------------
- 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*/);
-
- // WM frame extents are not useful for wxTaskBarIcon
- m_deferShow = false;
- gulong handler_id = g_signal_handler_find(
- m_widget,
- GSignalMatchType(G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DATA),
- g_signal_lookup("property_notify_event", GTK_TYPE_WIDGET),
- 0, NULL, NULL, this);
- if (handler_id != 0)
- g_signal_handler_disconnect(m_widget, handler_id);
-
- m_invokingWindow = NULL;
+extern "C" {
+static void
+icon_size_allocate(GtkWidget*, GtkAllocation* alloc, wxTaskBarIcon::Private* priv)
+{
+ priv->size_allocate(alloc->width, alloc->height);
}
-bool wxTaskBarIconAreaBase::IsProtocolSupported()
+static void
+icon_destroy(GtkWidget*, wxTaskBarIcon::Private* priv)
{
- Display *display = GDK_DISPLAY();
- Screen *screen = DefaultScreenOfDisplay(display);
+ // Icon window destroyed, probably because tray program has died.
+ // Recreate icon so it will appear if tray program is restarted.
+ priv->m_eggTrayIcon = NULL;
+ priv->SetIcon();
+}
+static void
+icon_activate(void*, wxTaskBarIcon* taskBarIcon)
+{
+ // activate occurs from single click with GTK+
+ wxTaskBarIconEvent event(wxEVT_TASKBAR_LEFT_DOWN, taskBarIcon);
+ if (!taskBarIcon->SafelyProcessEvent(event))
+ {
+ // if single click not handled, send double click for compatibility
+ event.SetEventType(wxEVT_TASKBAR_LEFT_DCLICK);
+ taskBarIcon->SafelyProcessEvent(event);
+ }
+}
+
+static gboolean
+icon_popup_menu(GtkWidget*, wxTaskBarIcon* taskBarIcon)
+{
+ wxTaskBarIconEvent event(wxEVT_TASKBAR_CLICK, taskBarIcon);
+ taskBarIcon->SafelyProcessEvent(event);
+ return true;
+}
+
+static gboolean
+icon_button_press_event(GtkWidget*, GdkEventButton* event, wxTaskBarIcon* taskBarIcon)
+{
+ if (event->type == GDK_BUTTON_PRESS)
+ {
+ if (event->button == 1)
+ icon_activate(NULL, taskBarIcon);
+ else if (event->button == 3)
+ icon_popup_menu(NULL, taskBarIcon);
+ }
+ return false;
+}
+
+#if GTK_CHECK_VERSION(2,10,0)
+static void
+status_icon_popup_menu(GtkStatusIcon*, guint, guint, wxTaskBarIcon* taskBarIcon)
+{
+ icon_popup_menu(NULL, taskBarIcon);
+}
+#endif
+} // extern "C"
+//-----------------------------------------------------------------------------
+
+bool wxTaskBarIconBase::IsAvailable()
+{
char name[32];
g_snprintf(name, sizeof(name), "_NET_SYSTEM_TRAY_S%d",
- XScreenNumberOfScreen(screen));
- Atom atom = XInternAtom(display, name, False);
+ gdk_x11_get_default_screen());
+ Atom atom = gdk_x11_get_xatom_by_name(name);
- Window manager = XGetSelectionOwner(display, atom);
+ Window manager = XGetSelectionOwner(gdk_x11_get_default_xdisplay(), atom);
- return (manager != None);
+ return manager != None;
}
-
-//-----------------------------------------------------------------------------
-// Pop-up menu stuff
//-----------------------------------------------------------------------------
-#if wxUSE_MENUS_NATIVE
-void wxTaskBarIconAreaBase::DoPopupMenuUpdateUI(wxMenu* menu)
+wxTaskBarIcon::Private::Private(wxTaskBarIcon* taskBarIcon)
{
- menu->UpdateUI(m_invokingWindow);
+ m_taskBarIcon = taskBarIcon;
+ m_statusIcon = NULL;
+ m_eggTrayIcon = NULL;
+ m_win = NULL;
+ m_tooltips = NULL;
+ m_size = 0;
}
-#endif // wxUSE_MENUS_NATIVE
+
+wxTaskBarIcon::Private::~Private()
+{
+ if (m_statusIcon)
+ g_object_unref(m_statusIcon);
+ else if (m_eggTrayIcon)
+ {
+ g_signal_handlers_disconnect_by_func(m_eggTrayIcon, (void*)icon_destroy, this);
+ gtk_widget_destroy(m_eggTrayIcon);
+ }
+ if (m_win)
+ {
+ m_win->PopEventHandler();
+ m_win->Destroy();
+ }
+ if (m_tooltips)
+ {
+ gtk_object_destroy(GTK_OBJECT(m_tooltips));
+ g_object_unref(m_tooltips);
+ }
+}
+
+void wxTaskBarIcon::Private::SetIcon()
+{
+#if GTK_CHECK_VERSION(2,10,0)
+ if (gtk_check_version(2,10,0) == NULL)
+ {
+ if (m_statusIcon)
+ gtk_status_icon_set_from_pixbuf(m_statusIcon, m_bitmap.GetPixbuf());
+ else
+ {
+ m_statusIcon = gtk_status_icon_new_from_pixbuf(m_bitmap.GetPixbuf());
+ g_signal_connect(m_statusIcon, "activate",
+ G_CALLBACK(icon_activate), m_taskBarIcon);
+ g_signal_connect(m_statusIcon, "popup_menu",
+ G_CALLBACK(status_icon_popup_menu), m_taskBarIcon);
+ }
+ }
+ else
+#endif
+ {
+ m_size = 0;
+ if (m_eggTrayIcon)
+ {
+ GtkWidget* image = GTK_BIN(m_eggTrayIcon)->child;
+ gtk_image_set_from_pixbuf(GTK_IMAGE(image), m_bitmap.GetPixbuf());
+ }
+ else
+ {
+ m_eggTrayIcon = GTK_WIDGET(egg_tray_icon_new("wxTaskBarIcon"));
+ gtk_widget_add_events(m_eggTrayIcon, GDK_BUTTON_PRESS_MASK);
+ g_signal_connect(m_eggTrayIcon, "size_allocate",
+ G_CALLBACK(icon_size_allocate), this);
+ g_signal_connect(m_eggTrayIcon, "destroy",
+ G_CALLBACK(icon_destroy), this);
+ g_signal_connect(m_eggTrayIcon, "button_press_event",
+ G_CALLBACK(icon_button_press_event), m_taskBarIcon);
+ g_signal_connect(m_eggTrayIcon, "popup_menu",
+ G_CALLBACK(icon_popup_menu), m_taskBarIcon);
+ GtkWidget* image = gtk_image_new_from_pixbuf(m_bitmap.GetPixbuf());
+ gtk_container_add(GTK_CONTAINER(m_eggTrayIcon), image);
+ gtk_widget_show_all(m_eggTrayIcon);
+ }
+ }
+#if wxUSE_TOOLTIPS
+ const char* tip_text = NULL;
+ if (!m_tipText.empty())
+ tip_text = m_tipText;
+
+#if GTK_CHECK_VERSION(2,10,0)
+ if (m_statusIcon)
+ gtk_status_icon_set_tooltip(m_statusIcon, tip_text);
+ else
+#endif
+ {
+ if (tip_text && m_tooltips == NULL)
+ {
+ m_tooltips = gtk_tooltips_new();
+ g_object_ref(m_tooltips);
+ gtk_object_sink(GTK_OBJECT(m_tooltips));
+ }
+ if (m_tooltips)
+ gtk_tooltips_set_tip(m_tooltips, m_eggTrayIcon, tip_text, "");
+ }
+#endif // wxUSE_TOOLTIPS
+}
+
+void wxTaskBarIcon::Private::size_allocate(int width, int height)
+{
+ int size = height;
+ EggTrayIcon* icon = EGG_TRAY_ICON(m_eggTrayIcon);
+ if (egg_tray_icon_get_orientation(icon) == GTK_ORIENTATION_VERTICAL)
+ size = width;
+ if (m_size == size)
+ return;
+ m_size = size;
+ int w = m_bitmap.GetWidth();
+ int h = m_bitmap.GetHeight();
+ if (w > size || h > size)
+ {
+ if (w > size) w = size;
+ if (h > size) h = size;
+ GdkPixbuf* pixbuf =
+ gdk_pixbuf_scale_simple(m_bitmap.GetPixbuf(), w, h, GDK_INTERP_BILINEAR);
+ GtkImage* image = GTK_IMAGE(GTK_BIN(m_eggTrayIcon)->child);
+ gtk_image_set_from_pixbuf(image, pixbuf);
+ g_object_unref(pixbuf);
+ }
+}
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler)
+
+wxTaskBarIcon::wxTaskBarIcon()
+{
+ m_priv = new Private(this);
+}
+
+wxTaskBarIcon::~wxTaskBarIcon()
+{
+ delete m_priv;
+}
+
+bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip)
+{
+ m_priv->m_bitmap = icon;
+ m_priv->m_tipText = tooltip;
+ m_priv->SetIcon();
+ return true;
+}
+
+bool wxTaskBarIcon::RemoveIcon()
+{
+ delete m_priv;
+ m_priv = new Private(this);
+ return true;
+}
+
+bool wxTaskBarIcon::IsIconInstalled() const
+{
+ return m_priv->m_statusIcon || m_priv->m_eggTrayIcon;
+}
+
+bool wxTaskBarIcon::PopupMenu(wxMenu* menu)
+{
+#if wxUSE_MENUS
+ if (m_priv->m_win == NULL)
+ {
+ m_priv->m_win = new wxTopLevelWindow(
+ NULL, wxID_ANY, wxString(), wxDefaultPosition, wxDefaultSize, 0);
+ m_priv->m_win->PushEventHandler(this);
+ }
+ wxPoint point(-1, -1);
+#ifdef __WXUNIVERSAL__
+ point = wxGetMousePosition();
+#endif
+ m_priv->m_win->PopupMenu(menu, point);
+#endif // wxUSE_MENUS
+ return true;
+}
+
#endif // wxUSE_TASKBARICON
diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp
index 1f64d565bd..b89ba436cb 100644
--- a/src/gtk/window.cpp
+++ b/src/gtk/window.cpp
@@ -3962,11 +3962,6 @@ void wxPopupMenuPositionCallback( GtkMenu *menu,
}
}
-void wxWindowGTK::DoPopupMenuUpdateUI(wxMenu* menu)
-{
- menu->UpdateUI();
-}
-
bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
{
wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
@@ -3975,7 +3970,7 @@ bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
SetInvokingWindow( menu, this );
- DoPopupMenuUpdateUI(menu);
+ menu->UpdateUI();
wxPoint pos;
gpointer userdata;
diff --git a/src/unix/taskbarx11.cpp b/src/unix/taskbarx11.cpp
index 385f05d46f..0978d60c1a 100644
--- a/src/unix/taskbarx11.cpp
+++ b/src/unix/taskbarx11.cpp
@@ -21,7 +21,7 @@
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
-#if wxUSE_TASKBARICON
+#if wxUSE_TASKBARICON && !defined(__WXGTK20__)
#include "wx/taskbar.h"
@@ -48,15 +48,6 @@
// base class that implements toolkit-specific method:
// ----------------------------------------------------------------------------
-#ifdef __WXGTK20__
- #include
- #if GTK_CHECK_VERSION(2,1,0)
- #include "wx/gtk/taskbarpriv.h"
- #define TASKBAR_ICON_AREA_BASE_INCLUDED
- #endif
-#endif
-
-#ifndef TASKBAR_ICON_AREA_BASE_INCLUDED
class WXDLLIMPEXP_ADV wxTaskBarIconAreaBase : public wxFrame
{
public:
@@ -68,17 +59,14 @@
static bool IsProtocolSupported() { return false; }
};
-#endif
-
// ----------------------------------------------------------------------------
// toolkit dependent methods to set properties on helper window:
// ----------------------------------------------------------------------------
#if defined(__WXGTK__)
- #include
- #include
#include
+ #include
#define GetDisplay() GDK_DISPLAY()
#define GetXWindow(wxwin) GDK_WINDOW_XWINDOW((wxwin)->m_widget->window)
#elif defined(__WXX11__) || defined(__WXMOTIF__)
@@ -126,10 +114,6 @@ END_EVENT_TABLE()
wxTaskBarIconArea::wxTaskBarIconArea(wxTaskBarIcon *icon, const wxBitmap &bmp)
: wxTaskBarIconAreaBase(), m_icon(icon), m_bmp(bmp)
{
-#if defined(__WXGTK20__) && defined(TASKBAR_ICON_AREA_BASE_INCLUDED)
- m_invokingWindow = icon;
-#endif
-
// Set initial size to bitmap size (tray manager may and often will
// change it):
SetClientSize(wxSize(bmp.GetWidth(), bmp.GetHeight()));