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