1 /* GST123 - GStreamer based command line media player
2 * Copyright (C) 2010 Stefan Westerfeld
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General
15 * Public License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20 #include "gtkinterface.h"
21
22 #include <gtk/gtk.h>
23 #include <X11/Xlib.h>
24 #include <gdk/gdkkeysyms.h>
25 #include <gdk/gdkx.h>
26 #include <stdlib.h>
27
28 using std::string;
29
30 static gboolean
key_press_event_cb(GtkWidget * widget,GdkEventKey * event,gpointer data)31 key_press_event_cb (GtkWidget *widget, GdkEventKey *event, gpointer data)
32 {
33 GtkInterface *gtk_interface = static_cast<GtkInterface *> (data);
34
35 return gtk_interface->handle_keypress_event (event);
36 }
37
38 static gboolean
motion_notify_event_cb(GtkWidget * widget,GdkEventMotion * event,gpointer data)39 motion_notify_event_cb (GtkWidget *widget, GdkEventMotion *event, gpointer data)
40 {
41 GtkInterface *gtk_interface = static_cast<GtkInterface *> (data);
42
43 return gtk_interface->handle_motion_notify_event (event);
44 }
45
46 static gboolean
timeout_cb(gpointer data)47 timeout_cb (gpointer data)
48 {
49 GtkInterface *gtk_interface = static_cast<GtkInterface *> (data);
50
51 return gtk_interface->handle_timeout();
52 }
53
54 static gboolean
close_cb(GtkWidget * widget,GdkEvent * event,gpointer data)55 close_cb (GtkWidget *widget,
56 GdkEvent *event,
57 gpointer data)
58 {
59 GtkInterface *gtk_interface = static_cast<GtkInterface *> (data);
60
61 return gtk_interface->handle_close();
62 }
63
64 bool
have_x11_display()65 GtkInterface::have_x11_display()
66 {
67 static Display *display = NULL;
68
69 if (!display)
70 display = XOpenDisplay (NULL); // this should work if and only if we do have an X11 server we can use
71
72 return display != NULL;
73 }
74
75 void
init(int * argc,char *** argv,KeyHandler * handler)76 GtkInterface::init (int *argc, char ***argv, KeyHandler *handler)
77 {
78 key_handler = handler;
79
80 if (have_x11_display())
81 {
82 gtk_init (argc, argv);
83 gtk_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
84 g_signal_connect (G_OBJECT (gtk_window), "key-press-event", G_CALLBACK (key_press_event_cb), this);
85 g_signal_connect (G_OBJECT (gtk_window), "motion-notify-event", G_CALLBACK (motion_notify_event_cb), this);
86 g_signal_connect (G_OBJECT (gtk_window), "delete-event", G_CALLBACK (close_cb), this);
87 g_object_set (G_OBJECT (gtk_window), "events", GDK_POINTER_MOTION_MASK, NULL);
88
89 // make background black
90 GdkColor color;
91 gdk_color_parse ("black", &color);
92 gtk_widget_modify_bg (gtk_window, GTK_STATE_NORMAL, &color);
93
94 visible_cursor = NULL;
95 invisible_cursor = gdk_cursor_new (GDK_BLANK_CURSOR);
96
97 cursor_timeout = 3;
98 g_timeout_add (500, (GSourceFunc) timeout_cb, this);
99 }
100 else
101 {
102 gtk_window = NULL;
103 }
104 gtk_window_visible = false;
105
106 /* initialize map from Gdk keysyms to KeyHandler codes */
107 key_map[GDK_Page_Up] = KEY_HANDLER_PAGE_UP;
108 key_map[GDK_Page_Down] = KEY_HANDLER_PAGE_DOWN;
109 key_map[GDK_Left] = KEY_HANDLER_LEFT;
110 key_map[GDK_Right] = KEY_HANDLER_RIGHT;
111 key_map[GDK_Up] = KEY_HANDLER_UP;
112 key_map[GDK_Down] = KEY_HANDLER_DOWN;
113 key_map[GDK_KP_Add] = '+';
114 key_map[GDK_KP_Subtract] = '-';
115 }
116
117 void
unfullscreen()118 GtkInterface::unfullscreen()
119 {
120 if (gtk_window != NULL && gtk_window_visible)
121 gtk_window_unfullscreen (GTK_WINDOW (gtk_window));
122 }
123
124 void
toggle_fullscreen()125 GtkInterface::toggle_fullscreen()
126 {
127 if (gtk_window != NULL && gtk_window_visible)
128 {
129 GdkWindowState state = gdk_window_get_state (GDK_WINDOW (gtk_window->window));
130 gboolean isFullscreen = ((state & GDK_WINDOW_STATE_FULLSCREEN) == GDK_WINDOW_STATE_FULLSCREEN);
131 if (isFullscreen)
132 gtk_window_unfullscreen (GTK_WINDOW (gtk_window));
133 else
134 gtk_window_fullscreen (GTK_WINDOW (gtk_window));
135 }
136 }
137
138 bool
init_ok()139 GtkInterface::init_ok()
140 {
141 return gtk_window != NULL;
142 }
143
144 GtkWidget*
window()145 GtkInterface::window()
146 {
147 return gtk_window;
148 }
149
150 void
show()151 GtkInterface::show()
152 {
153 if (gtk_window != NULL && !gtk_window_visible)
154 {
155 gtk_widget_show_all (gtk_window);
156
157 // get cursor, so we can restore it after hiding it
158 if (!visible_cursor)
159 visible_cursor = gdk_window_get_cursor (GDK_WINDOW (gtk_window->window));
160
161 // sync, to make the window really visible before we return
162 gdk_display_sync (gdk_display_get_default());
163
164 screen_saver (SUSPEND);
165 gtk_window_visible = true;
166 }
167 }
168
169 void
hide()170 GtkInterface::hide()
171 {
172 if (gtk_window != NULL && gtk_window_visible)
173 {
174 gtk_widget_hide_all (gtk_window);
175 screen_saver (RESUME);
176 gtk_window_visible = false;
177 }
178 }
179
180 void
end()181 GtkInterface::end()
182 {
183 if (gtk_window != NULL)
184 {
185 screen_saver (RESUME);
186 }
187 }
188
189
190 void
resize(int x,int y)191 GtkInterface::resize (int x, int y)
192 {
193 if (gtk_window != NULL)
194 gtk_window_resize (GTK_WINDOW (gtk_window), x, y);
195 }
196
197 bool
handle_keypress_event(GdkEventKey * event)198 GtkInterface::handle_keypress_event (GdkEventKey *event)
199 {
200 int ch = 0;
201
202 if (event->keyval > 0 && event->keyval <= 127)
203 ch = event->keyval;
204 else
205 ch = key_map[event->keyval];
206
207 if (ch != 0)
208 {
209 key_handler->process_input (ch);
210 return true;
211 }
212 return false;
213 }
214
215 void
set_title(const string & title)216 GtkInterface::set_title (const string& title)
217 {
218 if (gtk_window != NULL)
219 gtk_window_set_title (GTK_WINDOW (gtk_window), title.c_str());
220 }
221
222 bool
handle_timeout()223 GtkInterface::handle_timeout()
224 {
225 if (gtk_window != NULL && gtk_window_visible)
226 {
227 if (cursor_timeout == 0)
228 {
229 gdk_window_set_cursor (GDK_WINDOW (gtk_window->window), invisible_cursor);
230 cursor_timeout = -1;
231 }
232 else if (cursor_timeout > 0)
233 {
234 cursor_timeout--;
235 }
236 }
237 return true;
238 }
239
240 bool
handle_motion_notify_event(GdkEventMotion * event)241 GtkInterface::handle_motion_notify_event (GdkEventMotion *event)
242 {
243 if (gtk_window != NULL && gtk_window_visible)
244 {
245 gdk_window_set_cursor (GDK_WINDOW (gtk_window->window), visible_cursor);
246 cursor_timeout = 3;
247 }
248 return true;
249 }
250
251 bool
handle_close()252 GtkInterface::handle_close()
253 {
254 g_return_val_if_fail (gtk_window != NULL, true);
255
256 // quit on close
257 key_handler->process_input ('q');
258
259 return true;
260 }
261
262 void
screen_saver(ScreenSaverSetting setting)263 GtkInterface::screen_saver (ScreenSaverSetting setting)
264 {
265 GdkWindow *window = GTK_WIDGET (gtk_window)->window;
266 if (gtk_window != NULL && window)
267 {
268 guint64 wid = GDK_WINDOW_XWINDOW (window);
269
270 const char *setting_str = (setting == SUSPEND) ? "suspend" : "resume";
271
272 char *cmd = g_strdup_printf ("xdg-screensaver %s %" G_GUINT64_FORMAT " >/dev/null 2>&1", setting_str, wid);
273 int rc = system (cmd); // don't complain if xdg-screensaver is not installed
274 (void) rc;
275 g_free (cmd);
276 }
277 }
278