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