]> git.saurik.com Git - wxWidgets.git/blobdiff - src/unix/taskbarx11.cpp
Fixed drawing glitch with vertical MSW toolbars.
[wxWidgets.git] / src / unix / taskbarx11.cpp
index 52d44d68a24f8fc335d8161b2d5be5a2dd0b106d..3b4ffeea5403d63a07c4f8d31afdac698fb96bfd 100644 (file)
@@ -1,5 +1,5 @@
 /////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////
-// File:        taskbar.cpp
+// File:        src/unix/taskbarx11.cpp
 // Purpose:     wxTaskBarIcon class for common Unix desktops
 // Author:      Vaclav Slavik
 // Modified by:
 // Purpose:     wxTaskBarIcon class for common Unix desktops
 // Author:      Vaclav Slavik
 // Modified by:
@@ -9,19 +9,10 @@
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////
 
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////
 
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
-#pragma implementation "taskbarx11.h"
-#endif
-
-
 // NB: This implementation does *not* work with every X11 window manager.
 // 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 and XFCE 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.
 //
 //     Thanks to Ian Campbell, author of XMMS Status Docklet, for publishing
 //     KDE and GNOME 1.2 methods.
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
+#if wxUSE_TASKBARICON && !defined(__WXGTK20__)
+
 #include "wx/taskbar.h"
 #include "wx/taskbar.h"
-#include "wx/frame.h"
-#include "wx/bitmap.h"
-#include "wx/statbmp.h"
-#include "wx/sizer.h"
+
+#ifndef  WX_PRECOMP
+    #include "wx/log.h"
+    #include "wx/frame.h"
+    #include "wx/dcclient.h"
+    #include "wx/statbmp.h"
+    #include "wx/sizer.h"
+    #include "wx/bitmap.h"
+    #include "wx/image.h"
+#endif
 
 #ifdef __VMS
 #pragma message disable nosimpint
 
 #ifdef __VMS
 #pragma message disable nosimpint
 #pragma message enable nosimpint
 #endif
 
 #pragma message enable nosimpint
 #endif
 
+// ----------------------------------------------------------------------------
+// base class that implements toolkit-specific method:
+// ----------------------------------------------------------------------------
+
+    class WXDLLIMPEXP_ADV wxTaskBarIconAreaBase : public wxFrame
+    {
+    public:
+        wxTaskBarIconAreaBase()
+            : wxFrame(NULL, wxID_ANY, wxT("systray icon"),
+                      wxDefaultPosition, wxDefaultSize,
+                      wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR |
+                      wxSIMPLE_BORDER | wxFRAME_SHAPED) {}
+
+        static bool IsProtocolSupported() { return false; }
+    };
+
 // ----------------------------------------------------------------------------
 // toolkit dependent methods to set properties on helper window:
 // ----------------------------------------------------------------------------
 
 #if defined(__WXGTK__)
 // ----------------------------------------------------------------------------
 // toolkit dependent methods to set properties on helper window:
 // ----------------------------------------------------------------------------
 
 #if defined(__WXGTK__)
-    #include <gdk/gdk.h>
-    #include <gdk/gdkx.h>
     #include <gtk/gtk.h>
     #include <gtk/gtk.h>
+    #include <gdk/gdkx.h>
     #define GetDisplay()        GDK_DISPLAY()
     #define GetXWindow(wxwin)   GDK_WINDOW_XWINDOW((wxwin)->m_widget->window)
 #elif defined(__WXX11__) || defined(__WXMOTIF__)
     #define GetDisplay()        GDK_DISPLAY()
     #define GetXWindow(wxwin)   GDK_WINDOW_XWINDOW((wxwin)->m_widget->window)
 #elif defined(__WXX11__) || defined(__WXMOTIF__)
     #error "You must define X11 accessors for this port!"
 #endif
 
     #error "You must define X11 accessors for this port!"
 #endif
 
+
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
-// code for making wxFrame a toolbar icon by setting appropriate properties:
+// wxTaskBarIconArea is the real window that shows the icon:
 // ----------------------------------------------------------------------------
 
 // ----------------------------------------------------------------------------
 
