Hi Alexandre,
This has missed the last two commits. Is this codes presence in shell32 really a blocking issue? If so then I'd note that quite a lot of people have problems caused by the lack of this patch (can't quit apps etc).
thanks -mike
On Sun, 2003-11-30 at 16:16, Mike Hearn wrote:
Hi,
This patch updates my system tray patch to work with the new atom interning code, fixes a few bugs and replaces the per-icon mutex with a global one. The critical section handling should therefore be much less broken now.
Yes, I know it should be in wineshell.exe but for now this will do, and the code can always be moved later.
thanks -mike
ChangeLog: Implement support for XEMBED based system trays
Index: dlls/shell32/systray.c
RCS file: /home/wine/wine/dlls/shell32/systray.c,v retrieving revision 1.24 diff -u -r1.24 systray.c --- dlls/shell32/systray.c 24 Oct 2003 04:23:37 -0000 1.24 +++ dlls/shell32/systray.c 30 Nov 2003 16:08:37 -0000 @@ -1,11 +1,11 @@ /*
- Systray
- System tray handling code (client side)
- Copyright 1999 Kai Morich kai.morich@bigfoot.de
- Copyright 1999 Kai Morich kai.morich@bigfoot.de
- Copyright 2003 Mike Hearn mike@theoretic.com
- Manage the systray window. That it actually appears in the docking
- area of KDE or GNOME is delegated to windows/x11drv/wnd.c,
- X11DRV_WND_DockWindow.
- This code creates a window with the WS_EX_TRAYWINDOW style. The actual
- environment integration code is handled inside the X11 driver.
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
@@ -42,7 +42,17 @@ #include "commctrl.h" #include "wine/debug.h"
-WINE_DEFAULT_DEBUG_CHANNEL(shell); +WINE_DEFAULT_DEBUG_CHANNEL(systray);
+static CRITICAL_SECTION systray_lock; +static CRITICAL_SECTION_DEBUG critsect_debug = +{
- 0, 0, &systray_lock,
- { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, { 0, (DWORD)(__FILE__ ": system tray") }
+}; +static CRITICAL_SECTION systray_lock = { &critsect_debug, -1, 0, 0, 0, 0 };
typedef struct SystrayItem { HWND hWnd; @@ -51,12 +61,11 @@ struct SystrayItem *nextTrayItem; } SystrayItem;
-static SystrayItem *systray=NULL; -static int firstSystray=TRUE; /* defer creation of window class until first systray item is created */ +static SystrayItem *systray = NULL; +static int firstSystray = TRUE; /* defer creation of window class until first systray item is created */
static BOOL SYSTRAY_Delete(PNOTIFYICONDATAA pnid);
#define ICON_SIZE GetSystemMetrics(SM_CXSMICON) /* space around icon (forces icon to center of KDE systray area) */ #define ICON_BORDER 4 @@ -74,21 +83,26 @@ { HDC hdc; PAINTSTRUCT ps;
- TRACE("hwnd=%p, msg=0x%x\n", hWnd, message); switch (message) { case WM_PAINT: { RECT rc; SystrayItem *ptrayItem = systray;
- int top;
- EnterCriticalSection(&systray_lock);
- while (ptrayItem) {
if (ptrayItem->hWnd==hWnd) {
if (ptrayItem->notifyIcon.hIcon) { hdc = BeginPaint(hWnd, &ps); GetClientRect(hWnd, &rc);if (ptrayItem->hWnd == hWnd) {
if (!DrawIconEx(hdc, rc.left+ICON_BORDER, rc.top+ICON_BORDER, ptrayItem->notifyIcon.hIcon,
/* calculate top so we can deal with arbitrary sized trays */
top = ((rc.bottom-rc.top)/2) - ((ICON_SIZE)/2);
if (!DrawIconEx(hdc, (ICON_BORDER/2), top, ptrayItem->notifyIcon.hIcon, ICON_SIZE, ICON_SIZE, 0, 0, DI_DEFAULTSIZE|DI_NORMAL)) { ERR("Paint(SystrayWindow %p) failed -> removing SystrayItem %p\n", hWnd, ptrayItem);
} }LeaveCriticalSection(&systray_lock); SYSTRAY_Delete(&ptrayItem->notifyIcon);
@@ -97,10 +111,10 @@ ptrayItem = ptrayItem->nextTrayItem; } EndPaint(hWnd, &ps);
- LeaveCriticalSection(&systray_lock); } break;
- case WM_MOUSEMOVE: case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONDOWN:
@@ -110,7 +124,8 @@ { MSG msg; SystrayItem *ptrayItem = systray;
- /* relay the event to the tooltip */
- EnterCriticalSection(&systray_lock); while ( ptrayItem ) { if (ptrayItem->hWnd == hWnd) { msg.hwnd=hWnd;
@@ -125,15 +140,17 @@ } ptrayItem = ptrayItem->nextTrayItem; }
- LeaveCriticalSection(&systray_lock); }
- /* fall through */
/* fall through, so the message is sent to the callback as well */
case WM_LBUTTONDBLCLK: case WM_RBUTTONDBLCLK: case WM_MBUTTONDBLCLK: { SystrayItem *ptrayItem = systray;
- /* iterate over the currently active tray items */
- EnterCriticalSection(&systray_lock); while (ptrayItem) { if (ptrayItem->hWnd == hWnd) { if (ptrayItem->notifyIcon.hWnd && ptrayItem->notifyIcon.uCallbackMessage) {
@@ -147,9 +164,18 @@ } ptrayItem = ptrayItem->nextTrayItem; }
LeaveCriticalSection(&systray_lock); } break;
case WM_NOTIFYFORMAT:
{
TRACE("Received WM_NOTIFYFORMAT, showing the tray window\n");
ShowWindow(hWnd, SW_SHOW);
return (DefWindowProcA(hWnd, message, wParam, lParam));
}
default: return (DefWindowProcA(hWnd, message, wParam, lParam)); }
@@ -169,7 +195,7 @@ wc.hInstance = 0; wc.hIcon = 0; wc.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
- wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
- wc.hbrBackground = (HBRUSH) COLOR_WINDOW; wc.lpszMenuName = NULL; wc.lpszClassName = "WineSystray";
@@ -181,30 +207,21 @@ }
-BOOL SYSTRAY_ItemInit(SystrayItem *ptrayItem) -{ +DWORD WINAPI SYSTRAY_ThreadProc(LPVOID p1) {
- SystrayItem *ptrayItem = (SystrayItem *)p1;
- MSG msg; RECT rect;
- /* Register the class if this is our first tray item. */
- if ( firstSystray ) {
- firstSystray = FALSE;
- if ( !SYSTRAY_RegisterClass() ) {
ERR( "RegisterClass(WineSystray) failed\n" );
return FALSE;
- }
- }
- /* Initialize the window size. */ rect.left = 0; rect.top = 0; rect.right = ICON_SIZE+2*ICON_BORDER; rect.bottom = ICON_SIZE+2*ICON_BORDER;
- ZeroMemory( ptrayItem, sizeof(SystrayItem) ); /* Create tray window for icon. */ ptrayItem->hWnd = CreateWindowExA( WS_EX_TRAYWINDOW,
"WineSystray", "Wine-Systray",
WS_VISIBLE,
"WineSystray", "Windows System Tray",
0, CW_USEDEFAULT, CW_USEDEFAULT, rect.right-rect.left, rect.bottom-rect.top, 0, 0, 0, 0 );
@@ -222,31 +239,73 @@ ERR( "CreateWindow(TOOLTIP) failed\n" ); return FALSE; }
- /* Enter the message loop */
- while (GetMessageA (&msg, 0, 0, 0) > 0) {
- TranslateMessage (&msg);
- DispatchMessageA (&msg);
- }
- TRACE("Shutting down system tray thread\n");
- if(ptrayItem->notifyIcon.hIcon)
DestroyIcon(ptrayItem->notifyIcon.hIcon);
- if(ptrayItem->hWndToolTip)
DestroyWindow(ptrayItem->hWndToolTip);
- return 0;
+}
+BOOL SYSTRAY_ItemInit(SystrayItem *ptrayItem) +{
- DWORD threadID;
- /* Register the class if this is our first tray item. */
- EnterCriticalSection(&systray_lock);
- if ( firstSystray ) {
- firstSystray = FALSE;
- if ( !SYSTRAY_RegisterClass() ) {
ERR( "RegisterClass(WineSystray) failed\n" );
LeaveCriticalSection(&systray_lock);
return FALSE;
- }
- }
- LeaveCriticalSection(&systray_lock);
- ZeroMemory( ptrayItem, sizeof(SystrayItem) );
- /* We need to run the system tray window in a separate thread, as otherwise if the originating thread
stops processing messages, the tray window will hang. If another part of the application then does
for instance a FindWindow call, this can deadlock the application. */
- if (!CreateThread(NULL, 0, SYSTRAY_ThreadProc, (LPVOID) ptrayItem, 0, &threadID)) {
- ERR("Could not create system tray item thread\n");
- return FALSE;
- } return TRUE;
}
static void SYSTRAY_ItemTerm(SystrayItem *ptrayItem) {
- if(ptrayItem->notifyIcon.hIcon)
DestroyIcon(ptrayItem->notifyIcon.hIcon);
- if(ptrayItem->hWndToolTip)
DestroyWindow(ptrayItem->hWndToolTip);
- if(ptrayItem->hWnd)
- DestroyWindow(ptrayItem->hWnd);
- /* MSDN says we shouldn't do this, but I can't see another way to make GetMessage() return zero */
- PostMessageA(ptrayItem->hWnd, WM_QUIT, 0, 0); return;
}
void SYSTRAY_ItemSetMessage(SystrayItem *ptrayItem, UINT uCallbackMessage) {
- EnterCriticalSection(&systray_lock); ptrayItem->notifyIcon.uCallbackMessage = uCallbackMessage;
- LeaveCriticalSection(&systray_lock);
}
void SYSTRAY_ItemSetIcon(SystrayItem *ptrayItem, HICON hIcon) {
- EnterCriticalSection(&systray_lock); ptrayItem->notifyIcon.hIcon = CopyIcon(hIcon);
- LeaveCriticalSection(&systray_lock);
- InvalidateRect(ptrayItem->hWnd, NULL, TRUE);
}
@@ -255,9 +314,11 @@ { TTTOOLINFOA ti;
- strncpy(ptrayItem->notifyIcon.szTip, szTip, sizeof(ptrayItem->notifyIcon.szTip));
- EnterCriticalSection(&systray_lock);
- strncpy(ptrayItem->notifyIcon.szTip, szTip, sizeof(ptrayItem->notifyIcon.szTip)); ptrayItem->notifyIcon.szTip[sizeof(ptrayItem->notifyIcon.szTip)-1]=0;
- LeaveCriticalSection(&systray_lock);
- ti.cbSize = sizeof(TTTOOLINFOA); ti.uFlags = 0; ti.hwnd = ptrayItem->hWnd;
@@ -280,10 +341,15 @@ { SystrayItem **ptrayItem = &systray;
- TRACE("%p\n", pnid);
- EnterCriticalSection(&systray_lock); /* Find last element. */ while( *ptrayItem ) {
- if ( SYSTRAY_ItemIsEqual(pnid, &(*ptrayItem)->notifyIcon) )
- if ( SYSTRAY_ItemIsEqual(pnid, &(*ptrayItem)->notifyIcon) ) {
LeaveCriticalSection(&systray_lock); return FALSE;
- } ptrayItem = &((*ptrayItem)->nextTrayItem); } /* Allocate SystrayItem for element and add to end of list. */
@@ -297,6 +363,7 @@ SYSTRAY_ItemSetMessage(*ptrayItem, (pnid->uFlags&NIF_MESSAGE)?pnid->uCallbackMessage:0); SYSTRAY_ItemSetTip (*ptrayItem, (pnid->uFlags&NIF_TIP) ?pnid->szTip :"", FALSE);
- LeaveCriticalSection(&systray_lock); TRACE("%p: %p %s\n", (*ptrayItem), (*ptrayItem)->notifyIcon.hWnd, (*ptrayItem)->notifyIcon.szTip); return TRUE;
@@ -307,8 +374,12 @@ { SystrayItem *ptrayItem = systray;
- TRACE("%p\n", pnid);
- EnterCriticalSection(&systray_lock); while ( ptrayItem ) { if ( SYSTRAY_ItemIsEqual(pnid, &ptrayItem->notifyIcon) ) {
LeaveCriticalSection(&systray_lock); if (pnid->uFlags & NIF_ICON) SYSTRAY_ItemSetIcon(ptrayItem, pnid->hIcon); if (pnid->uFlags & NIF_MESSAGE)
@@ -321,6 +392,7 @@ } ptrayItem = ptrayItem->nextTrayItem; }
- LeaveCriticalSection(&systray_lock); return FALSE; /* not found */
}
@@ -329,6 +401,9 @@ { SystrayItem **ptrayItem = &systray;
- TRACE("%p\n", pnid);
- EnterCriticalSection(&systray_lock); while (*ptrayItem) { if (SYSTRAY_ItemIsEqual(pnid, &(*ptrayItem)->notifyIcon)) { SystrayItem *next = (*ptrayItem)->nextTrayItem;
@@ -338,10 +413,12 @@ free(*ptrayItem); *ptrayItem = next;
LeaveCriticalSection(&systray_lock); return TRUE;
} ptrayItem = &((*ptrayItem)->nextTrayItem); }
LeaveCriticalSection(&systray_lock);
return FALSE; /* not found */
} Index: dlls/x11drv/event.c =================================================================== RCS file: /home/wine/wine/dlls/x11drv/event.c,v retrieving revision 1.29 diff -u -r1.29 event.c --- dlls/x11drv/event.c 21 Nov 2003 21:48:36 -0000 1.29 +++ dlls/x11drv/event.c 30 Nov 2003 16:08:37 -0000 @@ -3,6 +3,7 @@
- Copyright 1993 Alexandre Julliard
1999 Noel Borthwick
2003 Mike Hearn
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
@@ -51,10 +52,15 @@
WINE_DEFAULT_DEBUG_CHANNEL(event); WINE_DECLARE_DEBUG_CHANNEL(clipboard); +WINE_DECLARE_DEBUG_CHANNEL(systray);
/* X context to associate a hwnd to an X window */ extern XContext winContext;
+extern Atom systray_selection; +extern Window systray_window;
#define DndNotDnd -1 /* OffiX drag&drop */ #define DndUnknown 0 #define DndRawData 1 @@ -1213,7 +1219,47 @@ static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event ) { if (event->message_type != None && event->format == 32) {
- if (event->message_type == x11drv_atom(WM_PROTOCOLS))
- if (event->message_type == x11drv_atom(MANAGER)) {
- if (event->data.l[1] == systray_selection) {
TRACE_(systray)("New NETWM systray manager detected, id=%ld\n", event->data.l[2]);
/* NOTE: It turns out that the ability to detect when a new tray applet joins the
* desktop is not as helpful as you might think. In order to do something useful with it,
* we would need to be able to "store" icons unmapped as children of the root window while
* no tray applet is available.
*
* The basic problem is that tray icons are always destroyed when the applet is removed.
* This is apparently an issue with X itself, which the upcoming XFIXES extension should hopefully
* address. The EggTrayIcon code which will be soon moving into GTK+ doesn't attempt to handle this
* situation, so for now neither do we.
*
* This is theoretically fixable in Wine with enough work, we just have to modify the code in
* shell32/systray.c to save the image and recreate the window on demand. Exactly how the
* communication between the x11drv and shell32 takes place is left as an excercise for the
* reader.
* -mike (3rd August 2003)
*/
- }
- } else if (event->message_type == x11drv_atom(_XEMBED)) {
char* opcode;
- switch (event->data.l[1]) {
case 0: opcode = "XEMBED_EMBEDDED_NOTIFY"; break;
case 1: opcode = "XEMBED_WINDOW_ACTIVATE"; break;
case 2: opcode = "XEMBED_WINDOW_DEACTIVATE"; break;
case 3: opcode = "XEMBED_REQUEST_FOCUS"; break;
case 4: opcode = "XEMBED_FOCUS_IN"; break;
case 5: opcode = "XEMBED_FOCUS_OUT"; break;
case 6: opcode = "XEMBED_FOCUS_NEXT"; break;
case 7: opcode = "XEMEBD_FOCUS_PREV"; break;
case 10: opcode = "XEMBED_MODALITY_ON"; break;
case 11: opcode = "XEMBED_MODALITY_OFF"; break;
case 12: opcode = "XEMBED_REGISTER_ACCELERATOR"; break;
case 13: opcode = "XEMBED_UNREGISTER_ACCELERATOR"; break;
case 14: opcode = "XEMBED_ACTIVATE_ACCELERATOR"; break;
default: opcode = "[Unknown opcode]"; break;
- }
TRACE_(systray)("XEmbed message, opcode is %s : %ld\n", opcode, event->data.l[1]);
- /* we currently don't handle these messages */
- } else if (event->message_type == x11drv_atom(WM_PROTOCOLS)) handle_wm_protocols_message( hWnd, event ); else if (event->message_type == x11drv_atom(DndProtocol)) {
Index: dlls/x11drv/window.c
RCS file: /home/wine/wine/dlls/x11drv/window.c,v retrieving revision 1.65 diff -u -r1.65 window.c --- dlls/x11drv/window.c 21 Nov 2003 21:48:36 -0000 1.65 +++ dlls/x11drv/window.c 30 Nov 2003 16:08:37 -0000 @@ -4,6 +4,7 @@
- Copyright 1993, 1994, 1995, 1996, 2001 Alexandre Julliard
- Copyright 1993 David Metcalfe
- Copyright 1995, 1996 Alex Korobka
- Copyright 2003 Mike Hearn
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
@@ -24,6 +25,7 @@
#include <stdarg.h> #include <stdlib.h> +#include <stdio.h> #ifdef HAVE_UNISTD_H # include <unistd.h> #endif @@ -46,6 +48,7 @@ #include "mwm.h"
WINE_DEFAULT_DEBUG_CHANNEL(x11drv); +WINE_DECLARE_DEBUG_CHANNEL(systray);
extern Pixmap X11DRV_BITMAP_Pixmap( HBITMAP );
@@ -73,6 +76,7 @@ "WM_PROTOCOLS", "WM_DELETE_WINDOW", "WM_TAKE_FOCUS",
- "MANAGER", "KWM_DOCKWINDOW", "DndProtocol", "DndSelection",
@@ -81,6 +85,9 @@ "_NET_WM_PID", "_NET_WM_PING", "_NET_WM_NAME",
- "_XEMBED_INFO",
- "_XEMBED",
- "_NET_SYSTEM_TRAY_OPCODE", "XdndAware", "XdndEnter", "XdndPosition",
@@ -103,6 +110,14 @@ "text/richtext" };
+/* for XDG systray icons */ +Atom systray_selection; +Window systray_window; +#define SYSTEM_TRAY_REQUEST_DOCK 0 +#define SYSTEM_TRAY_BEGIN_MESSAGE 1 +#define SYSTEM_TRAY_CANCEL_MESSAGE 2
static LPCSTR whole_window_atom; static LPCSTR client_window_atom; static LPCSTR icon_window_atom; @@ -354,11 +369,60 @@ size_hints->min_height = size_hints->max_height; size_hints->flags |= PMinSize | PMaxSize; }
- if (win->dwExStyle & WS_EX_TRAYWINDOW) {
/* force the window to be the correct width */
size_hints->min_width = GetSystemMetrics(SM_CXSMICON) + 5; /* give some padding to make icons not bunched up */
- }
}XSetWMNormalHints( display, data->whole_window, size_hints ); XFree( size_hints );
}
+/***********************************************************************
X11DRV_systray_dock_window
- Docks the given X window with the NETWM system tray.
- */
+BOOL CALLBACK X11DRV_systray_dock_window( HWND hwnd, Display *display ) {
- WND* win = WIN_GetPtr((HWND)hwnd);
- struct x11drv_win_data *data = win->pDriverData;
- XEvent ev;
- unsigned long info[2];
- LONG exstyle;
- /* is the window a tray window? */
- if (IsWindowUnicode(hwnd))
- exstyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
- else
- exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
- if ( !(exstyle & WS_EX_TRAYWINDOW) ) return TRUE;
- TRACE_(systray)("Docking tray icon 0x%x\n", (int)hwnd);
- /* set XEMBED protocol data on the window */
- info[0] = 0; /* protocol version */
- info[1] = 0; /* mapped = true */
- XChangeProperty(display, data->whole_window, x11drv_atom(_XEMBED_INFO), x11drv_atom(_XEMBED_INFO), 32, PropModeReplace, (unsigned char*)info, 2);
- /* send the docking request message */
- memset(&ev, 0, sizeof(ev));
- ev.xclient.type = ClientMessage;
- ev.xclient.window = systray_window;
- ev.xclient.message_type = x11drv_atom(_NET_SYSTEM_TRAY_OPCODE);
- ev.xclient.format = 32;
- ev.xclient.data.l[0] = CurrentTime;
- ev.xclient.data.l[1] = SYSTEM_TRAY_REQUEST_DOCK;
- ev.xclient.data.l[2] = data->whole_window;
- XSendEvent(display, systray_window, False, NoEventMask, &ev);
- XSync(display, False);
- WIN_ReleasePtr(win);
- return TRUE;
+}
/***********************************************************************
X11DRV_set_wm_hints
@@ -408,7 +472,7 @@ set_size_hints( display, win );
/* systray properties (KDE only for now) */
- if (win->dwExStyle & WS_EX_TRAYWINDOW)
- if ((win->dwExStyle & WS_EX_TRAYWINDOW) && (systray_window == None)) { int val = 1; XChangeProperty( display, data->whole_window, x11drv_atom(KWM_DOCKWINDOW),
@@ -709,10 +773,19 @@ static void create_desktop( Display *display, WND *wndPtr ) { X11DRV_WND_DATA *data = wndPtr->pDriverData;
char *systray_buffer;
wine_tsx11_lock(); winContext = XUniqueContext(); XInternAtoms( display, (char **)atom_names, NB_XATOMS - FIRST_XATOM, False, X11DRV_Atoms );
/* we can't intern this with the rest as it depends on the screen we are connecting to */
systray_buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(char)*20);
sprintf(systray_buffer, "_NET_SYSTEM_TRAY_S%d", DefaultScreen(display));
systray_selection = XInternAtom(display, systray_buffer, False);
HeapFree(GetProcessHeap(), 0, systray_buffer);
wine_tsx11_unlock();
whole_window_atom = MAKEINTATOMA( GlobalAddAtomA( "__wine_x11_whole_window" ));
@@ -1109,6 +1182,14 @@ * we do a proper ShowWindow later on */ if (wndPtr->dwStyle & WS_VISIBLE) cs->style |= WS_VISIBLE;
- /* if it's a tray window, dock it */
- if (wndPtr->dwExStyle & WS_EX_TRAYWINDOW) {
/* get the tray window if present */
systray_window = XGetSelectionOwner(display, systray_selection);
if (systray_window != None)
- X11DRV_systray_dock_window(hwnd, display);
- }
- WIN_ReleaseWndPtr( wndPtr ); return TRUE;
Index: dlls/x11drv/x11drv.h
RCS file: /home/wine/wine/dlls/x11drv/x11drv.h,v retrieving revision 1.11 diff -u -r1.11 x11drv.h --- dlls/x11drv/x11drv.h 25 Nov 2003 03:27:38 -0000 1.11 +++ dlls/x11drv/x11drv.h 30 Nov 2003 16:08:37 -0000 @@ -387,6 +387,7 @@ XATOM_WM_PROTOCOLS, XATOM_WM_DELETE_WINDOW, XATOM_WM_TAKE_FOCUS,
- XATOM_MANAGER, XATOM_KWM_DOCKWINDOW, XATOM_DndProtocol, XATOM_DndSelection,
@@ -395,6 +396,9 @@ XATOM__NET_WM_PID, XATOM__NET_WM_PING, XATOM__NET_WM_NAME,
- XATOM__XEMBED_INFO,
- XATOM__XEMBED,
- XATOM__NET_SYSTEM_TRAY_OPCODE, XATOM_XdndAware, XATOM_XdndEnter, XATOM_XdndPosition,