Release 951003
[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 "menu.h"
17 #include "cursoricon.h"
18 #include "event.h"
19 #include "message.h"
20 #include "nonclient.h"
21 #include "winpos.h"
22 #include "color.h"
23 #include "shm_main_blk.h"
24 #include "dde_proc.h"
25 #include "callback.h"
26 #include "stddebug.h"
27 /* #define DEBUG_WIN  */ 
28 /* #define DEBUG_MENU */
29 #include "debug.h"
30
31 static HWND hwndDesktop = 0;
32 static HWND hWndSysModal = 0;
33
34 /***********************************************************************
35  *           WIN_FindWndPtr
36  *
37  * Return a pointer to the WND structure corresponding to a HWND.
38  */
39 WND * WIN_FindWndPtr( HWND hwnd )
40 {
41     WND * ptr;
42     
43     if (!hwnd) return NULL;
44     ptr = (WND *) USER_HEAP_LIN_ADDR( hwnd );
45     if (ptr->dwMagic != WND_MAGIC) return NULL;
46     return ptr;
47 }
48
49
50 /***********************************************************************
51  *           WIN_GetXWindow
52  *
53  * Return the X window associated to a window.
54  */
55 Window WIN_GetXWindow( HWND hwnd )
56 {
57     WND *wndPtr = WIN_FindWndPtr( hwnd );
58     while (wndPtr && !wndPtr->window)
59     {
60         wndPtr = WIN_FindWndPtr( wndPtr->hwndParent );
61     }
62     return wndPtr ? wndPtr->window : 0;
63 }
64
65
66 /***********************************************************************
67  *           WIN_UnlinkWindow
68  *
69  * Remove a window from the siblings linked list.
70  */
71 BOOL WIN_UnlinkWindow( HWND hwnd )
72 {    
73     HWND * curWndPtr;
74     WND *parentPtr, *wndPtr;
75
76     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
77     if (!(parentPtr = WIN_FindWndPtr( wndPtr->hwndParent ))) return FALSE;
78
79     curWndPtr = &parentPtr->hwndChild;
80
81     while (*curWndPtr != hwnd)
82     {
83         WND * curPtr = WIN_FindWndPtr( *curWndPtr );
84         curWndPtr = &curPtr->hwndNext;
85     }
86     *curWndPtr = wndPtr->hwndNext;
87     return TRUE;
88 }
89
90
91 /***********************************************************************
92  *           WIN_LinkWindow
93  *
94  * Insert a window into the siblings linked list.
95  * The window is inserted after the specified window, which can also
96  * be specified as HWND_TOP or HWND_BOTTOM.
97  */
98 BOOL WIN_LinkWindow( HWND hwnd, HWND hwndInsertAfter )
99 {    
100     HWND * hwndPtr = NULL;  /* pointer to hwnd to change */
101     WND *wndPtr, *parentPtr;
102
103     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
104     if (!(parentPtr = WIN_FindWndPtr( wndPtr->hwndParent ))) return FALSE;
105
106     if ((hwndInsertAfter == HWND_TOP) || (hwndInsertAfter == HWND_BOTTOM))
107     {
108         hwndPtr = &parentPtr->hwndChild;  /* Point to first sibling hwnd */
109         if (hwndInsertAfter == HWND_BOTTOM)  /* Find last sibling hwnd */
110             while (*hwndPtr)
111             {
112                 WND * nextPtr = WIN_FindWndPtr( *hwndPtr );
113                 hwndPtr = &nextPtr->hwndNext;
114             }
115     }
116     else  /* Normal case */
117     {
118         WND * afterPtr = WIN_FindWndPtr( hwndInsertAfter );
119         if (afterPtr) hwndPtr = &afterPtr->hwndNext;
120     }
121     if (!hwndPtr) return FALSE;
122     wndPtr->hwndNext = *hwndPtr;
123     *hwndPtr = hwnd;
124     return TRUE;
125 }
126
127
128 /***********************************************************************
129  *           WIN_FindWinToRepaint
130  *
131  * Find a window that needs repaint.
132  */
133 HWND WIN_FindWinToRepaint( HWND hwnd )
134 {
135     WND * wndPtr;
136
137       /* Note: the desktop window never gets WM_PAINT messages */
138     if (!hwnd) hwnd = GetTopWindow( hwndDesktop );
139     for ( ; hwnd != 0; hwnd = wndPtr->hwndNext )
140     {
141         if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
142         dprintf_win( stddeb, "WIN_FindWinToRepaint: "NPFMT", style %08lx\n",
143                      hwnd, wndPtr->dwStyle );
144         if (!(wndPtr->dwStyle & WS_VISIBLE) || (wndPtr->flags & WIN_NO_REDRAW))
145             continue;
146         if ((wndPtr->dwStyle & WS_MINIMIZE) && (WIN_CLASS_INFO(wndPtr).hIcon))
147             continue;
148         if (wndPtr->hrgnUpdate || (wndPtr->flags & WIN_INTERNAL_PAINT))
149             return hwnd;
150         if (wndPtr->hwndChild)
151         {
152             HWND child;
153             if ((child = WIN_FindWinToRepaint( wndPtr->hwndChild )))
154                 return child;
155         }
156     }
157     return 0;
158 }
159
160
161 /***********************************************************************
162  *           WIN_SendParentNotify
163  *
164  * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
165  * the window has the WS_EX_NOPARENTNOTIFY style.
166  */
167 void WIN_SendParentNotify( HWND hwnd, WORD event, WORD idChild, LONG lValue )
168 {
169     WND *wndPtr = WIN_FindWndPtr( hwnd );
170     
171     while (wndPtr && (wndPtr->dwStyle & WS_CHILD))
172     {
173         if (wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY) break;
174 #ifdef WINELIB32
175         SendMessage( wndPtr->hwndParent, WM_PARENTNOTIFY, 
176                      MAKEWPARAM(event,idChild),
177                      (LPARAM)lValue );
178 #else
179         SendMessage( wndPtr->hwndParent, WM_PARENTNOTIFY, event,
180                      MAKELPARAM(LOWORD(lValue), idChild) );
181 #endif
182         wndPtr = WIN_FindWndPtr( wndPtr->hwndParent );
183     }
184 }
185
186
187 /***********************************************************************
188  *           WIN_DestroyWindow
189  *
190  * Destroy storage associated to a window
191  */
192 static void WIN_DestroyWindow( HWND hwnd )
193 {
194     WND *wndPtr = WIN_FindWndPtr( hwnd );
195     CLASS *classPtr = CLASS_FindClassPtr( wndPtr->hClass );
196
197 #ifdef CONFIG_IPC
198     if (main_block)
199         DDE_DestroyWindow(hwnd);
200 #endif  /* CONFIG_IPC */
201         
202     if (!wndPtr || !classPtr) return;
203     WIN_UnlinkWindow( hwnd ); /* Remove the window from the linked list */
204     wndPtr->dwMagic = 0;  /* Mark it as invalid */
205     if ((wndPtr->hrgnUpdate) || (wndPtr->flags & WIN_INTERNAL_PAINT))
206     {
207         if (wndPtr->hrgnUpdate) DeleteObject( wndPtr->hrgnUpdate );
208         MSG_DecPaintCount( wndPtr->hmemTaskQ );
209     }
210     if (!(wndPtr->dwStyle & WS_CHILD))
211     {
212         if (wndPtr->wIDmenu) DestroyMenu( wndPtr->wIDmenu );
213     }
214     if (wndPtr->hSysMenu) DestroyMenu( wndPtr->hSysMenu );
215     if (wndPtr->window) XDestroyWindow( display, wndPtr->window );
216     if (classPtr->wc.style & CS_OWNDC) DCE_FreeDCE( wndPtr->hdce );
217     classPtr->cWindows--;
218     USER_HEAP_FREE( hwnd );
219 }
220
221
222 /***********************************************************************
223  *           WIN_CreateDesktopWindow
224  *
225  * Create the desktop window.
226  */
227 BOOL WIN_CreateDesktopWindow(void)
228 {
229     WND *wndPtr;
230     HCLASS hclass;
231     CLASS *classPtr;
232     HDC hdc;
233
234     if (!(hclass = CLASS_FindClassByName( DESKTOP_CLASS_ATOM, 0, &classPtr )))
235         return FALSE;
236
237     hwndDesktop = USER_HEAP_ALLOC( sizeof(WND)+classPtr->wc.cbWndExtra );
238     if (!hwndDesktop) return FALSE;
239     wndPtr = (WND *) USER_HEAP_LIN_ADDR( hwndDesktop );
240
241     wndPtr->hwndNext          = 0;
242     wndPtr->hwndChild         = 0;
243     wndPtr->dwMagic           = WND_MAGIC;
244     wndPtr->hwndParent        = 0;
245     wndPtr->hwndOwner         = 0;
246     wndPtr->hClass            = hclass;
247     wndPtr->hInstance         = 0;
248     wndPtr->rectWindow.left   = 0;
249     wndPtr->rectWindow.top    = 0;
250     wndPtr->rectWindow.right  = SYSMETRICS_CXSCREEN;
251     wndPtr->rectWindow.bottom = SYSMETRICS_CYSCREEN;
252     wndPtr->rectClient        = wndPtr->rectWindow;
253     wndPtr->rectNormal        = wndPtr->rectWindow;
254     wndPtr->ptIconPos.x       = -1;
255     wndPtr->ptIconPos.y       = -1;
256     wndPtr->ptMaxPos.x        = -1;
257     wndPtr->ptMaxPos.y        = -1;
258     wndPtr->hmemTaskQ         = 0;  /* Desktop does not belong to a task */
259     wndPtr->hrgnUpdate        = 0;
260     wndPtr->hwndLastActive    = hwndDesktop;
261     wndPtr->lpfnWndProc       = classPtr->wc.lpfnWndProc;
262     wndPtr->dwStyle           = WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
263     wndPtr->dwExStyle         = 0;
264     wndPtr->hdce              = 0;
265     wndPtr->hVScroll          = 0;
266     wndPtr->hHScroll          = 0;
267     wndPtr->wIDmenu           = 0;
268     wndPtr->hText             = 0;
269     wndPtr->flags             = 0;
270     wndPtr->window            = rootWindow;
271     wndPtr->hSysMenu          = 0;
272     wndPtr->hProp             = 0;
273     EVENT_RegisterWindow( wndPtr->window, hwndDesktop );
274     SendMessage( hwndDesktop, WM_NCCREATE, 0, 0 );
275     if ((hdc = GetDC( hwndDesktop )) != 0)
276     {
277         SendMessage( hwndDesktop, WM_ERASEBKGND, (WPARAM)hdc, 0 );
278         ReleaseDC( hwndDesktop, hdc );
279     }
280     return TRUE;
281 }
282
283
284 /***********************************************************************
285  *           CreateWindow   (USER.41)
286  */
287 HWND CreateWindow( SEGPTR className, SEGPTR windowName,
288                    DWORD style, short x, short y, short width, short height,
289                    HWND parent, HMENU menu, HANDLE instance, SEGPTR data ) 
290 {
291     return CreateWindowEx( 0, className, windowName, style,
292                            x, y, width, height, parent, menu, instance, data );
293 }
294
295
296 /***********************************************************************
297  *           CreateWindowEx   (USER.452)
298  */
299 HWND CreateWindowEx( DWORD exStyle, SEGPTR className, SEGPTR windowName,
300                      DWORD style, short x, short y, short width, short height,
301                      HWND parent, HMENU menu, HANDLE instance, SEGPTR data ) 
302 {
303     HANDLE class, hwnd;
304     CLASS *classPtr;
305     WND *wndPtr;
306     POINT maxSize, maxPos, minTrack, maxTrack;
307     CREATESTRUCT createStruct;
308     int wmcreate;
309     XSetWindowAttributes win_attr;
310
311     /* FIXME: windowName and className should be SEGPTRs */
312
313     dprintf_win( stddeb, "CreateWindowEx: " );
314     if (HIWORD(windowName))
315         dprintf_win( stddeb, "'%s' ", (char *)PTR_SEG_TO_LIN(windowName) );
316     else
317         dprintf_win( stddeb, "%04x ", LOWORD(windowName) );
318     if (HIWORD(className))
319         dprintf_win( stddeb, "'%s' ", (char *)PTR_SEG_TO_LIN(className) );
320     else
321         dprintf_win( stddeb, "%04x ", LOWORD(className) );
322
323     dprintf_win(stddeb, "%08lx %08lx %d,%d %dx%d "NPFMT" "NPFMT" "NPFMT" %08lx\n",
324                 exStyle, style, x, y, width, height,
325                 parent, menu, instance, (DWORD)data);
326
327     if (x == CW_USEDEFAULT) x = y = 0;
328     if (width == CW_USEDEFAULT)
329     {
330         width = 600;
331         height = 400;
332     }
333
334       /* Find the parent and class */
335
336     if (parent)
337     {
338         /* Make sure parent is valid */
339         if (!IsWindow( parent )) {
340             dprintf_win(stddeb,"CreateWindowEx: Parent "NPFMT" is not a window\n", parent);
341             return 0;
342         }
343     }
344     else 
345     {
346         if (style & WS_CHILD) {
347             dprintf_win(stddeb,"CreateWindowEx: no parent\n");
348             return 0;  /* WS_CHILD needs a parent */
349         }
350     }
351
352     if (!(class = CLASS_FindClassByName( className, GetExePtr(instance),
353                                          &classPtr )))
354     {
355         fprintf(stderr,"CreateWindow BAD CLASSNAME " );
356         if (HIWORD(className)) fprintf( stderr, "'%s'\n", 
357                                         (char *)PTR_SEG_TO_LIN(className) );
358         else fprintf( stderr, "%04x\n", LOWORD(className) );
359         return 0;
360     }
361
362       /* Correct the window style */
363
364     if (!(style & (WS_POPUP | WS_CHILD)))  /* Overlapped window */
365         style |= WS_CAPTION | WS_CLIPSIBLINGS;
366     if (exStyle & WS_EX_DLGMODALFRAME) style &= ~WS_THICKFRAME;
367
368       /* Create the window structure */
369
370     hwnd = USER_HEAP_ALLOC( sizeof(WND)+classPtr->wc.cbWndExtra );
371     if (!hwnd) {
372         dprintf_win(stddeb,"CreateWindowEx: Out of memory\n");
373         return 0;
374     }
375
376       /* Fill the structure */
377
378     wndPtr = (WND *) USER_HEAP_LIN_ADDR( hwnd );
379     wndPtr->hwndNext       = 0;
380     wndPtr->hwndChild      = 0;
381     wndPtr->window         = 0;
382     wndPtr->dwMagic        = WND_MAGIC;
383     wndPtr->hwndParent     = (style & WS_CHILD) ? parent : hwndDesktop;
384     wndPtr->hwndOwner      = (style & WS_CHILD) ? 0 : WIN_GetTopParent(parent);
385     wndPtr->hClass         = class;
386     wndPtr->hInstance      = instance;
387     wndPtr->ptIconPos.x    = -1;
388     wndPtr->ptIconPos.y    = -1;
389     wndPtr->ptMaxPos.x     = -1;
390     wndPtr->ptMaxPos.y     = -1;
391     wndPtr->hmemTaskQ      = GetTaskQueue(0);
392     wndPtr->hrgnUpdate     = 0;
393     wndPtr->hwndPrevActive = 0;
394     wndPtr->hwndLastActive = hwnd;
395     wndPtr->lpfnWndProc    = classPtr->wc.lpfnWndProc;
396     wndPtr->dwStyle        = style & ~WS_VISIBLE;
397     wndPtr->dwExStyle      = exStyle;
398     wndPtr->wIDmenu        = 0;
399     wndPtr->hText          = 0;
400     wndPtr->flags          = 0;
401     wndPtr->hVScroll       = 0;
402     wndPtr->hHScroll       = 0;
403     wndPtr->hSysMenu       = 0;
404     wndPtr->hProp          = 0;
405
406     if (classPtr->wc.cbWndExtra)
407         memset( wndPtr->wExtra, 0, classPtr->wc.cbWndExtra );
408     classPtr->cWindows++;
409
410       /* Get class or window DC if needed */
411
412     if (classPtr->wc.style & CS_OWNDC)
413         wndPtr->hdce = DCE_AllocDCE( DCE_WINDOW_DC );
414     else if (classPtr->wc.style & CS_CLASSDC)
415         wndPtr->hdce = classPtr->hdce;
416     else
417         wndPtr->hdce = 0;
418
419       /* Insert the window in the linked list */
420
421     WIN_LinkWindow( hwnd, HWND_TOP );
422
423       /* Send the WM_GETMINMAXINFO message and fix the size if needed */
424
425     NC_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack );
426
427     if (maxSize.x < width) width = maxSize.x;
428     if (maxSize.y < height) height = maxSize.y;
429     if (width <= 0) width = 1;
430     if (height <= 0) height = 1;
431
432     wndPtr->rectWindow.left   = x;
433     wndPtr->rectWindow.top    = y;
434     wndPtr->rectWindow.right  = x + width;
435     wndPtr->rectWindow.bottom = y + height;
436     wndPtr->rectClient        = wndPtr->rectWindow;
437     wndPtr->rectNormal        = wndPtr->rectWindow;
438
439       /* Create the X window (only for top-level windows, and then only */
440       /* when there's no desktop window) */
441
442     if (!(style & WS_CHILD) && (rootWindow == DefaultRootWindow(display)))
443     {
444         win_attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask |
445                               PointerMotionMask | ButtonPressMask |
446                               ButtonReleaseMask | FocusChangeMask;
447         win_attr.override_redirect = TRUE;
448         win_attr.colormap      = COLOR_WinColormap;
449         win_attr.backing_store = Options.backingstore ? WhenMapped : NotUseful;
450         win_attr.save_under    = ((classPtr->wc.style & CS_SAVEBITS) != 0);
451         win_attr.cursor        = CURSORICON_XCursor;
452         wndPtr->window = XCreateWindow( display, rootWindow, x, y,
453                                         width, height, 0, CopyFromParent,
454                                         InputOutput, CopyFromParent,
455                                         CWEventMask | CWOverrideRedirect |
456                                         CWColormap | CWCursor | CWSaveUnder |
457                                         CWBackingStore, &win_attr );
458         XStoreName( display, wndPtr->window, PTR_SEG_TO_LIN(windowName) );
459         EVENT_RegisterWindow( wndPtr->window, hwnd );
460     }
461     
462     if ((style & WS_CAPTION) && !(style & WS_CHILD))
463     {
464         if (menu) SetMenu(hwnd, menu);
465         else if (classPtr->wc.lpszMenuName)
466             SetMenu( hwnd, LoadMenu( instance, classPtr->wc.lpszMenuName ) );
467     }
468     else wndPtr->wIDmenu = menu;
469
470       /* Send the WM_CREATE message */
471
472     createStruct.lpCreateParams = (LPSTR)data;
473     createStruct.hInstance      = instance;
474     createStruct.hMenu          = menu;
475     createStruct.hwndParent     = parent;
476     createStruct.cx             = width;
477     createStruct.cy             = height;
478     createStruct.x              = x;
479     createStruct.y              = y;
480     createStruct.style          = style;
481     createStruct.lpszName       = windowName;
482     createStruct.lpszClass      = className;
483     createStruct.dwExStyle      = 0;
484
485     wmcreate = SendMessage( hwnd, WM_NCCREATE, 0, MAKE_SEGPTR(&createStruct) );
486     if (!wmcreate)
487     {
488         dprintf_win(stddeb,"CreateWindowEx: WM_NCCREATE return 0\n");
489         wmcreate = -1;
490     }
491     else
492     {
493         WINPOS_SendNCCalcSize( hwnd, FALSE, &wndPtr->rectWindow,
494                                NULL, NULL, NULL, &wndPtr->rectClient );
495         wmcreate = SendMessage(hwnd, WM_CREATE, 0, MAKE_SEGPTR(&createStruct));
496     }
497
498     if (wmcreate == -1)
499     {
500           /* Abort window creation */
501         dprintf_win(stddeb,"CreateWindowEx: wmcreate==-1, aborting\n");
502         WIN_DestroyWindow( hwnd );
503         return 0;
504     }
505
506       /* Create a copy of SysMenu */
507     if (style & WS_SYSMENU) wndPtr->hSysMenu = CopySysMenu();
508
509     WIN_SendParentNotify( hwnd, WM_CREATE, wndPtr->wIDmenu, (LONG)hwnd );
510
511     /* Show the window, maximizing or minimizing if needed */
512
513     if (wndPtr->dwStyle & WS_MINIMIZE)
514     {
515         wndPtr->dwStyle &= ~WS_MAXIMIZE;
516         WINPOS_FindIconPos( hwnd );
517         SetWindowPos( hwnd, 0, wndPtr->ptIconPos.x, wndPtr->ptIconPos.y,
518                       SYSMETRICS_CXICON, SYSMETRICS_CYICON,
519                       SWP_FRAMECHANGED |
520                       (style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0 );
521     }
522     else if (wndPtr->dwStyle & WS_MAXIMIZE)
523     {
524         SetWindowPos( hwnd, 0, maxPos.x, maxPos.y, maxSize.x, maxSize.y,
525                       SWP_FRAMECHANGED |
526                       (style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0 );
527     }
528     else if (style & WS_VISIBLE) ShowWindow( hwnd, SW_SHOW );
529
530     dprintf_win(stddeb, "CreateWindowEx: return "NPFMT" \n", hwnd);
531     return hwnd;
532 }
533
534
535 /***********************************************************************
536  *           DestroyWindow   (USER.53)
537  */
538 BOOL DestroyWindow( HWND hwnd )
539 {
540     WND * wndPtr;
541     CLASS * classPtr;
542
543     dprintf_win(stddeb, "DestroyWindow ("NPFMT")\n", hwnd);
544     
545       /* Initialisation */
546
547     if (hwnd == hwndDesktop) return FALSE;  /* Can't destroy desktop */
548     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
549     if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) return FALSE;
550
551       /* Hide the window */
552
553     if (wndPtr->dwStyle & WS_VISIBLE)
554         SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOACTIVATE |
555                       SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE );
556     if ((hwnd == GetCapture()) || IsChild( hwnd, GetCapture() ))
557         ReleaseCapture();
558     WIN_SendParentNotify( hwnd, WM_DESTROY, wndPtr->wIDmenu, (LONG)hwnd );
559
560       /* Recursively destroy owned windows */
561
562     for (;;)
563     {
564         HWND hwndSibling = GetWindow( hwnd, GW_HWNDFIRST );
565         while (hwndSibling)
566         {
567             WND *siblingPtr = WIN_FindWndPtr( hwndSibling );
568             if (siblingPtr->hwndOwner == hwnd) break;
569             hwndSibling = siblingPtr->hwndNext;
570         }
571         if (hwndSibling) DestroyWindow( hwndSibling );
572         else break;
573     }
574
575       /* Send destroy messages and destroy children */
576
577     SendMessage( hwnd, WM_DESTROY, 0, 0 );
578     while (wndPtr->hwndChild)  /* The child removes itself from the list */
579         DestroyWindow( wndPtr->hwndChild );
580     SendMessage( hwnd, WM_NCDESTROY, 0, 0 );
581
582       /* Destroy the window */
583
584     WIN_DestroyWindow( hwnd );
585     return TRUE;
586 }
587
588
589 /***********************************************************************
590  *           CloseWindow   (USER.43)
591  */
592 void CloseWindow(HWND hWnd)
593 {
594     WND * wndPtr = WIN_FindWndPtr(hWnd);
595     if (wndPtr->dwStyle & WS_CHILD) return;
596     ShowWindow(hWnd, SW_MINIMIZE);
597 }
598
599  
600 /***********************************************************************
601  *           OpenIcon   (USER.44)
602  */
603 BOOL OpenIcon(HWND hWnd)
604 {
605     if (!IsIconic(hWnd)) return FALSE;
606     ShowWindow(hWnd, SW_SHOWNORMAL);
607     return(TRUE);
608 }
609
610  
611 /***********************************************************************
612  *           FindWindow   (USER.50)
613  */
614 HWND FindWindow( SEGPTR ClassMatch, LPSTR TitleMatch )
615 {
616     HCLASS hclass;
617     CLASS *classPtr;
618     HWND hwnd;
619
620     if (ClassMatch)
621     {
622         hclass = CLASS_FindClassByName( ClassMatch, (HINSTANCE)0xffff,
623                                         &classPtr );
624         if (!hclass) return 0;
625     }
626     else hclass = 0;
627
628     hwnd = GetTopWindow( hwndDesktop );
629     while(hwnd)
630     {
631         WND *wndPtr = WIN_FindWndPtr( hwnd );
632         if (!hclass || (wndPtr->hClass == hclass))
633         {
634               /* Found matching class */
635             if (!TitleMatch) return hwnd;
636             if (wndPtr->hText)
637             {
638                 char *textPtr = (char *) USER_HEAP_LIN_ADDR( wndPtr->hText );
639                 if (!strcmp( textPtr, TitleMatch )) return hwnd;
640             }
641         }
642         hwnd = wndPtr->hwndNext;
643     }
644     return 0;
645 }
646  
647  
648 /**********************************************************************
649  *           GetDesktopWindow        (USER.286)
650  *           GetDeskTopHwnd          (USER.278)
651  */
652 HWND GetDesktopWindow(void)
653 {
654     return hwndDesktop;
655 }
656
657
658 /*******************************************************************
659  *           EnableWindow   (USER.34)
660  */
661 BOOL EnableWindow( HWND hwnd, BOOL enable )
662 {
663     WND *wndPtr;
664
665     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
666     if (enable && (wndPtr->dwStyle & WS_DISABLED))
667     {
668           /* Enable window */
669         wndPtr->dwStyle &= ~WS_DISABLED;
670         SendMessage( hwnd, WM_ENABLE, TRUE, 0 );
671         return TRUE;
672     }
673     else if (!enable && !(wndPtr->dwStyle & WS_DISABLED))
674     {
675           /* Disable window */
676         wndPtr->dwStyle |= WS_DISABLED;
677         if ((hwnd == GetFocus()) || IsChild( hwnd, GetFocus() ))
678             SetFocus( 0 );  /* A disabled window can't have the focus */
679         if ((hwnd == GetCapture()) || IsChild( hwnd, GetCapture() ))
680             ReleaseCapture();  /* A disabled window can't capture the mouse */
681         SendMessage( hwnd, WM_ENABLE, FALSE, 0 );
682         return FALSE;
683     }
684     return ((wndPtr->dwStyle & WS_DISABLED) != 0);
685 }
686
687
688 /***********************************************************************
689  *           IsWindowEnabled   (USER.35)
690  */ 
691 BOOL IsWindowEnabled(HWND hWnd)
692 {
693     WND * wndPtr; 
694
695     if (!(wndPtr = WIN_FindWndPtr(hWnd))) return FALSE;
696     return !(wndPtr->dwStyle & WS_DISABLED);
697 }
698
699
700 /**********************************************************************
701  *           GetWindowWord    (USER.133)
702  */
703 WORD GetWindowWord( HWND hwnd, short offset )
704 {
705     WND * wndPtr = WIN_FindWndPtr( hwnd );
706     if (!wndPtr) return 0;
707     if (offset >= 0) return *(WORD *)(((char *)wndPtr->wExtra) + offset);
708     switch(offset)
709     {
710         case GWW_ID:         return wndPtr->wIDmenu;
711 #ifdef WINELIB32
712         case GWW_HWNDPARENT:
713         case GWW_HINSTANCE: 
714             fprintf(stderr,"GetWindowWord called with offset %d.\n",offset);
715             return 0;
716 #else
717         case GWW_HWNDPARENT: return (WORD)wndPtr->hwndParent;
718         case GWW_HINSTANCE:  return (WORD)wndPtr->hInstance;
719 #endif
720     }
721     return 0;
722 }
723
724
725 /**********************************************************************
726  *           WIN_GetWindowInstance
727  */
728 HINSTANCE WIN_GetWindowInstance(HWND hwnd)
729 {
730     WND * wndPtr = WIN_FindWndPtr( hwnd );
731     if (!wndPtr) return (HINSTANCE)0;
732     return wndPtr->hInstance;
733 }
734
735
736 /**********************************************************************
737  *           SetWindowWord    (USER.134)
738  */
739 WORD SetWindowWord( HWND hwnd, short offset, WORD newval )
740 {
741     WORD *ptr, retval;
742     WND * wndPtr = WIN_FindWndPtr( hwnd );
743     if (!wndPtr) return 0;
744     if (offset >= 0) ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
745     else switch(offset)
746     {
747         case GWW_ID:        ptr = &wndPtr->wIDmenu;   break;
748 #ifdef WINELIB32
749         case GWW_HINSTANCE:
750             fprintf(stderr,"SetWindowWord called with offset %d.\n",offset);
751             return 0;
752 #else
753         case GWW_HINSTANCE: ptr = (WORD*)&wndPtr->hInstance; break;
754 #endif
755         default: return 0;
756     }
757     retval = *ptr;
758     *ptr = newval;
759     return retval;
760 }
761
762
763 /**********************************************************************
764  *           GetWindowLong    (USER.135)
765  */
766 LONG GetWindowLong( HWND hwnd, short offset )
767 {
768     WND * wndPtr = WIN_FindWndPtr( hwnd );
769     if (!wndPtr) return 0;
770     if (offset >= 0) return *(LONG *)(((char *)wndPtr->wExtra) + offset);
771     switch(offset)
772     {
773         case GWL_STYLE:   return wndPtr->dwStyle;
774         case GWL_EXSTYLE: return wndPtr->dwExStyle;
775         case GWL_WNDPROC: return (LONG)wndPtr->lpfnWndProc;
776 #ifdef WINELIB32
777         case GWW_HWNDPARENT: return (LONG)wndPtr->hwndParent;
778         case GWW_HINSTANCE:  return (LONG)wndPtr->hInstance;
779 #endif
780     }
781     return 0;
782 }
783
784
785 /**********************************************************************
786  *           SetWindowLong    (USER.136)
787  */
788 LONG SetWindowLong( HWND hwnd, short offset, LONG newval )
789 {
790     LONG *ptr, retval;
791     WND * wndPtr = WIN_FindWndPtr( hwnd );
792     if (!wndPtr) return 0;
793     if (offset >= 0) ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
794     else switch(offset)
795     {
796         case GWL_STYLE:   ptr = &wndPtr->dwStyle; break;
797         case GWL_EXSTYLE: ptr = &wndPtr->dwExStyle; break;
798         case GWL_WNDPROC: ptr = (LONG *)&wndPtr->lpfnWndProc; break;
799         default: return 0;
800     }
801     retval = *ptr;
802     *ptr = newval;
803     return retval;
804 }
805
806
807 /*******************************************************************
808  *         GetWindowText          (USER.36)
809  */
810 int WIN16_GetWindowText( HWND hwnd, SEGPTR lpString, int nMaxCount )
811 {
812     return (int)SendMessage(hwnd, WM_GETTEXT, (WORD)nMaxCount, 
813                                               (DWORD)lpString);
814 }
815
816 int GetWindowText( HWND hwnd, LPSTR lpString, int nMaxCount )
817 {
818     int len;
819     HANDLE handle;
820
821       /* We have to allocate a buffer on the USER heap */
822       /* to be able to pass its address to 16-bit code */
823     if (!(handle = USER_HEAP_ALLOC( nMaxCount ))) return 0;
824     len = (int)SendMessage( hwnd, WM_GETTEXT, (WPARAM)nMaxCount, 
825                             (LPARAM)USER_HEAP_SEG_ADDR(handle) );
826     strncpy( lpString, USER_HEAP_LIN_ADDR(handle), nMaxCount );
827     USER_HEAP_FREE( handle );
828     return len;
829 }
830
831
832 /*******************************************************************
833  *         SetWindowText          (USER.37)
834  */
835 void WIN16_SetWindowText( HWND hwnd, SEGPTR lpString )
836 {
837     SendMessage( hwnd, WM_SETTEXT, 0, (DWORD)lpString );
838 }
839
840 void SetWindowText( HWND hwnd, LPSTR lpString )
841 {
842     HANDLE handle;
843
844       /* We have to allocate a buffer on the USER heap */
845       /* to be able to pass its address to 16-bit code */
846     if (!(handle = USER_HEAP_ALLOC( strlen(lpString)+1 ))) return;
847     strcpy( USER_HEAP_LIN_ADDR(handle), lpString );
848     SendMessage( hwnd, WM_SETTEXT, 0, (LPARAM)USER_HEAP_SEG_ADDR(handle) );
849     USER_HEAP_FREE( handle );
850 }
851
852
853 /*******************************************************************
854  *         GetWindowTextLength    (USER.38)
855  */
856 int GetWindowTextLength(HWND hwnd)
857 {
858     return (int)SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0 );
859 }
860
861
862 /*******************************************************************
863  *         IsWindow    (USER.47)
864  */
865 BOOL IsWindow( HWND hwnd )
866 {
867     WND * wndPtr = WIN_FindWndPtr( hwnd );
868     return ((wndPtr != NULL) && (wndPtr->dwMagic == WND_MAGIC));
869 }
870
871
872 /*****************************************************************
873  *         GetParent              (USER.46)
874  */
875 HWND GetParent(HWND hwnd)
876 {
877     WND *wndPtr = WIN_FindWndPtr(hwnd);
878     if (!wndPtr) return 0;
879     return (wndPtr->dwStyle & WS_CHILD) ?
880             wndPtr->hwndParent : wndPtr->hwndOwner;
881 }
882
883
884 /*****************************************************************
885  *         WIN_GetTopParent
886  *
887  * Get the top-level parent for a child window.
888  */
889 HWND WIN_GetTopParent( HWND hwnd )
890 {
891     while (hwnd)
892     {
893         WND *wndPtr = WIN_FindWndPtr( hwnd );
894         if (wndPtr->dwStyle & WS_CHILD) hwnd = wndPtr->hwndParent;
895         else break;
896     }
897     return hwnd;
898 }
899
900
901 /*****************************************************************
902  *         SetParent              (USER.233)
903  */
904 HWND SetParent(HWND hwndChild, HWND hwndNewParent)
905 {
906     HWND temp;
907
908     WND *wndPtr = WIN_FindWndPtr(hwndChild);
909     if (!wndPtr || !(wndPtr->dwStyle & WS_CHILD)) return 0;
910
911     temp = wndPtr->hwndParent;
912
913     WIN_UnlinkWindow(hwndChild);
914     if (hwndNewParent)
915       wndPtr->hwndParent = hwndNewParent;
916     else
917       wndPtr->hwndParent = GetDesktopWindow();
918     WIN_LinkWindow(hwndChild, HWND_BOTTOM);
919     
920     if (IsWindowVisible(hwndChild)) UpdateWindow(hwndChild);
921     
922     return temp;
923 }
924
925
926
927 /*******************************************************************
928  *         IsChild    (USER.48)
929  */
930 BOOL IsChild( HWND parent, HWND child )
931 {
932     WND * wndPtr = WIN_FindWndPtr( child );
933     while (wndPtr && (wndPtr->dwStyle & WS_CHILD))
934     {
935         if (wndPtr->hwndParent == parent) return TRUE;
936         wndPtr = WIN_FindWndPtr( wndPtr->hwndParent );
937     }
938     return FALSE;
939 }
940
941
942 /***********************************************************************
943  *           IsWindowVisible   (USER.49)
944  */
945 BOOL IsWindowVisible( HWND hwnd )
946 {
947     WND *wndPtr = WIN_FindWndPtr( hwnd );
948     while (wndPtr && (wndPtr->dwStyle & WS_CHILD))
949     {
950         if (!(wndPtr->dwStyle & WS_VISIBLE)) return FALSE;
951         wndPtr = WIN_FindWndPtr( wndPtr->hwndParent );
952     }
953     return (wndPtr && (wndPtr->dwStyle & WS_VISIBLE));
954 }
955
956  
957  
958 /*******************************************************************
959  *         GetTopWindow    (USER.229)
960  */
961 HWND GetTopWindow( HWND hwnd )
962 {
963     WND * wndPtr = WIN_FindWndPtr( hwnd );
964     if (wndPtr) return wndPtr->hwndChild;
965     else return 0;
966 }
967
968
969 /*******************************************************************
970  *         GetWindow    (USER.262)
971  */
972 HWND GetWindow( HWND hwnd, WORD rel )
973 {
974     WND * wndPtr = WIN_FindWndPtr( hwnd );
975     if (!wndPtr) return 0;
976     switch(rel)
977     {
978     case GW_HWNDFIRST:
979         if (wndPtr->hwndParent)
980         {
981             WND * parentPtr = WIN_FindWndPtr( wndPtr->hwndParent );
982             return parentPtr->hwndChild;
983         }
984         else return 0;
985         
986     case GW_HWNDLAST:
987         if (!wndPtr->hwndParent) return 0;  /* Desktop window */
988         while (wndPtr->hwndNext)
989         {
990             hwnd = wndPtr->hwndNext;
991             wndPtr = WIN_FindWndPtr( hwnd );
992         }
993         return hwnd;
994         
995     case GW_HWNDNEXT:
996         return wndPtr->hwndNext;
997         
998     case GW_HWNDPREV:   
999         {
1000             HWND hwndPrev;
1001             
1002             if (wndPtr->hwndParent)
1003             {
1004                 WND * parentPtr = WIN_FindWndPtr( wndPtr->hwndParent );
1005                 hwndPrev = parentPtr->hwndChild;
1006             }
1007             else return 0;  /* Desktop window */
1008             if (hwndPrev == hwnd) return 0;
1009             while (hwndPrev)
1010             {
1011                 wndPtr = WIN_FindWndPtr( hwndPrev );
1012                 if (wndPtr->hwndNext == hwnd) break;
1013                 hwndPrev = wndPtr->hwndNext;
1014             }
1015             return hwndPrev;
1016         }
1017         
1018     case GW_OWNER:
1019         return wndPtr->hwndOwner;
1020
1021     case GW_CHILD:
1022         return wndPtr->hwndChild;
1023     }
1024     return 0;
1025 }
1026
1027
1028 /*******************************************************************
1029  *         GetNextWindow    (USER.230)
1030  */
1031 HWND GetNextWindow( HWND hwnd, WORD flag )
1032 {
1033     if ((flag != GW_HWNDNEXT) && (flag != GW_HWNDPREV)) return 0;
1034     return GetWindow( hwnd, flag );
1035 }
1036
1037 /*******************************************************************
1038  *         ShowOwnedPopups  (USER.265)
1039  */
1040 void ShowOwnedPopups( HWND owner, BOOL fShow )
1041 {
1042     HWND hwnd = GetWindow( hwndDesktop, GW_CHILD );
1043     while (hwnd)
1044     {
1045         WND *wnd = WIN_FindWndPtr(hwnd);
1046         if (wnd->hwndOwner == owner && (wnd->dwStyle & WS_POPUP))
1047             ShowWindow( hwnd, fShow ? SW_SHOW : SW_HIDE );
1048         hwnd = wnd->hwndNext;
1049     }
1050 }
1051
1052
1053 /*******************************************************************
1054  *         GetLastActivePopup    (USER.287)
1055  */
1056 HWND GetLastActivePopup(HWND hwnd)
1057 {
1058     WND *wndPtr;
1059     wndPtr = WIN_FindWndPtr(hwnd);
1060     if (wndPtr == NULL) return hwnd;
1061     return wndPtr->hwndLastActive;
1062 }
1063
1064
1065 /*******************************************************************
1066  *           EnumWindows   (USER.54)
1067  */
1068 BOOL EnumWindows( FARPROC lpEnumFunc, LPARAM lParam )
1069 {
1070     HWND hwnd;
1071     WND *wndPtr;
1072     HWND *list, *pWnd;
1073     int count;
1074
1075     /* We have to build a list of all windows first, to avoid */
1076     /* unpleasant side-effects, for instance if the callback  */
1077     /* function changes the Z-order of the windows.           */
1078
1079       /* First count the windows */
1080
1081     count = 0;
1082     for (hwnd = GetTopWindow(hwndDesktop); hwnd != 0; hwnd = wndPtr->hwndNext)
1083     {
1084         if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
1085         count++;
1086     }
1087     if (!count) return TRUE;
1088
1089       /* Now build the list of all windows */
1090
1091     if (!(list = (HWND *)malloc( sizeof(HWND) * count ))) return FALSE;
1092     for (hwnd = GetTopWindow(hwndDesktop), pWnd = list; hwnd != 0; hwnd = wndPtr->hwndNext)
1093     {
1094         wndPtr = WIN_FindWndPtr( hwnd );
1095         *pWnd++ = hwnd;
1096     }
1097
1098       /* Now call the callback function for every window */
1099
1100     for (pWnd = list; count > 0; count--, pWnd++)
1101     {
1102           /* Make sure that window still exists */
1103         if (!IsWindow(*pWnd)) continue;
1104         if (!CallEnumWindowsProc( lpEnumFunc, *pWnd, lParam )) break;
1105     }
1106     free( list );
1107     return TRUE;
1108 }
1109
1110
1111 /**********************************************************************
1112  *           EnumTaskWindows   (USER.225)
1113  */
1114 BOOL EnumTaskWindows( HTASK hTask, FARPROC lpEnumFunc, LONG lParam )
1115 {
1116     HWND hwnd;
1117     WND *wndPtr;
1118     HWND *list, *pWnd;
1119     HANDLE hQueue = GetTaskQueue( hTask );
1120     int count;
1121
1122     /* This function is the same as EnumWindows(),    */
1123     /* except for an added check on the window queue. */
1124
1125       /* First count the windows */
1126
1127     count = 0;
1128     for (hwnd = GetTopWindow(hwndDesktop); hwnd != 0; hwnd = wndPtr->hwndNext)
1129     {
1130         if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
1131         if (wndPtr->hmemTaskQ == hQueue) count++;
1132     }
1133     if (!count) return TRUE;
1134
1135       /* Now build the list of all windows */
1136
1137     if (!(list = (HWND *)malloc( sizeof(HWND) * count ))) return FALSE;
1138     for (hwnd = GetTopWindow(hwndDesktop), pWnd = list; hwnd != 0; hwnd = wndPtr->hwndNext)
1139     {
1140         wndPtr = WIN_FindWndPtr( hwnd );
1141         if (wndPtr->hmemTaskQ == hQueue) *pWnd++ = hwnd;
1142     }
1143
1144       /* Now call the callback function for every window */
1145
1146     for (pWnd = list; count > 0; count--, pWnd++)
1147     {
1148           /* Make sure that window still exists */
1149         if (!IsWindow(*pWnd)) continue;
1150         if (!CallEnumTaskWndProc( lpEnumFunc, *pWnd, lParam )) break;
1151     }
1152     free( list );
1153     return TRUE;
1154 }
1155
1156
1157 /*******************************************************************
1158  *    WIN_EnumChildWin
1159  *
1160  *   o hwnd is the first child to use, loop until all next windows
1161  *     are processed
1162  * 
1163  *   o call wdnenumprc
1164  *
1165  *   o call ourselves with the next child window
1166  * 
1167  */
1168 static BOOL WIN_EnumChildWin(HWND hwnd, FARPROC wndenumprc, LPARAM lParam)
1169 {
1170     WND *wndPtr;
1171
1172     while (hwnd)
1173     {
1174         if (!(wndPtr=WIN_FindWndPtr(hwnd))) return 0;
1175         if (!CallEnumWindowsProc( wndenumprc, hwnd, lParam )) return 0;
1176         if (!WIN_EnumChildWin(wndPtr->hwndChild, wndenumprc, lParam)) return 0;
1177         hwnd=wndPtr->hwndNext;
1178     } 
1179     return 1;
1180 }
1181
1182 /*******************************************************************
1183  *    EnumChildWindows        (USER.55)
1184  *
1185  *   o gets the first child of hwnd
1186  *
1187  *   o calls WIN_EnumChildWin to do a recursive decent of child windows
1188  */
1189 BOOL EnumChildWindows(HWND hwnd, FARPROC wndenumprc, LPARAM lParam)
1190 {
1191     WND *wndPtr;
1192
1193     dprintf_enum(stddeb,"EnumChildWindows\n");
1194
1195     if (hwnd == 0) return 0;
1196     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
1197     hwnd = wndPtr->hwndChild;
1198     return WIN_EnumChildWin(hwnd, wndenumprc, lParam);         
1199 }
1200
1201
1202 /*******************************************************************
1203  *                      AnyPopup                [USER.52]
1204  */
1205 BOOL AnyPopup()
1206 {
1207         dprintf_win(stdnimp,"EMPTY STUB !! AnyPopup !\n");
1208         return FALSE;
1209 }
1210
1211 /*******************************************************************
1212  *                      FlashWindow             [USER.105]
1213  */
1214 BOOL FlashWindow(HWND hWnd, BOOL bInvert)
1215 {
1216         dprintf_win(stdnimp,"EMPTY STUB !! FlashWindow !\n");
1217         return FALSE;
1218 }
1219
1220
1221 /*******************************************************************
1222  *                      SetSysModalWindow               [USER.188]
1223  */
1224 HWND SetSysModalWindow(HWND hWnd)
1225 {
1226         HWND hWndOldModal = hWndSysModal;
1227         hWndSysModal = hWnd;
1228         dprintf_win(stdnimp,"EMPTY STUB !! SetSysModalWindow("NPFMT") !\n", hWnd);
1229         return hWndOldModal;
1230 }
1231
1232
1233 /*******************************************************************
1234  *                      GetSysModalWindow               [USER.189]
1235  */
1236 HWND GetSysModalWindow(void)
1237 {
1238         return hWndSysModal;
1239 }