2 * Window related functions
4 * Copyright 1993, 1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #define WIN32_NO_STATUS
30 #include "ntgdi_private.h"
31 #include "ntuser_private.h"
32 #include "wine/server.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(win
);
37 #define NB_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
38 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1)
40 static void *user_handles
[NB_USER_HANDLES
];
42 #define SWP_AGG_NOGEOMETRYCHANGE \
43 (SWP_NOSIZE | SWP_NOCLIENTSIZE | SWP_NOZORDER)
44 #define SWP_AGG_NOPOSCHANGE \
45 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER)
46 #define SWP_AGG_STATUSFLAGS \
47 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
48 #define SWP_AGG_NOCLIENTCHANGE \
49 (SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
51 #define PLACE_MIN 0x0001
52 #define PLACE_MAX 0x0002
53 #define PLACE_RECT 0x0004
55 /***********************************************************************
58 HANDLE
alloc_user_handle( struct user_object
*ptr
, unsigned int type
)
62 SERVER_START_REQ( alloc_user_handle
)
64 if (!wine_server_call_err( req
)) handle
= wine_server_ptr_handle( reply
->handle
);
70 UINT index
= USER_HANDLE_TO_INDEX( handle
);
72 assert( index
< NB_USER_HANDLES
);
75 InterlockedExchangePointer( &user_handles
[index
], ptr
);
80 /***********************************************************************
83 void *get_user_handle_ptr( HANDLE handle
, unsigned int type
)
85 struct user_object
*ptr
;
86 WORD index
= USER_HANDLE_TO_INDEX( handle
);
88 if (index
>= NB_USER_HANDLES
) return NULL
;
91 if ((ptr
= user_handles
[index
]))
93 if (ptr
->type
== type
&&
94 ((UINT
)(UINT_PTR
)ptr
->handle
== (UINT
)(UINT_PTR
)handle
||
95 !HIWORD(handle
) || HIWORD(handle
) == 0xffff))
99 else ptr
= OBJ_OTHER_PROCESS
;
104 /***********************************************************************
105 * set_user_handle_ptr
107 static void set_user_handle_ptr( HANDLE handle
, struct user_object
*ptr
)
109 WORD index
= USER_HANDLE_TO_INDEX(handle
);
110 assert( index
< NB_USER_HANDLES
);
111 InterlockedExchangePointer( &user_handles
[index
], ptr
);
114 /***********************************************************************
115 * release_user_handle_ptr
117 void release_user_handle_ptr( void *ptr
)
119 assert( ptr
&& ptr
!= OBJ_OTHER_PROCESS
);
123 /***********************************************************************
126 void *free_user_handle( HANDLE handle
, unsigned int type
)
128 struct user_object
*ptr
;
129 WORD index
= USER_HANDLE_TO_INDEX( handle
);
131 if ((ptr
= get_user_handle_ptr( handle
, type
)) && ptr
!= OBJ_OTHER_PROCESS
)
133 SERVER_START_REQ( free_user_handle
)
135 req
->handle
= wine_server_user_handle( handle
);
136 if (wine_server_call( req
)) ptr
= NULL
;
137 else InterlockedCompareExchangePointer( &user_handles
[index
], NULL
, ptr
);
145 /***********************************************************************
148 static WND
*next_thread_window_ptr( HWND
*hwnd
)
150 struct user_object
*ptr
;
152 WORD index
= *hwnd
? USER_HANDLE_TO_INDEX( *hwnd
) + 1 : 0;
154 while (index
< NB_USER_HANDLES
)
156 if (!(ptr
= user_handles
[index
++])) continue;
157 if (ptr
->type
!= NTUSER_OBJ_WINDOW
) continue;
159 if (win
->tid
!= GetCurrentThreadId()) continue;
166 /*******************************************************************
167 * get_hwnd_message_parent
169 * Return the parent for HWND_MESSAGE windows.
171 HWND
get_hwnd_message_parent(void)
173 struct ntuser_thread_info
*thread_info
= NtUserGetThreadInfo();
175 if (!thread_info
->msg_window
) get_desktop_window(); /* trigger creation */
176 return UlongToHandle( thread_info
->msg_window
);
179 /***********************************************************************
180 * get_full_window_handle
182 * Convert a possibly truncated window handle to a full 32-bit handle.
184 HWND
get_full_window_handle( HWND hwnd
)
188 if (!hwnd
|| (ULONG_PTR
)hwnd
>> 16) return hwnd
;
189 if (LOWORD(hwnd
) <= 1 || LOWORD(hwnd
) == 0xffff) return hwnd
;
190 /* do sign extension for -2 and -3 */
191 if (LOWORD(hwnd
) >= (WORD
)-3) return (HWND
)(LONG_PTR
)(INT16
)LOWORD(hwnd
);
193 if (!(win
= get_win_ptr( hwnd
))) return hwnd
;
195 if (win
== WND_DESKTOP
)
197 if (LOWORD(hwnd
) == LOWORD(get_desktop_window())) return get_desktop_window();
198 else return get_hwnd_message_parent();
201 if (win
!= WND_OTHER_PROCESS
)
203 hwnd
= win
->obj
.handle
;
204 release_win_ptr( win
);
206 else /* may belong to another process */
208 SERVER_START_REQ( get_window_info
)
210 req
->handle
= wine_server_user_handle( hwnd
);
211 if (!wine_server_call_err( req
)) hwnd
= wine_server_ptr_handle( reply
->full_handle
);
218 /*******************************************************************
221 * Check if window is the desktop or the HWND_MESSAGE top parent.
223 BOOL
is_desktop_window( HWND hwnd
)
225 struct ntuser_thread_info
*thread_info
= NtUserGetThreadInfo();
227 if (!hwnd
) return FALSE
;
228 if (hwnd
== UlongToHandle( thread_info
->top_window
)) return TRUE
;
229 if (hwnd
== UlongToHandle( thread_info
->msg_window
)) return TRUE
;
231 if (!HIWORD(hwnd
) || HIWORD(hwnd
) == 0xffff)
233 if (LOWORD(thread_info
->top_window
) == LOWORD(hwnd
)) return TRUE
;
234 if (LOWORD(thread_info
->msg_window
) == LOWORD(hwnd
)) return TRUE
;
239 /***********************************************************************
242 * Return a pointer to the WND structure if local to the process,
243 * or WND_OTHER_PROCESS if handle may be valid in other process.
244 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
246 WND
*get_win_ptr( HWND hwnd
)
250 if ((win
= get_user_handle_ptr( hwnd
, NTUSER_OBJ_WINDOW
)) == WND_OTHER_PROCESS
)
252 if (is_desktop_window( hwnd
)) win
= WND_DESKTOP
;
257 /***********************************************************************
258 * is_current_thread_window
260 * Check whether a given window belongs to the current process (and return the full handle).
262 HWND
is_current_thread_window( HWND hwnd
)
267 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
)
269 if (win
->tid
== GetCurrentThreadId()) ret
= win
->obj
.handle
;
270 release_win_ptr( win
);
274 /***********************************************************************
275 * is_current_process_window
277 * Check whether a given window belongs to the current process (and return the full handle).
279 HWND
is_current_process_window( HWND hwnd
)
284 if (!(ptr
= get_win_ptr( hwnd
)) || ptr
== WND_OTHER_PROCESS
|| ptr
== WND_DESKTOP
) return 0;
285 ret
= ptr
->obj
.handle
;
286 release_win_ptr( ptr
);
291 BOOL
is_window( HWND hwnd
)
296 if (!(win
= get_win_ptr( hwnd
))) return FALSE
;
297 if (win
== WND_DESKTOP
) return TRUE
;
299 if (win
!= WND_OTHER_PROCESS
)
301 release_win_ptr( win
);
305 /* check other processes */
306 SERVER_START_REQ( get_window_info
)
308 req
->handle
= wine_server_user_handle( hwnd
);
309 ret
= !wine_server_call_err( req
);
315 /* see GetWindowThreadProcessId */
316 DWORD
get_window_thread( HWND hwnd
, DWORD
*process
)
321 if (!(ptr
= get_win_ptr( hwnd
)))
323 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
327 if (ptr
!= WND_OTHER_PROCESS
&& ptr
!= WND_DESKTOP
)
329 /* got a valid window */
331 if (process
) *process
= GetCurrentProcessId();
332 release_win_ptr( ptr
);
336 /* check other processes */
337 SERVER_START_REQ( get_window_info
)
339 req
->handle
= wine_server_user_handle( hwnd
);
340 if (!wine_server_call_err( req
))
342 tid
= (DWORD
)reply
->tid
;
343 if (process
) *process
= (DWORD
)reply
->pid
;
351 HWND
get_parent( HWND hwnd
)
356 if (!(win
= get_win_ptr( hwnd
)))
358 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
361 if (win
== WND_DESKTOP
) return 0;
362 if (win
== WND_OTHER_PROCESS
)
364 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
365 if (style
& (WS_POPUP
| WS_CHILD
))
367 SERVER_START_REQ( get_window_tree
)
369 req
->handle
= wine_server_user_handle( hwnd
);
370 if (!wine_server_call_err( req
))
372 if (style
& WS_POPUP
) retval
= wine_server_ptr_handle( reply
->owner
);
373 else if (style
& WS_CHILD
) retval
= wine_server_ptr_handle( reply
->parent
);
381 if (win
->dwStyle
& WS_POPUP
) retval
= win
->owner
;
382 else if (win
->dwStyle
& WS_CHILD
) retval
= win
->parent
;
383 release_win_ptr( win
);
388 /*****************************************************************
389 * NtUserSetParent (win32u.@)
391 HWND WINAPI
NtUserSetParent( HWND hwnd
, HWND parent
)
393 RECT window_rect
, old_screen_rect
, new_screen_rect
;
394 DPI_AWARENESS_CONTEXT context
;
402 TRACE("(%p %p)\n", hwnd
, parent
);
404 if (is_broadcast(hwnd
) || is_broadcast(parent
))
406 RtlSetLastWin32Error(ERROR_INVALID_PARAMETER
);
410 if (!parent
) parent
= get_desktop_window();
411 else if (parent
== HWND_MESSAGE
) parent
= get_hwnd_message_parent();
412 else parent
= get_full_window_handle( parent
);
414 if (!is_window( parent
))
416 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
420 /* Some applications try to set a child as a parent */
421 if (is_child( hwnd
, parent
))
423 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
427 if (!(full_handle
= is_current_thread_window( hwnd
)))
428 return UlongToHandle( send_message( hwnd
, WM_WINE_SETPARENT
, (WPARAM
)parent
, 0 ));
430 if (full_handle
== parent
)
432 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
436 /* Windows hides the window first, then shows it again
437 * including the WM_SHOWWINDOW messages and all */
438 was_visible
= NtUserShowWindow( hwnd
, SW_HIDE
);
440 win
= get_win_ptr( hwnd
);
441 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return 0;
443 get_window_rects( hwnd
, COORDS_PARENT
, &window_rect
, NULL
, get_dpi_for_window(hwnd
) );
444 get_window_rects( hwnd
, COORDS_SCREEN
, &old_screen_rect
, NULL
, 0 );
446 SERVER_START_REQ( set_parent
)
448 req
->handle
= wine_server_user_handle( hwnd
);
449 req
->parent
= wine_server_user_handle( parent
);
450 if ((ret
= !wine_server_call_err( req
)))
452 old_parent
= wine_server_ptr_handle( reply
->old_parent
);
453 win
->parent
= parent
= wine_server_ptr_handle( reply
->full_parent
);
454 win
->dpi
= reply
->dpi
;
455 win
->dpi_awareness
= reply
->awareness
;
460 release_win_ptr( win
);
463 get_window_rects( hwnd
, COORDS_SCREEN
, &new_screen_rect
, NULL
, 0 );
464 context
= SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( hwnd
));
466 user_driver
->pSetParent( full_handle
, parent
, old_parent
);
469 winpos
.hwndInsertAfter
= HWND_TOP
;
470 winpos
.x
= window_rect
.left
;
471 winpos
.y
= window_rect
.top
;
474 winpos
.flags
= SWP_NOSIZE
;
476 set_window_pos( &winpos
, new_screen_rect
.left
- old_screen_rect
.left
,
477 new_screen_rect
.top
- old_screen_rect
.top
);
479 if (was_visible
) NtUserShowWindow( hwnd
, SW_SHOW
);
481 SetThreadDpiAwarenessContext( context
);
486 HWND
get_window_relative( HWND hwnd
, UINT rel
)
490 if (rel
== GW_OWNER
) /* this one may be available locally */
492 WND
*win
= get_win_ptr( hwnd
);
495 RtlSetLastWin32Error( ERROR_INVALID_HANDLE
);
498 if (win
== WND_DESKTOP
) return 0;
499 if (win
!= WND_OTHER_PROCESS
)
502 release_win_ptr( win
);
505 /* else fall through to server call */
508 SERVER_START_REQ( get_window_tree
)
510 req
->handle
= wine_server_user_handle( hwnd
);
511 if (!wine_server_call_err( req
))
516 retval
= wine_server_ptr_handle( reply
->first_sibling
);
519 retval
= wine_server_ptr_handle( reply
->last_sibling
);
522 retval
= wine_server_ptr_handle( reply
->next_sibling
);
525 retval
= wine_server_ptr_handle( reply
->prev_sibling
);
528 retval
= wine_server_ptr_handle( reply
->owner
);
531 retval
= wine_server_ptr_handle( reply
->first_child
);
540 /*******************************************************************
541 * list_window_parents
543 * Build an array of all parents of a given window, starting with
544 * the immediate parent. The array must be freed with free().
546 static HWND
*list_window_parents( HWND hwnd
)
550 int i
, pos
= 0, size
= 16, count
;
552 if (!(list
= malloc( size
* sizeof(HWND
) ))) return NULL
;
557 if (!(win
= get_win_ptr( current
))) goto empty
;
558 if (win
== WND_OTHER_PROCESS
) break; /* need to do it the hard way */
559 if (win
== WND_DESKTOP
)
561 if (!pos
) goto empty
;
565 list
[pos
] = current
= win
->parent
;
566 release_win_ptr( win
);
567 if (!current
) return list
;
568 if (++pos
== size
- 1)
570 /* need to grow the list */
571 HWND
*new_list
= realloc( list
, (size
+ 16) * sizeof(HWND
) );
572 if (!new_list
) goto empty
;
578 /* at least one parent belongs to another process, have to query the server */
583 SERVER_START_REQ( get_window_parents
)
585 req
->handle
= wine_server_user_handle( hwnd
);
586 wine_server_set_reply( req
, list
, (size
-1) * sizeof(user_handle_t
) );
587 if (!wine_server_call( req
)) count
= reply
->count
;
590 if (!count
) goto empty
;
593 /* start from the end since HWND is potentially larger than user_handle_t */
594 for (i
= count
- 1; i
>= 0; i
--)
595 list
[i
] = wine_server_ptr_handle( ((user_handle_t
*)list
)[i
] );
601 if (!(list
= malloc( size
* sizeof(HWND
) ))) return NULL
;
609 /*******************************************************************
610 * list_window_children
612 * Build an array of the children of a given window. The array must be
613 * freed with HeapFree. Returns NULL when no windows are found.
615 HWND
*list_window_children( HDESK desktop
, HWND hwnd
, UNICODE_STRING
*class, DWORD tid
)
619 ATOM atom
= class ? get_int_atom_value( class ) : 0;
621 /* empty class is not the same as NULL class */
622 if (!atom
&& class && !class->Length
) return NULL
;
628 if (!(list
= malloc( size
* sizeof(HWND
) ))) break;
630 SERVER_START_REQ( get_window_children
)
632 req
->desktop
= wine_server_obj_handle( desktop
);
633 req
->parent
= wine_server_user_handle( hwnd
);
636 if (!atom
&& class) wine_server_add_data( req
, class->Buffer
, class->Length
);
637 wine_server_set_reply( req
, list
, (size
-1) * sizeof(user_handle_t
) );
638 if (!wine_server_call( req
)) count
= reply
->count
;
641 if (count
&& count
< size
)
643 /* start from the end since HWND is potentially larger than user_handle_t */
644 for (i
= count
- 1; i
>= 0; i
--)
645 list
[i
] = wine_server_ptr_handle( ((user_handle_t
*)list
)[i
] );
651 size
= count
+ 1; /* restart with a large enough buffer */
656 /*****************************************************************
657 * NtUserGetAncestor (win32u.@)
659 HWND WINAPI
NtUserGetAncestor( HWND hwnd
, UINT type
)
667 if (!(win
= get_win_ptr( hwnd
)))
669 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
672 if (win
== WND_DESKTOP
) return 0;
673 if (win
!= WND_OTHER_PROCESS
)
676 release_win_ptr( win
);
678 else /* need to query the server */
680 SERVER_START_REQ( get_window_tree
)
682 req
->handle
= wine_server_user_handle( hwnd
);
683 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->parent
);
690 if (!(list
= list_window_parents( hwnd
))) return 0;
692 if (!list
[0] || !list
[1]) ret
= get_full_window_handle( hwnd
); /* top-level window */
696 while (list
[count
]) count
++;
697 ret
= list
[count
- 2]; /* get the one before the desktop */
703 if (is_desktop_window( hwnd
)) return 0;
704 ret
= get_full_window_handle( hwnd
);
707 HWND parent
= get_parent( ret
);
717 BOOL
is_child( HWND parent
, HWND child
)
723 if (!(get_window_long( child
, GWL_STYLE
) & WS_CHILD
)) return FALSE
;
724 if (!(list
= list_window_parents( child
))) return FALSE
;
725 parent
= get_full_window_handle( parent
);
726 for (i
= 0; list
[i
]; i
++)
728 if (list
[i
] == parent
)
730 ret
= list
[i
] && list
[i
+1];
733 if (!(get_window_long( list
[i
], GWL_STYLE
) & WS_CHILD
)) break;
739 /* see IsWindowVisible */
740 BOOL
is_window_visible( HWND hwnd
)
746 if (!(get_window_long( hwnd
, GWL_STYLE
) & WS_VISIBLE
)) return FALSE
;
747 if (!(list
= list_window_parents( hwnd
))) return TRUE
;
750 for (i
= 0; list
[i
+1]; i
++)
751 if (!(get_window_long( list
[i
], GWL_STYLE
) & WS_VISIBLE
)) break;
752 retval
= !list
[i
+1] && (list
[i
] == get_desktop_window()); /* top message window isn't visible */
758 /***********************************************************************
761 * hwnd is drawable when it is visible, all parents are not
762 * minimized, and it is itself not minimized unless we are
763 * trying to draw its default class icon.
765 BOOL
is_window_drawable( HWND hwnd
, BOOL icon
)
770 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
772 if (!(style
& WS_VISIBLE
)) return FALSE
;
773 if ((style
& WS_MINIMIZE
) && icon
&& get_class_long_ptr( hwnd
, GCLP_HICON
, FALSE
)) return FALSE
;
775 if (!(list
= list_window_parents( hwnd
))) return TRUE
;
778 for (i
= 0; list
[i
+1]; i
++)
779 if ((get_window_long( list
[i
], GWL_STYLE
) & (WS_VISIBLE
|WS_MINIMIZE
)) != WS_VISIBLE
)
781 retval
= !list
[i
+1] && (list
[i
] == get_desktop_window()); /* top message window isn't visible */
787 /* see IsWindowUnicode */
788 BOOL
is_window_unicode( HWND hwnd
)
793 if (!(win
= get_win_ptr(hwnd
))) return FALSE
;
795 if (win
== WND_DESKTOP
) return TRUE
;
797 if (win
!= WND_OTHER_PROCESS
)
799 ret
= (win
->flags
& WIN_ISUNICODE
) != 0;
800 release_win_ptr( win
);
804 SERVER_START_REQ( get_window_info
)
806 req
->handle
= wine_server_user_handle( hwnd
);
807 if (!wine_server_call_err( req
)) ret
= reply
->is_unicode
;
814 /* see EnableWindow */
815 BOOL
enable_window( HWND hwnd
, BOOL enable
)
819 if (is_broadcast(hwnd
))
821 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
825 TRACE( "( %p, %d )\n", hwnd
, enable
);
829 ret
= (set_window_style( hwnd
, 0, WS_DISABLED
) & WS_DISABLED
) != 0;
830 if (ret
) send_message( hwnd
, WM_ENABLE
, TRUE
, 0 );
834 send_message( hwnd
, WM_CANCELMODE
, 0, 0 );
836 ret
= (set_window_style( hwnd
, WS_DISABLED
, 0 ) & WS_DISABLED
) != 0;
839 if (hwnd
== get_focus())
840 NtUserSetFocus( 0 ); /* A disabled window can't have the focus */
842 send_message( hwnd
, WM_ENABLE
, FALSE
, 0 );
848 /* see IsWindowEnabled */
849 BOOL
is_window_enabled( HWND hwnd
)
853 RtlSetLastWin32Error( NO_ERROR
);
854 ret
= get_window_long( hwnd
, GWL_STYLE
);
855 if (!ret
&& RtlGetLastWin32Error() != NO_ERROR
) return FALSE
;
856 return !(ret
& WS_DISABLED
);
859 /* see GetWindowDpiAwarenessContext */
860 DPI_AWARENESS_CONTEXT
get_window_dpi_awareness_context( HWND hwnd
)
862 DPI_AWARENESS_CONTEXT ret
= 0;
865 if (!(win
= get_win_ptr( hwnd
)))
867 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
870 if (win
== WND_DESKTOP
) return DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
;
871 if (win
!= WND_OTHER_PROCESS
)
873 ret
= ULongToHandle( win
->dpi_awareness
| 0x10 );
874 release_win_ptr( win
);
878 SERVER_START_REQ( get_window_info
)
880 req
->handle
= wine_server_user_handle( hwnd
);
881 if (!wine_server_call_err( req
)) ret
= ULongToHandle( reply
->awareness
| 0x10 );
888 /* see GetDpiForWindow */
889 UINT
get_dpi_for_window( HWND hwnd
)
894 if (!(win
= get_win_ptr( hwnd
)))
896 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
899 if (win
== WND_DESKTOP
)
902 return get_monitor_dpi( monitor_from_point( pt
, MONITOR_DEFAULTTOPRIMARY
, 0 ));
904 if (win
!= WND_OTHER_PROCESS
)
907 if (!ret
) ret
= get_win_monitor_dpi( hwnd
);
908 release_win_ptr( win
);
912 SERVER_START_REQ( get_window_info
)
914 req
->handle
= wine_server_user_handle( hwnd
);
915 if (!wine_server_call_err( req
)) ret
= reply
->dpi
;
922 static LONG_PTR
get_win_data( const void *ptr
, UINT size
)
924 if (size
== sizeof(WORD
))
927 memcpy( &ret
, ptr
, sizeof(ret
) );
930 else if (size
== sizeof(DWORD
))
933 memcpy( &ret
, ptr
, sizeof(ret
) );
939 memcpy( &ret
, ptr
, sizeof(ret
) );
944 /* helper for set_window_long */
945 static inline void set_win_data( void *ptr
, LONG_PTR val
, UINT size
)
947 if (size
== sizeof(WORD
))
950 memcpy( ptr
, &newval
, sizeof(newval
) );
952 else if (size
== sizeof(DWORD
))
955 memcpy( ptr
, &newval
, sizeof(newval
) );
959 memcpy( ptr
, &val
, sizeof(val
) );
963 BOOL
is_iconic( HWND hwnd
)
965 return (get_window_long( hwnd
, GWL_STYLE
) & WS_MINIMIZE
) != 0;
968 BOOL
is_zoomed( HWND hwnd
)
970 return (get_window_long( hwnd
, GWL_STYLE
) & WS_MAXIMIZE
) != 0;
973 static LONG_PTR
get_window_long_size( HWND hwnd
, INT offset
, UINT size
, BOOL ansi
)
978 if (offset
== GWLP_HWNDPARENT
)
980 HWND parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
981 if (parent
== get_desktop_window())
982 parent
= get_window_relative( hwnd
, GW_OWNER
);
983 return (ULONG_PTR
)parent
;
986 if (!(win
= get_win_ptr( hwnd
)))
988 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
992 if (win
== WND_DESKTOP
)
997 retval
= WS_POPUP
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
; /* message parent is not visible */
998 if (get_full_window_handle( hwnd
) == get_desktop_window())
999 retval
|= WS_VISIBLE
;
1004 case GWLP_HINSTANCE
:
1007 RtlSetLastWin32Error( ERROR_ACCESS_DENIED
);
1010 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
1014 if (win
== WND_OTHER_PROCESS
)
1016 if (offset
== GWLP_WNDPROC
)
1018 RtlSetLastWin32Error( ERROR_ACCESS_DENIED
);
1021 SERVER_START_REQ( set_window_info
)
1023 req
->handle
= wine_server_user_handle( hwnd
);
1024 req
->flags
= 0; /* don't set anything, just retrieve */
1025 req
->extra_offset
= (offset
>= 0) ? offset
: -1;
1026 req
->extra_size
= (offset
>= 0) ? size
: 0;
1027 if (!wine_server_call_err( req
))
1031 case GWL_STYLE
: retval
= reply
->old_style
; break;
1032 case GWL_EXSTYLE
: retval
= reply
->old_ex_style
; break;
1033 case GWLP_ID
: retval
= reply
->old_id
; break;
1034 case GWLP_HINSTANCE
: retval
= (ULONG_PTR
)wine_server_get_ptr( reply
->old_instance
); break;
1035 case GWLP_USERDATA
: retval
= reply
->old_user_data
; break;
1037 if (offset
>= 0) retval
= get_win_data( &reply
->old_extra_value
, size
);
1038 else RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
1047 /* now we have a valid win */
1051 if (offset
> (int)(win
->cbWndExtra
- size
))
1053 WARN("Invalid offset %d\n", offset
);
1054 release_win_ptr( win
);
1055 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
1058 retval
= get_win_data( (char *)win
->wExtra
+ offset
, size
);
1059 release_win_ptr( win
);
1065 case GWLP_USERDATA
: retval
= win
->userdata
; break;
1066 case GWL_STYLE
: retval
= win
->dwStyle
; break;
1067 case GWL_EXSTYLE
: retval
= win
->dwExStyle
; break;
1068 case GWLP_ID
: retval
= win
->wIDmenu
; break;
1069 case GWLP_HINSTANCE
: retval
= (ULONG_PTR
)win
->hInstance
; break;
1071 /* This looks like a hack only for the edit control (see tests). This makes these controls
1072 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
1073 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
1075 if (win
->winproc
== BUILTIN_WINPROC(WINPROC_EDIT
) && (!!ansi
!= !(win
->flags
& WIN_ISUNICODE
)))
1076 retval
= (ULONG_PTR
)win
->winproc
;
1078 retval
= (ULONG_PTR
)get_winproc( win
->winproc
, ansi
);
1081 WARN("Unknown offset %d\n", offset
);
1082 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
1085 release_win_ptr( win
);
1089 /* see GetWindowLongW */
1090 DWORD
get_window_long( HWND hwnd
, INT offset
)
1092 return get_window_long_size( hwnd
, offset
, sizeof(LONG
), FALSE
);
1095 /* see GetWindowLongPtr */
1096 ULONG_PTR
get_window_long_ptr( HWND hwnd
, INT offset
, BOOL ansi
)
1098 return get_window_long_size( hwnd
, offset
, sizeof(LONG_PTR
), ansi
);
1101 /* see GetWindowWord */
1102 static WORD
get_window_word( HWND hwnd
, INT offset
)
1104 if (offset
< 0 && offset
!= GWLP_USERDATA
)
1106 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
1109 return get_window_long_size( hwnd
, offset
, sizeof(WORD
), TRUE
);
1112 /***********************************************************************
1115 * Change the style of a window.
1117 ULONG
set_window_style( HWND hwnd
, ULONG set_bits
, ULONG clear_bits
)
1119 BOOL ok
, made_visible
= FALSE
;
1121 WND
*win
= get_win_ptr( hwnd
);
1123 if (!win
|| win
== WND_DESKTOP
) return 0;
1124 if (win
== WND_OTHER_PROCESS
)
1126 if (is_window(hwnd
))
1127 return send_message( hwnd
, WM_WINE_SETSTYLE
, set_bits
, clear_bits
);
1130 style
.styleOld
= win
->dwStyle
;
1131 style
.styleNew
= (win
->dwStyle
| set_bits
) & ~clear_bits
;
1132 if (style
.styleNew
== style
.styleOld
)
1134 release_win_ptr( win
);
1135 return style
.styleNew
;
1137 SERVER_START_REQ( set_window_info
)
1139 req
->handle
= wine_server_user_handle( hwnd
);
1140 req
->flags
= SET_WIN_STYLE
;
1141 req
->style
= style
.styleNew
;
1142 req
->extra_offset
= -1;
1143 if ((ok
= !wine_server_call( req
)))
1145 style
.styleOld
= reply
->old_style
;
1146 win
->dwStyle
= style
.styleNew
;
1151 if (ok
&& ((style
.styleOld
^ style
.styleNew
) & WS_VISIBLE
))
1153 made_visible
= (style
.styleNew
& WS_VISIBLE
) != 0;
1154 invalidate_dce( win
, NULL
);
1156 release_win_ptr( win
);
1160 user_driver
->pSetWindowStyle( hwnd
, GWL_STYLE
, &style
);
1161 if (made_visible
) update_window_state( hwnd
);
1163 return style
.styleOld
;
1166 static DWORD
fix_exstyle( DWORD style
, DWORD exstyle
)
1168 if ((exstyle
& WS_EX_DLGMODALFRAME
) ||
1169 (!(exstyle
& WS_EX_STATICEDGE
) && (style
& (WS_DLGFRAME
| WS_THICKFRAME
))))
1170 exstyle
|= WS_EX_WINDOWEDGE
;
1172 exstyle
&= ~WS_EX_WINDOWEDGE
;
1176 /* Change the owner of a window. */
1177 static HWND
set_window_owner( HWND hwnd
, HWND owner
)
1179 WND
*win
= get_win_ptr( hwnd
);
1182 if (!win
|| win
== WND_DESKTOP
) return 0;
1183 if (win
== WND_OTHER_PROCESS
)
1185 if (is_window(hwnd
)) ERR( "cannot set owner %p on other process window %p\n", owner
, hwnd
);
1188 SERVER_START_REQ( set_window_owner
)
1190 req
->handle
= wine_server_user_handle( hwnd
);
1191 req
->owner
= wine_server_user_handle( owner
);
1192 if (!wine_server_call( req
))
1194 win
->owner
= wine_server_ptr_handle( reply
->full_owner
);
1195 ret
= wine_server_ptr_handle( reply
->prev_owner
);
1199 release_win_ptr( win
);
1203 /* Helper function for SetWindowLong(). */
1204 LONG_PTR
set_window_long( HWND hwnd
, INT offset
, UINT size
, LONG_PTR newval
, BOOL ansi
)
1206 BOOL ok
, made_visible
= FALSE
;
1207 LONG_PTR retval
= 0;
1211 TRACE( "%p %d %lx %c\n", hwnd
, offset
, newval
, ansi
? 'A' : 'W' );
1213 if (is_broadcast(hwnd
))
1215 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
1219 if (!(win
= get_win_ptr( hwnd
)))
1221 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
1224 if (win
== WND_DESKTOP
)
1226 /* can't change anything on the desktop window */
1227 RtlSetLastWin32Error( ERROR_ACCESS_DENIED
);
1230 if (win
== WND_OTHER_PROCESS
)
1232 if (offset
== GWLP_WNDPROC
)
1234 RtlSetLastWin32Error( ERROR_ACCESS_DENIED
);
1237 if (offset
> 32767 || offset
< -32767)
1239 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
1242 return send_message( hwnd
, WM_WINE_SETWINDOWLONG
, MAKEWPARAM( offset
, size
), newval
);
1245 /* first some special cases */
1249 style
.styleOld
= win
->dwStyle
;
1250 style
.styleNew
= newval
;
1251 release_win_ptr( win
);
1252 send_message( hwnd
, WM_STYLECHANGING
, GWL_STYLE
, (LPARAM
)&style
);
1253 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
) return 0;
1254 newval
= style
.styleNew
;
1255 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
1256 if (win
->parent
== get_desktop_window()) newval
|= WS_CLIPSIBLINGS
;
1257 /* WS_MINIMIZE can't be reset */
1258 if (win
->dwStyle
& WS_MINIMIZE
) newval
|= WS_MINIMIZE
;
1261 style
.styleOld
= win
->dwExStyle
;
1262 style
.styleNew
= newval
;
1263 release_win_ptr( win
);
1264 send_message( hwnd
, WM_STYLECHANGING
, GWL_EXSTYLE
, (LPARAM
)&style
);
1265 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
) return 0;
1266 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
1267 newval
= (style
.styleNew
& ~WS_EX_TOPMOST
) | (win
->dwExStyle
& WS_EX_TOPMOST
);
1268 newval
= fix_exstyle(win
->dwStyle
, newval
);
1270 case GWLP_HWNDPARENT
:
1271 if (win
->parent
== get_desktop_window())
1273 release_win_ptr( win
);
1274 return (ULONG_PTR
)set_window_owner( hwnd
, (HWND
)newval
);
1278 release_win_ptr( win
);
1279 return (ULONG_PTR
)NtUserSetParent( hwnd
, (HWND
)newval
);
1284 UINT old_flags
= win
->flags
;
1285 retval
= get_window_long_ptr( hwnd
, offset
, ansi
);
1286 proc
= alloc_winproc( (WNDPROC
)newval
, ansi
);
1287 if (proc
) win
->winproc
= proc
;
1288 if (is_winproc_unicode( proc
, !ansi
)) win
->flags
|= WIN_ISUNICODE
;
1289 else win
->flags
&= ~WIN_ISUNICODE
;
1290 if (!((old_flags
^ win
->flags
) & WIN_ISUNICODE
))
1292 release_win_ptr( win
);
1295 /* update is_unicode flag on the server side */
1299 case GWLP_HINSTANCE
:
1303 if (offset
< 0 || offset
> (int)(win
->cbWndExtra
- size
))
1305 WARN("Invalid offset %d\n", offset
);
1306 release_win_ptr( win
);
1307 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
1310 else if (get_win_data( (char *)win
->wExtra
+ offset
, size
) == newval
)
1312 /* already set to the same value */
1313 release_win_ptr( win
);
1319 SERVER_START_REQ( set_window_info
)
1321 req
->handle
= wine_server_user_handle( hwnd
);
1322 req
->extra_offset
= -1;
1326 req
->flags
= SET_WIN_STYLE
| SET_WIN_EXSTYLE
;
1327 req
->style
= newval
;
1328 req
->ex_style
= fix_exstyle(newval
, win
->dwExStyle
);
1331 req
->flags
= SET_WIN_EXSTYLE
;
1332 req
->ex_style
= newval
;
1335 req
->flags
= SET_WIN_ID
;
1336 req
->extra_value
= newval
;
1338 case GWLP_HINSTANCE
:
1339 req
->flags
= SET_WIN_INSTANCE
;
1340 req
->instance
= wine_server_client_ptr( (void *)newval
);
1343 req
->flags
= SET_WIN_UNICODE
;
1344 req
->is_unicode
= (win
->flags
& WIN_ISUNICODE
) != 0;
1347 if (size
== sizeof(WORD
)) newval
= MAKELONG( newval
, win
->userdata
>> 16 );
1348 req
->flags
= SET_WIN_USERDATA
;
1349 req
->user_data
= newval
;
1352 req
->flags
= SET_WIN_EXTRA
;
1353 req
->extra_offset
= offset
;
1354 req
->extra_size
= size
;
1355 set_win_data( &req
->extra_value
, newval
, size
);
1357 if ((ok
= !wine_server_call_err( req
)))
1362 win
->dwStyle
= newval
;
1363 win
->dwExStyle
= fix_exstyle(win
->dwStyle
, win
->dwExStyle
);
1364 retval
= reply
->old_style
;
1367 win
->dwExStyle
= newval
;
1368 retval
= reply
->old_ex_style
;
1371 win
->wIDmenu
= newval
;
1372 retval
= reply
->old_id
;
1374 case GWLP_HINSTANCE
:
1375 win
->hInstance
= (HINSTANCE
)newval
;
1376 retval
= (ULONG_PTR
)wine_server_get_ptr( reply
->old_instance
);
1381 win
->userdata
= newval
;
1382 retval
= reply
->old_user_data
;
1385 retval
= get_win_data( (char *)win
->wExtra
+ offset
, size
);
1386 set_win_data( (char *)win
->wExtra
+ offset
, newval
, size
);
1393 if ((offset
== GWL_STYLE
&& ((style
.styleOld
^ style
.styleNew
) & WS_VISIBLE
)) ||
1394 (offset
== GWL_EXSTYLE
&& ((style
.styleOld
^ style
.styleNew
) & WS_EX_LAYERED
)))
1396 made_visible
= (win
->dwStyle
& WS_VISIBLE
) != 0;
1397 invalidate_dce( win
, NULL
);
1399 release_win_ptr( win
);
1403 if (offset
== GWL_STYLE
|| offset
== GWL_EXSTYLE
)
1405 style
.styleOld
= retval
;
1406 style
.styleNew
= newval
;
1407 user_driver
->pSetWindowStyle( hwnd
, offset
, &style
);
1408 if (made_visible
) update_window_state( hwnd
);
1409 send_message( hwnd
, WM_STYLECHANGED
, offset
, (LPARAM
)&style
);
1415 /**********************************************************************
1416 * NtUserSetWindowWord (win32u.@)
1418 WORD WINAPI
NtUserSetWindowWord( HWND hwnd
, INT offset
, WORD newval
)
1420 if (offset
< 0 && offset
!= GWLP_USERDATA
)
1422 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
1425 return set_window_long( hwnd
, offset
, sizeof(WORD
), newval
, TRUE
);
1428 /**********************************************************************
1429 * NtUserSetWindowLong (win32u.@)
1431 LONG WINAPI
NtUserSetWindowLong( HWND hwnd
, INT offset
, LONG newval
, BOOL ansi
)
1433 return set_window_long( hwnd
, offset
, sizeof(LONG
), newval
, ansi
);
1436 /*****************************************************************************
1437 * NtUserSetWindowLongPtr (win32u.@)
1439 LONG_PTR WINAPI
NtUserSetWindowLongPtr( HWND hwnd
, INT offset
, LONG_PTR newval
, BOOL ansi
)
1441 return set_window_long( hwnd
, offset
, sizeof(LONG_PTR
), newval
, ansi
);
1444 static BOOL
set_window_pixel_format( HWND hwnd
, int format
)
1446 WND
*win
= get_win_ptr( hwnd
);
1448 if (!win
|| win
== WND_DESKTOP
|| win
== WND_OTHER_PROCESS
)
1450 WARN( "setting format %d on win %p not supported\n", format
, hwnd
);
1453 win
->pixel_format
= format
;
1454 release_win_ptr( win
);
1456 update_window_state( hwnd
);
1460 /***********************************************************************
1461 * NtUserGetProp (win32u.@)
1463 * NOTE Native allows only ATOMs as the second argument. We allow strings
1464 * to save extra server call in GetPropW.
1466 HANDLE WINAPI
NtUserGetProp( HWND hwnd
, const WCHAR
*str
)
1470 SERVER_START_REQ( get_window_property
)
1472 req
->window
= wine_server_user_handle( hwnd
);
1473 if (IS_INTRESOURCE(str
)) req
->atom
= LOWORD(str
);
1474 else wine_server_add_data( req
, str
, lstrlenW(str
) * sizeof(WCHAR
) );
1475 if (!wine_server_call_err( req
)) ret
= reply
->data
;
1481 /*****************************************************************************
1482 * NtUserSetProp (win32u.@)
1484 * NOTE Native allows only ATOMs as the second argument. We allow strings
1485 * to save extra server call in SetPropW.
1487 BOOL WINAPI
NtUserSetProp( HWND hwnd
, const WCHAR
*str
, HANDLE handle
)
1491 SERVER_START_REQ( set_window_property
)
1493 req
->window
= wine_server_user_handle( hwnd
);
1494 req
->data
= (ULONG_PTR
)handle
;
1495 if (IS_INTRESOURCE(str
)) req
->atom
= LOWORD(str
);
1496 else wine_server_add_data( req
, str
, lstrlenW(str
) * sizeof(WCHAR
) );
1497 ret
= !wine_server_call_err( req
);
1504 /***********************************************************************
1505 * NtUserRemoveProp (win32u.@)
1507 * NOTE Native allows only ATOMs as the second argument. We allow strings
1508 * to save extra server call in RemovePropW.
1510 HANDLE WINAPI
NtUserRemoveProp( HWND hwnd
, const WCHAR
*str
)
1514 SERVER_START_REQ( remove_window_property
)
1516 req
->window
= wine_server_user_handle( hwnd
);
1517 if (IS_INTRESOURCE(str
)) req
->atom
= LOWORD(str
);
1518 else wine_server_add_data( req
, str
, lstrlenW(str
) * sizeof(WCHAR
) );
1519 if (!wine_server_call_err( req
)) ret
= reply
->data
;
1526 static void mirror_rect( const RECT
*window_rect
, RECT
*rect
)
1528 int width
= window_rect
->right
- window_rect
->left
;
1529 int tmp
= rect
->left
;
1530 rect
->left
= width
- rect
->right
;
1531 rect
->right
= width
- tmp
;
1534 /***********************************************************************
1537 * Get the window and client rectangles.
1539 BOOL
get_window_rects( HWND hwnd
, enum coords_relative relative
, RECT
*window_rect
,
1540 RECT
*client_rect
, UINT dpi
)
1542 WND
*win
= get_win_ptr( hwnd
);
1547 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
1550 if (win
== WND_DESKTOP
)
1553 rect
.left
= rect
.top
= 0;
1554 if (hwnd
== get_hwnd_message_parent())
1558 rect
= map_dpi_rect( rect
, get_dpi_for_window( hwnd
), dpi
);
1562 rect
= get_primary_monitor_rect( dpi
);
1564 if (window_rect
) *window_rect
= rect
;
1565 if (client_rect
) *client_rect
= rect
;
1568 if (win
!= WND_OTHER_PROCESS
)
1570 UINT window_dpi
= get_dpi_for_window( hwnd
);
1571 RECT window
= win
->window_rect
;
1572 RECT client
= win
->client_rect
;
1577 OffsetRect( &window
, -win
->client_rect
.left
, -win
->client_rect
.top
);
1578 OffsetRect( &client
, -win
->client_rect
.left
, -win
->client_rect
.top
);
1579 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
)
1580 mirror_rect( &win
->client_rect
, &window
);
1583 OffsetRect( &window
, -win
->window_rect
.left
, -win
->window_rect
.top
);
1584 OffsetRect( &client
, -win
->window_rect
.left
, -win
->window_rect
.top
);
1585 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
)
1586 mirror_rect( &win
->window_rect
, &client
);
1591 WND
*parent
= get_win_ptr( win
->parent
);
1592 if (parent
== WND_DESKTOP
) break;
1593 if (!parent
|| parent
== WND_OTHER_PROCESS
)
1595 release_win_ptr( win
);
1598 if (parent
->flags
& WIN_CHILDREN_MOVED
)
1600 release_win_ptr( parent
);
1601 release_win_ptr( win
);
1604 if (parent
->dwExStyle
& WS_EX_LAYOUTRTL
)
1606 mirror_rect( &parent
->client_rect
, &window
);
1607 mirror_rect( &parent
->client_rect
, &client
);
1609 release_win_ptr( parent
);
1615 WND
*parent
= get_win_ptr( win
->parent
);
1616 if (parent
== WND_DESKTOP
) break;
1617 if (!parent
|| parent
== WND_OTHER_PROCESS
)
1619 release_win_ptr( win
);
1622 release_win_ptr( win
);
1623 if (parent
->flags
& WIN_CHILDREN_MOVED
)
1625 release_win_ptr( parent
);
1631 OffsetRect( &window
, win
->client_rect
.left
, win
->client_rect
.top
);
1632 OffsetRect( &client
, win
->client_rect
.left
, win
->client_rect
.top
);
1637 if (window_rect
) *window_rect
= map_dpi_rect( window
, window_dpi
, dpi
);
1638 if (client_rect
) *client_rect
= map_dpi_rect( client
, window_dpi
, dpi
);
1639 release_win_ptr( win
);
1644 SERVER_START_REQ( get_window_rectangles
)
1646 req
->handle
= wine_server_user_handle( hwnd
);
1647 req
->relative
= relative
;
1649 if ((ret
= !wine_server_call_err( req
)))
1653 window_rect
->left
= reply
->window
.left
;
1654 window_rect
->top
= reply
->window
.top
;
1655 window_rect
->right
= reply
->window
.right
;
1656 window_rect
->bottom
= reply
->window
.bottom
;
1660 client_rect
->left
= reply
->client
.left
;
1661 client_rect
->top
= reply
->client
.top
;
1662 client_rect
->right
= reply
->client
.right
;
1663 client_rect
->bottom
= reply
->client
.bottom
;
1671 /* see GetWindowRect */
1672 BOOL
get_window_rect( HWND hwnd
, RECT
*rect
, UINT dpi
)
1674 return get_window_rects( hwnd
, COORDS_SCREEN
, rect
, NULL
, dpi
);
1677 /* see GetClientRect */
1678 BOOL
get_client_rect( HWND hwnd
, RECT
*rect
)
1680 return get_window_rects( hwnd
, COORDS_CLIENT
, NULL
, rect
, get_thread_dpi() );
1683 /* see GetWindowInfo */
1684 static BOOL
get_window_info( HWND hwnd
, WINDOWINFO
*info
)
1687 if (!info
|| !get_window_rects( hwnd
, COORDS_SCREEN
, &info
->rcWindow
,
1688 &info
->rcClient
, get_thread_dpi() ))
1691 info
->dwStyle
= get_window_long( hwnd
, GWL_STYLE
);
1692 info
->dwExStyle
= get_window_long( hwnd
, GWL_EXSTYLE
);
1693 info
->dwWindowStatus
= get_active_window() == hwnd
? WS_ACTIVECAPTION
: 0;
1694 info
->cxWindowBorders
= info
->rcClient
.left
- info
->rcWindow
.left
;
1695 info
->cyWindowBorders
= info
->rcWindow
.bottom
- info
->rcClient
.bottom
;
1696 info
->atomWindowType
= get_class_long( hwnd
, GCW_ATOM
, FALSE
);
1697 info
->wCreatorVersion
= 0x0400;
1701 /***********************************************************************
1702 * update_surface_region
1704 static void update_surface_region( HWND hwnd
)
1710 WND
*win
= get_win_ptr( hwnd
);
1712 if (!win
|| win
== WND_DESKTOP
|| win
== WND_OTHER_PROCESS
) return;
1713 if (!win
->surface
) goto done
;
1717 if (!(data
= malloc( FIELD_OFFSET( RGNDATA
, Buffer
[size
] )))) goto done
;
1719 SERVER_START_REQ( get_surface_region
)
1721 req
->window
= wine_server_user_handle( hwnd
);
1722 wine_server_set_reply( req
, data
->Buffer
, size
);
1723 if (!(status
= wine_server_call( req
)))
1725 size_t reply_size
= wine_server_reply_size( reply
);
1728 data
->rdh
.dwSize
= sizeof(data
->rdh
);
1729 data
->rdh
.iType
= RDH_RECTANGLES
;
1730 data
->rdh
.nCount
= reply_size
/ sizeof(RECT
);
1731 data
->rdh
.nRgnSize
= reply_size
;
1732 region
= NtGdiExtCreateRegion( NULL
, data
->rdh
.dwSize
+ data
->rdh
.nRgnSize
, data
);
1733 NtGdiOffsetRgn( region
, -reply
->visible_rect
.left
, -reply
->visible_rect
.top
);
1736 else size
= reply
->total_size
;
1740 } while (status
== STATUS_BUFFER_OVERFLOW
);
1742 if (status
) goto done
;
1744 win
->surface
->funcs
->set_region( win
->surface
, region
);
1745 if (region
) NtGdiDeleteObjectApp( region
);
1748 release_win_ptr( win
);
1751 /***********************************************************************
1754 * Backend implementation of SetWindowPos.
1756 static BOOL
apply_window_pos( HWND hwnd
, HWND insert_after
, UINT swp_flags
,
1757 const RECT
*window_rect
, const RECT
*client_rect
, const RECT
*valid_rects
)
1760 HWND surface_win
= 0, parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
1761 BOOL ret
, needs_update
= FALSE
;
1762 RECT visible_rect
, old_visible_rect
, old_window_rect
, old_client_rect
, extra_rects
[3];
1763 struct window_surface
*old_surface
, *new_surface
= NULL
;
1765 if (!parent
|| parent
== get_desktop_window())
1767 new_surface
= &dummy_surface
; /* provide a default surface for top-level windows */
1768 window_surface_add_ref( new_surface
);
1770 visible_rect
= *window_rect
;
1771 if (!(ret
= user_driver
->pWindowPosChanging( hwnd
, insert_after
, swp_flags
,
1772 window_rect
, client_rect
, &visible_rect
, &new_surface
)))
1774 if (IsRectEmpty( window_rect
)) visible_rect
= *window_rect
;
1777 visible_rect
= get_virtual_screen_rect( get_thread_dpi() );
1778 intersect_rect( &visible_rect
, &visible_rect
, window_rect
);
1782 get_window_rects( hwnd
, COORDS_SCREEN
, &old_window_rect
, NULL
, get_thread_dpi() );
1783 if (IsRectEmpty( &valid_rects
[0] )) valid_rects
= NULL
;
1785 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_DESKTOP
|| win
== WND_OTHER_PROCESS
)
1787 if (new_surface
) window_surface_release( new_surface
);
1791 /* create or update window surface for top-level windows if the driver doesn't implement WindowPosChanging */
1792 if (!ret
&& new_surface
&& !IsRectEmpty( &visible_rect
) &&
1793 (!(get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_LAYERED
) ||
1794 NtUserGetLayeredWindowAttributes( hwnd
, NULL
, NULL
, NULL
)))
1796 window_surface_release( new_surface
);
1797 if ((new_surface
= win
->surface
)) window_surface_add_ref( new_surface
);
1798 create_offscreen_window_surface( &visible_rect
, &new_surface
);
1801 old_visible_rect
= win
->visible_rect
;
1802 old_client_rect
= win
->client_rect
;
1803 old_surface
= win
->surface
;
1804 if (old_surface
!= new_surface
) swp_flags
|= SWP_FRAMECHANGED
; /* force refreshing non-client area */
1805 if (new_surface
== &dummy_surface
) swp_flags
|= SWP_NOREDRAW
;
1806 else if (old_surface
== &dummy_surface
)
1808 swp_flags
|= SWP_NOCOPYBITS
;
1812 SERVER_START_REQ( set_window_pos
)
1814 req
->handle
= wine_server_user_handle( hwnd
);
1815 req
->previous
= wine_server_user_handle( insert_after
);
1816 req
->swp_flags
= swp_flags
;
1817 req
->window
.left
= window_rect
->left
;
1818 req
->window
.top
= window_rect
->top
;
1819 req
->window
.right
= window_rect
->right
;
1820 req
->window
.bottom
= window_rect
->bottom
;
1821 req
->client
.left
= client_rect
->left
;
1822 req
->client
.top
= client_rect
->top
;
1823 req
->client
.right
= client_rect
->right
;
1824 req
->client
.bottom
= client_rect
->bottom
;
1825 if (!EqualRect( window_rect
, &visible_rect
) || new_surface
|| valid_rects
)
1827 extra_rects
[0] = extra_rects
[1] = visible_rect
;
1830 extra_rects
[1] = new_surface
->rect
;
1831 OffsetRect( &extra_rects
[1], visible_rect
.left
, visible_rect
.top
);
1833 if (valid_rects
) extra_rects
[2] = valid_rects
[0];
1834 else SetRectEmpty( &extra_rects
[2] );
1835 wine_server_add_data( req
, extra_rects
, sizeof(extra_rects
) );
1837 if (new_surface
) req
->paint_flags
|= SET_WINPOS_PAINT_SURFACE
;
1838 if (win
->pixel_format
) req
->paint_flags
|= SET_WINPOS_PIXEL_FORMAT
;
1840 if ((ret
= !wine_server_call( req
)))
1842 win
->dwStyle
= reply
->new_style
;
1843 win
->dwExStyle
= reply
->new_ex_style
;
1844 win
->window_rect
= *window_rect
;
1845 win
->client_rect
= *client_rect
;
1846 win
->visible_rect
= visible_rect
;
1847 win
->surface
= new_surface
;
1848 surface_win
= wine_server_ptr_handle( reply
->surface_win
);
1849 needs_update
= reply
->needs_update
;
1850 if (get_window_long( win
->parent
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
)
1853 get_window_rects( win
->parent
, COORDS_CLIENT
, NULL
, &client
, get_thread_dpi() );
1854 mirror_rect( &client
, &win
->window_rect
);
1855 mirror_rect( &client
, &win
->client_rect
);
1856 mirror_rect( &client
, &win
->visible_rect
);
1858 /* if an RTL window is resized the children have moved */
1859 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
&&
1860 client_rect
->right
- client_rect
->left
!= old_client_rect
.right
- old_client_rect
.left
)
1861 win
->flags
|= WIN_CHILDREN_MOVED
;
1868 if (needs_update
) update_surface_region( surface_win
);
1869 if (((swp_flags
& SWP_AGG_NOPOSCHANGE
) != SWP_AGG_NOPOSCHANGE
) ||
1870 (swp_flags
& (SWP_HIDEWINDOW
| SWP_SHOWWINDOW
| SWP_STATECHANGED
| SWP_FRAMECHANGED
)))
1871 invalidate_dce( win
, &old_window_rect
);
1874 release_win_ptr( win
);
1878 TRACE( "win %p surface %p -> %p\n", hwnd
, old_surface
, new_surface
);
1879 register_window_surface( old_surface
, new_surface
);
1884 move_window_bits( hwnd
, old_surface
, new_surface
, &visible_rect
,
1885 &old_visible_rect
, window_rect
, valid_rects
);
1886 valid_rects
= NULL
; /* prevent the driver from trying to also move the bits */
1888 window_surface_release( old_surface
);
1890 else if (surface_win
&& surface_win
!= hwnd
)
1895 int x_offset
= old_visible_rect
.left
- visible_rect
.left
;
1896 int y_offset
= old_visible_rect
.top
- visible_rect
.top
;
1898 /* if all that happened is that the whole window moved, copy everything */
1899 if (!(swp_flags
& SWP_FRAMECHANGED
) &&
1900 old_visible_rect
.right
- visible_rect
.right
== x_offset
&&
1901 old_visible_rect
.bottom
- visible_rect
.bottom
== y_offset
&&
1902 old_client_rect
.left
- client_rect
->left
== x_offset
&&
1903 old_client_rect
.right
- client_rect
->right
== x_offset
&&
1904 old_client_rect
.top
- client_rect
->top
== y_offset
&&
1905 old_client_rect
.bottom
- client_rect
->bottom
== y_offset
&&
1906 EqualRect( &valid_rects
[0], client_rect
))
1908 rects
[0] = visible_rect
;
1909 rects
[1] = old_visible_rect
;
1910 valid_rects
= rects
;
1912 move_window_bits_parent( hwnd
, surface_win
, window_rect
, valid_rects
);
1913 valid_rects
= NULL
; /* prevent the driver from trying to also move the bits */
1917 user_driver
->pWindowPosChanged( hwnd
, insert_after
, swp_flags
, window_rect
,
1918 client_rect
, &visible_rect
, valid_rects
, new_surface
);
1920 else if (new_surface
) window_surface_release( new_surface
);
1925 /*******************************************************************
1926 * NtUserGetWindowRgnEx (win32u.@)
1928 int WINAPI
NtUserGetWindowRgnEx( HWND hwnd
, HRGN hrgn
, UINT unk
)
1938 if (!(data
= malloc( sizeof(*data
) + size
- 1 )))
1940 RtlSetLastWin32Error( ERROR_OUTOFMEMORY
);
1943 SERVER_START_REQ( get_window_region
)
1945 req
->window
= wine_server_user_handle( hwnd
);
1946 wine_server_set_reply( req
, data
->Buffer
, size
);
1947 if (!(status
= wine_server_call( req
)))
1949 size_t reply_size
= wine_server_reply_size( reply
);
1952 data
->rdh
.dwSize
= sizeof(data
->rdh
);
1953 data
->rdh
.iType
= RDH_RECTANGLES
;
1954 data
->rdh
.nCount
= reply_size
/ sizeof(RECT
);
1955 data
->rdh
.nRgnSize
= reply_size
;
1956 win_rgn
= NtGdiExtCreateRegion( NULL
, data
->rdh
.dwSize
+ data
->rdh
.nRgnSize
, data
);
1959 else size
= reply
->total_size
;
1963 } while (status
== STATUS_BUFFER_OVERFLOW
);
1965 if (set_ntstatus( status
) && win_rgn
)
1967 ret
= NtGdiCombineRgn( hrgn
, win_rgn
, 0, RGN_COPY
);
1968 NtGdiDeleteObjectApp( win_rgn
);
1973 /***********************************************************************
1974 * NtUserSetWindowRgn (win32u.@)
1976 int WINAPI
NtUserSetWindowRgn( HWND hwnd
, HRGN hrgn
, BOOL redraw
)
1978 static const RECT empty_rect
;
1986 if (!(size
= NtGdiGetRegionData( hrgn
, 0, NULL
))) return FALSE
;
1987 if (!(data
= malloc( size
))) return FALSE
;
1988 if (!NtGdiGetRegionData( hrgn
, size
, data
))
1993 SERVER_START_REQ( set_window_region
)
1995 req
->window
= wine_server_user_handle( hwnd
);
1996 req
->redraw
= redraw
!= 0;
1997 if (data
->rdh
.nCount
)
1998 wine_server_add_data( req
, data
->Buffer
, data
->rdh
.nCount
* sizeof(RECT
) );
2000 wine_server_add_data( req
, &empty_rect
, sizeof(empty_rect
) );
2001 ret
= !wine_server_call_err( req
);
2006 else /* clear existing region */
2008 SERVER_START_REQ( set_window_region
)
2010 req
->window
= wine_server_user_handle( hwnd
);
2011 req
->redraw
= redraw
!= 0;
2012 ret
= !wine_server_call_err( req
);
2019 UINT swp_flags
= SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_FRAMECHANGED
|
2020 SWP_NOCLIENTSIZE
| SWP_NOCLIENTMOVE
;
2021 if (!redraw
) swp_flags
|= SWP_NOREDRAW
;
2022 user_driver
->pSetWindowRgn( hwnd
, hrgn
, redraw
);
2023 NtUserSetWindowPos( hwnd
, 0, 0, 0, 0, 0, swp_flags
);
2024 if (hrgn
) NtGdiDeleteObjectApp( hrgn
);
2029 /***********************************************************************
2030 * NtUserMoveWindow (win32u.@)
2032 BOOL WINAPI
NtUserMoveWindow( HWND hwnd
, INT x
, INT y
, INT cx
, INT cy
, BOOL repaint
)
2034 int flags
= SWP_NOZORDER
| SWP_NOACTIVATE
;
2035 if (!repaint
) flags
|= SWP_NOREDRAW
;
2036 TRACE( "%p %d,%d %dx%d %d\n", hwnd
, x
, y
, cx
, cy
, repaint
);
2037 return NtUserSetWindowPos( hwnd
, 0, x
, y
, cx
, cy
, flags
);
2040 /*****************************************************************************
2041 * NtUserGetLayeredWindowAttributes (win32u.@)
2043 BOOL WINAPI
NtUserGetLayeredWindowAttributes( HWND hwnd
, COLORREF
*key
, BYTE
*alpha
, DWORD
*flags
)
2047 SERVER_START_REQ( get_window_layered_info
)
2049 req
->handle
= wine_server_user_handle( hwnd
);
2050 if ((ret
= !wine_server_call_err( req
)))
2052 if (key
) *key
= reply
->color_key
;
2053 if (alpha
) *alpha
= reply
->alpha
;
2054 if (flags
) *flags
= reply
->flags
;
2062 /*****************************************************************************
2063 * NtUserSetLayeredWindowAttributes (win32u.@)
2065 BOOL WINAPI
NtUserSetLayeredWindowAttributes( HWND hwnd
, COLORREF key
, BYTE alpha
, DWORD flags
)
2069 TRACE( "(%p,%s,%d,%x)\n", hwnd
, debugstr_color(key
), alpha
, (int)flags
);
2071 SERVER_START_REQ( set_window_layered_info
)
2073 req
->handle
= wine_server_user_handle( hwnd
);
2074 req
->color_key
= key
;
2077 ret
= !wine_server_call_err( req
);
2083 user_driver
->pSetLayeredWindowAttributes( hwnd
, key
, alpha
, flags
);
2084 update_window_state( hwnd
);
2090 /*****************************************************************************
2091 * UpdateLayeredWindow (win32u.@)
2093 BOOL WINAPI
NtUserUpdateLayeredWindow( HWND hwnd
, HDC hdc_dst
, const POINT
*pts_dst
, const SIZE
*size
,
2094 HDC hdc_src
, const POINT
*pts_src
, COLORREF key
,
2095 const BLENDFUNCTION
*blend
, DWORD flags
, const RECT
*dirty
)
2097 DWORD swp_flags
= SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREDRAW
;
2098 RECT window_rect
, client_rect
;
2099 UPDATELAYEREDWINDOWINFO info
;
2102 if (flags
& ~(ULW_COLORKEY
| ULW_ALPHA
| ULW_OPAQUE
| ULW_EX_NORESIZE
) ||
2103 !(get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_LAYERED
) ||
2104 NtUserGetLayeredWindowAttributes( hwnd
, NULL
, NULL
, NULL
))
2106 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
2110 get_window_rects( hwnd
, COORDS_PARENT
, &window_rect
, &client_rect
, get_thread_dpi() );
2114 offset
.cx
= pts_dst
->x
- window_rect
.left
;
2115 offset
.cy
= pts_dst
->y
- window_rect
.top
;
2116 OffsetRect( &client_rect
, offset
.cx
, offset
.cy
);
2117 OffsetRect( &window_rect
, offset
.cx
, offset
.cy
);
2118 swp_flags
&= ~SWP_NOMOVE
;
2122 offset
.cx
= size
->cx
- (window_rect
.right
- window_rect
.left
);
2123 offset
.cy
= size
->cy
- (window_rect
.bottom
- window_rect
.top
);
2124 if (size
->cx
<= 0 || size
->cy
<= 0)
2126 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
2129 if ((flags
& ULW_EX_NORESIZE
) && (offset
.cx
|| offset
.cy
))
2131 RtlSetLastWin32Error( ERROR_INCORRECT_SIZE
);
2134 client_rect
.right
+= offset
.cx
;
2135 client_rect
.bottom
+= offset
.cy
;
2136 window_rect
.right
+= offset
.cx
;
2137 window_rect
.bottom
+= offset
.cy
;
2138 swp_flags
&= ~SWP_NOSIZE
;
2141 TRACE( "window %p win %s client %s\n", hwnd
,
2142 wine_dbgstr_rect(&window_rect
), wine_dbgstr_rect(&client_rect
) );
2144 apply_window_pos( hwnd
, 0, swp_flags
, &window_rect
, &client_rect
, NULL
);
2146 info
.cbSize
= sizeof(info
);
2147 info
.hdcDst
= hdc_dst
;
2148 info
.pptDst
= pts_dst
;
2150 info
.hdcSrc
= hdc_src
;
2151 info
.pptSrc
= pts_src
;
2153 info
.pblend
= blend
;
2154 info
.dwFlags
= flags
;
2155 info
.prcDirty
= dirty
;
2156 return user_driver
->pUpdateLayeredWindow( hwnd
, &info
, &window_rect
);
2159 /***********************************************************************
2160 * list_children_from_point
2162 * Get the list of children that can contain point from the server.
2163 * Point is in screen coordinates.
2164 * Returned list must be freed by caller.
2166 static HWND
*list_children_from_point( HWND hwnd
, POINT pt
)
2175 if (!(list
= malloc( size
* sizeof(HWND
) ))) break;
2177 SERVER_START_REQ( get_window_children_from_point
)
2179 req
->parent
= wine_server_user_handle( hwnd
);
2182 req
->dpi
= get_thread_dpi();
2183 wine_server_set_reply( req
, list
, (size
-1) * sizeof(user_handle_t
) );
2184 if (!wine_server_call( req
)) count
= reply
->count
;
2187 if (count
&& count
< size
)
2189 /* start from the end since HWND is potentially larger than user_handle_t */
2190 for (i
= count
- 1; i
>= 0; i
--)
2191 list
[i
] = wine_server_ptr_handle( ((user_handle_t
*)list
)[i
] );
2197 size
= count
+ 1; /* restart with a large enough buffer */
2202 /***********************************************************************
2205 * Find the window and hittest for a given point.
2207 HWND
window_from_point( HWND hwnd
, POINT pt
, INT
*hittest
)
2213 if (!hwnd
) hwnd
= get_desktop_window();
2215 *hittest
= HTNOWHERE
;
2217 if (!(list
= list_children_from_point( hwnd
, pt
))) return 0;
2219 /* now determine the hittest */
2221 for (i
= 0; list
[i
]; i
++)
2223 LONG style
= get_window_long( list
[i
], GWL_STYLE
);
2225 /* If window is minimized or disabled, return at once */
2226 if (style
& WS_DISABLED
)
2231 /* Send WM_NCCHITTEST (if same thread) */
2232 if (!is_current_thread_window( list
[i
] ))
2234 *hittest
= HTCLIENT
;
2237 win_pt
= map_dpi_point( pt
, get_thread_dpi(), get_dpi_for_window( list
[i
] ));
2238 res
= send_message( list
[i
], WM_NCHITTEST
, 0, MAKELPARAM( win_pt
.x
, win_pt
.y
));
2239 if (res
!= HTTRANSPARENT
)
2241 *hittest
= res
; /* Found the window */
2244 /* continue search with next window in z-order */
2248 TRACE( "scope %p (%d,%d) returning %p\n", hwnd
, (int)pt
.x
, (int)pt
.y
, ret
);
2252 /*******************************************************************
2253 * NtUserWindowFromPoint (win32u.@)
2255 HWND WINAPI
NtUserWindowFromPoint( LONG x
, LONG y
)
2257 POINT pt
= { .x
= x
, .y
= y
};
2259 return window_from_point( 0, pt
, &hittest
);
2262 /*******************************************************************
2263 * NtUserChildWindowFromPointEx (win32u.@)
2265 HWND WINAPI
NtUserChildWindowFromPointEx( HWND parent
, LONG x
, LONG y
, UINT flags
)
2267 POINT pt
= { .x
= x
, .y
= y
}; /* in the client coordinates */
2273 get_client_rect( parent
, &rect
);
2274 if (!PtInRect( &rect
, pt
)) return 0;
2275 if (!(list
= list_window_children( 0, parent
, NULL
, 0 ))) return parent
;
2277 for (i
= 0; list
[i
]; i
++)
2279 if (!get_window_rects( list
[i
], COORDS_PARENT
, &rect
, NULL
, get_thread_dpi() )) continue;
2280 if (!PtInRect( &rect
, pt
)) continue;
2281 if (flags
& (CWP_SKIPINVISIBLE
|CWP_SKIPDISABLED
))
2283 LONG style
= get_window_long( list
[i
], GWL_STYLE
);
2284 if ((flags
& CWP_SKIPINVISIBLE
) && !(style
& WS_VISIBLE
)) continue;
2285 if ((flags
& CWP_SKIPDISABLED
) && (style
& WS_DISABLED
)) continue;
2287 if (flags
& CWP_SKIPTRANSPARENT
)
2289 if (get_window_long( list
[i
], GWL_EXSTYLE
) & WS_EX_TRANSPARENT
) continue;
2295 if (!ret
) ret
= parent
;
2299 /*******************************************************************
2300 * NtUserRealChildWindowFromPoint (win32u.@)
2302 HWND WINAPI
NtUserRealChildWindowFromPoint( HWND parent
, LONG x
, LONG y
)
2304 return NtUserChildWindowFromPointEx( parent
, x
, y
, CWP_SKIPTRANSPARENT
| CWP_SKIPINVISIBLE
);
2307 /*******************************************************************
2310 * Get the work area that a maximized window can cover, depending on style.
2312 static BOOL
get_work_rect( HWND hwnd
, RECT
*rect
)
2314 HMONITOR monitor
= monitor_from_window( hwnd
, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
2315 MONITORINFO mon_info
;
2318 if (!monitor
) return FALSE
;
2320 mon_info
.cbSize
= sizeof(mon_info
);
2321 get_monitor_info( monitor
, &mon_info
);
2322 *rect
= mon_info
.rcMonitor
;
2324 style
= get_window_long( hwnd
, GWL_STYLE
);
2325 if (style
& WS_MAXIMIZEBOX
)
2327 if ((style
& WS_CAPTION
) == WS_CAPTION
|| !(style
& (WS_CHILD
| WS_POPUP
)))
2328 *rect
= mon_info
.rcWork
;
2333 static RECT
get_maximized_work_rect( HWND hwnd
)
2335 RECT work_rect
= { 0 };
2337 if ((get_window_long( hwnd
, GWL_STYLE
) & (WS_MINIMIZE
| WS_MAXIMIZE
)) == WS_MAXIMIZE
)
2339 if (!get_work_rect( hwnd
, &work_rect
))
2340 work_rect
= get_primary_monitor_rect( get_thread_dpi() );
2345 /*******************************************************************
2346 * update_maximized_pos
2348 * For top level windows covering the work area, we might have to
2349 * "forget" the maximized position. Windows presumably does this
2350 * to avoid situations where the border style changes, which would
2351 * lead the window to be outside the screen, or the window gets
2352 * reloaded on a different screen, and the "saved" position no
2353 * longer applies to it (despite being maximized).
2355 * Some applications (e.g. Imperiums: Greek Wars) depend on this.
2357 static void update_maximized_pos( WND
*wnd
, RECT
*work_rect
)
2359 if (wnd
->parent
&& wnd
->parent
!= get_desktop_window())
2362 if (wnd
->dwStyle
& WS_MAXIMIZE
)
2364 if (wnd
->window_rect
.left
<= work_rect
->left
&& wnd
->window_rect
.top
<= work_rect
->top
&&
2365 wnd
->window_rect
.right
>= work_rect
->right
&& wnd
->window_rect
.bottom
>= work_rect
->bottom
)
2366 wnd
->max_pos
.x
= wnd
->max_pos
.y
= -1;
2369 wnd
->max_pos
.x
= wnd
->max_pos
.y
= -1;
2372 static BOOL
empty_point( POINT pt
)
2374 return pt
.x
== -1 && pt
.y
== -1;
2377 /***********************************************************************
2378 * NtUserGetWindowPlacement (win32u.@)
2380 BOOL WINAPI
NtUserGetWindowPlacement( HWND hwnd
, WINDOWPLACEMENT
*placement
)
2382 RECT work_rect
= get_maximized_work_rect( hwnd
);
2383 WND
*win
= get_win_ptr( hwnd
);
2386 if (!win
) return FALSE
;
2388 if (win
== WND_DESKTOP
)
2390 placement
->length
= sizeof(*placement
);
2391 placement
->showCmd
= SW_SHOWNORMAL
;
2392 placement
->flags
= 0;
2393 placement
->ptMinPosition
.x
= -1;
2394 placement
->ptMinPosition
.y
= -1;
2395 placement
->ptMaxPosition
.x
= -1;
2396 placement
->ptMaxPosition
.y
= -1;
2397 get_window_rect( hwnd
, &placement
->rcNormalPosition
, get_thread_dpi() );
2400 if (win
== WND_OTHER_PROCESS
)
2402 RECT normal_position
;
2405 if (!get_window_rect( hwnd
, &normal_position
, get_thread_dpi() ))
2408 FIXME("not fully supported on other process window %p.\n", hwnd
);
2410 placement
->length
= sizeof(*placement
);
2411 style
= get_window_long( hwnd
, GWL_STYLE
);
2412 if (style
& WS_MINIMIZE
)
2413 placement
->showCmd
= SW_SHOWMINIMIZED
;
2415 placement
->showCmd
= (style
& WS_MAXIMIZE
) ? SW_SHOWMAXIMIZED
: SW_SHOWNORMAL
;
2416 /* provide some dummy information */
2417 placement
->flags
= 0;
2418 placement
->ptMinPosition
.x
= -1;
2419 placement
->ptMinPosition
.y
= -1;
2420 placement
->ptMaxPosition
.x
= -1;
2421 placement
->ptMaxPosition
.y
= -1;
2422 placement
->rcNormalPosition
= normal_position
;
2426 /* update the placement according to the current style */
2427 if (win
->dwStyle
& WS_MINIMIZE
)
2429 win
->min_pos
.x
= win
->window_rect
.left
;
2430 win
->min_pos
.y
= win
->window_rect
.top
;
2432 else if (win
->dwStyle
& WS_MAXIMIZE
)
2434 win
->max_pos
.x
= win
->window_rect
.left
;
2435 win
->max_pos
.y
= win
->window_rect
.top
;
2439 win
->normal_rect
= win
->window_rect
;
2441 update_maximized_pos( win
, &work_rect
);
2443 placement
->length
= sizeof(*placement
);
2444 if (win
->dwStyle
& WS_MINIMIZE
)
2445 placement
->showCmd
= SW_SHOWMINIMIZED
;
2447 placement
->showCmd
= ( win
->dwStyle
& WS_MAXIMIZE
) ? SW_SHOWMAXIMIZED
: SW_SHOWNORMAL
;
2448 if (win
->flags
& WIN_RESTORE_MAX
)
2449 placement
->flags
= WPF_RESTORETOMAXIMIZED
;
2451 placement
->flags
= 0;
2452 win_dpi
= get_dpi_for_window( hwnd
);
2453 placement
->ptMinPosition
= empty_point(win
->min_pos
) ? win
->min_pos
2454 : map_dpi_point( win
->min_pos
, win_dpi
, get_thread_dpi() );
2455 placement
->ptMaxPosition
= empty_point(win
->max_pos
) ? win
->max_pos
2456 : map_dpi_point( win
->max_pos
, win_dpi
, get_thread_dpi() );
2457 placement
->rcNormalPosition
= map_dpi_rect( win
->normal_rect
, win_dpi
, get_thread_dpi() );
2458 release_win_ptr( win
);
2460 TRACE( "%p: returning min %d,%d max %d,%d normal %s\n",
2461 hwnd
, (int)placement
->ptMinPosition
.x
, (int)placement
->ptMinPosition
.y
,
2462 (int)placement
->ptMaxPosition
.x
, (int)placement
->ptMaxPosition
.y
,
2463 wine_dbgstr_rect(&placement
->rcNormalPosition
) );
2467 /* make sure the specified rect is visible on screen */
2468 static void make_rect_onscreen( RECT
*rect
)
2471 HMONITOR monitor
= monitor_from_rect( rect
, MONITOR_DEFAULTTONEAREST
, get_thread_dpi() );
2473 info
.cbSize
= sizeof(info
);
2474 if (!monitor
|| !get_monitor_info( monitor
, &info
)) return;
2475 /* FIXME: map coordinates from rcWork to rcMonitor */
2476 if (rect
->right
<= info
.rcWork
.left
)
2478 rect
->right
+= info
.rcWork
.left
- rect
->left
;
2479 rect
->left
= info
.rcWork
.left
;
2481 else if (rect
->left
>= info
.rcWork
.right
)
2483 rect
->left
+= info
.rcWork
.right
- rect
->right
;
2484 rect
->right
= info
.rcWork
.right
;
2486 if (rect
->bottom
<= info
.rcWork
.top
)
2488 rect
->bottom
+= info
.rcWork
.top
- rect
->top
;
2489 rect
->top
= info
.rcWork
.top
;
2491 else if (rect
->top
>= info
.rcWork
.bottom
)
2493 rect
->top
+= info
.rcWork
.bottom
- rect
->bottom
;
2494 rect
->bottom
= info
.rcWork
.bottom
;
2498 /***********************************************************************
2499 * NtUserGetInternalWindowPos (win32u.@)
2501 UINT WINAPI
NtUserGetInternalWindowPos( HWND hwnd
, RECT
*rect
, POINT
*pt
)
2503 WINDOWPLACEMENT placement
;
2505 placement
.length
= sizeof(placement
);
2506 if (!NtUserGetWindowPlacement( hwnd
, &placement
)) return 0;
2507 if (rect
) *rect
= placement
.rcNormalPosition
;
2508 if (pt
) *pt
= placement
.ptMinPosition
;
2509 return placement
.showCmd
;
2512 /* make sure the specified point is visible on screen */
2513 static void make_point_onscreen( POINT
*pt
)
2517 SetRect( &rect
, pt
->x
, pt
->y
, pt
->x
+ 1, pt
->y
+ 1 );
2518 make_rect_onscreen( &rect
);
2523 static BOOL
set_window_placement( HWND hwnd
, const WINDOWPLACEMENT
*wndpl
, UINT flags
)
2525 RECT work_rect
= get_maximized_work_rect( hwnd
);
2526 WND
*win
= get_win_ptr( hwnd
);
2527 WINDOWPLACEMENT wp
= *wndpl
;
2530 if (flags
& PLACE_MIN
) make_point_onscreen( &wp
.ptMinPosition
);
2531 if (flags
& PLACE_MAX
) make_point_onscreen( &wp
.ptMaxPosition
);
2532 if (flags
& PLACE_RECT
) make_rect_onscreen( &wp
.rcNormalPosition
);
2534 TRACE( "%p: setting min %d,%d max %d,%d normal %s flags %x adjusted to min %d,%d max %d,%d normal %s\n",
2535 hwnd
, (int)wndpl
->ptMinPosition
.x
, (int)wndpl
->ptMinPosition
.y
,
2536 (int)wndpl
->ptMaxPosition
.x
, (int)wndpl
->ptMaxPosition
.y
,
2537 wine_dbgstr_rect(&wndpl
->rcNormalPosition
), flags
,
2538 (int)wp
.ptMinPosition
.x
, (int)wp
.ptMinPosition
.y
,
2539 (int)wp
.ptMaxPosition
.x
, (int)wp
.ptMaxPosition
.y
,
2540 wine_dbgstr_rect(&wp
.rcNormalPosition
) );
2542 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
2544 if (flags
& PLACE_MIN
) win
->min_pos
= point_thread_to_win_dpi( hwnd
, wp
.ptMinPosition
);
2545 if (flags
& PLACE_MAX
)
2547 win
->max_pos
= point_thread_to_win_dpi( hwnd
, wp
.ptMaxPosition
);
2548 update_maximized_pos( win
, &work_rect
);
2550 if (flags
& PLACE_RECT
) win
->normal_rect
= rect_thread_to_win_dpi( hwnd
, wp
.rcNormalPosition
);
2552 style
= win
->dwStyle
;
2554 release_win_ptr( win
);
2556 if (style
& WS_MINIMIZE
)
2558 if (flags
& PLACE_MIN
)
2560 NtUserSetWindowPos( hwnd
, 0, wp
.ptMinPosition
.x
, wp
.ptMinPosition
.y
, 0, 0,
2561 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
2564 else if (style
& WS_MAXIMIZE
)
2566 if (flags
& PLACE_MAX
)
2567 NtUserSetWindowPos( hwnd
, 0, wp
.ptMaxPosition
.x
, wp
.ptMaxPosition
.y
, 0, 0,
2568 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
2570 else if (flags
& PLACE_RECT
)
2571 NtUserSetWindowPos( hwnd
, 0, wp
.rcNormalPosition
.left
, wp
.rcNormalPosition
.top
,
2572 wp
.rcNormalPosition
.right
- wp
.rcNormalPosition
.left
,
2573 wp
.rcNormalPosition
.bottom
- wp
.rcNormalPosition
.top
,
2574 SWP_NOZORDER
| SWP_NOACTIVATE
);
2576 NtUserShowWindow( hwnd
, wndpl
->showCmd
);
2578 if (is_iconic( hwnd
))
2580 if (wndpl
->flags
& WPF_RESTORETOMAXIMIZED
)
2581 win_set_flags( hwnd
, WIN_RESTORE_MAX
, 0 );
2586 /***********************************************************************
2587 * NtUserSetWindowPlacement (win32u.@)
2589 BOOL WINAPI
NtUserSetWindowPlacement( HWND hwnd
, const WINDOWPLACEMENT
*wpl
)
2591 UINT flags
= PLACE_MAX
| PLACE_RECT
;
2592 if (!wpl
) return FALSE
;
2593 if (wpl
->length
!= sizeof(*wpl
))
2595 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
2598 if (wpl
->flags
& WPF_SETMINPOSITION
) flags
|= PLACE_MIN
;
2599 return set_window_placement( hwnd
, wpl
, flags
);
2602 /*****************************************************************************
2603 * NtUserBuildHwndList (win32u.@)
2605 NTSTATUS WINAPI
NtUserBuildHwndList( HDESK desktop
, ULONG unk2
, ULONG unk3
, ULONG unk4
,
2606 ULONG thread_id
, ULONG count
, HWND
*buffer
, ULONG
*size
)
2608 user_handle_t
*list
= (user_handle_t
*)buffer
;
2612 SERVER_START_REQ( get_window_children
)
2614 req
->desktop
= wine_server_obj_handle( desktop
);
2615 req
->tid
= thread_id
;
2616 if (count
) wine_server_set_reply( req
, list
, (count
- 1) * sizeof(user_handle_t
) );
2617 status
= wine_server_call( req
);
2618 if (status
&& status
!= STATUS_BUFFER_TOO_SMALL
) return status
;
2619 *size
= reply
->count
+ 1;
2622 if (*size
> count
) return STATUS_BUFFER_TOO_SMALL
;
2624 /* start from the end since HWND is potentially larger than user_handle_t */
2625 for (i
= *size
- 2; i
>= 0; i
--)
2626 buffer
[i
] = wine_server_ptr_handle( list
[i
] );
2627 buffer
[*size
- 1] = HWND_BOTTOM
;
2628 return STATUS_SUCCESS
;
2631 /***********************************************************************
2632 * NtUserFindWindowEx (USER32.@)
2634 HWND WINAPI
NtUserFindWindowEx( HWND parent
, HWND child
, UNICODE_STRING
*class, UNICODE_STRING
*title
,
2639 int i
= 0, len
= 0, title_len
;
2640 WCHAR
*buffer
= NULL
;
2642 if (!parent
&& child
) parent
= get_desktop_window();
2643 else if (parent
== HWND_MESSAGE
) parent
= get_hwnd_message_parent();
2647 len
= title
->Length
/ sizeof(WCHAR
) + 1; /* one extra char to check for chars beyond the end */
2648 if (!(buffer
= malloc( (len
+ 1) * sizeof(WCHAR
) ))) return 0;
2651 if (!(list
= list_window_children( 0, parent
, class, 0 ))) goto done
;
2655 child
= get_full_window_handle( child
);
2656 while (list
[i
] && list
[i
] != child
) i
++;
2657 if (!list
[i
]) goto done
;
2658 i
++; /* start from next window */
2665 title_len
= NtUserInternalGetWindowText( list
[i
], buffer
, len
+ 1 );
2666 if (title_len
* sizeof(WCHAR
) == title
->Length
&&
2667 (!title_len
|| !wcsnicmp( buffer
, title
->Buffer
, title_len
)))
2680 /* Retrieve the window text from the server. */
2681 static data_size_t
get_server_window_text( HWND hwnd
, WCHAR
*text
, data_size_t count
)
2683 data_size_t len
= 0, needed
= 0;
2685 SERVER_START_REQ( get_window_text
)
2687 req
->handle
= wine_server_user_handle( hwnd
);
2688 if (count
) wine_server_set_reply( req
, text
, (count
- 1) * sizeof(WCHAR
) );
2689 if (!wine_server_call_err( req
))
2691 needed
= reply
->length
;
2692 len
= wine_server_reply_size(reply
);
2696 if (text
) text
[len
/ sizeof(WCHAR
)] = 0;
2700 /*******************************************************************
2701 * NtUserInternalGetWindowText (win32u.@)
2703 INT WINAPI
NtUserInternalGetWindowText( HWND hwnd
, WCHAR
*text
, INT count
)
2707 if (count
<= 0) return 0;
2708 if (!(win
= get_win_ptr( hwnd
))) return 0;
2709 if (win
== WND_DESKTOP
) text
[0] = 0;
2710 else if (win
!= WND_OTHER_PROCESS
)
2712 if (win
->text
) lstrcpynW( text
, win
->text
, count
);
2714 release_win_ptr( win
);
2718 get_server_window_text( hwnd
, text
, count
);
2720 return lstrlenW(text
);
2723 /*******************************************************************
2724 * get_windows_offset
2726 * Calculate the offset between the origin of the two windows. Used
2727 * to implement MapWindowPoints.
2729 static BOOL
get_windows_offset( HWND hwnd_from
, HWND hwnd_to
, UINT dpi
, BOOL
*mirrored
, POINT
*ret_offset
)
2733 BOOL mirror_from
, mirror_to
, ret
;
2736 offset
.x
= offset
.y
= 0;
2737 *mirrored
= mirror_from
= mirror_to
= FALSE
;
2739 /* Translate source window origin to screen coords */
2742 if (!(win
= get_win_ptr( hwnd_from
)))
2744 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
2747 if (win
== WND_OTHER_PROCESS
) goto other_process
;
2748 if (win
!= WND_DESKTOP
)
2750 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
)
2753 offset
.x
+= win
->client_rect
.right
- win
->client_rect
.left
;
2757 offset
.x
+= win
->client_rect
.left
;
2758 offset
.y
+= win
->client_rect
.top
;
2760 release_win_ptr( win
);
2761 if (!(win
= get_win_ptr( hwnd
))) break;
2762 if (win
== WND_OTHER_PROCESS
) goto other_process
;
2763 if (win
== WND_DESKTOP
) break;
2764 if (win
->flags
& WIN_CHILDREN_MOVED
)
2766 release_win_ptr( win
);
2770 if (win
&& win
!= WND_DESKTOP
) release_win_ptr( win
);
2771 offset
= map_dpi_point( offset
, get_dpi_for_window( hwnd_from
), dpi
);
2775 /* Translate origin to destination window coords */
2778 if (!(win
= get_win_ptr( hwnd_to
)))
2780 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
2783 if (win
== WND_OTHER_PROCESS
) goto other_process
;
2784 if (win
!= WND_DESKTOP
)
2786 POINT pt
= { 0, 0 };
2787 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
)
2790 pt
.x
+= win
->client_rect
.right
- win
->client_rect
.left
;
2794 pt
.x
+= win
->client_rect
.left
;
2795 pt
.y
+= win
->client_rect
.top
;
2797 release_win_ptr( win
);
2798 if (!(win
= get_win_ptr( hwnd
))) break;
2799 if (win
== WND_OTHER_PROCESS
) goto other_process
;
2800 if (win
== WND_DESKTOP
) break;
2801 if (win
->flags
& WIN_CHILDREN_MOVED
)
2803 release_win_ptr( win
);
2807 if (win
&& win
!= WND_DESKTOP
) release_win_ptr( win
);
2808 pt
= map_dpi_point( pt
, get_dpi_for_window( hwnd_to
), dpi
);
2814 *mirrored
= mirror_from
^ mirror_to
;
2815 if (mirror_from
) offset
.x
= -offset
.x
;
2816 *ret_offset
= offset
;
2819 other_process
: /* one of the parents may belong to another process, do it the hard way */
2820 SERVER_START_REQ( get_windows_offset
)
2822 req
->from
= wine_server_user_handle( hwnd_from
);
2823 req
->to
= wine_server_user_handle( hwnd_to
);
2825 if ((ret
= !wine_server_call_err( req
)))
2827 ret_offset
->x
= reply
->x
;
2828 ret_offset
->y
= reply
->y
;
2829 *mirrored
= reply
->mirror
;
2836 /* see ClientToScreen */
2837 BOOL
client_to_screen( HWND hwnd
, POINT
*pt
)
2844 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
2848 if (!get_windows_offset( hwnd
, 0, get_thread_dpi(), &mirrored
, &offset
)) return FALSE
;
2851 if (mirrored
) pt
->x
= -pt
->x
;
2855 /* see ScreenToClient */
2856 BOOL
screen_to_client( HWND hwnd
, POINT
*pt
)
2863 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
2866 if (!get_windows_offset( 0, hwnd
, get_thread_dpi(), &mirrored
, &offset
)) return FALSE
;
2869 if (mirrored
) pt
->x
= -pt
->x
;
2873 /* map coordinates of a window region */
2874 void map_window_region( HWND from
, HWND to
, HRGN hrgn
)
2883 if (!get_windows_offset( from
, to
, get_thread_dpi(), &mirrored
, &offset
)) return;
2887 NtGdiOffsetRgn( hrgn
, offset
.x
, offset
.y
);
2890 if (!(size
= NtGdiGetRegionData( hrgn
, 0, NULL
))) return;
2891 if (!(data
= malloc( size
))) return;
2892 NtGdiGetRegionData( hrgn
, size
, data
);
2893 rect
= (RECT
*)data
->Buffer
;
2894 for (i
= 0; i
< data
->rdh
.nCount
; i
++)
2896 int tmp
= -(rect
[i
].left
+ offset
.x
);
2897 rect
[i
].left
= -(rect
[i
].right
+ offset
.x
);
2898 rect
[i
].right
= tmp
;
2899 rect
[i
].top
+= offset
.y
;
2900 rect
[i
].bottom
+= offset
.y
;
2902 if ((new_rgn
= NtGdiExtCreateRegion( NULL
, data
->rdh
.dwSize
+ data
->rdh
.nRgnSize
, data
)))
2904 NtGdiCombineRgn( hrgn
, new_rgn
, 0, RGN_COPY
);
2905 NtGdiDeleteObjectApp( new_rgn
);
2910 /* see MapWindowPoints */
2911 int map_window_points( HWND hwnd_from
, HWND hwnd_to
, POINT
*points
, UINT count
, UINT dpi
)
2917 if (!get_windows_offset( hwnd_from
, hwnd_to
, dpi
, &mirrored
, &offset
)) return 0;
2919 for (i
= 0; i
< count
; i
++)
2921 points
[i
].x
+= offset
.x
;
2922 points
[i
].y
+= offset
.y
;
2923 if (mirrored
) points
[i
].x
= -points
[i
].x
;
2925 if (mirrored
&& count
== 2) /* special case for rectangle */
2927 int tmp
= points
[0].x
;
2928 points
[0].x
= points
[1].x
;
2931 return MAKELONG( LOWORD(offset
.x
), LOWORD(offset
.y
) );
2934 /***********************************************************************
2937 static void dump_winpos_flags( UINT flags
)
2939 static const UINT dumped_flags
= (SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOREDRAW
|
2940 SWP_NOACTIVATE
| SWP_FRAMECHANGED
| SWP_SHOWWINDOW
|
2941 SWP_HIDEWINDOW
| SWP_NOCOPYBITS
| SWP_NOOWNERZORDER
|
2942 SWP_NOSENDCHANGING
| SWP_DEFERERASE
| SWP_ASYNCWINDOWPOS
|
2943 SWP_NOCLIENTSIZE
| SWP_NOCLIENTMOVE
| SWP_STATECHANGED
);
2945 if(flags
& SWP_NOSIZE
) TRACE( " SWP_NOSIZE" );
2946 if(flags
& SWP_NOMOVE
) TRACE( " SWP_NOMOVE" );
2947 if(flags
& SWP_NOZORDER
) TRACE( " SWP_NOZORDER" );
2948 if(flags
& SWP_NOREDRAW
) TRACE( " SWP_NOREDRAW" );
2949 if(flags
& SWP_NOACTIVATE
) TRACE( " SWP_NOACTIVATE" );
2950 if(flags
& SWP_FRAMECHANGED
) TRACE( " SWP_FRAMECHANGED" );
2951 if(flags
& SWP_SHOWWINDOW
) TRACE( " SWP_SHOWWINDOW" );
2952 if(flags
& SWP_HIDEWINDOW
) TRACE( " SWP_HIDEWINDOW" );
2953 if(flags
& SWP_NOCOPYBITS
) TRACE( " SWP_NOCOPYBITS" );
2954 if(flags
& SWP_NOOWNERZORDER
) TRACE( " SWP_NOOWNERZORDER" );
2955 if(flags
& SWP_NOSENDCHANGING
) TRACE( " SWP_NOSENDCHANGING" );
2956 if(flags
& SWP_DEFERERASE
) TRACE( " SWP_DEFERERASE" );
2957 if(flags
& SWP_ASYNCWINDOWPOS
) TRACE( " SWP_ASYNCWINDOWPOS" );
2958 if(flags
& SWP_NOCLIENTSIZE
) TRACE( " SWP_NOCLIENTSIZE" );
2959 if(flags
& SWP_NOCLIENTMOVE
) TRACE( " SWP_NOCLIENTMOVE" );
2960 if(flags
& SWP_STATECHANGED
) TRACE( " SWP_STATECHANGED" );
2962 if(flags
& ~dumped_flags
) TRACE( " %08x", flags
& ~dumped_flags
);
2966 /***********************************************************************
2969 static void map_dpi_winpos( WINDOWPOS
*winpos
)
2971 UINT dpi_from
= get_thread_dpi();
2972 UINT dpi_to
= get_dpi_for_window( winpos
->hwnd
);
2974 if (!dpi_from
) dpi_from
= get_win_monitor_dpi( winpos
->hwnd
);
2975 if (dpi_from
== dpi_to
) return;
2976 winpos
->x
= muldiv( winpos
->x
, dpi_to
, dpi_from
);
2977 winpos
->y
= muldiv( winpos
->y
, dpi_to
, dpi_from
);
2978 winpos
->cx
= muldiv( winpos
->cx
, dpi_to
, dpi_from
);
2979 winpos
->cy
= muldiv( winpos
->cy
, dpi_to
, dpi_from
);
2982 /***********************************************************************
2985 static BOOL
calc_winpos( WINDOWPOS
*winpos
, RECT
*old_window_rect
, RECT
*old_client_rect
,
2986 RECT
*new_window_rect
, RECT
*new_client_rect
)
2990 /* Send WM_WINDOWPOSCHANGING message */
2991 if (!(winpos
->flags
& SWP_NOSENDCHANGING
)
2992 && !((winpos
->flags
& SWP_AGG_NOCLIENTCHANGE
) && (winpos
->flags
& SWP_SHOWWINDOW
)))
2993 send_message( winpos
->hwnd
, WM_WINDOWPOSCHANGING
, 0, (LPARAM
)winpos
);
2995 if (!(win
= get_win_ptr( winpos
->hwnd
)) ||
2996 win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
2998 /* Calculate new position and size */
2999 get_window_rects( winpos
->hwnd
, COORDS_PARENT
, old_window_rect
, old_client_rect
, get_thread_dpi() );
3000 *new_window_rect
= *old_window_rect
;
3001 *new_client_rect
= *old_client_rect
;
3003 if (!(winpos
->flags
& SWP_NOSIZE
))
3005 if (win
->dwStyle
& WS_MINIMIZE
)
3007 new_window_rect
->right
= new_window_rect
->left
+ get_system_metrics( SM_CXMINIMIZED
);
3008 new_window_rect
->bottom
= new_window_rect
->top
+ get_system_metrics( SM_CYMINIMIZED
);
3012 new_window_rect
->right
= new_window_rect
->left
+ winpos
->cx
;
3013 new_window_rect
->bottom
= new_window_rect
->top
+ winpos
->cy
;
3017 if (!(winpos
->flags
& SWP_NOMOVE
))
3019 /* If the window is toplevel minimized off-screen, force keep it there */
3020 if ((win
->dwStyle
& WS_MINIMIZE
) &&
3021 win
->window_rect
.left
<= -32000 && win
->window_rect
.top
<= -32000 &&
3022 (!win
->parent
|| win
->parent
== get_desktop_window()))
3027 new_window_rect
->left
= winpos
->x
;
3028 new_window_rect
->top
= winpos
->y
;
3029 new_window_rect
->right
+= winpos
->x
- old_window_rect
->left
;
3030 new_window_rect
->bottom
+= winpos
->y
- old_window_rect
->top
;
3032 OffsetRect( new_client_rect
, winpos
->x
- old_window_rect
->left
,
3033 winpos
->y
- old_window_rect
->top
);
3035 winpos
->flags
|= SWP_NOCLIENTMOVE
| SWP_NOCLIENTSIZE
;
3037 TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x current %s style %08x new %s\n",
3038 winpos
->hwnd
, winpos
->hwndInsertAfter
, winpos
->x
, winpos
->y
,
3039 winpos
->cx
, winpos
->cy
, winpos
->flags
,
3040 wine_dbgstr_rect( old_window_rect
), win
->dwStyle
,
3041 wine_dbgstr_rect( new_window_rect
));
3043 release_win_ptr( win
);
3047 /***********************************************************************
3050 * Compute the valid rects from the old and new client rect and WVR_* flags.
3051 * Helper for WM_NCCALCSIZE handling.
3053 static inline void get_valid_rects( const RECT
*old_client
, const RECT
*new_client
, UINT flags
,
3058 if (flags
& WVR_REDRAW
)
3060 SetRectEmpty( &valid
[0] );
3061 SetRectEmpty( &valid
[1] );
3065 if (flags
& WVR_VALIDRECTS
)
3067 if (!intersect_rect( &valid
[0], &valid
[0], new_client
) ||
3068 !intersect_rect( &valid
[1], &valid
[1], old_client
))
3070 SetRectEmpty( &valid
[0] );
3071 SetRectEmpty( &valid
[1] );
3074 flags
= WVR_ALIGNLEFT
| WVR_ALIGNTOP
;
3078 valid
[0] = *new_client
;
3079 valid
[1] = *old_client
;
3082 /* make sure the rectangles have the same size */
3083 cx
= min( valid
[0].right
- valid
[0].left
, valid
[1].right
- valid
[1].left
);
3084 cy
= min( valid
[0].bottom
- valid
[0].top
, valid
[1].bottom
- valid
[1].top
);
3086 if (flags
& WVR_ALIGNBOTTOM
)
3088 valid
[0].top
= valid
[0].bottom
- cy
;
3089 valid
[1].top
= valid
[1].bottom
- cy
;
3093 valid
[0].bottom
= valid
[0].top
+ cy
;
3094 valid
[1].bottom
= valid
[1].top
+ cy
;
3096 if (flags
& WVR_ALIGNRIGHT
)
3098 valid
[0].left
= valid
[0].right
- cx
;
3099 valid
[1].left
= valid
[1].right
- cx
;
3103 valid
[0].right
= valid
[0].left
+ cx
;
3104 valid
[1].right
= valid
[1].left
+ cx
;
3108 static UINT
calc_ncsize( WINDOWPOS
*winpos
, const RECT
*old_window_rect
, const RECT
*old_client_rect
,
3109 const RECT
*new_window_rect
, RECT
*new_client_rect
, RECT
*valid_rects
,
3110 int parent_x
, int parent_y
)
3114 /* Send WM_NCCALCSIZE message to get new client area */
3115 if ((winpos
->flags
& (SWP_FRAMECHANGED
| SWP_NOSIZE
)) != SWP_NOSIZE
)
3117 NCCALCSIZE_PARAMS params
;
3118 WINDOWPOS winposCopy
;
3121 params
.rgrc
[0] = *new_window_rect
;
3122 params
.rgrc
[1] = *old_window_rect
;
3123 params
.rgrc
[2] = *old_client_rect
;
3124 params
.lppos
= &winposCopy
;
3125 winposCopy
= *winpos
;
3127 if (winpos
->flags
& SWP_NOMOVE
)
3129 winposCopy
.x
= old_window_rect
->left
;
3130 winposCopy
.y
= old_window_rect
->top
;
3133 if (winpos
->flags
& SWP_NOSIZE
)
3135 winposCopy
.cx
= old_window_rect
->right
- old_window_rect
->left
;
3136 winposCopy
.cy
= old_window_rect
->bottom
- old_window_rect
->top
;
3139 class_style
= get_class_long( winpos
->hwnd
, GCL_STYLE
, FALSE
);
3140 if (class_style
& CS_VREDRAW
) wvr_flags
|= WVR_VREDRAW
;
3141 if (class_style
& CS_HREDRAW
) wvr_flags
|= WVR_HREDRAW
;
3143 wvr_flags
|= send_message( winpos
->hwnd
, WM_NCCALCSIZE
, TRUE
, (LPARAM
)¶ms
);
3145 *new_client_rect
= params
.rgrc
[0];
3147 TRACE( "hwnd %p old win %s old client %s new win %s new client %s\n", winpos
->hwnd
,
3148 wine_dbgstr_rect(old_window_rect
), wine_dbgstr_rect(old_client_rect
),
3149 wine_dbgstr_rect(new_window_rect
), wine_dbgstr_rect(new_client_rect
) );
3151 if (new_client_rect
->left
!= old_client_rect
->left
- parent_x
||
3152 new_client_rect
->top
!= old_client_rect
->top
- parent_y
)
3153 winpos
->flags
&= ~SWP_NOCLIENTMOVE
;
3155 if ((new_client_rect
->right
- new_client_rect
->left
!=
3156 old_client_rect
->right
- old_client_rect
->left
))
3157 winpos
->flags
&= ~SWP_NOCLIENTSIZE
;
3159 wvr_flags
&= ~WVR_HREDRAW
;
3161 if (new_client_rect
->bottom
- new_client_rect
->top
!=
3162 old_client_rect
->bottom
- old_client_rect
->top
)
3163 winpos
->flags
&= ~SWP_NOCLIENTSIZE
;
3165 wvr_flags
&= ~WVR_VREDRAW
;
3167 valid_rects
[0] = params
.rgrc
[1];
3168 valid_rects
[1] = params
.rgrc
[2];
3172 if (!(winpos
->flags
& SWP_NOMOVE
) &&
3173 (new_client_rect
->left
!= old_client_rect
->left
- parent_x
||
3174 new_client_rect
->top
!= old_client_rect
->top
- parent_y
))
3175 winpos
->flags
&= ~SWP_NOCLIENTMOVE
;
3178 if (winpos
->flags
& (SWP_NOCOPYBITS
| SWP_NOREDRAW
| SWP_SHOWWINDOW
| SWP_HIDEWINDOW
))
3180 SetRectEmpty( &valid_rects
[0] );
3181 SetRectEmpty( &valid_rects
[1] );
3183 else get_valid_rects( old_client_rect
, new_client_rect
, wvr_flags
, valid_rects
);
3188 /* fix redundant flags and values in the WINDOWPOS structure */
3189 static BOOL
fixup_swp_flags( WINDOWPOS
*winpos
, const RECT
*old_window_rect
, int parent_x
, int parent_y
)
3192 WND
*win
= get_win_ptr( winpos
->hwnd
);
3195 if (!win
|| win
== WND_OTHER_PROCESS
)
3197 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
3200 winpos
->hwnd
= win
->obj
.handle
; /* make it a full handle */
3202 /* Finally make sure that all coordinates are valid */
3203 if (winpos
->x
< -32768) winpos
->x
= -32768;
3204 else if (winpos
->x
> 32767) winpos
->x
= 32767;
3205 if (winpos
->y
< -32768) winpos
->y
= -32768;
3206 else if (winpos
->y
> 32767) winpos
->y
= 32767;
3208 if (winpos
->cx
< 0) winpos
->cx
= 0;
3209 else if (winpos
->cx
> 32767) winpos
->cx
= 32767;
3210 if (winpos
->cy
< 0) winpos
->cy
= 0;
3211 else if (winpos
->cy
> 32767) winpos
->cy
= 32767;
3213 parent
= NtUserGetAncestor( winpos
->hwnd
, GA_PARENT
);
3214 if (!is_window_visible( parent
)) winpos
->flags
|= SWP_NOREDRAW
;
3216 if (win
->dwStyle
& WS_VISIBLE
) winpos
->flags
&= ~SWP_SHOWWINDOW
;
3219 winpos
->flags
&= ~SWP_HIDEWINDOW
;
3220 if (!(winpos
->flags
& SWP_SHOWWINDOW
)) winpos
->flags
|= SWP_NOREDRAW
;
3223 if ((old_window_rect
->right
- old_window_rect
->left
== winpos
->cx
) &&
3224 (old_window_rect
->bottom
- old_window_rect
->top
== winpos
->cy
))
3225 winpos
->flags
|= SWP_NOSIZE
; /* Already the right size */
3227 if ((old_window_rect
->left
- parent_x
== winpos
->x
) && (old_window_rect
->top
- parent_y
== winpos
->y
))
3228 winpos
->flags
|= SWP_NOMOVE
; /* Already the right position */
3230 if ((win
->dwStyle
& (WS_POPUP
| WS_CHILD
)) != WS_CHILD
)
3232 if (!(winpos
->flags
& (SWP_NOACTIVATE
|SWP_HIDEWINDOW
)) && /* Bring to the top when activating */
3233 (winpos
->flags
& SWP_NOZORDER
||
3234 (winpos
->hwndInsertAfter
!= HWND_TOPMOST
&& winpos
->hwndInsertAfter
!= HWND_NOTOPMOST
)))
3236 winpos
->flags
&= ~SWP_NOZORDER
;
3237 winpos
->hwndInsertAfter
= HWND_TOP
;
3241 /* Check hwndInsertAfter */
3242 if (winpos
->flags
& SWP_NOZORDER
) goto done
;
3244 if (winpos
->hwndInsertAfter
== HWND_TOP
)
3246 if (get_window_relative( winpos
->hwnd
, GW_HWNDFIRST
) == winpos
->hwnd
)
3247 winpos
->flags
|= SWP_NOZORDER
;
3249 else if (winpos
->hwndInsertAfter
== HWND_BOTTOM
)
3251 if (!(win
->dwExStyle
& WS_EX_TOPMOST
) &&
3252 get_window_relative( winpos
->hwnd
, GW_HWNDLAST
) == winpos
->hwnd
)
3253 winpos
->flags
|= SWP_NOZORDER
;
3255 else if (winpos
->hwndInsertAfter
== HWND_TOPMOST
)
3257 if ((win
->dwExStyle
& WS_EX_TOPMOST
) &&
3258 get_window_relative( winpos
->hwnd
, GW_HWNDFIRST
) == winpos
->hwnd
)
3259 winpos
->flags
|= SWP_NOZORDER
;
3261 else if (winpos
->hwndInsertAfter
== HWND_NOTOPMOST
)
3263 if (!(win
->dwExStyle
& WS_EX_TOPMOST
))
3264 winpos
->flags
|= SWP_NOZORDER
;
3268 if ((winpos
->hwnd
== winpos
->hwndInsertAfter
) ||
3269 (winpos
->hwnd
== get_window_relative( winpos
->hwndInsertAfter
, GW_HWNDNEXT
)))
3270 winpos
->flags
|= SWP_NOZORDER
;
3273 release_win_ptr( win
);
3277 /***********************************************************************
3280 * fix Z order taking into account owned popups -
3281 * basically we need to maintain them above the window that owns them
3283 * FIXME: hide/show owned popups when owner visibility changes.
3285 static HWND
swp_owner_popups( HWND hwnd
, HWND after
)
3287 HWND owner
, *list
= NULL
;
3290 TRACE( "(%p) after = %p\n", hwnd
, after
);
3292 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) return after
;
3294 if ((owner
= get_window_relative( hwnd
, GW_OWNER
)))
3296 /* make sure this popup stays above the owner */
3298 if (after
!= HWND_TOPMOST
)
3300 if (!(list
= list_window_children( 0, get_desktop_window(), NULL
, 0 ))) return after
;
3302 for (i
= 0; list
[i
]; i
++)
3304 BOOL topmost
= (get_window_long( list
[i
], GWL_EXSTYLE
) & WS_EX_TOPMOST
) != 0;
3306 if (list
[i
] == owner
)
3308 if (i
> 0) after
= list
[i
-1];
3309 else after
= topmost
? HWND_TOPMOST
: HWND_TOP
;
3313 if (after
== HWND_TOP
|| after
== HWND_NOTOPMOST
)
3315 if (!topmost
) break;
3317 else if (list
[i
] == after
) break;
3322 if (after
== HWND_BOTTOM
) goto done
;
3323 if (!list
&& !(list
= list_window_children( 0, get_desktop_window(), NULL
, 0 ))) goto done
;
3326 if (after
== HWND_TOP
|| after
== HWND_NOTOPMOST
)
3328 if (after
== HWND_NOTOPMOST
||
3329 !(get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_TOPMOST
))
3331 /* skip all the topmost windows */
3332 while (list
[i
] && (get_window_long( list
[i
], GWL_EXSTYLE
) & WS_EX_TOPMOST
)) i
++;
3335 else if (after
!= HWND_TOPMOST
)
3337 /* skip windows that are already placed correctly */
3338 for (i
= 0; list
[i
]; i
++)
3340 if (list
[i
] == after
) break;
3341 if (list
[i
] == hwnd
) goto done
; /* nothing to do if window is moving backwards in z-order */
3345 for ( ; list
[i
]; i
++)
3347 if (list
[i
] == hwnd
) break;
3348 if (get_window_relative( list
[i
], GW_OWNER
) != hwnd
) continue;
3349 TRACE( "moving %p owned by %p after %p\n", list
[i
], hwnd
, after
);
3350 NtUserSetWindowPos( list
[i
], after
, 0, 0, 0, 0,
3351 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOSENDCHANGING
| SWP_DEFERERASE
);
3360 /* NtUserSetWindowPos implementation */
3361 BOOL
set_window_pos( WINDOWPOS
*winpos
, int parent_x
, int parent_y
)
3363 RECT old_window_rect
, old_client_rect
, new_window_rect
, new_client_rect
, valid_rects
[2];
3366 DPI_AWARENESS_CONTEXT context
;
3368 orig_flags
= winpos
->flags
;
3370 /* First, check z-order arguments. */
3371 if (!(winpos
->flags
& SWP_NOZORDER
))
3373 /* fix sign extension */
3374 if (winpos
->hwndInsertAfter
== (HWND
)0xffff) winpos
->hwndInsertAfter
= HWND_TOPMOST
;
3375 else if (winpos
->hwndInsertAfter
== (HWND
)0xfffe) winpos
->hwndInsertAfter
= HWND_NOTOPMOST
;
3377 if (!(winpos
->hwndInsertAfter
== HWND_TOP
||
3378 winpos
->hwndInsertAfter
== HWND_BOTTOM
||
3379 winpos
->hwndInsertAfter
== HWND_TOPMOST
||
3380 winpos
->hwndInsertAfter
== HWND_NOTOPMOST
))
3382 HWND parent
= NtUserGetAncestor( winpos
->hwnd
, GA_PARENT
);
3383 HWND insertafter_parent
= NtUserGetAncestor( winpos
->hwndInsertAfter
, GA_PARENT
);
3385 /* hwndInsertAfter must be a sibling of the window */
3386 if (!insertafter_parent
) return FALSE
;
3387 if (insertafter_parent
!= parent
) return TRUE
;
3391 /* Make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
3392 if (!(winpos
->flags
& SWP_NOMOVE
))
3394 if (winpos
->x
< -32768) winpos
->x
= -32768;
3395 else if (winpos
->x
> 32767) winpos
->x
= 32767;
3396 if (winpos
->y
< -32768) winpos
->y
= -32768;
3397 else if (winpos
->y
> 32767) winpos
->y
= 32767;
3399 if (!(winpos
->flags
& SWP_NOSIZE
))
3401 if (winpos
->cx
< 0) winpos
->cx
= 0;
3402 else if (winpos
->cx
> 32767) winpos
->cx
= 32767;
3403 if (winpos
->cy
< 0) winpos
->cy
= 0;
3404 else if (winpos
->cy
> 32767) winpos
->cy
= 32767;
3407 context
= SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( winpos
->hwnd
));
3409 if (!calc_winpos( winpos
, &old_window_rect
, &old_client_rect
,
3410 &new_window_rect
, &new_client_rect
)) goto done
;
3412 /* Fix redundant flags */
3413 if (!fixup_swp_flags( winpos
, &old_window_rect
, parent_x
, parent_y
)) goto done
;
3415 if((winpos
->flags
& (SWP_NOZORDER
| SWP_HIDEWINDOW
| SWP_SHOWWINDOW
)) != SWP_NOZORDER
)
3417 if (NtUserGetAncestor( winpos
->hwnd
, GA_PARENT
) == get_desktop_window())
3418 winpos
->hwndInsertAfter
= swp_owner_popups( winpos
->hwnd
, winpos
->hwndInsertAfter
);
3421 /* Common operations */
3423 calc_ncsize( winpos
, &old_window_rect
, &old_client_rect
,
3424 &new_window_rect
, &new_client_rect
, valid_rects
, parent_x
, parent_y
);
3426 if (!apply_window_pos( winpos
->hwnd
, winpos
->hwndInsertAfter
, winpos
->flags
,
3427 &new_window_rect
, &new_client_rect
, valid_rects
))
3430 if (winpos
->flags
& SWP_HIDEWINDOW
)
3431 NtUserHideCaret( winpos
->hwnd
);
3432 else if (winpos
->flags
& SWP_SHOWWINDOW
)
3433 NtUserShowCaret( winpos
->hwnd
);
3435 if (!(winpos
->flags
& (SWP_NOACTIVATE
|SWP_HIDEWINDOW
)))
3437 /* child windows get WM_CHILDACTIVATE message */
3438 if ((get_window_long( winpos
->hwnd
, GWL_STYLE
) & (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
3439 send_message( winpos
->hwnd
, WM_CHILDACTIVATE
, 0, 0 );
3441 set_foreground_window( winpos
->hwnd
, FALSE
);
3444 if(!(orig_flags
& SWP_DEFERERASE
))
3446 /* erase parent when hiding or resizing child */
3447 if ((orig_flags
& SWP_HIDEWINDOW
) ||
3448 (!(orig_flags
& SWP_SHOWWINDOW
) &&
3449 (winpos
->flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOGEOMETRYCHANGE
))
3451 HWND parent
= NtUserGetAncestor( winpos
->hwnd
, GA_PARENT
);
3452 if (!parent
|| parent
== get_desktop_window()) parent
= winpos
->hwnd
;
3453 erase_now( parent
, 0 );
3456 /* Give newly shown windows a chance to redraw */
3457 if(((winpos
->flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOPOSCHANGE
)
3458 && !(orig_flags
& SWP_AGG_NOCLIENTCHANGE
) && (orig_flags
& SWP_SHOWWINDOW
))
3460 erase_now(winpos
->hwnd
, 0);
3464 /* And last, send the WM_WINDOWPOSCHANGED message */
3466 TRACE( "\tstatus flags = %04x\n", winpos
->flags
& SWP_AGG_STATUSFLAGS
);
3468 if (((winpos
->flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOPOSCHANGE
)
3469 && !((orig_flags
& SWP_AGG_NOCLIENTCHANGE
) && (orig_flags
& SWP_SHOWWINDOW
)))
3471 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
3472 and always contains final window position.
3474 winpos
->x
= new_window_rect
.left
;
3475 winpos
->y
= new_window_rect
.top
;
3476 winpos
->cx
= new_window_rect
.right
- new_window_rect
.left
;
3477 winpos
->cy
= new_window_rect
.bottom
- new_window_rect
.top
;
3478 send_message( winpos
->hwnd
, WM_WINDOWPOSCHANGED
, 0, (LPARAM
)winpos
);
3482 SetThreadDpiAwarenessContext( context
);
3486 /*******************************************************************
3487 * NtUserSetWindowPos (win32u.@)
3489 BOOL WINAPI
NtUserSetWindowPos( HWND hwnd
, HWND after
, INT x
, INT y
, INT cx
, INT cy
, UINT flags
)
3493 TRACE( "hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n", hwnd
, after
, x
, y
, cx
, cy
, flags
);
3494 if(TRACE_ON(win
)) dump_winpos_flags(flags
);
3496 if (is_broadcast( hwnd
))
3498 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
3502 winpos
.hwnd
= get_full_window_handle( hwnd
);
3503 winpos
.hwndInsertAfter
= get_full_window_handle( after
);
3508 winpos
.flags
= flags
;
3510 map_dpi_winpos( &winpos
);
3512 if (is_current_thread_window( hwnd
))
3513 return set_window_pos( &winpos
, 0, 0 );
3515 if (flags
& SWP_ASYNCWINDOWPOS
)
3516 return NtUserMessageCall( winpos
.hwnd
, WM_WINE_SETWINDOWPOS
, 0, (LPARAM
)&winpos
,
3517 0, NtUserSendNotifyMessage
, FALSE
);
3519 return send_message( winpos
.hwnd
, WM_WINE_SETWINDOWPOS
, 0, (LPARAM
)&winpos
);
3524 struct user_object obj
;
3526 INT suggested_count
;
3531 /* see BeginDeferWindowPos */
3532 HDWP
begin_defer_window_pos( INT count
)
3537 TRACE( "%d\n", count
);
3541 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
3544 /* Windows allows zero count, in which case it allocates context for 8 moves */
3545 if (count
== 0) count
= 8;
3547 if (!(dwp
= malloc( sizeof(DWP
) ))) return 0;
3551 dwp
->suggested_count
= count
;
3553 if (!(dwp
->winpos
= malloc( count
* sizeof(WINDOWPOS
) )) ||
3554 !(handle
= alloc_user_handle( &dwp
->obj
, NTUSER_OBJ_WINPOS
)))
3556 free( dwp
->winpos
);
3560 TRACE( "returning %p\n", handle
);
3564 /***********************************************************************
3565 * NtUserDeferWindowPosAndBand (win32u.@)
3567 HDWP WINAPI
NtUserDeferWindowPosAndBand( HDWP hdwp
, HWND hwnd
, HWND after
,
3568 INT x
, INT y
, INT cx
, INT cy
,
3569 UINT flags
, UINT unk1
, UINT unk2
)
3571 HDWP retvalue
= hdwp
;
3576 TRACE( "hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
3577 hdwp
, hwnd
, after
, x
, y
, cx
, cy
, flags
);
3579 winpos
.hwnd
= get_full_window_handle( hwnd
);
3580 if (is_desktop_window( winpos
.hwnd
) || !is_window( winpos
.hwnd
))
3582 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
3586 winpos
.hwndInsertAfter
= get_full_window_handle( after
);
3587 winpos
.flags
= flags
;
3592 map_dpi_winpos( &winpos
);
3594 if (!(dwp
= get_user_handle_ptr( hdwp
, NTUSER_OBJ_WINPOS
))) return 0;
3595 if (dwp
== OBJ_OTHER_PROCESS
)
3597 FIXME( "other process handle %p\n", hdwp
);
3601 for (i
= 0; i
< dwp
->count
; i
++)
3603 if (dwp
->winpos
[i
].hwnd
== winpos
.hwnd
)
3605 /* Merge with the other changes */
3606 if (!(flags
& SWP_NOZORDER
))
3608 dwp
->winpos
[i
].hwndInsertAfter
= winpos
.hwndInsertAfter
;
3610 if (!(flags
& SWP_NOMOVE
))
3612 dwp
->winpos
[i
].x
= winpos
.x
;
3613 dwp
->winpos
[i
].y
= winpos
.y
;
3615 if (!(flags
& SWP_NOSIZE
))
3617 dwp
->winpos
[i
].cx
= winpos
.cx
;
3618 dwp
->winpos
[i
].cy
= winpos
.cy
;
3620 dwp
->winpos
[i
].flags
&= flags
| ~(SWP_NOSIZE
| SWP_NOMOVE
|
3621 SWP_NOZORDER
| SWP_NOREDRAW
|
3622 SWP_NOACTIVATE
| SWP_NOCOPYBITS
|
3624 dwp
->winpos
[i
].flags
|= flags
& (SWP_SHOWWINDOW
| SWP_HIDEWINDOW
|
3629 if (dwp
->count
>= dwp
->suggested_count
)
3631 WINDOWPOS
*newpos
= realloc( dwp
->winpos
, dwp
->suggested_count
* 2 * sizeof(WINDOWPOS
) );
3637 dwp
->suggested_count
*= 2;
3638 dwp
->winpos
= newpos
;
3640 dwp
->winpos
[dwp
->count
++] = winpos
;
3642 release_user_handle_ptr( dwp
);
3646 /***********************************************************************
3647 * NtUserEndDeferWindowPosEx (win32u.@)
3649 BOOL WINAPI
NtUserEndDeferWindowPosEx( HDWP hdwp
, BOOL async
)
3655 TRACE( "%p\n", hdwp
);
3657 if (async
) FIXME( "async not supported\n" );
3659 if (!(dwp
= free_user_handle( hdwp
, NTUSER_OBJ_WINPOS
))) return FALSE
;
3660 if (dwp
== OBJ_OTHER_PROCESS
)
3662 FIXME( "other process handle %p\n", hdwp
);
3666 for (i
= 0, winpos
= dwp
->winpos
; i
< dwp
->count
; i
++, winpos
++)
3668 TRACE( "hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
3669 winpos
->hwnd
, winpos
->hwndInsertAfter
, winpos
->x
, winpos
->y
,
3670 winpos
->cx
, winpos
->cy
, winpos
->flags
);
3672 if (is_current_thread_window( winpos
->hwnd
))
3673 set_window_pos( winpos
, 0, 0 );
3675 send_message( winpos
->hwnd
, WM_WINE_SETWINDOWPOS
, 0, (LPARAM
)winpos
);
3677 free( dwp
->winpos
);
3682 /***********************************************************************
3683 * NtUserSetInternalWindowPos (win32u.@)
3685 void WINAPI
NtUserSetInternalWindowPos( HWND hwnd
, UINT cmd
, RECT
*rect
, POINT
*pt
)
3687 WINDOWPLACEMENT wndpl
;
3690 wndpl
.length
= sizeof(wndpl
);
3691 wndpl
.showCmd
= cmd
;
3692 wndpl
.flags
= flags
= 0;
3697 wndpl
.flags
|= WPF_SETMINPOSITION
;
3698 wndpl
.ptMinPosition
= *pt
;
3702 flags
|= PLACE_RECT
;
3703 wndpl
.rcNormalPosition
= *rect
;
3705 set_window_placement( hwnd
, &wndpl
, flags
);
3708 /***********************************************************************
3711 * Set the flags of a window and return the previous value.
3713 UINT
win_set_flags( HWND hwnd
, UINT set_mask
, UINT clear_mask
)
3715 WND
*win
= get_win_ptr( hwnd
);
3718 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return 0;
3720 win
->flags
= (ret
& ~clear_mask
) | set_mask
;
3721 release_win_ptr( win
);
3725 /*******************************************************************
3726 * can_activate_window
3728 * Check if we can activate the specified window.
3730 static BOOL
can_activate_window( HWND hwnd
)
3734 if (!hwnd
) return FALSE
;
3735 style
= get_window_long( hwnd
, GWL_STYLE
);
3736 if (!(style
& WS_VISIBLE
)) return FALSE
;
3737 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
3738 return !(style
& WS_DISABLED
);
3741 /*******************************************************************
3742 * activate_other_window
3744 * Activates window other than hwnd.
3746 static void activate_other_window( HWND hwnd
)
3750 if ((get_window_long( hwnd
, GWL_STYLE
) & WS_POPUP
) &&
3751 (hwnd_to
= get_window_relative( hwnd
, GW_OWNER
)))
3753 hwnd_to
= NtUserGetAncestor( hwnd_to
, GA_ROOT
);
3754 if (can_activate_window( hwnd_to
)) goto done
;
3760 if (!(hwnd_to
= get_window_relative( hwnd_to
, GW_HWNDNEXT
))) break;
3761 if (can_activate_window( hwnd_to
)) goto done
;
3764 hwnd_to
= get_window_relative( get_desktop_window(), GW_CHILD
);
3767 if (hwnd_to
== hwnd
)
3772 if (can_activate_window( hwnd_to
)) goto done
;
3773 if (!(hwnd_to
= get_window_relative( hwnd_to
, GW_HWNDNEXT
))) break;
3777 fg
= NtUserGetForegroundWindow();
3778 TRACE( "win = %p fg = %p\n", hwnd_to
, fg
);
3779 if (!fg
|| hwnd
== fg
)
3781 if (set_foreground_window( hwnd_to
, FALSE
)) return;
3783 if (NtUserSetActiveWindow( hwnd_to
)) NtUserSetActiveWindow( 0 );
3786 /*******************************************************************
3787 * send_parent_notify
3789 static void send_parent_notify( HWND hwnd
, UINT msg
)
3791 if ((get_window_long( hwnd
, GWL_STYLE
) & (WS_CHILD
| WS_POPUP
)) == WS_CHILD
&&
3792 !(get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_NOPARENTNOTIFY
))
3794 HWND parent
= get_parent( hwnd
);
3795 if (parent
&& parent
!= get_desktop_window())
3796 send_message( parent
, WM_PARENTNOTIFY
,
3797 MAKEWPARAM( msg
, get_window_long( hwnd
, GWLP_ID
)), (LPARAM
)hwnd
);
3801 /*******************************************************************
3804 * Get the minimized and maximized information for a window.
3806 MINMAXINFO
get_min_max_info( HWND hwnd
)
3808 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
3809 LONG exstyle
= get_window_long( hwnd
, GWL_EXSTYLE
);
3810 DPI_AWARENESS_CONTEXT context
;
3811 RECT rc_work
, rc_primary
;
3812 LONG adjusted_style
;
3818 context
= SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( hwnd
));
3820 /* Compute default values */
3822 get_window_rect( hwnd
, &rc
, get_thread_dpi() );
3823 minmax
.ptReserved
.x
= rc
.left
;
3824 minmax
.ptReserved
.y
= rc
.top
;
3826 if ((style
& WS_CAPTION
) == WS_CAPTION
)
3827 adjusted_style
= style
& ~WS_BORDER
; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
3829 adjusted_style
= style
;
3831 get_client_rect( NtUserGetAncestor( hwnd
, GA_PARENT
), &rc
);
3832 AdjustWindowRectEx( &rc
, adjusted_style
, (style
& WS_POPUP
) && get_menu( hwnd
), exstyle
);
3837 minmax
.ptMaxSize
.x
= rc
.right
- rc
.left
;
3838 minmax
.ptMaxSize
.y
= rc
.bottom
- rc
.top
;
3839 if (style
& (WS_DLGFRAME
| WS_BORDER
))
3841 minmax
.ptMinTrackSize
.x
= get_system_metrics( SM_CXMINTRACK
);
3842 minmax
.ptMinTrackSize
.y
= get_system_metrics( SM_CYMINTRACK
);
3846 minmax
.ptMinTrackSize
.x
= 2 * xinc
;
3847 minmax
.ptMinTrackSize
.y
= 2 * yinc
;
3849 minmax
.ptMaxTrackSize
.x
= get_system_metrics( SM_CXMAXTRACK
);
3850 minmax
.ptMaxTrackSize
.y
= get_system_metrics( SM_CYMAXTRACK
);
3851 minmax
.ptMaxPosition
.x
= -xinc
;
3852 minmax
.ptMaxPosition
.y
= -yinc
;
3854 if ((win
= get_win_ptr( hwnd
)) && win
!= WND_DESKTOP
&& win
!= WND_OTHER_PROCESS
)
3856 if (!empty_point( win
->max_pos
)) minmax
.ptMaxPosition
= win
->max_pos
;
3857 release_win_ptr( win
);
3860 send_message( hwnd
, WM_GETMINMAXINFO
, 0, (LPARAM
)&minmax
);
3862 /* if the app didn't change the values, adapt them for the current monitor */
3864 if (get_work_rect( hwnd
, &rc_work
))
3866 rc_primary
= get_primary_monitor_rect( get_thread_dpi() );
3867 if (minmax
.ptMaxSize
.x
== (rc_primary
.right
- rc_primary
.left
) + 2 * xinc
&&
3868 minmax
.ptMaxSize
.y
== (rc_primary
.bottom
- rc_primary
.top
) + 2 * yinc
)
3870 minmax
.ptMaxSize
.x
= (rc_work
.right
- rc_work
.left
) + 2 * xinc
;
3871 minmax
.ptMaxSize
.y
= (rc_work
.bottom
- rc_work
.top
) + 2 * yinc
;
3873 if (minmax
.ptMaxPosition
.x
== -xinc
&& minmax
.ptMaxPosition
.y
== -yinc
)
3875 minmax
.ptMaxPosition
.x
= rc_work
.left
- xinc
;
3876 minmax
.ptMaxPosition
.y
= rc_work
.top
- yinc
;
3880 TRACE( "%d %d / %d %d / %d %d / %d %d\n",
3881 (int)minmax
.ptMaxSize
.x
, (int)minmax
.ptMaxSize
.y
,
3882 (int)minmax
.ptMaxPosition
.x
, (int)minmax
.ptMaxPosition
.y
,
3883 (int)minmax
.ptMaxTrackSize
.x
, (int)minmax
.ptMaxTrackSize
.y
,
3884 (int)minmax
.ptMinTrackSize
.x
, (int)minmax
.ptMinTrackSize
.y
);
3886 minmax
.ptMaxTrackSize
.x
= max( minmax
.ptMaxTrackSize
.x
, minmax
.ptMinTrackSize
.x
);
3887 minmax
.ptMaxTrackSize
.y
= max( minmax
.ptMaxTrackSize
.y
, minmax
.ptMinTrackSize
.y
);
3889 SetThreadDpiAwarenessContext( context
);
3893 static POINT
get_first_minimized_child_pos( const RECT
*parent
, const MINIMIZEDMETRICS
*mm
,
3894 int width
, int height
)
3898 if (mm
->iArrange
& ARW_STARTRIGHT
)
3899 ret
.x
= parent
->right
- mm
->iHorzGap
- width
;
3901 ret
.x
= parent
->left
+ mm
->iHorzGap
;
3902 if (mm
->iArrange
& ARW_STARTTOP
)
3903 ret
.y
= parent
->top
+ mm
->iVertGap
;
3905 ret
.y
= parent
->bottom
- mm
->iVertGap
- height
;
3910 static void get_next_minimized_child_pos( const RECT
*parent
, const MINIMIZEDMETRICS
*mm
,
3911 int width
, int height
, POINT
*pos
)
3915 if (mm
->iArrange
& ARW_UP
) /* == ARW_DOWN */
3917 if (mm
->iArrange
& ARW_STARTTOP
)
3919 pos
->y
+= height
+ mm
->iVertGap
;
3920 if ((next
= pos
->y
+ height
> parent
->bottom
))
3921 pos
->y
= parent
->top
+ mm
->iVertGap
;
3925 pos
->y
-= height
+ mm
->iVertGap
;
3926 if ((next
= pos
->y
< parent
->top
))
3927 pos
->y
= parent
->bottom
- mm
->iVertGap
- height
;
3932 if (mm
->iArrange
& ARW_STARTRIGHT
)
3933 pos
->x
-= width
+ mm
->iHorzGap
;
3935 pos
->x
+= width
+ mm
->iHorzGap
;
3940 if (mm
->iArrange
& ARW_STARTRIGHT
)
3942 pos
->x
-= width
+ mm
->iHorzGap
;
3943 if ((next
= pos
->x
< parent
->left
))
3944 pos
->x
= parent
->right
- mm
->iHorzGap
- width
;
3948 pos
->x
+= width
+ mm
->iHorzGap
;
3949 if ((next
= pos
->x
+ width
> parent
->right
))
3950 pos
->x
= parent
->left
+ mm
->iHorzGap
;
3955 if (mm
->iArrange
& ARW_STARTTOP
)
3956 pos
->y
+= height
+ mm
->iVertGap
;
3958 pos
->y
-= height
+ mm
->iVertGap
;
3963 static POINT
get_minimized_pos( HWND hwnd
, POINT pt
)
3965 RECT rect
, parent_rect
;
3968 MINIMIZEDMETRICS metrics
;
3971 parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
3972 if (parent
== get_desktop_window())
3974 MONITORINFO mon_info
;
3975 HMONITOR monitor
= monitor_from_window( hwnd
, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
3977 mon_info
.cbSize
= sizeof( mon_info
);
3978 get_monitor_info( monitor
, &mon_info
);
3979 parent_rect
= mon_info
.rcWork
;
3981 else get_client_rect( parent
, &parent_rect
);
3983 if (pt
.x
>= parent_rect
.left
&& (pt
.x
+ get_system_metrics( SM_CXMINIMIZED
) < parent_rect
.right
) &&
3984 pt
.y
>= parent_rect
.top
&& (pt
.y
+ get_system_metrics( SM_CYMINIMIZED
) < parent_rect
.bottom
))
3985 return pt
; /* The icon already has a suitable position */
3987 width
= get_system_metrics( SM_CXMINIMIZED
);
3988 height
= get_system_metrics( SM_CYMINIMIZED
);
3990 metrics
.cbSize
= sizeof(metrics
);
3991 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(metrics
), &metrics
, 0 );
3993 /* Check if another icon already occupies this spot */
3994 /* FIXME: this is completely inefficient */
3996 hrgn
= NtGdiCreateRectRgn( 0, 0, 0, 0 );
3997 tmp
= NtGdiCreateRectRgn( 0, 0, 0, 0 );
3998 for (child
= get_window_relative( parent
, GW_CHILD
);
4000 child
= get_window_relative( child
, GW_HWNDNEXT
))
4002 if (child
== hwnd
) continue;
4003 if ((get_window_long( child
, GWL_STYLE
) & (WS_VISIBLE
|WS_MINIMIZE
)) != (WS_VISIBLE
|WS_MINIMIZE
))
4005 if (get_window_rects( child
, COORDS_PARENT
, &rect
, NULL
, get_thread_dpi() ))
4007 NtGdiSetRectRgn( tmp
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
4008 NtGdiCombineRgn( hrgn
, hrgn
, tmp
, RGN_OR
);
4011 NtGdiDeleteObjectApp( tmp
);
4013 pt
= get_first_minimized_child_pos( &parent_rect
, &metrics
, width
, height
);
4016 SetRect( &rect
, pt
.x
, pt
.y
, pt
.x
+ width
, pt
.y
+ height
);
4017 if (!NtGdiRectInRegion( hrgn
, &rect
))
4020 get_next_minimized_child_pos( &parent_rect
, &metrics
, width
, height
, &pt
);
4023 NtGdiDeleteObjectApp( hrgn
);
4027 /***********************************************************************
4028 * window_min_maximize
4030 static UINT
window_min_maximize( HWND hwnd
, UINT cmd
, RECT
*rect
)
4035 WINDOWPLACEMENT wpl
;
4037 TRACE( "%p %u\n", hwnd
, cmd
);
4039 wpl
.length
= sizeof(wpl
);
4040 NtUserGetWindowPlacement( hwnd
, &wpl
);
4042 if (call_hooks( WH_CBT
, HCBT_MINMAX
, (WPARAM
)hwnd
, cmd
, 0 ))
4043 return SWP_NOSIZE
| SWP_NOMOVE
;
4045 if (is_iconic( hwnd
))
4049 case SW_SHOWMINNOACTIVE
:
4050 case SW_SHOWMINIMIZED
:
4051 case SW_FORCEMINIMIZE
:
4053 wpl
.ptMinPosition
= get_minimized_pos( hwnd
, wpl
.ptMinPosition
);
4055 SetRect( rect
, wpl
.ptMinPosition
.x
, wpl
.ptMinPosition
.y
,
4056 wpl
.ptMinPosition
.x
+ get_system_metrics( SM_CXMINIMIZED
),
4057 wpl
.ptMinPosition
.y
+ get_system_metrics( SM_CYMINIMIZED
));
4058 return SWP_NOSIZE
| SWP_NOMOVE
;
4060 if (!send_message( hwnd
, WM_QUERYOPEN
, 0, 0 )) return SWP_NOSIZE
| SWP_NOMOVE
;
4061 swp_flags
|= SWP_NOCOPYBITS
;
4066 case SW_SHOWMINNOACTIVE
:
4067 case SW_SHOWMINIMIZED
:
4068 case SW_FORCEMINIMIZE
:
4070 if (is_zoomed( hwnd
)) win_set_flags( hwnd
, WIN_RESTORE_MAX
, 0 );
4071 else win_set_flags( hwnd
, 0, WIN_RESTORE_MAX
);
4073 if (get_focus() == hwnd
)
4075 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
)
4076 NtUserSetFocus( NtUserGetAncestor( hwnd
, GA_PARENT
));
4078 NtUserSetFocus( 0 );
4081 old_style
= set_window_style( hwnd
, WS_MINIMIZE
, WS_MAXIMIZE
);
4083 wpl
.ptMinPosition
= get_minimized_pos( hwnd
, wpl
.ptMinPosition
);
4085 if (!(old_style
& WS_MINIMIZE
)) swp_flags
|= SWP_STATECHANGED
;
4086 SetRect( rect
, wpl
.ptMinPosition
.x
, wpl
.ptMinPosition
.y
,
4087 wpl
.ptMinPosition
.x
+ get_system_metrics(SM_CXMINIMIZED
),
4088 wpl
.ptMinPosition
.y
+ get_system_metrics(SM_CYMINIMIZED
) );
4089 swp_flags
|= SWP_NOCOPYBITS
;
4093 old_style
= get_window_long( hwnd
, GWL_STYLE
);
4094 if ((old_style
& WS_MAXIMIZE
) && (old_style
& WS_VISIBLE
)) return SWP_NOSIZE
| SWP_NOMOVE
;
4096 minmax
= get_min_max_info( hwnd
);
4098 old_style
= set_window_style( hwnd
, WS_MAXIMIZE
, WS_MINIMIZE
);
4099 if (old_style
& WS_MINIMIZE
)
4100 win_set_flags( hwnd
, WIN_RESTORE_MAX
, 0 );
4102 if (!(old_style
& WS_MAXIMIZE
)) swp_flags
|= SWP_STATECHANGED
;
4103 SetRect( rect
, minmax
.ptMaxPosition
.x
, minmax
.ptMaxPosition
.y
,
4104 minmax
.ptMaxPosition
.x
+ minmax
.ptMaxSize
.x
,
4105 minmax
.ptMaxPosition
.y
+ minmax
.ptMaxSize
.y
);
4108 case SW_SHOWNOACTIVATE
:
4109 win_set_flags( hwnd
, 0, WIN_RESTORE_MAX
);
4113 case SW_SHOWDEFAULT
: /* FIXME: should have its own handler */
4114 old_style
= set_window_style( hwnd
, 0, WS_MINIMIZE
| WS_MAXIMIZE
);
4115 if (old_style
& WS_MINIMIZE
)
4117 if (win_get_flags( hwnd
) & WIN_RESTORE_MAX
)
4119 /* Restore to maximized position */
4120 minmax
= get_min_max_info( hwnd
);
4121 set_window_style( hwnd
, WS_MAXIMIZE
, 0 );
4122 swp_flags
|= SWP_STATECHANGED
;
4123 SetRect( rect
, minmax
.ptMaxPosition
.x
, minmax
.ptMaxPosition
.y
,
4124 minmax
.ptMaxPosition
.x
+ minmax
.ptMaxSize
.x
,
4125 minmax
.ptMaxPosition
.y
+ minmax
.ptMaxSize
.y
);
4129 else if (!(old_style
& WS_MAXIMIZE
)) break;
4131 swp_flags
|= SWP_STATECHANGED
;
4133 /* Restore to normal position */
4135 *rect
= wpl
.rcNormalPosition
;
4142 /* see ArrangeIconicWindows */
4143 static UINT
arrange_iconic_windows( HWND parent
)
4145 int width
, height
, count
= 0;
4146 MINIMIZEDMETRICS metrics
;
4151 metrics
.cbSize
= sizeof(metrics
);
4152 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(metrics
), &metrics
, 0 );
4153 width
= get_system_metrics( SM_CXMINIMIZED
);
4154 height
= get_system_metrics( SM_CYMINIMIZED
);
4156 if (parent
== get_desktop_window())
4158 MONITORINFO mon_info
;
4159 HMONITOR monitor
= monitor_from_window( 0, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
4161 mon_info
.cbSize
= sizeof( mon_info
);
4162 get_monitor_info( monitor
, &mon_info
);
4163 parent_rect
= mon_info
.rcWork
;
4165 else get_client_rect( parent
, &parent_rect
);
4167 pt
= get_first_minimized_child_pos( &parent_rect
, &metrics
, width
, height
);
4169 child
= get_window_relative( parent
, GW_CHILD
);
4172 if (is_iconic( child
))
4174 NtUserSetWindowPos( child
, 0, pt
.x
, pt
.y
, 0, 0,
4175 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
4176 get_next_minimized_child_pos( &parent_rect
, &metrics
, width
, height
, &pt
);
4179 child
= get_window_relative( child
, GW_HWNDNEXT
);
4184 /*******************************************************************
4185 * update_window_state
4187 * Trigger an update of the window's driver state and surface.
4189 void update_window_state( HWND hwnd
)
4191 DPI_AWARENESS_CONTEXT context
;
4192 RECT window_rect
, client_rect
, valid_rects
[2];
4194 if (!is_current_thread_window( hwnd
))
4196 NtUserPostMessage( hwnd
, WM_WINE_UPDATEWINDOWSTATE
, 0, 0 );
4200 context
= SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( hwnd
));
4201 get_window_rects( hwnd
, COORDS_PARENT
, &window_rect
, &client_rect
, get_thread_dpi() );
4202 valid_rects
[0] = valid_rects
[1] = client_rect
;
4203 apply_window_pos( hwnd
, 0, SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOCLIENTSIZE
| SWP_NOCLIENTMOVE
|
4204 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREDRAW
,
4205 &window_rect
, &client_rect
, valid_rects
);
4206 SetThreadDpiAwarenessContext( context
);
4209 /***********************************************************************
4212 * Implementation of ShowWindow and ShowWindowAsync.
4214 static BOOL
show_window( HWND hwnd
, INT cmd
)
4218 DPI_AWARENESS_CONTEXT context
;
4219 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
4220 BOOL was_visible
= (style
& WS_VISIBLE
) != 0;
4221 BOOL show_flag
= TRUE
;
4222 RECT newPos
= {0, 0, 0, 0};
4223 UINT new_swp
, swp
= 0;
4225 TRACE( "hwnd=%p, cmd=%d, was_visible %d\n", hwnd
, cmd
, was_visible
);
4227 context
= SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( hwnd
));
4232 if (!was_visible
) goto done
;
4234 swp
|= SWP_HIDEWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
4235 if (style
& WS_CHILD
) swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4238 case SW_SHOWMINNOACTIVE
:
4240 case SW_FORCEMINIMIZE
: /* FIXME: Does not work if thread is hung. */
4241 swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4243 case SW_SHOWMINIMIZED
:
4244 swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
4245 swp
|= window_min_maximize( hwnd
, cmd
, &newPos
);
4246 if ((style
& WS_MINIMIZE
) && was_visible
) goto done
;
4249 case SW_SHOWMAXIMIZED
: /* same as SW_MAXIMIZE */
4250 if (!was_visible
) swp
|= SWP_SHOWWINDOW
;
4251 swp
|= SWP_FRAMECHANGED
;
4252 swp
|= window_min_maximize( hwnd
, SW_MAXIMIZE
, &newPos
);
4253 if ((style
& WS_MAXIMIZE
) && was_visible
) goto done
;
4257 swp
|= SWP_NOACTIVATE
| SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
4258 if (style
& WS_CHILD
) swp
|= SWP_NOZORDER
;
4262 if (was_visible
) goto done
;
4263 swp
|= SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
4264 if (style
& WS_CHILD
) swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4267 case SW_SHOWNOACTIVATE
:
4268 swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4272 case SW_SHOWNORMAL
: /* same as SW_NORMAL: */
4273 case SW_SHOWDEFAULT
: /* FIXME: should have its own handler */
4274 if (!was_visible
) swp
|= SWP_SHOWWINDOW
;
4275 if (style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
4277 swp
|= SWP_FRAMECHANGED
;
4278 swp
|= window_min_maximize( hwnd
, cmd
, &newPos
);
4282 if (was_visible
) goto done
;
4283 swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
4285 if (style
& WS_CHILD
&& !(swp
& SWP_STATECHANGED
)) swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4292 if ((show_flag
!= was_visible
|| cmd
== SW_SHOWNA
) && cmd
!= SW_SHOWMAXIMIZED
&& !(swp
& SWP_STATECHANGED
))
4294 send_message( hwnd
, WM_SHOWWINDOW
, show_flag
, 0 );
4295 if (!is_window( hwnd
)) goto done
;
4298 if (IsRectEmpty( &newPos
)) new_swp
= swp
;
4299 else if ((new_swp
= user_driver
->pShowWindow( hwnd
, cmd
, &newPos
, swp
)) == ~0)
4301 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) new_swp
= swp
;
4302 else if (is_iconic( hwnd
) && (newPos
.left
!= -32000 || newPos
.top
!= -32000))
4304 OffsetRect( &newPos
, -32000 - newPos
.left
, -32000 - newPos
.top
);
4305 new_swp
= swp
& ~(SWP_NOMOVE
| SWP_NOCLIENTMOVE
);
4311 parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
4312 if (parent
&& !is_window_visible( parent
) && !(swp
& SWP_STATECHANGED
))
4314 /* if parent is not visible simply toggle WS_VISIBLE and return */
4315 if (show_flag
) set_window_style( hwnd
, WS_VISIBLE
, 0 );
4316 else set_window_style( hwnd
, 0, WS_VISIBLE
);
4319 NtUserSetWindowPos( hwnd
, HWND_TOP
, newPos
.left
, newPos
.top
,
4320 newPos
.right
- newPos
.left
, newPos
.bottom
- newPos
.top
, swp
);
4326 /* FIXME: This will cause the window to be activated irrespective
4327 * of whether it is owned by the same thread. Has to be done
4331 if (hwnd
== get_active_window()) activate_other_window( hwnd
);
4333 /* Revert focus to parent */
4334 hFocus
= get_focus();
4337 HWND parent
= NtUserGetAncestor(hwnd
, GA_PARENT
);
4338 if (parent
== get_desktop_window()) parent
= 0;
4339 NtUserSetFocus(parent
);
4344 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
) goto done
;
4346 if (win
->flags
& WIN_NEED_SIZE
)
4348 /* should happen only in CreateWindowEx() */
4349 int wParam
= SIZE_RESTORED
;
4353 get_window_rects( hwnd
, COORDS_PARENT
, NULL
, &client
, get_thread_dpi() );
4354 lparam
= MAKELONG( client
.right
- client
.left
, client
.bottom
- client
.top
);
4355 win
->flags
&= ~WIN_NEED_SIZE
;
4356 if (win
->dwStyle
& WS_MAXIMIZE
) wParam
= SIZE_MAXIMIZED
;
4357 else if (win
->dwStyle
& WS_MINIMIZE
)
4359 wParam
= SIZE_MINIMIZED
;
4362 release_win_ptr( win
);
4364 send_message( hwnd
, WM_SIZE
, wParam
, lparam
);
4365 send_message( hwnd
, WM_MOVE
, 0, MAKELONG( client
.left
, client
.top
));
4367 else release_win_ptr( win
);
4369 /* if previous state was minimized Windows sets focus to the window */
4370 if (style
& WS_MINIMIZE
)
4372 NtUserSetFocus( hwnd
);
4373 /* Send a WM_ACTIVATE message for a top level window, even if the window is already active */
4374 if (NtUserGetAncestor( hwnd
, GA_ROOT
) == hwnd
&& !(swp
& SWP_NOACTIVATE
))
4375 send_message( hwnd
, WM_ACTIVATE
, WA_ACTIVE
, 0 );
4379 SetThreadDpiAwarenessContext( context
);
4383 /***********************************************************************
4384 * NtUserShowWindowAsync (win32u.@)
4386 * doesn't wait; returns immediately.
4387 * used by threads to toggle windows in other (possibly hanging) threads
4389 BOOL WINAPI
NtUserShowWindowAsync( HWND hwnd
, INT cmd
)
4393 if (is_broadcast(hwnd
))
4395 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4399 if ((full_handle
= is_current_thread_window( hwnd
)))
4400 return show_window( full_handle
, cmd
);
4402 return NtUserMessageCall( hwnd
, WM_WINE_SHOWWINDOW
, cmd
, 0, 0,
4403 NtUserSendNotifyMessage
, FALSE
);
4406 /***********************************************************************
4407 * NtUserShowWindow (win32u.@)
4409 BOOL WINAPI
NtUserShowWindow( HWND hwnd
, INT cmd
)
4413 if (is_broadcast(hwnd
))
4415 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4418 if ((full_handle
= is_current_thread_window( hwnd
)))
4419 return show_window( full_handle
, cmd
);
4421 if ((cmd
== SW_HIDE
) && !(get_window_long( hwnd
, GWL_STYLE
) & WS_VISIBLE
))
4424 if ((cmd
== SW_SHOW
) && (get_window_long( hwnd
, GWL_STYLE
) & WS_VISIBLE
))
4427 return send_message( hwnd
, WM_WINE_SHOWWINDOW
, cmd
, 0 );
4430 /* see ShowOwnedPopups */
4431 BOOL
show_owned_popups( HWND owner
, BOOL show
)
4434 HWND
*win_array
= list_window_children( 0, get_desktop_window(), NULL
, 0 );
4436 if (!win_array
) return TRUE
;
4438 while (win_array
[count
]) count
++;
4439 while (--count
>= 0)
4441 if (get_window_relative( win_array
[count
], GW_OWNER
) != owner
) continue;
4444 if (win_get_flags( win_array
[count
] ) & WIN_NEEDS_SHOW_OWNEDPOPUP
)
4445 /* In Windows, ShowOwnedPopups(TRUE) generates
4446 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
4447 * regardless of the state of the owner
4449 send_message( win_array
[count
], WM_SHOWWINDOW
, SW_SHOWNORMAL
, SW_PARENTOPENING
);
4453 if (get_window_long( win_array
[count
], GWL_STYLE
) & WS_VISIBLE
)
4454 /* In Windows, ShowOwnedPopups(FALSE) generates
4455 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
4456 * regardless of the state of the owner
4458 send_message( win_array
[count
], WM_SHOWWINDOW
, SW_HIDE
, SW_PARENTCLOSING
);
4466 /*******************************************************************
4467 * NtUserFlashWindowEx (win32u.@)
4469 BOOL WINAPI
NtUserFlashWindowEx( FLASHWINFO
*info
)
4473 TRACE( "%p\n", info
);
4477 RtlSetLastWin32Error( ERROR_NOACCESS
);
4481 if (!info
->hwnd
|| info
->cbSize
!= sizeof(FLASHWINFO
) || !is_window( info
->hwnd
))
4483 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4486 FIXME( "%p - semi-stub\n", info
);
4488 if (is_iconic( info
->hwnd
))
4490 NtUserRedrawWindow( info
->hwnd
, 0, 0, RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_FRAME
);
4492 win
= get_win_ptr( info
->hwnd
);
4493 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
4494 if (info
->dwFlags
&& !(win
->flags
& WIN_NCACTIVATED
))
4496 win
->flags
|= WIN_NCACTIVATED
;
4500 win
->flags
&= ~WIN_NCACTIVATED
;
4502 release_win_ptr( win
);
4503 user_driver
->pFlashWindowEx( info
);
4509 HWND hwnd
= info
->hwnd
;
4511 win
= get_win_ptr( hwnd
);
4512 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
4513 hwnd
= win
->obj
.handle
; /* make it a full handle */
4515 if (info
->dwFlags
) wparam
= !(win
->flags
& WIN_NCACTIVATED
);
4516 else wparam
= (hwnd
== NtUserGetForegroundWindow());
4518 release_win_ptr( win
);
4519 send_message( hwnd
, WM_NCACTIVATE
, wparam
, 0 );
4520 user_driver
->pFlashWindowEx( info
);
4525 /* see GetWindowContextHelpId */
4526 DWORD
get_window_context_help_id( HWND hwnd
)
4529 WND
*win
= get_win_ptr( hwnd
);
4530 if (!win
|| win
== WND_DESKTOP
) return 0;
4531 if (win
== WND_OTHER_PROCESS
)
4533 if (is_window( hwnd
)) FIXME( "not supported on other process window %p\n", hwnd
);
4536 retval
= win
->helpContext
;
4537 release_win_ptr( win
);
4541 /* see SetWindowContextHelpId */
4542 static BOOL
set_window_context_help_id( HWND hwnd
, DWORD id
)
4544 WND
*win
= get_win_ptr( hwnd
);
4545 if (!win
|| win
== WND_DESKTOP
) return FALSE
;
4546 if (win
== WND_OTHER_PROCESS
)
4548 if (is_window( hwnd
)) FIXME( "not supported on other process window %p\n", hwnd
);
4551 win
->helpContext
= id
;
4552 release_win_ptr( win
);
4556 /***********************************************************************
4557 * NtUserInternalGetWindowIcon (win32u.@)
4559 HICON WINAPI
NtUserInternalGetWindowIcon( HWND hwnd
, UINT type
)
4561 WND
*win
= get_win_ptr( hwnd
);
4564 TRACE( "hwnd %p, type %#x\n", hwnd
, type
);
4568 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
4571 if (win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
)
4573 if (is_window( hwnd
)) FIXME( "not supported on other process window %p\n", hwnd
);
4581 if (!ret
) ret
= (HICON
)get_class_long_ptr( hwnd
, GCLP_HICON
, FALSE
);
4586 ret
= win
->hIconSmall
? win
->hIconSmall
: win
->hIconSmall2
;
4587 if (!ret
) ret
= (HICON
)get_class_long_ptr( hwnd
, GCLP_HICONSM
, FALSE
);
4588 if (!ret
) ret
= (HICON
)get_class_long_ptr( hwnd
, GCLP_HICON
, FALSE
);
4592 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4593 release_win_ptr( win
);
4596 release_win_ptr( win
);
4598 if (!ret
) ret
= LoadImageW( 0, (const WCHAR
*)IDI_APPLICATION
, IMAGE_ICON
,
4599 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
4601 return CopyImage( ret
, IMAGE_ICON
, 0, 0, 0 );
4604 /***********************************************************************
4605 * send_destroy_message
4607 static void send_destroy_message( HWND hwnd
)
4611 info
.cbSize
= sizeof(info
);
4612 if (NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
))
4614 if (hwnd
== info
.hwndCaret
) destroy_caret();
4615 if (hwnd
== info
.hwndActive
) activate_other_window( hwnd
);
4618 if (hwnd
== NtUserGetClipboardOwner()) release_clipboard_owner( hwnd
);
4620 send_message( hwnd
, WM_DESTROY
, 0, 0);
4623 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
4624 * make sure that the window still exists when we come back.
4626 if (is_window(hwnd
))
4631 if (!(children
= list_window_children( 0, hwnd
, NULL
, 0 ))) return;
4633 for (i
= 0; children
[i
]; i
++)
4635 if (is_window( children
[i
] )) send_destroy_message( children
[i
] );
4640 WARN( "\tdestroyed itself while in WM_DESTROY!\n" );
4643 /***********************************************************************
4644 * free_window_handle
4646 * Free a window handle.
4648 static void free_window_handle( HWND hwnd
)
4654 if ((win
= get_user_handle_ptr( hwnd
, NTUSER_OBJ_WINDOW
)) && win
!= OBJ_OTHER_PROCESS
)
4656 SERVER_START_REQ( destroy_window
)
4658 req
->handle
= wine_server_user_handle( hwnd
);
4659 wine_server_call( req
);
4660 set_user_handle_ptr( hwnd
, NULL
);
4664 free( win
->pScroll
);
4670 /***********************************************************************
4673 LRESULT
destroy_window( HWND hwnd
)
4675 struct window_surface
*surface
;
4676 HMENU menu
= 0, sys_menu
;
4680 TRACE( "%p\n", hwnd
);
4682 unregister_imm_window( hwnd
);
4684 /* free child windows */
4685 if ((children
= list_window_children( 0, hwnd
, NULL
, 0 )))
4688 for (i
= 0; children
[i
]; i
++)
4690 if (is_current_thread_window( children
[i
] ))
4691 destroy_window( children
[i
] );
4693 NtUserMessageCall( children
[i
], WM_WINE_DESTROYWINDOW
, 0, 0,
4694 0, NtUserSendNotifyMessage
, FALSE
);
4699 /* Unlink now so we won't bother with the children later on */
4700 SERVER_START_REQ( set_parent
)
4702 req
->handle
= wine_server_user_handle( hwnd
);
4704 wine_server_call( req
);
4708 send_message( hwnd
, WM_NCDESTROY
, 0, 0 );
4710 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
4712 /* free resources associated with the window */
4714 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
) return 0;
4715 if ((win
->dwStyle
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
)
4716 menu
= (HMENU
)win
->wIDmenu
;
4717 sys_menu
= win
->hSysMenu
;
4718 free_dce( win
->dce
, hwnd
);
4720 NtUserDestroyCursor( win
->hIconSmall2
, 0 );
4721 surface
= win
->surface
;
4722 win
->surface
= NULL
;
4723 release_win_ptr( win
);
4725 NtUserDestroyMenu( menu
);
4726 NtUserDestroyMenu( sys_menu
);
4729 register_window_surface( surface
, NULL
);
4730 window_surface_release( surface
);
4733 user_driver
->pDestroyWindow( hwnd
);
4735 free_window_handle( hwnd
);
4739 /***********************************************************************
4740 * NtUserDestroyWindow (win32u.@)
4742 BOOL WINAPI
NtUserDestroyWindow( HWND hwnd
)
4746 if (!(hwnd
= is_current_thread_window( hwnd
)) || is_desktop_window( hwnd
))
4748 RtlSetLastWin32Error( ERROR_ACCESS_DENIED
);
4752 TRACE( "(%p)\n", hwnd
);
4754 if (call_hooks( WH_CBT
, HCBT_DESTROYWND
, (WPARAM
)hwnd
, 0, 0 )) return FALSE
;
4756 if (is_menu_active() == hwnd
) NtUserEndMenu();
4758 is_child
= (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) != 0;
4762 if (!is_exiting_thread( GetCurrentThreadId() ))
4763 send_parent_notify( hwnd
, WM_DESTROY
);
4765 else if (!get_window_relative( hwnd
, GW_OWNER
))
4767 call_hooks( WH_SHELL
, HSHELL_WINDOWDESTROYED
, (WPARAM
)hwnd
, 0, 0 );
4768 /* FIXME: clean up palette - see "Internals" p.352 */
4771 if (!is_window( hwnd
)) return TRUE
;
4773 /* Hide the window */
4774 if (get_window_long( hwnd
, GWL_STYLE
) & WS_VISIBLE
)
4776 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
4778 NtUserShowWindow( hwnd
, SW_HIDE
);
4780 NtUserSetWindowPos( hwnd
, 0, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
|
4781 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_HIDEWINDOW
);
4784 if (!is_window( hwnd
)) return TRUE
;
4786 /* Recursively destroy child windows */
4791 BOOL got_one
= FALSE
;
4795 if (!(children
= list_window_children( 0, get_desktop_window(), NULL
, 0 ))) break;
4797 for (i
= 0; children
[i
]; i
++)
4799 if (get_window_relative( children
[i
], GW_OWNER
) != hwnd
) continue;
4800 if (is_current_thread_window( children
[i
] ))
4802 NtUserDestroyWindow( children
[i
] );
4806 set_window_owner( children
[i
], 0 );
4809 if (!got_one
) break;
4813 send_destroy_message( hwnd
);
4814 if (!is_window( hwnd
)) return TRUE
;
4816 destroy_window( hwnd
);
4820 /*****************************************************************************
4821 * destroy_thread_windows
4823 * Destroy all window owned by the current thread.
4825 void destroy_thread_windows(void)
4827 WND
*win
, *free_list
= NULL
;
4831 while ((win
= next_thread_window_ptr( &hwnd
)))
4833 free_dce( win
->dce
, win
->obj
.handle
);
4834 set_user_handle_ptr( hwnd
, NULL
);
4835 win
->obj
.handle
= free_list
;
4840 SERVER_START_REQ( destroy_window
)
4842 req
->handle
= 0; /* destroy all thread windows */
4843 wine_server_call( req
);
4849 while ((win
= free_list
))
4851 free_list
= win
->obj
.handle
;
4852 TRACE( "destroying %p\n", win
);
4854 if ((win
->dwStyle
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
&& win
->wIDmenu
)
4855 NtUserDestroyMenu( UlongToHandle(win
->wIDmenu
) );
4856 if (win
->hSysMenu
) NtUserDestroyMenu( win
->hSysMenu
);
4859 register_window_surface( win
->surface
, NULL
);
4860 window_surface_release( win
->surface
);
4862 free( win
->pScroll
);
4868 /***********************************************************************
4869 * create_window_handle
4871 * Create a window handle with the server.
4873 static WND
*create_window_handle( HWND parent
, HWND owner
, UNICODE_STRING
*name
,
4874 HINSTANCE instance
, BOOL ansi
,
4875 DWORD style
, DWORD ex_style
)
4877 DPI_AWARENESS awareness
= get_thread_dpi_awareness();
4878 HWND handle
= 0, full_parent
= 0, full_owner
= 0;
4879 struct tagCLASS
*class = NULL
;
4880 int extra_bytes
= 0;
4884 SERVER_START_REQ( create_window
)
4886 req
->parent
= wine_server_user_handle( parent
);
4887 req
->owner
= wine_server_user_handle( owner
);
4888 req
->instance
= wine_server_client_ptr( instance
);
4889 req
->dpi
= get_system_dpi();
4890 req
->awareness
= awareness
;
4892 req
->ex_style
= ex_style
;
4893 if (!(req
->atom
= get_int_atom_value( name
)) && name
->Length
)
4894 wine_server_add_data( req
, name
->Buffer
, name
->Length
);
4895 if (!wine_server_call_err( req
))
4897 handle
= wine_server_ptr_handle( reply
->handle
);
4898 full_parent
= wine_server_ptr_handle( reply
->parent
);
4899 full_owner
= wine_server_ptr_handle( reply
->owner
);
4900 extra_bytes
= reply
->extra
;
4902 awareness
= reply
->awareness
;
4903 class = wine_server_get_ptr( reply
->class_ptr
);
4910 WARN( "error %d creating window\n", (int)RtlGetLastWin32Error() );
4914 if (!(win
= calloc( 1, FIELD_OFFSET(WND
, wExtra
) + extra_bytes
)))
4916 SERVER_START_REQ( destroy_window
)
4918 req
->handle
= wine_server_user_handle( handle
);
4919 wine_server_call( req
);
4922 RtlSetLastWin32Error( ERROR_NOT_ENOUGH_MEMORY
);
4926 if (!parent
) /* if parent is 0 we don't have a desktop window yet */
4928 struct ntuser_thread_info
*thread_info
= NtUserGetThreadInfo();
4930 if (name
->Buffer
== (const WCHAR
*)DESKTOP_CLASS_ATOM
)
4932 if (!thread_info
->top_window
)
4933 thread_info
->top_window
= HandleToUlong( full_parent
? full_parent
: handle
);
4934 else assert( full_parent
== UlongToHandle( thread_info
->top_window
));
4936 !user_driver
->pCreateDesktopWindow( UlongToHandle( thread_info
->top_window
)))
4937 ERR( "failed to create desktop window\n" );
4938 register_builtin_classes();
4940 else /* HWND_MESSAGE parent */
4942 if (!thread_info
->msg_window
&& !full_parent
)
4943 thread_info
->msg_window
= HandleToUlong( handle
);
4949 win
->obj
.handle
= handle
;
4950 win
->obj
.type
= NTUSER_OBJ_WINDOW
;
4951 win
->parent
= full_parent
;
4952 win
->owner
= full_owner
;
4954 win
->winproc
= get_class_winproc( class );
4955 win
->cbWndExtra
= extra_bytes
;
4957 win
->dpi_awareness
= awareness
;
4958 set_user_handle_ptr( handle
, &win
->obj
);
4959 if (is_winproc_unicode( win
->winproc
, !ansi
)) win
->flags
|= WIN_ISUNICODE
;
4963 static BOOL
is_default_coord( int x
)
4965 return x
== CW_USEDEFAULT
|| x
== 0x8000;
4968 /***********************************************************************
4969 * fix_cs_coordinates
4971 * Fix the coordinates and return default show mode in sw.
4973 static void fix_cs_coordinates( CREATESTRUCTW
*cs
, INT
*sw
)
4975 if (cs
->style
& (WS_CHILD
| WS_POPUP
))
4977 if (is_default_coord(cs
->x
)) cs
->x
= cs
->y
= 0;
4978 if (is_default_coord(cs
->cx
)) cs
->cx
= cs
->cy
= 0;
4980 else /* overlapped window */
4982 RTL_USER_PROCESS_PARAMETERS
*params
= NtCurrentTeb()->Peb
->ProcessParameters
;
4984 MONITORINFO mon_info
;
4986 if (!is_default_coord( cs
->x
) && !is_default_coord( cs
->cx
) && !is_default_coord( cs
->cy
))
4989 monitor
= monitor_from_window( cs
->hwndParent
, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
4990 mon_info
.cbSize
= sizeof(mon_info
);
4991 get_monitor_info( monitor
, &mon_info
);
4993 if (is_default_coord( cs
->x
))
4995 if (!is_default_coord( cs
->y
)) *sw
= cs
->y
;
4996 cs
->x
= (params
->dwFlags
& STARTF_USEPOSITION
) ? params
->dwX
: mon_info
.rcWork
.left
;
4997 cs
->y
= (params
->dwFlags
& STARTF_USEPOSITION
) ? params
->dwY
: mon_info
.rcWork
.top
;
5000 if (is_default_coord( cs
->cx
))
5002 if (params
->dwFlags
& STARTF_USESIZE
)
5004 cs
->cx
= params
->dwXSize
;
5005 cs
->cy
= params
->dwYSize
;
5009 cs
->cx
= (mon_info
.rcWork
.right
- mon_info
.rcWork
.left
) * 3 / 4 - cs
->x
;
5010 cs
->cy
= (mon_info
.rcWork
.bottom
- mon_info
.rcWork
.top
) * 3 / 4 - cs
->y
;
5013 /* neither x nor cx are default. Check the y values.
5014 * In the trace we see Outlook and Outlook Express using
5015 * cy set to CW_USEDEFAULT when opening the address book.
5017 else if (is_default_coord( cs
->cy
))
5019 FIXME( "Strange use of CW_USEDEFAULT in cy\n" );
5020 cs
->cy
= (mon_info
.rcWork
.bottom
- mon_info
.rcWork
.top
) * 3 / 4 - cs
->y
;
5025 /***********************************************************************
5026 * map_dpi_create_struct
5028 static void map_dpi_create_struct( CREATESTRUCTW
*cs
, UINT dpi_from
, UINT dpi_to
)
5030 if (!dpi_from
&& !dpi_to
) return;
5031 if (!dpi_from
|| !dpi_to
)
5033 POINT pt
= { cs
->x
, cs
->y
};
5034 UINT mon_dpi
= get_monitor_dpi( monitor_from_point( pt
, MONITOR_DEFAULTTONEAREST
, dpi_from
));
5035 if (!dpi_from
) dpi_from
= mon_dpi
;
5036 else dpi_to
= mon_dpi
;
5038 if (dpi_from
== dpi_to
) return;
5039 cs
->x
= muldiv( cs
->x
, dpi_to
, dpi_from
);
5040 cs
->y
= muldiv( cs
->y
, dpi_to
, dpi_from
);
5041 cs
->cx
= muldiv( cs
->cx
, dpi_to
, dpi_from
);
5042 cs
->cy
= muldiv( cs
->cy
, dpi_to
, dpi_from
);
5045 /***********************************************************************
5046 * NtUserCreateWindowEx (win32u.@)
5048 HWND WINAPI
NtUserCreateWindowEx( DWORD ex_style
, UNICODE_STRING
*class_name
,
5049 UNICODE_STRING
*version
, UNICODE_STRING
*window_name
,
5050 DWORD style
, INT x
, INT y
, INT cx
, INT cy
,
5051 HWND parent
, HMENU menu
, HINSTANCE instance
, void *params
,
5052 DWORD flags
, HINSTANCE client_instance
, DWORD unk
, BOOL ansi
)
5054 UINT win_dpi
, thread_dpi
= get_thread_dpi();
5055 DPI_AWARENESS_CONTEXT context
;
5056 CBT_CREATEWNDW cbtc
;
5057 HWND hwnd
, owner
= 0;
5063 static const WCHAR messageW
[] = {'M','e','s','s','a','g','e'};
5065 cs
.lpCreateParams
= params
;
5066 cs
.hInstance
= client_instance
? client_instance
: instance
;
5068 cs
.hwndParent
= parent
;
5070 cs
.dwExStyle
= ex_style
;
5071 cs
.lpszName
= window_name
? window_name
->Buffer
: NULL
;
5072 cs
.lpszClass
= class_name
? class_name
->Buffer
: NULL
;
5078 /* Find the parent window */
5079 if (parent
== HWND_MESSAGE
)
5081 cs
.hwndParent
= parent
= get_hwnd_message_parent();
5085 if ((cs
.style
& (WS_CHILD
|WS_POPUP
)) != WS_CHILD
)
5088 parent
= get_desktop_window();
5092 DWORD parent_style
= get_window_long( parent
, GWL_EXSTYLE
);
5093 if ((parent_style
& WS_EX_LAYOUTRTL
) && !(parent_style
& WS_EX_NOINHERITLAYOUT
))
5094 cs
.dwExStyle
|= WS_EX_LAYOUTRTL
;
5099 if ((cs
.style
& (WS_CHILD
|WS_POPUP
)) == WS_CHILD
)
5101 WARN( "No parent for child window\n" );
5102 RtlSetLastWin32Error( ERROR_TLW_WITH_WSCHILD
);
5103 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
5106 /* are we creating the desktop or HWND_MESSAGE parent itself? */
5107 if (class_name
->Buffer
!= (LPCWSTR
)DESKTOP_CLASS_ATOM
&&
5108 (class_name
->Length
!= sizeof(messageW
) ||
5109 wcsnicmp( class_name
->Buffer
, messageW
, ARRAYSIZE(messageW
) )))
5111 if (get_process_layout() & LAYOUT_RTL
) cs
.dwExStyle
|= WS_EX_LAYOUTRTL
;
5112 parent
= get_desktop_window();
5116 fix_cs_coordinates( &cs
, &sw
);
5117 cs
.dwExStyle
= fix_exstyle( cs
.style
, cs
.dwExStyle
);
5119 /* Create the window structure */
5121 style
= cs
.style
& ~WS_VISIBLE
;
5122 ex_style
= cs
.dwExStyle
& ~WS_EX_LAYERED
;
5123 if (!(win
= create_window_handle( parent
, owner
, class_name
, instance
, ansi
, style
, ex_style
)))
5125 hwnd
= win
->obj
.handle
;
5127 /* Fill the window structure */
5129 win
->tid
= GetCurrentThreadId();
5130 win
->hInstance
= cs
.hInstance
;
5132 win
->dwStyle
= style
;
5133 win
->dwExStyle
= ex_style
;
5135 win
->helpContext
= 0;
5136 win
->pScroll
= NULL
;
5139 win
->hIconSmall
= 0;
5140 win
->hIconSmall2
= 0;
5143 win
->min_pos
.x
= win
->min_pos
.y
= -1;
5144 win
->max_pos
.x
= win
->max_pos
.y
= -1;
5145 SetRect( &win
->normal_rect
, cs
.x
, cs
.y
, cs
.x
+ cs
.cx
, cs
.y
+ cs
.cy
);
5147 if (win
->dwStyle
& WS_SYSMENU
) NtUserSetSystemMenu( hwnd
, 0 );
5149 win
->imc
= get_default_input_context();
5151 /* call the WH_CBT hook */
5153 release_win_ptr( win
);
5154 cbtc
.hwndInsertAfter
= HWND_TOP
;
5156 if (call_hooks( WH_CBT
, HCBT_CREATEWND
, (WPARAM
)hwnd
, (LPARAM
)&cbtc
, sizeof(cbtc
) ))
5158 free_window_handle( hwnd
);
5161 if (!(win
= get_win_ptr( hwnd
))) return 0;
5164 * Correct the window styles.
5166 * It affects only the style loaded into the WND structure.
5169 if ((win
->dwStyle
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
)
5171 win
->dwStyle
|= WS_CLIPSIBLINGS
;
5172 if (!(win
->dwStyle
& WS_POPUP
)) win
->dwStyle
|= WS_CAPTION
;
5175 win
->dwExStyle
= cs
.dwExStyle
;
5176 /* WS_EX_WINDOWEDGE depends on some other styles */
5177 if ((win
->dwStyle
& (WS_DLGFRAME
| WS_THICKFRAME
)) &&
5178 !(win
->dwStyle
& (WS_CHILD
| WS_POPUP
)))
5179 win
->dwExStyle
|= WS_EX_WINDOWEDGE
;
5181 if (!(win
->dwStyle
& (WS_CHILD
| WS_POPUP
))) win
->flags
|= WIN_NEED_SIZE
;
5183 SERVER_START_REQ( set_window_info
)
5185 req
->handle
= wine_server_user_handle( hwnd
);
5186 req
->flags
= SET_WIN_STYLE
| SET_WIN_EXSTYLE
| SET_WIN_INSTANCE
| SET_WIN_UNICODE
;
5187 req
->style
= win
->dwStyle
;
5188 req
->ex_style
= win
->dwExStyle
;
5189 req
->instance
= wine_server_client_ptr( win
->hInstance
);
5190 req
->is_unicode
= (win
->flags
& WIN_ISUNICODE
) != 0;
5191 req
->extra_offset
= -1;
5192 wine_server_call( req
);
5196 /* Set the window menu */
5198 if ((win
->dwStyle
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
)
5200 if (cs
.hMenu
&& !set_window_menu( hwnd
, cs
.hMenu
))
5202 release_win_ptr( win
);
5203 free_window_handle( hwnd
);
5207 else NtUserSetWindowLongPtr( hwnd
, GWLP_ID
, (ULONG_PTR
)cs
.hMenu
, FALSE
);
5210 release_win_ptr( win
);
5212 if (parent
) map_dpi_create_struct( &cs
, thread_dpi
, win_dpi
);
5214 context
= SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( hwnd
));
5216 /* send the WM_GETMINMAXINFO message and fix the size if needed */
5220 if ((cs
.style
& WS_THICKFRAME
) || !(cs
.style
& (WS_POPUP
| WS_CHILD
)))
5222 MINMAXINFO info
= get_min_max_info( hwnd
);
5223 cx
= max( min( cx
, info
.ptMaxTrackSize
.x
), info
.ptMinTrackSize
.x
);
5224 cy
= max( min( cy
, info
.ptMaxTrackSize
.y
), info
.ptMinTrackSize
.y
);
5229 SetRect( &rect
, cs
.x
, cs
.y
, cs
.x
+ cx
, cs
.y
+ cy
);
5230 /* check for wraparound */
5231 if (cs
.x
> 0x7fffffff - cx
) rect
.right
= 0x7fffffff;
5232 if (cs
.y
> 0x7fffffff - cy
) rect
.bottom
= 0x7fffffff;
5233 if (!apply_window_pos( hwnd
, 0, SWP_NOZORDER
| SWP_NOACTIVATE
, &rect
, &rect
, NULL
)) goto failed
;
5235 /* send WM_NCCREATE */
5237 TRACE( "hwnd %p cs %d,%d %dx%d %s\n", hwnd
, cs
.x
, cs
.y
, cs
.cx
, cs
.cy
, wine_dbgstr_rect(&rect
) );
5238 if (!send_message_timeout( hwnd
, WM_NCCREATE
, 0, (LPARAM
)&cs
, SMTO_NORMAL
, 0, ansi
))
5240 WARN( "%p: aborted by WM_NCCREATE\n", hwnd
);
5244 /* create default IME window */
5246 if (!is_desktop_window( hwnd
) && parent
!= get_hwnd_message_parent() &&
5247 register_imm_window( hwnd
))
5249 TRACE( "register IME window for %p\n", hwnd
);
5250 win_set_flags( hwnd
, WIN_HAS_IME_WIN
, 0 );
5253 /* send WM_NCCALCSIZE */
5255 if (get_window_rects( hwnd
, COORDS_PARENT
, &rect
, NULL
, win_dpi
))
5257 /* yes, even if the CBT hook was called with HWND_TOP */
5258 HWND insert_after
= (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) ? HWND_BOTTOM
: HWND_TOP
;
5259 RECT client_rect
= rect
;
5261 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
5262 map_window_points( parent
, 0, (POINT
*)&client_rect
, 2, win_dpi
);
5263 send_message( hwnd
, WM_NCCALCSIZE
, FALSE
, (LPARAM
)&client_rect
);
5264 map_window_points( 0, parent
, (POINT
*)&client_rect
, 2, win_dpi
);
5265 apply_window_pos( hwnd
, insert_after
, SWP_NOACTIVATE
, &rect
, &client_rect
, NULL
);
5269 /* send WM_CREATE */
5270 if (send_message_timeout( hwnd
, WM_CREATE
, 0, (LPARAM
)&cs
, SMTO_NORMAL
, 0, ansi
) == -1)
5273 /* call the driver */
5275 if (!user_driver
->pCreateWindow( hwnd
)) goto failed
;
5277 NtUserNotifyWinEvent( EVENT_OBJECT_CREATE
, hwnd
, OBJID_WINDOW
, 0 );
5279 /* send the size messages */
5281 if (!(win_get_flags( hwnd
) & WIN_NEED_SIZE
))
5283 get_window_rects( hwnd
, COORDS_PARENT
, NULL
, &rect
, win_dpi
);
5284 send_message( hwnd
, WM_SIZE
, SIZE_RESTORED
,
5285 MAKELONG(rect
.right
-rect
.left
, rect
.bottom
-rect
.top
));
5286 send_message( hwnd
, WM_MOVE
, 0, MAKELONG( rect
.left
, rect
.top
) );
5289 /* Show the window, maximizing or minimizing if needed */
5291 style
= set_window_style( hwnd
, 0, WS_MAXIMIZE
| WS_MINIMIZE
);
5292 if (style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
5295 UINT sw_flags
= (style
& WS_MINIMIZE
) ? SW_MINIMIZE
: SW_MAXIMIZE
;
5297 sw_flags
= window_min_maximize( hwnd
, sw_flags
, &new_pos
);
5298 sw_flags
|= SWP_FRAMECHANGED
; /* Frame always gets changed */
5299 if (!(style
& WS_VISIBLE
) || (style
& WS_CHILD
) || get_active_window())
5300 sw_flags
|= SWP_NOACTIVATE
;
5301 NtUserSetWindowPos( hwnd
, 0, new_pos
.left
, new_pos
.top
, new_pos
.right
- new_pos
.left
,
5302 new_pos
.bottom
- new_pos
.top
, sw_flags
);
5305 /* Notify the parent window only */
5307 send_parent_notify( hwnd
, WM_CREATE
);
5308 if (!is_window( hwnd
))
5310 SetThreadDpiAwarenessContext( context
);
5314 if (parent
== get_desktop_window())
5315 NtUserPostMessage( parent
, WM_PARENTNOTIFY
, WM_CREATE
, (LPARAM
)hwnd
);
5317 if (cs
.style
& WS_VISIBLE
)
5319 if (cs
.style
& WS_MAXIMIZE
)
5321 else if (cs
.style
& WS_MINIMIZE
)
5322 sw
= SW_SHOWMINIMIZED
;
5324 NtUserShowWindow( hwnd
, sw
);
5325 if (cs
.dwExStyle
& WS_EX_MDICHILD
)
5327 send_message( cs
.hwndParent
, WM_MDIREFRESHMENU
, 0, 0 );
5328 /* ShowWindow won't activate child windows */
5329 NtUserSetWindowPos( hwnd
, HWND_TOP
, 0, 0, 0, 0, SWP_SHOWWINDOW
| SWP_NOMOVE
| SWP_NOSIZE
);
5333 /* Call WH_SHELL hook */
5335 if (!(get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) && !get_window_relative( hwnd
, GW_OWNER
))
5336 call_hooks( WH_SHELL
, HSHELL_WINDOWCREATED
, (WPARAM
)hwnd
, 0, 0 );
5338 TRACE( "created window %p\n", hwnd
);
5339 SetThreadDpiAwarenessContext( context
);
5343 destroy_window( hwnd
);
5344 SetThreadDpiAwarenessContext( context
);
5348 static void *get_dialog_info( HWND hwnd
)
5353 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
)
5355 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
5360 release_win_ptr( win
);
5364 static BOOL
set_dialog_info( HWND hwnd
, void *info
)
5368 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
5369 win
->dlgInfo
= info
;
5370 release_win_ptr( win
);
5374 /*****************************************************************************
5375 * NtUserCallHwnd (win32u.@)
5377 ULONG_PTR WINAPI
NtUserCallHwnd( HWND hwnd
, DWORD code
)
5381 case NtUserCallHwnd_ActivateOtherWindow
:
5382 activate_other_window( hwnd
);
5385 case NtUserCallHwnd_ArrangeIconicWindows
:
5386 return arrange_iconic_windows( hwnd
);
5388 case NtUserCallHwnd_DrawMenuBar
:
5389 return draw_menu_bar( hwnd
);
5391 case NtUserCallHwnd_GetDefaultImeWindow
:
5392 return HandleToUlong( get_default_ime_window( hwnd
));
5394 case NtUserCallHwnd_GetDpiForWindow
:
5395 return get_dpi_for_window( hwnd
);
5397 case NtUserCallHwnd_GetParent
:
5398 return HandleToUlong( get_parent( hwnd
));
5400 case NtUserCallHwnd_GetDialogInfo
:
5401 return (ULONG_PTR
)get_dialog_info( hwnd
);
5403 case NtUserCallHwnd_GetMDIClientInfo
:
5404 if (!(win_get_flags( hwnd
) & WIN_ISMDICLIENT
)) return 0;
5405 return get_window_long_ptr( hwnd
, sizeof(void *), FALSE
);
5407 case NtUserCallHwnd_GetWindowContextHelpId
:
5408 return get_window_context_help_id( hwnd
);
5410 case NtUserCallHwnd_GetWindowDpiAwarenessContext
:
5411 return (ULONG_PTR
)get_window_dpi_awareness_context( hwnd
);
5413 case NtUserCallHwnd_GetWindowInputContext
:
5414 return HandleToUlong( get_window_input_context( hwnd
));
5416 case NtUserCallHwnd_GetWindowSysSubMenu
:
5417 return HandleToUlong( get_window_sys_sub_menu( hwnd
));
5419 case NtUserCallHwnd_GetWindowTextLength
:
5420 return get_server_window_text( hwnd
, NULL
, 0 );
5422 case NtUserCallHwnd_IsWindow
:
5423 return is_window( hwnd
);
5425 case NtUserCallHwnd_IsWindowEnabled
:
5426 return is_window_enabled( hwnd
);
5428 case NtUserCallHwnd_IsWindowUnicode
:
5429 return is_window_unicode( hwnd
);
5431 case NtUserCallHwnd_IsWindowVisible
:
5432 return is_window_visible( hwnd
);
5434 case NtUserCallHwnd_SetForegroundWindow
:
5435 return set_foreground_window( hwnd
, FALSE
);
5437 case NtUserCallHwnd_SetProgmanWindow
:
5438 return HandleToUlong( set_progman_window( hwnd
));
5440 case NtUserCallHwnd_SetTaskmanWindow
:
5441 return HandleToUlong( set_taskman_window( hwnd
));
5443 /* temporary exports */
5444 case NtUserGetFullWindowHandle
:
5445 return HandleToUlong( get_full_window_handle( hwnd
));
5447 case NtUserIsCurrehtProcessWindow
:
5448 return HandleToUlong( is_current_process_window( hwnd
));
5450 case NtUserIsCurrehtThreadWindow
:
5451 return HandleToUlong( is_current_thread_window( hwnd
));
5454 FIXME( "invalid code %u\n", (int)code
);
5459 /*****************************************************************************
5460 * NtUserCallHwndParam (win32u.@)
5462 ULONG_PTR WINAPI
NtUserCallHwndParam( HWND hwnd
, DWORD_PTR param
, DWORD code
)
5466 case NtUserCallHwndParam_ClientToScreen
:
5467 return client_to_screen( hwnd
, (POINT
*)param
);
5469 case NtUserCallHwndParam_EnableWindow
:
5470 return enable_window( hwnd
, param
);
5472 case NtUserCallHwndParam_GetChildRect
:
5473 return get_window_rects( hwnd
, COORDS_PARENT
, (RECT
*)param
, NULL
, get_thread_dpi() );
5475 case NtUserCallHwndParam_GetClassLongA
:
5476 return get_class_long( hwnd
, param
, TRUE
);
5478 case NtUserCallHwndParam_GetClassLongW
:
5479 return get_class_long( hwnd
, param
, FALSE
);
5481 case NtUserCallHwndParam_GetClassLongPtrA
:
5482 return get_class_long_ptr( hwnd
, param
, TRUE
);
5484 case NtUserCallHwndParam_GetClassLongPtrW
:
5485 return get_class_long_ptr( hwnd
, param
, FALSE
);
5487 case NtUserCallHwndParam_GetClassWord
:
5488 return get_class_word( hwnd
, param
);
5490 case NtUserCallHwndParam_GetClientRect
:
5491 return get_client_rect( hwnd
, (RECT
*)param
);
5493 case NtUserCallHwndParam_GetScrollInfo
:
5495 struct get_scroll_info_params
*params
= (void *)param
;
5496 return get_scroll_info( hwnd
, params
->bar
, params
->info
);
5499 case NtUserCallHwndParam_GetWindowInfo
:
5500 return get_window_info( hwnd
, (WINDOWINFO
*)param
);
5502 case NtUserCallHwndParam_GetWindowLongA
:
5503 return get_window_long_size( hwnd
, param
, sizeof(LONG
), TRUE
);
5505 case NtUserCallHwndParam_GetWindowLongW
:
5506 return get_window_long( hwnd
, param
);
5508 case NtUserCallHwndParam_GetWindowLongPtrA
:
5509 return get_window_long_ptr( hwnd
, param
, TRUE
);
5511 case NtUserCallHwndParam_GetWindowLongPtrW
:
5512 return get_window_long_ptr( hwnd
, param
, FALSE
);
5514 case NtUserCallHwndParam_GetWindowRect
:
5515 return get_window_rect( hwnd
, (RECT
*)param
, get_thread_dpi() );
5517 case NtUserCallHwndParam_GetWindowRelative
:
5518 return HandleToUlong( get_window_relative( hwnd
, param
));
5520 case NtUserCallHwndParam_GetWindowThread
:
5521 return get_window_thread( hwnd
, (DWORD
*)param
);
5523 case NtUserCallHwndParam_GetWindowWord
:
5524 return get_window_word( hwnd
, param
);
5526 case NtUserCallHwndParam_IsChild
:
5527 return is_child( hwnd
, UlongToHandle(param
) );
5529 case NtUserCallHwndParam_KillSystemTimer
:
5530 return kill_system_timer( hwnd
, param
);
5532 case NtUserCallHwndParam_MapWindowPoints
:
5534 struct map_window_points_params
*params
= (void *)param
;
5535 return map_window_points( hwnd
, params
->hwnd_to
, params
->points
, params
->count
,
5539 case NtUserCallHwndParam_MirrorRgn
:
5540 return mirror_window_region( hwnd
, UlongToHandle(param
) );
5542 case NtUserCallHwndParam_MonitorFromWindow
:
5543 return HandleToUlong( monitor_from_window( hwnd
, param
, get_thread_dpi() ));
5545 case NtUserCallHwndParam_ScreenToClient
:
5546 return screen_to_client( hwnd
, (POINT
*)param
);
5548 case NtUserCallHwndParam_SetDialogInfo
:
5549 return set_dialog_info( hwnd
, (void *)param
);
5551 case NtUserCallHwndParam_SetMDIClientInfo
:
5552 NtUserSetWindowLongPtr( hwnd
, sizeof(void *), param
, FALSE
);
5553 return win_set_flags( hwnd
, WIN_ISMDICLIENT
, 0 );
5555 case NtUserCallHwndParam_SetWindowContextHelpId
:
5556 return set_window_context_help_id( hwnd
, param
);
5558 case NtUserCallHwndParam_SetWindowPixelFormat
:
5559 return set_window_pixel_format( hwnd
, param
);
5561 case NtUserCallHwndParam_ShowOwnedPopups
:
5562 return show_owned_popups( hwnd
, param
);
5564 /* temporary exports */
5565 case NtUserSetWindowStyle
:
5567 STYLESTRUCT
*style
= (void *)param
;
5568 return set_window_style( hwnd
, style
->styleNew
, style
->styleOld
);
5572 FIXME( "invalid code %u\n", (int)code
);
5577 /*******************************************************************
5578 * NtUserDragDetect (win32u.@)
5580 BOOL WINAPI
NtUserDragDetect( HWND hwnd
, int x
, int y
)
5586 TRACE( "%p (%d,%d)\n", hwnd
, x
, y
);
5588 if (!(NtUserGetKeyState( VK_LBUTTON
) & 0x8000)) return FALSE
;
5590 width
= get_system_metrics( SM_CXDRAG
);
5591 height
= get_system_metrics( SM_CYDRAG
);
5592 SetRect( &rect
, x
- width
, y
- height
, x
+ width
, y
+ height
);
5594 NtUserSetCapture( hwnd
);
5598 while (NtUserPeekMessage( &msg
, 0, WM_MOUSEFIRST
, WM_MOUSELAST
, PM_REMOVE
))
5600 if (msg
.message
== WM_LBUTTONUP
)
5605 if (msg
.message
== WM_MOUSEMOVE
)
5608 tmp
.x
= (short)LOWORD( msg
.lParam
);
5609 tmp
.y
= (short)HIWORD( msg
.lParam
);
5610 if (!PtInRect( &rect
, tmp
))
5617 NtUserMsgWaitForMultipleObjectsEx( 0, NULL
, INFINITE
, QS_ALLINPUT
, 0 );
5622 /*******************************************************************
5623 * NtUserDragObject (win32u.@)
5625 DWORD WINAPI
NtUserDragObject( HWND parent
, HWND hwnd
, UINT fmt
, ULONG_PTR data
, HCURSOR cursor
)
5627 FIXME( "%p, %p, %u, %#lx, %p stub!\n", parent
, hwnd
, fmt
, data
, cursor
);