Added XEmbed embedder support

Jacek Caban jack at itma.pwr.wroc.pl
Mon Jun 20 10:21:52 CDT 2005


This time with patch.

Changelog:
     Added XEmbed embedder support

-------------- next part --------------
? dlls/x11drv/.window.c.swp
? dlls/x11drv/bak
? dlls/x11drv/diff
? dlls/x11drv/xembed.c
Index: dlls/user/user_main.c
===================================================================
RCS file: /home/wine/wine/dlls/user/user_main.c,v
retrieving revision 1.85
diff -u -p -r1.85 user_main.c
--- dlls/user/user_main.c	13 Jun 2005 18:56:01 -0000	1.85
+++ dlls/user/user_main.c	20 Jun 2005 14:44:31 -0000
@@ -260,6 +260,9 @@ static BOOL process_attach(void)
     /* some Win9x dlls expect keyboard to be loaded */
     if (GetVersion() & 0x80000000) LoadLibrary16( "keyboard.drv" );
 
+    /* Initialize built-in window classes */
+    CLASS_RegisterBuiltinClasses();
+
     /* Load the graphics driver */
     if (!load_driver()) return FALSE;
 
@@ -268,9 +271,6 @@ static BOOL process_attach(void)
 
     /* Setup palette function pointers */
     palette_init();
-
-    /* Initialize built-in window classes */
-    CLASS_RegisterBuiltinClasses();
 
     /* Initialize menus */
     if (!MENU_Init()) return FALSE;
Index: dlls/x11drv/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/Makefile.in,v
retrieving revision 1.43
diff -u -p -r1.43 Makefile.in
--- dlls/x11drv/Makefile.in	6 May 2005 19:38:50 -0000	1.43
+++ dlls/x11drv/Makefile.in	20 Jun 2005 14:44:31 -0000
@@ -40,6 +40,7 @@ C_SRCS = \
 	xdnd.c \
 	xfont.c \
 	xim.c \
+	xembed.c \
 	xrandr.c \
 	xrender.c \
 	xvidmode.c
