X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/fb29dcac01af849053d8f85b69aae7e7ca8c7d26..820c05dfd61d43c5a6d58e5d91951ff91fa8d505:/src/unix/taskbarx11.cpp?ds=sidebyside diff --git a/src/unix/taskbarx11.cpp b/src/unix/taskbarx11.cpp index 1d01758c9f..0978d60c1a 100644 --- a/src/unix/taskbarx11.cpp +++ b/src/unix/taskbarx11.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// File: taskbar.cpp +// File: src/unix/taskbarx11.cpp // Purpose: wxTaskBarIcon class for common Unix desktops // Author: Vaclav Slavik // Modified by: @@ -9,19 +9,10 @@ // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#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. @@ -30,10 +21,19 @@ // 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" + +#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 @@ -44,14 +44,29 @@ #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 - #include #include + #include #define GetDisplay() GDK_DISPLAY() #define GetXWindow(wxwin) GDK_WINDOW_XWINDOW((wxwin)->m_widget->window) #elif defined(__WXX11__) || defined(__WXMOTIF__) @@ -62,23 +77,103 @@ #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); @@ -87,44 +182,32 @@ static bool wxMakeTaskBarIcon(wxFrame *wnd) 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) @@ -147,10 +230,19 @@ void wxTaskBarIconArea::OnMouseEvent(wxMouseEvent& event) } void wxTaskBarIconArea::OnMenuEvent(wxCommandEvent& event) -{ +{ m_icon->ProcessEvent(event); } +// ---------------------------------------------------------------------------- +// wxTaskBarIconBase class: +// ---------------------------------------------------------------------------- + +bool wxTaskBarIconBase::IsAvailable() +{ + return wxTaskBarIconArea::IsProtocolSupported(); +} + // ---------------------------------------------------------------------------- // wxTaskBarIcon class: // ---------------------------------------------------------------------------- @@ -164,7 +256,11 @@ wxTaskBarIcon::wxTaskBarIcon() : m_iconWnd(NULL) wxTaskBarIcon::~wxTaskBarIcon() { if (m_iconWnd) + { + m_iconWnd->Disconnect(wxEVT_DESTROY, + wxWindowDestroyEventHandler(wxTaskBarIcon::OnDestroy), NULL, this); RemoveIcon(); + } } bool wxTaskBarIcon::IsOk() const @@ -177,34 +273,50 @@ bool wxTaskBarIcon::IsIconInstalled() 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); - 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() @@ -220,7 +332,8 @@ bool wxTaskBarIcon::PopupMenu(wxMenu *menu) { 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