| 1 | ///////////////////////////////////////////////////////////////////////// |
| 2 | // File: taskbar.cpp |
| 3 | // Purpose: wxTaskBarIcon class for common Unix desktops |
| 4 | // Author: Vaclav Slavik |
| 5 | // Modified by: |
| 6 | // Created: 04/04/2003 |
| 7 | // RCS-ID: $Id$ |
| 8 | // Copyright: (c) Vaclav Slavik, 2003 |
| 9 | // Licence: wxWindows licence |
| 10 | ///////////////////////////////////////////////////////////////////////// |
| 11 | |
| 12 | #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) |
| 13 | #pragma implementation "taskbarx11.h" |
| 14 | #endif |
| 15 | |
| 16 | // NB: This implementation does *not* work with every X11 window manager. |
| 17 | // Currently only GNOME 1.2 and KDE 1,2,3 methods are implemented here. |
| 18 | // Freedesktop.org's System Tray specification is implemented in |
| 19 | // src/gtk/taskbar.cpp and used from here under wxGTK. |
| 20 | // |
| 21 | // Thanks to Ian Campbell, author of XMMS Status Docklet, for publishing |
| 22 | // KDE and GNOME 1.2 methods. |
| 23 | |
| 24 | |
| 25 | // For compilers that support precompilation, includes "wx.h". |
| 26 | #include "wx/wxprec.h" |
| 27 | |
| 28 | #include "wx/taskbar.h" |
| 29 | #include "wx/frame.h" |
| 30 | #include "wx/bitmap.h" |
| 31 | #include "wx/statbmp.h" |
| 32 | #include "wx/sizer.h" |
| 33 | #include "wx/dcclient.h" |
| 34 | #include "wx/log.h" |
| 35 | #include "wx/image.h" |
| 36 | |
| 37 | #ifdef __VMS |
| 38 | #pragma message disable nosimpint |
| 39 | #endif |
| 40 | #include <X11/Xlib.h> |
| 41 | #include <X11/Xatom.h> |
| 42 | #ifdef __VMS |
| 43 | #pragma message enable nosimpint |
| 44 | #endif |
| 45 | |
| 46 | // ---------------------------------------------------------------------------- |
| 47 | // base class that implements toolkit-specific method: |
| 48 | // ---------------------------------------------------------------------------- |
| 49 | |
| 50 | #ifdef __WXGTK20__ |
| 51 | #include "wx/gtk/taskbarpriv.h" |
| 52 | #else |
| 53 | class WXDLLIMPEXP_ADV wxTaskBarIconAreaBase : public wxFrame |
| 54 | { |
| 55 | public: |
| 56 | wxTaskBarIconAreaBase() |
| 57 | : wxFrame(NULL, wxID_ANY, _T("systray icon"), |
| 58 | wxDefaultPosition, wxDefaultSize, |
| 59 | wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR | |
| 60 | wxSIMPLE_BORDER | wxFRAME_SHAPED) {} |
| 61 | |
| 62 | bool IsProtocolSupported() const { return false; } |
| 63 | }; |
| 64 | #endif |
| 65 | |
| 66 | |
| 67 | // ---------------------------------------------------------------------------- |
| 68 | // toolkit dependent methods to set properties on helper window: |
| 69 | // ---------------------------------------------------------------------------- |
| 70 | |
| 71 | #if defined(__WXGTK__) |
| 72 | #include <gdk/gdk.h> |
| 73 | #include <gdk/gdkx.h> |
| 74 | #include <gtk/gtk.h> |
| 75 | #define GetDisplay() GDK_DISPLAY() |
| 76 | #define GetXWindow(wxwin) GDK_WINDOW_XWINDOW((wxwin)->m_widget->window) |
| 77 | #elif defined(__WXX11__) || defined(__WXMOTIF__) |
| 78 | #include "wx/x11/privx.h" |
| 79 | #define GetDisplay() ((Display*)wxGlobalDisplay()) |
| 80 | #define GetXWindow(wxwin) ((Window)(wxwin)->GetHandle()) |
| 81 | #else |
| 82 | #error "You must define X11 accessors for this port!" |
| 83 | #endif |
| 84 | |
| 85 | |
| 86 | // ---------------------------------------------------------------------------- |
| 87 | // wxTaskBarIconArea is the real window that shows the icon: |
| 88 | // ---------------------------------------------------------------------------- |
| 89 | |
| 90 | class WXDLLIMPEXP_ADV wxTaskBarIconArea : public wxTaskBarIconAreaBase |
| 91 | { |
| 92 | public: |
| 93 | wxTaskBarIconArea(wxTaskBarIcon *icon, const wxBitmap &bmp); |
| 94 | void SetTrayIcon(const wxBitmap& bmp); |
| 95 | bool IsOk() { return true; } |
| 96 | |
| 97 | protected: |
| 98 | void SetLegacyWMProperties(); |
| 99 | |
| 100 | void OnSizeChange(wxSizeEvent& event); |
| 101 | void OnPaint(wxPaintEvent& evt); |
| 102 | void OnMouseEvent(wxMouseEvent& event); |
| 103 | void OnMenuEvent(wxCommandEvent& event); |
| 104 | |
| 105 | wxTaskBarIcon *m_icon; |
| 106 | wxPoint m_pos; |
| 107 | wxBitmap m_bmp; |
| 108 | |
| 109 | DECLARE_EVENT_TABLE() |
| 110 | }; |
| 111 | |
| 112 | BEGIN_EVENT_TABLE(wxTaskBarIconArea, wxTaskBarIconAreaBase) |
| 113 | EVT_SIZE(wxTaskBarIconArea::OnSizeChange) |
| 114 | EVT_MOUSE_EVENTS(wxTaskBarIconArea::OnMouseEvent) |
| 115 | EVT_MENU(-1, wxTaskBarIconArea::OnMenuEvent) |
| 116 | EVT_PAINT(wxTaskBarIconArea::OnPaint) |
| 117 | END_EVENT_TABLE() |
| 118 | |
| 119 | wxTaskBarIconArea::wxTaskBarIconArea(wxTaskBarIcon *icon, const wxBitmap &bmp) |
| 120 | : wxTaskBarIconAreaBase(), m_icon(icon), m_pos(0,0) |
| 121 | { |
| 122 | if (!IsProtocolSupported()) |
| 123 | { |
| 124 | wxLogTrace(_T("systray"), |
| 125 | _T("using legacy KDE1,2 and GNOME 1.2 methods")); |
| 126 | SetLegacyWMProperties(); |
| 127 | } |
| 128 | |
| 129 | // Set initial size to bitmap size (tray manager may and often will |
| 130 | // change it): |
| 131 | SetSize(wxSize(bmp.GetWidth(), bmp.GetHeight())); |
| 132 | |
| 133 | SetTrayIcon(bmp); |
| 134 | } |
| 135 | |
| 136 | void wxTaskBarIconArea::SetTrayIcon(const wxBitmap& bmp) |
| 137 | { |
| 138 | m_bmp = bmp; |
| 139 | |
| 140 | // determine suitable bitmap size: |
| 141 | wxSize winsize(GetSize()); |
| 142 | wxSize bmpsize(m_bmp.GetWidth(), m_bmp.GetHeight()); |
| 143 | wxSize iconsize(wxMin(winsize.x, bmpsize.x), wxMin(winsize.y, bmpsize.y)); |
| 144 | |
| 145 | // rescale the bitmap to fit into the tray icon window: |
| 146 | if (bmpsize != iconsize) |
| 147 | { |
| 148 | wxImage img = m_bmp.ConvertToImage(); |
| 149 | img.Rescale(iconsize.x, iconsize.y); |
| 150 | m_bmp = wxBitmap(img); |
| 151 | } |
| 152 | |
| 153 | wxRegion region; |
| 154 | region.Union(m_bmp); |
| 155 | |
| 156 | // if the bitmap is smaller than the window, offset it: |
| 157 | if (winsize != iconsize) |
| 158 | { |
| 159 | m_pos.x = (winsize.x - iconsize.x) / 2; |
| 160 | m_pos.y = (winsize.y - iconsize.y) / 2; |
| 161 | region.Offset(m_pos.x, m_pos.y); |
| 162 | } |
| 163 | |
| 164 | // set frame's shape to correct value and redraw: |
| 165 | SetShape(region); |
| 166 | Refresh(); |
| 167 | } |
| 168 | |
| 169 | void wxTaskBarIconArea::SetLegacyWMProperties() |
| 170 | { |
| 171 | #ifdef __WXGTK__ |
| 172 | gtk_widget_realize(m_widget); |
| 173 | #endif |
| 174 | |
| 175 | long data[1]; |
| 176 | |
| 177 | // KDE 2 & KDE 3: |
| 178 | Atom _KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR = |
| 179 | XInternAtom(GetDisplay(), "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False); |
| 180 | data[0] = 0; |
| 181 | XChangeProperty(GetDisplay(), GetXWindow(this), |
| 182 | _KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR, |
| 183 | XA_WINDOW, 32, |
| 184 | PropModeReplace, (unsigned char*)data, 1); |
| 185 | |
| 186 | // GNOME 1.2 & KDE 1: |
| 187 | Atom KWM_DOCKWINDOW = |
| 188 | XInternAtom(GetDisplay(), "KWM_DOCKWINDOW", False); |
| 189 | data[0] = 1; |
| 190 | XChangeProperty(GetDisplay(), GetXWindow(this), |
| 191 | KWM_DOCKWINDOW, |
| 192 | KWM_DOCKWINDOW, 32, |
| 193 | PropModeReplace, (unsigned char*)data, 1); |
| 194 | } |
| 195 | |
| 196 | void wxTaskBarIconArea::OnSizeChange(wxSizeEvent& event) |
| 197 | { |
| 198 | wxLogTrace(_T("systray"), _T("icon size changed to %i x %i"), |
| 199 | GetSize().x, GetSize().y); |
| 200 | // rescale or reposition the icon as needed: |
| 201 | wxBitmap bmp(m_bmp); |
| 202 | SetTrayIcon(bmp); |
| 203 | } |
| 204 | |
| 205 | void wxTaskBarIconArea::OnPaint(wxPaintEvent& WXUNUSED(event)) |
| 206 | { |
| 207 | wxPaintDC dc(this); |
| 208 | dc.DrawBitmap(m_bmp, m_pos.x, m_pos.y, true); |
| 209 | } |
| 210 | |
| 211 | void wxTaskBarIconArea::OnMouseEvent(wxMouseEvent& event) |
| 212 | { |
| 213 | wxEventType type = 0; |
| 214 | wxEventType mtype = event.GetEventType(); |
| 215 | |
| 216 | if (mtype == wxEVT_LEFT_DOWN) |
| 217 | type = wxEVT_TASKBAR_LEFT_DOWN; |
| 218 | else if (mtype == wxEVT_LEFT_UP) |
| 219 | type = wxEVT_TASKBAR_LEFT_UP; |
| 220 | else if (mtype == wxEVT_LEFT_DCLICK) |
| 221 | type = wxEVT_TASKBAR_LEFT_DCLICK; |
| 222 | else if (mtype == wxEVT_RIGHT_DOWN) |
| 223 | type = wxEVT_TASKBAR_RIGHT_DOWN; |
| 224 | else if (mtype == wxEVT_RIGHT_UP) |
| 225 | type = wxEVT_TASKBAR_RIGHT_UP; |
| 226 | else if (mtype == wxEVT_RIGHT_DCLICK) |
| 227 | type = wxEVT_TASKBAR_RIGHT_DCLICK; |
| 228 | else if (mtype == wxEVT_MOTION) |
| 229 | type = wxEVT_TASKBAR_MOVE; |
| 230 | else |
| 231 | return; |
| 232 | |
| 233 | wxTaskBarIconEvent e(type, m_icon); |
| 234 | m_icon->ProcessEvent(e); |
| 235 | } |
| 236 | |
| 237 | void wxTaskBarIconArea::OnMenuEvent(wxCommandEvent& event) |
| 238 | { |
| 239 | m_icon->ProcessEvent(event); |
| 240 | } |
| 241 | |
| 242 | // ---------------------------------------------------------------------------- |
| 243 | // wxTaskBarIcon class: |
| 244 | // ---------------------------------------------------------------------------- |
| 245 | |
| 246 | IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler) |
| 247 | |
| 248 | wxTaskBarIcon::wxTaskBarIcon() : m_iconWnd(NULL) |
| 249 | { |
| 250 | } |
| 251 | |
| 252 | wxTaskBarIcon::~wxTaskBarIcon() |
| 253 | { |
| 254 | if (m_iconWnd) |
| 255 | RemoveIcon(); |
| 256 | } |
| 257 | |
| 258 | bool wxTaskBarIcon::IsOk() const |
| 259 | { |
| 260 | return true; |
| 261 | } |
| 262 | |
| 263 | bool wxTaskBarIcon::IsIconInstalled() const |
| 264 | { |
| 265 | return m_iconWnd != NULL; |
| 266 | } |
| 267 | |
| 268 | bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip) |
| 269 | { |
| 270 | wxBitmap bmp; |
| 271 | bmp.CopyFromIcon(icon); |
| 272 | |
| 273 | if (!m_iconWnd) |
| 274 | { |
| 275 | m_iconWnd = new wxTaskBarIconArea(this, bmp); |
| 276 | if (m_iconWnd->IsOk()) |
| 277 | { |
| 278 | m_iconWnd->Show(); |
| 279 | } |
| 280 | else |
| 281 | { |
| 282 | m_iconWnd->Destroy(); |
| 283 | m_iconWnd = NULL; |
| 284 | return false; |
| 285 | } |
| 286 | } |
| 287 | else |
| 288 | { |
| 289 | m_iconWnd->SetTrayIcon(bmp); |
| 290 | } |
| 291 | |
| 292 | #if wxUSE_TOOLTIPS |
| 293 | if (!tooltip.empty()) |
| 294 | m_iconWnd->SetToolTip(tooltip); |
| 295 | else |
| 296 | m_iconWnd->SetToolTip(NULL); |
| 297 | #endif |
| 298 | return true; |
| 299 | } |
| 300 | |
| 301 | bool wxTaskBarIcon::RemoveIcon() |
| 302 | { |
| 303 | if (!m_iconWnd) |
| 304 | return false; |
| 305 | m_iconWnd->Destroy(); |
| 306 | m_iconWnd = NULL; |
| 307 | return true; |
| 308 | } |
| 309 | |
| 310 | bool wxTaskBarIcon::PopupMenu(wxMenu *menu) |
| 311 | { |
| 312 | if (!m_iconWnd) |
| 313 | return false; |
| 314 | m_iconWnd->PopupMenu(menu); |
| 315 | return true; |
| 316 | } |