Alexandre Julliard : wineandroid: Add an event queue to support handling Java callbacks in the desktop thread.

Alexandre Julliard julliard at winehq.org
Wed May 31 16:20:17 CDT 2017


Module: wine
Branch: master
Commit: 5be4a0e38842d2fa241ca769ce4d50e4eb55c68a
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=5be4a0e38842d2fa241ca769ce4d50e4eb55c68a

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Wed May 31 11:49:12 2017 +0200

wineandroid: Add an event queue to support handling Java callbacks in the desktop thread.

Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/wineandroid.drv/android.h            |  18 ++++
 dlls/wineandroid.drv/window.c             | 168 ++++++++++++++++++++++++++++++
 dlls/wineandroid.drv/wineandroid.drv.spec |   2 +
 3 files changed, 188 insertions(+)

diff --git a/dlls/wineandroid.drv/android.h b/dlls/wineandroid.drv/android.h
index ab4a431..9fefb11 100644
--- a/dlls/wineandroid.drv/android.h
+++ b/dlls/wineandroid.drv/android.h
@@ -57,6 +57,24 @@ extern void init_monitors( int width, int height ) DECLSPEC_HIDDEN;
 /* JNI entry points */
 extern void desktop_changed( JNIEnv *env, jobject obj, jint width, jint height ) DECLSPEC_HIDDEN;
 
+enum event_type
+{
+    DESKTOP_CHANGED,
+};
+
+union event_data
+{
+    enum event_type type;
+    struct
+    {
+        enum event_type type;
+        unsigned int    width;
+        unsigned int    height;
+    } desktop;
+};
+
+int send_event( const union event_data *data );
+
 extern JavaVM *wine_get_java_vm(void);
 extern jobject wine_get_java_object(void);
 
diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c
index e7c83b0..cf35215 100644
--- a/dlls/wineandroid.drv/window.c
+++ b/dlls/wineandroid.drv/window.c
@@ -44,6 +44,7 @@
 #include "wine/unicode.h"
 
 #include "android.h"
+#include "wine/server.h"
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(android);
@@ -133,6 +134,35 @@ static void release_win_data( struct android_win_data *data )
 }
 
 
