1/*
2 *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
3 *Copyright (C) Colin Harrison 2005-2008
4 *
5 *Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 *"Software"), to deal in the Software without restriction, including
8 *without limitation the rights to use, copy, modify, merge, publish,
9 *distribute, sublicense, and/or sell copies of the Software, and to
10 *permit persons to whom the Software is furnished to do so, subject to
11 *the following conditions:
12 *
13 *The above copyright notice and this permission notice shall be
14 *included in all copies or substantial portions of the Software.
15 *
16 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
20 *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21 *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 *Except as contained in this notice, the name of the XFree86 Project
25 *shall not be used in advertising or otherwise to promote the sale, use
26 *or other dealings in this Software without prior written authorization
27 *from the XFree86 Project.
28 *
29 * Authors:	Kensuke Matsuzaki
30 *		Earle F. Philhower, III
31 *		Harold L Hunt II
32 *              Colin Harrison
33 */
34
35#ifdef HAVE_XWIN_CONFIG_H
36#include <xwin-config.h>
37#endif
38
39#include "win.h"
40#include "dixevents.h"
41#include "winmultiwindowclass.h"
42#include "winmultiwindowicons.h"
43
44/*
45 * Prototypes for local functions
46 */
47
48void
49 winCreateWindowsWindow(WindowPtr pWin);
50
51static void
52 winDestroyWindowsWindow(WindowPtr pWin);
53
54static void
55 winUpdateWindowsWindow(WindowPtr pWin);
56
57static void
58 winFindWindow(void *value, XID id, void *cdata);
59
60static
61    void
62winInitMultiWindowClass(void)
63{
64    static wATOM atomXWinClass = 0;
65    WNDCLASSEX wcx;
66
67    if (atomXWinClass == 0) {
68        HICON hIcon, hIconSmall;
69
70        /* Load the default icons */
71        winSelectIcons(&hIcon, &hIconSmall);
72
73        /* Setup our window class */
74        wcx.cbSize = sizeof(WNDCLASSEX);
75        wcx.style = CS_HREDRAW | CS_VREDRAW | (g_fNativeGl ? CS_OWNDC : 0);
76        wcx.lpfnWndProc = winTopLevelWindowProc;
77        wcx.cbClsExtra = 0;
78        wcx.cbWndExtra = 0;
79        wcx.hInstance = g_hInstance;
80        wcx.hIcon = hIcon;
81        wcx.hCursor = 0;
82        wcx.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
83        wcx.lpszMenuName = NULL;
84        wcx.lpszClassName = WINDOW_CLASS_X;
85        wcx.hIconSm = hIconSmall;
86
87#if CYGMULTIWINDOW_DEBUG
88        ErrorF("winCreateWindowsWindow - Creating class: %s\n", WINDOW_CLASS_X);
89#endif
90
91        atomXWinClass = RegisterClassEx(&wcx);
92    }
93}
94
95/*
96 * CreateWindow - See Porting Layer Definition - p. 37
97 */
98
99Bool
100winCreateWindowMultiWindow(WindowPtr pWin)
101{
102    Bool fResult = TRUE;
103    ScreenPtr pScreen = pWin->drawable.pScreen;
104
105    winWindowPriv(pWin);
106    winScreenPriv(pScreen);
107
108#if CYGMULTIWINDOW_DEBUG
109    winTrace("winCreateWindowMultiWindow - pWin: %p\n", pWin);
110#endif
111
112    WIN_UNWRAP(CreateWindow);
113    fResult = (*pScreen->CreateWindow) (pWin);
114    WIN_WRAP(CreateWindow, winCreateWindowMultiWindow);
115
116    /* Initialize some privates values */
117    pWinPriv->hRgn = NULL;
118    pWinPriv->hWnd = NULL;
119    pWinPriv->pScreenPriv = winGetScreenPriv(pWin->drawable.pScreen);
120    pWinPriv->fXKilled = FALSE;
121#ifdef XWIN_GLX_WINDOWS
122    pWinPriv->fWglUsed = FALSE;
123#endif
124
125    return fResult;
126}
127
128/*
129 * DestroyWindow - See Porting Layer Definition - p. 37
130 */
131
132Bool
133winDestroyWindowMultiWindow(WindowPtr pWin)
134{
135    Bool fResult = TRUE;
136    ScreenPtr pScreen = pWin->drawable.pScreen;
137
138    winWindowPriv(pWin);
139    winScreenPriv(pScreen);
140
141#if CYGMULTIWINDOW_DEBUG
142    ErrorF("winDestroyWindowMultiWindow - pWin: %p\n", pWin);
143#endif
144
145    WIN_UNWRAP(DestroyWindow);
146    fResult = (*pScreen->DestroyWindow) (pWin);
147    WIN_WRAP(DestroyWindow, winDestroyWindowMultiWindow);
148
149    /* Flag that the window has been destroyed */
150    pWinPriv->fXKilled = TRUE;
151
152    /* Kill the MS Windows window associated with this window */
153    winDestroyWindowsWindow(pWin);
154
155    return fResult;
156}
157
158/*
159 * PositionWindow - See Porting Layer Definition - p. 37
160 *
161 * This function adjusts the position and size of Windows window
162 * with respect to the underlying X window.  This is the inverse
163 * of winAdjustXWindow, which adjusts X window to Windows window.
164 */
165
166Bool
167winPositionWindowMultiWindow(WindowPtr pWin, int x, int y)
168{
169    Bool fResult = TRUE;
170    int iX, iY, iWidth, iHeight;
171    ScreenPtr pScreen = pWin->drawable.pScreen;
172
173    winWindowPriv(pWin);
174    winScreenPriv(pScreen);
175
176    HWND hWnd = pWinPriv->hWnd;
177    RECT rcNew;
178    RECT rcOld;
179
180#if CYGMULTIWINDOW_DEBUG
181    RECT rcClient;
182    RECT *lpRc;
183#endif
184    DWORD dwExStyle;
185    DWORD dwStyle;
186
187#if CYGMULTIWINDOW_DEBUG
188    winTrace("winPositionWindowMultiWindow - pWin: %p\n", pWin);
189#endif
190
191    WIN_UNWRAP(PositionWindow);
192    fResult = (*pScreen->PositionWindow) (pWin, x, y);
193    WIN_WRAP(PositionWindow, winPositionWindowMultiWindow);
194
195#if CYGWINDOWING_DEBUG
196    ErrorF("winPositionWindowMultiWindow: (x, y) = (%d, %d)\n", x, y);
197#endif
198
199    /* Bail out if the Windows window handle is bad */
200    if (!hWnd) {
201#if CYGWINDOWING_DEBUG
202        ErrorF("\timmediately return since hWnd is NULL\n");
203#endif
204        return fResult;
205    }
206
207    /* Get the Windows window style and extended style */
208    dwExStyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE);
209    dwStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
210
211    /* Get the X and Y location of the X window */
212    iX = pWin->drawable.x + GetSystemMetrics(SM_XVIRTUALSCREEN);
213    iY = pWin->drawable.y + GetSystemMetrics(SM_YVIRTUALSCREEN);
214
215    /* Get the height and width of the X window */
216    iWidth = pWin->drawable.width;
217    iHeight = pWin->drawable.height;
218
219    /* Store the origin, height, and width in a rectangle structure */
220    SetRect(&rcNew, iX, iY, iX + iWidth, iY + iHeight);
221
222#if CYGMULTIWINDOW_DEBUG
223    lpRc = &rcNew;
224    ErrorF("winPositionWindowMultiWindow - drawable (%d, %d)-(%d, %d)\n",
225           (int)lpRc->left, (int)lpRc->top, (int)lpRc->right, (int)lpRc->bottom);
226#endif
227
228    /*
229     * Calculate the required size of the Windows window rectangle,
230     * given the size of the Windows window client area.
231     */
232    AdjustWindowRectEx(&rcNew, dwStyle, FALSE, dwExStyle);
233
234    /* Get a rectangle describing the old Windows window */
235    GetWindowRect(hWnd, &rcOld);
236
237#if CYGMULTIWINDOW_DEBUG
238    /* Get a rectangle describing the Windows window client area */
239    GetClientRect(hWnd, &rcClient);
240
241    lpRc = &rcNew;
242    ErrorF("winPositionWindowMultiWindow - rcNew (%d, %d)-(%d, %d)\n",
243           (int)lpRc->left, (int)lpRc->top, (int)lpRc->right, (int)lpRc->bottom);
244
245    lpRc = &rcOld;
246    ErrorF("winPositionWindowMultiWindow - rcOld (%d, %d)-(%d, %d)\n",
247           (int)lpRc->left, (int)lpRc->top, (int)lpRc->right, (int)lpRc->bottom);
248
249    lpRc = &rcClient;
250    ErrorF("rcClient (%d, %d)-(%d, %d)\n",
251           (int)lpRc->left, (int)lpRc->top, (int)lpRc->right, (int)lpRc->bottom);
252#endif
253
254    /* Check if the old rectangle and new rectangle are the same */
255    if (!EqualRect(&rcNew, &rcOld)) {
256#if CYGMULTIWINDOW_DEBUG
257        ErrorF("winPositionWindowMultiWindow - Need to move\n");
258#endif
259
260#if CYGWINDOWING_DEBUG
261        ErrorF("\tMoveWindow to (%d, %d) - %dx%d\n", (int)rcNew.left, (int)rcNew.top,
262               (int)(rcNew.right - rcNew.left), (int)(rcNew.bottom - rcNew.top));
263#endif
264        /* Change the position and dimensions of the Windows window */
265        MoveWindow(hWnd,
266                   rcNew.left, rcNew.top,
267                   rcNew.right - rcNew.left, rcNew.bottom - rcNew.top, TRUE);
268    }
269    else {
270#if CYGMULTIWINDOW_DEBUG
271        ErrorF("winPositionWindowMultiWindow - Not need to move\n");
272#endif
273    }
274
275    return fResult;
276}
277
278/*
279 * ChangeWindowAttributes - See Porting Layer Definition - p. 37
280 */
281
282Bool
283winChangeWindowAttributesMultiWindow(WindowPtr pWin, unsigned long mask)
284{
285    Bool fResult = TRUE;
286    ScreenPtr pScreen = pWin->drawable.pScreen;
287
288    winScreenPriv(pScreen);
289
290#if CYGMULTIWINDOW_DEBUG
291    ErrorF("winChangeWindowAttributesMultiWindow - pWin: %p\n", pWin);
292#endif
293
294    WIN_UNWRAP(ChangeWindowAttributes);
295    fResult = (*pScreen->ChangeWindowAttributes) (pWin, mask);
296    WIN_WRAP(ChangeWindowAttributes, winChangeWindowAttributesMultiWindow);
297
298    /*
299     * NOTE: We do not currently need to do anything here.
300     */
301
302    return fResult;
303}
304
305/*
306 * UnmapWindow - See Porting Layer Definition - p. 37
307 * Also referred to as UnrealizeWindow
308 */
309
310Bool
311winUnmapWindowMultiWindow(WindowPtr pWin)
312{
313    Bool fResult = TRUE;
314    ScreenPtr pScreen = pWin->drawable.pScreen;
315
316    winWindowPriv(pWin);
317    winScreenPriv(pScreen);
318
319#if CYGMULTIWINDOW_DEBUG
320    ErrorF("winUnmapWindowMultiWindow - pWin: %p\n", pWin);
321#endif
322
323    WIN_UNWRAP(UnrealizeWindow);
324    fResult = (*pScreen->UnrealizeWindow) (pWin);
325    WIN_WRAP(UnrealizeWindow, winUnmapWindowMultiWindow);
326
327    /* Flag that the window has been killed */
328    pWinPriv->fXKilled = TRUE;
329
330    /* Destroy the Windows window associated with this X window */
331    winDestroyWindowsWindow(pWin);
332
333    return fResult;
334}
335
336/*
337 * MapWindow - See Porting Layer Definition - p. 37
338 * Also referred to as RealizeWindow
339 */
340
341Bool
342winMapWindowMultiWindow(WindowPtr pWin)
343{
344    Bool fResult = TRUE;
345    ScreenPtr pScreen = pWin->drawable.pScreen;
346
347    winWindowPriv(pWin);
348    winScreenPriv(pScreen);
349
350#if CYGMULTIWINDOW_DEBUG
351    ErrorF("winMapWindowMultiWindow - pWin: %p\n", pWin);
352#endif
353
354    WIN_UNWRAP(RealizeWindow);
355    fResult = (*pScreen->RealizeWindow) (pWin);
356    WIN_WRAP(RealizeWindow, winMapWindowMultiWindow);
357
358    /* Flag that this window has not been destroyed */
359    pWinPriv->fXKilled = FALSE;
360
361    /* Refresh/redisplay the Windows window associated with this X window */
362    winUpdateWindowsWindow(pWin);
363
364    /* Update the Windows window's shape */
365    winReshapeMultiWindow(pWin);
366    winUpdateRgnMultiWindow(pWin);
367
368    return fResult;
369}
370
371/*
372 * ReparentWindow - See Porting Layer Definition - p. 42
373 */
374
375void
376winReparentWindowMultiWindow(WindowPtr pWin, WindowPtr pPriorParent)
377{
378    ScreenPtr pScreen = pWin->drawable.pScreen;
379
380    winScreenPriv(pScreen);
381
382    winDebug
383        ("winReparentMultiWindow - pWin:%p XID:0x%x, reparent from pWin:%p XID:0x%x to pWin:%p XID:0x%x\n",
384         pWin, (unsigned int)pWin->drawable.id,
385         pPriorParent, (unsigned int)pPriorParent->drawable.id,
386         pWin->parent, (unsigned int)pWin->parent->drawable.id);
387
388    WIN_UNWRAP(ReparentWindow);
389    if (pScreen->ReparentWindow)
390        (*pScreen->ReparentWindow) (pWin, pPriorParent);
391    WIN_WRAP(ReparentWindow, winReparentWindowMultiWindow);
392
393    /* Update the Windows window associated with this X window */
394    winUpdateWindowsWindow(pWin);
395}
396
397/*
398 * RestackWindow - Shuffle the z-order of a window
399 */
400
401void
402winRestackWindowMultiWindow(WindowPtr pWin, WindowPtr pOldNextSib)
403{
404#if 0
405    WindowPtr pPrevWin;
406    UINT uFlags;
407    HWND hInsertAfter;
408    HWND hWnd = NULL;
409#endif
410    ScreenPtr pScreen = pWin->drawable.pScreen;
411
412    winScreenPriv(pScreen);
413
414#if CYGMULTIWINDOW_DEBUG || CYGWINDOWING_DEBUG
415    winTrace("winRestackMultiWindow - %p\n", pWin);
416#endif
417
418    WIN_UNWRAP(RestackWindow);
419    if (pScreen->RestackWindow)
420        (*pScreen->RestackWindow) (pWin, pOldNextSib);
421    WIN_WRAP(RestackWindow, winRestackWindowMultiWindow);
422
423#if 1
424    /*
425     * Calling winReorderWindowsMultiWindow here means our window manager
426     * (i.e. Windows Explorer) has initiative to determine Z order.
427     */
428    if (pWin->nextSib != pOldNextSib)
429        winReorderWindowsMultiWindow();
430#else
431    /* Bail out if no window privates or window handle is invalid */
432    if (!pWinPriv || !pWinPriv->hWnd)
433        return;
434
435    /* Get a pointer to our previous sibling window */
436    pPrevWin = pWin->prevSib;
437
438    /*
439     * Look for a sibling window with
440     * valid privates and window handle
441     */
442    while (pPrevWin && !winGetWindowPriv(pPrevWin)
443           && !winGetWindowPriv(pPrevWin)->hWnd)
444        pPrevWin = pPrevWin->prevSib;
445
446    /* Check if we found a valid sibling */
447    if (pPrevWin) {
448        /* Valid sibling - get handle to insert window after */
449        hInsertAfter = winGetWindowPriv(pPrevWin)->hWnd;
450        uFlags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE;
451
452        hWnd = GetNextWindow(pWinPriv->hWnd, GW_HWNDPREV);
453
454        do {
455            if (GetProp(hWnd, WIN_WINDOW_PROP)) {
456                if (hWnd == winGetWindowPriv(pPrevWin)->hWnd) {
457                    uFlags |= SWP_NOZORDER;
458                }
459                break;
460            }
461            hWnd = GetNextWindow(hWnd, GW_HWNDPREV);
462        }
463        while (hWnd);
464    }
465    else {
466        /* No valid sibling - make this window the top window */
467        hInsertAfter = HWND_TOP;
468        uFlags = SWP_NOMOVE | SWP_NOSIZE;
469    }
470
471    /* Perform the restacking operation in Windows */
472    SetWindowPos(pWinPriv->hWnd, hInsertAfter, 0, 0, 0, 0, uFlags);
473#endif
474}
475
476/*
477 * winCreateWindowsWindow - Create a Windows window associated with an X window
478 */
479
480void
481winCreateWindowsWindow(WindowPtr pWin)
482{
483    int iX, iY;
484    int iWidth;
485    int iHeight;
486    HWND hWnd;
487    HWND hFore = NULL;
488
489    winWindowPriv(pWin);
490    WinXSizeHints hints;
491    Window daddyId;
492    DWORD dwStyle, dwExStyle;
493    RECT rc;
494
495    winInitMultiWindowClass();
496
497    winDebug("winCreateWindowsTopLevelWindow - pWin:%p XID:0x%x \n", pWin,
498             (unsigned int)pWin->drawable.id);
499
500    iX = pWin->drawable.x + GetSystemMetrics(SM_XVIRTUALSCREEN);
501    iY = pWin->drawable.y + GetSystemMetrics(SM_YVIRTUALSCREEN);
502
503    iWidth = pWin->drawable.width;
504    iHeight = pWin->drawable.height;
505
506    /* If it's an InputOutput window, and so is going to end up being made visible,
507       make sure the window actually ends up somewhere where it will be visible
508
509       To handle arrangements of monitors which form a non-rectangular virtual
510       desktop, check if the window will end up with its top-left corner on any
511       monitor
512    */
513    if (pWin->drawable.class != InputOnly) {
514        POINT pt = { iX, iY };
515        if (MonitorFromPoint(pt, MONITOR_DEFAULTTONULL) == NULL)
516            {
517                iX = CW_USEDEFAULT;
518                iY = CW_USEDEFAULT;
519            }
520    }
521
522    winDebug("winCreateWindowsWindow - %dx%d @ %dx%d\n", iWidth, iHeight, iX,
523             iY);
524
525    if (winMultiWindowGetTransientFor(pWin, &daddyId)) {
526        if (daddyId) {
527            WindowPtr pParent;
528            int res = dixLookupWindow(&pParent, daddyId, serverClient, DixReadAccess);
529            if (res == Success)
530                {
531                    winPrivWinPtr pParentPriv = winGetWindowPriv(pParent);
532                    hFore = pParentPriv->hWnd;
533                }
534        }
535    }
536    else {
537        /* Default positions if none specified */
538        if (!winMultiWindowGetWMNormalHints(pWin, &hints))
539            hints.flags = 0;
540        if (!(hints.flags & (USPosition | PPosition)) &&
541            !pWin->overrideRedirect) {
542            iX = CW_USEDEFAULT;
543            iY = CW_USEDEFAULT;
544        }
545    }
546
547    /* Make it WS_OVERLAPPED in create call since WS_POPUP doesn't support */
548    /* CW_USEDEFAULT, change back to popup after creation */
549    dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
550    dwExStyle = WS_EX_TOOLWINDOW;
551
552    /*
553       Calculate the window coordinates containing the requested client area,
554       being careful to preserve CW_USEDEFAULT
555     */
556    rc.top = (iY != CW_USEDEFAULT) ? iY : 0;
557    rc.left = (iX != CW_USEDEFAULT) ? iX : 0;
558    rc.bottom = rc.top + iHeight;
559    rc.right = rc.left + iWidth;
560    AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle);
561    if (iY != CW_USEDEFAULT)
562        iY = rc.top;
563    if (iX != CW_USEDEFAULT)
564        iX = rc.left;
565    iHeight = rc.bottom - rc.top;
566    iWidth = rc.right - rc.left;
567
568    winDebug("winCreateWindowsWindow - %dx%d @ %dx%d\n", iWidth, iHeight, iX,
569             iY);
570
571    /* Create the window */
572    hWnd = CreateWindowExA(dwExStyle,   /* Extended styles */
573                           WINDOW_CLASS_X,      /* Class name */
574                           WINDOW_TITLE_X,      /* Window name */
575                           dwStyle,     /* Styles */
576                           iX,  /* Horizontal position */
577                           iY,  /* Vertical position */
578                           iWidth,      /* Right edge */
579                           iHeight,     /* Bottom edge */
580                           hFore,       /* Null or Parent window if transient */
581                           (HMENU) NULL,        /* No menu */
582                           GetModuleHandle(NULL),       /* Instance handle */
583                           pWin);       /* ScreenPrivates */
584    if (hWnd == NULL) {
585        ErrorF("winCreateWindowsWindow - CreateWindowExA () failed: %d\n",
586               (int) GetLastError());
587    }
588    pWinPriv->hWnd = hWnd;
589
590    /* Change style back to popup, already placed... */
591    SetWindowLongPtr(hWnd, GWL_STYLE,
592                     WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
593    SetWindowPos(hWnd, 0, 0, 0, 0, 0,
594                 SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE |
595                 SWP_NOACTIVATE);
596
597    /* Adjust the X window to match the window placement we actually got... */
598    winAdjustXWindow(pWin, hWnd);
599
600    /* Make sure it gets the proper system menu for a WS_POPUP, too */
601    GetSystemMenu(hWnd, TRUE);
602
603    /* Cause any .XWinrc menus to be added in main WNDPROC */
604    PostMessage(hWnd, WM_INIT_SYS_MENU, 0, 0);
605
606    SetProp(hWnd, WIN_WID_PROP, (HANDLE) (INT_PTR) winGetWindowID(pWin));
607
608    /* Flag that this Windows window handles its own activation */
609    SetProp(hWnd, WIN_NEEDMANAGE_PROP, (HANDLE) 0);
610}
611
612Bool winInDestroyWindowsWindow = FALSE;
613
614/*
615 * winDestroyWindowsWindow - Destroy a Windows window associated
616 * with an X window
617 */
618static void
619winDestroyWindowsWindow(WindowPtr pWin)
620{
621    MSG msg;
622
623    winWindowPriv(pWin);
624    BOOL oldstate = winInDestroyWindowsWindow;
625    HICON hIcon;
626    HICON hIconSm;
627
628    winDebug("winDestroyWindowsWindow - pWin:%p XID:0x%x \n", pWin,
629             (unsigned int)pWin->drawable.id);
630
631    /* Bail out if the Windows window handle is invalid */
632    if (pWinPriv->hWnd == NULL)
633        return;
634
635    winInDestroyWindowsWindow = TRUE;
636
637    /* Store the info we need to destroy after this window is gone */
638    hIcon = (HICON) SendMessage(pWinPriv->hWnd, WM_GETICON, ICON_BIG, 0);
639    hIconSm = (HICON) SendMessage(pWinPriv->hWnd, WM_GETICON, ICON_SMALL, 0);
640
641    /* Destroy the Windows window */
642    DestroyWindow(pWinPriv->hWnd);
643
644    /* Null our handle to the Window so referencing it will cause an error */
645    pWinPriv->hWnd = NULL;
646
647    /* Destroy any icons we created for this window */
648    winDestroyIcon(hIcon);
649    winDestroyIcon(hIconSm);
650
651#ifdef XWIN_GLX_WINDOWS
652    /* No longer note WGL used on this window */
653    pWinPriv->fWglUsed = FALSE;
654#endif
655
656    /* Process all messages on our queue */
657    while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
658        if (g_hDlgDepthChange == 0 || !IsDialogMessage(g_hDlgDepthChange, &msg)) {
659            DispatchMessage(&msg);
660        }
661    }
662
663    winInDestroyWindowsWindow = oldstate;
664
665    winDebug("winDestroyWindowsWindow - done\n");
666}
667
668/*
669 * winUpdateWindowsWindow - Redisplay/redraw a Windows window
670 * associated with an X window
671 */
672
673static void
674winUpdateWindowsWindow(WindowPtr pWin)
675{
676    winWindowPriv(pWin);
677    HWND hWnd = pWinPriv->hWnd;
678
679#if CYGMULTIWINDOW_DEBUG
680    ErrorF("winUpdateWindowsWindow\n");
681#endif
682
683    /* Check if the Windows window's parents have been destroyed */
684    if (pWin->parent != NULL && pWin->parent->parent == NULL && pWin->mapped) {
685        /* Create the Windows window if it has been destroyed */
686        if (hWnd == NULL) {
687            winCreateWindowsWindow(pWin);
688            assert(pWinPriv->hWnd != NULL);
689        }
690
691        /* Display the window without activating it */
692        if (pWin->drawable.class != InputOnly)
693            ShowWindow(pWinPriv->hWnd, SW_SHOWNOACTIVATE);
694
695        /* Send first paint message */
696        UpdateWindow(pWinPriv->hWnd);
697    }
698    else if (hWnd != NULL) {
699        /* Destroy the Windows window if its parents are destroyed */
700        winDestroyWindowsWindow(pWin);
701        assert(pWinPriv->hWnd == NULL);
702    }
703
704#if CYGMULTIWINDOW_DEBUG
705    ErrorF("-winUpdateWindowsWindow\n");
706#endif
707}
708
709/*
710 * winGetWindowID -
711 */
712
713XID
714winGetWindowID(WindowPtr pWin)
715{
716    WindowIDPairRec wi = { pWin, 0 };
717    ClientPtr c = wClient(pWin);
718
719    /* */
720    FindClientResourcesByType(c, RT_WINDOW, winFindWindow, &wi);
721
722#if CYGMULTIWINDOW_DEBUG
723    ErrorF("winGetWindowID - Window ID: %u\n", (unsigned int)wi.id);
724#endif
725
726    return wi.id;
727}
728
729/*
730 * winFindWindow -
731 */
732
733static void
734winFindWindow(void *value, XID id, void *cdata)
735{
736    WindowIDPairPtr wi = (WindowIDPairPtr) cdata;
737
738    if (value == wi->value) {
739        wi->id = id;
740    }
741}
742
743/*
744 * winReorderWindowsMultiWindow -
745 */
746
747void
748winReorderWindowsMultiWindow(void)
749{
750    HWND hwnd = NULL;
751    WindowPtr pWin = NULL;
752    WindowPtr pWinSib = NULL;
753    XID vlist[2];
754    static Bool fRestacking = FALSE; /* Avoid recursive calls to this function */
755    DWORD dwCurrentProcessID = GetCurrentProcessId();
756    DWORD dwWindowProcessID = 0;
757
758#if CYGMULTIWINDOW_DEBUG || CYGWINDOWING_DEBUG
759    winTrace("winReorderWindowsMultiWindow\n");
760#endif
761
762    if (fRestacking) {
763        /* It is a recursive call so immediately exit */
764#if CYGWINDOWING_DEBUG
765        ErrorF("winReorderWindowsMultiWindow - "
766               "exit because fRestacking == TRUE\n");
767#endif
768        return;
769    }
770    fRestacking = TRUE;
771
772    /* Loop through top level Window windows, descending in Z order */
773    for (hwnd = GetTopWindow(NULL);
774         hwnd; hwnd = GetNextWindow(hwnd, GW_HWNDNEXT)) {
775        /* Don't take care of other Cygwin/X process's windows */
776        GetWindowThreadProcessId(hwnd, &dwWindowProcessID);
777
778        if (GetProp(hwnd, WIN_WINDOW_PROP)
779            && (dwWindowProcessID == dwCurrentProcessID)
780            && !IsIconic(hwnd)) {       /* ignore minimized windows */
781            pWinSib = pWin;
782            pWin = GetProp(hwnd, WIN_WINDOW_PROP);
783
784            if (!pWinSib) {     /* 1st window - raise to the top */
785                vlist[0] = Above;
786
787                ConfigureWindow(pWin, CWStackMode, vlist, wClient(pWin));
788            }
789            else {              /* 2nd or deeper windows - just below the previous one */
790                vlist[0] = winGetWindowID(pWinSib);
791                vlist[1] = Below;
792
793                ConfigureWindow(pWin, CWSibling | CWStackMode,
794                                vlist, wClient(pWin));
795            }
796        }
797    }
798
799    fRestacking = FALSE;
800}
801
802/*
803 * CopyWindow - See Porting Layer Definition - p. 39
804 */
805void
806winCopyWindowMultiWindow(WindowPtr pWin, DDXPointRec oldpt, RegionPtr oldRegion)
807{
808    ScreenPtr pScreen = pWin->drawable.pScreen;
809
810    winScreenPriv(pScreen);
811
812#if CYGWINDOWING_DEBUG
813    ErrorF("CopyWindowMultiWindow\n");
814#endif
815    WIN_UNWRAP(CopyWindow);
816    (*pScreen->CopyWindow) (pWin, oldpt, oldRegion);
817    WIN_WRAP(CopyWindow, winCopyWindowMultiWindow);
818}
819
820/*
821 * MoveWindow - See Porting Layer Definition - p. 42
822 */
823void
824winMoveWindowMultiWindow(WindowPtr pWin, int x, int y,
825                         WindowPtr pSib, VTKind kind)
826{
827    ScreenPtr pScreen = pWin->drawable.pScreen;
828
829    winScreenPriv(pScreen);
830
831#if CYGWINDOWING_DEBUG
832    ErrorF("MoveWindowMultiWindow to (%d, %d)\n", x, y);
833#endif
834
835    WIN_UNWRAP(MoveWindow);
836    (*pScreen->MoveWindow) (pWin, x, y, pSib, kind);
837    WIN_WRAP(MoveWindow, winMoveWindowMultiWindow);
838}
839
840/*
841 * ResizeWindow - See Porting Layer Definition - p. 42
842 */
843void
844winResizeWindowMultiWindow(WindowPtr pWin, int x, int y, unsigned int w,
845                           unsigned int h, WindowPtr pSib)
846{
847    ScreenPtr pScreen = pWin->drawable.pScreen;
848
849    winScreenPriv(pScreen);
850
851#if CYGWINDOWING_DEBUG
852    ErrorF("ResizeWindowMultiWindow to (%d, %d) - %dx%d\n", x, y, w, h);
853#endif
854    WIN_UNWRAP(ResizeWindow);
855    (*pScreen->ResizeWindow) (pWin, x, y, w, h, pSib);
856    WIN_WRAP(ResizeWindow, winResizeWindowMultiWindow);
857}
858
859/*
860 * winAdjustXWindow
861 *
862 * Move and resize X window with respect to corresponding Windows window.
863 * This is called from WM_MOVE/WM_SIZE handlers when the user performs
864 * any windowing operation (move, resize, minimize, maximize, restore).
865 *
866 * The functionality is the inverse of winPositionWindowMultiWindow, which
867 * adjusts Windows window with respect to X window.
868 */
869int
870winAdjustXWindow(WindowPtr pWin, HWND hwnd)
871{
872    RECT rcDraw;                /* Rect made from pWin->drawable to be adjusted */
873    RECT rcWin;                 /* The source: WindowRect from hwnd */
874    DrawablePtr pDraw;
875    XID vlist[4];
876    LONG dX, dY, dW, dH, x, y;
877    DWORD dwStyle, dwExStyle;
878
879#define WIDTH(rc) (rc.right - rc.left)
880#define HEIGHT(rc) (rc.bottom - rc.top)
881
882#if CYGWINDOWING_DEBUG
883    ErrorF("winAdjustXWindow\n");
884#endif
885
886    if (IsIconic(hwnd)) {
887#if CYGWINDOWING_DEBUG
888        ErrorF("\timmediately return because the window is iconized\n");
889#endif
890        /*
891         * If the Windows window is minimized, its WindowRect has
892         * meaningless values so we don't adjust X window to it.
893         */
894        vlist[0] = 0;
895        vlist[1] = 0;
896        return ConfigureWindow(pWin, CWX | CWY, vlist, wClient(pWin));
897    }
898
899    pDraw = &pWin->drawable;
900
901    /* Calculate the window rect from the drawable */
902    x = pDraw->x + GetSystemMetrics(SM_XVIRTUALSCREEN);
903    y = pDraw->y + GetSystemMetrics(SM_YVIRTUALSCREEN);
904    SetRect(&rcDraw, x, y, x + pDraw->width, y + pDraw->height);
905#ifdef CYGMULTIWINDOW_DEBUG
906    winDebug("\tDrawable extend {%d, %d, %d, %d}, {%d, %d}\n",
907             (int)rcDraw.left, (int)rcDraw.top, (int)rcDraw.right, (int)rcDraw.bottom,
908             (int)(rcDraw.right - rcDraw.left), (int)(rcDraw.bottom - rcDraw.top));
909#endif
910    dwExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
911    dwStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
912#ifdef CYGMULTIWINDOW_DEBUG
913    winDebug("\tWindowStyle: %08x %08x\n", (unsigned int)dwStyle, (unsigned int)dwExStyle);
914#endif
915    AdjustWindowRectEx(&rcDraw, dwStyle, FALSE, dwExStyle);
916
917    /* The source of adjust */
918    GetWindowRect(hwnd, &rcWin);
919#ifdef CYGMULTIWINDOW_DEBUG
920    winDebug("\tWindow extend {%d, %d, %d, %d}, {%d, %d}\n",
921             (int)rcWin.left, (int)rcWin.top, (int)rcWin.right, (int)rcWin.bottom,
922             (int)(rcWin.right - rcWin.left), (int)(rcWin.bottom - rcWin.top));
923    winDebug("\tDraw extend {%d, %d, %d, %d}, {%d, %d}\n",
924             (int)rcDraw.left, (int)rcDraw.top, (int)rcDraw.right, (int)rcDraw.bottom,
925             (int)(rcDraw.right - rcDraw.left), (int)(rcDraw.bottom - rcDraw.top));
926#endif
927
928    if (EqualRect(&rcDraw, &rcWin)) {
929        /* Bail if no adjust is needed */
930#if CYGWINDOWING_DEBUG
931        ErrorF("\treturn because already adjusted\n");
932#endif
933        return 0;
934    }
935
936    /* Calculate delta values */
937    dX = rcWin.left - rcDraw.left;
938    dY = rcWin.top - rcDraw.top;
939    dW = WIDTH(rcWin) - WIDTH(rcDraw);
940    dH = HEIGHT(rcWin) - HEIGHT(rcDraw);
941
942    /*
943     * Adjust.
944     * We may only need to move (vlist[0] and [1]), or only resize
945     * ([2] and [3]) but currently we set all the parameters and leave
946     * the decision to ConfigureWindow.  The reason is code simplicity.
947     */
948    vlist[0] = pDraw->x + dX - wBorderWidth(pWin);
949    vlist[1] = pDraw->y + dY - wBorderWidth(pWin);
950    vlist[2] = pDraw->width + dW;
951    vlist[3] = pDraw->height + dH;
952#if CYGWINDOWING_DEBUG
953    ErrorF("\tConfigureWindow to (%u, %u) - %ux%u\n",
954           (unsigned int)vlist[0], (unsigned int)vlist[1],
955           (unsigned int)vlist[2], (unsigned int)vlist[3]);
956#endif
957    return ConfigureWindow(pWin, CWX | CWY | CWWidth | CWHeight,
958                           vlist, wClient(pWin));
959
960#undef WIDTH
961#undef HEIGHT
962}
963
964/*
965  Helper function for creating a DIB to back a pixmap
966 */
967static HBITMAP winCreateDIB(ScreenPtr pScreen, int width, int height, int bpp, void **ppvBits, BITMAPINFOHEADER **ppbmih)
968{
969    winScreenPriv(pScreen);
970    BITMAPV4HEADER *pbmih = NULL;
971    HBITMAP hBitmap = NULL;
972
973    /* Allocate bitmap info header */
974    pbmih = malloc(sizeof(BITMAPV4HEADER) + 256 * sizeof(RGBQUAD));
975    if (pbmih == NULL) {
976        ErrorF("winCreateDIB: malloc() failed\n");
977        return NULL;
978    }
979    memset(pbmih, 0, sizeof(BITMAPV4HEADER) + 256 * sizeof(RGBQUAD));
980
981    /* Describe bitmap to be created */
982    pbmih->bV4Size = sizeof(BITMAPV4HEADER);
983    pbmih->bV4Width = width;
984    pbmih->bV4Height = -height;  /* top-down bitmap */
985    pbmih->bV4Planes = 1;
986    pbmih->bV4BitCount = bpp;
987    if (bpp == 1) {
988        RGBQUAD *bmiColors = (RGBQUAD *)((char *)pbmih + sizeof(BITMAPV4HEADER));
989        pbmih->bV4V4Compression = BI_RGB;
990        bmiColors[1].rgbBlue = 255;
991        bmiColors[1].rgbGreen = 255;
992        bmiColors[1].rgbRed = 255;
993    }
994    else if (bpp == 8) {
995        pbmih->bV4V4Compression = BI_RGB;
996        pbmih->bV4ClrUsed = 0;
997    }
998    else if (bpp == 16) {
999        pbmih->bV4V4Compression = BI_RGB;
1000        pbmih->bV4ClrUsed = 0;
1001    }
1002    else if (bpp == 32) {
1003        pbmih->bV4V4Compression = BI_BITFIELDS;
1004        pbmih->bV4RedMask = pScreenPriv->dwRedMask;
1005        pbmih->bV4GreenMask = pScreenPriv->dwGreenMask;
1006        pbmih->bV4BlueMask = pScreenPriv->dwBlueMask;
1007        pbmih->bV4AlphaMask = 0;
1008    }
1009    else {
1010        ErrorF("winCreateDIB: %d bpp unhandled\n", bpp);
1011    }
1012
1013    /* Create a DIB with a bit pointer */
1014    hBitmap = CreateDIBSection(NULL,
1015                               (BITMAPINFO *) pbmih,
1016                               DIB_RGB_COLORS, ppvBits, NULL, 0);
1017    if (hBitmap == NULL) {
1018        ErrorF("winCreateDIB: CreateDIBSection() failed\n");
1019        return NULL;
1020    }
1021
1022    /* Store the address of the BMIH in the ppbmih parameter */
1023    *ppbmih = (BITMAPINFOHEADER *)pbmih;
1024
1025    winDebug("winCreateDIB: HBITMAP %p pBMIH %p pBits %p\n", hBitmap, pbmih, *ppvBits);
1026
1027    return hBitmap;
1028}
1029
1030
1031/*
1032 * CreatePixmap - See Porting Layer Definition
1033 */
1034PixmapPtr
1035winCreatePixmapMultiwindow(ScreenPtr pScreen, int width, int height, int depth,
1036                           unsigned usage_hint)
1037{
1038    winPrivPixmapPtr pPixmapPriv = NULL;
1039    PixmapPtr pPixmap = NULL;
1040    int bpp, paddedwidth;
1041
1042    /* allocate Pixmap header and privates */
1043    pPixmap = AllocatePixmap(pScreen, 0);
1044    if (!pPixmap)
1045        return NullPixmap;
1046
1047    bpp = BitsPerPixel(depth);
1048    /*
1049      DIBs have 4-byte aligned rows
1050
1051      paddedwidth is the width in bytes, padded to align
1052
1053      i.e. round up the number of bits used by a row so it is a multiple of 32,
1054      then convert to bytes
1055    */
1056    paddedwidth = (((bpp * width) + 31) & ~31)/8;
1057
1058    /* setup Pixmap header */
1059    pPixmap->drawable.type = DRAWABLE_PIXMAP;
1060    pPixmap->drawable.class = 0;
1061    pPixmap->drawable.pScreen = pScreen;
1062    pPixmap->drawable.depth = depth;
1063    pPixmap->drawable.bitsPerPixel = bpp;
1064    pPixmap->drawable.id = 0;
1065    pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
1066    pPixmap->drawable.x = 0;
1067    pPixmap->drawable.y = 0;
1068    pPixmap->drawable.width = width;
1069    pPixmap->drawable.height = height;
1070    pPixmap->devKind = paddedwidth;
1071    pPixmap->refcnt = 1;
1072    pPixmap->devPrivate.ptr = NULL; // later set to pbBits
1073    pPixmap->primary_pixmap = NULL;
1074#ifdef COMPOSITE
1075    pPixmap->screen_x = 0;
1076    pPixmap->screen_y = 0;
1077#endif
1078    pPixmap->usage_hint = usage_hint;
1079
1080    /* Check for zero width or height pixmaps */
1081    if (width == 0 || height == 0) {
1082        /* DIBs with a dimension of 0 aren't permitted, so don't try to allocate
1083           a DIB, just set fields and return */
1084        return pPixmap;
1085    }
1086
1087    /* Initialize pixmap privates */
1088    pPixmapPriv = winGetPixmapPriv(pPixmap);
1089    pPixmapPriv->hBitmap = NULL;
1090    pPixmapPriv->pbBits = NULL;
1091    pPixmapPriv->pbmih = NULL;
1092
1093    /* Create a DIB for the pixmap */
1094    pPixmapPriv->hBitmap = winCreateDIB(pScreen, width, height, bpp, &pPixmapPriv->pbBits, &pPixmapPriv->pbmih);
1095    pPixmapPriv->owned = TRUE;
1096
1097    winDebug("winCreatePixmap: pPixmap %p HBITMAP %p pBMIH %p pBits %p\n", pPixmap, pPixmapPriv->hBitmap, pPixmapPriv->pbmih, pPixmapPriv->pbBits);
1098    /* XXX: so why do we need this in privates ??? */
1099    pPixmap->devPrivate.ptr = pPixmapPriv->pbBits;
1100
1101    return pPixmap;
1102}
1103
1104/*
1105 * DestroyPixmap - See Porting Layer Definition
1106 */
1107Bool
1108winDestroyPixmapMultiwindow(PixmapPtr pPixmap)
1109{
1110    winPrivPixmapPtr pPixmapPriv = NULL;
1111
1112    /* Bail early if there is not a pixmap to destroy */
1113    if (pPixmap == NULL) {
1114        return TRUE;
1115    }
1116
1117    /* Decrement reference count, return if nonzero */
1118    --pPixmap->refcnt;
1119    if (pPixmap->refcnt != 0)
1120        return TRUE;
1121
1122    winDebug("winDestroyPixmap: pPixmap %p\n", pPixmap);
1123
1124    /* Get a handle to the pixmap privates */
1125    pPixmapPriv = winGetPixmapPriv(pPixmap);
1126
1127    /* Nothing to do if we don't own the DIB */
1128    if (!pPixmapPriv->owned)
1129        return TRUE;
1130
1131    /* Free GDI bitmap */
1132    if (pPixmapPriv->hBitmap)
1133        DeleteObject(pPixmapPriv->hBitmap);
1134
1135    /* Free the bitmap info header memory */
1136    free(pPixmapPriv->pbmih);
1137    pPixmapPriv->pbmih = NULL;
1138
1139    /* Free the pixmap memory */
1140    free(pPixmap);
1141    pPixmap = NULL;
1142
1143    return TRUE;
1144}
1145
1146/*
1147 * ModifyPixmapHeader - See Porting Layer Definition
1148 */
1149Bool
1150winModifyPixmapHeaderMultiwindow(PixmapPtr pPixmap,
1151                                 int width,
1152                                 int height,
1153                                 int depth,
1154                                 int bitsPerPixel, int devKind, void *pPixData)
1155{
1156    int i;
1157    winPrivPixmapPtr pPixmapPriv = winGetPixmapPriv(pPixmap);
1158    Bool fResult;
1159
1160    /* reinitialize everything */
1161    pPixmap->drawable.depth = depth;
1162    pPixmap->drawable.bitsPerPixel = bitsPerPixel;
1163    pPixmap->drawable.id = 0;
1164    pPixmap->drawable.x = 0;
1165    pPixmap->drawable.y = 0;
1166    pPixmap->drawable.width = width;
1167    pPixmap->drawable.height = height;
1168    pPixmap->devKind = devKind;
1169    pPixmap->refcnt = 1;
1170    pPixmap->devPrivate.ptr = pPixData;
1171    pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
1172
1173    /*
1174      This can be used for some out-of-order initialization on the screen
1175      pixmap, which is the only case we can properly support.
1176    */
1177
1178    /* Look for which screen this pixmap corresponds to */
1179    for (i = 0; i < screenInfo.numScreens; i++) {
1180        ScreenPtr pScreen = screenInfo.screens[i];
1181        winScreenPriv(pScreen);
1182        winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo;
1183
1184        if (pScreenInfo->pfb == pPixData)
1185            {
1186                /* and initialize pixmap privates from screen privates */
1187                pPixmapPriv->hBitmap = pScreenPriv->hbmpShadow;
1188                pPixmapPriv->pbBits = pScreenInfo->pfb;
1189                pPixmapPriv->pbmih = pScreenPriv->pbmih;
1190
1191                /* mark these not to get released by DestroyPixmap */
1192                pPixmapPriv->owned = FALSE;
1193
1194                return TRUE;
1195            }
1196    }
1197
1198    /* Otherwise, since creating a DIBSection from arbitrary memory is not
1199     * possible, fallback to normal.  If needed, we can create a DIBSection with
1200     * a copy of the bits later (see comment about a potential slow-path in
1201     * winBltExposedWindowRegionShadowGDI()). */
1202    pPixmapPriv->hBitmap = 0;
1203    pPixmapPriv->pbBits = 0;
1204    pPixmapPriv->pbmih = 0;
1205    pPixmapPriv->owned = FALSE;
1206
1207    winDebug("winModifyPixmapHeaderMultiwindow: falling back\n");
1208
1209    {
1210        ScreenPtr pScreen = pPixmap->drawable.pScreen;
1211        winScreenPriv(pScreen);
1212        WIN_UNWRAP(ModifyPixmapHeader);
1213        fResult = (*pScreen->ModifyPixmapHeader) (pPixmap, width, height, depth, bitsPerPixel, devKind, pPixData);
1214        WIN_WRAP(ModifyPixmapHeader, winModifyPixmapHeaderMultiwindow);
1215    }
1216
1217    return fResult;
1218}
1219