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
)
2234 if (!hwnd
) hwnd
= get_desktop_window();
2235 if (!(dpi
= get_thread_dpi())) dpi
= get_win_monitor_dpi( hwnd
);
2237 *hittest
= HTNOWHERE
;
2239 if (!(list
= list_children_from_point( hwnd
, pt
))) return 0;
2241 /* now determine the hittest */
2243 for (i
= 0; list
[i
]; i
++)
2245 LONG style
= get_window_long( list
[i
], GWL_STYLE
);
2247 /* If window is minimized or disabled, return at once */
2248 if (style
& WS_DISABLED
)
2253 /* Send WM_NCCHITTEST (if same thread) */
2254 if (!is_current_thread_window( list
[i
] ))
2256 *hittest
= HTCLIENT
;
2259 win_pt
= map_dpi_point( pt
, dpi
, get_dpi_for_window( list
[i
] ));
2260 res
= send_message( list
[i
], WM_NCHITTEST
, 0, MAKELPARAM( win_pt
.x
, win_pt
.y
));
2261 if (res
!= HTTRANSPARENT
)
2263 *hittest
= res
; /* Found the window */
2266 /* continue search with next window in z-order */
2270 TRACE( "scope %p (%d,%d) returning %p\n", hwnd
, (int)pt
.x
, (int)pt
.y
, ret
);
2274 /*******************************************************************
2275 * NtUserWindowFromPoint (win32u.@)
2277 HWND WINAPI
NtUserWindowFromPoint( LONG x
, LONG y
)
2279 POINT pt
= { .x
= x
, .y
= y
};
2281 return window_from_point( 0, pt
, &hittest
);
2284 /*******************************************************************
2285 * NtUserChildWindowFromPointEx (win32u.@)
2287 HWND WINAPI
NtUserChildWindowFromPointEx( HWND parent
, LONG x
, LONG y
, UINT flags
)
2289 POINT pt
= { .x
= x
, .y
= y
}; /* in the client coordinates */
2295 get_client_rect( parent
, &rect
);
2296 if (!PtInRect( &rect
, pt
)) return 0;
2297 if (!(list
= list_window_children( 0, parent
, NULL
, 0 ))) return parent
;
2299 for (i
= 0; list
[i
]; i
++)
2301 if (!get_window_rects( list
[i
], COORDS_PARENT
, &rect
, NULL
, get_thread_dpi() )) continue;
2302 if (!PtInRect( &rect
, pt
)) continue;
2303 if (flags
& (CWP_SKIPINVISIBLE
|CWP_SKIPDISABLED
))
2305 LONG style
= get_window_long( list
[i
], GWL_STYLE
);
2306 if ((flags
& CWP_SKIPINVISIBLE
) && !(style
& WS_VISIBLE
)) continue;
2307 if ((flags
& CWP_SKIPDISABLED
) && (style
& WS_DISABLED
)) continue;
2309 if (flags
& CWP_SKIPTRANSPARENT
)
2311 if (get_window_long( list
[i
], GWL_EXSTYLE
) & WS_EX_TRANSPARENT
) continue;
2317 if (!ret
) ret
= parent
;
2321 /*******************************************************************
2322 * NtUserRealChildWindowFromPoint (win32u.@)
2324 HWND WINAPI
NtUserRealChildWindowFromPoint( HWND parent
, LONG x
, LONG y
)
2326 return NtUserChildWindowFromPointEx( parent
, x
, y
, CWP_SKIPTRANSPARENT
| CWP_SKIPINVISIBLE
);
2329 /*******************************************************************
2332 * Get the work area that a maximized window can cover, depending on style.
2334 static BOOL
get_work_rect( HWND hwnd
, RECT
*rect
)
2336 HMONITOR monitor
= monitor_from_window( hwnd
, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
2337 MONITORINFO mon_info
;
2340 if (!monitor
) return FALSE
;
2342 mon_info
.cbSize
= sizeof(mon_info
);
2343 get_monitor_info( monitor
, &mon_info
);
2344 *rect
= mon_info
.rcMonitor
;
2346 style
= get_window_long( hwnd
, GWL_STYLE
);
2347 if (style
& WS_MAXIMIZEBOX
)
2349 if ((style
& WS_CAPTION
) == WS_CAPTION
|| !(style
& (WS_CHILD
| WS_POPUP
)))
2350 *rect
= mon_info
.rcWork
;
2355 static RECT
get_maximized_work_rect( HWND hwnd
)
2357 RECT work_rect
= { 0 };
2359 if ((get_window_long( hwnd
, GWL_STYLE
) & (WS_MINIMIZE
| WS_MAXIMIZE
)) == WS_MAXIMIZE
)
2361 if (!get_work_rect( hwnd
, &work_rect
))
2362 work_rect
= get_primary_monitor_rect( get_thread_dpi() );
2367 /*******************************************************************
2368 * update_maximized_pos
2370 * For top level windows covering the work area, we might have to
2371 * "forget" the maximized position. Windows presumably does this
2372 * to avoid situations where the border style changes, which would
2373 * lead the window to be outside the screen, or the window gets
2374 * reloaded on a different screen, and the "saved" position no
2375 * longer applies to it (despite being maximized).
2377 * Some applications (e.g. Imperiums: Greek Wars) depend on this.
2379 static void update_maximized_pos( WND
*wnd
, RECT
*work_rect
)
2381 if (wnd
->parent
&& wnd
->parent
!= get_desktop_window())
2384 if (wnd
->dwStyle
& WS_MAXIMIZE
)
2386 if (wnd
->window_rect
.left
<= work_rect
->left
&& wnd
->window_rect
.top
<= work_rect
->top
&&
2387 wnd
->window_rect
.right
>= work_rect
->right
&& wnd
->window_rect
.bottom
>= work_rect
->bottom
)
2388 wnd
->max_pos
.x
= wnd
->max_pos
.y
= -1;
2391 wnd
->max_pos
.x
= wnd
->max_pos
.y
= -1;
2394 static BOOL
empty_point( POINT pt
)
2396 return pt
.x
== -1 && pt
.y
== -1;
2399 /***********************************************************************
2400 * NtUserGetWindowPlacement (win32u.@)
2402 BOOL WINAPI
NtUserGetWindowPlacement( HWND hwnd
, WINDOWPLACEMENT
*placement
)
2404 RECT work_rect
= get_maximized_work_rect( hwnd
);
2405 WND
*win
= get_win_ptr( hwnd
);
2408 if (!win
) return FALSE
;
2410 if (win
== WND_DESKTOP
)
2412 placement
->length
= sizeof(*placement
);
2413 placement
->showCmd
= SW_SHOWNORMAL
;
2414 placement
->flags
= 0;
2415 placement
->ptMinPosition
.x
= -1;
2416 placement
->ptMinPosition
.y
= -1;
2417 placement
->ptMaxPosition
.x
= -1;
2418 placement
->ptMaxPosition
.y
= -1;
2419 get_window_rect( hwnd
, &placement
->rcNormalPosition
, get_thread_dpi() );
2422 if (win
== WND_OTHER_PROCESS
)
2424 RECT normal_position
;
2427 if (!get_window_rect( hwnd
, &normal_position
, get_thread_dpi() ))
2430 FIXME("not fully supported on other process window %p.\n", hwnd
);
2432 placement
->length
= sizeof(*placement
);
2433 style
= get_window_long( hwnd
, GWL_STYLE
);
2434 if (style
& WS_MINIMIZE
)
2435 placement
->showCmd
= SW_SHOWMINIMIZED
;
2437 placement
->showCmd
= (style
& WS_MAXIMIZE
) ? SW_SHOWMAXIMIZED
: SW_SHOWNORMAL
;
2438 /* provide some dummy information */
2439 placement
->flags
= 0;
2440 placement
->ptMinPosition
.x
= -1;
2441 placement
->ptMinPosition
.y
= -1;
2442 placement
->ptMaxPosition
.x
= -1;
2443 placement
->ptMaxPosition
.y
= -1;
2444 placement
->rcNormalPosition
= normal_position
;
2448 /* update the placement according to the current style */
2449 if (win
->dwStyle
& WS_MINIMIZE
)
2451 win
->min_pos
.x
= win
->window_rect
.left
;
2452 win
->min_pos
.y
= win
->window_rect
.top
;
2454 else if (win
->dwStyle
& WS_MAXIMIZE
)
2456 win
->max_pos
.x
= win
->window_rect
.left
;
2457 win
->max_pos
.y
= win
->window_rect
.top
;
2461 win
->normal_rect
= win
->window_rect
;
2463 update_maximized_pos( win
, &work_rect
);
2465 placement
->length
= sizeof(*placement
);
2466 if (win
->dwStyle
& WS_MINIMIZE
)
2467 placement
->showCmd
= SW_SHOWMINIMIZED
;
2469 placement
->showCmd
= ( win
->dwStyle
& WS_MAXIMIZE
) ? SW_SHOWMAXIMIZED
: SW_SHOWNORMAL
;
2470 if (win
->flags
& WIN_RESTORE_MAX
)
2471 placement
->flags
= WPF_RESTORETOMAXIMIZED
;
2473 placement
->flags
= 0;
2474 win_dpi
= get_dpi_for_window( hwnd
);
2475 placement
->ptMinPosition
= empty_point(win
->min_pos
) ? win
->min_pos
2476 : map_dpi_point( win
->min_pos
, win_dpi
, get_thread_dpi() );
2477 placement
->ptMaxPosition
= empty_point(win
->max_pos
) ? win
->max_pos
2478 : map_dpi_point( win
->max_pos
, win_dpi
, get_thread_dpi() );
2479 placement
->rcNormalPosition
= map_dpi_rect( win
->normal_rect
, win_dpi
, get_thread_dpi() );
2480 release_win_ptr( win
);
2482 TRACE( "%p: returning min %d,%d max %d,%d normal %s\n",
2483 hwnd
, (int)placement
->ptMinPosition
.x
, (int)placement
->ptMinPosition
.y
,
2484 (int)placement
->ptMaxPosition
.x
, (int)placement
->ptMaxPosition
.y
,
2485 wine_dbgstr_rect(&placement
->rcNormalPosition
) );
2489 /* make sure the specified rect is visible on screen */
2490 static void make_rect_onscreen( RECT
*rect
)
2493 HMONITOR monitor
= monitor_from_rect( rect
, MONITOR_DEFAULTTONEAREST
, get_thread_dpi() );
2495 info
.cbSize
= sizeof(info
);
2496 if (!monitor
|| !get_monitor_info( monitor
, &info
)) return;
2497 /* FIXME: map coordinates from rcWork to rcMonitor */
2498 if (rect
->right
<= info
.rcWork
.left
)
2500 rect
->right
+= info
.rcWork
.left
- rect
->left
;
2501 rect
->left
= info
.rcWork
.left
;
2503 else if (rect
->left
>= info
.rcWork
.right
)
2505 rect
->left
+= info
.rcWork
.right
- rect
->right
;
2506 rect
->right
= info
.rcWork
.right
;
2508 if (rect
->bottom
<= info
.rcWork
.top
)
2510 rect
->bottom
+= info
.rcWork
.top
- rect
->top
;
2511 rect
->top
= info
.rcWork
.top
;
2513 else if (rect
->top
>= info
.rcWork
.bottom
)
2515 rect
->top
+= info
.rcWork
.bottom
- rect
->bottom
;
2516 rect
->bottom
= info
.rcWork
.bottom
;
2520 /***********************************************************************
2521 * NtUserGetInternalWindowPos (win32u.@)
2523 UINT WINAPI
NtUserGetInternalWindowPos( HWND hwnd
, RECT
*rect
, POINT
*pt
)
2525 WINDOWPLACEMENT placement
;
2527 placement
.length
= sizeof(placement
);
2528 if (!NtUserGetWindowPlacement( hwnd
, &placement
)) return 0;
2529 if (rect
) *rect
= placement
.rcNormalPosition
;
2530 if (pt
) *pt
= placement
.ptMinPosition
;
2531 return placement
.showCmd
;
2534 /* make sure the specified point is visible on screen */
2535 static void make_point_onscreen( POINT
*pt
)
2539 SetRect( &rect
, pt
->x
, pt
->y
, pt
->x
+ 1, pt
->y
+ 1 );
2540 make_rect_onscreen( &rect
);
2545 static BOOL
set_window_placement( HWND hwnd
, const WINDOWPLACEMENT
*wndpl
, UINT flags
)
2547 RECT work_rect
= get_maximized_work_rect( hwnd
);
2548 WND
*win
= get_win_ptr( hwnd
);
2549 WINDOWPLACEMENT wp
= *wndpl
;
2552 if (flags
& PLACE_MIN
) make_point_onscreen( &wp
.ptMinPosition
);
2553 if (flags
& PLACE_MAX
) make_point_onscreen( &wp
.ptMaxPosition
);
2554 if (flags
& PLACE_RECT
) make_rect_onscreen( &wp
.rcNormalPosition
);
2556 TRACE( "%p: setting min %d,%d max %d,%d normal %s flags %x adjusted to min %d,%d max %d,%d normal %s\n",
2557 hwnd
, (int)wndpl
->ptMinPosition
.x
, (int)wndpl
->ptMinPosition
.y
,
2558 (int)wndpl
->ptMaxPosition
.x
, (int)wndpl
->ptMaxPosition
.y
,
2559 wine_dbgstr_rect(&wndpl
->rcNormalPosition
), flags
,
2560 (int)wp
.ptMinPosition
.x
, (int)wp
.ptMinPosition
.y
,
2561 (int)wp
.ptMaxPosition
.x
, (int)wp
.ptMaxPosition
.y
,
2562 wine_dbgstr_rect(&wp
.rcNormalPosition
) );
2564 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
2566 if (flags
& PLACE_MIN
) win
->min_pos
= point_thread_to_win_dpi( hwnd
, wp
.ptMinPosition
);
2567 if (flags
& PLACE_MAX
)
2569 win
->max_pos
= point_thread_to_win_dpi( hwnd
, wp
.ptMaxPosition
);
2570 update_maximized_pos( win
, &work_rect
);
2572 if (flags
& PLACE_RECT
) win
->normal_rect
= rect_thread_to_win_dpi( hwnd
, wp
.rcNormalPosition
);
2574 style
= win
->dwStyle
;
2576 release_win_ptr( win
);
2578 if (style
& WS_MINIMIZE
)
2580 if (flags
& PLACE_MIN
)
2582 NtUserSetWindowPos( hwnd
, 0, wp
.ptMinPosition
.x
, wp
.ptMinPosition
.y
, 0, 0,
2583 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
2586 else if (style
& WS_MAXIMIZE
)
2588 if (flags
& PLACE_MAX
)
2589 NtUserSetWindowPos( hwnd
, 0, wp
.ptMaxPosition
.x
, wp
.ptMaxPosition
.y
, 0, 0,
2590 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
2592 else if (flags
& PLACE_RECT
)
2593 NtUserSetWindowPos( hwnd
, 0, wp
.rcNormalPosition
.left
, wp
.rcNormalPosition
.top
,
2594 wp
.rcNormalPosition
.right
- wp
.rcNormalPosition
.left
,
2595 wp
.rcNormalPosition
.bottom
- wp
.rcNormalPosition
.top
,
2596 SWP_NOZORDER
| SWP_NOACTIVATE
);
2598 NtUserShowWindow( hwnd
, wndpl
->showCmd
);
2600 if (is_iconic( hwnd
))
2602 if (wndpl
->flags
& WPF_RESTORETOMAXIMIZED
)
2603 win_set_flags( hwnd
, WIN_RESTORE_MAX
, 0 );
2608 /***********************************************************************
2609 * NtUserSetWindowPlacement (win32u.@)
2611 BOOL WINAPI
NtUserSetWindowPlacement( HWND hwnd
, const WINDOWPLACEMENT
*wpl
)
2613 UINT flags
= PLACE_MAX
| PLACE_RECT
;
2614 if (!wpl
) return FALSE
;
2615 if (wpl
->length
!= sizeof(*wpl
))
2617 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
2620 if (wpl
->flags
& WPF_SETMINPOSITION
) flags
|= PLACE_MIN
;
2621 return set_window_placement( hwnd
, wpl
, flags
);
2624 /*****************************************************************************
2625 * NtUserBuildHwndList (win32u.@)
2627 NTSTATUS WINAPI
NtUserBuildHwndList( HDESK desktop
, ULONG unk2
, ULONG unk3
, ULONG unk4
,
2628 ULONG thread_id
, ULONG count
, HWND
*buffer
, ULONG
*size
)
2630 user_handle_t
*list
= (user_handle_t
*)buffer
;
2634 SERVER_START_REQ( get_window_children
)
2636 req
->desktop
= wine_server_obj_handle( desktop
);
2637 req
->tid
= thread_id
;
2638 if (count
) wine_server_set_reply( req
, list
, (count
- 1) * sizeof(user_handle_t
) );
2639 status
= wine_server_call( req
);
2640 if (status
&& status
!= STATUS_BUFFER_TOO_SMALL
) return status
;
2641 *size
= reply
->count
+ 1;
2644 if (*size
> count
) return STATUS_BUFFER_TOO_SMALL
;
2646 /* start from the end since HWND is potentially larger than user_handle_t */
2647 for (i
= *size
- 2; i
>= 0; i
--)
2648 buffer
[i
] = wine_server_ptr_handle( list
[i
] );
2649 buffer
[*size
- 1] = HWND_BOTTOM
;
2650 return STATUS_SUCCESS
;
2653 /***********************************************************************
2654 * NtUserFindWindowEx (USER32.@)
2656 HWND WINAPI
NtUserFindWindowEx( HWND parent
, HWND child
, UNICODE_STRING
*class, UNICODE_STRING
*title
,
2661 int i
= 0, len
= 0, title_len
;
2662 WCHAR
*buffer
= NULL
;
2664 if (!parent
&& child
) parent
= get_desktop_window();
2665 else if (parent
== HWND_MESSAGE
) parent
= get_hwnd_message_parent();
2669 len
= title
->Length
/ sizeof(WCHAR
) + 1; /* one extra char to check for chars beyond the end */
2670 if (!(buffer
= malloc( (len
+ 1) * sizeof(WCHAR
) ))) return 0;
2673 if (!(list
= list_window_children( 0, parent
, class, 0 ))) goto done
;
2677 child
= get_full_window_handle( child
);
2678 while (list
[i
] && list
[i
] != child
) i
++;
2679 if (!list
[i
]) goto done
;
2680 i
++; /* start from next window */
2687 title_len
= NtUserInternalGetWindowText( list
[i
], buffer
, len
+ 1 );
2688 if (title_len
* sizeof(WCHAR
) == title
->Length
&&
2689 (!title_len
|| !wcsnicmp( buffer
, title
->Buffer
, title_len
)))
2702 /* Retrieve the window text from the server. */
2703 static data_size_t
get_server_window_text( HWND hwnd
, WCHAR
*text
, data_size_t count
)
2705 data_size_t len
= 0, needed
= 0;
2707 SERVER_START_REQ( get_window_text
)
2709 req
->handle
= wine_server_user_handle( hwnd
);
2710 if (count
) wine_server_set_reply( req
, text
, (count
- 1) * sizeof(WCHAR
) );
2711 if (!wine_server_call_err( req
))
2713 needed
= reply
->length
;
2714 len
= wine_server_reply_size(reply
);
2718 if (text
) text
[len
/ sizeof(WCHAR
)] = 0;
2722 /*******************************************************************
2723 * NtUserInternalGetWindowText (win32u.@)
2725 INT WINAPI
NtUserInternalGetWindowText( HWND hwnd
, WCHAR
*text
, INT count
)
2729 if (count
<= 0) return 0;
2730 if (!(win
= get_win_ptr( hwnd
))) return 0;
2731 if (win
== WND_DESKTOP
) text
[0] = 0;
2732 else if (win
!= WND_OTHER_PROCESS
)
2734 if (win
->text
) lstrcpynW( text
, win
->text
, count
);
2736 release_win_ptr( win
);
2740 get_server_window_text( hwnd
, text
, count
);
2742 return lstrlenW(text
);
2745 /*******************************************************************
2746 * get_windows_offset
2748 * Calculate the offset between the origin of the two windows. Used
2749 * to implement MapWindowPoints.
2751 static BOOL
get_windows_offset( HWND hwnd_from
, HWND hwnd_to
, UINT dpi
, BOOL
*mirrored
, POINT
*ret_offset
)
2755 BOOL mirror_from
, mirror_to
, ret
;
2758 offset
.x
= offset
.y
= 0;
2759 *mirrored
= mirror_from
= mirror_to
= FALSE
;
2761 /* Translate source window origin to screen coords */
2764 if (!(win
= get_win_ptr( hwnd_from
)))
2766 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
2769 if (win
== WND_OTHER_PROCESS
) goto other_process
;
2770 if (win
!= WND_DESKTOP
)
2772 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
)
2775 offset
.x
+= win
->client_rect
.right
- win
->client_rect
.left
;
2779 offset
.x
+= win
->client_rect
.left
;
2780 offset
.y
+= win
->client_rect
.top
;
2782 release_win_ptr( win
);
2783 if (!(win
= get_win_ptr( hwnd
))) break;
2784 if (win
== WND_OTHER_PROCESS
) goto other_process
;
2785 if (win
== WND_DESKTOP
) break;
2786 if (win
->flags
& WIN_CHILDREN_MOVED
)
2788 release_win_ptr( win
);
2792 if (win
&& win
!= WND_DESKTOP
) release_win_ptr( win
);
2793 offset
= map_dpi_point( offset
, get_dpi_for_window( hwnd_from
), dpi
);
2797 /* Translate origin to destination window coords */
2800 if (!(win
= get_win_ptr( hwnd_to
)))
2802 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
2805 if (win
== WND_OTHER_PROCESS
) goto other_process
;
2806 if (win
!= WND_DESKTOP
)
2808 POINT pt
= { 0, 0 };
2809 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
)
2812 pt
.x
+= win
->client_rect
.right
- win
->client_rect
.left
;
2816 pt
.x
+= win
->client_rect
.left
;
2817 pt
.y
+= win
->client_rect
.top
;
2819 release_win_ptr( win
);
2820 if (!(win
= get_win_ptr( hwnd
))) break;
2821 if (win
== WND_OTHER_PROCESS
) goto other_process
;
2822 if (win
== WND_DESKTOP
) break;
2823 if (win
->flags
& WIN_CHILDREN_MOVED
)
2825 release_win_ptr( win
);
2829 if (win
&& win
!= WND_DESKTOP
) release_win_ptr( win
);
2830 pt
= map_dpi_point( pt
, get_dpi_for_window( hwnd_to
), dpi
);
2836 *mirrored
= mirror_from
^ mirror_to
;
2837 if (mirror_from
) offset
.x
= -offset
.x
;
2838 *ret_offset
= offset
;
2841 other_process
: /* one of the parents may belong to another process, do it the hard way */
2842 SERVER_START_REQ( get_windows_offset
)
2844 req
->from
= wine_server_user_handle( hwnd_from
);
2845 req
->to
= wine_server_user_handle( hwnd_to
);
2847 if ((ret
= !wine_server_call_err( req
)))
2849 ret_offset
->x
= reply
->x
;
2850 ret_offset
->y
= reply
->y
;
2851 *mirrored
= reply
->mirror
;
2858 /* see ClientToScreen */
2859 BOOL
client_to_screen( HWND hwnd
, POINT
*pt
)
2866 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
2870 if (!get_windows_offset( hwnd
, 0, get_thread_dpi(), &mirrored
, &offset
)) return FALSE
;
2873 if (mirrored
) pt
->x
= -pt
->x
;
2877 /* see ScreenToClient */
2878 BOOL
screen_to_client( HWND hwnd
, POINT
*pt
)
2885 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
2888 if (!get_windows_offset( 0, hwnd
, get_thread_dpi(), &mirrored
, &offset
)) return FALSE
;
2891 if (mirrored
) pt
->x
= -pt
->x
;
2895 /* map coordinates of a window region */
2896 void map_window_region( HWND from
, HWND to
, HRGN hrgn
)
2905 if (!get_windows_offset( from
, to
, get_thread_dpi(), &mirrored
, &offset
)) return;
2909 NtGdiOffsetRgn( hrgn
, offset
.x
, offset
.y
);
2912 if (!(size
= NtGdiGetRegionData( hrgn
, 0, NULL
))) return;
2913 if (!(data
= malloc( size
))) return;
2914 NtGdiGetRegionData( hrgn
, size
, data
);
2915 rect
= (RECT
*)data
->Buffer
;
2916 for (i
= 0; i
< data
->rdh
.nCount
; i
++)
2918 int tmp
= -(rect
[i
].left
+ offset
.x
);
2919 rect
[i
].left
= -(rect
[i
].right
+ offset
.x
);
2920 rect
[i
].right
= tmp
;
2921 rect
[i
].top
+= offset
.y
;
2922 rect
[i
].bottom
+= offset
.y
;
2924 if ((new_rgn
= NtGdiExtCreateRegion( NULL
, data
->rdh
.dwSize
+ data
->rdh
.nRgnSize
, data
)))
2926 NtGdiCombineRgn( hrgn
, new_rgn
, 0, RGN_COPY
);
2927 NtGdiDeleteObjectApp( new_rgn
);
2932 /* see MapWindowPoints */
2933 int map_window_points( HWND hwnd_from
, HWND hwnd_to
, POINT
*points
, UINT count
, UINT dpi
)
2939 if (!get_windows_offset( hwnd_from
, hwnd_to
, dpi
, &mirrored
, &offset
)) return 0;
2941 for (i
= 0; i
< count
; i
++)
2943 points
[i
].x
+= offset
.x
;
2944 points
[i
].y
+= offset
.y
;
2945 if (mirrored
) points
[i
].x
= -points
[i
].x
;
2947 if (mirrored
&& count
== 2) /* special case for rectangle */
2949 int tmp
= points
[0].x
;
2950 points
[0].x
= points
[1].x
;
2953 return MAKELONG( LOWORD(offset
.x
), LOWORD(offset
.y
) );
2956 /***********************************************************************
2959 static void dump_winpos_flags( UINT flags
)
2961 static const UINT dumped_flags
= (SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOREDRAW
|
2962 SWP_NOACTIVATE
| SWP_FRAMECHANGED
| SWP_SHOWWINDOW
|
2963 SWP_HIDEWINDOW
| SWP_NOCOPYBITS
| SWP_NOOWNERZORDER
|
2964 SWP_NOSENDCHANGING
| SWP_DEFERERASE
| SWP_ASYNCWINDOWPOS
|
2965 SWP_NOCLIENTSIZE
| SWP_NOCLIENTMOVE
| SWP_STATECHANGED
);
2967 if(flags
& SWP_NOSIZE
) TRACE( " SWP_NOSIZE" );
2968 if(flags
& SWP_NOMOVE
) TRACE( " SWP_NOMOVE" );
2969 if(flags
& SWP_NOZORDER
) TRACE( " SWP_NOZORDER" );
2970 if(flags
& SWP_NOREDRAW
) TRACE( " SWP_NOREDRAW" );
2971 if(flags
& SWP_NOACTIVATE
) TRACE( " SWP_NOACTIVATE" );
2972 if(flags
& SWP_FRAMECHANGED
) TRACE( " SWP_FRAMECHANGED" );
2973 if(flags
& SWP_SHOWWINDOW
) TRACE( " SWP_SHOWWINDOW" );
2974 if(flags
& SWP_HIDEWINDOW
) TRACE( " SWP_HIDEWINDOW" );
2975 if(flags
& SWP_NOCOPYBITS
) TRACE( " SWP_NOCOPYBITS" );
2976 if(flags
& SWP_NOOWNERZORDER
) TRACE( " SWP_NOOWNERZORDER" );
2977 if(flags
& SWP_NOSENDCHANGING
) TRACE( " SWP_NOSENDCHANGING" );
2978 if(flags
& SWP_DEFERERASE
) TRACE( " SWP_DEFERERASE" );
2979 if(flags
& SWP_ASYNCWINDOWPOS
) TRACE( " SWP_ASYNCWINDOWPOS" );
2980 if(flags
& SWP_NOCLIENTSIZE
) TRACE( " SWP_NOCLIENTSIZE" );
2981 if(flags
& SWP_NOCLIENTMOVE
) TRACE( " SWP_NOCLIENTMOVE" );
2982 if(flags
& SWP_STATECHANGED
) TRACE( " SWP_STATECHANGED" );
2984 if(flags
& ~dumped_flags
) TRACE( " %08x", flags
& ~dumped_flags
);
2988 /***********************************************************************
2991 static void map_dpi_winpos( WINDOWPOS
*winpos
)
2993 UINT dpi_from
= get_thread_dpi();
2994 UINT dpi_to
= get_dpi_for_window( winpos
->hwnd
);
2996 if (!dpi_from
) dpi_from
= get_win_monitor_dpi( winpos
->hwnd
);
2997 if (dpi_from
== dpi_to
) return;
2998 winpos
->x
= muldiv( winpos
->x
, dpi_to
, dpi_from
);
2999 winpos
->y
= muldiv( winpos
->y
, dpi_to
, dpi_from
);
3000 winpos
->cx
= muldiv( winpos
->cx
, dpi_to
, dpi_from
);
3001 winpos
->cy
= muldiv( winpos
->cy
, dpi_to
, dpi_from
);
3004 /***********************************************************************
3007 static BOOL
calc_winpos( WINDOWPOS
*winpos
, RECT
*old_window_rect
, RECT
*old_client_rect
,
3008 RECT
*new_window_rect
, RECT
*new_client_rect
)
3012 /* Send WM_WINDOWPOSCHANGING message */
3013 if (!(winpos
->flags
& SWP_NOSENDCHANGING
)
3014 && !((winpos
->flags
& SWP_AGG_NOCLIENTCHANGE
) && (winpos
->flags
& SWP_SHOWWINDOW
)))
3015 send_message( winpos
->hwnd
, WM_WINDOWPOSCHANGING
, 0, (LPARAM
)winpos
);
3017 if (!(win
= get_win_ptr( winpos
->hwnd
)) ||
3018 win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
3020 /* Calculate new position and size */
3021 get_window_rects( winpos
->hwnd
, COORDS_PARENT
, old_window_rect
, old_client_rect
, get_thread_dpi() );
3022 *new_window_rect
= *old_window_rect
;
3023 *new_client_rect
= *old_client_rect
;
3025 if (!(winpos
->flags
& SWP_NOSIZE
))
3027 if (win
->dwStyle
& WS_MINIMIZE
)
3029 new_window_rect
->right
= new_window_rect
->left
+ get_system_metrics( SM_CXMINIMIZED
);
3030 new_window_rect
->bottom
= new_window_rect
->top
+ get_system_metrics( SM_CYMINIMIZED
);
3034 new_window_rect
->right
= new_window_rect
->left
+ winpos
->cx
;
3035 new_window_rect
->bottom
= new_window_rect
->top
+ winpos
->cy
;
3039 if (!(winpos
->flags
& SWP_NOMOVE
))
3041 /* If the window is toplevel minimized off-screen, force keep it there */
3042 if ((win
->dwStyle
& WS_MINIMIZE
) &&
3043 win
->window_rect
.left
<= -32000 && win
->window_rect
.top
<= -32000 &&
3044 (!win
->parent
|| win
->parent
== get_desktop_window()))
3049 new_window_rect
->left
= winpos
->x
;
3050 new_window_rect
->top
= winpos
->y
;
3051 new_window_rect
->right
+= winpos
->x
- old_window_rect
->left
;
3052 new_window_rect
->bottom
+= winpos
->y
- old_window_rect
->top
;
3054 OffsetRect( new_client_rect
, winpos
->x
- old_window_rect
->left
,
3055 winpos
->y
- old_window_rect
->top
);
3057 winpos
->flags
|= SWP_NOCLIENTMOVE
| SWP_NOCLIENTSIZE
;
3059 TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x current %s style %08x new %s\n",
3060 winpos
->hwnd
, winpos
->hwndInsertAfter
, winpos
->x
, winpos
->y
,
3061 winpos
->cx
, winpos
->cy
, winpos
->flags
,
3062 wine_dbgstr_rect( old_window_rect
), win
->dwStyle
,
3063 wine_dbgstr_rect( new_window_rect
));
3065 release_win_ptr( win
);
3069 /***********************************************************************
3072 * Compute the valid rects from the old and new client rect and WVR_* flags.
3073 * Helper for WM_NCCALCSIZE handling.
3075 static inline void get_valid_rects( const RECT
*old_client
, const RECT
*new_client
, UINT flags
,
3080 if (flags
& WVR_REDRAW
)
3082 SetRectEmpty( &valid
[0] );
3083 SetRectEmpty( &valid
[1] );
3087 if (flags
& WVR_VALIDRECTS
)
3089 if (!intersect_rect( &valid
[0], &valid
[0], new_client
) ||
3090 !intersect_rect( &valid
[1], &valid
[1], old_client
))
3092 SetRectEmpty( &valid
[0] );
3093 SetRectEmpty( &valid
[1] );
3096 flags
= WVR_ALIGNLEFT
| WVR_ALIGNTOP
;
3100 valid
[0] = *new_client
;
3101 valid
[1] = *old_client
;
3104 /* make sure the rectangles have the same size */
3105 cx
= min( valid
[0].right
- valid
[0].left
, valid
[1].right
- valid
[1].left
);
3106 cy
= min( valid
[0].bottom
- valid
[0].top
, valid
[1].bottom
- valid
[1].top
);
3108 if (flags
& WVR_ALIGNBOTTOM
)
3110 valid
[0].top
= valid
[0].bottom
- cy
;
3111 valid
[1].top
= valid
[1].bottom
- cy
;
3115 valid
[0].bottom
= valid
[0].top
+ cy
;
3116 valid
[1].bottom
= valid
[1].top
+ cy
;
3118 if (flags
& WVR_ALIGNRIGHT
)
3120 valid
[0].left
= valid
[0].right
- cx
;
3121 valid
[1].left
= valid
[1].right
- cx
;
3125 valid
[0].right
= valid
[0].left
+ cx
;
3126 valid
[1].right
= valid
[1].left
+ cx
;
3130 static UINT
calc_ncsize( WINDOWPOS
*winpos
, const RECT
*old_window_rect
, const RECT
*old_client_rect
,
3131 const RECT
*new_window_rect
, RECT
*new_client_rect
, RECT
*valid_rects
,
3132 int parent_x
, int parent_y
)
3136 /* Send WM_NCCALCSIZE message to get new client area */
3137 if ((winpos
->flags
& (SWP_FRAMECHANGED
| SWP_NOSIZE
)) != SWP_NOSIZE
)
3139 NCCALCSIZE_PARAMS params
;
3140 WINDOWPOS winposCopy
;
3143 params
.rgrc
[0] = *new_window_rect
;
3144 params
.rgrc
[1] = *old_window_rect
;
3145 params
.rgrc
[2] = *old_client_rect
;
3146 params
.lppos
= &winposCopy
;
3147 winposCopy
= *winpos
;
3149 if (winpos
->flags
& SWP_NOMOVE
)
3151 winposCopy
.x
= old_window_rect
->left
;
3152 winposCopy
.y
= old_window_rect
->top
;
3155 if (winpos
->flags
& SWP_NOSIZE
)
3157 winposCopy
.cx
= old_window_rect
->right
- old_window_rect
->left
;
3158 winposCopy
.cy
= old_window_rect
->bottom
- old_window_rect
->top
;
3161 class_style
= get_class_long( winpos
->hwnd
, GCL_STYLE
, FALSE
);
3162 if (class_style
& CS_VREDRAW
) wvr_flags
|= WVR_VREDRAW
;
3163 if (class_style
& CS_HREDRAW
) wvr_flags
|= WVR_HREDRAW
;
3165 wvr_flags
|= send_message( winpos
->hwnd
, WM_NCCALCSIZE
, TRUE
, (LPARAM
)¶ms
);
3167 *new_client_rect
= params
.rgrc
[0];
3169 TRACE( "hwnd %p old win %s old client %s new win %s new client %s\n", winpos
->hwnd
,
3170 wine_dbgstr_rect(old_window_rect
), wine_dbgstr_rect(old_client_rect
),
3171 wine_dbgstr_rect(new_window_rect
), wine_dbgstr_rect(new_client_rect
) );
3173 if (new_client_rect
->left
!= old_client_rect
->left
- parent_x
||
3174 new_client_rect
->top
!= old_client_rect
->top
- parent_y
)
3175 winpos
->flags
&= ~SWP_NOCLIENTMOVE
;
3177 if ((new_client_rect
->right
- new_client_rect
->left
!=
3178 old_client_rect
->right
- old_client_rect
->left
))
3179 winpos
->flags
&= ~SWP_NOCLIENTSIZE
;
3181 wvr_flags
&= ~WVR_HREDRAW
;
3183 if (new_client_rect
->bottom
- new_client_rect
->top
!=
3184 old_client_rect
->bottom
- old_client_rect
->top
)
3185 winpos
->flags
&= ~SWP_NOCLIENTSIZE
;
3187 wvr_flags
&= ~WVR_VREDRAW
;
3189 valid_rects
[0] = params
.rgrc
[1];
3190 valid_rects
[1] = params
.rgrc
[2];
3194 if (!(winpos
->flags
& SWP_NOMOVE
) &&
3195 (new_client_rect
->left
!= old_client_rect
->left
- parent_x
||
3196 new_client_rect
->top
!= old_client_rect
->top
- parent_y
))
3197 winpos
->flags
&= ~SWP_NOCLIENTMOVE
;
3200 if (winpos
->flags
& (SWP_NOCOPYBITS
| SWP_NOREDRAW
| SWP_SHOWWINDOW
| SWP_HIDEWINDOW
))
3202 SetRectEmpty( &valid_rects
[0] );
3203 SetRectEmpty( &valid_rects
[1] );
3205 else get_valid_rects( old_client_rect
, new_client_rect
, wvr_flags
, valid_rects
);
3210 /* fix redundant flags and values in the WINDOWPOS structure */
3211 static BOOL
fixup_swp_flags( WINDOWPOS
*winpos
, const RECT
*old_window_rect
, int parent_x
, int parent_y
)
3214 WND
*win
= get_win_ptr( winpos
->hwnd
);
3217 if (!win
|| win
== WND_OTHER_PROCESS
)
3219 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
3222 winpos
->hwnd
= win
->obj
.handle
; /* make it a full handle */
3224 /* Finally make sure that all coordinates are valid */
3225 if (winpos
->x
< -32768) winpos
->x
= -32768;
3226 else if (winpos
->x
> 32767) winpos
->x
= 32767;
3227 if (winpos
->y
< -32768) winpos
->y
= -32768;
3228 else if (winpos
->y
> 32767) winpos
->y
= 32767;
3230 if (winpos
->cx
< 0) winpos
->cx
= 0;
3231 else if (winpos
->cx
> 32767) winpos
->cx
= 32767;
3232 if (winpos
->cy
< 0) winpos
->cy
= 0;
3233 else if (winpos
->cy
> 32767) winpos
->cy
= 32767;
3235 parent
= NtUserGetAncestor( winpos
->hwnd
, GA_PARENT
);
3236 if (!is_window_visible( parent
)) winpos
->flags
|= SWP_NOREDRAW
;
3238 if (win
->dwStyle
& WS_VISIBLE
) winpos
->flags
&= ~SWP_SHOWWINDOW
;
3241 winpos
->flags
&= ~SWP_HIDEWINDOW
;
3242 if (!(winpos
->flags
& SWP_SHOWWINDOW
)) winpos
->flags
|= SWP_NOREDRAW
;
3245 if ((old_window_rect
->right
- old_window_rect
->left
== winpos
->cx
) &&
3246 (old_window_rect
->bottom
- old_window_rect
->top
== winpos
->cy
))
3247 winpos
->flags
|= SWP_NOSIZE
; /* Already the right size */
3249 if ((old_window_rect
->left
- parent_x
== winpos
->x
) && (old_window_rect
->top
- parent_y
== winpos
->y
))
3250 winpos
->flags
|= SWP_NOMOVE
; /* Already the right position */
3252 if ((win
->dwStyle
& (WS_POPUP
| WS_CHILD
)) != WS_CHILD
)
3254 if (!(winpos
->flags
& (SWP_NOACTIVATE
|SWP_HIDEWINDOW
)) && /* Bring to the top when activating */
3255 (winpos
->flags
& SWP_NOZORDER
||
3256 (winpos
->hwndInsertAfter
!= HWND_TOPMOST
&& winpos
->hwndInsertAfter
!= HWND_NOTOPMOST
)))
3258 winpos
->flags
&= ~SWP_NOZORDER
;
3259 winpos
->hwndInsertAfter
= HWND_TOP
;
3263 /* Check hwndInsertAfter */
3264 if (winpos
->flags
& SWP_NOZORDER
) goto done
;
3266 if (winpos
->hwndInsertAfter
== HWND_TOP
)
3268 if (get_window_relative( winpos
->hwnd
, GW_HWNDFIRST
) == winpos
->hwnd
)
3269 winpos
->flags
|= SWP_NOZORDER
;
3271 else if (winpos
->hwndInsertAfter
== HWND_BOTTOM
)
3273 if (!(win
->dwExStyle
& WS_EX_TOPMOST
) &&
3274 get_window_relative( winpos
->hwnd
, GW_HWNDLAST
) == winpos
->hwnd
)
3275 winpos
->flags
|= SWP_NOZORDER
;
3277 else if (winpos
->hwndInsertAfter
== HWND_TOPMOST
)
3279 if ((win
->dwExStyle
& WS_EX_TOPMOST
) &&
3280 get_window_relative( winpos
->hwnd
, GW_HWNDFIRST
) == winpos
->hwnd
)
3281 winpos
->flags
|= SWP_NOZORDER
;
3283 else if (winpos
->hwndInsertAfter
== HWND_NOTOPMOST
)
3285 if (!(win
->dwExStyle
& WS_EX_TOPMOST
))
3286 winpos
->flags
|= SWP_NOZORDER
;
3290 if ((winpos
->hwnd
== winpos
->hwndInsertAfter
) ||
3291 (winpos
->hwnd
== get_window_relative( winpos
->hwndInsertAfter
, GW_HWNDNEXT
)))
3292 winpos
->flags
|= SWP_NOZORDER
;
3295 release_win_ptr( win
);
3299 /***********************************************************************
3302 * fix Z order taking into account owned popups -
3303 * basically we need to maintain them above the window that owns them
3305 * FIXME: hide/show owned popups when owner visibility changes.
3307 static HWND
swp_owner_popups( HWND hwnd
, HWND after
)
3309 HWND owner
, *list
= NULL
;
3312 TRACE( "(%p) after = %p\n", hwnd
, after
);
3314 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) return after
;
3316 if ((owner
= get_window_relative( hwnd
, GW_OWNER
)))
3318 /* make sure this popup stays above the owner */
3320 if (after
!= HWND_TOPMOST
)
3322 if (!(list
= list_window_children( 0, get_desktop_window(), NULL
, 0 ))) return after
;
3324 for (i
= 0; list
[i
]; i
++)
3326 BOOL topmost
= (get_window_long( list
[i
], GWL_EXSTYLE
) & WS_EX_TOPMOST
) != 0;
3328 if (list
[i
] == owner
)
3330 if (i
> 0) after
= list
[i
-1];
3331 else after
= topmost
? HWND_TOPMOST
: HWND_TOP
;
3335 if (after
== HWND_TOP
|| after
== HWND_NOTOPMOST
)
3337 if (!topmost
) break;
3339 else if (list
[i
] == after
) break;
3344 if (after
== HWND_BOTTOM
) goto done
;
3345 if (!list
&& !(list
= list_window_children( 0, get_desktop_window(), NULL
, 0 ))) goto done
;
3348 if (after
== HWND_TOP
|| after
== HWND_NOTOPMOST
)
3350 if (after
== HWND_NOTOPMOST
||
3351 !(get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_TOPMOST
))
3353 /* skip all the topmost windows */
3354 while (list
[i
] && (get_window_long( list
[i
], GWL_EXSTYLE
) & WS_EX_TOPMOST
)) i
++;
3357 else if (after
!= HWND_TOPMOST
)
3359 /* skip windows that are already placed correctly */
3360 for (i
= 0; list
[i
]; i
++)
3362 if (list
[i
] == after
) break;
3363 if (list
[i
] == hwnd
) goto done
; /* nothing to do if window is moving backwards in z-order */
3367 for ( ; list
[i
]; i
++)
3369 if (list
[i
] == hwnd
) break;
3370 if (get_window_relative( list
[i
], GW_OWNER
) != hwnd
) continue;
3371 TRACE( "moving %p owned by %p after %p\n", list
[i
], hwnd
, after
);
3372 NtUserSetWindowPos( list
[i
], after
, 0, 0, 0, 0,
3373 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOSENDCHANGING
| SWP_DEFERERASE
);
3382 /* NtUserSetWindowPos implementation */
3383 BOOL
set_window_pos( WINDOWPOS
*winpos
, int parent_x
, int parent_y
)
3385 RECT old_window_rect
, old_client_rect
, new_window_rect
, new_client_rect
, valid_rects
[2];
3388 DPI_AWARENESS_CONTEXT context
;
3390 orig_flags
= winpos
->flags
;
3392 /* First, check z-order arguments. */
3393 if (!(winpos
->flags
& SWP_NOZORDER
))
3395 /* fix sign extension */
3396 if (winpos
->hwndInsertAfter
== (HWND
)0xffff) winpos
->hwndInsertAfter
= HWND_TOPMOST
;
3397 else if (winpos
->hwndInsertAfter
== (HWND
)0xfffe) winpos
->hwndInsertAfter
= HWND_NOTOPMOST
;
3399 if (!(winpos
->hwndInsertAfter
== HWND_TOP
||
3400 winpos
->hwndInsertAfter
== HWND_BOTTOM
||
3401 winpos
->hwndInsertAfter
== HWND_TOPMOST
||
3402 winpos
->hwndInsertAfter
== HWND_NOTOPMOST
))
3404 HWND parent
= NtUserGetAncestor( winpos
->hwnd
, GA_PARENT
);
3405 HWND insertafter_parent
= NtUserGetAncestor( winpos
->hwndInsertAfter
, GA_PARENT
);
3407 /* hwndInsertAfter must be a sibling of the window */
3408 if (!insertafter_parent
) return FALSE
;
3409 if (insertafter_parent
!= parent
) return TRUE
;
3413 /* Make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
3414 if (!(winpos
->flags
& SWP_NOMOVE
))
3416 if (winpos
->x
< -32768) winpos
->x
= -32768;
3417 else if (winpos
->x
> 32767) winpos
->x
= 32767;
3418 if (winpos
->y
< -32768) winpos
->y
= -32768;
3419 else if (winpos
->y
> 32767) winpos
->y
= 32767;
3421 if (!(winpos
->flags
& SWP_NOSIZE
))
3423 if (winpos
->cx
< 0) winpos
->cx
= 0;
3424 else if (winpos
->cx
> 32767) winpos
->cx
= 32767;
3425 if (winpos
->cy
< 0) winpos
->cy
= 0;
3426 else if (winpos
->cy
> 32767) winpos
->cy
= 32767;
3429 context
= SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( winpos
->hwnd
));
3431 if (!calc_winpos( winpos
, &old_window_rect
, &old_client_rect
,
3432 &new_window_rect
, &new_client_rect
)) goto done
;
3434 /* Fix redundant flags */
3435 if (!fixup_swp_flags( winpos
, &old_window_rect
, parent_x
, parent_y
)) goto done
;
3437 if((winpos
->flags
& (SWP_NOZORDER
| SWP_HIDEWINDOW
| SWP_SHOWWINDOW
)) != SWP_NOZORDER
)
3439 if (NtUserGetAncestor( winpos
->hwnd
, GA_PARENT
) == get_desktop_window())
3440 winpos
->hwndInsertAfter
= swp_owner_popups( winpos
->hwnd
, winpos
->hwndInsertAfter
);
3443 /* Common operations */
3445 calc_ncsize( winpos
, &old_window_rect
, &old_client_rect
,
3446 &new_window_rect
, &new_client_rect
, valid_rects
, parent_x
, parent_y
);
3448 if (!apply_window_pos( winpos
->hwnd
, winpos
->hwndInsertAfter
, winpos
->flags
,
3449 &new_window_rect
, &new_client_rect
, valid_rects
))
3452 if (winpos
->flags
& SWP_HIDEWINDOW
)
3454 NtUserNotifyWinEvent( EVENT_OBJECT_HIDE
, winpos
->hwnd
, 0, 0 );
3456 NtUserHideCaret( winpos
->hwnd
);
3458 else if (winpos
->flags
& SWP_SHOWWINDOW
)
3460 NtUserNotifyWinEvent( EVENT_OBJECT_SHOW
, winpos
->hwnd
, 0, 0 );
3462 NtUserShowCaret( winpos
->hwnd
);
3465 if (!(winpos
->flags
& (SWP_NOACTIVATE
|SWP_HIDEWINDOW
)))
3467 /* child windows get WM_CHILDACTIVATE message */
3468 if ((get_window_long( winpos
->hwnd
, GWL_STYLE
) & (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
3469 send_message( winpos
->hwnd
, WM_CHILDACTIVATE
, 0, 0 );
3471 set_foreground_window( winpos
->hwnd
, FALSE
);
3474 if(!(orig_flags
& SWP_DEFERERASE
))
3476 /* erase parent when hiding or resizing child */
3477 if ((orig_flags
& SWP_HIDEWINDOW
) ||
3478 (!(orig_flags
& SWP_SHOWWINDOW
) &&
3479 (winpos
->flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOGEOMETRYCHANGE
))
3481 HWND parent
= NtUserGetAncestor( winpos
->hwnd
, GA_PARENT
);
3482 if (!parent
|| parent
== get_desktop_window()) parent
= winpos
->hwnd
;
3483 erase_now( parent
, 0 );
3486 /* Give newly shown windows a chance to redraw */
3487 if(((winpos
->flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOPOSCHANGE
)
3488 && !(orig_flags
& SWP_AGG_NOCLIENTCHANGE
) && (orig_flags
& SWP_SHOWWINDOW
))
3490 erase_now(winpos
->hwnd
, 0);
3494 /* And last, send the WM_WINDOWPOSCHANGED message */
3496 TRACE( "\tstatus flags = %04x\n", winpos
->flags
& SWP_AGG_STATUSFLAGS
);
3498 if (((winpos
->flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOPOSCHANGE
)
3499 && !((orig_flags
& SWP_AGG_NOCLIENTCHANGE
) && (orig_flags
& SWP_SHOWWINDOW
)))
3501 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
3502 and always contains final window position.
3504 winpos
->x
= new_window_rect
.left
;
3505 winpos
->y
= new_window_rect
.top
;
3506 winpos
->cx
= new_window_rect
.right
- new_window_rect
.left
;
3507 winpos
->cy
= new_window_rect
.bottom
- new_window_rect
.top
;
3508 send_message( winpos
->hwnd
, WM_WINDOWPOSCHANGED
, 0, (LPARAM
)winpos
);
3512 SetThreadDpiAwarenessContext( context
);
3516 /*******************************************************************
3517 * NtUserSetWindowPos (win32u.@)
3519 BOOL WINAPI
NtUserSetWindowPos( HWND hwnd
, HWND after
, INT x
, INT y
, INT cx
, INT cy
, UINT flags
)
3523 TRACE( "hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n", hwnd
, after
, x
, y
, cx
, cy
, flags
);
3524 if(TRACE_ON(win
)) dump_winpos_flags(flags
);
3526 if (is_broadcast( hwnd
))
3528 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
3532 winpos
.hwnd
= get_full_window_handle( hwnd
);
3533 winpos
.hwndInsertAfter
= get_full_window_handle( after
);
3538 winpos
.flags
= flags
;
3540 map_dpi_winpos( &winpos
);
3542 if (is_current_thread_window( hwnd
))
3543 return set_window_pos( &winpos
, 0, 0 );
3545 if (flags
& SWP_ASYNCWINDOWPOS
)
3546 return NtUserMessageCall( winpos
.hwnd
, WM_WINE_SETWINDOWPOS
, 0, (LPARAM
)&winpos
,
3547 0, NtUserSendNotifyMessage
, FALSE
);
3549 return send_message( winpos
.hwnd
, WM_WINE_SETWINDOWPOS
, 0, (LPARAM
)&winpos
);
3554 struct user_object obj
;
3556 INT suggested_count
;
3561 /* see BeginDeferWindowPos */
3562 HDWP
begin_defer_window_pos( INT count
)
3567 TRACE( "%d\n", count
);
3571 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
3574 /* Windows allows zero count, in which case it allocates context for 8 moves */
3575 if (count
== 0) count
= 8;
3577 if (!(dwp
= malloc( sizeof(DWP
) ))) return 0;
3581 dwp
->suggested_count
= count
;
3583 if (!(dwp
->winpos
= malloc( count
* sizeof(WINDOWPOS
) )) ||
3584 !(handle
= alloc_user_handle( &dwp
->obj
, NTUSER_OBJ_WINPOS
)))
3586 free( dwp
->winpos
);
3590 TRACE( "returning %p\n", handle
);
3594 /***********************************************************************
3595 * NtUserDeferWindowPosAndBand (win32u.@)
3597 HDWP WINAPI
NtUserDeferWindowPosAndBand( HDWP hdwp
, HWND hwnd
, HWND after
,
3598 INT x
, INT y
, INT cx
, INT cy
,
3599 UINT flags
, UINT unk1
, UINT unk2
)
3601 HDWP retvalue
= hdwp
;
3606 TRACE( "hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
3607 hdwp
, hwnd
, after
, x
, y
, cx
, cy
, flags
);
3609 winpos
.hwnd
= get_full_window_handle( hwnd
);
3610 if (is_desktop_window( winpos
.hwnd
) || !is_window( winpos
.hwnd
))
3612 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
3616 winpos
.hwndInsertAfter
= get_full_window_handle( after
);
3617 winpos
.flags
= flags
;
3622 map_dpi_winpos( &winpos
);
3624 if (!(dwp
= get_user_handle_ptr( hdwp
, NTUSER_OBJ_WINPOS
))) return 0;
3625 if (dwp
== OBJ_OTHER_PROCESS
)
3627 FIXME( "other process handle %p\n", hdwp
);
3631 for (i
= 0; i
< dwp
->count
; i
++)
3633 if (dwp
->winpos
[i
].hwnd
== winpos
.hwnd
)
3635 /* Merge with the other changes */
3636 if (!(flags
& SWP_NOZORDER
))
3638 dwp
->winpos
[i
].hwndInsertAfter
= winpos
.hwndInsertAfter
;
3640 if (!(flags
& SWP_NOMOVE
))
3642 dwp
->winpos
[i
].x
= winpos
.x
;
3643 dwp
->winpos
[i
].y
= winpos
.y
;
3645 if (!(flags
& SWP_NOSIZE
))
3647 dwp
->winpos
[i
].cx
= winpos
.cx
;
3648 dwp
->winpos
[i
].cy
= winpos
.cy
;
3650 dwp
->winpos
[i
].flags
&= flags
| ~(SWP_NOSIZE
| SWP_NOMOVE
|
3651 SWP_NOZORDER
| SWP_NOREDRAW
|
3652 SWP_NOACTIVATE
| SWP_NOCOPYBITS
|
3654 dwp
->winpos
[i
].flags
|= flags
& (SWP_SHOWWINDOW
| SWP_HIDEWINDOW
|
3659 if (dwp
->count
>= dwp
->suggested_count
)
3661 WINDOWPOS
*newpos
= realloc( dwp
->winpos
, dwp
->suggested_count
* 2 * sizeof(WINDOWPOS
) );
3667 dwp
->suggested_count
*= 2;
3668 dwp
->winpos
= newpos
;
3670 dwp
->winpos
[dwp
->count
++] = winpos
;
3672 release_user_handle_ptr( dwp
);
3676 /***********************************************************************
3677 * NtUserEndDeferWindowPosEx (win32u.@)
3679 BOOL WINAPI
NtUserEndDeferWindowPosEx( HDWP hdwp
, BOOL async
)
3685 TRACE( "%p\n", hdwp
);
3687 if (async
) FIXME( "async not supported\n" );
3689 if (!(dwp
= free_user_handle( hdwp
, NTUSER_OBJ_WINPOS
))) return FALSE
;
3690 if (dwp
== OBJ_OTHER_PROCESS
)
3692 FIXME( "other process handle %p\n", hdwp
);
3696 for (i
= 0, winpos
= dwp
->winpos
; i
< dwp
->count
; i
++, winpos
++)
3698 TRACE( "hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
3699 winpos
->hwnd
, winpos
->hwndInsertAfter
, winpos
->x
, winpos
->y
,
3700 winpos
->cx
, winpos
->cy
, winpos
->flags
);
3702 if (is_current_thread_window( winpos
->hwnd
))
3703 set_window_pos( winpos
, 0, 0 );
3705 send_message( winpos
->hwnd
, WM_WINE_SETWINDOWPOS
, 0, (LPARAM
)winpos
);
3707 free( dwp
->winpos
);
3712 /***********************************************************************
3713 * NtUserSetInternalWindowPos (win32u.@)
3715 void WINAPI
NtUserSetInternalWindowPos( HWND hwnd
, UINT cmd
, RECT
*rect
, POINT
*pt
)
3717 WINDOWPLACEMENT wndpl
;
3720 wndpl
.length
= sizeof(wndpl
);
3721 wndpl
.showCmd
= cmd
;
3722 wndpl
.flags
= flags
= 0;
3727 wndpl
.flags
|= WPF_SETMINPOSITION
;
3728 wndpl
.ptMinPosition
= *pt
;
3732 flags
|= PLACE_RECT
;
3733 wndpl
.rcNormalPosition
= *rect
;
3735 set_window_placement( hwnd
, &wndpl
, flags
);
3738 /***********************************************************************
3741 * Set the flags of a window and return the previous value.
3743 UINT
win_set_flags( HWND hwnd
, UINT set_mask
, UINT clear_mask
)
3745 WND
*win
= get_win_ptr( hwnd
);
3748 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return 0;
3750 win
->flags
= (ret
& ~clear_mask
) | set_mask
;
3751 release_win_ptr( win
);
3755 /*******************************************************************
3756 * can_activate_window
3758 * Check if we can activate the specified window.
3760 static BOOL
can_activate_window( HWND hwnd
)
3764 if (!hwnd
) return FALSE
;
3765 style
= get_window_long( hwnd
, GWL_STYLE
);
3766 if (!(style
& WS_VISIBLE
)) return FALSE
;
3767 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
3768 return !(style
& WS_DISABLED
);
3771 /*******************************************************************
3772 * activate_other_window
3774 * Activates window other than hwnd.
3776 static void activate_other_window( HWND hwnd
)
3780 if ((get_window_long( hwnd
, GWL_STYLE
) & WS_POPUP
) &&
3781 (hwnd_to
= get_window_relative( hwnd
, GW_OWNER
)))
3783 hwnd_to
= NtUserGetAncestor( hwnd_to
, GA_ROOT
);
3784 if (can_activate_window( hwnd_to
)) goto done
;
3790 if (!(hwnd_to
= get_window_relative( hwnd_to
, GW_HWNDNEXT
))) break;
3791 if (can_activate_window( hwnd_to
)) goto done
;
3794 hwnd_to
= get_window_relative( get_desktop_window(), GW_CHILD
);
3797 if (hwnd_to
== hwnd
)
3802 if (can_activate_window( hwnd_to
)) goto done
;
3803 if (!(hwnd_to
= get_window_relative( hwnd_to
, GW_HWNDNEXT
))) break;
3807 fg
= NtUserGetForegroundWindow();
3808 TRACE( "win = %p fg = %p\n", hwnd_to
, fg
);
3809 if (!fg
|| hwnd
== fg
)
3811 if (set_foreground_window( hwnd_to
, FALSE
)) return;
3813 if (NtUserSetActiveWindow( hwnd_to
)) NtUserSetActiveWindow( 0 );
3816 /*******************************************************************
3817 * send_parent_notify
3819 static void send_parent_notify( HWND hwnd
, UINT msg
)
3821 if ((get_window_long( hwnd
, GWL_STYLE
) & (WS_CHILD
| WS_POPUP
)) == WS_CHILD
&&
3822 !(get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_NOPARENTNOTIFY
))
3824 HWND parent
= get_parent( hwnd
);
3825 if (parent
&& parent
!= get_desktop_window())
3826 send_message( parent
, WM_PARENTNOTIFY
,
3827 MAKEWPARAM( msg
, get_window_long( hwnd
, GWLP_ID
)), (LPARAM
)hwnd
);
3831 /*******************************************************************
3834 * Get the minimized and maximized information for a window.
3836 MINMAXINFO
get_min_max_info( HWND hwnd
)
3838 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
3839 LONG exstyle
= get_window_long( hwnd
, GWL_EXSTYLE
);
3840 DPI_AWARENESS_CONTEXT context
;
3841 RECT rc_work
, rc_primary
;
3842 LONG adjusted_style
;
3848 context
= SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( hwnd
));
3850 /* Compute default values */
3852 get_window_rect( hwnd
, &rc
, get_thread_dpi() );
3853 minmax
.ptReserved
.x
= rc
.left
;
3854 minmax
.ptReserved
.y
= rc
.top
;
3856 if ((style
& WS_CAPTION
) == WS_CAPTION
)
3857 adjusted_style
= style
& ~WS_BORDER
; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
3859 adjusted_style
= style
;
3861 get_client_rect( NtUserGetAncestor( hwnd
, GA_PARENT
), &rc
);
3862 AdjustWindowRectEx( &rc
, adjusted_style
, (style
& WS_POPUP
) && get_menu( hwnd
), exstyle
);
3867 minmax
.ptMaxSize
.x
= rc
.right
- rc
.left
;
3868 minmax
.ptMaxSize
.y
= rc
.bottom
- rc
.top
;
3869 if (style
& (WS_DLGFRAME
| WS_BORDER
))
3871 minmax
.ptMinTrackSize
.x
= get_system_metrics( SM_CXMINTRACK
);
3872 minmax
.ptMinTrackSize
.y
= get_system_metrics( SM_CYMINTRACK
);
3876 minmax
.ptMinTrackSize
.x
= 2 * xinc
;
3877 minmax
.ptMinTrackSize
.y
= 2 * yinc
;
3879 minmax
.ptMaxTrackSize
.x
= get_system_metrics( SM_CXMAXTRACK
);
3880 minmax
.ptMaxTrackSize
.y
= get_system_metrics( SM_CYMAXTRACK
);
3881 minmax
.ptMaxPosition
.x
= -xinc
;
3882 minmax
.ptMaxPosition
.y
= -yinc
;
3884 if ((win
= get_win_ptr( hwnd
)) && win
!= WND_DESKTOP
&& win
!= WND_OTHER_PROCESS
)
3886 if (!empty_point( win
->max_pos
)) minmax
.ptMaxPosition
= win
->max_pos
;
3887 release_win_ptr( win
);
3890 send_message( hwnd
, WM_GETMINMAXINFO
, 0, (LPARAM
)&minmax
);
3892 /* if the app didn't change the values, adapt them for the current monitor */
3894 if (get_work_rect( hwnd
, &rc_work
))
3896 rc_primary
= get_primary_monitor_rect( get_thread_dpi() );
3897 if (minmax
.ptMaxSize
.x
== (rc_primary
.right
- rc_primary
.left
) + 2 * xinc
&&
3898 minmax
.ptMaxSize
.y
== (rc_primary
.bottom
- rc_primary
.top
) + 2 * yinc
)
3900 minmax
.ptMaxSize
.x
= (rc_work
.right
- rc_work
.left
) + 2 * xinc
;
3901 minmax
.ptMaxSize
.y
= (rc_work
.bottom
- rc_work
.top
) + 2 * yinc
;
3903 if (minmax
.ptMaxPosition
.x
== -xinc
&& minmax
.ptMaxPosition
.y
== -yinc
)
3905 minmax
.ptMaxPosition
.x
= rc_work
.left
- xinc
;
3906 minmax
.ptMaxPosition
.y
= rc_work
.top
- yinc
;
3910 TRACE( "%d %d / %d %d / %d %d / %d %d\n",
3911 (int)minmax
.ptMaxSize
.x
, (int)minmax
.ptMaxSize
.y
,
3912 (int)minmax
.ptMaxPosition
.x
, (int)minmax
.ptMaxPosition
.y
,
3913 (int)minmax
.ptMaxTrackSize
.x
, (int)minmax
.ptMaxTrackSize
.y
,
3914 (int)minmax
.ptMinTrackSize
.x
, (int)minmax
.ptMinTrackSize
.y
);
3916 minmax
.ptMaxTrackSize
.x
= max( minmax
.ptMaxTrackSize
.x
, minmax
.ptMinTrackSize
.x
);
3917 minmax
.ptMaxTrackSize
.y
= max( minmax
.ptMaxTrackSize
.y
, minmax
.ptMinTrackSize
.y
);
3919 SetThreadDpiAwarenessContext( context
);
3923 static POINT
get_first_minimized_child_pos( const RECT
*parent
, const MINIMIZEDMETRICS
*mm
,
3924 int width
, int height
)
3928 if (mm
->iArrange
& ARW_STARTRIGHT
)
3929 ret
.x
= parent
->right
- mm
->iHorzGap
- width
;
3931 ret
.x
= parent
->left
+ mm
->iHorzGap
;
3932 if (mm
->iArrange
& ARW_STARTTOP
)
3933 ret
.y
= parent
->top
+ mm
->iVertGap
;
3935 ret
.y
= parent
->bottom
- mm
->iVertGap
- height
;
3940 static void get_next_minimized_child_pos( const RECT
*parent
, const MINIMIZEDMETRICS
*mm
,
3941 int width
, int height
, POINT
*pos
)
3945 if (mm
->iArrange
& ARW_UP
) /* == ARW_DOWN */
3947 if (mm
->iArrange
& ARW_STARTTOP
)
3949 pos
->y
+= height
+ mm
->iVertGap
;
3950 if ((next
= pos
->y
+ height
> parent
->bottom
))
3951 pos
->y
= parent
->top
+ mm
->iVertGap
;
3955 pos
->y
-= height
+ mm
->iVertGap
;
3956 if ((next
= pos
->y
< parent
->top
))
3957 pos
->y
= parent
->bottom
- mm
->iVertGap
- height
;
3962 if (mm
->iArrange
& ARW_STARTRIGHT
)
3963 pos
->x
-= width
+ mm
->iHorzGap
;
3965 pos
->x
+= width
+ mm
->iHorzGap
;
3970 if (mm
->iArrange
& ARW_STARTRIGHT
)
3972 pos
->x
-= width
+ mm
->iHorzGap
;
3973 if ((next
= pos
->x
< parent
->left
))
3974 pos
->x
= parent
->right
- mm
->iHorzGap
- width
;
3978 pos
->x
+= width
+ mm
->iHorzGap
;
3979 if ((next
= pos
->x
+ width
> parent
->right
))
3980 pos
->x
= parent
->left
+ mm
->iHorzGap
;
3985 if (mm
->iArrange
& ARW_STARTTOP
)
3986 pos
->y
+= height
+ mm
->iVertGap
;
3988 pos
->y
-= height
+ mm
->iVertGap
;
3993 static POINT
get_minimized_pos( HWND hwnd
, POINT pt
)
3995 RECT rect
, parent_rect
;
3998 MINIMIZEDMETRICS metrics
;
4001 parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
4002 if (parent
== get_desktop_window())
4004 MONITORINFO mon_info
;
4005 HMONITOR monitor
= monitor_from_window( hwnd
, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
4007 mon_info
.cbSize
= sizeof( mon_info
);
4008 get_monitor_info( monitor
, &mon_info
);
4009 parent_rect
= mon_info
.rcWork
;
4011 else get_client_rect( parent
, &parent_rect
);
4013 if (pt
.x
>= parent_rect
.left
&& (pt
.x
+ get_system_metrics( SM_CXMINIMIZED
) < parent_rect
.right
) &&
4014 pt
.y
>= parent_rect
.top
&& (pt
.y
+ get_system_metrics( SM_CYMINIMIZED
) < parent_rect
.bottom
))
4015 return pt
; /* The icon already has a suitable position */
4017 width
= get_system_metrics( SM_CXMINIMIZED
);
4018 height
= get_system_metrics( SM_CYMINIMIZED
);
4020 metrics
.cbSize
= sizeof(metrics
);
4021 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(metrics
), &metrics
, 0 );
4023 /* Check if another icon already occupies this spot */
4024 /* FIXME: this is completely inefficient */
4026 hrgn
= NtGdiCreateRectRgn( 0, 0, 0, 0 );
4027 tmp
= NtGdiCreateRectRgn( 0, 0, 0, 0 );
4028 for (child
= get_window_relative( parent
, GW_CHILD
);
4030 child
= get_window_relative( child
, GW_HWNDNEXT
))
4032 if (child
== hwnd
) continue;
4033 if ((get_window_long( child
, GWL_STYLE
) & (WS_VISIBLE
|WS_MINIMIZE
)) != (WS_VISIBLE
|WS_MINIMIZE
))
4035 if (get_window_rects( child
, COORDS_PARENT
, &rect
, NULL
, get_thread_dpi() ))
4037 NtGdiSetRectRgn( tmp
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
4038 NtGdiCombineRgn( hrgn
, hrgn
, tmp
, RGN_OR
);
4041 NtGdiDeleteObjectApp( tmp
);
4043 pt
= get_first_minimized_child_pos( &parent_rect
, &metrics
, width
, height
);
4046 SetRect( &rect
, pt
.x
, pt
.y
, pt
.x
+ width
, pt
.y
+ height
);
4047 if (!NtGdiRectInRegion( hrgn
, &rect
))
4050 get_next_minimized_child_pos( &parent_rect
, &metrics
, width
, height
, &pt
);
4053 NtGdiDeleteObjectApp( hrgn
);
4057 /***********************************************************************
4058 * window_min_maximize
4060 static UINT
window_min_maximize( HWND hwnd
, UINT cmd
, RECT
*rect
)
4065 WINDOWPLACEMENT wpl
;
4067 TRACE( "%p %u\n", hwnd
, cmd
);
4069 wpl
.length
= sizeof(wpl
);
4070 NtUserGetWindowPlacement( hwnd
, &wpl
);
4072 if (call_hooks( WH_CBT
, HCBT_MINMAX
, (WPARAM
)hwnd
, cmd
, 0 ))
4073 return SWP_NOSIZE
| SWP_NOMOVE
;
4075 if (is_iconic( hwnd
))
4079 case SW_SHOWMINNOACTIVE
:
4080 case SW_SHOWMINIMIZED
:
4081 case SW_FORCEMINIMIZE
:
4083 wpl
.ptMinPosition
= get_minimized_pos( hwnd
, wpl
.ptMinPosition
);
4085 SetRect( rect
, wpl
.ptMinPosition
.x
, wpl
.ptMinPosition
.y
,
4086 wpl
.ptMinPosition
.x
+ get_system_metrics( SM_CXMINIMIZED
),
4087 wpl
.ptMinPosition
.y
+ get_system_metrics( SM_CYMINIMIZED
));
4088 return SWP_NOSIZE
| SWP_NOMOVE
;
4090 if (!send_message( hwnd
, WM_QUERYOPEN
, 0, 0 )) return SWP_NOSIZE
| SWP_NOMOVE
;
4091 swp_flags
|= SWP_NOCOPYBITS
;
4096 case SW_SHOWMINNOACTIVE
:
4097 case SW_SHOWMINIMIZED
:
4098 case SW_FORCEMINIMIZE
:
4100 if (is_zoomed( hwnd
)) win_set_flags( hwnd
, WIN_RESTORE_MAX
, 0 );
4101 else win_set_flags( hwnd
, 0, WIN_RESTORE_MAX
);
4103 if (get_focus() == hwnd
)
4105 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
)
4106 NtUserSetFocus( NtUserGetAncestor( hwnd
, GA_PARENT
));
4108 NtUserSetFocus( 0 );
4111 old_style
= set_window_style( hwnd
, WS_MINIMIZE
, WS_MAXIMIZE
);
4113 wpl
.ptMinPosition
= get_minimized_pos( hwnd
, wpl
.ptMinPosition
);
4115 if (!(old_style
& WS_MINIMIZE
)) swp_flags
|= SWP_STATECHANGED
;
4116 SetRect( rect
, wpl
.ptMinPosition
.x
, wpl
.ptMinPosition
.y
,
4117 wpl
.ptMinPosition
.x
+ get_system_metrics(SM_CXMINIMIZED
),
4118 wpl
.ptMinPosition
.y
+ get_system_metrics(SM_CYMINIMIZED
) );
4119 swp_flags
|= SWP_NOCOPYBITS
;
4123 old_style
= get_window_long( hwnd
, GWL_STYLE
);
4124 if ((old_style
& WS_MAXIMIZE
) && (old_style
& WS_VISIBLE
)) return SWP_NOSIZE
| SWP_NOMOVE
;
4126 minmax
= get_min_max_info( hwnd
);
4128 old_style
= set_window_style( hwnd
, WS_MAXIMIZE
, WS_MINIMIZE
);
4129 if (old_style
& WS_MINIMIZE
)
4130 win_set_flags( hwnd
, WIN_RESTORE_MAX
, 0 );
4132 if (!(old_style
& WS_MAXIMIZE
)) swp_flags
|= SWP_STATECHANGED
;
4133 SetRect( rect
, minmax
.ptMaxPosition
.x
, minmax
.ptMaxPosition
.y
,
4134 minmax
.ptMaxPosition
.x
+ minmax
.ptMaxSize
.x
,
4135 minmax
.ptMaxPosition
.y
+ minmax
.ptMaxSize
.y
);
4138 case SW_SHOWNOACTIVATE
:
4139 win_set_flags( hwnd
, 0, WIN_RESTORE_MAX
);
4143 case SW_SHOWDEFAULT
: /* FIXME: should have its own handler */
4144 old_style
= set_window_style( hwnd
, 0, WS_MINIMIZE
| WS_MAXIMIZE
);
4145 if (old_style
& WS_MINIMIZE
)
4147 if (win_get_flags( hwnd
) & WIN_RESTORE_MAX
)
4149 /* Restore to maximized position */
4150 minmax
= get_min_max_info( hwnd
);
4151 set_window_style( hwnd
, WS_MAXIMIZE
, 0 );
4152 swp_flags
|= SWP_STATECHANGED
;
4153 SetRect( rect
, minmax
.ptMaxPosition
.x
, minmax
.ptMaxPosition
.y
,
4154 minmax
.ptMaxPosition
.x
+ minmax
.ptMaxSize
.x
,
4155 minmax
.ptMaxPosition
.y
+ minmax
.ptMaxSize
.y
);
4159 else if (!(old_style
& WS_MAXIMIZE
)) break;
4161 swp_flags
|= SWP_STATECHANGED
;
4163 /* Restore to normal position */
4165 *rect
= wpl
.rcNormalPosition
;
4172 /* see ArrangeIconicWindows */
4173 static UINT
arrange_iconic_windows( HWND parent
)
4175 int width
, height
, count
= 0;
4176 MINIMIZEDMETRICS metrics
;
4181 metrics
.cbSize
= sizeof(metrics
);
4182 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(metrics
), &metrics
, 0 );
4183 width
= get_system_metrics( SM_CXMINIMIZED
);
4184 height
= get_system_metrics( SM_CYMINIMIZED
);
4186 if (parent
== get_desktop_window())
4188 MONITORINFO mon_info
;
4189 HMONITOR monitor
= monitor_from_window( 0, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
4191 mon_info
.cbSize
= sizeof( mon_info
);
4192 get_monitor_info( monitor
, &mon_info
);
4193 parent_rect
= mon_info
.rcWork
;
4195 else get_client_rect( parent
, &parent_rect
);
4197 pt
= get_first_minimized_child_pos( &parent_rect
, &metrics
, width
, height
);
4199 child
= get_window_relative( parent
, GW_CHILD
);
4202 if (is_iconic( child
))
4204 NtUserSetWindowPos( child
, 0, pt
.x
, pt
.y
, 0, 0,
4205 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
4206 get_next_minimized_child_pos( &parent_rect
, &metrics
, width
, height
, &pt
);
4209 child
= get_window_relative( child
, GW_HWNDNEXT
);
4214 /*******************************************************************
4215 * update_window_state
4217 * Trigger an update of the window's driver state and surface.
4219 void update_window_state( HWND hwnd
)
4221 DPI_AWARENESS_CONTEXT context
;
4222 RECT window_rect
, client_rect
, valid_rects
[2];
4224 if (!is_current_thread_window( hwnd
))
4226 NtUserPostMessage( hwnd
, WM_WINE_UPDATEWINDOWSTATE
, 0, 0 );
4230 context
= SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( hwnd
));
4231 get_window_rects( hwnd
, COORDS_PARENT
, &window_rect
, &client_rect
, get_thread_dpi() );
4232 valid_rects
[0] = valid_rects
[1] = client_rect
;
4233 apply_window_pos( hwnd
, 0, SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOCLIENTSIZE
| SWP_NOCLIENTMOVE
|
4234 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREDRAW
,
4235 &window_rect
, &client_rect
, valid_rects
);
4236 SetThreadDpiAwarenessContext( context
);
4239 /***********************************************************************
4242 * Implementation of ShowWindow and ShowWindowAsync.
4244 static BOOL
show_window( HWND hwnd
, INT cmd
)
4248 DPI_AWARENESS_CONTEXT context
;
4249 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
4250 BOOL was_visible
= (style
& WS_VISIBLE
) != 0;
4251 BOOL show_flag
= TRUE
;
4252 RECT newPos
= {0, 0, 0, 0};
4253 UINT new_swp
, swp
= 0;
4255 TRACE( "hwnd=%p, cmd=%d, was_visible %d\n", hwnd
, cmd
, was_visible
);
4257 context
= SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( hwnd
));
4262 if (!was_visible
) goto done
;
4264 swp
|= SWP_HIDEWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
4265 if (style
& WS_CHILD
) swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4268 case SW_SHOWMINNOACTIVE
:
4270 case SW_FORCEMINIMIZE
: /* FIXME: Does not work if thread is hung. */
4271 swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4273 case SW_SHOWMINIMIZED
:
4274 swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
4275 swp
|= window_min_maximize( hwnd
, cmd
, &newPos
);
4276 if ((style
& WS_MINIMIZE
) && was_visible
) goto done
;
4279 case SW_SHOWMAXIMIZED
: /* same as SW_MAXIMIZE */
4280 if (!was_visible
) swp
|= SWP_SHOWWINDOW
;
4281 swp
|= SWP_FRAMECHANGED
;
4282 swp
|= window_min_maximize( hwnd
, SW_MAXIMIZE
, &newPos
);
4283 if ((style
& WS_MAXIMIZE
) && was_visible
) goto done
;
4287 swp
|= SWP_NOACTIVATE
| SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
4288 if (style
& WS_CHILD
) swp
|= SWP_NOZORDER
;
4292 if (was_visible
) goto done
;
4293 swp
|= SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
4294 if (style
& WS_CHILD
) swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4297 case SW_SHOWNOACTIVATE
:
4298 swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4302 case SW_SHOWNORMAL
: /* same as SW_NORMAL: */
4303 case SW_SHOWDEFAULT
: /* FIXME: should have its own handler */
4304 if (!was_visible
) swp
|= SWP_SHOWWINDOW
;
4305 if (style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
4307 swp
|= SWP_FRAMECHANGED
;
4308 swp
|= window_min_maximize( hwnd
, cmd
, &newPos
);
4312 if (was_visible
) goto done
;
4313 swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
4315 if (style
& WS_CHILD
&& !(swp
& SWP_STATECHANGED
)) swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4322 if ((show_flag
!= was_visible
|| cmd
== SW_SHOWNA
) && cmd
!= SW_SHOWMAXIMIZED
&& !(swp
& SWP_STATECHANGED
))
4324 send_message( hwnd
, WM_SHOWWINDOW
, show_flag
, 0 );
4325 if (!is_window( hwnd
)) goto done
;
4328 if (IsRectEmpty( &newPos
)) new_swp
= swp
;
4329 else if ((new_swp
= user_driver
->pShowWindow( hwnd
, cmd
, &newPos
, swp
)) == ~0)
4331 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) new_swp
= swp
;
4332 else if (is_iconic( hwnd
) && (newPos
.left
!= -32000 || newPos
.top
!= -32000))
4334 OffsetRect( &newPos
, -32000 - newPos
.left
, -32000 - newPos
.top
);
4335 new_swp
= swp
& ~(SWP_NOMOVE
| SWP_NOCLIENTMOVE
);
4341 parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
4342 if (parent
&& !is_window_visible( parent
) && !(swp
& SWP_STATECHANGED
))
4344 /* if parent is not visible simply toggle WS_VISIBLE and return */
4345 if (show_flag
) set_window_style( hwnd
, WS_VISIBLE
, 0 );
4346 else set_window_style( hwnd
, 0, WS_VISIBLE
);
4349 NtUserSetWindowPos( hwnd
, HWND_TOP
, newPos
.left
, newPos
.top
,
4350 newPos
.right
- newPos
.left
, newPos
.bottom
- newPos
.top
, swp
);
4356 /* FIXME: This will cause the window to be activated irrespective
4357 * of whether it is owned by the same thread. Has to be done
4361 if (hwnd
== get_active_window()) activate_other_window( hwnd
);
4363 /* Revert focus to parent */
4364 hFocus
= get_focus();
4367 HWND parent
= NtUserGetAncestor(hwnd
, GA_PARENT
);
4368 if (parent
== get_desktop_window()) parent
= 0;
4369 NtUserSetFocus(parent
);
4374 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
) goto done
;
4376 if (win
->flags
& WIN_NEED_SIZE
)
4378 /* should happen only in CreateWindowEx() */
4379 int wParam
= SIZE_RESTORED
;
4383 get_window_rects( hwnd
, COORDS_PARENT
, NULL
, &client
, get_thread_dpi() );
4384 lparam
= MAKELONG( client
.right
- client
.left
, client
.bottom
- client
.top
);
4385 win
->flags
&= ~WIN_NEED_SIZE
;
4386 if (win
->dwStyle
& WS_MAXIMIZE
) wParam
= SIZE_MAXIMIZED
;
4387 else if (win
->dwStyle
& WS_MINIMIZE
)
4389 wParam
= SIZE_MINIMIZED
;
4392 release_win_ptr( win
);
4394 send_message( hwnd
, WM_SIZE
, wParam
, lparam
);
4395 send_message( hwnd
, WM_MOVE
, 0, MAKELONG( client
.left
, client
.top
));
4397 else release_win_ptr( win
);
4399 /* if previous state was minimized Windows sets focus to the window */
4400 if (style
& WS_MINIMIZE
)
4402 NtUserSetFocus( hwnd
);
4403 /* Send a WM_ACTIVATE message for a top level window, even if the window is already active */
4404 if (NtUserGetAncestor( hwnd
, GA_ROOT
) == hwnd
&& !(swp
& SWP_NOACTIVATE
))
4405 send_message( hwnd
, WM_ACTIVATE
, WA_ACTIVE
, 0 );
4409 SetThreadDpiAwarenessContext( context
);
4413 /***********************************************************************
4414 * NtUserShowWindowAsync (win32u.@)
4416 * doesn't wait; returns immediately.
4417 * used by threads to toggle windows in other (possibly hanging) threads
4419 BOOL WINAPI
NtUserShowWindowAsync( HWND hwnd
, INT cmd
)
4423 if (is_broadcast(hwnd
))
4425 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4429 if ((full_handle
= is_current_thread_window( hwnd
)))
4430 return show_window( full_handle
, cmd
);
4432 return NtUserMessageCall( hwnd
, WM_WINE_SHOWWINDOW
, cmd
, 0, 0,
4433 NtUserSendNotifyMessage
, FALSE
);
4436 /***********************************************************************
4437 * NtUserShowWindow (win32u.@)
4439 BOOL WINAPI
NtUserShowWindow( HWND hwnd
, INT cmd
)
4443 if (is_broadcast(hwnd
))
4445 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4448 if ((full_handle
= is_current_thread_window( hwnd
)))
4449 return show_window( full_handle
, cmd
);
4451 if ((cmd
== SW_HIDE
) && !(get_window_long( hwnd
, GWL_STYLE
) & WS_VISIBLE
))
4454 if ((cmd
== SW_SHOW
) && (get_window_long( hwnd
, GWL_STYLE
) & WS_VISIBLE
))
4457 return send_message( hwnd
, WM_WINE_SHOWWINDOW
, cmd
, 0 );
4460 /* see ShowOwnedPopups */
4461 BOOL
show_owned_popups( HWND owner
, BOOL show
)
4464 HWND
*win_array
= list_window_children( 0, get_desktop_window(), NULL
, 0 );
4466 if (!win_array
) return TRUE
;
4468 while (win_array
[count
]) count
++;
4469 while (--count
>= 0)
4471 if (get_window_relative( win_array
[count
], GW_OWNER
) != owner
) continue;
4474 if (win_get_flags( win_array
[count
] ) & WIN_NEEDS_SHOW_OWNEDPOPUP
)
4475 /* In Windows, ShowOwnedPopups(TRUE) generates
4476 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
4477 * regardless of the state of the owner
4479 send_message( win_array
[count
], WM_SHOWWINDOW
, SW_SHOWNORMAL
, SW_PARENTOPENING
);
4483 if (get_window_long( win_array
[count
], GWL_STYLE
) & WS_VISIBLE
)
4484 /* In Windows, ShowOwnedPopups(FALSE) generates
4485 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
4486 * regardless of the state of the owner
4488 send_message( win_array
[count
], WM_SHOWWINDOW
, SW_HIDE
, SW_PARENTCLOSING
);
4496 /*******************************************************************
4497 * NtUserFlashWindowEx (win32u.@)
4499 BOOL WINAPI
NtUserFlashWindowEx( FLASHWINFO
*info
)
4503 TRACE( "%p\n", info
);
4507 RtlSetLastWin32Error( ERROR_NOACCESS
);
4511 if (!info
->hwnd
|| info
->cbSize
!= sizeof(FLASHWINFO
) || !is_window( info
->hwnd
))
4513 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4516 FIXME( "%p - semi-stub\n", info
);
4518 if (is_iconic( info
->hwnd
))
4520 NtUserRedrawWindow( info
->hwnd
, 0, 0, RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_FRAME
);
4522 win
= get_win_ptr( info
->hwnd
);
4523 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
4524 if (info
->dwFlags
& FLASHW_CAPTION
&& !(win
->flags
& WIN_NCACTIVATED
))
4526 win
->flags
|= WIN_NCACTIVATED
;
4528 else if (!info
->dwFlags
)
4530 win
->flags
&= ~WIN_NCACTIVATED
;
4532 release_win_ptr( win
);
4533 user_driver
->pFlashWindowEx( info
);
4539 HWND hwnd
= info
->hwnd
;
4541 win
= get_win_ptr( hwnd
);
4542 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
4543 hwnd
= win
->obj
.handle
; /* make it a full handle */
4545 if (info
->dwFlags
) wparam
= !(win
->flags
& WIN_NCACTIVATED
);
4546 else wparam
= (hwnd
== NtUserGetForegroundWindow());
4548 release_win_ptr( win
);
4550 if (!info
->dwFlags
|| info
->dwFlags
& FLASHW_CAPTION
)
4551 send_message( hwnd
, WM_NCACTIVATE
, wparam
, 0 );
4553 user_driver
->pFlashWindowEx( info
);
4558 /* see GetWindowContextHelpId */
4559 DWORD
get_window_context_help_id( HWND hwnd
)
4562 WND
*win
= get_win_ptr( hwnd
);
4563 if (!win
|| win
== WND_DESKTOP
) return 0;
4564 if (win
== WND_OTHER_PROCESS
)
4566 if (is_window( hwnd
)) FIXME( "not supported on other process window %p\n", hwnd
);
4569 retval
= win
->helpContext
;
4570 release_win_ptr( win
);
4574 /* see SetWindowContextHelpId */
4575 static BOOL
set_window_context_help_id( HWND hwnd
, DWORD id
)
4577 WND
*win
= get_win_ptr( hwnd
);
4578 if (!win
|| win
== WND_DESKTOP
) return FALSE
;
4579 if (win
== WND_OTHER_PROCESS
)
4581 if (is_window( hwnd
)) FIXME( "not supported on other process window %p\n", hwnd
);
4584 win
->helpContext
= id
;
4585 release_win_ptr( win
);
4589 /***********************************************************************
4590 * NtUserInternalGetWindowIcon (win32u.@)
4592 HICON WINAPI
NtUserInternalGetWindowIcon( HWND hwnd
, UINT type
)
4594 WND
*win
= get_win_ptr( hwnd
);
4597 TRACE( "hwnd %p, type %#x\n", hwnd
, type
);
4601 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
4604 if (win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
)
4606 if (is_window( hwnd
)) FIXME( "not supported on other process window %p\n", hwnd
);
4614 if (!ret
) ret
= (HICON
)get_class_long_ptr( hwnd
, GCLP_HICON
, FALSE
);
4619 ret
= win
->hIconSmall
? win
->hIconSmall
: win
->hIconSmall2
;
4620 if (!ret
) ret
= (HICON
)get_class_long_ptr( hwnd
, GCLP_HICONSM
, FALSE
);
4621 if (!ret
) ret
= (HICON
)get_class_long_ptr( hwnd
, GCLP_HICON
, FALSE
);
4625 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4626 release_win_ptr( win
);
4629 release_win_ptr( win
);
4631 if (!ret
) ret
= LoadImageW( 0, (const WCHAR
*)IDI_APPLICATION
, IMAGE_ICON
,
4632 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
4634 return CopyImage( ret
, IMAGE_ICON
, 0, 0, 0 );
4637 /***********************************************************************
4638 * send_destroy_message
4640 static void send_destroy_message( HWND hwnd
)
4644 info
.cbSize
= sizeof(info
);
4645 if (NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
))
4647 if (hwnd
== info
.hwndCaret
) destroy_caret();
4648 if (hwnd
== info
.hwndActive
) activate_other_window( hwnd
);
4651 if (hwnd
== NtUserGetClipboardOwner()) release_clipboard_owner( hwnd
);
4653 send_message( hwnd
, WM_DESTROY
, 0, 0);
4656 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
4657 * make sure that the window still exists when we come back.
4659 if (is_window(hwnd
))
4664 if (!(children
= list_window_children( 0, hwnd
, NULL
, 0 ))) return;
4666 for (i
= 0; children
[i
]; i
++)
4668 if (is_window( children
[i
] )) send_destroy_message( children
[i
] );
4673 WARN( "\tdestroyed itself while in WM_DESTROY!\n" );
4676 /***********************************************************************
4677 * free_window_handle
4679 * Free a window handle.
4681 static void free_window_handle( HWND hwnd
)
4687 if ((win
= get_user_handle_ptr( hwnd
, NTUSER_OBJ_WINDOW
)) && win
!= OBJ_OTHER_PROCESS
)
4689 SERVER_START_REQ( destroy_window
)
4691 req
->handle
= wine_server_user_handle( hwnd
);
4692 wine_server_call( req
);
4693 set_user_handle_ptr( hwnd
, NULL
);
4697 free( win
->pScroll
);
4703 /***********************************************************************
4706 LRESULT
destroy_window( HWND hwnd
)
4708 struct window_surface
*surface
;
4709 HMENU menu
= 0, sys_menu
;
4713 TRACE( "%p\n", hwnd
);
4715 unregister_imm_window( hwnd
);
4717 /* free child windows */
4718 if ((children
= list_window_children( 0, hwnd
, NULL
, 0 )))
4721 for (i
= 0; children
[i
]; i
++)
4723 if (is_current_thread_window( children
[i
] ))
4724 destroy_window( children
[i
] );
4726 NtUserMessageCall( children
[i
], WM_WINE_DESTROYWINDOW
, 0, 0,
4727 0, NtUserSendNotifyMessage
, FALSE
);
4732 /* Unlink now so we won't bother with the children later on */
4733 SERVER_START_REQ( set_parent
)
4735 req
->handle
= wine_server_user_handle( hwnd
);
4737 wine_server_call( req
);
4741 send_message( hwnd
, WM_NCDESTROY
, 0, 0 );
4743 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
4745 /* free resources associated with the window */
4747 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
) return 0;
4748 if ((win
->dwStyle
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
)
4749 menu
= (HMENU
)win
->wIDmenu
;
4750 sys_menu
= win
->hSysMenu
;
4751 free_dce( win
->dce
, hwnd
);
4753 NtUserDestroyCursor( win
->hIconSmall2
, 0 );
4754 surface
= win
->surface
;
4755 win
->surface
= NULL
;
4756 release_win_ptr( win
);
4758 NtUserDestroyMenu( menu
);
4759 NtUserDestroyMenu( sys_menu
);
4762 register_window_surface( surface
, NULL
);
4763 window_surface_release( surface
);
4766 user_driver
->pDestroyWindow( hwnd
);
4768 free_window_handle( hwnd
);
4772 /***********************************************************************
4773 * NtUserDestroyWindow (win32u.@)
4775 BOOL WINAPI
NtUserDestroyWindow( HWND hwnd
)
4779 if (!(hwnd
= is_current_thread_window( hwnd
)) || is_desktop_window( hwnd
))
4781 RtlSetLastWin32Error( ERROR_ACCESS_DENIED
);
4785 TRACE( "(%p)\n", hwnd
);
4787 if (call_hooks( WH_CBT
, HCBT_DESTROYWND
, (WPARAM
)hwnd
, 0, 0 )) return FALSE
;
4789 if (is_menu_active() == hwnd
) NtUserEndMenu();
4791 is_child
= (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) != 0;
4795 if (!is_exiting_thread( GetCurrentThreadId() ))
4796 send_parent_notify( hwnd
, WM_DESTROY
);
4798 else if (!get_window_relative( hwnd
, GW_OWNER
))
4800 call_hooks( WH_SHELL
, HSHELL_WINDOWDESTROYED
, (WPARAM
)hwnd
, 0, 0 );
4801 /* FIXME: clean up palette - see "Internals" p.352 */
4804 if (!is_window( hwnd
)) return TRUE
;
4806 /* Hide the window */
4807 if (get_window_long( hwnd
, GWL_STYLE
) & WS_VISIBLE
)
4809 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
4811 NtUserShowWindow( hwnd
, SW_HIDE
);
4813 NtUserSetWindowPos( hwnd
, 0, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
|
4814 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_HIDEWINDOW
);
4817 if (!is_window( hwnd
)) return TRUE
;
4819 /* Recursively destroy child windows */
4824 BOOL got_one
= FALSE
;
4828 if (!(children
= list_window_children( 0, get_desktop_window(), NULL
, 0 ))) break;
4830 for (i
= 0; children
[i
]; i
++)
4832 if (get_window_relative( children
[i
], GW_OWNER
) != hwnd
) continue;
4833 if (is_current_thread_window( children
[i
] ))
4835 NtUserDestroyWindow( children
[i
] );
4839 set_window_owner( children
[i
], 0 );
4842 if (!got_one
) break;
4846 send_destroy_message( hwnd
);
4847 if (!is_window( hwnd
)) return TRUE
;
4849 destroy_window( hwnd
);
4853 /*****************************************************************************
4854 * destroy_thread_windows
4856 * Destroy all window owned by the current thread.
4858 void destroy_thread_windows(void)
4860 WND
*win
, *free_list
= NULL
;
4864 while ((win
= next_process_user_handle_ptr( &handle
, NTUSER_OBJ_WINDOW
)))
4866 if (win
->tid
!= GetCurrentThreadId()) continue;
4867 free_dce( win
->dce
, win
->obj
.handle
);
4868 set_user_handle_ptr( handle
, NULL
);
4869 win
->obj
.handle
= free_list
;
4874 SERVER_START_REQ( destroy_window
)
4876 req
->handle
= 0; /* destroy all thread windows */
4877 wine_server_call( req
);
4883 while ((win
= free_list
))
4885 free_list
= win
->obj
.handle
;
4886 TRACE( "destroying %p\n", win
);
4888 if ((win
->dwStyle
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
&& win
->wIDmenu
)
4889 NtUserDestroyMenu( UlongToHandle(win
->wIDmenu
) );
4890 if (win
->hSysMenu
) NtUserDestroyMenu( win
->hSysMenu
);
4893 register_window_surface( win
->surface
, NULL
);
4894 window_surface_release( win
->surface
);
4896 free( win
->pScroll
);
4902 /***********************************************************************
4903 * create_window_handle
4905 * Create a window handle with the server.
4907 static WND
*create_window_handle( HWND parent
, HWND owner
, UNICODE_STRING
*name
,
4908 HINSTANCE instance
, BOOL ansi
,
4909 DWORD style
, DWORD ex_style
)
4911 DPI_AWARENESS awareness
= get_thread_dpi_awareness();
4912 HWND handle
= 0, full_parent
= 0, full_owner
= 0;
4913 struct tagCLASS
*class = NULL
;
4914 int extra_bytes
= 0;
4918 SERVER_START_REQ( create_window
)
4920 req
->parent
= wine_server_user_handle( parent
);
4921 req
->owner
= wine_server_user_handle( owner
);
4922 req
->instance
= wine_server_client_ptr( instance
);
4923 req
->dpi
= get_system_dpi();
4924 req
->awareness
= awareness
;
4926 req
->ex_style
= ex_style
;
4927 if (!(req
->atom
= get_int_atom_value( name
)) && name
->Length
)
4928 wine_server_add_data( req
, name
->Buffer
, name
->Length
);
4929 if (!wine_server_call_err( req
))
4931 handle
= wine_server_ptr_handle( reply
->handle
);
4932 full_parent
= wine_server_ptr_handle( reply
->parent
);
4933 full_owner
= wine_server_ptr_handle( reply
->owner
);
4934 extra_bytes
= reply
->extra
;
4936 awareness
= reply
->awareness
;
4937 class = wine_server_get_ptr( reply
->class_ptr
);
4944 WARN( "error %d creating window\n", (int)RtlGetLastWin32Error() );
4948 if (!(win
= calloc( 1, FIELD_OFFSET(WND
, wExtra
) + extra_bytes
)))
4950 SERVER_START_REQ( destroy_window
)
4952 req
->handle
= wine_server_user_handle( handle
);
4953 wine_server_call( req
);
4956 RtlSetLastWin32Error( ERROR_NOT_ENOUGH_MEMORY
);
4960 if (!parent
) /* if parent is 0 we don't have a desktop window yet */
4962 struct ntuser_thread_info
*thread_info
= NtUserGetThreadInfo();
4964 if (name
->Buffer
== (const WCHAR
*)DESKTOP_CLASS_ATOM
)
4966 if (!thread_info
->top_window
) thread_info
->top_window
= HandleToUlong( full_parent
? full_parent
: handle
);
4967 else assert( full_parent
== UlongToHandle( thread_info
->top_window
));
4968 if (!thread_info
->top_window
) ERR_(win
)( "failed to create desktop window\n" );
4969 else user_driver
->pSetDesktopWindow( UlongToHandle( thread_info
->top_window
));
4970 register_builtin_classes();
4972 else /* HWND_MESSAGE parent */
4974 if (!thread_info
->msg_window
&& !full_parent
)
4975 thread_info
->msg_window
= HandleToUlong( handle
);
4981 win
->obj
.handle
= handle
;
4982 win
->obj
.type
= NTUSER_OBJ_WINDOW
;
4983 win
->parent
= full_parent
;
4984 win
->owner
= full_owner
;
4986 win
->winproc
= get_class_winproc( class );
4987 win
->cbWndExtra
= extra_bytes
;
4989 win
->dpi_awareness
= awareness
;
4990 set_user_handle_ptr( handle
, &win
->obj
);
4991 if (is_winproc_unicode( win
->winproc
, !ansi
)) win
->flags
|= WIN_ISUNICODE
;
4995 static BOOL
is_default_coord( int x
)
4997 return x
== CW_USEDEFAULT
|| x
== 0x8000;
5000 /***********************************************************************
5001 * fix_cs_coordinates
5003 * Fix the coordinates and return default show mode in sw.
5005 static void fix_cs_coordinates( CREATESTRUCTW
*cs
, INT
*sw
)
5007 if (cs
->style
& (WS_CHILD
| WS_POPUP
))
5009 if (is_default_coord(cs
->x
)) cs
->x
= cs
->y
= 0;
5010 if (is_default_coord(cs
->cx
)) cs
->cx
= cs
->cy
= 0;
5012 else /* overlapped window */
5014 RTL_USER_PROCESS_PARAMETERS
*params
= NtCurrentTeb()->Peb
->ProcessParameters
;
5016 MONITORINFO mon_info
;
5018 if (!is_default_coord( cs
->x
) && !is_default_coord( cs
->cx
) && !is_default_coord( cs
->cy
))
5021 monitor
= monitor_from_window( cs
->hwndParent
, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
5022 mon_info
.cbSize
= sizeof(mon_info
);
5023 get_monitor_info( monitor
, &mon_info
);
5025 if (is_default_coord( cs
->x
))
5027 if (!is_default_coord( cs
->y
)) *sw
= cs
->y
;
5028 cs
->x
= (params
->dwFlags
& STARTF_USEPOSITION
) ? params
->dwX
: mon_info
.rcWork
.left
;
5029 cs
->y
= (params
->dwFlags
& STARTF_USEPOSITION
) ? params
->dwY
: mon_info
.rcWork
.top
;
5032 if (is_default_coord( cs
->cx
))
5034 if (params
->dwFlags
& STARTF_USESIZE
)
5036 cs
->cx
= params
->dwXSize
;
5037 cs
->cy
= params
->dwYSize
;
5041 cs
->cx
= (mon_info
.rcWork
.right
- mon_info
.rcWork
.left
) * 3 / 4 - cs
->x
;
5042 cs
->cy
= (mon_info
.rcWork
.bottom
- mon_info
.rcWork
.top
) * 3 / 4 - cs
->y
;
5045 /* neither x nor cx are default. Check the y values.
5046 * In the trace we see Outlook and Outlook Express using
5047 * cy set to CW_USEDEFAULT when opening the address book.
5049 else if (is_default_coord( cs
->cy
))
5051 FIXME( "Strange use of CW_USEDEFAULT in cy\n" );
5052 cs
->cy
= (mon_info
.rcWork
.bottom
- mon_info
.rcWork
.top
) * 3 / 4 - cs
->y
;
5057 /***********************************************************************
5058 * map_dpi_create_struct
5060 static void map_dpi_create_struct( CREATESTRUCTW
*cs
, UINT dpi_from
, UINT dpi_to
)
5062 if (!dpi_from
&& !dpi_to
) return;
5063 if (!dpi_from
|| !dpi_to
)
5065 POINT pt
= { cs
->x
, cs
->y
};
5066 UINT mon_dpi
= get_monitor_dpi( monitor_from_point( pt
, MONITOR_DEFAULTTONEAREST
, dpi_from
));
5067 if (!dpi_from
) dpi_from
= mon_dpi
;
5068 else dpi_to
= mon_dpi
;
5070 if (dpi_from
== dpi_to
) return;
5071 cs
->x
= muldiv( cs
->x
, dpi_to
, dpi_from
);
5072 cs
->y
= muldiv( cs
->y
, dpi_to
, dpi_from
);
5073 cs
->cx
= muldiv( cs
->cx
, dpi_to
, dpi_from
);
5074 cs
->cy
= muldiv( cs
->cy
, dpi_to
, dpi_from
);
5077 /***********************************************************************
5078 * NtUserCreateWindowEx (win32u.@)
5080 HWND WINAPI
NtUserCreateWindowEx( DWORD ex_style
, UNICODE_STRING
*class_name
,
5081 UNICODE_STRING
*version
, UNICODE_STRING
*window_name
,
5082 DWORD style
, INT x
, INT y
, INT cx
, INT cy
,
5083 HWND parent
, HMENU menu
, HINSTANCE instance
, void *params
,
5084 DWORD flags
, HINSTANCE client_instance
, DWORD unk
, BOOL ansi
)
5086 UINT win_dpi
, thread_dpi
= get_thread_dpi();
5087 DPI_AWARENESS_CONTEXT context
;
5088 CBT_CREATEWNDW cbtc
;
5089 HWND hwnd
, owner
= 0;
5095 static const WCHAR messageW
[] = {'M','e','s','s','a','g','e'};
5097 cs
.lpCreateParams
= params
;
5098 cs
.hInstance
= client_instance
? client_instance
: instance
;
5100 cs
.hwndParent
= parent
;
5102 cs
.dwExStyle
= ex_style
;
5103 cs
.lpszName
= window_name
? window_name
->Buffer
: NULL
;
5104 cs
.lpszClass
= class_name
? class_name
->Buffer
: NULL
;
5110 /* Find the parent window */
5111 if (parent
== HWND_MESSAGE
)
5113 cs
.hwndParent
= parent
= get_hwnd_message_parent();
5117 if ((cs
.style
& (WS_CHILD
|WS_POPUP
)) != WS_CHILD
)
5120 parent
= get_desktop_window();
5124 DWORD parent_style
= get_window_long( parent
, GWL_EXSTYLE
);
5125 if ((parent_style
& WS_EX_LAYOUTRTL
) && !(parent_style
& WS_EX_NOINHERITLAYOUT
))
5126 cs
.dwExStyle
|= WS_EX_LAYOUTRTL
;
5131 if ((cs
.style
& (WS_CHILD
|WS_POPUP
)) == WS_CHILD
)
5133 WARN( "No parent for child window\n" );
5134 RtlSetLastWin32Error( ERROR_TLW_WITH_WSCHILD
);
5135 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
5138 /* are we creating the desktop or HWND_MESSAGE parent itself? */
5139 if (class_name
->Buffer
!= (LPCWSTR
)DESKTOP_CLASS_ATOM
&&
5140 (class_name
->Length
!= sizeof(messageW
) ||
5141 wcsnicmp( class_name
->Buffer
, messageW
, ARRAYSIZE(messageW
) )))
5143 if (get_process_layout() & LAYOUT_RTL
) cs
.dwExStyle
|= WS_EX_LAYOUTRTL
;
5144 parent
= get_desktop_window();
5148 fix_cs_coordinates( &cs
, &sw
);
5149 cs
.dwExStyle
= fix_exstyle( cs
.style
, cs
.dwExStyle
);
5151 /* Create the window structure */
5153 style
= cs
.style
& ~WS_VISIBLE
;
5154 ex_style
= cs
.dwExStyle
& ~WS_EX_LAYERED
;
5155 if (!(win
= create_window_handle( parent
, owner
, class_name
, instance
, ansi
, style
, ex_style
)))
5157 hwnd
= win
->obj
.handle
;
5159 /* Fill the window structure */
5161 win
->tid
= GetCurrentThreadId();
5162 win
->hInstance
= cs
.hInstance
;
5164 win
->dwStyle
= style
;
5165 win
->dwExStyle
= ex_style
;
5167 win
->helpContext
= 0;
5168 win
->pScroll
= NULL
;
5171 win
->hIconSmall
= 0;
5172 win
->hIconSmall2
= 0;
5175 win
->min_pos
.x
= win
->min_pos
.y
= -1;
5176 win
->max_pos
.x
= win
->max_pos
.y
= -1;
5177 SetRect( &win
->normal_rect
, cs
.x
, cs
.y
, cs
.x
+ cs
.cx
, cs
.y
+ cs
.cy
);
5179 if (win
->dwStyle
& WS_SYSMENU
) NtUserSetSystemMenu( hwnd
, 0 );
5181 win
->imc
= get_default_input_context();
5183 /* call the WH_CBT hook */
5185 release_win_ptr( win
);
5186 cbtc
.hwndInsertAfter
= HWND_TOP
;
5188 if (call_hooks( WH_CBT
, HCBT_CREATEWND
, (WPARAM
)hwnd
, (LPARAM
)&cbtc
, sizeof(cbtc
) ))
5190 free_window_handle( hwnd
);
5193 if (!(win
= get_win_ptr( hwnd
))) return 0;
5196 * Correct the window styles.
5198 * It affects only the style loaded into the WND structure.
5201 if ((win
->dwStyle
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
)
5203 win
->dwStyle
|= WS_CLIPSIBLINGS
;
5204 if (!(win
->dwStyle
& WS_POPUP
)) win
->dwStyle
|= WS_CAPTION
;
5207 win
->dwExStyle
= cs
.dwExStyle
;
5208 /* WS_EX_WINDOWEDGE depends on some other styles */
5209 if ((win
->dwStyle
& (WS_DLGFRAME
| WS_THICKFRAME
)) &&
5210 !(win
->dwStyle
& (WS_CHILD
| WS_POPUP
)))
5211 win
->dwExStyle
|= WS_EX_WINDOWEDGE
;
5213 if (!(win
->dwStyle
& (WS_CHILD
| WS_POPUP
))) win
->flags
|= WIN_NEED_SIZE
;
5215 SERVER_START_REQ( set_window_info
)
5217 req
->handle
= wine_server_user_handle( hwnd
);
5218 req
->flags
= SET_WIN_STYLE
| SET_WIN_EXSTYLE
| SET_WIN_INSTANCE
| SET_WIN_UNICODE
;
5219 req
->style
= win
->dwStyle
;
5220 req
->ex_style
= win
->dwExStyle
;
5221 req
->instance
= wine_server_client_ptr( win
->hInstance
);
5222 req
->is_unicode
= (win
->flags
& WIN_ISUNICODE
) != 0;
5223 req
->extra_offset
= -1;
5224 wine_server_call( req
);
5228 /* Set the window menu */
5230 if ((win
->dwStyle
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
)
5232 if (cs
.hMenu
&& !set_window_menu( hwnd
, cs
.hMenu
))
5234 release_win_ptr( win
);
5235 free_window_handle( hwnd
);
5239 else NtUserSetWindowLongPtr( hwnd
, GWLP_ID
, (ULONG_PTR
)cs
.hMenu
, FALSE
);
5242 release_win_ptr( win
);
5244 if (parent
) map_dpi_create_struct( &cs
, thread_dpi
, win_dpi
);
5246 context
= SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( hwnd
));
5248 /* send the WM_GETMINMAXINFO message and fix the size if needed */
5252 if ((cs
.style
& WS_THICKFRAME
) || !(cs
.style
& (WS_POPUP
| WS_CHILD
)))
5254 MINMAXINFO info
= get_min_max_info( hwnd
);
5255 cx
= max( min( cx
, info
.ptMaxTrackSize
.x
), info
.ptMinTrackSize
.x
);
5256 cy
= max( min( cy
, info
.ptMaxTrackSize
.y
), info
.ptMinTrackSize
.y
);
5261 SetRect( &rect
, cs
.x
, cs
.y
, cs
.x
+ cx
, cs
.y
+ cy
);
5262 /* check for wraparound */
5263 if (cs
.x
> 0x7fffffff - cx
) rect
.right
= 0x7fffffff;
5264 if (cs
.y
> 0x7fffffff - cy
) rect
.bottom
= 0x7fffffff;
5265 if (!apply_window_pos( hwnd
, 0, SWP_NOZORDER
| SWP_NOACTIVATE
, &rect
, &rect
, NULL
)) goto failed
;
5267 /* send WM_NCCREATE */
5269 TRACE( "hwnd %p cs %d,%d %dx%d %s\n", hwnd
, cs
.x
, cs
.y
, cs
.cx
, cs
.cy
, wine_dbgstr_rect(&rect
) );
5270 if (!send_message_timeout( hwnd
, WM_NCCREATE
, 0, (LPARAM
)&cs
, SMTO_NORMAL
, 0, ansi
))
5272 WARN( "%p: aborted by WM_NCCREATE\n", hwnd
);
5276 /* create default IME window */
5278 if (!is_desktop_window( hwnd
) && parent
!= get_hwnd_message_parent() &&
5279 register_imm_window( hwnd
))
5281 TRACE( "register IME window for %p\n", hwnd
);
5282 win_set_flags( hwnd
, WIN_HAS_IME_WIN
, 0 );
5285 /* send WM_NCCALCSIZE */
5287 if (get_window_rects( hwnd
, COORDS_PARENT
, &rect
, NULL
, win_dpi
))
5289 /* yes, even if the CBT hook was called with HWND_TOP */
5290 HWND insert_after
= (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) ? HWND_BOTTOM
: HWND_TOP
;
5291 RECT client_rect
= rect
;
5293 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
5294 map_window_points( parent
, 0, (POINT
*)&client_rect
, 2, win_dpi
);
5295 send_message( hwnd
, WM_NCCALCSIZE
, FALSE
, (LPARAM
)&client_rect
);
5296 map_window_points( 0, parent
, (POINT
*)&client_rect
, 2, win_dpi
);
5297 apply_window_pos( hwnd
, insert_after
, SWP_NOACTIVATE
, &rect
, &client_rect
, NULL
);
5301 /* send WM_CREATE */
5302 if (send_message_timeout( hwnd
, WM_CREATE
, 0, (LPARAM
)&cs
, SMTO_NORMAL
, 0, ansi
) == -1)
5305 /* call the driver */
5307 if (!user_driver
->pCreateWindow( hwnd
)) goto failed
;
5309 NtUserNotifyWinEvent( EVENT_OBJECT_CREATE
, hwnd
, OBJID_WINDOW
, 0 );
5311 /* send the size messages */
5313 if (!(win_get_flags( hwnd
) & WIN_NEED_SIZE
))
5315 get_window_rects( hwnd
, COORDS_PARENT
, NULL
, &rect
, win_dpi
);
5316 send_message( hwnd
, WM_SIZE
, SIZE_RESTORED
,
5317 MAKELONG(rect
.right
-rect
.left
, rect
.bottom
-rect
.top
));
5318 send_message( hwnd
, WM_MOVE
, 0, MAKELONG( rect
.left
, rect
.top
) );
5321 /* Show the window, maximizing or minimizing if needed */
5323 style
= set_window_style( hwnd
, 0, WS_MAXIMIZE
| WS_MINIMIZE
);
5324 if (style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
5327 UINT sw_flags
= (style
& WS_MINIMIZE
) ? SW_MINIMIZE
: SW_MAXIMIZE
;
5329 sw_flags
= window_min_maximize( hwnd
, sw_flags
, &new_pos
);
5330 sw_flags
|= SWP_FRAMECHANGED
; /* Frame always gets changed */
5331 if (!(style
& WS_VISIBLE
) || (style
& WS_CHILD
) || get_active_window())
5332 sw_flags
|= SWP_NOACTIVATE
;
5333 NtUserSetWindowPos( hwnd
, 0, new_pos
.left
, new_pos
.top
, new_pos
.right
- new_pos
.left
,
5334 new_pos
.bottom
- new_pos
.top
, sw_flags
);
5337 /* Notify the parent window only */
5339 send_parent_notify( hwnd
, WM_CREATE
);
5340 if (!is_window( hwnd
))
5342 SetThreadDpiAwarenessContext( context
);
5346 if (parent
== get_desktop_window())
5347 NtUserPostMessage( parent
, WM_PARENTNOTIFY
, WM_CREATE
, (LPARAM
)hwnd
);
5349 if (cs
.style
& WS_VISIBLE
)
5351 if (cs
.style
& WS_MAXIMIZE
)
5353 else if (cs
.style
& WS_MINIMIZE
)
5354 sw
= SW_SHOWMINIMIZED
;
5356 NtUserShowWindow( hwnd
, sw
);
5357 if (cs
.dwExStyle
& WS_EX_MDICHILD
)
5359 send_message( cs
.hwndParent
, WM_MDIREFRESHMENU
, 0, 0 );
5360 /* ShowWindow won't activate child windows */
5361 NtUserSetWindowPos( hwnd
, HWND_TOP
, 0, 0, 0, 0, SWP_SHOWWINDOW
| SWP_NOMOVE
| SWP_NOSIZE
);
5365 /* Call WH_SHELL hook */
5367 if (!(get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) && !get_window_relative( hwnd
, GW_OWNER
))
5368 call_hooks( WH_SHELL
, HSHELL_WINDOWCREATED
, (WPARAM
)hwnd
, 0, 0 );
5370 TRACE( "created window %p\n", hwnd
);
5371 SetThreadDpiAwarenessContext( context
);
5375 destroy_window( hwnd
);
5376 SetThreadDpiAwarenessContext( context
);
5380 static void *get_dialog_info( HWND hwnd
)
5385 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
)
5387 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
5392 release_win_ptr( win
);
5396 static BOOL
set_dialog_info( HWND hwnd
, void *info
)
5400 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
5401 win
->dlgInfo
= info
;
5402 release_win_ptr( win
);
5406 /*****************************************************************************
5407 * NtUserCallHwnd (win32u.@)
5409 ULONG_PTR WINAPI
NtUserCallHwnd( HWND hwnd
, DWORD code
)
5413 case NtUserCallHwnd_ActivateOtherWindow
:
5414 activate_other_window( hwnd
);
5417 case NtUserCallHwnd_ArrangeIconicWindows
:
5418 return arrange_iconic_windows( hwnd
);
5420 case NtUserCallHwnd_DrawMenuBar
:
5421 return draw_menu_bar( hwnd
);
5423 case NtUserCallHwnd_GetDefaultImeWindow
:
5424 return HandleToUlong( get_default_ime_window( hwnd
));
5426 case NtUserCallHwnd_GetDpiForWindow
:
5427 return get_dpi_for_window( hwnd
);
5429 case NtUserCallHwnd_GetParent
:
5430 return HandleToUlong( get_parent( hwnd
));
5432 case NtUserCallHwnd_GetDialogInfo
:
5433 return (ULONG_PTR
)get_dialog_info( hwnd
);
5435 case NtUserCallHwnd_GetMDIClientInfo
:
5436 if (!(win_get_flags( hwnd
) & WIN_ISMDICLIENT
)) return 0;
5437 return get_window_long_ptr( hwnd
, sizeof(void *), FALSE
);
5439 case NtUserCallHwnd_GetWindowContextHelpId
:
5440 return get_window_context_help_id( hwnd
);
5442 case NtUserCallHwnd_GetWindowDpiAwarenessContext
:
5443 return (ULONG_PTR
)get_window_dpi_awareness_context( hwnd
);
5445 case NtUserCallHwnd_GetWindowInputContext
:
5446 return HandleToUlong( get_window_input_context( hwnd
));
5448 case NtUserCallHwnd_GetWindowSysSubMenu
:
5449 return HandleToUlong( get_window_sys_sub_menu( hwnd
));
5451 case NtUserCallHwnd_GetWindowTextLength
:
5452 return get_server_window_text( hwnd
, NULL
, 0 );
5454 case NtUserCallHwnd_IsWindow
:
5455 return is_window( hwnd
);
5457 case NtUserCallHwnd_IsWindowEnabled
:
5458 return is_window_enabled( hwnd
);
5460 case NtUserCallHwnd_IsWindowUnicode
:
5461 return is_window_unicode( hwnd
);
5463 case NtUserCallHwnd_IsWindowVisible
:
5464 return is_window_visible( hwnd
);
5466 case NtUserCallHwnd_SetForegroundWindow
:
5467 return set_foreground_window( hwnd
, FALSE
);
5469 case NtUserCallHwnd_SetProgmanWindow
:
5470 return HandleToUlong( set_progman_window( hwnd
));
5472 case NtUserCallHwnd_SetTaskmanWindow
:
5473 return HandleToUlong( set_taskman_window( hwnd
));
5475 /* temporary exports */
5476 case NtUserGetFullWindowHandle
:
5477 return HandleToUlong( get_full_window_handle( hwnd
));
5479 case NtUserIsCurrentProcessWindow
:
5480 return HandleToUlong( is_current_process_window( hwnd
));
5482 case NtUserIsCurrentThreadWindow
:
5483 return HandleToUlong( is_current_thread_window( hwnd
));
5486 FIXME( "invalid code %u\n", (int)code
);
5491 /*****************************************************************************
5492 * NtUserCallHwndParam (win32u.@)
5494 ULONG_PTR WINAPI
NtUserCallHwndParam( HWND hwnd
, DWORD_PTR param
, DWORD code
)
5498 case NtUserCallHwndParam_ClientToScreen
:
5499 return client_to_screen( hwnd
, (POINT
*)param
);
5501 case NtUserCallHwndParam_EnableWindow
:
5502 return enable_window( hwnd
, param
);
5504 case NtUserCallHwndParam_GetChildRect
:
5505 return get_window_rects( hwnd
, COORDS_PARENT
, (RECT
*)param
, NULL
, get_thread_dpi() );
5507 case NtUserCallHwndParam_GetClassLongA
:
5508 return get_class_long( hwnd
, param
, TRUE
);
5510 case NtUserCallHwndParam_GetClassLongW
:
5511 return get_class_long( hwnd
, param
, FALSE
);
5513 case NtUserCallHwndParam_GetClassLongPtrA
:
5514 return get_class_long_ptr( hwnd
, param
, TRUE
);
5516 case NtUserCallHwndParam_GetClassLongPtrW
:
5517 return get_class_long_ptr( hwnd
, param
, FALSE
);
5519 case NtUserCallHwndParam_GetClassWord
:
5520 return get_class_word( hwnd
, param
);
5522 case NtUserCallHwndParam_GetClientRect
:
5523 return get_client_rect( hwnd
, (RECT
*)param
);
5525 case NtUserCallHwndParam_GetScrollInfo
:
5527 struct get_scroll_info_params
*params
= (void *)param
;
5528 return get_scroll_info( hwnd
, params
->bar
, params
->info
);
5531 case NtUserCallHwndParam_GetWindowInfo
:
5532 return get_window_info( hwnd
, (WINDOWINFO
*)param
);
5534 case NtUserCallHwndParam_GetWindowLongA
:
5535 return get_window_long_size( hwnd
, param
, sizeof(LONG
), TRUE
);
5537 case NtUserCallHwndParam_GetWindowLongW
:
5538 return get_window_long( hwnd
, param
);
5540 case NtUserCallHwndParam_GetWindowLongPtrA
:
5541 return get_window_long_ptr( hwnd
, param
, TRUE
);
5543 case NtUserCallHwndParam_GetWindowLongPtrW
:
5544 return get_window_long_ptr( hwnd
, param
, FALSE
);
5546 case NtUserCallHwndParam_GetWindowRect
:
5547 return get_window_rect( hwnd
, (RECT
*)param
, get_thread_dpi() );
5549 case NtUserCallHwndParam_GetWindowRelative
:
5550 return HandleToUlong( get_window_relative( hwnd
, param
));
5552 case NtUserCallHwndParam_GetWindowThread
:
5553 return get_window_thread( hwnd
, (DWORD
*)param
);
5555 case NtUserCallHwndParam_GetWindowWord
:
5556 return get_window_word( hwnd
, param
);
5558 case NtUserCallHwndParam_IsChild
:
5559 return is_child( hwnd
, UlongToHandle(param
) );
5561 case NtUserCallHwndParam_KillSystemTimer
:
5562 return kill_system_timer( hwnd
, param
);
5564 case NtUserCallHwndParam_MapWindowPoints
:
5566 struct map_window_points_params
*params
= (void *)param
;
5567 return map_window_points( hwnd
, params
->hwnd_to
, params
->points
, params
->count
,
5571 case NtUserCallHwndParam_MirrorRgn
:
5572 return mirror_window_region( hwnd
, UlongToHandle(param
) );
5574 case NtUserCallHwndParam_MonitorFromWindow
:
5575 return HandleToUlong( monitor_from_window( hwnd
, param
, get_thread_dpi() ));
5577 case NtUserCallHwndParam_ScreenToClient
:
5578 return screen_to_client( hwnd
, (POINT
*)param
);
5580 case NtUserCallHwndParam_SetDialogInfo
:
5581 return set_dialog_info( hwnd
, (void *)param
);
5583 case NtUserCallHwndParam_SetMDIClientInfo
:
5584 NtUserSetWindowLongPtr( hwnd
, sizeof(void *), param
, FALSE
);
5585 return win_set_flags( hwnd
, WIN_ISMDICLIENT
, 0 );
5587 case NtUserCallHwndParam_SetWindowContextHelpId
:
5588 return set_window_context_help_id( hwnd
, param
);
5590 case NtUserCallHwndParam_ShowOwnedPopups
:
5591 return show_owned_popups( hwnd
, param
);
5593 /* temporary exports */
5594 case NtUserSetWindowStyle
:
5596 STYLESTRUCT
*style
= (void *)param
;
5597 return set_window_style( hwnd
, style
->styleNew
, style
->styleOld
);
5601 FIXME( "invalid code %u\n", (int)code
);
5606 /*******************************************************************
5607 * NtUserDragDetect (win32u.@)
5609 BOOL WINAPI
NtUserDragDetect( HWND hwnd
, int x
, int y
)
5615 TRACE( "%p (%d,%d)\n", hwnd
, x
, y
);
5617 if (!(NtUserGetKeyState( VK_LBUTTON
) & 0x8000)) return FALSE
;
5619 width
= get_system_metrics( SM_CXDRAG
);
5620 height
= get_system_metrics( SM_CYDRAG
);
5621 SetRect( &rect
, x
- width
, y
- height
, x
+ width
, y
+ height
);
5623 NtUserSetCapture( hwnd
);
5627 while (NtUserPeekMessage( &msg
, 0, WM_MOUSEFIRST
, WM_MOUSELAST
, PM_REMOVE
))
5629 if (msg
.message
== WM_LBUTTONUP
)
5634 if (msg
.message
== WM_MOUSEMOVE
)
5637 tmp
.x
= (short)LOWORD( msg
.lParam
);
5638 tmp
.y
= (short)HIWORD( msg
.lParam
);
5639 if (!PtInRect( &rect
, tmp
))
5646 NtUserMsgWaitForMultipleObjectsEx( 0, NULL
, INFINITE
, QS_ALLINPUT
, 0 );
5651 /*******************************************************************
5652 * NtUserDragObject (win32u.@)
5654 DWORD WINAPI
NtUserDragObject( HWND parent
, HWND hwnd
, UINT fmt
, ULONG_PTR data
, HCURSOR cursor
)
5656 FIXME( "%p, %p, %u, %#lx, %p stub!\n", parent
, hwnd
, fmt
, data
, cursor
);
5662 HWND
get_shell_window(void)
5666 SERVER_START_REQ(set_global_windows
)
5669 if (!wine_server_call_err(req
))
5670 hwnd
= wine_server_ptr_handle( reply
->old_shell_window
);
5677 /***********************************************************************
5678 * NtUserSetShellWindowEx (win32u.@)
5680 BOOL WINAPI
NtUserSetShellWindowEx( HWND shell
, HWND list_view
)
5684 /* shell = Progman[Program Manager]
5685 * |-> SHELLDLL_DefView
5686 * list_view = | |-> SysListView32
5687 * | | |-> tooltips_class32
5694 if (get_shell_window())
5697 if (get_window_long( shell
, GWL_EXSTYLE
) & WS_EX_TOPMOST
)
5700 if (list_view
!= shell
&& (get_window_long( list_view
, GWL_EXSTYLE
) & WS_EX_TOPMOST
))
5703 if (list_view
&& list_view
!= shell
)
5704 NtUserSetWindowPos( list_view
, HWND_BOTTOM
, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
5706 NtUserSetWindowPos( shell
, HWND_BOTTOM
, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
5708 SERVER_START_REQ(set_global_windows
)
5710 req
->flags
= SET_GLOBAL_SHELL_WINDOWS
;
5711 req
->shell_window
= wine_server_user_handle( shell
);
5712 req
->shell_listview
= wine_server_user_handle( list_view
);
5713 ret
= !wine_server_call_err(req
);
5719 HWND
get_progman_window(void)
5723 SERVER_START_REQ(set_global_windows
)
5726 if (!wine_server_call_err(req
))
5727 ret
= wine_server_ptr_handle( reply
->old_progman_window
);
5733 HWND
set_progman_window( HWND hwnd
)
5735 SERVER_START_REQ(set_global_windows
)
5737 req
->flags
= SET_GLOBAL_PROGMAN_WINDOW
;
5738 req
->progman_window
= wine_server_user_handle( hwnd
);
5739 if (wine_server_call_err( req
)) hwnd
= 0;
5745 HWND
get_taskman_window(void)
5749 SERVER_START_REQ(set_global_windows
)
5752 if (!wine_server_call_err(req
))
5753 ret
= wine_server_ptr_handle( reply
->old_taskman_window
);
5759 HWND
set_taskman_window( HWND hwnd
)
5761 /* hwnd = MSTaskSwWClass
5762 * |-> SysTabControl32
5764 SERVER_START_REQ(set_global_windows
)
5766 req
->flags
= SET_GLOBAL_TASKMAN_WINDOW
;
5767 req
->taskman_window
= wine_server_user_handle( hwnd
);
5768 if (wine_server_call_err( req
)) hwnd
= 0;