summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan C. Gordon <icculus@icculus.org>2007-04-19 07:12:30 +0000
committerRyan C. Gordon <icculus@icculus.org>2007-04-19 07:12:30 +0000
commita1b62b78c5eb53c605c7d4cfa51a451faa94ab4b (patch)
tree19503dc65834836d6af8b17d99fcef4ae1c56631
parent3af8c562a09a0215513bc9463b929a11be269d0e (diff)
downloadsdl-a1b62b78c5eb53c605c7d4cfa51a451faa94ab4b.tar.gz
First shot at GTK+ video target for the OLPC laptops. Seriously incomplete,
but it's enough to get some bits to a window...
-rw-r--r--configure.in30
-rw-r--r--include/SDL_config.h.in1
-rw-r--r--src/video/SDL_sysvideo.h3
-rw-r--r--src/video/SDL_video.c3
-rw-r--r--src/video/gtk/SDL_gtkevents.c413
-rw-r--r--src/video/gtk/SDL_gtkevents_c.h34
-rw-r--r--src/video/gtk/SDL_gtkmouse.c33
-rw-r--r--src/video/gtk/SDL_gtkmouse_c.h26
-rw-r--r--src/video/gtk/SDL_gtkvideo.c643
-rw-r--r--src/video/gtk/SDL_gtkvideo.h51
10 files changed, 1237 insertions, 0 deletions
diff --git a/configure.in b/configure.in
index 1d456a143..69099c3c2 100644
--- a/configure.in
+++ b/configure.in
@@ -1347,6 +1347,35 @@ AC_HELP_STRING([--enable-video-aalib], [use AAlib video driver [[default=no]]]),
fi
}
+dnl Find the GTK+ includes
+CheckGTK()
+{
+ AC_ARG_ENABLE(video-gtk,
+AC_HELP_STRING([--enable-video-gtk], [use GTK+ video driver [[default=no]]]),
+ , enable_video_gtk=no)
+ if test x$enable_video = xyes -a x$enable_video_gtk = xyes; then
+ AC_PATH_PROG(HAVEPKGCONFIG, pkg-config, $PATH)
+ if test -z "$HAVEPKGCONFIG"; then
+ AC_MSG_ERROR([*** pkg-config not found. Cannot probe for gtk+-2.0.])
+ else
+ AC_MSG_CHECKING(for GTK+ support)
+ video_gtk=no
+ $HAVEPKGCONFIG --exists gtk+-2.0
+ if test $? -eq 0 ; then
+ video_gtk=yes
+ have_video=yes
+ AC_DEFINE(SDL_VIDEO_DRIVER_GTK)
+ SOURCES="$SOURCES $srcdir/src/video/gtk/*.c"
+ GTK2_CFLAGS=`$HAVEPKGCONFIG --cflags libglade-2.0 gtk+-2.0`
+ GTK2_LIBS=`$HAVEPKGCONFIG --libs libglade-2.0 gtk+-2.0`
+ EXTRA_CFLAGS="$EXTRA_CFLAGS $GTK2_CFLAGS"
+ EXTRA_LDFLAGS="$EXTRA_LDFLAGS $GTK2_LIBS"
+ fi
+ AC_MSG_RESULT($video_gtk)
+ fi
+ fi
+}
+
dnl Set up the QTopia video driver if enabled
CheckQtopia()
{
@@ -2161,6 +2190,7 @@ case "$host" in
CheckVGL
CheckWscons
CheckAAlib
+ CheckGTK
CheckQtopia
CheckPicoGUI
CheckOpenGLX11
diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in
index afd6eb73f..decba8756 100644
--- a/include/SDL_config.h.in
+++ b/include/SDL_config.h.in
@@ -258,6 +258,7 @@
#undef SDL_VIDEO_DRIVER_GAPI
#undef SDL_VIDEO_DRIVER_GEM
#undef SDL_VIDEO_DRIVER_GGI
+#undef SDL_VIDEO_DRIVER_GTK
#undef SDL_VIDEO_DRIVER_IPOD
#undef SDL_VIDEO_DRIVER_NANOX
#undef SDL_VIDEO_DRIVER_OS2FS
diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h
index 80a579c35..75a2c0e50 100644
--- a/src/video/SDL_sysvideo.h
+++ b/src/video/SDL_sysvideo.h
@@ -401,6 +401,9 @@ extern VideoBootStrap OS2FSLib_bootstrap;
#if SDL_VIDEO_DRIVER_AALIB
extern VideoBootStrap AALIB_bootstrap;
#endif
+#if SDL_VIDEO_DRIVER_GTK
+extern VideoBootStrap GTKPLUS_bootstrap;
+#endif
#if SDL_VIDEO_DRIVER_DUMMY
extern VideoBootStrap DUMMY_bootstrap;
#endif
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 3329b85ac..53f5eb609 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -117,6 +117,9 @@ static VideoBootStrap *bootstrap[] = {
#if SDL_VIDEO_DRIVER_AALIB
&AALIB_bootstrap,
#endif
+#if SDL_VIDEO_DRIVER_GTK
+ &GTKPLUS_bootstrap,
+#endif
#if SDL_VIDEO_DRIVER_DUMMY
&DUMMY_bootstrap,
#endif
diff --git a/src/video/gtk/SDL_gtkevents.c b/src/video/gtk/SDL_gtkevents.c
new file mode 100644
index 000000000..988234d86
--- /dev/null
+++ b/src/video/gtk/SDL_gtkevents.c
@@ -0,0 +1,413 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2006 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#include "SDL.h"
+#include "../../events/SDL_sysevents.h"
+#include "../../events/SDL_events_c.h"
+
+#include "SDL_gtkvideo.h"
+#include "SDL_gtkevents_c.h"
+
+#define DEBUG_GTKPLUS_EVENTS 0
+#if DEBUG_GTKPLUS_EVENTS
+#define DEBUG_GTKPLUS_SIGNAL() printf("GTK+: %s\n", __FUNCTION__)
+#else
+#define DEBUG_GTKPLUS_SIGNAL()
+#endif
+
+static gboolean
+signal_enter_notify(GtkWidget *w, GdkEventCrossing *evt, gpointer data)
+{
+ SET_THIS_POINTER(data);
+ DEBUG_GTKPLUS_SIGNAL();
+ if ( (evt->mode != GDK_CROSSING_GRAB) &&
+ (evt->mode != GDK_CROSSING_UNGRAB) ) {
+ if ( this->input_grab == SDL_GRAB_OFF ) {
+ SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
+ }
+ SDL_PrivateMouseMotion(0, 0, evt->x, evt->y);
+ }
+
+ return FALSE; /* don't eat event, in case app connected a handler. */
+}
+
+
+static gboolean
+signal_leave_notify(GtkWidget *w, GdkEventCrossing *evt, gpointer data)
+{
+ SET_THIS_POINTER(data);
+ DEBUG_GTKPLUS_SIGNAL();
+ if ( (evt->mode != GDK_CROSSING_GRAB) &&
+ (evt->mode != GDK_CROSSING_UNGRAB) &&
+ (evt->detail != GDK_NOTIFY_INFERIOR) ) {
+ if ( this->input_grab == SDL_GRAB_OFF ) {
+ SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
+ } else {
+ SDL_PrivateMouseMotion(0, 0, evt->x, evt->y);
+ }
+ }
+ return FALSE; /* don't eat event, in case app connected a handler. */
+}
+
+
+static gboolean
+signal_focus_in(GtkWidget *w, GdkEventFocus *evt, gpointer data)
+{
+ DEBUG_GTKPLUS_SIGNAL();
+ SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS);
+ return FALSE; /* don't eat event, in case app connected a handler. */
+}
+
+
+static gboolean
+signal_focus_out(GtkWidget *w, GdkEventFocus *evt, gpointer data)
+{
+ DEBUG_GTKPLUS_SIGNAL();
+ SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS);
+ return FALSE; /* don't eat event, in case app connected a handler. */
+}
+
+
+#if 0
+ /* Generated upon EnterWindow and FocusIn */
+ case KeymapNotify: {
+#ifdef DEBUG_XEVENTS
+printf("KeymapNotify!\n");
+#endif
+ X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector);
+ }
+ break;
+#endif
+
+
+static gboolean
+signal_motion_notify(GtkWidget *w, GdkEventMotion *evt, gpointer data)
+{
+ SET_THIS_POINTER(data);
+ DEBUG_GTKPLUS_SIGNAL();
+ if ( SDL_VideoSurface ) {
+ if ( 0 /* !!! FIXME mouse_relative */ ) {
+ SDLGTK_WarpedMotion(this, evt);
+ } else {
+ SDL_PrivateMouseMotion(0, 0, evt->x, evt->y);
+ }
+ }
+
+ return FALSE; /* don't eat event, in case app connected a handler. */
+}
+
+
+static gboolean
+signal_button_press(GtkWidget *w, GdkEventButton *evt, gpointer data)
+{
+ DEBUG_GTKPLUS_SIGNAL();
+ SDL_PrivateMouseButton(SDL_PRESSED, evt->button, 0, 0);
+ return FALSE; /* don't eat event, in case app connected a handler. */
+}
+
+static gboolean
+signal_button_release(GtkWidget *w, GdkEventButton *evt, gpointer data)
+{
+ DEBUG_GTKPLUS_SIGNAL();
+ SDL_PrivateMouseButton(SDL_RELEASED, evt->button, 0, 0);
+ return FALSE; /* don't eat event, in case app connected a handler. */
+}
+
+static gboolean
+signal_expose(GtkWidget *w, GdkEventExpose *evt, gpointer data)
+{
+ SET_THIS_POINTER(data);
+ const GdkRectangle *area = &evt->area;
+ SDL_Rect r = { area->x, area->y, area->width, area->height };
+ DEBUG_GTKPLUS_SIGNAL();
+ this->UpdateRects(this, 1, &r);
+ return FALSE; /* don't eat event, in case app connected a handler. */
+}
+
+
+static gboolean
+signal_delete(GtkWidget *w, GdkEvent *evt, gpointer data)
+{
+ DEBUG_GTKPLUS_SIGNAL();
+ SDL_PrivateQuit();
+ return TRUE; /* eat event: default handler destroys window! */
+}
+
+
+void GTKPLUS_ConnectSignals(_THIS)
+{
+ gtk_widget_set_events( this->hidden->gtkdrawingarea,
+ GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+ GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
+ GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK );
+
+ gtk_signal_connect(GTK_OBJECT(this->hidden->gtkwindow),
+ "delete-event",
+ GTK_SIGNAL_FUNC(signal_delete), this);
+ gtk_signal_connect(GTK_OBJECT(this->hidden->gtkdrawingarea),
+ "enter-notify-event",
+ GTK_SIGNAL_FUNC(signal_enter_notify), this);
+ gtk_signal_connect(GTK_OBJECT(this->hidden->gtkdrawingarea),
+ "leave-notify-event",
+ GTK_SIGNAL_FUNC(signal_leave_notify), this);
+ gtk_signal_connect(GTK_OBJECT(this->hidden->gtkwindow),
+ "focus-in-event",
+ GTK_SIGNAL_FUNC(signal_focus_in), this);
+ gtk_signal_connect(GTK_OBJECT(this->hidden->gtkwindow),
+ "focus-out-event",
+ GTK_SIGNAL_FUNC(signal_focus_out), this);
+ gtk_signal_connect(GTK_OBJECT(this->hidden->gtkdrawingarea),
+ "motion-notify-event",
+ GTK_SIGNAL_FUNC(signal_motion_notify), this);
+ gtk_signal_connect(GTK_OBJECT(this->hidden->gtkdrawingarea),
+ "button-press-event",
+ GTK_SIGNAL_FUNC(signal_button_press), this);
+ gtk_signal_connect(GTK_OBJECT(this->hidden->gtkdrawingarea),
+ "button-release-event",
+ GTK_SIGNAL_FUNC(signal_button_release), this);
+ gtk_signal_connect(GTK_OBJECT(this->hidden->gtkdrawingarea),
+ "expose-event", GTK_SIGNAL_FUNC(signal_expose), this);
+ /* !!! FIXME: more to connect here. */
+}
+
+
+
+/* !!! FIXME: more to connect here. */
+#if 0
+ /* Key press? */
+ case KeyPress: {
+ static SDL_keysym saved_keysym;
+ SDL_keysym keysym;
+ KeyCode keycode = xevent.xkey.keycode;
+
+#ifdef DEBUG_XEVENTS
+printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
+#endif
+ /* Get the translated SDL virtual keysym */
+ if ( keycode ) {
+ keysym.scancode = keycode;
+ keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
+ keysym.mod = KMOD_NONE;
+ keysym.unicode = 0;
+ } else {
+ keysym = saved_keysym;
+ }
+
+ /* If we're not doing translation, we're done! */
+ if ( !SDL_TranslateUNICODE ) {
+ posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
+ break;
+ }
+
+ if ( XFilterEvent(&xevent, None) ) {
+ if ( xevent.xkey.keycode ) {
+ posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
+ } else {
+ /* Save event to be associated with IM text
+ In 1.3 we'll have a text event instead.. */
+ saved_keysym = keysym;
+ }
+ break;
+ }
+
+ /* Look up the translated value for the key event */
+#ifdef X_HAVE_UTF8_STRING
+ if ( SDL_IC != NULL ) {
+ static Status state;
+ /* A UTF-8 character can be at most 6 bytes */
+ char keybuf[6];
+ if ( Xutf8LookupString(SDL_IC, &xevent.xkey,
+ keybuf, sizeof(keybuf),
+ NULL, &state) ) {
+ keysym.unicode = Utf8ToUcs4((Uint8*)keybuf);
+ }
+ }
+ else
+#endif
+ {
+ static XComposeStatus state;
+ char keybuf[32];
+
+ if ( XLookupString(&xevent.xkey,
+ keybuf, sizeof(keybuf),
+ NULL, &state) ) {
+ /*
+ * FIXME: XLookupString() may yield more than one
+ * character, so we need a mechanism to allow for
+ * this (perhaps null keypress events with a
+ * unicode value)
+ */
+ keysym.unicode = (Uint8)keybuf[0];
+ }
+ }
+ posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
+ }
+ break;
+
+ /* Key release? */
+ case KeyRelease: {
+ SDL_keysym keysym;
+ KeyCode keycode = xevent.xkey.keycode;
+
+#ifdef DEBUG_XEVENTS
+printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
+#endif
+ /* Check to see if this is a repeated key */
+ if ( X11_KeyRepeat(SDL_Display, &xevent) ) {
+ break;
+ }
+
+ /* Get the translated SDL virtual keysym */
+ keysym.scancode = keycode;
+ keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
+ keysym.mod = KMOD_NONE;
+ keysym.unicode = 0;
+
+ posted = SDL_PrivateKeyboard(SDL_RELEASED, &keysym);
+ }
+ break;
+
+ /* Have we been iconified? */
+ case UnmapNotify: {
+#ifdef DEBUG_XEVENTS
+printf("UnmapNotify!\n");
+#endif
+ /* If we're active, make ourselves inactive */
+ if ( SDL_GetAppState() & SDL_APPACTIVE ) {
+ /* Swap out the gamma before we go inactive */
+ X11_SwapVidModeGamma(this);
+
+ /* Send an internal deactivate event */
+ posted = SDL_PrivateAppActive(0,
+ SDL_APPACTIVE|SDL_APPINPUTFOCUS);
+ }
+ }
+ break;
+
+ /* Have we been restored? */
+ case MapNotify: {
+#ifdef DEBUG_XEVENTS
+printf("MapNotify!\n");
+#endif
+ /* If we're not active, make ourselves active */
+ if ( !(SDL_GetAppState() & SDL_APPACTIVE) ) {
+ /* Send an internal activate event */
+ posted = SDL_PrivateAppActive(1, SDL_APPACTIVE);
+
+ /* Now that we're active, swap the gamma back */
+ X11_SwapVidModeGamma(this);
+ }
+
+ if ( SDL_VideoSurface &&
+ (SDL_VideoSurface->flags & SDL_FULLSCREEN) ) {
+ X11_EnterFullScreen(this);
+ } else {
+ X11_GrabInputNoLock(this, this->input_grab);
+ }
+ X11_CheckMouseModeNoLock(this);
+
+ if ( SDL_VideoSurface ) {
+ X11_RefreshDisplay(this);
+ }
+ }
+ break;
+
+ /* Have we been resized or moved? */
+ case ConfigureNotify: {
+#ifdef DEBUG_XEVENTS
+printf("ConfigureNotify! (resize: %dx%d)\n", xevent.xconfigure.width, xevent.xconfigure.height);
+#endif
+ if ( SDL_VideoSurface ) {
+ if ((xevent.xconfigure.width != SDL_VideoSurface->w) ||
+ (xevent.xconfigure.height != SDL_VideoSurface->h)) {
+ /* FIXME: Find a better fix for the bug with KDE 1.2 */
+ if ( ! ((xevent.xconfigure.width == 32) &&
+ (xevent.xconfigure.height == 32)) ) {
+ SDL_PrivateResize(xevent.xconfigure.width,
+ xevent.xconfigure.height);
+ }
+ } else {
+ /* OpenGL windows need to know about the change */
+ if ( SDL_VideoSurface->flags & SDL_OPENGL ) {
+ SDL_PrivateExpose();
+ }
+ }
+ }
+ }
+ break;
+
+ /* Have we been requested to quit (or another client message?) */
+ case ClientMessage: {
+ if ( (xevent.xclient.format == 32) &&
+ (xevent.xclient.data.l[0] == WM_DELETE_WINDOW) )
+ {
+ posted = SDL_PrivateQuit();
+ } else
+ if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
+ SDL_SysWMmsg wmmsg;
+
+ SDL_VERSION(&wmmsg.version);
+ wmmsg.subsystem = SDL_SYSWM_X11;
+ wmmsg.event.xevent = xevent;
+ posted = SDL_PrivateSysWMEvent(&wmmsg);
+ }
+ }
+ break;
+
+
+
+ default: {
+#ifdef DEBUG_XEVENTS
+printf("Unhandled event %d\n", xevent.type);
+#endif
+ /* Only post the event if we're watching for it */
+ if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
+ SDL_SysWMmsg wmmsg;
+
+ SDL_VERSION(&wmmsg.version);
+ wmmsg.subsystem = SDL_SYSWM_X11;
+ wmmsg.event.xevent = xevent;
+ posted = SDL_PrivateSysWMEvent(&wmmsg);
+ }
+ }
+ break;
+ }
+#endif
+
+
+
+void GTKPLUS_PumpEvents(_THIS)
+{
+ while (gtk_events_pending())
+ gtk_main_iteration();
+}
+
+void GTKPLUS_InitOSKeymap(_THIS)
+{
+ /* !!! FIXME */
+ /* do nothing. */
+}
+
+/* end of SDL_gtkevents.c ... */
+
diff --git a/src/video/gtk/SDL_gtkevents_c.h b/src/video/gtk/SDL_gtkevents_c.h
new file mode 100644
index 000000000..c458ee3e1
--- /dev/null
+++ b/src/video/gtk/SDL_gtkevents_c.h
@@ -0,0 +1,34 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2006 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#include "SDL_gtkvideo.h"
+
+/* Variables and functions exported by SDL_sysevents.c to other parts
+ of the native video subsystem (SDL_sysvideo.c)
+*/
+extern void GTKPLUS_InitOSKeymap(_THIS);
+extern void GTKPLUS_PumpEvents(_THIS);
+extern void GTKPLUS_ConnectSignals(_THIS);
+
+/* end of SDL_gtkevents_c.h ... */
+
diff --git a/src/video/gtk/SDL_gtkmouse.c b/src/video/gtk/SDL_gtkmouse.c
new file mode 100644
index 000000000..0d03e7189
--- /dev/null
+++ b/src/video/gtk/SDL_gtkmouse.c
@@ -0,0 +1,33 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2006 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#include "SDL_mouse.h"
+#include "../../events/SDL_events_c.h"
+
+#include "SDL_gtkmouse_c.h"
+
+
+/* The implementation dependent data for the window manager cursor */
+struct WMcursor {
+ int unused;
+};
diff --git a/src/video/gtk/SDL_gtkmouse_c.h b/src/video/gtk/SDL_gtkmouse_c.h
new file mode 100644
index 000000000..04fece674
--- /dev/null
+++ b/src/video/gtk/SDL_gtkmouse_c.h
@@ -0,0 +1,26 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2006 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#include "SDL_gtkvideo.h"
+
+/* Functions to be exported */
diff --git a/src/video/gtk/SDL_gtkvideo.c b/src/video/gtk/SDL_gtkvideo.c
new file mode 100644
index 000000000..bf32689bb
--- /dev/null
+++ b/src/video/gtk/SDL_gtkvideo.c
@@ -0,0 +1,643 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2006 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/*
+ * GTK+ SDL video driver implementation; this is a little like a pared-down
+ * version of the X11 driver. You almost certainly do NOT want this target
+ * on a desktop machine. This was written for the One Laptop Per Child
+ * project so they wouldn't need to use the SDL_WINDOWID hack with the X11
+ * driver and compete for the event queue.
+ *
+ * Initial work by Ryan C. Gordon (icculus@icculus.org). A good portion
+ * of this was cut-and-pasted from the dummy video target just to have a
+ * starting point for the bare minimum to fill in, and some was lifted from
+ * the x11 target.
+ */
+
+#include "SDL_video.h"
+#include "SDL_mouse.h"
+#include "../SDL_sysvideo.h"
+#include "../SDL_pixels_c.h"
+#include "../../events/SDL_events_c.h"
+
+#include "SDL_gtkvideo.h"
+#include "SDL_gtkevents_c.h"
+#include "SDL_gtkmouse_c.h"
+
+#define GTKPLUSVID_DRIVER_NAME "gtk"
+
+/* Initialization/Query functions */
+static int GTKPLUS_VideoInit(_THIS, SDL_PixelFormat *vformat);
+static SDL_Rect **GTKPLUS_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
+static SDL_Surface *GTKPLUS_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
+static int GTKPLUS_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
+static void GTKPLUS_VideoQuit(_THIS);
+
+/* Hardware surface functions */
+static int GTKPLUS_AllocHWSurface(_THIS, SDL_Surface *surface);
+static int GTKPLUS_LockHWSurface(_THIS, SDL_Surface *surface);
+static void GTKPLUS_UnlockHWSurface(_THIS, SDL_Surface *surface);
+static void GTKPLUS_FreeHWSurface(_THIS, SDL_Surface *surface);
+static void GTKPLUS_SetCaption(_THIS, const char *title, const char *icon);
+
+/* etc. */
+static void GTKPLUS_UpdateRects(_THIS, int numrects, SDL_Rect *rects);
+
+/* GTKPLUS driver bootstrap functions */
+
+static int do_gtk_init(void)
+{
+ static int initted = 0;
+ if (!initted) { /* !!! FIXME: I can't see a way to deinit gtk... */
+ int tmpargc = 0;
+ char *args[] = { NULL, NULL };
+ char **tmpargv = args;
+ initted = (gtk_init_check(&tmpargc, &tmpargv));
+ }
+ return initted;
+}
+
+
+static int GTKPLUS_Available(void)
+{
+ return 1; /* !!! FIXME */
+}
+
+static void GTKPLUS_DeleteDevice(SDL_VideoDevice *device)
+{
+ SDL_free(device->hidden);
+ SDL_free(device);
+}
+
+static SDL_VideoDevice *GTKPLUS_CreateDevice(int devindex)
+{
+ SDL_VideoDevice *device;
+
+ /* Initialize all variables that we clean on shutdown */
+ device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
+ if ( device ) {
+ SDL_memset(device, 0, (sizeof *device));
+ device->hidden = (struct SDL_PrivateVideoData *)
+ SDL_malloc((sizeof *device->hidden));
+ }
+ if ( (device == NULL) || (device->hidden == NULL) ) {
+ SDL_OutOfMemory();
+ if ( device ) {
+ SDL_free(device);
+ }
+ return(0);
+ }
+ SDL_memset(device->hidden, 0, (sizeof *device->hidden));
+
+ device->handles_any_size = 1;
+
+ /* Set the function pointers */
+ device->VideoInit = GTKPLUS_VideoInit;
+ device->ListModes = GTKPLUS_ListModes;
+ device->SetVideoMode = GTKPLUS_SetVideoMode;
+ device->CreateYUVOverlay = NULL;
+ device->SetColors = GTKPLUS_SetColors;
+ device->UpdateRects = GTKPLUS_UpdateRects;
+ device->VideoQuit = GTKPLUS_VideoQuit;
+ device->AllocHWSurface = GTKPLUS_AllocHWSurface;
+ device->CheckHWBlit = NULL;
+ device->FillHWRect = NULL;
+ device->SetHWColorKey = NULL;
+ device->SetHWAlpha = NULL;
+ device->LockHWSurface = GTKPLUS_LockHWSurface;
+ device->UnlockHWSurface = GTKPLUS_UnlockHWSurface;
+ device->FlipHWSurface = NULL;
+ device->FreeHWSurface = GTKPLUS_FreeHWSurface;
+ device->SetCaption = GTKPLUS_SetCaption;
+ device->SetIcon = NULL;
+ device->IconifyWindow = NULL;
+ device->GrabInput = NULL;
+ device->GetWMInfo = NULL;
+ device->InitOSKeymap = GTKPLUS_InitOSKeymap;
+ device->PumpEvents = GTKPLUS_PumpEvents;
+
+ device->free = GTKPLUS_DeleteDevice;
+
+ return device;
+}
+
+VideoBootStrap GTKPLUS_bootstrap = {
+ GTKPLUSVID_DRIVER_NAME, "SDL GTK+ video driver",
+ GTKPLUS_Available, GTKPLUS_CreateDevice
+};
+
+
+static int add_visual(_THIS, int depth, GdkVisualType vistype)
+{
+ GdkVisual *vi = gdk_visual_get_best_with_both(depth, vistype);
+ if(vi != NULL) {
+ g_object_ref(vi);
+ this->hidden->visuals[this->hidden->nvisuals++] = vi;
+ }
+ return(this->hidden->nvisuals);
+}
+
+static int GTKPLUS_GetVideoModes(_THIS)
+{
+ const gint screen_w = gdk_screen_width();
+ const gint screen_h = gdk_screen_height();
+ int i, n;
+
+ {
+ /* It's interesting to note that if we allow 32 bit depths (on X11),
+ we get a visual with an alpha mask on composite servers.
+ static int depth_list[] = { 32, 24, 16, 15, 8 };
+ */
+ static int depth_list[] = { 24, 16, 15, 8 };
+ int use_directcolor = 1;
+
+ /* Search for the visuals in deepest-first order, so that the first
+ will be the richest one */
+ if ( SDL_getenv("SDL_VIDEO_GTK_NODIRECTCOLOR") ) {
+ use_directcolor = 0;
+ }
+ this->hidden->nvisuals = 0;
+ for ( i=0; i<SDL_arraysize(depth_list); ++i ) {
+ if ( depth_list[i] > 8 ) {
+ if ( use_directcolor ) {
+ add_visual(this, depth_list[i], GDK_VISUAL_DIRECT_COLOR);
+ }
+ add_visual(this, depth_list[i], GDK_VISUAL_TRUE_COLOR);
+ } else {
+ add_visual(this, depth_list[i], GDK_VISUAL_PSEUDO_COLOR);
+ add_visual(this, depth_list[i], GDK_VISUAL_STATIC_COLOR);
+ }
+ }
+ if ( this->hidden->nvisuals == 0 ) {
+ SDL_SetError("Found no sufficiently capable GTK+ visuals");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+int GTKPLUS_VideoInit(_THIS, SDL_PixelFormat *vformat)
+{
+ GdkVisual *sysvis = NULL;
+ int i;
+
+ if (!do_gtk_init()) {
+ return -1;
+ }
+
+ /* Get the available video modes */
+ if(GTKPLUS_GetVideoModes(this) < 0)
+ return -1;
+
+ /* Determine the current screen size */
+ this->info.current_w = gdk_screen_width();
+ this->info.current_h = gdk_screen_height();
+
+ /* Determine the default screen depth:
+ Use the default visual (or at least one with the same depth) */
+ this->hidden->display_colormap = gdk_colormap_get_system(); /* !!! FIXME: refcount? */
+ sysvis = gdk_visual_get_system(); /* !!! FIXME: refcount? */
+
+ for(i = 0; i < this->hidden->nvisuals; i++) {
+ if(this->hidden->visuals[i]->depth == sysvis->depth)
+ break;
+ }
+
+ if(i == this->hidden->nvisuals) {
+ /* default visual was useless, take the deepest one instead */
+ i = 0;
+ }
+
+ this->hidden->visual = this->hidden->visuals[i];
+ if ( this->hidden->visual == sysvis ) { /* !!! FIXME: same pointer? */
+ this->hidden->colormap = this->hidden->display_colormap;
+ g_object_ref(this->hidden->colormap);
+ } else {
+ this->hidden->colormap = gdk_colormap_new(this->hidden->visual, FALSE);
+ }
+
+ // !!! FIXME: this is not a public GDK symbol!!
+ vformat->BitsPerPixel = _gdk_windowing_get_bits_for_depth(
+ gdk_display_get_default(),
+ this->hidden->visuals[i]->depth);
+ this->hidden->depth = vformat->BitsPerPixel;
+
+ if ( vformat->BitsPerPixel > 8 ) {
+ vformat->Rmask = this->hidden->visual->red_mask;
+ vformat->Gmask = this->hidden->visual->green_mask;
+ vformat->Bmask = this->hidden->visual->blue_mask;
+ }
+ if ( this->hidden->depth == 32 ) {
+ vformat->Amask = (0xFFFFFFFF & ~(vformat->Rmask|vformat->Gmask|vformat->Bmask));
+ }
+
+#if 0
+ /* Create the fullscreen and managed windows */
+ create_aux_windows(this);
+
+ /* Create the blank cursor */
+ SDL_BlankCursor = this->CreateWMCursor(this, blank_cdata, blank_cmask,
+ BLANK_CWIDTH, BLANK_CHEIGHT,
+ BLANK_CHOTX, BLANK_CHOTY);
+
+ /* Allow environment override of screensaver disable. */
+ env = SDL_getenv("SDL_VIDEO_ALLOW_SCREENSAVER");
+ this->hidden->allow_screensaver = ( (env && SDL_atoi(env)) ? 1 : 0 );
+#endif
+
+ /* We're done! */
+ gdk_flush(); /* just in case. */
+
+ /* Fill in some window manager capabilities */
+ this->info.wm_available = 1;
+
+ return(0);
+}
+
+
+static GdkVisual *find_visual(_THIS, int bpp)
+{
+ GdkDisplay *display = gdk_display_get_default();
+ int i;
+ for ( i = 0; i < this->hidden->nvisuals; i++ ) {
+ const int videpth = this->hidden->visuals[i]->depth;
+ // !!! FIXME: this is not a public GDK symbol!!
+ const int depth = _gdk_windowing_get_bits_for_depth(display, videpth);
+ if ( depth == bpp )
+ break;
+ }
+
+ if ( i == this->hidden->nvisuals ) {
+ SDL_SetError("No matching visual for requested depth");
+ return NULL; /* should never happen */
+ }
+ return this->hidden->visuals[i];
+}
+
+
+SDL_Rect **GTKPLUS_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
+{
+ if ((flags & SDL_OPENGL) == 0) {
+ if (find_visual(this, format->BitsPerPixel) != NULL) {
+ return (SDL_Rect **) -1; /* !!! FIXME: maybe not right. */
+ }
+ }
+ return NULL; /* unsupported. */
+}
+
+
+SDL_Surface *GTKPLUS_SetVideoMode(_THIS, SDL_Surface *current,
+ int width, int height, int bpp, Uint32 flags)
+{
+ Uint32 Amask = 0;
+ int vis_change = 0;
+ GtkWindow *win = NULL;
+ GdkImage *img = NULL;
+ GdkVisual *sysvis = gdk_visual_get_system(); /* !!! FIXME: refcount? */
+ GdkVisual *vis = find_visual(this, bpp);
+ if (vis == NULL) {
+ return(NULL);
+ }
+
+ if (flags & SDL_OPENGL) {
+ SDL_SetError("No OpenGL support in the GTK+ target");
+ return(NULL);
+ }
+
+ /* These are the only flags we allow here... */
+ flags &= /*SDL_FULLSCREEN |*/ SDL_RESIZABLE | SDL_NOFRAME | SDL_HWPALETTE;
+
+ vis_change = (vis != this->hidden->visual);
+ this->hidden->visual = vis;
+ this->hidden->depth = vis->depth;
+
+ /* Allocate the new pixel format for this video mode */
+ if ( this->hidden->depth == 32 ) {
+ Amask = (0xFFFFFFFF & ~(vis->red_mask|vis->green_mask|vis->blue_mask));
+ } else {
+ Amask = 0;
+ }
+ if ( ! SDL_ReallocFormat(current, bpp,
+ vis->red_mask, vis->green_mask, vis->blue_mask, Amask) ) {
+ return NULL;
+ }
+
+ /* Create the appropriate colormap */
+ g_object_unref(this->hidden->colormap);
+ this->hidden->colormap = NULL;
+
+ if ( this->hidden->visual->type == GDK_VISUAL_PSEUDO_COLOR ) {
+ int ncolors;
+
+ /* Allocate the pixel flags */
+ ncolors = this->hidden->visual->colormap_size;
+
+ #if 0
+ SDL_XPixels = SDL_malloc(ncolors * sizeof(int));
+ if(SDL_XPixels == NULL) {
+ SDL_OutOfMemory();
+ return -1;
+ }
+ SDL_memset(SDL_XPixels, 0, ncolors * sizeof(*SDL_XPixels));
+ #endif
+
+ /* always allocate a private colormap on non-default visuals */
+ if ( this->hidden->visual != sysvis ) {
+ flags |= SDL_HWPALETTE;
+ }
+ if ( flags & SDL_HWPALETTE ) {
+ current->flags |= SDL_HWPALETTE;
+ this->hidden->colormap = gdk_colormap_new(this->hidden->visual, TRUE);
+ } else {
+ this->hidden->colormap = this->hidden->display_colormap;
+ g_object_ref(this->hidden->colormap);
+ }
+ } else if ( this->hidden->visual->type == GDK_VISUAL_DIRECT_COLOR ) {
+
+ /* Create a colormap which we can manipulate for gamma */
+ this->hidden->colormap = gdk_colormap_new(this->hidden->visual, TRUE);
+ gdk_flush();
+
+ /* Initialize the colormap to the identity mapping */
+ SDL_GetGammaRamp(0, 0, 0);
+ this->screen = current;
+#if 0 // !!! FIXME
+ GTKPLUS_SetGammaRamp(this, this->gamma);
+#endif
+ this->screen = NULL;
+ } else {
+ /* Create a read-only colormap for our window */
+ this->hidden->colormap = gdk_colormap_new(this->hidden->visual, FALSE);
+ }
+
+#if 0 // !!! FIXME
+ /* Recreate the auxiliary windows, if needed (required for GL) */
+ if ( vis_change )
+ create_aux_windows(this);
+
+ if(current->flags & SDL_HWPALETTE) {
+ /* Since the full-screen window might have got a nonzero background
+ colour (0 is white on some displays), we should reset the
+ background to 0 here since that is what the user expects
+ with a private colormap */
+ XSetWindowBackground(SDL_Display, FSwindow, 0);
+ XClearWindow(SDL_Display, FSwindow);
+ }
+
+ /* resize the (possibly new) window manager window */
+ if( !SDL_windowid ) {
+ X11_SetSizeHints(this, w, h, flags);
+ window_w = w;
+ window_h = h;
+ XResizeWindow(SDL_Display, WMwindow, w, h);
+ }
+#endif
+
+ if ( this->hidden->gdkimage ) {
+ g_object_unref(this->hidden->gdkimage);
+ this->hidden->gdkimage = NULL;
+ }
+
+ img = this->hidden->gdkimage = gdk_image_new(GDK_IMAGE_FASTEST,
+ vis, width, height);
+ if (img == NULL) {
+ SDL_SetError("Couldn't allocate buffer for requested mode");
+ return(NULL);
+ }
+ gdk_image_set_colormap(this->hidden->gdkimage, this->hidden->colormap);
+
+ SDL_memset(img->mem, 0, height * img->bpl);
+
+ if ( this->hidden->gtkwindow == NULL ) {
+ this->hidden->gtkdrawingarea = gtk_drawing_area_new();
+ if ( this->hidden->gtkdrawingarea == NULL ) {
+ SDL_SetError("Couldn't create drawing area for requested mode");
+ g_object_unref(this->hidden->gdkimage);
+ this->hidden->gdkimage = NULL;
+ return(NULL);
+ }
+
+ this->hidden->gtkwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ if ( this->hidden->gtkwindow == NULL ) {
+ SDL_SetError("Couldn't create window for requested mode");
+ g_object_unref(this->hidden->gdkimage);
+ g_object_unref(this->hidden->gtkdrawingarea);
+ this->hidden->gdkimage = NULL;
+ this->hidden->gtkdrawingarea = NULL;
+ return(NULL);
+ }
+
+ gtk_window_set_title(GTK_WINDOW(this->hidden->gtkwindow), "");
+ gtk_widget_set_app_paintable(this->hidden->gtkwindow, TRUE);
+ gtk_widget_set_app_paintable(this->hidden->gtkdrawingarea, TRUE);
+ gtk_widget_set_double_buffered(this->hidden->gtkwindow, FALSE);
+ gtk_widget_set_double_buffered(this->hidden->gtkdrawingarea, FALSE);
+
+ GTKPLUS_ConnectSignals(this);
+
+ gtk_container_add(GTK_CONTAINER(this->hidden->gtkwindow),
+ this->hidden->gtkdrawingarea);
+ }
+
+ win = GTK_WINDOW(this->hidden->gtkwindow);
+ gtk_widget_set_colormap(this->hidden->gtkdrawingarea, this->hidden->colormap);
+
+// !!! FIXME
+#if 0
+ /* Cache the window in the server, when possible */
+ {
+ Screen *xscreen;
+ XSetWindowAttributes a;
+
+ xscreen = ScreenOfDisplay(SDL_Display, SDL_Screen);
+ a.backing_store = DoesBackingStore(xscreen);
+ if ( a.backing_store != NotUseful ) {
+ XChangeWindowAttributes(SDL_Display, SDL_Window,
+ CWBackingStore, &a);
+ }
+ }
+
+ /* Update the internal keyboard state */
+ X11_SetKeyboardState(SDL_Display, NULL);
+
+ /* When the window is first mapped, ignore non-modifier keys */
+ {
+ Uint8 *keys = SDL_GetKeyState(NULL);
+ for ( i = 0; i < SDLK_LAST; ++i ) {
+ switch (i) {
+ case SDLK_NUMLOCK:
+ case SDLK_CAPSLOCK:
+ case SDLK_LCTRL:
+ case SDLK_RCTRL:
+ case SDLK_LSHIFT:
+ case SDLK_RSHIFT:
+ case SDLK_LALT:
+ case SDLK_RALT:
+ case SDLK_LMETA:
+ case SDLK_RMETA:
+ case SDLK_MODE:
+ break;
+ default:
+ keys[i] = SDL_RELEASED;
+ break;
+ }
+ }
+ }
+
+ /* Map them both and go fullscreen, if requested */
+ if ( ! SDL_windowid ) {
+ XMapWindow(SDL_Display, SDL_Window);
+ XMapWindow(SDL_Display, WMwindow);
+ X11_WaitMapped(this, WMwindow);
+ if ( flags & SDL_FULLSCREEN ) {
+ current->flags |= SDL_FULLSCREEN;
+ X11_EnterFullScreen(this);
+ } else {
+ current->flags &= ~SDL_FULLSCREEN;
+ }
+ }
+#endif
+
+ if ((flags & SDL_FULLSCREEN) == 0) {
+ gtk_window_unfullscreen(win);
+ } else {
+ gtk_window_fullscreen(win);
+ flags &= ~SDL_RESIZABLE;
+ flags |= SDL_NOFRAME;
+ }
+
+ gtk_window_set_resizable(win, (flags & SDL_RESIZABLE) ? TRUE : FALSE);
+ gtk_window_set_decorated(win, (flags & SDL_NOFRAME) ? FALSE : TRUE);
+ gtk_window_resize(win, width, height);
+ gtk_widget_set_size_request(this->hidden->gtkdrawingarea, width, height);
+ gtk_widget_show(this->hidden->gtkdrawingarea);
+ gtk_widget_show(this->hidden->gtkwindow);
+
+ /* Set up the new mode framebuffer */
+ current->w = width;
+ current->h = height;
+ //current->format->depth = vis->bits_per_rgb;
+ current->flags = flags | SDL_PREALLOC;
+ current->pitch = img->bpl;
+ current->pixels = this->hidden->gdkimage->mem;
+
+ /* We're done */
+ return(current);
+}
+
+static void GTKPLUS_SetCaption(_THIS, const char *title, const char *icon)
+{
+ gtk_window_set_title(GTK_WINDOW(this->hidden->gtkwindow),
+ (const gchar *) title);
+}
+
+/* We don't actually allow hardware surfaces. */
+static int GTKPLUS_AllocHWSurface(_THIS, SDL_Surface *surface)
+{
+ return(-1);
+}
+
+static void GTKPLUS_FreeHWSurface(_THIS, SDL_Surface *surface)
+{
+}
+
+/* We need to wait for vertical retrace on page flipped displays */
+static int GTKPLUS_LockHWSurface(_THIS, SDL_Surface *surface)
+{
+ return(0);
+}
+
+static void GTKPLUS_UnlockHWSurface(_THIS, SDL_Surface *surface)
+{
+}
+
+static void GTKPLUS_UpdateRects(_THIS, int numrects, SDL_Rect *rects)
+{
+ if ( (this->hidden->gtkdrawingarea != NULL) &&
+ (GTK_WIDGET_DRAWABLE(this->hidden->gtkdrawingarea)) &&
+ (numrects > 0) ) {
+ GdkDrawable *draw = GDK_DRAWABLE(this->hidden->gtkdrawingarea->window);
+ if (this->hidden->gc == NULL) {
+ this->hidden->gc = gdk_gc_new(draw);
+ }
+
+ if (this->hidden->gc != NULL) {
+ GdkImage *img = this->hidden->gdkimage;
+ const SDL_Rect *r = rects;
+ int i;
+ for (i = 0; i < numrects; i++, r++) {
+ const gint x = r->x;
+ const gint y = r->y;
+ gdk_draw_image(draw, this->hidden->gc, img,
+ x, y, x, y, r->w, r->h);
+ }
+ gdk_flush(); /* transfer the GdkImage so we can make changes. */
+ }
+ }
+}
+
+int GTKPLUS_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
+{
+ /* !!! FIXME */
+ return(0);
+}
+
+/* Note: If we are terminated, this could be called in the middle of
+ another SDL video routine -- notably UpdateRects.
+*/
+void GTKPLUS_VideoQuit(_THIS)
+{
+ int i;
+
+ gdk_flush();
+
+ if (this->hidden->gc != NULL) {
+ g_object_unref(this->hidden->gc);
+ this->hidden->gc = NULL;
+ }
+
+ if ( this->hidden->gtkwindow ) {
+ /* this deletes the drawing area widget, too. */
+ gtk_widget_destroy(this->hidden->gtkwindow);
+ this->hidden->gtkwindow = NULL;
+ }
+
+ if ( this->hidden->gdkimage ) {
+ g_object_unref(this->hidden->gdkimage);
+ this->hidden->gdkimage = NULL;
+ }
+
+ for (i = 0; i < this->hidden->nvisuals; i++) {
+ g_object_unref(this->hidden->visuals[i]);
+ this->hidden->visuals[i] = NULL;
+ }
+ this->hidden->nvisuals = 0;
+
+ g_object_unref(this->hidden->colormap);
+ this->hidden->colormap = NULL;
+
+ gdk_flush();
+}
+
diff --git a/src/video/gtk/SDL_gtkvideo.h b/src/video/gtk/SDL_gtkvideo.h
new file mode 100644
index 000000000..06a6b3410
--- /dev/null
+++ b/src/video/gtk/SDL_gtkvideo.h
@@ -0,0 +1,51 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2006 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_gtkvideo_h
+#define _SDL_gtkvideo_h
+
+#include "../SDL_sysvideo.h"
+
+#include <gtk/gtk.h>
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS SDL_VideoDevice *this
+#define SET_THIS_POINTER(x) SDL_VideoDevice *this = (SDL_VideoDevice *) x
+
+
+/* Private display data */
+
+struct SDL_PrivateVideoData {
+ GdkImage *gdkimage;
+ GtkWidget *gtkwindow;
+ GtkWidget *gtkdrawingarea;
+ GdkVisual *visuals[2*5]; /* at most 2 entries for 8, 15, 16, 24, 32 */
+ GdkVisual *visual;
+ GdkColormap *colormap;
+ GdkColormap *display_colormap;
+ GdkGC *gc;
+ int nvisuals;
+ int depth;
+};
+
+#endif /* _SDL_gtkvideo_h */