From be15c0cfecee29773830065ec0e1b1103fe47c08 Mon Sep 17 00:00:00 2001 From: punkrockguy318 Date: Tue, 25 Jan 2011 03:26:09 +0000 Subject: [PATCH] *ID: 3165057 - Embed SDL window in GTK window patch applied Big thanks to Bryan Cain! *fixed issues with xscale/yscale options "not sticking" in gtk gui *set gtk window to resize to xscale/yscale options introduced known bug: alt-tab won't currently go into fullscreen --- Authors.txt | 6 +- TODO-SDL | 6 +- src/drivers/sdl/gui.cpp | 289 ++++++++++++++++++++++++++-------- src/drivers/sdl/gui.h | 3 + src/drivers/sdl/sdl-video.cpp | 27 +++- 5 files changed, 263 insertions(+), 68 deletions(-) diff --git a/Authors.txt b/Authors.txt index c22b6ad5..a235382f 100644 --- a/Authors.txt +++ b/Authors.txt @@ -71,7 +71,7 @@ Debugger additions Shinydoofy - sf:shinydoofy SDL maintenence -Lukas Sabota - ltsmooth42 at comcast.net (sf:punkrockguy318) +Lukas Sabota - ltsmooth42 at gmail dot com (sf:punkrockguy318) Head SDL developer Soules - gimmedonutnow at gmail dot com (sf:gimmedonutnow) @@ -80,6 +80,10 @@ Linux SDL driver maintenance radsaq - radsaq at gmail dot com (sf:radsaq) Build system, testing, and random cleanups +bryan cain - +sdl in gtk gui patch + + ----------------------------------------- Included components: diff --git a/TODO-SDL b/TODO-SDL index 571a2966..14ee616e 100644 --- a/TODO-SDL +++ b/TODO-SDL @@ -1,9 +1,9 @@ TODO-SVN: -* DONE! Working!Test and work on unix-netplay +*** Auto-resize game window +*** Add alt-enter for fullscreen in GTK * DONE! Get to compile with SDL 1.3 * segfaults when opening a second game * segfaults on fullscreen entry -* DONE! Fix sound stuttering/lag (fixed in SDL 1.1.14) * Flesh out GTK GUI * Sound config * DONE! Individual volume mixers @@ -25,7 +25,7 @@ TODO-SVN: * OpenGLip * Scanline end/start * DONE! pallete -* Integrate SDL window into GTK GUI +* THANKS BRYAN CAIN! Integrate SDL window into GTK GUI * DONE! Fix opening compressed ROMs * DONE! Fix Famicom Disk System * DONE!(PAUSE) Add a key to resume normal playback when finished frameskipping diff --git a/src/drivers/sdl/gui.cpp b/src/drivers/sdl/gui.cpp index c76d3d6e..f5df5739 100644 --- a/src/drivers/sdl/gui.cpp +++ b/src/drivers/sdl/gui.cpp @@ -33,6 +33,7 @@ void loadGame (); extern Config *g_config; GtkWidget* MainWindow = NULL; +GtkWidget* socket = NULL; GtkWidget* padNoCombo; // This function configures a single button on a gamepad @@ -670,8 +671,8 @@ void openVideoConfig() gtk_box_pack_start(GTK_BOX(yscaleHbox), yscaleLbl, FALSE, FALSE, 2); gtk_box_pack_start(GTK_BOX(yscaleHbox), yscaleSpin, FALSE, FALSE, 2); - g_signal_connect(xscaleSpin, "button-release-event", G_CALLBACK(setXscale), NULL); - g_signal_connect(yscaleSpin, "button-release-event", G_CALLBACK(setYscale), NULL); + g_signal_connect(xscaleSpin, "value-changed", G_CALLBACK(setXscale), NULL); + g_signal_connect(yscaleSpin, "value-changed", G_CALLBACK(setYscale), NULL); double f; // sync with config @@ -1277,16 +1278,11 @@ void loadGame () gtk_widget_destroy (fileChooser); } -void closeGame() { CloseGame(); } - -// this is not used currently; it is used in rendering sdl in -// the gtk window which is broken -gint configureEvent (GtkWidget* widget, GdkEventConfigure* event) +void closeGame() { - //neccessary for SDL rendering on gtk win (i think?) - //s_screen = SDL_SetVideoMode(event->width, event->height, 0, 0); - - return TRUE; + GdkColor bg = {0, 0, 0, 0}; + gtk_widget_modify_bg(socket, GTK_STATE_NORMAL, &bg); + CloseGame(); } void saveStateAs() @@ -1357,7 +1353,198 @@ void loadStateFrom() } + + +// Adapted from Gens/GS. Converts a GDK key value into an SDL key value. +unsigned short GDKToSDLKeyval(int gdk_key) +{ + if (!(gdk_key & 0xFF00)) + { + // ASCII symbol. + // SDL and GDK use the same values for these keys. + + // Make sure the key value is lowercase. + gdk_key = tolower(gdk_key); + + // Return the key value. + return gdk_key; + } + if (gdk_key & 0xFFFF0000) + { + // Extended X11 key. Not supported by SDL. +#ifdef GDK_WINDOWING_X11 + fprintf(stderr, "Unhandled extended X11 key: 0x%08X (%s)", gdk_key, XKeysymToString(gdk_key)); +#else + fprintf(stderr, "Unhandled extended key: 0x%08X\n", gdk_key); +#endif + return 0; + } + + // Non-ASCII symbol. + static const uint16_t gdk_to_sdl_table[0x100] = + { + // 0x00 - 0x0F + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + SDLK_BACKSPACE, SDLK_TAB, SDLK_RETURN, SDLK_CLEAR, + 0x0000, SDLK_RETURN, 0x0000, 0x0000, + + // 0x10 - 0x1F + 0x0000, 0x0000, 0x0000, SDLK_PAUSE, + SDLK_SCROLLOCK, SDLK_SYSREQ, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, SDLK_ESCAPE, + 0x0000, 0x0000, 0x0000, 0x0000, + + // 0x20 - 0x2F + SDLK_COMPOSE, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + + // 0x30 - 0x3F [Japanese keys] + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + + // 0x40 - 0x4F [unused] + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + + // 0x50 - 0x5F + SDLK_HOME, SDLK_LEFT, SDLK_UP, SDLK_RIGHT, + SDLK_DOWN, SDLK_PAGEUP, SDLK_PAGEDOWN, SDLK_END, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + + // 0x60 - 0x6F + 0x0000, SDLK_PRINT, 0x0000, SDLK_INSERT, + SDLK_UNDO, 0x0000, 0x0000, SDLK_MENU, + 0x0000, SDLK_HELP, SDLK_BREAK, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + + // 0x70 - 0x7F [mostly unused, except for Alt Gr and Num Lock] + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, SDLK_MODE, SDLK_NUMLOCK, + + // 0x80 - 0x8F [mostly unused, except for some numeric keypad keys] + SDLK_KP5, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, SDLK_KP_ENTER, 0x0000, 0x0000, + + // 0x90 - 0x9F + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, SDLK_KP7, SDLK_KP4, SDLK_KP8, + SDLK_KP6, SDLK_KP2, SDLK_KP9, SDLK_KP3, + SDLK_KP1, SDLK_KP5, SDLK_KP0, SDLK_KP_PERIOD, + + // 0xA0 - 0xAF + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, SDLK_KP_MULTIPLY, SDLK_KP_PLUS, + 0x0000, SDLK_KP_MINUS, SDLK_KP_PERIOD, SDLK_KP_DIVIDE, + + // 0xB0 - 0xBF + SDLK_KP0, SDLK_KP1, SDLK_KP2, SDLK_KP3, + SDLK_KP4, SDLK_KP5, SDLK_KP6, SDLK_KP7, + SDLK_KP8, SDLK_KP9, 0x0000, 0x0000, + 0x0000, SDLK_KP_EQUALS, SDLK_F1, SDLK_F2, + + // 0xC0 - 0xCF + SDLK_F3, SDLK_F4, SDLK_F5, SDLK_F6, + SDLK_F7, SDLK_F8, SDLK_F9, SDLK_F10, + SDLK_F11, SDLK_F12, SDLK_F13, SDLK_F14, + SDLK_F15, 0x0000, 0x0000, 0x0000, + + // 0xD0 - 0xDF [L* and R* function keys] + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + + // 0xE0 - 0xEF + 0x0000, SDLK_LSHIFT, SDLK_RSHIFT, SDLK_LCTRL, + SDLK_RCTRL, SDLK_CAPSLOCK, 0x0000, SDLK_LMETA, + SDLK_RMETA, SDLK_LALT, SDLK_RALT, SDLK_LSUPER, + SDLK_RSUPER, 0x0000, 0x0000, 0x0000, + + // 0xF0 - 0xFF [mostly unused, except for Delete] + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, SDLK_DELETE, + }; + + unsigned short sdl_key = gdk_to_sdl_table[gdk_key & 0xFF]; + if (sdl_key == 0) + { + // Unhandled GDK key. + fprintf(stderr, "Unhandled GDK key: 0x%04X (%s)", gdk_key, gdk_keyval_name(gdk_key)); + return 0; + } + + return sdl_key; +} + + +// Function adapted from Gens/GS (source/gens/input/input_sdl.c) +gint convertKeypress(GtkWidget *grab, GdkEventKey *event, gpointer user_data) +{ + SDL_Event sdlev; + SDLKey sdlkey; + int keystate; + + // Only grab keys from the main window. + if (grab != MainWindow) + { + // Don't push this key onto the SDL event stack. + return FALSE; + } + + switch (event->type) + { + case GDK_KEY_PRESS: + sdlev.type = SDL_KEYDOWN; + sdlev.key.state = SDL_PRESSED; + keystate = 1; + break; + + case GDK_KEY_RELEASE: + sdlev.type = SDL_KEYUP; + sdlev.key.state = SDL_RELEASED; + keystate = 0; + break; + + default: + fprintf(stderr, "Unhandled GDK event type: %d", event->type); + return FALSE; + } + + // Convert this keypress from GDK to SDL. + sdlkey = (SDLKey)GDKToSDLKeyval(event->keyval); + + // Create an SDL event from the keypress. + sdlev.key.keysym.sym = sdlkey; + if (sdlkey != 0) + { + SDL_PushEvent(&sdlev); + #if SDL_VERSION_ATLEAST(1, 3, 0) + SDL_GetKeyboardState(NULL)[SDL_GetScancodeFromKey(sdlkey)] = keystate; + #else + SDL_GetKeyState(NULL)[sdlkey] = keystate; + #endif + } + + // Allow GTK+ to process this key. + return FALSE; +} + /* Our menu, an array of GtkItemFactoryEntry structures that defines each menu item */ static GtkItemFactoryEntry menu_items[] = { @@ -1469,78 +1656,54 @@ int InitGTKSubsystem(int argc, char** argv) gtk_window_set_title(GTK_WINDOW(MainWindow), FCEU_NAME_AND_VERSION); gtk_window_set_default_size(GTK_WINDOW(MainWindow), 359, 200); - vbox = gtk_vbox_new(FALSE, 3); + vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(MainWindow), vbox); Menubar = CreateMenubar(MainWindow); - - //consoleOutput = gtk_text_view_new_with_buffer(gtkConsoleBuf); - //gtk_text_view_set_editable(GTK_TEXT_VIEW(consoleOutput), FALSE); - - //gtkConsoleBuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(consoleOutput)); - //gtk_text_buffer_get_iter_at_offset(gtkConsoleBuf, &iter, 0); - //gtk_text_buffer_insert(gtkConsoleBuf, &iter, "FceuX GUI Started.\n", -1); - // = vte_terminal_new(); - //vte_terminal_feed(VTE_TERMINAL(term), "FceuX GUI Started", -1); - - - - //gtk_container_add(GTK_CONTAINER(vbox), Menubar); + gtk_box_pack_start (GTK_BOX(vbox), Menubar, FALSE, TRUE, 0); - //gtk_box_pack_start (GTK_BOX(vbox), term, TRUE, TRUE, 0); - - - - - // broken SDL embedding code - //gtk_widget_set_usize(MainWindow, xres, yres); - //gtk_widget_realize(MainWindow); - - // event handlers - //gtk_widget_add_events(MainWindow, GDK_BUTTON_PRESS_MASK); - //gtk_signal_connect(GTK_OBJECT(MainWindow), "configure_event", - // GTK_SIGNAL_FUNC(configureEvent), 0); - - + // PRG: this code here is the the windowID "hack" to render SDL // in a GTK window. however, I can't get it to work right now // so i'm commenting it out and haivng a seperate GTK2 window with // controls // 12/21/09 - /* - GtkWidget* socket = gtk_socket_new(); - gtk_widget_show (socket) ; - gtk_container_add (GTK_CONTAINER(MainWindow), socket); + // --- + // uncommented and fixed by Bryan Cain + // 1/24/11 + // + // prg - Bryan Cain, you are the man! + GtkWidget* hbox = gtk_hbox_new(FALSE, 0); + gtk_widget_show(hbox); + gtk_box_pack_end (GTK_BOX(vbox), hbox, TRUE, TRUE, 0); - gtk_widget_realize (socket); - - char SDL_windowhack[24]; - sprintf(SDL_windowhack, "SDL_WINDOWID=%ld", (long int)gtk_socket_get_id (GTK_SOCKET(socket))); - putenv(SDL_windowhack); + socket = gtk_event_box_new(); + gtk_box_pack_start (GTK_BOX(hbox), socket, TRUE, FALSE, 0); + double xscale, yscale; + printf("%f %f", xscale, yscale); + g_config->getOption("SDL.XScale", &xscale); + g_config->getOption("SDL.YScale", &yscale); + gtk_widget_set_size_request(socket, 256*xscale, 224*yscale); + gtk_widget_realize(socket); + gtk_widget_show(socket); + GdkColor bg = {0, 0, 0, 0}; + gtk_widget_modify_bg(socket, GTK_STATE_NORMAL, &bg); - // init SDL - if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) - { - fprintf(stderr, "Couldn't init SDL: %s\n", SDL_GetError()); - gtk_main_quit(); - } + // set up keypress "snooper" to convert GDK keypress events into SDL keypresses + gtk_key_snooper_install(convertKeypress, NULL); - - - // test rendering - //screen = SDL_SetVideoMode(xres, yres, 0, 0); - //hello = SDL_LoadBMP( "hello.bmp" ); - */ g_signal_connect(MainWindow, "destroy-event", quit, NULL); - //gtk_idle_add(mainLoop, MainWindow); // signal handlers g_signal_connect(MainWindow, "delete-event", quit, NULL); - gtk_widget_show_all(MainWindow); + + GtkRequisition req; + gtk_widget_size_request(GTK_WIDGET(MainWindow), &req); + gtk_window_resize(GTK_WINDOW(MainWindow), req.width, req.height); return 0; } diff --git a/src/drivers/sdl/gui.h b/src/drivers/sdl/gui.h index 4b65c58f..2b92f207 100644 --- a/src/drivers/sdl/gui.h +++ b/src/drivers/sdl/gui.h @@ -20,6 +20,9 @@ #ifndef FCEUX_GUI_H #define FCEUX_GUI_H #define GTK_LITE +#include +extern GtkWidget* MainWindow; +extern GtkWidget* socket; int InitGTKSubsystem(int argc, char** argv); void pushOutputToGTK(const char* str); void showGui(bool b); diff --git a/src/drivers/sdl/sdl-video.cpp b/src/drivers/sdl/sdl-video.cpp index 427130d3..b2b509de 100644 --- a/src/drivers/sdl/sdl-video.cpp +++ b/src/drivers/sdl/sdl-video.cpp @@ -45,6 +45,7 @@ #ifdef _GTK #include "gui.h" +#include #endif // GLOBALS @@ -312,7 +313,7 @@ InitVideo(FCEUGI *gi) return -1; } - + s_screen = SDL_SetVideoMode(xres, yres, desbpp, flags); if(!s_screen) { FCEUD_PrintError(SDL_GetError()); @@ -357,6 +358,24 @@ InitVideo(FCEUGI *gi) return -1; } #endif + +#ifdef _GTK + while (gtk_events_pending()) + gtk_main_iteration_do(FALSE); + + char SDL_windowhack[128]; + sprintf(SDL_windowhack, "SDL_WINDOWID=%u", (unsigned int)GDK_WINDOW_XWINDOW(gtk_widget_get_window(socket))); + SDL_putenv(SDL_windowhack); + + // init SDL video + if (SDL_WasInit(SDL_INIT_VIDEO)) + SDL_QuitSubSystem(SDL_INIT_VIDEO); + if ( SDL_InitSubSystem(SDL_INIT_VIDEO) < 0 ) + { + fprintf(stderr, "Couldn't init SDL video: %s\n", SDL_GetError()); + gtk_main_quit(); + } +#endif s_screen = SDL_SetVideoMode((int)(NWIDTH * s_exs), (int)(s_tlines * s_eys), @@ -365,6 +384,12 @@ InitVideo(FCEUGI *gi) FCEUD_PrintError(SDL_GetError()); return -1; } + +#ifdef _GTK + GtkRequisition req; + gtk_widget_size_request(GTK_WIDGET(MainWindow), &req); + gtk_window_resize(GTK_WINDOW(MainWindow), req.width, req.height); +#endif } s_curbpp = s_screen->format->BitsPerPixel; if(!s_screen) {