+/* Handling of events coming from the Java side */
+
+struct java_event
+{
+    struct list      entry;
+    union event_data data;
+};
+
+static struct list event_queue = LIST_INIT( event_queue );
+static struct java_event *current_event;
+static int event_pipe[2];
+static DWORD desktop_tid;
+
+/***********************************************************************
+ *           send_event
+ */
+int send_event( const union event_data *data )
+{
+    int res;
+
+    if ((res = write( event_pipe[1], data, sizeof(*data) )) != sizeof(*data))
+    {
+        p__android_log_print( ANDROID_LOG_ERROR, "wine", "failed to send event" );
+        return -1;
+    }
+    return 0;
+}
+
+
 /***********************************************************************
  *           desktop_changed
  *
@@ -140,7 +170,145 @@ static void release_win_data( struct android_win_data *data )
  */
 void desktop_changed( JNIEnv *env, jobject obj, jint width, jint height )
 {
+    union event_data data;
+
+    memset( &data, 0, sizeof(data) );
+    data.type = DESKTOP_CHANGED;
+    data.desktop.width = width;
+    data.desktop.height = height;
     p__android_log_print( ANDROID_LOG_INFO, "wine", "desktop_changed: %ux%u", width, height );
+    send_event( &data );
+}
+
+
+/***********************************************************************
+ *           init_event_queue
+ */
+static void init_event_queue(void)
+{
+    HANDLE handle;
+    int ret;
+
+    if (pipe2( event_pipe, O_CLOEXEC | O_NONBLOCK ) == -1)
+    {
+        ERR( "could not create data\n" );
+        ExitProcess(1);
+    }
+    if (wine_server_fd_to_handle( event_pipe[0], GENERIC_READ | SYNCHRONIZE, 0, &handle ))
+    {
+        ERR( "Can't allocate handle for event fd\n" );
+        ExitProcess(1);
+    }
+    SERVER_START_REQ( set_queue_fd )
+    {
+        req->handle = wine_server_obj_handle( handle );
+        ret = wine_server_call( req );
+    }
+    SERVER_END_REQ;
+    if (ret)
+    {
+        ERR( "Can't store handle for event fd %x\n", ret );
+        ExitProcess(1);
+    }
+    CloseHandle( handle );
+    desktop_tid = GetCurrentThreadId();
+}
+
+
+/***********************************************************************
+ *           pull_events
+ *
+ * Pull events from the event pipe and add them to the queue
+ */
+static void pull_events(void)
+{
+    struct java_event *event;
+    int res;
+
+    for (;;)
+    {
+        if (!(event = HeapAlloc( GetProcessHeap(), 0, sizeof(*event) ))) break;
+
+        res = read( event_pipe[0], &event->data, sizeof(event->data) );
+        if (res != sizeof(event->data)) break;
+        list_add_tail( &event_queue, &event->entry );
+    }
+    HeapFree( GetProcessHeap(), 0, event );
+}
+
+
+/***********************************************************************
+ *           process_events
+ */
+static int process_events( DWORD mask )
+{
+    struct java_event *event, *next, *previous;
+    unsigned int count = 0;
+
+    assert( GetCurrentThreadId() == desktop_tid );
+
+    pull_events();
+
+    previous = current_event;
+
+    LIST_FOR_EACH_ENTRY_SAFE( event, next, &event_queue, struct java_event, entry )
+    {
+        if (!(mask & QS_SENDMESSAGE)) continue;  /* skip it */
+
+        /* remove it first, in case we process events recursively */
+        list_remove( &event->entry );
+        current_event = event;
+
+        switch (event->data.type)
+        {
+        case DESKTOP_CHANGED:
+            TRACE( "DESKTOP_CHANGED %ux%u\n", event->data.desktop.width, event->data.desktop.height );
+            screen_width = event->data.desktop.width;
+            screen_height = event->data.desktop.height;
+            init_monitors( screen_width, screen_height );
+            SetWindowPos( GetDesktopWindow(), 0, 0, 0, screen_width, screen_height,
+                          SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW );
+            break;
+
+        default:
+            FIXME( "got event %u\n", event->data.type );
+        }
+        HeapFree( GetProcessHeap(), 0, event );
+        count++;
+    }
+    current_event = previous;
+    return count;
+}
+
+
+/***********************************************************************
+ *           ANDROID_MsgWaitForMultipleObjectsEx
+ */
+DWORD CDECL ANDROID_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
+                                                 DWORD timeout, DWORD mask, DWORD flags )
+{
+    if (GetCurrentThreadId() == desktop_tid)
+    {
+        /* don't process nested events */
+        if (current_event) mask = 0;
+        if (process_events( mask )) return count - 1;
+    }
+    return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
+                                     timeout, flags & MWMO_ALERTABLE );
+}
+
+/**********************************************************************
+ *           ANDROID_CreateWindow
+ */
+BOOL CDECL ANDROID_CreateWindow( HWND hwnd )
+{
+    TRACE( "%p\n", hwnd );
+
+    if (hwnd == GetDesktopWindow())
+    {
+        init_event_queue();
+    }
+    return TRUE;
 }
 
 
diff --git a/dlls/wineandroid.drv/wineandroid.drv.spec b/dlls/wineandroid.drv/wineandroid.drv.spec
index b94c9f8..49402a8 100644
--- a/dlls/wineandroid.drv/wineandroid.drv.spec
+++ b/dlls/wineandroid.drv/wineandroid.drv.spec
@@ -6,6 +6,8 @@
 
 @ cdecl EnumDisplayMonitors(long ptr ptr long) ANDROID_EnumDisplayMonitors
 @ cdecl GetMonitorInfo(long ptr) ANDROID_GetMonitorInfo
+@ cdecl CreateWindow(long) ANDROID_CreateWindow
 @ cdecl DestroyWindow(long) ANDROID_DestroyWindow
+@ cdecl MsgWaitForMultipleObjectsEx(long ptr long long long) ANDROID_MsgWaitForMultipleObjectsEx
 @ cdecl WindowPosChanging(long long long ptr ptr ptr ptr) ANDROID_WindowPosChanging
 @ cdecl WindowPosChanged(long long long ptr ptr ptr ptr ptr) ANDROID_WindowPosChanged




More information about the wine-cvs mailing list