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