/////////////////////////////////////////////////////////////////////////
-// File: taskbar.cpp
+// File: src/unix/taskbarx11.cpp
// Purpose: wxTaskBarIcon class for common Unix desktops
// Author: Vaclav Slavik
// Modified by:
// 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.
-// 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.
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
+#if wxUSE_TASKBARICON && !defined(__WXGTK20__)
+
#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
#pragma message enable nosimpint
#endif
+// ----------------------------------------------------------------------------
+// base class that implements toolkit-specific method:
+// ----------------------------------------------------------------------------
+
+ 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) {}
+
+ static bool IsProtocolSupported() { return false; }
+ };
+
// ----------------------------------------------------------------------------
// 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 <gdk/gdkx.h>
#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
+
// ----------------------------------------------------------------------------
-// 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(_T("systray"),
+ _T("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__
- gtk_widget_realize(wnd->m_widget);
+ gtk_widget_realize(m_widget);
#endif
-
+
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;
- XChangeProperty(GetDisplay(), GetXWindow(wnd),
+ XChangeProperty(GetDisplay(), GetXWindow(this),
_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR,
XA_WINDOW, 32,
PropModeReplace, (unsigned char*)data, 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);
-
- 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(_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);
+}
- 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();
-
+
if (mtype == wxEVT_LEFT_DOWN)
type = wxEVT_TASKBAR_LEFT_DOWN;
else if (mtype == wxEVT_LEFT_UP)
}
void wxTaskBarIconArea::OnMenuEvent(wxCommandEvent& event)
-{
+{
m_icon->ProcessEvent(event);
}
+// ----------------------------------------------------------------------------
+// wxTaskBarIconBase class:
+// ----------------------------------------------------------------------------
+
+bool wxTaskBarIconBase::IsAvailable()
+{
+ return wxTaskBarIconArea::IsProtocolSupported();
+}
+
// ----------------------------------------------------------------------------
// wxTaskBarIcon class:
// ----------------------------------------------------------------------------
wxTaskBarIcon::~wxTaskBarIcon()
{
if (m_iconWnd)
+ {
+ m_iconWnd->Disconnect(wxEVT_DESTROY,
+ wxWindowDestroyEventHandler(wxTaskBarIcon::OnDestroy), NULL, this);
RemoveIcon();
+ }
}
bool wxTaskBarIcon::IsOk() const
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);
- 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
{
- 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()
{
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;
}
+
+#endif // wxUSE_TASKBARICON