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