2
* Copyright (C) 2007 the xine-project
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License as published by the Free
6
* Software Foundation; either version 2 of the License, or (at your option)
9
* This program is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14
* You should have received a copy of the GNU General Public License along
15
* with this program; if not, write to the Free Software Foundation, Inc., 51
16
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
* System tray icon for gxine.
26
#include "drag_drop.h"
29
#include "noskin_window.h"
36
static GtkWidget *tray_icon, *tray_menu;
37
static Window tray = None;
40
Atom data, manager, opcode, selection;
43
static GdkFilterReturn systray_filter (GdkXEvent *, GdkEvent *, gpointer);
44
static gboolean button_cb (GtkWidget *, GdkEventButton *, gpointer);
48
send_opcode (glong d1, glong d2, glong d3, glong d4)
50
GdkDisplay *display = gtk_widget_get_display (tray_icon);
51
Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
53
XClientMessageEvent xev = {
54
ClientMessage, 0, True,
55
xdisplay, tray, atoms.opcode,
56
32, { .l = { gdk_x11_get_server_time (tray_icon->window), d1, d2, d3, d4 } }
59
gdk_error_trap_push ();
60
XSendEvent (xdisplay, tray, False, NoEventMask, (XEvent *) &xev);
61
XSync (xdisplay, FALSE);
62
gdk_error_trap_pop ();
65
static inline GdkScreen *
66
create_tray_icon (void)
68
tray_icon = gtk_plug_new (0);
69
gtk_container_add (GTK_CONTAINER (tray_icon),
70
gtk_image_new_from_icon_name ("gxine", GTK_ICON_SIZE_LARGE_TOOLBAR));
71
gtk_widget_show_all (tray_icon);
72
drag_drop_setup (tray_icon, TRUE);
74
GdkScreen *screen = gtk_widget_get_screen (tray_icon);
75
Screen *xscreen = GDK_SCREEN_XSCREEN (screen);
76
GdkDisplay *display = gtk_widget_get_display (tray_icon);
77
Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
80
snprintf (selection, sizeof (selection), "_NET_SYSTEM_TRAY_S%d",
81
XScreenNumberOfScreen (xscreen));
82
atoms.data = XInternAtom (xdisplay, "_NET_SYSTEM_TRAY_MESSAGE_DATA", False);
83
atoms.manager = XInternAtom (xdisplay, "MANAGER", False);
84
atoms.opcode = XInternAtom (xdisplay, "_NET_SYSTEM_TRAY_OPCODE", False);
85
atoms.selection = XInternAtom (xdisplay, selection, False);
91
systray_delete_icon (void)
97
gtk_widget_destroy (tray_icon);
100
GdkDisplay *display = gtk_widget_get_display (app);
101
GdkWindow *window = gdk_window_lookup_for_display (display, tray);
102
gdk_window_remove_filter (window, systray_filter, NULL);
104
if (!GTK_WIDGET_MAPPED (app))
107
gtk_action_set_visible (action_items.showmain, FALSE);
108
gtk_action_set_visible (action_items.hidemain, FALSE);
112
systray_create_icon (void)
115
systray_delete_icon ();
117
GdkDisplay *display = gtk_widget_get_display (app);
118
Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
120
/* Create the tray icon */
121
GdkDisplay *tray_screen = create_tray_icon ();
123
/* Get the tray id */
124
XGrabServer (xdisplay);
125
tray = XGetSelectionOwner (xdisplay, atoms.selection);
127
XSelectInput (xdisplay, tray, StructureNotifyMask);
128
XUngrabServer (xdisplay);
136
GdkWindow *window = gdk_window_lookup_for_display (display, tray);
137
gdk_window_add_filter (window, systray_filter, NULL);
139
send_opcode (0, gtk_plug_get_id (GTK_PLUG (tray_icon)), 0, 0);
141
/* Filtering & events */
142
gdk_window_add_filter (gdk_screen_get_root_window (tray_screen),
143
systray_filter, NULL);
144
gdk_window_set_events (tray_icon->window,
145
gdk_window_get_events (tray_icon->window) | GDK_BUTTON_PRESS_MASK);
146
g_signal_connect (G_OBJECT (tray_icon), "button-press-event",
147
G_CALLBACK (button_cb), NULL);
149
/* Handle menu items */
150
gtk_action_set_visible (action_items.showmain, FALSE);
151
gtk_action_set_visible (action_items.hidemain, TRUE);
154
static GdkFilterReturn
155
systray_filter (GdkXEvent *gxev, GdkEvent *ev, gpointer data)
157
XEvent *xev = (XEvent *) gxev;
163
if (xev->xclient.message_type == atoms.manager
164
&& xev->xclient.data.l[1] == atoms.selection)
165
systray_create_icon ();
169
/* tray disappeared? */
170
if (xev->xclient.window == tray)
171
systray_delete_icon ();
175
return GDK_FILTER_CONTINUE;
178
static const char popup_menu_xml[] =
179
"<ui><popup name='tray'>\n"
180
"<menuitem action='PrevTrack' />\n"
181
"<menuitem action='Play' />\n"
182
"<menuitem action='Pause' />\n"
183
"<menuitem action='FFwd' />\n"
184
"<menuitem action='Stop' />\n"
185
"<menuitem action='NextTrack' />\n"
186
"<menuitem action='Playlist' />\n"
188
"<menuitem action='HideMain' />\n"
189
"<menuitem action='ShowMain' />\n"
190
"<menuitem action='Quit' />\n"
194
button_cb (GtkWidget *widget, GdkEventButton *ev, gpointer data)
199
gtk_menu_popup (GTK_MENU (tray_menu), NULL, NULL, NULL, NULL,
200
ev->button, ev->time);
203
if (GTK_WIDGET_MAPPED (app))
209
gtk_menu_popup (GTK_MENU (popup_menu), NULL, NULL, NULL, NULL,
210
ev->button, ev->time);
217
static JSBool js_minimise (JSContext *cx, JSObject *obj, uintN argc,
218
jsval *argv, jsval *rval)
222
se_log_fncall_checkinit ("set_minimised");
223
se_argc_check_max (1, "set_minimised");
227
se_arg_is_int_or_bool (0, "set_minimised");
228
JS_ValueToInt32 (cx, argv[0], &tray_state);
233
default: /* toggle */
234
if (GTK_WIDGET_MAPPED (app))
245
void systray_init (void)
247
static const se_f_def_t defs[] = {
248
{ "set_minimised", js_minimise, 0, 0,
249
SE_GROUP_ENGINE, N_("[bool]"),
250
N_("true to hide, false to show") },
253
se_defuns (gse, NULL, defs);
255
GError *error = NULL;
256
gtk_ui_manager_add_ui_from_string (ui, popup_menu_xml, -1, &error);
257
tray_menu = gtk_ui_manager_get_widget (ui, "/ui/tray");
259
static const char items[][16] = {
260
[Control_STOP] = "/ui/tray/Stop",
261
[Control_PAUSE] = "/ui/tray/Pause",
262
[Control_PLAY] = "/ui/tray/Play",
263
[Control_FASTFWD] = "/ui/tray/FFwd",
265
for (int i = 0; i < G_N_ELEMENTS (items); ++i)
267
ui_register_control_button (i, gtk_ui_manager_get_widget (ui, items[i]));
269
systray_create_icon ();
272
gboolean systray_present (void)