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
);
791 continue; /* We are not interested in other messages */
796 if (msg
.message
== WM_KEYDOWN
)
800 case VK_UP
: pt
.y
-= 8; break;
801 case VK_DOWN
: pt
.y
+= 8; break;
802 case VK_LEFT
: pt
.x
-= 8; break;
803 case VK_RIGHT
: pt
.x
+= 8; break;
807 pt
.x
= max( pt
.x
, mouse_rect
.left
);
808 pt
.x
= min( pt
.x
, mouse_rect
.right
- 1 );
809 pt
.y
= max( pt
.y
, mouse_rect
.top
);
810 pt
.y
= min( pt
.y
, mouse_rect
.bottom
- 1 );
817 if ((newmon
= monitor_from_point( pt
, MONITOR_DEFAULTTONULL
, get_thread_dpi() )))
820 info
.cbSize
= sizeof(info
);
821 if (mon
&& get_monitor_info( mon
, &info
))
823 pt
.x
= max( pt
.x
, info
.rcWork
.left
);
824 pt
.x
= min( pt
.x
, info
.rcWork
.right
- 1 );
825 pt
.y
= max( pt
.y
, info
.rcWork
.top
);
826 pt
.y
= min( pt
.y
, info
.rcWork
.bottom
- 1 );
830 dx
= pt
.x
- capture_point
.x
;
831 dy
= pt
.y
- capture_point
.y
;
838 if (!drag_full_windows
)
839 draw_moving_frame( parent
, hdc
, &sizing_rect
, thickframe
);
842 if (msg
.message
== WM_KEYDOWN
) NtUserSetCursorPos( pt
.x
, pt
.y
);
845 if (!drag_full_windows
) draw_moving_frame( parent
, hdc
, &sizing_rect
, thickframe
);
846 if (hittest
== HTCAPTION
|| hittest
== HTBORDER
) OffsetRect( &sizing_rect
, dx
, dy
);
847 if (on_left_border( hittest
)) sizing_rect
.left
+= dx
;
848 else if (on_right_border( hittest
)) sizing_rect
.right
+= dx
;
849 if (on_top_border( hittest
)) sizing_rect
.top
+= dy
;
850 else if (on_bottom_border( hittest
)) sizing_rect
.bottom
+= dy
;
853 /* determine the hit location */
854 if (syscommand
== SC_SIZE
&& hittest
!= HTBORDER
)
856 WPARAM sizing_hit
= 0;
858 if (hittest
>= HTLEFT
&& hittest
<= HTBOTTOMRIGHT
)
859 sizing_hit
= WMSZ_LEFT
+ (hittest
- HTLEFT
);
860 send_message( hwnd
, WM_SIZING
, sizing_hit
, (LPARAM
)&sizing_rect
);
863 send_message( hwnd
, WM_MOVING
, 0, (LPARAM
)&sizing_rect
);
865 if (!drag_full_windows
)
866 draw_moving_frame( parent
, hdc
, &sizing_rect
, thickframe
);
869 RECT rect
= sizing_rect
;
870 map_window_points( 0, parent
, (POINT
*)&rect
, 2, get_thread_dpi() );
871 NtUserSetWindowPos( hwnd
, 0, rect
.left
, rect
.top
,
872 rect
.right
- rect
.left
, rect
.bottom
- rect
.top
,
873 hittest
== HTCAPTION
? SWP_NOSIZE
: 0 );
879 if (moved
&& !drag_full_windows
)
880 draw_moving_frame( parent
, hdc
, &sizing_rect
, thickframe
);
882 set_capture_window( 0, GUI_INMOVESIZE
, NULL
);
883 NtUserReleaseDC( parent
, hdc
);
884 if (parent
) map_window_points( 0, parent
, (POINT
*)&sizing_rect
, 2, get_thread_dpi() );
886 if (call_hooks( WH_CBT
, HCBT_MOVESIZE
, (WPARAM
)hwnd
, (LPARAM
)&sizing_rect
, sizeof(sizing_rect
) ))
889 send_message( hwnd
, WM_EXITSIZEMOVE
, 0, 0 );
890 send_message( hwnd
, WM_SETVISIBLE
, !is_iconic(hwnd
), 0 );
892 /* window moved or resized */
895 /* if the moving/resizing isn't canceled call SetWindowPos
896 * with the new position or the new size of the window
898 if (!(msg
.message
== WM_KEYDOWN
&& msg
.wParam
== VK_ESCAPE
) )
900 /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
901 if (!drag_full_windows
)
902 NtUserSetWindowPos( hwnd
, 0, sizing_rect
.left
, sizing_rect
.top
,
903 sizing_rect
.right
- sizing_rect
.left
,
904 sizing_rect
.bottom
- sizing_rect
.top
,
905 hittest
== HTCAPTION
? SWP_NOSIZE
: 0 );
909 /* restore previous size/position */
910 if (drag_full_windows
)
911 NtUserSetWindowPos( hwnd
, 0, orig_rect
.left
, orig_rect
.top
,
912 orig_rect
.right
- orig_rect
.left
,
913 orig_rect
.bottom
- orig_rect
.top
,
914 hittest
== HTCAPTION
? SWP_NOSIZE
: 0 );
918 if (is_iconic(hwnd
) && !moved
&& (style
& WS_SYSMENU
))
920 /* Single click brings up the system menu when iconized */
921 send_message( hwnd
, WM_SYSCOMMAND
, SC_MOUSEMENU
+ HTSYSMENU
, MAKELONG(pt
.x
, pt
.y
) );
925 /***********************************************************************
926 * track_nc_scroll_bar
928 * Track a mouse button press on the horizontal or vertical scroll-bar.
930 static void track_nc_scroll_bar( HWND hwnd
, WPARAM wparam
, POINT pt
)
934 if ((wparam
& 0xfff0) == SC_HSCROLL
)
936 if ((wparam
& 0x0f) != HTHSCROLL
) return;
939 else /* SC_VSCROLL */
941 if ((wparam
& 0x0f) != HTVSCROLL
) return;
944 track_scroll_bar( hwnd
, scrollbar
, pt
);
947 static LRESULT
handle_sys_command( HWND hwnd
, WPARAM wparam
, LPARAM lparam
)
949 TRACE( "hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd
, (long)wparam
, lparam
);
951 if (!is_window_enabled( hwnd
)) return 0;
953 if (call_hooks( WH_CBT
, HCBT_SYSCOMMAND
, wparam
, lparam
, 0 ))
956 if (!user_driver
->pSysCommand( hwnd
, wparam
, lparam
))
959 switch (wparam
& 0xfff0)
963 sys_command_size_move( hwnd
, wparam
);
967 show_owned_popups( hwnd
, FALSE
);
968 NtUserShowWindow( hwnd
, SW_MINIMIZE
);
972 if (is_iconic(hwnd
)) show_owned_popups( hwnd
, TRUE
);
973 NtUserShowWindow( hwnd
, SW_MAXIMIZE
);
977 return send_message( hwnd
, WM_CLOSE
, 0, 0 );
983 pt
.x
= (short)LOWORD( lparam
);
984 pt
.y
= (short)HIWORD( lparam
);
985 track_nc_scroll_bar( hwnd
, wparam
, pt
);
990 track_mouse_menu_bar( hwnd
, wparam
& 0x000F, (short)LOWORD(lparam
), (short)HIWORD(lparam
) );
994 track_keyboard_menu_bar( hwnd
, wparam
, lparam
);
998 if (is_iconic( hwnd
)) show_owned_popups( hwnd
, TRUE
);
999 NtUserShowWindow( hwnd
, SW_RESTORE
);
1004 return 1; /* FIXME: handle on client side */
1010 FIXME( "unimplemented WM_SYSCOMMAND %04lx\n", (long)wparam
);
1014 return 1; /* handle on client side */
1019 /* Get the 'inside' rectangle of a window, i.e. the whole window rectangle
1020 * but without the borders (if any). */
1021 static void get_inside_rect( HWND hwnd
, enum coords_relative relative
, RECT
*rect
,
1022 DWORD style
, DWORD ex_style
)
1024 get_window_rects( hwnd
, relative
, rect
, NULL
, get_thread_dpi() );
1026 /* Remove frame from rectangle */
1027 if (has_thick_frame( style
, ex_style
))
1029 InflateRect( rect
, -get_system_metrics( SM_CXFRAME
), -get_system_metrics( SM_CYFRAME
));
1031 else if (has_dialog_frame( style
, ex_style
))
1033 InflateRect( rect
, -get_system_metrics( SM_CXDLGFRAME
), -get_system_metrics( SM_CYDLGFRAME
));
1035 else if (has_thin_frame( style
))
1037 InflateRect( rect
, -get_system_metrics( SM_CXBORDER
), -get_system_metrics( SM_CYBORDER
));
1040 /* We have additional border information if the window
1041 * is a child (but not an MDI child) */
1042 if ((style
& WS_CHILD
) && !(ex_style
& WS_EX_MDICHILD
))
1044 if (ex_style
& WS_EX_CLIENTEDGE
)
1045 InflateRect( rect
, -get_system_metrics( SM_CXEDGE
), -get_system_metrics( SM_CYEDGE
));
1046 if (ex_style
& WS_EX_STATICEDGE
)
1047 InflateRect( rect
, -get_system_metrics( SM_CXBORDER
), -get_system_metrics( SM_CYBORDER
));
1051 void get_sys_popup_pos( HWND hwnd
, RECT
*rect
)
1053 if (is_iconic(hwnd
)) get_window_rect( hwnd
, rect
, get_thread_dpi() );
1056 DWORD style
= get_window_long( hwnd
, GWL_STYLE
);
1057 DWORD ex_style
= get_window_long( hwnd
, GWL_EXSTYLE
);
1059 get_inside_rect( hwnd
, COORDS_CLIENT
, rect
, style
, ex_style
);
1060 rect
->right
= rect
->left
+ get_system_metrics( SM_CYCAPTION
) - 1;
1061 rect
->bottom
= rect
->top
+ get_system_metrics( SM_CYCAPTION
) - 1;
1062 map_window_points( hwnd
, 0, (POINT
*)rect
, 2, get_thread_dpi() );
1066 /* Draw a window frame inside the given rectangle, and update the rectangle. */
1067 static void draw_nc_frame( HDC hdc
, RECT
*rect
, BOOL active
, DWORD style
, DWORD ex_style
)
1071 if (style
& WS_THICKFRAME
)
1073 width
= get_system_metrics( SM_CXFRAME
) - get_system_metrics( SM_CXDLGFRAME
);
1074 height
= get_system_metrics( SM_CYFRAME
) - get_system_metrics( SM_CYDLGFRAME
);
1076 NtGdiSelectBrush( hdc
, get_sys_color_brush( active
? COLOR_ACTIVEBORDER
:
1077 COLOR_INACTIVEBORDER
));
1079 NtGdiPatBlt( hdc
, rect
->left
, rect
->top
, rect
->right
- rect
->left
, height
, PATCOPY
);
1080 NtGdiPatBlt( hdc
, rect
->left
, rect
->top
, width
, rect
->bottom
- rect
->top
, PATCOPY
);
1081 NtGdiPatBlt( hdc
, rect
->left
, rect
->bottom
- 1, rect
->right
- rect
->left
, -height
, PATCOPY
);
1082 NtGdiPatBlt( hdc
, rect
->right
- 1, rect
->top
, -width
, rect
->bottom
- rect
->top
, PATCOPY
);
1084 InflateRect( rect
, -width
, -height
);
1087 /* Now the other bit of the frame */
1088 if ((style
& (WS_BORDER
|WS_DLGFRAME
)) || (ex_style
& WS_EX_DLGMODALFRAME
))
1092 width
= get_system_metrics( SM_CXDLGFRAME
) - get_system_metrics( SM_CXEDGE
);
1093 height
= get_system_metrics( SM_CYDLGFRAME
) - get_system_metrics( SM_CYEDGE
);
1094 /* This should give a value of 1 that should also work for a border */
1096 if (ex_style
& (WS_EX_DLGMODALFRAME
| WS_EX_CLIENTEDGE
)) color
= COLOR_3DFACE
;
1097 else if (ex_style
& WS_EX_STATICEDGE
) color
= COLOR_WINDOWFRAME
;
1098 else if (style
& (WS_DLGFRAME
|WS_THICKFRAME
)) color
= COLOR_3DFACE
;
1099 else color
= COLOR_WINDOWFRAME
;
1100 NtGdiSelectBrush( hdc
, get_sys_color_brush( color
));
1103 NtGdiPatBlt( hdc
, rect
->left
, rect
->top
,
1104 rect
->right
- rect
->left
, height
, PATCOPY
);
1105 NtGdiPatBlt( hdc
, rect
->left
, rect
->top
,
1106 width
, rect
->bottom
- rect
->top
, PATCOPY
);
1107 NtGdiPatBlt( hdc
, rect
->left
, rect
->bottom
- 1,
1108 rect
->right
- rect
->left
, -height
, PATCOPY
);
1109 NtGdiPatBlt( hdc
, rect
->right
- 1, rect
->top
,
1110 -width
, rect
->bottom
- rect
->top
, PATCOPY
);
1112 InflateRect( rect
, -width
, -height
);
1116 static HICON
get_nc_icon_for_window( HWND hwnd
)
1119 WND
*win
= get_win_ptr( hwnd
);
1121 if (win
&& win
!= WND_OTHER_PROCESS
&& win
!= WND_DESKTOP
)
1123 icon
= win
->hIconSmall
;
1124 if (!icon
) icon
= win
->hIcon
;
1125 release_win_ptr( win
);
1127 if (!icon
) icon
= (HICON
) get_class_long_ptr( hwnd
, GCLP_HICONSM
, FALSE
);
1128 if (!icon
) icon
= (HICON
) get_class_long_ptr( hwnd
, GCLP_HICON
, FALSE
);
1130 /* If there is no icon specified and this is not a modal dialog, get the default one. */
1131 if (!icon
&& !(get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_DLGMODALFRAME
))
1132 icon
= LoadImageW( 0, (LPCWSTR
)IDI_WINLOGO
, IMAGE_ICON
, get_system_metrics( SM_CXSMICON
),
1133 get_system_metrics( SM_CYSMICON
), LR_DEFAULTCOLOR
| LR_SHARED
);
1137 /* Draws the bar part (ie the big rectangle) of the caption */
1138 static void draw_caption_bar( HDC hdc
, const RECT
*rect
, DWORD style
, BOOL active
, BOOL gradient
)
1142 TRIVERTEX vertices
[4];
1144 int buttons_size
= get_system_metrics( SM_CYCAPTION
) - 1;
1146 static GRADIENT_RECT mesh
[] = {{0, 1}, {1, 2}, {2, 3}};
1148 left
= get_sys_color( active
? COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
);
1149 right
= get_sys_color( active
? COLOR_GRADIENTACTIVECAPTION
: COLOR_GRADIENTINACTIVECAPTION
);
1150 vertices
[0].Red
= vertices
[1].Red
= GetRValue( left
) << 8;
1151 vertices
[0].Green
= vertices
[1].Green
= GetGValue( left
) << 8;
1152 vertices
[0].Blue
= vertices
[1].Blue
= GetBValue( left
) << 8;
1153 vertices
[0].Alpha
= vertices
[1].Alpha
= 0xff00;
1154 vertices
[2].Red
= vertices
[3].Red
= GetRValue( right
) << 8;
1155 vertices
[2].Green
= vertices
[3].Green
= GetGValue( right
) << 8;
1156 vertices
[2].Blue
= vertices
[3].Blue
= GetBValue( right
) << 8;
1157 vertices
[2].Alpha
= vertices
[3].Alpha
= 0xff00;
1159 if ((style
& WS_SYSMENU
) && ((style
& WS_MAXIMIZEBOX
) || (style
& WS_MINIMIZEBOX
)))
1160 buttons_size
+= 2 * (get_system_metrics( SM_CXSIZE
) + 1);
1162 /* area behind icon; solid filled with left color */
1163 vertices
[0].x
= rect
->left
;
1164 vertices
[0].y
= rect
->top
;
1165 if (style
& WS_SYSMENU
)
1166 vertices
[1].x
= min( rect
->left
+ get_system_metrics( SM_CXSMICON
), rect
->right
);
1168 vertices
[1].x
= vertices
[0].x
;
1169 vertices
[1].y
= rect
->bottom
;
1171 /* area behind text; gradient */
1172 vertices
[2].x
= max( vertices
[1].x
, rect
->right
- buttons_size
);
1173 vertices
[2].y
= rect
->top
;
1175 /* area behind buttons; solid filled with right color */
1176 vertices
[3].x
= rect
->right
;
1177 vertices
[3].y
= rect
->bottom
;
1179 NtGdiGradientFill( hdc
, vertices
, 4, mesh
, 3, GRADIENT_FILL_RECT_H
);
1183 DWORD color
= active
? COLOR_ACTIVECAPTION
: COLOR_INACTIVECAPTION
;
1184 fill_rect( hdc
, rect
, get_sys_color_brush( color
));
1188 /* Draw the system icon */
1189 BOOL
draw_nc_sys_button( HWND hwnd
, HDC hdc
, BOOL down
)
1191 HICON icon
= get_nc_icon_for_window( hwnd
);
1197 DWORD style
= get_window_long( hwnd
, GWL_STYLE
);
1198 DWORD ex_style
= get_window_long( hwnd
, GWL_EXSTYLE
);
1200 get_inside_rect( hwnd
, COORDS_WINDOW
, &rect
, style
, ex_style
);
1201 pt
.x
= rect
.left
+ 2;
1202 pt
.y
= rect
.top
+ (get_system_metrics( SM_CYCAPTION
) - get_system_metrics( SM_CYSMICON
)) / 2;
1203 NtUserDrawIconEx( hdc
, pt
.x
, pt
.y
, icon
,
1204 get_system_metrics( SM_CXSMICON
),
1205 get_system_metrics( SM_CYSMICON
), 0, 0, DI_NORMAL
);
1211 /* Create a square rectangle and return its width */
1212 static int make_square_rect( RECT
*src
, RECT
*dst
)
1214 int width
= src
->right
- src
->left
;
1215 int height
= src
->bottom
- src
->top
;
1216 int small_diam
= width
> height
? height
: width
;
1220 /* Make it a square box */
1223 dst
->top
+= (height
- width
) / 2;
1224 dst
->bottom
= dst
->top
+ small_diam
;
1226 else if (width
> height
)
1228 dst
->left
+= (width
- height
) / 2;
1229 dst
->right
= dst
->left
+ small_diam
;
1235 static void draw_checked_rect( HDC dc
, RECT
*rect
)
1237 if (get_sys_color( COLOR_BTNHIGHLIGHT
) == RGB( 255, 255, 255 ))
1242 fill_rect( dc
, rect
, get_sys_color_brush( COLOR_BTNFACE
));
1243 NtGdiGetAndSetDCDword( dc
, NtGdiSetBkColor
, RGB(255, 255, 255), &prev_bg
);
1244 prev_brush
= NtGdiSelectBrush( dc
, get_55aa_brush() );
1245 NtGdiPatBlt( dc
, rect
->left
, rect
->top
, rect
->right
-rect
->left
,
1246 rect
->bottom
-rect
->top
, 0x00fa0089 );
1247 NtGdiSelectBrush( dc
, prev_brush
);
1248 NtGdiGetAndSetDCDword( dc
, NtGdiSetBkColor
, prev_bg
, NULL
);
1252 fill_rect( dc
, rect
, get_sys_color_brush( COLOR_BTNHIGHLIGHT
));
1256 static BOOL
draw_push_button( HDC dc
, RECT
*r
, UINT flags
)
1261 if (flags
& (DFCS_PUSHED
| DFCS_CHECKED
| DFCS_FLAT
))
1266 if (flags
& DFCS_CHECKED
)
1268 if (flags
& DFCS_MONO
)
1269 draw_rect_edge( dc
, &rect
, edge
, BF_MONO
|BF_RECT
|BF_ADJUST
, 1 );
1271 draw_rect_edge( dc
, &rect
, edge
, (flags
& DFCS_FLAT
)|BF_RECT
|BF_SOFT
|BF_ADJUST
, 1 );
1272 if (!(flags
& DFCS_TRANSPARENT
)) draw_checked_rect( dc
, &rect
);
1276 if (flags
& DFCS_MONO
)
1278 draw_rect_edge( dc
, &rect
, edge
, BF_MONO
|BF_RECT
|BF_ADJUST
, 1 );
1279 if (!(flags
& DFCS_TRANSPARENT
))
1280 fill_rect( dc
, &rect
, get_sys_color_brush( COLOR_BTNFACE
));
1284 UINT edge_flags
= BF_RECT
| BF_SOFT
| (flags
& DFCS_FLAT
);
1285 if (!(flags
& DFCS_TRANSPARENT
)) edge_flags
|= BF_MIDDLE
;
1286 draw_rect_edge( dc
, r
, edge
, edge_flags
, 1 );
1290 /* Adjust rectangle if asked */
1291 if (flags
& DFCS_ADJUSTRECT
) InflateRect( r
, -2, -2 );
1295 static BOOL
draw_frame_caption( HDC dc
, RECT
*r
, UINT flags
)
1298 int small_diam
= make_square_rect( r
, &rect
) - 2;
1299 HFONT prev_font
, font
;
1300 int color_idx
= flags
& DFCS_INACTIVE
? COLOR_BTNSHADOW
: COLOR_BTNTEXT
;
1301 int xc
= (rect
.left
+ rect
.right
) / 2;
1302 int yc
= (rect
.top
+ rect
.bottom
) / 2;
1303 LOGFONTW lf
= { 0 };
1304 WCHAR str
[] = {0, 0};
1305 DWORD prev_align
, prev_bk
;
1306 COLORREF prev_color
;
1309 static const WCHAR marlettW
[] = {'M','a','r','l','e','t','t',0};
1311 draw_push_button( dc
, r
, flags
& 0xff00 );
1313 switch (flags
& 0xf)
1315 case DFCS_CAPTIONCLOSE
: str
[0] = 0x72; break;
1316 case DFCS_CAPTIONHELP
: str
[0] = 0x73; break;
1317 case DFCS_CAPTIONMIN
: str
[0] = 0x30; break;
1318 case DFCS_CAPTIONMAX
: str
[0] = 0x31; break;
1319 case DFCS_CAPTIONRESTORE
: str
[0] = 0x32; break;
1321 WARN( "Invalid caption; flags=0x%04x\n", flags
);
1325 lf
.lfHeight
= -small_diam
;
1326 lf
.lfWeight
= FW_NORMAL
;
1327 lf
.lfCharSet
= SYMBOL_CHARSET
;
1328 lf
.lfPitchAndFamily
= FIXED_PITCH
| FF_DONTCARE
;
1329 memcpy( lf
.lfFaceName
, marlettW
, sizeof(marlettW
) );
1330 font
= NtGdiHfontCreate( &lf
, sizeof(lf
), 0, 0, NULL
);
1331 NtGdiGetAndSetDCDword( dc
, NtGdiSetTextAlign
, TA_TOP
| TA_LEFT
, &prev_align
);
1332 NtGdiGetAndSetDCDword( dc
, NtGdiSetBkMode
, TRANSPARENT
, &prev_bk
);
1333 NtGdiGetDCDword( dc
, NtGdiGetTextColor
, &prev_color
);
1334 prev_font
= NtGdiSelectFont( dc
, font
);
1335 NtGdiGetTextExtentExW( dc
, str
, 1, 0, NULL
, NULL
, &size
, 0 );
1337 if (flags
& DFCS_INACTIVE
)
1339 NtGdiGetAndSetDCDword( dc
, NtGdiSetTextColor
, get_sys_color(COLOR_BTNHIGHLIGHT
), NULL
);
1340 NtGdiExtTextOutW( dc
, xc
-size
.cx
/2+1, yc
-size
.cy
/2+1, 0, NULL
, str
, 1, NULL
, 0 );
1342 NtGdiGetAndSetDCDword( dc
, NtGdiSetTextColor
, get_sys_color( color_idx
), NULL
);
1343 NtGdiExtTextOutW( dc
, xc
-size
.cx
/2, yc
-size
.cy
/2, 0, NULL
, str
, 1, NULL
, 0 );
1345 NtGdiSelectFont(dc
, prev_font
);
1346 NtGdiGetAndSetDCDword( dc
, NtGdiSetTextColor
, prev_color
, NULL
);
1347 NtGdiGetAndSetDCDword( dc
, NtGdiSetTextAlign
, prev_align
, NULL
);
1348 NtGdiGetAndSetDCDword( dc
, NtGdiSetBkMode
, prev_bk
, NULL
);
1349 NtGdiDeleteObjectApp( font
);
1354 BOOL
draw_menu_button( HWND hwnd
, HDC dc
, RECT
*r
, enum NONCLIENT_BUTTON_TYPE type
, BOOL down
,
1357 struct draw_non_client_button_params params
;
1366 params
.grayed
= grayed
;
1367 return KeUserModeCallback( NtUserDrawNonClientButton
, ¶ms
, sizeof(params
), &ret_ptr
, &ret_len
);
1370 BOOL
draw_frame_menu( HDC dc
, RECT
*r
, UINT flags
)
1373 int dmall_diam
= make_square_rect( r
, &rect
);
1383 fill_rect( dc
, r
, GetStockObject( WHITE_BRUSH
));
1385 prev_brush
= NtGdiSelectBrush( dc
, GetStockObject( BLACK_BRUSH
));
1386 prev_pen
= NtGdiSelectPen( dc
, GetStockObject( BLACK_PEN
));
1388 switch (flags
& 0xff)
1390 case DFCS_MENUARROW
:
1391 i
= 187 * dmall_diam
/ 750;
1392 points
[2].x
= rect
.left
+ 468 * dmall_diam
/ 750;
1393 points
[2].y
= rect
.top
+ 352 * dmall_diam
/ 750 + 1;
1394 points
[0].y
= points
[2].y
- i
;
1395 points
[1].y
= points
[2].y
+ i
;
1396 points
[0].x
= points
[1].x
= points
[2].x
- i
;
1398 NtGdiPolyPolyDraw( dc
, points
, &count
, 1, NtGdiPolyPolygon
);
1401 case DFCS_MENUBULLET
:
1403 ye
= rect
.top
+ dmall_diam
- dmall_diam
/ 2;
1404 xc
= rect
.left
+ dmall_diam
- dmall_diam
/ 2;
1405 yc
= rect
.top
+ dmall_diam
- dmall_diam
/ 2;
1406 i
= 234 * dmall_diam
/ 750;
1408 SetRect( &rect
, xc
- i
+ i
/ 2, yc
- i
+ i
/ 2, xc
+ i
/ 2, yc
+ i
/ 2 );
1409 NtGdiArcInternal( NtGdiPie
, dc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
,
1413 case DFCS_MENUCHECK
:
1414 points
[0].x
= rect
.left
+ 253 * dmall_diam
/ 1000;
1415 points
[0].y
= rect
.top
+ 445 * dmall_diam
/ 1000;
1416 points
[1].x
= rect
.left
+ 409 * dmall_diam
/ 1000;
1417 points
[1].y
= points
[0].y
+ (points
[1].x
- points
[0].x
);
1418 points
[2].x
= rect
.left
+ 690 * dmall_diam
/ 1000;
1419 points
[2].y
= points
[1].y
- (points
[2].x
- points
[1].x
);
1420 points
[3].x
= points
[2].x
;
1421 points
[3].y
= points
[2].y
+ 3 * dmall_diam
/ 16;
1422 points
[4].x
= points
[1].x
;
1423 points
[4].y
= points
[1].y
+ 3 * dmall_diam
/ 16;
1424 points
[5].x
= points
[0].x
;
1425 points
[5].y
= points
[0].y
+ 3 * dmall_diam
/ 16;
1427 NtGdiPolyPolyDraw( dc
, points
, &count
, 1, NtGdiPolyPolygon
);
1431 WARN( "Invalid menu; flags=0x%04x\n", flags
);
1436 NtGdiSelectPen( dc
, prev_pen
);
1437 NtGdiSelectBrush( dc
, prev_brush
);
1441 static void draw_close_button( HWND hwnd
, HDC hdc
, BOOL down
, BOOL grayed
)
1444 DWORD style
= get_window_long( hwnd
, GWL_STYLE
);
1445 DWORD ex_style
= get_window_long( hwnd
, GWL_EXSTYLE
);
1446 UINT flags
= DFCS_CAPTIONCLOSE
;
1448 get_inside_rect( hwnd
, COORDS_WINDOW
, &rect
, style
, ex_style
);
1450 /* A tool window has a smaller Close button */
1451 if (ex_style
& WS_EX_TOOLWINDOW
)
1453 /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE
1454 * it uses 11x11 for the close button in tool window */
1455 const int bmp_height
= 11;
1456 const int bmp_width
= 11;
1457 int caption_height
= get_system_metrics( SM_CYSMCAPTION
);
1459 rect
.top
= rect
.top
+ (caption_height
- 1 - bmp_height
) / 2;
1460 rect
.left
= rect
.right
- (caption_height
+ 1 + bmp_width
) / 2;
1461 rect
.bottom
= rect
.top
+ bmp_height
;
1462 rect
.right
= rect
.left
+ bmp_width
;
1466 rect
.left
= rect
.right
- get_system_metrics( SM_CXSIZE
);
1467 rect
.bottom
= rect
.top
+ get_system_metrics( SM_CYSIZE
) - 2;
1472 if (down
) flags
|= DFCS_PUSHED
;
1473 if (grayed
) flags
|= DFCS_INACTIVE
;
1474 draw_frame_caption( hdc
, &rect
, flags
);
1477 static void draw_max_button( HWND hwnd
, HDC hdc
, BOOL down
, BOOL grayed
)
1481 DWORD style
= get_window_long( hwnd
, GWL_STYLE
);
1482 DWORD ex_style
= get_window_long( hwnd
, GWL_EXSTYLE
);
1484 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
1485 if (ex_style
& WS_EX_TOOLWINDOW
) return;
1487 flags
= (style
& WS_MAXIMIZE
) ? DFCS_CAPTIONRESTORE
: DFCS_CAPTIONMAX
;
1489 get_inside_rect( hwnd
, COORDS_WINDOW
, &rect
, style
, ex_style
);
1490 if (style
& WS_SYSMENU
) rect
.right
-= get_system_metrics( SM_CXSIZE
);
1491 rect
.left
= rect
.right
- get_system_metrics( SM_CXSIZE
);
1492 rect
.bottom
= rect
.top
+ get_system_metrics( SM_CYSIZE
) - 2;
1495 if (down
) flags
|= DFCS_PUSHED
;
1496 if (grayed
) flags
|= DFCS_INACTIVE
;
1497 draw_frame_caption( hdc
, &rect
, flags
);
1500 static void draw_min_button( HWND hwnd
, HDC hdc
, BOOL down
, BOOL grayed
)
1504 DWORD style
= get_window_long( hwnd
, GWL_STYLE
);
1505 DWORD ex_style
= get_window_long( hwnd
, GWL_EXSTYLE
);
1507 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
1508 if (ex_style
& WS_EX_TOOLWINDOW
) return;
1510 flags
= (style
& WS_MINIMIZE
) ? DFCS_CAPTIONRESTORE
: DFCS_CAPTIONMIN
;
1512 get_inside_rect( hwnd
, COORDS_WINDOW
, &rect
, style
, ex_style
);
1513 if (style
& WS_SYSMENU
)
1514 rect
.right
-= get_system_metrics( SM_CXSIZE
);
1515 if (style
& (WS_MAXIMIZEBOX
|WS_MINIMIZEBOX
))
1516 rect
.right
-= get_system_metrics( SM_CXSIZE
) - 2;
1517 rect
.left
= rect
.right
- get_system_metrics( SM_CXSIZE
);
1518 rect
.bottom
= rect
.top
+ get_system_metrics( SM_CYSIZE
) - 2;
1521 if (down
) flags
|= DFCS_PUSHED
;
1522 if (grayed
) flags
|= DFCS_INACTIVE
;
1523 draw_frame_caption( hdc
, &rect
, flags
);
1526 static void draw_nc_caption( HDC hdc
, RECT
*rect
, HWND hwnd
, DWORD style
,
1527 DWORD ex_style
, BOOL active
)
1533 BOOL gradient
= FALSE
;
1534 UINT pen_color
= COLOR_3DFACE
;
1537 if ((ex_style
& (WS_EX_STATICEDGE
|WS_EX_CLIENTEDGE
|WS_EX_DLGMODALFRAME
)) == WS_EX_STATICEDGE
)
1538 pen_color
= COLOR_WINDOWFRAME
;
1539 prev_pen
= NtGdiSelectPen( hdc
, get_sys_color_pen( pen_color
));
1540 NtGdiMoveTo( hdc
, r
.left
, r
.bottom
- 1, NULL
);
1541 NtGdiLineTo( hdc
, r
.right
, r
.bottom
- 1 );
1542 NtGdiSelectPen( hdc
, prev_pen
);
1545 NtUserSystemParametersInfo( SPI_GETGRADIENTCAPTIONS
, 0, &gradient
, 0 );
1546 draw_caption_bar( hdc
, &r
, style
, active
, gradient
);
1548 if ((style
& WS_SYSMENU
) && !(ex_style
& WS_EX_TOOLWINDOW
))
1550 if (draw_nc_sys_button( hwnd
, hdc
, FALSE
))
1551 r
.left
+= get_system_metrics( SM_CXSMICON
) + 2;
1554 if (style
& WS_SYSMENU
)
1558 /* Go get the sysmenu */
1559 sys_menu
= NtUserGetSystemMenu( hwnd
, FALSE
);
1560 state
= get_menu_state( sys_menu
, SC_CLOSE
, MF_BYCOMMAND
);
1562 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
1563 draw_close_button( hwnd
, hdc
, FALSE
,
1564 (state
& (MF_DISABLED
| MF_GRAYED
)) || (state
== 0xFFFFFFFF) );
1565 r
.right
-= get_system_metrics( SM_CYCAPTION
) - 1;
1567 if ((style
& WS_MAXIMIZEBOX
) || (style
& WS_MINIMIZEBOX
))
1569 draw_max_button( hwnd
, hdc
, FALSE
, !(style
& WS_MAXIMIZEBOX
) );
1570 r
.right
-= get_system_metrics( SM_CXSIZE
) + 1;
1572 draw_min_button( hwnd
, hdc
, FALSE
, !(style
& WS_MINIMIZEBOX
) );
1573 r
.right
-= get_system_metrics( SM_CXSIZE
) + 1;
1577 len
= get_window_text( hwnd
, buffer
, ARRAY_SIZE( buffer
));
1580 NONCLIENTMETRICSW nclm
;
1581 HFONT hFont
, hOldFont
;
1582 nclm
.cbSize
= sizeof(nclm
);
1583 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &nclm
, 0 );
1584 if (ex_style
& WS_EX_TOOLWINDOW
)
1585 hFont
= NtGdiHfontCreate( &nclm
.lfSmCaptionFont
, sizeof(nclm
.lfSmCaptionFont
), 0, 0, NULL
);
1587 hFont
= NtGdiHfontCreate( &nclm
.lfCaptionFont
, sizeof(nclm
.lfCaptionFont
), 0, 0, NULL
);
1588 hOldFont
= NtGdiSelectFont( hdc
, hFont
);
1590 NtGdiGetAndSetDCDword( hdc
, NtGdiSetTextColor
, get_sys_color( COLOR_CAPTIONTEXT
), NULL
);
1592 NtGdiGetAndSetDCDword( hdc
, NtGdiSetTextColor
, get_sys_color( COLOR_INACTIVECAPTIONTEXT
), NULL
);
1593 NtGdiGetAndSetDCDword( hdc
, NtGdiSetBkMode
, TRANSPARENT
, NULL
);
1595 DrawTextW( hdc
, buffer
, -1, &r
,
1596 DT_SINGLELINE
| DT_VCENTER
| DT_NOPREFIX
| DT_LEFT
);
1597 NtGdiDeleteObjectApp( NtGdiSelectFont( hdc
, hOldFont
));
1601 /***********************************************************************
1602 * NtUserDrawCaptionTemp (win32u.@)
1604 BOOL WINAPI
NtUserDrawCaptionTemp( HWND hwnd
, HDC hdc
, const RECT
*rect
, HFONT font
,
1605 HICON icon
, const WCHAR
*str
, UINT flags
)
1609 TRACE( "(%p,%p,%p,%p,%p,%s,%08x)\n", hwnd
, hdc
, rect
, font
, icon
, debugstr_w(str
), flags
);
1611 /* drawing background */
1612 if (flags
& DC_INBUTTON
)
1614 fill_rect( hdc
, &rc
, get_sys_color_brush( COLOR_3DFACE
));
1616 if (flags
& DC_ACTIVE
)
1618 HBRUSH hbr
= NtGdiSelectBrush( hdc
, get_55aa_brush() );
1619 NtGdiPatBlt( hdc
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, 0xfa0089 );
1620 NtGdiSelectBrush( hdc
, hbr
);
1625 DWORD style
= get_window_long( hwnd
, GWL_STYLE
);
1626 draw_caption_bar( hdc
, &rc
, style
, flags
& DC_ACTIVE
, flags
& DC_GRADIENT
);
1630 if ((flags
& DC_ICON
) && !(flags
& DC_SMALLCAP
))
1635 pt
.y
= (rc
.bottom
+ rc
.top
- get_system_metrics( SM_CYSMICON
)) / 2;
1637 if (!icon
) icon
= get_nc_icon_for_window( hwnd
);
1638 NtUserDrawIconEx( hdc
, pt
.x
, pt
.y
, icon
, get_system_metrics( SM_CXSMICON
),
1639 get_system_metrics( SM_CYSMICON
), 0, 0, DI_NORMAL
);
1640 rc
.left
= pt
.x
+ get_system_metrics( SM_CXSMICON
);
1644 if (flags
& DC_TEXT
)
1650 if (flags
& DC_INBUTTON
)
1651 color
= COLOR_BTNTEXT
;
1652 else if (flags
& DC_ACTIVE
)
1653 color
= COLOR_CAPTIONTEXT
;
1655 color
= COLOR_INACTIVECAPTIONTEXT
;
1656 NtGdiGetAndSetDCDword( hdc
, NtGdiSetTextColor
, get_sys_color( color
), NULL
);
1657 NtGdiGetAndSetDCDword( hdc
, NtGdiSetBkMode
, TRANSPARENT
, NULL
);
1660 prev_font
= NtGdiSelectFont( hdc
, font
);
1663 NONCLIENTMETRICSW nclm
;
1666 nclm
.cbSize
= sizeof(NONCLIENTMETRICSW
);
1667 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &nclm
, 0 );
1668 lf
= (flags
& DC_SMALLCAP
) ? &nclm
.lfSmCaptionFont
: &nclm
.lfCaptionFont
;
1669 new_font
= NtGdiHfontCreate( lf
, sizeof(*lf
), 0, 0, NULL
);
1670 prev_font
= NtGdiSelectFont( hdc
, new_font
);
1675 if (!get_window_text( hwnd
, text
, ARRAY_SIZE( text
))) text
[0] = 0;
1679 DrawTextW( hdc
, str
, -1, &rc
, ((flags
& 0x4000) ? DT_CENTER
: DT_LEFT
) |
1680 DT_SINGLELINE
| DT_VCENTER
| DT_NOPREFIX
| DT_END_ELLIPSIS
);
1683 NtGdiSelectFont( hdc
, prev_font
);
1685 NtGdiDeleteObjectApp( NtGdiSelectFont( hdc
, prev_font
));
1688 if (flags
& 0x2000) FIXME( "undocumented flag (0x2000)!\n" );
1692 /* Paint the non-client area for windows */
1693 static void nc_paint( HWND hwnd
, HRGN clip
)
1696 RECT rfuzz
, rect
, clip_rect
;
1699 DWORD style
, ex_style
;
1704 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
) return;
1705 style
= win
->dwStyle
;
1706 ex_style
= win
->dwExStyle
;
1708 release_win_ptr( win
);
1710 active
= flags
& WIN_NCACTIVATED
;
1712 TRACE( "%p %d\n", hwnd
, active
);
1714 get_window_rects( hwnd
, COORDS_SCREEN
, NULL
, &rectClient
, get_thread_dpi() );
1715 hrgn
= NtGdiCreateRectRgn( rectClient
.left
, rectClient
.top
,
1716 rectClient
.right
, rectClient
.bottom
);
1720 NtGdiCombineRgn( hrgn
, clip
, hrgn
, RGN_DIFF
);
1721 hdc
= NtUserGetDCEx( hwnd
, hrgn
, DCX_USESTYLE
| DCX_WINDOW
| DCX_INTERSECTRGN
);
1725 hdc
= NtUserGetDCEx( hwnd
, hrgn
, DCX_USESTYLE
| DCX_WINDOW
| DCX_EXCLUDERGN
);
1730 NtGdiDeleteObjectApp( hrgn
);
1734 get_window_rects( hwnd
, COORDS_WINDOW
, &rect
, NULL
, get_thread_dpi() );
1735 NtGdiGetAppClipBox( hdc
, &clip_rect
);
1737 NtGdiSelectPen( hdc
, get_sys_color_pen( COLOR_WINDOWFRAME
));
1739 if (has_static_outer_frame( ex_style
))
1740 draw_rect_edge( hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
| BF_ADJUST
, 1 );
1741 else if (has_big_frame( style
, ex_style
))
1742 draw_rect_edge( hdc
, &rect
, EDGE_RAISED
, BF_RECT
| BF_ADJUST
, 1 );
1744 draw_nc_frame( hdc
, &rect
, active
, style
, ex_style
);
1746 if ((style
& WS_CAPTION
) == WS_CAPTION
)
1749 if (ex_style
& WS_EX_TOOLWINDOW
)
1751 r
.bottom
= rect
.top
+ get_system_metrics( SM_CYSMCAPTION
);
1752 rect
.top
+= get_system_metrics( SM_CYSMCAPTION
);
1755 r
.bottom
= rect
.top
+ get_system_metrics( SM_CYCAPTION
);
1756 rect
.top
+= get_system_metrics( SM_CYCAPTION
);
1759 if (intersect_rect( &rfuzz
, &r
, &clip_rect
))
1760 draw_nc_caption( hdc
, &r
, hwnd
, style
, ex_style
, active
);
1763 if (has_menu( hwnd
, style
))
1768 r
.bottom
= rect
.top
+ get_system_metrics( SM_CYMENU
);
1770 TRACE( "drawing menu with rect %s\n", wine_dbgstr_rect( &r
));
1772 menu
= get_menu( hwnd
);
1773 if (!is_menu( menu
)) rect
.top
+= get_system_metrics( SM_CYMENU
);
1774 else rect
.top
+= NtUserDrawMenuBarTemp( hwnd
, hdc
, &r
, menu
, NULL
);
1777 TRACE( "rect after menu %s\n", wine_dbgstr_rect( &rect
));
1779 if (ex_style
& WS_EX_CLIENTEDGE
)
1780 draw_rect_edge( hdc
, &rect
, EDGE_SUNKEN
, BF_RECT
| BF_ADJUST
, 1 );
1782 /* Draw the scroll-bars */
1783 draw_nc_scrollbar( hwnd
, hdc
, style
& WS_HSCROLL
, style
& WS_VSCROLL
);
1785 /* Draw the "size-box" */
1786 if ((style
& WS_VSCROLL
) && (style
& WS_HSCROLL
))
1789 if ((ex_style
& WS_EX_LEFTSCROLLBAR
) != 0)
1790 r
.right
= r
.left
+ get_system_metrics( SM_CXVSCROLL
) + 1;
1792 r
.left
= r
.right
- get_system_metrics( SM_CXVSCROLL
) + 1;
1793 r
.top
= r
.bottom
- get_system_metrics( SM_CYHSCROLL
) + 1;
1794 fill_rect( hdc
, &r
, get_sys_color_brush( COLOR_BTNFACE
) );
1797 NtUserReleaseDC( hwnd
, hdc
);
1800 static LRESULT
handle_nc_paint( HWND hwnd
, HRGN clip
)
1802 HWND parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
1803 DWORD style
= get_window_long( hwnd
, GWL_STYLE
);
1805 if (style
& WS_VISIBLE
)
1807 nc_paint( hwnd
, clip
);
1809 if (parent
== get_desktop_window())
1810 NtUserPostMessage( parent
, WM_PARENTNOTIFY
, WM_NCPAINT
, (LPARAM
)hwnd
);
1815 static LRESULT
handle_nc_activate( HWND hwnd
, WPARAM wparam
, LPARAM lparam
)
1817 /* Lotus Notes draws menu descriptions in the caption of its main
1818 * window. When it wants to restore original "system" view, it just
1819 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1820 * attempt to minimize redrawings lead to a not restored caption.
1822 if (wparam
) win_set_flags( hwnd
, WIN_NCACTIVATED
, 0 );
1823 else win_set_flags( hwnd
, 0, WIN_NCACTIVATED
);
1825 /* This isn't documented but is reproducible in at least XP SP2 and
1826 * Outlook 2007 depends on it
1830 nc_paint( hwnd
, (HRGN
)1 );
1832 if (NtUserGetAncestor( hwnd
, GA_PARENT
) == get_desktop_window())
1833 NtUserPostMessage( get_desktop_window(), WM_PARENTNOTIFY
, WM_NCACTIVATE
, (LPARAM
)hwnd
);
1839 static void handle_nc_calc_size( HWND hwnd
, WPARAM wparam
, RECT
*win_rect
)
1841 RECT rect
= { 0, 0, 0, 0 };
1842 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
1843 LONG ex_style
= get_window_long( hwnd
, GWL_EXSTYLE
);
1845 if (!win_rect
) return;
1847 if (!(style
& WS_MINIMIZE
))
1849 AdjustWindowRectEx( &rect
, style
, FALSE
, ex_style
& ~WS_EX_CLIENTEDGE
);
1851 win_rect
->left
-= rect
.left
;
1852 win_rect
->top
-= rect
.top
;
1853 win_rect
->right
-= rect
.right
;
1854 win_rect
->bottom
-= rect
.bottom
;
1856 if (((style
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
) && get_menu( hwnd
))
1858 TRACE( "getting menu bar height with hwnd %p, width %d, at (%d, %d)\n",
1859 hwnd
, (int)(win_rect
->right
- win_rect
->left
), (int)-rect
.left
, (int)-rect
.top
);
1861 win_rect
->top
+= get_menu_bar_height( hwnd
, win_rect
->right
- win_rect
->left
,
1862 -rect
.left
, -rect
.top
);
1865 if (ex_style
& WS_EX_CLIENTEDGE
)
1866 if (win_rect
->right
- win_rect
->left
> 2 * get_system_metrics( SM_CXEDGE
) &&
1867 win_rect
->bottom
- win_rect
->top
> 2 * get_system_metrics( SM_CYEDGE
))
1868 InflateRect( win_rect
, -get_system_metrics( SM_CXEDGE
),
1869 -get_system_metrics( SM_CYEDGE
));
1871 if ((style
& WS_VSCROLL
) &&
1872 win_rect
->right
- win_rect
->left
>= get_system_metrics( SM_CXVSCROLL
))
1874 /* rectangle is in screen coords when wparam is false */
1875 if (!wparam
&& (ex_style
& WS_EX_LAYOUTRTL
)) ex_style
^= WS_EX_LEFTSCROLLBAR
;
1877 if (ex_style
& WS_EX_LEFTSCROLLBAR
)
1878 win_rect
->left
+= get_system_metrics( SM_CXVSCROLL
);
1880 win_rect
->right
-= get_system_metrics( SM_CXVSCROLL
);
1883 if ((style
& WS_HSCROLL
) &&
1884 win_rect
->bottom
- win_rect
->top
> get_system_metrics( SM_CYHSCROLL
))
1886 win_rect
->bottom
-= get_system_metrics( SM_CYHSCROLL
);
1889 if (win_rect
->top
> win_rect
->bottom
) win_rect
->bottom
= win_rect
->top
;
1890 if (win_rect
->left
> win_rect
->right
) win_rect
->right
= win_rect
->left
;
1894 win_rect
->right
= win_rect
->left
;
1895 win_rect
->bottom
= win_rect
->top
;
1899 LRESULT
handle_nc_hit_test( HWND hwnd
, POINT pt
)
1901 RECT rect
, client_rect
;
1902 DWORD style
, ex_style
;
1904 TRACE( "hwnd %p pt %d,%d\n", hwnd
, (int)pt
.x
, (int)pt
.y
);
1906 get_window_rects( hwnd
, COORDS_SCREEN
, &rect
, &client_rect
, get_thread_dpi() );
1907 if (!PtInRect( &rect
, pt
)) return HTNOWHERE
;
1909 style
= get_window_long( hwnd
, GWL_STYLE
);
1910 ex_style
= get_window_long( hwnd
, GWL_EXSTYLE
);
1912 if (PtInRect( &client_rect
, pt
)) return HTCLIENT
;
1915 if (has_thick_frame( style
, ex_style
))
1917 InflateRect( &rect
, -get_system_metrics( SM_CXFRAME
), -get_system_metrics( SM_CYFRAME
));
1918 if (!PtInRect( &rect
, pt
))
1920 /* Check top sizing border */
1921 if (pt
.y
< rect
.top
)
1923 if (pt
.x
< rect
.left
+ get_system_metrics( SM_CXSIZE
)) return HTTOPLEFT
;
1924 if (pt
.x
>= rect
.right
- get_system_metrics( SM_CXSIZE
)) return HTTOPRIGHT
;
1927 /* Check bottom sizing border */
1928 if (pt
.y
>= rect
.bottom
)
1930 if (pt
.x
< rect
.left
+ get_system_metrics( SM_CXSIZE
)) return HTBOTTOMLEFT
;
1931 if (pt
.x
>= rect
.right
- get_system_metrics( SM_CXSIZE
)) return HTBOTTOMRIGHT
;
1934 /* Check left sizing border */
1935 if (pt
.x
< rect
.left
)
1937 if (pt
.y
< rect
.top
+ get_system_metrics( SM_CYSIZE
)) return HTTOPLEFT
;
1938 if (pt
.y
>= rect
.bottom
- get_system_metrics( SM_CYSIZE
)) return HTBOTTOMLEFT
;
1941 /* Check right sizing border */
1942 if (pt
.x
>= rect
.right
)
1944 if (pt
.y
< rect
.top
+ get_system_metrics( SM_CYSIZE
)) return HTTOPRIGHT
;
1945 if (pt
.y
>= rect
.bottom
-get_system_metrics( SM_CYSIZE
)) return HTBOTTOMRIGHT
;
1950 else /* No thick frame */
1952 if (has_dialog_frame( style
, ex_style
))
1953 InflateRect( &rect
, -get_system_metrics( SM_CXDLGFRAME
),
1954 -get_system_metrics( SM_CYDLGFRAME
));
1955 else if (has_thin_frame( style
))
1956 InflateRect(&rect
, -get_system_metrics( SM_CXBORDER
),
1957 -get_system_metrics( SM_CYBORDER
));
1958 if (!PtInRect( &rect
, pt
)) return HTBORDER
;
1962 if ((style
& WS_CAPTION
) == WS_CAPTION
)
1964 if (ex_style
& WS_EX_TOOLWINDOW
)
1965 rect
.top
+= get_system_metrics( SM_CYSMCAPTION
) - 1;
1967 rect
.top
+= get_system_metrics( SM_CYCAPTION
) - 1;
1968 if (!PtInRect( &rect
, pt
))
1970 BOOL min_or_max_box
= (style
& WS_SYSMENU
) && (style
& (WS_MINIMIZEBOX
| WS_MAXIMIZEBOX
));
1971 if (ex_style
& WS_EX_LAYOUTRTL
)
1973 /* Check system menu */
1974 if ((style
& WS_SYSMENU
) && !(ex_style
& WS_EX_TOOLWINDOW
) &&
1975 get_nc_icon_for_window( hwnd
))
1977 rect
.right
-= get_system_metrics( SM_CYCAPTION
) - 1;
1978 if (pt
.x
> rect
.right
) return HTSYSMENU
;
1981 /* Check close button */
1982 if (style
& WS_SYSMENU
)
1984 rect
.left
+= get_system_metrics( SM_CYCAPTION
);
1985 if (pt
.x
< rect
.left
) return HTCLOSE
;
1988 if (min_or_max_box
&& !(ex_style
& WS_EX_TOOLWINDOW
))
1990 /* Check maximize box */
1991 rect
.left
+= get_system_metrics( SM_CXSIZE
);
1992 if (pt
.x
< rect
.left
) return HTMAXBUTTON
;
1994 /* Check minimize box */
1995 rect
.left
+= get_system_metrics( SM_CXSIZE
);
1996 if (pt
.x
< rect
.left
) return HTMINBUTTON
;
2001 /* Check system menu */
2002 if ((style
& WS_SYSMENU
) && !(ex_style
& WS_EX_TOOLWINDOW
) &&
2003 get_nc_icon_for_window( hwnd
))
2005 rect
.left
+= get_system_metrics( SM_CYCAPTION
) - 1;
2006 if (pt
.x
< rect
.left
) return HTSYSMENU
;
2009 /* Check close button */
2010 if (style
& WS_SYSMENU
)
2012 rect
.right
-= get_system_metrics( SM_CYCAPTION
);
2013 if (pt
.x
> rect
.right
) return HTCLOSE
;
2016 if (min_or_max_box
&& !(ex_style
& WS_EX_TOOLWINDOW
))
2018 /* Check maximize box */
2019 rect
.right
-= get_system_metrics( SM_CXSIZE
);
2020 if (pt
.x
> rect
.right
) return HTMAXBUTTON
;
2022 /* Check minimize box */
2023 rect
.right
-= get_system_metrics( SM_CXSIZE
);
2024 if (pt
.x
> rect
.right
) return HTMINBUTTON
;
2031 /* Check menu bar */
2032 if (has_menu( hwnd
, style
) && (pt
.y
< client_rect
.top
) &&
2033 (pt
.x
>= client_rect
.left
) && (pt
.x
< client_rect
.right
))
2036 /* Check vertical scroll bar */
2037 if (ex_style
& WS_EX_LAYOUTRTL
) ex_style
^= WS_EX_LEFTSCROLLBAR
;
2038 if (style
& WS_VSCROLL
)
2040 if (ex_style
& WS_EX_LEFTSCROLLBAR
)
2041 client_rect
.left
-= get_system_metrics( SM_CXVSCROLL
);
2043 client_rect
.right
+= get_system_metrics( SM_CXVSCROLL
);
2044 if (PtInRect( &client_rect
, pt
)) return HTVSCROLL
;
2047 /* Check horizontal scroll bar */
2048 if (style
& WS_HSCROLL
)
2050 client_rect
.bottom
+= get_system_metrics( SM_CYHSCROLL
);
2051 if (PtInRect( &client_rect
, pt
))
2053 /* Check size box */
2054 if ((style
& WS_VSCROLL
) &&
2055 ((ex_style
& WS_EX_LEFTSCROLLBAR
)
2056 ? (pt
.x
<= client_rect
.left
+ get_system_metrics( SM_CXVSCROLL
))
2057 : (pt
.x
>= client_rect
.right
- get_system_metrics( SM_CXVSCROLL
))))
2063 /* Has to return HTNOWHERE if nothing was found
2064 Could happen when a window has a customized non client area */
2068 static void track_min_max_box( HWND hwnd
, WORD wparam
)
2070 HDC hdc
= NtUserGetWindowDC( hwnd
);
2071 DWORD style
= get_window_long( hwnd
, GWL_STYLE
);
2072 HMENU sys_menu
= NtUserGetSystemMenu(hwnd
, FALSE
);
2073 void (*paint_button
)( HWND
, HDC
, BOOL
, BOOL
);
2074 BOOL pressed
= TRUE
;
2078 if (wparam
== HTMINBUTTON
)
2080 /* If the style is not present, do nothing */
2081 if (!(style
& WS_MINIMIZEBOX
)) return;
2083 /* Check if the sysmenu item for minimize is there */
2084 state
= get_menu_state( sys_menu
, SC_MINIMIZE
, MF_BYCOMMAND
);
2085 paint_button
= draw_min_button
;
2089 /* If the style is not present, do nothing */
2090 if (!(style
& WS_MAXIMIZEBOX
)) return;
2092 /* Check if the sysmenu item for maximize is there */
2093 state
= get_menu_state( sys_menu
, SC_MAXIMIZE
, MF_BYCOMMAND
);
2094 paint_button
= draw_max_button
;
2097 NtUserSetCapture( hwnd
);
2098 paint_button( hwnd
, hdc
, TRUE
, FALSE
);
2102 BOOL oldstate
= pressed
;
2104 if (!NtUserGetMessage( &msg
, 0, WM_MOUSEFIRST
, WM_MOUSELAST
)) break;
2105 if (NtUserCallMsgFilter( &msg
, MSGF_MAX
)) continue;
2106 if(msg
.message
== WM_LBUTTONUP
) break;
2107 if(msg
.message
!= WM_MOUSEMOVE
) continue;
2109 pressed
= handle_nc_hit_test( hwnd
, msg
.pt
) == wparam
;
2110 if (pressed
!= oldstate
) paint_button( hwnd
, hdc
, pressed
, FALSE
);
2113 if (pressed
) paint_button( hwnd
, hdc
, FALSE
, FALSE
);
2116 NtUserReleaseDC( hwnd
, hdc
);
2118 /* If the minimize or maximize items of the sysmenu are not there
2119 * or if the style is not present, do nothing */
2120 if (!pressed
|| state
== 0xffffffff) return;
2122 if (wparam
== HTMINBUTTON
)
2123 send_message( hwnd
, WM_SYSCOMMAND
,
2124 is_iconic( hwnd
) ? SC_RESTORE
: SC_MINIMIZE
, MAKELONG( msg
.pt
.x
, msg
.pt
.y
));
2126 send_message( hwnd
, WM_SYSCOMMAND
,
2127 is_zoomed( hwnd
) ? SC_RESTORE
: SC_MAXIMIZE
, MAKELONG( msg
.pt
.x
, msg
.pt
.y
));
2130 static void track_close_button( HWND hwnd
, WPARAM wparam
, LPARAM lparam
)
2133 BOOL pressed
= TRUE
;
2138 if (!(sys_menu
= NtUserGetSystemMenu( hwnd
, FALSE
))) return;
2140 state
= get_menu_state( sys_menu
, SC_CLOSE
, MF_BYCOMMAND
);
2142 /* If the close item of the sysmenu is disabled or not present do nothing */
2143 if((state
& MF_DISABLED
) || (state
& MF_GRAYED
) || state
== 0xFFFFFFFF) return;
2144 hdc
= NtUserGetWindowDC( hwnd
);
2145 NtUserSetCapture( hwnd
);
2146 draw_close_button( hwnd
, hdc
, TRUE
, FALSE
);
2150 BOOL oldstate
= pressed
;
2152 if (!NtUserGetMessage( &msg
, 0, WM_MOUSEFIRST
, WM_MOUSELAST
)) break;
2153 if (NtUserCallMsgFilter( &msg
, MSGF_MAX
)) continue;
2154 if (msg
.message
== WM_LBUTTONUP
) break;
2155 if (msg
.message
!= WM_MOUSEMOVE
) continue;
2157 pressed
= handle_nc_hit_test( hwnd
, msg
.pt
) == wparam
;
2158 if (pressed
!= oldstate
) draw_close_button( hwnd
, hdc
, pressed
, FALSE
);
2161 if (pressed
) draw_close_button( hwnd
, hdc
, FALSE
, FALSE
);
2164 NtUserReleaseDC( hwnd
, hdc
);
2165 if (pressed
) send_message( hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, lparam
);
2168 static LRESULT
handle_nc_lbutton_down( HWND hwnd
, WPARAM wparam
, LPARAM lparam
)
2170 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
2172 switch (wparam
) /* Hit test */
2176 HWND top
= hwnd
, parent
;
2179 if ((get_window_long( top
, GWL_STYLE
) & (WS_POPUP
| WS_CHILD
)) != WS_CHILD
)
2181 parent
= NtUserGetAncestor( top
, GA_PARENT
);
2182 if (!parent
|| parent
== get_desktop_window()) break;
2186 if (set_foreground_window( top
, TRUE
) || (get_active_window() == top
))
2187 send_message( hwnd
, WM_SYSCOMMAND
, SC_MOVE
+ HTCAPTION
, lparam
);
2192 if (style
& WS_SYSMENU
)
2194 HDC hdc
= NtUserGetWindowDC( hwnd
);
2195 draw_nc_sys_button( hwnd
, hdc
, TRUE
);
2196 NtUserReleaseDC( hwnd
, hdc
);
2197 send_message( hwnd
, WM_SYSCOMMAND
, SC_MOUSEMENU
+ HTSYSMENU
, lparam
);
2202 send_message( hwnd
, WM_SYSCOMMAND
, SC_MOUSEMENU
, lparam
);
2206 send_message( hwnd
, WM_SYSCOMMAND
, SC_HSCROLL
+ HTHSCROLL
, lparam
);
2210 send_message( hwnd
, WM_SYSCOMMAND
, SC_VSCROLL
+ HTVSCROLL
, lparam
);
2215 track_min_max_box( hwnd
, wparam
);
2219 track_close_button( hwnd
, wparam
, lparam
);
2230 send_message( hwnd
, WM_SYSCOMMAND
, SC_SIZE
+ wparam
- (HTLEFT
- WMSZ_LEFT
), lparam
);
2239 static LRESULT
handle_nc_rbutton_down( HWND hwnd
, WPARAM wparam
, LPARAM lparam
)
2241 int hittest
= wparam
;
2248 NtUserSetCapture( hwnd
);
2251 if (!NtUserGetMessage( &msg
, 0, WM_MOUSEFIRST
, WM_MOUSELAST
)) break;
2252 if (NtUserCallMsgFilter( &msg
, MSGF_MAX
)) continue;
2253 if (msg
.message
== WM_RBUTTONUP
)
2255 hittest
= handle_nc_hit_test( hwnd
, msg
.pt
);
2260 if (hittest
== HTCAPTION
|| hittest
== HTSYSMENU
)
2261 send_message( hwnd
, WM_CONTEXTMENU
, (WPARAM
)hwnd
, MAKELPARAM( msg
.pt
.x
, msg
.pt
.y
));
2267 static LRESULT
handle_nc_button_dbl_click( HWND hwnd
, WPARAM wparam
, LPARAM lparam
)
2269 /* if this is an icon, send a restore since we are handling a double click */
2270 if (is_iconic(hwnd
))
2272 send_message( hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, lparam
);
2276 switch (wparam
) /* Hit test */
2279 /* stop processing if WS_MAXIMIZEBOX is missing */
2280 if (get_window_long( hwnd
, GWL_STYLE
) & WS_MAXIMIZEBOX
)
2281 send_message( hwnd
, WM_SYSCOMMAND
,
2282 is_zoomed( hwnd
) ? SC_RESTORE
: SC_MAXIMIZE
, lparam
);
2287 HMENU hSysMenu
= NtUserGetSystemMenu( hwnd
, FALSE
);
2288 UINT state
= get_menu_state( hSysMenu
, SC_CLOSE
, MF_BYCOMMAND
);
2290 /* If the close item of the sysmenu is disabled or not present do nothing */
2291 if ((state
& (MF_DISABLED
| MF_GRAYED
)) || state
== 0xffffffff)
2294 send_message( hwnd
, WM_SYSCOMMAND
, SC_CLOSE
, lparam
);
2299 send_message( hwnd
, WM_SYSCOMMAND
, SC_HSCROLL
+ HTHSCROLL
, lparam
);
2303 send_message( hwnd
, WM_SYSCOMMAND
, SC_VSCROLL
+ HTVSCROLL
, lparam
);
2309 static HBRUSH
handle_control_color( HDC hdc
, UINT type
)
2311 if (type
== CTLCOLOR_SCROLLBAR
)
2313 HBRUSH hb
= get_sys_color_brush( COLOR_SCROLLBAR
);
2314 COLORREF bk
= get_sys_color( COLOR_3DHILIGHT
);
2315 NtGdiGetAndSetDCDword( hdc
, NtGdiSetTextColor
, get_sys_color( COLOR_3DFACE
), NULL
);
2316 NtGdiGetAndSetDCDword( hdc
, NtGdiSetBkColor
, bk
, NULL
);
2318 /* if COLOR_WINDOW happens to be the same as COLOR_3DHILIGHT
2319 * we better use 0x55aa bitmap brush to make scrollbar's background
2320 * look different from the window background.
2322 if (bk
== get_sys_color( COLOR_WINDOW
)) return get_55aa_brush();
2324 NtGdiUnrealizeObject( hb
);
2328 NtGdiGetAndSetDCDword( hdc
, NtGdiSetTextColor
, get_sys_color( COLOR_WINDOWTEXT
), NULL
);
2330 if (type
== CTLCOLOR_EDIT
|| type
== CTLCOLOR_LISTBOX
)
2331 NtGdiGetAndSetDCDword( hdc
, NtGdiSetBkColor
, get_sys_color( COLOR_WINDOW
), NULL
);
2334 NtGdiGetAndSetDCDword( hdc
, NtGdiSetBkColor
, get_sys_color( COLOR_3DFACE
), NULL
);
2335 return get_sys_color_brush( COLOR_3DFACE
);
2338 return get_sys_color_brush( COLOR_WINDOW
);
2341 static LRESULT
handle_nc_mouse_move( HWND hwnd
, WPARAM wparam
, LPARAM lparam
)
2346 TRACE( "hwnd=%p wparam=%#lx lparam=%#lx\n", hwnd
, (long)wparam
, lparam
);
2348 if (wparam
!= HTHSCROLL
&& wparam
!= HTVSCROLL
)
2351 get_window_rects( hwnd
, COORDS_CLIENT
, &rect
, NULL
, get_thread_dpi() );
2353 pt
.x
= (short)LOWORD( lparam
);
2354 pt
.y
= (short)HIWORD( lparam
);
2355 screen_to_client( hwnd
, &pt
);
2358 handle_scroll_event( hwnd
, wparam
== HTHSCROLL
? SB_HORZ
: SB_VERT
, WM_NCMOUSEMOVE
, pt
);
2362 static LRESULT
handle_nc_mouse_leave( HWND hwnd
)
2364 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
2367 TRACE( "hwnd=%p\n", hwnd
);
2369 if (style
& WS_HSCROLL
)
2370 handle_scroll_event( hwnd
, SB_HORZ
, WM_NCMOUSELEAVE
, pt
);
2371 if (style
& WS_VSCROLL
)
2372 handle_scroll_event( hwnd
, SB_VERT
, WM_NCMOUSELEAVE
, pt
);
2377 LRESULT
default_window_proc( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
, BOOL ansi
)
2386 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*)lparam
;
2387 set_window_text( hwnd
, cs
->lpszName
, ansi
);
2389 if (cs
->style
& (WS_HSCROLL
| WS_VSCROLL
))
2391 SCROLLINFO si
= { .cbSize
= sizeof(si
), .fMask
= SIF_ALL
, .nMax
= 100 };
2392 NtUserSetScrollInfo( hwnd
, SB_HORZ
, &si
, FALSE
);
2393 NtUserSetScrollInfo( hwnd
, SB_VERT
, &si
, FALSE
);
2402 WND
*win
= get_win_ptr( hwnd
);
2406 free( win
->pScroll
);
2407 win
->pScroll
= NULL
;
2408 release_win_ptr( win
);
2413 handle_nc_calc_size( hwnd
, wparam
, (RECT
*)lparam
);
2419 pt
.x
= (short)LOWORD( lparam
);
2420 pt
.y
= (short)HIWORD( lparam
);
2421 return handle_nc_hit_test( hwnd
, pt
);
2425 return handle_nc_paint( hwnd
, (HRGN
)wparam
);
2428 return handle_nc_activate( hwnd
, wparam
, lparam
);
2430 case WM_NCLBUTTONDOWN
:
2431 return handle_nc_lbutton_down( hwnd
, wparam
, lparam
);
2433 case WM_NCRBUTTONDOWN
:
2434 return handle_nc_rbutton_down( hwnd
, wparam
, lparam
);
2436 case WM_LBUTTONDBLCLK
:
2437 return handle_nc_button_dbl_click( hwnd
, HTCLIENT
, lparam
);
2439 case WM_NCLBUTTONDBLCLK
:
2440 return handle_nc_button_dbl_click( hwnd
, wparam
, lparam
);
2442 case WM_NCMOUSEMOVE
:
2443 result
= handle_nc_mouse_move( hwnd
, wparam
, lparam
);
2446 case WM_NCMOUSELEAVE
:
2447 result
= handle_nc_mouse_leave( hwnd
);
2453 pt
.x
= (short)LOWORD( lparam
);
2454 pt
.y
= (short)HIWORD( lparam
);
2455 client_to_screen( hwnd
, &pt
);
2456 send_message( hwnd
, WM_CONTEXTMENU
, (WPARAM
)hwnd
, MAKELPARAM( pt
.x
, pt
.y
));
2460 case WM_NCRBUTTONUP
:
2464 case WM_NCXBUTTONUP
:
2465 if (HIWORD(wparam
) == XBUTTON1
|| HIWORD(wparam
) == XBUTTON2
)
2467 send_message( hwnd
, WM_APPCOMMAND
, (WPARAM
)hwnd
,
2468 MAKELPARAM( LOWORD( wparam
), FAPPCOMMAND_MOUSE
| HIWORD( wparam
)));
2472 case WM_CONTEXTMENU
:
2473 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
)
2474 send_message( get_parent( hwnd
), msg
, (WPARAM
)hwnd
, lparam
);
2479 pt
.x
= (short)LOWORD( lparam
);
2480 pt
.y
= (short)HIWORD( lparam
);
2481 hitcode
= handle_nc_hit_test( hwnd
, pt
);
2483 /* Track system popup if click was in the caption area. */
2484 if (hitcode
== HTCAPTION
|| hitcode
== HTSYSMENU
)
2485 NtUserTrackPopupMenuEx( NtUserGetSystemMenu( hwnd
, FALSE
),
2486 TPM_LEFTBUTTON
| TPM_RIGHTBUTTON
,
2487 pt
.x
, pt
.y
, hwnd
, NULL
);
2491 case WM_POPUPSYSTEMMENU
:
2492 /* This is an undocumented message used by the windows taskbar to
2493 * display the system menu of windows that belong to other processes. */
2494 NtUserTrackPopupMenuEx( NtUserGetSystemMenu( hwnd
, FALSE
), TPM_LEFTBUTTON
| TPM_RIGHTBUTTON
,
2495 (short)LOWORD(lparam
), (short)HIWORD(lparam
), hwnd
, NULL
);
2498 case WM_WINDOWPOSCHANGING
:
2499 return handle_window_pos_changing( hwnd
, (WINDOWPOS
*)lparam
);
2501 case WM_WINDOWPOSCHANGED
:
2502 handle_window_pos_changed( hwnd
, (const WINDOWPOS
*)lparam
);
2509 HDC hdc
= NtUserBeginPaint( hwnd
, &ps
);
2513 if (is_iconic(hwnd
) && ((icon
= UlongToHandle( get_class_long( hwnd
, GCLP_HICON
, FALSE
)))))
2518 get_client_rect( hwnd
, &rc
);
2519 x
= (rc
.right
- rc
.left
- get_system_metrics( SM_CXICON
)) / 2;
2520 y
= (rc
.bottom
- rc
.top
- get_system_metrics( SM_CYICON
)) / 2;
2521 TRACE( "Painting class icon: vis rect=(%s)\n", wine_dbgstr_rect(&ps
.rcPaint
) );
2522 NtUserDrawIconEx( hdc
, x
, y
, icon
, 0, 0, 0, 0, DI_NORMAL
| DI_COMPAT
| DI_DEFAULTSIZE
);
2524 NtUserEndPaint( hwnd
, &ps
);
2530 NtUserRedrawWindow ( hwnd
, NULL
, 0, RDW_ERASENOW
| RDW_ERASE
| RDW_ALLCHILDREN
);
2534 if (wparam
) set_window_style( hwnd
, WS_VISIBLE
, 0 );
2537 NtUserRedrawWindow( hwnd
, NULL
, 0, RDW_ALLCHILDREN
| RDW_VALIDATE
);
2538 set_window_style( hwnd
, 0, WS_VISIBLE
);
2543 NtUserDestroyWindow( hwnd
);
2546 case WM_MOUSEACTIVATE
:
2547 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
)
2549 result
= send_message( get_parent(hwnd
), WM_MOUSEACTIVATE
, wparam
, lparam
);
2553 /* Caption clicks are handled by handle_nc_lbutton_down() */
2554 result
= HIWORD(lparam
) == WM_LBUTTONDOWN
&& LOWORD(lparam
) == HTCAPTION
?
2555 MA_NOACTIVATE
: MA_ACTIVATE
;
2559 /* The default action in Windows is to set the keyboard focus to
2560 * the window, if it's being activated and not minimized */
2561 if (LOWORD(wparam
) != WA_INACTIVE
&& !is_iconic( hwnd
)) NtUserSetFocus( hwnd
);
2565 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
)
2566 result
= send_message( get_parent( hwnd
), WM_MOUSEWHEEL
, wparam
, lparam
);
2570 case WM_ICONERASEBKGND
:
2573 HDC hdc
= (HDC
)wparam
;
2574 HBRUSH hbr
= UlongToHandle( get_class_long( hwnd
, GCLP_HBRBACKGROUND
, FALSE
));
2577 if (get_class_long( hwnd
, GCL_STYLE
, FALSE
) & CS_PARENTDC
)
2579 /* can't use GetClipBox with a parent DC or we fill the whole parent */
2580 get_client_rect( hwnd
, &rect
);
2581 NtGdiTransformPoints( hdc
, (POINT
*)&rect
, (POINT
*)&rect
, 1, NtGdiDPtoLP
);
2583 else NtGdiGetAppClipBox( hdc
, &rect
);
2584 fill_rect( hdc
, &rect
, hbr
);
2594 if (get_capture() == hwnd
) release_capture();
2598 result
= set_window_text( hwnd
, (void *)lparam
, ansi
);
2599 if (result
&& (get_window_long( hwnd
, GWL_STYLE
) & WS_CAPTION
) == WS_CAPTION
)
2600 handle_nc_paint( hwnd
, (HRGN
)1 ); /* repaint caption */
2603 case WM_GETTEXTLENGTH
:
2605 WND
*win
= get_win_ptr( hwnd
);
2606 if (win
&& win
->text
)
2609 result
= win32u_wctomb_size( &ansi_cp
, win
->text
, wcslen( win
->text
));
2611 result
= wcslen( win
->text
);
2613 release_win_ptr( win
);
2622 if (!(win
= get_win_ptr( hwnd
))) break;
2628 char *dest
= (char *)lparam
;
2630 result
= win32u_wctomb( &ansi_cp
, dest
, wparam
- 1,
2631 win
->text
, wcslen( win
->text
));
2636 WCHAR
*dest
= (WCHAR
*)lparam
;
2637 if (win
->text
) result
= min( wcslen( win
->text
), wparam
- 1 );
2638 if (result
) memcpy( dest
, win
->text
, result
* sizeof(WCHAR
) );
2647 release_win_ptr( win
);
2652 result
= (LRESULT
)set_window_icon( hwnd
, wparam
, (HICON
)lparam
);
2653 if ((get_window_long( hwnd
, GWL_STYLE
) & WS_CAPTION
) == WS_CAPTION
)
2654 handle_nc_paint( hwnd
, (HRGN
)1 ); /* repaint caption */
2658 result
= (LRESULT
)get_window_icon( hwnd
, wparam
);
2662 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
)
2664 /* with the exception of the border around a resizable window,
2665 * give the parent first chance to set the cursor */
2666 if ((LOWORD( lparam
) < HTSIZEFIRST
) || (LOWORD( lparam
) > HTSIZELAST
))
2668 HWND parent
= get_parent( hwnd
);
2669 if (parent
!= get_desktop_window() &&
2670 send_message( parent
, WM_SETCURSOR
, wparam
, lparam
)) return TRUE
;
2673 handle_set_cursor( hwnd
, wparam
, lparam
);
2678 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
2680 if (!lparam
) break; /* sent from ShowWindow */
2681 if ((style
& WS_VISIBLE
) && wparam
) break;
2682 if (!(style
& WS_VISIBLE
) && !wparam
) break;
2683 if (!get_window_relative( hwnd
, GW_OWNER
)) break;
2684 if (!(win
= get_win_ptr( hwnd
))) break;
2685 if (win
== WND_OTHER_PROCESS
) break;
2688 if (!(win
->flags
& WIN_NEEDS_SHOW_OWNEDPOPUP
))
2690 release_win_ptr( win
);
2693 win
->flags
&= ~WIN_NEEDS_SHOW_OWNEDPOPUP
;
2695 else win
->flags
|= WIN_NEEDS_SHOW_OWNEDPOPUP
;
2696 release_win_ptr( win
);
2697 NtUserShowWindow( hwnd
, wparam
? SW_SHOWNOACTIVATE
: SW_HIDE
);
2701 case WM_CTLCOLORMSGBOX
:
2702 case WM_CTLCOLOREDIT
:
2703 case WM_CTLCOLORLISTBOX
:
2704 case WM_CTLCOLORBTN
:
2705 case WM_CTLCOLORDLG
:
2706 case WM_CTLCOLORSTATIC
:
2707 case WM_CTLCOLORSCROLLBAR
:
2708 return (LRESULT
)handle_control_color( (HDC
)wparam
, msg
- WM_CTLCOLORMSGBOX
);
2711 return (LRESULT
)handle_control_color( (HDC
)wparam
, HIWORD( lparam
));
2714 result
= handle_sys_command( hwnd
, wparam
, lparam
);
2717 case WM_LBUTTONDOWN
:
2718 case WM_RBUTTONDOWN
:
2719 case WM_MBUTTONDOWN
:
2720 f10_key
= menu_sys_key
= 0;
2724 if (wparam
== VK_F10
) f10_key
= VK_F10
;
2728 if (HIWORD( lparam
) & KEYDATA_ALT
)
2730 if ((wparam
== VK_MENU
|| wparam
== VK_LMENU
|| wparam
== VK_RMENU
) && !menu_sys_key
)
2737 if (wparam
== VK_F4
) /* try to close the window */
2739 HWND top
= NtUserGetAncestor( hwnd
, GA_ROOT
);
2740 if (!(get_class_long( top
, GCL_STYLE
, FALSE
) & CS_NOCLOSE
))
2741 NtUserPostMessage( top
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
2744 else if (wparam
== VK_F10
)
2746 if (NtUserGetKeyState(VK_SHIFT
) & 0x8000)
2747 send_message( hwnd
, WM_CONTEXTMENU
, (WPARAM
)hwnd
, -1 );
2750 else if (wparam
== VK_ESCAPE
&& (NtUserGetKeyState( VK_SHIFT
) & 0x8000))
2751 send_message( hwnd
, WM_SYSCOMMAND
, SC_KEYMENU
, ' ' );
2756 /* Press and release F10 or ALT */
2757 if (((wparam
== VK_MENU
|| wparam
== VK_LMENU
|| wparam
== VK_RMENU
) && menu_sys_key
) ||
2758 (wparam
== VK_F10
&& f10_key
))
2759 send_message( NtUserGetAncestor( hwnd
, GA_ROOT
), WM_SYSCOMMAND
, SC_KEYMENU
, 0 );
2760 menu_sys_key
= f10_key
= 0;
2765 if (wparam
== '\r' && is_iconic( hwnd
))
2767 NtUserPostMessage( hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, 0 );
2770 if ((HIWORD( lparam
) & KEYDATA_ALT
) && wparam
)
2776 win32u_mbtowc( &ansi_cp
, &wch
, 1, &ch
, 1 );
2779 if (wch
== '\t' || wch
== '\x1b') break;
2780 if (wch
== ' ' && (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
))
2781 send_message( get_parent( hwnd
), msg
, wch
, lparam
);
2783 send_message( hwnd
, WM_SYSCOMMAND
, SC_KEYMENU
, wch
);
2785 else if (wparam
!= '\x1b') /* Ctrl-Esc */
2793 hi
.cbSize
= sizeof(HELPINFO
);
2794 get_cursor_pos( &hi
.MousePos
);
2795 if (is_menu_active())
2797 MENUINFO info
= { .cbSize
= sizeof(info
), .fMask
= MIM_HELPID
};
2798 hi
.iContextType
= HELPINFO_MENUITEM
;
2799 hi
.hItemHandle
= is_menu_active();
2800 hi
.iCtrlId
= NtUserMenuItemFromPoint( hwnd
, hi
.hItemHandle
,
2801 hi
.MousePos
.x
, hi
.MousePos
.y
);
2802 get_menu_info( hi
.hItemHandle
, &info
);
2803 hi
.dwContextId
= info
.dwContextHelpID
;
2807 hi
.iContextType
= HELPINFO_WINDOW
;
2808 hi
.hItemHandle
= hwnd
;
2809 hi
.iCtrlId
= get_window_long_ptr( hwnd
, GWLP_ID
, FALSE
);
2810 hi
.dwContextId
= get_window_context_help_id( hwnd
);
2812 send_message( hwnd
, WM_HELP
, 0, (LPARAM
)&hi
);
2817 if ((lparam
& PRF_CHECKVISIBLE
) && !is_window_visible ( hwnd
)) break;
2819 if (lparam
& (PRF_CHILDREN
| PRF_OWNED
| PRF_NONCLIENT
))
2820 WARN( "WM_PRINT message with unsupported lparam %lx\n", lparam
);
2822 if (lparam
& PRF_ERASEBKGND
) send_message( hwnd
, WM_ERASEBKGND
, wparam
, 0 );
2823 if (lparam
& PRF_CLIENT
) send_message(hwnd
, WM_PRINTCLIENT
, wparam
, lparam
);
2828 HWND parent
= get_parent( hwnd
);
2830 call_hooks( WH_SHELL
, HSHELL_APPCOMMAND
, wparam
, lparam
, 0 );
2832 send_message( parent
, msg
, wparam
, lparam
);
2845 case WM_QUERYDROPOBJECT
:
2846 result
= (get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_ACCEPTFILES
) != 0;
2849 case WM_QUERYDRAGICON
:
2852 HICON icon
= (HICON
)get_class_long_ptr( hwnd
, GCLP_HICON
, FALSE
);
2853 HINSTANCE instance
= (HINSTANCE
)get_window_long_ptr( hwnd
, GWLP_HINSTANCE
, FALSE
);
2857 result
= (LRESULT
)icon
;
2861 for (len
= 1; len
< 64; len
++)
2863 if((icon
= LoadImageW( instance
, MAKEINTRESOURCEW( len
), IMAGE_ICON
, 0, 0,
2864 LR_SHARED
| LR_DEFAULTSIZE
)))
2866 result
= (LRESULT
)icon
;
2870 if (!result
) result
= (LRESULT
)LoadImageW( 0, (WCHAR
*)IDI_APPLICATION
, IMAGE_ICON
,
2871 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
2875 case WM_ISACTIVEICON
:
2876 result
= (win_get_flags( hwnd
) & WIN_NCACTIVATED
) != 0;
2879 case WM_NOTIFYFORMAT
:
2880 result
= is_window_unicode(hwnd
) ? NFR_UNICODE
: NFR_ANSI
;
2884 case WM_QUERYENDSESSION
:
2889 send_message( get_parent( hwnd
), msg
, wparam
, lparam
);
2892 case WM_STYLECHANGED
:
2893 if (wparam
== GWL_STYLE
&& (get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_LAYERED
))
2895 STYLESTRUCT
*style
= (STYLESTRUCT
*)lparam
;
2896 if ((style
->styleOld
^ style
->styleNew
) & (WS_CAPTION
|WS_THICKFRAME
|WS_VSCROLL
|WS_HSCROLL
))
2897 NtUserSetWindowPos( hwnd
, 0, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOZORDER
|
2898 SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOCLIENTSIZE
| SWP_NOCLIENTMOVE
);
2902 case WM_INPUTLANGCHANGEREQUEST
:
2903 NtUserActivateKeyboardLayout( (HKL
)lparam
, 0 );
2906 case WM_INPUTLANGCHANGE
:
2908 struct user_thread_info
*info
= get_user_thread_info();
2909 HWND
*win_array
= list_window_children( 0, hwnd
, NULL
, 0 );
2911 info
->kbd_layout
= (HKL
)lparam
;
2915 while (win_array
[count
])
2916 send_message( win_array
[count
++], WM_INPUTLANGCHANGE
, wparam
, lparam
);
2921 case WM_IME_SETCONTEXT
:
2922 case WM_IME_COMPOSITION
:
2923 case WM_IME_STARTCOMPOSITION
:
2924 case WM_IME_ENDCOMPOSITION
:
2927 case WM_IME_CONTROL
:
2929 HWND ime_hwnd
= get_default_ime_window( hwnd
);
2931 result
= NtUserMessageCall( ime_hwnd
, msg
, wparam
, lparam
,
2932 0, NtUserSendMessage
, ansi
);
2940 LRESULT
desktop_window_proc( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
2942 static const WCHAR wine_display_device_guidW
[] =
2943 {'_','_','w','i','n','e','_','d','i','s','p','l','a','y','_','d','e','v','i','c','e',
2944 '_','g','u','i','d',0};
2950 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*)lparam
;
2951 const GUID
*guid
= cs
->lpCreateParams
;
2959 if (NtUserGetAncestor( hwnd
, GA_PARENT
)) return FALSE
; /* refuse to create non-desktop window */
2961 sprintf( buffer
, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
2962 (unsigned int)guid
->Data1
, guid
->Data2
, guid
->Data3
,
2963 guid
->Data4
[0], guid
->Data4
[1], guid
->Data4
[2], guid
->Data4
[3],
2964 guid
->Data4
[4], guid
->Data4
[5], guid
->Data4
[6], guid
->Data4
[7] );
2965 NtAddAtom( bufferW
, asciiz_to_unicode( bufferW
, buffer
) - sizeof(WCHAR
), &atom
);
2966 NtUserSetProp( hwnd
, wine_display_device_guidW
, ULongToHandle( atom
) );
2972 case WM_DISPLAYCHANGE
:
2973 return user_driver
->pDesktopWindowProc( hwnd
, msg
, wparam
, lparam
);
2975 if (msg
>= WM_USER
&& hwnd
== get_desktop_window())
2976 return user_driver
->pDesktopWindowProc( hwnd
, msg
, wparam
, lparam
);
2979 return default_window_proc( hwnd
, msg
, wparam
, lparam
, FALSE
);
2982 /***********************************************************************
2983 * NtUserGetTitleBarInfo (win32u.@)
2985 BOOL WINAPI
NtUserGetTitleBarInfo( HWND hwnd
, TITLEBARINFO
*info
)
2987 DWORD style
, ex_style
;
2989 TRACE( "(%p %p)\n", hwnd
, info
);
2993 RtlSetLastWin32Error( ERROR_NOACCESS
);
2997 if (info
->cbSize
!= sizeof(TITLEBARINFO
))
2999 TRACE( "Invalid TITLEBARINFO size: %d\n", (int)info
->cbSize
);
3000 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
3004 style
= get_window_long( hwnd
, GWL_STYLE
);
3005 ex_style
= get_window_long( hwnd
, GWL_EXSTYLE
);
3006 get_inside_rect( hwnd
, COORDS_SCREEN
, &info
->rcTitleBar
, style
, ex_style
);
3008 info
->rcTitleBar
.bottom
= info
->rcTitleBar
.top
;
3009 if (ex_style
& WS_EX_TOOLWINDOW
)
3010 info
->rcTitleBar
.bottom
+= get_system_metrics( SM_CYSMCAPTION
);
3013 info
->rcTitleBar
.bottom
+= get_system_metrics( SM_CYCAPTION
);
3014 info
->rcTitleBar
.left
+= get_system_metrics( SM_CXSIZE
);
3017 memset( info
->rgstate
, 0, sizeof(info
->rgstate
) );
3018 info
->rgstate
[0] = STATE_SYSTEM_FOCUSABLE
;
3020 if (style
& WS_CAPTION
)
3022 info
->rgstate
[1] = STATE_SYSTEM_INVISIBLE
;
3023 if (style
& WS_SYSMENU
)
3025 if (!(style
& (WS_MINIMIZEBOX
|WS_MAXIMIZEBOX
)))
3027 info
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
3028 info
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
3032 if (!(style
& WS_MINIMIZEBOX
))
3033 info
->rgstate
[2] = STATE_SYSTEM_UNAVAILABLE
;
3034 if (!(style
& WS_MAXIMIZEBOX
))
3035 info
->rgstate
[3] = STATE_SYSTEM_UNAVAILABLE
;
3037 if (!(ex_style
& WS_EX_CONTEXTHELP
))
3038 info
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
3039 if (get_class_long( hwnd
, GCL_STYLE
, FALSE
) & CS_NOCLOSE
)
3040 info
->rgstate
[5] = STATE_SYSTEM_UNAVAILABLE
;
3044 info
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
3045 info
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
3046 info
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
3047 info
->rgstate
[5] = STATE_SYSTEM_INVISIBLE
;
3051 info
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;