4 * Copyright 1998,1999 Patrik Stridvall
14 #include "debugtools.h"
16 DEFAULT_DEBUG_CHANNEL(ttydrv
);
18 #define SWP_AGG_NOGEOMETRYCHANGE \
19 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
20 #define SWP_AGG_NOPOSCHANGE \
21 (SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
22 #define SWP_AGG_STATUSFLAGS \
23 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
25 /**********************************************************************
26 * CreateWindow (TTYDRV.@)
28 BOOL
TTYDRV_CreateWindow( HWND hwnd
, CREATESTRUCTA
*cs
, BOOL unicode
)
33 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
35 INT cellWidth
=8, cellHeight
=8; /* FIXME: Hardcoded */
37 TRACE("(%x)\n", hwnd
);
39 /* Only create top-level windows */
40 if (!(wndPtr
->dwStyle
& WS_CHILD
))
42 if (!wndPtr
->parent
) /* desktop */
46 int x
= wndPtr
->rectWindow
.left
;
47 int y
= wndPtr
->rectWindow
.top
;
48 int cx
= wndPtr
->rectWindow
.right
- wndPtr
->rectWindow
.left
;
49 int cy
= wndPtr
->rectWindow
.bottom
- wndPtr
->rectWindow
.top
;
51 window
= subwin( root_window
, cy
/cellHeight
, cx
/cellWidth
,
52 y
/cellHeight
, x
/cellWidth
);
56 wndPtr
->pDriverData
= window
;
58 WIN_ReleaseWndPtr( wndPtr
);
59 #else /* defined(WINE_CURSES) */
60 FIXME("(%x): stub\n", hwnd
);
61 #endif /* defined(WINE_CURSES) */
65 ret
= SendMessageW( hwnd
, WM_NCCREATE
, 0, (LPARAM
)cs
);
66 if (ret
) ret
= (SendMessageW( hwnd
, WM_CREATE
, 0, (LPARAM
)cs
) != -1);
70 ret
= SendMessageA( hwnd
, WM_NCCREATE
, 0, (LPARAM
)cs
);
71 if (ret
) ret
= (SendMessageA( hwnd
, WM_CREATE
, 0, (LPARAM
)cs
) != -1);
76 /***********************************************************************
77 * DestroyWindow (TTYDRV.@)
79 BOOL
TTYDRV_DestroyWindow( HWND hwnd
)
82 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
83 WINDOW
*window
= wndPtr
->pDriverData
;
85 TRACE("(%x)\n", hwnd
);
87 if (window
&& window
!= root_window
) delwin(window
);
88 wndPtr
->pDriverData
= NULL
;
89 WIN_ReleaseWndPtr( wndPtr
);
90 #else /* defined(WINE_CURSES) */
91 FIXME("(%x): stub\n", hwnd
);
92 #endif /* defined(WINE_CURSES) */
97 /***********************************************************************
100 * Change region from DC-origin relative coordinates to screen coords.
103 static void DCE_OffsetVisRgn( HDC hDC
, HRGN hVisRgn
)
106 if (!(dc
= DC_GetDCPtr( hDC
))) return;
108 OffsetRgn( hVisRgn
, dc
->DCOrgX
, dc
->DCOrgY
);
110 GDI_ReleaseObj( hDC
);
114 /***********************************************************************
117 * Calculate the visible rectangle of a window (i.e. the client or
118 * window area clipped by the client area of all ancestors) in the
119 * corresponding coordinates. Return FALSE if the visible region is empty.
121 static BOOL
DCE_GetVisRect( WND
*wndPtr
, BOOL clientArea
, RECT
*lprect
)
123 *lprect
= clientArea
? wndPtr
->rectClient
: wndPtr
->rectWindow
;
125 if (wndPtr
->dwStyle
& WS_VISIBLE
)
127 INT xoffset
= lprect
->left
;
128 INT yoffset
= lprect
->top
;
130 while ((wndPtr
= WIN_LockWndPtr(wndPtr
->parent
)))
132 if ( (wndPtr
->dwStyle
& (WS_ICONIC
| WS_VISIBLE
)) != WS_VISIBLE
)
134 WIN_ReleaseWndPtr(wndPtr
);
138 xoffset
+= wndPtr
->rectClient
.left
;
139 yoffset
+= wndPtr
->rectClient
.top
;
140 OffsetRect( lprect
, wndPtr
->rectClient
.left
,
141 wndPtr
->rectClient
.top
);
143 if( (wndPtr
->rectClient
.left
>= wndPtr
->rectClient
.right
) ||
144 (wndPtr
->rectClient
.top
>= wndPtr
->rectClient
.bottom
) ||
145 (lprect
->left
>= wndPtr
->rectClient
.right
) ||
146 (lprect
->right
<= wndPtr
->rectClient
.left
) ||
147 (lprect
->top
>= wndPtr
->rectClient
.bottom
) ||
148 (lprect
->bottom
<= wndPtr
->rectClient
.top
) )
150 WIN_ReleaseWndPtr(wndPtr
);
154 lprect
->left
= max( lprect
->left
, wndPtr
->rectClient
.left
);
155 lprect
->right
= min( lprect
->right
, wndPtr
->rectClient
.right
);
156 lprect
->top
= max( lprect
->top
, wndPtr
->rectClient
.top
);
157 lprect
->bottom
= min( lprect
->bottom
, wndPtr
->rectClient
.bottom
);
159 WIN_ReleaseWndPtr(wndPtr
);
161 OffsetRect( lprect
, -xoffset
, -yoffset
);
166 SetRectEmpty( lprect
);
171 /***********************************************************************
174 * Go through the linked list of windows from pWndStart to pWndEnd,
175 * adding to the clip region the intersection of the target rectangle
176 * with an offset window rectangle.
178 static BOOL
DCE_AddClipRects( WND
*pWndStart
, WND
*pWndEnd
,
179 HRGN hrgnClip
, LPRECT lpRect
, int x
, int y
)
183 for (WIN_LockWndPtr(pWndStart
); (pWndStart
&& (pWndStart
!= pWndEnd
)); WIN_UpdateWndPtr(&pWndStart
,pWndStart
->next
))
185 if( !(pWndStart
->dwStyle
& WS_VISIBLE
) ) continue;
187 rect
.left
= pWndStart
->rectWindow
.left
+ x
;
188 rect
.top
= pWndStart
->rectWindow
.top
+ y
;
189 rect
.right
= pWndStart
->rectWindow
.right
+ x
;
190 rect
.bottom
= pWndStart
->rectWindow
.bottom
+ y
;
192 if( IntersectRect( &rect
, &rect
, lpRect
))
194 if(!REGION_UnionRectWithRgn( hrgnClip
, &rect
)) break;
197 WIN_ReleaseWndPtr(pWndStart
);
198 return (pWndStart
== pWndEnd
);
202 /***********************************************************************
205 * Return the visible region of a window, i.e. the client or window area
206 * clipped by the client area of all ancestors, and then optionally
207 * by siblings and children.
209 static HRGN
DCE_GetVisRgn( HWND hwnd
, WORD flags
, HWND hwndChild
, WORD cflags
)
213 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
214 WND
*childWnd
= WIN_FindWndPtr( hwndChild
);
216 /* Get visible rectangle and create a region with it. */
218 if (wndPtr
&& DCE_GetVisRect(wndPtr
, !(flags
& DCX_WINDOW
), &rect
))
220 if((hrgnVis
= CreateRectRgnIndirect( &rect
)))
222 HRGN hrgnClip
= CreateRectRgn( 0, 0, 0, 0 );
223 INT xoffset
, yoffset
;
227 /* Compute obscured region for the visible rectangle by
228 * clipping children, siblings, and ancestors. Note that
229 * DCE_GetVisRect() returns a rectangle either in client
230 * or in window coordinates (for DCX_WINDOW request). */
232 if( (flags
& DCX_CLIPCHILDREN
) && wndPtr
->child
)
234 if( flags
& DCX_WINDOW
)
236 /* adjust offsets since child window rectangles are
237 * in client coordinates */
239 xoffset
= wndPtr
->rectClient
.left
- wndPtr
->rectWindow
.left
;
240 yoffset
= wndPtr
->rectClient
.top
- wndPtr
->rectWindow
.top
;
243 xoffset
= yoffset
= 0;
245 DCE_AddClipRects( wndPtr
->child
, NULL
, hrgnClip
, &rect
, xoffset
, yoffset
);
248 /* We may need to clip children of child window, if a window with PARENTDC
249 * class style and CLIPCHILDREN window style (like in Free Agent 16
250 * preference dialogs) gets here, we take the region for the parent window
251 * but apparently still need to clip the children of the child window... */
253 if( (cflags
& DCX_CLIPCHILDREN
) && childWnd
&& childWnd
->child
)
255 if( flags
& DCX_WINDOW
)
257 /* adjust offsets since child window rectangles are
258 * in client coordinates */
260 xoffset
= wndPtr
->rectClient
.left
- wndPtr
->rectWindow
.left
;
261 yoffset
= wndPtr
->rectClient
.top
- wndPtr
->rectWindow
.top
;
264 xoffset
= yoffset
= 0;
266 /* client coordinates of child window */
267 xoffset
+= childWnd
->rectClient
.left
;
268 yoffset
+= childWnd
->rectClient
.top
;
270 DCE_AddClipRects( childWnd
->child
, NULL
, hrgnClip
,
271 &rect
, xoffset
, yoffset
);
274 /* sibling window rectangles are in client
275 * coordinates of the parent window */
277 if (flags
& DCX_WINDOW
)
279 xoffset
= -wndPtr
->rectWindow
.left
;
280 yoffset
= -wndPtr
->rectWindow
.top
;
284 xoffset
= -wndPtr
->rectClient
.left
;
285 yoffset
= -wndPtr
->rectClient
.top
;
288 if (flags
& DCX_CLIPSIBLINGS
&& wndPtr
->parent
)
289 DCE_AddClipRects( wndPtr
->parent
->child
,
290 wndPtr
, hrgnClip
, &rect
, xoffset
, yoffset
);
292 /* Clip siblings of all ancestors that have the
293 * WS_CLIPSIBLINGS style
296 while (wndPtr
->parent
)
298 WIN_UpdateWndPtr(&wndPtr
,wndPtr
->parent
);
299 xoffset
-= wndPtr
->rectClient
.left
;
300 yoffset
-= wndPtr
->rectClient
.top
;
301 if(wndPtr
->dwStyle
& WS_CLIPSIBLINGS
&& wndPtr
->parent
)
303 DCE_AddClipRects( wndPtr
->parent
->child
, wndPtr
,
304 hrgnClip
, &rect
, xoffset
, yoffset
);
308 /* Now once we've got a jumbo clip region we have
309 * to substract it from the visible rectangle.
311 CombineRgn( hrgnVis
, hrgnVis
, hrgnClip
, RGN_DIFF
);
312 DeleteObject( hrgnClip
);
316 DeleteObject( hrgnVis
);
322 hrgnVis
= CreateRectRgn(0, 0, 0, 0); /* empty */
323 WIN_ReleaseWndPtr(wndPtr
);
324 WIN_ReleaseWndPtr(childWnd
);
329 /***********************************************************************
332 * Set the drawable, origin and dimensions for the DC associated to
335 BOOL
TTYDRV_GetDC( HWND hwnd
, HDC hdc
, HRGN hrgn
, DWORD flags
)
337 WND
*wndPtr
= WIN_FindWndPtr(hwnd
);
340 HRGN hrgnVisible
= 0;
342 if (!wndPtr
) return FALSE
;
344 if (!(dc
= DC_GetDCPtr( hdc
)))
346 WIN_ReleaseWndPtr( wndPtr
);
350 if(flags
& DCX_WINDOW
)
352 dc
->DCOrgX
= wndPtr
->rectWindow
.left
;
353 dc
->DCOrgY
= wndPtr
->rectWindow
.top
;
357 dc
->DCOrgX
= wndPtr
->rectClient
.left
;
358 dc
->DCOrgY
= wndPtr
->rectClient
.top
;
360 updateVisRgn
= (dc
->flags
& DC_DIRTY
) != 0;
361 GDI_ReleaseObj( hdc
);
365 if (flags
& DCX_PARENTCLIP
)
367 WND
*parentPtr
= WIN_LockWndPtr(wndPtr
->parent
);
369 if( wndPtr
->dwStyle
& WS_VISIBLE
&& !(parentPtr
->dwStyle
& WS_MINIMIZE
) )
373 if( parentPtr
->dwStyle
& WS_CLIPSIBLINGS
)
374 dcxFlags
= DCX_CLIPSIBLINGS
| (flags
& ~(DCX_CLIPCHILDREN
| DCX_WINDOW
));
376 dcxFlags
= flags
& ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
| DCX_WINDOW
);
378 hrgnVisible
= DCE_GetVisRgn( parentPtr
->hwndSelf
, dcxFlags
,
379 wndPtr
->hwndSelf
, flags
);
380 if( flags
& DCX_WINDOW
)
381 OffsetRgn( hrgnVisible
, -wndPtr
->rectWindow
.left
,
382 -wndPtr
->rectWindow
.top
);
384 OffsetRgn( hrgnVisible
, -wndPtr
->rectClient
.left
,
385 -wndPtr
->rectClient
.top
);
386 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
389 hrgnVisible
= CreateRectRgn( 0, 0, 0, 0 );
390 WIN_ReleaseWndPtr(parentPtr
);
394 hrgnVisible
= DCE_GetVisRgn( hwnd
, flags
, 0, 0 );
395 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
397 SelectVisRgn16( hdc
, hrgnVisible
);
400 /* apply additional region operation (if any) */
402 if( flags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
) )
404 if( !hrgnVisible
) hrgnVisible
= CreateRectRgn( 0, 0, 0, 0 );
406 TRACE("\tsaved VisRgn, clipRgn = %04x\n", hrgn
);
409 CombineRgn( hrgnVisible
, hrgn
, 0, RGN_COPY
);
410 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
411 CombineRgn( hrgnVisible
, InquireVisRgn16( hdc
), hrgnVisible
,
412 (flags
& DCX_INTERSECTRGN
) ? RGN_AND
: RGN_DIFF
);
413 SelectVisRgn16( hdc
, hrgnVisible
);
416 if (hrgnVisible
) DeleteObject( hrgnVisible
);
418 WIN_ReleaseWndPtr( wndPtr
);
423 /***********************************************************************
424 * SetWindowPos (TTYDRV.@)
426 BOOL
TTYDRV_SetWindowPos( WINDOWPOS
*winpos
)
429 RECT newWindowRect
, newClientRect
;
431 HWND hwndActive
= GetForegroundWindow();
433 TRACE( "hwnd %04x, swp (%i,%i)-(%i,%i) flags %08x\n",
434 winpos
->hwnd
, winpos
->x
, winpos
->y
,
435 winpos
->x
+ winpos
->cx
, winpos
->y
+ winpos
->cy
, winpos
->flags
);
437 /* ------------------------------------------------------------------------ CHECKS */
439 /* Check window handle */
441 if (winpos
->hwnd
== GetDesktopWindow()) return FALSE
;
442 if (!(wndPtr
= WIN_FindWndPtr( winpos
->hwnd
))) return FALSE
;
444 TRACE("\tcurrent (%i,%i)-(%i,%i), style %08x\n",
445 wndPtr
->rectWindow
.left
, wndPtr
->rectWindow
.top
,
446 wndPtr
->rectWindow
.right
, wndPtr
->rectWindow
.bottom
, (unsigned)wndPtr
->dwStyle
);
448 /* Fix redundant flags */
450 if(wndPtr
->dwStyle
& WS_VISIBLE
)
451 winpos
->flags
&= ~SWP_SHOWWINDOW
;
454 if (!(winpos
->flags
& SWP_SHOWWINDOW
)) winpos
->flags
|= SWP_NOREDRAW
;
455 winpos
->flags
&= ~SWP_HIDEWINDOW
;
458 if ( winpos
->cx
< 0 ) winpos
->cx
= 0;
459 if ( winpos
->cy
< 0 ) winpos
->cy
= 0;
461 if ((wndPtr
->rectWindow
.right
- wndPtr
->rectWindow
.left
== winpos
->cx
) &&
462 (wndPtr
->rectWindow
.bottom
- wndPtr
->rectWindow
.top
== winpos
->cy
))
463 winpos
->flags
|= SWP_NOSIZE
; /* Already the right size */
465 if ((wndPtr
->rectWindow
.left
== winpos
->x
) && (wndPtr
->rectWindow
.top
== winpos
->y
))
466 winpos
->flags
|= SWP_NOMOVE
; /* Already the right position */
468 if (winpos
->hwnd
== hwndActive
)
469 winpos
->flags
|= SWP_NOACTIVATE
; /* Already active */
470 else if ( (wndPtr
->dwStyle
& (WS_POPUP
| WS_CHILD
)) != WS_CHILD
)
472 if(!(winpos
->flags
& SWP_NOACTIVATE
)) /* Bring to the top when activating */
474 winpos
->flags
&= ~SWP_NOZORDER
;
475 winpos
->hwndInsertAfter
= HWND_TOP
;
480 /* Check hwndInsertAfter */
482 /* FIXME: TOPMOST not supported yet */
483 if ((winpos
->hwndInsertAfter
== HWND_TOPMOST
) ||
484 (winpos
->hwndInsertAfter
== HWND_NOTOPMOST
)) winpos
->hwndInsertAfter
= HWND_TOP
;
486 /* hwndInsertAfter must be a sibling of the window */
487 if ((winpos
->hwndInsertAfter
!= HWND_TOP
) && (winpos
->hwndInsertAfter
!= HWND_BOTTOM
))
489 WND
* wnd
= WIN_FindWndPtr(winpos
->hwndInsertAfter
);
492 if( wnd
->parent
!= wndPtr
->parent
)
495 WIN_ReleaseWndPtr(wnd
);
498 /* don't need to change the Zorder of hwnd if it's already inserted
499 * after hwndInsertAfter or when inserting hwnd after itself.
501 if(( wnd
->next
== wndPtr
) || (winpos
->hwnd
== winpos
->hwndInsertAfter
))
502 winpos
->flags
|= SWP_NOZORDER
;
504 WIN_ReleaseWndPtr(wnd
);
507 Pos
: /* ------------------------------------------------------------------------ MAIN part */
509 /* Send WM_WINDOWPOSCHANGING message */
511 if (!(winpos
->flags
& SWP_NOSENDCHANGING
))
512 SendMessageA( wndPtr
->hwndSelf
, WM_WINDOWPOSCHANGING
, 0, (LPARAM
)winpos
);
514 /* Calculate new position and size */
516 newWindowRect
= wndPtr
->rectWindow
;
517 newClientRect
= (wndPtr
->dwStyle
& WS_MINIMIZE
) ? wndPtr
->rectWindow
518 : wndPtr
->rectClient
;
520 if (!(winpos
->flags
& SWP_NOSIZE
))
522 newWindowRect
.right
= newWindowRect
.left
+ winpos
->cx
;
523 newWindowRect
.bottom
= newWindowRect
.top
+ winpos
->cy
;
525 if (!(winpos
->flags
& SWP_NOMOVE
))
527 newWindowRect
.left
= winpos
->x
;
528 newWindowRect
.top
= winpos
->y
;
529 newWindowRect
.right
+= winpos
->x
- wndPtr
->rectWindow
.left
;
530 newWindowRect
.bottom
+= winpos
->y
- wndPtr
->rectWindow
.top
;
532 OffsetRect( &newClientRect
, winpos
->x
- wndPtr
->rectWindow
.left
,
533 winpos
->y
- wndPtr
->rectWindow
.top
);
536 if( winpos
->hwndInsertAfter
== HWND_TOP
)
537 winpos
->flags
|= ( wndPtr
->parent
->child
== wndPtr
)? SWP_NOZORDER
: 0;
539 if( winpos
->hwndInsertAfter
== HWND_BOTTOM
)
540 winpos
->flags
|= ( wndPtr
->next
)? 0: SWP_NOZORDER
;
542 if( !(winpos
->flags
& SWP_NOZORDER
) )
543 if( GetWindow(winpos
->hwndInsertAfter
, GW_HWNDNEXT
) == wndPtr
->hwndSelf
)
544 winpos
->flags
|= SWP_NOZORDER
;
546 /* Common operations */
548 /* Send WM_NCCALCSIZE message to get new client area */
549 if( (winpos
->flags
& (SWP_FRAMECHANGED
| SWP_NOSIZE
)) != SWP_NOSIZE
)
551 WINPOS_SendNCCalcSize( winpos
->hwnd
, TRUE
, &newWindowRect
,
552 &wndPtr
->rectWindow
, &wndPtr
->rectClient
,
553 winpos
, &newClientRect
);
556 if(!(winpos
->flags
& SWP_NOZORDER
) && winpos
->hwnd
!= winpos
->hwndInsertAfter
)
558 if ( WIN_UnlinkWindow( winpos
->hwnd
) )
559 WIN_LinkWindow( winpos
->hwnd
, winpos
->hwndInsertAfter
);
562 /* FIXME: actually do something with WVR_VALIDRECTS */
564 wndPtr
->rectWindow
= newWindowRect
;
565 wndPtr
->rectClient
= newClientRect
;
567 if( winpos
->flags
& SWP_SHOWWINDOW
)
569 wndPtr
->dwStyle
|= WS_VISIBLE
;
571 else if( winpos
->flags
& SWP_HIDEWINDOW
)
573 wndPtr
->dwStyle
&= ~WS_VISIBLE
;
576 /* ------------------------------------------------------------------------ FINAL */
578 /* repaint invalidated region (if any)
580 * FIXME: if SWP_NOACTIVATE is not set then set invalid regions here without any painting
581 * and force update after ChangeActiveWindow() to avoid painting frames twice.
584 if( !(winpos
->flags
& SWP_NOREDRAW
) )
586 RedrawWindow( wndPtr
->parent
->hwndSelf
, NULL
, 0,
587 RDW_ERASE
| RDW_INVALIDATE
| RDW_ALLCHILDREN
);
588 if (wndPtr
->parent
->hwndSelf
== GetDesktopWindow() ||
589 wndPtr
->parent
->parent
->hwndSelf
== GetDesktopWindow())
591 RedrawWindow( wndPtr
->parent
->hwndSelf
, NULL
, 0,
592 RDW_ERASENOW
| RDW_NOCHILDREN
);
596 if (!(winpos
->flags
& SWP_NOACTIVATE
))
597 WINPOS_ChangeActiveWindow( winpos
->hwnd
, FALSE
);
599 /* And last, send the WM_WINDOWPOSCHANGED message */
601 TRACE("\tstatus flags = %04x\n", winpos
->flags
& SWP_AGG_STATUSFLAGS
);
603 if ((((winpos
->flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOPOSCHANGE
) &&
604 !(winpos
->flags
& SWP_NOSENDCHANGING
)) )
605 SendMessageA( winpos
->hwnd
, WM_WINDOWPOSCHANGED
, 0, (LPARAM
)winpos
);
609 WIN_ReleaseWndPtr(wndPtr
);