Search
lxdream.org :: lxdream/src/gtkui/main_win.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/gtkui/main_win.c
changeset 608:4f588e52bce0
prev606:23029426ab8f
next612:410b48e63d53
author nkeynes
date Sat Jan 26 02:45:27 2008 +0000 (16 years ago)
permissions -rw-r--r--
last change Bug #50: Implement mouse and keyboard
file annotate diff log raw
1.1 --- a/src/gtkui/main_win.c Fri Jan 25 05:52:51 2008 +0000
1.2 +++ b/src/gtkui/main_win.c Sat Jan 26 02:45:27 2008 +0000
1.3 @@ -26,7 +26,9 @@
1.4 #include <stdlib.h>
1.5
1.6 #include <gtk/gtk.h>
1.7 +#include <gdk/gdk.h>
1.8 #include <gdk/gdkx.h>
1.9 +#include <gdk/gdkkeysyms.h>
1.10 #include <X11/Xutil.h>
1.11
1.12 #include "dream.h"
1.13 @@ -41,8 +43,159 @@
1.14 GtkWidget *toolbar;
1.15 GtkWidget *statusbar;
1.16 GtkActionGroup *actions;
1.17 + gboolean use_grab;
1.18 + gboolean is_grabbed;
1.19 + int32_t mouse_x, mouse_y;
1.20 };
1.21
1.22 +
1.23 +/******************** Video window **************************/
1.24 +
1.25 +/**
1.26 + * Adjust the mouse pointer so that it appears in the center of the video
1.27 + * window. Mainly used for when we have the mouse grab
1.28 + */
1.29 +void video_window_center_pointer( main_window_t win )
1.30 +{
1.31 + GdkDisplay *display = gtk_widget_get_display(win->video);
1.32 + GdkScreen *screen = gtk_widget_get_screen(win->video);
1.33 + int x,y;
1.34 + int width, height;
1.35 +
1.36 + gdk_window_get_origin(win->video->window, &x, &y);
1.37 + gdk_drawable_get_size(GDK_DRAWABLE(win->video->window), &width, &height);
1.38 + x += width / 2;
1.39 + y += height / 2;
1.40 +
1.41 + gdk_display_warp_pointer( display, screen, x, y );
1.42 + win->mouse_x = width/2;
1.43 + win->mouse_y = height/2;
1.44 +}
1.45 +
1.46 +/**
1.47 + * Grab the keyboard and mouse for the display. The mouse cursor is hidden and
1.48 + * moved to the centre of the window.
1.49 + *
1.50 + * @param win The window receiving the grab
1.51 + * @return TRUE if the grab was successful, FALSE on failure.
1.52 + */
1.53 +gboolean video_window_grab_display( main_window_t win )
1.54 +{
1.55 + GdkWindow *gdkwin = win->video->window;
1.56 + GdkColor color = { 0,0,0,0 };
1.57 + char bytes[32]; /* 16 * 16 / 8 */
1.58 + memset(bytes, 0, 32);
1.59 + GdkPixmap *pixmap = gdk_bitmap_create_from_data(NULL, bytes, 16, 16);
1.60 + GdkCursor *cursor = gdk_cursor_new_from_pixmap(pixmap, pixmap, &color, &color, 16, 16);
1.61 + gdk_pixmap_unref(pixmap);
1.62 +
1.63 + gboolean success =
1.64 + gdk_pointer_grab( gdkwin, FALSE,
1.65 + GDK_POINTER_MOTION_MASK|GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK,
1.66 + gdkwin, cursor, GDK_CURRENT_TIME ) == GDK_GRAB_SUCCESS;
1.67 + gdk_cursor_unref(cursor);
1.68 + if( success ) {
1.69 + success = gdk_keyboard_grab( gdkwin, FALSE, GDK_CURRENT_TIME ) == GDK_GRAB_SUCCESS;
1.70 + if( !success ) {
1.71 + gdk_pointer_ungrab(GDK_CURRENT_TIME);
1.72 + }
1.73 + }
1.74 + win->is_grabbed = success;
1.75 + main_window_set_running(win, dreamcast_is_running());
1.76 + return success;
1.77 +}
1.78 +
1.79 +/**
1.80 + * Release the display grab.
1.81 + */
1.82 +void video_window_ungrab_display( main_window_t win )
1.83 +{
1.84 + gdk_pointer_ungrab(GDK_CURRENT_TIME);
1.85 + gdk_keyboard_ungrab(GDK_CURRENT_TIME);
1.86 + win->is_grabbed = FALSE;
1.87 + main_window_set_running(win, dreamcast_is_running());
1.88 +}
1.89 +
1.90 +static gboolean on_video_window_mouse_motion( GtkWidget *widget, GdkEventMotion *event,
1.91 + gpointer user_data )
1.92 +{
1.93 + main_window_t win = (main_window_t)user_data;
1.94 + int32_t x = (int32_t)event->x;
1.95 + int32_t y = (int32_t)event->y;
1.96 + if( win->is_grabbed &&
1.97 + (x != win->mouse_x || y != win->mouse_y) ) {
1.98 + uint32_t buttons = (event->state >> 8)&0x1F;
1.99 + input_event_mouse( buttons, x - win->mouse_x, y - win->mouse_y );
1.100 + video_window_center_pointer(win);
1.101 + }
1.102 + return TRUE;
1.103 +}
1.104 +
1.105 +static gboolean on_video_window_mouse_pressed( GtkWidget *widget, GdkEventButton *event,
1.106 + gpointer user_data )
1.107 +{
1.108 + main_window_t win = (main_window_t)user_data;
1.109 + if( win->is_grabbed ) {
1.110 + // Get the buttons from the event state, and remove the released button
1.111 + uint32_t buttons = ((event->state >> 8) & 0x1F) | (1<<(event->button-1));
1.112 + input_event_mouse( buttons, 0, 0 );
1.113 + }
1.114 + return TRUE;
1.115 +}
1.116 +
1.117 +static gboolean on_video_window_mouse_released( GtkWidget *widget, GdkEventButton *event,
1.118 + gpointer user_data )
1.119 +{
1.120 + main_window_t win = (main_window_t)user_data;
1.121 + if( win->is_grabbed ) {
1.122 + // Get the buttons from the event state, and remove the released button
1.123 + uint32_t buttons = ((event->state >> 8) & 0x1F) & (~(1<<(event->button-1)));
1.124 + input_event_mouse( buttons, 0, 0 );
1.125 + } else if( win->use_grab) {
1.126 + video_window_grab_display(win);
1.127 + }
1.128 + return TRUE;
1.129 +}
1.130 +
1.131 +static gboolean on_video_window_key_pressed( GtkWidget *widget, GdkEventKey *event,
1.132 + gpointer user_data )
1.133 +{
1.134 + main_window_t win = (main_window_t)user_data;
1.135 + if( win->is_grabbed ) {
1.136 + /* Check for ungrab key combo (ctrl-alt). Unfortunately GDK sends it as
1.137 + * a singly-modified keypress rather than a double-modified 'null' press,
1.138 + * so we have to do a little more work.
1.139 + */
1.140 + if( (event->state == GDK_CONTROL_MASK &&
1.141 + (event->keyval == GDK_Alt_L || event->keyval == GDK_Alt_R)) ||
1.142 + (event->state == GDK_MOD1_MASK &&
1.143 + (event->keyval == GDK_Control_L || event->keyval == GDK_Control_R)) ) {
1.144 + video_window_ungrab_display(win);
1.145 + // Consume the keypress, DC doesn't get it.
1.146 + return TRUE;
1.147 + }
1.148 + }
1.149 + input_event_keydown( gtk_get_unmodified_keyval(event) );
1.150 + return TRUE;
1.151 +}
1.152 +
1.153 +static gboolean on_video_window_key_released( GtkWidget *widget, GdkEventKey *event,
1.154 + gpointer user_data )
1.155 +{
1.156 + main_window_t win = (main_window_t)user_data;
1.157 + input_event_keyup( gtk_get_unmodified_keyval(event) );
1.158 + return TRUE;
1.159 +}
1.160 +
1.161 +static gboolean on_video_window_grab_broken( GtkWidget *widget, GdkEventGrabBroken *event,
1.162 + gpointer user_data )
1.163 +{
1.164 + main_window_t win = (main_window_t)user_data;
1.165 + fprintf( stderr, "Grab broken\n" );
1.166 +}
1.167 +
1.168 +/*************************** Main window (frame) ******************************/
1.169 +
1.170 static gboolean on_main_window_deleted( GtkWidget *widget, GdkEvent event, gpointer user_data )
1.171 {
1.172 exit(0);
1.173 @@ -86,6 +239,8 @@
1.174 win->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1.175 win->menubar = menubar;
1.176 win->toolbar = toolbar;
1.177 + win->use_grab = FALSE;
1.178 + win->is_grabbed = FALSE;
1.179 gtk_window_set_title( GTK_WINDOW(win->window), title );
1.180 gtk_window_add_accel_group (GTK_WINDOW (win->window), accel_group);
1.181
1.182 @@ -106,6 +261,7 @@
1.183 gtk_widget_set_colormap( win->video, colormap );
1.184 GTK_WIDGET_SET_FLAGS(win->video, GTK_CAN_FOCUS|GTK_CAN_DEFAULT);
1.185 gtk_widget_set_size_request( win->video, 640, 480 );
1.186 + gtk_widget_set_double_buffered( win->video, FALSE );
1.187 frame = gtk_frame_new(NULL);
1.188 gtk_frame_set_shadow_type( GTK_FRAME(frame), GTK_SHADOW_IN );
1.189 gtk_container_add( GTK_CONTAINER(frame), win->video );
1.190 @@ -122,19 +278,51 @@
1.191 gtk_widget_grab_focus( win->video );
1.192
1.193 gtk_statusbar_push( GTK_STATUSBAR(win->statusbar), 1, "Stopped" );
1.194 +
1.195 g_signal_connect( win->window, "delete_event",
1.196 G_CALLBACK(on_main_window_deleted), win );
1.197 g_signal_connect( win->window, "window-state-event",
1.198 G_CALLBACK(on_main_window_state_changed), win );
1.199 +
1.200 + g_signal_connect( win->video, "grab-broken-event",
1.201 + G_CALLBACK(on_video_window_grab_broken), win );
1.202 + g_signal_connect( win->video, "key-press-event",
1.203 + G_CALLBACK(on_video_window_key_pressed), win );
1.204 + g_signal_connect( win->video, "key-release-event",
1.205 + G_CALLBACK(on_video_window_key_released), win );
1.206 + g_signal_connect( win->video, "motion-notify-event",
1.207 + G_CALLBACK(on_video_window_mouse_motion), win );
1.208 + g_signal_connect( win->video, "button-press-event",
1.209 + G_CALLBACK(on_video_window_mouse_pressed), win );
1.210 + g_signal_connect( win->video, "button-release-event",
1.211 + G_CALLBACK(on_video_window_mouse_released), win );
1.212 +
1.213 + gtk_widget_add_events( win->video,
1.214 + GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
1.215 + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1.216 + GDK_POINTER_MOTION_MASK );
1.217 +
1.218 return win;
1.219 }
1.220
1.221 +void main_window_set_status_text( main_window_t win, char *text )
1.222 +{
1.223 + gtk_statusbar_pop( GTK_STATUSBAR(win->statusbar), 1 );
1.224 + if( win->is_grabbed ) {
1.225 + char buf[128];
1.226 + snprintf( buf, sizeof(buf), "%s %s", text, _("(Press <ctrl><alt> to release grab)") );
1.227 + gtk_statusbar_push( GTK_STATUSBAR(win->statusbar), 1, buf );
1.228 + } else {
1.229 + gtk_statusbar_push( GTK_STATUSBAR(win->statusbar), 1, text );
1.230 + }
1.231 +}
1.232 +
1.233 void main_window_set_running( main_window_t win, gboolean running )
1.234 {
1.235 + char *text = running ? _("Running") : _("Stopped");
1.236 gtk_gui_enable_action( "Pause", running );
1.237 gtk_gui_enable_action( "Run", !running && dreamcast_can_run() );
1.238 - gtk_statusbar_pop( GTK_STATUSBAR(win->statusbar), 1 );
1.239 - gtk_statusbar_push( GTK_STATUSBAR(win->statusbar), 1, running ? "Running" : "Stopped" );
1.240 + main_window_set_status_text( win, text );
1.241 }
1.242
1.243 void main_window_set_framerate( main_window_t win, float rate )
1.244 @@ -148,10 +336,7 @@
1.245 char buf[32];
1.246
1.247 snprintf( buf, 32, "Running (%2.4f%%)", speed );
1.248 - gtk_statusbar_pop( GTK_STATUSBAR(win->statusbar), 1 );
1.249 - gtk_statusbar_push( GTK_STATUSBAR(win->statusbar), 1, buf );
1.250 -
1.251 -
1.252 + main_window_set_status_text( win, buf );
1.253 }
1.254
1.255 GtkWidget *main_window_get_renderarea( main_window_t win )
1.256 @@ -172,3 +357,20 @@
1.257 gtk_window_unfullscreen( GTK_WINDOW(win->window) );
1.258 }
1.259 }
1.260 +
1.261 +void main_window_set_use_grab( main_window_t win, gboolean use_grab )
1.262 +{
1.263 + if( use_grab != win->use_grab ) {
1.264 + if( use_grab ) {
1.265 + GdkCursor *cursor = gdk_cursor_new( GDK_HAND2 );
1.266 + gdk_window_set_cursor( win->video->window, cursor );
1.267 + gdk_cursor_unref( cursor );
1.268 + } else {
1.269 + gdk_window_set_cursor( win->video->window, NULL );
1.270 + if( gdk_pointer_is_grabbed() ) {
1.271 + video_window_ungrab_display(win);
1.272 + }
1.273 + }
1.274 + win->use_grab = use_grab;
1.275 + }
1.276 +}
.