Release 960805
[wine] / windows / win.c
1 /*
2  * Window related functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  */
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <X11/Xatom.h>
11
12 #include "options.h"
13 #include "class.h"
14 #include "win.h"
15 #include "heap.h"
16 #include "user.h"
17 #include "dce.h"
18 #include "sysmetrics.h"
19 #include "cursoricon.h"
20 #include "heap.h"
21 #include "hook.h"
22 #include "menu.h"
23 #include "message.h"
24 #include "nonclient.h"
25 #include "string32.h"
26 #include "queue.h"
27 #include "winpos.h"
28 #include "color.h"
29 #include "shm_main_blk.h"
30 #include "dde_proc.h"
31 #include "clipboard.h"
32 #include "winproc.h"
33 #include "stddebug.h"
34 /* #define DEBUG_WIN  */ 
35 /* #define DEBUG_MENU */
36 #include "debug.h"
37
38 /* Desktop window */
39 static WND *pWndDesktop = NULL;
40
41 static HWND hwndSysModal = 0;
42
43 static WORD wDragWidth = 4;
44 static WORD wDragHeight= 3;
45
46 extern HCURSOR CURSORICON_IconToCursor(HICON);
47 extern HQUEUE  QUEUE_GetDoomedQueue();
48
49 /***********************************************************************
50  *           WIN_FindWndPtr
51  *
52  * Return a pointer to the WND structure corresponding to a HWND.
53  */
54 WND * WIN_FindWndPtr( HWND32 hwnd )
55 {
56     WND * ptr;
57     
58     if (!hwnd || HIWORD(hwnd)) return NULL;
59     ptr = (WND *) USER_HEAP_LIN_ADDR( hwnd );
60     if (ptr->dwMagic != WND_MAGIC) return NULL;
61     if (ptr->hwndSelf != hwnd)
62     {
63         fprintf( stderr, "Can't happen: hwnd %04x self pointer is %04x\n",
64                  hwnd, ptr->hwndSelf );
65         return NULL;
66     }
67     return ptr;
68 }
69
70
71 /***********************************************************************
72  *           WIN_DumpWindow
73  *
74  * Dump the content of a window structure to stderr.
75  */
76 void WIN_DumpWindow( HWND32 hwnd )
77 {
78     WND *ptr;
79     char className[80];
80     int i;
81
82     if (!(ptr = WIN_FindWndPtr( hwnd )))
83     {
84         fprintf( stderr, "%04x is not a window handle\n", hwnd );
85         return;
86     }
87
88     if (!GetClassName32A( hwnd, className, sizeof(className ) ))
89         strcpy( className, "#NULL#" );
90
91     fprintf( stderr, "Window %04x (%p):\n", hwnd, ptr );
92     fprintf( stderr,
93              "next=%p  child=%p  parent=%p  owner=%p  class=%p '%s'\n"
94              "inst=%04x  taskQ=%04x  updRgn=%04x  active=%04x hdce=%04x  idmenu=%04x\n"
95              "style=%08lx  exstyle=%08lx  wndproc=%08x  text='%s'\n"
96              "client=%d,%d-%d,%d  window=%d,%d-%d,%d  iconpos=%d,%d  maxpos=%d,%d\n"
97              "sysmenu=%04x  flags=%04x  props=%p  vscroll=%p  hscroll=%p\n",
98              ptr->next, ptr->child, ptr->parent, ptr->owner,
99              ptr->class, className, ptr->hInstance, ptr->hmemTaskQ,
100              ptr->hrgnUpdate, ptr->hwndLastActive, ptr->hdce, ptr->wIDmenu,
101              ptr->dwStyle, ptr->dwExStyle, (UINT32)ptr->winproc,
102              ptr->text ? ptr->text : "",
103              ptr->rectClient.left, ptr->rectClient.top, ptr->rectClient.right,
104              ptr->rectClient.bottom, ptr->rectWindow.left, ptr->rectWindow.top,
105              ptr->rectWindow.right, ptr->rectWindow.bottom, ptr->ptIconPos.x,
106              ptr->ptIconPos.y, ptr->ptMaxPos.x, ptr->ptMaxPos.y, ptr->hSysMenu,
107              ptr->flags, ptr->pProp, ptr->pVScroll, ptr->pHScroll );
108
109     if (ptr->class->cbWndExtra)
110     {
111         fprintf( stderr, "extra bytes:" );
112         for (i = 0; i < ptr->class->cbWndExtra; i++)
113             fprintf( stderr, " %02x", *((BYTE*)ptr->wExtra+i) );
114         fprintf( stderr, "\n" );
115     }
116     fprintf( stderr, "\n" );
117 }
118
119
120 /***********************************************************************
121  *           WIN_WalkWindows
122  *
123  * Walk the windows tree and print each window on stderr.
124  */
125 void WIN_WalkWindows( HWND32 hwnd, int indent )
126 {
127     WND *ptr;
128     char className[80];
129
130     ptr = hwnd ? WIN_FindWndPtr( hwnd ) : pWndDesktop;
131     if (!ptr)
132     {
133         fprintf( stderr, "*** Invalid window handle %04x\n", hwnd );
134         return;
135     }
136
137     if (!indent)  /* first time around */
138         fprintf( stderr, "%-16.16s %-8.8s %-6.6s %-17.17s %-8.8s %s\n",
139                  "hwnd", " wndPtr", "queue", "Class Name", " Style", " WndProc");
140
141     while (ptr)
142     {
143         fprintf(stderr, "%*s%04x%*s", indent, "", ptr->hwndSelf, 13-indent,"");
144
145         GlobalGetAtomName16(ptr->class->atomName,className,sizeof(className));
146         
147         fprintf( stderr, "%08lx %-6.4x %-17.17s %08x %08x\n",
148                  (DWORD)ptr, ptr->hmemTaskQ, className,
149                  (UINT32)ptr->dwStyle, (UINT32)ptr->winproc );
150         
151         if (ptr->child) WIN_WalkWindows( ptr->child->hwndSelf, indent+1 );
152         ptr = ptr->next;
153     }
154 }
155
156
157 /***********************************************************************
158  *           WIN_GetXWindow
159  *
160  * Return the X window associated to a window.
161  */
162 Window WIN_GetXWindow( HWND32 hwnd )
163 {
164     WND *wndPtr = WIN_FindWndPtr( hwnd );
165     while (wndPtr && !wndPtr->window) wndPtr = wndPtr->parent;
166     return wndPtr ? wndPtr->window : 0;
167 }
168
169
170 /***********************************************************************
171  *           WIN_UnlinkWindow
172  *
173  * Remove a window from the siblings linked list.
174  */
175 BOOL32 WIN_UnlinkWindow( HWND32 hwnd )
176 {    
177     WND *wndPtr, **ppWnd;
178
179     if (!(wndPtr = WIN_FindWndPtr( hwnd )) || !wndPtr->parent) return FALSE;
180     ppWnd = &wndPtr->parent->child;
181     while (*ppWnd != wndPtr) ppWnd = &(*ppWnd)->next;
182     *ppWnd = wndPtr->next;
183     return TRUE;
184 }
185
186
187 /***********************************************************************
188  *           WIN_LinkWindow
189  *
190  * Insert a window into the siblings linked list.
191  * The window is inserted after the specified window, which can also
192  * be specified as HWND_TOP or HWND_BOTTOM.
193  */
194 BOOL32 WIN_LinkWindow( HWND32 hwnd, HWND32 hwndInsertAfter )
195 {    
196     WND *wndPtr, **ppWnd;
197
198     if (!(wndPtr = WIN_FindWndPtr( hwnd )) || !wndPtr->parent) return FALSE;
199
200     if ((hwndInsertAfter == HWND_TOP) || (hwndInsertAfter == HWND_BOTTOM))
201     {
202         ppWnd = &wndPtr->parent->child;  /* Point to first sibling hwnd */
203         if (hwndInsertAfter == HWND_BOTTOM)  /* Find last sibling hwnd */
204             while (*ppWnd) ppWnd = &(*ppWnd)->next;
205     }
206     else  /* Normal case */
207     {
208         WND * afterPtr = WIN_FindWndPtr( hwndInsertAfter );
209         if (!afterPtr) return FALSE;
210         ppWnd = &afterPtr->next;
211     }
212     wndPtr->next = *ppWnd;
213     *ppWnd = wndPtr;
214     return TRUE;
215 }
216
217
218 /***********************************************************************
219  *           WIN_FindWinToRepaint
220  *
221  * Find a window that needs repaint.
222  */
223 HWND32 WIN_FindWinToRepaint( HWND32 hwnd, HQUEUE16 hQueue )
224 {
225     HWND hwndRet;
226     WND *pWnd = pWndDesktop;
227
228     /* Note: the desktop window never gets WM_PAINT messages */
229     pWnd = hwnd ? WIN_FindWndPtr( hwnd ) : pWndDesktop->child;
230
231     for ( ; pWnd ; pWnd = pWnd->next )
232     {
233         if (!(pWnd->dwStyle & WS_VISIBLE) || (pWnd->flags & WIN_NO_REDRAW))
234         {
235             dprintf_win( stddeb, "FindWinToRepaint: skipping window %04x\n",
236                          pWnd->hwndSelf );
237             continue;
238         }
239         if ((pWnd->hmemTaskQ == hQueue) &&
240             (pWnd->hrgnUpdate || (pWnd->flags & WIN_INTERNAL_PAINT))) break;
241         
242         if (pWnd->child )
243             if ((hwndRet = WIN_FindWinToRepaint( pWnd->child->hwndSelf, hQueue )) )
244                 return hwndRet;
245     }
246     
247     if (!pWnd) return 0;
248     
249     hwndRet = pWnd->hwndSelf;
250
251     /* look among siblings if we got a transparent window */
252     while (pWnd && ((pWnd->dwExStyle & WS_EX_TRANSPARENT) ||
253                     !(pWnd->hrgnUpdate || (pWnd->flags & WIN_INTERNAL_PAINT))))
254     {
255         pWnd = pWnd->next;
256     }
257     if (pWnd) hwndRet = pWnd->hwndSelf;
258     dprintf_win(stddeb,"FindWinToRepaint: found %04x\n",hwndRet);
259     return hwndRet;
260 }
261
262
263 /***********************************************************************
264  *           WIN_SendParentNotify
265  *
266  * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
267  * the window has the WS_EX_NOPARENTNOTIFY style.
268  */
269 void WIN_SendParentNotify( HWND32 hwnd, WORD event, WORD idChild, LONG lValue )
270 {
271     LPPOINT16 lppt = (LPPOINT16)&lValue;
272     WND     *wndPtr = WIN_FindWndPtr( hwnd );
273     BOOL     bMouse = ((event <= WM_MOUSELAST) && (event >= WM_MOUSEFIRST));
274
275     /* if lValue contains cursor coordinates they have to be
276      * mapped to the client area of parent window */
277
278     if (bMouse) MapWindowPoints16(0, hwnd, lppt, 1);
279 #ifndef WINELIB32
280     else lValue = MAKELONG( LOWORD(lValue), idChild );
281 #endif
282
283     while (wndPtr)
284     {
285         if ((wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY) ||
286            !(wndPtr->dwStyle & WS_CHILD)) break;
287
288         if (bMouse)
289         {
290             lppt->x += wndPtr->rectClient.left;
291             lppt->y += wndPtr->rectClient.top;
292         }
293
294         wndPtr = wndPtr->parent;
295 #ifdef WINELIB32
296         SendMessage32A( wndPtr->hwndSelf, WM_PARENTNOTIFY, 
297                         MAKEWPARAM( event, idChild ), lValue );
298 #else
299         SendMessage16( wndPtr->hwndSelf, WM_PARENTNOTIFY, event, (LPARAM)lValue);
300 #endif
301     }
302 }
303
304
305 /***********************************************************************
306  *           WIN_DestroyWindow
307  *
308  * Destroy storage associated to a window
309  */
310 static void WIN_DestroyWindow( HWND hwnd )
311 {
312     WND *wndPtr = WIN_FindWndPtr( hwnd );
313
314 #ifdef CONFIG_IPC
315     if (main_block)
316         DDE_DestroyWindow(hwnd);
317 #endif  /* CONFIG_IPC */
318         
319     if (!wndPtr) return;
320     WIN_UnlinkWindow( hwnd ); /* Remove the window from the linked list */
321     TIMER_RemoveWindowTimers( hwnd );
322     PROPERTY_RemoveWindowProps( wndPtr );
323     wndPtr->dwMagic = 0;  /* Mark it as invalid */
324     wndPtr->hwndSelf = 0;
325     if ((wndPtr->hrgnUpdate) || (wndPtr->flags & WIN_INTERNAL_PAINT))
326     {
327         if (wndPtr->hrgnUpdate) DeleteObject( wndPtr->hrgnUpdate );
328         QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
329     }
330     if (!(wndPtr->dwStyle & WS_CHILD))
331     {
332         if (wndPtr->wIDmenu) DestroyMenu( (HMENU)wndPtr->wIDmenu );
333     }
334     if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
335     if (wndPtr->window) XDestroyWindow( display, wndPtr->window );
336     if (wndPtr->class->style & CS_OWNDC) DCE_FreeDCE( wndPtr->hdce );
337     WINPROC_FreeProc( wndPtr->winproc );
338     wndPtr->class->cWindows--;
339     USER_HEAP_FREE( hwnd );
340 }
341
342
343 /***********************************************************************
344  *           WIN_DestroyQueueWindows
345  */
346 void WIN_DestroyQueueWindows( WND* wnd, HQUEUE hQueue )
347 {
348     WND* next;
349
350     while (wnd)
351     {
352         next = wnd->next;
353         if (wnd->hmemTaskQ == hQueue) DestroyWindow( wnd->hwndSelf );
354         else WIN_DestroyQueueWindows( wnd->child, hQueue );
355         wnd = next;
356     }
357 }
358
359
360 /***********************************************************************
361  *           WIN_CreateDesktopWindow
362  *
363  * Create the desktop window.
364  */
365 BOOL32 WIN_CreateDesktopWindow(void)
366 {
367     CLASS *class;
368     HDC hdc;
369     HWND hwndDesktop;
370
371     dprintf_win(stddeb,"Creating desktop window\n");
372
373     if (!(class = CLASS_FindClassByAtom( DESKTOP_CLASS_ATOM, 0 )))
374         return FALSE;
375
376     hwndDesktop = USER_HEAP_ALLOC( sizeof(WND)+class->cbWndExtra );
377     if (!hwndDesktop) return FALSE;
378     pWndDesktop = (WND *) USER_HEAP_LIN_ADDR( hwndDesktop );
379
380     pWndDesktop->next              = NULL;
381     pWndDesktop->child             = NULL;
382     pWndDesktop->parent            = NULL;
383     pWndDesktop->owner             = NULL;
384     pWndDesktop->class             = class;
385     pWndDesktop->winproc           = NULL;
386     pWndDesktop->dwMagic           = WND_MAGIC;
387     pWndDesktop->hwndSelf          = hwndDesktop;
388     pWndDesktop->hInstance         = 0;
389     pWndDesktop->rectWindow.left   = 0;
390     pWndDesktop->rectWindow.top    = 0;
391     pWndDesktop->rectWindow.right  = SYSMETRICS_CXSCREEN;
392     pWndDesktop->rectWindow.bottom = SYSMETRICS_CYSCREEN;
393     pWndDesktop->rectClient        = pWndDesktop->rectWindow;
394     pWndDesktop->rectNormal        = pWndDesktop->rectWindow;
395     pWndDesktop->ptIconPos.x       = -1;
396     pWndDesktop->ptIconPos.y       = -1;
397     pWndDesktop->ptMaxPos.x        = -1;
398     pWndDesktop->ptMaxPos.y        = -1;
399     pWndDesktop->text              = NULL;
400     pWndDesktop->hmemTaskQ         = 0; /* Desktop does not belong to a task */
401     pWndDesktop->hrgnUpdate        = 0;
402     pWndDesktop->hwndLastActive    = hwndDesktop;
403     pWndDesktop->dwStyle           = WS_VISIBLE | WS_CLIPCHILDREN |
404                                      WS_CLIPSIBLINGS;
405     pWndDesktop->dwExStyle         = 0;
406     pWndDesktop->hdce              = 0;
407     pWndDesktop->pVScroll          = NULL;
408     pWndDesktop->pHScroll          = NULL;
409     pWndDesktop->pProp             = NULL;
410     pWndDesktop->wIDmenu           = 0;
411     pWndDesktop->flags             = 0;
412     pWndDesktop->window            = rootWindow;
413     pWndDesktop->hSysMenu          = 0;
414     pWndDesktop->userdata          = 0;
415
416     WINPROC_SetProc( &pWndDesktop->winproc, (WNDPROC16)class->winproc, 0 );
417     EVENT_RegisterWindow( pWndDesktop );
418     SendMessage32A( hwndDesktop, WM_NCCREATE, 0, 0 );
419     if ((hdc = GetDC( hwndDesktop )) != 0)
420     {
421         SendMessage32A( hwndDesktop, WM_ERASEBKGND, hdc, 0 );
422         ReleaseDC( hwndDesktop, hdc );
423     }
424     return TRUE;
425 }
426
427
428 /***********************************************************************
429  *           WIN_CreateWindowEx
430  *
431  * Implementation of CreateWindowEx().
432  */
433 static HWND WIN_CreateWindowEx( CREATESTRUCT32A *cs, ATOM classAtom,
434                                 BOOL unicode )
435 {
436     CLASS *classPtr;
437     WND *wndPtr;
438     HWND16 hwnd;
439     POINT16 maxSize, maxPos, minTrack, maxTrack;
440     LRESULT wmcreate;
441
442     dprintf_win( stddeb, "CreateWindowEx: " );
443     if (HIWORD(cs->lpszName)) dprintf_win( stddeb, "'%s' ", cs->lpszName );
444     else dprintf_win( stddeb, "#%04x ", LOWORD(cs->lpszName) );
445     if (HIWORD(cs->lpszClass)) dprintf_win( stddeb, "'%s' ", cs->lpszClass );
446     else dprintf_win( stddeb, "#%04x ", LOWORD(cs->lpszClass) );
447
448     dprintf_win( stddeb, "%08lx %08lx %d,%d %dx%d %04x %04x %04x %p\n",
449                  cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
450                  cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams);
451
452     /* Find the parent window */
453
454     if (cs->hwndParent)
455     {
456         /* Make sure parent is valid */
457         if (!IsWindow( cs->hwndParent ))
458         {
459             fprintf( stderr, "CreateWindowEx: bad parent %04x\n", cs->hwndParent );
460             return 0;
461         }
462     }
463     else if (cs->style & WS_CHILD)
464     {
465         fprintf( stderr, "CreateWindowEx: no parent for child window\n" );
466         return 0;  /* WS_CHILD needs a parent */
467     }
468
469     /* Find the window class */
470
471     if (!(classPtr = CLASS_FindClassByAtom( classAtom,
472                                             GetExePtr(cs->hInstance) )))
473     {
474         char buffer[256];
475         GlobalGetAtomName32A( classAtom, buffer, sizeof(buffer) );
476         fprintf( stderr, "CreateWindowEx: bad class '%s'\n", buffer );
477         return 0;
478     }
479
480     /* Fix the coordinates */
481
482     if (cs->x == CW_USEDEFAULT32) cs->x = cs->y = 0;
483     if (cs->cx == CW_USEDEFAULT32)
484     {
485 /*        if (!(cs->style & (WS_CHILD | WS_POPUP))) cs->cx = cs->cy = 0;
486         else */
487         {
488             cs->cx = 600;
489             cs->cy = 400;
490         }
491     }
492
493     /* Create the window structure */
494
495     if (!(hwnd = USER_HEAP_ALLOC( sizeof(*wndPtr) + classPtr->cbWndExtra
496                                   - sizeof(wndPtr->wExtra) )))
497     {
498         dprintf_win( stddeb, "CreateWindowEx: out of memory\n" );
499         return 0;
500     }
501
502     /* Fill the window structure */
503
504     wndPtr = (WND *) USER_HEAP_LIN_ADDR( hwnd );
505     wndPtr->next           = NULL;
506     wndPtr->child          = NULL;
507     wndPtr->parent         = (cs->style & WS_CHILD) ?
508                               WIN_FindWndPtr( cs->hwndParent ) : pWndDesktop;
509     wndPtr->owner          = (cs->style & WS_CHILD) ? NULL :
510                               WIN_FindWndPtr(WIN_GetTopParent(cs->hwndParent));
511     wndPtr->window         = 0;
512     wndPtr->class          = classPtr;
513     wndPtr->winproc        = NULL;
514     wndPtr->dwMagic        = WND_MAGIC;
515     wndPtr->hwndSelf       = hwnd;
516     wndPtr->hInstance      = cs->hInstance;
517     wndPtr->ptIconPos.x    = -1;
518     wndPtr->ptIconPos.y    = -1;
519     wndPtr->ptMaxPos.x     = -1;
520     wndPtr->ptMaxPos.y     = -1;
521     wndPtr->text           = NULL;
522     wndPtr->hmemTaskQ      = GetTaskQueue(0);
523     wndPtr->hrgnUpdate     = 0;
524     wndPtr->hwndLastActive = hwnd;
525     wndPtr->dwStyle        = cs->style & ~WS_VISIBLE;
526     wndPtr->dwExStyle      = cs->dwExStyle;
527     wndPtr->wIDmenu        = 0;
528     wndPtr->flags          = 0;
529     wndPtr->pVScroll       = NULL;
530     wndPtr->pHScroll       = NULL;
531     wndPtr->pProp          = NULL;
532     wndPtr->hSysMenu       = MENU_GetDefSysMenu();
533     wndPtr->userdata       = 0;
534
535     if (classPtr->cbWndExtra) memset( wndPtr->wExtra, 0, classPtr->cbWndExtra);
536     classPtr->cWindows++;
537
538     /* Set the window procedure */
539
540     WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)classPtr->winproc, 0 );
541
542     /* Correct the window style */
543
544     if (!(cs->style & (WS_POPUP | WS_CHILD)))  /* Overlapped window */
545     {
546         wndPtr->dwStyle |= WS_CAPTION | WS_CLIPSIBLINGS;
547         wndPtr->flags |= WIN_NEED_SIZE;
548     }
549     if (cs->dwExStyle & WS_EX_DLGMODALFRAME) wndPtr->dwStyle &= ~WS_THICKFRAME;
550
551     /* Get class or window DC if needed */
552
553     if (classPtr->style & CS_OWNDC) wndPtr->hdce = DCE_AllocDCE(hwnd, DCE_WINDOW_DC);
554     else if (classPtr->style & CS_CLASSDC) wndPtr->hdce = classPtr->hdce;
555     else wndPtr->hdce = 0;
556
557     /* Insert the window in the linked list */
558
559     WIN_LinkWindow( hwnd, (cs->style & WS_CHILD) ? HWND_BOTTOM : HWND_TOP );
560
561     /* Send the WM_GETMINMAXINFO message and fix the size if needed */
562
563     if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
564     {
565         NC_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack );
566         if (maxSize.x < cs->cx) cs->cx = maxSize.x;
567         if (maxSize.y < cs->cy) cs->cy = maxSize.y;
568         if (cs->cx < minTrack.x ) cs->cx = minTrack.x;
569         if (cs->cy < minTrack.y ) cs->cy = minTrack.y;
570     }
571     if (cs->cx <= 0) cs->cx = 1;
572     if (cs->cy <= 0) cs->cy = 1;
573
574     wndPtr->rectWindow.left   = cs->x;
575     wndPtr->rectWindow.top    = cs->y;
576     wndPtr->rectWindow.right  = cs->x + cs->cx;
577     wndPtr->rectWindow.bottom = cs->y + cs->cy;
578     wndPtr->rectClient        = wndPtr->rectWindow;
579     wndPtr->rectNormal        = wndPtr->rectWindow;
580
581     /* Create the X window (only for top-level windows, and then only */
582     /* when there's no desktop window) */
583
584     if (!(cs->style & WS_CHILD) && (rootWindow == DefaultRootWindow(display)))
585     {
586         XSetWindowAttributes win_attr;
587         Atom XA_WM_DELETE_WINDOW;
588
589         if (Options.managed && ((cs->style & (WS_DLGFRAME | WS_THICKFRAME)) ||
590             (cs->dwExStyle & WS_EX_DLGMODALFRAME)))
591         {
592             win_attr.event_mask = ExposureMask | KeyPressMask |
593                                   KeyReleaseMask | PointerMotionMask |
594                                   ButtonPressMask | ButtonReleaseMask |
595                                   FocusChangeMask | StructureNotifyMask;
596             win_attr.override_redirect = FALSE;
597             wndPtr->flags |= WIN_MANAGED;
598         }
599         else
600         {
601             win_attr.event_mask = ExposureMask | KeyPressMask |
602                                   KeyReleaseMask | PointerMotionMask |
603                                   ButtonPressMask | ButtonReleaseMask |
604                                   FocusChangeMask | StructureNotifyMask;
605             win_attr.override_redirect = TRUE;
606         }
607         win_attr.colormap      = COLOR_GetColormap();
608         win_attr.backing_store = Options.backingstore ? WhenMapped : NotUseful;
609         win_attr.save_under    = ((classPtr->style & CS_SAVEBITS) != 0);
610         win_attr.cursor        = CURSORICON_XCursor;
611         wndPtr->window = XCreateWindow( display, rootWindow, cs->x, cs->y,
612                                         cs->cx, cs->cy, 0, CopyFromParent,
613                                         InputOutput, CopyFromParent,
614                                         CWEventMask | CWOverrideRedirect |
615                                         CWColormap | CWCursor | CWSaveUnder |
616                                         CWBackingStore, &win_attr );
617         XA_WM_DELETE_WINDOW = XInternAtom( display, "WM_DELETE_WINDOW",
618                                            False );
619         XSetWMProtocols( display, wndPtr->window, &XA_WM_DELETE_WINDOW, 1 );
620
621         if ((wndPtr->flags & WIN_MANAGED) &&
622             (cs->dwExStyle & WS_EX_DLGMODALFRAME))
623         {
624             XSizeHints* size_hints = XAllocSizeHints();
625
626             if (size_hints)
627             {
628                 size_hints->min_width = size_hints->max_width = cs->cx;
629                 size_hints->min_height = size_hints->max_height = cs->cy;
630                 size_hints->flags = (PSize | PMinSize | PMaxSize);
631                 XSetWMSizeHints( display, wndPtr->window, size_hints,
632                                  XA_WM_NORMAL_HINTS );
633                 XFree(size_hints);
634             }
635         }
636
637         if (cs->hwndParent)  /* Get window owner */
638         {
639             Window win = WIN_GetXWindow( cs->hwndParent );
640             if (win) XSetTransientForHint( display, wndPtr->window, win );
641         }
642         EVENT_RegisterWindow( wndPtr );
643     }
644
645     /* Set the window menu */
646
647     if ((cs->style & WS_CAPTION) && !(cs->style & WS_CHILD))
648     {
649         if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
650         else
651         {
652 #if 0  /* FIXME: should check if classPtr->menuNameW can be used as is */
653             if (classPtr->menuNameA)
654                 cs->hMenu = HIWORD(classPtr->menuNameA) ?
655                        LoadMenu(cs->hInstance,SEGPTR_GET(classPtr->menuNameA)):
656                        LoadMenu(cs->hInstance,(SEGPTR)classPtr->menuNameA);
657 #else
658             SEGPTR menuName = (SEGPTR)GetClassLong16( hwnd, GCL_MENUNAME );
659             if (menuName) cs->hMenu = LoadMenu16( cs->hInstance, menuName );
660 #endif
661         }
662         if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
663     }
664     else wndPtr->wIDmenu = (UINT)cs->hMenu;
665
666     /* Send the WM_CREATE message */
667
668     if (unicode)
669     {
670         if (!SendMessage32W( hwnd, WM_NCCREATE, 0, (LPARAM)cs)) wmcreate = -1;
671         else
672         {
673             WINPOS_SendNCCalcSize( hwnd, FALSE, &wndPtr->rectWindow,
674                                    NULL, NULL, 0, &wndPtr->rectClient );
675             wmcreate = SendMessage32W( hwnd, WM_CREATE, 0, (LPARAM)cs );
676         }
677     }
678     else
679     {
680         if (!SendMessage32A( hwnd, WM_NCCREATE, 0, (LPARAM)cs)) wmcreate = -1;
681         else
682         {
683             WINPOS_SendNCCalcSize( hwnd, FALSE, &wndPtr->rectWindow,
684                                    NULL, NULL, 0, &wndPtr->rectClient );
685             wmcreate = SendMessage32A( hwnd, WM_CREATE, 0, (LPARAM)cs );
686         }
687     }
688     
689     if (wmcreate == -1)
690     {
691           /* Abort window creation */
692         dprintf_win(stddeb,"CreateWindowEx: wmcreate==-1, aborting\n");
693         WIN_DestroyWindow( hwnd );
694         return 0;
695     }
696
697     /* Send the size messages */
698
699     if (!(wndPtr->flags & WIN_NEED_SIZE))
700     {
701         /* send it anyway */
702         SendMessage16( hwnd, WM_SIZE, SIZE_RESTORED,
703                    MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
704                             wndPtr->rectClient.bottom-wndPtr->rectClient.top));
705         SendMessage16( hwnd, WM_MOVE, 0, MAKELONG( wndPtr->rectClient.left,
706                                                    wndPtr->rectClient.top ));
707     } 
708
709     WIN_SendParentNotify( hwnd, WM_CREATE, wndPtr->wIDmenu, (LONG)hwnd );
710     if (!IsWindow(hwnd)) return 0;
711
712     /* Show the window, maximizing or minimizing if needed */
713
714     if (wndPtr->dwStyle & WS_MINIMIZE)
715     {
716         /* MinMaximize(hwnd, SW_SHOWMINNOACTIVE, 1) in "Internals" */
717
718         wndPtr->dwStyle &= ~WS_MAXIMIZE;
719         WINPOS_FindIconPos( hwnd );
720         SetWindowPos( hwnd, 0, wndPtr->ptIconPos.x, wndPtr->ptIconPos.y,
721                       SYSMETRICS_CXICON, SYSMETRICS_CYICON, 
722                       SWP_FRAMECHANGED | ((GetActiveWindow())? SWP_NOACTIVATE : 0)  );
723     }
724     else if (wndPtr->dwStyle & WS_MAXIMIZE)
725     {
726         /* MinMaximize(hwnd, SW_SHOWMAXIMIZED, 1) */
727
728         POINT16 maxSize, maxPos, minTrack, maxTrack;
729         NC_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack );
730         SetWindowPos( hwnd, 0, maxPos.x, maxPos.y, maxSize.x, maxSize.y,
731             ((GetActiveWindow())? SWP_NOACTIVATE : 0) | SWP_FRAMECHANGED );
732     }
733     
734     if (cs->style & WS_VISIBLE) ShowWindow( hwnd, SW_SHOW );
735
736     /* Call WH_SHELL hook */
737
738     if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner)
739         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, hwnd, 0 );
740
741     dprintf_win(stddeb, "CreateWindowEx: returning %04x\n", hwnd);
742     return hwnd;
743 }
744
745
746 /***********************************************************************
747  *           CreateWindow16   (USER.41)
748  */
749 HWND16 CreateWindow16( LPCSTR className, LPCSTR windowName,
750                        DWORD style, INT16 x, INT16 y, INT16 width,
751                        INT16 height, HWND16 parent, HMENU16 menu,
752                        HINSTANCE16 instance, LPVOID data ) 
753 {
754     return CreateWindowEx16( 0, className, windowName, style,
755                            x, y, width, height, parent, menu, instance, data );
756 }
757
758
759 /***********************************************************************
760  *           CreateWindowEx16   (USER.452)
761  */
762 HWND16 CreateWindowEx16( DWORD exStyle, LPCSTR className, LPCSTR windowName,
763                          DWORD style, INT16 x, INT16 y, INT16 width,
764                          INT16 height, HWND16 parent, HMENU16 menu,
765                          HINSTANCE16 instance, LPVOID data ) 
766 {
767     ATOM classAtom;
768     CREATESTRUCT32A cs;
769
770     /* Find the class atom */
771
772     if (!(classAtom = GlobalFindAtom32A( className )))
773     {
774         fprintf( stderr, "CreateWindowEx16: bad class name " );
775         if (!HIWORD(className)) fprintf( stderr, "%04x\n", LOWORD(className) );
776         else fprintf( stderr, "'%s'\n", className );
777         return 0;
778     }
779
780     /* Fix the coordinates */
781
782     cs.x  = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT32 : (INT32)x;
783     cs.y  = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT32 : (INT32)y;
784     cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT32 : (INT32)width;
785     cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT32 : (INT32)height;
786
787     /* Create the window */
788
789     cs.lpCreateParams = data;
790     cs.hInstance      = (HINSTANCE32)instance;
791     cs.hMenu          = (HMENU32)menu;
792     cs.hwndParent     = (HWND32)parent;
793     cs.style          = style;
794     cs.lpszName       = windowName;
795     cs.lpszClass      = className;
796     cs.dwExStyle      = exStyle;
797     return WIN_CreateWindowEx( &cs, classAtom, FALSE );
798 }
799
800
801 /***********************************************************************
802  *           CreateWindowEx32A   (USER32.82)
803  */
804 HWND32 CreateWindowEx32A( DWORD exStyle, LPCSTR className, LPCSTR windowName,
805                           DWORD style, INT32 x, INT32 y, INT32 width,
806                           INT32 height, HWND32 parent, HMENU32 menu,
807                           HINSTANCE32 instance, LPVOID data )
808 {
809     ATOM classAtom;
810     CREATESTRUCT32A cs;
811
812     /* Find the class atom */
813
814     if (!(classAtom = GlobalFindAtom32A( className )))
815     {
816         fprintf( stderr, "CreateWindowEx32A: bad class name " );
817         if (!HIWORD(className)) fprintf( stderr, "%04x\n", LOWORD(className) );
818         else fprintf( stderr, "'%s'\n", className );
819         return 0;
820     }
821
822     /* Create the window */
823
824     cs.lpCreateParams = data;
825     cs.hInstance      = instance;
826     cs.hMenu          = menu;
827     cs.hwndParent     = parent;
828     cs.x              = x;
829     cs.y              = y;
830     cs.cx             = width;
831     cs.cy             = height;
832     cs.style          = style;
833     cs.lpszName       = windowName;
834     cs.lpszClass      = className;
835     cs.dwExStyle      = exStyle;
836     return WIN_CreateWindowEx( &cs, classAtom, FALSE );
837 }
838
839
840 /***********************************************************************
841  *           CreateWindowEx32W   (USER32.83)
842  */
843 HWND32 CreateWindowEx32W( DWORD exStyle, LPCWSTR className, LPCWSTR windowName,
844                           DWORD style, INT32 x, INT32 y, INT32 width,
845                           INT32 height, HWND32 parent, HMENU32 menu,
846                           HINSTANCE32 instance, LPVOID data )
847 {
848     ATOM classAtom;
849     CREATESTRUCT32W cs;
850
851     /* Find the class atom */
852
853     if (!(classAtom = GlobalFindAtom32W( className )))
854     {
855         fprintf( stderr, "CreateWindowEx32W: bad class name %p\n", className );
856         return 0;
857     }
858
859     /* Create the window */
860
861     cs.lpCreateParams = data;
862     cs.hInstance      = instance;
863     cs.hMenu          = menu;
864     cs.hwndParent     = parent;
865     cs.x              = x;
866     cs.y              = y;
867     cs.cx             = width;
868     cs.cy             = height;
869     cs.style          = style;
870     cs.lpszName       = windowName;
871     cs.lpszClass      = className;
872     cs.dwExStyle      = exStyle;
873     /* Note: we rely on the fact that CREATESTRUCT32A and */
874     /* CREATESTRUCT32W have the same layout. */
875     return WIN_CreateWindowEx( (CREATESTRUCT32A *)&cs, classAtom, TRUE );
876 }
877
878
879 /***********************************************************************
880  *           DestroyWindow   (USER.53)
881  */
882 BOOL DestroyWindow( HWND hwnd )
883 {
884     WND * wndPtr;
885
886     dprintf_win(stddeb, "DestroyWindow(%04x)\n", hwnd);
887     
888       /* Initialization */
889
890     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
891     if (wndPtr == pWndDesktop) return FALSE; /* Can't destroy desktop */
892
893       /* Top-level window */
894
895     if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner)
896     {
897         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, hwnd, 0L );
898         /* FIXME: clean up palette - see "Internals" p.352 */
899     }
900
901       /* Hide the window */
902
903     if (wndPtr->dwStyle & WS_VISIBLE)
904         SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOACTIVATE |
905                       SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE );
906     if ((hwnd == GetCapture()) || IsChild( hwnd, GetCapture() ))
907         ReleaseCapture();
908     if (!QUEUE_GetDoomedQueue())
909         WIN_SendParentNotify( hwnd, WM_DESTROY, wndPtr->wIDmenu, (LONG)hwnd );
910
911     CLIPBOARD_DisOwn( hwnd );
912
913       /* Recursively destroy owned windows */
914
915     for (;;)
916     {
917         WND *siblingPtr = wndPtr->parent->child;  /* First sibling */
918         while (siblingPtr)
919         {
920             if (siblingPtr->owner == wndPtr) break;
921             siblingPtr = siblingPtr->next;
922         }
923         if (siblingPtr) DestroyWindow( siblingPtr->hwndSelf );
924         else break;
925     }
926
927       /* Send destroy messages and destroy children */
928
929     SendMessage16( hwnd, WM_DESTROY, 0, 0 );
930     while (wndPtr->child)  /* The child removes itself from the list */
931         DestroyWindow( wndPtr->child->hwndSelf );
932     SendMessage16( hwnd, WM_NCDESTROY, 0, 0 );
933
934       /* Destroy the window */
935
936     WIN_DestroyWindow( hwnd );
937     return TRUE;
938 }
939
940
941 /***********************************************************************
942  *           CloseWindow   (USER.43)
943  */
944 BOOL CloseWindow(HWND hWnd)
945 {
946     WND * wndPtr = WIN_FindWndPtr(hWnd);
947     if (!wndPtr || (wndPtr->dwStyle & WS_CHILD)) return TRUE;
948     ShowWindow(hWnd, SW_MINIMIZE);
949     return TRUE;
950 }
951
952  
953 /***********************************************************************
954  *           OpenIcon   (USER.44)
955  */
956 BOOL OpenIcon(HWND hWnd)
957 {
958     if (!IsIconic(hWnd)) return FALSE;
959     ShowWindow(hWnd, SW_SHOWNORMAL);
960     return(TRUE);
961 }
962
963
964 /***********************************************************************
965  *           WIN_FindWindow
966  *
967  * Implementation of FindWindow() and FindWindowEx().
968  */
969 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className,
970                             LPCSTR title )
971 {
972     WND *pWnd;
973     CLASS *pClass = NULL;
974
975     if (child)
976     {
977         if (!(pWnd = WIN_FindWndPtr( child ))) return 0;
978         if (parent)
979         {
980             if (!pWnd->parent || (pWnd->parent->hwndSelf != parent)) return 0;
981         }
982         else if (pWnd->parent != pWndDesktop) return 0;
983         pWnd = pWnd->next;
984     }
985     else
986     {
987         if (!(pWnd = parent ? WIN_FindWndPtr(parent) : pWndDesktop)) return 0;
988         pWnd = pWnd->child;
989     }
990     if (!pWnd) return 0;
991
992     /* For a child window, all siblings will have the same hInstance, */
993     /* so we can look for the class once and for all. */
994
995     if (className && (pWnd->dwStyle & WS_CHILD))
996     {
997         if (!(pClass = CLASS_FindClassByAtom( className, pWnd->hInstance )))
998             return 0;
999     }
1000
1001     for ( ; pWnd; pWnd = pWnd->next)
1002     {
1003         if (className && !(pWnd->dwStyle & WS_CHILD))
1004         {
1005             if (!(pClass = CLASS_FindClassByAtom( className, pWnd->hInstance)))
1006                 continue;  /* Skip this window */
1007         }
1008         if (pClass && (pWnd->class != pClass))
1009             continue;  /* Not the right class */
1010
1011         /* Now check the title */
1012
1013         if (!title) return pWnd->hwndSelf;
1014         if (pWnd->text && !strcmp( pWnd->text, title )) return pWnd->hwndSelf;
1015     }
1016     return 0;
1017 }
1018
1019
1020
1021 /***********************************************************************
1022  *           FindWindow16   (USER.50)
1023  */
1024 HWND16 FindWindow16( SEGPTR className, LPCSTR title )
1025 {
1026     return FindWindowEx16( 0, 0, className, title );
1027 }
1028
1029
1030 /***********************************************************************
1031  *           FindWindowEx16   (USER.427)
1032  */
1033 HWND16 FindWindowEx16( HWND16 parent, HWND16 child,
1034                        SEGPTR className, LPCSTR title )
1035 {
1036     ATOM atom;
1037
1038     atom = className ? GlobalFindAtom16( className ) : 0;
1039     return WIN_FindWindow( parent, child, atom, title );
1040 }
1041
1042
1043 /***********************************************************************
1044  *           FindWindow32A   (USER32.197)
1045  */
1046 HWND32 FindWindow32A( LPCSTR className, LPCSTR title )
1047 {
1048     return FindWindowEx32A( 0, 0, className, title );
1049 }
1050
1051
1052 /***********************************************************************
1053  *           FindWindowEx32A   (USER32.198)
1054  */
1055 HWND32 FindWindowEx32A( HWND32 parent, HWND32 child,
1056                         LPCSTR className, LPCSTR title )
1057 {
1058     ATOM atom;
1059
1060     atom = className ? GlobalFindAtom32A( className ) : 0;
1061     return WIN_FindWindow( 0, 0, atom, title );
1062 }
1063
1064
1065 /***********************************************************************
1066  *           FindWindowEx32W   (USER32.199)
1067  */
1068 HWND32 FindWindowEx32W( HWND32 parent, HWND32 child,
1069                         LPCWSTR className, LPCWSTR title )
1070 {
1071     ATOM atom;
1072     char *buffer;
1073     HWND hwnd;
1074
1075     atom = className ? GlobalFindAtom32W( className ) : 0;
1076     buffer = title ? STRING32_DupUniToAnsi( title ) : NULL;
1077     hwnd = WIN_FindWindow( 0, 0, atom, buffer );
1078     if (buffer) free( buffer );
1079     return hwnd;
1080 }
1081
1082
1083 /***********************************************************************
1084  *           FindWindow32W   (USER32.200)
1085  */
1086 HWND32 FindWindow32W( LPCWSTR className, LPCWSTR title )
1087 {
1088     return FindWindowEx32W( 0, 0, className, title );
1089 }
1090
1091
1092 /**********************************************************************
1093  *           WIN_GetDesktop
1094  */
1095 WND *WIN_GetDesktop(void)
1096 {
1097     return pWndDesktop;
1098 }
1099
1100
1101 /**********************************************************************
1102  *           GetDesktopWindow   (USER.286)
1103  */
1104 HWND GetDesktopWindow(void)
1105 {
1106     return pWndDesktop->hwndSelf;
1107 }
1108
1109
1110 /**********************************************************************
1111  *           GetDesktopHwnd   (USER.278)
1112  *
1113  * Exactly the same thing as GetDesktopWindow(), but not documented.
1114  * Don't ask me why...
1115  */
1116 HWND GetDesktopHwnd(void)
1117 {
1118     return pWndDesktop->hwndSelf;
1119 }
1120
1121
1122 /*******************************************************************
1123  *           EnableWindow   (USER.34)
1124  */
1125 BOOL EnableWindow( HWND hwnd, BOOL enable )
1126 {
1127     WND *wndPtr;
1128
1129     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
1130     if (enable && (wndPtr->dwStyle & WS_DISABLED))
1131     {
1132           /* Enable window */
1133         wndPtr->dwStyle &= ~WS_DISABLED;
1134         SendMessage16( hwnd, WM_ENABLE, TRUE, 0 );
1135         return TRUE;
1136     }
1137     else if (!enable && !(wndPtr->dwStyle & WS_DISABLED))
1138     {
1139           /* Disable window */
1140         wndPtr->dwStyle |= WS_DISABLED;
1141         if ((hwnd == GetFocus()) || IsChild( hwnd, GetFocus() ))
1142             SetFocus( 0 );  /* A disabled window can't have the focus */
1143         if ((hwnd == GetCapture()) || IsChild( hwnd, GetCapture() ))
1144             ReleaseCapture();  /* A disabled window can't capture the mouse */
1145         SendMessage16( hwnd, WM_ENABLE, FALSE, 0 );
1146         return FALSE;
1147     }
1148     return ((wndPtr->dwStyle & WS_DISABLED) != 0);
1149 }
1150
1151
1152 /***********************************************************************
1153  *           IsWindowEnabled   (USER.35) (USER32.348)
1154  */ 
1155 BOOL IsWindowEnabled(HWND hWnd)
1156 {
1157     WND * wndPtr; 
1158
1159     if (!(wndPtr = WIN_FindWndPtr(hWnd))) return FALSE;
1160     return !(wndPtr->dwStyle & WS_DISABLED);
1161 }
1162
1163
1164 /***********************************************************************
1165  *           IsWindowUnicode   (USER32.349)
1166  */
1167 BOOL32 IsWindowUnicode( HWND32 hwnd )
1168 {
1169     WND * wndPtr; 
1170
1171     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1172     return (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1173 }
1174
1175
1176 /**********************************************************************
1177  *           GetWindowWord    (USER.133) (USER32.313)
1178  */
1179 WORD GetWindowWord( HWND32 hwnd, INT32 offset )
1180 {
1181     WND * wndPtr = WIN_FindWndPtr( hwnd );
1182     if (!wndPtr) return 0;
1183     if (offset >= 0)
1184     {
1185         if (offset + sizeof(WORD) > wndPtr->class->cbWndExtra)
1186         {
1187             fprintf( stderr, "SetWindowWord: invalid offset %d\n", offset );
1188             return 0;
1189         }
1190         return *(WORD *)(((char *)wndPtr->wExtra) + offset);
1191     }
1192     switch(offset)
1193     {
1194     case GWW_ID:         return wndPtr->wIDmenu;
1195     case GWW_HWNDPARENT: return wndPtr->parent ? wndPtr->parent->hwndSelf : 0;
1196     case GWW_HINSTANCE:  return (WORD)wndPtr->hInstance;
1197     default:
1198         fprintf( stderr, "GetWindowWord: invalid offset %d\n", offset );
1199         return 0;
1200     }
1201 }
1202
1203
1204 /**********************************************************************
1205  *           WIN_GetWindowInstance
1206  */
1207 HINSTANCE16 WIN_GetWindowInstance( HWND32 hwnd )
1208 {
1209     WND * wndPtr = WIN_FindWndPtr( hwnd );
1210     if (!wndPtr) return (HINSTANCE16)0;
1211     return wndPtr->hInstance;
1212 }
1213
1214
1215 /**********************************************************************
1216  *           SetWindowWord    (USER.134) (USER32.523)
1217  */
1218 WORD SetWindowWord( HWND32 hwnd, INT32 offset, WORD newval )
1219 {
1220     WORD *ptr, retval;
1221     WND * wndPtr = WIN_FindWndPtr( hwnd );
1222     if (!wndPtr) return 0;
1223     if (offset >= 0)
1224     {
1225         if (offset + sizeof(WORD) > wndPtr->class->cbWndExtra)
1226         {
1227             fprintf( stderr, "SetWindowWord: invalid offset %d\n", offset );
1228             return 0;
1229         }
1230         ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
1231     }
1232     else switch(offset)
1233     {
1234         case GWW_ID:        ptr = (WORD *)&wndPtr->wIDmenu; break;
1235         case GWW_HINSTANCE: ptr = (WORD *)&wndPtr->hInstance; break;
1236         default:
1237             fprintf( stderr, "SetWindowWord: invalid offset %d\n", offset );
1238             return 0;
1239     }
1240     retval = *ptr;
1241     *ptr = newval;
1242     return retval;
1243 }
1244
1245
1246 /**********************************************************************
1247  *           WIN_GetWindowLong
1248  *
1249  * Helper function for GetWindowLong().
1250  */
1251 static LONG WIN_GetWindowLong( HWND32 hwnd, INT32 offset, WINDOWPROCTYPE type )
1252 {
1253     LONG retval;
1254     WND * wndPtr = WIN_FindWndPtr( hwnd );
1255     if (!wndPtr) return 0;
1256     if (offset >= 0)
1257     {
1258         if (offset + sizeof(LONG) > wndPtr->class->cbWndExtra)
1259         {
1260             fprintf( stderr, "GetWindowLong: invalid offset %d\n", offset );
1261             return 0;
1262         }
1263         retval = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1264         /* Special case for dialog window procedure */
1265         if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1266             return (LONG)WINPROC_GetProc( (HWINDOWPROC)retval, type );
1267         return retval;
1268     }
1269     switch(offset)
1270     {
1271         case GWL_USERDATA:   return wndPtr->userdata;
1272         case GWL_STYLE:      return wndPtr->dwStyle;
1273         case GWL_EXSTYLE:    return wndPtr->dwExStyle;
1274         case GWL_ID:         return wndPtr->wIDmenu;
1275         case GWL_WNDPROC:    return (LONG)WINPROC_GetProc( wndPtr->winproc,
1276                                                            type );
1277         case GWL_HWNDPARENT: return wndPtr->parent ?
1278                                         (HWND32)wndPtr->parent->hwndSelf : 0;
1279         case GWL_HINSTANCE:  return (HINSTANCE32)wndPtr->hInstance;
1280         default:
1281             fprintf( stderr, "GetWindowLong: unknown offset %d\n", offset );
1282     }
1283     return 0;
1284 }
1285
1286
1287 /**********************************************************************
1288  *           WIN_SetWindowLong
1289  *
1290  * Helper function for SetWindowLong().
1291  */
1292 static LONG WIN_SetWindowLong( HWND32 hwnd, INT32 offset, LONG newval,
1293                                WINDOWPROCTYPE type )
1294 {
1295     LONG *ptr, retval;
1296     WND * wndPtr = WIN_FindWndPtr( hwnd );
1297     if (!wndPtr) return 0;
1298     if (offset >= 0)
1299     {
1300         if (offset + sizeof(LONG) > wndPtr->class->cbWndExtra)
1301         {
1302             fprintf( stderr, "SetWindowLong: invalid offset %d\n", offset );
1303             return 0;
1304         }
1305         ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
1306         /* Special case for dialog window procedure */
1307         if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1308         {
1309             retval = (LONG)WINPROC_GetProc( (HWINDOWPROC)*ptr, type );
1310             WINPROC_SetProc( (HWINDOWPROC *)ptr, (WNDPROC16)newval, type );
1311             return retval;
1312         }
1313     }
1314     else switch(offset)
1315     {
1316         case GWL_ID:
1317         case GWL_HINSTANCE:
1318             return SetWindowWord( hwnd, offset, (WORD)newval );
1319         case GWL_WNDPROC:
1320             retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
1321             WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval, type );
1322             return retval;
1323         case GWL_STYLE:
1324             ptr = &wndPtr->dwStyle;
1325             /* Some bits can't be changed this way */
1326             newval &= ~(WS_VISIBLE | WS_CHILD);
1327             newval |= (*ptr & (WS_VISIBLE | WS_CHILD));
1328             break;
1329         case GWL_USERDATA: ptr = &wndPtr->userdata; break;
1330         case GWL_EXSTYLE:  ptr = &wndPtr->dwExStyle; break;
1331         default:
1332             fprintf( stderr, "SetWindowLong: invalid offset %d\n", offset );
1333             return 0;
1334     }
1335     retval = *ptr;
1336     *ptr = newval;
1337     return retval;
1338 }
1339
1340
1341 /**********************************************************************
1342  *           GetWindowLong16    (USER.135)
1343  */
1344 LONG GetWindowLong16( HWND16 hwnd, INT16 offset )
1345 {
1346     return WIN_GetWindowLong( (HWND32)hwnd, offset, WIN_PROC_16 );
1347 }
1348
1349
1350 /**********************************************************************
1351  *           GetWindowLong32A    (USER32.304)
1352  */
1353 LONG GetWindowLong32A( HWND32 hwnd, INT32 offset )
1354 {
1355     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
1356 }
1357
1358
1359 /**********************************************************************
1360  *           GetWindowLong32W    (USER32.305)
1361  */
1362 LONG GetWindowLong32W( HWND32 hwnd, INT32 offset )
1363 {
1364     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
1365 }
1366
1367
1368 /**********************************************************************
1369  *           SetWindowLong16    (USER.136)
1370  */
1371 LONG SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
1372 {
1373     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_16 );
1374 }
1375
1376
1377 /**********************************************************************
1378  *           SetWindowLong32A    (USER32.516)
1379  */
1380 LONG SetWindowLong32A( HWND32 hwnd, INT32 offset, LONG newval )
1381 {
1382     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
1383 }
1384
1385
1386 /**********************************************************************
1387  *           SetWindowLong32W    (USER32.517)
1388  */
1389 LONG SetWindowLong32W( HWND32 hwnd, INT32 offset, LONG newval )
1390 {
1391     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
1392 }
1393
1394
1395 /*******************************************************************
1396  *           GetWindowText16    (USER.36)
1397  */
1398 INT16 GetWindowText16( HWND16 hwnd, SEGPTR lpString, INT16 nMaxCount )
1399 {
1400     return (INT16)SendMessage16(hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString);
1401 }
1402
1403
1404 /*******************************************************************
1405  *           GetWindowText32A    (USER32.308)
1406  */
1407 INT32 GetWindowText32A( HWND32 hwnd, LPSTR lpString, INT32 nMaxCount )
1408 {
1409     return (INT32)SendMessage32A( hwnd, WM_GETTEXT, nMaxCount,
1410                                   (LPARAM)lpString );
1411 }
1412
1413
1414 /*******************************************************************
1415  *           GetWindowText32W    (USER32.311)
1416  */
1417 INT32 GetWindowText32W( HWND32 hwnd, LPWSTR lpString, INT32 nMaxCount )
1418 {
1419     return (INT32)SendMessage32W( hwnd, WM_GETTEXT, nMaxCount,
1420                                   (LPARAM)lpString );
1421 }
1422
1423
1424 /*******************************************************************
1425  *           SetWindowText16    (USER.37)
1426  */
1427 void SetWindowText16( HWND16 hwnd, SEGPTR lpString )
1428 {
1429     SendMessage16( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
1430 }
1431
1432
1433 /*******************************************************************
1434  *           SetWindowText32A    (USER32.)
1435  */
1436 void SetWindowText32A( HWND32 hwnd, LPCSTR lpString )
1437 {
1438     SendMessage32A( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
1439 }
1440
1441
1442 /*******************************************************************
1443  *           SetWindowText32W    (USER32.)
1444  */
1445 void SetWindowText32W( HWND32 hwnd, LPCWSTR lpString )
1446 {
1447     SendMessage32W( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
1448 }
1449
1450
1451 /*******************************************************************
1452  *         GetWindowTextLength    (USER.38)
1453  */
1454 int GetWindowTextLength(HWND hwnd)
1455 {
1456     return (int)SendMessage16(hwnd, WM_GETTEXTLENGTH, 0, 0 );
1457 }
1458
1459
1460 /*******************************************************************
1461  *         IsWindow   (USER.47) (USER32.347)
1462  */
1463 BOOL16 IsWindow( HWND32 hwnd )
1464 {
1465     WND * wndPtr = WIN_FindWndPtr( hwnd );
1466     return ((wndPtr != NULL) && (wndPtr->dwMagic == WND_MAGIC));
1467 }
1468
1469
1470 /*****************************************************************
1471  *         GetParent              (USER.46)
1472  */
1473 HWND GetParent(HWND hwnd)
1474 {
1475     WND *wndPtr = WIN_FindWndPtr(hwnd);
1476     if (!wndPtr) return 0;
1477     wndPtr = (wndPtr->dwStyle & WS_CHILD) ? wndPtr->parent : wndPtr->owner;
1478     return wndPtr ? wndPtr->hwndSelf : 0;
1479 }
1480
1481
1482 /*****************************************************************
1483  *         WIN_GetTopParent
1484  *
1485  * Get the top-level parent for a child window.
1486  */
1487 HWND32 WIN_GetTopParent( HWND32 hwnd )
1488 {
1489     WND *wndPtr = WIN_FindWndPtr( hwnd );
1490     while (wndPtr && (wndPtr->dwStyle & WS_CHILD)) wndPtr = wndPtr->parent;
1491     return wndPtr ? wndPtr->hwndSelf : 0;
1492 }
1493
1494
1495 /*****************************************************************
1496  *         SetParent              (USER.233)
1497  */
1498 HWND SetParent(HWND hwndChild, HWND hwndNewParent)
1499 {
1500     HWND oldParent;
1501
1502     WND *wndPtr = WIN_FindWndPtr(hwndChild);
1503     WND *pWndParent = WIN_FindWndPtr( hwndNewParent );
1504     if (!wndPtr || !pWndParent || !(wndPtr->dwStyle & WS_CHILD)) return 0;
1505
1506     oldParent = wndPtr->parent->hwndSelf;
1507
1508     WIN_UnlinkWindow(hwndChild);
1509     if (hwndNewParent) wndPtr->parent = pWndParent;
1510     WIN_LinkWindow(hwndChild, HWND_BOTTOM);
1511     
1512     if (IsWindowVisible(hwndChild)) UpdateWindow(hwndChild);
1513     
1514     return oldParent;
1515 }
1516
1517
1518
1519 /*******************************************************************
1520  *         IsChild    (USER.48)
1521  */
1522 BOOL IsChild( HWND parent, HWND child )
1523 {
1524     WND * wndPtr = WIN_FindWndPtr( child );
1525     while (wndPtr && (wndPtr->dwStyle & WS_CHILD))
1526     {
1527         wndPtr = wndPtr->parent;
1528         if (wndPtr->hwndSelf == parent) return TRUE;
1529     }
1530     return FALSE;
1531 }
1532
1533
1534 /***********************************************************************
1535  *           IsWindowVisible   (USER.49) (USER32.350)
1536  */
1537 BOOL IsWindowVisible( HWND hwnd )
1538 {
1539     WND *wndPtr = WIN_FindWndPtr( hwnd );
1540     while (wndPtr && (wndPtr->dwStyle & WS_CHILD))
1541     {
1542         if (!(wndPtr->dwStyle & WS_VISIBLE)) return FALSE;
1543         wndPtr = wndPtr->parent;
1544     }
1545     return (wndPtr && (wndPtr->dwStyle & WS_VISIBLE));
1546 }
1547
1548  
1549  
1550 /*******************************************************************
1551  *         GetTopWindow    (USER.229)
1552  */
1553 HWND GetTopWindow( HWND hwnd )
1554 {
1555     WND * wndPtr = WIN_FindWndPtr( hwnd );
1556     if (wndPtr && wndPtr->child) return wndPtr->child->hwndSelf;
1557     else return 0;
1558 }
1559
1560
1561 /*******************************************************************
1562  *         GetWindow    (USER.262)
1563  */
1564 HWND GetWindow( HWND hwnd, WORD rel )
1565 {
1566     WND * wndPtr = WIN_FindWndPtr( hwnd );
1567     if (!wndPtr) return 0;
1568     switch(rel)
1569     {
1570     case GW_HWNDFIRST:
1571         if (wndPtr->parent) return wndPtr->parent->child->hwndSelf;
1572         else return 0;
1573         
1574     case GW_HWNDLAST:
1575         if (!wndPtr->parent) return 0;  /* Desktop window */
1576         while (wndPtr->next) wndPtr = wndPtr->next;
1577         return wndPtr->hwndSelf;
1578         
1579     case GW_HWNDNEXT:
1580         if (!wndPtr->next) return 0;
1581         return wndPtr->next->hwndSelf;
1582         
1583     case GW_HWNDPREV:
1584         if (!wndPtr->parent) return 0;  /* Desktop window */
1585         wndPtr = wndPtr->parent->child;  /* First sibling */
1586         if (wndPtr->hwndSelf == hwnd) return 0;  /* First in list */
1587         while (wndPtr->next)
1588         {
1589             if (wndPtr->next->hwndSelf == hwnd) return wndPtr->hwndSelf;
1590             wndPtr = wndPtr->next;
1591         }
1592         return 0;
1593         
1594     case GW_OWNER:
1595         return wndPtr->owner ? wndPtr->owner->hwndSelf : 0;
1596
1597     case GW_CHILD:
1598         return wndPtr->child ? wndPtr->child->hwndSelf : 0;
1599     }
1600     return 0;
1601 }
1602
1603
1604 /*******************************************************************
1605  *         GetNextWindow    (USER.230)
1606  */
1607 HWND GetNextWindow( HWND hwnd, WORD flag )
1608 {
1609     if ((flag != GW_HWNDNEXT) && (flag != GW_HWNDPREV)) return 0;
1610     return GetWindow( hwnd, flag );
1611 }
1612
1613 /*******************************************************************
1614  *         ShowOwnedPopups  (USER.265)
1615  */
1616 void ShowOwnedPopups( HWND owner, BOOL fShow )
1617 {
1618     WND *pWnd = pWndDesktop->child;
1619     while (pWnd)
1620     {
1621         if (pWnd->owner && (pWnd->owner->hwndSelf == owner) &&
1622             (pWnd->dwStyle & WS_POPUP))
1623             ShowWindow( pWnd->hwndSelf, fShow ? SW_SHOW : SW_HIDE );
1624         pWnd = pWnd->next;
1625     }
1626 }
1627
1628
1629 /*******************************************************************
1630  *         GetLastActivePopup    (USER.287)
1631  */
1632 HWND GetLastActivePopup(HWND hwnd)
1633 {
1634     WND *wndPtr;
1635     wndPtr = WIN_FindWndPtr(hwnd);
1636     if (wndPtr == NULL) return hwnd;
1637     return wndPtr->hwndLastActive;
1638 }
1639
1640
1641 /*******************************************************************
1642  *           WIN_BuildWinArray
1643  *
1644  * Build an array of pointers to all children of a given window.
1645  * The array must be freed with HeapFree(SystemHeap).
1646  */
1647 WND **WIN_BuildWinArray( WND *wndPtr )
1648 {
1649     WND **list, **ppWnd;
1650     WND *pWnd;
1651     INT32 count;
1652
1653     /* First count the windows */
1654
1655     if (!wndPtr) wndPtr = pWndDesktop;
1656     for (pWnd = wndPtr->child, count = 0; pWnd; pWnd = pWnd->next) count++;
1657     count++;  /* For the terminating NULL */
1658
1659     /* Now build the list of all windows */
1660
1661     if (!(list = (WND **)HeapAlloc( SystemHeap, 0, sizeof(WND *) * count )))
1662         return NULL;
1663     for (pWnd = wndPtr->child, ppWnd = list; pWnd; pWnd = pWnd->next)
1664         *ppWnd++ = pWnd;
1665     *ppWnd = NULL;
1666     return list;
1667 }
1668
1669
1670 /*******************************************************************
1671  *           EnumWindows16   (USER.54)
1672  */
1673 BOOL16 EnumWindows16( WNDENUMPROC16 lpEnumFunc, LPARAM lParam )
1674 {
1675     WND **list, **ppWnd;
1676
1677     /* We have to build a list of all windows first, to avoid */
1678     /* unpleasant side-effects, for instance if the callback  */
1679     /* function changes the Z-order of the windows.           */
1680
1681     if (!(list = WIN_BuildWinArray( pWndDesktop ))) return FALSE;
1682
1683     /* Now call the callback function for every window */
1684
1685     for (ppWnd = list; *ppWnd; ppWnd++)
1686     {
1687         /* Make sure that the window still exists */
1688         if (!IsWindow((*ppWnd)->hwndSelf)) continue;
1689         if (!lpEnumFunc( (*ppWnd)->hwndSelf, lParam )) break;
1690     }
1691     HeapFree( SystemHeap, 0, list );
1692     return TRUE;
1693 }
1694
1695
1696 /*******************************************************************
1697  *           EnumWindows32   (USER32.192)
1698  */
1699 BOOL32 EnumWindows32( WNDENUMPROC32 lpEnumFunc, LPARAM lParam )
1700 {
1701     return (BOOL32)EnumWindows16( (WNDENUMPROC16)lpEnumFunc, lParam );
1702 }
1703
1704
1705 /**********************************************************************
1706  *           EnumTaskWindows16   (USER.225)
1707  */
1708 BOOL16 EnumTaskWindows16( HTASK16 hTask, WNDENUMPROC16 func, LPARAM lParam )
1709 {
1710     WND **list, **ppWnd;
1711     HANDLE hQueue = GetTaskQueue( hTask );
1712
1713     /* This function is the same as EnumWindows(),    */
1714     /* except for an added check on the window queue. */
1715
1716     if (!(list = WIN_BuildWinArray( pWndDesktop ))) return FALSE;
1717
1718     /* Now call the callback function for every window */
1719
1720     for (ppWnd = list; *ppWnd; ppWnd++)
1721     {
1722         /* Make sure that the window still exists */
1723         if (!IsWindow((*ppWnd)->hwndSelf)) continue;
1724         if ((*ppWnd)->hmemTaskQ != hQueue) continue;  /* Check the queue */
1725         if (!func( (*ppWnd)->hwndSelf, lParam )) break;
1726     }
1727     HeapFree( SystemHeap, 0, list );
1728     return TRUE;
1729 }
1730
1731
1732 /**********************************************************************
1733  *           EnumThreadWindows   (USER32.189)
1734  */
1735 BOOL32 EnumThreadWindows( DWORD id, WNDENUMPROC32 func, LPARAM lParam )
1736 {
1737     return (BOOL16)EnumTaskWindows16((HTASK16)id, (WNDENUMPROC16)func, lParam);
1738 }
1739
1740
1741 /**********************************************************************
1742  *           WIN_EnumChildWindows
1743  *
1744  * Helper function for EnumChildWindows().
1745  */
1746 static BOOL16 WIN_EnumChildWindows( WND **ppWnd, WNDENUMPROC16 func,
1747                                     LPARAM lParam )
1748 {
1749     WND **childList;
1750     BOOL16 ret = FALSE;
1751
1752     while (*ppWnd)
1753     {
1754         /* Make sure that the window still exists */
1755         if (!IsWindow((*ppWnd)->hwndSelf)) continue;
1756         /* Build children list first */
1757         if (!(childList = WIN_BuildWinArray( *ppWnd ))) return FALSE;
1758         if (!func( (*ppWnd)->hwndSelf, lParam )) return FALSE;
1759         ret = WIN_EnumChildWindows( childList, func, lParam );
1760         HeapFree( SystemHeap, 0, childList );
1761         if (!ret) return FALSE;
1762         ppWnd++;
1763     }
1764     return TRUE;
1765 }
1766
1767
1768 /**********************************************************************
1769  *           EnumChildWindows16   (USER.55)
1770  */
1771 BOOL16 EnumChildWindows16( HWND16 parent, WNDENUMPROC16 func, LPARAM lParam )
1772 {
1773     WND **list, *pParent;
1774
1775     if (!(pParent = WIN_FindWndPtr( parent ))) return FALSE;
1776     if (!(list = WIN_BuildWinArray( pParent ))) return FALSE;
1777     WIN_EnumChildWindows( list, func, lParam );
1778     HeapFree( SystemHeap, 0, list );
1779     return TRUE;
1780 }
1781
1782
1783 /**********************************************************************
1784  *           EnumChildWindows32   (USER32.177)
1785  */
1786 BOOL32 EnumChildWindows32( HWND32 parent, WNDENUMPROC32 func, LPARAM lParam )
1787 {
1788     return (BOOL32)EnumChildWindows16( (HWND16)parent, (WNDENUMPROC16)func,
1789                                        lParam );
1790 }
1791
1792
1793 /*******************************************************************
1794  *           AnyPopup   (USER.52)
1795  */
1796 BOOL AnyPopup(void)
1797 {
1798     WND *wndPtr;
1799     for (wndPtr = pWndDesktop->child; wndPtr; wndPtr = wndPtr->next)
1800         if (wndPtr->owner && (wndPtr->dwStyle & WS_VISIBLE)) return TRUE;
1801     return FALSE;
1802 }
1803
1804 /*******************************************************************
1805  *                      FlashWindow             [USER.105]
1806  */
1807 BOOL FlashWindow(HWND hWnd, BOOL bInvert)
1808 {
1809     WND *wndPtr = WIN_FindWndPtr(hWnd);
1810
1811     dprintf_win(stddeb,"FlashWindow: %04x\n", hWnd);
1812
1813     if (!wndPtr) return FALSE;
1814
1815     if (wndPtr->dwStyle & WS_MINIMIZE)
1816     {
1817         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
1818         {
1819             HDC hDC = GetDC(hWnd);
1820             
1821             if (!SendMessage16( hWnd, WM_ERASEBKGND, (WPARAM)hDC, (LPARAM)0 ))
1822                 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
1823             
1824             ReleaseDC( hWnd, hDC );
1825             wndPtr->flags |= WIN_NCACTIVATED;
1826         }
1827         else
1828         {
1829             RedrawWindow32( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE |
1830                             RDW_UPDATENOW | RDW_FRAME );
1831             wndPtr->flags &= ~WIN_NCACTIVATED;
1832         }
1833         return TRUE;
1834     }
1835     else
1836     {
1837         WPARAM wparam;
1838         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
1839         else wparam = (hWnd == GetActiveWindow());
1840
1841         SendMessage16( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
1842         return wparam;
1843     }
1844 }
1845
1846
1847 /*******************************************************************
1848  *           SetSysModalWindow16   (USER.188)
1849  */
1850 HWND16 SetSysModalWindow16( HWND16 hWnd )
1851 {
1852     HWND hWndOldModal = hwndSysModal;
1853     hwndSysModal = hWnd;
1854     dprintf_win(stdnimp,"EMPTY STUB !! SetSysModalWindow(%04x) !\n", hWnd);
1855     return hWndOldModal;
1856 }
1857
1858
1859 /*******************************************************************
1860  *           GetSysModalWindow16   (USER.52)
1861  */
1862 HWND16 GetSysModalWindow16(void)
1863 {
1864     return hwndSysModal;
1865 }
1866
1867
1868 /*******************************************************************
1869  *                      DRAG_QueryUpdate
1870  *
1871  * recursively find a child that contains spDragInfo->pt point 
1872  * and send WM_QUERYDROPOBJECT
1873  */
1874 BOOL DRAG_QueryUpdate( HWND hQueryWnd, SEGPTR spDragInfo )
1875 {
1876  BOOL           wParam,bResult = 0;
1877  POINT16        pt;
1878  LPDRAGINFO     ptrDragInfo = (LPDRAGINFO) PTR_SEG_TO_LIN(spDragInfo);
1879  WND           *ptrQueryWnd = WIN_FindWndPtr(hQueryWnd),*ptrWnd;
1880  RECT16         tempRect;       /* this sucks */
1881
1882  if( !ptrQueryWnd || !ptrDragInfo ) return 0;
1883
1884  pt             = ptrDragInfo->pt;
1885
1886  GetWindowRect16(hQueryWnd,&tempRect); 
1887
1888  if( !PtInRect16(&tempRect,pt) ||
1889      (ptrQueryWnd->dwStyle & WS_DISABLED) )
1890         return 0;
1891
1892  if( !(ptrQueryWnd->dwStyle & WS_MINIMIZE) ) 
1893    {
1894      tempRect = ptrQueryWnd->rectClient;
1895      if(ptrQueryWnd->dwStyle & WS_CHILD)
1896         MapWindowPoints16(ptrQueryWnd->parent->hwndSelf,0,(LPPOINT16)&tempRect,2);
1897
1898      if( PtInRect16(&tempRect,pt) )
1899         {
1900          wParam = 0;
1901          
1902          for (ptrWnd = ptrQueryWnd->child; ptrWnd ;ptrWnd = ptrWnd->next)
1903              if( ptrWnd->dwStyle & WS_VISIBLE )
1904              {
1905                  GetWindowRect16(ptrWnd->hwndSelf,&tempRect);
1906
1907                  if( PtInRect16(&tempRect,pt) ) 
1908                      break;
1909              }
1910
1911          if(ptrWnd)
1912          {
1913             dprintf_msg(stddeb,"DragQueryUpdate: hwnd = %04x, %d %d - %d %d\n",
1914                         ptrWnd->hwndSelf, ptrWnd->rectWindow.left, ptrWnd->rectWindow.top,
1915                         ptrWnd->rectWindow.right, ptrWnd->rectWindow.bottom );
1916             if( !(ptrWnd->dwStyle & WS_DISABLED) )
1917                 bResult = DRAG_QueryUpdate(ptrWnd->hwndSelf, spDragInfo);
1918          }
1919
1920          if(bResult) return bResult;
1921         }
1922      else wParam = 1;
1923    }
1924  else wParam = 1;
1925
1926  ScreenToClient16(hQueryWnd,&ptrDragInfo->pt);
1927
1928  ptrDragInfo->hScope = hQueryWnd;
1929
1930  bResult = SendMessage16( hQueryWnd ,WM_QUERYDROPOBJECT ,
1931                        (WPARAM)wParam ,(LPARAM) spDragInfo );
1932  if( !bResult ) 
1933       ptrDragInfo->pt = pt;
1934
1935  return bResult;
1936 }
1937
1938 /*******************************************************************
1939  *                      DragDetect ( USER.465 )
1940  *
1941  */
1942 BOOL16 DragDetect(HWND16 hWnd, POINT16 pt)
1943 {
1944   MSG16 msg;
1945   RECT16  rect;
1946
1947   rect.left = pt.x - wDragWidth;
1948   rect.right = pt.x + wDragWidth;
1949
1950   rect.top = pt.y - wDragHeight;
1951   rect.bottom = pt.y + wDragHeight;
1952
1953   SetCapture(hWnd);
1954
1955   while(1)
1956    {
1957         while(PeekMessage16(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
1958          {
1959            if( msg.message == WM_LBUTTONUP )
1960                 {
1961                   ReleaseCapture();
1962                   return 0;
1963                 }
1964            if( msg.message == WM_MOUSEMOVE )
1965                 {
1966                   if( !PtInRect16( &rect, MAKEPOINT16(msg.lParam) ) )
1967                     {
1968                       ReleaseCapture();
1969                       return 1;
1970                     }
1971                 }
1972          }
1973         WaitMessage();
1974    }
1975
1976   return 0;
1977 }
1978
1979 /******************************************************************************
1980  *                              DragObject ( USER.464 )
1981  *
1982  */
1983 DWORD DragObject(HWND hwndScope, HWND hWnd, WORD wObj, HANDLE hOfStruct,
1984                 WORD szList , HCURSOR hCursor)
1985 {
1986  MSG16          msg;
1987  LPDRAGINFO     lpDragInfo;
1988  SEGPTR         spDragInfo;
1989  HCURSOR        hDragCursor=0, hOldCursor=0, hBummer=0;
1990  HANDLE         hDragInfo  = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO));
1991  WND           *wndPtr = WIN_FindWndPtr(hWnd);
1992  DWORD          dwRet = 0;
1993  short          dragDone = 0;
1994  HCURSOR        hCurrentCursor = 0;
1995  HWND           hCurrentWnd = 0;
1996  WORD           btemp;
1997
1998  lpDragInfo = (LPDRAGINFO) GlobalLock16(hDragInfo);
1999  spDragInfo = (SEGPTR) WIN16_GlobalLock16(hDragInfo);
2000
2001  if( !lpDragInfo || !spDragInfo ) return 0L;
2002
2003  hBummer = LoadCursor16(0,IDC_BUMMER);
2004
2005  if( !hBummer || !wndPtr )
2006    {
2007         GlobalFree16(hDragInfo);
2008         return 0L;
2009    }
2010
2011  if(hCursor)
2012    {
2013         if( !(hDragCursor = CURSORICON_IconToCursor(hCursor)) )
2014           {
2015            GlobalFree16(hDragInfo);
2016            return 0L;
2017           }
2018
2019         if( hDragCursor == hCursor ) hDragCursor = 0;
2020         else hCursor = hDragCursor;
2021
2022         hOldCursor = SetCursor(hDragCursor);
2023    }
2024
2025  lpDragInfo->hWnd   = hWnd;
2026  lpDragInfo->hScope = 0;
2027  lpDragInfo->wFlags = wObj;
2028  lpDragInfo->hList  = szList; /* near pointer! */
2029  lpDragInfo->hOfStruct = hOfStruct;
2030  lpDragInfo->l = 0L; 
2031
2032  SetCapture(hWnd);
2033  ShowCursor(1);
2034
2035  while( !dragDone )
2036   {
2037     WaitMessage();
2038
2039     if( !PeekMessage16(&msg,0,WM_MOUSEFIRST,WM_MOUSELAST,PM_REMOVE) )
2040          continue;
2041
2042    *(lpDragInfo+1) = *lpDragInfo;
2043
2044     lpDragInfo->pt = msg.pt;
2045
2046     /* update DRAGINFO struct */
2047     dprintf_msg(stddeb,"drag: lpDI->hScope = %04x\n",lpDragInfo->hScope);
2048
2049     if( (btemp = (WORD)DRAG_QueryUpdate(hwndScope, spDragInfo)) > 0 )
2050          hCurrentCursor = hCursor;
2051     else
2052         {
2053          hCurrentCursor = hBummer;
2054          lpDragInfo->hScope = 0;
2055         }
2056     if( hCurrentCursor )
2057         SetCursor(hCurrentCursor);
2058
2059     dprintf_msg(stddeb,"drag: got %04x\n",btemp);
2060
2061     /* send WM_DRAGLOOP */
2062     SendMessage16( hWnd, WM_DRAGLOOP, (WPARAM)(hCurrentCursor != hBummer) , 
2063                                     (LPARAM) spDragInfo );
2064     /* send WM_DRAGSELECT or WM_DRAGMOVE */
2065     if( hCurrentWnd != lpDragInfo->hScope )
2066         {
2067          if( hCurrentWnd )
2068            SendMessage16( hCurrentWnd, WM_DRAGSELECT, 0, 
2069                        (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO),
2070                                         HIWORD(spDragInfo)) );
2071          hCurrentWnd = lpDragInfo->hScope;
2072          if( hCurrentWnd )
2073            SendMessage16( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo); 
2074         }
2075     else
2076         if( hCurrentWnd )
2077            SendMessage16( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
2078
2079
2080     /* check if we're done */
2081     if( msg.message == WM_LBUTTONUP || msg.message == WM_NCLBUTTONUP )
2082         dragDone = TRUE;
2083   }
2084
2085  ReleaseCapture();
2086  ShowCursor(0);
2087
2088  if( hCursor )
2089    {
2090      SetCursor(hOldCursor);
2091      if( hDragCursor )
2092          DestroyCursor(hDragCursor);
2093    }
2094
2095  if( hCurrentCursor != hBummer ) 
2096         dwRet = SendMessage16( lpDragInfo->hScope, WM_DROPOBJECT, 
2097                              (WPARAM)hWnd, (LPARAM)spDragInfo );
2098  GlobalFree16(hDragInfo);
2099
2100  return dwRet;
2101 }
2102