Prevent lock-up with a focus loop between two top level unmanaged
[wine/multimedia.git] / windows / x11drv / event.c
blobe9022e949a6affc691a9b99472162522191af25c
1 /*
2 * X11 event driver
4 * Copyright 1993 Alexandre Julliard
5 * 1999 Noel Borthwick
6 */
8 #include "config.h"
10 #include <X11/Xatom.h>
11 #include <X11/keysym.h>
13 #include "ts_xlib.h"
14 #include "ts_xresource.h"
15 #include "ts_xutil.h"
16 #ifdef HAVE_LIBXXF86DGA2
17 #include "ts_xf86dga2.h"
18 #endif
20 #include <assert.h>
21 #include <string.h>
22 #include "wine/winuser16.h"
23 #include "shlobj.h" /* DROPFILES */
25 #include "clipboard.h"
26 #include "dce.h"
27 #include "debugtools.h"
28 #include "input.h"
29 #include "options.h"
30 #include "win.h"
31 #include "winpos.h"
32 #include "windef.h"
33 #include "winreg.h"
34 #include "x11drv.h"
35 #include "shellapi.h"
37 DEFAULT_DEBUG_CHANNEL(event);
38 DECLARE_DEBUG_CHANNEL(win);
40 /* X context to associate a hwnd to an X window */
41 extern XContext winContext;
43 extern Atom wmProtocols;
44 extern Atom wmDeleteWindow;
45 extern Atom dndProtocol;
46 extern Atom dndSelection;
48 #define DndNotDnd -1 /* OffiX drag&drop */
49 #define DndUnknown 0
50 #define DndRawData 1
51 #define DndFile 2
52 #define DndFiles 3
53 #define DndText 4
54 #define DndDir 5
55 #define DndLink 6
56 #define DndExe 7
58 #define DndEND 8
60 #define DndURL 128 /* KDE drag&drop */
62 /* The last X window which had the focus */
63 static Window glastXFocusWin = 0;
65 static const char * const event_names[] =
67 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
68 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
69 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
70 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
71 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
72 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
73 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
74 "ClientMessage", "MappingNotify"
78 static void EVENT_ProcessEvent( XEvent *event );
79 static BOOL X11DRV_CheckFocus(void);
81 /* Event handlers */
82 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event );
83 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event );
84 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple );
85 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event);
86 static void EVENT_PropertyNotify( XPropertyEvent *event );
87 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
89 extern void X11DRV_ButtonPress( HWND hwnd, XButtonEvent *event );
90 extern void X11DRV_ButtonRelease( HWND hwnd, XButtonEvent *event );
91 extern void X11DRV_MotionNotify( HWND hwnd, XMotionEvent *event );
92 extern void X11DRV_KeyEvent( HWND hwnd, XKeyEvent *event );
93 extern void X11DRV_KeymapNotify( HWND hwnd, XKeymapEvent *event );
94 extern void X11DRV_Expose( HWND hwnd, XExposeEvent *event );
95 extern void X11DRV_MapNotify( HWND hwnd, XMapEvent *event );
96 extern void X11DRV_UnmapNotify( HWND hwnd, XUnmapEvent *event );
97 extern void X11DRV_ConfigureNotify( HWND hwnd, XConfigureEvent *event );
98 extern void X11DRV_MappingNotify( XMappingEvent *event );
100 #ifdef HAVE_LIBXXF86DGA2
101 static int DGAMotionEventType;
102 static int DGAButtonPressEventType;
103 static int DGAButtonReleaseEventType;
104 static int DGAKeyPressEventType;
105 static int DGAKeyReleaseEventType;
107 static BOOL DGAUsed = FALSE;
108 static HWND DGAhwnd = 0;
110 extern void X11DRV_DGAMotionEvent( HWND hwnd, XDGAMotionEvent *event );
111 extern void X11DRV_DGAButtonPressEvent( HWND hwnd, XDGAButtonEvent *event );
112 extern void X11DRV_DGAButtonReleaseEvent( HWND hwnd, XDGAButtonEvent *event );
113 #endif
115 /* Static used for the current input method */
116 static INPUT_TYPE current_input_type = X11DRV_INPUT_ABSOLUTE;
117 static BOOL in_transition = FALSE; /* This is not used as for today */
120 /***********************************************************************
121 * process_events
123 static int process_events( struct x11drv_thread_data *data )
125 XEvent event;
126 int count = 0;
128 wine_tsx11_lock();
129 while ( XPending( data->display ) )
131 XNextEvent( data->display, &event );
132 wine_tsx11_unlock();
133 EVENT_ProcessEvent( &event );
134 count++;
135 wine_tsx11_lock();
137 wine_tsx11_unlock();
138 return count;
142 /***********************************************************************
143 * MsgWaitForMultipleObjectsEx (X11DRV.@)
145 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
146 DWORD timeout, DWORD mask, DWORD flags )
148 HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1]; /* FIXME! */
149 DWORD i, ret;
150 struct x11drv_thread_data *data = NtCurrentTeb()->driver_data;
152 if (!data || data->process_event_count)
153 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
154 timeout, flags & MWMO_ALERTABLE );
156 for (i = 0; i < count; i++) new_handles[i] = handles[i];
157 new_handles[count] = data->display_fd;
159 wine_tsx11_lock();
160 XFlush( gdi_display );
161 XFlush( data->display );
162 wine_tsx11_unlock();
164 data->process_event_count++;
165 if (process_events( data )) ret = count;
166 else
168 ret = WaitForMultipleObjectsEx( count+1, new_handles, flags & MWMO_WAITALL,
169 timeout, flags & MWMO_ALERTABLE );
170 if (ret == count) process_events( data );
172 data->process_event_count--;
173 return ret;
177 /***********************************************************************
178 * EVENT_ProcessEvent
180 * Process an X event.
182 static void EVENT_ProcessEvent( XEvent *event )
184 HWND hWnd;
185 Display *display = event->xany.display;
187 TRACE( "called.\n" );
189 switch (event->type)
191 case SelectionNotify: /* all of these should be caught by XCheckTypedWindowEvent() */
192 FIXME("Got SelectionNotify - must not happen!\n");
193 /* fall through */
195 /* We get all these because of StructureNotifyMask.
196 This check is placed here to avoid getting error messages below,
197 as X might send some of these even for windows that have already
198 been deleted ... */
199 case CirculateNotify:
200 case CreateNotify:
201 case DestroyNotify:
202 case GravityNotify:
203 case ReparentNotify:
204 return;
207 #ifdef HAVE_LIBXXF86DGA2
208 if (DGAUsed) {
209 if (event->type == DGAMotionEventType) {
210 TRACE("DGAMotionEvent received.\n");
211 X11DRV_DGAMotionEvent( DGAhwnd, (XDGAMotionEvent *)event );
212 return;
214 if (event->type == DGAButtonPressEventType) {
215 TRACE("DGAButtonPressEvent received.\n");
216 X11DRV_DGAButtonPressEvent( DGAhwnd, (XDGAButtonEvent *)event );
217 return;
219 if (event->type == DGAButtonReleaseEventType) {
220 TRACE("DGAButtonReleaseEvent received.\n");
221 X11DRV_DGAButtonReleaseEvent( DGAhwnd, (XDGAButtonEvent *)event );
222 return;
224 if ((event->type == DGAKeyPressEventType) ||
225 (event->type == DGAKeyReleaseEventType)) {
226 /* Fill a XKeyEvent to send to EVENT_Key */
227 XKeyEvent ke;
228 XDGAKeyEvent *evt = (XDGAKeyEvent *) event;
230 TRACE("DGAKeyPress/ReleaseEvent received.\n");
232 if (evt->type == DGAKeyReleaseEventType)
233 ke.type = KeyRelease;
234 else
235 ke.type = KeyPress;
236 ke.serial = evt->serial;
237 ke.send_event = FALSE;
238 ke.display = evt->display;
239 ke.window = 0;
240 ke.root = 0;
241 ke.subwindow = 0;
242 ke.time = evt->time;
243 ke.x = -1;
244 ke.y = -1;
245 ke.x_root = -1;
246 ke.y_root = -1;
247 ke.state = evt->state;
248 ke.keycode = evt->keycode;
249 ke.same_screen = TRUE;
250 X11DRV_KeyEvent( 0, &ke );
251 return;
254 #endif
256 if (TSXFindContext( display, event->xany.window, winContext, (char **)&hWnd ) != 0)
257 hWnd = 0; /* Not for a registered window */
259 if ( !hWnd && event->xany.window != root_window
260 && event->type != PropertyNotify
261 && event->type != MappingNotify)
262 WARN( "Got event %s for unknown Window %08lx\n",
263 event_names[event->type], event->xany.window );
264 else
265 TRACE("Got event %s for hwnd %04x\n",
266 event_names[event->type], hWnd );
268 switch(event->type)
270 case KeyPress:
271 case KeyRelease:
272 /* FIXME: should generate a motion event if event point is different from current pos */
273 X11DRV_KeyEvent( hWnd, (XKeyEvent*)event );
274 break;
276 case ButtonPress:
277 X11DRV_ButtonPress( hWnd, (XButtonEvent*)event );
278 break;
280 case ButtonRelease:
281 X11DRV_ButtonRelease( hWnd, (XButtonEvent*)event );
282 break;
284 case MotionNotify:
285 X11DRV_MotionNotify( hWnd, (XMotionEvent*)event );
286 break;
288 case FocusIn:
289 EVENT_FocusIn( hWnd, (XFocusChangeEvent*)event );
290 break;
292 case FocusOut:
293 EVENT_FocusOut( hWnd, (XFocusChangeEvent*)event );
294 break;
296 case Expose:
297 X11DRV_Expose( hWnd, &event->xexpose );
298 break;
300 case ConfigureNotify:
301 if (!hWnd) return;
302 X11DRV_ConfigureNotify( hWnd, &event->xconfigure );
303 break;
305 case SelectionRequest:
306 if (!hWnd) return;
307 EVENT_SelectionRequest( hWnd, (XSelectionRequestEvent *)event, FALSE );
308 break;
310 case SelectionClear:
311 if (!hWnd) return;
312 EVENT_SelectionClear( hWnd, (XSelectionClearEvent*) event );
313 break;
315 case PropertyNotify:
316 EVENT_PropertyNotify( (XPropertyEvent *)event );
317 break;
319 case ClientMessage:
320 if (!hWnd) return;
321 EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event );
322 break;
324 case NoExpose:
325 break;
327 case MapNotify:
328 X11DRV_MapNotify( hWnd, (XMapEvent *)event );
329 break;
331 case UnmapNotify:
332 X11DRV_UnmapNotify( hWnd, (XUnmapEvent *)event );
333 break;
335 case KeymapNotify:
336 X11DRV_KeymapNotify( hWnd, (XKeymapEvent *)event );
337 break;
339 case MappingNotify:
340 X11DRV_MappingNotify( (XMappingEvent *) event );
341 break;
343 default:
344 WARN("Unprocessed event %s for hwnd %04x\n",
345 event_names[event->type], hWnd );
346 break;
348 TRACE( "returns.\n" );
352 /**********************************************************************
353 * EVENT_FocusIn
355 static void EVENT_FocusIn( HWND hWnd, XFocusChangeEvent *event )
357 WND *pWndLastFocus;
358 XWindowAttributes win_attr;
359 BOOL bIsDisabled;
361 if (!hWnd) return;
363 bIsDisabled = GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED;
365 /* If the window has been disabled and we are in managed mode,
366 * revert the X focus back to the last focus window. This is to disallow
367 * the window manager from switching focus away while the app is
368 * in a modal state.
370 if ( Options.managed && bIsDisabled && glastXFocusWin)
372 /* Change focus only if saved focus window is registered and viewable */
373 wine_tsx11_lock();
374 if (XFindContext( event->display, glastXFocusWin, winContext,
375 (char **)&pWndLastFocus ) == 0 )
377 if (XGetWindowAttributes( event->display, glastXFocusWin, &win_attr ) &&
378 (win_attr.map_state == IsViewable) )
380 XSetInputFocus( event->display, glastXFocusWin, RevertToParent, CurrentTime );
381 wine_tsx11_unlock();
382 return;
385 wine_tsx11_unlock();
388 if (event->detail != NotifyPointer && event->detail != NotifyNonlinear && hWnd != GetForegroundWindow())
389 SetForegroundWindow( hWnd );
393 /**********************************************************************
394 * EVENT_FocusOut
396 * Note: only top-level override-redirect windows get FocusOut events.
398 static void EVENT_FocusOut( HWND hWnd, XFocusChangeEvent *event )
400 /* Save the last window which had the focus */
401 glastXFocusWin = event->window;
402 if (!hWnd) return;
403 if (GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED) glastXFocusWin = 0;
405 if (event->detail != NotifyPointer && hWnd == GetForegroundWindow())
407 /* don't reset the foreground window, if the window which is
408 getting the focus is a Wine window */
409 if (!X11DRV_CheckFocus())
411 SendMessageA( hWnd, WM_CANCELMODE, 0, 0 );
412 /* Abey : 6-Oct-99. Check again if the focus out window is the
413 Foreground window, because in most cases the messages sent
414 above must have already changed the foreground window, in which
415 case we don't have to change the foreground window to 0 */
417 if (hWnd == GetForegroundWindow())
418 SetForegroundWindow( 0 );
423 /**********************************************************************
424 * CheckFocus (X11DRV.@)
426 static BOOL X11DRV_CheckFocus(void)
428 Display *display = thread_display();
429 HWND hWnd;
430 Window xW;
431 int state;
433 TSXGetInputFocus(display, &xW, &state);
434 if( xW == None ||
435 TSXFindContext(display, xW, winContext, (char **)&hWnd) )
436 return FALSE;
437 return TRUE;
441 /***********************************************************************
442 * EVENT_SelectionRequest_TARGETS
443 * Service a TARGETS selection request event
445 static Atom EVENT_SelectionRequest_TARGETS( Display *display, Window requestor,
446 Atom target, Atom rprop )
448 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
449 Atom* targets;
450 Atom prop;
451 UINT wFormat;
452 unsigned long cTargets;
453 BOOL bHavePixmap;
454 int xRc;
456 TRACE("Request for %s\n", TSXGetAtomName(display, target));
459 * Count the number of items we wish to expose as selection targets.
460 * We include the TARGETS item, and a PIXMAP if we have CF_DIB or CF_BITMAP
462 cTargets = CountClipboardFormats() + 1;
463 if ( CLIPBOARD_IsPresent(CF_DIB) || CLIPBOARD_IsPresent(CF_BITMAP) )
464 cTargets++;
466 /* Allocate temp buffer */
467 targets = (Atom*)HeapAlloc( GetProcessHeap(), 0, cTargets * sizeof(Atom));
468 if(targets == NULL) return None;
470 /* Create TARGETS property list (First item in list is TARGETS itself) */
472 for ( targets[0] = xaTargets, cTargets = 1, wFormat = 0, bHavePixmap = FALSE;
473 (wFormat = EnumClipboardFormats( wFormat )); )
475 if ( (prop = X11DRV_CLIPBOARD_MapFormatToProperty(wFormat)) != None )
477 /* Scan through what we have so far to avoid duplicates */
478 int i;
479 BOOL bExists;
480 for (i = 0, bExists = FALSE; i < cTargets; i++)
482 if (targets[i] == prop)
484 bExists = TRUE;
485 break;
488 if (!bExists)
490 targets[cTargets++] = prop;
492 /* Add PIXMAP prop for bitmaps additionally */
493 if ( (wFormat == CF_DIB || wFormat == CF_BITMAP )
494 && !bHavePixmap )
496 targets[cTargets++] = XA_PIXMAP;
497 bHavePixmap = TRUE;
503 if (TRACE_ON(event))
505 int i;
506 for ( i = 0; i < cTargets; i++)
508 if (targets[i])
510 char *itemFmtName = TSXGetAtomName(display, targets[i]);
511 TRACE("\tAtom# %d: Type %s\n", i, itemFmtName);
512 TSXFree(itemFmtName);
517 /* Update the X property */
518 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
520 /* We may want to consider setting the type to xaTargets instead,
521 * in case some apps expect this instead of XA_ATOM */
522 xRc = TSXChangeProperty(display, requestor, rprop,
523 XA_ATOM, 32, PropModeReplace,
524 (unsigned char *)targets, cTargets);
525 TRACE("(Rc=%d)\n", xRc);
527 HeapFree( GetProcessHeap(), 0, targets );
529 return rprop;
533 /***********************************************************************
534 * EVENT_SelectionRequest_STRING
535 * Service a STRING selection request event
537 static Atom EVENT_SelectionRequest_STRING( Display *display, Window requestor,
538 Atom target, Atom rprop )
540 static UINT text_cp = (UINT)-1;
541 HANDLE hUnicodeText;
542 LPWSTR uni_text;
543 LPSTR text;
544 int size,i,j;
545 char* lpstr = 0;
546 char *itemFmtName;
547 int xRc;
549 if(text_cp == (UINT)-1)
551 HKEY hkey;
552 /* default value */
553 text_cp = CP_ACP;
554 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
556 char buf[20];
557 DWORD type, count = sizeof(buf);
558 if(!RegQueryValueExA(hkey, "TextCP", 0, &type, buf, &count))
559 text_cp = atoi(buf);
560 RegCloseKey(hkey);
565 * Map the requested X selection property type atom name to a
566 * windows clipboard format ID.
568 itemFmtName = TSXGetAtomName(display, target);
569 TRACE("Request for %s (wFormat=%x %s)\n",
570 itemFmtName, CF_UNICODETEXT, CLIPBOARD_GetFormatName(CF_UNICODETEXT));
571 TSXFree(itemFmtName);
573 hUnicodeText = GetClipboardData(CF_UNICODETEXT);
574 if(!hUnicodeText)
575 return None;
576 uni_text = GlobalLock(hUnicodeText);
577 if(!uni_text)
578 return None;
580 size = WideCharToMultiByte(text_cp, 0, uni_text, -1, NULL, 0, NULL, NULL);
581 text = HeapAlloc(GetProcessHeap(), 0, size);
582 if (!text)
583 return None;
584 WideCharToMultiByte(text_cp, 0, uni_text, -1, text, size, NULL, NULL);
586 /* remove carriage returns */
588 lpstr = (char*)HeapAlloc( GetProcessHeap(), 0, size-- );
589 if(lpstr == NULL) return None;
590 for(i=0,j=0; i < size && text[i]; i++ )
592 if( text[i] == '\r' &&
593 (text[i+1] == '\n' || text[i+1] == '\0') ) continue;
594 lpstr[j++] = text[i];
596 lpstr[j]='\0';
598 /* Update the X property */
599 TRACE("\tUpdating property %s...\n", TSXGetAtomName(display, rprop));
600 xRc = TSXChangeProperty(display, requestor, rprop,
601 XA_STRING, 8, PropModeReplace,
602 lpstr, j);
603 TRACE("(Rc=%d)\n", xRc);
605 GlobalUnlock(hUnicodeText);
606 HeapFree(GetProcessHeap(), 0, text);
607 HeapFree( GetProcessHeap(), 0, lpstr );
609 return rprop;
612 /***********************************************************************
613 * EVENT_SelectionRequest_PIXMAP
614 * Service a PIXMAP selection request event
616 static Atom EVENT_SelectionRequest_PIXMAP( Display *display, Window requestor,
617 Atom target, Atom rprop )
619 HANDLE hClipData = 0;
620 Pixmap pixmap = 0;
621 UINT wFormat;
622 char * itemFmtName;
623 int xRc;
624 #if(0)
625 XSetWindowAttributes win_attr;
626 XWindowAttributes win_attr_src;
627 #endif
630 * Map the requested X selection property type atom name to a
631 * windows clipboard format ID.
633 itemFmtName = TSXGetAtomName(display, target);
634 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
635 TRACE("Request for %s (wFormat=%x %s)\n",
636 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
637 TSXFree(itemFmtName);
639 hClipData = GetClipboardData(wFormat);
640 if ( !hClipData )
642 TRACE("Could not retrieve a Pixmap compatible format from clipboard!\n");
643 rprop = None; /* Fail the request */
644 goto END;
647 if (wFormat == CF_DIB)
649 HWND hwnd = GetOpenClipboardWindow();
650 HDC hdc = GetDC(hwnd);
652 /* For convert from packed DIB to Pixmap */
653 pixmap = X11DRV_DIB_CreatePixmapFromDIB(hClipData, hdc);
655 ReleaseDC(hwnd, hdc);
657 else if (wFormat == CF_BITMAP)
659 HWND hwnd = GetOpenClipboardWindow();
660 HDC hdc = GetDC(hwnd);
662 pixmap = X11DRV_BITMAP_CreatePixmapFromBitmap(hClipData, hdc);
664 ReleaseDC(hwnd, hdc);
666 else
668 FIXME("%s to PIXMAP conversion not yet implemented!\n",
669 CLIPBOARD_GetFormatName(wFormat));
670 rprop = None;
671 goto END;
674 TRACE("\tUpdating property %s on Window %ld with %s %ld...\n",
675 TSXGetAtomName(display, rprop), (long)requestor,
676 TSXGetAtomName(display, target), pixmap);
678 /* Store the Pixmap handle in the property */
679 xRc = TSXChangeProperty(display, requestor, rprop, target,
680 32, PropModeReplace,
681 (unsigned char *)&pixmap, 1);
682 TRACE("(Rc=%d)\n", xRc);
684 /* Enable the code below if you want to handle destroying Pixmap resources
685 * in response to property notify events. Clients like XPaint don't
686 * appear to be duplicating Pixmaps so they don't like us deleting,
687 * the resource in response to the property being deleted.
689 #if(0)
690 /* Express interest in property notify events so that we can delete the
691 * pixmap when the client deletes the property atom.
693 xRc = TSXGetWindowAttributes(display, requestor, &win_attr_src);
694 TRACE("Turning on PropertyChangeEvent notifications from window %ld\n",
695 (long)requestor);
696 win_attr.event_mask = win_attr_src.your_event_mask | PropertyChangeMask;
697 TSXChangeWindowAttributes(display, requestor, CWEventMask, &win_attr);
699 /* Register the Pixmap we created with the request property Atom.
700 * When this property is destroyed we also destroy the Pixmap in
701 * response to the PropertyNotify event.
703 X11DRV_CLIPBOARD_RegisterPixmapResource( rprop, pixmap );
704 #endif
706 END:
707 return rprop;
711 /***********************************************************************
712 * EVENT_SelectionRequest_WCF
713 * Service a Wine Clipboard Format selection request event.
714 * For <WCF>* data types we simply copy the data to X without conversion.
716 static Atom EVENT_SelectionRequest_WCF( Display *display, Window requestor,
717 Atom target, Atom rprop )
719 HANDLE hClipData = 0;
720 void* lpClipData;
721 UINT wFormat;
722 char * itemFmtName;
723 int cBytes;
724 int xRc;
727 * Map the requested X selection property type atom name to a
728 * windows clipboard format ID.
730 itemFmtName = TSXGetAtomName(display, target);
731 wFormat = X11DRV_CLIPBOARD_MapPropertyToFormat(itemFmtName);
732 TRACE("Request for %s (wFormat=%x %s)\n",
733 itemFmtName, wFormat, CLIPBOARD_GetFormatName( wFormat));
734 TSXFree(itemFmtName);
736 hClipData = GetClipboardData(wFormat);
738 if( hClipData && (lpClipData = GlobalLock(hClipData)) )
740 cBytes = GlobalSize(hClipData);
742 TRACE("\tUpdating property %s, %d bytes...\n",
743 TSXGetAtomName(display, rprop), cBytes);
745 xRc = TSXChangeProperty(display, requestor, rprop,
746 target, 8, PropModeReplace,
747 (unsigned char *)lpClipData, cBytes);
748 TRACE("(Rc=%d)\n", xRc);
750 GlobalUnlock(hClipData);
752 else
754 TRACE("\tCould not retrieve native format!\n");
755 rprop = None; /* Fail the request */
758 return rprop;
762 /***********************************************************************
763 * EVENT_SelectionRequest_MULTIPLE
764 * Service a MULTIPLE selection request event
765 * rprop contains a list of (target,property) atom pairs.
766 * The first atom names a target and the second names a property.
767 * The effect is as if we have received a sequence of SelectionRequest events
768 * (one for each atom pair) except that:
769 * 1. We reply with a SelectionNotify only when all the requested conversions
770 * have been performed.
771 * 2. If we fail to convert the target named by an atom in the MULTIPLE property,
772 * we replace the atom in the property by None.
774 static Atom EVENT_SelectionRequest_MULTIPLE( HWND hWnd, XSelectionRequestEvent *pevent )
776 Display *display = pevent->display;
777 Atom rprop;
778 Atom atype=AnyPropertyType;
779 int aformat;
780 unsigned long remain;
781 Atom* targetPropList=NULL;
782 unsigned long cTargetPropList = 0;
783 /* Atom xAtomPair = TSXInternAtom(display, "ATOM_PAIR", False); */
785 /* If the specified property is None the requestor is an obsolete client.
786 * We support these by using the specified target atom as the reply property.
788 rprop = pevent->property;
789 if( rprop == None )
790 rprop = pevent->target;
791 if (!rprop)
792 goto END;
794 /* Read the MULTIPLE property contents. This should contain a list of
795 * (target,property) atom pairs.
797 if(TSXGetWindowProperty(display, pevent->requestor, rprop,
798 0, 0x3FFF, False, AnyPropertyType, &atype,&aformat,
799 &cTargetPropList, &remain,
800 (unsigned char**)&targetPropList) != Success)
801 TRACE("\tCouldn't read MULTIPLE property\n");
802 else
804 TRACE("\tType %s,Format %d,nItems %ld, Remain %ld\n",
805 TSXGetAtomName(display, atype), aformat, cTargetPropList, remain);
808 * Make sure we got what we expect.
809 * NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
810 * in a MULTIPLE selection request should be of type ATOM_PAIR.
811 * However some X apps(such as XPaint) are not compliant with this and return
812 * a user defined atom in atype when XGetWindowProperty is called.
813 * The data *is* an atom pair but is not denoted as such.
815 if(aformat == 32 /* atype == xAtomPair */ )
817 int i;
819 /* Iterate through the ATOM_PAIR list and execute a SelectionRequest
820 * for each (target,property) pair */
822 for (i = 0; i < cTargetPropList; i+=2)
824 char *targetName = TSXGetAtomName(display, targetPropList[i]);
825 char *propName = TSXGetAtomName(display, targetPropList[i+1]);
826 XSelectionRequestEvent event;
828 TRACE("MULTIPLE(%d): Target='%s' Prop='%s'\n",
829 i/2, targetName, propName);
830 TSXFree(targetName);
831 TSXFree(propName);
833 /* We must have a non "None" property to service a MULTIPLE target atom */
834 if ( !targetPropList[i+1] )
836 TRACE("\tMULTIPLE(%d): Skipping target with empty property!\n", i);
837 continue;
840 /* Set up an XSelectionRequestEvent for this (target,property) pair */
841 memcpy( &event, pevent, sizeof(XSelectionRequestEvent) );
842 event.target = targetPropList[i];
843 event.property = targetPropList[i+1];
845 /* Fire a SelectionRequest, informing the handler that we are processing
846 * a MULTIPLE selection request event.
848 EVENT_SelectionRequest( hWnd, &event, TRUE );
852 /* Free the list of targets/properties */
853 TSXFree(targetPropList);
856 END:
857 return rprop;
861 /***********************************************************************
862 * EVENT_SelectionRequest
863 * Process an event selection request event.
864 * The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
865 * recursively while servicing a "MULTIPLE" selection target.
867 * Note: We only receive this event when WINE owns the X selection
869 static void EVENT_SelectionRequest( HWND hWnd, XSelectionRequestEvent *event, BOOL bIsMultiple )
871 Display *display = event->display;
872 XSelectionEvent result;
873 Atom rprop = None;
874 Window request = event->requestor;
875 BOOL couldOpen = FALSE;
876 Atom xaClipboard = TSXInternAtom(display, "CLIPBOARD", False);
877 Atom xaTargets = TSXInternAtom(display, "TARGETS", False);
878 Atom xaMultiple = TSXInternAtom(display, "MULTIPLE", False);
881 * We can only handle the selection request if :
882 * The selection is PRIMARY or CLIPBOARD, AND we can successfully open the clipboard.
883 * Don't do these checks or open the clipboard while recursively processing MULTIPLE,
884 * since this has been already done.
886 if ( !bIsMultiple )
888 if ( ( (event->selection != XA_PRIMARY) && (event->selection != xaClipboard) )
889 || !(couldOpen = OpenClipboard(hWnd)) )
890 goto END;
893 /* If the specified property is None the requestor is an obsolete client.
894 * We support these by using the specified target atom as the reply property.
896 rprop = event->property;
897 if( rprop == None )
898 rprop = event->target;
900 if(event->target == xaTargets) /* Return a list of all supported targets */
902 /* TARGETS selection request */
903 rprop = EVENT_SelectionRequest_TARGETS( display, request, event->target, rprop );
905 else if(event->target == xaMultiple) /* rprop contains a list of (target, property) atom pairs */
907 /* MULTIPLE selection request */
908 rprop = EVENT_SelectionRequest_MULTIPLE( hWnd, event );
910 else if(event->target == XA_STRING) /* treat CF_TEXT as Unix text */
912 /* XA_STRING selection request */
913 rprop = EVENT_SelectionRequest_STRING( display, request, event->target, rprop );
915 else if(event->target == XA_PIXMAP) /* Convert DIB's to Pixmaps */
917 /* XA_PIXMAP selection request */
918 rprop = EVENT_SelectionRequest_PIXMAP( display, request, event->target, rprop );
920 else if(event->target == XA_BITMAP) /* Convert DIB's to 1-bit Pixmaps */
922 /* XA_BITMAP selection request - TODO: create a monochrome Pixmap */
923 rprop = EVENT_SelectionRequest_PIXMAP( display, request, XA_PIXMAP, rprop );
925 else if(X11DRV_CLIPBOARD_IsNativeProperty(event->target)) /* <WCF>* */
927 /* All <WCF> selection requests */
928 rprop = EVENT_SelectionRequest_WCF( display, request, event->target, rprop );
930 else
931 rprop = None; /* Don't support this format */
933 END:
934 /* close clipboard only if we opened before */
935 if(couldOpen) CloseClipboard();
937 if( rprop == None)
938 TRACE("\tRequest ignored\n");
940 /* reply to sender
941 * SelectionNotify should be sent only at the end of a MULTIPLE request
943 if ( !bIsMultiple )
945 result.type = SelectionNotify;
946 result.display = display;
947 result.requestor = request;
948 result.selection = event->selection;
949 result.property = rprop;
950 result.target = event->target;
951 result.time = event->time;
952 TRACE("Sending SelectionNotify event...\n");
953 TSXSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
957 /***********************************************************************
958 * EVENT_SelectionClear
960 static void EVENT_SelectionClear( HWND hWnd, XSelectionClearEvent *event )
962 Atom xaClipboard = TSXInternAtom(event->display, "CLIPBOARD", False);
964 if (event->selection == XA_PRIMARY || event->selection == xaClipboard)
965 X11DRV_CLIPBOARD_ReleaseSelection( event->selection, event->window, hWnd );
968 /***********************************************************************
969 * EVENT_PropertyNotify
970 * We use this to release resources like Pixmaps when a selection
971 * client no longer needs them.
973 static void EVENT_PropertyNotify( XPropertyEvent *event )
975 /* Check if we have any resources to free */
976 TRACE("Received PropertyNotify event: \n");
978 switch(event->state)
980 case PropertyDelete:
982 TRACE("\tPropertyDelete for atom %s on window %ld\n",
983 TSXGetAtomName(event->display, event->atom), (long)event->window);
985 if (X11DRV_IsSelectionOwner())
986 X11DRV_CLIPBOARD_FreeResources( event->atom );
987 break;
990 case PropertyNewValue:
992 TRACE("\tPropertyNewValue for atom %s on window %ld\n\n",
993 TSXGetAtomName(event->display, event->atom), (long)event->window);
994 break;
997 default:
998 break;
1002 /**********************************************************************
1003 * EVENT_DropFromOffix
1005 * don't know if it still works (last Changlog is from 96/11/04)
1007 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
1009 unsigned long data_length;
1010 unsigned long aux_long;
1011 unsigned char* p_data = NULL;
1012 union {
1013 Atom atom_aux;
1014 struct {
1015 int x;
1016 int y;
1017 } pt_aux;
1018 int i;
1019 } u;
1020 int x, y;
1021 BOOL16 bAccept;
1022 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, sizeof(DRAGINFO16));
1023 LPDRAGINFO16 lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
1024 SEGPTR spDragInfo = K32WOWGlobalLock16(hDragInfo);
1025 Window w_aux_root, w_aux_child;
1026 WND* pWnd;
1028 if( !lpDragInfo || !spDragInfo ) return;
1030 pWnd = WIN_FindWndPtr(hWnd);
1032 TSXQueryPointer( event->display, get_whole_window(pWnd), &w_aux_root, &w_aux_child,
1033 &x, &y, (int *) &u.pt_aux.x, (int *) &u.pt_aux.y,
1034 (unsigned int*)&aux_long);
1036 lpDragInfo->hScope = hWnd;
1037 lpDragInfo->pt.x = (INT16)x; lpDragInfo->pt.y = (INT16)y;
1039 /* find out drop point and drop window */
1040 if( x < 0 || y < 0 ||
1041 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
1042 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
1043 { bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES; x = y = 0; }
1044 else
1046 bAccept = DRAG_QueryUpdate( hWnd, spDragInfo, TRUE );
1047 x = lpDragInfo->pt.x; y = lpDragInfo->pt.y;
1049 WIN_ReleaseWndPtr(pWnd);
1051 GlobalFree16( hDragInfo );
1053 if (!bAccept) return;
1055 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1056 dndSelection, 0, 65535, FALSE,
1057 AnyPropertyType, &u.atom_aux, (int *) &u.pt_aux.y,
1058 &data_length, &aux_long, &p_data);
1060 if( !aux_long && p_data) /* don't bother if > 64K */
1062 signed char *p = (signed char*) p_data;
1063 char *p_drop;
1065 aux_long = 0;
1066 while( *p ) /* calculate buffer size */
1068 p_drop = p;
1069 if((u.i = *p) != -1 )
1071 INT len = GetShortPathNameA( p, NULL, 0 );
1072 if (len) aux_long += len + 1;
1073 else *p = -1;
1075 p += strlen(p) + 1;
1077 if( aux_long && aux_long < 65535 )
1079 HDROP hDrop;
1080 DROPFILES *lpDrop;
1082 aux_long += sizeof(DROPFILES) + 1;
1083 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
1084 lpDrop = (DROPFILES*)GlobalLock( hDrop );
1086 if( lpDrop )
1088 WND *pDropWnd = WIN_FindWndPtr( lpDragInfo->hScope );
1089 lpDrop->pFiles = sizeof(DROPFILES);
1090 lpDrop->pt.x = x;
1091 lpDrop->pt.y = y;
1092 lpDrop->fNC =
1093 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1094 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1095 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1096 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1097 lpDrop->fWide = FALSE;
1098 WIN_ReleaseWndPtr(pDropWnd);
1099 p_drop = (char *)(lpDrop + 1);
1100 p = p_data;
1101 while(*p)
1103 if( *p != -1 ) /* use only "good" entries */
1105 GetShortPathNameA( p, p_drop, 65535 );
1106 p_drop += strlen( p_drop ) + 1;
1108 p += strlen(p) + 1;
1110 *p_drop = '\0';
1111 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1115 if( p_data ) TSXFree(p_data);
1118 /**********************************************************************
1119 * EVENT_DropURLs
1121 * drop items are separated by \n
1122 * each item is prefixed by its mime type
1124 * event->data.l[3], event->data.l[4] contains drop x,y position
1126 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
1128 unsigned long data_length;
1129 unsigned long aux_long, drop_len = 0;
1130 unsigned char *p_data = NULL; /* property data */
1131 char *p_drop = NULL;
1132 char *p, *next;
1133 int x, y;
1134 DROPFILES *lpDrop;
1135 HDROP hDrop;
1136 union {
1137 Atom atom_aux;
1138 int i;
1139 Window w_aux;
1140 } u; /* unused */
1142 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
1144 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1145 dndSelection, 0, 65535, FALSE,
1146 AnyPropertyType, &u.atom_aux, &u.i,
1147 &data_length, &aux_long, &p_data);
1148 if (aux_long)
1149 WARN("property too large, truncated!\n");
1150 TRACE("urls=%s\n", p_data);
1152 if( !aux_long && p_data) { /* don't bother if > 64K */
1153 /* calculate length */
1154 p = p_data;
1155 next = strchr(p, '\n');
1156 while (p) {
1157 if (next) *next=0;
1158 if (strncmp(p,"file:",5) == 0 ) {
1159 INT len = GetShortPathNameA( p+5, NULL, 0 );
1160 if (len) drop_len += len + 1;
1162 if (next) {
1163 *next = '\n';
1164 p = next + 1;
1165 next = strchr(p, '\n');
1166 } else {
1167 p = NULL;
1171 if( drop_len && drop_len < 65535 ) {
1172 TSXQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
1173 &x, &y, &u.i, &u.i, &u.i);
1175 drop_len += sizeof(DROPFILES) + 1;
1176 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
1177 lpDrop = (DROPFILES *) GlobalLock( hDrop );
1179 if( lpDrop ) {
1180 WND *pDropWnd = WIN_FindWndPtr( hWnd );
1181 lpDrop->pFiles = sizeof(DROPFILES);
1182 lpDrop->pt.x = (INT)x;
1183 lpDrop->pt.y = (INT)y;
1184 lpDrop->fNC =
1185 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
1186 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
1187 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
1188 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
1189 lpDrop->fWide = FALSE;
1190 p_drop = (char*)(lpDrop + 1);
1191 WIN_ReleaseWndPtr(pDropWnd);
1194 /* create message content */
1195 if (p_drop) {
1196 p = p_data;
1197 next = strchr(p, '\n');
1198 while (p) {
1199 if (next) *next=0;
1200 if (strncmp(p,"file:",5) == 0 ) {
1201 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
1202 if (len) {
1203 TRACE("drop file %s as %s\n", p+5, p_drop);
1204 p_drop += len+1;
1205 } else {
1206 WARN("can't convert file %s to dos name \n", p+5);
1208 } else {
1209 WARN("unknown mime type %s\n", p);
1211 if (next) {
1212 *next = '\n';
1213 p = next + 1;
1214 next = strchr(p, '\n');
1215 } else {
1216 p = NULL;
1218 *p_drop = '\0';
1221 GlobalUnlock(hDrop);
1222 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
1225 if( p_data ) TSXFree(p_data);
1229 /**********************************************************************
1230 * EVENT_ClientMessage
1232 static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
1234 if (event->message_type != None && event->format == 32) {
1235 if ((event->message_type == wmProtocols) &&
1236 (((Atom) event->data.l[0]) == wmDeleteWindow))
1238 /* Ignore the delete window request if the window has been disabled */
1239 if (!(GetWindowLongA( hWnd, GWL_STYLE ) & WS_DISABLED))
1240 PostMessageA( hWnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
1242 else if (event->message_type == dndProtocol)
1244 /* query window (drag&drop event contains only drag window) */
1245 Window root, child;
1246 int root_x, root_y, child_x, child_y;
1247 unsigned int u;
1248 TSXQueryPointer( event->display, root_window, &root, &child,
1249 &root_x, &root_y, &child_x, &child_y, &u);
1250 if (TSXFindContext( event->display, child, winContext, (char **)&hWnd ) != 0) return;
1251 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
1252 EVENT_DropFromOffiX(hWnd, event);
1253 else if (event->data.l[0] == DndURL)
1254 EVENT_DropURLs(hWnd, event);
1256 else {
1257 #if 0
1258 /* enable this if you want to see the message */
1259 unsigned char* p_data = NULL;
1260 union {
1261 unsigned long l;
1262 int i;
1263 Atom atom;
1264 } u; /* unused */
1265 TSXGetWindowProperty( event->display, DefaultRootWindow(event->display),
1266 dndSelection, 0, 65535, FALSE,
1267 AnyPropertyType, &u.atom, &u.i,
1268 &u.l, &u.l, &p_data);
1269 TRACE("message_type=%ld, data=%ld,%ld,%ld,%ld,%ld, msg=%s\n",
1270 event->message_type, event->data.l[0], event->data.l[1],
1271 event->data.l[2], event->data.l[3], event->data.l[4],
1272 p_data);
1273 #endif
1274 TRACE("unrecognized ClientMessage\n" );
1280 /**********************************************************************
1281 * X11DRV_EVENT_SetInputMethod
1283 INPUT_TYPE X11DRV_EVENT_SetInputMethod(INPUT_TYPE type)
1285 INPUT_TYPE prev = current_input_type;
1287 /* Flag not used yet */
1288 in_transition = FALSE;
1289 current_input_type = type;
1291 return prev;
1294 #ifdef HAVE_LIBXXF86DGA2
1295 /**********************************************************************
1296 * X11DRV_EVENT_SetDGAStatus
1298 void X11DRV_EVENT_SetDGAStatus(HWND hwnd, int event_base)
1300 if (event_base < 0) {
1301 DGAUsed = FALSE;
1302 DGAhwnd = 0;
1303 } else {
1304 DGAUsed = TRUE;
1305 DGAhwnd = hwnd;
1306 DGAMotionEventType = event_base + MotionNotify;
1307 DGAButtonPressEventType = event_base + ButtonPress;
1308 DGAButtonReleaseEventType = event_base + ButtonRelease;
1309 DGAKeyPressEventType = event_base + KeyPress;
1310 DGAKeyReleaseEventType = event_base + KeyRelease;
1313 #endif