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 * next_process_user_handle_ptr
107 * user_lock must be held by caller.
109 void *next_process_user_handle_ptr( HANDLE
*handle
, unsigned int type
)
111 struct user_object
*ptr
;
112 WORD index
= *handle
? USER_HANDLE_TO_INDEX( *handle
) + 1 : 0;
114 while (index
< NB_USER_HANDLES
)
116 if (!(ptr
= user_handles
[index
++])) continue; /* OBJ_OTHER_PROCESS */
117 if (ptr
->type
!= type
) continue;
118 *handle
= ptr
->handle
;
124 /***********************************************************************
125 * set_user_handle_ptr
127 static void set_user_handle_ptr( HANDLE handle
, struct user_object
*ptr
)
129 WORD index
= USER_HANDLE_TO_INDEX(handle
);
130 assert( index
< NB_USER_HANDLES
);
131 InterlockedExchangePointer( &user_handles
[index
], ptr
);
134 /***********************************************************************
135 * release_user_handle_ptr
137 void release_user_handle_ptr( void *ptr
)
139 assert( ptr
&& ptr
!= OBJ_OTHER_PROCESS
);
143 /***********************************************************************
146 void *free_user_handle( HANDLE handle
, unsigned int type
)
148 struct user_object
*ptr
;
149 WORD index
= USER_HANDLE_TO_INDEX( handle
);
151 if ((ptr
= get_user_handle_ptr( handle
, type
)) && ptr
!= OBJ_OTHER_PROCESS
)
153 SERVER_START_REQ( free_user_handle
)
155 req
->handle
= wine_server_user_handle( handle
);
156 if (wine_server_call( req
)) ptr
= NULL
;
157 else InterlockedCompareExchangePointer( &user_handles
[index
], NULL
, ptr
);
165 /*******************************************************************
166 * get_hwnd_message_parent
168 * Return the parent for HWND_MESSAGE windows.
170 HWND
get_hwnd_message_parent(void)
172 struct ntuser_thread_info
*thread_info
= NtUserGetThreadInfo();
174 if (!thread_info
->msg_window
) get_desktop_window(); /* trigger creation */
175 return UlongToHandle( thread_info
->msg_window
);
178 /***********************************************************************
179 * get_full_window_handle
181 * Convert a possibly truncated window handle to a full 32-bit handle.
183 HWND
get_full_window_handle( HWND hwnd
)
187 if (!hwnd
|| (ULONG_PTR
)hwnd
>> 16) return hwnd
;
188 if (LOWORD(hwnd
) <= 1 || LOWORD(hwnd
) == 0xffff) return hwnd
;
189 /* do sign extension for -2 and -3 */
190 if (LOWORD(hwnd
) >= (WORD
)-3) return (HWND
)(LONG_PTR
)(INT16
)LOWORD(hwnd
);
192 if (!(win
= get_win_ptr( hwnd
))) return hwnd
;
194 if (win
== WND_DESKTOP
)
196 if (LOWORD(hwnd
) == LOWORD(get_desktop_window())) return get_desktop_window();
197 else return get_hwnd_message_parent();
200 if (win
!= WND_OTHER_PROCESS
)
202 hwnd
= win
->obj
.handle
;
203 release_win_ptr( win
);
205 else /* may belong to another process */
207 SERVER_START_REQ( get_window_info
)
209 req
->handle
= wine_server_user_handle( hwnd
);
210 if (!wine_server_call_err( req
)) hwnd
= wine_server_ptr_handle( reply
->full_handle
);
217 /*******************************************************************
220 * Check if window is the desktop or the HWND_MESSAGE top parent.
222 BOOL
is_desktop_window( HWND hwnd
)
224 struct ntuser_thread_info
*thread_info
= NtUserGetThreadInfo();
226 if (!hwnd
) return FALSE
;
227 if (hwnd
== UlongToHandle( thread_info
->top_window
)) return TRUE
;
228 if (hwnd
== UlongToHandle( thread_info
->msg_window
)) return TRUE
;
230 if (!HIWORD(hwnd
) || HIWORD(hwnd
) == 0xffff)
232 if (LOWORD(thread_info
->top_window
) == LOWORD(hwnd
)) return TRUE
;
233 if (LOWORD(thread_info
->msg_window
) == LOWORD(hwnd
)) return TRUE
;
238 /***********************************************************************
241 * Return a pointer to the WND structure if local to the process,
242 * or WND_OTHER_PROCESS if handle may be valid in other process.
243 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
245 WND
*get_win_ptr( HWND hwnd
)
249 if ((win
= get_user_handle_ptr( hwnd
, NTUSER_OBJ_WINDOW
)) == WND_OTHER_PROCESS
)
251 if (is_desktop_window( hwnd
)) win
= WND_DESKTOP
;
256 /***********************************************************************
257 * is_current_thread_window
259 * Check whether a given window belongs to the current process (and return the full handle).
261 HWND
is_current_thread_window( HWND hwnd
)
266 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
)
268 if (win
->tid
== GetCurrentThreadId()) ret
= win
->obj
.handle
;
269 release_win_ptr( win
);
273 /***********************************************************************
274 * is_current_process_window
276 * Check whether a given window belongs to the current process (and return the full handle).
278 HWND
is_current_process_window( HWND hwnd
)
283 if (!(ptr
= get_win_ptr( hwnd
)) || ptr
== WND_OTHER_PROCESS
|| ptr
== WND_DESKTOP
) return 0;
284 ret
= ptr
->obj
.handle
;
285 release_win_ptr( ptr
);
290 BOOL
is_window( HWND hwnd
)
295 if (!(win
= get_win_ptr( hwnd
))) return FALSE
;
296 if (win
== WND_DESKTOP
) return TRUE
;
298 if (win
!= WND_OTHER_PROCESS
)
300 release_win_ptr( win
);
304 /* check other processes */
305 SERVER_START_REQ( get_window_info
)
307 req
->handle
= wine_server_user_handle( hwnd
);
308 ret
= !wine_server_call_err( req
);
314 /* see GetWindowThreadProcessId */
315 DWORD
get_window_thread( HWND hwnd
, DWORD
*process
)
320 if (!(ptr
= get_win_ptr( hwnd
)))
322 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
326 if (ptr
!= WND_OTHER_PROCESS
&& ptr
!= WND_DESKTOP
)
328 /* got a valid window */
330 if (process
) *process
= GetCurrentProcessId();
331 release_win_ptr( ptr
);
335 /* check other processes */
336 SERVER_START_REQ( get_window_info
)
338 req
->handle
= wine_server_user_handle( hwnd
);
339 if (!wine_server_call_err( req
))
341 tid
= (DWORD
)reply
->tid
;
342 if (process
) *process
= (DWORD
)reply
->pid
;
350 HWND
get_parent( HWND hwnd
)
355 if (!(win
= get_win_ptr( hwnd
)))
357 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
360 if (win
== WND_DESKTOP
) return 0;
361 if (win
== WND_OTHER_PROCESS
)
363 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
364 if (style
& (WS_POPUP
| WS_CHILD
))
366 SERVER_START_REQ( get_window_tree
)
368 req
->handle
= wine_server_user_handle( hwnd
);
369 if (!wine_server_call_err( req
))
371 if (style
& WS_POPUP
) retval
= wine_server_ptr_handle( reply
->owner
);
372 else if (style
& WS_CHILD
) retval
= wine_server_ptr_handle( reply
->parent
);
380 if (win
->dwStyle
& WS_POPUP
) retval
= win
->owner
;
381 else if (win
->dwStyle
& WS_CHILD
) retval
= win
->parent
;
382 release_win_ptr( win
);
387 /*****************************************************************
388 * NtUserSetParent (win32u.@)
390 HWND WINAPI
NtUserSetParent( HWND hwnd
, HWND parent
)
392 RECT window_rect
, old_screen_rect
, new_screen_rect
;
393 DPI_AWARENESS_CONTEXT context
;
401 TRACE("(%p %p)\n", hwnd
, parent
);
403 if (is_broadcast(hwnd
) || is_broadcast(parent
))
405 RtlSetLastWin32Error(ERROR_INVALID_PARAMETER
);
409 if (!parent
) parent
= get_desktop_window();
410 else if (parent
== HWND_MESSAGE
) parent
= get_hwnd_message_parent();
411 else parent
= get_full_window_handle( parent
);
413 if (!is_window( parent
))
415 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
419 /* Some applications try to set a child as a parent */
420 if (is_child( hwnd
, parent
))
422 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
426 if (!(full_handle
= is_current_thread_window( hwnd
)))
427 return UlongToHandle( send_message( hwnd
, WM_WINE_SETPARENT
, (WPARAM
)parent
, 0 ));
429 if (full_handle
== parent
)
431 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
435 /* Windows hides the window first, then shows it again
436 * including the WM_SHOWWINDOW messages and all */
437 was_visible
= NtUserShowWindow( hwnd
, SW_HIDE
);
439 win
= get_win_ptr( hwnd
);
440 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return 0;
442 get_window_rects( hwnd
, COORDS_PARENT
, &window_rect
, NULL
, get_dpi_for_window(hwnd
) );
443 get_window_rects( hwnd
, COORDS_SCREEN
, &old_screen_rect
, NULL
, 0 );
445 SERVER_START_REQ( set_parent
)
447 req
->handle
= wine_server_user_handle( hwnd
);
448 req
->parent
= wine_server_user_handle( parent
);
449 if ((ret
= !wine_server_call_err( req
)))
451 old_parent
= wine_server_ptr_handle( reply
->old_parent
);
452 win
->parent
= parent
= wine_server_ptr_handle( reply
->full_parent
);
453 win
->dpi
= reply
->dpi
;
454 win
->dpi_awareness
= reply
->awareness
;
459 release_win_ptr( win
);
462 get_window_rects( hwnd
, COORDS_SCREEN
, &new_screen_rect
, NULL
, 0 );
463 context
= SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( hwnd
));
465 user_driver
->pSetParent( full_handle
, parent
, old_parent
);
468 winpos
.hwndInsertAfter
= HWND_TOP
;
469 winpos
.x
= window_rect
.left
;
470 winpos
.y
= window_rect
.top
;
473 winpos
.flags
= SWP_NOSIZE
;
475 set_window_pos( &winpos
, new_screen_rect
.left
- old_screen_rect
.left
,
476 new_screen_rect
.top
- old_screen_rect
.top
);
478 if (was_visible
) NtUserShowWindow( hwnd
, SW_SHOW
);
480 SetThreadDpiAwarenessContext( context
);
485 HWND
get_window_relative( HWND hwnd
, UINT rel
)
489 if (rel
== GW_OWNER
) /* this one may be available locally */
491 WND
*win
= get_win_ptr( hwnd
);
494 RtlSetLastWin32Error( ERROR_INVALID_HANDLE
);
497 if (win
== WND_DESKTOP
) return 0;
498 if (win
!= WND_OTHER_PROCESS
)
501 release_win_ptr( win
);
504 /* else fall through to server call */
507 SERVER_START_REQ( get_window_tree
)
509 req
->handle
= wine_server_user_handle( hwnd
);
510 if (!wine_server_call_err( req
))
515 retval
= wine_server_ptr_handle( reply
->first_sibling
);
518 retval
= wine_server_ptr_handle( reply
->last_sibling
);
521 retval
= wine_server_ptr_handle( reply
->next_sibling
);
524 retval
= wine_server_ptr_handle( reply
->prev_sibling
);
527 retval
= wine_server_ptr_handle( reply
->owner
);
530 retval
= wine_server_ptr_handle( reply
->first_child
);
539 /*******************************************************************
540 * list_window_parents
542 * Build an array of all parents of a given window, starting with
543 * the immediate parent. The array must be freed with free().
545 static HWND
*list_window_parents( HWND hwnd
)
549 int i
, pos
= 0, size
= 16, count
;
551 if (!(list
= malloc( size
* sizeof(HWND
) ))) return NULL
;
556 if (!(win
= get_win_ptr( current
))) goto empty
;
557 if (win
== WND_OTHER_PROCESS
) break; /* need to do it the hard way */
558 if (win
== WND_DESKTOP
)
560 if (!pos
) goto empty
;
564 list
[pos
] = current
= win
->parent
;
565 release_win_ptr( win
);
566 if (!current
) return list
;
567 if (++pos
== size
- 1)
569 /* need to grow the list */
570 HWND
*new_list
= realloc( list
, (size
+ 16) * sizeof(HWND
) );
571 if (!new_list
) goto empty
;
577 /* at least one parent belongs to another process, have to query the server */
582 SERVER_START_REQ( get_window_parents
)
584 req
->handle
= wine_server_user_handle( hwnd
);
585 wine_server_set_reply( req
, list
, (size
-1) * sizeof(user_handle_t
) );
586 if (!wine_server_call( req
)) count
= reply
->count
;
589 if (!count
) goto empty
;
592 /* start from the end since HWND is potentially larger than user_handle_t */
593 for (i
= count
- 1; i
>= 0; i
--)
594 list
[i
] = wine_server_ptr_handle( ((user_handle_t
*)list
)[i
] );
600 if (!(list
= malloc( size
* sizeof(HWND
) ))) return NULL
;
608 /*******************************************************************
609 * list_window_children
611 * Build an array of the children of a given window. The array must be
612 * freed with HeapFree. Returns NULL when no windows are found.
614 HWND
*list_window_children( HDESK desktop
, HWND hwnd
, UNICODE_STRING
*class, DWORD tid
)
618 ATOM atom
= class ? get_int_atom_value( class ) : 0;
620 /* empty class is not the same as NULL class */
621 if (!atom
&& class && !class->Length
) return NULL
;
627 if (!(list
= malloc( size
* sizeof(HWND
) ))) break;
629 SERVER_START_REQ( get_window_children
)
631 req
->desktop
= wine_server_obj_handle( desktop
);
632 req
->parent
= wine_server_user_handle( hwnd
);
635 if (!atom
&& class) wine_server_add_data( req
, class->Buffer
, class->Length
);
636 wine_server_set_reply( req
, list
, (size
-1) * sizeof(user_handle_t
) );
637 if (!wine_server_call( req
)) count
= reply
->count
;
640 if (count
&& count
< size
)
642 /* start from the end since HWND is potentially larger than user_handle_t */
643 for (i
= count
- 1; i
>= 0; i
--)
644 list
[i
] = wine_server_ptr_handle( ((user_handle_t
*)list
)[i
] );
650 size
= count
+ 1; /* restart with a large enough buffer */
655 /*****************************************************************
656 * NtUserGetAncestor (win32u.@)
658 HWND WINAPI
NtUserGetAncestor( HWND hwnd
, UINT type
)
666 if (!(win
= get_win_ptr( hwnd
)))
668 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
671 if (win
== WND_DESKTOP
) return 0;
672 if (win
!= WND_OTHER_PROCESS
)
675 release_win_ptr( win
);
677 else /* need to query the server */
679 SERVER_START_REQ( get_window_tree
)
681 req
->handle
= wine_server_user_handle( hwnd
);
682 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->parent
);
689 if (!(list
= list_window_parents( hwnd
))) return 0;
691 if (!list
[0] || !list
[1]) ret
= get_full_window_handle( hwnd
); /* top-level window */
695 while (list
[count
]) count
++;
696 ret
= list
[count
- 2]; /* get the one before the desktop */
702 if (is_desktop_window( hwnd
)) return 0;
703 ret
= get_full_window_handle( hwnd
);
706 HWND parent
= get_parent( ret
);
716 BOOL
is_child( HWND parent
, HWND child
)
722 if (!(get_window_long( child
, GWL_STYLE
) & WS_CHILD
)) return FALSE
;
723 if (!(list
= list_window_parents( child
))) return FALSE
;
724 parent
= get_full_window_handle( parent
);
725 for (i
= 0; list
[i
]; i
++)
727 if (list
[i
] == parent
)
729 ret
= list
[i
] && list
[i
+1];
732 if (!(get_window_long( list
[i
], GWL_STYLE
) & WS_CHILD
)) break;
738 /* see IsWindowVisible */
739 BOOL
is_window_visible( HWND hwnd
)
745 if (!(get_window_long( hwnd
, GWL_STYLE
) & WS_VISIBLE
)) return FALSE
;
746 if (!(list
= list_window_parents( hwnd
))) return TRUE
;
749 for (i
= 0; list
[i
+1]; i
++)
750 if (!(get_window_long( list
[i
], GWL_STYLE
) & WS_VISIBLE
)) break;
751 retval
= !list
[i
+1] && (list
[i
] == get_desktop_window()); /* top message window isn't visible */
757 /***********************************************************************
760 * hwnd is drawable when it is visible, all parents are not
761 * minimized, and it is itself not minimized unless we are
762 * trying to draw its default class icon.
764 BOOL
is_window_drawable( HWND hwnd
, BOOL icon
)
769 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
771 if (!(style
& WS_VISIBLE
)) return FALSE
;
772 if ((style
& WS_MINIMIZE
) && icon
&& get_class_long_ptr( hwnd
, GCLP_HICON
, FALSE
)) return FALSE
;
774 if (!(list
= list_window_parents( hwnd
))) return TRUE
;
777 for (i
= 0; list
[i
+1]; i
++)
778 if ((get_window_long( list
[i
], GWL_STYLE
) & (WS_VISIBLE
|WS_MINIMIZE
)) != WS_VISIBLE
)
780 retval
= !list
[i
+1] && (list
[i
] == get_desktop_window()); /* top message window isn't visible */
786 /* see IsWindowUnicode */
787 BOOL
is_window_unicode( HWND hwnd
)
792 if (!(win
= get_win_ptr(hwnd
))) return FALSE
;
794 if (win
== WND_DESKTOP
) return TRUE
;
796 if (win
!= WND_OTHER_PROCESS
)
798 ret
= (win
->flags
& WIN_ISUNICODE
) != 0;
799 release_win_ptr( win
);
803 SERVER_START_REQ( get_window_info
)
805 req
->handle
= wine_server_user_handle( hwnd
);
806 if (!wine_server_call_err( req
)) ret
= reply
->is_unicode
;
813 /* see EnableWindow */
814 BOOL
enable_window( HWND hwnd
, BOOL enable
)
818 if (is_broadcast(hwnd
))
820 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
824 TRACE( "( %p, %d )\n", hwnd
, enable
);
828 ret
= (set_window_style( hwnd
, 0, WS_DISABLED
) & WS_DISABLED
) != 0;
829 if (ret
) send_message( hwnd
, WM_ENABLE
, TRUE
, 0 );
833 send_message( hwnd
, WM_CANCELMODE
, 0, 0 );
835 ret
= (set_window_style( hwnd
, WS_DISABLED
, 0 ) & WS_DISABLED
) != 0;
838 if (hwnd
== get_focus())
839 NtUserSetFocus( 0 ); /* A disabled window can't have the focus */
841 send_message( hwnd
, WM_ENABLE
, FALSE
, 0 );
847 /* see IsWindowEnabled */
848 BOOL
is_window_enabled( HWND hwnd
)
852 RtlSetLastWin32Error( NO_ERROR
);
853 ret
= get_window_long( hwnd
, GWL_STYLE
);
854 if (!ret
&& RtlGetLastWin32Error() != NO_ERROR
) return FALSE
;
855 return !(ret
& WS_DISABLED
);
858 /* see GetWindowDpiAwarenessContext */
859 DPI_AWARENESS_CONTEXT
get_window_dpi_awareness_context( HWND hwnd
)
861 DPI_AWARENESS_CONTEXT ret
= 0;
864 if (!(win
= get_win_ptr( hwnd
)))
866 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
869 if (win
== WND_DESKTOP
) return DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
;
870 if (win
!= WND_OTHER_PROCESS
)
872 ret
= ULongToHandle( win
->dpi_awareness
| 0x10 );
873 release_win_ptr( win
);
877 SERVER_START_REQ( get_window_info
)
879 req
->handle
= wine_server_user_handle( hwnd
);
880 if (!wine_server_call_err( req
)) ret
= ULongToHandle( reply
->awareness
| 0x10 );
887 /* see GetDpiForWindow */
888 UINT
get_dpi_for_window( HWND hwnd
)
893 if (!(win
= get_win_ptr( hwnd
)))
895 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
898 if (win
== WND_DESKTOP
)
901 return get_monitor_dpi( monitor_from_point( pt
, MONITOR_DEFAULTTOPRIMARY
, 0 ));
903 if (win
!= WND_OTHER_PROCESS
)
906 if (!ret
) ret
= get_win_monitor_dpi( hwnd
);
907 release_win_ptr( win
);
911 SERVER_START_REQ( get_window_info
)
913 req
->handle
= wine_server_user_handle( hwnd
);
914 if (!wine_server_call_err( req
)) ret
= reply
->dpi
;
921 static LONG_PTR
get_win_data( const void *ptr
, UINT size
)
923 if (size
== sizeof(WORD
))
926 memcpy( &ret
, ptr
, sizeof(ret
) );
929 else if (size
== sizeof(DWORD
))
932 memcpy( &ret
, ptr
, sizeof(ret
) );
938 memcpy( &ret
, ptr
, sizeof(ret
) );
943 /* helper for set_window_long */
944 static inline void set_win_data( void *ptr
, LONG_PTR val
, UINT size
)
946 if (size
== sizeof(WORD
))
949 memcpy( ptr
, &newval
, sizeof(newval
) );
951 else if (size
== sizeof(DWORD
))
954 memcpy( ptr
, &newval
, sizeof(newval
) );
958 memcpy( ptr
, &val
, sizeof(val
) );
962 BOOL
is_iconic( HWND hwnd
)
964 return (get_window_long( hwnd
, GWL_STYLE
) & WS_MINIMIZE
) != 0;
967 BOOL
is_zoomed( HWND hwnd
)
969 return (get_window_long( hwnd
, GWL_STYLE
) & WS_MAXIMIZE
) != 0;
972 static LONG_PTR
get_window_long_size( HWND hwnd
, INT offset
, UINT size
, BOOL ansi
)
977 if (offset
== GWLP_HWNDPARENT
)
979 HWND parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
980 if (parent
== get_desktop_window())
981 parent
= get_window_relative( hwnd
, GW_OWNER
);
982 return (ULONG_PTR
)parent
;
985 if (!(win
= get_win_ptr( hwnd
)))
987 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
991 if (win
== WND_DESKTOP
)
996 retval
= WS_POPUP
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
; /* message parent is not visible */
997 if (get_full_window_handle( hwnd
) == get_desktop_window())
998 retval
|= WS_VISIBLE
;
1003 case GWLP_HINSTANCE
:
1006 RtlSetLastWin32Error( ERROR_ACCESS_DENIED
);
1009 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
1013 if (win
== WND_OTHER_PROCESS
)
1015 if (offset
== GWLP_WNDPROC
)
1017 RtlSetLastWin32Error( ERROR_ACCESS_DENIED
);
1020 SERVER_START_REQ( set_window_info
)
1022 req
->handle
= wine_server_user_handle( hwnd
);
1023 req
->flags
= 0; /* don't set anything, just retrieve */
1024 req
->extra_offset
= (offset
>= 0) ? offset
: -1;
1025 req
->extra_size
= (offset
>= 0) ? size
: 0;
1026 if (!wine_server_call_err( req
))
1030 case GWL_STYLE
: retval
= reply
->old_style
; break;
1031 case GWL_EXSTYLE
: retval
= reply
->old_ex_style
; break;
1032 case GWLP_ID
: retval
= reply
->old_id
; break;
1033 case GWLP_HINSTANCE
: retval
= (ULONG_PTR
)wine_server_get_ptr( reply
->old_instance
); break;
1034 case GWLP_USERDATA
: retval
= reply
->old_user_data
; break;
1036 if (offset
>= 0) retval
= get_win_data( &reply
->old_extra_value
, size
);
1037 else RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
1046 /* now we have a valid win */
1050 if (offset
> (int)(win
->cbWndExtra
- size
))
1052 WARN("Invalid offset %d\n", offset
);
1053 release_win_ptr( win
);
1054 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
1057 retval
= get_win_data( (char *)win
->wExtra
+ offset
, size
);
1058 release_win_ptr( win
);
1064 case GWLP_USERDATA
: retval
= win
->userdata
; break;
1065 case GWL_STYLE
: retval
= win
->dwStyle
; break;
1066 case GWL_EXSTYLE
: retval
= win
->dwExStyle
; break;
1067 case GWLP_ID
: retval
= win
->wIDmenu
; break;
1068 case GWLP_HINSTANCE
: retval
= (ULONG_PTR
)win
->hInstance
; break;
1070 /* This looks like a hack only for the edit control (see tests). This makes these controls
1071 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
1072 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
1074 if (win
->winproc
== BUILTIN_WINPROC(WINPROC_EDIT
) && (!!ansi
!= !(win
->flags
& WIN_ISUNICODE
)))
1075 retval
= (ULONG_PTR
)win
->winproc
;
1077 retval
= (ULONG_PTR
)get_winproc( win
->winproc
, ansi
);
1080 WARN("Unknown offset %d\n", offset
);
1081 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
1084 release_win_ptr( win
);
1088 /* see GetWindowLongW */
1089 DWORD
get_window_long( HWND hwnd
, INT offset
)
1091 return get_window_long_size( hwnd
, offset
, sizeof(LONG
), FALSE
);
1094 /* see GetWindowLongPtr */
1095 ULONG_PTR
get_window_long_ptr( HWND hwnd
, INT offset
, BOOL ansi
)
1097 return get_window_long_size( hwnd
, offset
, sizeof(LONG_PTR
), ansi
);
1100 /* see GetWindowWord */
1101 static WORD
get_window_word( HWND hwnd
, INT offset
)
1103 if (offset
< 0 && offset
!= GWLP_USERDATA
)
1105 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
1108 return get_window_long_size( hwnd
, offset
, sizeof(WORD
), TRUE
);
1111 /***********************************************************************
1114 * Change the style of a window.
1116 ULONG
set_window_style( HWND hwnd
, ULONG set_bits
, ULONG clear_bits
)
1118 BOOL ok
, made_visible
= FALSE
;
1120 WND
*win
= get_win_ptr( hwnd
);
1122 if (!win
|| win
== WND_DESKTOP
) return 0;
1123 if (win
== WND_OTHER_PROCESS
)
1125 if (is_window(hwnd
))
1126 return send_message( hwnd
, WM_WINE_SETSTYLE
, set_bits
, clear_bits
);
1129 style
.styleOld
= win
->dwStyle
;
1130 style
.styleNew
= (win
->dwStyle
| set_bits
) & ~clear_bits
;
1131 if (style
.styleNew
== style
.styleOld
)
1133 release_win_ptr( win
);
1134 return style
.styleNew
;
1136 SERVER_START_REQ( set_window_info
)
1138 req
->handle
= wine_server_user_handle( hwnd
);
1139 req
->flags
= SET_WIN_STYLE
;
1140 req
->style
= style
.styleNew
;
1141 req
->extra_offset
= -1;
1142 if ((ok
= !wine_server_call( req
)))
1144 style
.styleOld
= reply
->old_style
;
1145 win
->dwStyle
= style
.styleNew
;
1150 if (ok
&& ((style
.styleOld
^ style
.styleNew
) & WS_VISIBLE
))
1152 made_visible
= (style
.styleNew
& WS_VISIBLE
) != 0;
1153 invalidate_dce( win
, NULL
);
1155 release_win_ptr( win
);
1159 user_driver
->pSetWindowStyle( hwnd
, GWL_STYLE
, &style
);
1160 if (made_visible
) update_window_state( hwnd
);
1162 return style
.styleOld
;
1165 static DWORD
fix_exstyle( DWORD style
, DWORD exstyle
)
1167 if ((exstyle
& WS_EX_DLGMODALFRAME
) ||
1168 (!(exstyle
& WS_EX_STATICEDGE
) && (style
& (WS_DLGFRAME
| WS_THICKFRAME
))))
1169 exstyle
|= WS_EX_WINDOWEDGE
;
1171 exstyle
&= ~WS_EX_WINDOWEDGE
;
1175 /* Change the owner of a window. */
1176 static HWND
set_window_owner( HWND hwnd
, HWND owner
)
1178 WND
*win
= get_win_ptr( hwnd
);
1181 if (!win
|| win
== WND_DESKTOP
) return 0;
1182 if (win
== WND_OTHER_PROCESS
)
1184 if (is_window(hwnd
)) ERR( "cannot set owner %p on other process window %p\n", owner
, hwnd
);
1187 SERVER_START_REQ( set_window_owner
)
1189 req
->handle
= wine_server_user_handle( hwnd
);
1190 req
->owner
= wine_server_user_handle( owner
);
1191 if (!wine_server_call( req
))
1193 win
->owner
= wine_server_ptr_handle( reply
->full_owner
);
1194 ret
= wine_server_ptr_handle( reply
->prev_owner
);
1198 release_win_ptr( win
);
1202 /* Helper function for SetWindowLong(). */
1203 LONG_PTR
set_window_long( HWND hwnd
, INT offset
, UINT size
, LONG_PTR newval
, BOOL ansi
)
1205 BOOL ok
, made_visible
= FALSE
;
1206 LONG_PTR retval
= 0;
1210 TRACE( "%p %d %lx %c\n", hwnd
, offset
, newval
, ansi
? 'A' : 'W' );
1212 if (is_broadcast(hwnd
))
1214 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
1218 if (!(win
= get_win_ptr( hwnd
)))
1220 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
1223 if (win
== WND_DESKTOP
)
1225 /* can't change anything on the desktop window */
1226 RtlSetLastWin32Error( ERROR_ACCESS_DENIED
);
1229 if (win
== WND_OTHER_PROCESS
)
1231 if (offset
== GWLP_WNDPROC
)
1233 RtlSetLastWin32Error( ERROR_ACCESS_DENIED
);
1236 if (offset
> 32767 || offset
< -32767)
1238 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
1241 return send_message( hwnd
, WM_WINE_SETWINDOWLONG
, MAKEWPARAM( offset
, size
), newval
);
1244 /* first some special cases */
1248 style
.styleOld
= win
->dwStyle
;
1249 style
.styleNew
= newval
;
1250 release_win_ptr( win
);
1251 send_message( hwnd
, WM_STYLECHANGING
, GWL_STYLE
, (LPARAM
)&style
);
1252 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
) return 0;
1253 newval
= style
.styleNew
;
1254 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
1255 if (win
->parent
== get_desktop_window()) newval
|= WS_CLIPSIBLINGS
;
1256 /* WS_MINIMIZE can't be reset */
1257 if (win
->dwStyle
& WS_MINIMIZE
) newval
|= WS_MINIMIZE
;
1260 style
.styleOld
= win
->dwExStyle
;
1261 style
.styleNew
= newval
;
1262 release_win_ptr( win
);
1263 send_message( hwnd
, WM_STYLECHANGING
, GWL_EXSTYLE
, (LPARAM
)&style
);
1264 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
) return 0;
1265 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
1266 newval
= (style
.styleNew
& ~WS_EX_TOPMOST
) | (win
->dwExStyle
& WS_EX_TOPMOST
);
1267 newval
= fix_exstyle(win
->dwStyle
, newval
);
1269 case GWLP_HWNDPARENT
:
1270 if (win
->parent
== get_desktop_window())
1272 release_win_ptr( win
);
1273 return (ULONG_PTR
)set_window_owner( hwnd
, (HWND
)newval
);
1277 release_win_ptr( win
);
1278 return (ULONG_PTR
)NtUserSetParent( hwnd
, (HWND
)newval
);
1283 UINT old_flags
= win
->flags
;
1284 retval
= get_window_long_ptr( hwnd
, offset
, ansi
);
1285 proc
= alloc_winproc( (WNDPROC
)newval
, ansi
);
1286 if (proc
) win
->winproc
= proc
;
1287 if (is_winproc_unicode( proc
, !ansi
)) win
->flags
|= WIN_ISUNICODE
;
1288 else win
->flags
&= ~WIN_ISUNICODE
;
1289 if (!((old_flags
^ win
->flags
) & WIN_ISUNICODE
))
1291 release_win_ptr( win
);
1294 /* update is_unicode flag on the server side */
1298 case GWLP_HINSTANCE
:
1302 if (offset
< 0 || offset
> (int)(win
->cbWndExtra
- size
))
1304 WARN("Invalid offset %d\n", offset
);
1305 release_win_ptr( win
);
1306 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
1309 else if (get_win_data( (char *)win
->wExtra
+ offset
, size
) == newval
)
1311 /* already set to the same value */
1312 release_win_ptr( win
);
1318 SERVER_START_REQ( set_window_info
)
1320 req
->handle
= wine_server_user_handle( hwnd
);
1321 req
->extra_offset
= -1;
1325 req
->flags
= SET_WIN_STYLE
| SET_WIN_EXSTYLE
;
1326 req
->style
= newval
;
1327 req
->ex_style
= fix_exstyle(newval
, win
->dwExStyle
);
1330 req
->flags
= SET_WIN_EXSTYLE
;
1331 req
->ex_style
= newval
;
1334 req
->flags
= SET_WIN_ID
;
1335 req
->extra_value
= newval
;
1337 case GWLP_HINSTANCE
:
1338 req
->flags
= SET_WIN_INSTANCE
;
1339 req
->instance
= wine_server_client_ptr( (void *)newval
);
1342 req
->flags
= SET_WIN_UNICODE
;
1343 req
->is_unicode
= (win
->flags
& WIN_ISUNICODE
) != 0;
1346 if (size
== sizeof(WORD
)) newval
= MAKELONG( newval
, win
->userdata
>> 16 );
1347 req
->flags
= SET_WIN_USERDATA
;
1348 req
->user_data
= newval
;
1351 req
->flags
= SET_WIN_EXTRA
;
1352 req
->extra_offset
= offset
;
1353 req
->extra_size
= size
;
1354 set_win_data( &req
->extra_value
, newval
, size
);
1356 if ((ok
= !wine_server_call_err( req
)))
1361 win
->dwStyle
= newval
;
1362 win
->dwExStyle
= fix_exstyle(win
->dwStyle
, win
->dwExStyle
);
1363 retval
= reply
->old_style
;
1366 win
->dwExStyle
= newval
;
1367 retval
= reply
->old_ex_style
;
1370 win
->wIDmenu
= newval
;
1371 retval
= reply
->old_id
;
1373 case GWLP_HINSTANCE
:
1374 win
->hInstance
= (HINSTANCE
)newval
;
1375 retval
= (ULONG_PTR
)wine_server_get_ptr( reply
->old_instance
);
1380 win
->userdata
= newval
;
1381 retval
= reply
->old_user_data
;
1384 retval
= get_win_data( (char *)win
->wExtra
+ offset
, size
);
1385 set_win_data( (char *)win
->wExtra
+ offset
, newval
, size
);
1392 if ((offset
== GWL_STYLE
&& ((style
.styleOld
^ style
.styleNew
) & WS_VISIBLE
)) ||
1393 (offset
== GWL_EXSTYLE
&& ((style
.styleOld
^ style
.styleNew
) & WS_EX_LAYERED
)))
1395 made_visible
= (win
->dwStyle
& WS_VISIBLE
) != 0;
1396 invalidate_dce( win
, NULL
);
1398 release_win_ptr( win
);
1402 if (offset
== GWL_STYLE
|| offset
== GWL_EXSTYLE
)
1404 style
.styleOld
= retval
;
1405 style
.styleNew
= newval
;
1406 user_driver
->pSetWindowStyle( hwnd
, offset
, &style
);
1407 if (made_visible
) update_window_state( hwnd
);
1408 send_message( hwnd
, WM_STYLECHANGED
, offset
, (LPARAM
)&style
);
1414 /**********************************************************************
1415 * NtUserSetWindowWord (win32u.@)
1417 WORD WINAPI
NtUserSetWindowWord( HWND hwnd
, INT offset
, WORD newval
)
1419 if (offset
< 0 && offset
!= GWLP_USERDATA
)
1421 RtlSetLastWin32Error( ERROR_INVALID_INDEX
);
1424 return set_window_long( hwnd
, offset
, sizeof(WORD
), newval
, TRUE
);
1427 /**********************************************************************
1428 * NtUserSetWindowLong (win32u.@)
1430 LONG WINAPI
NtUserSetWindowLong( HWND hwnd
, INT offset
, LONG newval
, BOOL ansi
)
1432 return set_window_long( hwnd
, offset
, sizeof(LONG
), newval
, ansi
);
1435 /*****************************************************************************
1436 * NtUserSetWindowLongPtr (win32u.@)
1438 LONG_PTR WINAPI
NtUserSetWindowLongPtr( HWND hwnd
, INT offset
, LONG_PTR newval
, BOOL ansi
)
1440 return set_window_long( hwnd
, offset
, sizeof(LONG_PTR
), newval
, ansi
);
1443 BOOL
win32u_set_window_pixel_format( HWND hwnd
, int format
, BOOL internal
)
1445 WND
*win
= get_win_ptr( hwnd
);
1447 if (!win
|| win
== WND_DESKTOP
|| win
== WND_OTHER_PROCESS
)
1449 WARN( "setting format %d on win %p not supported\n", format
, hwnd
);
1453 win
->internal_pixel_format
= format
;
1455 win
->pixel_format
= format
;
1456 release_win_ptr( win
);
1458 update_window_state( hwnd
);
1462 int win32u_get_window_pixel_format( HWND hwnd
)
1464 WND
*win
= get_win_ptr( hwnd
);
1467 if (!win
|| win
== WND_DESKTOP
|| win
== WND_OTHER_PROCESS
)
1469 WARN( "getting format on win %p not supported\n", hwnd
);
1473 ret
= win
->pixel_format
;
1474 release_win_ptr( win
);
1479 /***********************************************************************
1480 * NtUserGetProp (win32u.@)
1482 * NOTE Native allows only ATOMs as the second argument. We allow strings
1483 * to save extra server call in GetPropW.
1485 HANDLE WINAPI
NtUserGetProp( HWND hwnd
, const WCHAR
*str
)
1489 SERVER_START_REQ( get_window_property
)
1491 req
->window
= wine_server_user_handle( hwnd
);
1492 if (IS_INTRESOURCE(str
)) req
->atom
= LOWORD(str
);
1493 else wine_server_add_data( req
, str
, lstrlenW(str
) * sizeof(WCHAR
) );
1494 if (!wine_server_call_err( req
)) ret
= reply
->data
;
1500 /*****************************************************************************
1501 * NtUserSetProp (win32u.@)
1503 * NOTE Native allows only ATOMs as the second argument. We allow strings
1504 * to save extra server call in SetPropW.
1506 BOOL WINAPI
NtUserSetProp( HWND hwnd
, const WCHAR
*str
, HANDLE handle
)
1510 SERVER_START_REQ( set_window_property
)
1512 req
->window
= wine_server_user_handle( hwnd
);
1513 req
->data
= (ULONG_PTR
)handle
;
1514 if (IS_INTRESOURCE(str
)) req
->atom
= LOWORD(str
);
1515 else wine_server_add_data( req
, str
, lstrlenW(str
) * sizeof(WCHAR
) );
1516 ret
= !wine_server_call_err( req
);
1523 /***********************************************************************
1524 * NtUserRemoveProp (win32u.@)
1526 * NOTE Native allows only ATOMs as the second argument. We allow strings
1527 * to save extra server call in RemovePropW.
1529 HANDLE WINAPI
NtUserRemoveProp( HWND hwnd
, const WCHAR
*str
)
1533 SERVER_START_REQ( remove_window_property
)
1535 req
->window
= wine_server_user_handle( hwnd
);
1536 if (IS_INTRESOURCE(str
)) req
->atom
= LOWORD(str
);
1537 else wine_server_add_data( req
, str
, lstrlenW(str
) * sizeof(WCHAR
) );
1538 if (!wine_server_call_err( req
)) ret
= reply
->data
;
1545 static void mirror_rect( const RECT
*window_rect
, RECT
*rect
)
1547 int width
= window_rect
->right
- window_rect
->left
;
1548 int tmp
= rect
->left
;
1549 rect
->left
= width
- rect
->right
;
1550 rect
->right
= width
- tmp
;
1553 /***********************************************************************
1556 * Get the window and client rectangles.
1558 BOOL
get_window_rects( HWND hwnd
, enum coords_relative relative
, RECT
*window_rect
,
1559 RECT
*client_rect
, UINT dpi
)
1561 WND
*win
= get_win_ptr( hwnd
);
1566 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
1569 if (win
== WND_DESKTOP
)
1572 rect
.left
= rect
.top
= 0;
1573 if (hwnd
== get_hwnd_message_parent())
1577 rect
= map_dpi_rect( rect
, get_dpi_for_window( hwnd
), dpi
);
1581 rect
= get_primary_monitor_rect( dpi
);
1583 if (window_rect
) *window_rect
= rect
;
1584 if (client_rect
) *client_rect
= rect
;
1587 if (win
!= WND_OTHER_PROCESS
)
1589 UINT window_dpi
= get_dpi_for_window( hwnd
);
1590 RECT window
= win
->window_rect
;
1591 RECT client
= win
->client_rect
;
1596 OffsetRect( &window
, -win
->client_rect
.left
, -win
->client_rect
.top
);
1597 OffsetRect( &client
, -win
->client_rect
.left
, -win
->client_rect
.top
);
1598 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
)
1599 mirror_rect( &win
->client_rect
, &window
);
1602 OffsetRect( &window
, -win
->window_rect
.left
, -win
->window_rect
.top
);
1603 OffsetRect( &client
, -win
->window_rect
.left
, -win
->window_rect
.top
);
1604 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
)
1605 mirror_rect( &win
->window_rect
, &client
);
1610 WND
*parent
= get_win_ptr( win
->parent
);
1611 if (parent
== WND_DESKTOP
) break;
1612 if (!parent
|| parent
== WND_OTHER_PROCESS
)
1614 release_win_ptr( win
);
1617 if (parent
->flags
& WIN_CHILDREN_MOVED
)
1619 release_win_ptr( parent
);
1620 release_win_ptr( win
);
1623 if (parent
->dwExStyle
& WS_EX_LAYOUTRTL
)
1625 mirror_rect( &parent
->client_rect
, &window
);
1626 mirror_rect( &parent
->client_rect
, &client
);
1628 release_win_ptr( parent
);
1634 WND
*parent
= get_win_ptr( win
->parent
);
1635 if (parent
== WND_DESKTOP
) break;
1636 if (!parent
|| parent
== WND_OTHER_PROCESS
)
1638 release_win_ptr( win
);
1641 release_win_ptr( win
);
1642 if (parent
->flags
& WIN_CHILDREN_MOVED
)
1644 release_win_ptr( parent
);
1650 OffsetRect( &window
, win
->client_rect
.left
, win
->client_rect
.top
);
1651 OffsetRect( &client
, win
->client_rect
.left
, win
->client_rect
.top
);
1656 if (window_rect
) *window_rect
= map_dpi_rect( window
, window_dpi
, dpi
);
1657 if (client_rect
) *client_rect
= map_dpi_rect( client
, window_dpi
, dpi
);
1658 release_win_ptr( win
);
1663 SERVER_START_REQ( get_window_rectangles
)
1665 req
->handle
= wine_server_user_handle( hwnd
);
1666 req
->relative
= relative
;
1668 if ((ret
= !wine_server_call_err( req
)))
1672 window_rect
->left
= reply
->window
.left
;
1673 window_rect
->top
= reply
->window
.top
;
1674 window_rect
->right
= reply
->window
.right
;
1675 window_rect
->bottom
= reply
->window
.bottom
;
1679 client_rect
->left
= reply
->client
.left
;
1680 client_rect
->top
= reply
->client
.top
;
1681 client_rect
->right
= reply
->client
.right
;
1682 client_rect
->bottom
= reply
->client
.bottom
;
1690 /* see GetWindowRect */
1691 BOOL
get_window_rect( HWND hwnd
, RECT
*rect
, UINT dpi
)
1693 return get_window_rects( hwnd
, COORDS_SCREEN
, rect
, NULL
, dpi
);
1696 /* see GetClientRect */
1697 BOOL
get_client_rect( HWND hwnd
, RECT
*rect
)
1699 return get_window_rects( hwnd
, COORDS_CLIENT
, NULL
, rect
, get_thread_dpi() );
1702 /* see GetWindowInfo */
1703 static BOOL
get_window_info( HWND hwnd
, WINDOWINFO
*info
)
1706 if (!info
|| !get_window_rects( hwnd
, COORDS_SCREEN
, &info
->rcWindow
,
1707 &info
->rcClient
, get_thread_dpi() ))
1710 info
->dwStyle
= get_window_long( hwnd
, GWL_STYLE
);
1711 info
->dwExStyle
= get_window_long( hwnd
, GWL_EXSTYLE
);
1712 info
->dwWindowStatus
= get_active_window() == hwnd
? WS_ACTIVECAPTION
: 0;
1713 info
->cxWindowBorders
= info
->rcClient
.left
- info
->rcWindow
.left
;
1714 info
->cyWindowBorders
= info
->rcWindow
.bottom
- info
->rcClient
.bottom
;
1715 info
->atomWindowType
= get_class_long( hwnd
, GCW_ATOM
, FALSE
);
1716 info
->wCreatorVersion
= 0x0400;
1720 /***********************************************************************
1721 * update_surface_region
1723 static void update_surface_region( HWND hwnd
)
1729 WND
*win
= get_win_ptr( hwnd
);
1731 if (!win
|| win
== WND_DESKTOP
|| win
== WND_OTHER_PROCESS
) return;
1732 if (!win
->surface
) goto done
;
1736 if (!(data
= malloc( FIELD_OFFSET( RGNDATA
, Buffer
[size
] )))) goto done
;
1738 SERVER_START_REQ( get_surface_region
)
1740 req
->window
= wine_server_user_handle( hwnd
);
1741 wine_server_set_reply( req
, data
->Buffer
, size
);
1742 if (!(status
= wine_server_call( req
)))
1744 size_t reply_size
= wine_server_reply_size( reply
);
1747 data
->rdh
.dwSize
= sizeof(data
->rdh
);
1748 data
->rdh
.iType
= RDH_RECTANGLES
;
1749 data
->rdh
.nCount
= reply_size
/ sizeof(RECT
);
1750 data
->rdh
.nRgnSize
= reply_size
;
1751 region
= NtGdiExtCreateRegion( NULL
, data
->rdh
.dwSize
+ data
->rdh
.nRgnSize
, data
);
1752 NtGdiOffsetRgn( region
, -reply
->visible_rect
.left
, -reply
->visible_rect
.top
);
1755 else size
= reply
->total_size
;
1759 } while (status
== STATUS_BUFFER_OVERFLOW
);
1761 if (status
) goto done
;
1763 win
->surface
->funcs
->set_region( win
->surface
, region
);
1764 if (region
) NtGdiDeleteObjectApp( region
);
1767 release_win_ptr( win
);
1770 /***********************************************************************
1773 * Backend implementation of SetWindowPos.
1775 static BOOL
apply_window_pos( HWND hwnd
, HWND insert_after
, UINT swp_flags
,
1776 const RECT
*window_rect
, const RECT
*client_rect
, const RECT
*valid_rects
)
1779 HWND surface_win
= 0, parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
1780 BOOL ret
, needs_update
= FALSE
;
1781 RECT visible_rect
, old_visible_rect
, old_window_rect
, old_client_rect
, extra_rects
[3];
1782 struct window_surface
*old_surface
, *new_surface
= NULL
;
1784 if (!parent
|| parent
== get_desktop_window())
1786 new_surface
= &dummy_surface
; /* provide a default surface for top-level windows */
1787 window_surface_add_ref( new_surface
);
1789 visible_rect
= *window_rect
;
1790 if (!(ret
= user_driver
->pWindowPosChanging( hwnd
, insert_after
, swp_flags
,
1791 window_rect
, client_rect
, &visible_rect
, &new_surface
)))
1793 if (IsRectEmpty( window_rect
)) visible_rect
= *window_rect
;
1796 visible_rect
= get_virtual_screen_rect( get_thread_dpi() );
1797 intersect_rect( &visible_rect
, &visible_rect
, window_rect
);
1801 get_window_rects( hwnd
, COORDS_SCREEN
, &old_window_rect
, NULL
, get_thread_dpi() );
1802 if (IsRectEmpty( &valid_rects
[0] )) valid_rects
= NULL
;
1804 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_DESKTOP
|| win
== WND_OTHER_PROCESS
)
1806 if (new_surface
) window_surface_release( new_surface
);
1810 /* create or update window surface for top-level windows if the driver doesn't implement WindowPosChanging */
1811 if (!ret
&& new_surface
&& !IsRectEmpty( &visible_rect
) &&
1812 (!(get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_LAYERED
) ||
1813 NtUserGetLayeredWindowAttributes( hwnd
, NULL
, NULL
, NULL
)))
1815 window_surface_release( new_surface
);
1816 if ((new_surface
= win
->surface
)) window_surface_add_ref( new_surface
);
1817 create_offscreen_window_surface( &visible_rect
, &new_surface
);
1820 old_visible_rect
= win
->visible_rect
;
1821 old_client_rect
= win
->client_rect
;
1822 old_surface
= win
->surface
;
1823 if (old_surface
!= new_surface
) swp_flags
|= SWP_FRAMECHANGED
; /* force refreshing non-client area */
1824 if (new_surface
== &dummy_surface
) swp_flags
|= SWP_NOREDRAW
;
1825 else if (old_surface
== &dummy_surface
)
1827 swp_flags
|= SWP_NOCOPYBITS
;
1831 SERVER_START_REQ( set_window_pos
)
1833 req
->handle
= wine_server_user_handle( hwnd
);
1834 req
->previous
= wine_server_user_handle( insert_after
);
1835 req
->swp_flags
= swp_flags
;
1836 req
->window
.left
= window_rect
->left
;
1837 req
->window
.top
= window_rect
->top
;
1838 req
->window
.right
= window_rect
->right
;
1839 req
->window
.bottom
= window_rect
->bottom
;
1840 req
->client
.left
= client_rect
->left
;
1841 req
->client
.top
= client_rect
->top
;
1842 req
->client
.right
= client_rect
->right
;
1843 req
->client
.bottom
= client_rect
->bottom
;
1844 if (!EqualRect( window_rect
, &visible_rect
) || new_surface
|| valid_rects
)
1846 extra_rects
[0] = extra_rects
[1] = visible_rect
;
1849 extra_rects
[1] = new_surface
->rect
;
1850 OffsetRect( &extra_rects
[1], visible_rect
.left
, visible_rect
.top
);
1852 if (valid_rects
) extra_rects
[2] = valid_rects
[0];
1853 else SetRectEmpty( &extra_rects
[2] );
1854 wine_server_add_data( req
, extra_rects
, sizeof(extra_rects
) );
1856 if (new_surface
) req
->paint_flags
|= SET_WINPOS_PAINT_SURFACE
;
1857 if (win
->pixel_format
|| win
->internal_pixel_format
)
1858 req
->paint_flags
|= SET_WINPOS_PIXEL_FORMAT
;
1860 if ((ret
= !wine_server_call( req
)))
1862 win
->dwStyle
= reply
->new_style
;
1863 win
->dwExStyle
= reply
->new_ex_style
;
1864 win
->window_rect
= *window_rect
;
1865 win
->client_rect
= *client_rect
;
1866 win
->visible_rect
= visible_rect
;
1867 win
->surface
= new_surface
;
1868 surface_win
= wine_server_ptr_handle( reply
->surface_win
);
1869 needs_update
= reply
->needs_update
;
1870 if (get_window_long( win
->parent
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
)
1873 get_window_rects( win
->parent
, COORDS_CLIENT
, NULL
, &client
, get_thread_dpi() );
1874 mirror_rect( &client
, &win
->window_rect
);
1875 mirror_rect( &client
, &win
->client_rect
);
1876 mirror_rect( &client
, &win
->visible_rect
);
1878 /* if an RTL window is resized the children have moved */
1879 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
&&
1880 client_rect
->right
- client_rect
->left
!= old_client_rect
.right
- old_client_rect
.left
)
1881 win
->flags
|= WIN_CHILDREN_MOVED
;
1888 if (needs_update
) update_surface_region( surface_win
);
1889 if (((swp_flags
& SWP_AGG_NOPOSCHANGE
) != SWP_AGG_NOPOSCHANGE
) ||
1890 (swp_flags
& (SWP_HIDEWINDOW
| SWP_SHOWWINDOW
| SWP_STATECHANGED
| SWP_FRAMECHANGED
)))
1891 invalidate_dce( win
, &old_window_rect
);
1894 release_win_ptr( win
);
1898 TRACE( "win %p surface %p -> %p\n", hwnd
, old_surface
, new_surface
);
1899 register_window_surface( old_surface
, new_surface
);
1904 move_window_bits( hwnd
, old_surface
, new_surface
, &visible_rect
,
1905 &old_visible_rect
, window_rect
, valid_rects
);
1906 valid_rects
= NULL
; /* prevent the driver from trying to also move the bits */
1908 window_surface_release( old_surface
);
1910 else if (surface_win
&& surface_win
!= hwnd
)
1915 int x_offset
= old_visible_rect
.left
- visible_rect
.left
;
1916 int y_offset
= old_visible_rect
.top
- visible_rect
.top
;
1918 /* if all that happened is that the whole window moved, copy everything */
1919 if (!(swp_flags
& SWP_FRAMECHANGED
) &&
1920 old_visible_rect
.right
- visible_rect
.right
== x_offset
&&
1921 old_visible_rect
.bottom
- visible_rect
.bottom
== y_offset
&&
1922 old_client_rect
.left
- client_rect
->left
== x_offset
&&
1923 old_client_rect
.right
- client_rect
->right
== x_offset
&&
1924 old_client_rect
.top
- client_rect
->top
== y_offset
&&
1925 old_client_rect
.bottom
- client_rect
->bottom
== y_offset
&&
1926 EqualRect( &valid_rects
[0], client_rect
))
1928 rects
[0] = visible_rect
;
1929 rects
[1] = old_visible_rect
;
1930 valid_rects
= rects
;
1932 move_window_bits_parent( hwnd
, surface_win
, window_rect
, valid_rects
);
1933 valid_rects
= NULL
; /* prevent the driver from trying to also move the bits */
1937 user_driver
->pWindowPosChanged( hwnd
, insert_after
, swp_flags
, window_rect
,
1938 client_rect
, &visible_rect
, valid_rects
, new_surface
);
1940 else if (new_surface
) window_surface_release( new_surface
);
1945 /*******************************************************************
1946 * NtUserGetWindowRgnEx (win32u.@)
1948 int WINAPI
NtUserGetWindowRgnEx( HWND hwnd
, HRGN hrgn
, UINT unk
)
1958 if (!(data
= malloc( sizeof(*data
) + size
- 1 )))
1960 RtlSetLastWin32Error( ERROR_OUTOFMEMORY
);
1963 SERVER_START_REQ( get_window_region
)
1965 req
->window
= wine_server_user_handle( hwnd
);
1966 wine_server_set_reply( req
, data
->Buffer
, size
);
1967 if (!(status
= wine_server_call( req
)))
1969 size_t reply_size
= wine_server_reply_size( reply
);
1972 data
->rdh
.dwSize
= sizeof(data
->rdh
);
1973 data
->rdh
.iType
= RDH_RECTANGLES
;
1974 data
->rdh
.nCount
= reply_size
/ sizeof(RECT
);
1975 data
->rdh
.nRgnSize
= reply_size
;
1976 win_rgn
= NtGdiExtCreateRegion( NULL
, data
->rdh
.dwSize
+ data
->rdh
.nRgnSize
, data
);
1979 else size
= reply
->total_size
;
1983 } while (status
== STATUS_BUFFER_OVERFLOW
);
1985 if (set_ntstatus( status
) && win_rgn
)
1987 ret
= NtGdiCombineRgn( hrgn
, win_rgn
, 0, RGN_COPY
);
1988 NtGdiDeleteObjectApp( win_rgn
);
1993 /***********************************************************************
1994 * NtUserSetWindowRgn (win32u.@)
1996 int WINAPI
NtUserSetWindowRgn( HWND hwnd
, HRGN hrgn
, BOOL redraw
)
1998 static const RECT empty_rect
;
2006 if (!(size
= NtGdiGetRegionData( hrgn
, 0, NULL
))) return FALSE
;
2007 if (!(data
= malloc( size
))) return FALSE
;
2008 if (!NtGdiGetRegionData( hrgn
, size
, data
))
2013 SERVER_START_REQ( set_window_region
)
2015 req
->window
= wine_server_user_handle( hwnd
);
2016 req
->redraw
= redraw
!= 0;
2017 if (data
->rdh
.nCount
)
2018 wine_server_add_data( req
, data
->Buffer
, data
->rdh
.nCount
* sizeof(RECT
) );
2020 wine_server_add_data( req
, &empty_rect
, sizeof(empty_rect
) );
2021 ret
= !wine_server_call_err( req
);
2026 else /* clear existing region */
2028 SERVER_START_REQ( set_window_region
)
2030 req
->window
= wine_server_user_handle( hwnd
);
2031 req
->redraw
= redraw
!= 0;
2032 ret
= !wine_server_call_err( req
);
2039 UINT swp_flags
= SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_FRAMECHANGED
|
2040 SWP_NOCLIENTSIZE
| SWP_NOCLIENTMOVE
;
2041 if (!redraw
) swp_flags
|= SWP_NOREDRAW
;
2042 user_driver
->pSetWindowRgn( hwnd
, hrgn
, redraw
);
2043 NtUserSetWindowPos( hwnd
, 0, 0, 0, 0, 0, swp_flags
);
2044 if (hrgn
) NtGdiDeleteObjectApp( hrgn
);
2049 /***********************************************************************
2050 * NtUserMoveWindow (win32u.@)
2052 BOOL WINAPI
NtUserMoveWindow( HWND hwnd
, INT x
, INT y
, INT cx
, INT cy
, BOOL repaint
)
2054 int flags
= SWP_NOZORDER
| SWP_NOACTIVATE
;
2055 if (!repaint
) flags
|= SWP_NOREDRAW
;
2056 TRACE( "%p %d,%d %dx%d %d\n", hwnd
, x
, y
, cx
, cy
, repaint
);
2057 return NtUserSetWindowPos( hwnd
, 0, x
, y
, cx
, cy
, flags
);
2060 /*****************************************************************************
2061 * NtUserGetLayeredWindowAttributes (win32u.@)
2063 BOOL WINAPI
NtUserGetLayeredWindowAttributes( HWND hwnd
, COLORREF
*key
, BYTE
*alpha
, DWORD
*flags
)
2067 SERVER_START_REQ( get_window_layered_info
)
2069 req
->handle
= wine_server_user_handle( hwnd
);
2070 if ((ret
= !wine_server_call_err( req
)))
2072 if (key
) *key
= reply
->color_key
;
2073 if (alpha
) *alpha
= reply
->alpha
;
2074 if (flags
) *flags
= reply
->flags
;
2082 /*****************************************************************************
2083 * NtUserSetLayeredWindowAttributes (win32u.@)
2085 BOOL WINAPI
NtUserSetLayeredWindowAttributes( HWND hwnd
, COLORREF key
, BYTE alpha
, DWORD flags
)
2089 TRACE( "(%p,%s,%d,%x)\n", hwnd
, debugstr_color(key
), alpha
, (int)flags
);
2091 SERVER_START_REQ( set_window_layered_info
)
2093 req
->handle
= wine_server_user_handle( hwnd
);
2094 req
->color_key
= key
;
2097 ret
= !wine_server_call_err( req
);
2103 user_driver
->pSetLayeredWindowAttributes( hwnd
, key
, alpha
, flags
);
2104 update_window_state( hwnd
);
2110 /*****************************************************************************
2111 * UpdateLayeredWindow (win32u.@)
2113 BOOL WINAPI
NtUserUpdateLayeredWindow( HWND hwnd
, HDC hdc_dst
, const POINT
*pts_dst
, const SIZE
*size
,
2114 HDC hdc_src
, const POINT
*pts_src
, COLORREF key
,
2115 const BLENDFUNCTION
*blend
, DWORD flags
, const RECT
*dirty
)
2117 DWORD swp_flags
= SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREDRAW
;
2118 RECT window_rect
, client_rect
;
2119 UPDATELAYEREDWINDOWINFO info
;
2122 if (flags
& ~(ULW_COLORKEY
| ULW_ALPHA
| ULW_OPAQUE
| ULW_EX_NORESIZE
) ||
2123 !(get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_LAYERED
) ||
2124 NtUserGetLayeredWindowAttributes( hwnd
, NULL
, NULL
, NULL
))
2126 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
2130 get_window_rects( hwnd
, COORDS_PARENT
, &window_rect
, &client_rect
, get_thread_dpi() );
2134 offset
.cx
= pts_dst
->x
- window_rect
.left
;
2135 offset
.cy
= pts_dst
->y
- window_rect
.top
;
2136 OffsetRect( &client_rect
, offset
.cx
, offset
.cy
);
2137 OffsetRect( &window_rect
, offset
.cx
, offset
.cy
);
2138 swp_flags
&= ~SWP_NOMOVE
;
2142 offset
.cx
= size
->cx
- (window_rect
.right
- window_rect
.left
);
2143 offset
.cy
= size
->cy
- (window_rect
.bottom
- window_rect
.top
);
2144 if (size
->cx
<= 0 || size
->cy
<= 0)
2146 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
2149 if ((flags
& ULW_EX_NORESIZE
) && (offset
.cx
|| offset
.cy
))
2151 RtlSetLastWin32Error( ERROR_INCORRECT_SIZE
);
2154 client_rect
.right
+= offset
.cx
;
2155 client_rect
.bottom
+= offset
.cy
;
2156 window_rect
.right
+= offset
.cx
;
2157 window_rect
.bottom
+= offset
.cy
;
2158 swp_flags
&= ~SWP_NOSIZE
;
2161 TRACE( "window %p win %s client %s\n", hwnd
,
2162 wine_dbgstr_rect(&window_rect
), wine_dbgstr_rect(&client_rect
) );
2164 apply_window_pos( hwnd
, 0, swp_flags
, &window_rect
, &client_rect
, NULL
);
2166 info
.cbSize
= sizeof(info
);
2167 info
.hdcDst
= hdc_dst
;
2168 info
.pptDst
= pts_dst
;
2170 info
.hdcSrc
= hdc_src
;
2171 info
.pptSrc
= pts_src
;
2173 info
.pblend
= blend
;
2174 info
.dwFlags
= flags
;
2175 info
.prcDirty
= dirty
;
2176 return user_driver
->pUpdateLayeredWindow( hwnd
, &info
, &window_rect
);
2179 /***********************************************************************
2180 * list_children_from_point
2182 * Get the list of children that can contain point from the server.
2183 * Point is in screen coordinates.
2184 * Returned list must be freed by caller.
2186 static HWND
*list_children_from_point( HWND hwnd
, POINT pt
)
2195 if (!(list
= malloc( size
* sizeof(HWND
) ))) break;
2197 SERVER_START_REQ( get_window_children_from_point
)
2199 req
->parent
= wine_server_user_handle( hwnd
);
2202 req
->dpi
= get_thread_dpi();
2203 wine_server_set_reply( req
, list
, (size
-1) * sizeof(user_handle_t
) );
2204 if (!wine_server_call( req
)) count
= reply
->count
;
2207 if (count
&& count
< size
)
2209 /* start from the end since HWND is potentially larger than user_handle_t */
2210 for (i
= count
- 1; i
>= 0; i
--)
2211 list
[i
] = wine_server_ptr_handle( ((user_handle_t
*)list
)[i
] );
2217 size
= count
+ 1; /* restart with a large enough buffer */
2222 /***********************************************************************
2225 * Find the window and hittest for a given point.
2227 HWND
window_from_point( HWND hwnd
, POINT pt
, INT
*hittest
)
2233 if (!hwnd
) hwnd
= get_desktop_window();
2235 *hittest
= HTNOWHERE
;
2237 if (!(list
= list_children_from_point( hwnd
, pt
))) return 0;
2239 /* now determine the hittest */
2241 for (i
= 0; list
[i
]; i
++)
2243 LONG style
= get_window_long( list
[i
], GWL_STYLE
);
2245 /* If window is minimized or disabled, return at once */
2246 if (style
& WS_DISABLED
)
2251 /* Send WM_NCCHITTEST (if same thread) */
2252 if (!is_current_thread_window( list
[i
] ))
2254 *hittest
= HTCLIENT
;
2257 win_pt
= map_dpi_point( pt
, get_thread_dpi(), get_dpi_for_window( list
[i
] ));
2258 res
= send_message( list
[i
], WM_NCHITTEST
, 0, MAKELPARAM( win_pt
.x
, win_pt
.y
));
2259 if (res
!= HTTRANSPARENT
)
2261 *hittest
= res
; /* Found the window */
2264 /* continue search with next window in z-order */
2268 TRACE( "scope %p (%d,%d) returning %p\n", hwnd
, (int)pt
.x
, (int)pt
.y
, ret
);
2272 /*******************************************************************
2273 * NtUserWindowFromPoint (win32u.@)
2275 HWND WINAPI
NtUserWindowFromPoint( LONG x
, LONG y
)
2277 POINT pt
= { .x
= x
, .y
= y
};
2279 return window_from_point( 0, pt
, &hittest
);
2282 /*******************************************************************
2283 * NtUserChildWindowFromPointEx (win32u.@)
2285 HWND WINAPI
NtUserChildWindowFromPointEx( HWND parent
, LONG x
, LONG y
, UINT flags
)
2287 POINT pt
= { .x
= x
, .y
= y
}; /* in the client coordinates */
2293 get_client_rect( parent
, &rect
);
2294 if (!PtInRect( &rect
, pt
)) return 0;
2295 if (!(list
= list_window_children( 0, parent
, NULL
, 0 ))) return parent
;
2297 for (i
= 0; list
[i
]; i
++)
2299 if (!get_window_rects( list
[i
], COORDS_PARENT
, &rect
, NULL
, get_thread_dpi() )) continue;
2300 if (!PtInRect( &rect
, pt
)) continue;
2301 if (flags
& (CWP_SKIPINVISIBLE
|CWP_SKIPDISABLED
))
2303 LONG style
= get_window_long( list
[i
], GWL_STYLE
);
2304 if ((flags
& CWP_SKIPINVISIBLE
) && !(style
& WS_VISIBLE
)) continue;
2305 if ((flags
& CWP_SKIPDISABLED
) && (style
& WS_DISABLED
)) continue;
2307 if (flags
& CWP_SKIPTRANSPARENT
)
2309 if (get_window_long( list
[i
], GWL_EXSTYLE
) & WS_EX_TRANSPARENT
) continue;
2315 if (!ret
) ret
= parent
;
2319 /*******************************************************************
2320 * NtUserRealChildWindowFromPoint (win32u.@)
2322 HWND WINAPI
NtUserRealChildWindowFromPoint( HWND parent
, LONG x
, LONG y
)
2324 return NtUserChildWindowFromPointEx( parent
, x
, y
, CWP_SKIPTRANSPARENT
| CWP_SKIPINVISIBLE
);
2327 /*******************************************************************
2330 * Get the work area that a maximized window can cover, depending on style.
2332 static BOOL
get_work_rect( HWND hwnd
, RECT
*rect
)
2334 HMONITOR monitor
= monitor_from_window( hwnd
, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
2335 MONITORINFO mon_info
;
2338 if (!monitor
) return FALSE
;
2340 mon_info
.cbSize
= sizeof(mon_info
);
2341 get_monitor_info( monitor
, &mon_info
);
2342 *rect
= mon_info
.rcMonitor
;
2344 style
= get_window_long( hwnd
, GWL_STYLE
);
2345 if (style
& WS_MAXIMIZEBOX
)
2347 if ((style
& WS_CAPTION
) == WS_CAPTION
|| !(style
& (WS_CHILD
| WS_POPUP
)))
2348 *rect
= mon_info
.rcWork
;
2353 static RECT
get_maximized_work_rect( HWND hwnd
)
2355 RECT work_rect
= { 0 };
2357 if ((get_window_long( hwnd
, GWL_STYLE
) & (WS_MINIMIZE
| WS_MAXIMIZE
)) == WS_MAXIMIZE
)
2359 if (!get_work_rect( hwnd
, &work_rect
))
2360 work_rect
= get_primary_monitor_rect( get_thread_dpi() );
2365 /*******************************************************************
2366 * update_maximized_pos
2368 * For top level windows covering the work area, we might have to
2369 * "forget" the maximized position. Windows presumably does this
2370 * to avoid situations where the border style changes, which would
2371 * lead the window to be outside the screen, or the window gets
2372 * reloaded on a different screen, and the "saved" position no
2373 * longer applies to it (despite being maximized).
2375 * Some applications (e.g. Imperiums: Greek Wars) depend on this.
2377 static void update_maximized_pos( WND
*wnd
, RECT
*work_rect
)
2379 if (wnd
->parent
&& wnd
->parent
!= get_desktop_window())
2382 if (wnd
->dwStyle
& WS_MAXIMIZE
)
2384 if (wnd
->window_rect
.left
<= work_rect
->left
&& wnd
->window_rect
.top
<= work_rect
->top
&&
2385 wnd
->window_rect
.right
>= work_rect
->right
&& wnd
->window_rect
.bottom
>= work_rect
->bottom
)
2386 wnd
->max_pos
.x
= wnd
->max_pos
.y
= -1;
2389 wnd
->max_pos
.x
= wnd
->max_pos
.y
= -1;
2392 static BOOL
empty_point( POINT pt
)
2394 return pt
.x
== -1 && pt
.y
== -1;
2397 /***********************************************************************
2398 * NtUserGetWindowPlacement (win32u.@)
2400 BOOL WINAPI
NtUserGetWindowPlacement( HWND hwnd
, WINDOWPLACEMENT
*placement
)
2402 RECT work_rect
= get_maximized_work_rect( hwnd
);
2403 WND
*win
= get_win_ptr( hwnd
);
2406 if (!win
) return FALSE
;
2408 if (win
== WND_DESKTOP
)
2410 placement
->length
= sizeof(*placement
);
2411 placement
->showCmd
= SW_SHOWNORMAL
;
2412 placement
->flags
= 0;
2413 placement
->ptMinPosition
.x
= -1;
2414 placement
->ptMinPosition
.y
= -1;
2415 placement
->ptMaxPosition
.x
= -1;
2416 placement
->ptMaxPosition
.y
= -1;
2417 get_window_rect( hwnd
, &placement
->rcNormalPosition
, get_thread_dpi() );
2420 if (win
== WND_OTHER_PROCESS
)
2422 RECT normal_position
;
2425 if (!get_window_rect( hwnd
, &normal_position
, get_thread_dpi() ))
2428 FIXME("not fully supported on other process window %p.\n", hwnd
);
2430 placement
->length
= sizeof(*placement
);
2431 style
= get_window_long( hwnd
, GWL_STYLE
);
2432 if (style
& WS_MINIMIZE
)
2433 placement
->showCmd
= SW_SHOWMINIMIZED
;
2435 placement
->showCmd
= (style
& WS_MAXIMIZE
) ? SW_SHOWMAXIMIZED
: SW_SHOWNORMAL
;
2436 /* provide some dummy information */
2437 placement
->flags
= 0;
2438 placement
->ptMinPosition
.x
= -1;
2439 placement
->ptMinPosition
.y
= -1;
2440 placement
->ptMaxPosition
.x
= -1;
2441 placement
->ptMaxPosition
.y
= -1;
2442 placement
->rcNormalPosition
= normal_position
;
2446 /* update the placement according to the current style */
2447 if (win
->dwStyle
& WS_MINIMIZE
)
2449 win
->min_pos
.x
= win
->window_rect
.left
;
2450 win
->min_pos
.y
= win
->window_rect
.top
;
2452 else if (win
->dwStyle
& WS_MAXIMIZE
)
2454 win
->max_pos
.x
= win
->window_rect
.left
;
2455 win
->max_pos
.y
= win
->window_rect
.top
;
2459 win
->normal_rect
= win
->window_rect
;
2461 update_maximized_pos( win
, &work_rect
);
2463 placement
->length
= sizeof(*placement
);
2464 if (win
->dwStyle
& WS_MINIMIZE
)
2465 placement
->showCmd
= SW_SHOWMINIMIZED
;
2467 placement
->showCmd
= ( win
->dwStyle
& WS_MAXIMIZE
) ? SW_SHOWMAXIMIZED
: SW_SHOWNORMAL
;
2468 if (win
->flags
& WIN_RESTORE_MAX
)
2469 placement
->flags
= WPF_RESTORETOMAXIMIZED
;
2471 placement
->flags
= 0;
2472 win_dpi
= get_dpi_for_window( hwnd
);
2473 placement
->ptMinPosition
= empty_point(win
->min_pos
) ? win
->min_pos
2474 : map_dpi_point( win
->min_pos
, win_dpi
, get_thread_dpi() );
2475 placement
->ptMaxPosition
= empty_point(win
->max_pos
) ? win
->max_pos
2476 : map_dpi_point( win
->max_pos
, win_dpi
, get_thread_dpi() );
2477 placement
->rcNormalPosition
= map_dpi_rect( win
->normal_rect
, win_dpi
, get_thread_dpi() );
2478 release_win_ptr( win
);
2480 TRACE( "%p: returning min %d,%d max %d,%d normal %s\n",
2481 hwnd
, (int)placement
->ptMinPosition
.x
, (int)placement
->ptMinPosition
.y
,
2482 (int)placement
->ptMaxPosition
.x
, (int)placement
->ptMaxPosition
.y
,
2483 wine_dbgstr_rect(&placement
->rcNormalPosition
) );
2487 /* make sure the specified rect is visible on screen */
2488 static void make_rect_onscreen( RECT
*rect
)
2491 HMONITOR monitor
= monitor_from_rect( rect
, MONITOR_DEFAULTTONEAREST
, get_thread_dpi() );
2493 info
.cbSize
= sizeof(info
);
2494 if (!monitor
|| !get_monitor_info( monitor
, &info
)) return;
2495 /* FIXME: map coordinates from rcWork to rcMonitor */
2496 if (rect
->right
<= info
.rcWork
.left
)
2498 rect
->right
+= info
.rcWork
.left
- rect
->left
;
2499 rect
->left
= info
.rcWork
.left
;
2501 else if (rect
->left
>= info
.rcWork
.right
)
2503 rect
->left
+= info
.rcWork
.right
- rect
->right
;
2504 rect
->right
= info
.rcWork
.right
;
2506 if (rect
->bottom
<= info
.rcWork
.top
)
2508 rect
->bottom
+= info
.rcWork
.top
- rect
->top
;
2509 rect
->top
= info
.rcWork
.top
;
2511 else if (rect
->top
>= info
.rcWork
.bottom
)
2513 rect
->top
+= info
.rcWork
.bottom
- rect
->bottom
;
2514 rect
->bottom
= info
.rcWork
.bottom
;
2518 /***********************************************************************
2519 * NtUserGetInternalWindowPos (win32u.@)
2521 UINT WINAPI
NtUserGetInternalWindowPos( HWND hwnd
, RECT
*rect
, POINT
*pt
)
2523 WINDOWPLACEMENT placement
;
2525 placement
.length
= sizeof(placement
);
2526 if (!NtUserGetWindowPlacement( hwnd
, &placement
)) return 0;
2527 if (rect
) *rect
= placement
.rcNormalPosition
;
2528 if (pt
) *pt
= placement
.ptMinPosition
;
2529 return placement
.showCmd
;
2532 /* make sure the specified point is visible on screen */
2533 static void make_point_onscreen( POINT
*pt
)
2537 SetRect( &rect
, pt
->x
, pt
->y
, pt
->x
+ 1, pt
->y
+ 1 );
2538 make_rect_onscreen( &rect
);
2543 static BOOL
set_window_placement( HWND hwnd
, const WINDOWPLACEMENT
*wndpl
, UINT flags
)
2545 RECT work_rect
= get_maximized_work_rect( hwnd
);
2546 WND
*win
= get_win_ptr( hwnd
);
2547 WINDOWPLACEMENT wp
= *wndpl
;
2550 if (flags
& PLACE_MIN
) make_point_onscreen( &wp
.ptMinPosition
);
2551 if (flags
& PLACE_MAX
) make_point_onscreen( &wp
.ptMaxPosition
);
2552 if (flags
& PLACE_RECT
) make_rect_onscreen( &wp
.rcNormalPosition
);
2554 TRACE( "%p: setting min %d,%d max %d,%d normal %s flags %x adjusted to min %d,%d max %d,%d normal %s\n",
2555 hwnd
, (int)wndpl
->ptMinPosition
.x
, (int)wndpl
->ptMinPosition
.y
,
2556 (int)wndpl
->ptMaxPosition
.x
, (int)wndpl
->ptMaxPosition
.y
,
2557 wine_dbgstr_rect(&wndpl
->rcNormalPosition
), flags
,
2558 (int)wp
.ptMinPosition
.x
, (int)wp
.ptMinPosition
.y
,
2559 (int)wp
.ptMaxPosition
.x
, (int)wp
.ptMaxPosition
.y
,
2560 wine_dbgstr_rect(&wp
.rcNormalPosition
) );
2562 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
2564 if (flags
& PLACE_MIN
) win
->min_pos
= point_thread_to_win_dpi( hwnd
, wp
.ptMinPosition
);
2565 if (flags
& PLACE_MAX
)
2567 win
->max_pos
= point_thread_to_win_dpi( hwnd
, wp
.ptMaxPosition
);
2568 update_maximized_pos( win
, &work_rect
);
2570 if (flags
& PLACE_RECT
) win
->normal_rect
= rect_thread_to_win_dpi( hwnd
, wp
.rcNormalPosition
);
2572 style
= win
->dwStyle
;
2574 release_win_ptr( win
);
2576 if (style
& WS_MINIMIZE
)
2578 if (flags
& PLACE_MIN
)
2580 NtUserSetWindowPos( hwnd
, 0, wp
.ptMinPosition
.x
, wp
.ptMinPosition
.y
, 0, 0,
2581 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
2584 else if (style
& WS_MAXIMIZE
)
2586 if (flags
& PLACE_MAX
)
2587 NtUserSetWindowPos( hwnd
, 0, wp
.ptMaxPosition
.x
, wp
.ptMaxPosition
.y
, 0, 0,
2588 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
2590 else if (flags
& PLACE_RECT
)
2591 NtUserSetWindowPos( hwnd
, 0, wp
.rcNormalPosition
.left
, wp
.rcNormalPosition
.top
,
2592 wp
.rcNormalPosition
.right
- wp
.rcNormalPosition
.left
,
2593 wp
.rcNormalPosition
.bottom
- wp
.rcNormalPosition
.top
,
2594 SWP_NOZORDER
| SWP_NOACTIVATE
);
2596 NtUserShowWindow( hwnd
, wndpl
->showCmd
);
2598 if (is_iconic( hwnd
))
2600 if (wndpl
->flags
& WPF_RESTORETOMAXIMIZED
)
2601 win_set_flags( hwnd
, WIN_RESTORE_MAX
, 0 );
2606 /***********************************************************************
2607 * NtUserSetWindowPlacement (win32u.@)
2609 BOOL WINAPI
NtUserSetWindowPlacement( HWND hwnd
, const WINDOWPLACEMENT
*wpl
)
2611 UINT flags
= PLACE_MAX
| PLACE_RECT
;
2612 if (!wpl
) return FALSE
;
2613 if (wpl
->length
!= sizeof(*wpl
))
2615 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
2618 if (wpl
->flags
& WPF_SETMINPOSITION
) flags
|= PLACE_MIN
;
2619 return set_window_placement( hwnd
, wpl
, flags
);
2622 /*****************************************************************************
2623 * NtUserBuildHwndList (win32u.@)
2625 NTSTATUS WINAPI
NtUserBuildHwndList( HDESK desktop
, ULONG unk2
, ULONG unk3
, ULONG unk4
,
2626 ULONG thread_id
, ULONG count
, HWND
*buffer
, ULONG
*size
)
2628 user_handle_t
*list
= (user_handle_t
*)buffer
;
2632 SERVER_START_REQ( get_window_children
)
2634 req
->desktop
= wine_server_obj_handle( desktop
);
2635 req
->tid
= thread_id
;
2636 if (count
) wine_server_set_reply( req
, list
, (count
- 1) * sizeof(user_handle_t
) );
2637 status
= wine_server_call( req
);
2638 if (status
&& status
!= STATUS_BUFFER_TOO_SMALL
) return status
;
2639 *size
= reply
->count
+ 1;
2642 if (*size
> count
) return STATUS_BUFFER_TOO_SMALL
;
2644 /* start from the end since HWND is potentially larger than user_handle_t */
2645 for (i
= *size
- 2; i
>= 0; i
--)
2646 buffer
[i
] = wine_server_ptr_handle( list
[i
] );
2647 buffer
[*size
- 1] = HWND_BOTTOM
;
2648 return STATUS_SUCCESS
;
2651 /***********************************************************************
2652 * NtUserFindWindowEx (USER32.@)
2654 HWND WINAPI
NtUserFindWindowEx( HWND parent
, HWND child
, UNICODE_STRING
*class, UNICODE_STRING
*title
,
2659 int i
= 0, len
= 0, title_len
;
2660 WCHAR
*buffer
= NULL
;
2662 if (!parent
&& child
) parent
= get_desktop_window();
2663 else if (parent
== HWND_MESSAGE
) parent
= get_hwnd_message_parent();
2667 len
= title
->Length
/ sizeof(WCHAR
) + 1; /* one extra char to check for chars beyond the end */
2668 if (!(buffer
= malloc( (len
+ 1) * sizeof(WCHAR
) ))) return 0;
2671 if (!(list
= list_window_children( 0, parent
, class, 0 ))) goto done
;
2675 child
= get_full_window_handle( child
);
2676 while (list
[i
] && list
[i
] != child
) i
++;
2677 if (!list
[i
]) goto done
;
2678 i
++; /* start from next window */
2685 title_len
= NtUserInternalGetWindowText( list
[i
], buffer
, len
+ 1 );
2686 if (title_len
* sizeof(WCHAR
) == title
->Length
&&
2687 (!title_len
|| !wcsnicmp( buffer
, title
->Buffer
, title_len
)))
2700 /* Retrieve the window text from the server. */
2701 static data_size_t
get_server_window_text( HWND hwnd
, WCHAR
*text
, data_size_t count
)
2703 data_size_t len
= 0, needed
= 0;
2705 SERVER_START_REQ( get_window_text
)
2707 req
->handle
= wine_server_user_handle( hwnd
);
2708 if (count
) wine_server_set_reply( req
, text
, (count
- 1) * sizeof(WCHAR
) );
2709 if (!wine_server_call_err( req
))
2711 needed
= reply
->length
;
2712 len
= wine_server_reply_size(reply
);
2716 if (text
) text
[len
/ sizeof(WCHAR
)] = 0;
2720 /*******************************************************************
2721 * NtUserInternalGetWindowText (win32u.@)
2723 INT WINAPI
NtUserInternalGetWindowText( HWND hwnd
, WCHAR
*text
, INT count
)
2727 if (count
<= 0) return 0;
2728 if (!(win
= get_win_ptr( hwnd
))) return 0;
2729 if (win
== WND_DESKTOP
) text
[0] = 0;
2730 else if (win
!= WND_OTHER_PROCESS
)
2732 if (win
->text
) lstrcpynW( text
, win
->text
, count
);
2734 release_win_ptr( win
);
2738 get_server_window_text( hwnd
, text
, count
);
2740 return lstrlenW(text
);
2743 /*******************************************************************
2744 * get_windows_offset
2746 * Calculate the offset between the origin of the two windows. Used
2747 * to implement MapWindowPoints.
2749 static BOOL
get_windows_offset( HWND hwnd_from
, HWND hwnd_to
, UINT dpi
, BOOL
*mirrored
, POINT
*ret_offset
)
2753 BOOL mirror_from
, mirror_to
, ret
;
2756 offset
.x
= offset
.y
= 0;
2757 *mirrored
= mirror_from
= mirror_to
= FALSE
;
2759 /* Translate source window origin to screen coords */
2762 if (!(win
= get_win_ptr( hwnd_from
)))
2764 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
2767 if (win
== WND_OTHER_PROCESS
) goto other_process
;
2768 if (win
!= WND_DESKTOP
)
2770 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
)
2773 offset
.x
+= win
->client_rect
.right
- win
->client_rect
.left
;
2777 offset
.x
+= win
->client_rect
.left
;
2778 offset
.y
+= win
->client_rect
.top
;
2780 release_win_ptr( win
);
2781 if (!(win
= get_win_ptr( hwnd
))) break;
2782 if (win
== WND_OTHER_PROCESS
) goto other_process
;
2783 if (win
== WND_DESKTOP
) break;
2784 if (win
->flags
& WIN_CHILDREN_MOVED
)
2786 release_win_ptr( win
);
2790 if (win
&& win
!= WND_DESKTOP
) release_win_ptr( win
);
2791 offset
= map_dpi_point( offset
, get_dpi_for_window( hwnd_from
), dpi
);
2795 /* Translate origin to destination window coords */
2798 if (!(win
= get_win_ptr( hwnd_to
)))
2800 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
2803 if (win
== WND_OTHER_PROCESS
) goto other_process
;
2804 if (win
!= WND_DESKTOP
)
2806 POINT pt
= { 0, 0 };
2807 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
)
2810 pt
.x
+= win
->client_rect
.right
- win
->client_rect
.left
;
2814 pt
.x
+= win
->client_rect
.left
;
2815 pt
.y
+= win
->client_rect
.top
;
2817 release_win_ptr( win
);
2818 if (!(win
= get_win_ptr( hwnd
))) break;
2819 if (win
== WND_OTHER_PROCESS
) goto other_process
;
2820 if (win
== WND_DESKTOP
) break;
2821 if (win
->flags
& WIN_CHILDREN_MOVED
)
2823 release_win_ptr( win
);
2827 if (win
&& win
!= WND_DESKTOP
) release_win_ptr( win
);
2828 pt
= map_dpi_point( pt
, get_dpi_for_window( hwnd_to
), dpi
);
2834 *mirrored
= mirror_from
^ mirror_to
;
2835 if (mirror_from
) offset
.x
= -offset
.x
;
2836 *ret_offset
= offset
;
2839 other_process
: /* one of the parents may belong to another process, do it the hard way */
2840 SERVER_START_REQ( get_windows_offset
)
2842 req
->from
= wine_server_user_handle( hwnd_from
);
2843 req
->to
= wine_server_user_handle( hwnd_to
);
2845 if ((ret
= !wine_server_call_err( req
)))
2847 ret_offset
->x
= reply
->x
;
2848 ret_offset
->y
= reply
->y
;
2849 *mirrored
= reply
->mirror
;
2856 /* see ClientToScreen */
2857 BOOL
client_to_screen( HWND hwnd
, POINT
*pt
)
2864 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
2868 if (!get_windows_offset( hwnd
, 0, get_thread_dpi(), &mirrored
, &offset
)) return FALSE
;
2871 if (mirrored
) pt
->x
= -pt
->x
;
2875 /* see ScreenToClient */
2876 BOOL
screen_to_client( HWND hwnd
, POINT
*pt
)
2883 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
2886 if (!get_windows_offset( 0, hwnd
, get_thread_dpi(), &mirrored
, &offset
)) return FALSE
;
2889 if (mirrored
) pt
->x
= -pt
->x
;
2893 /* map coordinates of a window region */
2894 void map_window_region( HWND from
, HWND to
, HRGN hrgn
)
2903 if (!get_windows_offset( from
, to
, get_thread_dpi(), &mirrored
, &offset
)) return;
2907 NtGdiOffsetRgn( hrgn
, offset
.x
, offset
.y
);
2910 if (!(size
= NtGdiGetRegionData( hrgn
, 0, NULL
))) return;
2911 if (!(data
= malloc( size
))) return;
2912 NtGdiGetRegionData( hrgn
, size
, data
);
2913 rect
= (RECT
*)data
->Buffer
;
2914 for (i
= 0; i
< data
->rdh
.nCount
; i
++)
2916 int tmp
= -(rect
[i
].left
+ offset
.x
);
2917 rect
[i
].left
= -(rect
[i
].right
+ offset
.x
);
2918 rect
[i
].right
= tmp
;
2919 rect
[i
].top
+= offset
.y
;
2920 rect
[i
].bottom
+= offset
.y
;
2922 if ((new_rgn
= NtGdiExtCreateRegion( NULL
, data
->rdh
.dwSize
+ data
->rdh
.nRgnSize
, data
)))
2924 NtGdiCombineRgn( hrgn
, new_rgn
, 0, RGN_COPY
);
2925 NtGdiDeleteObjectApp( new_rgn
);
2930 /* see MapWindowPoints */
2931 int map_window_points( HWND hwnd_from
, HWND hwnd_to
, POINT
*points
, UINT count
, UINT dpi
)
2937 if (!get_windows_offset( hwnd_from
, hwnd_to
, dpi
, &mirrored
, &offset
)) return 0;
2939 for (i
= 0; i
< count
; i
++)
2941 points
[i
].x
+= offset
.x
;
2942 points
[i
].y
+= offset
.y
;
2943 if (mirrored
) points
[i
].x
= -points
[i
].x
;
2945 if (mirrored
&& count
== 2) /* special case for rectangle */
2947 int tmp
= points
[0].x
;
2948 points
[0].x
= points
[1].x
;
2951 return MAKELONG( LOWORD(offset
.x
), LOWORD(offset
.y
) );
2954 /***********************************************************************
2957 static void dump_winpos_flags( UINT flags
)
2959 static const UINT dumped_flags
= (SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOREDRAW
|
2960 SWP_NOACTIVATE
| SWP_FRAMECHANGED
| SWP_SHOWWINDOW
|
2961 SWP_HIDEWINDOW
| SWP_NOCOPYBITS
| SWP_NOOWNERZORDER
|
2962 SWP_NOSENDCHANGING
| SWP_DEFERERASE
| SWP_ASYNCWINDOWPOS
|
2963 SWP_NOCLIENTSIZE
| SWP_NOCLIENTMOVE
| SWP_STATECHANGED
);
2965 if(flags
& SWP_NOSIZE
) TRACE( " SWP_NOSIZE" );
2966 if(flags
& SWP_NOMOVE
) TRACE( " SWP_NOMOVE" );
2967 if(flags
& SWP_NOZORDER
) TRACE( " SWP_NOZORDER" );
2968 if(flags
& SWP_NOREDRAW
) TRACE( " SWP_NOREDRAW" );
2969 if(flags
& SWP_NOACTIVATE
) TRACE( " SWP_NOACTIVATE" );
2970 if(flags
& SWP_FRAMECHANGED
) TRACE( " SWP_FRAMECHANGED" );
2971 if(flags
& SWP_SHOWWINDOW
) TRACE( " SWP_SHOWWINDOW" );
2972 if(flags
& SWP_HIDEWINDOW
) TRACE( " SWP_HIDEWINDOW" );
2973 if(flags
& SWP_NOCOPYBITS
) TRACE( " SWP_NOCOPYBITS" );
2974 if(flags
& SWP_NOOWNERZORDER
) TRACE( " SWP_NOOWNERZORDER" );
2975 if(flags
& SWP_NOSENDCHANGING
) TRACE( " SWP_NOSENDCHANGING" );
2976 if(flags
& SWP_DEFERERASE
) TRACE( " SWP_DEFERERASE" );
2977 if(flags
& SWP_ASYNCWINDOWPOS
) TRACE( " SWP_ASYNCWINDOWPOS" );
2978 if(flags
& SWP_NOCLIENTSIZE
) TRACE( " SWP_NOCLIENTSIZE" );
2979 if(flags
& SWP_NOCLIENTMOVE
) TRACE( " SWP_NOCLIENTMOVE" );
2980 if(flags
& SWP_STATECHANGED
) TRACE( " SWP_STATECHANGED" );
2982 if(flags
& ~dumped_flags
) TRACE( " %08x", flags
& ~dumped_flags
);
2986 /***********************************************************************
2989 static void map_dpi_winpos( WINDOWPOS
*winpos
)
2991 UINT dpi_from
= get_thread_dpi();
2992 UINT dpi_to
= get_dpi_for_window( winpos
->hwnd
);
2994 if (!dpi_from
) dpi_from
= get_win_monitor_dpi( winpos
->hwnd
);
2995 if (dpi_from
== dpi_to
) return;
2996 winpos
->x
= muldiv( winpos
->x
, dpi_to
, dpi_from
);
2997 winpos
->y
= muldiv( winpos
->y
, dpi_to
, dpi_from
);
2998 winpos
->cx
= muldiv( winpos
->cx
, dpi_to
, dpi_from
);
2999 winpos
->cy
= muldiv( winpos
->cy
, dpi_to
, dpi_from
);
3002 /***********************************************************************
3005 static BOOL
calc_winpos( WINDOWPOS
*winpos
, RECT
*old_window_rect
, RECT
*old_client_rect
,
3006 RECT
*new_window_rect
, RECT
*new_client_rect
)
3010 /* Send WM_WINDOWPOSCHANGING message */
3011 if (!(winpos
->flags
& SWP_NOSENDCHANGING
)
3012 && !((winpos
->flags
& SWP_AGG_NOCLIENTCHANGE
) && (winpos
->flags
& SWP_SHOWWINDOW
)))
3013 send_message( winpos
->hwnd
, WM_WINDOWPOSCHANGING
, 0, (LPARAM
)winpos
);
3015 if (!(win
= get_win_ptr( winpos
->hwnd
)) ||
3016 win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
3018 /* Calculate new position and size */
3019 get_window_rects( winpos
->hwnd
, COORDS_PARENT
, old_window_rect
, old_client_rect
, get_thread_dpi() );
3020 *new_window_rect
= *old_window_rect
;
3021 *new_client_rect
= *old_client_rect
;
3023 if (!(winpos
->flags
& SWP_NOSIZE
))
3025 if (win
->dwStyle
& WS_MINIMIZE
)
3027 new_window_rect
->right
= new_window_rect
->left
+ get_system_metrics( SM_CXMINIMIZED
);
3028 new_window_rect
->bottom
= new_window_rect
->top
+ get_system_metrics( SM_CYMINIMIZED
);
3032 new_window_rect
->right
= new_window_rect
->left
+ winpos
->cx
;
3033 new_window_rect
->bottom
= new_window_rect
->top
+ winpos
->cy
;
3037 if (!(winpos
->flags
& SWP_NOMOVE
))
3039 /* If the window is toplevel minimized off-screen, force keep it there */
3040 if ((win
->dwStyle
& WS_MINIMIZE
) &&
3041 win
->window_rect
.left
<= -32000 && win
->window_rect
.top
<= -32000 &&
3042 (!win
->parent
|| win
->parent
== get_desktop_window()))
3047 new_window_rect
->left
= winpos
->x
;
3048 new_window_rect
->top
= winpos
->y
;
3049 new_window_rect
->right
+= winpos
->x
- old_window_rect
->left
;
3050 new_window_rect
->bottom
+= winpos
->y
- old_window_rect
->top
;
3052 OffsetRect( new_client_rect
, winpos
->x
- old_window_rect
->left
,
3053 winpos
->y
- old_window_rect
->top
);
3055 winpos
->flags
|= SWP_NOCLIENTMOVE
| SWP_NOCLIENTSIZE
;
3057 TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x current %s style %08x new %s\n",
3058 winpos
->hwnd
, winpos
->hwndInsertAfter
, winpos
->x
, winpos
->y
,
3059 winpos
->cx
, winpos
->cy
, winpos
->flags
,
3060 wine_dbgstr_rect( old_window_rect
), win
->dwStyle
,
3061 wine_dbgstr_rect( new_window_rect
));
3063 release_win_ptr( win
);
3067 /***********************************************************************
3070 * Compute the valid rects from the old and new client rect and WVR_* flags.
3071 * Helper for WM_NCCALCSIZE handling.
3073 static inline void get_valid_rects( const RECT
*old_client
, const RECT
*new_client
, UINT flags
,
3078 if (flags
& WVR_REDRAW
)
3080 SetRectEmpty( &valid
[0] );
3081 SetRectEmpty( &valid
[1] );
3085 if (flags
& WVR_VALIDRECTS
)
3087 if (!intersect_rect( &valid
[0], &valid
[0], new_client
) ||
3088 !intersect_rect( &valid
[1], &valid
[1], old_client
))
3090 SetRectEmpty( &valid
[0] );
3091 SetRectEmpty( &valid
[1] );
3094 flags
= WVR_ALIGNLEFT
| WVR_ALIGNTOP
;
3098 valid
[0] = *new_client
;
3099 valid
[1] = *old_client
;
3102 /* make sure the rectangles have the same size */
3103 cx
= min( valid
[0].right
- valid
[0].left
, valid
[1].right
- valid
[1].left
);
3104 cy
= min( valid
[0].bottom
- valid
[0].top
, valid
[1].bottom
- valid
[1].top
);
3106 if (flags
& WVR_ALIGNBOTTOM
)
3108 valid
[0].top
= valid
[0].bottom
- cy
;
3109 valid
[1].top
= valid
[1].bottom
- cy
;
3113 valid
[0].bottom
= valid
[0].top
+ cy
;
3114 valid
[1].bottom
= valid
[1].top
+ cy
;
3116 if (flags
& WVR_ALIGNRIGHT
)
3118 valid
[0].left
= valid
[0].right
- cx
;
3119 valid
[1].left
= valid
[1].right
- cx
;
3123 valid
[0].right
= valid
[0].left
+ cx
;
3124 valid
[1].right
= valid
[1].left
+ cx
;
3128 static UINT
calc_ncsize( WINDOWPOS
*winpos
, const RECT
*old_window_rect
, const RECT
*old_client_rect
,
3129 const RECT
*new_window_rect
, RECT
*new_client_rect
, RECT
*valid_rects
,
3130 int parent_x
, int parent_y
)
3134 /* Send WM_NCCALCSIZE message to get new client area */
3135 if ((winpos
->flags
& (SWP_FRAMECHANGED
| SWP_NOSIZE
)) != SWP_NOSIZE
)
3137 NCCALCSIZE_PARAMS params
;
3138 WINDOWPOS winposCopy
;
3141 params
.rgrc
[0] = *new_window_rect
;
3142 params
.rgrc
[1] = *old_window_rect
;
3143 params
.rgrc
[2] = *old_client_rect
;
3144 params
.lppos
= &winposCopy
;
3145 winposCopy
= *winpos
;
3147 if (winpos
->flags
& SWP_NOMOVE
)
3149 winposCopy
.x
= old_window_rect
->left
;
3150 winposCopy
.y
= old_window_rect
->top
;
3153 if (winpos
->flags
& SWP_NOSIZE
)
3155 winposCopy
.cx
= old_window_rect
->right
- old_window_rect
->left
;
3156 winposCopy
.cy
= old_window_rect
->bottom
- old_window_rect
->top
;
3159 class_style
= get_class_long( winpos
->hwnd
, GCL_STYLE
, FALSE
);
3160 if (class_style
& CS_VREDRAW
) wvr_flags
|= WVR_VREDRAW
;
3161 if (class_style
& CS_HREDRAW
) wvr_flags
|= WVR_HREDRAW
;
3163 wvr_flags
|= send_message( winpos
->hwnd
, WM_NCCALCSIZE
, TRUE
, (LPARAM
)¶ms
);
3165 *new_client_rect
= params
.rgrc
[0];
3167 TRACE( "hwnd %p old win %s old client %s new win %s new client %s\n", winpos
->hwnd
,
3168 wine_dbgstr_rect(old_window_rect
), wine_dbgstr_rect(old_client_rect
),
3169 wine_dbgstr_rect(new_window_rect
), wine_dbgstr_rect(new_client_rect
) );
3171 if (new_client_rect
->left
!= old_client_rect
->left
- parent_x
||
3172 new_client_rect
->top
!= old_client_rect
->top
- parent_y
)
3173 winpos
->flags
&= ~SWP_NOCLIENTMOVE
;
3175 if ((new_client_rect
->right
- new_client_rect
->left
!=
3176 old_client_rect
->right
- old_client_rect
->left
))
3177 winpos
->flags
&= ~SWP_NOCLIENTSIZE
;
3179 wvr_flags
&= ~WVR_HREDRAW
;
3181 if (new_client_rect
->bottom
- new_client_rect
->top
!=
3182 old_client_rect
->bottom
- old_client_rect
->top
)
3183 winpos
->flags
&= ~SWP_NOCLIENTSIZE
;
3185 wvr_flags
&= ~WVR_VREDRAW
;
3187 valid_rects
[0] = params
.rgrc
[1];
3188 valid_rects
[1] = params
.rgrc
[2];
3192 if (!(winpos
->flags
& SWP_NOMOVE
) &&
3193 (new_client_rect
->left
!= old_client_rect
->left
- parent_x
||
3194 new_client_rect
->top
!= old_client_rect
->top
- parent_y
))
3195 winpos
->flags
&= ~SWP_NOCLIENTMOVE
;
3198 if (winpos
->flags
& (SWP_NOCOPYBITS
| SWP_NOREDRAW
| SWP_SHOWWINDOW
| SWP_HIDEWINDOW
))
3200 SetRectEmpty( &valid_rects
[0] );
3201 SetRectEmpty( &valid_rects
[1] );
3203 else get_valid_rects( old_client_rect
, new_client_rect
, wvr_flags
, valid_rects
);
3208 /* fix redundant flags and values in the WINDOWPOS structure */
3209 static BOOL
fixup_swp_flags( WINDOWPOS
*winpos
, const RECT
*old_window_rect
, int parent_x
, int parent_y
)
3212 WND
*win
= get_win_ptr( winpos
->hwnd
);
3215 if (!win
|| win
== WND_OTHER_PROCESS
)
3217 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
3220 winpos
->hwnd
= win
->obj
.handle
; /* make it a full handle */
3222 /* Finally make sure that all coordinates are valid */
3223 if (winpos
->x
< -32768) winpos
->x
= -32768;
3224 else if (winpos
->x
> 32767) winpos
->x
= 32767;
3225 if (winpos
->y
< -32768) winpos
->y
= -32768;
3226 else if (winpos
->y
> 32767) winpos
->y
= 32767;
3228 if (winpos
->cx
< 0) winpos
->cx
= 0;
3229 else if (winpos
->cx
> 32767) winpos
->cx
= 32767;
3230 if (winpos
->cy
< 0) winpos
->cy
= 0;
3231 else if (winpos
->cy
> 32767) winpos
->cy
= 32767;
3233 parent
= NtUserGetAncestor( winpos
->hwnd
, GA_PARENT
);
3234 if (!is_window_visible( parent
)) winpos
->flags
|= SWP_NOREDRAW
;
3236 if (win
->dwStyle
& WS_VISIBLE
) winpos
->flags
&= ~SWP_SHOWWINDOW
;
3239 winpos
->flags
&= ~SWP_HIDEWINDOW
;
3240 if (!(winpos
->flags
& SWP_SHOWWINDOW
)) winpos
->flags
|= SWP_NOREDRAW
;
3243 if ((old_window_rect
->right
- old_window_rect
->left
== winpos
->cx
) &&
3244 (old_window_rect
->bottom
- old_window_rect
->top
== winpos
->cy
))
3245 winpos
->flags
|= SWP_NOSIZE
; /* Already the right size */
3247 if ((old_window_rect
->left
- parent_x
== winpos
->x
) && (old_window_rect
->top
- parent_y
== winpos
->y
))
3248 winpos
->flags
|= SWP_NOMOVE
; /* Already the right position */
3250 if ((win
->dwStyle
& (WS_POPUP
| WS_CHILD
)) != WS_CHILD
)
3252 if (!(winpos
->flags
& (SWP_NOACTIVATE
|SWP_HIDEWINDOW
)) && /* Bring to the top when activating */
3253 (winpos
->flags
& SWP_NOZORDER
||
3254 (winpos
->hwndInsertAfter
!= HWND_TOPMOST
&& winpos
->hwndInsertAfter
!= HWND_NOTOPMOST
)))
3256 winpos
->flags
&= ~SWP_NOZORDER
;
3257 winpos
->hwndInsertAfter
= HWND_TOP
;
3261 /* Check hwndInsertAfter */
3262 if (winpos
->flags
& SWP_NOZORDER
) goto done
;
3264 if (winpos
->hwndInsertAfter
== HWND_TOP
)
3266 if (get_window_relative( winpos
->hwnd
, GW_HWNDFIRST
) == winpos
->hwnd
)
3267 winpos
->flags
|= SWP_NOZORDER
;
3269 else if (winpos
->hwndInsertAfter
== HWND_BOTTOM
)
3271 if (!(win
->dwExStyle
& WS_EX_TOPMOST
) &&
3272 get_window_relative( winpos
->hwnd
, GW_HWNDLAST
) == winpos
->hwnd
)
3273 winpos
->flags
|= SWP_NOZORDER
;
3275 else if (winpos
->hwndInsertAfter
== HWND_TOPMOST
)
3277 if ((win
->dwExStyle
& WS_EX_TOPMOST
) &&
3278 get_window_relative( winpos
->hwnd
, GW_HWNDFIRST
) == winpos
->hwnd
)
3279 winpos
->flags
|= SWP_NOZORDER
;
3281 else if (winpos
->hwndInsertAfter
== HWND_NOTOPMOST
)
3283 if (!(win
->dwExStyle
& WS_EX_TOPMOST
))
3284 winpos
->flags
|= SWP_NOZORDER
;
3288 if ((winpos
->hwnd
== winpos
->hwndInsertAfter
) ||
3289 (winpos
->hwnd
== get_window_relative( winpos
->hwndInsertAfter
, GW_HWNDNEXT
)))
3290 winpos
->flags
|= SWP_NOZORDER
;
3293 release_win_ptr( win
);
3297 /***********************************************************************
3300 * fix Z order taking into account owned popups -
3301 * basically we need to maintain them above the window that owns them
3303 * FIXME: hide/show owned popups when owner visibility changes.
3305 static HWND
swp_owner_popups( HWND hwnd
, HWND after
)
3307 HWND owner
, *list
= NULL
;
3310 TRACE( "(%p) after = %p\n", hwnd
, after
);
3312 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) return after
;
3314 if ((owner
= get_window_relative( hwnd
, GW_OWNER
)))
3316 /* make sure this popup stays above the owner */
3318 if (after
!= HWND_TOPMOST
)
3320 if (!(list
= list_window_children( 0, get_desktop_window(), NULL
, 0 ))) return after
;
3322 for (i
= 0; list
[i
]; i
++)
3324 BOOL topmost
= (get_window_long( list
[i
], GWL_EXSTYLE
) & WS_EX_TOPMOST
) != 0;
3326 if (list
[i
] == owner
)
3328 if (i
> 0) after
= list
[i
-1];
3329 else after
= topmost
? HWND_TOPMOST
: HWND_TOP
;
3333 if (after
== HWND_TOP
|| after
== HWND_NOTOPMOST
)
3335 if (!topmost
) break;
3337 else if (list
[i
] == after
) break;
3342 if (after
== HWND_BOTTOM
) goto done
;
3343 if (!list
&& !(list
= list_window_children( 0, get_desktop_window(), NULL
, 0 ))) goto done
;
3346 if (after
== HWND_TOP
|| after
== HWND_NOTOPMOST
)
3348 if (after
== HWND_NOTOPMOST
||
3349 !(get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_TOPMOST
))
3351 /* skip all the topmost windows */
3352 while (list
[i
] && (get_window_long( list
[i
], GWL_EXSTYLE
) & WS_EX_TOPMOST
)) i
++;
3355 else if (after
!= HWND_TOPMOST
)
3357 /* skip windows that are already placed correctly */
3358 for (i
= 0; list
[i
]; i
++)
3360 if (list
[i
] == after
) break;
3361 if (list
[i
] == hwnd
) goto done
; /* nothing to do if window is moving backwards in z-order */
3365 for ( ; list
[i
]; i
++)
3367 if (list
[i
] == hwnd
) break;
3368 if (get_window_relative( list
[i
], GW_OWNER
) != hwnd
) continue;
3369 TRACE( "moving %p owned by %p after %p\n", list
[i
], hwnd
, after
);
3370 NtUserSetWindowPos( list
[i
], after
, 0, 0, 0, 0,
3371 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOSENDCHANGING
| SWP_DEFERERASE
);
3380 /* NtUserSetWindowPos implementation */
3381 BOOL
set_window_pos( WINDOWPOS
*winpos
, int parent_x
, int parent_y
)
3383 RECT old_window_rect
, old_client_rect
, new_window_rect
, new_client_rect
, valid_rects
[2];
3386 DPI_AWARENESS_CONTEXT context
;
3388 orig_flags
= winpos
->flags
;
3390 /* First, check z-order arguments. */
3391 if (!(winpos
->flags
& SWP_NOZORDER
))
3393 /* fix sign extension */
3394 if (winpos
->hwndInsertAfter
== (HWND
)0xffff) winpos
->hwndInsertAfter
= HWND_TOPMOST
;
3395 else if (winpos
->hwndInsertAfter
== (HWND
)0xfffe) winpos
->hwndInsertAfter
= HWND_NOTOPMOST
;
3397 if (!(winpos
->hwndInsertAfter
== HWND_TOP
||
3398 winpos
->hwndInsertAfter
== HWND_BOTTOM
||
3399 winpos
->hwndInsertAfter
== HWND_TOPMOST
||
3400 winpos
->hwndInsertAfter
== HWND_NOTOPMOST
))
3402 HWND parent
= NtUserGetAncestor( winpos
->hwnd
, GA_PARENT
);
3403 HWND insertafter_parent
= NtUserGetAncestor( winpos
->hwndInsertAfter
, GA_PARENT
);
3405 /* hwndInsertAfter must be a sibling of the window */
3406 if (!insertafter_parent
) return FALSE
;
3407 if (insertafter_parent
!= parent
) return TRUE
;
3411 /* Make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
3412 if (!(winpos
->flags
& SWP_NOMOVE
))
3414 if (winpos
->x
< -32768) winpos
->x
= -32768;
3415 else if (winpos
->x
> 32767) winpos
->x
= 32767;
3416 if (winpos
->y
< -32768) winpos
->y
= -32768;
3417 else if (winpos
->y
> 32767) winpos
->y
= 32767;
3419 if (!(winpos
->flags
& SWP_NOSIZE
))
3421 if (winpos
->cx
< 0) winpos
->cx
= 0;
3422 else if (winpos
->cx
> 32767) winpos
->cx
= 32767;
3423 if (winpos
->cy
< 0) winpos
->cy
= 0;
3424 else if (winpos
->cy
> 32767) winpos
->cy
= 32767;
3427 context
= SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( winpos
->hwnd
));
3429 if (!calc_winpos( winpos
, &old_window_rect
, &old_client_rect
,
3430 &new_window_rect
, &new_client_rect
)) goto done
;
3432 /* Fix redundant flags */
3433 if (!fixup_swp_flags( winpos
, &old_window_rect
, parent_x
, parent_y
)) goto done
;
3435 if((winpos
->flags
& (SWP_NOZORDER
| SWP_HIDEWINDOW
| SWP_SHOWWINDOW
)) != SWP_NOZORDER
)
3437 if (NtUserGetAncestor( winpos
->hwnd
, GA_PARENT
) == get_desktop_window())
3438 winpos
->hwndInsertAfter
= swp_owner_popups( winpos
->hwnd
, winpos
->hwndInsertAfter
);
3441 /* Common operations */
3443 calc_ncsize( winpos
, &old_window_rect
, &old_client_rect
,
3444 &new_window_rect
, &new_client_rect
, valid_rects
, parent_x
, parent_y
);
3446 if (!apply_window_pos( winpos
->hwnd
, winpos
->hwndInsertAfter
, winpos
->flags
,
3447 &new_window_rect
, &new_client_rect
, valid_rects
))
3450 if (winpos
->flags
& SWP_HIDEWINDOW
)
3452 NtUserNotifyWinEvent( EVENT_OBJECT_HIDE
, winpos
->hwnd
, 0, 0 );
3454 NtUserHideCaret( winpos
->hwnd
);
3456 else if (winpos
->flags
& SWP_SHOWWINDOW
)
3458 NtUserNotifyWinEvent( EVENT_OBJECT_SHOW
, winpos
->hwnd
, 0, 0 );
3460 NtUserShowCaret( winpos
->hwnd
);
3463 if (!(winpos
->flags
& (SWP_NOACTIVATE
|SWP_HIDEWINDOW
)))
3465 /* child windows get WM_CHILDACTIVATE message */
3466 if ((get_window_long( winpos
->hwnd
, GWL_STYLE
) & (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
3467 send_message( winpos
->hwnd
, WM_CHILDACTIVATE
, 0, 0 );
3469 set_foreground_window( winpos
->hwnd
, FALSE
);
3472 if(!(orig_flags
& SWP_DEFERERASE
))
3474 /* erase parent when hiding or resizing child */
3475 if ((orig_flags
& SWP_HIDEWINDOW
) ||
3476 (!(orig_flags
& SWP_SHOWWINDOW
) &&
3477 (winpos
->flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOGEOMETRYCHANGE
))
3479 HWND parent
= NtUserGetAncestor( winpos
->hwnd
, GA_PARENT
);
3480 if (!parent
|| parent
== get_desktop_window()) parent
= winpos
->hwnd
;
3481 erase_now( parent
, 0 );
3484 /* Give newly shown windows a chance to redraw */
3485 if(((winpos
->flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOPOSCHANGE
)
3486 && !(orig_flags
& SWP_AGG_NOCLIENTCHANGE
) && (orig_flags
& SWP_SHOWWINDOW
))
3488 erase_now(winpos
->hwnd
, 0);
3492 /* And last, send the WM_WINDOWPOSCHANGED message */
3494 TRACE( "\tstatus flags = %04x\n", winpos
->flags
& SWP_AGG_STATUSFLAGS
);
3496 if (((winpos
->flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOPOSCHANGE
)
3497 && !((orig_flags
& SWP_AGG_NOCLIENTCHANGE
) && (orig_flags
& SWP_SHOWWINDOW
)))
3499 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
3500 and always contains final window position.
3502 winpos
->x
= new_window_rect
.left
;
3503 winpos
->y
= new_window_rect
.top
;
3504 winpos
->cx
= new_window_rect
.right
- new_window_rect
.left
;
3505 winpos
->cy
= new_window_rect
.bottom
- new_window_rect
.top
;
3506 send_message( winpos
->hwnd
, WM_WINDOWPOSCHANGED
, 0, (LPARAM
)winpos
);
3510 SetThreadDpiAwarenessContext( context
);
3514 /*******************************************************************
3515 * NtUserSetWindowPos (win32u.@)
3517 BOOL WINAPI
NtUserSetWindowPos( HWND hwnd
, HWND after
, INT x
, INT y
, INT cx
, INT cy
, UINT flags
)
3521 TRACE( "hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n", hwnd
, after
, x
, y
, cx
, cy
, flags
);
3522 if(TRACE_ON(win
)) dump_winpos_flags(flags
);
3524 if (is_broadcast( hwnd
))
3526 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
3530 winpos
.hwnd
= get_full_window_handle( hwnd
);
3531 winpos
.hwndInsertAfter
= get_full_window_handle( after
);
3536 winpos
.flags
= flags
;
3538 map_dpi_winpos( &winpos
);
3540 if (is_current_thread_window( hwnd
))
3541 return set_window_pos( &winpos
, 0, 0 );
3543 if (flags
& SWP_ASYNCWINDOWPOS
)
3544 return NtUserMessageCall( winpos
.hwnd
, WM_WINE_SETWINDOWPOS
, 0, (LPARAM
)&winpos
,
3545 0, NtUserSendNotifyMessage
, FALSE
);
3547 return send_message( winpos
.hwnd
, WM_WINE_SETWINDOWPOS
, 0, (LPARAM
)&winpos
);
3552 struct user_object obj
;
3554 INT suggested_count
;
3559 /* see BeginDeferWindowPos */
3560 HDWP
begin_defer_window_pos( INT count
)
3565 TRACE( "%d\n", count
);
3569 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
3572 /* Windows allows zero count, in which case it allocates context for 8 moves */
3573 if (count
== 0) count
= 8;
3575 if (!(dwp
= malloc( sizeof(DWP
) ))) return 0;
3579 dwp
->suggested_count
= count
;
3581 if (!(dwp
->winpos
= malloc( count
* sizeof(WINDOWPOS
) )) ||
3582 !(handle
= alloc_user_handle( &dwp
->obj
, NTUSER_OBJ_WINPOS
)))
3584 free( dwp
->winpos
);
3588 TRACE( "returning %p\n", handle
);
3592 /***********************************************************************
3593 * NtUserDeferWindowPosAndBand (win32u.@)
3595 HDWP WINAPI
NtUserDeferWindowPosAndBand( HDWP hdwp
, HWND hwnd
, HWND after
,
3596 INT x
, INT y
, INT cx
, INT cy
,
3597 UINT flags
, UINT unk1
, UINT unk2
)
3599 HDWP retvalue
= hdwp
;
3604 TRACE( "hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
3605 hdwp
, hwnd
, after
, x
, y
, cx
, cy
, flags
);
3607 winpos
.hwnd
= get_full_window_handle( hwnd
);
3608 if (is_desktop_window( winpos
.hwnd
) || !is_window( winpos
.hwnd
))
3610 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
3614 winpos
.hwndInsertAfter
= get_full_window_handle( after
);
3615 winpos
.flags
= flags
;
3620 map_dpi_winpos( &winpos
);
3622 if (!(dwp
= get_user_handle_ptr( hdwp
, NTUSER_OBJ_WINPOS
))) return 0;
3623 if (dwp
== OBJ_OTHER_PROCESS
)
3625 FIXME( "other process handle %p\n", hdwp
);
3629 for (i
= 0; i
< dwp
->count
; i
++)
3631 if (dwp
->winpos
[i
].hwnd
== winpos
.hwnd
)
3633 /* Merge with the other changes */
3634 if (!(flags
& SWP_NOZORDER
))
3636 dwp
->winpos
[i
].hwndInsertAfter
= winpos
.hwndInsertAfter
;
3638 if (!(flags
& SWP_NOMOVE
))
3640 dwp
->winpos
[i
].x
= winpos
.x
;
3641 dwp
->winpos
[i
].y
= winpos
.y
;
3643 if (!(flags
& SWP_NOSIZE
))
3645 dwp
->winpos
[i
].cx
= winpos
.cx
;
3646 dwp
->winpos
[i
].cy
= winpos
.cy
;
3648 dwp
->winpos
[i
].flags
&= flags
| ~(SWP_NOSIZE
| SWP_NOMOVE
|
3649 SWP_NOZORDER
| SWP_NOREDRAW
|
3650 SWP_NOACTIVATE
| SWP_NOCOPYBITS
|
3652 dwp
->winpos
[i
].flags
|= flags
& (SWP_SHOWWINDOW
| SWP_HIDEWINDOW
|
3657 if (dwp
->count
>= dwp
->suggested_count
)
3659 WINDOWPOS
*newpos
= realloc( dwp
->winpos
, dwp
->suggested_count
* 2 * sizeof(WINDOWPOS
) );
3665 dwp
->suggested_count
*= 2;
3666 dwp
->winpos
= newpos
;
3668 dwp
->winpos
[dwp
->count
++] = winpos
;
3670 release_user_handle_ptr( dwp
);
3674 /***********************************************************************
3675 * NtUserEndDeferWindowPosEx (win32u.@)
3677 BOOL WINAPI
NtUserEndDeferWindowPosEx( HDWP hdwp
, BOOL async
)
3683 TRACE( "%p\n", hdwp
);
3685 if (async
) FIXME( "async not supported\n" );
3687 if (!(dwp
= free_user_handle( hdwp
, NTUSER_OBJ_WINPOS
))) return FALSE
;
3688 if (dwp
== OBJ_OTHER_PROCESS
)
3690 FIXME( "other process handle %p\n", hdwp
);
3694 for (i
= 0, winpos
= dwp
->winpos
; i
< dwp
->count
; i
++, winpos
++)
3696 TRACE( "hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
3697 winpos
->hwnd
, winpos
->hwndInsertAfter
, winpos
->x
, winpos
->y
,
3698 winpos
->cx
, winpos
->cy
, winpos
->flags
);
3700 if (is_current_thread_window( winpos
->hwnd
))
3701 set_window_pos( winpos
, 0, 0 );
3703 send_message( winpos
->hwnd
, WM_WINE_SETWINDOWPOS
, 0, (LPARAM
)winpos
);
3705 free( dwp
->winpos
);
3710 /***********************************************************************
3711 * NtUserSetInternalWindowPos (win32u.@)
3713 void WINAPI
NtUserSetInternalWindowPos( HWND hwnd
, UINT cmd
, RECT
*rect
, POINT
*pt
)
3715 WINDOWPLACEMENT wndpl
;
3718 wndpl
.length
= sizeof(wndpl
);
3719 wndpl
.showCmd
= cmd
;
3720 wndpl
.flags
= flags
= 0;
3725 wndpl
.flags
|= WPF_SETMINPOSITION
;
3726 wndpl
.ptMinPosition
= *pt
;
3730 flags
|= PLACE_RECT
;
3731 wndpl
.rcNormalPosition
= *rect
;
3733 set_window_placement( hwnd
, &wndpl
, flags
);
3736 /***********************************************************************
3739 * Set the flags of a window and return the previous value.
3741 UINT
win_set_flags( HWND hwnd
, UINT set_mask
, UINT clear_mask
)
3743 WND
*win
= get_win_ptr( hwnd
);
3746 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return 0;
3748 win
->flags
= (ret
& ~clear_mask
) | set_mask
;
3749 release_win_ptr( win
);
3753 /*******************************************************************
3754 * can_activate_window
3756 * Check if we can activate the specified window.
3758 static BOOL
can_activate_window( HWND hwnd
)
3762 if (!hwnd
) return FALSE
;
3763 style
= get_window_long( hwnd
, GWL_STYLE
);
3764 if (!(style
& WS_VISIBLE
)) return FALSE
;
3765 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
3766 return !(style
& WS_DISABLED
);
3769 /*******************************************************************
3770 * activate_other_window
3772 * Activates window other than hwnd.
3774 static void activate_other_window( HWND hwnd
)
3778 if ((get_window_long( hwnd
, GWL_STYLE
) & WS_POPUP
) &&
3779 (hwnd_to
= get_window_relative( hwnd
, GW_OWNER
)))
3781 hwnd_to
= NtUserGetAncestor( hwnd_to
, GA_ROOT
);
3782 if (can_activate_window( hwnd_to
)) goto done
;
3788 if (!(hwnd_to
= get_window_relative( hwnd_to
, GW_HWNDNEXT
))) break;
3789 if (can_activate_window( hwnd_to
)) goto done
;
3792 hwnd_to
= get_window_relative( get_desktop_window(), GW_CHILD
);
3795 if (hwnd_to
== hwnd
)
3800 if (can_activate_window( hwnd_to
)) goto done
;
3801 if (!(hwnd_to
= get_window_relative( hwnd_to
, GW_HWNDNEXT
))) break;
3805 fg
= NtUserGetForegroundWindow();
3806 TRACE( "win = %p fg = %p\n", hwnd_to
, fg
);
3807 if (!fg
|| hwnd
== fg
)
3809 if (set_foreground_window( hwnd_to
, FALSE
)) return;
3811 if (NtUserSetActiveWindow( hwnd_to
)) NtUserSetActiveWindow( 0 );
3814 /*******************************************************************
3815 * send_parent_notify
3817 static void send_parent_notify( HWND hwnd
, UINT msg
)
3819 if ((get_window_long( hwnd
, GWL_STYLE
) & (WS_CHILD
| WS_POPUP
)) == WS_CHILD
&&
3820 !(get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_NOPARENTNOTIFY
))
3822 HWND parent
= get_parent( hwnd
);
3823 if (parent
&& parent
!= get_desktop_window())
3824 send_message( parent
, WM_PARENTNOTIFY
,
3825 MAKEWPARAM( msg
, get_window_long( hwnd
, GWLP_ID
)), (LPARAM
)hwnd
);
3829 /*******************************************************************
3832 * Get the minimized and maximized information for a window.
3834 MINMAXINFO
get_min_max_info( HWND hwnd
)
3836 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
3837 LONG exstyle
= get_window_long( hwnd
, GWL_EXSTYLE
);
3838 DPI_AWARENESS_CONTEXT context
;
3839 RECT rc_work
, rc_primary
;
3840 LONG adjusted_style
;
3846 context
= SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( hwnd
));
3848 /* Compute default values */
3850 get_window_rect( hwnd
, &rc
, get_thread_dpi() );
3851 minmax
.ptReserved
.x
= rc
.left
;
3852 minmax
.ptReserved
.y
= rc
.top
;
3854 if ((style
& WS_CAPTION
) == WS_CAPTION
)
3855 adjusted_style
= style
& ~WS_BORDER
; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
3857 adjusted_style
= style
;
3859 get_client_rect( NtUserGetAncestor( hwnd
, GA_PARENT
), &rc
);
3860 AdjustWindowRectEx( &rc
, adjusted_style
, (style
& WS_POPUP
) && get_menu( hwnd
), exstyle
);
3865 minmax
.ptMaxSize
.x
= rc
.right
- rc
.left
;
3866 minmax
.ptMaxSize
.y
= rc
.bottom
- rc
.top
;
3867 if (style
& (WS_DLGFRAME
| WS_BORDER
))
3869 minmax
.ptMinTrackSize
.x
= get_system_metrics( SM_CXMINTRACK
);
3870 minmax
.ptMinTrackSize
.y
= get_system_metrics( SM_CYMINTRACK
);
3874 minmax
.ptMinTrackSize
.x
= 2 * xinc
;
3875 minmax
.ptMinTrackSize
.y
= 2 * yinc
;
3877 minmax
.ptMaxTrackSize
.x
= get_system_metrics( SM_CXMAXTRACK
);
3878 minmax
.ptMaxTrackSize
.y
= get_system_metrics( SM_CYMAXTRACK
);
3879 minmax
.ptMaxPosition
.x
= -xinc
;
3880 minmax
.ptMaxPosition
.y
= -yinc
;
3882 if ((win
= get_win_ptr( hwnd
)) && win
!= WND_DESKTOP
&& win
!= WND_OTHER_PROCESS
)
3884 if (!empty_point( win
->max_pos
)) minmax
.ptMaxPosition
= win
->max_pos
;
3885 release_win_ptr( win
);
3888 send_message( hwnd
, WM_GETMINMAXINFO
, 0, (LPARAM
)&minmax
);
3890 /* if the app didn't change the values, adapt them for the current monitor */
3892 if (get_work_rect( hwnd
, &rc_work
))
3894 rc_primary
= get_primary_monitor_rect( get_thread_dpi() );
3895 if (minmax
.ptMaxSize
.x
== (rc_primary
.right
- rc_primary
.left
) + 2 * xinc
&&
3896 minmax
.ptMaxSize
.y
== (rc_primary
.bottom
- rc_primary
.top
) + 2 * yinc
)
3898 minmax
.ptMaxSize
.x
= (rc_work
.right
- rc_work
.left
) + 2 * xinc
;
3899 minmax
.ptMaxSize
.y
= (rc_work
.bottom
- rc_work
.top
) + 2 * yinc
;
3901 if (minmax
.ptMaxPosition
.x
== -xinc
&& minmax
.ptMaxPosition
.y
== -yinc
)
3903 minmax
.ptMaxPosition
.x
= rc_work
.left
- xinc
;
3904 minmax
.ptMaxPosition
.y
= rc_work
.top
- yinc
;
3908 TRACE( "%d %d / %d %d / %d %d / %d %d\n",
3909 (int)minmax
.ptMaxSize
.x
, (int)minmax
.ptMaxSize
.y
,
3910 (int)minmax
.ptMaxPosition
.x
, (int)minmax
.ptMaxPosition
.y
,
3911 (int)minmax
.ptMaxTrackSize
.x
, (int)minmax
.ptMaxTrackSize
.y
,
3912 (int)minmax
.ptMinTrackSize
.x
, (int)minmax
.ptMinTrackSize
.y
);
3914 minmax
.ptMaxTrackSize
.x
= max( minmax
.ptMaxTrackSize
.x
, minmax
.ptMinTrackSize
.x
);
3915 minmax
.ptMaxTrackSize
.y
= max( minmax
.ptMaxTrackSize
.y
, minmax
.ptMinTrackSize
.y
);
3917 SetThreadDpiAwarenessContext( context
);
3921 static POINT
get_first_minimized_child_pos( const RECT
*parent
, const MINIMIZEDMETRICS
*mm
,
3922 int width
, int height
)
3926 if (mm
->iArrange
& ARW_STARTRIGHT
)
3927 ret
.x
= parent
->right
- mm
->iHorzGap
- width
;
3929 ret
.x
= parent
->left
+ mm
->iHorzGap
;
3930 if (mm
->iArrange
& ARW_STARTTOP
)
3931 ret
.y
= parent
->top
+ mm
->iVertGap
;
3933 ret
.y
= parent
->bottom
- mm
->iVertGap
- height
;
3938 static void get_next_minimized_child_pos( const RECT
*parent
, const MINIMIZEDMETRICS
*mm
,
3939 int width
, int height
, POINT
*pos
)
3943 if (mm
->iArrange
& ARW_UP
) /* == ARW_DOWN */
3945 if (mm
->iArrange
& ARW_STARTTOP
)
3947 pos
->y
+= height
+ mm
->iVertGap
;
3948 if ((next
= pos
->y
+ height
> parent
->bottom
))
3949 pos
->y
= parent
->top
+ mm
->iVertGap
;
3953 pos
->y
-= height
+ mm
->iVertGap
;
3954 if ((next
= pos
->y
< parent
->top
))
3955 pos
->y
= parent
->bottom
- mm
->iVertGap
- height
;
3960 if (mm
->iArrange
& ARW_STARTRIGHT
)
3961 pos
->x
-= width
+ mm
->iHorzGap
;
3963 pos
->x
+= width
+ mm
->iHorzGap
;
3968 if (mm
->iArrange
& ARW_STARTRIGHT
)
3970 pos
->x
-= width
+ mm
->iHorzGap
;
3971 if ((next
= pos
->x
< parent
->left
))
3972 pos
->x
= parent
->right
- mm
->iHorzGap
- width
;
3976 pos
->x
+= width
+ mm
->iHorzGap
;
3977 if ((next
= pos
->x
+ width
> parent
->right
))
3978 pos
->x
= parent
->left
+ mm
->iHorzGap
;
3983 if (mm
->iArrange
& ARW_STARTTOP
)
3984 pos
->y
+= height
+ mm
->iVertGap
;
3986 pos
->y
-= height
+ mm
->iVertGap
;
3991 static POINT
get_minimized_pos( HWND hwnd
, POINT pt
)
3993 RECT rect
, parent_rect
;
3996 MINIMIZEDMETRICS metrics
;
3999 parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
4000 if (parent
== get_desktop_window())
4002 MONITORINFO mon_info
;
4003 HMONITOR monitor
= monitor_from_window( hwnd
, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
4005 mon_info
.cbSize
= sizeof( mon_info
);
4006 get_monitor_info( monitor
, &mon_info
);
4007 parent_rect
= mon_info
.rcWork
;
4009 else get_client_rect( parent
, &parent_rect
);
4011 if (pt
.x
>= parent_rect
.left
&& (pt
.x
+ get_system_metrics( SM_CXMINIMIZED
) < parent_rect
.right
) &&
4012 pt
.y
>= parent_rect
.top
&& (pt
.y
+ get_system_metrics( SM_CYMINIMIZED
) < parent_rect
.bottom
))
4013 return pt
; /* The icon already has a suitable position */
4015 width
= get_system_metrics( SM_CXMINIMIZED
);
4016 height
= get_system_metrics( SM_CYMINIMIZED
);
4018 metrics
.cbSize
= sizeof(metrics
);
4019 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(metrics
), &metrics
, 0 );
4021 /* Check if another icon already occupies this spot */
4022 /* FIXME: this is completely inefficient */
4024 hrgn
= NtGdiCreateRectRgn( 0, 0, 0, 0 );
4025 tmp
= NtGdiCreateRectRgn( 0, 0, 0, 0 );
4026 for (child
= get_window_relative( parent
, GW_CHILD
);
4028 child
= get_window_relative( child
, GW_HWNDNEXT
))
4030 if (child
== hwnd
) continue;
4031 if ((get_window_long( child
, GWL_STYLE
) & (WS_VISIBLE
|WS_MINIMIZE
)) != (WS_VISIBLE
|WS_MINIMIZE
))
4033 if (get_window_rects( child
, COORDS_PARENT
, &rect
, NULL
, get_thread_dpi() ))
4035 NtGdiSetRectRgn( tmp
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
4036 NtGdiCombineRgn( hrgn
, hrgn
, tmp
, RGN_OR
);
4039 NtGdiDeleteObjectApp( tmp
);
4041 pt
= get_first_minimized_child_pos( &parent_rect
, &metrics
, width
, height
);
4044 SetRect( &rect
, pt
.x
, pt
.y
, pt
.x
+ width
, pt
.y
+ height
);
4045 if (!NtGdiRectInRegion( hrgn
, &rect
))
4048 get_next_minimized_child_pos( &parent_rect
, &metrics
, width
, height
, &pt
);
4051 NtGdiDeleteObjectApp( hrgn
);
4055 /***********************************************************************
4056 * window_min_maximize
4058 static UINT
window_min_maximize( HWND hwnd
, UINT cmd
, RECT
*rect
)
4063 WINDOWPLACEMENT wpl
;
4065 TRACE( "%p %u\n", hwnd
, cmd
);
4067 wpl
.length
= sizeof(wpl
);
4068 NtUserGetWindowPlacement( hwnd
, &wpl
);
4070 if (call_hooks( WH_CBT
, HCBT_MINMAX
, (WPARAM
)hwnd
, cmd
, 0 ))
4071 return SWP_NOSIZE
| SWP_NOMOVE
;
4073 if (is_iconic( hwnd
))
4077 case SW_SHOWMINNOACTIVE
:
4078 case SW_SHOWMINIMIZED
:
4079 case SW_FORCEMINIMIZE
:
4081 wpl
.ptMinPosition
= get_minimized_pos( hwnd
, wpl
.ptMinPosition
);
4083 SetRect( rect
, wpl
.ptMinPosition
.x
, wpl
.ptMinPosition
.y
,
4084 wpl
.ptMinPosition
.x
+ get_system_metrics( SM_CXMINIMIZED
),
4085 wpl
.ptMinPosition
.y
+ get_system_metrics( SM_CYMINIMIZED
));
4086 return SWP_NOSIZE
| SWP_NOMOVE
;
4088 if (!send_message( hwnd
, WM_QUERYOPEN
, 0, 0 )) return SWP_NOSIZE
| SWP_NOMOVE
;
4089 swp_flags
|= SWP_NOCOPYBITS
;
4094 case SW_SHOWMINNOACTIVE
:
4095 case SW_SHOWMINIMIZED
:
4096 case SW_FORCEMINIMIZE
:
4098 if (is_zoomed( hwnd
)) win_set_flags( hwnd
, WIN_RESTORE_MAX
, 0 );
4099 else win_set_flags( hwnd
, 0, WIN_RESTORE_MAX
);
4101 if (get_focus() == hwnd
)
4103 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
)
4104 NtUserSetFocus( NtUserGetAncestor( hwnd
, GA_PARENT
));
4106 NtUserSetFocus( 0 );
4109 old_style
= set_window_style( hwnd
, WS_MINIMIZE
, WS_MAXIMIZE
);
4111 wpl
.ptMinPosition
= get_minimized_pos( hwnd
, wpl
.ptMinPosition
);
4113 if (!(old_style
& WS_MINIMIZE
)) swp_flags
|= SWP_STATECHANGED
;
4114 SetRect( rect
, wpl
.ptMinPosition
.x
, wpl
.ptMinPosition
.y
,
4115 wpl
.ptMinPosition
.x
+ get_system_metrics(SM_CXMINIMIZED
),
4116 wpl
.ptMinPosition
.y
+ get_system_metrics(SM_CYMINIMIZED
) );
4117 swp_flags
|= SWP_NOCOPYBITS
;
4121 old_style
= get_window_long( hwnd
, GWL_STYLE
);
4122 if ((old_style
& WS_MAXIMIZE
) && (old_style
& WS_VISIBLE
)) return SWP_NOSIZE
| SWP_NOMOVE
;
4124 minmax
= get_min_max_info( hwnd
);
4126 old_style
= set_window_style( hwnd
, WS_MAXIMIZE
, WS_MINIMIZE
);
4127 if (old_style
& WS_MINIMIZE
)
4128 win_set_flags( hwnd
, WIN_RESTORE_MAX
, 0 );
4130 if (!(old_style
& WS_MAXIMIZE
)) swp_flags
|= SWP_STATECHANGED
;
4131 SetRect( rect
, minmax
.ptMaxPosition
.x
, minmax
.ptMaxPosition
.y
,
4132 minmax
.ptMaxPosition
.x
+ minmax
.ptMaxSize
.x
,
4133 minmax
.ptMaxPosition
.y
+ minmax
.ptMaxSize
.y
);
4136 case SW_SHOWNOACTIVATE
:
4137 win_set_flags( hwnd
, 0, WIN_RESTORE_MAX
);
4141 case SW_SHOWDEFAULT
: /* FIXME: should have its own handler */
4142 old_style
= set_window_style( hwnd
, 0, WS_MINIMIZE
| WS_MAXIMIZE
);
4143 if (old_style
& WS_MINIMIZE
)
4145 if (win_get_flags( hwnd
) & WIN_RESTORE_MAX
)
4147 /* Restore to maximized position */
4148 minmax
= get_min_max_info( hwnd
);
4149 set_window_style( hwnd
, WS_MAXIMIZE
, 0 );
4150 swp_flags
|= SWP_STATECHANGED
;
4151 SetRect( rect
, minmax
.ptMaxPosition
.x
, minmax
.ptMaxPosition
.y
,
4152 minmax
.ptMaxPosition
.x
+ minmax
.ptMaxSize
.x
,
4153 minmax
.ptMaxPosition
.y
+ minmax
.ptMaxSize
.y
);
4157 else if (!(old_style
& WS_MAXIMIZE
)) break;
4159 swp_flags
|= SWP_STATECHANGED
;
4161 /* Restore to normal position */
4163 *rect
= wpl
.rcNormalPosition
;
4170 /* see ArrangeIconicWindows */
4171 static UINT
arrange_iconic_windows( HWND parent
)
4173 int width
, height
, count
= 0;
4174 MINIMIZEDMETRICS metrics
;
4179 metrics
.cbSize
= sizeof(metrics
);
4180 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(metrics
), &metrics
, 0 );
4181 width
= get_system_metrics( SM_CXMINIMIZED
);
4182 height
= get_system_metrics( SM_CYMINIMIZED
);
4184 if (parent
== get_desktop_window())
4186 MONITORINFO mon_info
;
4187 HMONITOR monitor
= monitor_from_window( 0, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
4189 mon_info
.cbSize
= sizeof( mon_info
);
4190 get_monitor_info( monitor
, &mon_info
);
4191 parent_rect
= mon_info
.rcWork
;
4193 else get_client_rect( parent
, &parent_rect
);
4195 pt
= get_first_minimized_child_pos( &parent_rect
, &metrics
, width
, height
);
4197 child
= get_window_relative( parent
, GW_CHILD
);
4200 if (is_iconic( child
))
4202 NtUserSetWindowPos( child
, 0, pt
.x
, pt
.y
, 0, 0,
4203 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
4204 get_next_minimized_child_pos( &parent_rect
, &metrics
, width
, height
, &pt
);
4207 child
= get_window_relative( child
, GW_HWNDNEXT
);
4212 /*******************************************************************
4213 * update_window_state
4215 * Trigger an update of the window's driver state and surface.
4217 void update_window_state( HWND hwnd
)
4219 DPI_AWARENESS_CONTEXT context
;
4220 RECT window_rect
, client_rect
, valid_rects
[2];
4222 if (!is_current_thread_window( hwnd
))
4224 NtUserPostMessage( hwnd
, WM_WINE_UPDATEWINDOWSTATE
, 0, 0 );
4228 context
= SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( hwnd
));
4229 get_window_rects( hwnd
, COORDS_PARENT
, &window_rect
, &client_rect
, get_thread_dpi() );
4230 valid_rects
[0] = valid_rects
[1] = client_rect
;
4231 apply_window_pos( hwnd
, 0, SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOCLIENTSIZE
| SWP_NOCLIENTMOVE
|
4232 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREDRAW
,
4233 &window_rect
, &client_rect
, valid_rects
);
4234 SetThreadDpiAwarenessContext( context
);
4237 /***********************************************************************
4240 * Implementation of ShowWindow and ShowWindowAsync.
4242 static BOOL
show_window( HWND hwnd
, INT cmd
)
4246 DPI_AWARENESS_CONTEXT context
;
4247 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
4248 BOOL was_visible
= (style
& WS_VISIBLE
) != 0;
4249 BOOL show_flag
= TRUE
;
4250 RECT newPos
= {0, 0, 0, 0};
4251 UINT new_swp
, swp
= 0;
4253 TRACE( "hwnd=%p, cmd=%d, was_visible %d\n", hwnd
, cmd
, was_visible
);
4255 context
= SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( hwnd
));
4260 if (!was_visible
) goto done
;
4262 swp
|= SWP_HIDEWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
4263 if (style
& WS_CHILD
) swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4266 case SW_SHOWMINNOACTIVE
:
4268 case SW_FORCEMINIMIZE
: /* FIXME: Does not work if thread is hung. */
4269 swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4271 case SW_SHOWMINIMIZED
:
4272 swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
4273 swp
|= window_min_maximize( hwnd
, cmd
, &newPos
);
4274 if ((style
& WS_MINIMIZE
) && was_visible
) goto done
;
4277 case SW_SHOWMAXIMIZED
: /* same as SW_MAXIMIZE */
4278 if (!was_visible
) swp
|= SWP_SHOWWINDOW
;
4279 swp
|= SWP_FRAMECHANGED
;
4280 swp
|= window_min_maximize( hwnd
, SW_MAXIMIZE
, &newPos
);
4281 if ((style
& WS_MAXIMIZE
) && was_visible
) goto done
;
4285 swp
|= SWP_NOACTIVATE
| SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
4286 if (style
& WS_CHILD
) swp
|= SWP_NOZORDER
;
4290 if (was_visible
) goto done
;
4291 swp
|= SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
4292 if (style
& WS_CHILD
) swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4295 case SW_SHOWNOACTIVATE
:
4296 swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4300 case SW_SHOWNORMAL
: /* same as SW_NORMAL: */
4301 case SW_SHOWDEFAULT
: /* FIXME: should have its own handler */
4302 if (!was_visible
) swp
|= SWP_SHOWWINDOW
;
4303 if (style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
4305 swp
|= SWP_FRAMECHANGED
;
4306 swp
|= window_min_maximize( hwnd
, cmd
, &newPos
);
4310 if (was_visible
) goto done
;
4311 swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
4313 if (style
& WS_CHILD
&& !(swp
& SWP_STATECHANGED
)) swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4320 if ((show_flag
!= was_visible
|| cmd
== SW_SHOWNA
) && cmd
!= SW_SHOWMAXIMIZED
&& !(swp
& SWP_STATECHANGED
))
4322 send_message( hwnd
, WM_SHOWWINDOW
, show_flag
, 0 );
4323 if (!is_window( hwnd
)) goto done
;
4326 if (IsRectEmpty( &newPos
)) new_swp
= swp
;
4327 else if ((new_swp
= user_driver
->pShowWindow( hwnd
, cmd
, &newPos
, swp
)) == ~0)
4329 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) new_swp
= swp
;
4330 else if (is_iconic( hwnd
) && (newPos
.left
!= -32000 || newPos
.top
!= -32000))
4332 OffsetRect( &newPos
, -32000 - newPos
.left
, -32000 - newPos
.top
);
4333 new_swp
= swp
& ~(SWP_NOMOVE
| SWP_NOCLIENTMOVE
);
4339 parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
4340 if (parent
&& !is_window_visible( parent
) && !(swp
& SWP_STATECHANGED
))
4342 /* if parent is not visible simply toggle WS_VISIBLE and return */
4343 if (show_flag
) set_window_style( hwnd
, WS_VISIBLE
, 0 );
4344 else set_window_style( hwnd
, 0, WS_VISIBLE
);
4347 NtUserSetWindowPos( hwnd
, HWND_TOP
, newPos
.left
, newPos
.top
,
4348 newPos
.right
- newPos
.left
, newPos
.bottom
- newPos
.top
, swp
);
4354 /* FIXME: This will cause the window to be activated irrespective
4355 * of whether it is owned by the same thread. Has to be done
4359 if (hwnd
== get_active_window()) activate_other_window( hwnd
);
4361 /* Revert focus to parent */
4362 hFocus
= get_focus();
4365 HWND parent
= NtUserGetAncestor(hwnd
, GA_PARENT
);
4366 if (parent
== get_desktop_window()) parent
= 0;
4367 NtUserSetFocus(parent
);
4372 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
) goto done
;
4374 if (win
->flags
& WIN_NEED_SIZE
)
4376 /* should happen only in CreateWindowEx() */
4377 int wParam
= SIZE_RESTORED
;
4381 get_window_rects( hwnd
, COORDS_PARENT
, NULL
, &client
, get_thread_dpi() );
4382 lparam
= MAKELONG( client
.right
- client
.left
, client
.bottom
- client
.top
);
4383 win
->flags
&= ~WIN_NEED_SIZE
;
4384 if (win
->dwStyle
& WS_MAXIMIZE
) wParam
= SIZE_MAXIMIZED
;
4385 else if (win
->dwStyle
& WS_MINIMIZE
)
4387 wParam
= SIZE_MINIMIZED
;
4390 release_win_ptr( win
);
4392 send_message( hwnd
, WM_SIZE
, wParam
, lparam
);
4393 send_message( hwnd
, WM_MOVE
, 0, MAKELONG( client
.left
, client
.top
));
4395 else release_win_ptr( win
);
4397 /* if previous state was minimized Windows sets focus to the window */
4398 if (style
& WS_MINIMIZE
)
4400 NtUserSetFocus( hwnd
);
4401 /* Send a WM_ACTIVATE message for a top level window, even if the window is already active */
4402 if (NtUserGetAncestor( hwnd
, GA_ROOT
) == hwnd
&& !(swp
& SWP_NOACTIVATE
))
4403 send_message( hwnd
, WM_ACTIVATE
, WA_ACTIVE
, 0 );
4407 SetThreadDpiAwarenessContext( context
);
4411 /***********************************************************************
4412 * NtUserShowWindowAsync (win32u.@)
4414 * doesn't wait; returns immediately.
4415 * used by threads to toggle windows in other (possibly hanging) threads
4417 BOOL WINAPI
NtUserShowWindowAsync( HWND hwnd
, INT cmd
)
4421 if (is_broadcast(hwnd
))
4423 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4427 if ((full_handle
= is_current_thread_window( hwnd
)))
4428 return show_window( full_handle
, cmd
);
4430 return NtUserMessageCall( hwnd
, WM_WINE_SHOWWINDOW
, cmd
, 0, 0,
4431 NtUserSendNotifyMessage
, FALSE
);
4434 /***********************************************************************
4435 * NtUserShowWindow (win32u.@)
4437 BOOL WINAPI
NtUserShowWindow( HWND hwnd
, INT cmd
)
4441 if (is_broadcast(hwnd
))
4443 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4446 if ((full_handle
= is_current_thread_window( hwnd
)))
4447 return show_window( full_handle
, cmd
);
4449 if ((cmd
== SW_HIDE
) && !(get_window_long( hwnd
, GWL_STYLE
) & WS_VISIBLE
))
4452 if ((cmd
== SW_SHOW
) && (get_window_long( hwnd
, GWL_STYLE
) & WS_VISIBLE
))
4455 return send_message( hwnd
, WM_WINE_SHOWWINDOW
, cmd
, 0 );
4458 /* see ShowOwnedPopups */
4459 BOOL
show_owned_popups( HWND owner
, BOOL show
)
4462 HWND
*win_array
= list_window_children( 0, get_desktop_window(), NULL
, 0 );
4464 if (!win_array
) return TRUE
;
4466 while (win_array
[count
]) count
++;
4467 while (--count
>= 0)
4469 if (get_window_relative( win_array
[count
], GW_OWNER
) != owner
) continue;
4472 if (win_get_flags( win_array
[count
] ) & WIN_NEEDS_SHOW_OWNEDPOPUP
)
4473 /* In Windows, ShowOwnedPopups(TRUE) generates
4474 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
4475 * regardless of the state of the owner
4477 send_message( win_array
[count
], WM_SHOWWINDOW
, SW_SHOWNORMAL
, SW_PARENTOPENING
);
4481 if (get_window_long( win_array
[count
], GWL_STYLE
) & WS_VISIBLE
)
4482 /* In Windows, ShowOwnedPopups(FALSE) generates
4483 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
4484 * regardless of the state of the owner
4486 send_message( win_array
[count
], WM_SHOWWINDOW
, SW_HIDE
, SW_PARENTCLOSING
);
4494 /*******************************************************************
4495 * NtUserFlashWindowEx (win32u.@)
4497 BOOL WINAPI
NtUserFlashWindowEx( FLASHWINFO
*info
)
4501 TRACE( "%p\n", info
);
4505 RtlSetLastWin32Error( ERROR_NOACCESS
);
4509 if (!info
->hwnd
|| info
->cbSize
!= sizeof(FLASHWINFO
) || !is_window( info
->hwnd
))
4511 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4514 FIXME( "%p - semi-stub\n", info
);
4516 if (is_iconic( info
->hwnd
))
4518 NtUserRedrawWindow( info
->hwnd
, 0, 0, RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_FRAME
);
4520 win
= get_win_ptr( info
->hwnd
);
4521 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
4522 if (info
->dwFlags
& FLASHW_CAPTION
&& !(win
->flags
& WIN_NCACTIVATED
))
4524 win
->flags
|= WIN_NCACTIVATED
;
4526 else if (!info
->dwFlags
)
4528 win
->flags
&= ~WIN_NCACTIVATED
;
4530 release_win_ptr( win
);
4531 user_driver
->pFlashWindowEx( info
);
4537 HWND hwnd
= info
->hwnd
;
4539 win
= get_win_ptr( hwnd
);
4540 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
4541 hwnd
= win
->obj
.handle
; /* make it a full handle */
4543 if (info
->dwFlags
) wparam
= !(win
->flags
& WIN_NCACTIVATED
);
4544 else wparam
= (hwnd
== NtUserGetForegroundWindow());
4546 release_win_ptr( win
);
4548 if (!info
->dwFlags
|| info
->dwFlags
& FLASHW_CAPTION
)
4549 send_message( hwnd
, WM_NCACTIVATE
, wparam
, 0 );
4551 user_driver
->pFlashWindowEx( info
);
4556 /* see GetWindowContextHelpId */
4557 DWORD
get_window_context_help_id( HWND hwnd
)
4560 WND
*win
= get_win_ptr( hwnd
);
4561 if (!win
|| win
== WND_DESKTOP
) return 0;
4562 if (win
== WND_OTHER_PROCESS
)
4564 if (is_window( hwnd
)) FIXME( "not supported on other process window %p\n", hwnd
);
4567 retval
= win
->helpContext
;
4568 release_win_ptr( win
);
4572 /* see SetWindowContextHelpId */
4573 static BOOL
set_window_context_help_id( HWND hwnd
, DWORD id
)
4575 WND
*win
= get_win_ptr( hwnd
);
4576 if (!win
|| win
== WND_DESKTOP
) return FALSE
;
4577 if (win
== WND_OTHER_PROCESS
)
4579 if (is_window( hwnd
)) FIXME( "not supported on other process window %p\n", hwnd
);
4582 win
->helpContext
= id
;
4583 release_win_ptr( win
);
4587 /***********************************************************************
4588 * NtUserInternalGetWindowIcon (win32u.@)
4590 HICON WINAPI
NtUserInternalGetWindowIcon( HWND hwnd
, UINT type
)
4592 WND
*win
= get_win_ptr( hwnd
);
4595 TRACE( "hwnd %p, type %#x\n", hwnd
, type
);
4599 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
4602 if (win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
)
4604 if (is_window( hwnd
)) FIXME( "not supported on other process window %p\n", hwnd
);
4612 if (!ret
) ret
= (HICON
)get_class_long_ptr( hwnd
, GCLP_HICON
, FALSE
);
4617 ret
= win
->hIconSmall
? win
->hIconSmall
: win
->hIconSmall2
;
4618 if (!ret
) ret
= (HICON
)get_class_long_ptr( hwnd
, GCLP_HICONSM
, FALSE
);
4619 if (!ret
) ret
= (HICON
)get_class_long_ptr( hwnd
, GCLP_HICON
, FALSE
);
4623 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4624 release_win_ptr( win
);
4627 release_win_ptr( win
);
4629 if (!ret
) ret
= LoadImageW( 0, (const WCHAR
*)IDI_APPLICATION
, IMAGE_ICON
,
4630 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
4632 return CopyImage( ret
, IMAGE_ICON
, 0, 0, 0 );
4635 /***********************************************************************
4636 * send_destroy_message
4638 static void send_destroy_message( HWND hwnd
)
4642 info
.cbSize
= sizeof(info
);
4643 if (NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
))
4645 if (hwnd
== info
.hwndCaret
) destroy_caret();
4646 if (hwnd
== info
.hwndActive
) activate_other_window( hwnd
);
4649 if (hwnd
== NtUserGetClipboardOwner()) release_clipboard_owner( hwnd
);
4651 send_message( hwnd
, WM_DESTROY
, 0, 0);
4654 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
4655 * make sure that the window still exists when we come back.
4657 if (is_window(hwnd
))
4662 if (!(children
= list_window_children( 0, hwnd
, NULL
, 0 ))) return;
4664 for (i
= 0; children
[i
]; i
++)
4666 if (is_window( children
[i
] )) send_destroy_message( children
[i
] );
4671 WARN( "\tdestroyed itself while in WM_DESTROY!\n" );
4674 /***********************************************************************
4675 * free_window_handle
4677 * Free a window handle.
4679 static void free_window_handle( HWND hwnd
)
4685 if ((win
= get_user_handle_ptr( hwnd
, NTUSER_OBJ_WINDOW
)) && win
!= OBJ_OTHER_PROCESS
)
4687 SERVER_START_REQ( destroy_window
)
4689 req
->handle
= wine_server_user_handle( hwnd
);
4690 wine_server_call( req
);
4691 set_user_handle_ptr( hwnd
, NULL
);
4695 free( win
->pScroll
);
4701 /***********************************************************************
4704 LRESULT
destroy_window( HWND hwnd
)
4706 struct window_surface
*surface
;
4707 HMENU menu
= 0, sys_menu
;
4711 TRACE( "%p\n", hwnd
);
4713 unregister_imm_window( hwnd
);
4715 /* free child windows */
4716 if ((children
= list_window_children( 0, hwnd
, NULL
, 0 )))
4719 for (i
= 0; children
[i
]; i
++)
4721 if (is_current_thread_window( children
[i
] ))
4722 destroy_window( children
[i
] );
4724 NtUserMessageCall( children
[i
], WM_WINE_DESTROYWINDOW
, 0, 0,
4725 0, NtUserSendNotifyMessage
, FALSE
);
4730 /* Unlink now so we won't bother with the children later on */
4731 SERVER_START_REQ( set_parent
)
4733 req
->handle
= wine_server_user_handle( hwnd
);
4735 wine_server_call( req
);
4739 send_message( hwnd
, WM_NCDESTROY
, 0, 0 );
4741 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
4743 /* free resources associated with the window */
4745 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
) return 0;
4746 if ((win
->dwStyle
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
)
4747 menu
= (HMENU
)win
->wIDmenu
;
4748 sys_menu
= win
->hSysMenu
;
4749 free_dce( win
->dce
, hwnd
);
4751 NtUserDestroyCursor( win
->hIconSmall2
, 0 );
4752 surface
= win
->surface
;
4753 win
->surface
= NULL
;
4754 release_win_ptr( win
);
4756 NtUserDestroyMenu( menu
);
4757 NtUserDestroyMenu( sys_menu
);
4760 register_window_surface( surface
, NULL
);
4761 window_surface_release( surface
);
4764 user_driver
->pDestroyWindow( hwnd
);
4766 free_window_handle( hwnd
);
4770 /***********************************************************************
4771 * NtUserDestroyWindow (win32u.@)
4773 BOOL WINAPI
NtUserDestroyWindow( HWND hwnd
)
4777 if (!(hwnd
= is_current_thread_window( hwnd
)) || is_desktop_window( hwnd
))
4779 RtlSetLastWin32Error( ERROR_ACCESS_DENIED
);
4783 TRACE( "(%p)\n", hwnd
);
4785 if (call_hooks( WH_CBT
, HCBT_DESTROYWND
, (WPARAM
)hwnd
, 0, 0 )) return FALSE
;
4787 if (is_menu_active() == hwnd
) NtUserEndMenu();
4789 is_child
= (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) != 0;
4793 if (!is_exiting_thread( GetCurrentThreadId() ))
4794 send_parent_notify( hwnd
, WM_DESTROY
);
4796 else if (!get_window_relative( hwnd
, GW_OWNER
))
4798 call_hooks( WH_SHELL
, HSHELL_WINDOWDESTROYED
, (WPARAM
)hwnd
, 0, 0 );
4799 /* FIXME: clean up palette - see "Internals" p.352 */
4802 if (!is_window( hwnd
)) return TRUE
;
4804 /* Hide the window */
4805 if (get_window_long( hwnd
, GWL_STYLE
) & WS_VISIBLE
)
4807 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
4809 NtUserShowWindow( hwnd
, SW_HIDE
);
4811 NtUserSetWindowPos( hwnd
, 0, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
|
4812 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_HIDEWINDOW
);
4815 if (!is_window( hwnd
)) return TRUE
;
4817 /* Recursively destroy child windows */
4822 BOOL got_one
= FALSE
;
4826 if (!(children
= list_window_children( 0, get_desktop_window(), NULL
, 0 ))) break;
4828 for (i
= 0; children
[i
]; i
++)
4830 if (get_window_relative( children
[i
], GW_OWNER
) != hwnd
) continue;
4831 if (is_current_thread_window( children
[i
] ))
4833 NtUserDestroyWindow( children
[i
] );
4837 set_window_owner( children
[i
], 0 );
4840 if (!got_one
) break;
4844 send_destroy_message( hwnd
);
4845 if (!is_window( hwnd
)) return TRUE
;
4847 destroy_window( hwnd
);
4851 /*****************************************************************************
4852 * destroy_thread_windows
4854 * Destroy all window owned by the current thread.
4856 void destroy_thread_windows(void)
4858 WND
*win
, *free_list
= NULL
;
4862 while ((win
= next_process_user_handle_ptr( &handle
, NTUSER_OBJ_WINDOW
)))
4864 if (win
->tid
!= GetCurrentThreadId()) continue;
4865 free_dce( win
->dce
, win
->obj
.handle
);
4866 set_user_handle_ptr( handle
, NULL
);
4867 win
->obj
.handle
= free_list
;
4872 SERVER_START_REQ( destroy_window
)
4874 req
->handle
= 0; /* destroy all thread windows */
4875 wine_server_call( req
);
4881 while ((win
= free_list
))
4883 free_list
= win
->obj
.handle
;
4884 TRACE( "destroying %p\n", win
);
4886 if ((win
->dwStyle
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
&& win
->wIDmenu
)
4887 NtUserDestroyMenu( UlongToHandle(win
->wIDmenu
) );
4888 if (win
->hSysMenu
) NtUserDestroyMenu( win
->hSysMenu
);
4891 register_window_surface( win
->surface
, NULL
);
4892 window_surface_release( win
->surface
);
4894 free( win
->pScroll
);
4900 /***********************************************************************
4901 * create_window_handle
4903 * Create a window handle with the server.
4905 static WND
*create_window_handle( HWND parent
, HWND owner
, UNICODE_STRING
*name
,
4906 HINSTANCE instance
, BOOL ansi
,
4907 DWORD style
, DWORD ex_style
)
4909 DPI_AWARENESS awareness
= get_thread_dpi_awareness();
4910 HWND handle
= 0, full_parent
= 0, full_owner
= 0;
4911 struct tagCLASS
*class = NULL
;
4912 int extra_bytes
= 0;
4916 SERVER_START_REQ( create_window
)
4918 req
->parent
= wine_server_user_handle( parent
);
4919 req
->owner
= wine_server_user_handle( owner
);
4920 req
->instance
= wine_server_client_ptr( instance
);
4921 req
->dpi
= get_system_dpi();
4922 req
->awareness
= awareness
;
4924 req
->ex_style
= ex_style
;
4925 if (!(req
->atom
= get_int_atom_value( name
)) && name
->Length
)
4926 wine_server_add_data( req
, name
->Buffer
, name
->Length
);
4927 if (!wine_server_call_err( req
))
4929 handle
= wine_server_ptr_handle( reply
->handle
);
4930 full_parent
= wine_server_ptr_handle( reply
->parent
);
4931 full_owner
= wine_server_ptr_handle( reply
->owner
);
4932 extra_bytes
= reply
->extra
;
4934 awareness
= reply
->awareness
;
4935 class = wine_server_get_ptr( reply
->class_ptr
);
4942 WARN( "error %d creating window\n", (int)RtlGetLastWin32Error() );
4946 if (!(win
= calloc( 1, FIELD_OFFSET(WND
, wExtra
) + extra_bytes
)))
4948 SERVER_START_REQ( destroy_window
)
4950 req
->handle
= wine_server_user_handle( handle
);
4951 wine_server_call( req
);
4954 RtlSetLastWin32Error( ERROR_NOT_ENOUGH_MEMORY
);
4958 if (!parent
) /* if parent is 0 we don't have a desktop window yet */
4960 struct ntuser_thread_info
*thread_info
= NtUserGetThreadInfo();
4962 if (name
->Buffer
== (const WCHAR
*)DESKTOP_CLASS_ATOM
)
4964 if (!thread_info
->top_window
) thread_info
->top_window
= HandleToUlong( full_parent
? full_parent
: handle
);
4965 else assert( full_parent
== UlongToHandle( thread_info
->top_window
));
4966 if (!thread_info
->top_window
) ERR_(win
)( "failed to create desktop window\n" );
4967 else user_driver
->pSetDesktopWindow( UlongToHandle( thread_info
->top_window
));
4968 register_builtin_classes();
4970 else /* HWND_MESSAGE parent */
4972 if (!thread_info
->msg_window
&& !full_parent
)
4973 thread_info
->msg_window
= HandleToUlong( handle
);
4979 win
->obj
.handle
= handle
;
4980 win
->obj
.type
= NTUSER_OBJ_WINDOW
;
4981 win
->parent
= full_parent
;
4982 win
->owner
= full_owner
;
4984 win
->winproc
= get_class_winproc( class );
4985 win
->cbWndExtra
= extra_bytes
;
4987 win
->dpi_awareness
= awareness
;
4988 set_user_handle_ptr( handle
, &win
->obj
);
4989 if (is_winproc_unicode( win
->winproc
, !ansi
)) win
->flags
|= WIN_ISUNICODE
;
4993 static BOOL
is_default_coord( int x
)
4995 return x
== CW_USEDEFAULT
|| x
== 0x8000;
4998 /***********************************************************************
4999 * fix_cs_coordinates
5001 * Fix the coordinates and return default show mode in sw.
5003 static void fix_cs_coordinates( CREATESTRUCTW
*cs
, INT
*sw
)
5005 if (cs
->style
& (WS_CHILD
| WS_POPUP
))
5007 if (is_default_coord(cs
->x
)) cs
->x
= cs
->y
= 0;
5008 if (is_default_coord(cs
->cx
)) cs
->cx
= cs
->cy
= 0;
5010 else /* overlapped window */
5012 RTL_USER_PROCESS_PARAMETERS
*params
= NtCurrentTeb()->Peb
->ProcessParameters
;
5014 MONITORINFO mon_info
;
5016 if (!is_default_coord( cs
->x
) && !is_default_coord( cs
->cx
) && !is_default_coord( cs
->cy
))
5019 monitor
= monitor_from_window( cs
->hwndParent
, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
5020 mon_info
.cbSize
= sizeof(mon_info
);
5021 get_monitor_info( monitor
, &mon_info
);
5023 if (is_default_coord( cs
->x
))
5025 if (!is_default_coord( cs
->y
)) *sw
= cs
->y
;
5026 cs
->x
= (params
->dwFlags
& STARTF_USEPOSITION
) ? params
->dwX
: mon_info
.rcWork
.left
;
5027 cs
->y
= (params
->dwFlags
& STARTF_USEPOSITION
) ? params
->dwY
: mon_info
.rcWork
.top
;
5030 if (is_default_coord( cs
->cx
))
5032 if (params
->dwFlags
& STARTF_USESIZE
)
5034 cs
->cx
= params
->dwXSize
;
5035 cs
->cy
= params
->dwYSize
;
5039 cs
->cx
= (mon_info
.rcWork
.right
- mon_info
.rcWork
.left
) * 3 / 4 - cs
->x
;
5040 cs
->cy
= (mon_info
.rcWork
.bottom
- mon_info
.rcWork
.top
) * 3 / 4 - cs
->y
;
5043 /* neither x nor cx are default. Check the y values.
5044 * In the trace we see Outlook and Outlook Express using
5045 * cy set to CW_USEDEFAULT when opening the address book.
5047 else if (is_default_coord( cs
->cy
))
5049 FIXME( "Strange use of CW_USEDEFAULT in cy\n" );
5050 cs
->cy
= (mon_info
.rcWork
.bottom
- mon_info
.rcWork
.top
) * 3 / 4 - cs
->y
;
5055 /***********************************************************************
5056 * map_dpi_create_struct
5058 static void map_dpi_create_struct( CREATESTRUCTW
*cs
, UINT dpi_from
, UINT dpi_to
)
5060 if (!dpi_from
&& !dpi_to
) return;
5061 if (!dpi_from
|| !dpi_to
)
5063 POINT pt
= { cs
->x
, cs
->y
};
5064 UINT mon_dpi
= get_monitor_dpi( monitor_from_point( pt
, MONITOR_DEFAULTTONEAREST
, dpi_from
));
5065 if (!dpi_from
) dpi_from
= mon_dpi
;
5066 else dpi_to
= mon_dpi
;
5068 if (dpi_from
== dpi_to
) return;
5069 cs
->x
= muldiv( cs
->x
, dpi_to
, dpi_from
);
5070 cs
->y
= muldiv( cs
->y
, dpi_to
, dpi_from
);
5071 cs
->cx
= muldiv( cs
->cx
, dpi_to
, dpi_from
);
5072 cs
->cy
= muldiv( cs
->cy
, dpi_to
, dpi_from
);
5075 /***********************************************************************
5076 * NtUserCreateWindowEx (win32u.@)
5078 HWND WINAPI
NtUserCreateWindowEx( DWORD ex_style
, UNICODE_STRING
*class_name
,
5079 UNICODE_STRING
*version
, UNICODE_STRING
*window_name
,
5080 DWORD style
, INT x
, INT y
, INT cx
, INT cy
,
5081 HWND parent
, HMENU menu
, HINSTANCE instance
, void *params
,
5082 DWORD flags
, HINSTANCE client_instance
, DWORD unk
, BOOL ansi
)
5084 UINT win_dpi
, thread_dpi
= get_thread_dpi();
5085 DPI_AWARENESS_CONTEXT context
;
5086 CBT_CREATEWNDW cbtc
;
5087 HWND hwnd
, owner
= 0;
5093 static const WCHAR messageW
[] = {'M','e','s','s','a','g','e'};
5095 cs
.lpCreateParams
= params
;
5096 cs
.hInstance
= client_instance
? client_instance
: instance
;
5098 cs
.hwndParent
= parent
;
5100 cs
.dwExStyle
= ex_style
;
5101 cs
.lpszName
= window_name
? window_name
->Buffer
: NULL
;
5102 cs
.lpszClass
= class_name
? class_name
->Buffer
: NULL
;
5108 /* Find the parent window */
5109 if (parent
== HWND_MESSAGE
)
5111 cs
.hwndParent
= parent
= get_hwnd_message_parent();
5115 if ((cs
.style
& (WS_CHILD
|WS_POPUP
)) != WS_CHILD
)
5118 parent
= get_desktop_window();
5122 DWORD parent_style
= get_window_long( parent
, GWL_EXSTYLE
);
5123 if ((parent_style
& WS_EX_LAYOUTRTL
) && !(parent_style
& WS_EX_NOINHERITLAYOUT
))
5124 cs
.dwExStyle
|= WS_EX_LAYOUTRTL
;
5129 if ((cs
.style
& (WS_CHILD
|WS_POPUP
)) == WS_CHILD
)
5131 WARN( "No parent for child window\n" );
5132 RtlSetLastWin32Error( ERROR_TLW_WITH_WSCHILD
);
5133 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
5136 /* are we creating the desktop or HWND_MESSAGE parent itself? */
5137 if (class_name
->Buffer
!= (LPCWSTR
)DESKTOP_CLASS_ATOM
&&
5138 (class_name
->Length
!= sizeof(messageW
) ||
5139 wcsnicmp( class_name
->Buffer
, messageW
, ARRAYSIZE(messageW
) )))
5141 if (get_process_layout() & LAYOUT_RTL
) cs
.dwExStyle
|= WS_EX_LAYOUTRTL
;
5142 parent
= get_desktop_window();
5146 fix_cs_coordinates( &cs
, &sw
);
5147 cs
.dwExStyle
= fix_exstyle( cs
.style
, cs
.dwExStyle
);
5149 /* Create the window structure */
5151 style
= cs
.style
& ~WS_VISIBLE
;
5152 ex_style
= cs
.dwExStyle
& ~WS_EX_LAYERED
;
5153 if (!(win
= create_window_handle( parent
, owner
, class_name
, instance
, ansi
, style
, ex_style
)))
5155 hwnd
= win
->obj
.handle
;
5157 /* Fill the window structure */
5159 win
->tid
= GetCurrentThreadId();
5160 win
->hInstance
= cs
.hInstance
;
5162 win
->dwStyle
= style
;
5163 win
->dwExStyle
= ex_style
;
5165 win
->helpContext
= 0;
5166 win
->pScroll
= NULL
;
5169 win
->hIconSmall
= 0;
5170 win
->hIconSmall2
= 0;
5173 win
->min_pos
.x
= win
->min_pos
.y
= -1;
5174 win
->max_pos
.x
= win
->max_pos
.y
= -1;
5175 SetRect( &win
->normal_rect
, cs
.x
, cs
.y
, cs
.x
+ cs
.cx
, cs
.y
+ cs
.cy
);
5177 if (win
->dwStyle
& WS_SYSMENU
) NtUserSetSystemMenu( hwnd
, 0 );
5179 win
->imc
= get_default_input_context();
5181 /* call the WH_CBT hook */
5183 release_win_ptr( win
);
5184 cbtc
.hwndInsertAfter
= HWND_TOP
;
5186 if (call_hooks( WH_CBT
, HCBT_CREATEWND
, (WPARAM
)hwnd
, (LPARAM
)&cbtc
, sizeof(cbtc
) ))
5188 free_window_handle( hwnd
);
5191 if (!(win
= get_win_ptr( hwnd
))) return 0;
5194 * Correct the window styles.
5196 * It affects only the style loaded into the WND structure.
5199 if ((win
->dwStyle
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
)
5201 win
->dwStyle
|= WS_CLIPSIBLINGS
;
5202 if (!(win
->dwStyle
& WS_POPUP
)) win
->dwStyle
|= WS_CAPTION
;
5205 win
->dwExStyle
= cs
.dwExStyle
;
5206 /* WS_EX_WINDOWEDGE depends on some other styles */
5207 if ((win
->dwStyle
& (WS_DLGFRAME
| WS_THICKFRAME
)) &&
5208 !(win
->dwStyle
& (WS_CHILD
| WS_POPUP
)))
5209 win
->dwExStyle
|= WS_EX_WINDOWEDGE
;
5211 if (!(win
->dwStyle
& (WS_CHILD
| WS_POPUP
))) win
->flags
|= WIN_NEED_SIZE
;
5213 SERVER_START_REQ( set_window_info
)
5215 req
->handle
= wine_server_user_handle( hwnd
);
5216 req
->flags
= SET_WIN_STYLE
| SET_WIN_EXSTYLE
| SET_WIN_INSTANCE
| SET_WIN_UNICODE
;
5217 req
->style
= win
->dwStyle
;
5218 req
->ex_style
= win
->dwExStyle
;
5219 req
->instance
= wine_server_client_ptr( win
->hInstance
);
5220 req
->is_unicode
= (win
->flags
& WIN_ISUNICODE
) != 0;
5221 req
->extra_offset
= -1;
5222 wine_server_call( req
);
5226 /* Set the window menu */
5228 if ((win
->dwStyle
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
)
5230 if (cs
.hMenu
&& !set_window_menu( hwnd
, cs
.hMenu
))
5232 release_win_ptr( win
);
5233 free_window_handle( hwnd
);
5237 else NtUserSetWindowLongPtr( hwnd
, GWLP_ID
, (ULONG_PTR
)cs
.hMenu
, FALSE
);
5240 release_win_ptr( win
);
5242 if (parent
) map_dpi_create_struct( &cs
, thread_dpi
, win_dpi
);
5244 context
= SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( hwnd
));
5246 /* send the WM_GETMINMAXINFO message and fix the size if needed */
5250 if ((cs
.style
& WS_THICKFRAME
) || !(cs
.style
& (WS_POPUP
| WS_CHILD
)))
5252 MINMAXINFO info
= get_min_max_info( hwnd
);
5253 cx
= max( min( cx
, info
.ptMaxTrackSize
.x
), info
.ptMinTrackSize
.x
);
5254 cy
= max( min( cy
, info
.ptMaxTrackSize
.y
), info
.ptMinTrackSize
.y
);
5259 SetRect( &rect
, cs
.x
, cs
.y
, cs
.x
+ cx
, cs
.y
+ cy
);
5260 /* check for wraparound */
5261 if (cs
.x
> 0x7fffffff - cx
) rect
.right
= 0x7fffffff;
5262 if (cs
.y
> 0x7fffffff - cy
) rect
.bottom
= 0x7fffffff;
5263 if (!apply_window_pos( hwnd
, 0, SWP_NOZORDER
| SWP_NOACTIVATE
, &rect
, &rect
, NULL
)) goto failed
;
5265 /* send WM_NCCREATE */
5267 TRACE( "hwnd %p cs %d,%d %dx%d %s\n", hwnd
, cs
.x
, cs
.y
, cs
.cx
, cs
.cy
, wine_dbgstr_rect(&rect
) );
5268 if (!send_message_timeout( hwnd
, WM_NCCREATE
, 0, (LPARAM
)&cs
, SMTO_NORMAL
, 0, ansi
))
5270 WARN( "%p: aborted by WM_NCCREATE\n", hwnd
);
5274 /* create default IME window */
5276 if (!is_desktop_window( hwnd
) && parent
!= get_hwnd_message_parent() &&
5277 register_imm_window( hwnd
))
5279 TRACE( "register IME window for %p\n", hwnd
);
5280 win_set_flags( hwnd
, WIN_HAS_IME_WIN
, 0 );
5283 /* send WM_NCCALCSIZE */
5285 if (get_window_rects( hwnd
, COORDS_PARENT
, &rect
, NULL
, win_dpi
))
5287 /* yes, even if the CBT hook was called with HWND_TOP */
5288 HWND insert_after
= (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) ? HWND_BOTTOM
: HWND_TOP
;
5289 RECT client_rect
= rect
;
5291 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
5292 map_window_points( parent
, 0, (POINT
*)&client_rect
, 2, win_dpi
);
5293 send_message( hwnd
, WM_NCCALCSIZE
, FALSE
, (LPARAM
)&client_rect
);
5294 map_window_points( 0, parent
, (POINT
*)&client_rect
, 2, win_dpi
);
5295 apply_window_pos( hwnd
, insert_after
, SWP_NOACTIVATE
, &rect
, &client_rect
, NULL
);
5299 /* send WM_CREATE */
5300 if (send_message_timeout( hwnd
, WM_CREATE
, 0, (LPARAM
)&cs
, SMTO_NORMAL
, 0, ansi
) == -1)
5303 /* call the driver */
5305 if (!user_driver
->pCreateWindow( hwnd
)) goto failed
;
5307 NtUserNotifyWinEvent( EVENT_OBJECT_CREATE
, hwnd
, OBJID_WINDOW
, 0 );
5309 /* send the size messages */
5311 if (!(win_get_flags( hwnd
) & WIN_NEED_SIZE
))
5313 get_window_rects( hwnd
, COORDS_PARENT
, NULL
, &rect
, win_dpi
);
5314 send_message( hwnd
, WM_SIZE
, SIZE_RESTORED
,
5315 MAKELONG(rect
.right
-rect
.left
, rect
.bottom
-rect
.top
));
5316 send_message( hwnd
, WM_MOVE
, 0, MAKELONG( rect
.left
, rect
.top
) );
5319 /* Show the window, maximizing or minimizing if needed */
5321 style
= set_window_style( hwnd
, 0, WS_MAXIMIZE
| WS_MINIMIZE
);
5322 if (style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
5325 UINT sw_flags
= (style
& WS_MINIMIZE
) ? SW_MINIMIZE
: SW_MAXIMIZE
;
5327 sw_flags
= window_min_maximize( hwnd
, sw_flags
, &new_pos
);
5328 sw_flags
|= SWP_FRAMECHANGED
; /* Frame always gets changed */
5329 if (!(style
& WS_VISIBLE
) || (style
& WS_CHILD
) || get_active_window())
5330 sw_flags
|= SWP_NOACTIVATE
;
5331 NtUserSetWindowPos( hwnd
, 0, new_pos
.left
, new_pos
.top
, new_pos
.right
- new_pos
.left
,
5332 new_pos
.bottom
- new_pos
.top
, sw_flags
);
5335 /* Notify the parent window only */
5337 send_parent_notify( hwnd
, WM_CREATE
);
5338 if (!is_window( hwnd
))
5340 SetThreadDpiAwarenessContext( context
);
5344 if (parent
== get_desktop_window())
5345 NtUserPostMessage( parent
, WM_PARENTNOTIFY
, WM_CREATE
, (LPARAM
)hwnd
);
5347 if (cs
.style
& WS_VISIBLE
)
5349 if (cs
.style
& WS_MAXIMIZE
)
5351 else if (cs
.style
& WS_MINIMIZE
)
5352 sw
= SW_SHOWMINIMIZED
;
5354 NtUserShowWindow( hwnd
, sw
);
5355 if (cs
.dwExStyle
& WS_EX_MDICHILD
)
5357 send_message( cs
.hwndParent
, WM_MDIREFRESHMENU
, 0, 0 );
5358 /* ShowWindow won't activate child windows */
5359 NtUserSetWindowPos( hwnd
, HWND_TOP
, 0, 0, 0, 0, SWP_SHOWWINDOW
| SWP_NOMOVE
| SWP_NOSIZE
);
5363 /* Call WH_SHELL hook */
5365 if (!(get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) && !get_window_relative( hwnd
, GW_OWNER
))
5366 call_hooks( WH_SHELL
, HSHELL_WINDOWCREATED
, (WPARAM
)hwnd
, 0, 0 );
5368 TRACE( "created window %p\n", hwnd
);
5369 SetThreadDpiAwarenessContext( context
);
5373 destroy_window( hwnd
);
5374 SetThreadDpiAwarenessContext( context
);
5378 static void *get_dialog_info( HWND hwnd
)
5383 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
)
5385 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
5390 release_win_ptr( win
);
5394 static BOOL
set_dialog_info( HWND hwnd
, void *info
)
5398 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
5399 win
->dlgInfo
= info
;
5400 release_win_ptr( win
);
5404 /*****************************************************************************
5405 * NtUserCallHwnd (win32u.@)
5407 ULONG_PTR WINAPI
NtUserCallHwnd( HWND hwnd
, DWORD code
)
5411 case NtUserCallHwnd_ActivateOtherWindow
:
5412 activate_other_window( hwnd
);
5415 case NtUserCallHwnd_ArrangeIconicWindows
:
5416 return arrange_iconic_windows( hwnd
);
5418 case NtUserCallHwnd_DrawMenuBar
:
5419 return draw_menu_bar( hwnd
);
5421 case NtUserCallHwnd_GetDefaultImeWindow
:
5422 return HandleToUlong( get_default_ime_window( hwnd
));
5424 case NtUserCallHwnd_GetDpiForWindow
:
5425 return get_dpi_for_window( hwnd
);
5427 case NtUserCallHwnd_GetParent
:
5428 return HandleToUlong( get_parent( hwnd
));
5430 case NtUserCallHwnd_GetDialogInfo
:
5431 return (ULONG_PTR
)get_dialog_info( hwnd
);
5433 case NtUserCallHwnd_GetMDIClientInfo
:
5434 if (!(win_get_flags( hwnd
) & WIN_ISMDICLIENT
)) return 0;
5435 return get_window_long_ptr( hwnd
, sizeof(void *), FALSE
);
5437 case NtUserCallHwnd_GetWindowContextHelpId
:
5438 return get_window_context_help_id( hwnd
);
5440 case NtUserCallHwnd_GetWindowDpiAwarenessContext
:
5441 return (ULONG_PTR
)get_window_dpi_awareness_context( hwnd
);
5443 case NtUserCallHwnd_GetWindowInputContext
:
5444 return HandleToUlong( get_window_input_context( hwnd
));
5446 case NtUserCallHwnd_GetWindowSysSubMenu
:
5447 return HandleToUlong( get_window_sys_sub_menu( hwnd
));
5449 case NtUserCallHwnd_GetWindowTextLength
:
5450 return get_server_window_text( hwnd
, NULL
, 0 );
5452 case NtUserCallHwnd_IsWindow
:
5453 return is_window( hwnd
);
5455 case NtUserCallHwnd_IsWindowEnabled
:
5456 return is_window_enabled( hwnd
);
5458 case NtUserCallHwnd_IsWindowUnicode
:
5459 return is_window_unicode( hwnd
);
5461 case NtUserCallHwnd_IsWindowVisible
:
5462 return is_window_visible( hwnd
);
5464 case NtUserCallHwnd_SetForegroundWindow
:
5465 return set_foreground_window( hwnd
, FALSE
);
5467 case NtUserCallHwnd_SetProgmanWindow
:
5468 return HandleToUlong( set_progman_window( hwnd
));
5470 case NtUserCallHwnd_SetTaskmanWindow
:
5471 return HandleToUlong( set_taskman_window( hwnd
));
5473 /* temporary exports */
5474 case NtUserGetFullWindowHandle
:
5475 return HandleToUlong( get_full_window_handle( hwnd
));
5477 case NtUserIsCurrehtProcessWindow
:
5478 return HandleToUlong( is_current_process_window( hwnd
));
5480 case NtUserIsCurrehtThreadWindow
:
5481 return HandleToUlong( is_current_thread_window( hwnd
));
5484 FIXME( "invalid code %u\n", (int)code
);
5489 /*****************************************************************************
5490 * NtUserCallHwndParam (win32u.@)
5492 ULONG_PTR WINAPI
NtUserCallHwndParam( HWND hwnd
, DWORD_PTR param
, DWORD code
)
5496 case NtUserCallHwndParam_ClientToScreen
:
5497 return client_to_screen( hwnd
, (POINT
*)param
);
5499 case NtUserCallHwndParam_EnableWindow
:
5500 return enable_window( hwnd
, param
);
5502 case NtUserCallHwndParam_GetChildRect
:
5503 return get_window_rects( hwnd
, COORDS_PARENT
, (RECT
*)param
, NULL
, get_thread_dpi() );
5505 case NtUserCallHwndParam_GetClassLongA
:
5506 return get_class_long( hwnd
, param
, TRUE
);
5508 case NtUserCallHwndParam_GetClassLongW
:
5509 return get_class_long( hwnd
, param
, FALSE
);
5511 case NtUserCallHwndParam_GetClassLongPtrA
:
5512 return get_class_long_ptr( hwnd
, param
, TRUE
);
5514 case NtUserCallHwndParam_GetClassLongPtrW
:
5515 return get_class_long_ptr( hwnd
, param
, FALSE
);
5517 case NtUserCallHwndParam_GetClassWord
:
5518 return get_class_word( hwnd
, param
);
5520 case NtUserCallHwndParam_GetClientRect
:
5521 return get_client_rect( hwnd
, (RECT
*)param
);
5523 case NtUserCallHwndParam_GetScrollInfo
:
5525 struct get_scroll_info_params
*params
= (void *)param
;
5526 return get_scroll_info( hwnd
, params
->bar
, params
->info
);
5529 case NtUserCallHwndParam_GetWindowInfo
:
5530 return get_window_info( hwnd
, (WINDOWINFO
*)param
);
5532 case NtUserCallHwndParam_GetWindowLongA
:
5533 return get_window_long_size( hwnd
, param
, sizeof(LONG
), TRUE
);
5535 case NtUserCallHwndParam_GetWindowLongW
:
5536 return get_window_long( hwnd
, param
);
5538 case NtUserCallHwndParam_GetWindowLongPtrA
:
5539 return get_window_long_ptr( hwnd
, param
, TRUE
);
5541 case NtUserCallHwndParam_GetWindowLongPtrW
:
5542 return get_window_long_ptr( hwnd
, param
, FALSE
);
5544 case NtUserCallHwndParam_GetWindowRect
:
5545 return get_window_rect( hwnd
, (RECT
*)param
, get_thread_dpi() );
5547 case NtUserCallHwndParam_GetWindowRelative
:
5548 return HandleToUlong( get_window_relative( hwnd
, param
));
5550 case NtUserCallHwndParam_GetWindowThread
:
5551 return get_window_thread( hwnd
, (DWORD
*)param
);
5553 case NtUserCallHwndParam_GetWindowWord
:
5554 return get_window_word( hwnd
, param
);
5556 case NtUserCallHwndParam_IsChild
:
5557 return is_child( hwnd
, UlongToHandle(param
) );
5559 case NtUserCallHwndParam_KillSystemTimer
:
5560 return kill_system_timer( hwnd
, param
);
5562 case NtUserCallHwndParam_MapWindowPoints
:
5564 struct map_window_points_params
*params
= (void *)param
;
5565 return map_window_points( hwnd
, params
->hwnd_to
, params
->points
, params
->count
,
5569 case NtUserCallHwndParam_MirrorRgn
:
5570 return mirror_window_region( hwnd
, UlongToHandle(param
) );
5572 case NtUserCallHwndParam_MonitorFromWindow
:
5573 return HandleToUlong( monitor_from_window( hwnd
, param
, get_thread_dpi() ));
5575 case NtUserCallHwndParam_ScreenToClient
:
5576 return screen_to_client( hwnd
, (POINT
*)param
);
5578 case NtUserCallHwndParam_SetDialogInfo
:
5579 return set_dialog_info( hwnd
, (void *)param
);
5581 case NtUserCallHwndParam_SetMDIClientInfo
:
5582 NtUserSetWindowLongPtr( hwnd
, sizeof(void *), param
, FALSE
);
5583 return win_set_flags( hwnd
, WIN_ISMDICLIENT
, 0 );
5585 case NtUserCallHwndParam_SetWindowContextHelpId
:
5586 return set_window_context_help_id( hwnd
, param
);
5588 case NtUserCallHwndParam_ShowOwnedPopups
:
5589 return show_owned_popups( hwnd
, param
);
5591 /* temporary exports */
5592 case NtUserSetWindowStyle
:
5594 STYLESTRUCT
*style
= (void *)param
;
5595 return set_window_style( hwnd
, style
->styleNew
, style
->styleOld
);
5599 FIXME( "invalid code %u\n", (int)code
);
5604 /*******************************************************************
5605 * NtUserDragDetect (win32u.@)
5607 BOOL WINAPI
NtUserDragDetect( HWND hwnd
, int x
, int y
)
5613 TRACE( "%p (%d,%d)\n", hwnd
, x
, y
);
5615 if (!(NtUserGetKeyState( VK_LBUTTON
) & 0x8000)) return FALSE
;
5617 width
= get_system_metrics( SM_CXDRAG
);
5618 height
= get_system_metrics( SM_CYDRAG
);
5619 SetRect( &rect
, x
- width
, y
- height
, x
+ width
, y
+ height
);
5621 NtUserSetCapture( hwnd
);
5625 while (NtUserPeekMessage( &msg
, 0, WM_MOUSEFIRST
, WM_MOUSELAST
, PM_REMOVE
))
5627 if (msg
.message
== WM_LBUTTONUP
)
5632 if (msg
.message
== WM_MOUSEMOVE
)
5635 tmp
.x
= (short)LOWORD( msg
.lParam
);
5636 tmp
.y
= (short)HIWORD( msg
.lParam
);
5637 if (!PtInRect( &rect
, tmp
))
5644 NtUserMsgWaitForMultipleObjectsEx( 0, NULL
, INFINITE
, QS_ALLINPUT
, 0 );
5649 /*******************************************************************
5650 * NtUserDragObject (win32u.@)
5652 DWORD WINAPI
NtUserDragObject( HWND parent
, HWND hwnd
, UINT fmt
, ULONG_PTR data
, HCURSOR cursor
)
5654 FIXME( "%p, %p, %u, %#lx, %p stub!\n", parent
, hwnd
, fmt
, data
, cursor
);
5660 HWND
get_shell_window(void)
5664 SERVER_START_REQ(set_global_windows
)
5667 if (!wine_server_call_err(req
))
5668 hwnd
= wine_server_ptr_handle( reply
->old_shell_window
);
5675 /***********************************************************************
5676 * NtUserSetShellWindowEx (win32u.@)
5678 BOOL WINAPI
NtUserSetShellWindowEx( HWND shell
, HWND list_view
)
5682 /* shell = Progman[Program Manager]
5683 * |-> SHELLDLL_DefView
5684 * list_view = | |-> SysListView32
5685 * | | |-> tooltips_class32
5692 if (get_shell_window())
5695 if (get_window_long( shell
, GWL_EXSTYLE
) & WS_EX_TOPMOST
)
5698 if (list_view
!= shell
&& (get_window_long( list_view
, GWL_EXSTYLE
) & WS_EX_TOPMOST
))
5701 if (list_view
&& list_view
!= shell
)
5702 NtUserSetWindowPos( list_view
, HWND_BOTTOM
, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
5704 NtUserSetWindowPos( shell
, HWND_BOTTOM
, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
5706 SERVER_START_REQ(set_global_windows
)
5708 req
->flags
= SET_GLOBAL_SHELL_WINDOWS
;
5709 req
->shell_window
= wine_server_user_handle( shell
);
5710 req
->shell_listview
= wine_server_user_handle( list_view
);
5711 ret
= !wine_server_call_err(req
);
5717 HWND
get_progman_window(void)
5721 SERVER_START_REQ(set_global_windows
)
5724 if (!wine_server_call_err(req
))
5725 ret
= wine_server_ptr_handle( reply
->old_progman_window
);
5731 HWND
set_progman_window( HWND hwnd
)
5733 SERVER_START_REQ(set_global_windows
)
5735 req
->flags
= SET_GLOBAL_PROGMAN_WINDOW
;
5736 req
->progman_window
= wine_server_user_handle( hwnd
);
5737 if (wine_server_call_err( req
)) hwnd
= 0;
5743 HWND
get_taskman_window(void)
5747 SERVER_START_REQ(set_global_windows
)
5750 if (!wine_server_call_err(req
))
5751 ret
= wine_server_ptr_handle( reply
->old_taskman_window
);
5757 HWND
set_taskman_window( HWND hwnd
)
5759 /* hwnd = MSTaskSwWClass
5760 * |-> SysTabControl32
5762 SERVER_START_REQ(set_global_windows
)
5764 req
->flags
= SET_GLOBAL_TASKMAN_WINDOW
;
5765 req
->taskman_window
= wine_server_user_handle( hwnd
);
5766 if (wine_server_call_err( req
)) hwnd
= 0;