From a1c6f06900982928371d2036a81b44e410baa4cc Mon Sep 17 00:00:00 2001 From: Paul Cornett Date: Sun, 8 Feb 2009 22:21:24 +0000 Subject: [PATCH] new wxTaskBarIcon implementation for GTK2 git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58777 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- build/bakefiles/files.bkl | 1 + include/wx/gtk/taskbar.h | 34 ++++ include/wx/gtk/taskbarpriv.h | 33 ---- include/wx/gtk/window.h | 1 - include/wx/taskbar.h | 2 + src/gtk/taskbar.cpp | 382 +++++++++++++++++++++++++++++++++---------- src/gtk/window.cpp | 7 +- src/unix/taskbarx11.cpp | 20 +-- 8 files changed, 336 insertions(+), 144 deletions(-) create mode 100644 include/wx/gtk/taskbar.h delete mode 100644 include/wx/gtk/taskbarpriv.h rewrite src/gtk/taskbar.cpp (66%) diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index 2997810..49d6da1 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 0000000..b46758a --- /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 242d3c6..0000000 --- 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 9f6a26f..4cd39e9 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 8c789f0..fdc2ea0 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 dissimilarity index 66% index ee192ae..03bee569 100644 --- a/src/gtk/taskbar.cpp +++ b/src/gtk/taskbar.cpp @@ -1,86 +1,296 @@ -///////////////////////////////////////////////////////////////////////// -// File: src/gtk/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 -///////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if wxUSE_TASKBARICON - -#include "wx/gtk/taskbarpriv.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/frame.h" - #include "wx/menu.h" -#endif - -#include -#include - -#include "eggtrayicon.h" - -wxTaskBarIconAreaBase::wxTaskBarIconAreaBase() -{ - 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); - - 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*/); - - // 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; -} - -bool wxTaskBarIconAreaBase::IsProtocolSupported() -{ - Display *display = GDK_DISPLAY(); - Screen *screen = DefaultScreenOfDisplay(display); - - char name[32]; - g_snprintf(name, sizeof(name), "_NET_SYSTEM_TRAY_S%d", - XScreenNumberOfScreen(screen)); - Atom atom = XInternAtom(display, name, False); - - Window manager = XGetSelectionOwner(display, atom); - - return (manager != None); -} - -//----------------------------------------------------------------------------- -// Pop-up menu stuff -//----------------------------------------------------------------------------- - -#if wxUSE_MENUS_NATIVE -void wxTaskBarIconAreaBase::DoPopupMenuUpdateUI(wxMenu* menu) -{ - menu->UpdateUI(m_invokingWindow); -} -#endif // wxUSE_MENUS_NATIVE -#endif // wxUSE_TASKBARICON +///////////////////////////////////////////////////////////////////////// +// File: src/gtk/taskbar.cpp +// Purpose: wxTaskBarIcon +// Author: Vaclav Slavik +// Modified by: Paul Cornett +// Created: 2004/05/29 +// RCS-ID: $Id$ +// Copyright: (c) Vaclav Slavik, 2004 +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if wxUSE_TASKBARICON + +#include "wx/taskbar.h" + +#ifndef WX_PRECOMP + #include "wx/toplevel.h" + #include "wx/menu.h" + #include "wx/icon.h" +#endif + +#include "eggtrayicon.h" +#include + +class wxTaskBarIcon::Private +{ +public: + Private(wxTaskBarIcon* taskBarIcon); + ~Private(); + void SetIcon(); + void size_allocate(int width, int height); + + // 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; +}; +//----------------------------------------------------------------------------- + +extern "C" { +static void +icon_size_allocate(GtkWidget*, GtkAllocation* alloc, wxTaskBarIcon::Private* priv) +{ + priv->size_allocate(alloc->width, alloc->height); +} + +static void +icon_destroy(GtkWidget*, wxTaskBarIcon::Private* priv) +{ + // 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", + gdk_x11_get_default_screen()); + Atom atom = gdk_x11_get_xatom_by_name(name); + + Window manager = XGetSelectionOwner(gdk_x11_get_default_xdisplay(), atom); + + return manager != None; +} +//----------------------------------------------------------------------------- + +wxTaskBarIcon::Private::Private(wxTaskBarIcon* taskBarIcon) +{ + m_taskBarIcon = taskBarIcon; + m_statusIcon = NULL; + m_eggTrayIcon = NULL; + m_win = NULL; + m_tooltips = NULL; + m_size = 0; +} + +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 1f64d56..b89ba43 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 385f05d..0978d60 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())); -- 2.7.4