-static bool wxMakeTaskBarIcon(wxFrame *wnd)
-{ 
+class WXDLLIMPEXP_ADV wxTaskBarIconArea : public wxTaskBarIconAreaBase
+{
+public:
+    wxTaskBarIconArea(wxTaskBarIcon *icon, const wxBitmap &bmp);
+    void SetTrayIcon(const wxBitmap& bmp);
+    bool IsOk() { return true; }
+
+protected:
+    void SetLegacyWMProperties();
+
+    void OnSizeChange(wxSizeEvent& event);
+    void OnPaint(wxPaintEvent& evt);
+    void OnMouseEvent(wxMouseEvent& event);
+    void OnMenuEvent(wxCommandEvent& event);
+
+    wxTaskBarIcon *m_icon;
+    wxPoint        m_pos;
+    wxBitmap       m_bmp;
+
+    DECLARE_EVENT_TABLE()
+};
+
+BEGIN_EVENT_TABLE(wxTaskBarIconArea, wxTaskBarIconAreaBase)
+    EVT_SIZE(wxTaskBarIconArea::OnSizeChange)
+    EVT_MOUSE_EVENTS(wxTaskBarIconArea::OnMouseEvent)
+    EVT_MENU(wxID_ANY, wxTaskBarIconArea::OnMenuEvent)
+    EVT_PAINT(wxTaskBarIconArea::OnPaint)
+END_EVENT_TABLE()
+
+wxTaskBarIconArea::wxTaskBarIconArea(wxTaskBarIcon *icon, const wxBitmap &bmp)
+    : wxTaskBarIconAreaBase(), m_icon(icon), m_bmp(bmp)
+{
+    // Set initial size to bitmap size (tray manager may and often will
+    // change it):
+    SetClientSize(wxSize(bmp.GetWidth(), bmp.GetHeight()));
+
+    SetTrayIcon(bmp);
+
+    if (!IsProtocolSupported())
+    {
+        wxLogTrace(wxT("systray"),
+                   wxT("using legacy KDE1,2 and GNOME 1.2 methods"));
+        SetLegacyWMProperties();
+    }
+}
+
+void wxTaskBarIconArea::SetTrayIcon(const wxBitmap& bmp)
+{
+    m_bmp = bmp;
+
+    // determine suitable bitmap size:
+    wxSize winsize(GetClientSize());
+    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);
+    }
+
+    wxRegion region;
+    region.Union(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__
 #ifdef __WXGTK__
-    gtk_widget_realize(wnd->m_widget);
+    gtk_widget_realize(m_widget);
 #endif
 #endif
-    
+
     long data[1];
     long data[1];
-    
+
     // KDE 2 & KDE 3:
     Atom _KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR =
         XInternAtom(GetDisplay(), "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False);
     data[0] = 0;
     // KDE 2 & KDE 3:
     Atom _KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR =
         XInternAtom(GetDisplay(), "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False);
     data[0] = 0;
-    XChangeProperty(GetDisplay(), GetXWindow(wnd),
+    XChangeProperty(GetDisplay(), GetXWindow(this),
                     _KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR,
                     XA_WINDOW, 32,
                     PropModeReplace, (unsigned char*)data, 1);
                     _KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR,
                     XA_WINDOW, 32,
                     PropModeReplace, (unsigned char*)data, 1);
@@ -88,44 +182,32 @@ static bool wxMakeTaskBarIcon(wxFrame *wnd)
     Atom KWM_DOCKWINDOW =
         XInternAtom(GetDisplay(), "KWM_DOCKWINDOW", False);
     data[0] = 1;
     Atom KWM_DOCKWINDOW =
         XInternAtom(GetDisplay(), "KWM_DOCKWINDOW", False);
     data[0] = 1;
-    XChangeProperty(GetDisplay(), GetXWindow(wnd),
+    XChangeProperty(GetDisplay(), GetXWindow(this),
                     KWM_DOCKWINDOW,
                     KWM_DOCKWINDOW, 32,
                     PropModeReplace, (unsigned char*)data, 1);
                     KWM_DOCKWINDOW,
                     KWM_DOCKWINDOW, 32,
                     PropModeReplace, (unsigned char*)data, 1);
-
-    return true;
 }
 }
-    
-// ----------------------------------------------------------------------------
-// wxTaskBarIconArea is the real window that shows the icon:
-// ----------------------------------------------------------------------------
 
 
-class wxTaskBarIconArea : public wxStaticBitmap
+void wxTaskBarIconArea::OnSizeChange(wxSizeEvent& WXUNUSED(event))
 {
 {
-public:
-    wxTaskBarIconArea(wxTaskBarIcon *icon,
-                      wxWindow *parent, const wxBitmap &bmp)
-        : wxStaticBitmap(parent, -1, bmp), m_icon(icon) {}
-
-protected:
-    void OnMouseEvent(wxMouseEvent& event);
-    void OnMenuEvent(wxCommandEvent& event);
+    wxLogTrace(wxT("systray"), wxT("icon size changed to %i x %i"),
+               GetSize().x, GetSize().y);
+    // rescale or reposition the icon as needed:
+    wxBitmap bmp(m_bmp);
+    SetTrayIcon(bmp);
+}
 
 
-    wxTaskBarIcon *m_icon;
-    
-    DECLARE_EVENT_TABLE()
-};
+void wxTaskBarIconArea::OnPaint(wxPaintEvent& WXUNUSED(event))
+{
+    wxPaintDC dc(this);
+    dc.DrawBitmap(m_bmp, m_pos.x, m_pos.y, true);
+}
 
 
-BEGIN_EVENT_TABLE(wxTaskBarIconArea, wxStaticBitmap)    
-    EVT_MOUSE_EVENTS(wxTaskBarIconArea::OnMouseEvent)
-    EVT_MENU(-1, wxTaskBarIconArea::OnMenuEvent)
-END_EVENT_TABLE()
-    
 void wxTaskBarIconArea::OnMouseEvent(wxMouseEvent& event)
 {
     wxEventType type = 0;
     wxEventType mtype = event.GetEventType();
 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)
     if (mtype == wxEVT_LEFT_DOWN)
         type = wxEVT_TASKBAR_LEFT_DOWN;
     else if (mtype == wxEVT_LEFT_UP)
@@ -148,10 +230,19 @@ void wxTaskBarIconArea::OnMouseEvent(wxMouseEvent& event)
 }
 
 void wxTaskBarIconArea::OnMenuEvent(wxCommandEvent& event)
 }
 
 void wxTaskBarIconArea::OnMenuEvent(wxCommandEvent& event)
