Release 960309
[wine] / windows / win.c
1 /*
2  * Window related functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  */
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <string.h>
9
10 #include "options.h"
11 #include "class.h"
12 #include "win.h"
13 #include "user.h"
14 #include "dce.h"
15 #include "sysmetrics.h"
16 #include "cursoricon.h"
17 #include "event.h"
18 #include "message.h"
19 #include "nonclient.h"
20 #include "winpos.h"
21 #include "color.h"
22 #include "shm_main_blk.h"
23 #include "dde_proc.h"
24 #include "callback.h"
25 #include "stddebug.h"
26 /* #define DEBUG_WIN  */ 
27 /* #define DEBUG_MENU */
28 #include "debug.h"
29
30 static HWND hwndDesktop  = 0;
31 static HWND hwndSysModal = 0;
32
33 static WORD wDragWidth = 4;
34 static WORD wDragHeight= 3;
35
36 extern HCURSOR CURSORICON_IconToCursor(HICON);
37
38 /***********************************************************************
39  *           WIN_FindWndPtr
40  *
41  * Return a pointer to the WND structure corresponding to a HWND.
42  */
43 WND * WIN_FindWndPtr( HWND hwnd )
44 {
45     WND * ptr;
46     
47     if (!hwnd) return NULL;
48     ptr = (WND *) USER_HEAP_LIN_ADDR( hwnd );
49     if (ptr->dwMagic != WND_MAGIC) return NULL;
50     return ptr;
51 }
52
53
54 /***********************************************************************
55  *           WIN_GetXWindow
56  *
57  * Return the X window associated to a window.
58  */
59 Window WIN_GetXWindow( HWND hwnd )
60 {
61     WND *wndPtr = WIN_FindWndPtr( hwnd );
62     while (wndPtr && !wndPtr->window)
63     {
64         wndPtr = WIN_FindWndPtr( wndPtr->hwndParent );
65     }
66     return wndPtr ? wndPtr->window : 0;
67 }
68
69
70 /***********************************************************************
71  *           WIN_UnlinkWindow
72  *
73  * Remove a window from the siblings linked list.
74  */
75 BOOL WIN_UnlinkWindow( HWND hwnd )
76 {    
77     HWND * curWndPtr;
78     WND *parentPtr, *wndPtr;
79
80     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
81     if (!(parentPtr = WIN_FindWndPtr( wndPtr->hwndParent ))) return FALSE;
82
83     curWndPtr = &parentPtr->hwndChild;
84
85     while (*curWndPtr != hwnd)
86     {
87         WND * curPtr = WIN_FindWndPtr( *curWndPtr );
88         curWndPtr = &curPtr->hwndNext;
89     }
90     *curWndPtr = wndPtr->hwndNext;
91     return TRUE;
92 }
93
94
95 /***********************************************************************
96  *           WIN_LinkWindow
97  *
98  * Insert a window into the siblings linked list.
99  * The window is inserted after the specified window, which can also
100  * be specified as HWND_TOP or HWND_BOTTOM.
101  */
102 BOOL WIN_LinkWindow( HWND hwnd, HWND hwndInsertAfter )
103 {    
104     HWND * hwndPtr = NULL;  /* pointer to hwnd to change */
105     WND *wndPtr, *parentPtr;
106
107     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
108     if (!(parentPtr = WIN_FindWndPtr( wndPtr->hwndParent ))) return FALSE;
109
110     if ((hwndInsertAfter == HWND_TOP) || (hwndInsertAfter == HWND_BOTTOM))
111     {
112         hwndPtr = &parentPtr->hwndChild;  /* Point to first sibling hwnd */
113         if (hwndInsertAfter == HWND_BOTTOM)  /* Find last sibling hwnd */
114             while (*hwndPtr)
115             {
116                 WND * nextPtr = WIN_FindWndPtr( *hwndPtr );
117                 hwndPtr = &nextPtr->hwndNext;
118             }
119     }
120     else  /* Normal case */
121     {
122         WND * afterPtr = WIN_FindWndPtr( hwndInsertAfter );
123         if (afterPtr) hwndPtr = &afterPtr->hwndNext;
124     }
125     if (!hwndPtr) return FALSE;
126     wndPtr->hwndNext = *hwndPtr;
127     *hwndPtr = hwnd;
128     return TRUE;
129 }
130
131
132 /***********************************************************************
133  *           WIN_FindWinToRepaint
134  *
135  * Find a window that needs repaint.
136  */
137 HWND WIN_FindWinToRepaint( HWND hwnd )
138 {
139     WND * wndPtr;
140
141       /* Note: the desktop window never gets WM_PAINT messages */
142     if (!hwnd) hwnd = GetTopWindow( hwndDesktop );
143     for ( ; hwnd != 0; hwnd = wndPtr->hwndNext )
144     {
145         if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
146         dprintf_win( stddeb, "WIN_FindWinToRepaint: "NPFMT", style %08lx\n",
147                      hwnd, wndPtr->dwStyle );
148         if (!(wndPtr->dwStyle & WS_VISIBLE) || (wndPtr->flags & WIN_NO_REDRAW))
149             continue;
150         if ((wndPtr->dwStyle & WS_MINIMIZE) && (WIN_CLASS_INFO(wndPtr).hIcon))
151             continue;
152         if (wndPtr->hrgnUpdate || (wndPtr->flags & WIN_INTERNAL_PAINT))
153             return hwnd;
154         if (wndPtr->hwndChild)
155         {
156             HWND child;
157             if ((child = WIN_FindWinToRepaint( wndPtr->hwndChild )))
158                 return child;
159         }
160     }
161     return 0;
162 }
163
164
165 /***********************************************************************
166  *           WIN_SendParentNotify
167  *
168  * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
169  * the window has the WS_EX_NOPARENTNOTIFY style.
170  */
171 void WIN_SendParentNotify( HWND hwnd, WORD event, WORD idChild, LONG lValue )
172 {
173     WND *wndPtr = WIN_FindWndPtr( hwnd );
174     
175     while (wndPtr && (wndPtr->dwStyle & WS_CHILD))
176     {
177         if (wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY) break;
178 #ifdef WINELIB32
179         SendMessage( wndPtr->hwndParent, WM_PARENTNOTIFY, 
180                      MAKEWPARAM(event,idChild),
181                      (LPARAM)lValue );
182 #else
183         SendMessage( wndPtr->hwndParent, WM_PARENTNOTIFY, event,
184                      MAKELPARAM(LOWORD(lValue), idChild) );
185 #endif
186         wndPtr = WIN_FindWndPtr( wndPtr->hwndParent );
187     }
188 }
189
190
191 /***********************************************************************
192  *           WIN_DestroyWindow
193  *
194  * Destroy storage associated to a window
195  */
196 static void WIN_DestroyWindow( HWND hwnd )
197 {
198     WND *wndPtr = WIN_FindWndPtr( hwnd );
199     CLASS *classPtr = CLASS_FindClassPtr( wndPtr->hClass );
200
201 #ifdef CONFIG_IPC
202     if (main_block)
203         DDE_DestroyWindow(hwnd);
204 #endif  /* CONFIG_IPC */
205         
206     if (!wndPtr || !classPtr) return;
207     WIN_UnlinkWindow( hwnd ); /* Remove the window from the linked list */
208     wndPtr->dwMagic = 0;  /* Mark it as invalid */
209     if ((wndPtr->hrgnUpdate) || (wndPtr->flags & WIN_INTERNAL_PAINT))
210     {
211         if (wndPtr->hrgnUpdate) DeleteObject( wndPtr->hrgnUpdate );
212         MSG_DecPaintCount( wndPtr->hmemTaskQ );
213     }
214     if (!(wndPtr->dwStyle & WS_CHILD))
215     {
216         if (wndPtr->wIDmenu) DestroyMenu( (HMENU)wndPtr->wIDmenu );
217     }
218     if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
219     if (wndPtr->window) XDestroyWindow( display, wndPtr->window );
220     if (classPtr->wc.style & CS_OWNDC) DCE_FreeDCE( wndPtr->hdce );
221     classPtr->cWindows--;
222     USER_HEAP_FREE( hwnd );
223 }
224
225
226 /***********************************************************************
227  *           WIN_CreateDesktopWindow
228  *
229  * Create the desktop window.
230  */
231 BOOL WIN_CreateDesktopWindow(void)
232 {
233     WND *wndPtr;
234     HCLASS hclass;
235     CLASS *classPtr;
236     HDC hdc;
237
238     if (!(hclass = CLASS_FindClassByName( DESKTOP_CLASS_ATOM, 0, &classPtr )))
239         return FALSE;
240
241     hwndDesktop = USER_HEAP_ALLOC( sizeof(WND)+classPtr->wc.cbWndExtra );
242     if (!hwndDesktop) return FALSE;
243     wndPtr = (WND *) USER_HEAP_LIN_ADDR( hwndDesktop );
244
245     wndPtr->hwndNext          = 0;
246     wndPtr->hwndChild         = 0;
247     wndPtr->dwMagic           = WND_MAGIC;
248     wndPtr->hwndParent        = 0;
249     wndPtr->hwndOwner         = 0;
250     wndPtr->hClass            = hclass;
251     wndPtr->hInstance         = 0;
252     wndPtr->rectWindow.left   = 0;
253     wndPtr->rectWindow.top    = 0;
254     wndPtr->rectWindow.right  = SYSMETRICS_CXSCREEN;
255     wndPtr->rectWindow.bottom = SYSMETRICS_CYSCREEN;
256     wndPtr->rectClient        = wndPtr->rectWindow;
257     wndPtr->rectNormal        = wndPtr->rectWindow;
258     wndPtr->ptIconPos.x       = -1;
259     wndPtr->ptIconPos.y       = -1;
260     wndPtr->ptMaxPos.x        = -1;
261     wndPtr->ptMaxPos.y        = -1;
262     wndPtr->hmemTaskQ         = 0;  /* Desktop does not belong to a task */
263     wndPtr->hrgnUpdate        = 0;
264     wndPtr->hwndLastActive    = hwndDesktop;
265     wndPtr->lpfnWndProc       = classPtr->wc.lpfnWndProc;
266     wndPtr->dwStyle           = WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
267     wndPtr->dwExStyle         = 0;
268     wndPtr->hdce              = 0;
269     wndPtr->hVScroll          = 0;
270     wndPtr->hHScroll          = 0;
271     wndPtr->wIDmenu           = 0;
272     wndPtr->hText             = 0;
273     wndPtr->flags             = 0;
274     wndPtr->window            = rootWindow;
275     wndPtr->hSysMenu          = 0;
276     wndPtr->hProp             = 0;
277     EVENT_RegisterWindow( wndPtr->window, hwndDesktop );
278     SendMessage( hwndDesktop, WM_NCCREATE, 0, 0 );
279     if ((hdc = GetDC( hwndDesktop )) != 0)
280     {
281         SendMessage( hwndDesktop, WM_ERASEBKGND, (WPARAM)hdc, 0 );
282         ReleaseDC( hwndDesktop, hdc );
283     }
284     return TRUE;
285 }
286
287
288 /***********************************************************************
289  *           CreateWindow   (USER.41)
290  */
291 HWND CreateWindow( SEGPTR className, SEGPTR windowName,
292                    DWORD style, INT x, INT y, INT width, INT height,
293                    HWND parent, HMENU menu, HANDLE instance, SEGPTR data ) 
294 {
295     return CreateWindowEx( 0, className, windowName, style,
296                            x, y, width, height, parent, menu, instance, data );
297 }
298
299
300 /***********************************************************************
301  *           CreateWindowEx   (USER.452)
302  */
303 HWND CreateWindowEx( DWORD exStyle, SEGPTR className, SEGPTR windowName,
304                      DWORD style, INT x, INT y, INT width, INT height,
305                      HWND parent, HMENU menu, HANDLE instance, SEGPTR data ) 
306 {
307     HANDLE class, hwnd;
308     CLASS *classPtr;
309     WND *wndPtr;
310     POINT maxSize, maxPos, minTrack, maxTrack;
311     CREATESTRUCT createStruct;
312     int wmcreate;
313     XSetWindowAttributes win_attr;
314     Atom XA_WM_DELETE_WINDOW;
315
316     /* FIXME: windowName and className should be SEGPTRs */
317
318     dprintf_win( stddeb, "CreateWindowEx: " );
319     if (HIWORD(windowName))
320         dprintf_win( stddeb, "'%s' ", (char *)PTR_SEG_TO_LIN(windowName) );
321     else
322         dprintf_win( stddeb, "%04x ", LOWORD(windowName) );
323     if (HIWORD(className))
324         dprintf_win( stddeb, "'%s' ", (char *)PTR_SEG_TO_LIN(className) );
325     else
326         dprintf_win( stddeb, "%04x ", LOWORD(className) );
327
328     dprintf_win(stddeb, "%08lx %08lx %d,%d %dx%d "NPFMT" "NPFMT" "NPFMT" %08lx\n",
329                 exStyle, style, x, y, width, height,
330                 parent, menu, instance, (DWORD)data);
331
332     if (x == CW_USEDEFAULT) x = y = 0;
333     if (width == CW_USEDEFAULT)
334     {
335         width = 600;
336         height = 400;
337     }
338
339       /* Find the parent and class */
340
341     if (parent)
342     {
343         /* Make sure parent is valid */
344         if (!IsWindow( parent )) {
345             dprintf_win(stddeb,"CreateWindowEx: Parent "NPFMT" is not a window\n", parent);
346             return 0;
347         }
348     }
349     else 
350     {
351         if (style & WS_CHILD) {
352             dprintf_win(stddeb,"CreateWindowEx: no parent\n");
353             return 0;  /* WS_CHILD needs a parent */
354         }
355     }
356
357     if (!(class = CLASS_FindClassByName( className, GetExePtr(instance),
358                                          &classPtr )))
359     {
360         fprintf(stderr,"CreateWindow BAD CLASSNAME " );
361         if (HIWORD(className)) fprintf( stderr, "'%s'\n", 
362                                         (char *)PTR_SEG_TO_LIN(className) );
363         else fprintf( stderr, "%04x\n", LOWORD(className) );
364         return 0;
365     }
366
367       /* Correct the window style */
368
369     if (!(style & (WS_POPUP | WS_CHILD)))  /* Overlapped window */
370         style |= WS_CAPTION | WS_CLIPSIBLINGS;
371     if (exStyle & WS_EX_DLGMODALFRAME) style &= ~WS_THICKFRAME;
372
373       /* Create the window structure */
374
375     hwnd = USER_HEAP_ALLOC( sizeof(WND)+classPtr->wc.cbWndExtra );
376     if (!hwnd) {
377         dprintf_win(stddeb,"CreateWindowEx: Out of memory\n");
378         return 0;
379     }
380
381       /* Fill the structure */
382
383     wndPtr = (WND *) USER_HEAP_LIN_ADDR( hwnd );
384     wndPtr->hwndNext       = 0;
385     wndPtr->hwndChild      = 0;
386     wndPtr->window         = 0;
387     wndPtr->dwMagic        = WND_MAGIC;
388     wndPtr->hwndParent     = (style & WS_CHILD) ? parent : hwndDesktop;
389     wndPtr->hwndOwner      = (style & WS_CHILD) ? 0 : WIN_GetTopParent(parent);
390     wndPtr->hClass         = class;
391     wndPtr->hInstance      = instance;
392     wndPtr->ptIconPos.x    = -1;
393     wndPtr->ptIconPos.y    = -1;
394     wndPtr->ptMaxPos.x     = -1;
395     wndPtr->ptMaxPos.y     = -1;
396     wndPtr->hmemTaskQ      = GetTaskQueue(0);
397     wndPtr->hrgnUpdate     = 0;
398     wndPtr->hwndLastActive = hwnd;
399     wndPtr->lpfnWndProc    = classPtr->wc.lpfnWndProc;
400     wndPtr->dwStyle        = style & ~WS_VISIBLE;
401     wndPtr->dwExStyle      = exStyle;
402     wndPtr->wIDmenu        = 0;
403     wndPtr->hText          = 0;
404     wndPtr->flags          = 0;
405     wndPtr->hVScroll       = 0;
406     wndPtr->hHScroll       = 0;
407     wndPtr->hSysMenu       = 0;
408     wndPtr->hProp          = 0;
409
410     if (classPtr->wc.cbWndExtra)
411         memset( wndPtr->wExtra, 0, classPtr->wc.cbWndExtra );
412     classPtr->cWindows++;
413
414       /* Get class or window DC if needed */
415
416     if (classPtr->wc.style & CS_OWNDC)
417         wndPtr->hdce = DCE_AllocDCE( DCE_WINDOW_DC );
418     else if (classPtr->wc.style & CS_CLASSDC)
419         wndPtr->hdce = classPtr->hdce;
420     else
421         wndPtr->hdce = 0;
422
423       /* Insert the window in the linked list */
424
425     WIN_LinkWindow( hwnd, HWND_TOP );
426
427       /* Send the WM_GETMINMAXINFO message and fix the size if needed */
428
429     NC_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack );
430
431     if (maxSize.x < width) width = maxSize.x;
432     if (maxSize.y < height) height = maxSize.y;
433     if (width <= 0) width = 1;
434     if (height <= 0) height = 1;
435
436     wndPtr->rectWindow.left   = x;
437     wndPtr->rectWindow.top    = y;
438     wndPtr->rectWindow.right  = x + width;
439     wndPtr->rectWindow.bottom = y + height;
440     wndPtr->rectClient        = wndPtr->rectWindow;
441     wndPtr->rectNormal        = wndPtr->rectWindow;
442
443       /* Create the X window (only for top-level windows, and then only */
444       /* when there's no desktop window) */
445
446     if (!(style & WS_CHILD) && (rootWindow == DefaultRootWindow(display)))
447     {
448         if (Options.managed && ((style & (WS_DLGFRAME | WS_THICKFRAME)) ||
449             (exStyle & WS_EX_DLGMODALFRAME)))
450         {
451             win_attr.event_mask = ExposureMask | KeyPressMask |
452                                   KeyReleaseMask | PointerMotionMask |
453                                   ButtonPressMask | ButtonReleaseMask |
454                                   FocusChangeMask | StructureNotifyMask;
455             win_attr.override_redirect = FALSE;
456             wndPtr->flags |= WIN_MANAGED;
457         }
458         else
459         {
460             win_attr.event_mask = ExposureMask | KeyPressMask |
461                                   KeyReleaseMask | PointerMotionMask |
462                                   ButtonPressMask | ButtonReleaseMask |
463                                   FocusChangeMask;
464             win_attr.override_redirect = TRUE;
465         }
466         win_attr.colormap      = COLOR_WinColormap;
467         win_attr.backing_store = Options.backingstore ? WhenMapped : NotUseful;
468         win_attr.save_under    = ((classPtr->wc.style & CS_SAVEBITS) != 0);
469         win_attr.cursor        = CURSORICON_XCursor;
470         wndPtr->window = XCreateWindow( display, rootWindow, x, y,
471                                         width, height, 0, CopyFromParent,
472                                         InputOutput, CopyFromParent,
473                                         CWEventMask | CWOverrideRedirect |
474                                         CWColormap | CWCursor | CWSaveUnder |
475                                         CWBackingStore, &win_attr );
476         XStoreName( display, wndPtr->window, PTR_SEG_TO_LIN(windowName) );
477         XA_WM_DELETE_WINDOW = XInternAtom( display, "WM_DELETE_WINDOW",
478                                            False );
479         XSetWMProtocols( display, wndPtr->window, &XA_WM_DELETE_WINDOW, 1 );
480         if (parent)  /* Get window owner */
481         {
482             Window win = WIN_GetXWindow( parent );
483             if (win) XSetTransientForHint( display, wndPtr->window, win );
484         }
485             
486         EVENT_RegisterWindow( wndPtr->window, hwnd );
487     }
488     
489     if ((style & WS_CAPTION) && !(style & WS_CHILD))
490     {
491         if (menu) SetMenu(hwnd, menu);
492         else if (classPtr->wc.lpszMenuName)
493             SetMenu( hwnd, LoadMenu( instance, classPtr->wc.lpszMenuName ) );
494     }
495     else wndPtr->wIDmenu = (UINT)menu;
496
497     GetSystemMenu( hwnd, TRUE );  /* Create a copy of the system menu */
498
499       /* Send the WM_CREATE message */
500
501     createStruct.lpCreateParams = (LPSTR)data;
502     createStruct.hInstance      = instance;
503     createStruct.hMenu          = menu;
504     createStruct.hwndParent     = parent;
505     createStruct.cx             = width;
506     createStruct.cy             = height;
507     createStruct.x              = x;
508     createStruct.y              = y;
509     createStruct.style          = style;
510     createStruct.lpszName       = windowName;
511     createStruct.lpszClass      = className;
512     createStruct.dwExStyle      = 0;
513
514     wmcreate = SendMessage( hwnd, WM_NCCREATE, 0, (LPARAM)MAKE_SEGPTR(&createStruct) );
515     if (!wmcreate)
516     {
517         dprintf_win(stddeb,"CreateWindowEx: WM_NCCREATE return 0\n");
518         wmcreate = -1;
519     }
520     else
521     {
522         WINPOS_SendNCCalcSize( hwnd, FALSE, &wndPtr->rectWindow,
523                                NULL, NULL, NULL, &wndPtr->rectClient );
524         wmcreate = SendMessage(hwnd, WM_CREATE, 0, (LPARAM)MAKE_SEGPTR(&createStruct));
525     }
526
527     if (wmcreate == -1)
528     {
529           /* Abort window creation */
530         dprintf_win(stddeb,"CreateWindowEx: wmcreate==-1, aborting\n");
531         WIN_DestroyWindow( hwnd );
532         return 0;
533     }
534
535     WIN_SendParentNotify( hwnd, WM_CREATE, wndPtr->wIDmenu, (LONG)hwnd );
536
537     /* Show the window, maximizing or minimizing if needed */
538
539     if (wndPtr->dwStyle & WS_MINIMIZE)
540     {
541         wndPtr->dwStyle &= ~WS_MAXIMIZE;
542         WINPOS_FindIconPos( hwnd );
543         SetWindowPos( hwnd, 0, wndPtr->ptIconPos.x, wndPtr->ptIconPos.y,
544                       SYSMETRICS_CXICON, SYSMETRICS_CYICON,
545                       SWP_FRAMECHANGED |
546                       (style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0 );
547     }
548     else if (wndPtr->dwStyle & WS_MAXIMIZE)
549     {
550         SetWindowPos( hwnd, 0, maxPos.x, maxPos.y, maxSize.x, maxSize.y,
551                       SWP_FRAMECHANGED |
552                       (style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0 );
553     }
554     else if (style & WS_VISIBLE) ShowWindow( hwnd, SW_SHOW );
555
556     dprintf_win(stddeb, "CreateWindowEx: return "NPFMT" \n", hwnd);
557     return hwnd;
558 }
559
560
561 /***********************************************************************
562  *           DestroyWindow   (USER.53)
563  */
564 BOOL DestroyWindow( HWND hwnd )
565 {
566     WND * wndPtr;
567     CLASS * classPtr;
568
569     dprintf_win(stddeb, "DestroyWindow ("NPFMT")\n", hwnd);
570     
571       /* Initialisation */
572
573     if (hwnd == hwndDesktop) return FALSE;  /* Can't destroy desktop */
574     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
575     if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return FALSE;
576
577       /* Hide the window */
578
579     if (wndPtr->dwStyle & WS_VISIBLE)
580         SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOACTIVATE |
581                       SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE );
582     if ((hwnd == GetCapture()) || IsChild( hwnd, GetCapture() ))
583         ReleaseCapture();
584     WIN_SendParentNotify( hwnd, WM_DESTROY, wndPtr->wIDmenu, (LONG)hwnd );
585
586       /* Recursively destroy owned windows */
587
588     for (;;)
589     {
590         HWND hwndSibling = GetWindow( hwnd, GW_HWNDFIRST );
591         while (hwndSibling)
592         {
593             WND *siblingPtr = WIN_FindWndPtr( hwndSibling );
594             if (siblingPtr->hwndOwner == hwnd) break;
595             hwndSibling = siblingPtr->hwndNext;
596         }
597         if (hwndSibling) DestroyWindow( hwndSibling );
598         else break;
599     }
600
601       /* Send destroy messages and destroy children */
602
603     SendMessage( hwnd, WM_DESTROY, 0, 0 );
604     while (wndPtr->hwndChild)  /* The child removes itself from the list */
605         DestroyWindow( wndPtr->hwndChild );
606     SendMessage( hwnd, WM_NCDESTROY, 0, 0 );
607
608       /* Destroy the window */
609
610     WIN_DestroyWindow( hwnd );
611     return TRUE;
612 }
613
614
615 /***********************************************************************
616  *           CloseWindow   (USER.43)
617  */
618 BOOL CloseWindow(HWND hWnd)
619 {
620     WND * wndPtr = WIN_FindWndPtr(hWnd);
621     if (wndPtr->dwStyle & WS_CHILD) return TRUE;
622     ShowWindow(hWnd, SW_MINIMIZE);
623     return TRUE;
624 }
625
626  
627 /***********************************************************************
628  *           OpenIcon   (USER.44)
629  */
630 BOOL OpenIcon(HWND hWnd)
631 {
632     if (!IsIconic(hWnd)) return FALSE;
633     ShowWindow(hWnd, SW_SHOWNORMAL);
634     return(TRUE);
635 }
636
637  
638 /***********************************************************************
639  *           FindWindow   (USER.50)
640  */
641 HWND FindWindow( SEGPTR ClassMatch, LPSTR TitleMatch )
642 {
643     HCLASS hclass;
644     CLASS *classPtr;
645     HWND hwnd;
646
647     if (ClassMatch)
648     {
649         hclass = CLASS_FindClassByName( ClassMatch, (HINSTANCE)0xffff,
650                                         &classPtr );
651         if (!hclass) return 0;
652     }
653     else hclass = 0;
654
655     hwnd = GetTopWindow( hwndDesktop );
656     while(hwnd)
657     {
658         WND *wndPtr = WIN_FindWndPtr( hwnd );
659         if (!hclass || (wndPtr->hClass == hclass))
660         {
661               /* Found matching class */
662             if (!TitleMatch) return hwnd;
663             if (wndPtr->hText)
664             {
665                 char *textPtr = (char *) USER_HEAP_LIN_ADDR( wndPtr->hText );
666                 if (!strcmp( textPtr, TitleMatch )) return hwnd;
667             }
668         }
669         hwnd = wndPtr->hwndNext;
670     }
671     return 0;
672 }
673  
674  
675 /**********************************************************************
676  *           GetDesktopWindow   (USER.286)
677  */
678 HWND GetDesktopWindow(void)
679 {
680     return hwndDesktop;
681 }
682
683
684 /**********************************************************************
685  *           GetDesktopHwnd   (USER.278)
686  *
687  * Exactly the same thing as GetDesktopWindow(), but not documented.
688  * Don't ask me why...
689  */
690 HWND GetDesktopHwnd(void)
691 {
692     return hwndDesktop;
693 }
694
695
696 /*******************************************************************
697  *           EnableWindow   (USER.34)
698  */
699 BOOL EnableWindow( HWND hwnd, BOOL enable )
700 {
701     WND *wndPtr;
702
703     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
704     if (enable && (wndPtr->dwStyle & WS_DISABLED))
705     {
706           /* Enable window */
707         wndPtr->dwStyle &= ~WS_DISABLED;
708         SendMessage( hwnd, WM_ENABLE, TRUE, 0 );
709         return TRUE;
710     }
711     else if (!enable && !(wndPtr->dwStyle & WS_DISABLED))
712     {
713           /* Disable window */
714         wndPtr->dwStyle |= WS_DISABLED;
715         if ((hwnd == GetFocus()) || IsChild( hwnd, GetFocus() ))
716             SetFocus( 0 );  /* A disabled window can't have the focus */
717         if ((hwnd == GetCapture()) || IsChild( hwnd, GetCapture() ))
718             ReleaseCapture();  /* A disabled window can't capture the mouse */
719         SendMessage( hwnd, WM_ENABLE, FALSE, 0 );
720         return FALSE;
721     }
722     return ((wndPtr->dwStyle & WS_DISABLED) != 0);
723 }
724
725
726 /***********************************************************************
727  *           IsWindowEnabled   (USER.35)
728  */ 
729 BOOL IsWindowEnabled(HWND hWnd)
730 {
731     WND * wndPtr; 
732
733     if (!(wndPtr = WIN_FindWndPtr(hWnd))) return FALSE;
734     return !(wndPtr->dwStyle & WS_DISABLED);
735 }
736
737
738 /**********************************************************************
739  *           GetWindowWord    (USER.133)
740  */
741 WORD GetWindowWord( HWND hwnd, short offset )
742 {
743     WND * wndPtr = WIN_FindWndPtr( hwnd );
744     if (!wndPtr) return 0;
745     if (offset >= 0) return *(WORD *)(((char *)wndPtr->wExtra) + offset);
746     switch(offset)
747     {
748         case GWW_ID:         return wndPtr->wIDmenu;
749 #ifdef WINELIB32
750         case GWW_HWNDPARENT:
751         case GWW_HINSTANCE: 
752             fprintf(stderr,"GetWindowWord called with offset %d.\n",offset);
753             return 0;
754 #else
755         case GWW_HWNDPARENT: return (WORD)wndPtr->hwndParent;
756         case GWW_HINSTANCE:  return (WORD)wndPtr->hInstance;
757 #endif
758     }
759     return 0;
760 }
761
762
763 /**********************************************************************
764  *           WIN_GetWindowInstance
765  */
766 HINSTANCE WIN_GetWindowInstance(HWND hwnd)
767 {
768     WND * wndPtr = WIN_FindWndPtr( hwnd );
769     if (!wndPtr) return (HINSTANCE)0;
770     return wndPtr->hInstance;
771 }
772
773
774 /**********************************************************************
775  *           SetWindowWord    (USER.134)
776  */
777 WORD SetWindowWord( HWND hwnd, short offset, WORD newval )
778 {
779     WORD *ptr, retval;
780     WND * wndPtr = WIN_FindWndPtr( hwnd );
781     if (!wndPtr) return 0;
782     if (offset >= 0) ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
783     else switch(offset)
784     {
785 #ifdef WINELIB32
786         case GWW_ID:
787         case GWW_HINSTANCE:
788             fprintf(stderr,"SetWindowWord called with offset %d.\n",offset);
789             return 0;
790 #else
791         case GWW_ID:        ptr = &wndPtr->wIDmenu;   break;
792         case GWW_HINSTANCE: ptr = (WORD*)&wndPtr->hInstance; break;
793 #endif
794         default: return 0;
795     }
796     retval = *ptr;
797     *ptr = newval;
798     return retval;
799 }
800
801
802 /**********************************************************************
803  *           GetWindowLong    (USER.135)
804  */
805 LONG GetWindowLong( HWND hwnd, short offset )
806 {
807     WND * wndPtr = WIN_FindWndPtr( hwnd );
808     if (!wndPtr) return 0;
809     if (offset >= 0) return *(LONG *)(((char *)wndPtr->wExtra) + offset);
810     switch(offset)
811     {
812         case GWL_STYLE:   return wndPtr->dwStyle;
813         case GWL_EXSTYLE: return wndPtr->dwExStyle;
814         case GWL_WNDPROC: return (LONG)wndPtr->lpfnWndProc;
815 #ifdef WINELIB32
816         case GWW_HWNDPARENT: return (LONG)wndPtr->hwndParent;
817         case GWW_HINSTANCE:  return (LONG)wndPtr->hInstance;
818 #endif
819     }
820     return 0;
821 }
822
823
824 /**********************************************************************
825  *           SetWindowLong    (USER.136)
826  */
827 LONG SetWindowLong( HWND hwnd, short offset, LONG newval )
828 {
829     LONG *ptr, retval;
830     WND * wndPtr = WIN_FindWndPtr( hwnd );
831     if (!wndPtr) return 0;
832     if (offset >= 0) ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
833     else switch(offset)
834     {
835         case GWL_STYLE:   ptr = &wndPtr->dwStyle; break;
836         case GWL_EXSTYLE: ptr = &wndPtr->dwExStyle; break;
837         case GWL_WNDPROC: ptr = (LONG *)&wndPtr->lpfnWndProc; break;
838         default: return 0;
839     }
840     retval = *ptr;
841     *ptr = newval;
842     return retval;
843 }
844
845
846 /*******************************************************************
847  *         GetWindowText          (USER.36)
848  */
849 int WIN16_GetWindowText( HWND hwnd, SEGPTR lpString, int nMaxCount )
850 {
851     return (int)SendMessage(hwnd, WM_GETTEXT, (WORD)nMaxCount, 
852                                               (DWORD)lpString);
853 }
854
855 int GetWindowText( HWND hwnd, LPSTR lpString, int nMaxCount )
856 {
857     int len;
858     HANDLE handle;
859
860       /* We have to allocate a buffer on the USER heap */
861       /* to be able to pass its address to 16-bit code */
862     if (!(handle = USER_HEAP_ALLOC( nMaxCount ))) return 0;
863     len = (int)SendMessage( hwnd, WM_GETTEXT, (WPARAM)nMaxCount, 
864                             (LPARAM)USER_HEAP_SEG_ADDR(handle) );
865     strncpy( lpString, USER_HEAP_LIN_ADDR(handle), nMaxCount );
866     USER_HEAP_FREE( handle );
867     return len;
868 }
869
870
871 /*******************************************************************
872  *         SetWindowText          (USER.37)
873  */
874 void WIN16_SetWindowText( HWND hwnd, SEGPTR lpString )
875 {
876     SendMessage( hwnd, WM_SETTEXT, 0, (DWORD)lpString );
877 }
878
879 void SetWindowText( HWND hwnd, LPCSTR lpString )
880 {
881     HANDLE handle;
882
883       /* We have to allocate a buffer on the USER heap */
884       /* to be able to pass its address to 16-bit code */
885     if (!(handle = USER_HEAP_ALLOC( strlen(lpString)+1 ))) return;
886     strcpy( USER_HEAP_LIN_ADDR(handle), lpString );
887     SendMessage( hwnd, WM_SETTEXT, 0, (LPARAM)USER_HEAP_SEG_ADDR(handle) );
888     USER_HEAP_FREE( handle );
889 }
890
891
892 /*******************************************************************
893  *         GetWindowTextLength    (USER.38)
894  */
895 int GetWindowTextLength(HWND hwnd)
896 {
897     return (int)SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0 );
898 }
899
900
901 /*******************************************************************
902  *         IsWindow    (USER.47)
903  */
904 BOOL IsWindow( HWND hwnd )
905 {
906     WND * wndPtr = WIN_FindWndPtr( hwnd );
907     return ((wndPtr != NULL) && (wndPtr->dwMagic == WND_MAGIC));
908 }
909
910
911 /*****************************************************************
912  *         GetParent              (USER.46)
913  */
914 HWND GetParent(HWND hwnd)
915 {
916     WND *wndPtr = WIN_FindWndPtr(hwnd);
917     if (!wndPtr) return 0;
918     return (wndPtr->dwStyle & WS_CHILD) ?
919             wndPtr->hwndParent : wndPtr->hwndOwner;
920 }
921
922
923 /*****************************************************************
924  *         WIN_GetTopParent
925  *
926  * Get the top-level parent for a child window.
927  */
928 HWND WIN_GetTopParent( HWND hwnd )
929 {
930     while (hwnd)
931     {
932         WND *wndPtr = WIN_FindWndPtr( hwnd );
933         if (wndPtr->dwStyle & WS_CHILD) hwnd = wndPtr->hwndParent;
934         else break;
935     }
936     return hwnd;
937 }
938
939
940 /*****************************************************************
941  *         SetParent              (USER.233)
942  */
943 HWND SetParent(HWND hwndChild, HWND hwndNewParent)
944 {
945     HWND temp;
946
947     WND *wndPtr = WIN_FindWndPtr(hwndChild);
948     if (!wndPtr || !(wndPtr->dwStyle & WS_CHILD)) return 0;
949
950     temp = wndPtr->hwndParent;
951
952     WIN_UnlinkWindow(hwndChild);
953     if (hwndNewParent)
954       wndPtr->hwndParent = hwndNewParent;
955     else
956       wndPtr->hwndParent = GetDesktopWindow();
957     WIN_LinkWindow(hwndChild, HWND_BOTTOM);
958     
959     if (IsWindowVisible(hwndChild)) UpdateWindow(hwndChild);
960     
961     return temp;
962 }
963
964
965
966 /*******************************************************************
967  *         IsChild    (USER.48)
968  */
969 BOOL IsChild( HWND parent, HWND child )
970 {
971     WND * wndPtr = WIN_FindWndPtr( child );
972     while (wndPtr && (wndPtr->dwStyle & WS_CHILD))
973     {
974         if (wndPtr->hwndParent == parent) return TRUE;
975         wndPtr = WIN_FindWndPtr( wndPtr->hwndParent );
976     }
977     return FALSE;
978 }
979
980
981 /***********************************************************************
982  *           IsWindowVisible   (USER.49)
983  */
984 BOOL IsWindowVisible( HWND hwnd )
985 {
986     WND *wndPtr = WIN_FindWndPtr( hwnd );
987     while (wndPtr && (wndPtr->dwStyle & WS_CHILD))
988     {
989         if (!(wndPtr->dwStyle & WS_VISIBLE)) return FALSE;
990         wndPtr = WIN_FindWndPtr( wndPtr->hwndParent );
991     }
992     return (wndPtr && (wndPtr->dwStyle & WS_VISIBLE));
993 }
994
995  
996  
997 /*******************************************************************
998  *         GetTopWindow    (USER.229)
999  */
1000 HWND GetTopWindow( HWND hwnd )
1001 {
1002     WND * wndPtr = WIN_FindWndPtr( hwnd );
1003     if (wndPtr) return wndPtr->hwndChild;
1004     else return 0;
1005 }
1006
1007
1008 /*******************************************************************
1009  *         GetWindow    (USER.262)
1010  */
1011 HWND GetWindow( HWND hwnd, WORD rel )
1012 {
1013     WND * wndPtr = WIN_FindWndPtr( hwnd );
1014     if (!wndPtr) return 0;
1015     switch(rel)
1016     {
1017     case GW_HWNDFIRST:
1018         if (wndPtr->hwndParent)
1019         {
1020             WND * parentPtr = WIN_FindWndPtr( wndPtr->hwndParent );
1021             return parentPtr->hwndChild;
1022         }
1023         else return 0;
1024         
1025     case GW_HWNDLAST:
1026         if (!wndPtr->hwndParent) return 0;  /* Desktop window */
1027         while (wndPtr->hwndNext)
1028         {
1029             hwnd = wndPtr->hwndNext;
1030             wndPtr = WIN_FindWndPtr( hwnd );
1031         }
1032         return hwnd;
1033         
1034     case GW_HWNDNEXT:
1035         return wndPtr->hwndNext;
1036         
1037     case GW_HWNDPREV:   
1038         {
1039             HWND hwndPrev;
1040             
1041             if (wndPtr->hwndParent)
1042             {
1043                 WND * parentPtr = WIN_FindWndPtr( wndPtr->hwndParent );
1044                 hwndPrev = parentPtr->hwndChild;
1045             }
1046             else return 0;  /* Desktop window */
1047             if (hwndPrev == hwnd) return 0;
1048             while (hwndPrev)
1049             {
1050                 wndPtr = WIN_FindWndPtr( hwndPrev );
1051                 if (wndPtr->hwndNext == hwnd) break;
1052                 hwndPrev = wndPtr->hwndNext;
1053             }
1054             return hwndPrev;
1055         }
1056         
1057     case GW_OWNER:
1058         return wndPtr->hwndOwner;
1059
1060     case GW_CHILD:
1061         return wndPtr->hwndChild;
1062     }
1063     return 0;
1064 }
1065
1066
1067 /*******************************************************************
1068  *         GetNextWindow    (USER.230)
1069  */
1070 HWND GetNextWindow( HWND hwnd, WORD flag )
1071 {
1072     if ((flag != GW_HWNDNEXT) && (flag != GW_HWNDPREV)) return 0;
1073     return GetWindow( hwnd, flag );
1074 }
1075
1076 /*******************************************************************
1077  *         ShowOwnedPopups  (USER.265)
1078  */
1079 void ShowOwnedPopups( HWND owner, BOOL fShow )
1080 {
1081     HWND hwnd = GetWindow( hwndDesktop, GW_CHILD );
1082     while (hwnd)
1083     {
1084         WND *wnd = WIN_FindWndPtr(hwnd);
1085         if (wnd->hwndOwner == owner && (wnd->dwStyle & WS_POPUP))
1086             ShowWindow( hwnd, fShow ? SW_SHOW : SW_HIDE );
1087         hwnd = wnd->hwndNext;
1088     }
1089 }
1090
1091
1092 /*******************************************************************
1093  *         GetLastActivePopup    (USER.287)
1094  */
1095 HWND GetLastActivePopup(HWND hwnd)
1096 {
1097     WND *wndPtr;
1098     wndPtr = WIN_FindWndPtr(hwnd);
1099     if (wndPtr == NULL) return hwnd;
1100     return wndPtr->hwndLastActive;
1101 }
1102
1103
1104 /*******************************************************************
1105  *           EnumWindows   (USER.54)
1106  */
1107 BOOL EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
1108 {
1109     HWND hwnd;
1110     WND *wndPtr;
1111     HWND *list, *pWnd;
1112     int count;
1113
1114     /* We have to build a list of all windows first, to avoid */
1115     /* unpleasant side-effects, for instance if the callback  */
1116     /* function changes the Z-order of the windows.           */
1117
1118       /* First count the windows */
1119
1120     count = 0;
1121     for (hwnd = GetTopWindow(hwndDesktop); hwnd != 0; hwnd = wndPtr->hwndNext)
1122     {
1123         if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
1124         count++;
1125     }
1126     if (!count) return TRUE;
1127
1128       /* Now build the list of all windows */
1129
1130     if (!(list = (HWND *)malloc( sizeof(HWND) * count ))) return FALSE;
1131     for (hwnd = GetTopWindow(hwndDesktop), pWnd = list; hwnd != 0; hwnd = wndPtr->hwndNext)
1132     {
1133         wndPtr = WIN_FindWndPtr( hwnd );
1134         *pWnd++ = hwnd;
1135     }
1136
1137       /* Now call the callback function for every window */
1138
1139     for (pWnd = list; count > 0; count--, pWnd++)
1140     {
1141           /* Make sure that window still exists */
1142         if (!IsWindow(*pWnd)) continue;
1143         if (!CallEnumWindowsProc( lpEnumFunc, *pWnd, lParam )) break;
1144     }
1145     free( list );
1146     return TRUE;
1147 }
1148
1149
1150 /**********************************************************************
1151  *           EnumTaskWindows   (USER.225)
1152  */
1153 BOOL EnumTaskWindows( HTASK hTask, WNDENUMPROC lpEnumFunc, LPARAM lParam )
1154 {
1155     HWND hwnd;
1156     WND *wndPtr;
1157     HWND *list, *pWnd;
1158     HANDLE hQueue = GetTaskQueue( hTask );
1159     int count;
1160
1161     /* This function is the same as EnumWindows(),    */
1162     /* except for an added check on the window queue. */
1163
1164       /* First count the windows */
1165
1166     count = 0;
1167     for (hwnd = GetTopWindow(hwndDesktop); hwnd != 0; hwnd = wndPtr->hwndNext)
1168     {
1169         if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
1170         if (wndPtr->hmemTaskQ == hQueue) count++;
1171     }
1172     if (!count) return TRUE;
1173
1174       /* Now build the list of all windows */
1175
1176     if (!(list = (HWND *)malloc( sizeof(HWND) * count ))) return FALSE;
1177     for (hwnd = GetTopWindow(hwndDesktop), pWnd = list; hwnd != 0; hwnd = wndPtr->hwndNext)
1178     {
1179         wndPtr = WIN_FindWndPtr( hwnd );
1180         if (wndPtr->hmemTaskQ == hQueue) *pWnd++ = hwnd;
1181     }
1182
1183       /* Now call the callback function for every window */
1184
1185     for (pWnd = list; count > 0; count--, pWnd++)
1186     {
1187           /* Make sure that window still exists */
1188         if (!IsWindow(*pWnd)) continue;
1189         if (!CallEnumTaskWndProc( lpEnumFunc, *pWnd, lParam )) break;
1190     }
1191     free( list );
1192     return TRUE;
1193 }
1194
1195
1196 /*******************************************************************
1197  *    WIN_EnumChildWin
1198  *
1199  *   o hwnd is the first child to use, loop until all next windows
1200  *     are processed
1201  * 
1202  *   o call wdnenumprc
1203  *
1204  *   o call ourselves with the next child window
1205  * 
1206  */
1207 static BOOL WIN_EnumChildWin(HWND hwnd, FARPROC wndenumprc, LPARAM lParam)
1208 {
1209     WND *wndPtr;
1210     HWND hwndN,hwndCh;
1211
1212     while (hwnd)
1213     {
1214         if (!(wndPtr=WIN_FindWndPtr(hwnd))) return 0;
1215         hwndN=wndPtr->hwndNext;         /* storing hwnd is a way to avoid.. */
1216         hwndCh=wndPtr->hwndChild;               /* ..side effects after wndenumprc  */
1217         if (!CallEnumWindowsProc( wndenumprc, hwnd, lParam )) return 0;
1218         if (IsWindow(hwndCh))                   /* to prevent too early termination */
1219          if (!WIN_EnumChildWin(hwndCh, wndenumprc, lParam)) return 0;
1220         hwnd=hwndN;
1221     } 
1222     return 1;
1223 }
1224
1225 /*******************************************************************
1226  *    EnumChildWindows        (USER.55)
1227  *
1228  *   o gets the first child of hwnd
1229  *
1230  *   o calls WIN_EnumChildWin to do a recursive decent of child windows
1231  */
1232 BOOL EnumChildWindows(HWND hwnd, WNDENUMPROC wndenumprc, LPARAM lParam)
1233 {
1234     WND *wndPtr;
1235
1236     dprintf_enum(stddeb,"EnumChildWindows\n");
1237
1238     if (hwnd == 0) return 0;
1239     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
1240     hwnd = wndPtr->hwndChild;
1241     return WIN_EnumChildWin(hwnd, wndenumprc, lParam);         
1242 }
1243
1244
1245 /*******************************************************************
1246  *                      AnyPopup                [USER.52]
1247  */
1248 BOOL AnyPopup()
1249 {
1250  WND   *wndPtr = WIN_FindWndPtr(hwndDesktop);
1251  HWND   hwnd = wndPtr->hwndChild;
1252  
1253  for( ; hwnd ; hwnd = wndPtr->hwndNext )
1254   {
1255         wndPtr = WIN_FindWndPtr(hwnd);
1256         if(wndPtr->hwndOwner)
1257            if(wndPtr->dwStyle & WS_VISIBLE)
1258                 return TRUE;
1259   }
1260         return FALSE;
1261 }
1262
1263 /*******************************************************************
1264  *                      FlashWindow             [USER.105]
1265  */
1266 BOOL FlashWindow(HWND hWnd, BOOL bInvert)
1267 {
1268     WND *wndPtr = WIN_FindWndPtr(hWnd);
1269
1270     dprintf_win(stddeb,"FlashWindow: "NPFMT"\n", hWnd);
1271
1272     if (!wndPtr) return FALSE;
1273
1274     if (wndPtr->dwStyle & WS_MINIMIZE)
1275     {
1276         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
1277         {
1278             HDC hDC = GetDC(hWnd);
1279             
1280             if (!SendMessage( hWnd, WM_ERASEBKGND, (WPARAM)hDC, (LPARAM)0 ))
1281                 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
1282             
1283             ReleaseDC( hWnd, hDC );
1284             wndPtr->flags |= WIN_NCACTIVATED;
1285         }
1286         else
1287         {
1288             RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE |
1289                           RDW_UPDATENOW | RDW_FRAME );
1290             wndPtr->flags &= ~WIN_NCACTIVATED;
1291         }
1292         return TRUE;
1293     }
1294     else
1295     {
1296         WPARAM wparam;
1297         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
1298         else wparam = (hWnd == GetActiveWindow());
1299
1300         SendMessage( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
1301         return wparam;
1302     }
1303 }
1304
1305
1306 /*******************************************************************
1307  *                      SetSysModalWindow               [USER.188]
1308  */
1309 HWND SetSysModalWindow(HWND hWnd)
1310 {
1311     HWND hWndOldModal = hwndSysModal;
1312     hwndSysModal = hWnd;
1313     dprintf_win(stdnimp,"EMPTY STUB !! SetSysModalWindow("NPFMT") !\n", hWnd);
1314     return hWndOldModal;
1315 }
1316
1317
1318 /*******************************************************************
1319  *                      GetSysModalWindow               [USER.189]
1320  */
1321 HWND GetSysModalWindow(void)
1322 {
1323     return hwndSysModal;
1324 }
1325
1326 /*******************************************************************
1327  *                      DRAG_QueryUpdate
1328  *
1329  * recursively find a child that contains spDragInfo->pt point 
1330  * and send WM_QUERYDROPOBJECT
1331  */
1332 BOOL DRAG_QueryUpdate( HWND hQueryWnd, SEGPTR spDragInfo )
1333 {
1334  HWND           hWnd;
1335  BOOL           wParam,bResult = 0;
1336  POINT          pt;
1337  LPDRAGINFO     ptrDragInfo = (LPDRAGINFO) PTR_SEG_TO_LIN(spDragInfo);
1338  WND           *ptrQueryWnd = WIN_FindWndPtr(hQueryWnd),*ptrWnd;
1339  RECT           tempRect;       /* this sucks */
1340
1341  if( !ptrQueryWnd || !ptrDragInfo ) return 0;
1342
1343  pt             = ptrDragInfo->pt;
1344
1345  GetWindowRect(hQueryWnd,&tempRect); 
1346
1347  if( !PtInRect(&tempRect,pt) ||
1348      (ptrQueryWnd->dwStyle & WS_DISABLED) )
1349         return 0;
1350
1351  if( !(ptrQueryWnd->dwStyle & WS_MINIMIZE) ) 
1352    {
1353      tempRect = ptrQueryWnd->rectClient;
1354      if(ptrQueryWnd->dwStyle & WS_CHILD)
1355         MapWindowPoints(ptrQueryWnd->hwndParent,0,(LPPOINT)&tempRect,2);
1356
1357      if( PtInRect(&tempRect,pt) )
1358         {
1359          wParam = 0;
1360          ptrWnd = WIN_FindWndPtr(hWnd = ptrQueryWnd->hwndChild);
1361
1362          for( ;ptrWnd ;ptrWnd = WIN_FindWndPtr(hWnd = ptrWnd->hwndNext) )
1363            if( ptrWnd->dwStyle & WS_VISIBLE )
1364              {
1365               GetWindowRect(hWnd,&tempRect);
1366
1367               if( PtInRect(&tempRect,pt) ) 
1368                   break;
1369              }
1370
1371          if(ptrWnd)
1372             dprintf_msg(stddeb,"DragQueryUpdate: hwnd = "NPFMT", %i %i - %i %i\n",hWnd,
1373                         (int)ptrWnd->rectWindow.left,(int)ptrWnd->rectWindow.top,
1374                         (int)ptrWnd->rectWindow.right,(int)ptrWnd->rectWindow.bottom);   
1375          else
1376             dprintf_msg(stddeb,"DragQueryUpdate: hwnd = "NPFMT"\n",hWnd);
1377
1378          if(ptrWnd)
1379            if( !(ptrWnd->dwStyle & WS_DISABLED) )
1380                 bResult = DRAG_QueryUpdate(hWnd, spDragInfo);
1381
1382          if(bResult) return bResult;
1383         }
1384      else wParam = 1;
1385    }
1386  else wParam = 1;
1387
1388  ScreenToClient(hQueryWnd,&ptrDragInfo->pt);
1389
1390  ptrDragInfo->hScope = hQueryWnd;
1391
1392  bResult = SendMessage( hQueryWnd ,WM_QUERYDROPOBJECT ,
1393                        (WPARAM)wParam ,(LPARAM) spDragInfo );
1394  if( !bResult ) 
1395       ptrDragInfo->pt = pt;
1396
1397  return bResult;
1398 }
1399
1400 /*******************************************************************
1401  *                      DragDetect ( USER.465 )
1402  *
1403  */
1404 BOOL DragDetect(HWND hWnd, POINT pt)
1405 {
1406   MSG   msg;
1407   RECT  rect;
1408
1409   rect.left = pt.x - wDragWidth;
1410   rect.right = pt.x + wDragWidth;
1411
1412   rect.top = pt.y - wDragHeight;
1413   rect.bottom = pt.y + wDragHeight;
1414
1415   SetCapture(hWnd);
1416
1417   while(1)
1418    {
1419         while(PeekMessage(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
1420          {
1421            if( msg.message == WM_LBUTTONUP )
1422                 {
1423                   ReleaseCapture();
1424                   return 0;
1425                 }
1426            if( msg.message == WM_MOUSEMOVE )
1427                 {
1428                   POINT pt = { LOWORD(msg.lParam), HIWORD(msg.lParam) };
1429                   if( !PtInRect( &rect, pt ) )
1430                     {
1431                       ReleaseCapture();
1432                       return 1;
1433                     }
1434                 }
1435          }
1436         WaitMessage();
1437    }
1438
1439   return 0;
1440 }
1441
1442 /******************************************************************************
1443  *                              DragObject ( USER.464 )
1444  *
1445  */
1446 DWORD DragObject(HWND hwndScope, HWND hWnd, WORD wObj, HANDLE hOfStruct,
1447                 WORD szList , HCURSOR hCursor)
1448 {
1449  MSG            msg;
1450  LPDRAGINFO     lpDragInfo;
1451  SEGPTR         spDragInfo;
1452  HCURSOR        hDragCursor=0, hOldCursor=0, hBummer=0;
1453  HANDLE         hDragInfo  = GlobalAlloc( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO));
1454  WND           *wndPtr = WIN_FindWndPtr(hWnd);
1455  DWORD          dwRet = 0;
1456  short          dragDone = 0;
1457  HCURSOR        hCurrentCursor = 0;
1458  HWND           hCurrentWnd = 0;
1459  WORD           btemp;
1460
1461  lpDragInfo = (LPDRAGINFO) GlobalLock(hDragInfo);
1462  spDragInfo = (SEGPTR) WIN16_GlobalLock(hDragInfo);
1463
1464  if( !lpDragInfo || !spDragInfo ) return 0L;
1465
1466  hBummer = LoadCursor(0,IDC_BUMMER);
1467
1468  if( !hBummer || !wndPtr )
1469    {
1470         GlobalFree(hDragInfo);
1471         return 0L;
1472    }
1473
1474  if(hCursor)
1475    {
1476         if( !(hDragCursor = CURSORICON_IconToCursor(hCursor)) )
1477           {
1478            GlobalFree(hDragInfo);
1479            return 0L;
1480           }
1481
1482         if( hDragCursor == hCursor ) hDragCursor = 0;
1483         else hCursor = hDragCursor;
1484
1485         hOldCursor = SetCursor(hDragCursor);
1486    }
1487
1488  lpDragInfo->hWnd   = hWnd;
1489  lpDragInfo->hScope = 0;
1490  lpDragInfo->wFlags = wObj;
1491  lpDragInfo->hList  = szList; /* near pointer! */
1492  lpDragInfo->hOfStruct = hOfStruct;
1493  lpDragInfo->l = 0L; 
1494
1495  SetCapture(hWnd);
1496  ShowCursor(1);
1497
1498  while( !dragDone )
1499   {
1500     WaitMessage();
1501
1502     if( !PeekMessage(&msg,0,WM_MOUSEFIRST,WM_MOUSELAST,PM_REMOVE) )
1503          continue;
1504
1505    *(lpDragInfo+1) = *lpDragInfo;
1506
1507     lpDragInfo->pt = msg.pt;
1508
1509     /* update DRAGINFO struct */
1510     dprintf_msg(stddeb,"drag: lpDI->hScope = "NPFMT"\n",lpDragInfo->hScope);
1511
1512     if( (btemp = (WORD)DRAG_QueryUpdate(hwndScope, spDragInfo)) > 0 )
1513          hCurrentCursor = hCursor;
1514     else
1515         {
1516          hCurrentCursor = hBummer;
1517          lpDragInfo->hScope = 0;
1518         }
1519     if( hCurrentCursor )
1520         SetCursor(hCurrentCursor);
1521
1522     dprintf_msg(stddeb,"drag: got %04x\n",btemp);
1523
1524     /* send WM_DRAGLOOP */
1525     SendMessage( hWnd, WM_DRAGLOOP, (WPARAM)(hCurrentCursor != hBummer) , 
1526                                     (LPARAM) spDragInfo );
1527     /* send WM_DRAGSELECT or WM_DRAGMOVE */
1528     if( hCurrentWnd != lpDragInfo->hScope )
1529         {
1530          if( hCurrentWnd )
1531            SendMessage( hCurrentWnd, WM_DRAGSELECT, 0, 
1532                        (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO),
1533                                         HIWORD(spDragInfo)) );
1534          hCurrentWnd = lpDragInfo->hScope;
1535          if( hCurrentWnd )
1536            SendMessage( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo); 
1537         }
1538     else
1539         if( hCurrentWnd )
1540            SendMessage( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
1541
1542
1543     /* check if we're done */
1544     if( msg.message == WM_LBUTTONUP || msg.message == WM_NCLBUTTONUP )
1545         dragDone = TRUE;
1546   }
1547
1548  ReleaseCapture();
1549  ShowCursor(0);
1550
1551  if( hCursor )
1552    {
1553      SetCursor(hOldCursor);
1554      if( hDragCursor )
1555          DestroyCursor(hDragCursor);
1556    }
1557
1558  if( hCurrentCursor != hBummer ) 
1559         dwRet = SendMessage( lpDragInfo->hScope, WM_DROPOBJECT, 
1560                              (WPARAM)hWnd, (LPARAM)spDragInfo );
1561  GlobalFree(hDragInfo);
1562
1563  return dwRet;
1564 }
1565