Added an unknown VxD error code.
[wine] / dlls / x11drv / window.c
1 /*
2  * Window related functions
3  *
4  * Copyright 1993, 1994, 1995, 1996, 2001 Alexandre Julliard
5  * Copyright 1993 David Metcalfe
6  * Copyright 1995, 1996 Alex Korobka
7  */
8
9 #include "config.h"
10
11 #include "ts_xlib.h"
12 #include "ts_xutil.h"
13
14 #include "winbase.h"
15 #include "wingdi.h"
16 #include "winuser.h"
17
18 #include "debugtools.h"
19 #include "x11drv.h"
20 #include "win.h"
21 #include "dce.h"
22 #include "options.h"
23
24 DEFAULT_DEBUG_CHANNEL(win);
25
26 extern Pixmap X11DRV_BITMAP_Pixmap( HBITMAP );
27
28 #define HAS_DLGFRAME(style,exStyle) \
29 ((!((style) & WS_THICKFRAME)) && (((style) & WS_DLGFRAME) || ((exStyle) & WS_EX_DLGMODALFRAME)))
30
31 /* X context to associate a hwnd to an X window */
32 XContext winContext = 0;
33
34 Atom wmProtocols = None;
35 Atom wmDeleteWindow = None;
36 Atom dndProtocol = None;
37 Atom dndSelection = None;
38 Atom wmChangeState = None;
39 Atom kwmDockWindow = None;
40 Atom _kde_net_wm_system_tray_window_for = None; /* KDE 2 Final */
41
42
43 /***********************************************************************
44  *              X11DRV_register_window
45  *
46  * Associate an X window to a HWND.
47  */
48 void X11DRV_register_window( Display *display, HWND hwnd, Window win )
49 {
50     if (!winContext) winContext = TSXUniqueContext();
51     TSXSaveContext( display, win, winContext, (char *)hwnd );
52     TSXSetWMProtocols( display, win, &wmDeleteWindow, 1 );
53 }
54
55
56 /***********************************************************************
57  *              set_wm_hint
58  *
59  * Set a window manager hint.
60  */
61 static void set_wm_hint( Display *display, Window win, int hint, int val )
62 {
63     XWMHints* wm_hints = TSXGetWMHints( display, win );
64     if (!wm_hints) wm_hints = TSXAllocWMHints();
65     if (wm_hints)
66     {
67         wm_hints->flags = hint;
68         switch( hint )
69         {
70         case InputHint:
71             wm_hints->input = val;
72             break;
73
74         case StateHint:
75             wm_hints->initial_state = val;
76             break;
77
78         case IconPixmapHint:
79             wm_hints->icon_pixmap = (Pixmap)val;
80             break;
81
82         case IconWindowHint:
83             wm_hints->icon_window = (Window)val;
84             break;
85         }
86         TSXSetWMHints( display, win, wm_hints );
87         TSXFree(wm_hints);
88     }
89 }
90
91
92 /***********************************************************************
93  *              set_icon_hints
94  *
95  * Set the icon wm hints
96  */
97 static void set_icon_hints( Display *display, WND *wndPtr, XWMHints *hints )
98 {
99     X11DRV_WND_DATA *data = wndPtr->pDriverData;
100     HICON hIcon = GetClassLongA( wndPtr->hwndSelf, GCL_HICON );
101
102     if (data->hWMIconBitmap) DeleteObject( data->hWMIconBitmap );
103     if (data->hWMIconMask) DeleteObject( data->hWMIconMask);
104
105     if (!hIcon)
106     {
107         data->hWMIconBitmap = 0;
108         data->hWMIconMask = 0;
109         hints->flags &= ~(IconPixmapHint | IconMaskHint);
110     }
111     else
112     {
113         HBITMAP hbmOrig;
114         RECT rcMask;
115         BITMAP bmMask;
116         ICONINFO ii;
117         HDC hDC;
118
119         GetIconInfo(hIcon, &ii);
120
121         X11DRV_CreateBitmap(ii.hbmMask);
122         X11DRV_CreateBitmap(ii.hbmColor);
123
124         GetObjectA(ii.hbmMask, sizeof(bmMask), &bmMask);
125         rcMask.top    = 0;
126         rcMask.left   = 0;
127         rcMask.right  = bmMask.bmWidth;
128         rcMask.bottom = bmMask.bmHeight;
129
130         hDC = CreateCompatibleDC(0);
131         hbmOrig = SelectObject(hDC, ii.hbmMask);
132         InvertRect(hDC, &rcMask);
133         SelectObject(hDC, hbmOrig);
134         DeleteDC(hDC);
135
136         data->hWMIconBitmap = ii.hbmColor;
137         data->hWMIconMask = ii.hbmMask;
138
139         hints->icon_pixmap = X11DRV_BITMAP_Pixmap(data->hWMIconBitmap);
140         hints->icon_mask = X11DRV_BITMAP_Pixmap(data->hWMIconMask);
141         hints->flags |= IconPixmapHint | IconMaskHint;
142     }
143 }
144
145
146 /***********************************************************************
147  *              dock_window
148  *
149  * Set the X Property of the window that tells the windowmanager we really
150  * want to be in the systray
151  *
152  * KDE: set "KWM_DOCKWINDOW", type "KWM_DOCKWINDOW" to 1 before a window is 
153  *      mapped.
154  *
155  * all others: to be added ;)
156  */
157 inline static void dock_window( Display *display, Window win )
158 {
159     int data = 1;
160     if (kwmDockWindow != None)
161         TSXChangeProperty( display, win, kwmDockWindow, kwmDockWindow,
162                            32, PropModeReplace, (char*)&data, 1 );
163     if (_kde_net_wm_system_tray_window_for != None)
164         TSXChangeProperty( display, win, _kde_net_wm_system_tray_window_for, XA_WINDOW,
165                            32, PropModeReplace, (char*)&win, 1 );
166 }
167
168
169 /**********************************************************************
170  *              create_desktop
171  */
172 static void create_desktop( Display *display, WND *wndPtr )
173 {
174     X11DRV_WND_DATA *data = wndPtr->pDriverData;
175
176     wmProtocols = TSXInternAtom( display, "WM_PROTOCOLS", True );
177     wmDeleteWindow = TSXInternAtom( display, "WM_DELETE_WINDOW", True );
178     dndProtocol = TSXInternAtom( display, "DndProtocol" , False );
179     dndSelection = TSXInternAtom( display, "DndSelection" , False );
180     wmChangeState = TSXInternAtom (display, "WM_CHANGE_STATE", False);
181     kwmDockWindow = TSXInternAtom( display, "KWM_DOCKWINDOW", False );
182     _kde_net_wm_system_tray_window_for = TSXInternAtom( display, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False );
183
184     data->window = root_window;
185     if (root_window != DefaultRootWindow(display))
186     {
187         wndPtr->flags |= WIN_NATIVE;
188         X11DRV_create_desktop_thread();
189     }
190 }
191
192
193 /**********************************************************************
194  *              CreateWindow   (X11DRV.@)
195  */
196 BOOL X11DRV_CreateWindow( HWND hwnd )
197 {
198     Display *display = thread_display();
199     X11DRV_WND_DATA *data;
200     WND *wndPtr = WIN_FindWndPtr( hwnd );
201     int x = wndPtr->rectWindow.left;
202     int y = wndPtr->rectWindow.top;
203     int cx = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
204     int cy = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
205
206     if (!(data = HeapAlloc(GetProcessHeap(), 0, sizeof(X11DRV_WND_DATA))))
207     {
208         WIN_ReleaseWndPtr( wndPtr );
209         return FALSE;
210     }
211     data->window = 0;
212     wndPtr->pDriverData = data;
213
214     if (!wndPtr->parent)
215     {
216         create_desktop( display, wndPtr );
217         WIN_ReleaseWndPtr( wndPtr );
218         return TRUE;
219     }
220
221     /* Create the X window (only for top-level windows, and then only */
222     /* when there's no desktop window) */
223
224     if ((root_window == DefaultRootWindow(display))
225         && (wndPtr->parent->hwndSelf == GetDesktopWindow()))
226     {
227         Window    wGroupLeader;
228         XWMHints* wm_hints;
229         XSetWindowAttributes win_attr;
230
231         /* Create "managed" windows only if a title bar or resizable */
232         /* frame is required. */
233         if (WIN_WindowNeedsWMBorder(wndPtr->dwStyle, wndPtr->dwExStyle))
234         {
235             win_attr.event_mask = ExposureMask | KeyPressMask |
236                 KeyReleaseMask | PointerMotionMask |
237                 ButtonPressMask | ButtonReleaseMask |
238                 FocusChangeMask | StructureNotifyMask;
239             win_attr.override_redirect = FALSE;
240             wndPtr->dwExStyle |= WS_EX_MANAGED;
241         }
242         else
243         {
244             win_attr.event_mask = ExposureMask | KeyPressMask |
245                 KeyReleaseMask | PointerMotionMask |
246                 ButtonPressMask | ButtonReleaseMask |
247                 FocusChangeMask;
248             win_attr.override_redirect = TRUE;
249         }
250         wndPtr->flags |= WIN_NATIVE;
251
252         wine_tsx11_lock();
253
254         win_attr.bit_gravity   = (wndPtr->clsStyle & (CS_VREDRAW | CS_HREDRAW)) ? ForgetGravity : NorthWestGravity;
255         win_attr.colormap      = X11DRV_PALETTE_PaletteXColormap;
256         win_attr.backing_store = NotUseful;
257         win_attr.save_under    = ((wndPtr->clsStyle & CS_SAVEBITS) != 0);
258         win_attr.cursor        = X11DRV_GetCursor( display, GlobalLock16(GetCursor()) );
259
260         data->hWMIconBitmap = 0;
261         data->hWMIconMask = 0;
262         data->bit_gravity = win_attr.bit_gravity;
263
264         /* Zero-size X11 window hack.  X doesn't like them, and will crash */
265         /* with a BadValue unless we do something ugly like this. */
266         /* Zero size window won't be mapped  */
267         if (cx <= 0) cx = 1;
268         if (cy <= 0) cy = 1;
269
270         data->window = XCreateWindow( display, root_window,
271                                         x, y, cx, cy,
272                                         0, screen_depth,
273                                         InputOutput, visual,
274                                         CWEventMask | CWOverrideRedirect |
275                                         CWColormap | CWCursor | CWSaveUnder |
276                                         CWBackingStore | CWBitGravity,
277                                         &win_attr );
278
279         if (win_attr.cursor) XFreeCursor( display, win_attr.cursor );
280         wine_tsx11_unlock();
281
282         if(!(wGroupLeader = data->window))
283         {
284             HeapFree( GetProcessHeap(), 0, data );
285             WIN_ReleaseWndPtr( wndPtr );
286             return FALSE;
287         }
288
289         /* If we are the systray, we need to be managed to be noticed by KWM */
290         if (wndPtr->dwExStyle & WS_EX_TRAYWINDOW) dock_window( display, data->window );
291
292         if (wndPtr->dwExStyle & WS_EX_MANAGED)
293         {
294             XClassHint *class_hints = TSXAllocClassHint();
295             XSizeHints* size_hints = TSXAllocSizeHints();
296
297             if (class_hints)
298             {
299                 class_hints->res_name = "wineManaged";
300                 class_hints->res_class = "Wine";
301                 TSXSetClassHint( display, data->window, class_hints );
302                 TSXFree (class_hints);
303             }
304
305             if (size_hints)
306             {
307                 size_hints->win_gravity = StaticGravity;
308                 size_hints->x = x;
309                 size_hints->y = y;
310                 size_hints->flags = PWinGravity|PPosition;
311
312                 if (HAS_DLGFRAME(wndPtr->dwStyle,wndPtr->dwExStyle))
313                 {
314                     size_hints->min_width = size_hints->max_width = cx;
315                     size_hints->min_height = size_hints->max_height = cy;
316                     size_hints->flags |= PMinSize | PMaxSize;
317                 }
318
319                 TSXSetWMSizeHints( display, X11DRV_WND_GetXWindow(wndPtr), 
320                                    size_hints, XA_WM_NORMAL_HINTS );
321                 TSXFree(size_hints);
322             }
323         }
324
325         if (wndPtr->owner)  /* Get window owner */
326         {
327             Window w = X11DRV_WND_FindXWindow( wndPtr->owner );
328             if (w != None)
329             {
330                 TSXSetTransientForHint( display, X11DRV_WND_GetXWindow(wndPtr), w );
331                 wGroupLeader = w;
332             }
333         }
334
335         if ((wm_hints = TSXAllocWMHints()))
336         {
337             wm_hints->flags = InputHint | StateHint | WindowGroupHint;
338             wm_hints->input = True;
339
340             if (wndPtr->dwExStyle & WS_EX_MANAGED)
341             {
342                 set_icon_hints( display, wndPtr, wm_hints );
343                 wm_hints->initial_state = (wndPtr->dwStyle & WS_MINIMIZE)
344                     ? IconicState : NormalState;
345             }
346             else
347                 wm_hints->initial_state = NormalState;
348             wm_hints->window_group = wGroupLeader;
349
350             TSXSetWMHints( display, X11DRV_WND_GetXWindow(wndPtr), wm_hints );
351             TSXFree(wm_hints);
352         }
353         X11DRV_register_window( display, hwnd, data->window );
354         TSXFlush( display );
355     }
356     WIN_ReleaseWndPtr( wndPtr );
357     return TRUE;
358 }
359
360
361 /***********************************************************************
362  *              DestroyWindow   (X11DRV.@)
363  */
364 BOOL X11DRV_DestroyWindow( HWND hwnd )
365 {
366     Display *display = thread_display();
367     WND *wndPtr = WIN_FindWndPtr( hwnd );
368     X11DRV_WND_DATA *data = wndPtr->pDriverData;
369     Window w;
370
371     if (data && (w = data->window))
372     {
373         XEvent xe;
374         wine_tsx11_lock();
375         XSync( gdi_display, False );  /* flush any reference to this drawable in GDI queue */
376         XDeleteContext( display, w, winContext );
377         XDestroyWindow( display, w );
378         while( XCheckWindowEvent(display, w, NoEventMask, &xe) );
379         wine_tsx11_unlock();
380
381         data->window = None;
382         if( data->hWMIconBitmap )
383         {
384             DeleteObject( data->hWMIconBitmap );
385             data->hWMIconBitmap = 0;
386         }
387         if( data->hWMIconMask )
388         {
389             DeleteObject( data->hWMIconMask);
390             data->hWMIconMask= 0;
391         }
392     }
393     HeapFree( GetProcessHeap(), 0, data );
394     wndPtr->pDriverData = NULL;
395     WIN_ReleaseWndPtr( wndPtr );
396     return TRUE;
397 }
398
399
400 /*****************************************************************
401  *              SetParent   (X11DRV.@)
402  */
403 HWND X11DRV_SetParent( HWND hwnd, HWND parent )
404 {
405     Display *display = thread_display();
406     WND *wndPtr;
407     WND *pWndParent;
408     DWORD dwStyle;
409     HWND retvalue;
410
411     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
412
413     dwStyle = wndPtr->dwStyle;
414
415     if (!parent) parent = GetDesktopWindow();
416
417     if (!(pWndParent = WIN_FindWndPtr(parent)))
418     {
419         WIN_ReleaseWndPtr( wndPtr );
420         return 0;
421     }
422
423     /* Windows hides the window first, then shows it again
424      * including the WM_SHOWWINDOW messages and all */
425     if (dwStyle & WS_VISIBLE) ShowWindow( hwnd, SW_HIDE );
426
427     retvalue = wndPtr->parent->hwndSelf;  /* old parent */
428     if (pWndParent != wndPtr->parent)
429     {
430         if ( X11DRV_WND_GetXWindow(wndPtr) )
431         {
432             /* Toplevel window needs to be reparented.  Used by Tk 8.0 */
433             TSXDestroyWindow( display, X11DRV_WND_GetXWindow(wndPtr) );
434             ((X11DRV_WND_DATA *) wndPtr->pDriverData)->window = None;
435         }
436         WIN_UnlinkWindow(wndPtr->hwndSelf);
437         wndPtr->parent = pWndParent;
438
439         /* Create an X counterpart for reparented top-level windows
440              * when not in the desktop mode. */
441         if (parent == GetDesktopWindow())
442         {
443             if(root_window == DefaultRootWindow(display))
444                 X11DRV_CreateWindow(wndPtr->hwndSelf);
445         }
446         else /* a child window */
447         {
448             if( !( wndPtr->dwStyle & WS_CHILD ) )
449             {
450                 if( wndPtr->wIDmenu != 0)
451                 {
452                     DestroyMenu( (HMENU) wndPtr->wIDmenu );
453                     wndPtr->wIDmenu = 0;
454                 }
455             }
456         }
457         WIN_LinkWindow(wndPtr->hwndSelf, HWND_TOP);
458     }
459     WIN_ReleaseWndPtr( pWndParent );
460     WIN_ReleaseWndPtr( wndPtr );
461
462     /* SetParent additionally needs to make hwnd the topmost window
463        in the x-order and send the expected WM_WINDOWPOSCHANGING and
464        WM_WINDOWPOSCHANGED notification messages. 
465     */
466     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
467                   SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|
468                   ((dwStyle & WS_VISIBLE)?SWP_SHOWWINDOW:0));
469     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
470      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
471
472     return retvalue;
473 }
474
475
476 /*******************************************************************
477  *              EnableWindow   (X11DRV.@)
478  */
479 BOOL X11DRV_EnableWindow( HWND hwnd, BOOL enable )
480 {
481     Display *display = thread_display();
482     WND *wndPtr;
483     BOOL retvalue;
484     Window w;
485
486     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
487
488     retvalue = ((wndPtr->dwStyle & WS_DISABLED) != 0);
489
490     if (enable && (wndPtr->dwStyle & WS_DISABLED))
491     {
492         /* Enable window */
493         wndPtr->dwStyle &= ~WS_DISABLED;
494
495         if ((wndPtr->dwExStyle & WS_EX_MANAGED) && (w = X11DRV_WND_GetXWindow( wndPtr )))
496             set_wm_hint( display, w, InputHint, TRUE );
497
498         SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
499     }
500     else if (!enable && !(wndPtr->dwStyle & WS_DISABLED))
501     {
502         SendMessageA( wndPtr->hwndSelf, WM_CANCELMODE, 0, 0 );
503
504         /* Disable window */
505         wndPtr->dwStyle |= WS_DISABLED;
506
507         if ((wndPtr->dwExStyle & WS_EX_MANAGED) && (w = X11DRV_WND_GetXWindow( wndPtr )))
508             set_wm_hint( display, w, InputHint, FALSE );
509
510         if (hwnd == GetFocus())
511             SetFocus( 0 );  /* A disabled window can't have the focus */
512
513         if (hwnd == GetCapture())
514             ReleaseCapture();  /* A disabled window can't capture the mouse */
515
516         SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
517     }
518     WIN_ReleaseWndPtr(wndPtr);
519     return retvalue;
520 }
521
522
523 /*****************************************************************
524  *              SetFocus   (X11DRV.@)
525  *
526  * Set the X focus.
527  * Explicit colormap management seems to work only with OLVWM.
528  */
529 void X11DRV_SetFocus( HWND hwnd )
530 {
531     Display *display = thread_display();
532     XWindowAttributes win_attr;
533     Window win;
534     WND *wndPtr = WIN_FindWndPtr( hwnd );
535     WND *w = wndPtr;
536
537     if (!wndPtr) return;
538
539     /* Only mess with the X focus if there's */
540     /* no desktop window and if the window is not managed by the WM. */
541     if (root_window != DefaultRootWindow(display)) goto done;
542
543     while (w && !((X11DRV_WND_DATA *) w->pDriverData)->window)
544         w = w->parent;
545     if (!w) w = wndPtr;
546     if (w->dwExStyle & WS_EX_MANAGED) goto done;
547
548     if (!hwnd)  /* If setting the focus to 0, uninstall the colormap */
549     {
550         if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
551             TSXUninstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
552     }
553     else if ((win = X11DRV_WND_FindXWindow(wndPtr)))
554     {
555         /* Set X focus and install colormap */
556         if (TSXGetWindowAttributes( display, win, &win_attr ) &&
557             (win_attr.map_state == IsViewable))
558         {
559             /* If window is not viewable, don't change anything */
560             TSXSetInputFocus( display, win, RevertToParent, CurrentTime );
561             if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE)
562                 TSXInstallColormap( display, X11DRV_PALETTE_PaletteXColormap );
563             X11DRV_Synchronize();
564         }
565     }
566
567  done:
568     WIN_ReleaseWndPtr( wndPtr );
569 }
570
571
572 /*****************************************************************
573  *              SetWindowText   (X11DRV.@)
574  */
575 BOOL X11DRV_SetWindowText( HWND hwnd, LPCWSTR text )
576 {
577     Display *display = thread_display();
578     UINT count;
579     char *buffer;
580     static UINT text_cp = (UINT)-1;
581     Window win;
582     WND *wndPtr = WIN_FindWndPtr( hwnd );
583
584     if (!wndPtr) return FALSE;
585     if ((win = X11DRV_WND_GetXWindow(wndPtr)))
586     {
587         if (text_cp == (UINT)-1)
588         {
589             text_cp = PROFILE_GetWineIniInt("x11drv", "TextCP", CP_ACP);
590             TRACE("text_cp = %u\n", text_cp);
591         }
592
593         /* allocate new buffer for window text */
594         count = WideCharToMultiByte(text_cp, 0, text, -1, NULL, 0, NULL, NULL);
595         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, count * sizeof(WCHAR) )))
596         {
597             ERR("Not enough memory for window text\n");
598             WIN_ReleaseWndPtr( wndPtr );
599             return FALSE;
600         }
601         WideCharToMultiByte(text_cp, 0, text, -1, buffer, count, NULL, NULL);
602
603         TSXStoreName( display, win, buffer );
604         TSXSetIconName( display, win, buffer );
605         HeapFree( GetProcessHeap(), 0, buffer );
606     }
607     WIN_ReleaseWndPtr( wndPtr );
608     return TRUE;
609 }
610
611
612 /**********************************************************************
613  *              X11DRV_SetWindowIcon
614  *
615  * hIcon or hIconSm has changed (or is being initialised for the
616  * first time). Complete the X11 driver-specific initialisation
617  * and set the window hints.
618  *
619  * This is not entirely correct, may need to create
620  * an icon window and set the pixmap as a background
621  */
622 HICON X11DRV_SetWindowIcon( HWND hwnd, HICON icon, BOOL small )
623 {
624     Display *display = thread_display();
625     WND *wndPtr = WIN_FindWndPtr( hwnd );
626     int index = small ? GCL_HICONSM : GCL_HICON;
627     HICON old;
628
629     if (!wndPtr) return 0;
630
631     old = GetClassLongW( hwnd, index );
632     SetClassLongW( hwnd, index, icon );
633
634     SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE |
635                   SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
636
637     if (wndPtr->dwExStyle & WS_EX_MANAGED)
638     {
639         Window win = X11DRV_WND_GetXWindow(wndPtr);
640         XWMHints* wm_hints = TSXGetWMHints( display, win );
641
642         if (!wm_hints) wm_hints = TSXAllocWMHints();
643         if (wm_hints)
644         {
645             set_icon_hints( display, wndPtr, wm_hints );
646             TSXSetWMHints( display, win, wm_hints );
647             TSXFree( wm_hints );
648         }
649     }
650
651     WIN_ReleaseWndPtr( wndPtr );
652     return old;
653 }
654
655
656 /*************************************************************************
657  *             fix_caret
658  */
659 static BOOL fix_caret(HWND hWnd, LPRECT lprc, UINT flags)
660 {
661    HWND hCaret = CARET_GetHwnd();
662
663    if( hCaret )
664    {
665        RECT rc;
666        CARET_GetRect( &rc );
667        if( hCaret == hWnd ||
668           (flags & SW_SCROLLCHILDREN && IsChild(hWnd, hCaret)) )
669        {
670            POINT pt;
671            pt.x = rc.left;
672            pt.y = rc.top;
673            MapWindowPoints( hCaret, hWnd, (LPPOINT)&rc, 2 );
674            if( IntersectRect(lprc, lprc, &rc) )
675            {
676                HideCaret(0);
677                lprc->left = pt.x;
678                lprc->top = pt.y;
679                return TRUE;
680            }
681        }
682    }
683    return FALSE;
684 }
685
686
687 /*************************************************************************
688  *              ScrollWindowEx   (X11DRV.@)
689  */
690 INT X11DRV_ScrollWindowEx( HWND hwnd, INT dx, INT dy,
691                            const RECT *rect, const RECT *clipRect,
692                            HRGN hrgnUpdate, LPRECT rcUpdate, UINT flags )
693 {
694     INT  retVal = NULLREGION;
695     BOOL bCaret = FALSE, bOwnRgn = TRUE;
696     RECT rc, cliprc;
697     WND*   wnd = WIN_FindWndPtr( hwnd );
698
699     if( !wnd || !WIN_IsWindowDrawable( wnd, TRUE ))
700     {
701         retVal = ERROR;
702         goto END;
703     }
704
705     GetClientRect(hwnd, &rc);
706     if (rect) IntersectRect(&rc, &rc, rect);
707
708     if (clipRect) IntersectRect(&cliprc,&rc,clipRect);
709     else cliprc = rc;
710
711     if (!IsRectEmpty(&cliprc) && (dx || dy))
712     {
713         HDC   hDC;
714         BOOL  bUpdate = (rcUpdate || hrgnUpdate || flags & (SW_INVALIDATE | SW_ERASE));
715         HRGN  hrgnClip = CreateRectRgnIndirect(&cliprc);
716         HRGN  hrgnTemp = CreateRectRgnIndirect(&rc);
717         RECT  caretrc;
718
719         TRACE("%04x, %d,%d hrgnUpdate=%04x rcUpdate = %p cliprc = (%d,%d-%d,%d), rc=(%d,%d-%d,%d) %04x\n",
720               (HWND16)hwnd, dx, dy, hrgnUpdate, rcUpdate,
721               clipRect?clipRect->left:0, clipRect?clipRect->top:0,
722               clipRect?clipRect->right:0, clipRect?clipRect->bottom:0,
723               rc.left, rc.top, rc.right, rc.bottom, (UINT16)flags );
724
725         caretrc = rc;
726         bCaret = fix_caret(hwnd, &caretrc, flags);
727
728         if( hrgnUpdate ) bOwnRgn = FALSE;
729         else if( bUpdate ) hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 );
730
731         hDC = GetDCEx( hwnd, hrgnClip, DCX_CACHE | DCX_USESTYLE |
732                          DCX_KEEPCLIPRGN | DCX_INTERSECTRGN |
733                        ((flags & SW_SCROLLCHILDREN) ? DCX_NOCLIPCHILDREN : 0) );
734         if (hDC)
735         {
736             X11DRV_WND_SurfaceCopy(wnd,hDC,dx,dy,&rc,bUpdate);
737             if( bUpdate )
738             {
739                 DC* dc;
740
741                 if( (dc = DC_GetDCPtr(hDC)) )
742                 {
743                     OffsetRgn( hrgnTemp, dc->DCOrgX, dc->DCOrgY );
744                     CombineRgn( hrgnTemp, hrgnTemp, dc->hVisRgn,
745                                 RGN_AND );
746                     OffsetRgn( hrgnTemp, -dc->DCOrgX, -dc->DCOrgY );
747                     CombineRgn( hrgnUpdate, hrgnTemp, hrgnClip,
748                                 RGN_AND );
749                     OffsetRgn( hrgnTemp, dx, dy );
750                     retVal =
751                         CombineRgn( hrgnUpdate, hrgnUpdate, hrgnTemp,
752                                     RGN_DIFF );
753
754                     if( rcUpdate ) GetRgnBox( hrgnUpdate, rcUpdate );
755                     GDI_ReleaseObj( hDC );
756                 }
757             }
758             ReleaseDC(hwnd, hDC);
759         }
760
761         if( wnd->hrgnUpdate > 1 )
762         {
763             /* Takes into account the fact that some damages may have
764                occured during the scroll. */
765             CombineRgn( hrgnTemp, wnd->hrgnUpdate, 0, RGN_COPY );
766             OffsetRgn( hrgnTemp, dx, dy );
767             CombineRgn( hrgnTemp, hrgnTemp, hrgnClip, RGN_AND );
768             CombineRgn( wnd->hrgnUpdate, wnd->hrgnUpdate, hrgnTemp, RGN_OR );
769         }
770
771         if( flags & SW_SCROLLCHILDREN )
772         {
773             RECT r;
774             WND *w;
775             for( w =WIN_LockWndPtr(wnd->child); w; WIN_UpdateWndPtr(&w, w->next))
776             {
777                 r = w->rectWindow;
778                 if( !rect || IntersectRect(&r, &r, &rc) )
779                     SetWindowPos(w->hwndSelf, 0, w->rectWindow.left + dx,
780                                  w->rectWindow.top  + dy, 0,0, SWP_NOZORDER |
781                                  SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW |
782                                  SWP_DEFERERASE );
783             }
784         }
785
786         if( flags & (SW_INVALIDATE | SW_ERASE) )
787             RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE |
788                           ((flags & SW_ERASE) ? RDW_ERASENOW : 0) |
789                           ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0 ) );
790
791         if( bCaret )
792         {
793             SetCaretPos( caretrc.left + dx, caretrc.top + dy );
794             ShowCaret(0);
795         }
796
797         if( bOwnRgn && hrgnUpdate ) DeleteObject( hrgnUpdate );
798         DeleteObject( hrgnClip );
799         DeleteObject( hrgnTemp );
800     }
801 END:
802     WIN_ReleaseWndPtr(wnd);
803     return retVal;
804 }