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