From d74afdb47beebb7b1d3e88621208ed0206a8350f Mon Sep 17 00:00:00 2001 From: "Pierre-Loup A. Griffais" Date: Thu, 11 Sep 2014 19:24:42 -0700 Subject: [PATCH 01/68] [X11] Reconcile logical keyboard state with physical state on FocusIn since the window system doesn't do it for us like other platforms. This prevents sticky keys and missed keys when going in and out of focus, for example Alt would appear to stick if switching away from an SDL app with Alt-Tab and had to be pressed again. CR: Sam --- src/video/x11/SDL_x11events.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index c67fc38e3..b4b33d76a 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -507,6 +507,27 @@ ProcessHitTest(_THIS, const SDL_WindowData *data, const XEvent *xev) return ret; } +static void +ReconcileKeyboardState(_THIS, const SDL_WindowData *data) +{ + SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; + SDL_Window* window = data->window; + Display *display = viddata->display; + char keys[32]; + int keycode = 0; + + X11_XQueryKeymap( display, keys ); + + while ( keycode < 256 ) { + if ( keys[keycode / 8] & (1 << (keycode % 8)) ) { + SDL_SendKeyboardKey(SDL_PRESSED, viddata->key_layout[keycode]); + } else { + SDL_SendKeyboardKey(SDL_RELEASED, viddata->key_layout[keycode]); + } + keycode++; + } +} + static void X11_DispatchEvent(_THIS) { @@ -655,16 +676,7 @@ X11_DispatchEvent(_THIS) #endif if (data->pending_focus == PENDING_FOCUS_OUT && data->window == SDL_GetKeyboardFocus()) { - /* We want to reset the keyboard here, because we may have - missed keyboard messages after our previous FocusOut. - */ - /* Actually, if we do this we clear the ALT key on Unity - because it briefly takes focus for their dashboard. - - I think it's better to think the ALT key is held down - when it's not, then always lose the ALT modifier on Unity. - */ - /* SDL_ResetKeyboard(); */ + ReconcileKeyboardState(_this, data); } data->pending_focus = PENDING_FOCUS_IN; data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_IN_TIME; From f464f677f25978083028add1d129e4485f1ac758 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 12 Sep 2014 15:09:33 -0700 Subject: [PATCH 02/68] Fixed using uninitialized display data in iMX6 initialization --- src/video/mx6/SDL_mx6opengles.c | 26 +++++++++++--------------- src/video/mx6/SDL_mx6video.c | 20 ++++++++++---------- src/video/mx6/SDL_mx6video.h | 1 - 3 files changed, 21 insertions(+), 26 deletions(-) diff --git a/src/video/mx6/SDL_mx6opengles.c b/src/video/mx6/SDL_mx6opengles.c index 375a14a58..1e513751d 100644 --- a/src/video/mx6/SDL_mx6opengles.c +++ b/src/video/mx6/SDL_mx6opengles.c @@ -48,12 +48,12 @@ if (!egl_viv_data->NAME) \ /* EGL implementation of SDL OpenGL support */ int -MX6_GLES_LoadLibrary(_THIS, const char *egl_path) { +MX6_GLES_LoadLibrary(_THIS, const char *egl_path) +{ /* The definitions of egl_dll_handle and dll_handle were interchanged for some reason. Just left them as is for compatibility */ void *dll_handle = NULL, *egl_dll_handle = NULL; char *path = NULL; - SDL_DisplayData *displaydata; if (_this->egl_data) { return SDL_SetError("OpenGL ES context already created"); @@ -75,7 +75,7 @@ MX6_GLES_LoadLibrary(_THIS, const char *egl_path) { } if (egl_dll_handle == NULL) { - if(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) { + if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) { if (_this->gl_config.major_version > 1) { path = DEFAULT_OGL_ES2; egl_dll_handle = SDL_LoadObject(path); @@ -84,11 +84,11 @@ MX6_GLES_LoadLibrary(_THIS, const char *egl_path) { path = DEFAULT_OGL_ES; egl_dll_handle = SDL_LoadObject(path); } - } + } else { path = DEFAULT_OGL; egl_dll_handle = SDL_LoadObject(path); - } + } } _this->egl_data->egl_dll_handle = egl_dll_handle; @@ -98,8 +98,8 @@ MX6_GLES_LoadLibrary(_THIS, const char *egl_path) { if (egl_path != NULL) { dll_handle = SDL_LoadObject(egl_path); - } - + } + if (SDL_LoadFunction(dll_handle, "eglChooseConfig") == NULL) { if (dll_handle != NULL) { SDL_UnloadObject(dll_handle); @@ -148,20 +148,16 @@ MX6_GLES_LoadLibrary(_THIS, const char *egl_path) { LOAD_VIV_FUNC(fbGetPixmapGeometry); LOAD_VIV_FUNC(fbGetPixmapInfo); LOAD_VIV_FUNC(fbDestroyPixmap); - - displaydata = SDL_GetDisplayDriverData(0); - _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(displaydata->native_display); + _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(egl_viv_data->fbGetDisplayByIndex(0)); if (!_this->egl_data->egl_display) { return SDL_SetError("Could not get EGL display"); } - + if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) { return SDL_SetError("Could not initialize EGL"); } - displaydata->egl_display = _this->egl_data->egl_display; - _this->gl_config.driver_loaded = 1; if (path) { @@ -169,7 +165,7 @@ MX6_GLES_LoadLibrary(_THIS, const char *egl_path) { } else { *_this->gl_config.driver_path = '\0'; } - + return 0; } @@ -190,7 +186,7 @@ MX6_GLES_UnloadLibrary(_THIS) SDL_UnloadObject(_this->egl_data->egl_dll_handle); _this->egl_data->egl_dll_handle = NULL; } - + SDL_free(_this->egl_data); _this->egl_data = NULL; diff --git a/src/video/mx6/SDL_mx6video.c b/src/video/mx6/SDL_mx6video.c index 2f9c04f2a..d449ef636 100644 --- a/src/video/mx6/SDL_mx6video.c +++ b/src/video/mx6/SDL_mx6video.c @@ -163,7 +163,7 @@ MX6_VideoInit(_THIS) SDL_VideoDisplay display; SDL_DisplayMode current_mode; SDL_DisplayData *data; - + data = (SDL_DisplayData *) SDL_calloc(1, sizeof(SDL_DisplayData)); if (data == NULL) { return SDL_OutOfMemory(); @@ -181,9 +181,9 @@ MX6_VideoInit(_THIS) } MX6_UpdateDisplay(_this); -#ifdef SDL_INPUT_LINUXEV +#ifdef SDL_INPUT_LINUXEV SDL_EVDEV_Init(); -#endif +#endif return 1; } @@ -191,9 +191,9 @@ MX6_VideoInit(_THIS) void MX6_VideoQuit(_THIS) { -#ifdef SDL_INPUT_LINUXEV +#ifdef SDL_INPUT_LINUXEV SDL_EVDEV_Quit(); -#endif +#endif } void @@ -214,9 +214,9 @@ MX6_CreateWindow(_THIS, SDL_Window * window) { SDL_DisplayData *displaydata; SDL_WindowData *wdata; - + displaydata = SDL_GetDisplayDriverData(0); - + /* Allocate window internal data */ wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData)); if (wdata == NULL) { @@ -226,12 +226,12 @@ MX6_CreateWindow(_THIS, SDL_Window * window) /* Setup driver data for this window */ window->driverdata = wdata; window->flags |= SDL_WINDOW_OPENGL; - + if (!_this->egl_data) { return -1; } - wdata->native_window = egl_viv_data->fbCreateWindow(displaydata->native_display, window->x, window->y, window->w, window->h); + wdata->native_window = egl_viv_data->fbCreateWindow(displaydata->native_display, window->x, window->y, window->w, window->h); if (!wdata->native_window) { return SDL_SetError("MX6: Can't create native window"); } @@ -249,7 +249,7 @@ void MX6_DestroyWindow(_THIS, SDL_Window * window) { SDL_WindowData *wdata; - + wdata = window->driverdata; if (wdata) { SDL_EGL_DestroySurface(_this, wdata->egl_surface); diff --git a/src/video/mx6/SDL_mx6video.h b/src/video/mx6/SDL_mx6video.h index 7827337f8..9dcae5a33 100644 --- a/src/video/mx6/SDL_mx6video.h +++ b/src/video/mx6/SDL_mx6video.h @@ -34,7 +34,6 @@ typedef struct SDL_VideoData typedef struct SDL_DisplayData { EGLNativeDisplayType native_display; - EGLDisplay egl_display; } SDL_DisplayData; typedef struct SDL_WindowData From 56f86cc81f97563fb7f5e962ba94c0e883e13860 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sat, 13 Sep 2014 02:15:18 -0700 Subject: [PATCH 03/68] Fixed bug 2415 - Message Boxes aren't implemented on Android Philipp Wiesemann I attached a patch for an incomplete implementation of the messagebox parts. It was not tested on lots of devices yet and features a very fragile workaround to block the calling SDL thread while the dialog is handled on Android's UI thread. Although it works for testmessage.c I assume there are lot of situations were it may fail (standby, device rotation and other changes). Also not all flags and colors are implemented. On the other hand most uses of the messagebox are to show an error on start and fragility (or working at all) may not matter there. --- .../src/org/libsdl/app/SDLActivity.java | 197 ++++++++++++++++++ src/core/android/SDL_android.c | 79 +++++++ src/video/SDL_video.c | 9 + src/video/android/SDL_androidmessagebox.c | 37 ++++ src/video/android/SDL_androidmessagebox.h | 29 +++ 5 files changed, 351 insertions(+) create mode 100644 src/video/android/SDL_androidmessagebox.c create mode 100644 src/video/android/SDL_androidmessagebox.h diff --git a/android-project/src/org/libsdl/app/SDLActivity.java b/android-project/src/org/libsdl/app/SDLActivity.java index d3b22647a..bfbbed528 100644 --- a/android-project/src/org/libsdl/app/SDLActivity.java +++ b/android-project/src/org/libsdl/app/SDLActivity.java @@ -17,8 +17,12 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.widget.AbsoluteLayout; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.TextView; import android.os.*; import android.util.Log; +import android.util.SparseArray; import android.graphics.*; import android.media.*; import android.hardware.*; @@ -583,6 +587,199 @@ public class SDLActivity extends Activity { return fileStream; } + + // Messagebox + + /** Result of current messagebox. Also used for blocking the calling thread. */ + protected final int[] messageboxSelection = new int[1]; + + /** Id of current dialog. */ + protected int dialogs = 0; + + /** + * This method is called by SDL using JNI. + * Shows the messagebox from UI thread and block calling thread. + * buttonFlags, buttonIds and buttonTexts must have same length. + * @param buttonFlags array containing flags for every button. + * @param buttonIds array containing id for every button. + * @param buttonTexts array containing text for every button. + * @param colors null for default or array of length 5 containing colors. + * @return button id or -1. + */ + public int messageboxShowMessageBox( + final int flags, + final String title, + final String message, + final int[] buttonFlags, + final int[] buttonIds, + final String[] buttonTexts, + final int[] colors) { + + messageboxSelection[0] = -1; + + // sanity checks + + if ((buttonFlags.length != buttonIds.length) && (buttonIds.length != buttonTexts.length)) { + return -1; // implementation broken + } + + // collect arguments for Dialog + + final Bundle args = new Bundle(); + args.putInt("flags", flags); + args.putString("title", title); + args.putString("message", message); + args.putIntArray("buttonFlags", buttonFlags); + args.putIntArray("buttonIds", buttonIds); + args.putStringArray("buttonTexts", buttonTexts); + args.putIntArray("colors", colors); + + // trigger Dialog creation on UI thread + + runOnUiThread(new Runnable() { + @Override + public void run() { + showDialog(dialogs++, args); + } + }); + + // block the calling thread + + synchronized (messageboxSelection) { + try { + messageboxSelection.wait(); + } catch (InterruptedException ex) { + ex.printStackTrace(); + return -1; + } + } + + // return selected value + + return messageboxSelection[0]; + } + + @Override + protected Dialog onCreateDialog(int ignore, Bundle args) { + + // TODO set values from "flags" to messagebox dialog + + // get colors + + int[] colors = args.getIntArray("colors"); + int backgroundColor; + int textColor; + int buttonBorderColor; + int buttonBackgroundColor; + int buttonSelectedColor; + if (colors != null) { + int i = -1; + backgroundColor = colors[++i]; + textColor = colors[++i]; + buttonBorderColor = colors[++i]; + buttonBackgroundColor = colors[++i]; + buttonSelectedColor = colors[++i]; + } else { + backgroundColor = Color.TRANSPARENT; + textColor = Color.TRANSPARENT; + buttonBorderColor = Color.TRANSPARENT; + buttonBackgroundColor = Color.TRANSPARENT; + buttonSelectedColor = Color.TRANSPARENT; + } + + // create dialog with title and a listener to wake up calling thread + + final Dialog dialog = new Dialog(this); + dialog.setTitle(args.getString("title")); + dialog.setCancelable(false); + dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface unused) { + synchronized (messageboxSelection) { + messageboxSelection.notify(); + } + } + }); + + // create text + + TextView message = new TextView(this); + message.setGravity(Gravity.CENTER); + message.setText(args.getString("message")); + if (textColor != Color.TRANSPARENT) { + message.setTextColor(textColor); + } + + // create buttons + + int[] buttonFlags = args.getIntArray("buttonFlags"); + int[] buttonIds = args.getIntArray("buttonIds"); + String[] buttonTexts = args.getStringArray("buttonTexts"); + + final SparseArray