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
;
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_context
= reply
->dpi_context
;
458 release_win_ptr( win
);
461 get_window_rects( hwnd
, COORDS_SCREEN
, &new_screen_rect
, NULL
, 0 );
462 context
= set_thread_dpi_awareness_context( get_window_dpi_awareness_context( hwnd
));
464 user_driver
->pSetParent( full_handle
, parent
, old_parent
);
467 winpos
.hwndInsertAfter
= HWND_TOP
;
468 winpos
.x
= window_rect
.left
;
469 winpos
.y
= window_rect
.top
;
472 winpos
.flags
= SWP_NOSIZE
;
474 set_window_pos( &winpos
, new_screen_rect
.left
- old_screen_rect
.left
,
475 new_screen_rect
.top
- old_screen_rect
.top
);
477 if (was_visible
) NtUserShowWindow( hwnd
, SW_SHOW
);
479 set_thread_dpi_awareness_context( context
);
484 HWND
get_window_relative( HWND hwnd
, UINT rel
)
488 if (rel
== GW_OWNER
) /* this one may be available locally */
490 WND
*win
= get_win_ptr( hwnd
);
493 RtlSetLastWin32Error( ERROR_INVALID_HANDLE
);
496 if (win
== WND_DESKTOP
) return 0;
497 if (win
!= WND_OTHER_PROCESS
)
500 release_win_ptr( win
);
503 /* else fall through to server call */
506 SERVER_START_REQ( get_window_tree
)
508 req
->handle
= wine_server_user_handle( hwnd
);
509 if (!wine_server_call_err( req
))
514 retval
= wine_server_ptr_handle( reply
->first_sibling
);
517 retval
= wine_server_ptr_handle( reply
->last_sibling
);
520 retval
= wine_server_ptr_handle( reply
->next_sibling
);
523 retval
= wine_server_ptr_handle( reply
->prev_sibling
);
526 retval
= wine_server_ptr_handle( reply
->owner
);
529 retval
= wine_server_ptr_handle( reply
->first_child
);
538 /*******************************************************************
539 * list_window_parents
541 * Build an array of all parents of a given window, starting with
542 * the immediate parent. The array must be freed with free().
544 static HWND
*list_window_parents( HWND hwnd
)
548 int i
, pos
= 0, size
= 16, count
;
550 if (!(list
= malloc( size
* sizeof(HWND
) ))) return NULL
;
555 if (!(win
= get_win_ptr( current
))) goto empty
;
556 if (win
== WND_OTHER_PROCESS
) break; /* need to do it the hard way */
557 if (win
== WND_DESKTOP
)
559 if (!pos
) goto empty
;
563 list
[pos
] = current
= win
->parent
;
564 release_win_ptr( win
);
565 if (!current
) return list
;
566 if (++pos
== size
- 1)
568 /* need to grow the list */
569 HWND
*new_list
= realloc( list
, (size
+ 16) * sizeof(HWND
) );
570 if (!new_list
) goto empty
;
576 /* at least one parent belongs to another process, have to query the server */
581 SERVER_START_REQ( get_window_parents
)
583 req
->handle
= wine_server_user_handle( hwnd
);
584 wine_server_set_reply( req
, list
, (size
-1) * sizeof(user_handle_t
) );
585 if (!wine_server_call( req
)) count
= reply
->count
;
588 if (!count
) goto empty
;
591 /* start from the end since HWND is potentially larger than user_handle_t */
592 for (i
= count
- 1; i
>= 0; i
--)
593 list
[i
] = wine_server_ptr_handle( ((user_handle_t
*)list
)[i
] );
599 if (!(list
= malloc( size
* sizeof(HWND
) ))) return NULL
;
607 /*******************************************************************
608 * list_window_children
610 * Build an array of the children of a given window. The array must be
611 * freed with HeapFree. Returns NULL when no windows are found.
613 HWND
*list_window_children( HDESK desktop
, HWND hwnd
, UNICODE_STRING
*class, DWORD tid
)
617 ATOM atom
= class ? get_int_atom_value( class ) : 0;
619 /* empty class is not the same as NULL class */
620 if (!atom
&& class && !class->Length
) return NULL
;
626 if (!(list
= malloc( size
* sizeof(HWND
) ))) break;
628 SERVER_START_REQ( get_window_children
)
630 req
->desktop
= wine_server_obj_handle( desktop
);
631 req
->parent
= wine_server_user_handle( hwnd
);
634 if (!atom
&& class) wine_server_add_data( req
, class->Buffer
, class->Length
);
635 wine_server_set_reply( req
, list
, (size
-1) * sizeof(user_handle_t
) );
636 if (!wine_server_call( req
)) count
= reply
->count
;
639 if (count
&& count
< size
)
641 /* start from the end since HWND is potentially larger than user_handle_t */
642 for (i
= count
- 1; i
>= 0; i
--)
643 list
[i
] = wine_server_ptr_handle( ((user_handle_t
*)list
)[i
] );
649 size
= count
+ 1; /* restart with a large enough buffer */
654 /*****************************************************************
655 * NtUserGetAncestor (win32u.@)
657 HWND WINAPI
NtUserGetAncestor( HWND hwnd
, UINT type
)
665 if (!(win
= get_win_ptr( hwnd
)))
667 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
670 if (win
== WND_DESKTOP
) return 0;
671 if (win
!= WND_OTHER_PROCESS
)
674 release_win_ptr( win
);
676 else /* need to query the server */
678 SERVER_START_REQ( get_window_tree
)
680 req
->handle
= wine_server_user_handle( hwnd
);
681 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->parent
);
688 if (!(list
= list_window_parents( hwnd
))) return 0;
690 if (!list
[0] || !list
[1]) ret
= get_full_window_handle( hwnd
); /* top-level window */
694 while (list
[count
]) count
++;
695 ret
= list
[count
- 2]; /* get the one before the desktop */
701 if (is_desktop_window( hwnd
)) return 0;
702 ret
= get_full_window_handle( hwnd
);
705 HWND parent
= get_parent( ret
);
715 BOOL
is_child( HWND parent
, HWND child
)
721 if (!(get_window_long( child
, GWL_STYLE
) & WS_CHILD
)) return FALSE
;
722 if (!(list
= list_window_parents( child
))) return FALSE
;
723 parent
= get_full_window_handle( parent
);
724 for (i
= 0; list
[i
]; i
++)
726 if (list
[i
] == parent
)
728 ret
= list
[i
] && list
[i
+1];
731 if (!(get_window_long( list
[i
], GWL_STYLE
) & WS_CHILD
)) break;
737 /* see IsWindowVisible */
738 BOOL
is_window_visible( HWND hwnd
)
744 if (!(get_window_long( hwnd
, GWL_STYLE
) & WS_VISIBLE
)) return FALSE
;
745 if (!(list
= list_window_parents( hwnd
))) return TRUE
;
748 for (i
= 0; list
[i
+1]; i
++)
749 if (!(get_window_long( list
[i
], GWL_STYLE
) & WS_VISIBLE
)) break;
750 retval
= !list
[i
+1] && (list
[i
] == get_desktop_window()); /* top message window isn't visible */
756 /***********************************************************************
759 * hwnd is drawable when it is visible, all parents are not
760 * minimized, and it is itself not minimized unless we are
761 * trying to draw its default class icon.
763 BOOL
is_window_drawable( HWND hwnd
, BOOL icon
)
768 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
770 if (!(style
& WS_VISIBLE
)) return FALSE
;
771 if ((style
& WS_MINIMIZE
) && icon
&& get_class_long_ptr( hwnd
, GCLP_HICON
, FALSE
)) return FALSE
;
773 if (!(list
= list_window_parents( hwnd
))) return TRUE
;
776 for (i
= 0; list
[i
+1]; i
++)
777 if ((get_window_long( list
[i
], GWL_STYLE
) & (WS_VISIBLE
|WS_MINIMIZE
)) != WS_VISIBLE
)
779 retval
= !list
[i
+1] && (list
[i
] == get_desktop_window()); /* top message window isn't visible */
785 /* see IsWindowUnicode */
786 BOOL
is_window_unicode( HWND hwnd
)
791 if (!(win
= get_win_ptr(hwnd
))) return FALSE
;
793 if (win
== WND_DESKTOP
) return TRUE
;
795 if (win
!= WND_OTHER_PROCESS
)
797 ret
= (win
->flags
& WIN_ISUNICODE
) != 0;
798 release_win_ptr( win
);
802 SERVER_START_REQ( get_window_info
)
804 req
->handle
= wine_server_user_handle( hwnd
);
805 if (!wine_server_call_err( req
)) ret
= reply
->is_unicode
;
812 /* see EnableWindow */
813 BOOL
enable_window( HWND hwnd
, BOOL enable
)
817 if (is_broadcast(hwnd
))
819 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
823 TRACE( "( %p, %d )\n", hwnd
, enable
);
827 ret
= (set_window_style( hwnd
, 0, WS_DISABLED
) & WS_DISABLED
) != 0;
828 if (ret
) send_message( hwnd
, WM_ENABLE
, TRUE
, 0 );
832 send_message( hwnd
, WM_CANCELMODE
, 0, 0 );
834 ret
= (set_window_style( hwnd
, WS_DISABLED
, 0 ) & WS_DISABLED
) != 0;
837 if (hwnd
== get_focus())
838 NtUserSetFocus( 0 ); /* A disabled window can't have the focus */
840 send_message( hwnd
, WM_ENABLE
, FALSE
, 0 );
846 /* see IsWindowEnabled */
847 BOOL
is_window_enabled( HWND hwnd
)
851 RtlSetLastWin32Error( NO_ERROR
);
852 ret
= get_window_long( hwnd
, GWL_STYLE
);
853 if (!ret
&& RtlGetLastWin32Error() != NO_ERROR
) return FALSE
;
854 return !(ret
& WS_DISABLED
);
857 /* see GetWindowDpiAwarenessContext */
858 UINT
get_window_dpi_awareness_context( HWND hwnd
)
863 if (!(win
= get_win_ptr( hwnd
)))
865 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
868 if (win
== WND_DESKTOP
) return NTUSER_DPI_PER_MONITOR_AWARE
;
869 if (win
!= WND_OTHER_PROCESS
)
871 ret
= win
->dpi_context
;
872 release_win_ptr( win
);
876 SERVER_START_REQ( get_window_info
)
878 req
->handle
= wine_server_user_handle( hwnd
);
879 if (!wine_server_call_err( req
)) ret
= reply
->dpi_context
;
886 /* see GetDpiForWindow */
887 UINT
get_dpi_for_window( HWND hwnd
)
892 if (!(win
= get_win_ptr( hwnd
)))
894 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
897 if (win
== WND_DESKTOP
)
900 return get_monitor_dpi( monitor_from_point( pt
, MONITOR_DEFAULTTOPRIMARY
, 0 ));
902 if (win
!= WND_OTHER_PROCESS
)
904 context
= win
->dpi_context
;
905 release_win_ptr( win
);
909 SERVER_START_REQ( get_window_info
)
911 req
->handle
= wine_server_user_handle( hwnd
);
912 if (!wine_server_call_err( req
)) context
= reply
->dpi_context
;
917 if (NTUSER_DPI_CONTEXT_IS_MONITOR_AWARE( context
)) return get_win_monitor_dpi( hwnd
);
918 return NTUSER_DPI_CONTEXT_GET_DPI( context
);
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
, layered
= 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_EXSTYLE
&& ((style
.styleOld
^ style
.styleNew
) & WS_EX_LAYERED
)) layered
= TRUE
;
1393 if ((offset
== GWL_STYLE
&& ((style
.styleOld
^ style
.styleNew
) & WS_VISIBLE
)) || 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
|| layered
) 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
)))
1670 if (window_rect
) *window_rect
= wine_server_get_rect( reply
->window
);
1671 if (client_rect
) *client_rect
= wine_server_get_rect( reply
->client
);
1678 /* see GetWindowRect */
1679 BOOL
get_window_rect( HWND hwnd
, RECT
*rect
, UINT dpi
)
1681 return get_window_rects( hwnd
, COORDS_SCREEN
, rect
, NULL
, dpi
);
1684 /* see GetClientRect */
1685 BOOL
get_client_rect( HWND hwnd
, RECT
*rect
, UINT dpi
)
1687 return get_window_rects( hwnd
, COORDS_CLIENT
, NULL
, rect
, dpi
);
1690 /* see GetWindowInfo */
1691 static BOOL
get_window_info( HWND hwnd
, WINDOWINFO
*info
)
1694 if (!info
|| !get_window_rects( hwnd
, COORDS_SCREEN
, &info
->rcWindow
,
1695 &info
->rcClient
, get_thread_dpi() ))
1698 info
->dwStyle
= get_window_long( hwnd
, GWL_STYLE
);
1699 info
->dwExStyle
= get_window_long( hwnd
, GWL_EXSTYLE
);
1700 info
->dwWindowStatus
= get_active_window() == hwnd
? WS_ACTIVECAPTION
: 0;
1701 info
->cxWindowBorders
= info
->rcClient
.left
- info
->rcWindow
.left
;
1702 info
->cyWindowBorders
= info
->rcWindow
.bottom
- info
->rcClient
.bottom
;
1703 info
->atomWindowType
= get_class_long( hwnd
, GCW_ATOM
, FALSE
);
1704 info
->wCreatorVersion
= 0x0400;
1708 static NTSTATUS
get_window_region( HWND hwnd
, BOOL surface
, HRGN
*region
, RECT
*visible
)
1717 if (!(data
= malloc( FIELD_OFFSET( RGNDATA
, Buffer
[size
] )))) return STATUS_NO_MEMORY
;
1719 SERVER_START_REQ( get_window_region
)
1721 req
->window
= wine_server_user_handle( hwnd
);
1722 req
->surface
= surface
;
1723 wine_server_set_reply( req
, data
->Buffer
, size
);
1724 if (!(status
= wine_server_call( req
)))
1726 size_t reply_size
= wine_server_reply_size( reply
);
1729 data
->rdh
.dwSize
= sizeof(data
->rdh
);
1730 data
->rdh
.iType
= RDH_RECTANGLES
;
1731 data
->rdh
.nCount
= reply_size
/ sizeof(RECT
);
1732 data
->rdh
.nRgnSize
= reply_size
;
1733 *region
= NtGdiExtCreateRegion( NULL
, data
->rdh
.dwSize
+ data
->rdh
.nRgnSize
, data
);
1734 *visible
= wine_server_get_rect( reply
->visible_rect
);
1737 else size
= reply
->total_size
;
1742 } while (status
== STATUS_BUFFER_OVERFLOW
);
1747 /***********************************************************************
1748 * update_surface_region
1750 static void update_surface_region( HWND hwnd
)
1752 WND
*win
= get_win_ptr( hwnd
);
1753 HRGN region
, shape
= 0;
1756 if (!win
|| win
== WND_DESKTOP
|| win
== WND_OTHER_PROCESS
) return;
1757 if (!win
->surface
) goto done
;
1759 if (get_window_region( hwnd
, FALSE
, &shape
, &visible
)) goto done
;
1762 region
= NtGdiCreateRectRgn( 0, 0, visible
.right
- visible
.left
, visible
.bottom
- visible
.top
);
1763 NtGdiCombineRgn( shape
, shape
, region
, RGN_AND
);
1764 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
) NtUserMirrorRgn( hwnd
, shape
);
1765 NtGdiDeleteObjectApp( region
);
1767 window_surface_set_shape( win
->surface
, shape
);
1769 if (get_window_region( hwnd
, TRUE
, ®ion
, &visible
)) goto done
;
1770 if (!region
) window_surface_set_clip( win
->surface
, shape
);
1773 NtGdiOffsetRgn( region
, -visible
.left
, -visible
.top
);
1774 if (shape
) NtGdiCombineRgn( region
, region
, shape
, RGN_AND
);
1775 window_surface_set_clip( win
->surface
, region
);
1776 NtGdiDeleteObjectApp( region
);
1780 if (shape
) NtGdiDeleteObjectApp( shape
);
1781 release_win_ptr( win
);
1785 static BOOL
get_surface_rect( const RECT
*visible_rect
, RECT
*surface_rect
)
1787 RECT virtual_rect
= NtUserGetVirtualScreenRect();
1789 *surface_rect
= *visible_rect
;
1791 /* crop surfaces which are larger than the virtual screen rect, some applications create huge windows */
1792 if ((surface_rect
->right
- surface_rect
->left
> virtual_rect
.right
- virtual_rect
.left
||
1793 surface_rect
->bottom
- surface_rect
->top
> virtual_rect
.bottom
- virtual_rect
.top
) &&
1794 !intersect_rect( surface_rect
, surface_rect
, &virtual_rect
))
1796 OffsetRect( surface_rect
, -visible_rect
->left
, -visible_rect
->top
);
1798 /* round the surface coordinates to avoid re-creating them too often on resize */
1799 surface_rect
->left
&= ~127;
1800 surface_rect
->top
&= ~127;
1801 surface_rect
->right
= max( surface_rect
->left
+ 128, (surface_rect
->right
+ 127) & ~127 );
1802 surface_rect
->bottom
= max( surface_rect
->top
+ 128, (surface_rect
->bottom
+ 127) & ~127 );
1806 static BOOL
get_default_window_surface( HWND hwnd
, const RECT
*surface_rect
, struct window_surface
**surface
)
1808 struct window_surface
*previous
;
1811 TRACE( "hwnd %p, surface_rect %s, surface %p\n", hwnd
, wine_dbgstr_rect( surface_rect
), surface
);
1813 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_DESKTOP
|| win
== WND_OTHER_PROCESS
) return FALSE
;
1815 if ((previous
= win
->surface
) && EqualRect( &previous
->rect
, surface_rect
))
1817 window_surface_add_ref( (*surface
= previous
) );
1818 TRACE( "trying to reuse previous surface %p\n", previous
);
1820 else if (!win
->parent
|| win
->parent
== get_desktop_window())
1822 *surface
= &dummy_surface
; /* provide a default surface for top-level windows */
1823 window_surface_add_ref( *surface
);
1827 *surface
= NULL
; /* use parent surface for child windows */
1828 TRACE( "using parent window surface\n" );
1831 release_win_ptr( win
);
1835 static struct window_surface
*create_window_surface( HWND hwnd
, UINT swp_flags
, BOOL create_layered
,
1836 const RECT
*window_rect
, const RECT
*client_rect
,
1837 RECT
*visible_rect
, RECT
*surface_rect
)
1839 BOOL shaped
, needs_surface
, create_opaque
, is_layered
;
1840 struct window_surface
*new_surface
;
1844 if (get_window_region( hwnd
, FALSE
, &shape
, &dummy
)) shaped
= FALSE
;
1845 else if ((shaped
= !!shape
)) NtGdiDeleteObjectApp( shape
);
1847 *visible_rect
= *window_rect
;
1848 if (!user_driver
->pWindowPosChanging( hwnd
, swp_flags
, shaped
, window_rect
, client_rect
, visible_rect
)) needs_surface
= FALSE
;
1849 else if (swp_flags
& SWP_HIDEWINDOW
) needs_surface
= FALSE
;
1850 else if (swp_flags
& SWP_SHOWWINDOW
) needs_surface
= TRUE
;
1851 else needs_surface
= !!(NtUserGetWindowLongW( hwnd
, GWL_STYLE
) & WS_VISIBLE
);
1853 if (!get_surface_rect( visible_rect
, surface_rect
)) needs_surface
= FALSE
;
1854 if (!get_default_window_surface( hwnd
, surface_rect
, &new_surface
)) return NULL
;
1856 is_layered
= new_surface
&& new_surface
->alpha_mask
;
1857 create_opaque
= !(get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_LAYERED
);
1859 if ((create_opaque
&& is_layered
) || (create_layered
&& !is_layered
))
1861 window_surface_release( new_surface
);
1862 new_surface
= &dummy_surface
;
1863 window_surface_add_ref( new_surface
);
1866 if (!needs_surface
|| IsRectEmpty( visible_rect
)) needs_surface
= FALSE
; /* use default surface */
1867 else needs_surface
= !user_driver
->pCreateWindowSurface( hwnd
, surface_rect
, &new_surface
);
1869 /* create or update window surface for top-level windows if the driver doesn't implement CreateWindowSurface */
1870 if (needs_surface
&& new_surface
== &dummy_surface
&& (create_opaque
&& !create_layered
))
1872 window_surface_release( new_surface
);
1873 create_offscreen_window_surface( hwnd
, surface_rect
, &new_surface
);
1876 if (new_surface
&& !is_layered
)
1878 DWORD lwa_flags
= 0;
1882 if (!NtUserGetLayeredWindowAttributes( hwnd
, &key
, &alpha
, &lwa_flags
)) lwa_flags
= 0;
1883 if (!(lwa_flags
& LWA_ALPHA
)) alpha
= 255;
1884 if (!(lwa_flags
& LWA_COLORKEY
)) key
= CLR_INVALID
;
1885 window_surface_set_layered( new_surface
, key
, alpha
<< 24, 0 );
1891 /***********************************************************************
1894 * Backend implementation of SetWindowPos.
1896 static BOOL
apply_window_pos( HWND hwnd
, HWND insert_after
, UINT swp_flags
, struct window_surface
*new_surface
,
1897 const RECT
*window_rect
, const RECT
*client_rect
, const RECT
*visible_rect
, const RECT
*valid_rects
)
1900 HWND surface_win
= 0;
1901 BOOL ret
, needs_update
= FALSE
;
1902 RECT old_visible_rect
, old_window_rect
, old_client_rect
, extra_rects
[3];
1903 struct window_surface
*old_surface
;
1905 get_window_rects( hwnd
, COORDS_SCREEN
, &old_window_rect
, NULL
, get_thread_dpi() );
1906 if (IsRectEmpty( &valid_rects
[0] )) valid_rects
= NULL
;
1908 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_DESKTOP
|| win
== WND_OTHER_PROCESS
) return FALSE
;
1910 old_visible_rect
= win
->visible_rect
;
1911 old_client_rect
= win
->client_rect
;
1912 old_surface
= win
->surface
;
1913 if (old_surface
!= new_surface
) swp_flags
|= SWP_FRAMECHANGED
; /* force refreshing non-client area */
1914 if (new_surface
== &dummy_surface
) swp_flags
|= SWP_NOREDRAW
;
1915 else if (old_surface
== &dummy_surface
)
1917 swp_flags
|= SWP_NOCOPYBITS
;
1921 SERVER_START_REQ( set_window_pos
)
1923 req
->handle
= wine_server_user_handle( hwnd
);
1924 req
->previous
= wine_server_user_handle( insert_after
);
1925 req
->swp_flags
= swp_flags
;
1926 req
->window
= wine_server_rectangle( *window_rect
);
1927 req
->client
= wine_server_rectangle( *client_rect
);
1928 if (!EqualRect( window_rect
, visible_rect
) || new_surface
|| valid_rects
)
1930 extra_rects
[0] = extra_rects
[1] = *visible_rect
;
1933 extra_rects
[1] = new_surface
->rect
;
1934 OffsetRect( &extra_rects
[1], visible_rect
->left
, visible_rect
->top
);
1936 if (valid_rects
) extra_rects
[2] = valid_rects
[0];
1937 else SetRectEmpty( &extra_rects
[2] );
1938 wine_server_add_data( req
, extra_rects
, sizeof(extra_rects
) );
1940 if (new_surface
) req
->paint_flags
|= SET_WINPOS_PAINT_SURFACE
;
1941 if (win
->pixel_format
|| win
->internal_pixel_format
)
1942 req
->paint_flags
|= SET_WINPOS_PIXEL_FORMAT
;
1944 if ((ret
= !wine_server_call( req
)))
1946 win
->dwStyle
= reply
->new_style
;
1947 win
->dwExStyle
= reply
->new_ex_style
;
1948 win
->window_rect
= *window_rect
;
1949 win
->client_rect
= *client_rect
;
1950 win
->visible_rect
= *visible_rect
;
1951 if ((win
->surface
= new_surface
)) window_surface_add_ref( win
->surface
);
1952 surface_win
= wine_server_ptr_handle( reply
->surface_win
);
1953 needs_update
= reply
->needs_update
;
1954 if (get_window_long( win
->parent
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
)
1957 get_window_rects( win
->parent
, COORDS_CLIENT
, NULL
, &client
, get_thread_dpi() );
1958 mirror_rect( &client
, &win
->window_rect
);
1959 mirror_rect( &client
, &win
->client_rect
);
1960 mirror_rect( &client
, &win
->visible_rect
);
1962 /* if an RTL window is resized the children have moved */
1963 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
&&
1964 client_rect
->right
- client_rect
->left
!= old_client_rect
.right
- old_client_rect
.left
)
1965 win
->flags
|= WIN_CHILDREN_MOVED
;
1972 if (needs_update
) update_surface_region( surface_win
);
1973 if (((swp_flags
& SWP_AGG_NOPOSCHANGE
) != SWP_AGG_NOPOSCHANGE
) ||
1974 (swp_flags
& (SWP_HIDEWINDOW
| SWP_SHOWWINDOW
| SWP_STATECHANGED
| SWP_FRAMECHANGED
)))
1975 invalidate_dce( win
, &old_window_rect
);
1978 release_win_ptr( win
);
1982 TRACE( "win %p surface %p -> %p\n", hwnd
, old_surface
, new_surface
);
1983 register_window_surface( old_surface
, new_surface
);
1988 if (old_surface
!= new_surface
)
1989 move_window_bits_surface( hwnd
, window_rect
, old_surface
, &old_visible_rect
, valid_rects
);
1991 move_window_bits( hwnd
, visible_rect
, &old_visible_rect
, window_rect
, valid_rects
);
1992 valid_rects
= NULL
; /* prevent the driver from trying to also move the bits */
1994 window_surface_release( old_surface
);
1996 else if (surface_win
&& surface_win
!= hwnd
)
2001 int x_offset
= old_visible_rect
.left
- visible_rect
->left
;
2002 int y_offset
= old_visible_rect
.top
- visible_rect
->top
;
2004 /* if all that happened is that the whole window moved, copy everything */
2005 if (!(swp_flags
& SWP_FRAMECHANGED
) &&
2006 old_visible_rect
.right
- visible_rect
->right
== x_offset
&&
2007 old_visible_rect
.bottom
- visible_rect
->bottom
== y_offset
&&
2008 old_client_rect
.left
- client_rect
->left
== x_offset
&&
2009 old_client_rect
.right
- client_rect
->right
== x_offset
&&
2010 old_client_rect
.top
- client_rect
->top
== y_offset
&&
2011 old_client_rect
.bottom
- client_rect
->bottom
== y_offset
&&
2012 EqualRect( &valid_rects
[0], client_rect
))
2014 rects
[0] = *visible_rect
;
2015 rects
[1] = old_visible_rect
;
2016 valid_rects
= rects
;
2018 move_window_bits( hwnd
, visible_rect
, visible_rect
, window_rect
, valid_rects
);
2019 valid_rects
= NULL
; /* prevent the driver from trying to also move the bits */
2023 user_driver
->pWindowPosChanged( hwnd
, insert_after
, swp_flags
, window_rect
,
2024 client_rect
, visible_rect
, valid_rects
, new_surface
);
2030 /*******************************************************************
2031 * NtUserGetWindowRgnEx (win32u.@)
2033 int WINAPI
NtUserGetWindowRgnEx( HWND hwnd
, HRGN hrgn
, UINT unk
)
2040 if ((status
= get_window_region( hwnd
, FALSE
, &win_rgn
, &visible
)))
2042 set_ntstatus( status
);
2048 ret
= NtGdiCombineRgn( hrgn
, win_rgn
, 0, RGN_COPY
);
2049 NtGdiDeleteObjectApp( win_rgn
);
2054 /***********************************************************************
2055 * NtUserSetWindowRgn (win32u.@)
2057 int WINAPI
NtUserSetWindowRgn( HWND hwnd
, HRGN hrgn
, BOOL redraw
)
2059 static const RECT empty_rect
;
2067 if (!(size
= NtGdiGetRegionData( hrgn
, 0, NULL
))) return FALSE
;
2068 if (!(data
= malloc( size
))) return FALSE
;
2069 if (!NtGdiGetRegionData( hrgn
, size
, data
))
2074 SERVER_START_REQ( set_window_region
)
2076 req
->window
= wine_server_user_handle( hwnd
);
2077 req
->redraw
= redraw
!= 0;
2078 if (data
->rdh
.nCount
)
2079 wine_server_add_data( req
, data
->Buffer
, data
->rdh
.nCount
* sizeof(RECT
) );
2081 wine_server_add_data( req
, &empty_rect
, sizeof(empty_rect
) );
2082 ret
= !wine_server_call_err( req
);
2087 else /* clear existing region */
2089 SERVER_START_REQ( set_window_region
)
2091 req
->window
= wine_server_user_handle( hwnd
);
2092 req
->redraw
= redraw
!= 0;
2093 ret
= !wine_server_call_err( req
);
2100 UINT swp_flags
= SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_FRAMECHANGED
|
2101 SWP_NOCLIENTSIZE
| SWP_NOCLIENTMOVE
;
2102 if (!redraw
) swp_flags
|= SWP_NOREDRAW
;
2103 user_driver
->pSetWindowRgn( hwnd
, hrgn
, redraw
);
2104 NtUserSetWindowPos( hwnd
, 0, 0, 0, 0, 0, swp_flags
);
2105 if (hrgn
) NtGdiDeleteObjectApp( hrgn
);
2110 /***********************************************************************
2111 * NtUserMoveWindow (win32u.@)
2113 BOOL WINAPI
NtUserMoveWindow( HWND hwnd
, INT x
, INT y
, INT cx
, INT cy
, BOOL repaint
)
2115 int flags
= SWP_NOZORDER
| SWP_NOACTIVATE
;
2116 if (!repaint
) flags
|= SWP_NOREDRAW
;
2117 TRACE( "%p %d,%d %dx%d %d\n", hwnd
, x
, y
, cx
, cy
, repaint
);
2118 return NtUserSetWindowPos( hwnd
, 0, x
, y
, cx
, cy
, flags
);
2121 /*****************************************************************************
2122 * NtUserGetLayeredWindowAttributes (win32u.@)
2124 BOOL WINAPI
NtUserGetLayeredWindowAttributes( HWND hwnd
, COLORREF
*key
, BYTE
*alpha
, DWORD
*flags
)
2128 SERVER_START_REQ( get_window_layered_info
)
2130 req
->handle
= wine_server_user_handle( hwnd
);
2131 if ((ret
= !wine_server_call_err( req
)))
2133 if (key
) *key
= reply
->color_key
;
2134 if (alpha
) *alpha
= reply
->alpha
;
2135 if (flags
) *flags
= reply
->flags
;
2143 /*****************************************************************************
2144 * NtUserSetLayeredWindowAttributes (win32u.@)
2146 BOOL WINAPI
NtUserSetLayeredWindowAttributes( HWND hwnd
, COLORREF key
, BYTE alpha
, DWORD flags
)
2150 TRACE( "(%p,%s,%d,%x)\n", hwnd
, debugstr_color(key
), alpha
, (int)flags
);
2152 SERVER_START_REQ( set_window_layered_info
)
2154 req
->handle
= wine_server_user_handle( hwnd
);
2155 req
->color_key
= key
;
2158 ret
= !wine_server_call_err( req
);
2164 user_driver
->pSetLayeredWindowAttributes( hwnd
, key
, alpha
, flags
);
2165 update_window_state( hwnd
);
2171 /*****************************************************************************
2172 * UpdateLayeredWindow (win32u.@)
2174 BOOL WINAPI
NtUserUpdateLayeredWindow( HWND hwnd
, HDC hdc_dst
, const POINT
*pts_dst
, const SIZE
*size
,
2175 HDC hdc_src
, const POINT
*pts_src
, COLORREF key
,
2176 const BLENDFUNCTION
*blend
, DWORD flags
, const RECT
*dirty
)
2178 DWORD swp_flags
= SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREDRAW
;
2179 struct window_surface
*surface
;
2180 RECT window_rect
, client_rect
, visible_rect
, surface_rect
;
2184 if (flags
& ~(ULW_COLORKEY
| ULW_ALPHA
| ULW_OPAQUE
| ULW_EX_NORESIZE
) ||
2185 !(get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_LAYERED
) ||
2186 NtUserGetLayeredWindowAttributes( hwnd
, NULL
, NULL
, NULL
))
2188 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
2192 get_window_rects( hwnd
, COORDS_PARENT
, &window_rect
, &client_rect
, get_thread_dpi() );
2196 offset
.cx
= pts_dst
->x
- window_rect
.left
;
2197 offset
.cy
= pts_dst
->y
- window_rect
.top
;
2198 OffsetRect( &client_rect
, offset
.cx
, offset
.cy
);
2199 OffsetRect( &window_rect
, offset
.cx
, offset
.cy
);
2200 swp_flags
&= ~SWP_NOMOVE
;
2204 offset
.cx
= size
->cx
- (window_rect
.right
- window_rect
.left
);
2205 offset
.cy
= size
->cy
- (window_rect
.bottom
- window_rect
.top
);
2206 if (size
->cx
<= 0 || size
->cy
<= 0)
2208 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
2211 if ((flags
& ULW_EX_NORESIZE
) && (offset
.cx
|| offset
.cy
))
2213 RtlSetLastWin32Error( ERROR_INCORRECT_SIZE
);
2216 client_rect
.right
+= offset
.cx
;
2217 client_rect
.bottom
+= offset
.cy
;
2218 window_rect
.right
+= offset
.cx
;
2219 window_rect
.bottom
+= offset
.cy
;
2220 swp_flags
&= ~SWP_NOSIZE
;
2223 TRACE( "window %p win %s client %s\n", hwnd
,
2224 wine_dbgstr_rect(&window_rect
), wine_dbgstr_rect(&client_rect
) );
2226 surface
= create_window_surface( hwnd
, swp_flags
, TRUE
, &window_rect
, &client_rect
, &visible_rect
, &surface_rect
);
2227 apply_window_pos( hwnd
, 0, swp_flags
, surface
, &window_rect
, &client_rect
, &visible_rect
, NULL
);
2228 if (surface
) window_surface_release( surface
);
2230 if (!(flags
& ULW_COLORKEY
)) key
= CLR_INVALID
;
2231 if (IsRectEmpty( &surface_rect
)) window_surface_add_ref( (surface
= &dummy_surface
) );
2232 else if (!(user_driver
->pCreateLayeredWindow( hwnd
, &surface_rect
, key
, &surface
)) || !surface
) return FALSE
;
2234 if (!hdc_src
|| surface
== &dummy_surface
) ret
= TRUE
;
2237 BLENDFUNCTION src_blend
= { AC_SRC_OVER
, 0, 255, 0 };
2238 RECT rect
= window_rect
, src_rect
;
2242 OffsetRect( &rect
, -rect
.left
, -rect
.top
);
2243 intersect_rect( &rect
, &rect
, &surface_rect
);
2245 if (!(hdc
= NtGdiCreateCompatibleDC( 0 ))) goto done
;
2246 window_surface_lock( surface
);
2247 NtGdiSelectBitmap( hdc
, surface
->color_bitmap
);
2249 if (dirty
) intersect_rect( &rect
, &rect
, dirty
);
2250 NtGdiPatBlt( hdc
, rect
.left
, rect
.top
, rect
.right
- rect
.left
, rect
.bottom
- rect
.top
, BLACKNESS
);
2253 if (pts_src
) OffsetRect( &src_rect
, pts_src
->x
, pts_src
->y
);
2254 NtGdiTransformPoints( hdc_src
, (POINT
*)&src_rect
, (POINT
*)&src_rect
, 2, NtGdiDPtoLP
);
2256 if (flags
& ULW_ALPHA
) src_blend
= *blend
;
2257 ret
= NtGdiAlphaBlend( hdc
, rect
.left
, rect
.top
, rect
.right
- rect
.left
, rect
.bottom
- rect
.top
,
2258 hdc_src
, src_rect
.left
, src_rect
.top
, src_rect
.right
- src_rect
.left
, src_rect
.bottom
- src_rect
.top
,
2259 *(DWORD
*)&src_blend
, 0 );
2260 if (ret
) add_bounds_rect( &surface
->bounds
, &rect
);
2262 NtGdiDeleteObjectApp( hdc
);
2263 window_surface_unlock( surface
);
2265 window_surface_set_layered( surface
, key
, -1, 0xff000000 );
2266 window_surface_flush( surface
);
2268 user_driver
->pUpdateLayeredWindow( hwnd
, &window_rect
, key
, alpha
, flags
);
2272 window_surface_release( surface
);
2276 /***********************************************************************
2277 * list_children_from_point
2279 * Get the list of children that can contain point from the server.
2280 * Point is in screen coordinates.
2281 * Returned list must be freed by caller.
2283 static HWND
*list_children_from_point( HWND hwnd
, POINT pt
)
2292 if (!(list
= malloc( size
* sizeof(HWND
) ))) break;
2294 SERVER_START_REQ( get_window_children_from_point
)
2296 req
->parent
= wine_server_user_handle( hwnd
);
2299 req
->dpi
= get_thread_dpi();
2300 wine_server_set_reply( req
, list
, (size
-1) * sizeof(user_handle_t
) );
2301 if (!wine_server_call( req
)) count
= reply
->count
;
2304 if (count
&& count
< size
)
2306 /* start from the end since HWND is potentially larger than user_handle_t */
2307 for (i
= count
- 1; i
>= 0; i
--)
2308 list
[i
] = wine_server_ptr_handle( ((user_handle_t
*)list
)[i
] );
2314 size
= count
+ 1; /* restart with a large enough buffer */
2319 /***********************************************************************
2322 * Find the window and hittest for a given point.
2324 HWND
window_from_point( HWND hwnd
, POINT pt
, INT
*hittest
)
2331 if (!hwnd
) hwnd
= get_desktop_window();
2332 if (!(dpi
= get_thread_dpi())) dpi
= get_win_monitor_dpi( hwnd
);
2334 *hittest
= HTNOWHERE
;
2336 if (!(list
= list_children_from_point( hwnd
, pt
))) return 0;
2338 /* now determine the hittest */
2340 for (i
= 0; list
[i
]; i
++)
2342 LONG style
= get_window_long( list
[i
], GWL_STYLE
);
2344 /* If window is minimized or disabled, return at once */
2345 if (style
& WS_DISABLED
)
2350 /* Send WM_NCCHITTEST (if same thread) */
2351 if (!is_current_thread_window( list
[i
] ))
2353 *hittest
= HTCLIENT
;
2356 win_pt
= map_dpi_point( pt
, dpi
, get_dpi_for_window( list
[i
] ));
2357 res
= send_message( list
[i
], WM_NCHITTEST
, 0, MAKELPARAM( win_pt
.x
, win_pt
.y
));
2358 if (res
!= HTTRANSPARENT
)
2360 *hittest
= res
; /* Found the window */
2363 /* continue search with next window in z-order */
2367 TRACE( "scope %p (%d,%d) returning %p\n", hwnd
, (int)pt
.x
, (int)pt
.y
, ret
);
2371 /*******************************************************************
2372 * NtUserWindowFromPoint (win32u.@)
2374 HWND WINAPI
NtUserWindowFromPoint( LONG x
, LONG y
)
2376 POINT pt
= { .x
= x
, .y
= y
};
2378 return window_from_point( 0, pt
, &hittest
);
2381 /*******************************************************************
2382 * NtUserChildWindowFromPointEx (win32u.@)
2384 HWND WINAPI
NtUserChildWindowFromPointEx( HWND parent
, LONG x
, LONG y
, UINT flags
)
2386 POINT pt
= { .x
= x
, .y
= y
}; /* in the client coordinates */
2392 get_client_rect( parent
, &rect
, get_thread_dpi() );
2393 if (!PtInRect( &rect
, pt
)) return 0;
2394 if (!(list
= list_window_children( 0, parent
, NULL
, 0 ))) return parent
;
2396 for (i
= 0; list
[i
]; i
++)
2398 if (!get_window_rects( list
[i
], COORDS_PARENT
, &rect
, NULL
, get_thread_dpi() )) continue;
2399 if (!PtInRect( &rect
, pt
)) continue;
2400 if (flags
& (CWP_SKIPINVISIBLE
|CWP_SKIPDISABLED
))
2402 LONG style
= get_window_long( list
[i
], GWL_STYLE
);
2403 if ((flags
& CWP_SKIPINVISIBLE
) && !(style
& WS_VISIBLE
)) continue;
2404 if ((flags
& CWP_SKIPDISABLED
) && (style
& WS_DISABLED
)) continue;
2406 if (flags
& CWP_SKIPTRANSPARENT
)
2408 if (get_window_long( list
[i
], GWL_EXSTYLE
) & WS_EX_TRANSPARENT
) continue;
2414 if (!ret
) ret
= parent
;
2418 /*******************************************************************
2419 * NtUserRealChildWindowFromPoint (win32u.@)
2421 HWND WINAPI
NtUserRealChildWindowFromPoint( HWND parent
, LONG x
, LONG y
)
2423 return NtUserChildWindowFromPointEx( parent
, x
, y
, CWP_SKIPTRANSPARENT
| CWP_SKIPINVISIBLE
);
2426 /*******************************************************************
2429 * Get the work area that a maximized window can cover, depending on style.
2431 static BOOL
get_work_rect( HWND hwnd
, RECT
*rect
)
2433 HMONITOR monitor
= monitor_from_window( hwnd
, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
2434 MONITORINFO mon_info
;
2437 if (!monitor
) return FALSE
;
2439 mon_info
.cbSize
= sizeof(mon_info
);
2440 get_monitor_info( monitor
, &mon_info
, get_thread_dpi() );
2441 *rect
= mon_info
.rcMonitor
;
2443 style
= get_window_long( hwnd
, GWL_STYLE
);
2444 if (style
& WS_MAXIMIZEBOX
)
2446 if ((style
& WS_CAPTION
) == WS_CAPTION
|| !(style
& (WS_CHILD
| WS_POPUP
)))
2447 *rect
= mon_info
.rcWork
;
2452 static RECT
get_maximized_work_rect( HWND hwnd
)
2454 RECT work_rect
= { 0 };
2456 if ((get_window_long( hwnd
, GWL_STYLE
) & (WS_MINIMIZE
| WS_MAXIMIZE
)) == WS_MAXIMIZE
)
2458 if (!get_work_rect( hwnd
, &work_rect
))
2459 work_rect
= get_primary_monitor_rect( get_thread_dpi() );
2464 /*******************************************************************
2465 * update_maximized_pos
2467 * For top level windows covering the work area, we might have to
2468 * "forget" the maximized position. Windows presumably does this
2469 * to avoid situations where the border style changes, which would
2470 * lead the window to be outside the screen, or the window gets
2471 * reloaded on a different screen, and the "saved" position no
2472 * longer applies to it (despite being maximized).
2474 * Some applications (e.g. Imperiums: Greek Wars) depend on this.
2476 static void update_maximized_pos( WND
*wnd
, RECT
*work_rect
)
2478 if (wnd
->parent
&& wnd
->parent
!= get_desktop_window())
2481 if (wnd
->dwStyle
& WS_MAXIMIZE
)
2483 if (wnd
->window_rect
.left
<= work_rect
->left
&& wnd
->window_rect
.top
<= work_rect
->top
&&
2484 wnd
->window_rect
.right
>= work_rect
->right
&& wnd
->window_rect
.bottom
>= work_rect
->bottom
)
2485 wnd
->max_pos
.x
= wnd
->max_pos
.y
= -1;
2488 wnd
->max_pos
.x
= wnd
->max_pos
.y
= -1;
2491 static BOOL
empty_point( POINT pt
)
2493 return pt
.x
== -1 && pt
.y
== -1;
2496 /***********************************************************************
2497 * NtUserGetWindowPlacement (win32u.@)
2499 BOOL WINAPI
NtUserGetWindowPlacement( HWND hwnd
, WINDOWPLACEMENT
*placement
)
2501 RECT work_rect
= get_maximized_work_rect( hwnd
);
2502 WND
*win
= get_win_ptr( hwnd
);
2505 if (!win
) return FALSE
;
2507 if (win
== WND_DESKTOP
)
2509 placement
->length
= sizeof(*placement
);
2510 placement
->showCmd
= SW_SHOWNORMAL
;
2511 placement
->flags
= 0;
2512 placement
->ptMinPosition
.x
= -1;
2513 placement
->ptMinPosition
.y
= -1;
2514 placement
->ptMaxPosition
.x
= -1;
2515 placement
->ptMaxPosition
.y
= -1;
2516 get_window_rect( hwnd
, &placement
->rcNormalPosition
, get_thread_dpi() );
2519 if (win
== WND_OTHER_PROCESS
)
2521 RECT normal_position
;
2524 if (!get_window_rect( hwnd
, &normal_position
, get_thread_dpi() ))
2527 FIXME("not fully supported on other process window %p.\n", hwnd
);
2529 placement
->length
= sizeof(*placement
);
2530 style
= get_window_long( hwnd
, GWL_STYLE
);
2531 if (style
& WS_MINIMIZE
)
2532 placement
->showCmd
= SW_SHOWMINIMIZED
;
2534 placement
->showCmd
= (style
& WS_MAXIMIZE
) ? SW_SHOWMAXIMIZED
: SW_SHOWNORMAL
;
2535 /* provide some dummy information */
2536 placement
->flags
= 0;
2537 placement
->ptMinPosition
.x
= -1;
2538 placement
->ptMinPosition
.y
= -1;
2539 placement
->ptMaxPosition
.x
= -1;
2540 placement
->ptMaxPosition
.y
= -1;
2541 placement
->rcNormalPosition
= normal_position
;
2545 /* update the placement according to the current style */
2546 if (win
->dwStyle
& WS_MINIMIZE
)
2548 win
->min_pos
.x
= win
->window_rect
.left
;
2549 win
->min_pos
.y
= win
->window_rect
.top
;
2551 else if (win
->dwStyle
& WS_MAXIMIZE
)
2553 win
->max_pos
.x
= win
->window_rect
.left
;
2554 win
->max_pos
.y
= win
->window_rect
.top
;
2558 win
->normal_rect
= win
->window_rect
;
2560 update_maximized_pos( win
, &work_rect
);
2562 placement
->length
= sizeof(*placement
);
2563 if (win
->dwStyle
& WS_MINIMIZE
)
2564 placement
->showCmd
= SW_SHOWMINIMIZED
;
2566 placement
->showCmd
= ( win
->dwStyle
& WS_MAXIMIZE
) ? SW_SHOWMAXIMIZED
: SW_SHOWNORMAL
;
2567 if (win
->flags
& WIN_RESTORE_MAX
)
2568 placement
->flags
= WPF_RESTORETOMAXIMIZED
;
2570 placement
->flags
= 0;
2571 win_dpi
= get_dpi_for_window( hwnd
);
2572 placement
->ptMinPosition
= empty_point(win
->min_pos
) ? win
->min_pos
2573 : map_dpi_point( win
->min_pos
, win_dpi
, get_thread_dpi() );
2574 placement
->ptMaxPosition
= empty_point(win
->max_pos
) ? win
->max_pos
2575 : map_dpi_point( win
->max_pos
, win_dpi
, get_thread_dpi() );
2576 placement
->rcNormalPosition
= map_dpi_rect( win
->normal_rect
, win_dpi
, get_thread_dpi() );
2577 release_win_ptr( win
);
2579 TRACE( "%p: returning min %d,%d max %d,%d normal %s\n",
2580 hwnd
, (int)placement
->ptMinPosition
.x
, (int)placement
->ptMinPosition
.y
,
2581 (int)placement
->ptMaxPosition
.x
, (int)placement
->ptMaxPosition
.y
,
2582 wine_dbgstr_rect(&placement
->rcNormalPosition
) );
2586 /* make sure the specified rect is visible on screen */
2587 static void make_rect_onscreen( RECT
*rect
)
2590 HMONITOR monitor
= monitor_from_rect( rect
, MONITOR_DEFAULTTONEAREST
, get_thread_dpi() );
2592 info
.cbSize
= sizeof(info
);
2593 if (!monitor
|| !get_monitor_info( monitor
, &info
, get_thread_dpi() )) return;
2594 /* FIXME: map coordinates from rcWork to rcMonitor */
2595 if (rect
->right
<= info
.rcWork
.left
)
2597 rect
->right
+= info
.rcWork
.left
- rect
->left
;
2598 rect
->left
= info
.rcWork
.left
;
2600 else if (rect
->left
>= info
.rcWork
.right
)
2602 rect
->left
+= info
.rcWork
.right
- rect
->right
;
2603 rect
->right
= info
.rcWork
.right
;
2605 if (rect
->bottom
<= info
.rcWork
.top
)
2607 rect
->bottom
+= info
.rcWork
.top
- rect
->top
;
2608 rect
->top
= info
.rcWork
.top
;
2610 else if (rect
->top
>= info
.rcWork
.bottom
)
2612 rect
->top
+= info
.rcWork
.bottom
- rect
->bottom
;
2613 rect
->bottom
= info
.rcWork
.bottom
;
2617 /***********************************************************************
2618 * NtUserGetInternalWindowPos (win32u.@)
2620 UINT WINAPI
NtUserGetInternalWindowPos( HWND hwnd
, RECT
*rect
, POINT
*pt
)
2622 WINDOWPLACEMENT placement
;
2624 placement
.length
= sizeof(placement
);
2625 if (!NtUserGetWindowPlacement( hwnd
, &placement
)) return 0;
2626 if (rect
) *rect
= placement
.rcNormalPosition
;
2627 if (pt
) *pt
= placement
.ptMinPosition
;
2628 return placement
.showCmd
;
2631 /* make sure the specified point is visible on screen */
2632 static void make_point_onscreen( POINT
*pt
)
2636 SetRect( &rect
, pt
->x
, pt
->y
, pt
->x
+ 1, pt
->y
+ 1 );
2637 make_rect_onscreen( &rect
);
2642 static BOOL
set_window_placement( HWND hwnd
, const WINDOWPLACEMENT
*wndpl
, UINT flags
)
2644 RECT work_rect
= get_maximized_work_rect( hwnd
);
2645 WND
*win
= get_win_ptr( hwnd
);
2646 WINDOWPLACEMENT wp
= *wndpl
;
2649 if (flags
& PLACE_MIN
) make_point_onscreen( &wp
.ptMinPosition
);
2650 if (flags
& PLACE_MAX
) make_point_onscreen( &wp
.ptMaxPosition
);
2651 if (flags
& PLACE_RECT
) make_rect_onscreen( &wp
.rcNormalPosition
);
2653 TRACE( "%p: setting min %d,%d max %d,%d normal %s flags %x adjusted to min %d,%d max %d,%d normal %s\n",
2654 hwnd
, (int)wndpl
->ptMinPosition
.x
, (int)wndpl
->ptMinPosition
.y
,
2655 (int)wndpl
->ptMaxPosition
.x
, (int)wndpl
->ptMaxPosition
.y
,
2656 wine_dbgstr_rect(&wndpl
->rcNormalPosition
), flags
,
2657 (int)wp
.ptMinPosition
.x
, (int)wp
.ptMinPosition
.y
,
2658 (int)wp
.ptMaxPosition
.x
, (int)wp
.ptMaxPosition
.y
,
2659 wine_dbgstr_rect(&wp
.rcNormalPosition
) );
2661 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
2663 if (flags
& PLACE_MIN
) win
->min_pos
= point_thread_to_win_dpi( hwnd
, wp
.ptMinPosition
);
2664 if (flags
& PLACE_MAX
)
2666 win
->max_pos
= point_thread_to_win_dpi( hwnd
, wp
.ptMaxPosition
);
2667 update_maximized_pos( win
, &work_rect
);
2669 if (flags
& PLACE_RECT
) win
->normal_rect
= rect_thread_to_win_dpi( hwnd
, wp
.rcNormalPosition
);
2671 style
= win
->dwStyle
;
2673 release_win_ptr( win
);
2675 if (style
& WS_MINIMIZE
)
2677 if (flags
& PLACE_MIN
)
2679 NtUserSetWindowPos( hwnd
, 0, wp
.ptMinPosition
.x
, wp
.ptMinPosition
.y
, 0, 0,
2680 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
2683 else if (style
& WS_MAXIMIZE
)
2685 if (flags
& PLACE_MAX
)
2686 NtUserSetWindowPos( hwnd
, 0, wp
.ptMaxPosition
.x
, wp
.ptMaxPosition
.y
, 0, 0,
2687 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
2689 else if (flags
& PLACE_RECT
)
2690 NtUserSetWindowPos( hwnd
, 0, wp
.rcNormalPosition
.left
, wp
.rcNormalPosition
.top
,
2691 wp
.rcNormalPosition
.right
- wp
.rcNormalPosition
.left
,
2692 wp
.rcNormalPosition
.bottom
- wp
.rcNormalPosition
.top
,
2693 SWP_NOZORDER
| SWP_NOACTIVATE
);
2695 NtUserShowWindow( hwnd
, wndpl
->showCmd
);
2697 if (is_iconic( hwnd
))
2699 if (wndpl
->flags
& WPF_RESTORETOMAXIMIZED
)
2700 win_set_flags( hwnd
, WIN_RESTORE_MAX
, 0 );
2705 /***********************************************************************
2706 * NtUserSetWindowPlacement (win32u.@)
2708 BOOL WINAPI
NtUserSetWindowPlacement( HWND hwnd
, const WINDOWPLACEMENT
*wpl
)
2710 UINT flags
= PLACE_MAX
| PLACE_RECT
;
2711 if (!wpl
) return FALSE
;
2712 if (wpl
->length
!= sizeof(*wpl
))
2714 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
2717 if (wpl
->flags
& WPF_SETMINPOSITION
) flags
|= PLACE_MIN
;
2718 return set_window_placement( hwnd
, wpl
, flags
);
2721 /*****************************************************************************
2722 * NtUserBuildHwndList (win32u.@)
2724 NTSTATUS WINAPI
NtUserBuildHwndList( HDESK desktop
, ULONG unk2
, ULONG unk3
, ULONG unk4
,
2725 ULONG thread_id
, ULONG count
, HWND
*buffer
, ULONG
*size
)
2727 user_handle_t
*list
= (user_handle_t
*)buffer
;
2731 SERVER_START_REQ( get_window_children
)
2733 req
->desktop
= wine_server_obj_handle( desktop
);
2734 req
->tid
= thread_id
;
2735 if (count
) wine_server_set_reply( req
, list
, (count
- 1) * sizeof(user_handle_t
) );
2736 status
= wine_server_call( req
);
2737 if (status
&& status
!= STATUS_BUFFER_TOO_SMALL
) return status
;
2738 *size
= reply
->count
+ 1;
2741 if (*size
> count
) return STATUS_BUFFER_TOO_SMALL
;
2743 /* start from the end since HWND is potentially larger than user_handle_t */
2744 for (i
= *size
- 2; i
>= 0; i
--)
2745 buffer
[i
] = wine_server_ptr_handle( list
[i
] );
2746 buffer
[*size
- 1] = HWND_BOTTOM
;
2747 return STATUS_SUCCESS
;
2750 /***********************************************************************
2751 * NtUserFindWindowEx (USER32.@)
2753 HWND WINAPI
NtUserFindWindowEx( HWND parent
, HWND child
, UNICODE_STRING
*class, UNICODE_STRING
*title
,
2758 int i
= 0, len
= 0, title_len
;
2759 WCHAR
*buffer
= NULL
;
2761 if (!parent
&& child
) parent
= get_desktop_window();
2762 else if (parent
== HWND_MESSAGE
) parent
= get_hwnd_message_parent();
2766 len
= title
->Length
/ sizeof(WCHAR
) + 1; /* one extra char to check for chars beyond the end */
2767 if (!(buffer
= malloc( (len
+ 1) * sizeof(WCHAR
) ))) return 0;
2770 if (!(list
= list_window_children( 0, parent
, class, 0 ))) goto done
;
2774 child
= get_full_window_handle( child
);
2775 while (list
[i
] && list
[i
] != child
) i
++;
2776 if (!list
[i
]) goto done
;
2777 i
++; /* start from next window */
2784 title_len
= NtUserInternalGetWindowText( list
[i
], buffer
, len
+ 1 );
2785 if (title_len
* sizeof(WCHAR
) == title
->Length
&&
2786 (!title_len
|| !wcsnicmp( buffer
, title
->Buffer
, title_len
)))
2799 /* Retrieve the window text from the server. */
2800 static data_size_t
get_server_window_text( HWND hwnd
, WCHAR
*text
, data_size_t count
)
2802 data_size_t len
= 0, needed
= 0;
2804 SERVER_START_REQ( get_window_text
)
2806 req
->handle
= wine_server_user_handle( hwnd
);
2807 if (count
) wine_server_set_reply( req
, text
, (count
- 1) * sizeof(WCHAR
) );
2808 if (!wine_server_call_err( req
))
2810 needed
= reply
->length
;
2811 len
= wine_server_reply_size(reply
);
2815 if (text
) text
[len
/ sizeof(WCHAR
)] = 0;
2819 /*******************************************************************
2820 * NtUserInternalGetWindowText (win32u.@)
2822 INT WINAPI
NtUserInternalGetWindowText( HWND hwnd
, WCHAR
*text
, INT count
)
2826 if (count
<= 0) return 0;
2827 if (!(win
= get_win_ptr( hwnd
))) return 0;
2828 if (win
== WND_DESKTOP
) text
[0] = 0;
2829 else if (win
!= WND_OTHER_PROCESS
)
2831 if (win
->text
) lstrcpynW( text
, win
->text
, count
);
2833 release_win_ptr( win
);
2837 get_server_window_text( hwnd
, text
, count
);
2839 return lstrlenW(text
);
2842 /*******************************************************************
2843 * get_windows_offset
2845 * Calculate the offset between the origin of the two windows. Used
2846 * to implement MapWindowPoints.
2848 static BOOL
get_windows_offset( HWND hwnd_from
, HWND hwnd_to
, UINT dpi
, BOOL
*mirrored
, POINT
*ret_offset
)
2852 BOOL mirror_from
, mirror_to
, ret
;
2855 offset
.x
= offset
.y
= 0;
2856 *mirrored
= mirror_from
= mirror_to
= FALSE
;
2858 /* Translate source window origin to screen coords */
2861 if (!(win
= get_win_ptr( hwnd_from
)))
2863 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
2866 if (win
== WND_OTHER_PROCESS
) goto other_process
;
2867 if (win
!= WND_DESKTOP
)
2869 UINT dpi_from
= dpi
? dpi
: get_win_monitor_dpi( hwnd_from
);
2870 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
)
2873 offset
.x
+= win
->client_rect
.right
- win
->client_rect
.left
;
2877 offset
.x
+= win
->client_rect
.left
;
2878 offset
.y
+= win
->client_rect
.top
;
2880 release_win_ptr( win
);
2881 if (!(win
= get_win_ptr( hwnd
))) break;
2882 if (win
== WND_OTHER_PROCESS
) goto other_process
;
2883 if (win
== WND_DESKTOP
) break;
2884 if (win
->flags
& WIN_CHILDREN_MOVED
)
2886 release_win_ptr( win
);
2890 if (win
&& win
!= WND_DESKTOP
) release_win_ptr( win
);
2891 offset
= map_dpi_point( offset
, get_dpi_for_window( hwnd_from
), dpi_from
);
2895 /* Translate origin to destination window coords */
2898 if (!(win
= get_win_ptr( hwnd_to
)))
2900 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
2903 if (win
== WND_OTHER_PROCESS
) goto other_process
;
2904 if (win
!= WND_DESKTOP
)
2906 UINT dpi_to
= dpi
? dpi
: get_win_monitor_dpi( hwnd_to
);
2907 POINT pt
= { 0, 0 };
2908 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
)
2911 pt
.x
+= win
->client_rect
.right
- win
->client_rect
.left
;
2915 pt
.x
+= win
->client_rect
.left
;
2916 pt
.y
+= win
->client_rect
.top
;
2918 release_win_ptr( win
);
2919 if (!(win
= get_win_ptr( hwnd
))) break;
2920 if (win
== WND_OTHER_PROCESS
) goto other_process
;
2921 if (win
== WND_DESKTOP
) break;
2922 if (win
->flags
& WIN_CHILDREN_MOVED
)
2924 release_win_ptr( win
);
2928 if (win
&& win
!= WND_DESKTOP
) release_win_ptr( win
);
2929 pt
= map_dpi_point( pt
, get_dpi_for_window( hwnd_to
), dpi_to
);
2935 *mirrored
= mirror_from
^ mirror_to
;
2936 if (mirror_from
) offset
.x
= -offset
.x
;
2937 *ret_offset
= offset
;
2940 other_process
: /* one of the parents may belong to another process, do it the hard way */
2941 SERVER_START_REQ( get_windows_offset
)
2943 req
->from
= wine_server_user_handle( hwnd_from
);
2944 req
->to
= wine_server_user_handle( hwnd_to
);
2946 if ((ret
= !wine_server_call_err( req
)))
2948 ret_offset
->x
= reply
->x
;
2949 ret_offset
->y
= reply
->y
;
2950 *mirrored
= reply
->mirror
;
2957 /* see ClientToScreen */
2958 BOOL
client_to_screen( HWND hwnd
, POINT
*pt
)
2965 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
2969 if (!get_windows_offset( hwnd
, 0, get_thread_dpi(), &mirrored
, &offset
)) return FALSE
;
2972 if (mirrored
) pt
->x
= -pt
->x
;
2976 /* see ScreenToClient */
2977 BOOL
screen_to_client( HWND hwnd
, POINT
*pt
)
2984 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
2987 if (!get_windows_offset( 0, hwnd
, get_thread_dpi(), &mirrored
, &offset
)) return FALSE
;
2990 if (mirrored
) pt
->x
= -pt
->x
;
2994 /* map coordinates of a window region */
2995 void map_window_region( HWND from
, HWND to
, HRGN hrgn
)
3004 if (!get_windows_offset( from
, to
, get_thread_dpi(), &mirrored
, &offset
)) return;
3008 NtGdiOffsetRgn( hrgn
, offset
.x
, offset
.y
);
3011 if (!(size
= NtGdiGetRegionData( hrgn
, 0, NULL
))) return;
3012 if (!(data
= malloc( size
))) return;
3013 NtGdiGetRegionData( hrgn
, size
, data
);
3014 rect
= (RECT
*)data
->Buffer
;
3015 for (i
= 0; i
< data
->rdh
.nCount
; i
++)
3017 int tmp
= -(rect
[i
].left
+ offset
.x
);
3018 rect
[i
].left
= -(rect
[i
].right
+ offset
.x
);
3019 rect
[i
].right
= tmp
;
3020 rect
[i
].top
+= offset
.y
;
3021 rect
[i
].bottom
+= offset
.y
;
3023 if ((new_rgn
= NtGdiExtCreateRegion( NULL
, data
->rdh
.dwSize
+ data
->rdh
.nRgnSize
, data
)))
3025 NtGdiCombineRgn( hrgn
, new_rgn
, 0, RGN_COPY
);
3026 NtGdiDeleteObjectApp( new_rgn
);
3031 /* see MapWindowPoints */
3032 int map_window_points( HWND hwnd_from
, HWND hwnd_to
, POINT
*points
, UINT count
, UINT dpi
)
3038 if (!get_windows_offset( hwnd_from
, hwnd_to
, dpi
, &mirrored
, &offset
)) return 0;
3040 for (i
= 0; i
< count
; i
++)
3042 points
[i
].x
+= offset
.x
;
3043 points
[i
].y
+= offset
.y
;
3044 if (mirrored
) points
[i
].x
= -points
[i
].x
;
3046 if (mirrored
&& count
== 2) /* special case for rectangle */
3048 int tmp
= points
[0].x
;
3049 points
[0].x
= points
[1].x
;
3052 return MAKELONG( LOWORD(offset
.x
), LOWORD(offset
.y
) );
3055 /***********************************************************************
3058 static void dump_winpos_flags( UINT flags
)
3060 static const UINT dumped_flags
= (SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOREDRAW
|
3061 SWP_NOACTIVATE
| SWP_FRAMECHANGED
| SWP_SHOWWINDOW
|
3062 SWP_HIDEWINDOW
| SWP_NOCOPYBITS
| SWP_NOOWNERZORDER
|
3063 SWP_NOSENDCHANGING
| SWP_DEFERERASE
| SWP_ASYNCWINDOWPOS
|
3064 SWP_NOCLIENTSIZE
| SWP_NOCLIENTMOVE
| SWP_STATECHANGED
);
3066 if(flags
& SWP_NOSIZE
) TRACE( " SWP_NOSIZE" );
3067 if(flags
& SWP_NOMOVE
) TRACE( " SWP_NOMOVE" );
3068 if(flags
& SWP_NOZORDER
) TRACE( " SWP_NOZORDER" );
3069 if(flags
& SWP_NOREDRAW
) TRACE( " SWP_NOREDRAW" );
3070 if(flags
& SWP_NOACTIVATE
) TRACE( " SWP_NOACTIVATE" );
3071 if(flags
& SWP_FRAMECHANGED
) TRACE( " SWP_FRAMECHANGED" );
3072 if(flags
& SWP_SHOWWINDOW
) TRACE( " SWP_SHOWWINDOW" );
3073 if(flags
& SWP_HIDEWINDOW
) TRACE( " SWP_HIDEWINDOW" );
3074 if(flags
& SWP_NOCOPYBITS
) TRACE( " SWP_NOCOPYBITS" );
3075 if(flags
& SWP_NOOWNERZORDER
) TRACE( " SWP_NOOWNERZORDER" );
3076 if(flags
& SWP_NOSENDCHANGING
) TRACE( " SWP_NOSENDCHANGING" );
3077 if(flags
& SWP_DEFERERASE
) TRACE( " SWP_DEFERERASE" );
3078 if(flags
& SWP_ASYNCWINDOWPOS
) TRACE( " SWP_ASYNCWINDOWPOS" );
3079 if(flags
& SWP_NOCLIENTSIZE
) TRACE( " SWP_NOCLIENTSIZE" );
3080 if(flags
& SWP_NOCLIENTMOVE
) TRACE( " SWP_NOCLIENTMOVE" );
3081 if(flags
& SWP_STATECHANGED
) TRACE( " SWP_STATECHANGED" );
3083 if(flags
& ~dumped_flags
) TRACE( " %08x", flags
& ~dumped_flags
);
3087 /***********************************************************************
3090 static void map_dpi_winpos( WINDOWPOS
*winpos
)
3092 UINT dpi_from
= get_thread_dpi();
3093 UINT dpi_to
= get_dpi_for_window( winpos
->hwnd
);
3095 if (!dpi_from
) dpi_from
= get_win_monitor_dpi( winpos
->hwnd
);
3096 if (dpi_from
== dpi_to
) return;
3097 winpos
->x
= muldiv( winpos
->x
, dpi_to
, dpi_from
);
3098 winpos
->y
= muldiv( winpos
->y
, dpi_to
, dpi_from
);
3099 winpos
->cx
= muldiv( winpos
->cx
, dpi_to
, dpi_from
);
3100 winpos
->cy
= muldiv( winpos
->cy
, dpi_to
, dpi_from
);
3103 /***********************************************************************
3106 static BOOL
calc_winpos( WINDOWPOS
*winpos
, RECT
*old_window_rect
, RECT
*old_client_rect
,
3107 RECT
*new_window_rect
, RECT
*new_client_rect
)
3111 /* Send WM_WINDOWPOSCHANGING message */
3112 if (!(winpos
->flags
& SWP_NOSENDCHANGING
)
3113 && !((winpos
->flags
& SWP_AGG_NOCLIENTCHANGE
) && (winpos
->flags
& SWP_SHOWWINDOW
)))
3114 send_message( winpos
->hwnd
, WM_WINDOWPOSCHANGING
, 0, (LPARAM
)winpos
);
3116 if (!(win
= get_win_ptr( winpos
->hwnd
)) ||
3117 win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
3119 /* Calculate new position and size */
3120 get_window_rects( winpos
->hwnd
, COORDS_PARENT
, old_window_rect
, old_client_rect
, get_thread_dpi() );
3121 *new_window_rect
= *old_window_rect
;
3122 *new_client_rect
= *old_client_rect
;
3124 if (!(winpos
->flags
& SWP_NOSIZE
))
3126 if (win
->dwStyle
& WS_MINIMIZE
)
3128 new_window_rect
->right
= new_window_rect
->left
+ get_system_metrics( SM_CXMINIMIZED
);
3129 new_window_rect
->bottom
= new_window_rect
->top
+ get_system_metrics( SM_CYMINIMIZED
);
3133 new_window_rect
->right
= new_window_rect
->left
+ winpos
->cx
;
3134 new_window_rect
->bottom
= new_window_rect
->top
+ winpos
->cy
;
3138 if (!(winpos
->flags
& SWP_NOMOVE
))
3140 /* If the window is toplevel minimized off-screen, force keep it there */
3141 if ((win
->dwStyle
& WS_MINIMIZE
) &&
3142 win
->window_rect
.left
<= -32000 && win
->window_rect
.top
<= -32000 &&
3143 (!win
->parent
|| win
->parent
== get_desktop_window()))
3148 new_window_rect
->left
= winpos
->x
;
3149 new_window_rect
->top
= winpos
->y
;
3150 new_window_rect
->right
+= winpos
->x
- old_window_rect
->left
;
3151 new_window_rect
->bottom
+= winpos
->y
- old_window_rect
->top
;
3153 OffsetRect( new_client_rect
, winpos
->x
- old_window_rect
->left
,
3154 winpos
->y
- old_window_rect
->top
);
3156 winpos
->flags
|= SWP_NOCLIENTMOVE
| SWP_NOCLIENTSIZE
;
3158 TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x current %s style %08x new %s\n",
3159 winpos
->hwnd
, winpos
->hwndInsertAfter
, winpos
->x
, winpos
->y
,
3160 winpos
->cx
, winpos
->cy
, winpos
->flags
,
3161 wine_dbgstr_rect( old_window_rect
), win
->dwStyle
,
3162 wine_dbgstr_rect( new_window_rect
));
3164 release_win_ptr( win
);
3168 /***********************************************************************
3171 * Compute the valid rects from the old and new client rect and WVR_* flags.
3172 * Helper for WM_NCCALCSIZE handling.
3174 static inline void get_valid_rects( const RECT
*old_client
, const RECT
*new_client
, UINT flags
,
3179 if (flags
& WVR_REDRAW
)
3181 SetRectEmpty( &valid
[0] );
3182 SetRectEmpty( &valid
[1] );
3186 if (flags
& WVR_VALIDRECTS
)
3188 if (!intersect_rect( &valid
[0], &valid
[0], new_client
) ||
3189 !intersect_rect( &valid
[1], &valid
[1], old_client
))
3191 SetRectEmpty( &valid
[0] );
3192 SetRectEmpty( &valid
[1] );
3195 flags
= WVR_ALIGNLEFT
| WVR_ALIGNTOP
;
3199 valid
[0] = *new_client
;
3200 valid
[1] = *old_client
;
3203 /* make sure the rectangles have the same size */
3204 cx
= min( valid
[0].right
- valid
[0].left
, valid
[1].right
- valid
[1].left
);
3205 cy
= min( valid
[0].bottom
- valid
[0].top
, valid
[1].bottom
- valid
[1].top
);
3207 if (flags
& WVR_ALIGNBOTTOM
)
3209 valid
[0].top
= valid
[0].bottom
- cy
;
3210 valid
[1].top
= valid
[1].bottom
- cy
;
3214 valid
[0].bottom
= valid
[0].top
+ cy
;
3215 valid
[1].bottom
= valid
[1].top
+ cy
;
3217 if (flags
& WVR_ALIGNRIGHT
)
3219 valid
[0].left
= valid
[0].right
- cx
;
3220 valid
[1].left
= valid
[1].right
- cx
;
3224 valid
[0].right
= valid
[0].left
+ cx
;
3225 valid
[1].right
= valid
[1].left
+ cx
;
3229 static UINT
calc_ncsize( WINDOWPOS
*winpos
, const RECT
*old_window_rect
, const RECT
*old_client_rect
,
3230 const RECT
*new_window_rect
, RECT
*new_client_rect
, RECT
*valid_rects
,
3231 int parent_x
, int parent_y
)
3235 /* Send WM_NCCALCSIZE message to get new client area */
3236 if ((winpos
->flags
& (SWP_FRAMECHANGED
| SWP_NOSIZE
)) != SWP_NOSIZE
)
3238 NCCALCSIZE_PARAMS params
;
3239 WINDOWPOS winposCopy
;
3242 params
.rgrc
[0] = *new_window_rect
;
3243 params
.rgrc
[1] = *old_window_rect
;
3244 params
.rgrc
[2] = *old_client_rect
;
3245 params
.lppos
= &winposCopy
;
3246 winposCopy
= *winpos
;
3248 if (winpos
->flags
& SWP_NOMOVE
)
3250 winposCopy
.x
= old_window_rect
->left
;
3251 winposCopy
.y
= old_window_rect
->top
;
3254 if (winpos
->flags
& SWP_NOSIZE
)
3256 winposCopy
.cx
= old_window_rect
->right
- old_window_rect
->left
;
3257 winposCopy
.cy
= old_window_rect
->bottom
- old_window_rect
->top
;
3260 class_style
= get_class_long( winpos
->hwnd
, GCL_STYLE
, FALSE
);
3261 if (class_style
& CS_VREDRAW
) wvr_flags
|= WVR_VREDRAW
;
3262 if (class_style
& CS_HREDRAW
) wvr_flags
|= WVR_HREDRAW
;
3264 wvr_flags
|= send_message( winpos
->hwnd
, WM_NCCALCSIZE
, TRUE
, (LPARAM
)¶ms
);
3266 *new_client_rect
= params
.rgrc
[0];
3268 TRACE( "hwnd %p old win %s old client %s new win %s new client %s\n", winpos
->hwnd
,
3269 wine_dbgstr_rect(old_window_rect
), wine_dbgstr_rect(old_client_rect
),
3270 wine_dbgstr_rect(new_window_rect
), wine_dbgstr_rect(new_client_rect
) );
3272 if (new_client_rect
->left
!= old_client_rect
->left
- parent_x
||
3273 new_client_rect
->top
!= old_client_rect
->top
- parent_y
)
3274 winpos
->flags
&= ~SWP_NOCLIENTMOVE
;
3276 if ((new_client_rect
->right
- new_client_rect
->left
!=
3277 old_client_rect
->right
- old_client_rect
->left
))
3278 winpos
->flags
&= ~SWP_NOCLIENTSIZE
;
3280 wvr_flags
&= ~WVR_HREDRAW
;
3282 if (new_client_rect
->bottom
- new_client_rect
->top
!=
3283 old_client_rect
->bottom
- old_client_rect
->top
)
3284 winpos
->flags
&= ~SWP_NOCLIENTSIZE
;
3286 wvr_flags
&= ~WVR_VREDRAW
;
3288 valid_rects
[0] = params
.rgrc
[1];
3289 valid_rects
[1] = params
.rgrc
[2];
3293 if (!(winpos
->flags
& SWP_NOMOVE
) &&
3294 (new_client_rect
->left
!= old_client_rect
->left
- parent_x
||
3295 new_client_rect
->top
!= old_client_rect
->top
- parent_y
))
3296 winpos
->flags
&= ~SWP_NOCLIENTMOVE
;
3299 if (winpos
->flags
& (SWP_NOCOPYBITS
| SWP_NOREDRAW
| SWP_SHOWWINDOW
| SWP_HIDEWINDOW
))
3301 SetRectEmpty( &valid_rects
[0] );
3302 SetRectEmpty( &valid_rects
[1] );
3304 else get_valid_rects( old_client_rect
, new_client_rect
, wvr_flags
, valid_rects
);
3309 /* fix redundant flags and values in the WINDOWPOS structure */
3310 static BOOL
fixup_swp_flags( WINDOWPOS
*winpos
, const RECT
*old_window_rect
, int parent_x
, int parent_y
)
3313 WND
*win
= get_win_ptr( winpos
->hwnd
);
3316 if (!win
|| win
== WND_OTHER_PROCESS
)
3318 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
3321 winpos
->hwnd
= win
->obj
.handle
; /* make it a full handle */
3323 /* Finally make sure that all coordinates are valid */
3324 if (winpos
->x
< -32768) winpos
->x
= -32768;
3325 else if (winpos
->x
> 32767) winpos
->x
= 32767;
3326 if (winpos
->y
< -32768) winpos
->y
= -32768;
3327 else if (winpos
->y
> 32767) winpos
->y
= 32767;
3329 if (winpos
->cx
< 0) winpos
->cx
= 0;
3330 else if (winpos
->cx
> 32767) winpos
->cx
= 32767;
3331 if (winpos
->cy
< 0) winpos
->cy
= 0;
3332 else if (winpos
->cy
> 32767) winpos
->cy
= 32767;
3334 parent
= NtUserGetAncestor( winpos
->hwnd
, GA_PARENT
);
3335 if (!is_window_visible( parent
)) winpos
->flags
|= SWP_NOREDRAW
;
3337 if (win
->dwStyle
& WS_VISIBLE
) winpos
->flags
&= ~SWP_SHOWWINDOW
;
3340 winpos
->flags
&= ~SWP_HIDEWINDOW
;
3341 if (!(winpos
->flags
& SWP_SHOWWINDOW
)) winpos
->flags
|= SWP_NOREDRAW
;
3344 if ((old_window_rect
->right
- old_window_rect
->left
== winpos
->cx
) &&
3345 (old_window_rect
->bottom
- old_window_rect
->top
== winpos
->cy
))
3346 winpos
->flags
|= SWP_NOSIZE
; /* Already the right size */
3348 if ((old_window_rect
->left
- parent_x
== winpos
->x
) && (old_window_rect
->top
- parent_y
== winpos
->y
))
3349 winpos
->flags
|= SWP_NOMOVE
; /* Already the right position */
3351 if ((win
->dwStyle
& (WS_POPUP
| WS_CHILD
)) != WS_CHILD
)
3353 if (!(winpos
->flags
& (SWP_NOACTIVATE
|SWP_HIDEWINDOW
)) && /* Bring to the top when activating */
3354 (winpos
->flags
& SWP_NOZORDER
||
3355 (winpos
->hwndInsertAfter
!= HWND_TOPMOST
&& winpos
->hwndInsertAfter
!= HWND_NOTOPMOST
)))
3357 winpos
->flags
&= ~SWP_NOZORDER
;
3358 winpos
->hwndInsertAfter
= HWND_TOP
;
3362 /* Check hwndInsertAfter */
3363 if (winpos
->flags
& SWP_NOZORDER
) goto done
;
3365 if (winpos
->hwndInsertAfter
== HWND_TOP
)
3367 if (get_window_relative( winpos
->hwnd
, GW_HWNDFIRST
) == winpos
->hwnd
)
3368 winpos
->flags
|= SWP_NOZORDER
;
3370 else if (winpos
->hwndInsertAfter
== HWND_BOTTOM
)
3372 if (!(win
->dwExStyle
& WS_EX_TOPMOST
) &&
3373 get_window_relative( winpos
->hwnd
, GW_HWNDLAST
) == winpos
->hwnd
)
3374 winpos
->flags
|= SWP_NOZORDER
;
3376 else if (winpos
->hwndInsertAfter
== HWND_TOPMOST
)
3378 if ((win
->dwExStyle
& WS_EX_TOPMOST
) &&
3379 get_window_relative( winpos
->hwnd
, GW_HWNDFIRST
) == winpos
->hwnd
)
3380 winpos
->flags
|= SWP_NOZORDER
;
3382 else if (winpos
->hwndInsertAfter
== HWND_NOTOPMOST
)
3384 if (!(win
->dwExStyle
& WS_EX_TOPMOST
))
3385 winpos
->flags
|= SWP_NOZORDER
;
3389 if ((winpos
->hwnd
== winpos
->hwndInsertAfter
) ||
3390 (winpos
->hwnd
== get_window_relative( winpos
->hwndInsertAfter
, GW_HWNDNEXT
)))
3391 winpos
->flags
|= SWP_NOZORDER
;
3394 release_win_ptr( win
);
3398 /***********************************************************************
3401 * fix Z order taking into account owned popups -
3402 * basically we need to maintain them above the window that owns them
3404 * FIXME: hide/show owned popups when owner visibility changes.
3406 static HWND
swp_owner_popups( HWND hwnd
, HWND after
)
3408 HWND owner
, *list
= NULL
;
3411 TRACE( "(%p) after = %p\n", hwnd
, after
);
3413 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) return after
;
3415 if ((owner
= get_window_relative( hwnd
, GW_OWNER
)))
3417 /* make sure this popup stays above the owner */
3419 if (after
!= HWND_TOPMOST
)
3421 if (!(list
= list_window_children( 0, get_desktop_window(), NULL
, 0 ))) return after
;
3423 for (i
= 0; list
[i
]; i
++)
3425 BOOL topmost
= (get_window_long( list
[i
], GWL_EXSTYLE
) & WS_EX_TOPMOST
) != 0;
3427 if (list
[i
] == owner
)
3429 if (i
> 0) after
= list
[i
-1];
3430 else after
= topmost
? HWND_TOPMOST
: HWND_TOP
;
3434 if (after
== HWND_TOP
|| after
== HWND_NOTOPMOST
)
3436 if (!topmost
) break;
3438 else if (list
[i
] == after
) break;
3443 if (after
== HWND_BOTTOM
) goto done
;
3444 if (!list
&& !(list
= list_window_children( 0, get_desktop_window(), NULL
, 0 ))) goto done
;
3447 if (after
== HWND_TOP
|| after
== HWND_NOTOPMOST
)
3449 if (after
== HWND_NOTOPMOST
||
3450 !(get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_TOPMOST
))
3452 /* skip all the topmost windows */
3453 while (list
[i
] && (get_window_long( list
[i
], GWL_EXSTYLE
) & WS_EX_TOPMOST
)) i
++;
3456 else if (after
!= HWND_TOPMOST
)
3458 /* skip windows that are already placed correctly */
3459 for (i
= 0; list
[i
]; i
++)
3461 if (list
[i
] == after
) break;
3462 if (list
[i
] == hwnd
) goto done
; /* nothing to do if window is moving backwards in z-order */
3466 for ( ; list
[i
]; i
++)
3468 if (list
[i
] == hwnd
) break;
3469 if (get_window_relative( list
[i
], GW_OWNER
) != hwnd
) continue;
3470 TRACE( "moving %p owned by %p after %p\n", list
[i
], hwnd
, after
);
3471 NtUserSetWindowPos( list
[i
], after
, 0, 0, 0, 0,
3472 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOSENDCHANGING
| SWP_DEFERERASE
);
3481 /* NtUserSetWindowPos implementation */
3482 BOOL
set_window_pos( WINDOWPOS
*winpos
, int parent_x
, int parent_y
)
3484 RECT old_window_rect
, old_client_rect
, new_window_rect
, new_client_rect
, valid_rects
[2], visible_rect
, surface_rect
;
3485 struct window_surface
*surface
;
3486 UINT orig_flags
, context
;
3489 orig_flags
= winpos
->flags
;
3491 /* First, check z-order arguments. */
3492 if (!(winpos
->flags
& SWP_NOZORDER
))
3494 /* fix sign extension */
3495 if (winpos
->hwndInsertAfter
== (HWND
)0xffff) winpos
->hwndInsertAfter
= HWND_TOPMOST
;
3496 else if (winpos
->hwndInsertAfter
== (HWND
)0xfffe) winpos
->hwndInsertAfter
= HWND_NOTOPMOST
;
3498 if (!(winpos
->hwndInsertAfter
== HWND_TOP
||
3499 winpos
->hwndInsertAfter
== HWND_BOTTOM
||
3500 winpos
->hwndInsertAfter
== HWND_TOPMOST
||
3501 winpos
->hwndInsertAfter
== HWND_NOTOPMOST
))
3503 HWND parent
= NtUserGetAncestor( winpos
->hwnd
, GA_PARENT
);
3504 HWND insertafter_parent
= NtUserGetAncestor( winpos
->hwndInsertAfter
, GA_PARENT
);
3506 /* hwndInsertAfter must be a sibling of the window */
3507 if (!insertafter_parent
) return FALSE
;
3508 if (insertafter_parent
!= parent
) return TRUE
;
3512 /* Make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
3513 if (!(winpos
->flags
& SWP_NOMOVE
))
3515 if (winpos
->x
< -32768) winpos
->x
= -32768;
3516 else if (winpos
->x
> 32767) winpos
->x
= 32767;
3517 if (winpos
->y
< -32768) winpos
->y
= -32768;
3518 else if (winpos
->y
> 32767) winpos
->y
= 32767;
3520 if (!(winpos
->flags
& SWP_NOSIZE
))
3522 if (winpos
->cx
< 0) winpos
->cx
= 0;
3523 else if (winpos
->cx
> 32767) winpos
->cx
= 32767;
3524 if (winpos
->cy
< 0) winpos
->cy
= 0;
3525 else if (winpos
->cy
> 32767) winpos
->cy
= 32767;
3528 context
= set_thread_dpi_awareness_context( get_window_dpi_awareness_context( winpos
->hwnd
));
3530 if (!calc_winpos( winpos
, &old_window_rect
, &old_client_rect
,
3531 &new_window_rect
, &new_client_rect
)) goto done
;
3533 /* Fix redundant flags */
3534 if (!fixup_swp_flags( winpos
, &old_window_rect
, parent_x
, parent_y
)) goto done
;
3536 if((winpos
->flags
& (SWP_NOZORDER
| SWP_HIDEWINDOW
| SWP_SHOWWINDOW
)) != SWP_NOZORDER
)
3538 if (NtUserGetAncestor( winpos
->hwnd
, GA_PARENT
) == get_desktop_window())
3539 winpos
->hwndInsertAfter
= swp_owner_popups( winpos
->hwnd
, winpos
->hwndInsertAfter
);
3542 /* Common operations */
3544 calc_ncsize( winpos
, &old_window_rect
, &old_client_rect
,
3545 &new_window_rect
, &new_client_rect
, valid_rects
, parent_x
, parent_y
);
3547 surface
= create_window_surface( winpos
->hwnd
, winpos
->flags
, FALSE
, &new_window_rect
, &new_client_rect
,
3548 &visible_rect
, &surface_rect
);
3549 if (!apply_window_pos( winpos
->hwnd
, winpos
->hwndInsertAfter
, winpos
->flags
, surface
,
3550 &new_window_rect
, &new_client_rect
, &visible_rect
, valid_rects
))
3552 if (surface
) window_surface_release( surface
);
3555 if (surface
) window_surface_release( surface
);
3557 if (winpos
->flags
& SWP_HIDEWINDOW
)
3559 NtUserNotifyWinEvent( EVENT_OBJECT_HIDE
, winpos
->hwnd
, 0, 0 );
3561 NtUserHideCaret( winpos
->hwnd
);
3563 else if (winpos
->flags
& SWP_SHOWWINDOW
)
3565 NtUserNotifyWinEvent( EVENT_OBJECT_SHOW
, winpos
->hwnd
, 0, 0 );
3567 NtUserShowCaret( winpos
->hwnd
);
3570 if (!(winpos
->flags
& (SWP_NOACTIVATE
|SWP_HIDEWINDOW
)))
3572 /* child windows get WM_CHILDACTIVATE message */
3573 if ((get_window_long( winpos
->hwnd
, GWL_STYLE
) & (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
3574 send_message( winpos
->hwnd
, WM_CHILDACTIVATE
, 0, 0 );
3576 set_foreground_window( winpos
->hwnd
, FALSE
);
3579 if(!(orig_flags
& SWP_DEFERERASE
))
3581 /* erase parent when hiding or resizing child */
3582 if ((orig_flags
& SWP_HIDEWINDOW
) ||
3583 (!(orig_flags
& SWP_SHOWWINDOW
) &&
3584 (winpos
->flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOGEOMETRYCHANGE
))
3586 HWND parent
= NtUserGetAncestor( winpos
->hwnd
, GA_PARENT
);
3587 if (!parent
|| parent
== get_desktop_window()) parent
= winpos
->hwnd
;
3588 erase_now( parent
, 0 );
3591 /* Give newly shown windows a chance to redraw */
3592 if(((winpos
->flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOPOSCHANGE
)
3593 && !(orig_flags
& SWP_AGG_NOCLIENTCHANGE
) && (orig_flags
& SWP_SHOWWINDOW
))
3595 erase_now(winpos
->hwnd
, 0);
3599 /* And last, send the WM_WINDOWPOSCHANGED message */
3601 TRACE( "\tstatus flags = %04x\n", winpos
->flags
& SWP_AGG_STATUSFLAGS
);
3603 if (((winpos
->flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOPOSCHANGE
)
3604 && !((orig_flags
& SWP_AGG_NOCLIENTCHANGE
) && (orig_flags
& SWP_SHOWWINDOW
)))
3606 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
3607 and always contains final window position.
3609 winpos
->x
= new_window_rect
.left
;
3610 winpos
->y
= new_window_rect
.top
;
3611 winpos
->cx
= new_window_rect
.right
- new_window_rect
.left
;
3612 winpos
->cy
= new_window_rect
.bottom
- new_window_rect
.top
;
3613 send_message( winpos
->hwnd
, WM_WINDOWPOSCHANGED
, 0, (LPARAM
)winpos
);
3616 if ((winpos
->flags
& (SWP_NOSIZE
|SWP_NOMOVE
|SWP_FRAMECHANGED
)) != (SWP_NOSIZE
|SWP_NOMOVE
))
3617 NtUserNotifyWinEvent( EVENT_OBJECT_LOCATIONCHANGE
, winpos
->hwnd
, OBJID_WINDOW
, 0 );
3621 set_thread_dpi_awareness_context( context
);
3625 /*******************************************************************
3626 * NtUserSetWindowPos (win32u.@)
3628 BOOL WINAPI
NtUserSetWindowPos( HWND hwnd
, HWND after
, INT x
, INT y
, INT cx
, INT cy
, UINT flags
)
3632 TRACE( "hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n", hwnd
, after
, x
, y
, cx
, cy
, flags
);
3633 if(TRACE_ON(win
)) dump_winpos_flags(flags
);
3635 if (is_broadcast( hwnd
))
3637 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
3641 winpos
.hwnd
= get_full_window_handle( hwnd
);
3642 winpos
.hwndInsertAfter
= get_full_window_handle( after
);
3647 winpos
.flags
= flags
;
3649 map_dpi_winpos( &winpos
);
3651 if (is_current_thread_window( hwnd
))
3652 return set_window_pos( &winpos
, 0, 0 );
3654 if (flags
& SWP_ASYNCWINDOWPOS
)
3655 return NtUserMessageCall( winpos
.hwnd
, WM_WINE_SETWINDOWPOS
, 0, (LPARAM
)&winpos
,
3656 0, NtUserSendNotifyMessage
, FALSE
);
3658 return send_message( winpos
.hwnd
, WM_WINE_SETWINDOWPOS
, 0, (LPARAM
)&winpos
);
3663 struct user_object obj
;
3665 INT suggested_count
;
3670 /* see BeginDeferWindowPos */
3671 HDWP
begin_defer_window_pos( INT count
)
3676 TRACE( "%d\n", count
);
3680 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
3683 /* Windows allows zero count, in which case it allocates context for 8 moves */
3684 if (count
== 0) count
= 8;
3686 if (!(dwp
= malloc( sizeof(DWP
) ))) return 0;
3690 dwp
->suggested_count
= count
;
3692 if (!(dwp
->winpos
= malloc( count
* sizeof(WINDOWPOS
) )) ||
3693 !(handle
= alloc_user_handle( &dwp
->obj
, NTUSER_OBJ_WINPOS
)))
3695 free( dwp
->winpos
);
3699 TRACE( "returning %p\n", handle
);
3703 /***********************************************************************
3704 * NtUserDeferWindowPosAndBand (win32u.@)
3706 HDWP WINAPI
NtUserDeferWindowPosAndBand( HDWP hdwp
, HWND hwnd
, HWND after
,
3707 INT x
, INT y
, INT cx
, INT cy
,
3708 UINT flags
, UINT unk1
, UINT unk2
)
3710 HDWP retvalue
= hdwp
;
3715 TRACE( "hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
3716 hdwp
, hwnd
, after
, x
, y
, cx
, cy
, flags
);
3718 winpos
.hwnd
= get_full_window_handle( hwnd
);
3719 if (is_desktop_window( winpos
.hwnd
) || !is_window( winpos
.hwnd
))
3721 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
3725 winpos
.hwndInsertAfter
= get_full_window_handle( after
);
3726 winpos
.flags
= flags
;
3731 map_dpi_winpos( &winpos
);
3733 if (!(dwp
= get_user_handle_ptr( hdwp
, NTUSER_OBJ_WINPOS
))) return 0;
3734 if (dwp
== OBJ_OTHER_PROCESS
)
3736 FIXME( "other process handle %p\n", hdwp
);
3740 for (i
= 0; i
< dwp
->count
; i
++)
3742 if (dwp
->winpos
[i
].hwnd
== winpos
.hwnd
)
3744 /* Merge with the other changes */
3745 if (!(flags
& SWP_NOZORDER
))
3747 dwp
->winpos
[i
].hwndInsertAfter
= winpos
.hwndInsertAfter
;
3749 if (!(flags
& SWP_NOMOVE
))
3751 dwp
->winpos
[i
].x
= winpos
.x
;
3752 dwp
->winpos
[i
].y
= winpos
.y
;
3754 if (!(flags
& SWP_NOSIZE
))
3756 dwp
->winpos
[i
].cx
= winpos
.cx
;
3757 dwp
->winpos
[i
].cy
= winpos
.cy
;
3759 dwp
->winpos
[i
].flags
&= flags
| ~(SWP_NOSIZE
| SWP_NOMOVE
|
3760 SWP_NOZORDER
| SWP_NOREDRAW
|
3761 SWP_NOACTIVATE
| SWP_NOCOPYBITS
|
3763 dwp
->winpos
[i
].flags
|= flags
& (SWP_SHOWWINDOW
| SWP_HIDEWINDOW
|
3768 if (dwp
->count
>= dwp
->suggested_count
)
3770 WINDOWPOS
*newpos
= realloc( dwp
->winpos
, dwp
->suggested_count
* 2 * sizeof(WINDOWPOS
) );
3776 dwp
->suggested_count
*= 2;
3777 dwp
->winpos
= newpos
;
3779 dwp
->winpos
[dwp
->count
++] = winpos
;
3781 release_user_handle_ptr( dwp
);
3785 /***********************************************************************
3786 * NtUserEndDeferWindowPosEx (win32u.@)
3788 BOOL WINAPI
NtUserEndDeferWindowPosEx( HDWP hdwp
, BOOL async
)
3794 TRACE( "%p\n", hdwp
);
3796 if (async
) FIXME( "async not supported\n" );
3798 if (!(dwp
= free_user_handle( hdwp
, NTUSER_OBJ_WINPOS
))) return FALSE
;
3799 if (dwp
== OBJ_OTHER_PROCESS
)
3801 FIXME( "other process handle %p\n", hdwp
);
3805 for (i
= 0, winpos
= dwp
->winpos
; i
< dwp
->count
; i
++, winpos
++)
3807 TRACE( "hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
3808 winpos
->hwnd
, winpos
->hwndInsertAfter
, winpos
->x
, winpos
->y
,
3809 winpos
->cx
, winpos
->cy
, winpos
->flags
);
3811 if (is_current_thread_window( winpos
->hwnd
))
3812 set_window_pos( winpos
, 0, 0 );
3814 send_message( winpos
->hwnd
, WM_WINE_SETWINDOWPOS
, 0, (LPARAM
)winpos
);
3816 free( dwp
->winpos
);
3821 /***********************************************************************
3822 * NtUserSetInternalWindowPos (win32u.@)
3824 void WINAPI
NtUserSetInternalWindowPos( HWND hwnd
, UINT cmd
, RECT
*rect
, POINT
*pt
)
3826 WINDOWPLACEMENT wndpl
;
3829 wndpl
.length
= sizeof(wndpl
);
3830 wndpl
.showCmd
= cmd
;
3831 wndpl
.flags
= flags
= 0;
3836 wndpl
.flags
|= WPF_SETMINPOSITION
;
3837 wndpl
.ptMinPosition
= *pt
;
3841 flags
|= PLACE_RECT
;
3842 wndpl
.rcNormalPosition
= *rect
;
3844 set_window_placement( hwnd
, &wndpl
, flags
);
3847 /***********************************************************************
3850 * Set the flags of a window and return the previous value.
3852 UINT
win_set_flags( HWND hwnd
, UINT set_mask
, UINT clear_mask
)
3854 WND
*win
= get_win_ptr( hwnd
);
3857 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return 0;
3859 win
->flags
= (ret
& ~clear_mask
) | set_mask
;
3860 release_win_ptr( win
);
3864 /*******************************************************************
3865 * can_activate_window
3867 * Check if we can activate the specified window.
3869 static BOOL
can_activate_window( HWND hwnd
)
3873 if (!hwnd
) return FALSE
;
3874 style
= get_window_long( hwnd
, GWL_STYLE
);
3875 if (!(style
& WS_VISIBLE
)) return FALSE
;
3876 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
3877 return !(style
& WS_DISABLED
);
3880 /*******************************************************************
3881 * activate_other_window
3883 * Activates window other than hwnd.
3885 static void activate_other_window( HWND hwnd
)
3889 if ((get_window_long( hwnd
, GWL_STYLE
) & WS_POPUP
) &&
3890 (hwnd_to
= get_window_relative( hwnd
, GW_OWNER
)))
3892 hwnd_to
= NtUserGetAncestor( hwnd_to
, GA_ROOT
);
3893 if (can_activate_window( hwnd_to
)) goto done
;
3899 if (!(hwnd_to
= get_window_relative( hwnd_to
, GW_HWNDNEXT
))) break;
3900 if (can_activate_window( hwnd_to
)) goto done
;
3903 hwnd_to
= get_window_relative( get_desktop_window(), GW_CHILD
);
3906 if (hwnd_to
== hwnd
)
3911 if (can_activate_window( hwnd_to
)) goto done
;
3912 if (!(hwnd_to
= get_window_relative( hwnd_to
, GW_HWNDNEXT
))) break;
3916 fg
= NtUserGetForegroundWindow();
3917 TRACE( "win = %p fg = %p\n", hwnd_to
, fg
);
3918 if (!fg
|| hwnd
== fg
)
3920 if (set_foreground_window( hwnd_to
, FALSE
)) return;
3922 if (NtUserSetActiveWindow( hwnd_to
)) NtUserSetActiveWindow( 0 );
3925 /*******************************************************************
3926 * send_parent_notify
3928 static void send_parent_notify( HWND hwnd
, UINT msg
)
3930 if ((get_window_long( hwnd
, GWL_STYLE
) & (WS_CHILD
| WS_POPUP
)) == WS_CHILD
&&
3931 !(get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_NOPARENTNOTIFY
))
3933 HWND parent
= get_parent( hwnd
);
3934 if (parent
&& parent
!= get_desktop_window())
3935 send_message( parent
, WM_PARENTNOTIFY
,
3936 MAKEWPARAM( msg
, get_window_long( hwnd
, GWLP_ID
)), (LPARAM
)hwnd
);
3940 /*******************************************************************
3943 * Get the minimized and maximized information for a window.
3945 MINMAXINFO
get_min_max_info( HWND hwnd
)
3947 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
3948 LONG exstyle
= get_window_long( hwnd
, GWL_EXSTYLE
);
3950 RECT rc_work
, rc_primary
;
3951 LONG adjusted_style
;
3957 context
= set_thread_dpi_awareness_context( get_window_dpi_awareness_context( hwnd
));
3959 /* Compute default values */
3961 get_window_rect( hwnd
, &rc
, get_thread_dpi() );
3962 minmax
.ptReserved
.x
= rc
.left
;
3963 minmax
.ptReserved
.y
= rc
.top
;
3965 if ((style
& WS_CAPTION
) == WS_CAPTION
)
3966 adjusted_style
= style
& ~WS_BORDER
; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
3968 adjusted_style
= style
;
3970 get_client_rect( NtUserGetAncestor( hwnd
, GA_PARENT
), &rc
, get_thread_dpi() );
3971 adjust_window_rect( &rc
, adjusted_style
, (style
& WS_POPUP
) && get_menu( hwnd
), exstyle
, get_system_dpi() );
3976 minmax
.ptMaxSize
.x
= rc
.right
- rc
.left
;
3977 minmax
.ptMaxSize
.y
= rc
.bottom
- rc
.top
;
3978 if (style
& (WS_DLGFRAME
| WS_BORDER
))
3980 minmax
.ptMinTrackSize
.x
= get_system_metrics( SM_CXMINTRACK
);
3981 minmax
.ptMinTrackSize
.y
= get_system_metrics( SM_CYMINTRACK
);
3985 minmax
.ptMinTrackSize
.x
= 2 * xinc
;
3986 minmax
.ptMinTrackSize
.y
= 2 * yinc
;
3988 minmax
.ptMaxTrackSize
.x
= get_system_metrics( SM_CXMAXTRACK
);
3989 minmax
.ptMaxTrackSize
.y
= get_system_metrics( SM_CYMAXTRACK
);
3990 minmax
.ptMaxPosition
.x
= -xinc
;
3991 minmax
.ptMaxPosition
.y
= -yinc
;
3993 if ((win
= get_win_ptr( hwnd
)) && win
!= WND_DESKTOP
&& win
!= WND_OTHER_PROCESS
)
3995 if (!empty_point( win
->max_pos
)) minmax
.ptMaxPosition
= win
->max_pos
;
3996 release_win_ptr( win
);
3999 send_message( hwnd
, WM_GETMINMAXINFO
, 0, (LPARAM
)&minmax
);
4001 /* if the app didn't change the values, adapt them for the current monitor */
4003 if (get_work_rect( hwnd
, &rc_work
))
4005 rc_primary
= get_primary_monitor_rect( get_thread_dpi() );
4006 if (minmax
.ptMaxSize
.x
== (rc_primary
.right
- rc_primary
.left
) + 2 * xinc
&&
4007 minmax
.ptMaxSize
.y
== (rc_primary
.bottom
- rc_primary
.top
) + 2 * yinc
)
4009 minmax
.ptMaxSize
.x
= (rc_work
.right
- rc_work
.left
) + 2 * xinc
;
4010 minmax
.ptMaxSize
.y
= (rc_work
.bottom
- rc_work
.top
) + 2 * yinc
;
4012 if (minmax
.ptMaxPosition
.x
== -xinc
&& minmax
.ptMaxPosition
.y
== -yinc
)
4014 minmax
.ptMaxPosition
.x
= rc_work
.left
- xinc
;
4015 minmax
.ptMaxPosition
.y
= rc_work
.top
- yinc
;
4019 TRACE( "%d %d / %d %d / %d %d / %d %d\n",
4020 (int)minmax
.ptMaxSize
.x
, (int)minmax
.ptMaxSize
.y
,
4021 (int)minmax
.ptMaxPosition
.x
, (int)minmax
.ptMaxPosition
.y
,
4022 (int)minmax
.ptMaxTrackSize
.x
, (int)minmax
.ptMaxTrackSize
.y
,
4023 (int)minmax
.ptMinTrackSize
.x
, (int)minmax
.ptMinTrackSize
.y
);
4025 minmax
.ptMaxTrackSize
.x
= max( minmax
.ptMaxTrackSize
.x
, minmax
.ptMinTrackSize
.x
);
4026 minmax
.ptMaxTrackSize
.y
= max( minmax
.ptMaxTrackSize
.y
, minmax
.ptMinTrackSize
.y
);
4028 set_thread_dpi_awareness_context( context
);
4032 static POINT
get_first_minimized_child_pos( const RECT
*parent
, const MINIMIZEDMETRICS
*mm
,
4033 int width
, int height
)
4037 if (mm
->iArrange
& ARW_STARTRIGHT
)
4038 ret
.x
= parent
->right
- mm
->iHorzGap
- width
;
4040 ret
.x
= parent
->left
+ mm
->iHorzGap
;
4041 if (mm
->iArrange
& ARW_STARTTOP
)
4042 ret
.y
= parent
->top
+ mm
->iVertGap
;
4044 ret
.y
= parent
->bottom
- mm
->iVertGap
- height
;
4049 static void get_next_minimized_child_pos( const RECT
*parent
, const MINIMIZEDMETRICS
*mm
,
4050 int width
, int height
, POINT
*pos
)
4054 if (mm
->iArrange
& ARW_UP
) /* == ARW_DOWN */
4056 if (mm
->iArrange
& ARW_STARTTOP
)
4058 pos
->y
+= height
+ mm
->iVertGap
;
4059 if ((next
= pos
->y
+ height
> parent
->bottom
))
4060 pos
->y
= parent
->top
+ mm
->iVertGap
;
4064 pos
->y
-= height
+ mm
->iVertGap
;
4065 if ((next
= pos
->y
< parent
->top
))
4066 pos
->y
= parent
->bottom
- mm
->iVertGap
- height
;
4071 if (mm
->iArrange
& ARW_STARTRIGHT
)
4072 pos
->x
-= width
+ mm
->iHorzGap
;
4074 pos
->x
+= width
+ mm
->iHorzGap
;
4079 if (mm
->iArrange
& ARW_STARTRIGHT
)
4081 pos
->x
-= width
+ mm
->iHorzGap
;
4082 if ((next
= pos
->x
< parent
->left
))
4083 pos
->x
= parent
->right
- mm
->iHorzGap
- width
;
4087 pos
->x
+= width
+ mm
->iHorzGap
;
4088 if ((next
= pos
->x
+ width
> parent
->right
))
4089 pos
->x
= parent
->left
+ mm
->iHorzGap
;
4094 if (mm
->iArrange
& ARW_STARTTOP
)
4095 pos
->y
+= height
+ mm
->iVertGap
;
4097 pos
->y
-= height
+ mm
->iVertGap
;
4102 static POINT
get_minimized_pos( HWND hwnd
, POINT pt
)
4104 RECT rect
, parent_rect
;
4107 MINIMIZEDMETRICS metrics
;
4110 parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
4111 if (parent
== get_desktop_window())
4113 MONITORINFO mon_info
;
4114 HMONITOR monitor
= monitor_from_window( hwnd
, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
4116 mon_info
.cbSize
= sizeof( mon_info
);
4117 get_monitor_info( monitor
, &mon_info
, get_thread_dpi() );
4118 parent_rect
= mon_info
.rcWork
;
4120 else get_client_rect( parent
, &parent_rect
, get_thread_dpi() );
4122 if (pt
.x
>= parent_rect
.left
&& (pt
.x
+ get_system_metrics( SM_CXMINIMIZED
) < parent_rect
.right
) &&
4123 pt
.y
>= parent_rect
.top
&& (pt
.y
+ get_system_metrics( SM_CYMINIMIZED
) < parent_rect
.bottom
))
4124 return pt
; /* The icon already has a suitable position */
4126 width
= get_system_metrics( SM_CXMINIMIZED
);
4127 height
= get_system_metrics( SM_CYMINIMIZED
);
4129 metrics
.cbSize
= sizeof(metrics
);
4130 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(metrics
), &metrics
, 0 );
4132 /* Check if another icon already occupies this spot */
4133 /* FIXME: this is completely inefficient */
4135 hrgn
= NtGdiCreateRectRgn( 0, 0, 0, 0 );
4136 tmp
= NtGdiCreateRectRgn( 0, 0, 0, 0 );
4137 for (child
= get_window_relative( parent
, GW_CHILD
);
4139 child
= get_window_relative( child
, GW_HWNDNEXT
))
4141 if (child
== hwnd
) continue;
4142 if ((get_window_long( child
, GWL_STYLE
) & (WS_VISIBLE
|WS_MINIMIZE
)) != (WS_VISIBLE
|WS_MINIMIZE
))
4144 if (get_window_rects( child
, COORDS_PARENT
, &rect
, NULL
, get_thread_dpi() ))
4146 NtGdiSetRectRgn( tmp
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
4147 NtGdiCombineRgn( hrgn
, hrgn
, tmp
, RGN_OR
);
4150 NtGdiDeleteObjectApp( tmp
);
4152 pt
= get_first_minimized_child_pos( &parent_rect
, &metrics
, width
, height
);
4155 SetRect( &rect
, pt
.x
, pt
.y
, pt
.x
+ width
, pt
.y
+ height
);
4156 if (!NtGdiRectInRegion( hrgn
, &rect
))
4159 get_next_minimized_child_pos( &parent_rect
, &metrics
, width
, height
, &pt
);
4162 NtGdiDeleteObjectApp( hrgn
);
4166 /***********************************************************************
4167 * window_min_maximize
4169 static UINT
window_min_maximize( HWND hwnd
, UINT cmd
, RECT
*rect
)
4174 WINDOWPLACEMENT wpl
;
4176 TRACE( "%p %u\n", hwnd
, cmd
);
4178 wpl
.length
= sizeof(wpl
);
4179 NtUserGetWindowPlacement( hwnd
, &wpl
);
4181 if (call_hooks( WH_CBT
, HCBT_MINMAX
, (WPARAM
)hwnd
, cmd
, 0 ))
4182 return SWP_NOSIZE
| SWP_NOMOVE
;
4184 if (is_iconic( hwnd
))
4188 case SW_SHOWMINNOACTIVE
:
4189 case SW_SHOWMINIMIZED
:
4190 case SW_FORCEMINIMIZE
:
4192 wpl
.ptMinPosition
= get_minimized_pos( hwnd
, wpl
.ptMinPosition
);
4194 SetRect( rect
, wpl
.ptMinPosition
.x
, wpl
.ptMinPosition
.y
,
4195 wpl
.ptMinPosition
.x
+ get_system_metrics( SM_CXMINIMIZED
),
4196 wpl
.ptMinPosition
.y
+ get_system_metrics( SM_CYMINIMIZED
));
4197 return SWP_NOSIZE
| SWP_NOMOVE
;
4199 if (!send_message( hwnd
, WM_QUERYOPEN
, 0, 0 )) return SWP_NOSIZE
| SWP_NOMOVE
;
4200 swp_flags
|= SWP_NOCOPYBITS
;
4205 case SW_SHOWMINNOACTIVE
:
4206 case SW_SHOWMINIMIZED
:
4207 case SW_FORCEMINIMIZE
:
4209 if (is_zoomed( hwnd
)) win_set_flags( hwnd
, WIN_RESTORE_MAX
, 0 );
4210 else win_set_flags( hwnd
, 0, WIN_RESTORE_MAX
);
4212 if (get_focus() == hwnd
)
4214 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
)
4215 NtUserSetFocus( NtUserGetAncestor( hwnd
, GA_PARENT
));
4217 NtUserSetFocus( 0 );
4220 old_style
= set_window_style( hwnd
, WS_MINIMIZE
, WS_MAXIMIZE
);
4222 wpl
.ptMinPosition
= get_minimized_pos( hwnd
, wpl
.ptMinPosition
);
4224 if (!(old_style
& WS_MINIMIZE
)) swp_flags
|= SWP_STATECHANGED
;
4225 SetRect( rect
, wpl
.ptMinPosition
.x
, wpl
.ptMinPosition
.y
,
4226 wpl
.ptMinPosition
.x
+ get_system_metrics(SM_CXMINIMIZED
),
4227 wpl
.ptMinPosition
.y
+ get_system_metrics(SM_CYMINIMIZED
) );
4228 swp_flags
|= SWP_NOCOPYBITS
;
4232 old_style
= get_window_long( hwnd
, GWL_STYLE
);
4233 if ((old_style
& WS_MAXIMIZE
) && (old_style
& WS_VISIBLE
)) return SWP_NOSIZE
| SWP_NOMOVE
;
4235 minmax
= get_min_max_info( hwnd
);
4237 old_style
= set_window_style( hwnd
, WS_MAXIMIZE
, WS_MINIMIZE
);
4238 if (old_style
& WS_MINIMIZE
)
4239 win_set_flags( hwnd
, WIN_RESTORE_MAX
, 0 );
4241 if (!(old_style
& WS_MAXIMIZE
)) swp_flags
|= SWP_STATECHANGED
;
4242 SetRect( rect
, minmax
.ptMaxPosition
.x
, minmax
.ptMaxPosition
.y
,
4243 minmax
.ptMaxPosition
.x
+ minmax
.ptMaxSize
.x
,
4244 minmax
.ptMaxPosition
.y
+ minmax
.ptMaxSize
.y
);
4247 case SW_SHOWNOACTIVATE
:
4248 win_set_flags( hwnd
, 0, WIN_RESTORE_MAX
);
4252 case SW_SHOWDEFAULT
: /* FIXME: should have its own handler */
4253 old_style
= set_window_style( hwnd
, 0, WS_MINIMIZE
| WS_MAXIMIZE
);
4254 if (old_style
& WS_MINIMIZE
)
4256 if (win_get_flags( hwnd
) & WIN_RESTORE_MAX
)
4258 /* Restore to maximized position */
4259 minmax
= get_min_max_info( hwnd
);
4260 set_window_style( hwnd
, WS_MAXIMIZE
, 0 );
4261 swp_flags
|= SWP_STATECHANGED
;
4262 SetRect( rect
, minmax
.ptMaxPosition
.x
, minmax
.ptMaxPosition
.y
,
4263 minmax
.ptMaxPosition
.x
+ minmax
.ptMaxSize
.x
,
4264 minmax
.ptMaxPosition
.y
+ minmax
.ptMaxSize
.y
);
4268 else if (!(old_style
& WS_MAXIMIZE
)) break;
4270 swp_flags
|= SWP_STATECHANGED
;
4272 /* Restore to normal position */
4274 *rect
= wpl
.rcNormalPosition
;
4281 /* see ArrangeIconicWindows */
4282 static UINT
arrange_iconic_windows( HWND parent
)
4284 int width
, height
, count
= 0;
4285 MINIMIZEDMETRICS metrics
;
4290 metrics
.cbSize
= sizeof(metrics
);
4291 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(metrics
), &metrics
, 0 );
4292 width
= get_system_metrics( SM_CXMINIMIZED
);
4293 height
= get_system_metrics( SM_CYMINIMIZED
);
4295 if (parent
== get_desktop_window())
4297 MONITORINFO mon_info
;
4298 HMONITOR monitor
= monitor_from_window( 0, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
4300 mon_info
.cbSize
= sizeof( mon_info
);
4301 get_monitor_info( monitor
, &mon_info
, get_thread_dpi() );
4302 parent_rect
= mon_info
.rcWork
;
4304 else get_client_rect( parent
, &parent_rect
, get_thread_dpi() );
4306 pt
= get_first_minimized_child_pos( &parent_rect
, &metrics
, width
, height
);
4308 child
= get_window_relative( parent
, GW_CHILD
);
4311 if (is_iconic( child
))
4313 NtUserSetWindowPos( child
, 0, pt
.x
, pt
.y
, 0, 0,
4314 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
4315 get_next_minimized_child_pos( &parent_rect
, &metrics
, width
, height
, &pt
);
4318 child
= get_window_relative( child
, GW_HWNDNEXT
);
4323 /*******************************************************************
4324 * update_window_state
4326 * Trigger an update of the window's driver state and surface.
4328 void update_window_state( HWND hwnd
)
4330 static const UINT swp_flags
= SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOCLIENTSIZE
| SWP_NOCLIENTMOVE
|
4331 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREDRAW
;
4333 RECT window_rect
, client_rect
, valid_rects
[2], visible_rect
, surface_rect
;
4334 struct window_surface
*surface
;
4336 if (!is_current_thread_window( hwnd
))
4338 NtUserPostMessage( hwnd
, WM_WINE_UPDATEWINDOWSTATE
, 0, 0 );
4342 context
= set_thread_dpi_awareness_context( get_window_dpi_awareness_context( hwnd
));
4343 get_window_rects( hwnd
, COORDS_PARENT
, &window_rect
, &client_rect
, get_thread_dpi() );
4344 valid_rects
[0] = valid_rects
[1] = client_rect
;
4346 surface
= create_window_surface( hwnd
, swp_flags
, FALSE
, &window_rect
, &client_rect
, &visible_rect
, &surface_rect
);
4347 apply_window_pos( hwnd
, 0, swp_flags
, surface
, &window_rect
, &client_rect
, &visible_rect
, valid_rects
);
4348 if (surface
) window_surface_release( surface
);
4350 set_thread_dpi_awareness_context( context
);
4353 /***********************************************************************
4356 * Implementation of ShowWindow and ShowWindowAsync.
4358 static BOOL
show_window( HWND hwnd
, INT cmd
)
4362 LONG style
= get_window_long( hwnd
, GWL_STYLE
), new_style
;
4363 BOOL was_visible
= (style
& WS_VISIBLE
) != 0;
4364 BOOL show_flag
= TRUE
;
4365 RECT newPos
= {0, 0, 0, 0};
4366 UINT new_swp
, swp
= 0, context
;
4368 TRACE( "hwnd=%p, cmd=%d, was_visible %d\n", hwnd
, cmd
, was_visible
);
4370 context
= set_thread_dpi_awareness_context( get_window_dpi_awareness_context( hwnd
));
4375 if (!was_visible
) goto done
;
4377 swp
|= SWP_HIDEWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
4378 if (style
& WS_CHILD
) swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4381 case SW_SHOWMINNOACTIVE
:
4383 case SW_FORCEMINIMIZE
: /* FIXME: Does not work if thread is hung. */
4384 swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4386 case SW_SHOWMINIMIZED
:
4387 swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
4388 swp
|= window_min_maximize( hwnd
, cmd
, &newPos
);
4389 if ((style
& WS_MINIMIZE
) && was_visible
) goto done
;
4392 case SW_SHOWMAXIMIZED
: /* same as SW_MAXIMIZE */
4393 if (!was_visible
) swp
|= SWP_SHOWWINDOW
;
4394 swp
|= SWP_FRAMECHANGED
;
4395 swp
|= window_min_maximize( hwnd
, SW_MAXIMIZE
, &newPos
);
4396 if ((style
& WS_MAXIMIZE
) && was_visible
) goto done
;
4400 swp
|= SWP_NOACTIVATE
| SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
4401 if (style
& WS_CHILD
) swp
|= SWP_NOZORDER
;
4405 if (was_visible
) goto done
;
4406 swp
|= SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
4407 if (style
& WS_CHILD
) swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4410 case SW_SHOWNOACTIVATE
:
4411 swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4415 case SW_SHOWNORMAL
: /* same as SW_NORMAL: */
4416 case SW_SHOWDEFAULT
: /* FIXME: should have its own handler */
4417 if (!was_visible
) swp
|= SWP_SHOWWINDOW
;
4418 if (style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
4420 swp
|= SWP_FRAMECHANGED
;
4421 swp
|= window_min_maximize( hwnd
, cmd
, &newPos
);
4425 if (was_visible
) goto done
;
4426 swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
4428 if (style
& WS_CHILD
&& !(swp
& SWP_STATECHANGED
)) swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4435 if ((show_flag
!= was_visible
|| cmd
== SW_SHOWNA
) && cmd
!= SW_SHOWMAXIMIZED
&& !(swp
& SWP_STATECHANGED
))
4437 send_message( hwnd
, WM_SHOWWINDOW
, show_flag
, 0 );
4438 if (!is_window( hwnd
)) goto done
;
4441 if (IsRectEmpty( &newPos
)) new_swp
= swp
;
4442 else if ((new_swp
= user_driver
->pShowWindow( hwnd
, cmd
, &newPos
, swp
)) == ~0)
4444 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) new_swp
= swp
;
4445 else if (is_iconic( hwnd
) && (newPos
.left
!= -32000 || newPos
.top
!= -32000))
4447 OffsetRect( &newPos
, -32000 - newPos
.left
, -32000 - newPos
.top
);
4448 new_swp
= swp
& ~(SWP_NOMOVE
| SWP_NOCLIENTMOVE
);
4454 parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
4455 if (parent
&& !is_window_visible( parent
) && !(swp
& SWP_STATECHANGED
))
4457 /* if parent is not visible simply toggle WS_VISIBLE and return */
4458 if (show_flag
) set_window_style( hwnd
, WS_VISIBLE
, 0 );
4459 else set_window_style( hwnd
, 0, WS_VISIBLE
);
4462 NtUserSetWindowPos( hwnd
, HWND_TOP
, newPos
.left
, newPos
.top
,
4463 newPos
.right
- newPos
.left
, newPos
.bottom
- newPos
.top
, swp
);
4465 new_style
= get_window_long( hwnd
, GWL_STYLE
);
4466 if (((style
^ new_style
) & WS_MINIMIZE
) != 0)
4468 if ((new_style
& WS_MINIMIZE
) != 0)
4469 NtUserNotifyWinEvent( EVENT_SYSTEM_MINIMIZESTART
, hwnd
, OBJID_WINDOW
, 0 );
4471 NtUserNotifyWinEvent( EVENT_SYSTEM_MINIMIZEEND
, hwnd
, OBJID_WINDOW
, 0 );
4478 /* FIXME: This will cause the window to be activated irrespective
4479 * of whether it is owned by the same thread. Has to be done
4483 if (hwnd
== get_active_window()) activate_other_window( hwnd
);
4485 /* Revert focus to parent */
4486 hFocus
= get_focus();
4489 HWND parent
= NtUserGetAncestor(hwnd
, GA_PARENT
);
4490 if (parent
== get_desktop_window()) parent
= 0;
4491 NtUserSetFocus(parent
);
4496 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
) goto done
;
4498 if (win
->flags
& WIN_NEED_SIZE
)
4500 /* should happen only in CreateWindowEx() */
4501 int wParam
= SIZE_RESTORED
;
4505 get_window_rects( hwnd
, COORDS_PARENT
, NULL
, &client
, get_thread_dpi() );
4506 lparam
= MAKELONG( client
.right
- client
.left
, client
.bottom
- client
.top
);
4507 win
->flags
&= ~WIN_NEED_SIZE
;
4508 if (win
->dwStyle
& WS_MAXIMIZE
) wParam
= SIZE_MAXIMIZED
;
4509 else if (win
->dwStyle
& WS_MINIMIZE
)
4511 wParam
= SIZE_MINIMIZED
;
4514 release_win_ptr( win
);
4516 send_message( hwnd
, WM_SIZE
, wParam
, lparam
);
4517 send_message( hwnd
, WM_MOVE
, 0, MAKELONG( client
.left
, client
.top
));
4519 else release_win_ptr( win
);
4521 /* if previous state was minimized Windows sets focus to the window */
4522 if (style
& WS_MINIMIZE
)
4524 NtUserSetFocus( hwnd
);
4525 /* Send a WM_ACTIVATE message for a top level window, even if the window is already active */
4526 if (NtUserGetAncestor( hwnd
, GA_ROOT
) == hwnd
&& !(swp
& SWP_NOACTIVATE
))
4527 send_message( hwnd
, WM_ACTIVATE
, WA_ACTIVE
, 0 );
4531 set_thread_dpi_awareness_context( context
);
4535 /***********************************************************************
4536 * NtUserShowWindowAsync (win32u.@)
4538 * doesn't wait; returns immediately.
4539 * used by threads to toggle windows in other (possibly hanging) threads
4541 BOOL WINAPI
NtUserShowWindowAsync( HWND hwnd
, INT cmd
)
4545 if (is_broadcast(hwnd
))
4547 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4551 if ((full_handle
= is_current_thread_window( hwnd
)))
4552 return show_window( full_handle
, cmd
);
4554 return NtUserMessageCall( hwnd
, WM_WINE_SHOWWINDOW
, cmd
, 0, 0,
4555 NtUserSendNotifyMessage
, FALSE
);
4558 /***********************************************************************
4559 * NtUserShowWindow (win32u.@)
4561 BOOL WINAPI
NtUserShowWindow( HWND hwnd
, INT cmd
)
4565 if (is_broadcast(hwnd
))
4567 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4570 if ((full_handle
= is_current_thread_window( hwnd
)))
4571 return show_window( full_handle
, cmd
);
4573 if ((cmd
== SW_HIDE
) && !(get_window_long( hwnd
, GWL_STYLE
) & WS_VISIBLE
))
4576 if ((cmd
== SW_SHOW
) && (get_window_long( hwnd
, GWL_STYLE
) & WS_VISIBLE
))
4579 return send_message( hwnd
, WM_WINE_SHOWWINDOW
, cmd
, 0 );
4582 /* see ShowOwnedPopups */
4583 BOOL
show_owned_popups( HWND owner
, BOOL show
)
4586 HWND
*win_array
= list_window_children( 0, get_desktop_window(), NULL
, 0 );
4588 if (!win_array
) return TRUE
;
4590 while (win_array
[count
]) count
++;
4591 while (--count
>= 0)
4593 if (get_window_relative( win_array
[count
], GW_OWNER
) != owner
) continue;
4596 if (win_get_flags( win_array
[count
] ) & WIN_NEEDS_SHOW_OWNEDPOPUP
)
4597 /* In Windows, ShowOwnedPopups(TRUE) generates
4598 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
4599 * regardless of the state of the owner
4601 send_message( win_array
[count
], WM_SHOWWINDOW
, SW_SHOWNORMAL
, SW_PARENTOPENING
);
4605 if (get_window_long( win_array
[count
], GWL_STYLE
) & WS_VISIBLE
)
4606 /* In Windows, ShowOwnedPopups(FALSE) generates
4607 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
4608 * regardless of the state of the owner
4610 send_message( win_array
[count
], WM_SHOWWINDOW
, SW_HIDE
, SW_PARENTCLOSING
);
4618 /*******************************************************************
4619 * NtUserFlashWindowEx (win32u.@)
4621 BOOL WINAPI
NtUserFlashWindowEx( FLASHWINFO
*info
)
4625 TRACE( "%p\n", info
);
4629 RtlSetLastWin32Error( ERROR_NOACCESS
);
4633 if (!info
->hwnd
|| info
->cbSize
!= sizeof(FLASHWINFO
) || !is_window( info
->hwnd
))
4635 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4638 FIXME( "%p - semi-stub\n", info
);
4640 if (is_iconic( info
->hwnd
))
4642 NtUserRedrawWindow( info
->hwnd
, 0, 0, RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_FRAME
);
4644 win
= get_win_ptr( info
->hwnd
);
4645 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
4646 if (info
->dwFlags
& FLASHW_CAPTION
&& !(win
->flags
& WIN_NCACTIVATED
))
4648 win
->flags
|= WIN_NCACTIVATED
;
4650 else if (!info
->dwFlags
)
4652 win
->flags
&= ~WIN_NCACTIVATED
;
4654 release_win_ptr( win
);
4655 user_driver
->pFlashWindowEx( info
);
4661 HWND hwnd
= info
->hwnd
;
4663 win
= get_win_ptr( hwnd
);
4664 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
4665 hwnd
= win
->obj
.handle
; /* make it a full handle */
4667 if (info
->dwFlags
) wparam
= !(win
->flags
& WIN_NCACTIVATED
);
4668 else wparam
= (hwnd
== NtUserGetForegroundWindow());
4670 release_win_ptr( win
);
4672 if (!info
->dwFlags
|| info
->dwFlags
& FLASHW_CAPTION
)
4673 send_message( hwnd
, WM_NCACTIVATE
, wparam
, 0 );
4675 user_driver
->pFlashWindowEx( info
);
4680 /* see GetWindowContextHelpId */
4681 DWORD
get_window_context_help_id( HWND hwnd
)
4684 WND
*win
= get_win_ptr( hwnd
);
4685 if (!win
|| win
== WND_DESKTOP
) return 0;
4686 if (win
== WND_OTHER_PROCESS
)
4688 if (is_window( hwnd
)) FIXME( "not supported on other process window %p\n", hwnd
);
4691 retval
= win
->helpContext
;
4692 release_win_ptr( win
);
4696 /* see SetWindowContextHelpId */
4697 static BOOL
set_window_context_help_id( HWND hwnd
, DWORD id
)
4699 WND
*win
= get_win_ptr( hwnd
);
4700 if (!win
|| win
== WND_DESKTOP
) return FALSE
;
4701 if (win
== WND_OTHER_PROCESS
)
4703 if (is_window( hwnd
)) FIXME( "not supported on other process window %p\n", hwnd
);
4706 win
->helpContext
= id
;
4707 release_win_ptr( win
);
4711 /***********************************************************************
4712 * NtUserInternalGetWindowIcon (win32u.@)
4714 HICON WINAPI
NtUserInternalGetWindowIcon( HWND hwnd
, UINT type
)
4716 WND
*win
= get_win_ptr( hwnd
);
4719 TRACE( "hwnd %p, type %#x\n", hwnd
, type
);
4723 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
4726 if (win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
)
4728 if (is_window( hwnd
)) FIXME( "not supported on other process window %p\n", hwnd
);
4736 if (!ret
) ret
= (HICON
)get_class_long_ptr( hwnd
, GCLP_HICON
, FALSE
);
4741 ret
= win
->hIconSmall
? win
->hIconSmall
: win
->hIconSmall2
;
4742 if (!ret
) ret
= (HICON
)get_class_long_ptr( hwnd
, GCLP_HICONSM
, FALSE
);
4743 if (!ret
) ret
= (HICON
)get_class_long_ptr( hwnd
, GCLP_HICON
, FALSE
);
4747 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4748 release_win_ptr( win
);
4751 release_win_ptr( win
);
4753 if (!ret
) ret
= LoadImageW( 0, (const WCHAR
*)IDI_APPLICATION
, IMAGE_ICON
,
4754 0, 0, LR_SHARED
| LR_DEFAULTSIZE
);
4756 return CopyImage( ret
, IMAGE_ICON
, 0, 0, 0 );
4759 /***********************************************************************
4760 * send_destroy_message
4762 static void send_destroy_message( HWND hwnd
, BOOL winevent
)
4766 info
.cbSize
= sizeof(info
);
4767 if (NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
))
4769 if (hwnd
== info
.hwndCaret
) destroy_caret();
4770 if (hwnd
== info
.hwndActive
) activate_other_window( hwnd
);
4773 if (hwnd
== NtUserGetClipboardOwner()) release_clipboard_owner( hwnd
);
4776 NtUserNotifyWinEvent( EVENT_OBJECT_DESTROY
, hwnd
, OBJID_WINDOW
, 0 );
4778 send_message( hwnd
, WM_DESTROY
, 0, 0);
4781 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
4782 * make sure that the window still exists when we come back.
4784 if (is_window(hwnd
))
4789 if (!(children
= list_window_children( 0, hwnd
, NULL
, 0 ))) return;
4791 for (i
= 0; children
[i
]; i
++)
4793 if (is_window( children
[i
] )) send_destroy_message( children
[i
], FALSE
);
4798 WARN( "\tdestroyed itself while in WM_DESTROY!\n" );
4801 /***********************************************************************
4802 * free_window_handle
4804 * Free a window handle.
4806 static void free_window_handle( HWND hwnd
)
4812 if ((win
= get_user_handle_ptr( hwnd
, NTUSER_OBJ_WINDOW
)) && win
!= OBJ_OTHER_PROCESS
)
4814 SERVER_START_REQ( destroy_window
)
4816 req
->handle
= wine_server_user_handle( hwnd
);
4817 wine_server_call( req
);
4818 set_user_handle_ptr( hwnd
, NULL
);
4822 free( win
->pScroll
);
4828 /***********************************************************************
4831 LRESULT
destroy_window( HWND hwnd
)
4833 struct list vulkan_surfaces
= LIST_INIT(vulkan_surfaces
);
4834 struct window_surface
*surface
;
4835 HMENU menu
= 0, sys_menu
;
4839 TRACE( "%p\n", hwnd
);
4841 unregister_imm_window( hwnd
);
4843 /* free child windows */
4844 if ((children
= list_window_children( 0, hwnd
, NULL
, 0 )))
4847 for (i
= 0; children
[i
]; i
++)
4849 if (is_current_thread_window( children
[i
] ))
4850 destroy_window( children
[i
] );
4852 NtUserMessageCall( children
[i
], WM_WINE_DESTROYWINDOW
, 0, 0,
4853 0, NtUserSendNotifyMessage
, FALSE
);
4858 /* Unlink now so we won't bother with the children later on */
4859 SERVER_START_REQ( set_parent
)
4861 req
->handle
= wine_server_user_handle( hwnd
);
4863 wine_server_call( req
);
4867 send_message( hwnd
, WM_NCDESTROY
, 0, 0 );
4869 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
4871 /* free resources associated with the window */
4873 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
) return 0;
4874 if ((win
->dwStyle
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
)
4875 menu
= (HMENU
)win
->wIDmenu
;
4876 sys_menu
= win
->hSysMenu
;
4877 free_dce( win
->dce
, hwnd
);
4879 NtUserDestroyCursor( win
->hIconSmall2
, 0 );
4880 list_move_tail( &vulkan_surfaces
, &win
->vulkan_surfaces
);
4881 surface
= win
->surface
;
4882 win
->surface
= NULL
;
4883 release_win_ptr( win
);
4885 NtUserDestroyMenu( menu
);
4886 NtUserDestroyMenu( sys_menu
);
4889 register_window_surface( surface
, NULL
);
4890 window_surface_release( surface
);
4893 vulkan_detach_surfaces( &vulkan_surfaces
);
4894 user_driver
->pDestroyWindow( hwnd
);
4896 free_window_handle( hwnd
);
4900 /***********************************************************************
4901 * NtUserDestroyWindow (win32u.@)
4903 static BOOL
user_destroy_window( HWND hwnd
, BOOL winevent
)
4907 if (!(hwnd
= is_current_thread_window( hwnd
)) || is_desktop_window( hwnd
))
4909 RtlSetLastWin32Error( ERROR_ACCESS_DENIED
);
4913 TRACE( "(%p)\n", hwnd
);
4915 if (call_hooks( WH_CBT
, HCBT_DESTROYWND
, (WPARAM
)hwnd
, 0, 0 )) return FALSE
;
4917 if (is_menu_active() == hwnd
) NtUserEndMenu();
4919 is_child
= (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) != 0;
4923 if (!is_exiting_thread( GetCurrentThreadId() ))
4924 send_parent_notify( hwnd
, WM_DESTROY
);
4926 else if (!get_window_relative( hwnd
, GW_OWNER
))
4928 call_hooks( WH_SHELL
, HSHELL_WINDOWDESTROYED
, (WPARAM
)hwnd
, 0, 0 );
4929 /* FIXME: clean up palette - see "Internals" p.352 */
4932 if (!is_window( hwnd
)) return TRUE
;
4934 /* Hide the window */
4935 if (get_window_long( hwnd
, GWL_STYLE
) & WS_VISIBLE
)
4937 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
4939 NtUserShowWindow( hwnd
, SW_HIDE
);
4941 NtUserSetWindowPos( hwnd
, 0, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
|
4942 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_HIDEWINDOW
);
4945 if (!is_window( hwnd
)) return TRUE
;
4947 /* Recursively destroy child windows */
4952 BOOL got_one
= FALSE
;
4956 if (!(children
= list_window_children( 0, get_desktop_window(), NULL
, 0 ))) break;
4958 for (i
= 0; children
[i
]; i
++)
4960 if (get_window_relative( children
[i
], GW_OWNER
) != hwnd
) continue;
4961 if (is_current_thread_window( children
[i
] ))
4963 user_destroy_window( children
[i
], FALSE
);
4967 set_window_owner( children
[i
], 0 );
4970 if (!got_one
) break;
4974 send_destroy_message( hwnd
, winevent
);
4975 if (!is_window( hwnd
)) return TRUE
;
4977 destroy_window( hwnd
);
4981 BOOL WINAPI
NtUserDestroyWindow( HWND hwnd
)
4983 return user_destroy_window( hwnd
, TRUE
);
4986 /*****************************************************************************
4987 * destroy_thread_windows
4989 * Destroy all window owned by the current thread.
4991 void destroy_thread_windows(void)
4993 WND
*win
, *free_list
= NULL
;
4997 while ((win
= next_process_user_handle_ptr( &handle
, NTUSER_OBJ_WINDOW
)))
4999 if (win
->tid
!= GetCurrentThreadId()) continue;
5000 free_dce( win
->dce
, win
->obj
.handle
);
5001 set_user_handle_ptr( handle
, NULL
);
5002 win
->obj
.handle
= free_list
;
5007 SERVER_START_REQ( destroy_window
)
5009 req
->handle
= 0; /* destroy all thread windows */
5010 wine_server_call( req
);
5016 while ((win
= free_list
))
5018 free_list
= win
->obj
.handle
;
5019 TRACE( "destroying %p\n", win
);
5021 vulkan_detach_surfaces( &win
->vulkan_surfaces
);
5023 if ((win
->dwStyle
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
&& win
->wIDmenu
)
5024 NtUserDestroyMenu( UlongToHandle(win
->wIDmenu
) );
5025 if (win
->hSysMenu
) NtUserDestroyMenu( win
->hSysMenu
);
5028 register_window_surface( win
->surface
, NULL
);
5029 window_surface_release( win
->surface
);
5031 free( win
->pScroll
);
5037 /***********************************************************************
5038 * create_window_handle
5040 * Create a window handle with the server.
5042 static WND
*create_window_handle( HWND parent
, HWND owner
, UNICODE_STRING
*name
,
5043 HINSTANCE instance
, BOOL ansi
,
5044 DWORD style
, DWORD ex_style
)
5046 UINT dpi_context
= get_thread_dpi_awareness_context();
5047 HWND handle
= 0, full_parent
= 0, full_owner
= 0;
5048 struct tagCLASS
*class = NULL
;
5049 int extra_bytes
= 0;
5052 SERVER_START_REQ( create_window
)
5054 req
->parent
= wine_server_user_handle( parent
);
5055 req
->owner
= wine_server_user_handle( owner
);
5056 req
->instance
= wine_server_client_ptr( instance
);
5057 req
->dpi_context
= dpi_context
;
5059 req
->ex_style
= ex_style
;
5060 if (!(req
->atom
= get_int_atom_value( name
)) && name
->Length
)
5061 wine_server_add_data( req
, name
->Buffer
, name
->Length
);
5062 if (!wine_server_call_err( req
))
5064 handle
= wine_server_ptr_handle( reply
->handle
);
5065 full_parent
= wine_server_ptr_handle( reply
->parent
);
5066 full_owner
= wine_server_ptr_handle( reply
->owner
);
5067 extra_bytes
= reply
->extra
;
5068 dpi_context
= reply
->dpi_context
;
5069 class = wine_server_get_ptr( reply
->class_ptr
);
5076 WARN( "error %d creating window\n", (int)RtlGetLastWin32Error() );
5080 if (!(win
= calloc( 1, FIELD_OFFSET(WND
, wExtra
) + extra_bytes
)))
5082 SERVER_START_REQ( destroy_window
)
5084 req
->handle
= wine_server_user_handle( handle
);
5085 wine_server_call( req
);
5088 RtlSetLastWin32Error( ERROR_NOT_ENOUGH_MEMORY
);
5092 if (!parent
) /* if parent is 0 we don't have a desktop window yet */
5094 struct ntuser_thread_info
*thread_info
= NtUserGetThreadInfo();
5096 if (name
->Buffer
== (const WCHAR
*)DESKTOP_CLASS_ATOM
)
5098 if (!thread_info
->top_window
) thread_info
->top_window
= HandleToUlong( full_parent
? full_parent
: handle
);
5099 else assert( full_parent
== UlongToHandle( thread_info
->top_window
));
5100 if (!thread_info
->top_window
) ERR_(win
)( "failed to create desktop window\n" );
5101 else user_driver
->pSetDesktopWindow( UlongToHandle( thread_info
->top_window
));
5102 register_builtin_classes();
5104 else /* HWND_MESSAGE parent */
5106 if (!thread_info
->msg_window
&& !full_parent
)
5107 thread_info
->msg_window
= HandleToUlong( handle
);
5113 win
->obj
.handle
= handle
;
5114 win
->obj
.type
= NTUSER_OBJ_WINDOW
;
5115 win
->parent
= full_parent
;
5116 win
->owner
= full_owner
;
5118 win
->winproc
= get_class_winproc( class );
5119 win
->cbWndExtra
= extra_bytes
;
5120 win
->dpi_context
= dpi_context
;
5121 list_init( &win
->vulkan_surfaces
);
5122 set_user_handle_ptr( handle
, &win
->obj
);
5123 if (is_winproc_unicode( win
->winproc
, !ansi
)) win
->flags
|= WIN_ISUNICODE
;
5127 static BOOL
is_default_coord( int x
)
5129 return x
== CW_USEDEFAULT
|| x
== 0x8000;
5132 /***********************************************************************
5133 * fix_cs_coordinates
5135 * Fix the coordinates and return default show mode in sw.
5137 static void fix_cs_coordinates( CREATESTRUCTW
*cs
, INT
*sw
)
5139 if (cs
->style
& (WS_CHILD
| WS_POPUP
))
5141 if (is_default_coord(cs
->x
)) cs
->x
= cs
->y
= 0;
5142 if (is_default_coord(cs
->cx
)) cs
->cx
= cs
->cy
= 0;
5144 else /* overlapped window */
5146 RTL_USER_PROCESS_PARAMETERS
*params
= NtCurrentTeb()->Peb
->ProcessParameters
;
5148 MONITORINFO mon_info
;
5150 if (!is_default_coord( cs
->x
) && !is_default_coord( cs
->cx
) && !is_default_coord( cs
->cy
))
5153 monitor
= monitor_from_window( cs
->hwndParent
, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
5154 mon_info
.cbSize
= sizeof(mon_info
);
5155 get_monitor_info( monitor
, &mon_info
, get_thread_dpi() );
5157 if (is_default_coord( cs
->x
))
5159 if (!is_default_coord( cs
->y
)) *sw
= cs
->y
;
5160 cs
->x
= (params
->dwFlags
& STARTF_USEPOSITION
) ? params
->dwX
: mon_info
.rcWork
.left
;
5161 cs
->y
= (params
->dwFlags
& STARTF_USEPOSITION
) ? params
->dwY
: mon_info
.rcWork
.top
;
5164 if (is_default_coord( cs
->cx
))
5166 if (params
->dwFlags
& STARTF_USESIZE
)
5168 cs
->cx
= params
->dwXSize
;
5169 cs
->cy
= params
->dwYSize
;
5173 cs
->cx
= (mon_info
.rcWork
.right
- mon_info
.rcWork
.left
) * 3 / 4 - cs
->x
;
5174 cs
->cy
= (mon_info
.rcWork
.bottom
- mon_info
.rcWork
.top
) * 3 / 4 - cs
->y
;
5177 /* neither x nor cx are default. Check the y values.
5178 * In the trace we see Outlook and Outlook Express using
5179 * cy set to CW_USEDEFAULT when opening the address book.
5181 else if (is_default_coord( cs
->cy
))
5183 FIXME( "Strange use of CW_USEDEFAULT in cy\n" );
5184 cs
->cy
= (mon_info
.rcWork
.bottom
- mon_info
.rcWork
.top
) * 3 / 4 - cs
->y
;
5189 /***********************************************************************
5190 * map_dpi_create_struct
5192 static void map_dpi_create_struct( CREATESTRUCTW
*cs
, UINT dpi_from
, UINT dpi_to
)
5194 if (!dpi_from
&& !dpi_to
) return;
5195 if (!dpi_from
|| !dpi_to
)
5197 POINT pt
= { cs
->x
, cs
->y
};
5198 UINT mon_dpi
= get_monitor_dpi( monitor_from_point( pt
, MONITOR_DEFAULTTONEAREST
, dpi_from
));
5199 if (!dpi_from
) dpi_from
= mon_dpi
;
5200 else dpi_to
= mon_dpi
;
5202 if (dpi_from
== dpi_to
) return;
5203 cs
->x
= muldiv( cs
->x
, dpi_to
, dpi_from
);
5204 cs
->y
= muldiv( cs
->y
, dpi_to
, dpi_from
);
5205 cs
->cx
= muldiv( cs
->cx
, dpi_to
, dpi_from
);
5206 cs
->cy
= muldiv( cs
->cy
, dpi_to
, dpi_from
);
5209 /***********************************************************************
5210 * NtUserCreateWindowEx (win32u.@)
5212 HWND WINAPI
NtUserCreateWindowEx( DWORD ex_style
, UNICODE_STRING
*class_name
,
5213 UNICODE_STRING
*version
, UNICODE_STRING
*window_name
,
5214 DWORD style
, INT x
, INT y
, INT cx
, INT cy
,
5215 HWND parent
, HMENU menu
, HINSTANCE instance
, void *params
,
5216 DWORD flags
, HINSTANCE client_instance
, DWORD unk
, BOOL ansi
)
5218 UINT win_dpi
, thread_dpi
= get_thread_dpi(), context
;
5219 struct window_surface
*surface
;
5220 CBT_CREATEWNDW cbtc
;
5221 HWND hwnd
, owner
= 0;
5224 RECT rect
, visible_rect
, surface_rect
;
5227 static const WCHAR messageW
[] = {'M','e','s','s','a','g','e'};
5229 cs
.lpCreateParams
= params
;
5230 cs
.hInstance
= client_instance
? client_instance
: instance
;
5232 cs
.hwndParent
= parent
;
5234 cs
.dwExStyle
= ex_style
;
5235 cs
.lpszName
= window_name
? window_name
->Buffer
: NULL
;
5236 cs
.lpszClass
= class_name
? class_name
->Buffer
: NULL
;
5242 /* Find the parent window */
5243 if (parent
== HWND_MESSAGE
)
5245 cs
.hwndParent
= parent
= get_hwnd_message_parent();
5249 if ((cs
.style
& (WS_CHILD
|WS_POPUP
)) != WS_CHILD
)
5252 parent
= get_desktop_window();
5256 DWORD parent_style
= get_window_long( parent
, GWL_EXSTYLE
);
5257 if ((parent_style
& WS_EX_LAYOUTRTL
) && !(parent_style
& WS_EX_NOINHERITLAYOUT
))
5258 cs
.dwExStyle
|= WS_EX_LAYOUTRTL
;
5263 if ((cs
.style
& (WS_CHILD
|WS_POPUP
)) == WS_CHILD
)
5265 WARN( "No parent for child window\n" );
5266 RtlSetLastWin32Error( ERROR_TLW_WITH_WSCHILD
);
5267 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
5270 /* are we creating the desktop or HWND_MESSAGE parent itself? */
5271 if (class_name
->Buffer
!= (LPCWSTR
)DESKTOP_CLASS_ATOM
&&
5272 (class_name
->Length
!= sizeof(messageW
) ||
5273 wcsnicmp( class_name
->Buffer
, messageW
, ARRAYSIZE(messageW
) )))
5275 if (get_process_layout() & LAYOUT_RTL
) cs
.dwExStyle
|= WS_EX_LAYOUTRTL
;
5276 parent
= get_desktop_window();
5280 fix_cs_coordinates( &cs
, &sw
);
5281 cs
.dwExStyle
= fix_exstyle( cs
.style
, cs
.dwExStyle
);
5283 /* Create the window structure */
5285 style
= cs
.style
& ~WS_VISIBLE
;
5286 ex_style
= cs
.dwExStyle
& ~WS_EX_LAYERED
;
5287 if (!(win
= create_window_handle( parent
, owner
, class_name
, instance
, ansi
, style
, ex_style
)))
5289 hwnd
= win
->obj
.handle
;
5291 /* Fill the window structure */
5293 win
->tid
= GetCurrentThreadId();
5294 win
->hInstance
= cs
.hInstance
;
5296 win
->dwStyle
= style
;
5297 win
->dwExStyle
= ex_style
;
5299 win
->helpContext
= 0;
5300 win
->pScroll
= NULL
;
5303 win
->hIconSmall
= 0;
5304 win
->hIconSmall2
= 0;
5307 win
->min_pos
.x
= win
->min_pos
.y
= -1;
5308 win
->max_pos
.x
= win
->max_pos
.y
= -1;
5309 SetRect( &win
->normal_rect
, cs
.x
, cs
.y
, cs
.x
+ cs
.cx
, cs
.y
+ cs
.cy
);
5311 if (win
->dwStyle
& WS_SYSMENU
) NtUserSetSystemMenu( hwnd
, 0 );
5313 win
->imc
= get_default_input_context();
5315 /* call the WH_CBT hook */
5317 release_win_ptr( win
);
5318 cbtc
.hwndInsertAfter
= HWND_TOP
;
5320 if (call_hooks( WH_CBT
, HCBT_CREATEWND
, (WPARAM
)hwnd
, (LPARAM
)&cbtc
, sizeof(cbtc
) ))
5322 free_window_handle( hwnd
);
5325 if (!(win
= get_win_ptr( hwnd
))) return 0;
5328 * Correct the window styles.
5330 * It affects only the style loaded into the WND structure.
5333 if ((win
->dwStyle
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
)
5335 win
->dwStyle
|= WS_CLIPSIBLINGS
;
5336 if (!(win
->dwStyle
& WS_POPUP
)) win
->dwStyle
|= WS_CAPTION
;
5339 win
->dwExStyle
= cs
.dwExStyle
;
5340 /* WS_EX_WINDOWEDGE depends on some other styles */
5341 if ((win
->dwStyle
& (WS_DLGFRAME
| WS_THICKFRAME
)) &&
5342 !(win
->dwStyle
& (WS_CHILD
| WS_POPUP
)))
5343 win
->dwExStyle
|= WS_EX_WINDOWEDGE
;
5345 if (!(win
->dwStyle
& (WS_CHILD
| WS_POPUP
))) win
->flags
|= WIN_NEED_SIZE
;
5347 SERVER_START_REQ( set_window_info
)
5349 req
->handle
= wine_server_user_handle( hwnd
);
5350 req
->flags
= SET_WIN_STYLE
| SET_WIN_EXSTYLE
| SET_WIN_INSTANCE
| SET_WIN_UNICODE
;
5351 req
->style
= win
->dwStyle
;
5352 req
->ex_style
= win
->dwExStyle
;
5353 req
->instance
= wine_server_client_ptr( win
->hInstance
);
5354 req
->is_unicode
= (win
->flags
& WIN_ISUNICODE
) != 0;
5355 req
->extra_offset
= -1;
5356 wine_server_call( req
);
5360 /* Set the window menu */
5362 if ((win
->dwStyle
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
)
5364 if (cs
.hMenu
&& !set_window_menu( hwnd
, cs
.hMenu
))
5366 release_win_ptr( win
);
5367 free_window_handle( hwnd
);
5371 else NtUserSetWindowLongPtr( hwnd
, GWLP_ID
, (ULONG_PTR
)cs
.hMenu
, FALSE
);
5373 win_dpi
= NTUSER_DPI_CONTEXT_GET_DPI( win
->dpi_context
);
5374 release_win_ptr( win
);
5376 if (parent
) map_dpi_create_struct( &cs
, thread_dpi
, win_dpi
);
5378 context
= set_thread_dpi_awareness_context( get_window_dpi_awareness_context( hwnd
));
5380 /* send the WM_GETMINMAXINFO message and fix the size if needed */
5384 if ((cs
.style
& WS_THICKFRAME
) || !(cs
.style
& (WS_POPUP
| WS_CHILD
)))
5386 MINMAXINFO info
= get_min_max_info( hwnd
);
5387 cx
= max( min( cx
, info
.ptMaxTrackSize
.x
), info
.ptMinTrackSize
.x
);
5388 cy
= max( min( cy
, info
.ptMaxTrackSize
.y
), info
.ptMinTrackSize
.y
);
5393 SetRect( &rect
, cs
.x
, cs
.y
, cs
.x
+ cx
, cs
.y
+ cy
);
5394 /* check for wraparound */
5395 if (cs
.x
> 0x7fffffff - cx
) rect
.right
= 0x7fffffff;
5396 if (cs
.y
> 0x7fffffff - cy
) rect
.bottom
= 0x7fffffff;
5398 surface
= create_window_surface( hwnd
, SWP_NOZORDER
| SWP_NOACTIVATE
, FALSE
, &rect
, &rect
, &visible_rect
, &surface_rect
);
5399 if (!apply_window_pos( hwnd
, 0, SWP_NOZORDER
| SWP_NOACTIVATE
, surface
, &rect
, &rect
, &visible_rect
, NULL
))
5401 if (surface
) window_surface_release( surface
);
5404 if (surface
) window_surface_release( surface
);
5406 /* send WM_NCCREATE */
5408 TRACE( "hwnd %p cs %d,%d %dx%d %s\n", hwnd
, cs
.x
, cs
.y
, cs
.cx
, cs
.cy
, wine_dbgstr_rect(&rect
) );
5409 if (!send_message_timeout( hwnd
, WM_NCCREATE
, 0, (LPARAM
)&cs
, SMTO_NORMAL
, 0, ansi
))
5411 WARN( "%p: aborted by WM_NCCREATE\n", hwnd
);
5415 /* create default IME window */
5417 if (!is_desktop_window( hwnd
) && parent
!= get_hwnd_message_parent() &&
5418 register_imm_window( hwnd
))
5420 TRACE( "register IME window for %p\n", hwnd
);
5421 win_set_flags( hwnd
, WIN_HAS_IME_WIN
, 0 );
5424 /* send WM_NCCALCSIZE */
5426 if (get_window_rects( hwnd
, COORDS_PARENT
, &rect
, NULL
, win_dpi
))
5428 /* yes, even if the CBT hook was called with HWND_TOP */
5429 HWND insert_after
= (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) ? HWND_BOTTOM
: HWND_TOP
;
5430 RECT client_rect
= rect
;
5432 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
5433 map_window_points( parent
, 0, (POINT
*)&client_rect
, 2, win_dpi
);
5434 send_message( hwnd
, WM_NCCALCSIZE
, FALSE
, (LPARAM
)&client_rect
);
5435 map_window_points( 0, parent
, (POINT
*)&client_rect
, 2, win_dpi
);
5437 surface
= create_window_surface( hwnd
, SWP_NOACTIVATE
, FALSE
, &rect
, &client_rect
, &visible_rect
, &surface_rect
);
5438 apply_window_pos( hwnd
, insert_after
, SWP_NOACTIVATE
, surface
, &rect
, &client_rect
, &visible_rect
, NULL
);
5439 if (surface
) window_surface_release( surface
);
5443 /* send WM_CREATE */
5444 if (send_message_timeout( hwnd
, WM_CREATE
, 0, (LPARAM
)&cs
, SMTO_NORMAL
, 0, ansi
) == -1)
5447 /* call the driver */
5449 if (!user_driver
->pCreateWindow( hwnd
)) goto failed
;
5451 NtUserNotifyWinEvent( EVENT_OBJECT_CREATE
, hwnd
, OBJID_WINDOW
, 0 );
5453 /* send the size messages */
5455 if (!(win_get_flags( hwnd
) & WIN_NEED_SIZE
))
5457 get_window_rects( hwnd
, COORDS_PARENT
, NULL
, &rect
, win_dpi
);
5458 send_message( hwnd
, WM_SIZE
, SIZE_RESTORED
,
5459 MAKELONG(rect
.right
-rect
.left
, rect
.bottom
-rect
.top
));
5460 send_message( hwnd
, WM_MOVE
, 0, MAKELONG( rect
.left
, rect
.top
) );
5463 /* Show the window, maximizing or minimizing if needed */
5465 style
= set_window_style( hwnd
, 0, WS_MAXIMIZE
| WS_MINIMIZE
);
5466 if (style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
5469 UINT sw_flags
= (style
& WS_MINIMIZE
) ? SW_MINIMIZE
: SW_MAXIMIZE
;
5471 sw_flags
= window_min_maximize( hwnd
, sw_flags
, &new_pos
);
5472 sw_flags
|= SWP_FRAMECHANGED
; /* Frame always gets changed */
5473 if (!(style
& WS_VISIBLE
) || (style
& WS_CHILD
) || get_active_window())
5474 sw_flags
|= SWP_NOACTIVATE
;
5475 NtUserSetWindowPos( hwnd
, 0, new_pos
.left
, new_pos
.top
, new_pos
.right
- new_pos
.left
,
5476 new_pos
.bottom
- new_pos
.top
, sw_flags
);
5479 /* Notify the parent window only */
5481 send_parent_notify( hwnd
, WM_CREATE
);
5482 if (!is_window( hwnd
))
5484 set_thread_dpi_awareness_context( context
);
5488 if (parent
== get_desktop_window())
5489 NtUserPostMessage( parent
, WM_PARENTNOTIFY
, WM_CREATE
, (LPARAM
)hwnd
);
5491 if (cs
.style
& WS_VISIBLE
)
5493 if (cs
.style
& WS_MAXIMIZE
)
5495 else if (cs
.style
& WS_MINIMIZE
)
5496 sw
= SW_SHOWMINIMIZED
;
5498 NtUserShowWindow( hwnd
, sw
);
5499 if (cs
.dwExStyle
& WS_EX_MDICHILD
)
5501 send_message( cs
.hwndParent
, WM_MDIREFRESHMENU
, 0, 0 );
5502 /* ShowWindow won't activate child windows */
5503 NtUserSetWindowPos( hwnd
, HWND_TOP
, 0, 0, 0, 0, SWP_SHOWWINDOW
| SWP_NOMOVE
| SWP_NOSIZE
);
5507 /* Call WH_SHELL hook */
5509 if (!(get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) && !get_window_relative( hwnd
, GW_OWNER
))
5510 call_hooks( WH_SHELL
, HSHELL_WINDOWCREATED
, (WPARAM
)hwnd
, 0, 0 );
5512 TRACE( "created window %p\n", hwnd
);
5513 set_thread_dpi_awareness_context( context
);
5517 destroy_window( hwnd
);
5518 set_thread_dpi_awareness_context( context
);
5522 static void *get_dialog_info( HWND hwnd
)
5527 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
)
5529 RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE
);
5534 release_win_ptr( win
);
5538 static BOOL
set_dialog_info( HWND hwnd
, void *info
)
5542 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
5543 win
->dlgInfo
= info
;
5544 release_win_ptr( win
);
5548 /*****************************************************************************
5549 * NtUserCallHwnd (win32u.@)
5551 ULONG_PTR WINAPI
NtUserCallHwnd( HWND hwnd
, DWORD code
)
5555 case NtUserCallHwnd_ActivateOtherWindow
:
5556 activate_other_window( hwnd
);
5559 case NtUserCallHwnd_ArrangeIconicWindows
:
5560 return arrange_iconic_windows( hwnd
);
5562 case NtUserCallHwnd_DrawMenuBar
:
5563 return draw_menu_bar( hwnd
);
5565 case NtUserCallHwnd_GetDefaultImeWindow
:
5566 return HandleToUlong( get_default_ime_window( hwnd
));
5568 case NtUserCallHwnd_GetDpiForWindow
:
5569 return get_dpi_for_window( hwnd
);
5571 case NtUserCallHwnd_GetParent
:
5572 return HandleToUlong( get_parent( hwnd
));
5574 case NtUserCallHwnd_GetDialogInfo
:
5575 return (ULONG_PTR
)get_dialog_info( hwnd
);
5577 case NtUserCallHwnd_GetMDIClientInfo
:
5578 if (!(win_get_flags( hwnd
) & WIN_ISMDICLIENT
)) return 0;
5579 return get_window_long_ptr( hwnd
, sizeof(void *), FALSE
);
5581 case NtUserCallHwnd_GetWindowContextHelpId
:
5582 return get_window_context_help_id( hwnd
);
5584 case NtUserCallHwnd_GetWindowDpiAwarenessContext
:
5585 return get_window_dpi_awareness_context( hwnd
);
5587 case NtUserCallHwnd_GetWindowInputContext
:
5588 return HandleToUlong( get_window_input_context( hwnd
));
5590 case NtUserCallHwnd_GetWindowSysSubMenu
:
5591 return HandleToUlong( get_window_sys_sub_menu( hwnd
));
5593 case NtUserCallHwnd_GetWindowTextLength
:
5594 return get_server_window_text( hwnd
, NULL
, 0 );
5596 case NtUserCallHwnd_IsWindow
:
5597 return is_window( hwnd
);
5599 case NtUserCallHwnd_IsWindowEnabled
:
5600 return is_window_enabled( hwnd
);
5602 case NtUserCallHwnd_IsWindowUnicode
:
5603 return is_window_unicode( hwnd
);
5605 case NtUserCallHwnd_IsWindowVisible
:
5606 return is_window_visible( hwnd
);
5608 case NtUserCallHwnd_SetForegroundWindow
:
5609 return set_foreground_window( hwnd
, FALSE
);
5611 case NtUserCallHwnd_SetProgmanWindow
:
5612 return HandleToUlong( set_progman_window( hwnd
));
5614 case NtUserCallHwnd_SetTaskmanWindow
:
5615 return HandleToUlong( set_taskman_window( hwnd
));
5617 /* temporary exports */
5618 case NtUserGetFullWindowHandle
:
5619 return HandleToUlong( get_full_window_handle( hwnd
));
5621 case NtUserIsCurrentProcessWindow
:
5622 return HandleToUlong( is_current_process_window( hwnd
));
5624 case NtUserIsCurrentThreadWindow
:
5625 return HandleToUlong( is_current_thread_window( hwnd
));
5628 FIXME( "invalid code %u\n", (int)code
);
5633 /*****************************************************************************
5634 * NtUserCallHwndParam (win32u.@)
5636 ULONG_PTR WINAPI
NtUserCallHwndParam( HWND hwnd
, DWORD_PTR param
, DWORD code
)
5640 case NtUserCallHwndParam_ClientToScreen
:
5641 return client_to_screen( hwnd
, (POINT
*)param
);
5643 case NtUserCallHwndParam_EnableWindow
:
5644 return enable_window( hwnd
, param
);
5646 case NtUserCallHwndParam_GetChildRect
:
5647 return get_window_rects( hwnd
, COORDS_PARENT
, (RECT
*)param
, NULL
, get_thread_dpi() );
5649 case NtUserCallHwndParam_GetClassLongA
:
5650 return get_class_long( hwnd
, param
, TRUE
);
5652 case NtUserCallHwndParam_GetClassLongW
:
5653 return get_class_long( hwnd
, param
, FALSE
);
5655 case NtUserCallHwndParam_GetClassLongPtrA
:
5656 return get_class_long_ptr( hwnd
, param
, TRUE
);
5658 case NtUserCallHwndParam_GetClassLongPtrW
:
5659 return get_class_long_ptr( hwnd
, param
, FALSE
);
5661 case NtUserCallHwndParam_GetClassWord
:
5662 return get_class_word( hwnd
, param
);
5664 case NtUserCallHwndParam_GetScrollInfo
:
5666 struct get_scroll_info_params
*params
= (void *)param
;
5667 return get_scroll_info( hwnd
, params
->bar
, params
->info
);
5670 case NtUserCallHwndParam_GetWindowInfo
:
5671 return get_window_info( hwnd
, (WINDOWINFO
*)param
);
5673 case NtUserCallHwndParam_GetWindowLongA
:
5674 return get_window_long_size( hwnd
, param
, sizeof(LONG
), TRUE
);
5676 case NtUserCallHwndParam_GetWindowLongW
:
5677 return get_window_long( hwnd
, param
);
5679 case NtUserCallHwndParam_GetWindowLongPtrA
:
5680 return get_window_long_ptr( hwnd
, param
, TRUE
);
5682 case NtUserCallHwndParam_GetWindowLongPtrW
:
5683 return get_window_long_ptr( hwnd
, param
, FALSE
);
5685 case NtUserCallHwndParam_GetWindowRects
:
5687 struct get_window_rects_params
*params
= (void *)param
;
5688 return params
->client
? get_client_rect( hwnd
, params
->rect
, params
->dpi
)
5689 : get_window_rect( hwnd
, params
->rect
, params
->dpi
);
5692 case NtUserCallHwndParam_GetWindowRelative
:
5693 return HandleToUlong( get_window_relative( hwnd
, param
));
5695 case NtUserCallHwndParam_GetWindowThread
:
5696 return get_window_thread( hwnd
, (DWORD
*)param
);
5698 case NtUserCallHwndParam_GetWindowWord
:
5699 return get_window_word( hwnd
, param
);
5701 case NtUserCallHwndParam_IsChild
:
5702 return is_child( hwnd
, UlongToHandle(param
) );
5704 case NtUserCallHwndParam_KillSystemTimer
:
5705 return kill_system_timer( hwnd
, param
);
5707 case NtUserCallHwndParam_MapWindowPoints
:
5709 struct map_window_points_params
*params
= (void *)param
;
5710 return map_window_points( hwnd
, params
->hwnd_to
, params
->points
, params
->count
, params
->dpi
);
5713 case NtUserCallHwndParam_MirrorRgn
:
5714 return mirror_window_region( hwnd
, UlongToHandle(param
) );
5716 case NtUserCallHwndParam_MonitorFromWindow
:
5717 return HandleToUlong( monitor_from_window( hwnd
, param
, get_thread_dpi() ));
5719 case NtUserCallHwndParam_ScreenToClient
:
5720 return screen_to_client( hwnd
, (POINT
*)param
);
5722 case NtUserCallHwndParam_SetDialogInfo
:
5723 return set_dialog_info( hwnd
, (void *)param
);
5725 case NtUserCallHwndParam_SetMDIClientInfo
:
5726 NtUserSetWindowLongPtr( hwnd
, sizeof(void *), param
, FALSE
);
5727 return win_set_flags( hwnd
, WIN_ISMDICLIENT
, 0 );
5729 case NtUserCallHwndParam_SetWindowContextHelpId
:
5730 return set_window_context_help_id( hwnd
, param
);
5732 case NtUserCallHwndParam_ShowOwnedPopups
:
5733 return show_owned_popups( hwnd
, param
);
5735 case NtUserCallHwndParam_SendHardwareInput
:
5737 struct send_hardware_input_params
*params
= (void *)param
;
5738 return send_hardware_message( hwnd
, params
->flags
, params
->input
, params
->lparam
);
5741 /* temporary exports */
5742 case NtUserSetWindowStyle
:
5744 STYLESTRUCT
*style
= (void *)param
;
5745 return set_window_style( hwnd
, style
->styleNew
, style
->styleOld
);
5749 FIXME( "invalid code %u\n", (int)code
);
5754 /*******************************************************************
5755 * NtUserDragDetect (win32u.@)
5757 BOOL WINAPI
NtUserDragDetect( HWND hwnd
, int x
, int y
)
5763 TRACE( "%p (%d,%d)\n", hwnd
, x
, y
);
5765 if (!(NtUserGetKeyState( VK_LBUTTON
) & 0x8000)) return FALSE
;
5767 width
= get_system_metrics( SM_CXDRAG
);
5768 height
= get_system_metrics( SM_CYDRAG
);
5769 SetRect( &rect
, x
- width
, y
- height
, x
+ width
, y
+ height
);
5771 NtUserSetCapture( hwnd
);
5775 while (NtUserPeekMessage( &msg
, 0, WM_MOUSEFIRST
, WM_MOUSELAST
, PM_REMOVE
))
5777 if (msg
.message
== WM_LBUTTONUP
)
5782 if (msg
.message
== WM_MOUSEMOVE
)
5785 tmp
.x
= (short)LOWORD( msg
.lParam
);
5786 tmp
.y
= (short)HIWORD( msg
.lParam
);
5787 if (!PtInRect( &rect
, tmp
))
5794 NtUserMsgWaitForMultipleObjectsEx( 0, NULL
, INFINITE
, QS_ALLINPUT
, 0 );
5799 /*******************************************************************
5800 * NtUserDragObject (win32u.@)
5802 DWORD WINAPI
NtUserDragObject( HWND parent
, HWND hwnd
, UINT fmt
, ULONG_PTR data
, HCURSOR cursor
)
5804 FIXME( "%p, %p, %u, %#lx, %p stub!\n", parent
, hwnd
, fmt
, data
, cursor
);
5810 HWND
get_shell_window(void)
5814 SERVER_START_REQ(set_global_windows
)
5817 if (!wine_server_call_err(req
))
5818 hwnd
= wine_server_ptr_handle( reply
->old_shell_window
);
5825 /***********************************************************************
5826 * NtUserSetShellWindowEx (win32u.@)
5828 BOOL WINAPI
NtUserSetShellWindowEx( HWND shell
, HWND list_view
)
5832 /* shell = Progman[Program Manager]
5833 * |-> SHELLDLL_DefView
5834 * list_view = | |-> SysListView32
5835 * | | |-> tooltips_class32
5842 if (get_shell_window())
5845 if (get_window_long( shell
, GWL_EXSTYLE
) & WS_EX_TOPMOST
)
5848 if (list_view
!= shell
&& (get_window_long( list_view
, GWL_EXSTYLE
) & WS_EX_TOPMOST
))
5851 if (list_view
&& list_view
!= shell
)
5852 NtUserSetWindowPos( list_view
, HWND_BOTTOM
, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
5854 NtUserSetWindowPos( shell
, HWND_BOTTOM
, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
5856 SERVER_START_REQ(set_global_windows
)
5858 req
->flags
= SET_GLOBAL_SHELL_WINDOWS
;
5859 req
->shell_window
= wine_server_user_handle( shell
);
5860 req
->shell_listview
= wine_server_user_handle( list_view
);
5861 ret
= !wine_server_call_err(req
);
5867 HWND
get_progman_window(void)
5871 SERVER_START_REQ(set_global_windows
)
5874 if (!wine_server_call_err(req
))
5875 ret
= wine_server_ptr_handle( reply
->old_progman_window
);
5881 HWND
set_progman_window( HWND hwnd
)
5883 SERVER_START_REQ(set_global_windows
)
5885 req
->flags
= SET_GLOBAL_PROGMAN_WINDOW
;
5886 req
->progman_window
= wine_server_user_handle( hwnd
);
5887 if (wine_server_call_err( req
)) hwnd
= 0;
5893 HWND
get_taskman_window(void)
5897 SERVER_START_REQ(set_global_windows
)
5900 if (!wine_server_call_err(req
))
5901 ret
= wine_server_ptr_handle( reply
->old_taskman_window
);
5907 HWND
set_taskman_window( HWND hwnd
)
5909 /* hwnd = MSTaskSwWClass
5910 * |-> SysTabControl32
5912 SERVER_START_REQ(set_global_windows
)
5914 req
->flags
= SET_GLOBAL_TASKMAN_WINDOW
;
5915 req
->taskman_window
= wine_server_user_handle( hwnd
);
5916 if (wine_server_call_err( req
)) hwnd
= 0;