Index: dlls/x11drv/event.c
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/event.c,v
retrieving revision 1.55
diff -u -p -r1.55 event.c
--- dlls/x11drv/event.c	1 Jun 2005 11:08:39 -0000	1.55
+++ dlls/x11drv/event.c	20 Jun 2005 14:44:32 -0000
@@ -246,6 +246,14 @@ static int process_events( Display *disp
         count++;
         if (XFilterEvent( &event, None )) continue;  /* filtered, ignore it */
 
+        if(!XFindContext( display, event.xany.window, winXEmbedContext, (char **)&hwnd)) {
+            /* XEmbed embedder window */
+            wine_tsx11_unlock();
+            XEMBED_event(hwnd, &event);
+            wine_tsx11_lock();
+            continue;
+        }
+
         if (!(handler = find_handler( event.type )))
         {
             TRACE( "%s, ignoring\n", dbgstr_event( event.type ));
@@ -521,7 +529,8 @@ static void EVENT_FocusOut( HWND hwnd, X
     XGetInputFocus( thread_display(), &focus_win, &revert );
     if (focus_win)
     {
-        if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
+        if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0
+                && XFindContext( thread_display(), focus_win, winXEmbedContext, (char **)&hwnd_tmp) != 0)
             focus_win = 0;
     }
     wine_tsx11_unlock();
@@ -874,7 +883,6 @@ static void handle_dnd_protocol( HWND hw
     else if (event->data.l[0] == DndURL)
         EVENT_DropURLs(hwnd, event);
 }
-
 
 struct client_message_handler
 {
Index: dlls/x11drv/window.c
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/window.c,v
retrieving revision 1.109
diff -u -p -r1.109 window.c
--- dlls/x11drv/window.c	24 May 2005 11:44:59 -0000	1.109
+++ dlls/x11drv/window.c	20 Jun 2005 14:44:33 -0000
@@ -97,6 +97,8 @@ static const char * const atom_names[NB_
     "XdndSelection",
     "XdndTarget",
     "XdndTypeList",
+    "_XEMBED",
+    "_XEMBED_INFO",
     "WCF_DIB",
     "image/gif",
     "text/html",
@@ -902,6 +904,7 @@ BOOL X11DRV_CreateWindow( HWND hwnd, CRE
     data->dce           = NULL;
     data->hWMIconBitmap = 0;
     data->hWMIconMask   = 0;
+    data->xembed_list   = NULL;
 
     wine_tsx11_lock();
     if (!win_data_context) win_data_context = XUniqueContext();
@@ -1103,7 +1106,8 @@ HWND X11DRV_SetParent( HWND hwnd, HWND p
     WND *wndPtr;
     BOOL ret;
     HWND old_parent = 0;
-
+    struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
+ 
     /* Windows hides the window first, then shows it again
      * including the WM_SHOWWINDOW messages and all */
     BOOL was_visible = ShowWindow( hwnd, SW_HIDE );
@@ -1128,8 +1132,6 @@ HWND X11DRV_SetParent( HWND hwnd, HWND p
 
     if (parent != old_parent)
     {
-        struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
-
         if (!data) return 0;
 
         if (parent != GetDesktopWindow()) /* a child window */
@@ -1152,6 +1154,9 @@ HWND X11DRV_SetParent( HWND hwnd, HWND p
             create_whole_window( display, data, GetWindowLongW( hwnd, GWL_STYLE ) );
         }
     }
+
+    if(X11DRV_win_has_xembed_child(data))
+        XEMBED_reparent(hwnd, parent, old_parent);
 
     /* SetParent additionally needs to make hwnd the topmost window
        in the x-order and send the expected WM_WINDOWPOSCHANGING and
Index: dlls/x11drv/winpos.c
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/winpos.c,v
retrieving revision 1.134
diff -u -p -r1.134 winpos.c
--- dlls/x11drv/winpos.c	17 Jun 2005 21:05:16 -0000	1.134
+++ dlls/x11drv/winpos.c	20 Jun 2005 14:44:33 -0000
@@ -677,6 +677,7 @@ BOOL X11DRV_SetWindowPos( WINDOWPOS *win
 {
     RECT newWindowRect, newClientRect, valid_rects[2];
     UINT orig_flags;
+    struct x11drv_win_data *data;
 
     TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n",
            winpos->hwnd, winpos->hwndInsertAfter, winpos->x, winpos->y,
@@ -752,6 +753,10 @@ BOOL X11DRV_SetWindowPos( WINDOWPOS *win
         winpos->cy = newWindowRect.bottom - newWindowRect.top;
         SendMessageW( winpos->hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)winpos );
     }
+
+    data = X11DRV_get_win_data(winpos->hwnd);
+    if(X11DRV_win_has_xembed_child(data))
+        XEMBED_update_child_pos(winpos->hwnd, winpos->flags);
 
     return TRUE;
 }
Index: dlls/x11drv/x11drv.h
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/x11drv.h,v
retrieving revision 1.75
diff -u -p -r1.75 x11drv.h
--- dlls/x11drv/x11drv.h	14 Jun 2005 18:12:15 -0000	1.75
+++ dlls/x11drv/x11drv.h	20 Jun 2005 14:44:33 -0000
@@ -287,6 +287,17 @@ extern void X11DRV_XDND_PositionEvent( H
 extern void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event );
 extern void X11DRV_XDND_LeaveEvent( HWND hWnd, XClientMessageEvent *event );
 
+struct xembed_list
+{
+    struct xembed_list *next;
+    HWND hwnd;
+};
+
+extern void XEMBED_update_child_pos(HWND, UINT);
+extern void XEMBED_reparent(HWND, HWND, HWND);
+extern void XEMBED_event(HWND, XEvent*);
+extern void XEMBED_init(void);
+
 /* exported dib functions for now */
 
 /* DIB Section sync state */
@@ -590,6 +601,8 @@ enum x11drv_atoms
     XATOM_XdndSelection,
     XATOM_XdndTarget,
     XATOM_XdndTypeList,
+    XATOM__XEMBED,
+    XATOM__XEMBED_INFO,
     XATOM_WCF_DIB,
     XATOM_image_gif,
     XATOM_text_html,
@@ -649,12 +662,14 @@ struct x11drv_win_data
     struct dce *dce;            /* DCE for CS_OWNDC or CS_CLASSDC windows */
     HBITMAP     hWMIconBitmap;
     HBITMAP     hWMIconMask;
+    struct xembed_list *xembed_list;
 };
 
 extern struct x11drv_win_data *X11DRV_get_win_data( HWND hwnd );
 extern Window X11DRV_get_whole_window( HWND hwnd );
 extern BOOL X11DRV_is_window_rect_mapped( const RECT *rect );
 extern XIC X11DRV_get_ic( HWND hwnd );
+extern BOOL X11DRV_win_has_xembed_child(struct x11drv_win_data *data);
 
 extern void alloc_window_dce( struct x11drv_win_data *data );
 extern void free_window_dce( struct x11drv_win_data *data );
@@ -662,6 +677,7 @@ extern void invalidate_dce( HWND hwnd, c
 
 /* X context to associate a hwnd to an X window */
 extern XContext winContext;
+extern XContext winXEmbedContext;
 
 extern void X11DRV_InitClipboard(void);
 extern void X11DRV_AcquireClipboard(HWND hWndClipWindow);
Index: dlls/x11drv/x11drv_main.c
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/x11drv_main.c,v
retrieving revision 1.107
diff -u -p -r1.107 x11drv_main.c
--- dlls/x11drv/x11drv_main.c	16 Jun 2005 16:14:46 -0000	1.107
+++ dlls/x11drv/x11drv_main.c	20 Jun 2005 14:44:34 -0000
@@ -397,6 +397,9 @@ static BOOL process_attach(void)
 
     X11DRV_InitKeyboard();
 
+    /* initialize XEmbed */
+    XEMBED_init();
+
     return TRUE;
 }
 
@@ -497,7 +500,6 @@ struct x11drv_thread_data *x11drv_init_t
     if (desktop_tid) AttachThreadInput( GetCurrentThreadId(), desktop_tid, TRUE );
     return data;
 }
-
 
 /***********************************************************************
  *           X11DRV initialisation routine
--- /dev/null	1970-01-01 01:00:00.000000000 +0100
+++ dlls/x11drv/xembed.c	2005-06-20 16:43:08.000000000 +0200
@@ -0,0 +1,636 @@
+/*
+ * Copyright 2005 Jacek Caban
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * 
+ * TODO:
+ *   - Implement Wine window as XEmbed client
+ *   - Implement accelerators
+ *   - Better focus handling
+ *   - Implement XReparentNotify so that client can be attached calling XReparentWindow itself
+ */
+
+#include "config.h"
+
+#include <X11/Xlib.h>
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wine/debug.h"
+
+#include "x11drv.h"
+
+#define XEMBED_EMBEDDED_NOTIFY         0
+#define XEMBED_WINDOW_ACTIVATE         1
+#define XEMBED_WINDOW_DEACTIVATE       2
+#define XEMBED_REQUEST_FOCUS           3
+#define XEMBED_FOCUS_IN                4
+#define XEMBED_FOCUS_OUT               5
+#define XEMBED_FOCUS_NEXT              6
+#define XEMBED_FOCUS_PREV              7
+#define XEMBED_MODALITY_ON             10
+#define XEMBED_MODALITY_OFF            11
+#define XEMBED_REGISTER_ACCELERATOR    12
+#define XEMBED_UNREGISTER_ACCELERATOR  13
+#define XEMBED_ACTIVATE_ACCELERATOR    14
+
+#define XEMBED_FOCUS_CURRENT  0
+#define XEMBED_FOCUS_FIRST    1
+#define XEMBED_FOCUS_LAST     2
+
+#define XEMBED_MAPPED 1 
+
+#define WM_ATTACH_XWINDOW WM_USER+600
+
+WINE_DEFAULT_DEBUG_CHANNEL(xembed);
+
+static const WCHAR wszClientWindow[] = 
+    {'_','_','w','i','n','e','_','x','1','1','_','c','l','i','e','n','t','_','w','i','n','d','o','w',0};
+static const WCHAR wszEmbedWindow[] =
+    {'_','_','w','i','n','e','_','x','1','1','_','e','m','b','e','d','d','e','r','_','w','i','n','d','o','w',0};
+
+XContext winXEmbedContext = 0;
+
+static void xembed_list_add(struct x11drv_win_data *data, HWND hwnd)
+{
+    struct xembed_list *new_elem = HeapAlloc(GetProcessHeap(), 0, sizeof(struct xembed_list));
+
+    new_elem->hwnd = hwnd;
+    new_elem->next = data->xembed_list;
+    data->xembed_list = new_elem;
+}
+
+static void xembed_list_remove(struct x11drv_win_data *data, HWND hwnd)
+{
+    struct xembed_list *iter;
+
+    if(!(iter = data->xembed_list))
+        return;
+
+    if(iter->hwnd == hwnd) {
+        data->xembed_list = iter->next;
+        HeapFree(GetProcessHeap(), 0, iter);
+    }else {
+        while(iter->next && iter->next->hwnd != hwnd)
+            iter = iter->next;
+        if(iter->next) {
+            struct xembed_list *tmp = iter->next;
+            iter->next = tmp->next;
+            HeapFree(GetProcessHeap(), 0, tmp);
+        }
+    }
+}
+
+static Window get_client_window(HWND hwnd)
+{
+    return (Window)GetPropW(hwnd, wszClientWindow);
+}
+
+static void set_client_window(HWND hwnd, Window window)
+{
+    SetPropW(hwnd, wszClientWindow, (LPVOID)window);
+}
+
+static Window get_embedder_window(HWND hwnd)
+{
+    return (Window)GetPropW(hwnd, wszEmbedWindow);
+}
+
+static void set_embedder_window(HWND hwnd, Window window)
+{
+    SetPropW(hwnd, wszEmbedWindow, (LPVOID)window);
+}
+
+static void check_xembed_info(Display *display, Window win, unsigned long *version, long unsigned *flags)
+{
+    Atom type;
+    int format, res;
+    unsigned long nitems, bytes_after, *data;
+
+    wine_tsx11_lock();
+    res = XGetWindowProperty(display, win, x11drv_atom(_XEMBED_INFO), 0, 2, False,
+            x11drv_atom(_XEMBED_INFO), &type, &format, &nitems, &bytes_after, (unsigned char**)&data);
+
+    if(res != Success || !format) {
+        XFree(data);
+        wine_tsx11_unlock();
+        WARN("Could not get _XEMBED_INFO\n");
+        return;
+    }
+
+    *version = data[0];
+    *flags = data[1];
+
+    XFree(data);
+    wine_tsx11_unlock();
+
+    TRACE("got version=%08lx flags=%08lx\n", data[0], data[1]);
+}
+
+static BOOL is_window_visible(HWND hwnd, HWND skip_hwnd)
+{
+    struct x11drv_win_data *data = X11DRV_get_win_data(hwnd);
+
+    while(!data->whole_window) {
+        if(data->hwnd != skip_hwnd && !(GetWindowLongW(data->hwnd, GWL_STYLE) & WS_VISIBLE))
+            return FALSE;
+        data = X11DRV_get_win_data(GetParent(data->hwnd));
+    }
+
+    return TRUE;
+}
+
+static void update_winpos(HWND hwnd, HWND update_hwnd, UINT flags)
+{
+    Display *display = ((struct x11drv_thread_data*)TlsGetValue(thread_data_tls_index))->display;
+    Window window;
+
+    if(!(flags & SWP_NOMOVE)) {
+        WINDOWINFO wininfo, whole_win_info;
+        struct x11drv_win_data *whole_win_data = X11DRV_get_win_data(hwnd);
+
+        TRACE("moving window %p\n", hwnd);
+
+        while(!whole_win_data->whole_window)
+            whole_win_data = X11DRV_get_win_data(GetParent(whole_win_data->hwnd));
+
+        wininfo.cbSize = sizeof(WINDOWINFO);
+        whole_win_info.cbSize = sizeof(WINDOWINFO);
+        GetWindowInfo(whole_win_data->hwnd, &whole_win_info);
+        GetWindowInfo(hwnd, &wininfo);
+
+        window = get_embedder_window(hwnd);
+
+        wine_tsx11_lock();
+        XMoveWindow(display, window,
+                wininfo.rcClient.left - whole_win_info.rcClient.left,
+                wininfo.rcClient.top - whole_win_info.rcClient.top);
+        wine_tsx11_unlock();
+    }
+
+    if(!(flags & SWP_NOSIZE)) {
+        RECT rect;
+
+        TRACE("resizing window %p\n", hwnd);
+
+        GetClientRect(hwnd, &rect);
+        window = get_embedder_window(hwnd);
+
+        wine_tsx11_lock();
+        XResizeWindow(display, window, rect.right, rect.bottom);
+        wine_tsx11_unlock();
+    }
+
+    if(flags & SWP_HIDEWINDOW) {
+        TRACE("hidding window %p\n", hwnd);
+
+        window = get_embedder_window(hwnd);
+        wine_tsx11_lock();
+        XUnmapWindow(display, window);
+        wine_tsx11_unlock();
+    }else if(flags & SWP_SHOWWINDOW && is_window_visible(hwnd, update_hwnd)) {
+        TRACE("showing window %p\n", hwnd);
+
+        window = get_embedder_window(hwnd);
+        wine_tsx11_lock();
+        XMapWindow(display, window);
+        wine_tsx11_unlock();
+    }
+}
+
+static void send_xembed_event(Display *display, Window window, int message,
+        unsigned long detail, unsigned long data1, unsigned long data2)
+{
+    XClientMessageEvent event;
+
+    event.type = ClientMessage;
+    event.window = window;
+    event.message_type = x11drv_atom(_XEMBED);
+    event.format = 32;
+    event.data.l[0] = CurrentTime;
+    event.data.l[1] = message;
+    event.data.l[2] = detail;
+    event.data.l[3] = data1;
+    event.data.l[4] = data2;
+
+    wine_tsx11_lock();
+    XSendEvent(display, window, False, NoEventMask, (XEvent*)&event);
+    wine_tsx11_unlock();
+}
+
+static void attach_window(HWND hwnd, Window window) {
+    Display *display = ((struct x11drv_thread_data*)TlsGetValue(thread_data_tls_index))->display;
+    unsigned long version = 0, flags = XEMBED_MAPPED;
+    RECT rect;
+
+    TRACE("(%p %08lx)\n", hwnd, window);
+
+    if(get_client_window(hwnd)) {
+        WARN("Embedder alredy has client\n");
+        return;
+    }
+
+    set_client_window(hwnd, window);
+
+    check_xembed_info(display, window, &version, &flags);
+
+    /* FIXME: handle XEmbed version correctly (while it is only version 0 it's not really important) */
+    send_xembed_event(display, window, XEMBED_EMBEDDED_NOTIFY, 0, get_embedder_window(hwnd), 0);
+
+    if(!(flags & XEMBED_MAPPED)) {
+        unsigned int prop[] = {0, XEMBED_MAPPED};
+        wine_tsx11_lock();
+        XChangeProperty(display, window, x11drv_atom(_XEMBED_INFO), XA_CARDINAL,
+                32, PropModeReplace, (unsigned char*)prop, 2);
+        wine_tsx11_unlock();
+    }
+
+    GetClientRect(hwnd, &rect);
+
+    wine_tsx11_lock();
+    XMapWindow(display, window);
+    XMoveResizeWindow(display, window, 0, 0, rect.right, rect.bottom);
+    wine_tsx11_unlock();
+
+    send_xembed_event(display, window, XEMBED_WINDOW_ACTIVATE, 0, 0, 0);
+
+    if(GetFocus() == hwnd)
+        send_xembed_event(display, window, XEMBED_FOCUS_IN, XEMBED_FOCUS_FIRST, 0, 0);
+}
+
+static void detach_window(HWND hwnd)
+{
+    Window client = get_client_window(hwnd);
+
+    TRACE("(%p) client=%08lx\n", hwnd, client);
+
+    if(client)
+        set_client_window(hwnd, 0);
+}
+
+static void xembed_window_create(HWND hwnd)
+{
+    struct x11drv_win_data *data = X11DRV_get_win_data(hwnd);
+    Window window;
+    Display * display = ((struct x11drv_thread_data*)TlsGetValue(thread_data_tls_index))->display;
+    XSetWindowAttributes attr;
+
+    TRACE("(%p)\n", hwnd);
+
+    xembed_list_add(data, hwnd);
+ 
+    if(!data->whole_window) {
+        do {
+            data = X11DRV_get_win_data(GetParent(data->hwnd));
+            xembed_list_add(data, hwnd);
+        } while(!data->whole_window);
+    }
+
+    attr.event_mask = (ExposureMask | KeyPressMask | KeyReleaseMask
+            | SubstructureNotifyMask | StructureNotifyMask);
+    attr.bit_gravity = NorthWestGravity;
+    attr.backing_store = NotUseful;
+    
+    wine_tsx11_lock();
+    window = XCreateWindow(display, data->whole_window, 0, 0, 100, 100,
+            0, screen_depth, InputOutput, visual,
+            CWEventMask | CWBitGravity | CWBackingStore, &attr);
+    XSaveContext(display, window, winXEmbedContext, (char*)hwnd);
+    XSync(display, False);
+    wine_tsx11_unlock();
+
+    TRACE("window = %08lx\n", window);
+
+    set_embedder_window(hwnd, window);
+    update_winpos(hwnd, hwnd, (IsWindowVisible(hwnd) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
+}
+
+static void xembed_window_destroy(HWND hwnd) {
+    struct x11drv_win_data *data;
+    Display * display = ((struct x11drv_thread_data*)TlsGetValue(thread_data_tls_index))->display;
+    Window window;
+    TRACE("(%p)\n", hwnd);
+
+    detach_window(hwnd);
+
+    window = get_embedder_window(hwnd);
+    wine_tsx11_lock();
+    XDestroyWindow(display, window);
+    wine_tsx11_unlock();
+
+    data = X11DRV_get_win_data(hwnd);
+
+    if(!data->whole_window) {
+        do {
+            data = X11DRV_get_win_data(GetParent(data->hwnd));
+            xembed_list_remove(data, hwnd);
+        }while(!data->whole_window);
+    }
+
+    xembed_list_remove(data, hwnd);
+}
+
+static void xembed_window_paint(HWND hwnd)
+{
+    Window client = get_client_window(hwnd);
+
+    TRACE("(%p)\n", hwnd);
+
+    if(client) {
+        Display *display = ((struct x11drv_thread_data*)TlsGetValue(thread_data_tls_index))->display;
+        RECT rect;
+
+        GetUpdateRect(hwnd, &rect, FALSE);
+
+        wine_tsx11_lock();
+        XClearArea(display, client, rect.left, rect.top, rect.right, rect.bottom, True);
+        wine_tsx11_unlock();
+    }
+}
+
+static void xembed_window_attach_xwindow(HWND hwnd, Window client)
+{
+    Window window = get_embedder_window(hwnd);
+    struct x11drv_thread_data *data = (struct x11drv_thread_data*)TlsGetValue(thread_data_tls_index);
+
+    TRACE("(%p %08lx)\n", hwnd, client);
+
+    wine_tsx11_lock();
+    XReparentWindow(data->display, client, window, 0, 0);
+    wine_tsx11_unlock();
+}
+
+static void xembed_window_set_focus(HWND hwnd)
+{
+    Window window = get_embedder_window(hwnd);
+    Window client = get_client_window(hwnd);
+    struct x11drv_thread_data *data = (struct x11drv_thread_data*)TlsGetValue(thread_data_tls_index);
+
+    TRACE("(%p)\n", hwnd);
+    
+    wine_tsx11_lock();
+    XSetInputFocus(data->display, window, RevertToParent, CurrentTime);
+    wine_tsx11_unlock();
+
+    if(client)
+        send_xembed_event(data->display, client, XEMBED_FOCUS_IN, XEMBED_FOCUS_FIRST, 0, 0);
+}
+
+static void xembed_window_kill_focus(HWND hwnd)
+{
+    Window client = get_client_window(hwnd);
+    struct x11drv_thread_data *data = (struct x11drv_thread_data*)TlsGetValue(thread_data_tls_index);
+    struct x11drv_win_data *win_data = X11DRV_get_win_data(hwnd);
+
+    TRACE("(%p)\n", hwnd);
+
+    while(!win_data->whole_window)
+        win_data = X11DRV_get_win_data(GetParent(win_data->hwnd));
+
+    wine_tsx11_lock();
+    XSetInputFocus(data->display, win_data->whole_window, RevertToParent, CurrentTime);
+    wine_tsx11_unlock();
+
+    if(client)
+        send_xembed_event(data->display, client, XEMBED_FOCUS_OUT, 0, 0, 0);
+}
+
+static void xembed_CreateNotify(HWND hwnd, XCreateWindowEvent *event)
+{
+    TRACE("(%p %p) window = %08lx parent = %08lx\n", hwnd, event, event->window, event->parent);
+
+    attach_window(hwnd, event->window);
+}
+
+static void xembed_ReparentNotify(HWND hwnd, XReparentEvent *event)
+{
+    TRACE("(%p %p)\n", hwnd, event);
+
+    if(event->parent == event->event)
+        attach_window(hwnd, event->window);
+}
+
+static void xembed_ConfigureNotify(HWND hwnd, XConfigureEvent *event)
+{
+    Window client;
+    
+    if(event->event != event->window)
+        return;
+
+    client = get_client_window(hwnd);
+
+    TRACE("(%p %p) window=%08lx client=%08lx\n", hwnd, event, event->window, client);
+
+    if(client) {
+        wine_tsx11_lock();
+        XResizeWindow(event->display, client, event->width, event->height);
+        wine_tsx11_unlock();
+    }
+}
+
+static void xembed_KeyNotify(HWND hwnd, XKeyEvent *event)
+{
+    Window client = get_client_window(hwnd);
+
+    TRACE("(%p %p)\n", hwnd, event);
+
+    if(client) {
+        event->window = client;
+
+        wine_tsx11_lock();
+        XSendEvent(event->display, client, False, NoEventMask, (XEvent*)event);
+        wine_tsx11_unlock();
+    }
+}
+
+static void xembed_protocol(HWND hwnd, XClientMessageEvent *event) {
+    if(event->message_type != x11drv_atom(_XEMBED))
+        return;
+
+    switch(event->data.l[1]) {
+    case XEMBED_REQUEST_FOCUS:
+        TRACE("XEMBED_REQUEST_FOCUS\n");
+        if(GetFocus() != hwnd)
+            SetFocus(hwnd);
+        break;
+    case XEMBED_FOCUS_NEXT:
+        TRACE("XEMBED_FOCUS_NEXT\n");
+        SendMessageW(GetParent(hwnd), WM_KEYDOWN, VK_TAB, 0);
+        break;
+    case XEMBED_FOCUS_PREV:
+        WARN("XEMBED_FOCUS_PREV\n");
+        break;
+    case XEMBED_REGISTER_ACCELERATOR:
+        WARN("XEMBED_REGISTER_ACCELERATOR\n");
+        break;
+    case XEMBED_UNREGISTER_ACCELERATOR:
+        WARN("XEMBED_UNREGISTER_ACCELERATOR\n");
+        break;
+    case XEMBED_ACTIVATE_ACCELERATOR:
+        WARN("XEMBED_ACTIVATE_ACCELERATOR\n");
+        break;
+    default:
+        WARN("got unknown message: %ld\n", event->data.l[1]);
+    };
+}
+
+/**********************************************************************
+ *              X11DRV_win_has_xembed_child
+ */
+BOOL X11DRV_win_has_xembed_child(struct x11drv_win_data *data)
+{
+    return data->xembed_list != NULL;
+}
+
+/**********************************************************************
+ *              XEMBED_update_child_pos
+ */
+void XEMBED_update_child_pos(HWND hwnd, UINT flags)
+{
+    struct xembed_list *iter;
+    struct x11drv_win_data *data = X11DRV_get_win_data(hwnd);
+
+    TRACE("(%p %08x)\n", hwnd, flags);
+
+    if(data->whole_window)
+        return;
+
+    for(iter = data->xembed_list; iter; iter = iter->next) {
+        if(iter->hwnd == hwnd || IsChild(hwnd, iter->hwnd))
+            update_winpos(iter->hwnd, hwnd, flags);
+    }
+}
+
+/**********************************************************************
+ *              XEMBED_reparent
+ */
+void XEMBED_reparent(HWND hwnd, HWND new_parent, HWND old_parent)
+{
+    struct x11drv_win_data *old_win_data, *new_win_data, *data;
+    struct xembed_list *iter;
+    Display *display = ((struct x11drv_thread_data*)TlsGetValue(thread_data_tls_index))->display;
+
+    TRACE("(%p %p %p)\n", hwnd, old_parent, new_parent);
+
+    data = X11DRV_get_win_data(hwnd);
+
+    old_win_data = X11DRV_get_win_data(old_parent);
+    if(!old_win_data->whole_window) {
+        do {
+            for(iter = old_win_data->xembed_list; iter; iter = iter->next)
+                xembed_list_remove(old_win_data, iter->hwnd);
+            old_win_data = X11DRV_get_win_data(GetParent(old_win_data->hwnd));
+        }while(!old_win_data->whole_window);
+    }
+
+    new_win_data = X11DRV_get_win_data(new_parent);
+    if(!new_win_data->whole_window) {
+        do {
+            for(iter = new_win_data->xembed_list; iter; iter = iter->next)
+                xembed_list_add(new_win_data, iter->hwnd);
+            new_win_data = X11DRV_get_win_data(GetParent(new_win_data->hwnd));
+        }while(!new_win_data->whole_window);
+    }
+
+    if(old_win_data == new_win_data)
+        return;
+
+    for(iter = data->xembed_list; iter; iter = iter->next) {
+        wine_tsx11_lock();
+        XReparentWindow(display, get_embedder_window(iter->hwnd), new_win_data->whole_window, 0, 0);
+        wine_tsx11_unlock();
+    }
+
+    XEMBED_update_child_pos(hwnd, 0);
+}
+
+/**********************************************************************
+ *              XEMBED_event
+ */
+void XEMBED_event(HWND hwnd, XEvent *event) 
+{
+    switch(event->xany.type) {
+    case CreateNotify:
+        xembed_CreateNotify(hwnd, &event->xcreatewindow);
+        break;
+    case ReparentNotify:
+        xembed_ReparentNotify(hwnd, &event->xreparent);
+        break;
+    case ConfigureNotify:
+        xembed_ConfigureNotify(hwnd, &event->xconfigure);
+        break;
+    case KeyPress:
+    case KeyRelease:
+        xembed_KeyNotify(hwnd, &event->xkey);
+        break;
+    case ClientMessage:
+        xembed_protocol(hwnd, &event->xclient);
+        break;
+    };
+}
+
+/**********************************************************************
+ *              xembed_wndproc
+ */
+static LRESULT WINAPI xembed_wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    switch(msg) {
+    case WM_CREATE:
+        xembed_window_create(hwnd);
+        break;
+    case WM_DESTROY:
+        xembed_window_destroy(hwnd);
+        break;
+    case WM_PAINT:
+        xembed_window_paint(hwnd);
+        break;
+    case WM_SETFOCUS:
+        xembed_window_set_focus(hwnd);
+        break;
+    case WM_KILLFOCUS:
+        xembed_window_kill_focus(hwnd);
+        break;
+    case WM_ATTACH_XWINDOW:
+        xembed_window_attach_xwindow(hwnd, lParam);
+        break;
+    };
+
+    return DefWindowProcW(hwnd, msg, wParam, lParam);
+}
+
+/**********************************************************************
+ *              XEMBED_init
+ */
+void XEMBED_init(void)
+{
+    static const WCHAR wszXEMBED[] = {'_','X','E','M','B','E','D',0};
+    static const WNDCLASSEXW wndclass = {
+        sizeof(WNDCLASSEXW),
+        0,
+        xembed_wndproc,
+        0, 0, NULL, NULL, NULL, NULL, NULL,
+        wszXEMBED,
+        NULL
+    };
+
+    RegisterClassExW(&wndclass);
+
+    wine_tsx11_lock();
+    winXEmbedContext = XUniqueContext();
+    wine_tsx11_unlock();
+}


More information about the wine-patches mailing list