]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/taskbar.cpp
attempt to get the 'new focus' window parameter of a focus kill event set correctly
[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
VS
6// Created: 2004/05/29
7// RCS-ID: $Id$
8// Copyright: (c) Vaclav Slavik, 2004
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////
11
33d4eef0
VS
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
7669dce5 15#if wxUSE_TASKBARICON
4f167b46 16
a1c6f069 17#include "wx/taskbar.h"
e4db172a
WS
18
19#ifndef WX_PRECOMP
a1c6f069 20 #include "wx/toplevel.h"
3b3dc801 21 #include "wx/menu.h"
a1c6f069 22 #include "wx/icon.h"
e4db172a
WS
23#endif
24
290cd301 25#include <gtk/gtk.h>
9dc44eff
PC
26#ifdef GDK_WINDOWING_X11
27 #include <gdk/gdkx.h>
28#endif
29#ifndef __WXGTK3__
30 #include "eggtrayicon.h"
31#endif
5dc22463 32
7669dce5
PC
33#if !GTK_CHECK_VERSION(2,10,0)
34 typedef struct _GtkStatusIcon GtkStatusIcon;
35#endif
36
a1c6f069
PC
37class wxTaskBarIcon::Private
38{
39public:
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;
a1c6f069
PC
49 // for PopupMenu
50 wxWindow* m_win;
a1c6f069
PC
51 wxBitmap m_bitmap;
52 wxString m_tipText;
9dc44eff
PC
53#ifndef __WXGTK3__
54 // used when GTK+ < 2.10
55 GtkWidget* m_eggTrayIcon;
56 // for tooltip when GTK+ < 2.10
57 GtkTooltips* m_tooltips;
a1c6f069
PC
58 // width and height of available space, only used when GTK+ < 2.10
59 int m_size;
9dc44eff 60#endif
a1c6f069
PC
61};
62//-----------------------------------------------------------------------------
33d4eef0 63
a1c6f069 64extern "C" {
9dc44eff 65#ifndef __WXGTK3__
a1c6f069
PC
66static void
67icon_size_allocate(GtkWidget*, GtkAllocation* alloc, wxTaskBarIcon::Private* priv)
33d4eef0 68{
a1c6f069
PC
69 priv->size_allocate(alloc->width, alloc->height);
70}
3d257b8d 71
a1c6f069
PC
72static void
73icon_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}
9dc44eff 80#endif
3d257b8d 81
a1c6f069
PC
82static void
83icon_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}
3d257b8d 94
a1c6f069
PC
95static gboolean
96icon_popup_menu(GtkWidget*, wxTaskBarIcon* taskBarIcon)
97{
98 wxTaskBarIconEvent event(wxEVT_TASKBAR_CLICK, taskBarIcon);
99 taskBarIcon->SafelyProcessEvent(event);
100 return true;
101}
53e3cd04 102
9dc44eff 103#ifndef __WXGTK3__
a1c6f069
PC
104static gboolean
105icon_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;
33d4eef0 115}
9dc44eff 116#endif
33d4eef0 117
a1c6f069
PC
118#if GTK_CHECK_VERSION(2,10,0)
119static void
120status_icon_popup_menu(GtkStatusIcon*, guint, guint, wxTaskBarIcon* taskBarIcon)
33d4eef0 121{
a1c6f069
PC
122 icon_popup_menu(NULL, taskBarIcon);
123}
124#endif
125} // extern "C"
126//-----------------------------------------------------------------------------
3d257b8d 127
a1c6f069
PC
128bool wxTaskBarIconBase::IsAvailable()
129{
3b81515c 130#ifdef GDK_WINDOWING_X11
61f6ba07
VS
131 char name[32];
132 g_snprintf(name, sizeof(name), "_NET_SYSTEM_TRAY_S%d",
a1c6f069
PC
133 gdk_x11_get_default_screen());
134 Atom atom = gdk_x11_get_xatom_by_name(name);
3d257b8d 135
a1c6f069 136 Window manager = XGetSelectionOwner(gdk_x11_get_default_xdisplay(), atom);
3d257b8d 137
a1c6f069 138 return manager != None;
3b81515c
VZ
139#else
140 return true;
141#endif
33d4eef0 142}
0bd3b8ec 143//-----------------------------------------------------------------------------
a1c6f069
PC
144
145wxTaskBarIcon::Private::Private(wxTaskBarIcon* taskBarIcon)
146{
147 m_taskBarIcon = taskBarIcon;
148 m_statusIcon = NULL;
a1c6f069 149 m_win = NULL;
9dc44eff
PC
150#ifndef __WXGTK3__
151 m_eggTrayIcon = NULL;
a1c6f069
PC
152 m_tooltips = NULL;
153 m_size = 0;
9dc44eff 154#endif
a1c6f069
PC
155}
156
157wxTaskBarIcon::Private::~Private()
158{
159 if (m_statusIcon)
160 g_object_unref(m_statusIcon);
9dc44eff 161#ifndef __WXGTK3__
a1c6f069
PC
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 }
9dc44eff 167#endif
a1c6f069
PC
168 if (m_win)
169 {
170 m_win->PopEventHandler();
171 m_win->Destroy();
172 }
9dc44eff 173#ifndef __WXGTK3__
a1c6f069
PC
174 if (m_tooltips)
175 {
176 gtk_object_destroy(GTK_OBJECT(m_tooltips));
177 g_object_unref(m_tooltips);
178 }
9dc44eff 179#endif
a1c6f069
PC
180}
181
182void wxTaskBarIcon::Private::SetIcon()
183{
184#if GTK_CHECK_VERSION(2,10,0)
9dc44eff 185 if (GTK_CHECK_VERSION(3,0,0) || gtk_check_version(2,10,0) == NULL)
a1c6f069
PC
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 {
9dc44eff 201#ifndef __WXGTK3__
a1c6f069
PC
202 m_size = 0;
203 if (m_eggTrayIcon)
204 {
385e8575 205 GtkWidget* image = gtk_bin_get_child(GTK_BIN(m_eggTrayIcon));
a1c6f069
PC
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 }
9dc44eff 224#endif
a1c6f069
PC
225 }
226#if wxUSE_TOOLTIPS
70ef48fe 227 const char *tip_text = NULL;
a1c6f069 228 if (!m_tipText.empty())
c3b0697e 229 tip_text = m_tipText.utf8_str();
a1c6f069
PC
230
231#if GTK_CHECK_VERSION(2,10,0)
232 if (m_statusIcon)
385e8575
PC
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 {
9dc44eff 240#ifndef __WXGTK3__
385e8575 241 gtk_status_icon_set_tooltip(m_statusIcon, tip_text);
a1c6f069 242#endif
385e8575
PC
243 }
244 }
245 else
246#endif // GTK_CHECK_VERSION(2,10,0)
a1c6f069 247 {
9dc44eff 248#ifndef __WXGTK3__
a1c6f069
PC
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, "");
385e8575 257#endif
a1c6f069
PC
258 }
259#endif // wxUSE_TOOLTIPS
260}
261
9dc44eff 262#ifndef __WXGTK3__
a1c6f069
PC
263void 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);
385e8575 280 GtkImage* image = GTK_IMAGE(gtk_bin_get_child(GTK_BIN(m_eggTrayIcon)));
a1c6f069
PC
281 gtk_image_set_from_pixbuf(image, pixbuf);
282 g_object_unref(pixbuf);
283 }
284}
9dc44eff 285#endif
0bd3b8ec
RR
286//-----------------------------------------------------------------------------
287
a1c6f069
PC
288IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler)
289
70175534 290wxTaskBarIcon::wxTaskBarIcon(wxTaskBarIconType WXUNUSED(iconType))
a1c6f069
PC
291{
292 m_priv = new Private(this);
293}
294
295wxTaskBarIcon::~wxTaskBarIcon()
296{
297 delete m_priv;
298}
299
300bool 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
308bool wxTaskBarIcon::RemoveIcon()
309{
310 delete m_priv;
311 m_priv = new Private(this);
312 return true;
313}
314
315bool wxTaskBarIcon::IsIconInstalled() const
0bd3b8ec 316{
9dc44eff
PC
317#ifdef __WXGTK3__
318 return m_priv->m_statusIcon != NULL;
319#else
a1c6f069 320 return m_priv->m_statusIcon || m_priv->m_eggTrayIcon;
9dc44eff 321#endif
0bd3b8ec 322}
a1c6f069
PC
323
324bool 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
4f167b46 342#endif // wxUSE_TASKBARICON