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