2 * Default window procedure
4 * Copyright 1993, 1996 Alexandre Julliard
5 * Copyright 1995 Alex Korobka
6 * Copyright 2022 Jacek Caban for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "ntgdi_private.h"
28 #include "ntuser_private.h"
29 #include "wine/server.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(win
);
34 #define DRAG_FILE 0x454c4946
36 /* bits in the dwKeyData */
37 #define KEYDATA_ALT 0x2000
38 #define KEYDATA_PREVSTATE 0x4000
40 static short f10_key
= 0;
41 static short menu_sys_key
= 0;
43 static BOOL
has_dialog_frame( UINT style
, UINT ex_style
)
45 return (ex_style
& WS_EX_DLGMODALFRAME
) || ((style
& WS_DLGFRAME
) && !(style
& WS_THICKFRAME
));
48 static BOOL
has_thick_frame( UINT style
, UINT ex_style
)
50 return (style
& WS_THICKFRAME
) && (style
& (WS_DLGFRAME
|WS_BORDER
)) != WS_DLGFRAME
;
53 static BOOL
has_thin_frame( UINT style
)
55 return (style
& WS_BORDER
) || !(style
& (WS_CHILD
| WS_POPUP
));
58 static BOOL
has_big_frame( UINT style
, UINT ex_style
)
60 return (style
& (WS_THICKFRAME
| WS_DLGFRAME
)) || (ex_style
& WS_EX_DLGMODALFRAME
);
63 static BOOL
has_static_outer_frame( UINT ex_style
)
65 return (ex_style
& (WS_EX_STATICEDGE
|WS_EX_DLGMODALFRAME
)) == WS_EX_STATICEDGE
;
68 static BOOL
has_menu( HWND hwnd
, UINT style
)
70 return (style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
&& get_menu( hwnd
);
73 void fill_rect( HDC dc
, const RECT
*rect
, HBRUSH hbrush
)
77 if (hbrush
<= (HBRUSH
)(COLOR_MENUBAR
+ 1)) hbrush
= get_sys_color_brush( HandleToULong(hbrush
) - 1 );
79 prev_brush
= NtGdiSelectBrush( dc
, hbrush
);
80 NtGdiPatBlt( dc
, rect
->left
, rect
->top
, rect
->right
- rect
->left
, rect
->bottom
- rect
->top
, PATCOPY
);
81 if (prev_brush
) NtGdiSelectBrush( dc
, prev_brush
);
84 /* see DrawFocusRect */
85 static BOOL
draw_focus_rect( HDC hdc
, const RECT
*rc
)
87 DWORD prev_draw_mode
, prev_bk_mode
;
91 prev_brush
= NtGdiSelectBrush(hdc
, GetStockObject(NULL_BRUSH
));
92 pen
= NtGdiExtCreatePen( PS_COSMETIC
|PS_ALTERNATE
, 1, BS_SOLID
,
93 0, 0, 0, 0, NULL
, 0, FALSE
, NULL
);
94 prev_pen
= NtGdiSelectPen(hdc
, pen
);
95 NtGdiGetAndSetDCDword( hdc
, NtGdiSetROP2
, R2_NOT
, &prev_draw_mode
);
96 NtGdiGetAndSetDCDword( hdc
, NtGdiSetBkMode
, TRANSPARENT
, &prev_bk_mode
);
98 NtGdiRectangle( hdc
, rc
->left
, rc
->top
, rc
->right
, rc
->bottom
);
100 NtGdiGetAndSetDCDword( hdc
, NtGdiSetBkMode
, prev_bk_mode
, NULL
);
101 NtGdiGetAndSetDCDword( hdc
, NtGdiSetROP2
, prev_draw_mode
, NULL
);
102 NtGdiSelectPen( hdc
, prev_pen
);
103 NtGdiDeleteObjectApp( pen
);
104 NtGdiSelectBrush( hdc
, prev_brush
);
108 static const signed char lt_inner_normal
[] = {
110 -1, COLOR_BTNHIGHLIGHT
, COLOR_BTNHIGHLIGHT
, -1,
111 -1, COLOR_3DDKSHADOW
, COLOR_3DDKSHADOW
, -1,
115 static const signed char lt_outer_normal
[] = {
116 -1, COLOR_3DLIGHT
, COLOR_BTNSHADOW
, -1,
117 COLOR_BTNHIGHLIGHT
, COLOR_3DLIGHT
, COLOR_BTNSHADOW
, -1,
118 COLOR_3DDKSHADOW
, COLOR_3DLIGHT
, COLOR_BTNSHADOW
, -1,
119 -1, COLOR_3DLIGHT
, COLOR_BTNSHADOW
, -1
122 static const signed char rb_inner_normal
[] = {
124 -1, COLOR_BTNSHADOW
, COLOR_BTNSHADOW
, -1,
125 -1, COLOR_3DLIGHT
, COLOR_3DLIGHT
, -1,
129 static const signed char rb_outer_normal
[] = {
130 -1, COLOR_3DDKSHADOW
, COLOR_BTNHIGHLIGHT
, -1,
131 COLOR_BTNSHADOW
, COLOR_3DDKSHADOW
, COLOR_BTNHIGHLIGHT
, -1,
132 COLOR_3DLIGHT
, COLOR_3DDKSHADOW
, COLOR_BTNHIGHLIGHT
, -1,
133 -1, COLOR_3DDKSHADOW
, COLOR_BTNHIGHLIGHT
, -1
136 static const signed char ltrb_outer_mono
[] = {
137 -1, COLOR_WINDOWFRAME
, COLOR_WINDOWFRAME
, COLOR_WINDOWFRAME
,
138 COLOR_WINDOW
, COLOR_WINDOWFRAME
, COLOR_WINDOWFRAME
, COLOR_WINDOWFRAME
,
139 COLOR_WINDOW
, COLOR_WINDOWFRAME
, COLOR_WINDOWFRAME
, COLOR_WINDOWFRAME
,
140 COLOR_WINDOW
, COLOR_WINDOWFRAME
, COLOR_WINDOWFRAME
, COLOR_WINDOWFRAME
,
143 static const signed char ltrb_inner_mono
[] = {
145 -1, COLOR_WINDOW
, COLOR_WINDOW
, COLOR_WINDOW
,
146 -1, COLOR_WINDOW
, COLOR_WINDOW
, COLOR_WINDOW
,
147 -1, COLOR_WINDOW
, COLOR_WINDOW
, COLOR_WINDOW
,
150 BOOL
draw_rect_edge( HDC hdc
, RECT
*rc
, UINT type
, UINT flags
, UINT width
)
152 int lbi_offset
= 0, lti_offset
= 0, rti_offset
= 0, rbi_offset
= 0;
153 signed char lt_inner
, lt_outer
, rb_inner
, rb_outer
;
154 HBRUSH lti_brush
, lto_brush
, rbi_brush
, rbo_brush
;
155 RECT inner_rect
= *rc
, rect
;
158 retval
= !((type
& BDR_INNER
) == BDR_INNER
|| (type
& BDR_OUTER
) == BDR_OUTER
) &&
159 !(flags
& (BF_FLAT
|BF_MONO
));
161 lti_brush
= lto_brush
= rbi_brush
= rbo_brush
= GetStockObject( NULL_BRUSH
);
163 /* Determine the colors of the edges */
164 lt_inner
= lt_inner_normal
[type
& (BDR_INNER
|BDR_OUTER
)];
165 lt_outer
= lt_outer_normal
[type
& (BDR_INNER
|BDR_OUTER
)];
166 rb_inner
= rb_inner_normal
[type
& (BDR_INNER
|BDR_OUTER
)];
167 rb_outer
= rb_outer_normal
[type
& (BDR_INNER
|BDR_OUTER
)];
169 if ((flags
& BF_BOTTOMLEFT
) == BF_BOTTOMLEFT
) lbi_offset
= width
;
170 if ((flags
& BF_TOPRIGHT
) == BF_TOPRIGHT
) rti_offset
= width
;
171 if ((flags
& BF_BOTTOMRIGHT
) == BF_BOTTOMRIGHT
) rbi_offset
= width
;
172 if ((flags
& BF_TOPLEFT
) == BF_TOPLEFT
) lti_offset
= width
;
174 if (lt_inner
!= -1) lti_brush
= get_sys_color_brush( lt_inner
);
175 if (lt_outer
!= -1) lto_brush
= get_sys_color_brush( lt_outer
);
176 if (rb_inner
!= -1) rbi_brush
= get_sys_color_brush( rb_inner
);
177 if (rb_outer
!= -1) rbo_brush
= get_sys_color_brush( rb_outer
);
179 /* Draw the outer edge */
183 rect
.bottom
= rect
.top
+ width
;
184 fill_rect( hdc
, &rect
, lto_brush
);
189 rect
.right
= rect
.left
+ width
;
190 fill_rect( hdc
, &rect
, lto_brush
);
192 if (flags
& BF_BOTTOM
)
195 rect
.top
= rect
.bottom
- width
;
196 fill_rect( hdc
, &rect
, rbo_brush
);
198 if (flags
& BF_RIGHT
)
201 rect
.left
= rect
.right
- width
;
202 fill_rect( hdc
, &rect
, rbo_brush
);
205 /* Draw the inner edge */
208 SetRect( &rect
, inner_rect
.left
+ lti_offset
, inner_rect
.top
+ width
,
209 inner_rect
.right
- rti_offset
, inner_rect
.top
+ 2 * width
);
210 fill_rect( hdc
, &rect
, lti_brush
);
214 SetRect( &rect
, inner_rect
.left
+ width
, inner_rect
.top
+ lti_offset
,
215 inner_rect
.left
+ 2 * width
, inner_rect
.bottom
- lbi_offset
);
216 fill_rect( hdc
, &rect
, lti_brush
);
218 if (flags
& BF_BOTTOM
)
220 SetRect( &rect
, inner_rect
.left
+ lbi_offset
, inner_rect
.bottom
- 2 * width
,
221 inner_rect
.right
- rbi_offset
, inner_rect
.bottom
- width
);
222 fill_rect( hdc
, &rect
, rbi_brush
);
224 if (flags
& BF_RIGHT
)
226 SetRect( &rect
, inner_rect
.right
- 2 * width
, inner_rect
.top
+ rti_offset
,
227 inner_rect
.right
- width
, inner_rect
.bottom
- rbi_offset
);
228 fill_rect( hdc
, &rect
, rbi_brush
);
231 if (((flags
& BF_MIDDLE
) && retval
) || (flags
& BF_ADJUST
))
233 int add
= (ltrb_inner_mono
[type
& (BDR_INNER
|BDR_OUTER
)] != -1 ? width
: 0)
234 + (ltrb_outer_mono
[type
& (BDR_INNER
|BDR_OUTER
)] != -1 ? width
: 0);
236 if (flags
& BF_LEFT
) inner_rect
.left
+= add
;
237 if (flags
& BF_RIGHT
) inner_rect
.right
-= add
;
238 if (flags
& BF_TOP
) inner_rect
.top
+= add
;
239 if (flags
& BF_BOTTOM
) inner_rect
.bottom
-= add
;
241 if ((flags
& BF_MIDDLE
) && retval
)
243 fill_rect( hdc
, &inner_rect
, get_sys_color_brush( flags
& BF_MONO
?
244 COLOR_WINDOW
: COLOR_BTNFACE
));
247 if (flags
& BF_ADJUST
) *rc
= inner_rect
;
253 /***********************************************************************
254 * AdjustWindowRectEx (win32u.so)
256 BOOL WINAPI
AdjustWindowRectEx( RECT
*rect
, DWORD style
, BOOL menu
, DWORD ex_style
)
258 NONCLIENTMETRICSW ncm
;
261 ncm
.cbSize
= sizeof(ncm
);
262 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
264 if ((ex_style
& (WS_EX_STATICEDGE
|WS_EX_DLGMODALFRAME
)) == WS_EX_STATICEDGE
)
265 adjust
= 1; /* for the outer frame always present */
266 else if ((ex_style
& WS_EX_DLGMODALFRAME
) || (style
& (WS_THICKFRAME
|WS_DLGFRAME
)))
267 adjust
= 2; /* outer */
269 if (style
& WS_THICKFRAME
)
270 adjust
+= ncm
.iBorderWidth
+ ncm
.iPaddedBorderWidth
; /* The resize border */
272 if ((style
& (WS_BORDER
|WS_DLGFRAME
)) || (ex_style
& WS_EX_DLGMODALFRAME
))
273 adjust
++; /* The other border */
275 InflateRect( rect
, adjust
, adjust
);
277 if ((style
& WS_CAPTION
) == WS_CAPTION
)
279 if (ex_style
& WS_EX_TOOLWINDOW
)
280 rect
->top
-= ncm
.iSmCaptionHeight
+ 1;
282 rect
->top
-= ncm
.iCaptionHeight
+ 1;
284 if (menu
) rect
->top
-= ncm
.iMenuHeight
+ 1;
286 if (ex_style
& WS_EX_CLIENTEDGE
)
287 InflateRect( rect
, get_system_metrics(SM_CXEDGE
), get_system_metrics(SM_CYEDGE
) );
291 static BOOL
set_window_text( HWND hwnd
, const void *text
, BOOL ansi
)
293 static const WCHAR emptyW
[] = { 0 };
297 /* check for string, as static icons, bitmaps (SS_ICON, SS_BITMAP)
298 * may have child window IDs instead of window name */
299 if (text
&& IS_INTRESOURCE(text
)) return FALSE
;
303 if (ansi
) str
= towstr( text
);
304 else str
= wcsdup( text
);
305 if (!str
) return FALSE
;
309 TRACE( "%s\n", debugstr_w(str
) );
311 if (!(win
= get_win_ptr( hwnd
)))
319 SERVER_START_REQ( set_window_text
)
321 req
->handle
= wine_server_user_handle( hwnd
);
322 if (str
) wine_server_add_data( req
, str
, lstrlenW( str
) * sizeof(WCHAR
) );
323 wine_server_call( req
);
327 release_win_ptr( win
);
329 user_driver
->pSetWindowText( hwnd
, str
? str
: emptyW
);
334 static int get_window_text( HWND hwnd
, WCHAR
*str
, int count
)
338 if (is_current_process_window( hwnd
))
340 /* FIXME: use packed send message */
341 ret
= send_message( hwnd
, WM_GETTEXT
, count
, (LPARAM
)str
);
345 /* when window belongs to other process, don't send a message */
346 ret
= NtUserInternalGetWindowText( hwnd
, str
, count
);
352 static HICON
get_window_icon( HWND hwnd
, WPARAM type
)
357 if (!(win
= get_win_ptr( hwnd
))) return 0;
362 ret
= win
->hIconSmall
;
368 ret
= win
->hIconSmall
? win
->hIconSmall
: win
->hIconSmall2
;
375 release_win_ptr( win
);
379 static HICON
set_window_icon( HWND hwnd
, WPARAM type
, HICON icon
)
384 if (!(win
= get_win_ptr( hwnd
))) return 0;
389 ret
= win
->hIconSmall
;
390 if (ret
&& !icon
&& win
->hIcon
)
392 win
->hIconSmall2
= CopyImage( win
->hIcon
, IMAGE_ICON
,
393 get_system_metrics( SM_CXSMICON
),
394 get_system_metrics( SM_CYSMICON
), 0 );
396 else if (icon
&& win
->hIconSmall2
)
398 NtUserDestroyCursor( win
->hIconSmall2
, 0 );
399 win
->hIconSmall2
= NULL
;
401 win
->hIconSmall
= icon
;
406 if (win
->hIconSmall2
)
408 NtUserDestroyCursor( win
->hIconSmall2
, 0 );
409 win
->hIconSmall2
= NULL
;
411 if (icon
&& !win
->hIconSmall
)
413 win
->hIconSmall2
= CopyImage( icon
, IMAGE_ICON
,
414 get_system_metrics( SM_CXSMICON
),
415 get_system_metrics( SM_CYSMICON
), 0 );
420 release_win_ptr( win
);
422 user_driver
->pSetWindowIcon( hwnd
, type
, icon
);
426 static LRESULT
handle_set_cursor( HWND hwnd
, WPARAM wparam
, LPARAM lparam
)
428 UINT cursor_id
= IDC_ARROW
;
431 hwnd
= get_full_window_handle( (HWND
)wparam
);
433 switch((short)LOWORD( lparam
))
437 WORD msg
= HIWORD( lparam
);
438 if (msg
== WM_LBUTTONDOWN
|| msg
== WM_MBUTTONDOWN
||
439 msg
== WM_RBUTTONDOWN
|| msg
== WM_XBUTTONDOWN
)
445 cursor
= (HCURSOR
)get_class_long_ptr( hwnd
, GCLP_HCURSOR
, FALSE
);
446 if (!cursor
) return FALSE
;
447 NtUserSetCursor( cursor
);
452 cursor_id
= IDC_SIZEWE
;
457 cursor_id
= IDC_SIZENS
;
462 cursor_id
= IDC_SIZENWSE
;
467 cursor_id
= IDC_SIZENESW
;
470 cursor
= LoadImageW( 0, MAKEINTRESOURCEW( cursor_id
), IMAGE_CURSOR
,
471 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
472 return (LRESULT
)NtUserSetCursor( cursor
);
475 static LONG
handle_window_pos_changing( HWND hwnd
, WINDOWPOS
*winpos
)
477 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
479 if (winpos
->flags
& SWP_NOSIZE
) return 0;
480 if ((style
& WS_THICKFRAME
) || ((style
& (WS_POPUP
| WS_CHILD
)) == 0))
482 MINMAXINFO info
= get_min_max_info( hwnd
);
483 winpos
->cx
= min( winpos
->cx
, info
.ptMaxTrackSize
.x
);
484 winpos
->cy
= min( winpos
->cy
, info
.ptMaxTrackSize
.y
);
485 if (!(style
& WS_MINIMIZE
))
487 winpos
->cx
= max( winpos
->cx
, info
.ptMinTrackSize
.x
);
488 winpos
->cy
= max( winpos
->cy
, info
.ptMinTrackSize
.y
);
494 static void handle_window_pos_changed( HWND hwnd
, const WINDOWPOS
*winpos
)
498 get_window_rects( hwnd
, COORDS_PARENT
, NULL
, &rect
, get_thread_dpi() );
499 if (!(winpos
->flags
& SWP_NOCLIENTMOVE
))
500 send_message( hwnd
, WM_MOVE
, 0, MAKELONG( rect
.left
, rect
.top
));
502 if (!(winpos
->flags
& SWP_NOCLIENTSIZE
) || (winpos
->flags
& SWP_STATECHANGED
))
504 if (is_iconic( hwnd
))
506 send_message( hwnd
, WM_SIZE
, SIZE_MINIMIZED
, 0 );
510 WPARAM wp
= is_zoomed( hwnd
) ? SIZE_MAXIMIZED
: SIZE_RESTORED
;
511 send_message( hwnd
, WM_SIZE
, wp
,
512 MAKELONG( rect
.right
-rect
.left
, rect
.bottom
-rect
.top
));
517 /***********************************************************************
520 * Draw the frame used when moving or resizing window.
522 static void draw_moving_frame( HWND parent
, HDC hdc
, RECT
*screen_rect
, BOOL thickframe
)
524 RECT rect
= *screen_rect
;
526 if (parent
) map_window_points( 0, parent
, (POINT
*)&rect
, 2, get_thread_dpi() );
529 const int width
= get_system_metrics( SM_CXFRAME
);
530 const int height
= get_system_metrics( SM_CYFRAME
);
532 HBRUSH hbrush
= NtGdiSelectBrush( hdc
, GetStockObject( GRAY_BRUSH
));
533 NtGdiPatBlt( hdc
, rect
.left
, rect
.top
,
534 rect
.right
- rect
.left
- width
, height
, PATINVERT
);
535 NtGdiPatBlt( hdc
, rect
.left
, rect
.top
+ height
, width
,
536 rect
.bottom
- rect
.top
- height
, PATINVERT
);
537 NtGdiPatBlt( hdc
, rect
.left
+ width
, rect
.bottom
- 1,
538 rect
.right
- rect
.left
- width
, -height
, PATINVERT
);
539 NtGdiPatBlt( hdc
, rect
.right
- 1, rect
.top
, -width
,
540 rect
.bottom
- rect
.top
- height
, PATINVERT
);
541 NtGdiSelectBrush( hdc
, hbrush
);
543 else draw_focus_rect( hdc
, &rect
);
546 /***********************************************************************
549 * Initialization of a move or resize, when initiated from a menu choice.
550 * Return hit test code for caption or sizing border.
552 static LONG
start_size_move( HWND hwnd
, WPARAM wparam
, POINT
*capture_point
, LONG style
)
559 get_window_rect( hwnd
, &window_rect
, get_thread_dpi() );
561 if ((wparam
& 0xfff0) == SC_MOVE
)
563 /* Move pointer at the center of the caption */
564 RECT rect
= window_rect
;
565 /* Note: to be exactly centered we should take the different types
566 * of border into account, but it shouldn't make more than a few pixels
567 * of difference so let's not bother with that */
568 rect
.top
+= get_system_metrics( SM_CYBORDER
);
569 if (style
& WS_SYSMENU
) rect
.left
+= get_system_metrics( SM_CXSIZE
) + 1;
570 if (style
& WS_MINIMIZEBOX
) rect
.right
-= get_system_metrics( SM_CXSIZE
) + 1;
571 if (style
& WS_MAXIMIZEBOX
) rect
.right
-= get_system_metrics( SM_CXSIZE
) + 1;
572 pt
.x
= (rect
.right
+ rect
.left
) / 2;
573 pt
.y
= rect
.top
+ get_system_metrics( SM_CYSIZE
) / 2;
580 cursor
= LoadImageW( 0, (WCHAR
*)IDC_SIZEALL
, IMAGE_CURSOR
, 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
581 NtUserSetCursor( cursor
);
585 if (!NtUserGetMessage( &msg
, 0, 0, 0 )) return 0;
586 if (NtUserCallMsgFilter( &msg
, MSGF_SIZE
)) continue;
591 pt
.x
= min( max( msg
.pt
.x
, window_rect
.left
), window_rect
.right
- 1 );
592 pt
.y
= min( max( msg
.pt
.y
, window_rect
.top
), window_rect
.bottom
- 1 );
593 hittest
= send_message( hwnd
, WM_NCHITTEST
, 0, MAKELONG( pt
.x
, pt
.y
));
594 if (hittest
< HTLEFT
|| hittest
> HTBOTTOMRIGHT
) hittest
= 0;
605 pt
.x
= (window_rect
.left
+ window_rect
.right
) / 2;
606 pt
.y
= window_rect
.top
+ get_system_metrics( SM_CYFRAME
) / 2;
610 pt
.x
= (window_rect
.left
+ window_rect
.right
) / 2;
611 pt
.y
= window_rect
.bottom
- get_system_metrics( SM_CYFRAME
) / 2;
615 pt
.x
= window_rect
.left
+ get_system_metrics( SM_CXFRAME
) / 2;
616 pt
.y
= (window_rect
.top
+ window_rect
.bottom
) / 2;
620 pt
.x
= window_rect
.right
- get_system_metrics( SM_CXFRAME
) / 2;
621 pt
.y
= (window_rect
.top
+ window_rect
.bottom
) / 2;
629 NtUserTranslateMessage( &msg
, 0 );
630 NtUserDispatchMessage( &msg
);
636 NtUserSetCursorPos( pt
.x
, pt
.y
);
637 send_message( hwnd
, WM_SETCURSOR
, (WPARAM
)hwnd
, MAKELONG( hittest
, WM_MOUSEMOVE
));
641 static BOOL
on_left_border( int hit
)
643 return hit
== HTLEFT
|| hit
== HTTOPLEFT
|| hit
== HTBOTTOMLEFT
;
646 static BOOL
on_right_border( int hit
)
648 return hit
== HTRIGHT
|| hit
== HTTOPRIGHT
|| hit
== HTBOTTOMRIGHT
;
651 static BOOL
on_top_border( int hit
)
653 return hit
== HTTOP
|| hit
== HTTOPLEFT
|| hit
== HTTOPRIGHT
;
656 static BOOL
on_bottom_border( int hit
)
658 return hit
== HTBOTTOM
|| hit
== HTBOTTOMLEFT
|| hit
== HTBOTTOMRIGHT
;
661 /***********************************************************************
662 * sys_command_size_move
664 * Perform SC_MOVE and SC_SIZE commands.
666 static void sys_command_size_move( HWND hwnd
, WPARAM wparam
)
668 DWORD msg_pos
= NtUserGetThreadInfo()->message_pos
;
669 BOOL thickframe
, drag_full_windows
= TRUE
, moved
= FALSE
;
670 RECT sizing_rect
, mouse_rect
, orig_rect
;
671 UINT hittest
= wparam
& 0x0f;
672 UINT syscommand
= wparam
& 0xfff0;
673 UINT style
= get_window_long( hwnd
, GWL_STYLE
);
674 POINT capture_point
, pt
;
682 if (is_zoomed( hwnd
) || !is_window_visible( hwnd
)) return;
684 thickframe
= (style
& WS_THICKFRAME
) && !((style
& (WS_DLGFRAME
| WS_BORDER
)) == WS_DLGFRAME
);
686 pt
.x
= (short)LOWORD(msg_pos
);
687 pt
.y
= (short)HIWORD(msg_pos
);
689 NtUserClipCursor( NULL
);
691 TRACE( "hwnd %p command %04x, hittest %d, pos %d,%d\n",
692 hwnd
, syscommand
, hittest
, (int)pt
.x
, (int)pt
.y
);
694 if (syscommand
== SC_MOVE
)
696 if (!hittest
) hittest
= start_size_move( hwnd
, wparam
, &capture_point
, style
);
697 if (!hittest
) return;
701 if (hittest
&& syscommand
!= SC_MOUSEMENU
)
702 hittest
+= (HTLEFT
- WMSZ_LEFT
);
705 set_capture_window( hwnd
, GUI_INMOVESIZE
, NULL
);
706 hittest
= start_size_move( hwnd
, wparam
, &capture_point
, style
);
709 set_capture_window( 0, GUI_INMOVESIZE
, NULL
);
715 minmax
= get_min_max_info( hwnd
);
716 dpi
= get_thread_dpi();
717 get_window_rects( hwnd
, COORDS_PARENT
, &sizing_rect
, NULL
, dpi
);
718 orig_rect
= sizing_rect
;
719 if (style
& WS_CHILD
)
721 parent
= get_parent( hwnd
);
722 get_client_rect( parent
, &mouse_rect
);
723 map_window_points( parent
, 0, (POINT
*)&mouse_rect
, 2, dpi
);
724 map_window_points( parent
, 0, (POINT
*)&sizing_rect
, 2, dpi
);
729 mouse_rect
= get_virtual_screen_rect( get_thread_dpi() );
730 mon
= monitor_from_point( pt
, MONITOR_DEFAULTTONEAREST
, dpi
);
733 if (on_left_border( hittest
))
735 mouse_rect
.left
= max( mouse_rect
.left
,
736 sizing_rect
.right
- minmax
.ptMaxTrackSize
.x
+ capture_point
.x
- sizing_rect
.left
);
737 mouse_rect
.right
= min( mouse_rect
.right
,
738 sizing_rect
.right
- minmax
.ptMinTrackSize
.x
+ capture_point
.x
- sizing_rect
.left
);
740 else if (on_right_border( hittest
))
742 mouse_rect
.left
= max( mouse_rect
.left
,
743 sizing_rect
.left
+ minmax
.ptMinTrackSize
.x
+ capture_point
.x
- sizing_rect
.right
);
744 mouse_rect
.right
= min( mouse_rect
.right
,
745 sizing_rect
.left
+ minmax
.ptMaxTrackSize
.x
+ capture_point
.x
- sizing_rect
.right
);
748 if (on_top_border( hittest
))
750 mouse_rect
.top
= max( mouse_rect
.top
,
751 sizing_rect
.bottom
- minmax
.ptMaxTrackSize
.y
+ capture_point
.y
- sizing_rect
.top
);
752 mouse_rect
.bottom
= min( mouse_rect
.bottom
,
753 sizing_rect
.bottom
- minmax
.ptMinTrackSize
.y
+ capture_point
.y
- sizing_rect
.top
);
755 else if (on_bottom_border( hittest
))
757 mouse_rect
.top
= max( mouse_rect
.top
,
758 sizing_rect
.top
+ minmax
.ptMinTrackSize
.y
+ capture_point
.y
- sizing_rect
.bottom
);
759 mouse_rect
.bottom
= min( mouse_rect
.bottom
,
760 sizing_rect
.top
+ minmax
.ptMaxTrackSize
.y
+ capture_point
.y
- sizing_rect
.bottom
);
763 /* Retrieve a default cache DC (without using the window style) */
764 hdc
= NtUserGetDCEx( parent
, 0, DCX_CACHE
);
766 /* we only allow disabling the full window drag for child windows */
767 if (parent
) NtUserSystemParametersInfo( SPI_GETDRAGFULLWINDOWS
, 0, &drag_full_windows
, 0 );
769 /* repaint the window before moving it around */
770 NtUserRedrawWindow( hwnd
, NULL
, 0, RDW_UPDATENOW
| RDW_ALLCHILDREN
);
772 send_message( hwnd
, WM_ENTERSIZEMOVE
, 0, 0 );
773 set_capture_window( hwnd
, GUI_INMOVESIZE
, NULL
);
779 if (!NtUserGetMessage( &msg
, 0, 0, 0 )) break;
780 if (NtUserCallMsgFilter( &msg
, MSGF_SIZE
)) continue;
782 /* Exit on button-up, Return, or Esc */
783 if (msg
.message
== WM_LBUTTONUP
||
784 (msg
.message
== WM_KEYDOWN
&& (msg
.wParam
== VK_RETURN
|| msg
.wParam
== VK_ESCAPE
)))
787 if (msg
.message
!= WM_KEYDOWN
&& msg
.message
!= WM_MOUSEMOVE
)
789 NtUserTranslateMessage( &msg
, 0 );
790 NtUserDispatchMessage( &msg
);
792 /* It's possible that the window proc that handled the dispatch consumed a
793 * WM_LBUTTONUP. Detect that and terminate the loop as if we'd gotten it. */
794 if (!(NtUserGetKeyState( VK_LBUTTON
) & 0x8000))
796 DWORD last_pos
= NtUserGetThreadInfo()->message_pos
;
797 pt
.x
= ((int)(short)LOWORD( last_pos
));
798 pt
.y
= ((int)(short)HIWORD( last_pos
));
802 continue; /* We are not interested in other messages */
807 if (msg
.message
== WM_KEYDOWN
)
811 case VK_UP
: pt
.y
-= 8; break;
812 case VK_DOWN
: pt
.y
+= 8; break;
813 case VK_LEFT
: pt
.x
-= 8; break;
814 case VK_RIGHT
: pt
.x
+= 8; break;
818 pt
.x
= max( pt
.x
, mouse_rect
.left
);
819 pt
.x
= min( pt
.x
, mouse_rect
.right
- 1 );
820 pt
.y
= max( pt
.y
, mouse_rect
.top
);
821 pt
.y
= min( pt
.y
, mouse_rect
.bottom
- 1 );
828 if ((newmon
= monitor_from_point( pt
, MONITOR_DEFAULTTONULL
, get_thread_dpi() )))
831 info
.cbSize
= sizeof(info
);
832 if (mon
&& get_monitor_info( mon
, &info
))
834 pt
.x
= max( pt
.x
, info
.rcWork
.left
);
835 pt
.x
= min( pt
.x
, info
.rcWork
.right
- 1 );
836 pt
.y
= max( pt
.y
, info
.rcWork
.top
);
837 pt
.y
= min( pt
.y
, info
.rcWork
.bottom
- 1 );
841 dx
= pt
.x
- capture_point
.x
;
842 dy
= pt
.y
- capture_point
.y
;
849 if (!drag_full_windows
)
850 draw_moving_frame( parent
, hdc
, &sizing_rect
, thickframe
);
853 if (msg
.message
== WM_KEYDOWN
) NtUserSetCursorPos( pt
.x
, pt
.y
);
856 if (!drag_full_windows
) draw_moving_frame( parent
, hdc
, &sizing_rect
, thickframe
);
857 if (hittest
== HTCAPTION
|| hittest
== HTBORDER
) OffsetRect( &sizing_rect
, dx
, dy
);
858 if (on_left_border( hittest
)) sizing_rect
.left
+= dx
;
859 else if (on_right_border( hittest
)) sizing_rect
.right
+= dx
;
860 if (on_top_border( hittest
)) sizing_rect
.top
+= dy
;
861 else if (on_bottom_border( hittest
)) sizing_rect
.bottom
+= dy
;
864 /* determine the hit location */
865 if (syscommand
== SC_SIZE
&& hittest
!= HTBORDER
)
867 WPARAM sizing_hit
= 0;
869 if (hittest
>= HTLEFT
&& hittest
<= HTBOTTOMRIGHT
)
870 sizing_hit
= WMSZ_LEFT
+ (hittest
- HTLEFT
);
871 send_message( hwnd
, WM_SIZING
, sizing_hit
, (LPARAM
)&sizing_rect
);
874 send_message( hwnd
, WM_MOVING
, 0, (LPARAM
)&sizing_rect
);
876 if (!drag_full_windows
)
877 draw_moving_frame( parent
, hdc
, &sizing_rect
, thickframe
);
880 RECT rect
= sizing_rect
;
881 map_window_points( 0, parent
, (POINT
*)&rect
, 2, get_thread_dpi() );
882 NtUserSetWindowPos( hwnd
, 0, rect
.left
, rect
.top
,
883 rect
.right
- rect
.left
, rect
.bottom
- rect
.top
,
884 hittest
== HTCAPTION
? SWP_NOSIZE
: 0 );
890 if (moved
&& !drag_full_windows
)
891 draw_moving_frame( parent
, hdc
, &sizing_rect
, thickframe
);
893 set_capture_window( 0, GUI_INMOVESIZE
, NULL
);
894 NtUserReleaseDC( parent
, hdc
);
895 if (parent
) map_window_points( 0, parent
, (POINT
*)&sizing_rect
, 2, get_thread_dpi() );
897 if (call_hooks( WH_CBT
, HCBT_MOVESIZE
, (WPARAM
)hwnd
, (LPARAM
)&sizing_rect
, sizeof(sizing_rect
) ))
900 send_message( hwnd
, WM_EXITSIZEMOVE
, 0, 0 );
901 send_message( hwnd
, WM_SETVISIBLE
, !is_iconic(hwnd
), 0 );
903 /* window moved or resized */
906 /* if the moving/resizing isn't canceled call SetWindowPos
907 * with the new position or the new size of the window
909 if (!(msg
.message
== WM_KEYDOWN
&& msg
.wParam
== VK_ESCAPE
) )
911 /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
912 if (!drag_full_windows
)
913 NtUserSetWindowPos( hwnd
, 0, sizing_rect
.left
, sizing_rect
.top
,
914 sizing_rect
.right
- sizing_rect
.left
,
915 sizing_rect
.bottom
- sizing_rect
.top
,
916 hittest
== HTCAPTION
? SWP_NOSIZE
: 0 );
920 /* restore previous size/position */
921 if (drag_full_windows
)
922 NtUserSetWindowPos( hwnd
, 0, orig_rect
.left
, orig_rect
.top
,
923 orig_rect
.right
- orig_rect
.left
,
924 orig_rect
.bottom
- orig_rect
.top
,
925 hittest
== HTCAPTION
? SWP_NOSIZE
: 0 );
929 if (is_iconic(hwnd
) && !moved
&& (style
& WS_SYSMENU
))
931 /* Single click brings up the system menu when iconized */
932 send_message( hwnd
, WM_SYSCOMMAND
, SC_MOUSEMENU
+ HTSYSMENU
, MAKELONG(pt
.x
, pt
.y
) );
936 /***********************************************************************
937 * track_nc_scroll_bar
939 * Track a mouse button press on the horizontal or vertical scroll-bar.
941 static void track_nc_scroll_bar( HWND hwnd
, WPARAM wparam
, POINT pt
)
945 if ((wparam
& 0xfff0) == SC_HSCROLL
)
947 if ((wparam
& 0x0f) != HTHSCROLL
) return;
950 else /* SC_VSCROLL */
952 if ((wparam
& 0x0f) != HTVSCROLL
) return;
955 track_scroll_bar( hwnd
, scrollbar
, pt
);
958 static LRESULT
handle_sys_command( HWND hwnd
, WPARAM wparam
, LPARAM lparam
)
960 TRACE( "hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd
, (long)wparam
, lparam
);
962 if (!is_window_enabled( hwnd
)) return 0;
964 if (call_hooks( WH_CBT
, HCBT_SYSCOMMAND
, wparam
, lparam
, 0 ))
967 if (!user_driver
->pSysCommand( hwnd
, wparam
, lparam
))
970 switch (wparam
& 0xfff0)
974 sys_command_size_move( hwnd
, wparam
);
978 show_owned_popups( hwnd
, FALSE
);
979 NtUserShowWindow( hwnd
, SW_MINIMIZE
);
983 if (is_iconic(hwnd
)) show_owned_popups( hwnd
, TRUE
);
984 NtUserShowWindow( hwnd
, SW_MAXIMIZE
);
988 return send_message( hwnd
, WM_CLOSE
, 0, 0 );
994 pt
.x
= (short)LOWORD( lparam
);
995 pt
.y
= (short)HIWORD( lparam
);
996 track_nc_scroll_bar( hwnd
, wparam
, pt
);
1001 track_mouse_menu_bar( hwnd
, wparam
& 0x000F, (short)LOWORD(lparam
), (short)HIWORD(lparam
) );
1005 track_keyboard_menu_bar( hwnd
, wparam
, lparam
);
1009 if (is_iconic( hwnd
)) show_owned_popups( hwnd
, TRUE
);
1010 NtUserShowWindow( hwnd
, SW_RESTORE
);
1015 return 1; /* FIXME: handle on client side */
1021 FIXME( "unimplemented WM_SYSCOMMAND %04lx\n", (long)wparam
);
1025 return 1; /* handle on client side */
1030 /* Get the 'inside' rectangle of a window, i.e. the whole window rectangle
1031 * but without the borders (if any). */
1032 static void get_inside_rect( HWND hwnd
, enum coords_relative relative
, RECT
*rect
,
1033 DWORD style
, DWORD ex_style
)
1035 get_window_rects( hwnd
, relative
, rect
, NULL
, get_thread_dpi() );
1037 /* Remove frame from rectangle */
1038 if (has_thick_frame( style
, ex_style
))
1040 InflateRect( rect
, -get_system_metrics( SM_CXFRAME
), -get_system_metrics( SM_CYFRAME
));
1042 else if (has_dialog_frame( style
, ex_style
))
1044 InflateRect( rect
, -get_system_metrics( SM_CXDLGFRAME
), -get_system_metrics( SM_CYDLGFRAME
));
1046 else if (has_thin_frame( style
))
1048 InflateRect( rect
, -get_system_metrics( SM_CXBORDER
), -get_system_metrics( SM_CYBORDER
));
1051 /* We have additional border information if the window
1052 * is a child (but not an MDI child) */
1053 if ((style
& WS_CHILD
) && !(ex_style
& WS_EX_MDICHILD
))
1055 if (ex_style
& WS_EX_CLIENTEDGE
)
1056 InflateRect( rect
, -get_system_metrics( SM_CXEDGE
), -get_system_metrics( SM_CYEDGE
));
1057 if (ex_style
& WS_EX_STATICEDGE
)
1058 InflateRect( rect
, -get_system_metrics( SM_CXBORDER
), -get_system_metrics( SM_CYBORDER
));
1062 void get_sys_popup_pos( HWND hwnd
, RECT
*rect
)
1064 if (is_iconic(hwnd
)) get_window_rect( hwnd
, rect
, get_thread_dpi() );
1067 DWORD style
= get_window_long( hwnd
, GWL_STYLE
);
1068 DWORD ex_style
= get_window_long( hwnd
, GWL_EXSTYLE
);
1070 get_inside_rect( hwnd
, COORDS_CLIENT
, rect
, style
, ex_style
);
1071 rect
->right
= rect
->left
+ get_system_metrics( SM_CYCAPTION
) - 1;
1072 rect
->bottom
= rect
->top
+ get_system_metrics( SM_CYCAPTION
) - 1;
1073 map_window_points( hwnd
, 0, (POINT
*)rect
, 2, get_thread_dpi() );
1077 /* Draw a window frame inside the given rectangle, and update the rectangle. */
1078 static void draw_nc_frame( HDC hdc
, RECT
*rect
, BOOL active
, DWORD style
, DWORD ex_style
)
1082 if (style
& WS_THICKFRAME
)
1084 width
= get_system_metrics( SM_CXFRAME
) - get_system_metrics( SM_CXDLGFRAME
);
1085 height
= get_system_metrics( SM_CYFRAME
) - get_system_metrics( SM_CYDLGFRAME
);
1087 NtGdiSelectBrush( hdc
, get_sys_color_brush( active
? COLOR_ACTIVEBORDER
:
1088 COLOR_INACTIVEBORDER
));
1090 NtGdiPatBlt( hdc
, rect
->left
, rect
->top
, rect
->right
- rect
->left
, height
, PATCOPY
);
1091 NtGdiPatBlt( hdc
, rect
->left
, rect
->top
, width
, rect
->bottom
- rect
->top
, PATCOPY
);
1092 NtGdiPatBlt( hdc
, rect
->left
, rect
->bottom
- 1, rect
->right
- rect
->left
, -height
, PATCOPY
);
1093 NtGdiPatBlt( hdc
, rect
->right
- 1, rect
->top
, -width
, rect
->bottom
- rect
->top
, PATCOPY
);
1095 InflateRect( rect
, -width
, -height
);
1098 /* Now the other bit of the frame */
1099 if ((style
& (WS_BORDER
|WS_DLGFRAME
)) || (ex_style
& WS_EX_DLGMODALFRAME
))
1103 width
= get_system_metrics( SM_CXDLGFRAME
) - get_system_metrics( SM_CXEDGE
);
1104 height
= get_system_metrics( SM_CYDLGFRAME
) - get_system_metrics( SM_CYEDGE
);
1105 /* This should give a value of 1 that should also work for a border */
1107 if (ex_style
& (WS_EX_DLGMODALFRAME
| WS_EX_CLIENTEDGE
)) color
= COLOR_3DFACE
;
1108 else if (ex_style
& WS_EX_STATICEDGE
) color
= COLOR_WINDOWFRAME
;
1109 else if (style
& (WS_DLGFRAME
|WS_THICKFRAME
)) color
= COLOR_3DFACE
;
1110 else color
= COLOR_WINDOWFRAME
;
1111 NtGdiSelectBrush( hdc
, get_sys_color_brush( color
));
1114 NtGdiPatBlt( hdc
, rect
->left
, rect
->top
,
1115 rect
->right
- rect
->left
, height
, PATCOPY
);
1116 NtGdiPatBlt( hdc
, rect
->left
, rect
->top
,
1117 width
, rect
->bottom
- rect
->top
, PATCOPY
);
1118 NtGdiPatBlt( hdc
, rect
->left
, rect
->bottom
- 1,
1119 rect
->right
- rect
->left
, -height
, PATCOPY
);
1120 NtGdiPatBlt( hdc
, rect
->right
- 1, rect
->top
,
1121 -width
, rect
->bottom
- rect
->top
, PATCOPY
);
1123 InflateRect( rect
, -width
, -height
);
1127 static HICON
get_nc_icon_for_window( HWND hwnd
)
1130 WND
*win
= get_win_ptr( hwnd
);
1132 if (win
&& win
!= WND_OTHER_PROCESS
&& win
!= WND_DESKTOP
)
1134 icon
= win
->hIconSmall
;
1135 if (!icon
) icon
= win
->hIcon
;
1136 release_win_ptr( win
);
1138 if (!icon
) icon
= (HICON
) get_class_long_ptr( hwnd
, GCLP_HICONSM
, FALSE
);
1139 if (!icon
) icon
= (HICON
) get_class_long_ptr( hwnd
, GCLP_HICON
, FALSE
);
1141 /* If there is no icon specified and this is not a modal dialog, get the default one. */
1142 if (!icon
&& !(get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_DLGMODALFRAME
))
1143 icon
= LoadImageW( 0, (LPCWSTR
)IDI_WINLOGO
, IMAGE_ICON
, get_system_metrics( SM_CXSMICON
),
1144 get_system_metrics( SM_CYSMICON
), LR_DEFAULTCOLOR
| LR_SHARED
);
1148 /* Draws the bar part (ie the big rectangle) of the caption */
1149 static void draw_caption_bar( HDC hdc
, const RECT
*rect
, DWORD style
, BOOL active
, BOOL gradient
)
1153 TRIVERTEX vertices
[4];
1155 int buttons_size
= get_system_metrics( SM_CYCAPTION
) - 1;
1157 static GRADIENT_RECT mesh
[] = {{0, 1}, {1, 2}, {2, 3}};
1159 left
= get_sys_color( active
? COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
);
1160 right
= get_sys_color( active
? COLOR_GRADIENTACTIVECAPTION
: COLOR_GRADIENTINACTIVECAPTION
);
1161 vertices
[0].Red
= vertices
[1].Red
= GetRValue( left
) << 8;
1162 vertices
[0].Green
= vertices
[1].Green
= GetGValue( left
) << 8;
1163 vertices
[0].Blue
= vertices
[1].Blue
= GetBValue( left
) << 8;
1164 vertices
[0].Alpha
= vertices
[1].Alpha
= 0xff00;
1165 vertices
[2].Red
= vertices
[3].Red
= GetRValue( right
) << 8;
1166 vertices
[2].Green
= vertices
[3].Green
= GetGValue( right
) << 8;
1167 vertices
[2].Blue
= vertices
[3].Blue
= GetBValue( right
) << 8;
1168 vertices
[2].Alpha
= vertices
[3].Alpha
= 0xff00;
1170 if ((style
& WS_SYSMENU
) && ((style
& WS_MAXIMIZEBOX
) || (style
& WS_MINIMIZEBOX
)))
1171 buttons_size
+= 2 * (get_system_metrics( SM_CXSIZE
) + 1);
1173 /* area behind icon; solid filled with left color */
1174 vertices
[0].x
= rect
->left
;
1175 vertices
[0].y
= rect
->top
;
1176 if (style
& WS_SYSMENU
)
1177 vertices
[1].x
= min( rect
->left
+ get_system_metrics( SM_CXSMICON
), rect
->right
);
1179 vertices
[1].x
= vertices
[0].x
;
1180 vertices
[1].y
= rect
->bottom
;
1182 /* area behind text; gradient */
1183 vertices
[2].x
= max( vertices
[1].x
, rect
->right
- buttons_size
);
1184 vertices
[2].y
= rect
->top
;
1186 /* area behind buttons; solid filled with right color */
1187 vertices
[3].x
= rect
->right
;
1188 vertices
[3].y
= rect
->bottom
;
1190 NtGdiGradientFill( hdc
, vertices
, 4, mesh
, 3, GRADIENT_FILL_RECT_H
);
1194 DWORD color
= active
? COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
;
1195 fill_rect( hdc
, rect
, get_sys_color_brush( color
));
1199 /* Draw the system icon */
1200 BOOL
draw_nc_sys_button( HWND hwnd
, HDC hdc
, BOOL down
)
1202 HICON icon
= get_nc_icon_for_window( hwnd
);
1208 DWORD style
= get_window_long( hwnd
, GWL_STYLE
);
1209 DWORD ex_style
= get_window_long( hwnd
, GWL_EXSTYLE
);
1211 get_inside_rect( hwnd
, COORDS_WINDOW
, &rect
, style
, ex_style
);
1212 pt
.x
= rect
.left
+ 2;
1213 pt
.y
= rect
.top
+ (get_system_metrics( SM_CYCAPTION
) - get_system_metrics( SM_CYSMICON
)) / 2;
1214 NtUserDrawIconEx( hdc
, pt
.x
, pt
.y
, icon
,
1215 get_system_metrics( SM_CXSMICON
),
1216 get_system_metrics( SM_CYSMICON
), 0, 0, DI_NORMAL
);
1222 /* Create a square rectangle and return its width */
1223 static int make_square_rect( RECT
*src
, RECT
*dst
)
1225 int width
= src
->right
- src
->left
;
1226 int height
= src
->bottom
- src
->top
;
1227 int small_diam
= width
> height
? height
: width
;
1231 /* Make it a square box */
1234 dst
->top
+= (height
- width
) / 2;
1235 dst
->bottom
= dst
->top
+ small_diam
;
1237 else if (width
> height
)
1239 dst
->left
+= (width
- height
) / 2;
1240 dst
->right
= dst
->left
+ small_diam
;
1246 static void draw_checked_rect( HDC dc
, RECT
*rect
)
1248 if (get_sys_color( COLOR_BTNHIGHLIGHT
) == RGB( 255, 255, 255 ))
1253 fill_rect( dc
, rect
, get_sys_color_brush( COLOR_BTNFACE
));
1254 NtGdiGetAndSetDCDword( dc
, NtGdiSetBkColor
, RGB(255, 255, 255), &prev_bg
);
1255 prev_brush
= NtGdiSelectBrush( dc
, get_55aa_brush() );
1256 NtGdiPatBlt( dc
, rect
->left
, rect
->top
, rect
->right
-rect
->left
,
1257 rect
->bottom
-rect
->top
, 0x00fa0089 );
1258 NtGdiSelectBrush( dc
, prev_brush
);
1259 NtGdiGetAndSetDCDword( dc
, NtGdiSetBkColor
, prev_bg
, NULL
);
1263 fill_rect( dc
, rect
, get_sys_color_brush( COLOR_BTNHIGHLIGHT
));
1267 static BOOL
draw_push_button( HDC dc
, RECT
*r
, UINT flags
)
1272 if (flags
& (DFCS_PUSHED
| DFCS_CHECKED
| DFCS_FLAT
))
1277 if (flags
& DFCS_CHECKED
)
1279 if (flags
& DFCS_MONO
)
1280 draw_rect_edge( dc
, &rect
, edge
, BF_MONO
|BF_RECT
|BF_ADJUST
, 1 );
1282 draw_rect_edge( dc
, &rect
, edge
, (flags
& DFCS_FLAT
)|BF_RECT
|BF_SOFT
|BF_ADJUST
, 1 );
1283 if (!(flags
& DFCS_TRANSPARENT
)) draw_checked_rect( dc
, &rect
);
1287 if (flags
& DFCS_MONO
)
1289 draw_rect_edge( dc
, &rect
, edge
, BF_MONO
|BF_RECT
|BF_ADJUST
, 1 );
1290 if (!(flags
& DFCS_TRANSPARENT
))
1291 fill_rect( dc
, &rect
, get_sys_color_brush( COLOR_BTNFACE
));
1295 UINT edge_flags
= BF_RECT
| BF_SOFT
| (flags
& DFCS_FLAT
);
1296 if (!(flags
& DFCS_TRANSPARENT
)) edge_flags
|= BF_MIDDLE
;
1297 draw_rect_edge( dc
, r
, edge
, edge_flags
, 1 );
1301 /* Adjust rectangle if asked */
1302 if (flags
& DFCS_ADJUSTRECT
) InflateRect( r
, -2, -2 );
1306 static BOOL
draw_frame_caption( HDC dc
, RECT
*r
, UINT flags
)
1309 int small_diam
= make_square_rect( r
, &rect
) - 2;
1310 HFONT prev_font
, font
;
1311 int color_idx
= flags
& DFCS_INACTIVE
? COLOR_BTNSHADOW
: COLOR_BTNTEXT
;
1312 int xc
= (rect
.left
+ rect
.right
) / 2;
1313 int yc
= (rect
.top
+ rect
.bottom
) / 2;
1314 LOGFONTW lf
= { 0 };
1315 WCHAR str
[] = {0, 0};
1316 DWORD prev_align
, prev_bk
;
1317 COLORREF prev_color
;
1320 static const WCHAR marlettW
[] = {'M','a','r','l','e','t','t',0};
1322 draw_push_button( dc
, r
, flags
& 0xff00 );
1324 switch (flags
& 0xf)
1326 case DFCS_CAPTIONCLOSE
: str
[0] = 0x72; break;
1327 case DFCS_CAPTIONHELP
: str
[0] = 0x73; break;
1328 case DFCS_CAPTIONMIN
: str
[0] = 0x30; break;
1329 case DFCS_CAPTIONMAX
: str
[0] = 0x31; break;
1330 case DFCS_CAPTIONRESTORE
: str
[0] = 0x32; break;
1332 WARN( "Invalid caption; flags=0x%04x\n", flags
);
1336 lf
.lfHeight
= -small_diam
;
1337 lf
.lfWeight
= FW_NORMAL
;
1338 lf
.lfCharSet
= SYMBOL_CHARSET
;
1339 lf
.lfPitchAndFamily
= FIXED_PITCH
| FF_DONTCARE
;
1340 memcpy( lf
.lfFaceName
, marlettW
, sizeof(marlettW
) );
1341 font
= NtGdiHfontCreate( &lf
, sizeof(lf
), 0, 0, NULL
);
1342 NtGdiGetAndSetDCDword( dc
, NtGdiSetTextAlign
, TA_TOP
| TA_LEFT
, &prev_align
);
1343 NtGdiGetAndSetDCDword( dc
, NtGdiSetBkMode
, TRANSPARENT
, &prev_bk
);
1344 NtGdiGetDCDword( dc
, NtGdiGetTextColor
, &prev_color
);
1345 prev_font
= NtGdiSelectFont( dc
, font
);
1346 NtGdiGetTextExtentExW( dc
, str
, 1, 0, NULL
, NULL
, &size
, 0 );
1348 if (flags
& DFCS_INACTIVE
)
1350 NtGdiGetAndSetDCDword( dc
, NtGdiSetTextColor
, get_sys_color(COLOR_BTNHIGHLIGHT
), NULL
);
1351 NtGdiExtTextOutW( dc
, xc
-size
.cx
/2+1, yc
-size
.cy
/2+1, 0, NULL
, str
, 1, NULL
, 0 );
1353 NtGdiGetAndSetDCDword( dc
, NtGdiSetTextColor
, get_sys_color( color_idx
), NULL
);
1354 NtGdiExtTextOutW( dc
, xc
-size
.cx
/2, yc
-size
.cy
/2, 0, NULL
, str
, 1, NULL
, 0 );
1356 NtGdiSelectFont(dc
, prev_font
);
1357 NtGdiGetAndSetDCDword( dc
, NtGdiSetTextColor
, prev_color
, NULL
);
1358 NtGdiGetAndSetDCDword( dc
, NtGdiSetTextAlign
, prev_align
, NULL
);
1359 NtGdiGetAndSetDCDword( dc
, NtGdiSetBkMode
, prev_bk
, NULL
);
1360 NtGdiDeleteObjectApp( font
);
1365 BOOL
draw_menu_button( HWND hwnd
, HDC dc
, RECT
*r
, enum NONCLIENT_BUTTON_TYPE type
, BOOL down
,
1368 struct draw_non_client_button_params params
;
1377 params
.grayed
= grayed
;
1378 return KeUserModeCallback( NtUserDrawNonClientButton
, ¶ms
, sizeof(params
), &ret_ptr
, &ret_len
);
1381 BOOL
draw_frame_menu( HDC dc
, RECT
*r
, UINT flags
)
1384 int dmall_diam
= make_square_rect( r
, &rect
);
1394 fill_rect( dc
, r
, GetStockObject( WHITE_BRUSH
));
1396 prev_brush
= NtGdiSelectBrush( dc
, GetStockObject( BLACK_BRUSH
));
1397 prev_pen
= NtGdiSelectPen( dc
, GetStockObject( BLACK_PEN
));
1399 switch (flags
& 0xff)
1401 case DFCS_MENUARROW
:
1402 i
= 187 * dmall_diam
/ 750;
1403 points
[2].x
= rect
.left
+ 468 * dmall_diam
/ 750;
1404 points
[2].y
= rect
.top
+ 352 * dmall_diam
/ 750 + 1;
1405 points
[0].y
= points
[2].y
- i
;
1406 points
[1].y
= points
[2].y
+ i
;
1407 points
[0].x
= points
[1].x
= points
[2].x
- i
;
1409 NtGdiPolyPolyDraw( dc
, points
, &count
, 1, NtGdiPolyPolygon
);
1412 case DFCS_MENUBULLET
:
1414 ye
= rect
.top
+ dmall_diam
- dmall_diam
/ 2;
1415 xc
= rect
.left
+ dmall_diam
- dmall_diam
/ 2;
1416 yc
= rect
.top
+ dmall_diam
- dmall_diam
/ 2;
1417 i
= 234 * dmall_diam
/ 750;
1419 SetRect( &rect
, xc
- i
+ i
/ 2, yc
- i
+ i
/ 2, xc
+ i
/ 2, yc
+ i
/ 2 );
1420 NtGdiArcInternal( NtGdiPie
, dc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
,
1424 case DFCS_MENUCHECK
:
1425 points
[0].x
= rect
.left
+ 253 * dmall_diam
/ 1000;
1426 points
[0].y
= rect
.top
+ 445 * dmall_diam
/ 1000;
1427 points
[1].x
= rect
.left
+ 409 * dmall_diam
/ 1000;
1428 points
[1].y
= points
[0].y
+ (points
[1].x
- points
[0].x
);
1429 points
[2].x
= rect
.left
+ 690 * dmall_diam
/ 1000;
1430 points
[2].y
= points
[1].y
- (points
[2].x
- points
[1].x
);
1431 points
[3].x
= points
[2].x
;
1432 points
[3].y
= points
[2].y
+ 3 * dmall_diam
/ 16;
1433 points
[4].x
= points
[1].x
;
1434 points
[4].y
= points
[1].y
+ 3 * dmall_diam
/ 16;
1435 points
[5].x
= points
[0].x
;
1436 points
[5].y
= points
[0].y
+ 3 * dmall_diam
/ 16;
1438 NtGdiPolyPolyDraw( dc
, points
, &count
, 1, NtGdiPolyPolygon
);
1442 WARN( "Invalid menu; flags=0x%04x\n", flags
);
1447 NtGdiSelectPen( dc
, prev_pen
);
1448 NtGdiSelectBrush( dc
, prev_brush
);
1452 static void draw_close_button( HWND hwnd
, HDC hdc
, BOOL down
, BOOL grayed
)
1455 DWORD style
= get_window_long( hwnd
, GWL_STYLE
);
1456 DWORD ex_style
= get_window_long( hwnd
, GWL_EXSTYLE
);
1457 UINT flags
= DFCS_CAPTIONCLOSE
;
1459 get_inside_rect( hwnd
, COORDS_WINDOW
, &rect
, style
, ex_style
);
1461 /* A tool window has a smaller Close button */
1462 if (ex_style
& WS_EX_TOOLWINDOW
)
1464 /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE
1465 * it uses 11x11 for the close button in tool window */
1466 const int bmp_height
= 11;
1467 const int bmp_width
= 11;
1468 int caption_height
= get_system_metrics( SM_CYSMCAPTION
);
1470 rect
.top
= rect
.top
+ (caption_height
- 1 - bmp_height
) / 2;
1471 rect
.left
= rect
.right
- (caption_height
+ 1 + bmp_width
) / 2;
1472 rect
.bottom
= rect
.top
+ bmp_height
;
1473 rect
.right
= rect
.left
+ bmp_width
;
1477 rect
.left
= rect
.right
- get_system_metrics( SM_CXSIZE
);
1478 rect
.bottom
= rect
.top
+ get_system_metrics( SM_CYSIZE
) - 2;
1483 if (down
) flags
|= DFCS_PUSHED
;
1484 if (grayed
) flags
|= DFCS_INACTIVE
;
1485 draw_frame_caption( hdc
, &rect
, flags
);
1488 static void draw_max_button( HWND hwnd
, HDC hdc
, BOOL down
, BOOL grayed
)
1492 DWORD style
= get_window_long( hwnd
, GWL_STYLE
);
1493 DWORD ex_style
= get_window_long( hwnd
, GWL_EXSTYLE
);
1495 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
1496 if (ex_style
& WS_EX_TOOLWINDOW
) return;
1498 flags
= (style
& WS_MAXIMIZE
) ? DFCS_CAPTIONRESTORE
: DFCS_CAPTIONMAX
;
1500 get_inside_rect( hwnd
, COORDS_WINDOW
, &rect
, style
, ex_style
);
1501 if (style
& WS_SYSMENU
) rect
.right
-= get_system_metrics( SM_CXSIZE
);
1502 rect
.left
= rect
.right
- get_system_metrics( SM_CXSIZE
);
1503 rect
.bottom
= rect
.top
+ get_system_metrics( SM_CYSIZE
) - 2;
1506 if (down
) flags
|= DFCS_PUSHED
;
1507 if (grayed
) flags
|= DFCS_INACTIVE
;
1508 draw_frame_caption( hdc
, &rect
, flags
);
1511 static void draw_min_button( HWND hwnd
, HDC hdc
, BOOL down
, BOOL grayed
)
1515 DWORD style
= get_window_long( hwnd
, GWL_STYLE
);
1516 DWORD ex_style
= get_window_long( hwnd
, GWL_EXSTYLE
);
1518 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
1519 if (ex_style
& WS_EX_TOOLWINDOW
) return;
1521 flags
= (style
& WS_MINIMIZE
) ? DFCS_CAPTIONRESTORE
: DFCS_CAPTIONMIN
;
1523 get_inside_rect( hwnd
, COORDS_WINDOW
, &rect
, style
, ex_style
);
1524 if (style
& WS_SYSMENU
)
1525 rect
.right
-= get_system_metrics( SM_CXSIZE
);
1526 if (style
& (WS_MAXIMIZEBOX
|WS_MINIMIZEBOX
))
1527 rect
.right
-= get_system_metrics( SM_CXSIZE
) - 2;
1528 rect
.left
= rect
.right
- get_system_metrics( SM_CXSIZE
);
1529 rect
.bottom
= rect
.top
+ get_system_metrics( SM_CYSIZE
) - 2;
1532 if (down
) flags
|= DFCS_PUSHED
;
1533 if (grayed
) flags
|= DFCS_INACTIVE
;
1534 draw_frame_caption( hdc
, &rect
, flags
);
1537 static void draw_nc_caption( HDC hdc
, RECT
*rect
, HWND hwnd
, DWORD style
,
1538 DWORD ex_style
, BOOL active
)
1544 BOOL gradient
= FALSE
;
1545 UINT pen_color
= COLOR_3DFACE
;
1548 if ((ex_style
& (WS_EX_STATICEDGE
|WS_EX_CLIENTEDGE
|WS_EX_DLGMODALFRAME
)) == WS_EX_STATICEDGE
)
1549 pen_color
= COLOR_WINDOWFRAME
;
1550 prev_pen
= NtGdiSelectPen( hdc
, get_sys_color_pen( pen_color
));
1551 NtGdiMoveTo( hdc
, r
.left
, r
.bottom
- 1, NULL
);
1552 NtGdiLineTo( hdc
, r
.right
, r
.bottom
- 1 );
1553 NtGdiSelectPen( hdc
, prev_pen
);
1556 NtUserSystemParametersInfo( SPI_GETGRADIENTCAPTIONS
, 0, &gradient
, 0 );
1557 draw_caption_bar( hdc
, &r
, style
, active
, gradient
);
1559 if ((style
& WS_SYSMENU
) && !(ex_style
& WS_EX_TOOLWINDOW
))
1561 if (draw_nc_sys_button( hwnd
, hdc
, FALSE
))
1562 r
.left
+= get_system_metrics( SM_CXSMICON
) + 2;
1565 if (style
& WS_SYSMENU
)
1569 /* Go get the sysmenu */
1570 sys_menu
= NtUserGetSystemMenu( hwnd
, FALSE
);
1571 state
= get_menu_state( sys_menu
, SC_CLOSE
, MF_BYCOMMAND
);
1573 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
1574 draw_close_button( hwnd
, hdc
, FALSE
,
1575 (state
& (MF_DISABLED
| MF_GRAYED
)) || (state
== 0xFFFFFFFF) );
1576 r
.right
-= get_system_metrics( SM_CYCAPTION
) - 1;
1578 if ((style
& WS_MAXIMIZEBOX
) || (style
& WS_MINIMIZEBOX
))
1580 draw_max_button( hwnd
, hdc
, FALSE
, !(style
& WS_MAXIMIZEBOX
) );
1581 r
.right
-= get_system_metrics( SM_CXSIZE
) + 1;
1583 draw_min_button( hwnd
, hdc
, FALSE
, !(style
& WS_MINIMIZEBOX
) );
1584 r
.right
-= get_system_metrics( SM_CXSIZE
) + 1;
1588 len
= get_window_text( hwnd
, buffer
, ARRAY_SIZE( buffer
));
1591 NONCLIENTMETRICSW nclm
;
1592 HFONT hFont
, hOldFont
;
1593 nclm
.cbSize
= sizeof(nclm
);
1594 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &nclm
, 0 );
1595 if (ex_style
& WS_EX_TOOLWINDOW
)
1596 hFont
= NtGdiHfontCreate( &nclm
.lfSmCaptionFont
, sizeof(nclm
.lfSmCaptionFont
), 0, 0, NULL
);
1598 hFont
= NtGdiHfontCreate( &nclm
.lfCaptionFont
, sizeof(nclm
.lfCaptionFont
), 0, 0, NULL
);
1599 hOldFont
= NtGdiSelectFont( hdc
, hFont
);
1601 NtGdiGetAndSetDCDword( hdc
, NtGdiSetTextColor
, get_sys_color( COLOR_CAPTIONTEXT
), NULL
);
1603 NtGdiGetAndSetDCDword( hdc
, NtGdiSetTextColor
, get_sys_color( COLOR_INACTIVECAPTIONTEXT
), NULL
);
1604 NtGdiGetAndSetDCDword( hdc
, NtGdiSetBkMode
, TRANSPARENT
, NULL
);
1606 DrawTextW( hdc
, buffer
, -1, &r
,
1607 DT_SINGLELINE
| DT_VCENTER
| DT_NOPREFIX
| DT_LEFT
);
1608 NtGdiDeleteObjectApp( NtGdiSelectFont( hdc
, hOldFont
));
1612 /***********************************************************************
1613 * NtUserDrawCaptionTemp (win32u.@)
1615 BOOL WINAPI
NtUserDrawCaptionTemp( HWND hwnd
, HDC hdc
, const RECT
*rect
, HFONT font
,
1616 HICON icon
, const WCHAR
*str
, UINT flags
)
1620 TRACE( "(%p,%p,%p,%p,%p,%s,%08x)\n", hwnd
, hdc
, rect
, font
, icon
, debugstr_w(str
), flags
);
1622 /* drawing background */
1623 if (flags
& DC_INBUTTON
)
1625 fill_rect( hdc
, &rc
, get_sys_color_brush( COLOR_3DFACE
));
1627 if (flags
& DC_ACTIVE
)
1629 HBRUSH hbr
= NtGdiSelectBrush( hdc
, get_55aa_brush() );
1630 NtGdiPatBlt( hdc
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, 0xfa0089 );
1631 NtGdiSelectBrush( hdc
, hbr
);
1636 DWORD style
= get_window_long( hwnd
, GWL_STYLE
);
1637 draw_caption_bar( hdc
, &rc
, style
, flags
& DC_ACTIVE
, flags
& DC_GRADIENT
);
1641 if ((flags
& DC_ICON
) && !(flags
& DC_SMALLCAP
))
1646 pt
.y
= (rc
.bottom
+ rc
.top
- get_system_metrics( SM_CYSMICON
)) / 2;
1648 if (!icon
) icon
= get_nc_icon_for_window( hwnd
);
1649 NtUserDrawIconEx( hdc
, pt
.x
, pt
.y
, icon
, get_system_metrics( SM_CXSMICON
),
1650 get_system_metrics( SM_CYSMICON
), 0, 0, DI_NORMAL
);
1651 rc
.left
= pt
.x
+ get_system_metrics( SM_CXSMICON
);
1655 if (flags
& DC_TEXT
)
1661 if (flags
& DC_INBUTTON
)
1662 color
= COLOR_BTNTEXT
;
1663 else if (flags
& DC_ACTIVE
)
1664 color
= COLOR_CAPTIONTEXT
;
1666 color
= COLOR_INACTIVECAPTIONTEXT
;
1667 NtGdiGetAndSetDCDword( hdc
, NtGdiSetTextColor
, get_sys_color( color
), NULL
);
1668 NtGdiGetAndSetDCDword( hdc
, NtGdiSetBkMode
, TRANSPARENT
, NULL
);
1671 prev_font
= NtGdiSelectFont( hdc
, font
);
1674 NONCLIENTMETRICSW nclm
;
1677 nclm
.cbSize
= sizeof(NONCLIENTMETRICSW
);
1678 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &nclm
, 0 );
1679 lf
= (flags
& DC_SMALLCAP
) ? &nclm
.lfSmCaptionFont
: &nclm
.lfCaptionFont
;
1680 new_font
= NtGdiHfontCreate( lf
, sizeof(*lf
), 0, 0, NULL
);
1681 prev_font
= NtGdiSelectFont( hdc
, new_font
);
1686 if (!get_window_text( hwnd
, text
, ARRAY_SIZE( text
))) text
[0] = 0;
1690 DrawTextW( hdc
, str
, -1, &rc
, ((flags
& 0x4000) ? DT_CENTER
: DT_LEFT
) |
1691 DT_SINGLELINE
| DT_VCENTER
| DT_NOPREFIX
| DT_END_ELLIPSIS
);
1694 NtGdiSelectFont( hdc
, prev_font
);
1696 NtGdiDeleteObjectApp( NtGdiSelectFont( hdc
, prev_font
));
1699 if (flags
& 0x2000) FIXME( "undocumented flag (0x2000)!\n" );
1703 /* Paint the non-client area for windows */
1704 static void nc_paint( HWND hwnd
, HRGN clip
)
1707 RECT rfuzz
, rect
, clip_rect
;
1710 DWORD style
, ex_style
;
1715 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
) return;
1716 style
= win
->dwStyle
;
1717 ex_style
= win
->dwExStyle
;
1719 release_win_ptr( win
);
1721 active
= flags
& WIN_NCACTIVATED
;
1723 TRACE( "%p %d\n", hwnd
, active
);
1725 get_window_rects( hwnd
, COORDS_SCREEN
, NULL
, &rectClient
, get_thread_dpi() );
1726 hrgn
= NtGdiCreateRectRgn( rectClient
.left
, rectClient
.top
,
1727 rectClient
.right
, rectClient
.bottom
);
1731 NtGdiCombineRgn( hrgn
, clip
, hrgn
, RGN_DIFF
);
1732 hdc
= NtUserGetDCEx( hwnd
, hrgn
, DCX_USESTYLE
| DCX_WINDOW
| DCX_INTERSECTRGN
);
1736 hdc
= NtUserGetDCEx( hwnd
, hrgn
, DCX_USESTYLE
| DCX_WINDOW
| DCX_EXCLUDERGN
);
1741 NtGdiDeleteObjectApp( hrgn
);
1745 get_window_rects( hwnd
, COORDS_WINDOW
, &rect
, NULL
, get_thread_dpi() );
1746 NtGdiGetAppClipBox( hdc
, &clip_rect
);
1748 NtGdiSelectPen( hdc
, get_sys_color_pen( COLOR_WINDOWFRAME
));
1750 if (has_static_outer_frame( ex_style
))
1751 draw_rect_edge( hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
| BF_ADJUST
, 1 );
1752 else if (has_big_frame( style
, ex_style
))
1753 draw_rect_edge( hdc
, &rect
, EDGE_RAISED
, BF_RECT
| BF_ADJUST
, 1 );
1755 draw_nc_frame( hdc
, &rect
, active
, style
, ex_style
);
1757 if ((style
& WS_CAPTION
) == WS_CAPTION
)
1760 if (ex_style
& WS_EX_TOOLWINDOW
)
1762 r
.bottom
= rect
.top
+ get_system_metrics( SM_CYSMCAPTION
);
1763 rect
.top
+= get_system_metrics( SM_CYSMCAPTION
);
1766 r
.bottom
= rect
.top
+ get_system_metrics( SM_CYCAPTION
);
1767 rect
.top
+= get_system_metrics( SM_CYCAPTION
);
1770 if (intersect_rect( &rfuzz
, &r
, &clip_rect
))
1771 draw_nc_caption( hdc
, &r
, hwnd
, style
, ex_style
, active
);
1774 if (has_menu( hwnd
, style
))
1779 r
.bottom
= rect
.top
+ get_system_metrics( SM_CYMENU
);
1781 TRACE( "drawing menu with rect %s\n", wine_dbgstr_rect( &r
));
1783 menu
= get_menu( hwnd
);
1784 if (!is_menu( menu
)) rect
.top
+= get_system_metrics( SM_CYMENU
);
1785 else rect
.top
+= NtUserDrawMenuBarTemp( hwnd
, hdc
, &r
, menu
, NULL
);
1788 TRACE( "rect after menu %s\n", wine_dbgstr_rect( &rect
));
1790 if (ex_style
& WS_EX_CLIENTEDGE
)
1791 draw_rect_edge( hdc
, &rect
, EDGE_SUNKEN
, BF_RECT
| BF_ADJUST
, 1 );
1793 /* Draw the scroll-bars */
1794 draw_nc_scrollbar( hwnd
, hdc
, style
& WS_HSCROLL
, style
& WS_VSCROLL
);
1796 /* Draw the "size-box" */
1797 if ((style
& WS_VSCROLL
) && (style
& WS_HSCROLL
))
1800 if ((ex_style
& WS_EX_LEFTSCROLLBAR
) != 0)
1801 r
.right
= r
.left
+ get_system_metrics( SM_CXVSCROLL
) + 1;
1803 r
.left
= r
.right
- get_system_metrics( SM_CXVSCROLL
) + 1;
1804 r
.top
= r
.bottom
- get_system_metrics( SM_CYHSCROLL
) + 1;
1805 fill_rect( hdc
, &r
, get_sys_color_brush( COLOR_BTNFACE
) );
1808 NtUserReleaseDC( hwnd
, hdc
);
1811 static LRESULT
handle_nc_paint( HWND hwnd
, HRGN clip
)
1813 HWND parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
1814 DWORD style
= get_window_long( hwnd
, GWL_STYLE
);
1816 if (style
& WS_VISIBLE
)
1818 nc_paint( hwnd
, clip
);
1820 if (parent
== get_desktop_window())
1821 NtUserPostMessage( parent
, WM_PARENTNOTIFY
, WM_NCPAINT
, (LPARAM
)hwnd
);
1826 static LRESULT
handle_nc_activate( HWND hwnd
, WPARAM wparam
, LPARAM lparam
)
1828 /* Lotus Notes draws menu descriptions in the caption of its main
1829 * window. When it wants to restore original "system" view, it just
1830 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1831 * attempt to minimize redrawings lead to a not restored caption.
1833 if (wparam
) win_set_flags( hwnd
, WIN_NCACTIVATED
, 0 );
1834 else win_set_flags( hwnd
, 0, WIN_NCACTIVATED
);
1836 /* This isn't documented but is reproducible in at least XP SP2 and
1837 * Outlook 2007 depends on it
1841 nc_paint( hwnd
, (HRGN
)1 );
1843 if (NtUserGetAncestor( hwnd
, GA_PARENT
) == get_desktop_window())
1844 NtUserPostMessage( get_desktop_window(), WM_PARENTNOTIFY
, WM_NCACTIVATE
, (LPARAM
)hwnd
);
1850 static void handle_nc_calc_size( HWND hwnd
, WPARAM wparam
, RECT
*win_rect
)
1852 RECT rect
= { 0, 0, 0, 0 };
1853 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
1854 LONG ex_style
= get_window_long( hwnd
, GWL_EXSTYLE
);
1856 if (!win_rect
) return;
1858 if (!(style
& WS_MINIMIZE
))
1860 AdjustWindowRectEx( &rect
, style
, FALSE
, ex_style
& ~WS_EX_CLIENTEDGE
);
1862 win_rect
->left
-= rect
.left
;
1863 win_rect
->top
-= rect
.top
;
1864 win_rect
->right
-= rect
.right
;
1865 win_rect
->bottom
-= rect
.bottom
;
1867 if (((style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) && get_menu( hwnd
))
1869 TRACE( "getting menu bar height with hwnd %p, width %d, at (%d, %d)\n",
1870 hwnd
, (int)(win_rect
->right
- win_rect
->left
), (int)-rect
.left
, (int)-rect
.top
);
1872 win_rect
->top
+= get_menu_bar_height( hwnd
, win_rect
->right
- win_rect
->left
,
1873 -rect
.left
, -rect
.top
);
1876 if (ex_style
& WS_EX_CLIENTEDGE
)
1877 if (win_rect
->right
- win_rect
->left
> 2 * get_system_metrics( SM_CXEDGE
) &&
1878 win_rect
->bottom
- win_rect
->top
> 2 * get_system_metrics( SM_CYEDGE
))
1879 InflateRect( win_rect
, -get_system_metrics( SM_CXEDGE
),
1880 -get_system_metrics( SM_CYEDGE
));
1882 if ((style
& WS_VSCROLL
) &&
1883 win_rect
->right
- win_rect
->left
>= get_system_metrics( SM_CXVSCROLL
))
1885 /* rectangle is in screen coords when wparam is false */
1886 if (!wparam
&& (ex_style
& WS_EX_LAYOUTRTL
)) ex_style
^= WS_EX_LEFTSCROLLBAR
;
1888 if (ex_style
& WS_EX_LEFTSCROLLBAR
)
1889 win_rect
->left
+= get_system_metrics( SM_CXVSCROLL
);
1891 win_rect
->right
-= get_system_metrics( SM_CXVSCROLL
);
1894 if ((style
& WS_HSCROLL
) &&
1895 win_rect
->bottom
- win_rect
->top
> get_system_metrics( SM_CYHSCROLL
))
1897 win_rect
->bottom
-= get_system_metrics( SM_CYHSCROLL
);
1900 if (win_rect
->top
> win_rect
->bottom
) win_rect
->bottom
= win_rect
->top
;
1901 if (win_rect
->left
> win_rect
->right
) win_rect
->right
= win_rect
->left
;
1905 win_rect
->right
= win_rect
->left
;
1906 win_rect
->bottom
= win_rect
->top
;
1910 LRESULT
handle_nc_hit_test( HWND hwnd
, POINT pt
)
1912 RECT rect
, client_rect
;
1913 DWORD style
, ex_style
;
1915 TRACE( "hwnd %p pt %d,%d\n", hwnd
, (int)pt
.x
, (int)pt
.y
);
1917 get_window_rects( hwnd
, COORDS_SCREEN
, &rect
, &client_rect
, get_thread_dpi() );
1918 if (!PtInRect( &rect
, pt
)) return HTNOWHERE
;
1920 style
= get_window_long( hwnd
, GWL_STYLE
);
1921 ex_style
= get_window_long( hwnd
, GWL_EXSTYLE
);
1923 if (PtInRect( &client_rect
, pt
)) return HTCLIENT
;
1926 if (has_thick_frame( style
, ex_style
))
1928 InflateRect( &rect
, -get_system_metrics( SM_CXFRAME
), -get_system_metrics( SM_CYFRAME
));
1929 if (!PtInRect( &rect
, pt
))
1931 /* Check top sizing border */
1932 if (pt
.y
< rect
.top
)
1934 if (pt
.x
< rect
.left
+ get_system_metrics( SM_CXSIZE
)) return HTTOPLEFT
;
1935 if (pt
.x
>= rect
.right
- get_system_metrics( SM_CXSIZE
)) return HTTOPRIGHT
;
1938 /* Check bottom sizing border */
1939 if (pt
.y
>= rect
.bottom
)
1941 if (pt
.x
< rect
.left
+ get_system_metrics( SM_CXSIZE
)) return HTBOTTOMLEFT
;
1942 if (pt
.x
>= rect
.right
- get_system_metrics( SM_CXSIZE
)) return HTBOTTOMRIGHT
;
1945 /* Check left sizing border */
1946 if (pt
.x
< rect
.left
)
1948 if (pt
.y
< rect
.top
+ get_system_metrics( SM_CYSIZE
)) return HTTOPLEFT
;
1949 if (pt
.y
>= rect
.bottom
- get_system_metrics( SM_CYSIZE
)) return HTBOTTOMLEFT
;
1952 /* Check right sizing border */
1953 if (pt
.x
>= rect
.right
)
1955 if (pt
.y
< rect
.top
+ get_system_metrics( SM_CYSIZE
)) return HTTOPRIGHT
;
1956 if (pt
.y
>= rect
.bottom
-get_system_metrics( SM_CYSIZE
)) return HTBOTTOMRIGHT
;
1961 else /* No thick frame */
1963 if (has_dialog_frame( style
, ex_style
))
1964 InflateRect( &rect
, -get_system_metrics( SM_CXDLGFRAME
),
1965 -get_system_metrics( SM_CYDLGFRAME
));
1966 else if (has_thin_frame( style
))
1967 InflateRect(&rect
, -get_system_metrics( SM_CXBORDER
),
1968 -get_system_metrics( SM_CYBORDER
));
1969 if (!PtInRect( &rect
, pt
)) return HTBORDER
;
1973 if ((style
& WS_CAPTION
) == WS_CAPTION
)
1975 if (ex_style
& WS_EX_TOOLWINDOW
)
1976 rect
.top
+= get_system_metrics( SM_CYSMCAPTION
) - 1;
1978 rect
.top
+= get_system_metrics( SM_CYCAPTION
) - 1;
1979 if (!PtInRect( &rect
, pt
))
1981 BOOL min_or_max_box
= (style
& WS_SYSMENU
) && (style
& (WS_MINIMIZEBOX
| WS_MAXIMIZEBOX
));
1982 if (ex_style
& WS_EX_LAYOUTRTL
)
1984 /* Check system menu */
1985 if ((style
& WS_SYSMENU
) && !(ex_style
& WS_EX_TOOLWINDOW
) &&
1986 get_nc_icon_for_window( hwnd
))
1988 rect
.right
-= get_system_metrics( SM_CYCAPTION
) - 1;
1989 if (pt
.x
> rect
.right
) return HTSYSMENU
;
1992 /* Check close button */
1993 if (style
& WS_SYSMENU
)
1995 rect
.left
+= get_system_metrics( SM_CYCAPTION
);
1996 if (pt
.x
< rect
.left
) return HTCLOSE
;
1999 if (min_or_max_box
&& !(ex_style
& WS_EX_TOOLWINDOW
))
2001 /* Check maximize box */
2002 rect
.left
+= get_system_metrics( SM_CXSIZE
);
2003 if (pt
.x
< rect
.left
) return HTMAXBUTTON
;
2005 /* Check minimize box */
2006 rect
.left
+= get_system_metrics( SM_CXSIZE
);
2007 if (pt
.x
< rect
.left
) return HTMINBUTTON
;
2012 /* Check system menu */
2013 if ((style
& WS_SYSMENU
) && !(ex_style
& WS_EX_TOOLWINDOW
) &&
2014 get_nc_icon_for_window( hwnd
))
2016 rect
.left
+= get_system_metrics( SM_CYCAPTION
) - 1;
2017 if (pt
.x
< rect
.left
) return HTSYSMENU
;
2020 /* Check close button */
2021 if (style
& WS_SYSMENU
)
2023 rect
.right
-= get_system_metrics( SM_CYCAPTION
);
2024 if (pt
.x
> rect
.right
) return HTCLOSE
;
2027 if (min_or_max_box
&& !(ex_style
& WS_EX_TOOLWINDOW
))
2029 /* Check maximize box */
2030 rect
.right
-= get_system_metrics( SM_CXSIZE
);
2031 if (pt
.x
> rect
.right
) return HTMAXBUTTON
;
2033 /* Check minimize box */
2034 rect
.right
-= get_system_metrics( SM_CXSIZE
);
2035 if (pt
.x
> rect
.right
) return HTMINBUTTON
;
2042 /* Check menu bar */
2043 if (has_menu( hwnd
, style
) && (pt
.y
< client_rect
.top
) &&
2044 (pt
.x
>= client_rect
.left
) && (pt
.x
< client_rect
.right
))
2047 /* Check vertical scroll bar */
2048 if (ex_style
& WS_EX_LAYOUTRTL
) ex_style
^= WS_EX_LEFTSCROLLBAR
;
2049 if (style
& WS_VSCROLL
)
2051 if (ex_style
& WS_EX_LEFTSCROLLBAR
)
2052 client_rect
.left
-= get_system_metrics( SM_CXVSCROLL
);
2054 client_rect
.right
+= get_system_metrics( SM_CXVSCROLL
);
2055 if (PtInRect( &client_rect
, pt
)) return HTVSCROLL
;
2058 /* Check horizontal scroll bar */
2059 if (style
& WS_HSCROLL
)
2061 client_rect
.bottom
+= get_system_metrics( SM_CYHSCROLL
);
2062 if (PtInRect( &client_rect
, pt
))
2064 /* Check size box */
2065 if ((style
& WS_VSCROLL
) &&
2066 ((ex_style
& WS_EX_LEFTSCROLLBAR
)
2067 ? (pt
.x
<= client_rect
.left
+ get_system_metrics( SM_CXVSCROLL
))
2068 : (pt
.x
>= client_rect
.right
- get_system_metrics( SM_CXVSCROLL
))))
2074 /* Has to return HTNOWHERE if nothing was found
2075 Could happen when a window has a customized non client area */
2079 static void track_min_max_box( HWND hwnd
, WORD wparam
)
2081 HDC hdc
= NtUserGetWindowDC( hwnd
);
2082 DWORD style
= get_window_long( hwnd
, GWL_STYLE
);
2083 HMENU sys_menu
= NtUserGetSystemMenu(hwnd
, FALSE
);
2084 void (*paint_button
)( HWND
, HDC
, BOOL
, BOOL
);
2085 BOOL pressed
= TRUE
;
2089 if (wparam
== HTMINBUTTON
)
2091 /* If the style is not present, do nothing */
2092 if (!(style
& WS_MINIMIZEBOX
)) return;
2094 /* Check if the sysmenu item for minimize is there */
2095 state
= get_menu_state( sys_menu
, SC_MINIMIZE
, MF_BYCOMMAND
);
2096 paint_button
= draw_min_button
;
2100 /* If the style is not present, do nothing */
2101 if (!(style
& WS_MAXIMIZEBOX
)) return;
2103 /* Check if the sysmenu item for maximize is there */
2104 state
= get_menu_state( sys_menu
, SC_MAXIMIZE
, MF_BYCOMMAND
);
2105 paint_button
= draw_max_button
;
2108 NtUserSetCapture( hwnd
);
2109 paint_button( hwnd
, hdc
, TRUE
, FALSE
);
2113 BOOL oldstate
= pressed
;
2115 if (!NtUserGetMessage( &msg
, 0, WM_MOUSEFIRST
, WM_MOUSELAST
)) break;
2116 if (NtUserCallMsgFilter( &msg
, MSGF_MAX
)) continue;
2117 if(msg
.message
== WM_LBUTTONUP
) break;
2118 if(msg
.message
!= WM_MOUSEMOVE
) continue;
2120 pressed
= handle_nc_hit_test( hwnd
, msg
.pt
) == wparam
;
2121 if (pressed
!= oldstate
) paint_button( hwnd
, hdc
, pressed
, FALSE
);
2124 if (pressed
) paint_button( hwnd
, hdc
, FALSE
, FALSE
);
2127 NtUserReleaseDC( hwnd
, hdc
);
2129 /* If the minimize or maximize items of the sysmenu are not there
2130 * or if the style is not present, do nothing */
2131 if (!pressed
|| state
== 0xffffffff) return;
2133 if (wparam
== HTMINBUTTON
)
2134 send_message( hwnd
, WM_SYSCOMMAND
,
2135 is_iconic( hwnd
) ? SC_RESTORE
: SC_MINIMIZE
, MAKELONG( msg
.pt
.x
, msg
.pt
.y
));
2137 send_message( hwnd
, WM_SYSCOMMAND
,
2138 is_zoomed( hwnd
) ? SC_RESTORE
: SC_MAXIMIZE
, MAKELONG( msg
.pt
.x
, msg
.pt
.y
));
2141 static void track_close_button( HWND hwnd
, WPARAM wparam
, LPARAM lparam
)
2144 BOOL pressed
= TRUE
;
2149 if (!(sys_menu
= NtUserGetSystemMenu( hwnd
, FALSE
))) return;
2151 state
= get_menu_state( sys_menu
, SC_CLOSE
, MF_BYCOMMAND
);
2153 /* If the close item of the sysmenu is disabled or not present do nothing */
2154 if((state
& MF_DISABLED
) || (state
& MF_GRAYED
) || state
== 0xFFFFFFFF) return;
2155 hdc
= NtUserGetWindowDC( hwnd
);
2156 NtUserSetCapture( hwnd
);
2157 draw_close_button( hwnd
, hdc
, TRUE
, FALSE
);
2161 BOOL oldstate
= pressed
;
2163 if (!NtUserGetMessage( &msg
, 0, WM_MOUSEFIRST
, WM_MOUSELAST
)) break;
2164 if (NtUserCallMsgFilter( &msg
, MSGF_MAX
)) continue;
2165 if (msg
.message
== WM_LBUTTONUP
) break;
2166 if (msg
.message
!= WM_MOUSEMOVE
) continue;
2168 pressed
= handle_nc_hit_test( hwnd
, msg
.pt
) == wparam
;
2169 if (pressed
!= oldstate
) draw_close_button( hwnd
, hdc
, pressed
, FALSE
);
2172 if (pressed
) draw_close_button( hwnd
, hdc
, FALSE
, FALSE
);
2175 NtUserReleaseDC( hwnd
, hdc
);
2176 if (pressed
) send_message( hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, lparam
);
2179 static LRESULT
handle_nc_lbutton_down( HWND hwnd
, WPARAM wparam
, LPARAM lparam
)
2181 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
2183 switch (wparam
) /* Hit test */
2187 HWND top
= hwnd
, parent
;
2190 if ((get_window_long( top
, GWL_STYLE
) & (WS_POPUP
| WS_CHILD
)) != WS_CHILD
)
2192 parent
= NtUserGetAncestor( top
, GA_PARENT
);
2193 if (!parent
|| parent
== get_desktop_window()) break;
2197 if (set_foreground_window( top
, TRUE
) || (get_active_window() == top
))
2198 send_message( hwnd
, WM_SYSCOMMAND
, SC_MOVE
+ HTCAPTION
, lparam
);
2203 if (style
& WS_SYSMENU
)
2205 HDC hdc
= NtUserGetWindowDC( hwnd
);
2206 draw_nc_sys_button( hwnd
, hdc
, TRUE
);
2207 NtUserReleaseDC( hwnd
, hdc
);
2208 send_message( hwnd
, WM_SYSCOMMAND
, SC_MOUSEMENU
+ HTSYSMENU
, lparam
);
2213 send_message( hwnd
, WM_SYSCOMMAND
, SC_MOUSEMENU
, lparam
);
2217 send_message( hwnd
, WM_SYSCOMMAND
, SC_HSCROLL
+ HTHSCROLL
, lparam
);
2221 send_message( hwnd
, WM_SYSCOMMAND
, SC_VSCROLL
+ HTVSCROLL
, lparam
);
2226 track_min_max_box( hwnd
, wparam
);
2230 track_close_button( hwnd
, wparam
, lparam
);
2241 send_message( hwnd
, WM_SYSCOMMAND
, SC_SIZE
+ wparam
- (HTLEFT
- WMSZ_LEFT
), lparam
);
2250 static LRESULT
handle_nc_rbutton_down( HWND hwnd
, WPARAM wparam
, LPARAM lparam
)
2252 int hittest
= wparam
;
2259 NtUserSetCapture( hwnd
);
2262 if (!NtUserGetMessage( &msg
, 0, WM_MOUSEFIRST
, WM_MOUSELAST
)) break;
2263 if (NtUserCallMsgFilter( &msg
, MSGF_MAX
)) continue;
2264 if (msg
.message
== WM_RBUTTONUP
)
2266 hittest
= handle_nc_hit_test( hwnd
, msg
.pt
);
2271 if (hittest
== HTCAPTION
|| hittest
== HTSYSMENU
)
2272 send_message( hwnd
, WM_CONTEXTMENU
, (WPARAM
)hwnd
, MAKELPARAM( msg
.pt
.x
, msg
.pt
.y
));
2278 static LRESULT
handle_nc_button_dbl_click( HWND hwnd
, WPARAM wparam
, LPARAM lparam
)
2280 /* if this is an icon, send a restore since we are handling a double click */
2281 if (is_iconic(hwnd
))
2283 send_message( hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, lparam
);
2287 switch (wparam
) /* Hit test */
2290 /* stop processing if WS_MAXIMIZEBOX is missing */
2291 if (get_window_long( hwnd
, GWL_STYLE
) & WS_MAXIMIZEBOX
)
2292 send_message( hwnd
, WM_SYSCOMMAND
,
2293 is_zoomed( hwnd
) ? SC_RESTORE
: SC_MAXIMIZE
, lparam
);
2298 HMENU hSysMenu
= NtUserGetSystemMenu( hwnd
, FALSE
);
2299 UINT state
= get_menu_state( hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
);
2301 /* If the close item of the sysmenu is disabled or not present do nothing */
2302 if ((state
& (MF_DISABLED
| MF_GRAYED
)) || state
== 0xffffffff)
2305 send_message( hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, lparam
);
2310 send_message( hwnd
, WM_SYSCOMMAND
, SC_HSCROLL
+ HTHSCROLL
, lparam
);
2314 send_message( hwnd
, WM_SYSCOMMAND
, SC_VSCROLL
+ HTVSCROLL
, lparam
);
2320 static HBRUSH
handle_control_color( HDC hdc
, UINT type
)
2322 if (type
== CTLCOLOR_SCROLLBAR
)
2324 HBRUSH hb
= get_sys_color_brush( COLOR_SCROLLBAR
);
2325 COLORREF bk
= get_sys_color( COLOR_3DHILIGHT
);
2326 NtGdiGetAndSetDCDword( hdc
, NtGdiSetTextColor
, get_sys_color( COLOR_3DFACE
), NULL
);
2327 NtGdiGetAndSetDCDword( hdc
, NtGdiSetBkColor
, bk
, NULL
);
2329 /* if COLOR_WINDOW happens to be the same as COLOR_3DHILIGHT
2330 * we better use 0x55aa bitmap brush to make scrollbar's background
2331 * look different from the window background.
2333 if (bk
== get_sys_color( COLOR_WINDOW
)) return get_55aa_brush();
2335 NtGdiUnrealizeObject( hb
);
2339 NtGdiGetAndSetDCDword( hdc
, NtGdiSetTextColor
, get_sys_color( COLOR_WINDOWTEXT
), NULL
);
2341 if (type
== CTLCOLOR_EDIT
|| type
== CTLCOLOR_LISTBOX
)
2342 NtGdiGetAndSetDCDword( hdc
, NtGdiSetBkColor
, get_sys_color( COLOR_WINDOW
), NULL
);
2345 NtGdiGetAndSetDCDword( hdc
, NtGdiSetBkColor
, get_sys_color( COLOR_3DFACE
), NULL
);
2346 return get_sys_color_brush( COLOR_3DFACE
);
2349 return get_sys_color_brush( COLOR_WINDOW
);
2352 static LRESULT
handle_nc_mouse_move( HWND hwnd
, WPARAM wparam
, LPARAM lparam
)
2357 TRACE( "hwnd=%p wparam=%#lx lparam=%#lx\n", hwnd
, (long)wparam
, lparam
);
2359 if (wparam
!= HTHSCROLL
&& wparam
!= HTVSCROLL
)
2362 get_window_rects( hwnd
, COORDS_CLIENT
, &rect
, NULL
, get_thread_dpi() );
2364 pt
.x
= (short)LOWORD( lparam
);
2365 pt
.y
= (short)HIWORD( lparam
);
2366 screen_to_client( hwnd
, &pt
);
2369 handle_scroll_event( hwnd
, wparam
== HTHSCROLL
? SB_HORZ
: SB_VERT
, WM_NCMOUSEMOVE
, pt
);
2373 static LRESULT
handle_nc_mouse_leave( HWND hwnd
)
2375 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
2378 TRACE( "hwnd=%p\n", hwnd
);
2380 if (style
& WS_HSCROLL
)
2381 handle_scroll_event( hwnd
, SB_HORZ
, WM_NCMOUSELEAVE
, pt
);
2382 if (style
& WS_VSCROLL
)
2383 handle_scroll_event( hwnd
, SB_VERT
, WM_NCMOUSELEAVE
, pt
);
2388 LRESULT
default_window_proc( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
, BOOL ansi
)
2397 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*)lparam
;
2398 set_window_text( hwnd
, cs
->lpszName
, ansi
);
2400 if (cs
->style
& (WS_HSCROLL
| WS_VSCROLL
))
2402 SCROLLINFO si
= { .cbSize
= sizeof(si
), .fMask
= SIF_ALL
, .nMax
= 100 };
2403 NtUserSetScrollInfo( hwnd
, SB_HORZ
, &si
, FALSE
);
2404 NtUserSetScrollInfo( hwnd
, SB_VERT
, &si
, FALSE
);
2413 WND
*win
= get_win_ptr( hwnd
);
2417 free( win
->pScroll
);
2418 win
->pScroll
= NULL
;
2419 release_win_ptr( win
);
2424 handle_nc_calc_size( hwnd
, wparam
, (RECT
*)lparam
);
2430 pt
.x
= (short)LOWORD( lparam
);
2431 pt
.y
= (short)HIWORD( lparam
);
2432 return handle_nc_hit_test( hwnd
, pt
);
2436 return handle_nc_paint( hwnd
, (HRGN
)wparam
);
2439 return handle_nc_activate( hwnd
, wparam
, lparam
);
2441 case WM_NCLBUTTONDOWN
:
2442 return handle_nc_lbutton_down( hwnd
, wparam
, lparam
);
2444 case WM_NCRBUTTONDOWN
:
2445 return handle_nc_rbutton_down( hwnd
, wparam
, lparam
);
2447 case WM_LBUTTONDBLCLK
:
2448 return handle_nc_button_dbl_click( hwnd
, HTCLIENT
, lparam
);
2450 case WM_NCLBUTTONDBLCLK
:
2451 return handle_nc_button_dbl_click( hwnd
, wparam
, lparam
);
2453 case WM_NCMOUSEMOVE
:
2454 result
= handle_nc_mouse_move( hwnd
, wparam
, lparam
);
2457 case WM_NCMOUSELEAVE
:
2458 result
= handle_nc_mouse_leave( hwnd
);
2464 pt
.x
= (short)LOWORD( lparam
);
2465 pt
.y
= (short)HIWORD( lparam
);
2466 client_to_screen( hwnd
, &pt
);
2467 send_message( hwnd
, WM_CONTEXTMENU
, (WPARAM
)hwnd
, MAKELPARAM( pt
.x
, pt
.y
));
2471 case WM_NCRBUTTONUP
:
2475 case WM_NCXBUTTONUP
:
2476 if (HIWORD(wparam
) == XBUTTON1
|| HIWORD(wparam
) == XBUTTON2
)
2478 send_message( hwnd
, WM_APPCOMMAND
, (WPARAM
)hwnd
,
2479 MAKELPARAM( LOWORD( wparam
), FAPPCOMMAND_MOUSE
| HIWORD( wparam
)));
2483 case WM_CONTEXTMENU
:
2484 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
)
2485 send_message( get_parent( hwnd
), msg
, (WPARAM
)hwnd
, lparam
);
2490 pt
.x
= (short)LOWORD( lparam
);
2491 pt
.y
= (short)HIWORD( lparam
);
2492 hitcode
= handle_nc_hit_test( hwnd
, pt
);
2494 /* Track system popup if click was in the caption area. */
2495 if (hitcode
== HTCAPTION
|| hitcode
== HTSYSMENU
)
2496 NtUserTrackPopupMenuEx( NtUserGetSystemMenu( hwnd
, FALSE
),
2497 TPM_LEFTBUTTON
| TPM_RIGHTBUTTON
,
2498 pt
.x
, pt
.y
, hwnd
, NULL
);
2502 case WM_POPUPSYSTEMMENU
:
2503 /* This is an undocumented message used by the windows taskbar to
2504 * display the system menu of windows that belong to other processes. */
2505 NtUserTrackPopupMenuEx( NtUserGetSystemMenu( hwnd
, FALSE
), TPM_LEFTBUTTON
| TPM_RIGHTBUTTON
,
2506 (short)LOWORD(lparam
), (short)HIWORD(lparam
), hwnd
, NULL
);
2509 case WM_WINDOWPOSCHANGING
:
2510 return handle_window_pos_changing( hwnd
, (WINDOWPOS
*)lparam
);
2512 case WM_WINDOWPOSCHANGED
:
2513 handle_window_pos_changed( hwnd
, (const WINDOWPOS
*)lparam
);
2520 HDC hdc
= NtUserBeginPaint( hwnd
, &ps
);
2524 if (is_iconic(hwnd
) && ((icon
= UlongToHandle( get_class_long( hwnd
, GCLP_HICON
, FALSE
)))))
2529 get_client_rect( hwnd
, &rc
);
2530 x
= (rc
.right
- rc
.left
- get_system_metrics( SM_CXICON
)) / 2;
2531 y
= (rc
.bottom
- rc
.top
- get_system_metrics( SM_CYICON
)) / 2;
2532 TRACE( "Painting class icon: vis rect=(%s)\n", wine_dbgstr_rect(&ps
.rcPaint
) );
2533 NtUserDrawIconEx( hdc
, x
, y
, icon
, 0, 0, 0, 0, DI_NORMAL
| DI_COMPAT
| DI_DEFAULTSIZE
);
2535 NtUserEndPaint( hwnd
, &ps
);
2541 NtUserRedrawWindow ( hwnd
, NULL
, 0, RDW_ERASENOW
| RDW_ERASE
| RDW_ALLCHILDREN
);
2545 if (wparam
) set_window_style( hwnd
, WS_VISIBLE
, 0 );
2548 NtUserRedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_VALIDATE
);
2549 set_window_style( hwnd
, 0, WS_VISIBLE
);
2554 NtUserDestroyWindow( hwnd
);
2557 case WM_MOUSEACTIVATE
:
2558 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
)
2560 result
= send_message( get_parent(hwnd
), WM_MOUSEACTIVATE
, wparam
, lparam
);
2564 /* Caption clicks are handled by handle_nc_lbutton_down() */
2565 result
= HIWORD(lparam
) == WM_LBUTTONDOWN
&& LOWORD(lparam
) == HTCAPTION
?
2566 MA_NOACTIVATE
: MA_ACTIVATE
;
2570 /* The default action in Windows is to set the keyboard focus to
2571 * the window, if it's being activated and not minimized */
2572 if (LOWORD(wparam
) != WA_INACTIVE
&& !is_iconic( hwnd
)) NtUserSetFocus( hwnd
);
2576 case WM_MOUSEHWHEEL
:
2577 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
)
2578 result
= send_message( get_parent( hwnd
), msg
, wparam
, lparam
);
2582 case WM_ICONERASEBKGND
:
2585 HDC hdc
= (HDC
)wparam
;
2586 HBRUSH hbr
= UlongToHandle( get_class_long( hwnd
, GCLP_HBRBACKGROUND
, FALSE
));
2589 if (get_class_long( hwnd
, GCL_STYLE
, FALSE
) & CS_PARENTDC
)
2591 /* can't use GetClipBox with a parent DC or we fill the whole parent */
2592 get_client_rect( hwnd
, &rect
);
2593 NtGdiTransformPoints( hdc
, (POINT
*)&rect
, (POINT
*)&rect
, 1, NtGdiDPtoLP
);
2595 else NtGdiGetAppClipBox( hdc
, &rect
);
2596 fill_rect( hdc
, &rect
, hbr
);
2606 if (get_capture() == hwnd
) release_capture();
2610 result
= set_window_text( hwnd
, (void *)lparam
, ansi
);
2611 if (result
&& (get_window_long( hwnd
, GWL_STYLE
) & WS_CAPTION
) == WS_CAPTION
)
2612 handle_nc_paint( hwnd
, (HRGN
)1 ); /* repaint caption */
2615 case WM_GETTEXTLENGTH
:
2617 WND
*win
= get_win_ptr( hwnd
);
2618 if (win
&& win
->text
)
2621 result
= win32u_wctomb_size( &ansi_cp
, win
->text
, wcslen( win
->text
));
2623 result
= wcslen( win
->text
);
2625 release_win_ptr( win
);
2634 if (!(win
= get_win_ptr( hwnd
))) break;
2640 char *dest
= (char *)lparam
;
2642 result
= win32u_wctomb( &ansi_cp
, dest
, wparam
- 1,
2643 win
->text
, wcslen( win
->text
));
2648 WCHAR
*dest
= (WCHAR
*)lparam
;
2649 if (win
->text
) result
= min( wcslen( win
->text
), wparam
- 1 );
2650 if (result
) memcpy( dest
, win
->text
, result
* sizeof(WCHAR
) );
2659 release_win_ptr( win
);
2664 result
= (LRESULT
)set_window_icon( hwnd
, wparam
, (HICON
)lparam
);
2665 if ((get_window_long( hwnd
, GWL_STYLE
) & WS_CAPTION
) == WS_CAPTION
)
2666 handle_nc_paint( hwnd
, (HRGN
)1 ); /* repaint caption */
2670 result
= (LRESULT
)get_window_icon( hwnd
, wparam
);
2674 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
)
2676 /* with the exception of the border around a resizable window,
2677 * give the parent first chance to set the cursor */
2678 if ((LOWORD( lparam
) < HTSIZEFIRST
) || (LOWORD( lparam
) > HTSIZELAST
))
2680 HWND parent
= get_parent( hwnd
);
2681 if (parent
!= get_desktop_window() &&
2682 send_message( parent
, WM_SETCURSOR
, wparam
, lparam
)) return TRUE
;
2685 handle_set_cursor( hwnd
, wparam
, lparam
);
2690 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
2692 if (!lparam
) break; /* sent from ShowWindow */
2693 if ((style
& WS_VISIBLE
) && wparam
) break;
2694 if (!(style
& WS_VISIBLE
) && !wparam
) break;
2695 if (!get_window_relative( hwnd
, GW_OWNER
)) break;
2696 if (!(win
= get_win_ptr( hwnd
))) break;
2697 if (win
== WND_OTHER_PROCESS
) break;
2700 if (!(win
->flags
& WIN_NEEDS_SHOW_OWNEDPOPUP
))
2702 release_win_ptr( win
);
2705 win
->flags
&= ~WIN_NEEDS_SHOW_OWNEDPOPUP
;
2707 else win
->flags
|= WIN_NEEDS_SHOW_OWNEDPOPUP
;
2708 release_win_ptr( win
);
2709 NtUserShowWindow( hwnd
, wparam
? SW_SHOWNOACTIVATE
: SW_HIDE
);
2713 case WM_CTLCOLORMSGBOX
:
2714 case WM_CTLCOLOREDIT
:
2715 case WM_CTLCOLORLISTBOX
:
2716 case WM_CTLCOLORBTN
:
2717 case WM_CTLCOLORDLG
:
2718 case WM_CTLCOLORSTATIC
:
2719 case WM_CTLCOLORSCROLLBAR
:
2720 return (LRESULT
)handle_control_color( (HDC
)wparam
, msg
- WM_CTLCOLORMSGBOX
);
2723 return (LRESULT
)handle_control_color( (HDC
)wparam
, HIWORD( lparam
));
2726 result
= handle_sys_command( hwnd
, wparam
, lparam
);
2729 case WM_LBUTTONDOWN
:
2730 case WM_RBUTTONDOWN
:
2731 case WM_MBUTTONDOWN
:
2732 f10_key
= menu_sys_key
= 0;
2736 if (wparam
== VK_F10
) f10_key
= VK_F10
;
2740 if (HIWORD( lparam
) & KEYDATA_ALT
)
2742 if ((wparam
== VK_MENU
|| wparam
== VK_LMENU
|| wparam
== VK_RMENU
) && !menu_sys_key
)
2749 if (wparam
== VK_F4
) /* try to close the window */
2751 HWND top
= NtUserGetAncestor( hwnd
, GA_ROOT
);
2752 if (!(get_class_long( top
, GCL_STYLE
, FALSE
) & CS_NOCLOSE
))
2753 NtUserPostMessage( top
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
2756 else if (wparam
== VK_F10
)
2758 if (NtUserGetKeyState(VK_SHIFT
) & 0x8000)
2759 send_message( hwnd
, WM_CONTEXTMENU
, (WPARAM
)hwnd
, -1 );
2762 else if (wparam
== VK_ESCAPE
&& (NtUserGetKeyState( VK_SHIFT
) & 0x8000))
2763 send_message( hwnd
, WM_SYSCOMMAND
, SC_KEYMENU
, ' ' );
2768 /* Press and release F10 or ALT */
2769 if (((wparam
== VK_MENU
|| wparam
== VK_LMENU
|| wparam
== VK_RMENU
) && menu_sys_key
) ||
2770 (wparam
== VK_F10
&& f10_key
))
2771 send_message( NtUserGetAncestor( hwnd
, GA_ROOT
), WM_SYSCOMMAND
, SC_KEYMENU
, 0 );
2772 menu_sys_key
= f10_key
= 0;
2777 if (wparam
== '\r' && is_iconic( hwnd
))
2779 NtUserPostMessage( hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, 0 );
2782 if ((HIWORD( lparam
) & KEYDATA_ALT
) && wparam
)
2788 win32u_mbtowc( &ansi_cp
, &wch
, 1, &ch
, 1 );
2791 if (wch
== '\t' || wch
== '\x1b') break;
2792 if (wch
== ' ' && (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
))
2793 send_message( get_parent( hwnd
), msg
, wch
, lparam
);
2795 send_message( hwnd
, WM_SYSCOMMAND
, SC_KEYMENU
, wch
);
2797 else if (wparam
!= '\x1b') /* Ctrl-Esc */
2805 hi
.cbSize
= sizeof(HELPINFO
);
2806 get_cursor_pos( &hi
.MousePos
);
2807 if (is_menu_active())
2809 MENUINFO info
= { .cbSize
= sizeof(info
), .fMask
= MIM_HELPID
};
2810 hi
.iContextType
= HELPINFO_MENUITEM
;
2811 hi
.hItemHandle
= is_menu_active();
2812 hi
.iCtrlId
= NtUserMenuItemFromPoint( hwnd
, hi
.hItemHandle
,
2813 hi
.MousePos
.x
, hi
.MousePos
.y
);
2814 get_menu_info( hi
.hItemHandle
, &info
);
2815 hi
.dwContextId
= info
.dwContextHelpID
;
2819 hi
.iContextType
= HELPINFO_WINDOW
;
2820 hi
.hItemHandle
= hwnd
;
2821 hi
.iCtrlId
= get_window_long_ptr( hwnd
, GWLP_ID
, FALSE
);
2822 hi
.dwContextId
= get_window_context_help_id( hwnd
);
2824 send_message( hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
2829 if ((lparam
& PRF_CHECKVISIBLE
) && !is_window_visible ( hwnd
)) break;
2831 if (lparam
& (PRF_CHILDREN
| PRF_OWNED
| PRF_NONCLIENT
))
2832 WARN( "WM_PRINT message with unsupported lparam %lx\n", lparam
);
2834 if (lparam
& PRF_ERASEBKGND
) send_message( hwnd
, WM_ERASEBKGND
, wparam
, 0 );
2835 if (lparam
& PRF_CLIENT
) send_message(hwnd
, WM_PRINTCLIENT
, wparam
, lparam
);
2840 HWND parent
= get_parent( hwnd
);
2842 call_hooks( WH_SHELL
, HSHELL_APPCOMMAND
, wparam
, lparam
, 0 );
2844 send_message( parent
, msg
, wparam
, lparam
);
2857 case WM_QUERYDROPOBJECT
:
2858 result
= (get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
) != 0;
2861 case WM_QUERYDRAGICON
:
2864 HICON icon
= (HICON
)get_class_long_ptr( hwnd
, GCLP_HICON
, FALSE
);
2865 HINSTANCE instance
= (HINSTANCE
)get_window_long_ptr( hwnd
, GWLP_HINSTANCE
, FALSE
);
2869 result
= (LRESULT
)icon
;
2873 for (len
= 1; len
< 64; len
++)
2875 if((icon
= LoadImageW( instance
, MAKEINTRESOURCEW( len
), IMAGE_ICON
, 0, 0,
2876 LR_SHARED
| LR_DEFAULTSIZE
)))
2878 result
= (LRESULT
)icon
;
2882 if (!result
) result
= (LRESULT
)LoadImageW( 0, (WCHAR
*)IDI_APPLICATION
, IMAGE_ICON
,
2883 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
2887 case WM_ISACTIVEICON
:
2888 result
= (win_get_flags( hwnd
) & WIN_NCACTIVATED
) != 0;
2891 case WM_NOTIFYFORMAT
:
2892 result
= is_window_unicode(hwnd
) ? NFR_UNICODE
: NFR_ANSI
;
2896 case WM_QUERYENDSESSION
:
2901 send_message( get_parent( hwnd
), msg
, wparam
, lparam
);
2904 case WM_STYLECHANGED
:
2905 if (wparam
== GWL_STYLE
&& (get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_LAYERED
))
2907 STYLESTRUCT
*style
= (STYLESTRUCT
*)lparam
;
2908 if ((style
->styleOld
^ style
->styleNew
) & (WS_CAPTION
|WS_THICKFRAME
|WS_VSCROLL
|WS_HSCROLL
))
2909 NtUserSetWindowPos( hwnd
, 0, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOZORDER
|
2910 SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOCLIENTSIZE
| SWP_NOCLIENTMOVE
);
2914 case WM_INPUTLANGCHANGEREQUEST
:
2915 NtUserActivateKeyboardLayout( (HKL
)lparam
, 0 );
2918 case WM_INPUTLANGCHANGE
:
2920 struct user_thread_info
*info
= get_user_thread_info();
2921 HWND
*win_array
= list_window_children( 0, hwnd
, NULL
, 0 );
2923 info
->kbd_layout
= (HKL
)lparam
;
2927 while (win_array
[count
])
2928 send_message( win_array
[count
++], WM_INPUTLANGCHANGE
, wparam
, lparam
);
2933 case WM_IME_SETCONTEXT
:
2934 case WM_IME_COMPOSITION
:
2935 case WM_IME_STARTCOMPOSITION
:
2936 case WM_IME_ENDCOMPOSITION
:
2939 HWND ime_hwnd
= get_default_ime_window( hwnd
);
2940 if (ime_hwnd
&& ime_hwnd
!= NtUserGetParent( hwnd
))
2941 result
= NtUserMessageCall( ime_hwnd
, msg
, wparam
, lparam
,
2942 0, NtUserSendMessage
, ansi
);
2950 LRESULT
desktop_window_proc( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
2952 static const WCHAR wine_display_device_guidW
[] =
2953 {'_','_','w','i','n','e','_','d','i','s','p','l','a','y','_','d','e','v','i','c','e',
2954 '_','g','u','i','d',0};
2960 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*)lparam
;
2961 const GUID
*guid
= cs
->lpCreateParams
;
2969 if (NtUserGetAncestor( hwnd
, GA_PARENT
)) return FALSE
; /* refuse to create non-desktop window */
2971 sprintf( buffer
, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2972 (unsigned int)guid
->Data1
, guid
->Data2
, guid
->Data3
,
2973 guid
->Data4
[0], guid
->Data4
[1], guid
->Data4
[2], guid
->Data4
[3],
2974 guid
->Data4
[4], guid
->Data4
[5], guid
->Data4
[6], guid
->Data4
[7] );
2975 NtAddAtom( bufferW
, asciiz_to_unicode( bufferW
, buffer
) - sizeof(WCHAR
), &atom
);
2976 NtUserSetProp( hwnd
, wine_display_device_guidW
, ULongToHandle( atom
) );
2982 case WM_DISPLAYCHANGE
:
2983 return user_driver
->pDesktopWindowProc( hwnd
, msg
, wparam
, lparam
);
2985 if (msg
>= WM_USER
&& hwnd
== get_desktop_window())
2986 return user_driver
->pDesktopWindowProc( hwnd
, msg
, wparam
, lparam
);
2989 return default_window_proc( hwnd
, msg
, wparam
, lparam
, FALSE
);
2992 /***********************************************************************
2993 * NtUserGetTitleBarInfo (win32u.@)
2995 BOOL WINAPI
NtUserGetTitleBarInfo( HWND hwnd
, TITLEBARINFO
*info
)
2997 DWORD style
, ex_style
;
2999 TRACE( "(%p %p)\n", hwnd
, info
);
3003 RtlSetLastWin32Error( ERROR_NOACCESS
);
3007 if (info
->cbSize
!= sizeof(TITLEBARINFO
))
3009 TRACE( "Invalid TITLEBARINFO size: %d\n", (int)info
->cbSize
);
3010 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
3014 style
= get_window_long( hwnd
, GWL_STYLE
);
3015 ex_style
= get_window_long( hwnd
, GWL_EXSTYLE
);
3016 get_inside_rect( hwnd
, COORDS_SCREEN
, &info
->rcTitleBar
, style
, ex_style
);
3018 info
->rcTitleBar
.bottom
= info
->rcTitleBar
.top
;
3019 if (ex_style
& WS_EX_TOOLWINDOW
)
3020 info
->rcTitleBar
.bottom
+= get_system_metrics( SM_CYSMCAPTION
);
3023 info
->rcTitleBar
.bottom
+= get_system_metrics( SM_CYCAPTION
);
3024 info
->rcTitleBar
.left
+= get_system_metrics( SM_CXSIZE
);
3027 memset( info
->rgstate
, 0, sizeof(info
->rgstate
) );
3028 info
->rgstate
[0] = STATE_SYSTEM_FOCUSABLE
;
3030 if (style
& WS_CAPTION
)
3032 info
->rgstate
[1] = STATE_SYSTEM_INVISIBLE
;
3033 if (style
& WS_SYSMENU
)
3035 if (!(style
& (WS_MINIMIZEBOX
|WS_MAXIMIZEBOX
)))
3037 info
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
3038 info
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
3042 if (!(style
& WS_MINIMIZEBOX
))
3043 info
->rgstate
[2] = STATE_SYSTEM_UNAVAILABLE
;
3044 if (!(style
& WS_MAXIMIZEBOX
))
3045 info
->rgstate
[3] = STATE_SYSTEM_UNAVAILABLE
;
3047 if (!(ex_style
& WS_EX_CONTEXTHELP
))
3048 info
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
3049 if (get_class_long( hwnd
, GCL_STYLE
, FALSE
) & CS_NOCLOSE
)
3050 info
->rgstate
[5] = STATE_SYSTEM_UNAVAILABLE
;
3054 info
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
3055 info
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
3056 info
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
3057 info
->rgstate
[5] = STATE_SYSTEM_INVISIBLE
;
3061 info
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;