1 /* gtkstatusicon.c:
2 *
3 * Copyright (C) 2003 Sun Microsystems, Inc.
4 * Copyright (C) 2005 Hans Breuer <hans@breuer.org>
5 * Copyright (C) 2005 Novell, Inc.
6 * Copyright (C) 2006 Imendio AB
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20 *
21 * Authors:
22 * Mark McLoughlin <mark@skynet.ie>
23 * Hans Breuer <hans@breuer.org>
24 * Tor Lillqvist <tml@novell.com>
25 * Mikael Hallendal <micke@imendio.com>
26 */
27
28 #include "config.h"
29
30 #include <string.h>
31 #include <stdlib.h>
32
33 #define GDK_DISABLE_DEPRECATION_WARNINGS
34 #include "gtkstatusicon.h"
35
36 #include "gtkintl.h"
37 #include "gtkiconhelperprivate.h"
38 #include "gtkmain.h"
39 #include "gtkmarshalers.h"
40 #include "gtksizerequest.h"
41 #include "gtkprivate.h"
42 #include "gtkwidget.h"
43 #include "gtktooltip.h"
44 #include "gtkicontheme.h"
45 #include "gtklabel.h"
46 #include "gtkstylecontextprivate.h"
47 #include "gtktypebuiltins.h"
48
49 #ifdef GDK_WINDOWING_X11
50 #include "gdk/x11/gdkx.h"
51 #include "gtktrayicon.h"
52 #endif
53
54 #ifdef GDK_WINDOWING_WIN32
55 #include "gdk/win32/gdkwin32.h"
56 #define WM_GTK_TRAY_NOTIFICATION (WM_USER+1)
57 #endif
58
59
60 /**
61 * SECTION:gtkstatusicon
62 * @Short_description: Display an icon in the system tray
63 * @Title: GtkStatusIcon
64 *
65 * The “system tray” or notification area is normally used for transient icons
66 * that indicate some special state. For example, a system tray icon might
67 * appear to tell the user that they have new mail, or have an incoming instant
68 * message, or something along those lines. The basic idea is that creating an
69 * icon in the notification area is less annoying than popping up a dialog.
70 *
71 * A #GtkStatusIcon object can be used to display an icon in a “system tray”.
72 * The icon can have a tooltip, and the user can interact with it by
73 * activating it or popping up a context menu.
74 *
75 * It is very important to notice that status icons depend on the existence
76 * of a notification area being available to the user; you should not use status
77 * icons as the only way to convey critical information regarding your application,
78 * as the notification area may not exist on the user's environment, or may have
79 * been removed. You should always check that a status icon has been embedded into
80 * a notification area by using gtk_status_icon_is_embedded(), and gracefully
81 * recover if the function returns %FALSE.
82 *
83 * On X11, the implementation follows the
84 * [FreeDesktop System Tray Specification](http://www.freedesktop.org/wiki/Specifications/systemtray-spec).
85 * Implementations of the “tray” side of this specification can
86 * be found e.g. in the GNOME 2 and KDE panel applications.
87 *
88 * Note that a GtkStatusIcon is not a widget, but just a #GObject. Making it a
89 * widget would be impractical, since the system tray on Windows doesn’t allow
90 * to embed arbitrary widgets.
91 *
92 * GtkStatusIcon has been deprecated in 3.14. You should consider using
93 * notifications or more modern platform-specific APIs instead. GLib provides
94 * the #GNotification API which works well with #GtkApplication on multiple
95 * platforms and environments, and should be the preferred mechanism to notify
96 * the users of transient status updates. See this [HowDoI](https://wiki.gnome.org/HowDoI/GNotification)
97 * for code examples.
98 */
99
100
101 #define BLINK_TIMEOUT 500
102
103 enum
104 {
105 PROP_0,
106 PROP_PIXBUF,
107 PROP_FILE,
108 PROP_STOCK,
109 PROP_ICON_NAME,
110 PROP_GICON,
111 PROP_STORAGE_TYPE,
112 PROP_SIZE,
113 PROP_SCREEN,
114 PROP_VISIBLE,
115 PROP_ORIENTATION,
116 PROP_EMBEDDED,
117 PROP_BLINKING,
118 PROP_HAS_TOOLTIP,
119 PROP_TOOLTIP_TEXT,
120 PROP_TOOLTIP_MARKUP,
121 PROP_TITLE
122 };
123
124 enum
125 {
126 ACTIVATE_SIGNAL,
127 POPUP_MENU_SIGNAL,
128 SIZE_CHANGED_SIGNAL,
129 BUTTON_PRESS_EVENT_SIGNAL,
130 BUTTON_RELEASE_EVENT_SIGNAL,
131 SCROLL_EVENT_SIGNAL,
132 QUERY_TOOLTIP_SIGNAL,
133 LAST_SIGNAL
134 };
135
136 static guint status_icon_signals [LAST_SIGNAL] = { 0 };
137
138 #ifdef GDK_WINDOWING_QUARTZ
139 #include "gtkstatusicon-quartz.c"
140 #endif
141
142 struct _GtkStatusIconPrivate
143 {
144 #ifdef GDK_WINDOWING_X11
145 GtkWidget *tray_icon;
146 GtkWidget *image;
147 #else
148 GtkWidget *dummy_widget;
149 #endif
150
151 #ifdef GDK_WINDOWING_WIN32
152 NOTIFYICONDATAW nid;
153 gint taskbar_top;
154 gint last_click_x, last_click_y;
155 GtkOrientation orientation;
156 gchar *tooltip_text;
157 gchar *title;
158 #endif
159
160 #ifdef GDK_WINDOWING_QUARTZ
161 GtkQuartzStatusIcon *status_item;
162 gchar *tooltip_text;
163 gchar *title;
164 #endif
165
166 gint size;
167 GtkImageDefinition *image_def;
168 guint visible : 1;
169 };
170
171 static void gtk_status_icon_constructed (GObject *object);
172 static void gtk_status_icon_finalize (GObject *object);
173 static void gtk_status_icon_set_property (GObject *object,
174 guint prop_id,
175 const GValue *value,
176 GParamSpec *pspec);
177 static void gtk_status_icon_get_property (GObject *object,
178 guint prop_id,
179 GValue *value,
180 GParamSpec *pspec);
181
182 #ifdef GDK_WINDOWING_X11
183 static void gtk_status_icon_size_allocate (GtkStatusIcon *status_icon,
184 GtkAllocation *allocation);
185 static void gtk_status_icon_screen_changed (GtkStatusIcon *status_icon,
186 GdkScreen *old_screen);
187 static void gtk_status_icon_embedded_changed (GtkStatusIcon *status_icon);
188 static void gtk_status_icon_orientation_changed (GtkStatusIcon *status_icon);
189 static void gtk_status_icon_padding_changed (GtkStatusIcon *status_icon);
190 static void gtk_status_icon_icon_size_changed(GtkStatusIcon *status_icon);
191 static void gtk_status_icon_fg_changed (GtkStatusIcon *status_icon);
192 static void gtk_status_icon_color_changed (GtkTrayIcon *tray,
193 GParamSpec *pspec,
194 GtkStatusIcon *status_icon);
195 static gboolean gtk_status_icon_scroll (GtkStatusIcon *status_icon,
196 GdkEventScroll *event);
197 static gboolean gtk_status_icon_query_tooltip (GtkStatusIcon *status_icon,
198 gint x,
199 gint y,
200 gboolean keyboard_tip,
201 GtkTooltip *tooltip);
202
203 static gboolean gtk_status_icon_key_press (GtkStatusIcon *status_icon,
204 GdkEventKey *event);
205 static void gtk_status_icon_popup_menu (GtkStatusIcon *status_icon);
206 #endif
207 static gboolean gtk_status_icon_button_press (GtkStatusIcon *status_icon,
208 GdkEventButton *event);
209 static gboolean gtk_status_icon_button_release (GtkStatusIcon *status_icon,
210 GdkEventButton *event);
211 static void gtk_status_icon_reset_image_data (GtkStatusIcon *status_icon);
212 static void gtk_status_icon_update_image (GtkStatusIcon *status_icon);
213
G_DEFINE_TYPE_WITH_PRIVATE(GtkStatusIcon,gtk_status_icon,G_TYPE_OBJECT)214 G_DEFINE_TYPE_WITH_PRIVATE (GtkStatusIcon, gtk_status_icon, G_TYPE_OBJECT)
215
216 static void
217 gtk_status_icon_class_init (GtkStatusIconClass *class)
218 {
219 GObjectClass *gobject_class = (GObjectClass *) class;
220
221 gobject_class->constructed = gtk_status_icon_constructed;
222 gobject_class->finalize = gtk_status_icon_finalize;
223 gobject_class->set_property = gtk_status_icon_set_property;
224 gobject_class->get_property = gtk_status_icon_get_property;
225
226 class->button_press_event = NULL;
227 class->button_release_event = NULL;
228 class->scroll_event = NULL;
229 class->query_tooltip = NULL;
230
231 g_object_class_install_property (gobject_class,
232 PROP_PIXBUF,
233 g_param_spec_object ("pixbuf",
234 P_("Pixbuf"),
235 P_("A GdkPixbuf to display"),
236 GDK_TYPE_PIXBUF,
237 GTK_PARAM_READWRITE));
238
239 g_object_class_install_property (gobject_class,
240 PROP_FILE,
241 g_param_spec_string ("file",
242 P_("Filename"),
243 P_("Filename to load and display"),
244 NULL,
245 GTK_PARAM_WRITABLE));
246
247 /**
248 * GtkStatusIcon:stock:
249 *
250 * Deprecated: 3.10: Use #GtkStatusIcon:icon-name instead.
251 */
252 g_object_class_install_property (gobject_class,
253 PROP_STOCK,
254 g_param_spec_string ("stock",
255 P_("Stock ID"),
256 P_("Stock ID for a stock image to display"),
257 NULL,
258 GTK_PARAM_READWRITE | G_PARAM_DEPRECATED));
259
260 g_object_class_install_property (gobject_class,
261 PROP_ICON_NAME,
262 g_param_spec_string ("icon-name",
263 P_("Icon Name"),
264 P_("The name of the icon from the icon theme"),
265 NULL,
266 GTK_PARAM_READWRITE));
267
268 /**
269 * GtkStatusIcon:gicon:
270 *
271 * The #GIcon displayed in the #GtkStatusIcon. For themed icons,
272 * the image will be updated automatically if the theme changes.
273 *
274 * Since: 2.14
275 */
276 g_object_class_install_property (gobject_class,
277 PROP_GICON,
278 g_param_spec_object ("gicon",
279 P_("GIcon"),
280 P_("The GIcon being displayed"),
281 G_TYPE_ICON,
282 GTK_PARAM_READWRITE));
283
284 g_object_class_install_property (gobject_class,
285 PROP_STORAGE_TYPE,
286 g_param_spec_enum ("storage-type",
287 P_("Storage type"),
288 P_("The representation being used for image data"),
289 GTK_TYPE_IMAGE_TYPE,
290 GTK_IMAGE_EMPTY,
291 GTK_PARAM_READABLE));
292
293 g_object_class_install_property (gobject_class,
294 PROP_SIZE,
295 g_param_spec_int ("size",
296 P_("Size"),
297 P_("The size of the icon"),
298 0,
299 G_MAXINT,
300 0,
301 GTK_PARAM_READABLE));
302
303 g_object_class_install_property (gobject_class,
304 PROP_SCREEN,
305 g_param_spec_object ("screen",
306 P_("Screen"),
307 P_("The screen where this status icon will be displayed"),
308 GDK_TYPE_SCREEN,
309 GTK_PARAM_READWRITE));
310
311 g_object_class_install_property (gobject_class,
312 PROP_VISIBLE,
313 g_param_spec_boolean ("visible",
314 P_("Visible"),
315 P_("Whether the status icon is visible"),
316 TRUE,
317 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
318
319
320 /**
321 * GtkStatusIcon:embedded:
322 *
323 * %TRUE if the statusicon is embedded in a notification area.
324 *
325 * Since: 2.12
326 */
327 g_object_class_install_property (gobject_class,
328 PROP_EMBEDDED,
329 g_param_spec_boolean ("embedded",
330 P_("Embedded"),
331 P_("Whether the status icon is embedded"),
332 FALSE,
333 GTK_PARAM_READABLE));
334
335 /**
336 * GtkStatusIcon:orientation:
337 *
338 * The orientation of the tray in which the statusicon
339 * is embedded.
340 *
341 * Since: 2.12
342 */
343 g_object_class_install_property (gobject_class,
344 PROP_ORIENTATION,
345 g_param_spec_enum ("orientation",
346 P_("Orientation"),
347 P_("The orientation of the tray"),
348 GTK_TYPE_ORIENTATION,
349 GTK_ORIENTATION_HORIZONTAL,
350 GTK_PARAM_READABLE));
351
352 /**
353 * GtkStatusIcon:has-tooltip:
354 *
355 * Enables or disables the emission of #GtkStatusIcon::query-tooltip on
356 * @status_icon. A value of %TRUE indicates that @status_icon can have a
357 * tooltip, in this case the status icon will be queried using
358 * #GtkStatusIcon::query-tooltip to determine whether it will provide a
359 * tooltip or not.
360 *
361 * Note that setting this property to %TRUE for the first time will change
362 * the event masks of the windows of this status icon to include leave-notify
363 * and motion-notify events. This will not be undone when the property is set
364 * to %FALSE again.
365 *
366 * Whether this property is respected is platform dependent.
367 * For plain text tooltips, use #GtkStatusIcon:tooltip-text in preference.
368 *
369 * Since: 2.16
370 */
371 g_object_class_install_property (gobject_class,
372 PROP_HAS_TOOLTIP,
373 g_param_spec_boolean ("has-tooltip",
374 P_("Has tooltip"),
375 P_("Whether this tray icon has a tooltip"),
376 FALSE,
377 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
378
379 /**
380 * GtkStatusIcon:tooltip-text:
381 *
382 * Sets the text of tooltip to be the given string.
383 *
384 * Also see gtk_tooltip_set_text().
385 *
386 * This is a convenience property which will take care of getting the
387 * tooltip shown if the given string is not %NULL.
388 * #GtkStatusIcon:has-tooltip will automatically be set to %TRUE and
389 * the default handler for the #GtkStatusIcon::query-tooltip signal
390 * will take care of displaying the tooltip.
391 *
392 * Note that some platforms have limitations on the length of tooltips
393 * that they allow on status icons, e.g. Windows only shows the first
394 * 64 characters.
395 *
396 * Since: 2.16
397 */
398 g_object_class_install_property (gobject_class,
399 PROP_TOOLTIP_TEXT,
400 g_param_spec_string ("tooltip-text",
401 P_("Tooltip Text"),
402 P_("The contents of the tooltip for this widget"),
403 NULL,
404 GTK_PARAM_READWRITE));
405 /**
406 * GtkStatusIcon:tooltip-markup:
407 *
408 * Sets the text of tooltip to be the given string, which is marked up
409 * with the [Pango text markup language][PangoMarkupFormat].
410 * Also see gtk_tooltip_set_markup().
411 *
412 * This is a convenience property which will take care of getting the
413 * tooltip shown if the given string is not %NULL.
414 * #GtkStatusIcon:has-tooltip will automatically be set to %TRUE and
415 * the default handler for the #GtkStatusIcon::query-tooltip signal
416 * will take care of displaying the tooltip.
417 *
418 * On some platforms, embedded markup will be ignored.
419 *
420 * Since: 2.16
421 */
422 g_object_class_install_property (gobject_class,
423 PROP_TOOLTIP_MARKUP,
424 g_param_spec_string ("tooltip-markup",
425 P_("Tooltip markup"),
426 P_("The contents of the tooltip for this tray icon"),
427 NULL,
428 GTK_PARAM_READWRITE));
429
430
431 /**
432 * GtkStatusIcon:title:
433 *
434 * The title of this tray icon. This should be a short, human-readable,
435 * localized string describing the tray icon. It may be used by tools
436 * like screen readers to render the tray icon.
437 *
438 * Since: 2.18
439 */
440 g_object_class_install_property (gobject_class,
441 PROP_TITLE,
442 g_param_spec_string ("title",
443 P_("Title"),
444 P_("The title of this tray icon"),
445 NULL,
446 GTK_PARAM_READWRITE));
447
448 /**
449 * GtkStatusIcon::activate:
450 * @status_icon: the object which received the signal
451 *
452 * Gets emitted when the user activates the status icon.
453 * If and how status icons can activated is platform-dependent.
454 *
455 * Unlike most G_SIGNAL_ACTION signals, this signal is meant to
456 * be used by applications and should be wrapped by language bindings.
457 *
458 * Since: 2.10
459 */
460 status_icon_signals [ACTIVATE_SIGNAL] =
461 g_signal_new (I_("activate"),
462 G_TYPE_FROM_CLASS (gobject_class),
463 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
464 G_STRUCT_OFFSET (GtkStatusIconClass, activate),
465 NULL,
466 NULL,
467 NULL,
468 G_TYPE_NONE,
469 0);
470
471 /**
472 * GtkStatusIcon::popup-menu:
473 * @status_icon: the object which received the signal
474 * @button: the button that was pressed, or 0 if the
475 * signal is not emitted in response to a button press event
476 * @activate_time: the timestamp of the event that
477 * triggered the signal emission
478 *
479 * Gets emitted when the user brings up the context menu
480 * of the status icon. Whether status icons can have context
481 * menus and how these are activated is platform-dependent.
482 *
483 * The @button and @activate_time parameters should be
484 * passed as the last to arguments to gtk_menu_popup().
485 *
486 * Unlike most G_SIGNAL_ACTION signals, this signal is meant to
487 * be used by applications and should be wrapped by language bindings.
488 *
489 * Since: 2.10
490 */
491 status_icon_signals [POPUP_MENU_SIGNAL] =
492 g_signal_new (I_("popup-menu"),
493 G_TYPE_FROM_CLASS (gobject_class),
494 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
495 G_STRUCT_OFFSET (GtkStatusIconClass, popup_menu),
496 NULL,
497 NULL,
498 _gtk_marshal_VOID__UINT_UINT,
499 G_TYPE_NONE,
500 2,
501 G_TYPE_UINT,
502 G_TYPE_UINT);
503
504 /**
505 * GtkStatusIcon::size-changed:
506 * @status_icon: the object which received the signal
507 * @size: the new size
508 *
509 * Gets emitted when the size available for the image
510 * changes, e.g. because the notification area got resized.
511 *
512 * Returns: %TRUE if the icon was updated for the new
513 * size. Otherwise, GTK+ will scale the icon as necessary.
514 *
515 * Since: 2.10
516 */
517 status_icon_signals [SIZE_CHANGED_SIGNAL] =
518 g_signal_new (I_("size-changed"),
519 G_TYPE_FROM_CLASS (gobject_class),
520 G_SIGNAL_RUN_LAST,
521 G_STRUCT_OFFSET (GtkStatusIconClass, size_changed),
522 g_signal_accumulator_true_handled,
523 NULL,
524 _gtk_marshal_BOOLEAN__INT,
525 G_TYPE_BOOLEAN,
526 1,
527 G_TYPE_INT);
528
529 /**
530 * GtkStatusIcon::button-press-event:
531 * @status_icon: the object which received the signal
532 * @event: (type Gdk.EventButton): the #GdkEventButton which triggered
533 * this signal
534 *
535 * The ::button-press-event signal will be emitted when a button
536 * (typically from a mouse) is pressed.
537 *
538 * Whether this event is emitted is platform-dependent. Use the ::activate
539 * and ::popup-menu signals in preference.
540 *
541 * Returns: %TRUE to stop other handlers from being invoked
542 * for the event. %FALSE to propagate the event further.
543 *
544 * Since: 2.14
545 */
546 status_icon_signals [BUTTON_PRESS_EVENT_SIGNAL] =
547 g_signal_new (I_("button_press_event"),
548 G_TYPE_FROM_CLASS (gobject_class),
549 G_SIGNAL_RUN_LAST,
550 G_STRUCT_OFFSET (GtkStatusIconClass, button_press_event),
551 g_signal_accumulator_true_handled, NULL,
552 _gtk_marshal_BOOLEAN__BOXED,
553 G_TYPE_BOOLEAN, 1,
554 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
555
556 /**
557 * GtkStatusIcon::button-release-event:
558 * @status_icon: the object which received the signal
559 * @event: (type Gdk.EventButton): the #GdkEventButton which triggered
560 * this signal
561 *
562 * The ::button-release-event signal will be emitted when a button
563 * (typically from a mouse) is released.
564 *
565 * Whether this event is emitted is platform-dependent. Use the ::activate
566 * and ::popup-menu signals in preference.
567 *
568 * Returns: %TRUE to stop other handlers from being invoked
569 * for the event. %FALSE to propagate the event further.
570 *
571 * Since: 2.14
572 */
573 status_icon_signals [BUTTON_RELEASE_EVENT_SIGNAL] =
574 g_signal_new (I_("button_release_event"),
575 G_TYPE_FROM_CLASS (gobject_class),
576 G_SIGNAL_RUN_LAST,
577 G_STRUCT_OFFSET (GtkStatusIconClass, button_release_event),
578 g_signal_accumulator_true_handled, NULL,
579 _gtk_marshal_BOOLEAN__BOXED,
580 G_TYPE_BOOLEAN, 1,
581 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
582
583 /**
584 * GtkStatusIcon::scroll-event:
585 * @status_icon: the object which received the signal.
586 * @event: (type Gdk.EventScroll): the #GdkEventScroll which triggered
587 * this signal
588 *
589 * The ::scroll-event signal is emitted when a button in the 4 to 7
590 * range is pressed. Wheel mice are usually configured to generate
591 * button press events for buttons 4 and 5 when the wheel is turned.
592 *
593 * Whether this event is emitted is platform-dependent.
594 *
595 * Returns: %TRUE to stop other handlers from being invoked for the event.
596 * %FALSE to propagate the event further.
597 *
598 * Since: 2.16
599 */
600 status_icon_signals[SCROLL_EVENT_SIGNAL] =
601 g_signal_new (I_("scroll_event"),
602 G_TYPE_FROM_CLASS (gobject_class),
603 G_SIGNAL_RUN_LAST,
604 G_STRUCT_OFFSET (GtkStatusIconClass, scroll_event),
605 g_signal_accumulator_true_handled, NULL,
606 _gtk_marshal_BOOLEAN__BOXED,
607 G_TYPE_BOOLEAN, 1,
608 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
609
610 /**
611 * GtkStatusIcon::query-tooltip:
612 * @status_icon: the object which received the signal
613 * @x: the x coordinate of the cursor position where the request has been
614 * emitted, relative to @status_icon
615 * @y: the y coordinate of the cursor position where the request has been
616 * emitted, relative to @status_icon
617 * @keyboard_mode: %TRUE if the tooltip was trigged using the keyboard
618 * @tooltip: a #GtkTooltip
619 *
620 * Emitted when the hover timeout has expired with the
621 * cursor hovering above @status_icon; or emitted when @status_icon got
622 * focus in keyboard mode.
623 *
624 * Using the given coordinates, the signal handler should determine
625 * whether a tooltip should be shown for @status_icon. If this is
626 * the case %TRUE should be returned, %FALSE otherwise. Note that if
627 * @keyboard_mode is %TRUE, the values of @x and @y are undefined and
628 * should not be used.
629 *
630 * The signal handler is free to manipulate @tooltip with the therefore
631 * destined function calls.
632 *
633 * Whether this signal is emitted is platform-dependent.
634 * For plain text tooltips, use #GtkStatusIcon:tooltip-text in preference.
635 *
636 * Returns: %TRUE if @tooltip should be shown right now, %FALSE otherwise.
637 *
638 * Since: 2.16
639 */
640 status_icon_signals [QUERY_TOOLTIP_SIGNAL] =
641 g_signal_new (I_("query_tooltip"),
642 G_TYPE_FROM_CLASS (gobject_class),
643 G_SIGNAL_RUN_LAST,
644 G_STRUCT_OFFSET (GtkStatusIconClass, query_tooltip),
645 g_signal_accumulator_true_handled, NULL,
646 _gtk_marshal_BOOLEAN__INT_INT_BOOLEAN_OBJECT,
647 G_TYPE_BOOLEAN, 4,
648 G_TYPE_INT,
649 G_TYPE_INT,
650 G_TYPE_BOOLEAN,
651 GTK_TYPE_TOOLTIP);
652 }
653
654 #ifdef GDK_WINDOWING_WIN32
655
656 static void
build_button_event(GtkStatusIconPrivate * priv,GdkEventButton * e,guint button)657 build_button_event (GtkStatusIconPrivate *priv,
658 GdkEventButton *e,
659 guint button)
660 {
661 POINT pos;
662 GdkRectangle monitor0;
663
664 /* We know that gdk/win32 puts the primary monitor at index 0 */
665 gdk_screen_get_monitor_geometry (gdk_screen_get_default (), 0, &monitor0);
666 e->window = g_object_ref (gdk_get_default_root_window ());
667 e->send_event = TRUE;
668 e->time = GetTickCount ();
669 GetCursorPos (&pos);
670 priv->last_click_x = e->x = pos.x + monitor0.x;
671 priv->last_click_y = e->y = pos.y + monitor0.y;
672 e->axes = NULL;
673 e->state = 0;
674 e->button = button;
675 //FIXME: e->device = gdk_display_get_default ()->core_pointer;
676 e->x_root = e->x;
677 e->y_root = e->y;
678 }
679
680 typedef struct
681 {
682 GtkStatusIcon *status_icon;
683 GdkEventButton *event;
684 } ButtonCallbackData;
685
686 static gboolean
button_callback(gpointer data)687 button_callback (gpointer data)
688 {
689 ButtonCallbackData *bc = (ButtonCallbackData *) data;
690
691 if (bc->event->type == GDK_BUTTON_PRESS)
692 gtk_status_icon_button_press (bc->status_icon, bc->event);
693 else
694 gtk_status_icon_button_release (bc->status_icon, bc->event);
695
696 gdk_event_free ((GdkEvent *) bc->event);
697 g_free (data);
698
699 return G_SOURCE_REMOVE;
700 }
701
702 static UINT taskbar_created_msg = 0;
703 static GSList *status_icons = NULL;
704 static UINT status_icon_id = 0;
705
706 static GtkStatusIcon *
find_status_icon(UINT id)707 find_status_icon (UINT id)
708 {
709 GSList *rover;
710
711 for (rover = status_icons; rover != NULL; rover = rover->next)
712 {
713 GtkStatusIcon *status_icon = GTK_STATUS_ICON (rover->data);
714 GtkStatusIconPrivate *priv = status_icon->priv;
715
716 if (priv->nid.uID == id)
717 return status_icon;
718 }
719
720 return NULL;
721 }
722
723 static LRESULT CALLBACK
wndproc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)724 wndproc (HWND hwnd,
725 UINT message,
726 WPARAM wparam,
727 LPARAM lparam)
728 {
729 if (message == taskbar_created_msg)
730 {
731 GSList *rover;
732
733 for (rover = status_icons; rover != NULL; rover = rover->next)
734 {
735 GtkStatusIcon *status_icon = GTK_STATUS_ICON (rover->data);
736 GtkStatusIconPrivate *priv = status_icon->priv;
737
738 if (priv->visible)
739 {
740 /* taskbar_created_msg is also fired when DPI changes. Try to delete existing icons if possible. */
741 if (priv->nid.hWnd)
742 if (!Shell_NotifyIconW (NIM_DELETE, &priv->nid))
743 g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_DELETE) on existing icon failed");
744
745 priv->nid.hWnd = hwnd;
746 priv->nid.uFlags &= ~NIF_ICON;
747
748 if (!Shell_NotifyIconW (NIM_ADD, &priv->nid))
749 {
750 g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_ADD) failed");
751 priv->nid.hWnd = NULL;
752 continue;
753 }
754
755 gtk_status_icon_update_image (status_icon);
756 }
757 }
758 return 0;
759 }
760
761 if (message == WM_GTK_TRAY_NOTIFICATION)
762 {
763 ButtonCallbackData *bc;
764 guint button;
765
766 switch (lparam)
767 {
768 case WM_LBUTTONDOWN:
769 button = 1;
770 goto buttondown0;
771
772 case WM_MBUTTONDOWN:
773 button = 2;
774 goto buttondown0;
775
776 case WM_RBUTTONDOWN:
777 button = 3;
778 goto buttondown0;
779
780 case WM_XBUTTONDOWN:
781 if (HIWORD (wparam) == XBUTTON1)
782 button = 4;
783 else
784 button = 5;
785
786 buttondown0:
787 bc = g_new (ButtonCallbackData, 1);
788 bc->event = (GdkEventButton *) gdk_event_new (GDK_BUTTON_PRESS);
789 bc->status_icon = find_status_icon (wparam);
790 build_button_event (bc->status_icon->priv, bc->event, button);
791 g_idle_add (button_callback, bc);
792 break;
793
794 case WM_LBUTTONUP:
795 button = 1;
796 goto buttonup0;
797
798 case WM_MBUTTONUP:
799 button = 2;
800 goto buttonup0;
801
802 case WM_RBUTTONUP:
803 button = 3;
804 goto buttonup0;
805
806 case WM_XBUTTONUP:
807 if (HIWORD (wparam) == XBUTTON1)
808 button = 4;
809 else
810 button = 5;
811
812 buttonup0:
813 bc = g_new (ButtonCallbackData, 1);
814 bc->event = (GdkEventButton *) gdk_event_new (GDK_BUTTON_RELEASE);
815 bc->status_icon = find_status_icon (wparam);
816 build_button_event (bc->status_icon->priv, bc->event, button);
817 g_idle_add (button_callback, bc);
818 break;
819
820 default :
821 break;
822 }
823 return 0;
824 }
825 else
826 {
827 return DefWindowProc (hwnd, message, wparam, lparam);
828 }
829 }
830
831 static HWND
create_tray_observer(void)832 create_tray_observer (void)
833 {
834 WNDCLASS wclass;
835 static HWND hwnd = NULL;
836 ATOM klass;
837 HINSTANCE hmodule = GetModuleHandle (NULL);
838
839 if (hwnd)
840 return hwnd;
841
842 taskbar_created_msg = RegisterWindowMessage("TaskbarCreated");
843
844 memset (&wclass, 0, sizeof(WNDCLASS));
845 wclass.lpszClassName = "gtkstatusicon-observer";
846 wclass.lpfnWndProc = wndproc;
847 wclass.hInstance = hmodule;
848
849 klass = RegisterClass (&wclass);
850 if (!klass)
851 return NULL;
852
853 hwnd = CreateWindow (MAKEINTRESOURCE (klass),
854 NULL, WS_POPUP,
855 0, 0, 1, 1, NULL, NULL,
856 hmodule, NULL);
857 if (!hwnd)
858 {
859 UnregisterClass (MAKEINTRESOURCE(klass), hmodule);
860 return NULL;
861 }
862
863 return hwnd;
864 }
865
866 #endif
867
868 static void
gtk_status_icon_init(GtkStatusIcon * status_icon)869 gtk_status_icon_init (GtkStatusIcon *status_icon)
870 {
871 GtkStatusIconPrivate *priv;
872
873 priv = gtk_status_icon_get_instance_private (status_icon);
874 status_icon->priv = priv;
875
876 priv->image_def = gtk_image_definition_new_empty ();
877 priv->visible = TRUE;
878
879 #ifdef GDK_WINDOWING_X11
880 if (GDK_IS_X11_DISPLAY (gdk_display_get_default ()))
881 {
882 priv->size = 0;
883 priv->tray_icon = GTK_WIDGET (_gtk_tray_icon_new (NULL));
884
885 gtk_widget_add_events (GTK_WIDGET (priv->tray_icon),
886 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
887 GDK_SCROLL_MASK);
888
889 g_signal_connect_swapped (priv->tray_icon, "key-press-event",
890 G_CALLBACK (gtk_status_icon_key_press), status_icon);
891 g_signal_connect_swapped (priv->tray_icon, "popup-menu",
892 G_CALLBACK (gtk_status_icon_popup_menu), status_icon);
893 g_signal_connect_swapped (priv->tray_icon, "notify::embedded",
894 G_CALLBACK (gtk_status_icon_embedded_changed), status_icon);
895 g_signal_connect_swapped (priv->tray_icon, "notify::orientation",
896 G_CALLBACK (gtk_status_icon_orientation_changed), status_icon);
897 g_signal_connect_swapped (priv->tray_icon, "notify::padding",
898 G_CALLBACK (gtk_status_icon_padding_changed), status_icon);
899 g_signal_connect_swapped (priv->tray_icon, "notify::icon-size",
900 G_CALLBACK (gtk_status_icon_icon_size_changed), status_icon);
901 g_signal_connect_swapped (priv->tray_icon, "notify::fg-color",
902 G_CALLBACK (gtk_status_icon_fg_changed), status_icon);
903 g_signal_connect (priv->tray_icon, "notify::error-color",
904 G_CALLBACK (gtk_status_icon_color_changed), status_icon);
905 g_signal_connect (priv->tray_icon, "notify::warning-color",
906 G_CALLBACK (gtk_status_icon_color_changed), status_icon);
907 g_signal_connect (priv->tray_icon, "notify::success-color",
908 G_CALLBACK (gtk_status_icon_color_changed), status_icon);
909 g_signal_connect_swapped (priv->tray_icon, "button-press-event",
910 G_CALLBACK (gtk_status_icon_button_press), status_icon);
911 g_signal_connect_swapped (priv->tray_icon, "button-release-event",
912 G_CALLBACK (gtk_status_icon_button_release), status_icon);
913 g_signal_connect_swapped (priv->tray_icon, "scroll-event",
914 G_CALLBACK (gtk_status_icon_scroll), status_icon);
915 g_signal_connect_swapped (priv->tray_icon, "query-tooltip",
916 G_CALLBACK (gtk_status_icon_query_tooltip), status_icon);
917 g_signal_connect_swapped (priv->tray_icon, "screen-changed",
918 G_CALLBACK (gtk_status_icon_screen_changed), status_icon);
919 priv->image = gtk_image_new ();
920 gtk_widget_set_can_focus (priv->image, TRUE);
921 gtk_container_add (GTK_CONTAINER (priv->tray_icon), priv->image);
922 gtk_widget_show (priv->image);
923
924 /* Force-initialize the symbolic colors */
925 g_object_notify (G_OBJECT (priv->tray_icon), "fg-color");
926 g_object_notify (G_OBJECT (priv->tray_icon), "error-color");
927 g_object_notify (G_OBJECT (priv->tray_icon), "warning-color");
928 g_object_notify (G_OBJECT (priv->tray_icon), "success-color");
929
930 g_signal_connect_swapped (priv->image, "size-allocate",
931 G_CALLBACK (gtk_status_icon_size_allocate), status_icon);
932 }
933 #else /* !GDK_WINDOWING_X11 */
934 priv->dummy_widget = gtk_label_new ("");
935 #endif
936
937 #ifdef GDK_WINDOWING_WIN32
938
939 /* Get position and orientation of Windows taskbar. */
940 {
941 APPBARDATA abd;
942
943 abd.cbSize = sizeof (abd);
944 SHAppBarMessage (ABM_GETTASKBARPOS, &abd);
945 if (abd.rc.bottom - abd.rc.top > abd.rc.right - abd.rc.left)
946 priv->orientation = GTK_ORIENTATION_VERTICAL;
947 else
948 priv->orientation = GTK_ORIENTATION_HORIZONTAL;
949
950 priv->taskbar_top = abd.rc.top;
951 }
952
953 priv->last_click_x = priv->last_click_y = 0;
954
955 /* Are the system tray icons always 16 pixels square? */
956 priv->size = 16;
957
958 memset (&priv->nid, 0, sizeof (priv->nid));
959
960 priv->nid.hWnd = create_tray_observer ();
961 priv->nid.uID = status_icon_id++;
962 priv->nid.uCallbackMessage = WM_GTK_TRAY_NOTIFICATION;
963 priv->nid.uFlags = NIF_MESSAGE;
964
965 /* To help win7 identify the icon create it with an application "unique" tip */
966 if (g_get_prgname ())
967 {
968 WCHAR *wcs = g_utf8_to_utf16 (g_get_prgname (), -1, NULL, NULL, NULL);
969
970 priv->nid.uFlags |= NIF_TIP;
971 wcsncpy (priv->nid.szTip, wcs, G_N_ELEMENTS (priv->nid.szTip) - 1);
972 priv->nid.szTip[G_N_ELEMENTS (priv->nid.szTip) - 1] = 0;
973 g_free (wcs);
974 }
975
976 if (!Shell_NotifyIconW (NIM_ADD, &priv->nid))
977 {
978 g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_ADD) failed");
979 priv->nid.hWnd = NULL;
980 }
981
982 status_icons = g_slist_append (status_icons, status_icon);
983
984 #endif
985
986 #ifdef GDK_WINDOWING_QUARTZ
987 QUARTZ_POOL_ALLOC;
988
989 priv->status_item = [[GtkQuartzStatusIcon alloc] initWithStatusIcon:status_icon];
990 priv->size = [priv->status_item getHeight];
991
992 QUARTZ_POOL_RELEASE;
993
994 #endif
995 }
996
997 static void
gtk_status_icon_constructed(GObject * object)998 gtk_status_icon_constructed (GObject *object)
999 {
1000 G_OBJECT_CLASS (gtk_status_icon_parent_class)->constructed (object);
1001
1002 #ifdef GDK_WINDOWING_X11
1003 {
1004 GtkStatusIcon *status_icon = GTK_STATUS_ICON (object);
1005 GtkStatusIconPrivate *priv = status_icon->priv;
1006
1007 if (priv->visible && priv->tray_icon)
1008 gtk_widget_show (priv->tray_icon);
1009 }
1010 #endif
1011 }
1012
1013 static void
gtk_status_icon_finalize(GObject * object)1014 gtk_status_icon_finalize (GObject *object)
1015 {
1016 GtkStatusIcon *status_icon = GTK_STATUS_ICON (object);
1017 GtkStatusIconPrivate *priv = status_icon->priv;
1018
1019 gtk_status_icon_reset_image_data (status_icon);
1020 gtk_image_definition_unref (priv->image_def);
1021
1022 #ifdef GDK_WINDOWING_X11
1023 if (priv->tray_icon)
1024 {
1025 g_signal_handlers_disconnect_by_func (priv->tray_icon,
1026 gtk_status_icon_key_press, status_icon);
1027 g_signal_handlers_disconnect_by_func (priv->tray_icon,
1028 gtk_status_icon_popup_menu, status_icon);
1029 g_signal_handlers_disconnect_by_func (priv->tray_icon,
1030 gtk_status_icon_embedded_changed, status_icon);
1031 g_signal_handlers_disconnect_by_func (priv->tray_icon,
1032 gtk_status_icon_orientation_changed, status_icon);
1033 g_signal_handlers_disconnect_by_func (priv->tray_icon,
1034 gtk_status_icon_padding_changed, status_icon);
1035 g_signal_handlers_disconnect_by_func (priv->tray_icon,
1036 gtk_status_icon_icon_size_changed, status_icon);
1037 g_signal_handlers_disconnect_by_func (priv->tray_icon,
1038 gtk_status_icon_fg_changed, status_icon);
1039 g_signal_handlers_disconnect_by_func (priv->tray_icon,
1040 gtk_status_icon_color_changed, status_icon);
1041 g_signal_handlers_disconnect_by_func (priv->tray_icon,
1042 gtk_status_icon_button_press, status_icon);
1043 g_signal_handlers_disconnect_by_func (priv->tray_icon,
1044 gtk_status_icon_button_release, status_icon);
1045 g_signal_handlers_disconnect_by_func (priv->tray_icon,
1046 gtk_status_icon_scroll, status_icon);
1047 g_signal_handlers_disconnect_by_func (priv->tray_icon,
1048 gtk_status_icon_query_tooltip, status_icon);
1049 g_signal_handlers_disconnect_by_func (priv->tray_icon,
1050 gtk_status_icon_screen_changed, status_icon);
1051 gtk_widget_destroy (priv->image);
1052 gtk_widget_destroy (priv->tray_icon);
1053 }
1054 #else /* !GDK_WINDOWING_X11 */
1055 gtk_widget_destroy (priv->dummy_widget);
1056 #endif
1057
1058 #ifdef GDK_WINDOWING_WIN32
1059 if (priv->nid.hWnd != NULL && priv->visible)
1060 Shell_NotifyIconW (NIM_DELETE, &priv->nid);
1061 if (priv->nid.hIcon)
1062 DestroyIcon (priv->nid.hIcon);
1063 g_free (priv->tooltip_text);
1064
1065 status_icons = g_slist_remove (status_icons, status_icon);
1066 #endif
1067
1068 #ifdef GDK_WINDOWING_QUARTZ
1069 QUARTZ_POOL_ALLOC;
1070 [priv->status_item release];
1071 QUARTZ_POOL_RELEASE;
1072 g_free (priv->tooltip_text);
1073 #endif
1074
1075 G_OBJECT_CLASS (gtk_status_icon_parent_class)->finalize (object);
1076 }
1077
1078 static void
gtk_status_icon_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1079 gtk_status_icon_set_property (GObject *object,
1080 guint prop_id,
1081 const GValue *value,
1082 GParamSpec *pspec)
1083 {
1084 GtkStatusIcon *status_icon = GTK_STATUS_ICON (object);
1085
1086 switch (prop_id)
1087 {
1088 case PROP_PIXBUF:
1089 gtk_status_icon_set_from_pixbuf (status_icon, g_value_get_object (value));
1090 break;
1091 case PROP_FILE:
1092 gtk_status_icon_set_from_file (status_icon, g_value_get_string (value));
1093 break;
1094 case PROP_STOCK:
1095 gtk_status_icon_set_from_stock (status_icon, g_value_get_string (value));
1096 break;
1097 case PROP_ICON_NAME:
1098 gtk_status_icon_set_from_icon_name (status_icon, g_value_get_string (value));
1099 break;
1100 case PROP_GICON:
1101 gtk_status_icon_set_from_gicon (status_icon, g_value_get_object (value));
1102 break;
1103 case PROP_SCREEN:
1104 gtk_status_icon_set_screen (status_icon, g_value_get_object (value));
1105 break;
1106 case PROP_VISIBLE:
1107 gtk_status_icon_set_visible (status_icon, g_value_get_boolean (value));
1108 break;
1109 case PROP_HAS_TOOLTIP:
1110 gtk_status_icon_set_has_tooltip (status_icon, g_value_get_boolean (value));
1111 break;
1112 case PROP_TOOLTIP_TEXT:
1113 gtk_status_icon_set_tooltip_text (status_icon, g_value_get_string (value));
1114 break;
1115 case PROP_TOOLTIP_MARKUP:
1116 gtk_status_icon_set_tooltip_markup (status_icon, g_value_get_string (value));
1117 break;
1118 case PROP_TITLE:
1119 gtk_status_icon_set_title (status_icon, g_value_get_string (value));
1120 break;
1121 default:
1122 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1123 break;
1124 }
1125 }
1126
1127 static void
gtk_status_icon_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1128 gtk_status_icon_get_property (GObject *object,
1129 guint prop_id,
1130 GValue *value,
1131 GParamSpec *pspec)
1132 {
1133 GtkStatusIcon *status_icon = GTK_STATUS_ICON (object);
1134
1135 switch (prop_id)
1136 {
1137 case PROP_PIXBUF:
1138 g_value_set_object (value, gtk_status_icon_get_pixbuf (status_icon));
1139 break;
1140 case PROP_STOCK:
1141 g_value_set_string (value, gtk_status_icon_get_stock (status_icon));
1142 break;
1143 case PROP_ICON_NAME:
1144 g_value_set_string (value, gtk_status_icon_get_icon_name (status_icon));
1145 break;
1146 case PROP_GICON:
1147 g_value_set_object (value, gtk_status_icon_get_gicon (status_icon));
1148 break;
1149 case PROP_STORAGE_TYPE:
1150 g_value_set_enum (value, gtk_status_icon_get_storage_type (status_icon));
1151 break;
1152 case PROP_SIZE:
1153 g_value_set_int (value, gtk_status_icon_get_size (status_icon));
1154 break;
1155 case PROP_SCREEN:
1156 g_value_set_object (value, gtk_status_icon_get_screen (status_icon));
1157 break;
1158 case PROP_VISIBLE:
1159 g_value_set_boolean (value, gtk_status_icon_get_visible (status_icon));
1160 break;
1161 case PROP_EMBEDDED:
1162 g_value_set_boolean (value, gtk_status_icon_is_embedded (status_icon));
1163 break;
1164 case PROP_ORIENTATION:
1165 #ifdef GDK_WINDOWING_X11
1166 if (status_icon->priv->tray_icon)
1167 g_value_set_enum (value, _gtk_tray_icon_get_orientation (GTK_TRAY_ICON (status_icon->priv->tray_icon)));
1168 else
1169 g_value_set_enum (value, GTK_ORIENTATION_HORIZONTAL);
1170 #endif
1171 #ifdef GDK_WINDOWING_WIN32
1172 g_value_set_enum (value, status_icon->priv->orientation);
1173 #endif
1174 break;
1175 case PROP_HAS_TOOLTIP:
1176 g_value_set_boolean (value, gtk_status_icon_get_has_tooltip (status_icon));
1177 break;
1178 case PROP_TOOLTIP_TEXT:
1179 g_value_set_string (value, gtk_status_icon_get_tooltip_text (status_icon));
1180 break;
1181 case PROP_TOOLTIP_MARKUP:
1182 g_value_set_string (value, gtk_status_icon_get_tooltip_markup (status_icon));
1183 break;
1184 case PROP_TITLE:
1185 g_value_set_string (value, gtk_status_icon_get_title (status_icon));
1186 break;
1187 default:
1188 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1189 break;
1190 }
1191 }
1192
1193 /**
1194 * gtk_status_icon_new:
1195 *
1196 * Creates an empty status icon object.
1197 *
1198 * Returns: a new #GtkStatusIcon
1199 *
1200 * Since: 2.10
1201 *
1202 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
1203 * provide status notifications
1204 */
1205 GtkStatusIcon *
gtk_status_icon_new(void)1206 gtk_status_icon_new (void)
1207 {
1208 return g_object_new (GTK_TYPE_STATUS_ICON, NULL);
1209 }
1210
1211 /**
1212 * gtk_status_icon_new_from_pixbuf:
1213 * @pixbuf: a #GdkPixbuf
1214 *
1215 * Creates a status icon displaying @pixbuf.
1216 *
1217 * The image will be scaled down to fit in the available
1218 * space in the notification area, if necessary.
1219 *
1220 * Returns: a new #GtkStatusIcon
1221 *
1222 * Since: 2.10
1223 *
1224 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
1225 * provide status notifications
1226 */
1227 GtkStatusIcon *
gtk_status_icon_new_from_pixbuf(GdkPixbuf * pixbuf)1228 gtk_status_icon_new_from_pixbuf (GdkPixbuf *pixbuf)
1229 {
1230 return g_object_new (GTK_TYPE_STATUS_ICON,
1231 "pixbuf", pixbuf,
1232 NULL);
1233 }
1234
1235 /**
1236 * gtk_status_icon_new_from_file:
1237 * @filename: (type filename): a filename
1238 *
1239 * Creates a status icon displaying the file @filename.
1240 *
1241 * The image will be scaled down to fit in the available
1242 * space in the notification area, if necessary.
1243 *
1244 * Returns: a new #GtkStatusIcon
1245 *
1246 * Since: 2.10
1247 *
1248 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
1249 * provide status notifications
1250 */
1251 GtkStatusIcon *
gtk_status_icon_new_from_file(const gchar * filename)1252 gtk_status_icon_new_from_file (const gchar *filename)
1253 {
1254 return g_object_new (GTK_TYPE_STATUS_ICON,
1255 "file", filename,
1256 NULL);
1257 }
1258
1259 /**
1260 * gtk_status_icon_new_from_stock:
1261 * @stock_id: a stock icon id
1262 *
1263 * Creates a status icon displaying a stock icon. Sample stock icon
1264 * names are #GTK_STOCK_OPEN, #GTK_STOCK_QUIT. You can register your
1265 * own stock icon names, see gtk_icon_factory_add_default() and
1266 * gtk_icon_factory_add().
1267 *
1268 * Returns: a new #GtkStatusIcon
1269 *
1270 * Since: 2.10
1271 *
1272 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
1273 * provide status notifications
1274 */
1275 GtkStatusIcon *
gtk_status_icon_new_from_stock(const gchar * stock_id)1276 gtk_status_icon_new_from_stock (const gchar *stock_id)
1277 {
1278 return g_object_new (GTK_TYPE_STATUS_ICON,
1279 "stock", stock_id,
1280 NULL);
1281 }
1282
1283 /**
1284 * gtk_status_icon_new_from_icon_name:
1285 * @icon_name: an icon name
1286 *
1287 * Creates a status icon displaying an icon from the current icon theme.
1288 * If the current icon theme is changed, the icon will be updated
1289 * appropriately.
1290 *
1291 * Returns: a new #GtkStatusIcon
1292 *
1293 * Since: 2.10
1294 *
1295 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
1296 * provide status notifications
1297 */
1298 GtkStatusIcon *
gtk_status_icon_new_from_icon_name(const gchar * icon_name)1299 gtk_status_icon_new_from_icon_name (const gchar *icon_name)
1300 {
1301 return g_object_new (GTK_TYPE_STATUS_ICON,
1302 "icon-name", icon_name,
1303 NULL);
1304 }
1305
1306 /**
1307 * gtk_status_icon_new_from_gicon:
1308 * @icon: a #GIcon
1309 *
1310 * Creates a status icon displaying a #GIcon. If the icon is a
1311 * themed icon, it will be updated when the theme changes.
1312 *
1313 * Returns: a new #GtkStatusIcon
1314 *
1315 * Since: 2.14
1316 *
1317 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
1318 * provide status notifications
1319 */
1320 GtkStatusIcon *
gtk_status_icon_new_from_gicon(GIcon * icon)1321 gtk_status_icon_new_from_gicon (GIcon *icon)
1322 {
1323 return g_object_new (GTK_TYPE_STATUS_ICON,
1324 "gicon", icon,
1325 NULL);
1326 }
1327
1328 static void
emit_activate_signal(GtkStatusIcon * status_icon)1329 emit_activate_signal (GtkStatusIcon *status_icon)
1330 {
1331 g_signal_emit (status_icon,
1332 status_icon_signals [ACTIVATE_SIGNAL], 0);
1333 }
1334
1335 static void
emit_popup_menu_signal(GtkStatusIcon * status_icon,guint button,guint32 activate_time)1336 emit_popup_menu_signal (GtkStatusIcon *status_icon,
1337 guint button,
1338 guint32 activate_time)
1339 {
1340 g_signal_emit (status_icon,
1341 status_icon_signals [POPUP_MENU_SIGNAL], 0,
1342 button,
1343 activate_time);
1344 }
1345
1346 #ifdef GDK_WINDOWING_X11
1347
1348 static gboolean
emit_size_changed_signal(GtkStatusIcon * status_icon,gint size)1349 emit_size_changed_signal (GtkStatusIcon *status_icon,
1350 gint size)
1351 {
1352 gboolean handled = FALSE;
1353
1354 g_signal_emit (status_icon,
1355 status_icon_signals [SIZE_CHANGED_SIGNAL], 0,
1356 size,
1357 &handled);
1358
1359 return handled;
1360 }
1361
1362 #endif
1363
1364 /* rounds the pixel size to the nearest size avaiable in the theme */
1365 static gint
round_pixel_size(GtkWidget * widget,gint pixel_size)1366 round_pixel_size (GtkWidget *widget,
1367 gint pixel_size)
1368 {
1369 GtkIconSize s;
1370 gint w, h, d, dist, size;
1371
1372 dist = G_MAXINT;
1373 size = 0;
1374
1375 for (s = GTK_ICON_SIZE_MENU; s <= GTK_ICON_SIZE_DIALOG; s++)
1376 {
1377 if (gtk_icon_size_lookup (s, &w, &h))
1378 {
1379 d = MAX (abs (pixel_size - w), abs (pixel_size - h));
1380 if (d < dist)
1381 {
1382 dist = d;
1383 size = MAX (w, h);
1384 }
1385 }
1386 }
1387
1388 return size;
1389 }
1390
1391 static void
gtk_status_icon_update_image(GtkStatusIcon * status_icon)1392 gtk_status_icon_update_image (GtkStatusIcon *status_icon)
1393 {
1394 GtkStatusIconPrivate *priv = status_icon->priv;
1395 #ifdef GDK_WINDOWING_WIN32
1396 HICON prev_hicon;
1397 #endif
1398 GtkIconHelper *icon_helper;
1399 cairo_surface_t *surface;
1400 GtkWidget *widget;
1401 #ifndef GDK_WINDOWING_X11
1402 GdkPixbuf *pixbuf;
1403 #endif
1404 gint round_size;
1405 gint scale;
1406
1407 #ifdef GDK_WINDOWING_X11
1408 widget = priv->image;
1409 scale = gtk_widget_get_scale_factor (widget);
1410 #else
1411 widget = priv->dummy_widget;
1412 scale = 1;
1413 #endif
1414
1415 if (widget == NULL)
1416 return;
1417
1418 round_size = round_pixel_size (widget, priv->size);
1419
1420 icon_helper = gtk_icon_helper_new (gtk_style_context_get_node (gtk_widget_get_style_context (widget)), widget);
1421 _gtk_icon_helper_set_force_scale_pixbuf (icon_helper, TRUE);
1422 _gtk_icon_helper_set_definition (icon_helper, priv->image_def);
1423 _gtk_icon_helper_set_icon_size (icon_helper, GTK_ICON_SIZE_SMALL_TOOLBAR);
1424 _gtk_icon_helper_set_pixel_size (icon_helper, round_size);
1425 surface = gtk_icon_helper_load_surface (icon_helper, scale);
1426
1427 g_object_unref (icon_helper);
1428
1429 #ifdef GDK_WINDOWING_X11
1430 if (surface)
1431 {
1432 gtk_image_set_from_surface (GTK_IMAGE (priv->image), surface);
1433 cairo_surface_destroy (surface);
1434 }
1435 else
1436 {
1437 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), NULL);
1438 }
1439 #endif
1440
1441 #ifdef GDK_WINDOWING_WIN32
1442 if (surface)
1443 {
1444 pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0,
1445 cairo_image_surface_get_width (surface),
1446 cairo_image_surface_get_height (surface));
1447 cairo_surface_destroy (surface);
1448 }
1449
1450 if (pixbuf != NULL)
1451 {
1452 prev_hicon = priv->nid.hIcon;
1453 priv->nid.hIcon = gdk_win32_pixbuf_to_hicon_libgtk_only (pixbuf);
1454 priv->nid.uFlags |= NIF_ICON;
1455 if (priv->nid.hWnd != NULL && priv->visible)
1456 if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
1457 g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_MODIFY) failed");
1458 if (prev_hicon)
1459 DestroyIcon (prev_hicon);
1460 }
1461 else
1462 {
1463 priv->nid.uFlags &= ~NIF_ICON;
1464 if (priv->nid.hWnd != NULL && priv->visible)
1465 if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
1466 g_warning (G_STRLOC ": Shell_NotifyIcon(NIM_MODIFY) failed");
1467 }
1468
1469 g_clear_object (&pixbuf);
1470 #endif
1471
1472 #ifdef GDK_WINDOWING_QUARTZ
1473 if (surface)
1474 {
1475 pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0,
1476 cairo_image_surface_get_width (surface),
1477 cairo_image_surface_get_height (surface));
1478 cairo_surface_destroy (surface);
1479 }
1480
1481 if (pixbuf != NULL)
1482 {
1483 QUARTZ_POOL_ALLOC;
1484 [priv->status_item setImage:pixbuf];
1485 QUARTZ_POOL_RELEASE;
1486 }
1487 else
1488 {
1489 [priv->status_item setImage:NULL];
1490 }
1491
1492 g_clear_object (&pixbuf);
1493 #endif
1494 }
1495
1496 #ifdef GDK_WINDOWING_X11
1497
1498 static void
gtk_status_icon_size_allocate(GtkStatusIcon * status_icon,GtkAllocation * allocation)1499 gtk_status_icon_size_allocate (GtkStatusIcon *status_icon,
1500 GtkAllocation *allocation)
1501 {
1502 GtkStatusIconPrivate *priv = status_icon->priv;
1503 GtkOrientation orientation;
1504 gint size;
1505
1506 orientation = _gtk_tray_icon_get_orientation (GTK_TRAY_ICON (priv->tray_icon));
1507
1508 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1509 size = allocation->height;
1510 else
1511 size = allocation->width;
1512
1513 if (priv->size - 1 > size || priv->size + 1 < size)
1514 {
1515 priv->size = size;
1516
1517 g_object_notify (G_OBJECT (status_icon), "size");
1518
1519 if (!emit_size_changed_signal (status_icon, size))
1520 gtk_status_icon_update_image (status_icon);
1521 }
1522 }
1523
1524 static void
gtk_status_icon_screen_changed(GtkStatusIcon * status_icon,GdkScreen * old_screen)1525 gtk_status_icon_screen_changed (GtkStatusIcon *status_icon,
1526 GdkScreen *old_screen)
1527 {
1528 GtkStatusIconPrivate *priv = status_icon->priv;
1529
1530 if (gtk_widget_get_screen (priv->tray_icon) != old_screen)
1531 {
1532 g_object_notify (G_OBJECT (status_icon), "screen");
1533 }
1534 }
1535
1536 static void
gtk_status_icon_padding_changed(GtkStatusIcon * status_icon)1537 gtk_status_icon_padding_changed (GtkStatusIcon *status_icon)
1538 {
1539 GtkStatusIconPrivate *priv = status_icon->priv;
1540 GtkOrientation orientation;
1541 gint padding;
1542
1543 orientation = _gtk_tray_icon_get_orientation (GTK_TRAY_ICON (priv->tray_icon));
1544 padding = _gtk_tray_icon_get_padding (GTK_TRAY_ICON (priv->tray_icon));
1545
1546 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1547 {
1548 gtk_widget_set_margin_start (priv->image, padding);
1549 gtk_widget_set_margin_end (priv->image, padding);
1550 }
1551 else
1552 {
1553 gtk_widget_set_margin_bottom (priv->image, padding);
1554 gtk_widget_set_margin_top (priv->image, padding);
1555 }
1556 }
1557
1558 static void
gtk_status_icon_icon_size_changed(GtkStatusIcon * status_icon)1559 gtk_status_icon_icon_size_changed (GtkStatusIcon *status_icon)
1560 {
1561 GtkStatusIconPrivate *priv = status_icon->priv;
1562 gint icon_size;
1563
1564 icon_size = _gtk_tray_icon_get_icon_size (GTK_TRAY_ICON (priv->tray_icon));
1565
1566 if (icon_size != 0)
1567 gtk_image_set_pixel_size (GTK_IMAGE (priv->image), icon_size);
1568 else
1569 gtk_image_set_pixel_size (GTK_IMAGE (priv->image), -1);
1570 }
1571
1572 static void
gtk_status_icon_embedded_changed(GtkStatusIcon * status_icon)1573 gtk_status_icon_embedded_changed (GtkStatusIcon *status_icon)
1574 {
1575 gtk_status_icon_padding_changed (status_icon);
1576 gtk_status_icon_icon_size_changed (status_icon);
1577 g_object_notify (G_OBJECT (status_icon), "embedded");
1578 }
1579
1580 static void
gtk_status_icon_orientation_changed(GtkStatusIcon * status_icon)1581 gtk_status_icon_orientation_changed (GtkStatusIcon *status_icon)
1582 {
1583 gtk_status_icon_padding_changed (status_icon);
1584 g_object_notify (G_OBJECT (status_icon), "orientation");
1585 }
1586
1587 static void
gtk_status_icon_fg_changed(GtkStatusIcon * status_icon)1588 gtk_status_icon_fg_changed (GtkStatusIcon *status_icon)
1589 {
1590 GtkStatusIconPrivate *priv = status_icon->priv;
1591 GdkRGBA *rgba;
1592
1593 g_object_get (priv->tray_icon, "fg-color", &rgba, NULL);
1594
1595 gtk_widget_override_color (priv->image, GTK_STATE_FLAG_NORMAL, rgba);
1596
1597 gdk_rgba_free (rgba);
1598 }
1599
1600 static void
gtk_status_icon_color_changed(GtkTrayIcon * tray,GParamSpec * pspec,GtkStatusIcon * status_icon)1601 gtk_status_icon_color_changed (GtkTrayIcon *tray,
1602 GParamSpec *pspec,
1603 GtkStatusIcon *status_icon)
1604 {
1605 GtkStatusIconPrivate *priv = status_icon->priv;
1606 const gchar *name;
1607
1608 switch (pspec->name[0])
1609 {
1610 case 'e':
1611 name = "error";
1612 break;
1613 case 'w':
1614 name = "warning";
1615 break;
1616 case 's':
1617 name = "success";
1618 break;
1619 default:
1620 name = NULL;
1621 break;
1622 }
1623
1624 if (name)
1625 {
1626 GdkRGBA rgba;
1627
1628 g_object_get (priv->tray_icon, pspec->name, &rgba, NULL);
1629
1630 rgba.alpha = 1;
1631
1632 gtk_widget_override_symbolic_color (priv->image, name, &rgba);
1633 }
1634 }
1635
1636 static gboolean
gtk_status_icon_key_press(GtkStatusIcon * status_icon,GdkEventKey * event)1637 gtk_status_icon_key_press (GtkStatusIcon *status_icon,
1638 GdkEventKey *event)
1639 {
1640 guint state, keyval;
1641
1642 state = event->state & gtk_accelerator_get_default_mod_mask ();
1643 keyval = event->keyval;
1644 if (state == 0 &&
1645 (keyval == GDK_KEY_Return ||
1646 keyval == GDK_KEY_KP_Enter ||
1647 keyval == GDK_KEY_ISO_Enter ||
1648 keyval == GDK_KEY_space ||
1649 keyval == GDK_KEY_KP_Space))
1650 {
1651 emit_activate_signal (status_icon);
1652 return TRUE;
1653 }
1654
1655 return FALSE;
1656 }
1657
1658 static void
gtk_status_icon_popup_menu(GtkStatusIcon * status_icon)1659 gtk_status_icon_popup_menu (GtkStatusIcon *status_icon)
1660 {
1661 emit_popup_menu_signal (status_icon, 0, gtk_get_current_event_time ());
1662 }
1663
1664 #endif /* GDK_WINDOWING_X11 */
1665
1666 static gboolean
gtk_status_icon_button_press(GtkStatusIcon * status_icon,GdkEventButton * event)1667 gtk_status_icon_button_press (GtkStatusIcon *status_icon,
1668 GdkEventButton *event)
1669 {
1670 gboolean handled = FALSE;
1671
1672 g_signal_emit (status_icon,
1673 status_icon_signals [BUTTON_PRESS_EVENT_SIGNAL], 0,
1674 event, &handled);
1675 if (handled)
1676 return TRUE;
1677
1678 if (gdk_event_triggers_context_menu ((GdkEvent *) event))
1679 {
1680 emit_popup_menu_signal (status_icon, event->button, event->time);
1681 return TRUE;
1682 }
1683 else if (event->button == GDK_BUTTON_PRIMARY && event->type == GDK_BUTTON_PRESS)
1684 {
1685 emit_activate_signal (status_icon);
1686 return TRUE;
1687 }
1688
1689 return FALSE;
1690 }
1691
1692 static gboolean
gtk_status_icon_button_release(GtkStatusIcon * status_icon,GdkEventButton * event)1693 gtk_status_icon_button_release (GtkStatusIcon *status_icon,
1694 GdkEventButton *event)
1695 {
1696 gboolean handled = FALSE;
1697 g_signal_emit (status_icon,
1698 status_icon_signals [BUTTON_RELEASE_EVENT_SIGNAL], 0,
1699 event, &handled);
1700 return handled;
1701 }
1702
1703 #ifdef GDK_WINDOWING_X11
1704
1705 static gboolean
gtk_status_icon_scroll(GtkStatusIcon * status_icon,GdkEventScroll * event)1706 gtk_status_icon_scroll (GtkStatusIcon *status_icon,
1707 GdkEventScroll *event)
1708 {
1709 gboolean handled = FALSE;
1710 g_signal_emit (status_icon,
1711 status_icon_signals [SCROLL_EVENT_SIGNAL], 0,
1712 event, &handled);
1713 return handled;
1714 }
1715
1716 static gboolean
gtk_status_icon_query_tooltip(GtkStatusIcon * status_icon,gint x,gint y,gboolean keyboard_tip,GtkTooltip * tooltip)1717 gtk_status_icon_query_tooltip (GtkStatusIcon *status_icon,
1718 gint x,
1719 gint y,
1720 gboolean keyboard_tip,
1721 GtkTooltip *tooltip)
1722 {
1723 gboolean handled = FALSE;
1724 g_signal_emit (status_icon,
1725 status_icon_signals [QUERY_TOOLTIP_SIGNAL], 0,
1726 x, y, keyboard_tip, tooltip, &handled);
1727 return handled;
1728 }
1729
1730 #endif /* GDK_WINDOWING_X11 */
1731
1732 static void
gtk_status_icon_reset_image_data(GtkStatusIcon * status_icon)1733 gtk_status_icon_reset_image_data (GtkStatusIcon *status_icon)
1734 {
1735 GtkStatusIconPrivate *priv = status_icon->priv;
1736 GtkImageType storage_type = gtk_image_definition_get_storage_type (priv->image_def);
1737
1738 switch (storage_type)
1739 {
1740 case GTK_IMAGE_PIXBUF:
1741 g_object_notify (G_OBJECT (status_icon), "pixbuf");
1742 break;
1743 case GTK_IMAGE_STOCK:
1744 g_object_notify (G_OBJECT (status_icon), "stock");
1745 break;
1746 case GTK_IMAGE_ICON_NAME:
1747 g_object_notify (G_OBJECT (status_icon), "icon-name");
1748 break;
1749 case GTK_IMAGE_GICON:
1750 g_object_notify (G_OBJECT (status_icon), "gicon");
1751 break;
1752 case GTK_IMAGE_EMPTY:
1753 break;
1754 default:
1755 g_assert_not_reached ();
1756 break;
1757 }
1758
1759 gtk_image_definition_unref (priv->image_def);
1760 priv->image_def = gtk_image_definition_new_empty ();
1761 g_object_notify (G_OBJECT (status_icon), "storage-type");
1762 }
1763
1764 static void
gtk_status_icon_take_image(GtkStatusIcon * status_icon,GtkImageDefinition * def)1765 gtk_status_icon_take_image (GtkStatusIcon *status_icon,
1766 GtkImageDefinition *def)
1767 {
1768 GtkStatusIconPrivate *priv = status_icon->priv;
1769
1770 g_object_freeze_notify (G_OBJECT (status_icon));
1771
1772 gtk_status_icon_reset_image_data (status_icon);
1773
1774 g_object_notify (G_OBJECT (status_icon), "storage-type");
1775
1776 if (def != NULL)
1777 {
1778 gtk_image_definition_unref (priv->image_def);
1779 priv->image_def = def;
1780 /* the icon size we pass here doesn't really matter, since
1781 * we force a pixel size before doing the actual rendering anyway.
1782 */
1783 switch (gtk_image_definition_get_storage_type (def))
1784 {
1785 case GTK_IMAGE_PIXBUF:
1786 g_object_notify (G_OBJECT (status_icon), "pixbuf");
1787 break;
1788 case GTK_IMAGE_STOCK:
1789 g_object_notify (G_OBJECT (status_icon), "stock");
1790 break;
1791 case GTK_IMAGE_ICON_NAME:
1792 g_object_notify (G_OBJECT (status_icon), "icon-name");
1793 break;
1794 case GTK_IMAGE_GICON:
1795 g_object_notify (G_OBJECT (status_icon), "gicon");
1796 break;
1797 default:
1798 g_warning ("Image type %u not handled by GtkStatusIcon",
1799 gtk_image_definition_get_storage_type (def));
1800 }
1801 }
1802
1803 g_object_thaw_notify (G_OBJECT (status_icon));
1804
1805 gtk_status_icon_update_image (status_icon);
1806 }
1807
1808 /**
1809 * gtk_status_icon_set_from_pixbuf:
1810 * @status_icon: a #GtkStatusIcon
1811 * @pixbuf: (allow-none): a #GdkPixbuf or %NULL
1812 *
1813 * Makes @status_icon display @pixbuf.
1814 * See gtk_status_icon_new_from_pixbuf() for details.
1815 *
1816 * Since: 2.10
1817 *
1818 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
1819 * provide status notifications; you can use g_notification_set_icon()
1820 * to associate a #GIcon with a notification
1821 */
1822 void
gtk_status_icon_set_from_pixbuf(GtkStatusIcon * status_icon,GdkPixbuf * pixbuf)1823 gtk_status_icon_set_from_pixbuf (GtkStatusIcon *status_icon,
1824 GdkPixbuf *pixbuf)
1825 {
1826 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1827 g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
1828
1829 gtk_status_icon_take_image (status_icon,
1830 gtk_image_definition_new_pixbuf (pixbuf, 1));
1831 }
1832
1833 /**
1834 * gtk_status_icon_set_from_file:
1835 * @status_icon: a #GtkStatusIcon
1836 * @filename: (type filename): a filename
1837 *
1838 * Makes @status_icon display the file @filename.
1839 * See gtk_status_icon_new_from_file() for details.
1840 *
1841 * Since: 2.10
1842 *
1843 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
1844 * provide status notifications; you can use g_notification_set_icon()
1845 * to associate a #GIcon with a notification
1846 */
1847 void
gtk_status_icon_set_from_file(GtkStatusIcon * status_icon,const gchar * filename)1848 gtk_status_icon_set_from_file (GtkStatusIcon *status_icon,
1849 const gchar *filename)
1850 {
1851 GdkPixbuf *pixbuf;
1852
1853 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1854 g_return_if_fail (filename != NULL);
1855
1856 pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
1857
1858 gtk_status_icon_set_from_pixbuf (status_icon, pixbuf);
1859
1860 if (pixbuf)
1861 g_object_unref (pixbuf);
1862 }
1863
1864 /**
1865 * gtk_status_icon_set_from_stock:
1866 * @status_icon: a #GtkStatusIcon
1867 * @stock_id: a stock icon id
1868 *
1869 * Makes @status_icon display the stock icon with the id @stock_id.
1870 * See gtk_status_icon_new_from_stock() for details.
1871 *
1872 * Since: 2.10
1873 *
1874 * Deprecated: 3.10: Use gtk_status_icon_set_from_icon_name() instead.
1875 **/
1876 void
gtk_status_icon_set_from_stock(GtkStatusIcon * status_icon,const gchar * stock_id)1877 gtk_status_icon_set_from_stock (GtkStatusIcon *status_icon,
1878 const gchar *stock_id)
1879 {
1880 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1881 g_return_if_fail (stock_id != NULL);
1882
1883 gtk_status_icon_take_image (status_icon,
1884 gtk_image_definition_new_stock (stock_id));
1885 }
1886
1887 /**
1888 * gtk_status_icon_set_from_icon_name:
1889 * @status_icon: a #GtkStatusIcon
1890 * @icon_name: an icon name
1891 *
1892 * Makes @status_icon display the icon named @icon_name from the
1893 * current icon theme.
1894 * See gtk_status_icon_new_from_icon_name() for details.
1895 *
1896 * Since: 2.10
1897 *
1898 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
1899 * provide status notifications; you can use g_notification_set_icon()
1900 * to associate a #GIcon with a notification
1901 */
1902 void
gtk_status_icon_set_from_icon_name(GtkStatusIcon * status_icon,const gchar * icon_name)1903 gtk_status_icon_set_from_icon_name (GtkStatusIcon *status_icon,
1904 const gchar *icon_name)
1905 {
1906 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1907 g_return_if_fail (icon_name != NULL);
1908
1909 gtk_status_icon_take_image (status_icon,
1910 gtk_image_definition_new_icon_name (icon_name));
1911 }
1912
1913 /**
1914 * gtk_status_icon_set_from_gicon:
1915 * @status_icon: a #GtkStatusIcon
1916 * @icon: a GIcon
1917 *
1918 * Makes @status_icon display the #GIcon.
1919 * See gtk_status_icon_new_from_gicon() for details.
1920 *
1921 * Since: 2.14
1922 *
1923 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
1924 * provide status notifications; you can use g_notification_set_icon()
1925 * to associate a #GIcon with a notification
1926 */
1927 void
gtk_status_icon_set_from_gicon(GtkStatusIcon * status_icon,GIcon * icon)1928 gtk_status_icon_set_from_gicon (GtkStatusIcon *status_icon,
1929 GIcon *icon)
1930 {
1931 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
1932 g_return_if_fail (icon != NULL);
1933
1934 gtk_status_icon_take_image (status_icon,
1935 gtk_image_definition_new_gicon (icon));
1936 }
1937
1938 /**
1939 * gtk_status_icon_get_storage_type:
1940 * @status_icon: a #GtkStatusIcon
1941 *
1942 * Gets the type of representation being used by the #GtkStatusIcon
1943 * to store image data. If the #GtkStatusIcon has no image data,
1944 * the return value will be %GTK_IMAGE_EMPTY.
1945 *
1946 * Returns: the image representation being used
1947 *
1948 * Since: 2.10
1949 *
1950 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
1951 * provide status notifications; there is no direct replacement
1952 * for this function, and #GNotification only supports #GIcon
1953 * instances
1954 */
1955 GtkImageType
gtk_status_icon_get_storage_type(GtkStatusIcon * status_icon)1956 gtk_status_icon_get_storage_type (GtkStatusIcon *status_icon)
1957 {
1958 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), GTK_IMAGE_EMPTY);
1959
1960 return gtk_image_definition_get_storage_type (status_icon->priv->image_def);
1961 }
1962 /**
1963 * gtk_status_icon_get_pixbuf:
1964 * @status_icon: a #GtkStatusIcon
1965 *
1966 * Gets the #GdkPixbuf being displayed by the #GtkStatusIcon.
1967 * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
1968 * %GTK_IMAGE_PIXBUF (see gtk_status_icon_get_storage_type()).
1969 * The caller of this function does not own a reference to the
1970 * returned pixbuf.
1971 *
1972 * Returns: (nullable) (transfer none): the displayed pixbuf,
1973 * or %NULL if the image is empty.
1974 *
1975 * Since: 2.10
1976 *
1977 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
1978 * provide status notifications; there is no direct replacement
1979 * for this function
1980 */
1981 GdkPixbuf *
gtk_status_icon_get_pixbuf(GtkStatusIcon * status_icon)1982 gtk_status_icon_get_pixbuf (GtkStatusIcon *status_icon)
1983 {
1984 GtkStatusIconPrivate *priv;
1985
1986 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
1987
1988 priv = status_icon->priv;
1989
1990 return gtk_image_definition_get_pixbuf (priv->image_def);
1991 }
1992
1993 /**
1994 * gtk_status_icon_get_stock:
1995 * @status_icon: a #GtkStatusIcon
1996 *
1997 * Gets the id of the stock icon being displayed by the #GtkStatusIcon.
1998 * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
1999 * %GTK_IMAGE_STOCK (see gtk_status_icon_get_storage_type()).
2000 * The returned string is owned by the #GtkStatusIcon and should not
2001 * be freed or modified.
2002 *
2003 * Returns: (nullable): stock id of the displayed stock icon,
2004 * or %NULL if the image is empty.
2005 *
2006 * Since: 2.10
2007 *
2008 * Deprecated: 3.10: Use gtk_status_icon_get_icon_name() instead.
2009 **/
2010 const gchar *
gtk_status_icon_get_stock(GtkStatusIcon * status_icon)2011 gtk_status_icon_get_stock (GtkStatusIcon *status_icon)
2012 {
2013 GtkStatusIconPrivate *priv;
2014
2015 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2016
2017 priv = status_icon->priv;
2018
2019 return gtk_image_definition_get_stock (priv->image_def);
2020 }
2021
2022 /**
2023 * gtk_status_icon_get_icon_name:
2024 * @status_icon: a #GtkStatusIcon
2025 *
2026 * Gets the name of the icon being displayed by the #GtkStatusIcon.
2027 * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
2028 * %GTK_IMAGE_ICON_NAME (see gtk_status_icon_get_storage_type()).
2029 * The returned string is owned by the #GtkStatusIcon and should not
2030 * be freed or modified.
2031 *
2032 * Returns: (nullable): name of the displayed icon, or %NULL if the image is empty.
2033 *
2034 * Since: 2.10
2035 *
2036 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
2037 * provide status notifications; there is no direct replacement
2038 * for this function
2039 */
2040 const gchar *
gtk_status_icon_get_icon_name(GtkStatusIcon * status_icon)2041 gtk_status_icon_get_icon_name (GtkStatusIcon *status_icon)
2042 {
2043 GtkStatusIconPrivate *priv;
2044
2045 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2046
2047 priv = status_icon->priv;
2048
2049 return gtk_image_definition_get_icon_name (priv->image_def);
2050 }
2051
2052 /**
2053 * gtk_status_icon_get_gicon:
2054 * @status_icon: a #GtkStatusIcon
2055 *
2056 * Retrieves the #GIcon being displayed by the #GtkStatusIcon.
2057 * The storage type of the status icon must be %GTK_IMAGE_EMPTY or
2058 * %GTK_IMAGE_GICON (see gtk_status_icon_get_storage_type()).
2059 * The caller of this function does not own a reference to the
2060 * returned #GIcon.
2061 *
2062 * If this function fails, @icon is left unchanged;
2063 *
2064 * Returns: (nullable) (transfer none): the displayed icon, or %NULL if the image is empty
2065 *
2066 * Since: 2.14
2067 *
2068 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
2069 * provide status notifications; there is no direct replacement
2070 * for this function
2071 */
2072 GIcon *
gtk_status_icon_get_gicon(GtkStatusIcon * status_icon)2073 gtk_status_icon_get_gicon (GtkStatusIcon *status_icon)
2074 {
2075 GtkStatusIconPrivate *priv;
2076
2077 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2078
2079 priv = status_icon->priv;
2080
2081 return gtk_image_definition_get_gicon (priv->image_def);
2082 }
2083
2084 /**
2085 * gtk_status_icon_get_size:
2086 * @status_icon: a #GtkStatusIcon
2087 *
2088 * Gets the size in pixels that is available for the image.
2089 * Stock icons and named icons adapt their size automatically
2090 * if the size of the notification area changes. For other
2091 * storage types, the size-changed signal can be used to
2092 * react to size changes.
2093 *
2094 * Note that the returned size is only meaningful while the
2095 * status icon is embedded (see gtk_status_icon_is_embedded()).
2096 *
2097 * Returns: the size that is available for the image
2098 *
2099 * Since: 2.10
2100 *
2101 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
2102 * provide status notifications; there is no direct replacement
2103 * for this function, as the representation of a notification
2104 * is left to the platform
2105 */
2106 gint
gtk_status_icon_get_size(GtkStatusIcon * status_icon)2107 gtk_status_icon_get_size (GtkStatusIcon *status_icon)
2108 {
2109 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), 0);
2110
2111 return status_icon->priv->size;
2112 }
2113
2114 /**
2115 * gtk_status_icon_set_screen:
2116 * @status_icon: a #GtkStatusIcon
2117 * @screen: a #GdkScreen
2118 *
2119 * Sets the #GdkScreen where @status_icon is displayed; if
2120 * the icon is already mapped, it will be unmapped, and
2121 * then remapped on the new screen.
2122 *
2123 * Since: 2.12
2124 *
2125 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
2126 * provide status notifications; there is no direct replacement
2127 * for this function, as GTK typically only has one #GdkScreen
2128 * and notifications are managed by the platform
2129 */
2130 void
gtk_status_icon_set_screen(GtkStatusIcon * status_icon,GdkScreen * screen)2131 gtk_status_icon_set_screen (GtkStatusIcon *status_icon,
2132 GdkScreen *screen)
2133 {
2134 g_return_if_fail (GDK_IS_SCREEN (screen));
2135
2136 #ifdef GDK_WINDOWING_X11
2137 if (status_icon->priv->tray_icon)
2138 gtk_window_set_screen (GTK_WINDOW (status_icon->priv->tray_icon), screen);
2139 #endif
2140 }
2141
2142 /**
2143 * gtk_status_icon_get_screen:
2144 * @status_icon: a #GtkStatusIcon
2145 *
2146 * Returns the #GdkScreen associated with @status_icon.
2147 *
2148 * Returns: (transfer none): a #GdkScreen.
2149 *
2150 * Since: 2.12
2151 *
2152 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
2153 * provide status notifications; there is no direct replacement
2154 * for this function, as notifications are managed by the platform
2155 */
2156 GdkScreen *
gtk_status_icon_get_screen(GtkStatusIcon * status_icon)2157 gtk_status_icon_get_screen (GtkStatusIcon *status_icon)
2158 {
2159 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2160
2161 #ifdef GDK_WINDOWING_X11
2162 if (status_icon->priv->tray_icon)
2163 return gtk_window_get_screen (GTK_WINDOW (status_icon->priv->tray_icon));
2164 else
2165 #endif
2166 return gdk_screen_get_default ();
2167 }
2168
2169 /**
2170 * gtk_status_icon_set_visible:
2171 * @status_icon: a #GtkStatusIcon
2172 * @visible: %TRUE to show the status icon, %FALSE to hide it
2173 *
2174 * Shows or hides a status icon.
2175 *
2176 * Since: 2.10
2177 *
2178 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
2179 * provide status notifications; there is no direct replacement
2180 * for this function, as notifications are managed by the platform
2181 */
2182 void
gtk_status_icon_set_visible(GtkStatusIcon * status_icon,gboolean visible)2183 gtk_status_icon_set_visible (GtkStatusIcon *status_icon,
2184 gboolean visible)
2185 {
2186 GtkStatusIconPrivate *priv;
2187
2188 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2189
2190 priv = status_icon->priv;
2191
2192 visible = visible != FALSE;
2193
2194 if (priv->visible != visible)
2195 {
2196 priv->visible = visible;
2197
2198 #ifdef GDK_WINDOWING_X11
2199 if (priv->tray_icon)
2200 {
2201 if (visible)
2202 gtk_widget_show (priv->tray_icon);
2203 else if (gtk_widget_get_realized (priv->tray_icon))
2204 {
2205 gtk_widget_hide (priv->tray_icon);
2206 gtk_widget_unrealize (priv->tray_icon);
2207 }
2208 }
2209 #endif
2210 #ifdef GDK_WINDOWING_WIN32
2211 if (priv->nid.hWnd != NULL)
2212 {
2213 if (visible)
2214 Shell_NotifyIconW (NIM_ADD, &priv->nid);
2215 else
2216 Shell_NotifyIconW (NIM_DELETE, &priv->nid);
2217 }
2218 #endif
2219 #ifdef GDK_WINDOWING_QUARTZ
2220 QUARTZ_POOL_ALLOC;
2221 [priv->status_item setVisible:visible];
2222 QUARTZ_POOL_RELEASE;
2223 #endif
2224 g_object_notify (G_OBJECT (status_icon), "visible");
2225 }
2226 }
2227
2228 /**
2229 * gtk_status_icon_get_visible:
2230 * @status_icon: a #GtkStatusIcon
2231 *
2232 * Returns whether the status icon is visible or not.
2233 * Note that being visible does not guarantee that
2234 * the user can actually see the icon, see also
2235 * gtk_status_icon_is_embedded().
2236 *
2237 * Returns: %TRUE if the status icon is visible
2238 *
2239 * Since: 2.10
2240 *
2241 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
2242 * provide status notifications; there is no direct replacement
2243 * for this function
2244 */
2245 gboolean
gtk_status_icon_get_visible(GtkStatusIcon * status_icon)2246 gtk_status_icon_get_visible (GtkStatusIcon *status_icon)
2247 {
2248 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
2249
2250 return status_icon->priv->visible;
2251 }
2252
2253 /**
2254 * gtk_status_icon_is_embedded:
2255 * @status_icon: a #GtkStatusIcon
2256 *
2257 * Returns whether the status icon is embedded in a notification
2258 * area.
2259 *
2260 * Returns: %TRUE if the status icon is embedded in
2261 * a notification area.
2262 *
2263 * Since: 2.10
2264 *
2265 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
2266 * provide status notifications; there is no direct replacement
2267 * for this function
2268 */
2269 gboolean
gtk_status_icon_is_embedded(GtkStatusIcon * status_icon)2270 gtk_status_icon_is_embedded (GtkStatusIcon *status_icon)
2271 {
2272 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
2273
2274 #ifdef GDK_WINDOWING_X11
2275 if (status_icon->priv->tray_icon == NULL ||
2276 !gtk_plug_get_embedded (GTK_PLUG (status_icon->priv->tray_icon)))
2277 return FALSE;
2278 #endif
2279 return TRUE;
2280 }
2281
2282 /**
2283 * gtk_status_icon_position_menu:
2284 * @menu: the #GtkMenu
2285 * @x: (inout): return location for the x position
2286 * @y: (inout): return location for the y position
2287 * @push_in: (out): whether the first menu item should be offset
2288 * (pushed in) to be aligned with the menu popup position
2289 * (only useful for GtkOptionMenu).
2290 * @user_data: (type GtkStatusIcon): the status icon to position the menu on
2291 *
2292 * Menu positioning function to use with gtk_menu_popup()
2293 * to position @menu aligned to the status icon @user_data.
2294 *
2295 * Since: 2.10
2296 *
2297 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
2298 * provide status notifications; notifications do not have menus,
2299 * but can have buttons, and actions associated with each button
2300 */
2301 void
gtk_status_icon_position_menu(GtkMenu * menu,gint * x,gint * y,gboolean * push_in,gpointer user_data)2302 gtk_status_icon_position_menu (GtkMenu *menu,
2303 gint *x,
2304 gint *y,
2305 gboolean *push_in,
2306 gpointer user_data)
2307 {
2308 #ifdef GDK_WINDOWING_X11
2309 GtkStatusIcon *status_icon = GTK_STATUS_ICON (user_data);
2310 GtkStatusIconPrivate *priv = status_icon->priv;
2311 GtkAllocation allocation;
2312 GtkTrayIcon *tray_icon;
2313 GtkWidget *widget;
2314 GdkScreen *screen;
2315 GtkTextDirection direction;
2316 GtkRequisition menu_req;
2317 GdkRectangle monitor;
2318 GdkWindow *window;
2319 gint monitor_num, height, width, xoffset, yoffset;
2320
2321 g_return_if_fail (GTK_IS_MENU (menu));
2322 g_return_if_fail (GTK_IS_STATUS_ICON (user_data));
2323
2324 if (priv->tray_icon == NULL)
2325 {
2326 *x = 0;
2327 *y = 0;
2328 return;
2329 }
2330
2331 tray_icon = GTK_TRAY_ICON (priv->tray_icon);
2332 widget = priv->tray_icon;
2333
2334 direction = gtk_widget_get_direction (widget);
2335
2336 screen = gtk_widget_get_screen (widget);
2337 gtk_menu_set_screen (menu, screen);
2338
2339 window = gtk_widget_get_window (widget);
2340 monitor_num = gdk_screen_get_monitor_at_window (screen, window);
2341 if (monitor_num < 0)
2342 monitor_num = 0;
2343 gtk_menu_set_monitor (menu, monitor_num);
2344
2345 gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
2346
2347 gdk_window_get_origin (window, x, y);
2348
2349 menu_req.width = gtk_widget_get_allocated_width (GTK_WIDGET (menu));
2350 menu_req.height = gtk_widget_get_allocated_height (GTK_WIDGET (menu));
2351
2352 gtk_widget_get_allocation (widget, &allocation);
2353 if (_gtk_tray_icon_get_orientation (tray_icon) == GTK_ORIENTATION_VERTICAL)
2354 {
2355 width = 0;
2356 height = allocation.height;
2357 xoffset = allocation.width;
2358 yoffset = 0;
2359 }
2360 else
2361 {
2362 width = allocation.width;
2363 height = 0;
2364 xoffset = 0;
2365 yoffset = allocation.height;
2366 }
2367
2368 if (direction == GTK_TEXT_DIR_RTL)
2369 {
2370 if ((*x - (menu_req.width - width)) >= monitor.x)
2371 *x -= menu_req.width - width;
2372 else if ((*x + xoffset + menu_req.width) < (monitor.x + monitor.width))
2373 *x += xoffset;
2374 else if ((monitor.x + monitor.width - (*x + xoffset)) < *x)
2375 *x -= menu_req.width - width;
2376 else
2377 *x += xoffset;
2378 }
2379 else
2380 {
2381 if ((*x + xoffset + menu_req.width) < (monitor.x + monitor.width))
2382 *x += xoffset;
2383 else if ((*x - (menu_req.width - width)) >= monitor.x)
2384 *x -= menu_req.width - width;
2385 else if ((monitor.x + monitor.width - (*x + xoffset)) > *x)
2386 *x += xoffset;
2387 else
2388 *x -= menu_req.width - width;
2389 }
2390
2391 if ((*y + yoffset + menu_req.height) < (monitor.y + monitor.height))
2392 *y += yoffset;
2393 else if ((*y - (menu_req.height - height)) >= monitor.y)
2394 *y -= menu_req.height - height;
2395 else if (monitor.y + monitor.height - (*y + yoffset) > *y)
2396 *y += yoffset;
2397 else
2398 *y -= menu_req.height - height;
2399
2400 *push_in = FALSE;
2401 #endif /* GDK_WINDOWING_X11 */
2402
2403 #ifdef GDK_WINDOWING_WIN32
2404 GtkStatusIcon *status_icon;
2405 GtkStatusIconPrivate *priv;
2406 GtkRequisition menu_req;
2407
2408 g_return_if_fail (GTK_IS_MENU (menu));
2409 g_return_if_fail (GTK_IS_STATUS_ICON (user_data));
2410
2411 status_icon = GTK_STATUS_ICON (user_data);
2412 priv = status_icon->priv;
2413
2414 gtk_widget_get_preferred_size (GTK_WIDGET (menu), &menu_req, NULL);
2415
2416 *x = priv->last_click_x;
2417 *y = priv->taskbar_top - menu_req.height;
2418
2419 *push_in = TRUE;
2420 #endif
2421 }
2422
2423 /**
2424 * gtk_status_icon_get_geometry:
2425 * @status_icon: a #GtkStatusIcon
2426 * @screen: (out) (transfer none) (allow-none): return location for
2427 * the screen, or %NULL if the information is not needed
2428 * @area: (out) (allow-none): return location for the area occupied by
2429 * the status icon, or %NULL
2430 * @orientation: (out) (allow-none): return location for the
2431 * orientation of the panel in which the status icon is embedded,
2432 * or %NULL. A panel at the top or bottom of the screen is
2433 * horizontal, a panel at the left or right is vertical.
2434 *
2435 * Obtains information about the location of the status icon
2436 * on screen. This information can be used to e.g. position
2437 * popups like notification bubbles.
2438 *
2439 * See gtk_status_icon_position_menu() for a more convenient
2440 * alternative for positioning menus.
2441 *
2442 * Note that some platforms do not allow GTK+ to provide
2443 * this information, and even on platforms that do allow it,
2444 * the information is not reliable unless the status icon
2445 * is embedded in a notification area, see
2446 * gtk_status_icon_is_embedded().
2447 *
2448 * Returns: %TRUE if the location information has
2449 * been filled in
2450 *
2451 * Since: 2.10
2452 *
2453 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
2454 * provide status notifications; there is no direct replacement
2455 * for this function, as the platform is responsible for the
2456 * presentation of notifications
2457 */
2458 gboolean
gtk_status_icon_get_geometry(GtkStatusIcon * status_icon,GdkScreen ** screen,GdkRectangle * area,GtkOrientation * orientation)2459 gtk_status_icon_get_geometry (GtkStatusIcon *status_icon,
2460 GdkScreen **screen,
2461 GdkRectangle *area,
2462 GtkOrientation *orientation)
2463 {
2464 #ifdef GDK_WINDOWING_X11
2465 GtkStatusIconPrivate *priv = status_icon->priv;
2466 GtkAllocation allocation;
2467 GtkWidget *widget;
2468 gint x, y;
2469
2470 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
2471
2472 if (priv->tray_icon == NULL)
2473 return FALSE;
2474
2475 widget = priv->tray_icon;
2476
2477 if (screen)
2478 *screen = gtk_widget_get_screen (widget);
2479
2480 if (area)
2481 {
2482 gdk_window_get_origin (gtk_widget_get_window (widget),
2483 &x, &y);
2484
2485 gtk_widget_get_allocation (widget, &allocation);
2486 area->x = x;
2487 area->y = y;
2488 area->width = allocation.width;
2489 area->height = allocation.height;
2490 }
2491
2492 if (orientation)
2493 *orientation = _gtk_tray_icon_get_orientation (GTK_TRAY_ICON (widget));
2494
2495 return TRUE;
2496 #else
2497 return FALSE;
2498 #endif /* GDK_WINDOWING_X11 */
2499 }
2500
2501 /**
2502 * gtk_status_icon_set_has_tooltip:
2503 * @status_icon: a #GtkStatusIcon
2504 * @has_tooltip: whether or not @status_icon has a tooltip
2505 *
2506 * Sets the has-tooltip property on @status_icon to @has_tooltip.
2507 * See #GtkStatusIcon:has-tooltip for more information.
2508 *
2509 * Since: 2.16
2510 *
2511 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
2512 * provide status notifications; there is no direct replacement
2513 * for this function, but notifications can display an arbitrary
2514 * amount of text using g_notification_set_body()
2515 */
2516 void
gtk_status_icon_set_has_tooltip(GtkStatusIcon * status_icon,gboolean has_tooltip)2517 gtk_status_icon_set_has_tooltip (GtkStatusIcon *status_icon,
2518 gboolean has_tooltip)
2519 {
2520 GtkStatusIconPrivate *priv;
2521 gboolean changed = FALSE;
2522
2523 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2524
2525 priv = status_icon->priv;
2526
2527 #ifdef GDK_WINDOWING_X11
2528 if (priv->tray_icon)
2529 {
2530 if (gtk_widget_get_has_tooltip (priv->tray_icon) != has_tooltip)
2531 {
2532 gtk_widget_set_has_tooltip (priv->tray_icon, has_tooltip);
2533 changed = TRUE;
2534 }
2535 }
2536 #endif
2537 #ifdef GDK_WINDOWING_WIN32
2538 changed = TRUE;
2539 if (!has_tooltip && priv->tooltip_text)
2540 gtk_status_icon_set_tooltip_text (status_icon, NULL);
2541 #endif
2542 #ifdef GDK_WINDOWING_QUARTZ
2543 changed = TRUE;
2544 if (!has_tooltip && priv->tooltip_text)
2545 gtk_status_icon_set_tooltip_text (status_icon, NULL);
2546 #endif
2547
2548 if (changed)
2549 g_object_notify (G_OBJECT (status_icon), "has-tooltip");
2550 }
2551
2552 /**
2553 * gtk_status_icon_get_has_tooltip:
2554 * @status_icon: a #GtkStatusIcon
2555 *
2556 * Returns the current value of the has-tooltip property.
2557 * See #GtkStatusIcon:has-tooltip for more information.
2558 *
2559 * Returns: current value of has-tooltip on @status_icon.
2560 *
2561 * Since: 2.16
2562 *
2563 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
2564 * provide status notifications; there is no direct replacement
2565 * for this function
2566 */
2567 gboolean
gtk_status_icon_get_has_tooltip(GtkStatusIcon * status_icon)2568 gtk_status_icon_get_has_tooltip (GtkStatusIcon *status_icon)
2569 {
2570 GtkStatusIconPrivate *priv;
2571 gboolean has_tooltip = FALSE;
2572
2573 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
2574
2575 priv = status_icon->priv;
2576
2577 #ifdef GDK_WINDOWING_X11
2578 if (priv->tray_icon)
2579 has_tooltip = gtk_widget_get_has_tooltip (priv->tray_icon);
2580 #endif
2581 #ifdef GDK_WINDOWING_WIN32
2582 has_tooltip = (priv->tooltip_text != NULL);
2583 #endif
2584 #ifdef GDK_WINDOWING_QUARTZ
2585 has_tooltip = (priv->tooltip_text != NULL);
2586 #endif
2587
2588 return has_tooltip;
2589 }
2590
2591 /**
2592 * gtk_status_icon_set_tooltip_text:
2593 * @status_icon: a #GtkStatusIcon
2594 * @text: the contents of the tooltip for @status_icon
2595 *
2596 * Sets @text as the contents of the tooltip.
2597 *
2598 * This function will take care of setting #GtkStatusIcon:has-tooltip to
2599 * %TRUE and of the default handler for the #GtkStatusIcon::query-tooltip
2600 * signal.
2601 *
2602 * See also the #GtkStatusIcon:tooltip-text property and
2603 * gtk_tooltip_set_text().
2604 *
2605 * Since: 2.16
2606 *
2607 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
2608 * provide status notifications; there is no direct replacement
2609 * for this function
2610 */
2611 void
gtk_status_icon_set_tooltip_text(GtkStatusIcon * status_icon,const gchar * text)2612 gtk_status_icon_set_tooltip_text (GtkStatusIcon *status_icon,
2613 const gchar *text)
2614 {
2615 GtkStatusIconPrivate *priv;
2616
2617 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2618
2619 priv = status_icon->priv;
2620
2621 #ifdef GDK_WINDOWING_X11
2622 if (priv->tray_icon)
2623 gtk_widget_set_tooltip_text (priv->tray_icon, text);
2624 #endif
2625 #ifdef GDK_WINDOWING_WIN32
2626 if (text == NULL)
2627 priv->nid.uFlags &= ~NIF_TIP;
2628 else
2629 {
2630 WCHAR *wcs = g_utf8_to_utf16 (text, -1, NULL, NULL, NULL);
2631
2632 priv->nid.uFlags |= NIF_TIP;
2633 wcsncpy (priv->nid.szTip, wcs, G_N_ELEMENTS (priv->nid.szTip) - 1);
2634 priv->nid.szTip[G_N_ELEMENTS (priv->nid.szTip) - 1] = 0;
2635 g_free (wcs);
2636 }
2637 if (priv->nid.hWnd != NULL && priv->visible)
2638 if (!Shell_NotifyIconW (NIM_MODIFY, &priv->nid))
2639 g_warning (G_STRLOC ": Shell_NotifyIconW(NIM_MODIFY) failed");
2640
2641 g_free (priv->tooltip_text);
2642 priv->tooltip_text = g_strdup (text);
2643 #endif
2644 #ifdef GDK_WINDOWING_QUARTZ
2645 QUARTZ_POOL_ALLOC;
2646 [priv->status_item setToolTip:text];
2647 QUARTZ_POOL_RELEASE;
2648
2649 g_free (priv->tooltip_text);
2650 priv->tooltip_text = g_strdup (text);
2651 #endif
2652 }
2653
2654 /**
2655 * gtk_status_icon_get_tooltip_text:
2656 * @status_icon: a #GtkStatusIcon
2657 *
2658 * Gets the contents of the tooltip for @status_icon.
2659 *
2660 * Returns: (nullable): the tooltip text, or %NULL. You should free the
2661 * returned string with g_free() when done.
2662 *
2663 * Since: 2.16
2664 *
2665 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
2666 * provide status notifications; there is no direct replacement
2667 * for this function
2668 */
2669 gchar *
gtk_status_icon_get_tooltip_text(GtkStatusIcon * status_icon)2670 gtk_status_icon_get_tooltip_text (GtkStatusIcon *status_icon)
2671 {
2672 GtkStatusIconPrivate *priv;
2673 gchar *tooltip_text = NULL;
2674
2675 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2676
2677 priv = status_icon->priv;
2678
2679 #ifdef GDK_WINDOWING_X11
2680 if (priv->tray_icon)
2681 tooltip_text = gtk_widget_get_tooltip_text (priv->tray_icon);
2682 #endif
2683 #ifdef GDK_WINDOWING_WIN32
2684 if (priv->tooltip_text)
2685 tooltip_text = g_strdup (priv->tooltip_text);
2686 #endif
2687 #ifdef GDK_WINDOWING_QUARTZ
2688 if (priv->tooltip_text)
2689 tooltip_text = g_strdup (priv->tooltip_text);
2690 #endif
2691
2692 return tooltip_text;
2693 }
2694
2695 /**
2696 * gtk_status_icon_set_tooltip_markup:
2697 * @status_icon: a #GtkStatusIcon
2698 * @markup: (allow-none): the contents of the tooltip for @status_icon, or %NULL
2699 *
2700 * Sets @markup as the contents of the tooltip, which is marked up with
2701 * the [Pango text markup language][PangoMarkupFormat].
2702 *
2703 * This function will take care of setting #GtkStatusIcon:has-tooltip to %TRUE
2704 * and of the default handler for the #GtkStatusIcon::query-tooltip signal.
2705 *
2706 * See also the #GtkStatusIcon:tooltip-markup property and
2707 * gtk_tooltip_set_markup().
2708 *
2709 * Since: 2.16
2710 *
2711 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
2712 * provide status notifications; there is no direct replacement
2713 * for this function
2714 */
2715 void
gtk_status_icon_set_tooltip_markup(GtkStatusIcon * status_icon,const gchar * markup)2716 gtk_status_icon_set_tooltip_markup (GtkStatusIcon *status_icon,
2717 const gchar *markup)
2718 {
2719 #ifdef GDK_WINDOWING_X11
2720 GtkStatusIconPrivate *priv;
2721 #endif
2722 #if defined (GDK_WINDOWING_WIN32) || defined (GDK_WINDOWING_QUARTZ)
2723 gchar *text = NULL;
2724 #endif
2725
2726 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2727
2728 #ifdef GDK_WINDOWING_X11
2729 priv = status_icon->priv;
2730
2731 if (priv->tray_icon)
2732 gtk_widget_set_tooltip_markup (priv->tray_icon, markup);
2733 #endif
2734 #ifdef GDK_WINDOWING_WIN32
2735 if (markup)
2736 pango_parse_markup (markup, -1, 0, NULL, &text, NULL, NULL);
2737 gtk_status_icon_set_tooltip_text (status_icon, text);
2738 g_free (text);
2739 #endif
2740 #ifdef GDK_WINDOWING_QUARTZ
2741 if (markup)
2742 pango_parse_markup (markup, -1, 0, NULL, &text, NULL, NULL);
2743 gtk_status_icon_set_tooltip_text (status_icon, text);
2744 g_free (text);
2745 #endif
2746 }
2747
2748 /**
2749 * gtk_status_icon_get_tooltip_markup:
2750 * @status_icon: a #GtkStatusIcon
2751 *
2752 * Gets the contents of the tooltip for @status_icon.
2753 *
2754 * Returns: (nullable): the tooltip text, or %NULL. You should free the
2755 * returned string with g_free() when done.
2756 *
2757 * Since: 2.16
2758 *
2759 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
2760 * provide status notifications; there is no direct replacement
2761 * for this function
2762 */
2763 gchar *
gtk_status_icon_get_tooltip_markup(GtkStatusIcon * status_icon)2764 gtk_status_icon_get_tooltip_markup (GtkStatusIcon *status_icon)
2765 {
2766 GtkStatusIconPrivate *priv;
2767 gchar *markup = NULL;
2768
2769 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2770
2771 priv = status_icon->priv;
2772
2773 #ifdef GDK_WINDOWING_X11
2774 if (priv->tray_icon)
2775 markup = gtk_widget_get_tooltip_markup (priv->tray_icon);
2776 #endif
2777 #ifdef GDK_WINDOWING_WIN32
2778 if (priv->tooltip_text)
2779 markup = g_markup_escape_text (priv->tooltip_text, -1);
2780 #endif
2781 #ifdef GDK_WINDOWING_QUARTZ
2782 if (priv->tooltip_text)
2783 markup = g_markup_escape_text (priv->tooltip_text, -1);
2784 #endif
2785
2786 return markup;
2787 }
2788
2789 /**
2790 * gtk_status_icon_get_x11_window_id:
2791 * @status_icon: a #GtkStatusIcon
2792 *
2793 * This function is only useful on the X11/freedesktop.org platform.
2794 *
2795 * It returns a window ID for the widget in the underlying
2796 * status icon implementation. This is useful for the Galago
2797 * notification service, which can send a window ID in the protocol
2798 * in order for the server to position notification windows
2799 * pointing to a status icon reliably.
2800 *
2801 * This function is not intended for other use cases which are
2802 * more likely to be met by one of the non-X11 specific methods, such
2803 * as gtk_status_icon_position_menu().
2804 *
2805 * Returns: An 32 bit unsigned integer identifier for the
2806 * underlying X11 Window
2807 *
2808 * Since: 2.14
2809 *
2810 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
2811 * provide status notifications; there is no direct replacement
2812 * for this function
2813 */
2814 guint32
gtk_status_icon_get_x11_window_id(GtkStatusIcon * status_icon)2815 gtk_status_icon_get_x11_window_id (GtkStatusIcon *status_icon)
2816 {
2817 #ifdef GDK_WINDOWING_X11
2818 if (status_icon->priv->tray_icon)
2819 {
2820 gtk_widget_realize (GTK_WIDGET (status_icon->priv->tray_icon));
2821 return GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (status_icon->priv->tray_icon)));
2822 }
2823 else
2824 #endif
2825 return 0;
2826 }
2827
2828 /**
2829 * gtk_status_icon_set_title:
2830 * @status_icon: a #GtkStatusIcon
2831 * @title: the title
2832 *
2833 * Sets the title of this tray icon.
2834 * This should be a short, human-readable, localized string
2835 * describing the tray icon. It may be used by tools like screen
2836 * readers to render the tray icon.
2837 *
2838 * Since: 2.18
2839 *
2840 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
2841 * provide status notifications; you should use g_notification_set_title()
2842 * and g_notification_set_body() to present text inside your notification
2843 */
2844 void
gtk_status_icon_set_title(GtkStatusIcon * status_icon,const gchar * title)2845 gtk_status_icon_set_title (GtkStatusIcon *status_icon,
2846 const gchar *title)
2847 {
2848 GtkStatusIconPrivate *priv;
2849
2850 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2851
2852 priv = status_icon->priv;
2853
2854 #ifdef GDK_WINDOWING_X11
2855 if (priv->tray_icon)
2856 gtk_window_set_title (GTK_WINDOW (priv->tray_icon), title);
2857 #endif
2858 #ifdef GDK_WINDOWING_QUARTZ
2859 g_free (priv->title);
2860 priv->title = g_strdup (title);
2861 #endif
2862 #ifdef GDK_WINDOWING_WIN32
2863 g_free (priv->title);
2864 priv->title = g_strdup (title);
2865 #endif
2866
2867 g_object_notify (G_OBJECT (status_icon), "title");
2868 }
2869
2870 /**
2871 * gtk_status_icon_get_title:
2872 * @status_icon: a #GtkStatusIcon
2873 *
2874 * Gets the title of this tray icon. See gtk_status_icon_set_title().
2875 *
2876 * Returns: the title of the status icon
2877 *
2878 * Since: 2.18
2879 *
2880 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
2881 * provide status notifications; there is no direct replacement
2882 * for this function
2883 */
2884 const gchar *
gtk_status_icon_get_title(GtkStatusIcon * status_icon)2885 gtk_status_icon_get_title (GtkStatusIcon *status_icon)
2886 {
2887 GtkStatusIconPrivate *priv;
2888 const gchar *title = NULL;
2889
2890 g_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), NULL);
2891
2892 priv = status_icon->priv;
2893
2894 #ifdef GDK_WINDOWING_X11
2895 if (priv->tray_icon)
2896 title = gtk_window_get_title (GTK_WINDOW (priv->tray_icon));
2897 #endif
2898 #ifdef GDK_WINDOWING_QUARTZ
2899 title = priv->title;
2900 #endif
2901 #ifdef GDK_WINDOWING_WIN32
2902 title = priv->title;
2903 #endif
2904
2905 return title;
2906 }
2907
2908
2909 /**
2910 * gtk_status_icon_set_name:
2911 * @status_icon: a #GtkStatusIcon
2912 * @name: the name
2913 *
2914 * Sets the name of this tray icon.
2915 * This should be a string identifying this icon. It is may be
2916 * used for sorting the icons in the tray and will not be shown to
2917 * the user.
2918 *
2919 * Since: 2.20
2920 *
2921 * Deprecated: 3.14: Use #GNotification and #GtkApplication to
2922 * provide status notifications; there is no direct replacement
2923 * for this function, as notifications are associated with a
2924 * unique application identifier by #GApplication
2925 */
2926 void
gtk_status_icon_set_name(GtkStatusIcon * status_icon,const gchar * name)2927 gtk_status_icon_set_name (GtkStatusIcon *status_icon,
2928 const gchar *name)
2929 {
2930 #ifdef GDK_WINDOWING_X11
2931 GtkStatusIconPrivate *priv;
2932 #endif
2933
2934 g_return_if_fail (GTK_IS_STATUS_ICON (status_icon));
2935
2936 #ifdef GDK_WINDOWING_X11
2937 priv = status_icon->priv;
2938
2939 if (priv->tray_icon)
2940 {
2941 if (gtk_widget_get_realized (priv->tray_icon))
2942 {
2943 /* gtk_window_set_wmclass() only operates on non-realized windows,
2944 * so temporarily unrealize the tray here
2945 */
2946 gtk_widget_hide (priv->tray_icon);
2947 gtk_widget_unrealize (priv->tray_icon);
2948 gtk_window_set_wmclass (GTK_WINDOW (priv->tray_icon), name, name);
2949 gtk_widget_show (priv->tray_icon);
2950 }
2951 else
2952 gtk_window_set_wmclass (GTK_WINDOW (priv->tray_icon), name, name);
2953 }
2954 #endif
2955 }
2956