-{    
+{
     m_icon->ProcessEvent(event);
 }
 
     m_icon->ProcessEvent(event);
 }
 
+// ----------------------------------------------------------------------------
+// wxTaskBarIconBase class:
+// ----------------------------------------------------------------------------
+
+bool wxTaskBarIconBase::IsAvailable()
+{
+    return wxTaskBarIconArea::IsProtocolSupported();
+}
+
 // ----------------------------------------------------------------------------
 // wxTaskBarIcon class:
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // wxTaskBarIcon class:
 // ----------------------------------------------------------------------------
@@ -165,7 +256,11 @@ wxTaskBarIcon::wxTaskBarIcon() : m_iconWnd(NULL)
 wxTaskBarIcon::~wxTaskBarIcon()
 {
     if (m_iconWnd)
 wxTaskBarIcon::~wxTaskBarIcon()
 {
     if (m_iconWnd)
+    {
+        m_iconWnd->Disconnect(wxEVT_DESTROY,
+            wxWindowDestroyEventHandler(wxTaskBarIcon::OnDestroy), NULL, this);
         RemoveIcon();
         RemoveIcon();
+    }
 }
 
 bool wxTaskBarIcon::IsOk() const
 }
 
 bool wxTaskBarIcon::IsOk() const
@@ -178,43 +273,50 @@ bool wxTaskBarIcon::IsIconInstalled() const
     return m_iconWnd != NULL;
 }
 
     return m_iconWnd != NULL;
 }
 
-bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip)
+// Destroy event from wxTaskBarIconArea
+void wxTaskBarIcon::OnDestroy(wxWindowDestroyEvent&)
 {
 {
-    if (m_iconWnd)
-        RemoveIcon();
+    // prevent crash if wxTaskBarIconArea is destroyed by something else,
+    // for example if panel/kicker is killed
+    m_iconWnd = NULL;
+}
 
 
-    m_iconWnd = new wxFrame(NULL, -1, wxT("taskbar icon"),
-                            wxDefaultPosition, wxDefaultSize,
-                            wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR);
+bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip)
+{
     wxBitmap bmp;
     bmp.CopyFromIcon(icon);
     wxBitmap bmp;
     bmp.CopyFromIcon(icon);
-    wxTaskBarIconArea *area = new wxTaskBarIconArea(this, m_iconWnd, bmp);
-
-    // make a sizer to keep the icon centered, in case it is smaller than the
-    // alotted space.
-    wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
-    sizer->Add(0,0,1);
-    sizer->Add(area, 0, wxALIGN_CENTER);
-    sizer->Add(0,0,1);
-    m_iconWnd->SetSizer(sizer);
-    
-    m_iconWnd->SetClientSize(area->GetSize());
-#if wxUSE_TOOLTIPS
-    if (!tooltip.empty())
-        area->SetToolTip(tooltip);
-#endif
-    if (wxMakeTaskBarIcon(m_iconWnd))
+
+    if (!m_iconWnd)
     {
     {
-        m_iconWnd->Show();
-        m_iconArea = area;
-        return true;
+        m_iconWnd = new wxTaskBarIconArea(this, bmp);
+        if (m_iconWnd->IsOk())
+        {
+            m_iconWnd->Connect(wxEVT_DESTROY,
+                wxWindowDestroyEventHandler(wxTaskBarIcon::OnDestroy),
+                NULL, this);
+            m_iconWnd->Show();
+        }
+        else
+        {
+            m_iconWnd->Destroy();
+            m_iconWnd = NULL;
+            return false;
+        }
     }
     else
     {
     }
     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);
+#else
+    wxUnusedVar(tooltip);
+#endif
+    return true;
 }
 
 bool wxTaskBarIcon::RemoveIcon()
 }
 
 bool wxTaskBarIcon::RemoveIcon()
@@ -230,7 +332,8 @@ bool wxTaskBarIcon::PopupMenu(wxMenu *menu)
 {
     if (!m_iconWnd)
         return false;
 {
     if (!m_iconWnd)
         return false;
-    wxSize size(m_iconArea->GetSize());
-    m_iconArea->PopupMenu(menu, size.x/2, size.y/2);
+    m_iconWnd->PopupMenu(menu);
     return true;
 }
     return true;
 }
+
+#endif // wxUSE_TASKBARICON