filename | src/gtkui/main_win.c |
changeset | 658:f5926310bfbe |
prev | 635:76c63aac3590 |
next | 659:6b1dff1575b3 |
author | nkeynes |
date | Wed Apr 16 12:43:52 2008 +0000 (14 years ago) |
permissions | -rw-r--r-- |
last change | Start removing X11isms from gtkui into drivers Overhaul the configure rules for figuring out the video driver |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * Define the main (emu) GTK window, along with its menubars,
5 * toolbars, etc.
6 *
7 * Copyright (c) 2005 Nathan Keynes.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 */
20 #include <assert.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <stdlib.h>
28 #include <gtk/gtk.h>
29 #include <gdk/gdk.h>
30 #include <gdk/gdkkeysyms.h>
31 #include <X11/Xutil.h>
33 #include "lxdream.h"
34 #include "gtkui/gtkui.h"
36 #ifdef HAVE_GLX
37 #include <gdk/gdkx.h>
38 #include "drivers/video_glx.h"
39 #endif
42 struct main_window_info {
43 GtkWidget *window;
44 GtkWidget *video;
45 GtkWidget *menubar;
46 GtkWidget *toolbar;
47 GtkWidget *statusbar;
48 GtkActionGroup *actions;
49 gboolean use_grab;
50 gboolean is_grabbed;
51 int32_t mouse_x, mouse_y;
52 };
55 /******************** Video window **************************/
57 /**
58 * Adjust the mouse pointer so that it appears in the center of the video
59 * window. Mainly used for when we have the mouse grab
60 */
61 void video_window_center_pointer( main_window_t win )
62 {
63 GdkDisplay *display = gtk_widget_get_display(win->video);
64 GdkScreen *screen = gtk_widget_get_screen(win->video);
65 int x,y;
66 int width, height;
68 gdk_window_get_origin(win->video->window, &x, &y);
69 gdk_drawable_get_size(GDK_DRAWABLE(win->video->window), &width, &height);
70 x += width / 2;
71 y += height / 2;
73 gdk_display_warp_pointer( display, screen, x, y );
74 win->mouse_x = width/2;
75 win->mouse_y = height/2;
76 }
78 /**
79 * Grab the keyboard and mouse for the display. The mouse cursor is hidden and
80 * moved to the centre of the window.
81 *
82 * @param win The window receiving the grab
83 * @return TRUE if the grab was successful, FALSE on failure.
84 */
85 gboolean video_window_grab_display( main_window_t win )
86 {
87 GdkWindow *gdkwin = win->video->window;
88 GdkColor color = { 0,0,0,0 };
89 char bytes[32]; /* 16 * 16 / 8 */
90 memset(bytes, 0, 32);
91 GdkPixmap *pixmap = gdk_bitmap_create_from_data(NULL, bytes, 16, 16);
92 GdkCursor *cursor = gdk_cursor_new_from_pixmap(pixmap, pixmap, &color, &color, 16, 16);
93 gdk_pixmap_unref(pixmap);
95 gboolean success =
96 gdk_pointer_grab( gdkwin, FALSE,
97 GDK_POINTER_MOTION_MASK|GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK,
98 gdkwin, cursor, GDK_CURRENT_TIME ) == GDK_GRAB_SUCCESS;
99 gdk_cursor_unref(cursor);
100 if( success ) {
101 success = gdk_keyboard_grab( gdkwin, FALSE, GDK_CURRENT_TIME ) == GDK_GRAB_SUCCESS;
102 if( !success ) {
103 gdk_pointer_ungrab(GDK_CURRENT_TIME);
104 }
105 }
106 win->is_grabbed = success;
107 main_window_set_running(win, dreamcast_is_running());
108 return success;
109 }
111 /**
112 * Release the display grab.
113 */
114 void video_window_ungrab_display( main_window_t win )
115 {
116 gdk_pointer_ungrab(GDK_CURRENT_TIME);
117 gdk_keyboard_ungrab(GDK_CURRENT_TIME);
118 win->is_grabbed = FALSE;
119 main_window_set_running(win, dreamcast_is_running());
120 }
122 static gboolean on_video_window_mouse_motion( GtkWidget *widget, GdkEventMotion *event,
123 gpointer user_data )
124 {
125 main_window_t win = (main_window_t)user_data;
126 int32_t x = (int32_t)event->x;
127 int32_t y = (int32_t)event->y;
128 if( win->is_grabbed &&
129 (x != win->mouse_x || y != win->mouse_y) ) {
130 uint32_t buttons = (event->state >> 8)&0x1F;
131 input_event_mouse( buttons, x - win->mouse_x, y - win->mouse_y );
132 video_window_center_pointer(win);
133 }
134 return TRUE;
135 }
137 static gboolean on_video_window_mouse_pressed( GtkWidget *widget, GdkEventButton *event,
138 gpointer user_data )
139 {
140 main_window_t win = (main_window_t)user_data;
141 if( win->is_grabbed ) {
142 // Get the buttons from the event state, and remove the released button
143 uint32_t buttons = ((event->state >> 8) & 0x1F) | (1<<(event->button-1));
144 input_event_mouse( buttons, 0, 0 );
145 }
146 return TRUE;
147 }
149 static gboolean on_video_window_mouse_released( GtkWidget *widget, GdkEventButton *event,
150 gpointer user_data )
151 {
152 main_window_t win = (main_window_t)user_data;
153 if( win->is_grabbed ) {
154 // Get the buttons from the event state, and remove the released button
155 uint32_t buttons = ((event->state >> 8) & 0x1F) & (~(1<<(event->button-1)));
156 input_event_mouse( buttons, 0, 0 );
157 } else if( win->use_grab) {
158 video_window_grab_display(win);
159 }
160 return TRUE;
161 }
163 static gboolean on_video_window_key_pressed( GtkWidget *widget, GdkEventKey *event,
164 gpointer user_data )
165 {
166 main_window_t win = (main_window_t)user_data;
167 if( win->is_grabbed ) {
168 /* Check for ungrab key combo (ctrl-alt). Unfortunately GDK sends it as
169 * a singly-modified keypress rather than a double-modified 'null' press,
170 * so we have to do a little more work.
171 * Only check Ctrl/Shift/Alt for state - don't want to check numlock/capslock/
172 * mouse buttons/etc
173 */
174 int mod = gdk_keycode_to_modifier(gtk_widget_get_display(widget), event->hardware_keycode);
175 int state = event->state & gtk_accelerator_get_default_mod_mask();
176 if( (state == GDK_CONTROL_MASK && mod == GDK_MOD1_MASK) ||
177 (state == GDK_MOD1_MASK && mod == GDK_CONTROL_MASK) ) {
178 video_window_ungrab_display(win);
179 // Consume the keypress, DC doesn't get it.
180 return TRUE;
181 }
182 }
183 input_event_keydown( NULL, gtk_get_unmodified_keyval(event), 1 );
184 return TRUE;
185 }
187 static gboolean on_video_window_key_released( GtkWidget *widget, GdkEventKey *event,
188 gpointer user_data )
189 {
190 main_window_t win = (main_window_t)user_data;
191 input_event_keyup( NULL, gtk_get_unmodified_keyval(event), 0 );
192 return TRUE;
193 }
195 static gboolean on_video_window_focus_changed( GtkWidget *widget, GdkEventFocus *event,
196 gpointer user_data )
197 {
198 display_set_focused(event->in);
199 }
201 /*************************** Main window (frame) ******************************/
203 static gboolean on_main_window_deleted( GtkWidget *widget, GdkEvent event, gpointer user_data )
204 {
205 exit(0);
206 }
208 static void on_main_window_state_changed( GtkWidget *widget, GdkEventWindowState *state,
209 gpointer userdata )
210 {
211 main_window_t win = (main_window_t)userdata;
212 if( state->changed_mask & GDK_WINDOW_STATE_FULLSCREEN ) {
213 gboolean fs = (state->new_window_state & GDK_WINDOW_STATE_FULLSCREEN);
214 GtkWidget *frame = gtk_widget_get_parent(win->video);
215 if( frame->style == NULL ) {
216 gtk_widget_set_style( frame, gtk_style_new() );
217 }
218 if( fs ) {
219 gtk_widget_hide( win->menubar );
220 gtk_widget_hide( win->toolbar );
221 gtk_widget_hide( win->statusbar );
223 frame->style->xthickness = 0;
224 frame->style->ythickness = 0;
225 } else {
226 frame->style->xthickness = 2;
227 frame->style->ythickness = 2;
228 gtk_widget_show( win->menubar );
229 gtk_widget_show( win->toolbar );
230 gtk_widget_show( win->statusbar );
231 }
232 gtk_widget_queue_draw( win->window );
233 }
234 }
236 main_window_t main_window_new( const gchar *title, GtkWidget *menubar, GtkWidget *toolbar,
237 GtkAccelGroup *accel_group )
238 {
239 GtkWidget *vbox;
240 GtkWidget *frame;
241 main_window_t win = g_malloc0( sizeof(struct main_window_info) );
243 win->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
244 win->menubar = menubar;
245 win->toolbar = toolbar;
246 win->use_grab = FALSE;
247 win->is_grabbed = FALSE;
248 gtk_window_set_title( GTK_WINDOW(win->window), title );
249 gtk_window_add_accel_group (GTK_WINDOW (win->window), accel_group);
251 gtk_toolbar_set_style( GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS );
253 win->video = gtk_drawing_area_new();
255 #ifdef HAVE_GLX
256 Display *display = gdk_x11_display_get_xdisplay( gtk_widget_get_display(win->window));
257 Screen *screen = gdk_x11_screen_get_xscreen( gtk_widget_get_screen(win->window));
258 int screen_no = XScreenNumberOfScreen(screen);
259 if( !video_glx_init(display, screen_no) ) {
260 ERROR( "Unable to initialize GLX, aborting" );
261 exit(3);
262 }
264 XVisualInfo *visual = video_gtk_get_visual();
265 if( visual != NULL ) {
266 GdkVisual *gdkvis = gdk_x11_screen_lookup_visual( gtk_widget_get_screen(win->window), visual->visualid );
267 GdkColormap *colormap = gdk_colormap_new( gdkvis, FALSE );
268 gtk_widget_set_colormap( win->video, colormap );
269 }
270 #endif
272 GTK_WIDGET_SET_FLAGS(win->video, GTK_CAN_FOCUS|GTK_CAN_DEFAULT);
273 gtk_widget_set_size_request( win->video, 640, 480 );
274 gtk_widget_set_double_buffered( win->video, FALSE );
275 frame = gtk_frame_new(NULL);
276 gtk_frame_set_shadow_type( GTK_FRAME(frame), GTK_SHADOW_IN );
277 gtk_container_add( GTK_CONTAINER(frame), win->video );
279 win->statusbar = gtk_statusbar_new();
281 vbox = gtk_vbox_new(FALSE, 0);
282 gtk_container_add( GTK_CONTAINER(win->window), vbox );
283 gtk_box_pack_start( GTK_BOX(vbox), menubar, FALSE, FALSE, 0 );
284 gtk_box_pack_start( GTK_BOX(vbox), toolbar, FALSE, FALSE, 0 );
285 gtk_box_pack_start( GTK_BOX(vbox), frame, TRUE, TRUE, 0 );
286 gtk_box_pack_start( GTK_BOX(vbox), win->statusbar, FALSE, FALSE, 0 );
287 gtk_widget_show_all( win->window );
288 gtk_widget_grab_focus( win->video );
290 gtk_statusbar_push( GTK_STATUSBAR(win->statusbar), 1, "Stopped" );
292 g_signal_connect( win->window, "delete_event",
293 G_CALLBACK(on_main_window_deleted), win );
294 g_signal_connect( win->window, "window-state-event",
295 G_CALLBACK(on_main_window_state_changed), win );
297 g_signal_connect( win->video, "key-press-event",
298 G_CALLBACK(on_video_window_key_pressed), win );
299 g_signal_connect( win->video, "key-release-event",
300 G_CALLBACK(on_video_window_key_released), win );
301 g_signal_connect( win->video, "motion-notify-event",
302 G_CALLBACK(on_video_window_mouse_motion), win );
303 g_signal_connect( win->video, "button-press-event",
304 G_CALLBACK(on_video_window_mouse_pressed), win );
305 g_signal_connect( win->video, "button-release-event",
306 G_CALLBACK(on_video_window_mouse_released), win );
307 g_signal_connect( win->video, "focus-in-event",
308 G_CALLBACK(on_video_window_focus_changed), win);
309 g_signal_connect( win->video, "focus-out-event",
310 G_CALLBACK(on_video_window_focus_changed), win);
312 gtk_widget_add_events( win->video,
313 GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
314 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
315 GDK_POINTER_MOTION_MASK | GDK_FOCUS_CHANGE_MASK );
317 return win;
318 }
320 void main_window_set_status_text( main_window_t win, char *text )
321 {
322 gtk_statusbar_pop( GTK_STATUSBAR(win->statusbar), 1 );
323 if( win->is_grabbed ) {
324 char buf[128];
325 snprintf( buf, sizeof(buf), "%s %s", text, _("(Press <ctrl><alt> to release grab)") );
326 gtk_statusbar_push( GTK_STATUSBAR(win->statusbar), 1, buf );
327 } else {
328 gtk_statusbar_push( GTK_STATUSBAR(win->statusbar), 1, text );
329 }
330 }
332 void main_window_set_running( main_window_t win, gboolean running )
333 {
334 char *text = running ? _("Running") : _("Stopped");
335 gtk_gui_enable_action( "Pause", running );
336 gtk_gui_enable_action( "Run", !running && dreamcast_can_run() );
337 main_window_set_status_text( win, text );
338 }
340 void main_window_set_framerate( main_window_t win, float rate )
341 {
344 }
346 void main_window_set_speed( main_window_t win, double speed )
347 {
348 char buf[32];
350 snprintf( buf, 32, "Running (%2.4f%%)", speed );
351 main_window_set_status_text( win, buf );
352 }
354 GtkWidget *main_window_get_renderarea( main_window_t win )
355 {
356 return win->video;
357 }
359 GtkWindow *main_window_get_frame( main_window_t win )
360 {
361 return GTK_WINDOW(win->window);
362 }
364 void main_window_set_fullscreen( main_window_t win, gboolean fullscreen )
365 {
366 if( fullscreen ) {
367 gtk_window_fullscreen( GTK_WINDOW(win->window) );
368 } else {
369 gtk_window_unfullscreen( GTK_WINDOW(win->window) );
370 }
371 }
373 void main_window_set_use_grab( main_window_t win, gboolean use_grab )
374 {
375 if( use_grab != win->use_grab ) {
376 if( use_grab ) {
377 GdkCursor *cursor = gdk_cursor_new( GDK_HAND2 );
378 gdk_window_set_cursor( win->video->window, cursor );
379 gdk_cursor_unref( cursor );
380 } else {
381 gdk_window_set_cursor( win->video->window, NULL );
382 if( gdk_pointer_is_grabbed() ) {
383 video_window_ungrab_display(win);
384 }
385 }
386 win->use_grab = use_grab;
387 }
388 }
.