1 /////////////////////////////////////////////////////////////////////////
2 // File: src/gtk/taskbar.cpp
3 // Purpose: wxTaskBarIcon
4 // Author: Vaclav Slavik
5 // Modified by: Paul Cornett
6 // Created: 2004/05/29
7 // Copyright: (c) Vaclav Slavik, 2004
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////
10
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13
14 #if wxUSE_TASKBARICON
15
16 #include "wx/taskbar.h"
17
18 #ifndef __WXGTK4__
19
20 #ifndef WX_PRECOMP
21 #include "wx/toplevel.h"
22 #include "wx/menu.h"
23 #include "wx/icon.h"
24 #endif
25
26 #include "wx/gtk/private/wrapgtk.h"
27 #ifdef GDK_WINDOWING_X11
28 #include <gdk/gdkx.h>
29 #endif
30 #ifndef __WXGTK3__
31 #include "eggtrayicon.h"
32 #endif
33
34 wxGCC_WARNING_SUPPRESS(deprecated-declarations)
35
36 #if !GTK_CHECK_VERSION(2,10,0)
37 typedef struct _GtkStatusIcon GtkStatusIcon;
38 #endif
39
40 class wxTaskBarIcon::Private
41 {
42 public:
43 Private(wxTaskBarIcon* taskBarIcon);
44 ~Private();
45 void SetIcon();
46 void size_allocate(int width, int height);
47
48 // owning wxTaskBarIcon
49 wxTaskBarIcon* m_taskBarIcon;
50 // used when GTK+ >= 2.10
51 GtkStatusIcon* m_statusIcon;
52 // for PopupMenu
53 wxWindow* m_win;
54 wxBitmap m_bitmap;
55 wxString m_tipText;
56 #ifndef __WXGTK3__
57 // used when GTK+ < 2.10
58 GtkWidget* m_eggTrayIcon;
59 // for tooltip when GTK+ < 2.10
60 GtkTooltips* m_tooltips;
61 // width and height of available space, only used when GTK+ < 2.10
62 int m_size;
63 #endif
64 };
65 //-----------------------------------------------------------------------------
66
67 extern "C" {
68 #ifndef __WXGTK3__
69 static void
icon_size_allocate(GtkWidget *,GtkAllocation * alloc,wxTaskBarIcon::Private * priv)70 icon_size_allocate(GtkWidget*, GtkAllocation* alloc, wxTaskBarIcon::Private* priv)
71 {
72 priv->size_allocate(alloc->width, alloc->height);
73 }
74
75 static void
icon_destroy(GtkWidget *,wxTaskBarIcon::Private * priv)76 icon_destroy(GtkWidget*, wxTaskBarIcon::Private* priv)
77 {
78 // Icon window destroyed, probably because tray program has died.
79 // Recreate icon so it will appear if tray program is restarted.
80 priv->m_eggTrayIcon = NULL;
81 priv->SetIcon();
82 }
83 #endif
84
85 static void
icon_activate(void *,wxTaskBarIcon * taskBarIcon)86 icon_activate(void*, wxTaskBarIcon* taskBarIcon)
87 {
88 // activate occurs from single click with GTK+
89 wxTaskBarIconEvent event(wxEVT_TASKBAR_LEFT_DOWN, taskBarIcon);
90 if (!taskBarIcon->SafelyProcessEvent(event))
91 {
92 // if single click not handled, send double click for compatibility
93 event.SetEventType(wxEVT_TASKBAR_LEFT_DCLICK);
94 taskBarIcon->SafelyProcessEvent(event);
95 }
96 }
97
98 static gboolean
icon_popup_menu(GtkWidget *,wxTaskBarIcon * taskBarIcon)99 icon_popup_menu(GtkWidget*, wxTaskBarIcon* taskBarIcon)
100 {
101 wxTaskBarIconEvent event(wxEVT_TASKBAR_CLICK, taskBarIcon);
102 taskBarIcon->SafelyProcessEvent(event);
103 return true;
104 }
105
106 #ifndef __WXGTK3__
107 static gboolean
icon_button_press_event(GtkWidget *,GdkEventButton * event,wxTaskBarIcon * taskBarIcon)108 icon_button_press_event(GtkWidget*, GdkEventButton* event, wxTaskBarIcon* taskBarIcon)
109 {
110 if (event->type == GDK_BUTTON_PRESS)
111 {
112 if (event->button == 1)
113 icon_activate(NULL, taskBarIcon);
114 else if (event->button == 3)
115 icon_popup_menu(NULL, taskBarIcon);
116 }
117 return false;
118 }
119 #endif
120
121 #if GTK_CHECK_VERSION(2,10,0)
122 static void
status_icon_popup_menu(GtkStatusIcon *,guint,guint,wxTaskBarIcon * taskBarIcon)123 status_icon_popup_menu(GtkStatusIcon*, guint, guint, wxTaskBarIcon* taskBarIcon)
124 {
125 icon_popup_menu(NULL, taskBarIcon);
126 }
127 #endif
128 } // extern "C"
129 //-----------------------------------------------------------------------------
130
IsAvailable()131 bool wxTaskBarIconBase::IsAvailable()
132 {
133 #ifdef GDK_WINDOWING_X11
134 #ifdef __WXGTK3__
135 GdkDisplay* display = gdk_display_get_default();
136 if (strcmp("GdkX11Display", g_type_name(G_TYPE_FROM_INSTANCE(display))) != 0)
137 return false;
138 #endif
139
140 char name[32];
141 g_snprintf(name, sizeof(name), "_NET_SYSTEM_TRAY_S%d",
142 gdk_x11_get_default_screen());
143 Atom atom = gdk_x11_get_xatom_by_name(name);
144
145 Window manager = XGetSelectionOwner(gdk_x11_get_default_xdisplay(), atom);
146
147 return manager != None;
148 #else
149 return true;
150 #endif
151 }
152 //-----------------------------------------------------------------------------
153
Private(wxTaskBarIcon * taskBarIcon)154 wxTaskBarIcon::Private::Private(wxTaskBarIcon* taskBarIcon)
155 {
156 m_taskBarIcon = taskBarIcon;
157 m_statusIcon = NULL;
158 m_win = NULL;
159 #ifndef __WXGTK3__
160 m_eggTrayIcon = NULL;
161 m_tooltips = NULL;
162 m_size = 0;
163 #endif
164 }
165
~Private()166 wxTaskBarIcon::Private::~Private()
167 {
168 if (m_statusIcon)
169 g_object_unref(m_statusIcon);
170 #ifndef __WXGTK3__
171 else if (m_eggTrayIcon)
172 {
173 g_signal_handlers_disconnect_by_func(m_eggTrayIcon, (void*)icon_destroy, this);
174 gtk_widget_destroy(m_eggTrayIcon);
175 }
176 #endif
177 if (m_win)
178 {
179 m_win->PopEventHandler();
180 m_win->Destroy();
181 }
182 #ifndef __WXGTK3__
183 if (m_tooltips)
184 {
185 gtk_object_destroy(GTK_OBJECT(m_tooltips));
186 g_object_unref(m_tooltips);
187 }
188 #endif
189 }
190
SetIcon()191 void wxTaskBarIcon::Private::SetIcon()
192 {
193 #if GTK_CHECK_VERSION(2,10,0)
194 if (wx_is_at_least_gtk2(10))
195 {
196 if (m_statusIcon)
197 gtk_status_icon_set_from_pixbuf(m_statusIcon, m_bitmap.GetPixbuf());
198 else
199 {
200 m_statusIcon = gtk_status_icon_new_from_pixbuf(m_bitmap.GetPixbuf());
201 g_signal_connect(m_statusIcon, "activate",
202 G_CALLBACK(icon_activate), m_taskBarIcon);
203 g_signal_connect(m_statusIcon, "popup_menu",
204 G_CALLBACK(status_icon_popup_menu), m_taskBarIcon);
205 }
206 }
207 else
208 #endif
209 {
210 #ifndef __WXGTK3__
211 m_size = 0;
212 if (m_eggTrayIcon)
213 {
214 GtkWidget* image = gtk_bin_get_child(GTK_BIN(m_eggTrayIcon));
215 gtk_image_set_from_pixbuf(GTK_IMAGE(image), m_bitmap.GetPixbuf());
216 }
217 else
218 {
219 m_eggTrayIcon = GTK_WIDGET(egg_tray_icon_new("wxTaskBarIcon"));
220 gtk_widget_add_events(m_eggTrayIcon, GDK_BUTTON_PRESS_MASK);
221 g_signal_connect(m_eggTrayIcon, "size_allocate",
222 G_CALLBACK(icon_size_allocate), this);
223 g_signal_connect(m_eggTrayIcon, "destroy",
224 G_CALLBACK(icon_destroy), this);
225 g_signal_connect(m_eggTrayIcon, "button_press_event",
226 G_CALLBACK(icon_button_press_event), m_taskBarIcon);
227 g_signal_connect(m_eggTrayIcon, "popup_menu",
228 G_CALLBACK(icon_popup_menu), m_taskBarIcon);
229 GtkWidget* image = gtk_image_new_from_pixbuf(m_bitmap.GetPixbuf());
230 gtk_container_add(GTK_CONTAINER(m_eggTrayIcon), image);
231 gtk_widget_show_all(m_eggTrayIcon);
232 }
233 #endif
234 }
235 #if wxUSE_TOOLTIPS
236 const char *tip_text = NULL;
237 if (!m_tipText.empty())
238 tip_text = m_tipText.utf8_str();
239
240 #if GTK_CHECK_VERSION(2,10,0)
241 if (m_statusIcon)
242 {
243 #if GTK_CHECK_VERSION(2,16,0)
244 if (wx_is_at_least_gtk2(16))
245 gtk_status_icon_set_tooltip_text(m_statusIcon, tip_text);
246 else
247 #endif
248 {
249 #ifndef __WXGTK3__
250 gtk_status_icon_set_tooltip(m_statusIcon, tip_text);
251 #endif
252 }
253 }
254 else
255 #endif // GTK_CHECK_VERSION(2,10,0)
256 {
257 #ifndef __WXGTK3__
258 if (tip_text && m_tooltips == NULL)
259 {
260 m_tooltips = gtk_tooltips_new();
261 g_object_ref(m_tooltips);
262 gtk_object_sink(GTK_OBJECT(m_tooltips));
263 }
264 if (m_tooltips)
265 gtk_tooltips_set_tip(m_tooltips, m_eggTrayIcon, tip_text, "");
266 #endif
267 }
268 #endif // wxUSE_TOOLTIPS
269 }
270
271 #ifndef __WXGTK3__
size_allocate(int width,int height)272 void wxTaskBarIcon::Private::size_allocate(int width, int height)
273 {
274 int size = height;
275 EggTrayIcon* icon = EGG_TRAY_ICON(m_eggTrayIcon);
276 if (egg_tray_icon_get_orientation(icon) == GTK_ORIENTATION_VERTICAL)
277 size = width;
278 if (m_size == size)
279 return;
280 m_size = size;
281 int w = m_bitmap.GetWidth();
282 int h = m_bitmap.GetHeight();
283 if (w > size || h > size)
284 {
285 if (w > size) w = size;
286 if (h > size) h = size;
287 GdkPixbuf* pixbuf =
288 gdk_pixbuf_scale_simple(m_bitmap.GetPixbuf(), w, h, GDK_INTERP_BILINEAR);
289 GtkImage* image = GTK_IMAGE(gtk_bin_get_child(GTK_BIN(m_eggTrayIcon)));
290 gtk_image_set_from_pixbuf(image, pixbuf);
291 g_object_unref(pixbuf);
292 }
293 }
294 #endif
295 //-----------------------------------------------------------------------------
296
297 wxIMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler);
298
wxTaskBarIcon(wxTaskBarIconType WXUNUSED (iconType))299 wxTaskBarIcon::wxTaskBarIcon(wxTaskBarIconType WXUNUSED(iconType))
300 {
301 m_priv = new Private(this);
302 }
303
~wxTaskBarIcon()304 wxTaskBarIcon::~wxTaskBarIcon()
305 {
306 delete m_priv;
307 }
308
SetIcon(const wxIcon & icon,const wxString & tooltip)309 bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip)
310 {
311 m_priv->m_bitmap = icon;
312 m_priv->m_tipText = tooltip;
313 m_priv->SetIcon();
314 return true;
315 }
316
RemoveIcon()317 bool wxTaskBarIcon::RemoveIcon()
318 {
319 delete m_priv;
320 m_priv = new Private(this);
321 return true;
322 }
323
IsIconInstalled() const324 bool wxTaskBarIcon::IsIconInstalled() const
325 {
326 #ifdef __WXGTK3__
327 return m_priv->m_statusIcon != NULL;
328 #else
329 return m_priv->m_statusIcon || m_priv->m_eggTrayIcon;
330 #endif
331 }
332
PopupMenu(wxMenu * menu)333 bool wxTaskBarIcon::PopupMenu(wxMenu* menu)
334 {
335 #if wxUSE_MENUS
336 if (m_priv->m_win == NULL)
337 {
338 m_priv->m_win = new wxTopLevelWindow(
339 NULL, wxID_ANY, wxString(), wxDefaultPosition, wxDefaultSize, 0);
340 m_priv->m_win->PushEventHandler(this);
341 }
342 wxPoint point(-1, -1);
343 #ifdef __WXUNIVERSAL__
344 point = wxGetMousePosition();
345 #endif
346 m_priv->m_win->PopupMenu(menu, point);
347 #endif // wxUSE_MENUS
348 return true;
349 }
350
351 #else
352 wxIMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler);
353
wxTaskBarIcon(wxTaskBarIconType)354 wxTaskBarIcon::wxTaskBarIcon(wxTaskBarIconType)
355 {
356 m_priv = NULL;
357 }
358
~wxTaskBarIcon()359 wxTaskBarIcon::~wxTaskBarIcon()
360 {
361 }
362
SetIcon(const wxIcon &,const wxString &)363 bool wxTaskBarIcon::SetIcon(const wxIcon&, const wxString&)
364 {
365 return false;
366 }
367
RemoveIcon()368 bool wxTaskBarIcon::RemoveIcon()
369 {
370 return false;
371 }
372
IsIconInstalled() const373 bool wxTaskBarIcon::IsIconInstalled() const
374 {
375 return false;
376 }
377
PopupMenu(wxMenu *)378 bool wxTaskBarIcon::PopupMenu(wxMenu*)
379 {
380 return false;
381 }
382 #endif // __WXGTK4__
383 #endif // wxUSE_TASKBARICON
384