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 /***********************************************************************
54 HANDLE
alloc_user_handle( struct user_object
*ptr
, unsigned int type
)
58 SERVER_START_REQ( alloc_user_handle
)
60 if (!wine_server_call_err( req
)) handle
= wine_server_ptr_handle( reply
->handle
);
66 UINT index
= USER_HANDLE_TO_INDEX( handle
);
68 assert( index
< NB_USER_HANDLES
);
71 InterlockedExchangePointer( &user_handles
[index
], ptr
);
76 /***********************************************************************
79 void *get_user_handle_ptr( HANDLE handle
, unsigned int type
)
81 struct user_object
*ptr
;
82 WORD index
= USER_HANDLE_TO_INDEX( handle
);
84 if (index
>= NB_USER_HANDLES
) return NULL
;
87 if ((ptr
= user_handles
[index
]))
89 if (ptr
->type
== type
&&
90 ((UINT
)(UINT_PTR
)ptr
->handle
== (UINT
)(UINT_PTR
)handle
||
91 !HIWORD(handle
) || HIWORD(handle
) == 0xffff))
95 else ptr
= OBJ_OTHER_PROCESS
;
100 /***********************************************************************
101 * set_user_handle_ptr
103 static void set_user_handle_ptr( HANDLE handle
, struct user_object
*ptr
)
105 WORD index
= USER_HANDLE_TO_INDEX(handle
);
106 assert( index
< NB_USER_HANDLES
);
107 InterlockedExchangePointer( &user_handles
[index
], ptr
);
110 /***********************************************************************
111 * release_user_handle_ptr
113 void release_user_handle_ptr( void *ptr
)
115 assert( ptr
&& ptr
!= OBJ_OTHER_PROCESS
);
119 /***********************************************************************
122 void *free_user_handle( HANDLE handle
, unsigned int type
)
124 struct user_object
*ptr
;
125 WORD index
= USER_HANDLE_TO_INDEX( handle
);
127 if ((ptr
= get_user_handle_ptr( handle
, type
)) && ptr
!= OBJ_OTHER_PROCESS
)
129 SERVER_START_REQ( free_user_handle
)
131 req
->handle
= wine_server_user_handle( handle
);
132 if (wine_server_call( req
)) ptr
= NULL
;
133 else InterlockedCompareExchangePointer( &user_handles
[index
], NULL
, ptr
);
141 /***********************************************************************
144 static WND
*next_thread_window_ptr( HWND
*hwnd
)
146 struct user_object
*ptr
;
148 WORD index
= *hwnd
? USER_HANDLE_TO_INDEX( *hwnd
) + 1 : 0;
150 while (index
< NB_USER_HANDLES
)
152 if (!(ptr
= user_handles
[index
++])) continue;
153 if (ptr
->type
!= NTUSER_OBJ_WINDOW
) continue;
155 if (win
->tid
!= GetCurrentThreadId()) continue;
162 /*******************************************************************
163 * get_hwnd_message_parent
165 * Return the parent for HWND_MESSAGE windows.
167 HWND
get_hwnd_message_parent(void)
169 struct user_thread_info
*thread_info
= get_user_thread_info();
171 if (!thread_info
->msg_window
) get_desktop_window(); /* trigger creation */
172 return thread_info
->msg_window
;
175 /***********************************************************************
176 * get_full_window_handle
178 * Convert a possibly truncated window handle to a full 32-bit handle.
180 HWND
get_full_window_handle( HWND hwnd
)
184 if (!hwnd
|| (ULONG_PTR
)hwnd
>> 16) return hwnd
;
185 if (LOWORD(hwnd
) <= 1 || LOWORD(hwnd
) == 0xffff) return hwnd
;
186 /* do sign extension for -2 and -3 */
187 if (LOWORD(hwnd
) >= (WORD
)-3) return (HWND
)(LONG_PTR
)(INT16
)LOWORD(hwnd
);
189 if (!(win
= get_win_ptr( hwnd
))) return hwnd
;
191 if (win
== WND_DESKTOP
)
193 if (LOWORD(hwnd
) == LOWORD(get_desktop_window())) return get_desktop_window();
194 else return get_hwnd_message_parent();
197 if (win
!= WND_OTHER_PROCESS
)
199 hwnd
= win
->obj
.handle
;
200 release_win_ptr( win
);
202 else /* may belong to another process */
204 SERVER_START_REQ( get_window_info
)
206 req
->handle
= wine_server_user_handle( hwnd
);
207 if (!wine_server_call_err( req
)) hwnd
= wine_server_ptr_handle( reply
->full_handle
);
214 /*******************************************************************
217 * Check if window is the desktop or the HWND_MESSAGE top parent.
219 BOOL
is_desktop_window( HWND hwnd
)
221 struct user_thread_info
*thread_info
= get_user_thread_info();
223 if (!hwnd
) return FALSE
;
224 if (hwnd
== thread_info
->top_window
) return TRUE
;
225 if (hwnd
== thread_info
->msg_window
) return TRUE
;
227 if (!HIWORD(hwnd
) || HIWORD(hwnd
) == 0xffff)
229 if (LOWORD(thread_info
->top_window
) == LOWORD(hwnd
)) return TRUE
;
230 if (LOWORD(thread_info
->msg_window
) == LOWORD(hwnd
)) return TRUE
;
235 /***********************************************************************
238 * Return a pointer to the WND structure if local to the process,
239 * or WND_OTHER_PROCESS if handle may be valid in other process.
240 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
242 WND
*get_win_ptr( HWND hwnd
)
246 if ((win
= get_user_handle_ptr( hwnd
, NTUSER_OBJ_WINDOW
)) == WND_OTHER_PROCESS
)
248 if (is_desktop_window( hwnd
)) win
= WND_DESKTOP
;
253 /***********************************************************************
254 * is_current_thread_window
256 * Check whether a given window belongs to the current process (and return the full handle).
258 HWND
is_current_thread_window( HWND hwnd
)
263 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
)
265 if (win
->tid
== GetCurrentThreadId()) ret
= win
->obj
.handle
;
266 release_win_ptr( win
);
270 /***********************************************************************
271 * is_current_process_window
273 * Check whether a given window belongs to the current process (and return the full handle).
275 HWND
is_current_process_window( HWND hwnd
)
280 if (!(ptr
= get_win_ptr( hwnd
)) || ptr
== WND_OTHER_PROCESS
|| ptr
== WND_DESKTOP
) return 0;
281 ret
= ptr
->obj
.handle
;
282 release_win_ptr( ptr
);
287 BOOL
is_window( HWND hwnd
)
292 if (!(win
= get_win_ptr( hwnd
))) return FALSE
;
293 if (win
== WND_DESKTOP
) return TRUE
;
295 if (win
!= WND_OTHER_PROCESS
)
297 release_win_ptr( win
);
301 /* check other processes */
302 SERVER_START_REQ( get_window_info
)
304 req
->handle
= wine_server_user_handle( hwnd
);
305 ret
= !wine_server_call_err( req
);
311 /* see GetWindowThreadProcessId */
312 DWORD
get_window_thread( HWND hwnd
, DWORD
*process
)
317 if (!(ptr
= get_win_ptr( hwnd
)))
319 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
323 if (ptr
!= WND_OTHER_PROCESS
&& ptr
!= WND_DESKTOP
)
325 /* got a valid window */
327 if (process
) *process
= GetCurrentProcessId();
328 release_win_ptr( ptr
);
332 /* check other processes */
333 SERVER_START_REQ( get_window_info
)
335 req
->handle
= wine_server_user_handle( hwnd
);
336 if (!wine_server_call_err( req
))
338 tid
= (DWORD
)reply
->tid
;
339 if (process
) *process
= (DWORD
)reply
->pid
;
347 static HWND
get_parent( HWND hwnd
)
352 if (!(win
= get_win_ptr( hwnd
)))
354 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
357 if (win
== WND_DESKTOP
) return 0;
358 if (win
== WND_OTHER_PROCESS
)
360 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
361 if (style
& (WS_POPUP
| WS_CHILD
))
363 SERVER_START_REQ( get_window_tree
)
365 req
->handle
= wine_server_user_handle( hwnd
);
366 if (!wine_server_call_err( req
))
368 if (style
& WS_POPUP
) retval
= wine_server_ptr_handle( reply
->owner
);
369 else if (style
& WS_CHILD
) retval
= wine_server_ptr_handle( reply
->parent
);
377 if (win
->dwStyle
& WS_POPUP
) retval
= win
->owner
;
378 else if (win
->dwStyle
& WS_CHILD
) retval
= win
->parent
;
379 release_win_ptr( win
);
384 /*****************************************************************
385 * NtUserSetParent (win32u.@)
387 HWND WINAPI
NtUserSetParent( HWND hwnd
, HWND parent
)
389 RECT window_rect
, old_screen_rect
, new_screen_rect
;
390 DPI_AWARENESS_CONTEXT context
;
398 TRACE("(%p %p)\n", hwnd
, parent
);
400 if (is_broadcast(hwnd
) || is_broadcast(parent
))
402 SetLastError(ERROR_INVALID_PARAMETER
);
406 if (!parent
) parent
= get_desktop_window();
407 else if (parent
== HWND_MESSAGE
) parent
= get_hwnd_message_parent();
408 else parent
= get_full_window_handle( parent
);
410 if (!is_window( parent
))
412 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
416 /* Some applications try to set a child as a parent */
417 if (is_child( hwnd
, parent
))
419 SetLastError( ERROR_INVALID_PARAMETER
);
423 if (!(full_handle
= is_current_thread_window( hwnd
)))
424 return UlongToHandle( send_message( hwnd
, WM_WINE_SETPARENT
, (WPARAM
)parent
, 0 ));
426 if (full_handle
== parent
)
428 SetLastError( ERROR_INVALID_PARAMETER
);
432 /* Windows hides the window first, then shows it again
433 * including the WM_SHOWWINDOW messages and all */
434 was_visible
= NtUserShowWindow( hwnd
, SW_HIDE
);
436 win
= get_win_ptr( hwnd
);
437 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return 0;
439 get_window_rects( hwnd
, COORDS_PARENT
, &window_rect
, NULL
, get_dpi_for_window(hwnd
) );
440 get_window_rects( hwnd
, COORDS_SCREEN
, &old_screen_rect
, NULL
, 0 );
442 SERVER_START_REQ( set_parent
)
444 req
->handle
= wine_server_user_handle( hwnd
);
445 req
->parent
= wine_server_user_handle( parent
);
446 if ((ret
= !wine_server_call_err( req
)))
448 old_parent
= wine_server_ptr_handle( reply
->old_parent
);
449 win
->parent
= parent
= wine_server_ptr_handle( reply
->full_parent
);
450 win
->dpi
= reply
->dpi
;
451 win
->dpi_awareness
= reply
->awareness
;
456 release_win_ptr( win
);
459 get_window_rects( hwnd
, COORDS_SCREEN
, &new_screen_rect
, NULL
, 0 );
460 context
= set_thread_dpi_awareness_context( get_window_dpi_awareness_context( hwnd
));
462 user_driver
->pSetParent( full_handle
, parent
, old_parent
);
465 winpos
.hwndInsertAfter
= HWND_TOP
;
466 winpos
.x
= window_rect
.left
;
467 winpos
.y
= window_rect
.top
;
470 winpos
.flags
= SWP_NOSIZE
;
472 set_window_pos( &winpos
, new_screen_rect
.left
- old_screen_rect
.left
,
473 new_screen_rect
.top
- old_screen_rect
.top
);
475 if (was_visible
) NtUserShowWindow( hwnd
, SW_SHOW
);
477 set_thread_dpi_awareness_context( context
);
482 static HWND
get_window_relative( HWND hwnd
, UINT rel
)
486 if (rel
== GW_OWNER
) /* this one may be available locally */
488 WND
*win
= get_win_ptr( hwnd
);
491 SetLastError( ERROR_INVALID_HANDLE
);
494 if (win
== WND_DESKTOP
) return 0;
495 if (win
!= WND_OTHER_PROCESS
)
498 release_win_ptr( win
);
501 /* else fall through to server call */
504 SERVER_START_REQ( get_window_tree
)
506 req
->handle
= wine_server_user_handle( hwnd
);
507 if (!wine_server_call_err( req
))
512 retval
= wine_server_ptr_handle( reply
->first_sibling
);
515 retval
= wine_server_ptr_handle( reply
->last_sibling
);
518 retval
= wine_server_ptr_handle( reply
->next_sibling
);
521 retval
= wine_server_ptr_handle( reply
->prev_sibling
);
524 retval
= wine_server_ptr_handle( reply
->owner
);
527 retval
= wine_server_ptr_handle( reply
->first_child
);
536 /*******************************************************************
537 * list_window_parents
539 * Build an array of all parents of a given window, starting with
540 * the immediate parent. The array must be freed with free().
542 static HWND
*list_window_parents( HWND hwnd
)
546 int i
, pos
= 0, size
= 16, count
;
548 if (!(list
= malloc( size
* sizeof(HWND
) ))) return NULL
;
553 if (!(win
= get_win_ptr( current
))) goto empty
;
554 if (win
== WND_OTHER_PROCESS
) break; /* need to do it the hard way */
555 if (win
== WND_DESKTOP
)
557 if (!pos
) goto empty
;
561 list
[pos
] = current
= win
->parent
;
562 release_win_ptr( win
);
563 if (!current
) return list
;
564 if (++pos
== size
- 1)
566 /* need to grow the list */
567 HWND
*new_list
= realloc( list
, (size
+ 16) * sizeof(HWND
) );
568 if (!new_list
) goto empty
;
574 /* at least one parent belongs to another process, have to query the server */
579 SERVER_START_REQ( get_window_parents
)
581 req
->handle
= wine_server_user_handle( hwnd
);
582 wine_server_set_reply( req
, list
, (size
-1) * sizeof(user_handle_t
) );
583 if (!wine_server_call( req
)) count
= reply
->count
;
586 if (!count
) goto empty
;
589 /* start from the end since HWND is potentially larger than user_handle_t */
590 for (i
= count
- 1; i
>= 0; i
--)
591 list
[i
] = wine_server_ptr_handle( ((user_handle_t
*)list
)[i
] );
597 if (!(list
= malloc( size
* sizeof(HWND
) ))) return NULL
;
605 /*******************************************************************
606 * list_window_children
608 * Build an array of the children of a given window. The array must be
609 * freed with HeapFree. Returns NULL when no windows are found.
611 HWND
*list_window_children( HDESK desktop
, HWND hwnd
, UNICODE_STRING
*class, DWORD tid
)
615 ATOM atom
= class ? get_int_atom_value( class ) : 0;
617 /* empty class is not the same as NULL class */
618 if (!atom
&& class && !class->Length
) return NULL
;
624 if (!(list
= malloc( size
* sizeof(HWND
) ))) break;
626 SERVER_START_REQ( get_window_children
)
628 req
->desktop
= wine_server_obj_handle( desktop
);
629 req
->parent
= wine_server_user_handle( hwnd
);
632 if (!atom
&& class) wine_server_add_data( req
, class->Buffer
, class->Length
);
633 wine_server_set_reply( req
, list
, (size
-1) * sizeof(user_handle_t
) );
634 if (!wine_server_call( req
)) count
= reply
->count
;
637 if (count
&& count
< size
)
639 /* start from the end since HWND is potentially larger than user_handle_t */
640 for (i
= count
- 1; i
>= 0; i
--)
641 list
[i
] = wine_server_ptr_handle( ((user_handle_t
*)list
)[i
] );
647 size
= count
+ 1; /* restart with a large enough buffer */
652 /*****************************************************************
653 * NtUserGetAncestor (win32u.@)
655 HWND WINAPI
NtUserGetAncestor( HWND hwnd
, UINT type
)
663 if (!(win
= get_win_ptr( hwnd
)))
665 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
668 if (win
== WND_DESKTOP
) return 0;
669 if (win
!= WND_OTHER_PROCESS
)
672 release_win_ptr( win
);
674 else /* need to query the server */
676 SERVER_START_REQ( get_window_tree
)
678 req
->handle
= wine_server_user_handle( hwnd
);
679 if (!wine_server_call_err( req
)) ret
= wine_server_ptr_handle( reply
->parent
);
686 if (!(list
= list_window_parents( hwnd
))) return 0;
688 if (!list
[0] || !list
[1]) ret
= get_full_window_handle( hwnd
); /* top-level window */
692 while (list
[count
]) count
++;
693 ret
= list
[count
- 2]; /* get the one before the desktop */
699 if (is_desktop_window( hwnd
)) return 0;
700 ret
= get_full_window_handle( hwnd
);
703 HWND parent
= get_parent( ret
);
713 BOOL
is_child( HWND parent
, HWND child
)
719 if (!(get_window_long( child
, GWL_STYLE
) & WS_CHILD
)) return FALSE
;
720 if (!(list
= list_window_parents( child
))) return FALSE
;
721 parent
= get_full_window_handle( parent
);
722 for (i
= 0; list
[i
]; i
++)
724 if (list
[i
] == parent
)
726 ret
= list
[i
] && list
[i
+1];
729 if (!(get_window_long( list
[i
], GWL_STYLE
) & WS_CHILD
)) break;
735 /* see IsWindowVisible */
736 static BOOL
is_window_visible( HWND hwnd
)
742 if (!(get_window_long( hwnd
, GWL_STYLE
) & WS_VISIBLE
)) return FALSE
;
743 if (!(list
= list_window_parents( hwnd
))) return TRUE
;
746 for (i
= 0; list
[i
+1]; i
++)
747 if (!(get_window_long( list
[i
], GWL_STYLE
) & WS_VISIBLE
)) break;
748 retval
= !list
[i
+1] && (list
[i
] == get_desktop_window()); /* top message window isn't visible */
754 /***********************************************************************
757 * hwnd is drawable when it is visible, all parents are not
758 * minimized, and it is itself not minimized unless we are
759 * trying to draw its default class icon.
761 static BOOL
is_window_drawable( HWND hwnd
, BOOL icon
)
766 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
768 if (!(style
& WS_VISIBLE
)) return FALSE
;
769 if ((style
& WS_MINIMIZE
) && icon
&& get_class_long_ptr( hwnd
, GCLP_HICON
, FALSE
)) return FALSE
;
771 if (!(list
= list_window_parents( hwnd
))) return TRUE
;
774 for (i
= 0; list
[i
+1]; i
++)
775 if ((get_window_long( list
[i
], GWL_STYLE
) & (WS_VISIBLE
|WS_MINIMIZE
)) != WS_VISIBLE
)
777 retval
= !list
[i
+1] && (list
[i
] == get_desktop_window()); /* top message window isn't visible */
783 /* see IsWindowUnicode */
784 BOOL
is_window_unicode( HWND hwnd
)
789 if (!(win
= get_win_ptr(hwnd
))) return FALSE
;
791 if (win
== WND_DESKTOP
) return TRUE
;
793 if (win
!= WND_OTHER_PROCESS
)
795 ret
= (win
->flags
& WIN_ISUNICODE
) != 0;
796 release_win_ptr( win
);
800 SERVER_START_REQ( get_window_info
)
802 req
->handle
= wine_server_user_handle( hwnd
);
803 if (!wine_server_call_err( req
)) ret
= reply
->is_unicode
;
810 /* see GetWindowDpiAwarenessContext */
811 DPI_AWARENESS_CONTEXT
get_window_dpi_awareness_context( HWND hwnd
)
813 DPI_AWARENESS_CONTEXT ret
= 0;
816 if (!(win
= get_win_ptr( hwnd
)))
818 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
821 if (win
== WND_DESKTOP
) return DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
;
822 if (win
!= WND_OTHER_PROCESS
)
824 ret
= ULongToHandle( win
->dpi_awareness
| 0x10 );
825 release_win_ptr( win
);
829 SERVER_START_REQ( get_window_info
)
831 req
->handle
= wine_server_user_handle( hwnd
);
832 if (!wine_server_call_err( req
)) ret
= ULongToHandle( reply
->awareness
| 0x10 );
839 /* see GetDpiForWindow */
840 UINT
get_dpi_for_window( HWND hwnd
)
845 if (!(win
= get_win_ptr( hwnd
)))
847 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
850 if (win
== WND_DESKTOP
)
853 return get_monitor_dpi( monitor_from_point( pt
, MONITOR_DEFAULTTOPRIMARY
, 0 ));
855 if (win
!= WND_OTHER_PROCESS
)
858 if (!ret
) ret
= get_win_monitor_dpi( hwnd
);
859 release_win_ptr( win
);
863 SERVER_START_REQ( get_window_info
)
865 req
->handle
= wine_server_user_handle( hwnd
);
866 if (!wine_server_call_err( req
)) ret
= reply
->dpi
;
873 static LONG_PTR
get_win_data( const void *ptr
, UINT size
)
875 if (size
== sizeof(WORD
))
878 memcpy( &ret
, ptr
, sizeof(ret
) );
881 else if (size
== sizeof(DWORD
))
884 memcpy( &ret
, ptr
, sizeof(ret
) );
890 memcpy( &ret
, ptr
, sizeof(ret
) );
895 /* helper for set_window_long */
896 static inline void set_win_data( void *ptr
, LONG_PTR val
, UINT size
)
898 if (size
== sizeof(WORD
))
901 memcpy( ptr
, &newval
, sizeof(newval
) );
903 else if (size
== sizeof(DWORD
))
906 memcpy( ptr
, &newval
, sizeof(newval
) );
910 memcpy( ptr
, &val
, sizeof(val
) );
914 BOOL
is_iconic( HWND hwnd
)
916 return (get_window_long( hwnd
, GWL_STYLE
) & WS_MINIMIZE
) != 0;
919 static BOOL
is_zoomed( HWND hwnd
)
921 return (get_window_long( hwnd
, GWL_STYLE
) & WS_MAXIMIZE
) != 0;
924 static LONG_PTR
get_window_long_size( HWND hwnd
, INT offset
, UINT size
, BOOL ansi
)
929 if (offset
== GWLP_HWNDPARENT
)
931 HWND parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
932 if (parent
== get_desktop_window())
933 parent
= get_window_relative( hwnd
, GW_OWNER
);
934 return (ULONG_PTR
)parent
;
937 if (!(win
= get_win_ptr( hwnd
)))
939 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
943 if (win
== WND_DESKTOP
)
948 retval
= WS_POPUP
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
; /* message parent is not visible */
949 if (get_full_window_handle( hwnd
) == get_desktop_window())
950 retval
|= WS_VISIBLE
;
958 SetLastError( ERROR_ACCESS_DENIED
);
961 SetLastError( ERROR_INVALID_INDEX
);
965 if (win
== WND_OTHER_PROCESS
)
967 if (offset
== GWLP_WNDPROC
)
969 SetLastError( ERROR_ACCESS_DENIED
);
972 SERVER_START_REQ( set_window_info
)
974 req
->handle
= wine_server_user_handle( hwnd
);
975 req
->flags
= 0; /* don't set anything, just retrieve */
976 req
->extra_offset
= (offset
>= 0) ? offset
: -1;
977 req
->extra_size
= (offset
>= 0) ? size
: 0;
978 if (!wine_server_call_err( req
))
982 case GWL_STYLE
: retval
= reply
->old_style
; break;
983 case GWL_EXSTYLE
: retval
= reply
->old_ex_style
; break;
984 case GWLP_ID
: retval
= reply
->old_id
; break;
985 case GWLP_HINSTANCE
: retval
= (ULONG_PTR
)wine_server_get_ptr( reply
->old_instance
); break;
986 case GWLP_USERDATA
: retval
= reply
->old_user_data
; break;
988 if (offset
>= 0) retval
= get_win_data( &reply
->old_extra_value
, size
);
989 else SetLastError( ERROR_INVALID_INDEX
);
998 /* now we have a valid win */
1002 if (offset
> (int)(win
->cbWndExtra
- size
))
1004 WARN("Invalid offset %d\n", offset
);
1005 release_win_ptr( win
);
1006 SetLastError( ERROR_INVALID_INDEX
);
1009 retval
= get_win_data( (char *)win
->wExtra
+ offset
, size
);
1011 /* Special case for dialog window procedure */
1012 if ((offset
== DWLP_DLGPROC
) && (size
== sizeof(LONG_PTR
)) && win
->dlgInfo
)
1013 retval
= (LONG_PTR
)get_winproc( (WNDPROC
)retval
, ansi
);
1014 release_win_ptr( win
);
1020 case GWLP_USERDATA
: retval
= win
->userdata
; break;
1021 case GWL_STYLE
: retval
= win
->dwStyle
; break;
1022 case GWL_EXSTYLE
: retval
= win
->dwExStyle
; break;
1023 case GWLP_ID
: retval
= win
->wIDmenu
; break;
1024 case GWLP_HINSTANCE
: retval
= (ULONG_PTR
)win
->hInstance
; break;
1026 /* This looks like a hack only for the edit control (see tests). This makes these controls
1027 * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
1028 * that the hack is in GetWindowLongPtr[AW], not in winprocs.
1030 if (win
->winproc
== BUILTIN_WINPROC(WINPROC_EDIT
) && (!!ansi
!= !(win
->flags
& WIN_ISUNICODE
)))
1031 retval
= (ULONG_PTR
)win
->winproc
;
1033 retval
= (ULONG_PTR
)get_winproc( win
->winproc
, ansi
);
1036 WARN("Unknown offset %d\n", offset
);
1037 SetLastError( ERROR_INVALID_INDEX
);
1040 release_win_ptr( win
);
1044 /* see GetWindowLongW */
1045 DWORD
get_window_long( HWND hwnd
, INT offset
)
1047 return get_window_long_size( hwnd
, offset
, sizeof(LONG
), FALSE
);
1050 /* see GetWindowLongPtr */
1051 static ULONG_PTR
get_window_long_ptr( HWND hwnd
, INT offset
, BOOL ansi
)
1053 return get_window_long_size( hwnd
, offset
, sizeof(LONG_PTR
), ansi
);
1056 /* see GetWindowWord */
1057 static WORD
get_window_word( HWND hwnd
, INT offset
)
1062 case GWLP_HINSTANCE
:
1063 case GWLP_HWNDPARENT
:
1068 WARN("Invalid offset %d\n", offset
);
1069 SetLastError( ERROR_INVALID_INDEX
);
1074 return get_window_long_size( hwnd
, offset
, sizeof(WORD
), TRUE
);
1077 /***********************************************************************
1080 * Change the style of a window.
1082 ULONG
set_window_style( HWND hwnd
, ULONG set_bits
, ULONG clear_bits
)
1084 BOOL ok
, made_visible
= FALSE
;
1086 WND
*win
= get_win_ptr( hwnd
);
1088 if (!win
|| win
== WND_DESKTOP
) return 0;
1089 if (win
== WND_OTHER_PROCESS
)
1091 if (is_window(hwnd
))
1092 return send_message( hwnd
, WM_WINE_SETSTYLE
, set_bits
, clear_bits
);
1095 style
.styleOld
= win
->dwStyle
;
1096 style
.styleNew
= (win
->dwStyle
| set_bits
) & ~clear_bits
;
1097 if (style
.styleNew
== style
.styleOld
)
1099 release_win_ptr( win
);
1100 return style
.styleNew
;
1102 SERVER_START_REQ( set_window_info
)
1104 req
->handle
= wine_server_user_handle( hwnd
);
1105 req
->flags
= SET_WIN_STYLE
;
1106 req
->style
= style
.styleNew
;
1107 req
->extra_offset
= -1;
1108 if ((ok
= !wine_server_call( req
)))
1110 style
.styleOld
= reply
->old_style
;
1111 win
->dwStyle
= style
.styleNew
;
1116 if (ok
&& ((style
.styleOld
^ style
.styleNew
) & WS_VISIBLE
))
1118 made_visible
= (style
.styleNew
& WS_VISIBLE
) != 0;
1119 invalidate_dce( win
, NULL
);
1121 release_win_ptr( win
);
1125 user_driver
->pSetWindowStyle( hwnd
, GWL_STYLE
, &style
);
1126 if (made_visible
) update_window_state( hwnd
);
1128 return style
.styleOld
;
1131 static DWORD
fix_exstyle( DWORD style
, DWORD exstyle
)
1133 if ((exstyle
& WS_EX_DLGMODALFRAME
) ||
1134 (!(exstyle
& WS_EX_STATICEDGE
) && (style
& (WS_DLGFRAME
| WS_THICKFRAME
))))
1135 exstyle
|= WS_EX_WINDOWEDGE
;
1137 exstyle
&= ~WS_EX_WINDOWEDGE
;
1141 /* Change the owner of a window. */
1142 static HWND
set_window_owner( HWND hwnd
, HWND owner
)
1144 WND
*win
= get_win_ptr( hwnd
);
1147 if (!win
|| win
== WND_DESKTOP
) return 0;
1148 if (win
== WND_OTHER_PROCESS
)
1150 if (is_window(hwnd
)) ERR( "cannot set owner %p on other process window %p\n", owner
, hwnd
);
1153 SERVER_START_REQ( set_window_owner
)
1155 req
->handle
= wine_server_user_handle( hwnd
);
1156 req
->owner
= wine_server_user_handle( owner
);
1157 if (!wine_server_call( req
))
1159 win
->owner
= wine_server_ptr_handle( reply
->full_owner
);
1160 ret
= wine_server_ptr_handle( reply
->prev_owner
);
1164 release_win_ptr( win
);
1168 /* Helper function for SetWindowLong(). */
1169 LONG_PTR
set_window_long( HWND hwnd
, INT offset
, UINT size
, LONG_PTR newval
, BOOL ansi
)
1171 BOOL ok
, made_visible
= FALSE
;
1172 LONG_PTR retval
= 0;
1176 TRACE( "%p %d %lx %c\n", hwnd
, offset
, newval
, ansi
? 'A' : 'W' );
1178 if (is_broadcast(hwnd
))
1180 SetLastError( ERROR_INVALID_PARAMETER
);
1184 if (!(win
= get_win_ptr( hwnd
)))
1186 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
1189 if (win
== WND_DESKTOP
)
1191 /* can't change anything on the desktop window */
1192 SetLastError( ERROR_ACCESS_DENIED
);
1195 if (win
== WND_OTHER_PROCESS
)
1197 if (offset
== GWLP_WNDPROC
)
1199 SetLastError( ERROR_ACCESS_DENIED
);
1202 if (offset
> 32767 || offset
< -32767)
1204 SetLastError( ERROR_INVALID_INDEX
);
1207 return send_message( hwnd
, WM_WINE_SETWINDOWLONG
, MAKEWPARAM( offset
, size
), newval
);
1210 /* first some special cases */
1214 style
.styleOld
= win
->dwStyle
;
1215 style
.styleNew
= newval
;
1216 release_win_ptr( win
);
1217 send_message( hwnd
, WM_STYLECHANGING
, GWL_STYLE
, (LPARAM
)&style
);
1218 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
) return 0;
1219 newval
= style
.styleNew
;
1220 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
1221 if (win
->parent
== get_desktop_window()) newval
|= WS_CLIPSIBLINGS
;
1222 /* WS_MINIMIZE can't be reset */
1223 if (win
->dwStyle
& WS_MINIMIZE
) newval
|= WS_MINIMIZE
;
1226 style
.styleOld
= win
->dwExStyle
;
1227 style
.styleNew
= newval
;
1228 release_win_ptr( win
);
1229 send_message( hwnd
, WM_STYLECHANGING
, GWL_EXSTYLE
, (LPARAM
)&style
);
1230 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
) return 0;
1231 /* WS_EX_TOPMOST can only be changed through SetWindowPos */
1232 newval
= (style
.styleNew
& ~WS_EX_TOPMOST
) | (win
->dwExStyle
& WS_EX_TOPMOST
);
1233 newval
= fix_exstyle(win
->dwStyle
, newval
);
1235 case GWLP_HWNDPARENT
:
1236 if (win
->parent
== get_desktop_window())
1238 release_win_ptr( win
);
1239 return (ULONG_PTR
)set_window_owner( hwnd
, (HWND
)newval
);
1243 release_win_ptr( win
);
1244 return (ULONG_PTR
)NtUserSetParent( hwnd
, (HWND
)newval
);
1249 UINT old_flags
= win
->flags
;
1250 retval
= get_window_long_ptr( hwnd
, offset
, ansi
);
1251 proc
= alloc_winproc( (WNDPROC
)newval
, ansi
);
1252 if (proc
) win
->winproc
= proc
;
1253 if (is_winproc_unicode( proc
, !ansi
)) win
->flags
|= WIN_ISUNICODE
;
1254 else win
->flags
&= ~WIN_ISUNICODE
;
1255 if (!((old_flags
^ win
->flags
) & WIN_ISUNICODE
))
1257 release_win_ptr( win
);
1260 /* update is_unicode flag on the server side */
1264 case GWLP_HINSTANCE
:
1268 if ((win
->cbWndExtra
- sizeof(LONG_PTR
) >= DWLP_DLGPROC
) &&
1269 (size
== sizeof(LONG_PTR
)) && win
->dlgInfo
)
1271 WNDPROC
*ptr
= (WNDPROC
*)((char *)win
->wExtra
+ DWLP_DLGPROC
);
1272 retval
= (ULONG_PTR
)get_winproc( *ptr
, ansi
);
1273 *ptr
= alloc_winproc( (WNDPROC
)newval
, ansi
);
1274 release_win_ptr( win
);
1279 if (offset
< 0 || offset
> (int)(win
->cbWndExtra
- size
))
1281 WARN("Invalid offset %d\n", offset
);
1282 release_win_ptr( win
);
1283 SetLastError( ERROR_INVALID_INDEX
);
1286 else if (get_win_data( (char *)win
->wExtra
+ offset
, size
) == newval
)
1288 /* already set to the same value */
1289 release_win_ptr( win
);
1295 SERVER_START_REQ( set_window_info
)
1297 req
->handle
= wine_server_user_handle( hwnd
);
1298 req
->extra_offset
= -1;
1302 req
->flags
= SET_WIN_STYLE
| SET_WIN_EXSTYLE
;
1303 req
->style
= newval
;
1304 req
->ex_style
= fix_exstyle(newval
, win
->dwExStyle
);
1307 req
->flags
= SET_WIN_EXSTYLE
;
1308 req
->ex_style
= newval
;
1311 req
->flags
= SET_WIN_ID
;
1312 req
->extra_value
= newval
;
1314 case GWLP_HINSTANCE
:
1315 req
->flags
= SET_WIN_INSTANCE
;
1316 req
->instance
= wine_server_client_ptr( (void *)newval
);
1319 req
->flags
= SET_WIN_UNICODE
;
1320 req
->is_unicode
= (win
->flags
& WIN_ISUNICODE
) != 0;
1323 req
->flags
= SET_WIN_USERDATA
;
1324 req
->user_data
= newval
;
1327 req
->flags
= SET_WIN_EXTRA
;
1328 req
->extra_offset
= offset
;
1329 req
->extra_size
= size
;
1330 set_win_data( &req
->extra_value
, newval
, size
);
1332 if ((ok
= !wine_server_call_err( req
)))
1337 win
->dwStyle
= newval
;
1338 win
->dwExStyle
= fix_exstyle(win
->dwStyle
, win
->dwExStyle
);
1339 retval
= reply
->old_style
;
1342 win
->dwExStyle
= newval
;
1343 retval
= reply
->old_ex_style
;
1346 win
->wIDmenu
= newval
;
1347 retval
= reply
->old_id
;
1349 case GWLP_HINSTANCE
:
1350 win
->hInstance
= (HINSTANCE
)newval
;
1351 retval
= (ULONG_PTR
)wine_server_get_ptr( reply
->old_instance
);
1356 win
->userdata
= newval
;
1357 retval
= reply
->old_user_data
;
1360 retval
= get_win_data( (char *)win
->wExtra
+ offset
, size
);
1361 set_win_data( (char *)win
->wExtra
+ offset
, newval
, size
);
1368 if ((offset
== GWL_STYLE
&& ((style
.styleOld
^ style
.styleNew
) & WS_VISIBLE
)) ||
1369 (offset
== GWL_EXSTYLE
&& ((style
.styleOld
^ style
.styleNew
) & WS_EX_LAYERED
)))
1371 made_visible
= (win
->dwStyle
& WS_VISIBLE
) != 0;
1372 invalidate_dce( win
, NULL
);
1374 release_win_ptr( win
);
1378 if (offset
== GWL_STYLE
|| offset
== GWL_EXSTYLE
)
1380 style
.styleOld
= retval
;
1381 style
.styleNew
= newval
;
1382 user_driver
->pSetWindowStyle( hwnd
, offset
, &style
);
1383 if (made_visible
) update_window_state( hwnd
);
1384 send_message( hwnd
, WM_STYLECHANGED
, offset
, (LPARAM
)&style
);
1390 /**********************************************************************
1391 * NtUserSetWindowWord (win32u.@)
1393 WORD WINAPI
NtUserSetWindowWord( HWND hwnd
, INT offset
, WORD newval
)
1398 case GWLP_HINSTANCE
:
1399 case GWLP_HWNDPARENT
:
1404 WARN("Invalid offset %d\n", offset
);
1405 SetLastError( ERROR_INVALID_INDEX
);
1410 return set_window_long( hwnd
, offset
, sizeof(WORD
), newval
, TRUE
);
1413 /**********************************************************************
1414 * NtUserSetWindowLong (win32u.@)
1416 LONG WINAPI
NtUserSetWindowLong( HWND hwnd
, INT offset
, LONG newval
, BOOL ansi
)
1418 return set_window_long( hwnd
, offset
, sizeof(LONG
), newval
, ansi
);
1421 /*****************************************************************************
1422 * NtUserSetWindowLongPtr (win32u.@)
1424 LONG_PTR WINAPI
NtUserSetWindowLongPtr( HWND hwnd
, INT offset
, LONG_PTR newval
, BOOL ansi
)
1426 return set_window_long( hwnd
, offset
, sizeof(LONG_PTR
), newval
, ansi
);
1429 static BOOL
set_window_pixel_format( HWND hwnd
, int format
)
1431 WND
*win
= get_win_ptr( hwnd
);
1433 if (!win
|| win
== WND_DESKTOP
|| win
== WND_OTHER_PROCESS
)
1435 WARN( "setting format %d on win %p not supported\n", format
, hwnd
);
1438 win
->pixel_format
= format
;
1439 release_win_ptr( win
);
1441 update_window_state( hwnd
);
1445 /***********************************************************************
1446 * NtUserGetProp (win32u.@)
1448 * NOTE Native allows only ATOMs as the second argument. We allow strings
1449 * to save extra server call in GetPropW.
1451 HANDLE WINAPI
NtUserGetProp( HWND hwnd
, const WCHAR
*str
)
1455 SERVER_START_REQ( get_window_property
)
1457 req
->window
= wine_server_user_handle( hwnd
);
1458 if (IS_INTRESOURCE(str
)) req
->atom
= LOWORD(str
);
1459 else wine_server_add_data( req
, str
, lstrlenW(str
) * sizeof(WCHAR
) );
1460 if (!wine_server_call_err( req
)) ret
= reply
->data
;
1466 /*****************************************************************************
1467 * NtUserSetProp (win32u.@)
1469 * NOTE Native allows only ATOMs as the second argument. We allow strings
1470 * to save extra server call in SetPropW.
1472 BOOL WINAPI
NtUserSetProp( HWND hwnd
, const WCHAR
*str
, HANDLE handle
)
1476 SERVER_START_REQ( set_window_property
)
1478 req
->window
= wine_server_user_handle( hwnd
);
1479 req
->data
= (ULONG_PTR
)handle
;
1480 if (IS_INTRESOURCE(str
)) req
->atom
= LOWORD(str
);
1481 else wine_server_add_data( req
, str
, lstrlenW(str
) * sizeof(WCHAR
) );
1482 ret
= !wine_server_call_err( req
);
1489 /***********************************************************************
1490 * NtUserRemoveProp (win32u.@)
1492 * NOTE Native allows only ATOMs as the second argument. We allow strings
1493 * to save extra server call in RemovePropW.
1495 HANDLE WINAPI
NtUserRemoveProp( HWND hwnd
, const WCHAR
*str
)
1499 SERVER_START_REQ( remove_window_property
)
1501 req
->window
= wine_server_user_handle( hwnd
);
1502 if (IS_INTRESOURCE(str
)) req
->atom
= LOWORD(str
);
1503 else wine_server_add_data( req
, str
, lstrlenW(str
) * sizeof(WCHAR
) );
1504 if (!wine_server_call_err( req
)) ret
= reply
->data
;
1511 static void mirror_rect( const RECT
*window_rect
, RECT
*rect
)
1513 int width
= window_rect
->right
- window_rect
->left
;
1514 int tmp
= rect
->left
;
1515 rect
->left
= width
- rect
->right
;
1516 rect
->right
= width
- tmp
;
1519 /***********************************************************************
1522 * Get the window and client rectangles.
1524 BOOL
get_window_rects( HWND hwnd
, enum coords_relative relative
, RECT
*window_rect
,
1525 RECT
*client_rect
, UINT dpi
)
1527 WND
*win
= get_win_ptr( hwnd
);
1532 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
1535 if (win
== WND_DESKTOP
)
1538 rect
.left
= rect
.top
= 0;
1539 if (hwnd
== get_hwnd_message_parent())
1543 rect
= map_dpi_rect( rect
, get_dpi_for_window( hwnd
), dpi
);
1547 rect
= get_primary_monitor_rect( dpi
);
1549 if (window_rect
) *window_rect
= rect
;
1550 if (client_rect
) *client_rect
= rect
;
1553 if (win
!= WND_OTHER_PROCESS
)
1555 UINT window_dpi
= get_dpi_for_window( hwnd
);
1556 RECT window
= win
->window_rect
;
1557 RECT client
= win
->client_rect
;
1562 OffsetRect( &window
, -win
->client_rect
.left
, -win
->client_rect
.top
);
1563 OffsetRect( &client
, -win
->client_rect
.left
, -win
->client_rect
.top
);
1564 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
)
1565 mirror_rect( &win
->client_rect
, &window
);
1568 OffsetRect( &window
, -win
->window_rect
.left
, -win
->window_rect
.top
);
1569 OffsetRect( &client
, -win
->window_rect
.left
, -win
->window_rect
.top
);
1570 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
)
1571 mirror_rect( &win
->window_rect
, &client
);
1576 WND
*parent
= get_win_ptr( win
->parent
);
1577 if (parent
== WND_DESKTOP
) break;
1578 if (!parent
|| parent
== WND_OTHER_PROCESS
)
1580 release_win_ptr( win
);
1583 if (parent
->flags
& WIN_CHILDREN_MOVED
)
1585 release_win_ptr( parent
);
1586 release_win_ptr( win
);
1589 if (parent
->dwExStyle
& WS_EX_LAYOUTRTL
)
1591 mirror_rect( &parent
->client_rect
, &window
);
1592 mirror_rect( &parent
->client_rect
, &client
);
1594 release_win_ptr( parent
);
1600 WND
*parent
= get_win_ptr( win
->parent
);
1601 if (parent
== WND_DESKTOP
) break;
1602 if (!parent
|| parent
== WND_OTHER_PROCESS
)
1604 release_win_ptr( win
);
1607 release_win_ptr( win
);
1608 if (parent
->flags
& WIN_CHILDREN_MOVED
)
1610 release_win_ptr( parent
);
1616 offset_rect( &window
, win
->client_rect
.left
, win
->client_rect
.top
);
1617 offset_rect( &client
, win
->client_rect
.left
, win
->client_rect
.top
);
1622 if (window_rect
) *window_rect
= map_dpi_rect( window
, window_dpi
, dpi
);
1623 if (client_rect
) *client_rect
= map_dpi_rect( client
, window_dpi
, dpi
);
1624 release_win_ptr( win
);
1629 SERVER_START_REQ( get_window_rectangles
)
1631 req
->handle
= wine_server_user_handle( hwnd
);
1632 req
->relative
= relative
;
1634 if ((ret
= !wine_server_call_err( req
)))
1638 window_rect
->left
= reply
->window
.left
;
1639 window_rect
->top
= reply
->window
.top
;
1640 window_rect
->right
= reply
->window
.right
;
1641 window_rect
->bottom
= reply
->window
.bottom
;
1645 client_rect
->left
= reply
->client
.left
;
1646 client_rect
->top
= reply
->client
.top
;
1647 client_rect
->right
= reply
->client
.right
;
1648 client_rect
->bottom
= reply
->client
.bottom
;
1656 /* see GetWindowRect */
1657 BOOL
get_window_rect( HWND hwnd
, RECT
*rect
, UINT dpi
)
1659 return get_window_rects( hwnd
, COORDS_SCREEN
, rect
, NULL
, dpi
);
1662 /* see GetClientRect */
1663 BOOL
get_client_rect( HWND hwnd
, RECT
*rect
)
1665 return get_window_rects( hwnd
, COORDS_CLIENT
, NULL
, rect
, get_thread_dpi() );
1668 /* see GetWindowInfo */
1669 static BOOL
get_window_info( HWND hwnd
, WINDOWINFO
*info
)
1672 if (!info
|| !get_window_rects( hwnd
, COORDS_SCREEN
, &info
->rcWindow
,
1673 &info
->rcClient
, get_thread_dpi() ))
1676 info
->dwStyle
= get_window_long( hwnd
, GWL_STYLE
);
1677 info
->dwExStyle
= get_window_long( hwnd
, GWL_EXSTYLE
);
1678 info
->dwWindowStatus
= get_active_window() == hwnd
? WS_ACTIVECAPTION
: 0;
1679 info
->cxWindowBorders
= info
->rcClient
.left
- info
->rcWindow
.left
;
1680 info
->cyWindowBorders
= info
->rcWindow
.bottom
- info
->rcClient
.bottom
;
1681 info
->atomWindowType
= get_class_long( hwnd
, GCW_ATOM
, FALSE
);
1682 info
->wCreatorVersion
= 0x0400;
1686 /***********************************************************************
1687 * update_surface_region
1689 static void update_surface_region( HWND hwnd
)
1695 WND
*win
= get_win_ptr( hwnd
);
1697 if (!win
|| win
== WND_DESKTOP
|| win
== WND_OTHER_PROCESS
) return;
1698 if (!win
->surface
) goto done
;
1702 if (!(data
= malloc( FIELD_OFFSET( RGNDATA
, Buffer
[size
] )))) goto done
;
1704 SERVER_START_REQ( get_surface_region
)
1706 req
->window
= wine_server_user_handle( hwnd
);
1707 wine_server_set_reply( req
, data
->Buffer
, size
);
1708 if (!(status
= wine_server_call( req
)))
1710 size_t reply_size
= wine_server_reply_size( reply
);
1713 data
->rdh
.dwSize
= sizeof(data
->rdh
);
1714 data
->rdh
.iType
= RDH_RECTANGLES
;
1715 data
->rdh
.nCount
= reply_size
/ sizeof(RECT
);
1716 data
->rdh
.nRgnSize
= reply_size
;
1717 region
= NtGdiExtCreateRegion( NULL
, data
->rdh
.dwSize
+ data
->rdh
.nRgnSize
, data
);
1718 NtGdiOffsetRgn( region
, -reply
->visible_rect
.left
, -reply
->visible_rect
.top
);
1721 else size
= reply
->total_size
;
1725 } while (status
== STATUS_BUFFER_OVERFLOW
);
1727 if (status
) goto done
;
1729 win
->surface
->funcs
->set_region( win
->surface
, region
);
1730 if (region
) NtGdiDeleteObjectApp( region
);
1733 release_win_ptr( win
);
1736 /***********************************************************************
1739 * Backend implementation of SetWindowPos.
1741 static BOOL
apply_window_pos( HWND hwnd
, HWND insert_after
, UINT swp_flags
,
1742 const RECT
*window_rect
, const RECT
*client_rect
, const RECT
*valid_rects
)
1745 HWND surface_win
= 0, parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
1746 BOOL ret
, needs_update
= FALSE
;
1747 RECT visible_rect
, old_visible_rect
, old_window_rect
, old_client_rect
, extra_rects
[3];
1748 struct window_surface
*old_surface
, *new_surface
= NULL
;
1750 if (!parent
|| parent
== get_desktop_window())
1752 new_surface
= &dummy_surface
; /* provide a default surface for top-level windows */
1753 window_surface_add_ref( new_surface
);
1755 visible_rect
= *window_rect
;
1756 if (!(ret
= user_driver
->pWindowPosChanging( hwnd
, insert_after
, swp_flags
,
1757 window_rect
, client_rect
, &visible_rect
, &new_surface
)))
1759 if (IsRectEmpty( window_rect
)) visible_rect
= *window_rect
;
1762 visible_rect
= get_virtual_screen_rect( get_thread_dpi() );
1763 intersect_rect( &visible_rect
, &visible_rect
, window_rect
);
1767 get_window_rects( hwnd
, COORDS_SCREEN
, &old_window_rect
, NULL
, get_thread_dpi() );
1768 if (IsRectEmpty( &valid_rects
[0] )) valid_rects
= NULL
;
1770 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_DESKTOP
|| win
== WND_OTHER_PROCESS
)
1772 if (new_surface
) window_surface_release( new_surface
);
1776 /* create or update window surface for top-level windows if the driver doesn't implement WindowPosChanging */
1777 if (!ret
&& new_surface
&& !IsRectEmpty( &visible_rect
) &&
1778 (!(get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_LAYERED
) ||
1779 NtUserGetLayeredWindowAttributes( hwnd
, NULL
, NULL
, NULL
)))
1781 window_surface_release( new_surface
);
1782 if ((new_surface
= win
->surface
)) window_surface_add_ref( new_surface
);
1783 create_offscreen_window_surface( &visible_rect
, &new_surface
);
1786 old_visible_rect
= win
->visible_rect
;
1787 old_client_rect
= win
->client_rect
;
1788 old_surface
= win
->surface
;
1789 if (old_surface
!= new_surface
) swp_flags
|= SWP_FRAMECHANGED
; /* force refreshing non-client area */
1790 if (new_surface
== &dummy_surface
) swp_flags
|= SWP_NOREDRAW
;
1791 else if (old_surface
== &dummy_surface
)
1793 swp_flags
|= SWP_NOCOPYBITS
;
1797 SERVER_START_REQ( set_window_pos
)
1799 req
->handle
= wine_server_user_handle( hwnd
);
1800 req
->previous
= wine_server_user_handle( insert_after
);
1801 req
->swp_flags
= swp_flags
;
1802 req
->window
.left
= window_rect
->left
;
1803 req
->window
.top
= window_rect
->top
;
1804 req
->window
.right
= window_rect
->right
;
1805 req
->window
.bottom
= window_rect
->bottom
;
1806 req
->client
.left
= client_rect
->left
;
1807 req
->client
.top
= client_rect
->top
;
1808 req
->client
.right
= client_rect
->right
;
1809 req
->client
.bottom
= client_rect
->bottom
;
1810 if (!EqualRect( window_rect
, &visible_rect
) || new_surface
|| valid_rects
)
1812 extra_rects
[0] = extra_rects
[1] = visible_rect
;
1815 extra_rects
[1] = new_surface
->rect
;
1816 OffsetRect( &extra_rects
[1], visible_rect
.left
, visible_rect
.top
);
1818 if (valid_rects
) extra_rects
[2] = valid_rects
[0];
1819 else SetRectEmpty( &extra_rects
[2] );
1820 wine_server_add_data( req
, extra_rects
, sizeof(extra_rects
) );
1822 if (new_surface
) req
->paint_flags
|= SET_WINPOS_PAINT_SURFACE
;
1823 if (win
->pixel_format
) req
->paint_flags
|= SET_WINPOS_PIXEL_FORMAT
;
1825 if ((ret
= !wine_server_call( req
)))
1827 win
->dwStyle
= reply
->new_style
;
1828 win
->dwExStyle
= reply
->new_ex_style
;
1829 win
->window_rect
= *window_rect
;
1830 win
->client_rect
= *client_rect
;
1831 win
->visible_rect
= visible_rect
;
1832 win
->surface
= new_surface
;
1833 surface_win
= wine_server_ptr_handle( reply
->surface_win
);
1834 needs_update
= reply
->needs_update
;
1835 if (get_window_long( win
->parent
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
)
1838 get_window_rects( win
->parent
, COORDS_CLIENT
, NULL
, &client
, get_thread_dpi() );
1839 mirror_rect( &client
, &win
->window_rect
);
1840 mirror_rect( &client
, &win
->client_rect
);
1841 mirror_rect( &client
, &win
->visible_rect
);
1843 /* if an RTL window is resized the children have moved */
1844 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
&&
1845 client_rect
->right
- client_rect
->left
!= old_client_rect
.right
- old_client_rect
.left
)
1846 win
->flags
|= WIN_CHILDREN_MOVED
;
1853 if (needs_update
) update_surface_region( surface_win
);
1854 if (((swp_flags
& SWP_AGG_NOPOSCHANGE
) != SWP_AGG_NOPOSCHANGE
) ||
1855 (swp_flags
& (SWP_HIDEWINDOW
| SWP_SHOWWINDOW
| SWP_STATECHANGED
| SWP_FRAMECHANGED
)))
1856 invalidate_dce( win
, &old_window_rect
);
1859 release_win_ptr( win
);
1863 TRACE( "win %p surface %p -> %p\n", hwnd
, old_surface
, new_surface
);
1864 register_window_surface( old_surface
, new_surface
);
1869 move_window_bits( hwnd
, old_surface
, new_surface
, &visible_rect
,
1870 &old_visible_rect
, window_rect
, valid_rects
);
1871 valid_rects
= NULL
; /* prevent the driver from trying to also move the bits */
1873 window_surface_release( old_surface
);
1875 else if (surface_win
&& surface_win
!= hwnd
)
1880 int x_offset
= old_visible_rect
.left
- visible_rect
.left
;
1881 int y_offset
= old_visible_rect
.top
- visible_rect
.top
;
1883 /* if all that happened is that the whole window moved, copy everything */
1884 if (!(swp_flags
& SWP_FRAMECHANGED
) &&
1885 old_visible_rect
.right
- visible_rect
.right
== x_offset
&&
1886 old_visible_rect
.bottom
- visible_rect
.bottom
== y_offset
&&
1887 old_client_rect
.left
- client_rect
->left
== x_offset
&&
1888 old_client_rect
.right
- client_rect
->right
== x_offset
&&
1889 old_client_rect
.top
- client_rect
->top
== y_offset
&&
1890 old_client_rect
.bottom
- client_rect
->bottom
== y_offset
&&
1891 EqualRect( &valid_rects
[0], client_rect
))
1893 rects
[0] = visible_rect
;
1894 rects
[1] = old_visible_rect
;
1895 valid_rects
= rects
;
1897 move_window_bits_parent( hwnd
, surface_win
, window_rect
, valid_rects
);
1898 valid_rects
= NULL
; /* prevent the driver from trying to also move the bits */
1902 user_driver
->pWindowPosChanged( hwnd
, insert_after
, swp_flags
, window_rect
,
1903 client_rect
, &visible_rect
, valid_rects
, new_surface
);
1905 else if (new_surface
) window_surface_release( new_surface
);
1910 /*******************************************************************
1911 * NtUserGetWindowRgnEx (win32u.@)
1913 int WINAPI
NtUserGetWindowRgnEx( HWND hwnd
, HRGN hrgn
, UINT unk
)
1923 if (!(data
= malloc( sizeof(*data
) + size
- 1 )))
1925 SetLastError( ERROR_OUTOFMEMORY
);
1928 SERVER_START_REQ( get_window_region
)
1930 req
->window
= wine_server_user_handle( hwnd
);
1931 wine_server_set_reply( req
, data
->Buffer
, size
);
1932 if (!(status
= wine_server_call( req
)))
1934 size_t reply_size
= wine_server_reply_size( reply
);
1937 data
->rdh
.dwSize
= sizeof(data
->rdh
);
1938 data
->rdh
.iType
= RDH_RECTANGLES
;
1939 data
->rdh
.nCount
= reply_size
/ sizeof(RECT
);
1940 data
->rdh
.nRgnSize
= reply_size
;
1941 win_rgn
= NtGdiExtCreateRegion( NULL
, data
->rdh
.dwSize
+ data
->rdh
.nRgnSize
, data
);
1944 else size
= reply
->total_size
;
1948 } while (status
== STATUS_BUFFER_OVERFLOW
);
1950 if (set_ntstatus( status
) && win_rgn
)
1952 ret
= NtGdiCombineRgn( hrgn
, win_rgn
, 0, RGN_COPY
);
1953 NtGdiDeleteObjectApp( win_rgn
);
1958 /***********************************************************************
1959 * NtUserSetWindowRgn (win32u.@)
1961 int WINAPI
NtUserSetWindowRgn( HWND hwnd
, HRGN hrgn
, BOOL redraw
)
1963 static const RECT empty_rect
;
1971 if (!(size
= NtGdiGetRegionData( hrgn
, 0, NULL
))) return FALSE
;
1972 if (!(data
= malloc( size
))) return FALSE
;
1973 if (!NtGdiGetRegionData( hrgn
, size
, data
))
1978 SERVER_START_REQ( set_window_region
)
1980 req
->window
= wine_server_user_handle( hwnd
);
1981 req
->redraw
= redraw
!= 0;
1982 if (data
->rdh
.nCount
)
1983 wine_server_add_data( req
, data
->Buffer
, data
->rdh
.nCount
* sizeof(RECT
) );
1985 wine_server_add_data( req
, &empty_rect
, sizeof(empty_rect
) );
1986 ret
= !wine_server_call_err( req
);
1991 else /* clear existing region */
1993 SERVER_START_REQ( set_window_region
)
1995 req
->window
= wine_server_user_handle( hwnd
);
1996 req
->redraw
= redraw
!= 0;
1997 ret
= !wine_server_call_err( req
);
2004 UINT swp_flags
= SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_FRAMECHANGED
|
2005 SWP_NOCLIENTSIZE
| SWP_NOCLIENTMOVE
;
2006 if (!redraw
) swp_flags
|= SWP_NOREDRAW
;
2007 user_driver
->pSetWindowRgn( hwnd
, hrgn
, redraw
);
2008 NtUserSetWindowPos( hwnd
, 0, 0, 0, 0, 0, swp_flags
);
2009 if (hrgn
) NtGdiDeleteObjectApp( hrgn
);
2014 /***********************************************************************
2015 * NtUserMoveWindow (win32u.@)
2017 BOOL WINAPI
NtUserMoveWindow( HWND hwnd
, INT x
, INT y
, INT cx
, INT cy
, BOOL repaint
)
2019 int flags
= SWP_NOZORDER
| SWP_NOACTIVATE
;
2020 if (!repaint
) flags
|= SWP_NOREDRAW
;
2021 TRACE( "%p %d,%d %dx%d %d\n", hwnd
, x
, y
, cx
, cy
, repaint
);
2022 return NtUserSetWindowPos( hwnd
, 0, x
, y
, cx
, cy
, flags
);
2025 /*****************************************************************************
2026 * NtUserGetLayeredWindowAttributes (win32u.@)
2028 BOOL WINAPI
NtUserGetLayeredWindowAttributes( HWND hwnd
, COLORREF
*key
, BYTE
*alpha
, DWORD
*flags
)
2032 SERVER_START_REQ( get_window_layered_info
)
2034 req
->handle
= wine_server_user_handle( hwnd
);
2035 if ((ret
= !wine_server_call_err( req
)))
2037 if (key
) *key
= reply
->color_key
;
2038 if (alpha
) *alpha
= reply
->alpha
;
2039 if (flags
) *flags
= reply
->flags
;
2047 /*****************************************************************************
2048 * NtUserSetLayeredWindowAttributes (win32u.@)
2050 BOOL WINAPI
NtUserSetLayeredWindowAttributes( HWND hwnd
, COLORREF key
, BYTE alpha
, DWORD flags
)
2054 TRACE( "(%p,%08x,%d,%x)\n", hwnd
, key
, alpha
, flags
);
2056 SERVER_START_REQ( set_window_layered_info
)
2058 req
->handle
= wine_server_user_handle( hwnd
);
2059 req
->color_key
= key
;
2062 ret
= !wine_server_call_err( req
);
2068 user_driver
->pSetLayeredWindowAttributes( hwnd
, key
, alpha
, flags
);
2069 update_window_state( hwnd
);
2075 /*****************************************************************************
2076 * UpdateLayeredWindow (win32u.@)
2078 BOOL WINAPI
NtUserUpdateLayeredWindow( HWND hwnd
, HDC hdc_dst
, const POINT
*pts_dst
, const SIZE
*size
,
2079 HDC hdc_src
, const POINT
*pts_src
, COLORREF key
,
2080 const BLENDFUNCTION
*blend
, DWORD flags
, const RECT
*dirty
)
2082 DWORD swp_flags
= SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREDRAW
;
2083 RECT window_rect
, client_rect
;
2084 UPDATELAYEREDWINDOWINFO info
;
2087 if (flags
& ~(ULW_COLORKEY
| ULW_ALPHA
| ULW_OPAQUE
| ULW_EX_NORESIZE
) ||
2088 !(get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_LAYERED
) ||
2089 NtUserGetLayeredWindowAttributes( hwnd
, NULL
, NULL
, NULL
))
2091 SetLastError( ERROR_INVALID_PARAMETER
);
2095 get_window_rects( hwnd
, COORDS_PARENT
, &window_rect
, &client_rect
, get_thread_dpi() );
2099 offset
.cx
= pts_dst
->x
- window_rect
.left
;
2100 offset
.cy
= pts_dst
->y
- window_rect
.top
;
2101 OffsetRect( &client_rect
, offset
.cx
, offset
.cy
);
2102 OffsetRect( &window_rect
, offset
.cx
, offset
.cy
);
2103 swp_flags
&= ~SWP_NOMOVE
;
2107 offset
.cx
= size
->cx
- (window_rect
.right
- window_rect
.left
);
2108 offset
.cy
= size
->cy
- (window_rect
.bottom
- window_rect
.top
);
2109 if (size
->cx
<= 0 || size
->cy
<= 0)
2111 SetLastError( ERROR_INVALID_PARAMETER
);
2114 if ((flags
& ULW_EX_NORESIZE
) && (offset
.cx
|| offset
.cy
))
2116 SetLastError( ERROR_INCORRECT_SIZE
);
2119 client_rect
.right
+= offset
.cx
;
2120 client_rect
.bottom
+= offset
.cy
;
2121 window_rect
.right
+= offset
.cx
;
2122 window_rect
.bottom
+= offset
.cy
;
2123 swp_flags
&= ~SWP_NOSIZE
;
2126 TRACE( "window %p win %s client %s\n", hwnd
,
2127 wine_dbgstr_rect(&window_rect
), wine_dbgstr_rect(&client_rect
) );
2129 apply_window_pos( hwnd
, 0, swp_flags
, &window_rect
, &client_rect
, NULL
);
2131 info
.cbSize
= sizeof(info
);
2132 info
.hdcDst
= hdc_dst
;
2133 info
.pptDst
= pts_dst
;
2135 info
.hdcSrc
= hdc_src
;
2136 info
.pptSrc
= pts_src
;
2138 info
.pblend
= blend
;
2139 info
.dwFlags
= flags
;
2140 info
.prcDirty
= dirty
;
2141 return user_driver
->pUpdateLayeredWindow( hwnd
, &info
, &window_rect
);
2144 /***********************************************************************
2145 * list_children_from_point
2147 * Get the list of children that can contain point from the server.
2148 * Point is in screen coordinates.
2149 * Returned list must be freed by caller.
2151 static HWND
*list_children_from_point( HWND hwnd
, POINT pt
)
2160 if (!(list
= malloc( size
* sizeof(HWND
) ))) break;
2162 SERVER_START_REQ( get_window_children_from_point
)
2164 req
->parent
= wine_server_user_handle( hwnd
);
2167 req
->dpi
= get_thread_dpi();
2168 wine_server_set_reply( req
, list
, (size
-1) * sizeof(user_handle_t
) );
2169 if (!wine_server_call( req
)) count
= reply
->count
;
2172 if (count
&& count
< size
)
2174 /* start from the end since HWND is potentially larger than user_handle_t */
2175 for (i
= count
- 1; i
>= 0; i
--)
2176 list
[i
] = wine_server_ptr_handle( ((user_handle_t
*)list
)[i
] );
2182 size
= count
+ 1; /* restart with a large enough buffer */
2187 /***********************************************************************
2190 * Find the window and hittest for a given point.
2192 static HWND
window_from_point( HWND hwnd
, POINT pt
, INT
*hittest
)
2198 if (!hwnd
) hwnd
= get_desktop_window();
2200 *hittest
= HTNOWHERE
;
2202 if (!(list
= list_children_from_point( hwnd
, pt
))) return 0;
2204 /* now determine the hittest */
2206 for (i
= 0; list
[i
]; i
++)
2208 LONG style
= get_window_long( list
[i
], GWL_STYLE
);
2210 /* If window is minimized or disabled, return at once */
2211 if (style
& WS_DISABLED
)
2216 /* Send WM_NCCHITTEST (if same thread) */
2217 if (!is_current_thread_window( list
[i
] ))
2219 *hittest
= HTCLIENT
;
2222 win_pt
= map_dpi_point( pt
, get_thread_dpi(), get_dpi_for_window( list
[i
] ));
2223 res
= send_message( list
[i
], WM_NCHITTEST
, 0, MAKELPARAM( win_pt
.x
, win_pt
.y
));
2224 if (res
!= HTTRANSPARENT
)
2226 *hittest
= res
; /* Found the window */
2229 /* continue search with next window in z-order */
2233 TRACE( "scope %p (%d,%d) returning %p\n", hwnd
, pt
.x
, pt
.y
, ret
);
2237 /*******************************************************************
2238 * NtUserWindowFromPoint (win32u.@)
2240 HWND WINAPI
NtUserWindowFromPoint( LONG x
, LONG y
)
2242 POINT pt
= { .x
= x
, .y
= y
};
2244 return window_from_point( 0, pt
, &hittest
);
2247 /*******************************************************************
2250 * Get the work area that a maximized window can cover, depending on style.
2252 static BOOL
get_work_rect( HWND hwnd
, RECT
*rect
)
2254 HMONITOR monitor
= monitor_from_window( hwnd
, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
2255 MONITORINFO mon_info
;
2258 if (!monitor
) return FALSE
;
2260 mon_info
.cbSize
= sizeof(mon_info
);
2261 get_monitor_info( monitor
, &mon_info
);
2262 *rect
= mon_info
.rcMonitor
;
2264 style
= get_window_long( hwnd
, GWL_STYLE
);
2265 if (style
& WS_MAXIMIZEBOX
)
2267 if ((style
& WS_CAPTION
) == WS_CAPTION
|| !(style
& (WS_CHILD
| WS_POPUP
)))
2268 *rect
= mon_info
.rcWork
;
2273 static RECT
get_maximized_work_rect( HWND hwnd
)
2275 RECT work_rect
= { 0 };
2277 if ((get_window_long( hwnd
, GWL_STYLE
) & (WS_MINIMIZE
| WS_MAXIMIZE
)) == WS_MAXIMIZE
)
2279 if (!get_work_rect( hwnd
, &work_rect
))
2280 work_rect
= get_primary_monitor_rect( get_thread_dpi() );
2285 /*******************************************************************
2286 * update_maximized_pos
2288 * For top level windows covering the work area, we might have to
2289 * "forget" the maximized position. Windows presumably does this
2290 * to avoid situations where the border style changes, which would
2291 * lead the window to be outside the screen, or the window gets
2292 * reloaded on a different screen, and the "saved" position no
2293 * longer applies to it (despite being maximized).
2295 * Some applications (e.g. Imperiums: Greek Wars) depend on this.
2297 static void update_maximized_pos( WND
*wnd
, RECT
*work_rect
)
2299 if (wnd
->parent
&& wnd
->parent
!= get_desktop_window())
2302 if (wnd
->dwStyle
& WS_MAXIMIZE
)
2304 if (wnd
->window_rect
.left
<= work_rect
->left
&& wnd
->window_rect
.top
<= work_rect
->top
&&
2305 wnd
->window_rect
.right
>= work_rect
->right
&& wnd
->window_rect
.bottom
>= work_rect
->bottom
)
2306 wnd
->max_pos
.x
= wnd
->max_pos
.y
= -1;
2309 wnd
->max_pos
.x
= wnd
->max_pos
.y
= -1;
2312 static BOOL
empty_point( POINT pt
)
2314 return pt
.x
== -1 && pt
.y
== -1;
2317 /* see GetWindowPlacement */
2318 BOOL
get_window_placement( HWND hwnd
, WINDOWPLACEMENT
*placement
)
2320 RECT work_rect
= get_maximized_work_rect( hwnd
);
2321 WND
*win
= get_win_ptr( hwnd
);
2324 if (!win
) return FALSE
;
2326 if (win
== WND_DESKTOP
)
2328 placement
->length
= sizeof(*placement
);
2329 placement
->showCmd
= SW_SHOWNORMAL
;
2330 placement
->flags
= 0;
2331 placement
->ptMinPosition
.x
= -1;
2332 placement
->ptMinPosition
.y
= -1;
2333 placement
->ptMaxPosition
.x
= -1;
2334 placement
->ptMaxPosition
.y
= -1;
2335 get_window_rect( hwnd
, &placement
->rcNormalPosition
, get_thread_dpi() );
2338 if (win
== WND_OTHER_PROCESS
)
2340 RECT normal_position
;
2343 if (!get_window_rect( hwnd
, &normal_position
, get_thread_dpi() ))
2346 FIXME("not fully supported on other process window %p.\n", hwnd
);
2348 placement
->length
= sizeof(*placement
);
2349 style
= get_window_long( hwnd
, GWL_STYLE
);
2350 if (style
& WS_MINIMIZE
)
2351 placement
->showCmd
= SW_SHOWMINIMIZED
;
2353 placement
->showCmd
= (style
& WS_MAXIMIZE
) ? SW_SHOWMAXIMIZED
: SW_SHOWNORMAL
;
2354 /* provide some dummy information */
2355 placement
->flags
= 0;
2356 placement
->ptMinPosition
.x
= -1;
2357 placement
->ptMinPosition
.y
= -1;
2358 placement
->ptMaxPosition
.x
= -1;
2359 placement
->ptMaxPosition
.y
= -1;
2360 placement
->rcNormalPosition
= normal_position
;
2364 /* update the placement according to the current style */
2365 if (win
->dwStyle
& WS_MINIMIZE
)
2367 win
->min_pos
.x
= win
->window_rect
.left
;
2368 win
->min_pos
.y
= win
->window_rect
.top
;
2370 else if (win
->dwStyle
& WS_MAXIMIZE
)
2372 win
->max_pos
.x
= win
->window_rect
.left
;
2373 win
->max_pos
.y
= win
->window_rect
.top
;
2377 win
->normal_rect
= win
->window_rect
;
2379 update_maximized_pos( win
, &work_rect
);
2381 placement
->length
= sizeof(*placement
);
2382 if (win
->dwStyle
& WS_MINIMIZE
)
2383 placement
->showCmd
= SW_SHOWMINIMIZED
;
2385 placement
->showCmd
= ( win
->dwStyle
& WS_MAXIMIZE
) ? SW_SHOWMAXIMIZED
: SW_SHOWNORMAL
;
2386 if (win
->flags
& WIN_RESTORE_MAX
)
2387 placement
->flags
= WPF_RESTORETOMAXIMIZED
;
2389 placement
->flags
= 0;
2390 win_dpi
= get_dpi_for_window( hwnd
);
2391 placement
->ptMinPosition
= empty_point(win
->min_pos
) ? win
->min_pos
2392 : map_dpi_point( win
->min_pos
, win_dpi
, get_thread_dpi() );
2393 placement
->ptMaxPosition
= empty_point(win
->max_pos
) ? win
->max_pos
2394 : map_dpi_point( win
->max_pos
, win_dpi
, get_thread_dpi() );
2395 placement
->rcNormalPosition
= map_dpi_rect( win
->normal_rect
, win_dpi
, get_thread_dpi() );
2396 release_win_ptr( win
);
2398 TRACE( "%p: returning min %d,%d max %d,%d normal %s\n",
2399 hwnd
, placement
->ptMinPosition
.x
, placement
->ptMinPosition
.y
,
2400 placement
->ptMaxPosition
.x
, placement
->ptMaxPosition
.y
,
2401 wine_dbgstr_rect(&placement
->rcNormalPosition
) );
2405 /*****************************************************************************
2406 * NtUserBuildHwndList (win32u.@)
2408 NTSTATUS WINAPI
NtUserBuildHwndList( HDESK desktop
, ULONG unk2
, ULONG unk3
, ULONG unk4
,
2409 ULONG thread_id
, ULONG count
, HWND
*buffer
, ULONG
*size
)
2411 user_handle_t
*list
= (user_handle_t
*)buffer
;
2415 SERVER_START_REQ( get_window_children
)
2417 req
->desktop
= wine_server_obj_handle( desktop
);
2418 req
->tid
= thread_id
;
2419 if (count
) wine_server_set_reply( req
, list
, (count
- 1) * sizeof(user_handle_t
) );
2420 status
= wine_server_call( req
);
2421 if (status
&& status
!= STATUS_BUFFER_TOO_SMALL
) return status
;
2422 *size
= reply
->count
+ 1;
2425 if (*size
> count
) return STATUS_BUFFER_TOO_SMALL
;
2427 /* start from the end since HWND is potentially larger than user_handle_t */
2428 for (i
= *size
- 2; i
>= 0; i
--)
2429 buffer
[i
] = wine_server_ptr_handle( list
[i
] );
2430 buffer
[*size
- 1] = HWND_BOTTOM
;
2431 return STATUS_SUCCESS
;
2434 /* Retrieve the window text from the server. */
2435 static data_size_t
get_server_window_text( HWND hwnd
, WCHAR
*text
, data_size_t count
)
2437 data_size_t len
= 0, needed
= 0;
2439 SERVER_START_REQ( get_window_text
)
2441 req
->handle
= wine_server_user_handle( hwnd
);
2442 if (count
) wine_server_set_reply( req
, text
, (count
- 1) * sizeof(WCHAR
) );
2443 if (!wine_server_call_err( req
))
2445 needed
= reply
->length
;
2446 len
= wine_server_reply_size(reply
);
2450 if (text
) text
[len
/ sizeof(WCHAR
)] = 0;
2454 /*******************************************************************
2455 * NtUserInternalGetWindowText (win32u.@)
2457 INT WINAPI
NtUserInternalGetWindowText( HWND hwnd
, WCHAR
*text
, INT count
)
2461 if (count
<= 0) return 0;
2462 if (!(win
= get_win_ptr( hwnd
))) return 0;
2463 if (win
== WND_DESKTOP
) text
[0] = 0;
2464 else if (win
!= WND_OTHER_PROCESS
)
2466 if (win
->text
) lstrcpynW( text
, win
->text
, count
);
2468 release_win_ptr( win
);
2472 get_server_window_text( hwnd
, text
, count
);
2474 return lstrlenW(text
);
2477 /*******************************************************************
2478 * get_windows_offset
2480 * Calculate the offset between the origin of the two windows. Used
2481 * to implement MapWindowPoints.
2483 static BOOL
get_windows_offset( HWND hwnd_from
, HWND hwnd_to
, UINT dpi
, BOOL
*mirrored
, POINT
*ret_offset
)
2487 BOOL mirror_from
, mirror_to
, ret
;
2490 offset
.x
= offset
.y
= 0;
2491 *mirrored
= mirror_from
= mirror_to
= FALSE
;
2493 /* Translate source window origin to screen coords */
2496 if (!(win
= get_win_ptr( hwnd_from
)))
2498 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
2501 if (win
== WND_OTHER_PROCESS
) goto other_process
;
2502 if (win
!= WND_DESKTOP
)
2504 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
)
2507 offset
.x
+= win
->client_rect
.right
- win
->client_rect
.left
;
2511 offset
.x
+= win
->client_rect
.left
;
2512 offset
.y
+= win
->client_rect
.top
;
2514 release_win_ptr( win
);
2515 if (!(win
= get_win_ptr( hwnd
))) break;
2516 if (win
== WND_OTHER_PROCESS
) goto other_process
;
2517 if (win
== WND_DESKTOP
) break;
2518 if (win
->flags
& WIN_CHILDREN_MOVED
)
2520 release_win_ptr( win
);
2524 if (win
&& win
!= WND_DESKTOP
) release_win_ptr( win
);
2525 offset
= map_dpi_point( offset
, get_dpi_for_window( hwnd_from
), dpi
);
2529 /* Translate origin to destination window coords */
2532 if (!(win
= get_win_ptr( hwnd_to
)))
2534 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
2537 if (win
== WND_OTHER_PROCESS
) goto other_process
;
2538 if (win
!= WND_DESKTOP
)
2540 POINT pt
= { 0, 0 };
2541 if (win
->dwExStyle
& WS_EX_LAYOUTRTL
)
2544 pt
.x
+= win
->client_rect
.right
- win
->client_rect
.left
;
2548 pt
.x
+= win
->client_rect
.left
;
2549 pt
.y
+= win
->client_rect
.top
;
2551 release_win_ptr( win
);
2552 if (!(win
= get_win_ptr( hwnd
))) break;
2553 if (win
== WND_OTHER_PROCESS
) goto other_process
;
2554 if (win
== WND_DESKTOP
) break;
2555 if (win
->flags
& WIN_CHILDREN_MOVED
)
2557 release_win_ptr( win
);
2561 if (win
&& win
!= WND_DESKTOP
) release_win_ptr( win
);
2562 pt
= map_dpi_point( pt
, get_dpi_for_window( hwnd_to
), dpi
);
2568 *mirrored
= mirror_from
^ mirror_to
;
2569 if (mirror_from
) offset
.x
= -offset
.x
;
2570 *ret_offset
= offset
;
2573 other_process
: /* one of the parents may belong to another process, do it the hard way */
2574 SERVER_START_REQ( get_windows_offset
)
2576 req
->from
= wine_server_user_handle( hwnd_from
);
2577 req
->to
= wine_server_user_handle( hwnd_to
);
2579 if ((ret
= !wine_server_call_err( req
)))
2581 ret_offset
->x
= reply
->x
;
2582 ret_offset
->y
= reply
->y
;
2583 *mirrored
= reply
->mirror
;
2590 /* see ScreenToClient */
2591 static BOOL
screen_to_client( HWND hwnd
, POINT
*pt
)
2598 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
2601 if (!get_windows_offset( 0, hwnd
, get_thread_dpi(), &mirrored
, &offset
)) return FALSE
;
2604 if (mirrored
) pt
->x
= -pt
->x
;
2608 /* map coordinates of a window region */
2609 void map_window_region( HWND from
, HWND to
, HRGN hrgn
)
2618 if (!get_windows_offset( from
, to
, get_thread_dpi(), &mirrored
, &offset
)) return;
2622 NtGdiOffsetRgn( hrgn
, offset
.x
, offset
.y
);
2625 if (!(size
= NtGdiGetRegionData( hrgn
, 0, NULL
))) return;
2626 if (!(data
= malloc( size
))) return;
2627 NtGdiGetRegionData( hrgn
, size
, data
);
2628 rect
= (RECT
*)data
->Buffer
;
2629 for (i
= 0; i
< data
->rdh
.nCount
; i
++)
2631 int tmp
= -(rect
[i
].left
+ offset
.x
);
2632 rect
[i
].left
= -(rect
[i
].right
+ offset
.x
);
2633 rect
[i
].right
= tmp
;
2634 rect
[i
].top
+= offset
.y
;
2635 rect
[i
].bottom
+= offset
.y
;
2637 if ((new_rgn
= NtGdiExtCreateRegion( NULL
, data
->rdh
.dwSize
+ data
->rdh
.nRgnSize
, data
)))
2639 NtGdiCombineRgn( hrgn
, new_rgn
, 0, RGN_COPY
);
2640 NtGdiDeleteObjectApp( new_rgn
);
2645 /* see MapWindowPoints */
2646 int map_window_points( HWND hwnd_from
, HWND hwnd_to
, POINT
*points
, UINT count
, UINT dpi
)
2652 if (!get_windows_offset( hwnd_from
, hwnd_to
, dpi
, &mirrored
, &offset
)) return 0;
2654 for (i
= 0; i
< count
; i
++)
2656 points
[i
].x
+= offset
.x
;
2657 points
[i
].y
+= offset
.y
;
2658 if (mirrored
) points
[i
].x
= -points
[i
].x
;
2660 if (mirrored
&& count
== 2) /* special case for rectangle */
2662 int tmp
= points
[0].x
;
2663 points
[0].x
= points
[1].x
;
2666 return MAKELONG( LOWORD(offset
.x
), LOWORD(offset
.y
) );
2669 /***********************************************************************
2672 static void dump_winpos_flags( UINT flags
)
2674 static const DWORD dumped_flags
= (SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOREDRAW
|
2675 SWP_NOACTIVATE
| SWP_FRAMECHANGED
| SWP_SHOWWINDOW
|
2676 SWP_HIDEWINDOW
| SWP_NOCOPYBITS
| SWP_NOOWNERZORDER
|
2677 SWP_NOSENDCHANGING
| SWP_DEFERERASE
| SWP_ASYNCWINDOWPOS
|
2678 SWP_NOCLIENTSIZE
| SWP_NOCLIENTMOVE
| SWP_STATECHANGED
);
2680 if(flags
& SWP_NOSIZE
) TRACE( " SWP_NOSIZE" );
2681 if(flags
& SWP_NOMOVE
) TRACE( " SWP_NOMOVE" );
2682 if(flags
& SWP_NOZORDER
) TRACE( " SWP_NOZORDER" );
2683 if(flags
& SWP_NOREDRAW
) TRACE( " SWP_NOREDRAW" );
2684 if(flags
& SWP_NOACTIVATE
) TRACE( " SWP_NOACTIVATE" );
2685 if(flags
& SWP_FRAMECHANGED
) TRACE( " SWP_FRAMECHANGED" );
2686 if(flags
& SWP_SHOWWINDOW
) TRACE( " SWP_SHOWWINDOW" );
2687 if(flags
& SWP_HIDEWINDOW
) TRACE( " SWP_HIDEWINDOW" );
2688 if(flags
& SWP_NOCOPYBITS
) TRACE( " SWP_NOCOPYBITS" );
2689 if(flags
& SWP_NOOWNERZORDER
) TRACE( " SWP_NOOWNERZORDER" );
2690 if(flags
& SWP_NOSENDCHANGING
) TRACE( " SWP_NOSENDCHANGING" );
2691 if(flags
& SWP_DEFERERASE
) TRACE( " SWP_DEFERERASE" );
2692 if(flags
& SWP_ASYNCWINDOWPOS
) TRACE( " SWP_ASYNCWINDOWPOS" );
2693 if(flags
& SWP_NOCLIENTSIZE
) TRACE( " SWP_NOCLIENTSIZE" );
2694 if(flags
& SWP_NOCLIENTMOVE
) TRACE( " SWP_NOCLIENTMOVE" );
2695 if(flags
& SWP_STATECHANGED
) TRACE( " SWP_STATECHANGED" );
2697 if(flags
& ~dumped_flags
) TRACE( " %08x", flags
& ~dumped_flags
);
2701 /***********************************************************************
2704 static void map_dpi_winpos( WINDOWPOS
*winpos
)
2706 UINT dpi_from
= get_thread_dpi();
2707 UINT dpi_to
= get_dpi_for_window( winpos
->hwnd
);
2709 if (!dpi_from
) dpi_from
= get_win_monitor_dpi( winpos
->hwnd
);
2710 if (dpi_from
== dpi_to
) return;
2711 winpos
->x
= muldiv( winpos
->x
, dpi_to
, dpi_from
);
2712 winpos
->y
= muldiv( winpos
->y
, dpi_to
, dpi_from
);
2713 winpos
->cx
= muldiv( winpos
->cx
, dpi_to
, dpi_from
);
2714 winpos
->cy
= muldiv( winpos
->cy
, dpi_to
, dpi_from
);
2717 /***********************************************************************
2720 static BOOL
calc_winpos( WINDOWPOS
*winpos
, RECT
*old_window_rect
, RECT
*old_client_rect
,
2721 RECT
*new_window_rect
, RECT
*new_client_rect
)
2725 /* Send WM_WINDOWPOSCHANGING message */
2726 if (!(winpos
->flags
& SWP_NOSENDCHANGING
)
2727 && !((winpos
->flags
& SWP_AGG_NOCLIENTCHANGE
) && (winpos
->flags
& SWP_SHOWWINDOW
)))
2728 send_message( winpos
->hwnd
, WM_WINDOWPOSCHANGING
, 0, (LPARAM
)winpos
);
2730 if (!(win
= get_win_ptr( winpos
->hwnd
)) ||
2731 win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
2733 /* Calculate new position and size */
2734 get_window_rects( winpos
->hwnd
, COORDS_PARENT
, old_window_rect
, old_client_rect
, get_thread_dpi() );
2735 *new_window_rect
= *old_window_rect
;
2736 *new_client_rect
= *old_client_rect
;
2738 if (!(winpos
->flags
& SWP_NOSIZE
))
2740 if (win
->dwStyle
& WS_MINIMIZE
)
2742 new_window_rect
->right
= new_window_rect
->left
+ get_system_metrics( SM_CXMINIMIZED
);
2743 new_window_rect
->bottom
= new_window_rect
->top
+ get_system_metrics( SM_CYMINIMIZED
);
2747 new_window_rect
->right
= new_window_rect
->left
+ winpos
->cx
;
2748 new_window_rect
->bottom
= new_window_rect
->top
+ winpos
->cy
;
2752 if (!(winpos
->flags
& SWP_NOMOVE
))
2754 /* If the window is toplevel minimized off-screen, force keep it there */
2755 if ((win
->dwStyle
& WS_MINIMIZE
) &&
2756 win
->window_rect
.left
<= -32000 && win
->window_rect
.top
<= -32000 &&
2757 (!win
->parent
|| win
->parent
== get_desktop_window()))
2762 new_window_rect
->left
= winpos
->x
;
2763 new_window_rect
->top
= winpos
->y
;
2764 new_window_rect
->right
+= winpos
->x
- old_window_rect
->left
;
2765 new_window_rect
->bottom
+= winpos
->y
- old_window_rect
->top
;
2767 offset_rect( new_client_rect
, winpos
->x
- old_window_rect
->left
,
2768 winpos
->y
- old_window_rect
->top
);
2770 winpos
->flags
|= SWP_NOCLIENTMOVE
| SWP_NOCLIENTSIZE
;
2772 TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x current %s style %08x new %s\n",
2773 winpos
->hwnd
, winpos
->hwndInsertAfter
, winpos
->x
, winpos
->y
,
2774 winpos
->cx
, winpos
->cy
, winpos
->flags
,
2775 wine_dbgstr_rect( old_window_rect
), win
->dwStyle
,
2776 wine_dbgstr_rect( new_window_rect
));
2778 release_win_ptr( win
);
2782 /***********************************************************************
2785 * Compute the valid rects from the old and new client rect and WVR_* flags.
2786 * Helper for WM_NCCALCSIZE handling.
2788 static inline void get_valid_rects( const RECT
*old_client
, const RECT
*new_client
, UINT flags
,
2793 if (flags
& WVR_REDRAW
)
2795 SetRectEmpty( &valid
[0] );
2796 SetRectEmpty( &valid
[1] );
2800 if (flags
& WVR_VALIDRECTS
)
2802 if (!intersect_rect( &valid
[0], &valid
[0], new_client
) ||
2803 !intersect_rect( &valid
[1], &valid
[1], old_client
))
2805 SetRectEmpty( &valid
[0] );
2806 SetRectEmpty( &valid
[1] );
2809 flags
= WVR_ALIGNLEFT
| WVR_ALIGNTOP
;
2813 valid
[0] = *new_client
;
2814 valid
[1] = *old_client
;
2817 /* make sure the rectangles have the same size */
2818 cx
= min( valid
[0].right
- valid
[0].left
, valid
[1].right
- valid
[1].left
);
2819 cy
= min( valid
[0].bottom
- valid
[0].top
, valid
[1].bottom
- valid
[1].top
);
2821 if (flags
& WVR_ALIGNBOTTOM
)
2823 valid
[0].top
= valid
[0].bottom
- cy
;
2824 valid
[1].top
= valid
[1].bottom
- cy
;
2828 valid
[0].bottom
= valid
[0].top
+ cy
;
2829 valid
[1].bottom
= valid
[1].top
+ cy
;
2831 if (flags
& WVR_ALIGNRIGHT
)
2833 valid
[0].left
= valid
[0].right
- cx
;
2834 valid
[1].left
= valid
[1].right
- cx
;
2838 valid
[0].right
= valid
[0].left
+ cx
;
2839 valid
[1].right
= valid
[1].left
+ cx
;
2843 static UINT
calc_ncsize( WINDOWPOS
*winpos
, const RECT
*old_window_rect
, const RECT
*old_client_rect
,
2844 const RECT
*new_window_rect
, RECT
*new_client_rect
, RECT
*valid_rects
,
2845 int parent_x
, int parent_y
)
2849 /* Send WM_NCCALCSIZE message to get new client area */
2850 if ((winpos
->flags
& (SWP_FRAMECHANGED
| SWP_NOSIZE
)) != SWP_NOSIZE
)
2852 NCCALCSIZE_PARAMS params
;
2853 WINDOWPOS winposCopy
;
2855 params
.rgrc
[0] = *new_window_rect
;
2856 params
.rgrc
[1] = *old_window_rect
;
2857 params
.rgrc
[2] = *old_client_rect
;
2858 params
.lppos
= &winposCopy
;
2859 winposCopy
= *winpos
;
2861 if (winpos
->flags
& SWP_NOMOVE
)
2863 winposCopy
.x
= old_window_rect
->left
;
2864 winposCopy
.y
= old_window_rect
->top
;
2867 if (winpos
->flags
& SWP_NOSIZE
)
2869 winposCopy
.cx
= old_window_rect
->right
- old_window_rect
->left
;
2870 winposCopy
.cy
= old_window_rect
->bottom
- old_window_rect
->top
;
2873 wvr_flags
= send_message( winpos
->hwnd
, WM_NCCALCSIZE
, TRUE
, (LPARAM
)¶ms
);
2875 *new_client_rect
= params
.rgrc
[0];
2877 TRACE( "hwnd %p old win %s old client %s new win %s new client %s\n", winpos
->hwnd
,
2878 wine_dbgstr_rect(old_window_rect
), wine_dbgstr_rect(old_client_rect
),
2879 wine_dbgstr_rect(new_window_rect
), wine_dbgstr_rect(new_client_rect
) );
2881 if (new_client_rect
->left
!= old_client_rect
->left
- parent_x
||
2882 new_client_rect
->top
!= old_client_rect
->top
- parent_y
)
2883 winpos
->flags
&= ~SWP_NOCLIENTMOVE
;
2885 if ((new_client_rect
->right
- new_client_rect
->left
!=
2886 old_client_rect
->right
- old_client_rect
->left
))
2887 winpos
->flags
&= ~SWP_NOCLIENTSIZE
;
2889 wvr_flags
&= ~WVR_HREDRAW
;
2891 if (new_client_rect
->bottom
- new_client_rect
->top
!=
2892 old_client_rect
->bottom
- old_client_rect
->top
)
2893 winpos
->flags
&= ~SWP_NOCLIENTSIZE
;
2895 wvr_flags
&= ~WVR_VREDRAW
;
2897 valid_rects
[0] = params
.rgrc
[1];
2898 valid_rects
[1] = params
.rgrc
[2];
2902 if (!(winpos
->flags
& SWP_NOMOVE
) &&
2903 (new_client_rect
->left
!= old_client_rect
->left
- parent_x
||
2904 new_client_rect
->top
!= old_client_rect
->top
- parent_y
))
2905 winpos
->flags
&= ~SWP_NOCLIENTMOVE
;
2908 if (winpos
->flags
& (SWP_NOCOPYBITS
| SWP_NOREDRAW
| SWP_SHOWWINDOW
| SWP_HIDEWINDOW
))
2910 SetRectEmpty( &valid_rects
[0] );
2911 SetRectEmpty( &valid_rects
[1] );
2913 else get_valid_rects( old_client_rect
, new_client_rect
, wvr_flags
, valid_rects
);
2918 /* fix redundant flags and values in the WINDOWPOS structure */
2919 static BOOL
fixup_swp_flags( WINDOWPOS
*winpos
, const RECT
*old_window_rect
, int parent_x
, int parent_y
)
2922 WND
*win
= get_win_ptr( winpos
->hwnd
);
2925 if (!win
|| win
== WND_OTHER_PROCESS
)
2927 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
2930 winpos
->hwnd
= win
->obj
.handle
; /* make it a full handle */
2932 /* Finally make sure that all coordinates are valid */
2933 if (winpos
->x
< -32768) winpos
->x
= -32768;
2934 else if (winpos
->x
> 32767) winpos
->x
= 32767;
2935 if (winpos
->y
< -32768) winpos
->y
= -32768;
2936 else if (winpos
->y
> 32767) winpos
->y
= 32767;
2938 if (winpos
->cx
< 0) winpos
->cx
= 0;
2939 else if (winpos
->cx
> 32767) winpos
->cx
= 32767;
2940 if (winpos
->cy
< 0) winpos
->cy
= 0;
2941 else if (winpos
->cy
> 32767) winpos
->cy
= 32767;
2943 parent
= NtUserGetAncestor( winpos
->hwnd
, GA_PARENT
);
2944 if (!is_window_visible( parent
)) winpos
->flags
|= SWP_NOREDRAW
;
2946 if (win
->dwStyle
& WS_VISIBLE
) winpos
->flags
&= ~SWP_SHOWWINDOW
;
2949 winpos
->flags
&= ~SWP_HIDEWINDOW
;
2950 if (!(winpos
->flags
& SWP_SHOWWINDOW
)) winpos
->flags
|= SWP_NOREDRAW
;
2953 if ((old_window_rect
->right
- old_window_rect
->left
== winpos
->cx
) &&
2954 (old_window_rect
->bottom
- old_window_rect
->top
== winpos
->cy
))
2955 winpos
->flags
|= SWP_NOSIZE
; /* Already the right size */
2957 if ((old_window_rect
->left
- parent_x
== winpos
->x
) && (old_window_rect
->top
- parent_y
== winpos
->y
))
2958 winpos
->flags
|= SWP_NOMOVE
; /* Already the right position */
2960 if ((win
->dwStyle
& (WS_POPUP
| WS_CHILD
)) != WS_CHILD
)
2962 if (!(winpos
->flags
& (SWP_NOACTIVATE
|SWP_HIDEWINDOW
)) && /* Bring to the top when activating */
2963 (winpos
->flags
& SWP_NOZORDER
||
2964 (winpos
->hwndInsertAfter
!= HWND_TOPMOST
&& winpos
->hwndInsertAfter
!= HWND_NOTOPMOST
)))
2966 winpos
->flags
&= ~SWP_NOZORDER
;
2967 winpos
->hwndInsertAfter
= HWND_TOP
;
2971 /* Check hwndInsertAfter */
2972 if (winpos
->flags
& SWP_NOZORDER
) goto done
;
2974 if (winpos
->hwndInsertAfter
== HWND_TOP
)
2976 if (get_window_relative( winpos
->hwnd
, GW_HWNDFIRST
) == winpos
->hwnd
)
2977 winpos
->flags
|= SWP_NOZORDER
;
2979 else if (winpos
->hwndInsertAfter
== HWND_BOTTOM
)
2981 if (!(win
->dwExStyle
& WS_EX_TOPMOST
) &&
2982 get_window_relative( winpos
->hwnd
, GW_HWNDLAST
) == winpos
->hwnd
)
2983 winpos
->flags
|= SWP_NOZORDER
;
2985 else if (winpos
->hwndInsertAfter
== HWND_TOPMOST
)
2987 if ((win
->dwExStyle
& WS_EX_TOPMOST
) &&
2988 get_window_relative( winpos
->hwnd
, GW_HWNDFIRST
) == winpos
->hwnd
)
2989 winpos
->flags
|= SWP_NOZORDER
;
2991 else if (winpos
->hwndInsertAfter
== HWND_NOTOPMOST
)
2993 if (!(win
->dwExStyle
& WS_EX_TOPMOST
))
2994 winpos
->flags
|= SWP_NOZORDER
;
2998 if ((winpos
->hwnd
== winpos
->hwndInsertAfter
) ||
2999 (winpos
->hwnd
== get_window_relative( winpos
->hwndInsertAfter
, GW_HWNDNEXT
)))
3000 winpos
->flags
|= SWP_NOZORDER
;
3003 release_win_ptr( win
);
3007 /***********************************************************************
3010 * fix Z order taking into account owned popups -
3011 * basically we need to maintain them above the window that owns them
3013 * FIXME: hide/show owned popups when owner visibility changes.
3015 static HWND
swp_owner_popups( HWND hwnd
, HWND after
)
3017 HWND owner
, *list
= NULL
;
3020 TRACE( "(%p) after = %p\n", hwnd
, after
);
3022 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) return after
;
3024 if ((owner
= get_window_relative( hwnd
, GW_OWNER
)))
3026 /* make sure this popup stays above the owner */
3028 if (after
!= HWND_TOPMOST
)
3030 if (!(list
= list_window_children( 0, get_desktop_window(), NULL
, 0 ))) return after
;
3032 for (i
= 0; list
[i
]; i
++)
3034 BOOL topmost
= (get_window_long( list
[i
], GWL_EXSTYLE
) & WS_EX_TOPMOST
) != 0;
3036 if (list
[i
] == owner
)
3038 if (i
> 0) after
= list
[i
-1];
3039 else after
= topmost
? HWND_TOPMOST
: HWND_TOP
;
3043 if (after
== HWND_TOP
|| after
== HWND_NOTOPMOST
)
3045 if (!topmost
) break;
3047 else if (list
[i
] == after
) break;
3052 if (after
== HWND_BOTTOM
) goto done
;
3053 if (!list
&& !(list
= list_window_children( 0, get_desktop_window(), NULL
, 0 ))) goto done
;
3056 if (after
== HWND_TOP
|| after
== HWND_NOTOPMOST
)
3058 if (after
== HWND_NOTOPMOST
||
3059 !(get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_TOPMOST
))
3061 /* skip all the topmost windows */
3062 while (list
[i
] && (get_window_long( list
[i
], GWL_EXSTYLE
) & WS_EX_TOPMOST
)) i
++;
3065 else if (after
!= HWND_TOPMOST
)
3067 /* skip windows that are already placed correctly */
3068 for (i
= 0; list
[i
]; i
++)
3070 if (list
[i
] == after
) break;
3071 if (list
[i
] == hwnd
) goto done
; /* nothing to do if window is moving backwards in z-order */
3075 for ( ; list
[i
]; i
++)
3077 if (list
[i
] == hwnd
) break;
3078 if (get_window_relative( list
[i
], GW_OWNER
) != hwnd
) continue;
3079 TRACE( "moving %p owned by %p after %p\n", list
[i
], hwnd
, after
);
3080 NtUserSetWindowPos( list
[i
], after
, 0, 0, 0, 0,
3081 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOSENDCHANGING
| SWP_DEFERERASE
);
3090 /* NtUserSetWindowPos implementation */
3091 BOOL
set_window_pos( WINDOWPOS
*winpos
, int parent_x
, int parent_y
)
3093 RECT old_window_rect
, old_client_rect
, new_window_rect
, new_client_rect
, valid_rects
[2];
3096 DPI_AWARENESS_CONTEXT context
;
3098 orig_flags
= winpos
->flags
;
3100 /* First, check z-order arguments. */
3101 if (!(winpos
->flags
& SWP_NOZORDER
))
3103 /* fix sign extension */
3104 if (winpos
->hwndInsertAfter
== (HWND
)0xffff) winpos
->hwndInsertAfter
= HWND_TOPMOST
;
3105 else if (winpos
->hwndInsertAfter
== (HWND
)0xfffe) winpos
->hwndInsertAfter
= HWND_NOTOPMOST
;
3107 if (!(winpos
->hwndInsertAfter
== HWND_TOP
||
3108 winpos
->hwndInsertAfter
== HWND_BOTTOM
||
3109 winpos
->hwndInsertAfter
== HWND_TOPMOST
||
3110 winpos
->hwndInsertAfter
== HWND_NOTOPMOST
))
3112 HWND parent
= NtUserGetAncestor( winpos
->hwnd
, GA_PARENT
);
3113 HWND insertafter_parent
= NtUserGetAncestor( winpos
->hwndInsertAfter
, GA_PARENT
);
3115 /* hwndInsertAfter must be a sibling of the window */
3116 if (!insertafter_parent
) return FALSE
;
3117 if (insertafter_parent
!= parent
) return TRUE
;
3121 /* Make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
3122 if (!(winpos
->flags
& SWP_NOMOVE
))
3124 if (winpos
->x
< -32768) winpos
->x
= -32768;
3125 else if (winpos
->x
> 32767) winpos
->x
= 32767;
3126 if (winpos
->y
< -32768) winpos
->y
= -32768;
3127 else if (winpos
->y
> 32767) winpos
->y
= 32767;
3129 if (!(winpos
->flags
& SWP_NOSIZE
))
3131 if (winpos
->cx
< 0) winpos
->cx
= 0;
3132 else if (winpos
->cx
> 32767) winpos
->cx
= 32767;
3133 if (winpos
->cy
< 0) winpos
->cy
= 0;
3134 else if (winpos
->cy
> 32767) winpos
->cy
= 32767;
3137 context
= set_thread_dpi_awareness_context( get_window_dpi_awareness_context( winpos
->hwnd
));
3139 if (!calc_winpos( winpos
, &old_window_rect
, &old_client_rect
,
3140 &new_window_rect
, &new_client_rect
)) goto done
;
3142 /* Fix redundant flags */
3143 if (!fixup_swp_flags( winpos
, &old_window_rect
, parent_x
, parent_y
)) goto done
;
3145 if((winpos
->flags
& (SWP_NOZORDER
| SWP_HIDEWINDOW
| SWP_SHOWWINDOW
)) != SWP_NOZORDER
)
3147 if (NtUserGetAncestor( winpos
->hwnd
, GA_PARENT
) == get_desktop_window())
3148 winpos
->hwndInsertAfter
= swp_owner_popups( winpos
->hwnd
, winpos
->hwndInsertAfter
);
3151 /* Common operations */
3153 calc_ncsize( winpos
, &old_window_rect
, &old_client_rect
,
3154 &new_window_rect
, &new_client_rect
, valid_rects
, parent_x
, parent_y
);
3156 if (!apply_window_pos( winpos
->hwnd
, winpos
->hwndInsertAfter
, winpos
->flags
,
3157 &new_window_rect
, &new_client_rect
, valid_rects
))
3162 if (winpos
->flags
& SWP_HIDEWINDOW
)
3163 user_callbacks
->pHideCaret( winpos
->hwnd
);
3164 else if (winpos
->flags
& SWP_SHOWWINDOW
)
3165 user_callbacks
->pShowCaret( winpos
->hwnd
);
3168 if (!(winpos
->flags
& (SWP_NOACTIVATE
|SWP_HIDEWINDOW
)))
3170 /* child windows get WM_CHILDACTIVATE message */
3171 if ((get_window_long( winpos
->hwnd
, GWL_STYLE
) & (WS_CHILD
| WS_POPUP
)) == WS_CHILD
)
3172 send_message( winpos
->hwnd
, WM_CHILDACTIVATE
, 0, 0 );
3173 else if (user_callbacks
)
3174 set_foreground_window( winpos
->hwnd
, FALSE
);
3177 if(!(orig_flags
& SWP_DEFERERASE
))
3179 /* erase parent when hiding or resizing child */
3180 if ((orig_flags
& SWP_HIDEWINDOW
) ||
3181 (!(orig_flags
& SWP_SHOWWINDOW
) &&
3182 (winpos
->flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOGEOMETRYCHANGE
))
3184 HWND parent
= NtUserGetAncestor( winpos
->hwnd
, GA_PARENT
);
3185 if (!parent
|| parent
== get_desktop_window()) parent
= winpos
->hwnd
;
3186 erase_now( parent
, 0 );
3189 /* Give newly shown windows a chance to redraw */
3190 if(((winpos
->flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOPOSCHANGE
)
3191 && !(orig_flags
& SWP_AGG_NOCLIENTCHANGE
) && (orig_flags
& SWP_SHOWWINDOW
))
3193 erase_now(winpos
->hwnd
, 0);
3197 /* And last, send the WM_WINDOWPOSCHANGED message */
3199 TRACE( "\tstatus flags = %04x\n", winpos
->flags
& SWP_AGG_STATUSFLAGS
);
3201 if (((winpos
->flags
& SWP_AGG_STATUSFLAGS
) != SWP_AGG_NOPOSCHANGE
)
3202 && !((orig_flags
& SWP_AGG_NOCLIENTCHANGE
) && (orig_flags
& SWP_SHOWWINDOW
)))
3204 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
3205 and always contains final window position.
3207 winpos
->x
= new_window_rect
.left
;
3208 winpos
->y
= new_window_rect
.top
;
3209 winpos
->cx
= new_window_rect
.right
- new_window_rect
.left
;
3210 winpos
->cy
= new_window_rect
.bottom
- new_window_rect
.top
;
3211 send_message( winpos
->hwnd
, WM_WINDOWPOSCHANGED
, 0, (LPARAM
)winpos
);
3215 set_thread_dpi_awareness_context( context
);
3219 /*******************************************************************
3220 * NtUserSetWindowPos (win32u.@)
3222 BOOL WINAPI
NtUserSetWindowPos( HWND hwnd
, HWND after
, INT x
, INT y
, INT cx
, INT cy
, UINT flags
)
3226 TRACE( "hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n", hwnd
, after
, x
, y
, cx
, cy
, flags
);
3227 if(TRACE_ON(win
)) dump_winpos_flags(flags
);
3229 if (is_broadcast( hwnd
))
3231 SetLastError( ERROR_INVALID_PARAMETER
);
3235 winpos
.hwnd
= get_full_window_handle( hwnd
);
3236 winpos
.hwndInsertAfter
= get_full_window_handle( after
);
3241 winpos
.flags
= flags
;
3243 map_dpi_winpos( &winpos
);
3245 if (is_current_thread_window( hwnd
))
3246 return set_window_pos( &winpos
, 0, 0 );
3248 if (flags
& SWP_ASYNCWINDOWPOS
)
3249 return NtUserMessageCall( winpos
.hwnd
, WM_WINE_SETWINDOWPOS
, 0, (LPARAM
)&winpos
,
3250 0, FNID_SENDNOTIFYMESSAGE
, FALSE
);
3252 return send_message( winpos
.hwnd
, WM_WINE_SETWINDOWPOS
, 0, (LPARAM
)&winpos
);
3257 struct user_object obj
;
3259 INT suggested_count
;
3264 /* see BeginDeferWindowPos */
3265 HDWP
begin_defer_window_pos( INT count
)
3270 TRACE( "%d\n", count
);
3274 SetLastError( ERROR_INVALID_PARAMETER
);
3277 /* Windows allows zero count, in which case it allocates context for 8 moves */
3278 if (count
== 0) count
= 8;
3280 if (!(dwp
= malloc( sizeof(DWP
) ))) return 0;
3284 dwp
->suggested_count
= count
;
3286 if (!(dwp
->winpos
= malloc( count
* sizeof(WINDOWPOS
) )) ||
3287 !(handle
= alloc_user_handle( &dwp
->obj
, NTUSER_OBJ_WINPOS
)))
3289 free( dwp
->winpos
);
3293 TRACE( "returning %p\n", handle
);
3297 /***********************************************************************
3298 * NtUserDeferWindowPosAndBand (win32u.@)
3300 HDWP WINAPI
NtUserDeferWindowPosAndBand( HDWP hdwp
, HWND hwnd
, HWND after
,
3301 INT x
, INT y
, INT cx
, INT cy
,
3302 UINT flags
, UINT unk1
, UINT unk2
)
3304 HDWP retvalue
= hdwp
;
3309 TRACE( "hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
3310 hdwp
, hwnd
, after
, x
, y
, cx
, cy
, flags
);
3312 winpos
.hwnd
= get_full_window_handle( hwnd
);
3313 if (is_desktop_window( winpos
.hwnd
) || !is_window( winpos
.hwnd
))
3315 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
3319 winpos
.hwndInsertAfter
= get_full_window_handle( after
);
3320 winpos
.flags
= flags
;
3325 map_dpi_winpos( &winpos
);
3327 if (!(dwp
= get_user_handle_ptr( hdwp
, NTUSER_OBJ_WINPOS
))) return 0;
3328 if (dwp
== OBJ_OTHER_PROCESS
)
3330 FIXME( "other process handle %p\n", hdwp
);
3334 for (i
= 0; i
< dwp
->count
; i
++)
3336 if (dwp
->winpos
[i
].hwnd
== winpos
.hwnd
)
3338 /* Merge with the other changes */
3339 if (!(flags
& SWP_NOZORDER
))
3341 dwp
->winpos
[i
].hwndInsertAfter
= winpos
.hwndInsertAfter
;
3343 if (!(flags
& SWP_NOMOVE
))
3345 dwp
->winpos
[i
].x
= winpos
.x
;
3346 dwp
->winpos
[i
].y
= winpos
.y
;
3348 if (!(flags
& SWP_NOSIZE
))
3350 dwp
->winpos
[i
].cx
= winpos
.cx
;
3351 dwp
->winpos
[i
].cy
= winpos
.cy
;
3353 dwp
->winpos
[i
].flags
&= flags
| ~(SWP_NOSIZE
| SWP_NOMOVE
|
3354 SWP_NOZORDER
| SWP_NOREDRAW
|
3355 SWP_NOACTIVATE
| SWP_NOCOPYBITS
|
3357 dwp
->winpos
[i
].flags
|= flags
& (SWP_SHOWWINDOW
| SWP_HIDEWINDOW
|
3362 if (dwp
->count
>= dwp
->suggested_count
)
3364 WINDOWPOS
*newpos
= realloc( dwp
->winpos
, dwp
->suggested_count
* 2 * sizeof(WINDOWPOS
) );
3370 dwp
->suggested_count
*= 2;
3371 dwp
->winpos
= newpos
;
3373 dwp
->winpos
[dwp
->count
++] = winpos
;
3375 release_user_handle_ptr( dwp
);
3379 /***********************************************************************
3380 * NtUserEndDeferWindowPosEx (win32u.@)
3382 BOOL WINAPI
NtUserEndDeferWindowPosEx( HDWP hdwp
, BOOL async
)
3388 TRACE( "%p\n", hdwp
);
3390 if (async
) FIXME( "async not supported\n" );
3392 if (!(dwp
= free_user_handle( hdwp
, NTUSER_OBJ_WINPOS
))) return FALSE
;
3393 if (dwp
== OBJ_OTHER_PROCESS
)
3395 FIXME( "other process handle %p\n", hdwp
);
3399 for (i
= 0, winpos
= dwp
->winpos
; i
< dwp
->count
; i
++, winpos
++)
3401 TRACE( "hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
3402 winpos
->hwnd
, winpos
->hwndInsertAfter
, winpos
->x
, winpos
->y
,
3403 winpos
->cx
, winpos
->cy
, winpos
->flags
);
3405 if (is_current_thread_window( winpos
->hwnd
))
3406 set_window_pos( winpos
, 0, 0 );
3408 send_message( winpos
->hwnd
, WM_WINE_SETWINDOWPOS
, 0, (LPARAM
)winpos
);
3410 free( dwp
->winpos
);
3415 /***********************************************************************
3418 * Set the flags of a window and return the previous value.
3420 UINT
win_set_flags( HWND hwnd
, UINT set_mask
, UINT clear_mask
)
3422 WND
*win
= get_win_ptr( hwnd
);
3425 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return 0;
3427 win
->flags
= (ret
& ~clear_mask
) | set_mask
;
3428 release_win_ptr( win
);
3432 /*******************************************************************
3433 * can_activate_window
3435 * Check if we can activate the specified window.
3437 static BOOL
can_activate_window( HWND hwnd
)
3441 if (!hwnd
) return FALSE
;
3442 style
= get_window_long( hwnd
, GWL_STYLE
);
3443 if (!(style
& WS_VISIBLE
)) return FALSE
;
3444 if ((style
& (WS_POPUP
|WS_CHILD
)) == WS_CHILD
) return FALSE
;
3445 return !(style
& WS_DISABLED
);
3448 /*******************************************************************
3449 * activate_other_window
3451 * Activates window other than hwnd.
3453 static void activate_other_window( HWND hwnd
)
3457 if ((get_window_long( hwnd
, GWL_STYLE
) & WS_POPUP
) &&
3458 (hwnd_to
= get_window_relative( hwnd
, GW_OWNER
)))
3460 hwnd_to
= NtUserGetAncestor( hwnd_to
, GA_ROOT
);
3461 if (can_activate_window( hwnd_to
)) goto done
;
3467 if (!(hwnd_to
= get_window_relative( hwnd_to
, GW_HWNDNEXT
))) break;
3468 if (can_activate_window( hwnd_to
)) goto done
;
3471 hwnd_to
= get_window_relative( get_desktop_window(), GW_CHILD
);
3474 if (hwnd_to
== hwnd
)
3479 if (can_activate_window( hwnd_to
)) goto done
;
3480 if (!(hwnd_to
= get_window_relative( hwnd_to
, GW_HWNDNEXT
))) break;
3484 fg
= NtUserGetForegroundWindow();
3485 TRACE( "win = %p fg = %p\n", hwnd_to
, fg
);
3486 if (!fg
|| hwnd
== fg
)
3488 if (set_foreground_window( hwnd_to
, FALSE
)) return;
3490 if (NtUserSetActiveWindow( hwnd_to
)) NtUserSetActiveWindow( 0 );
3493 /*******************************************************************
3494 * send_parent_notify
3496 static void send_parent_notify( HWND hwnd
, UINT msg
)
3498 if ((get_window_long( hwnd
, GWL_STYLE
) & (WS_CHILD
| WS_POPUP
)) == WS_CHILD
&&
3499 !(get_window_long( hwnd
, GWL_EXSTYLE
) & WS_EX_NOPARENTNOTIFY
))
3501 HWND parent
= get_parent( hwnd
);
3502 if (parent
&& parent
!= get_desktop_window())
3503 send_message( parent
, WM_PARENTNOTIFY
,
3504 MAKEWPARAM( msg
, get_window_long( hwnd
, GWLP_ID
)), (LPARAM
)hwnd
);
3508 /*******************************************************************
3511 * Get the minimized and maximized information for a window.
3513 static MINMAXINFO
get_min_max_info( HWND hwnd
)
3515 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
3516 LONG exstyle
= get_window_long( hwnd
, GWL_EXSTYLE
);
3517 DPI_AWARENESS_CONTEXT context
;
3518 RECT rc_work
, rc_primary
;
3519 LONG adjusted_style
;
3525 context
= set_thread_dpi_awareness_context( get_window_dpi_awareness_context( hwnd
));
3527 /* Compute default values */
3529 get_window_rect( hwnd
, &rc
, get_thread_dpi() );
3530 minmax
.ptReserved
.x
= rc
.left
;
3531 minmax
.ptReserved
.y
= rc
.top
;
3533 if ((style
& WS_CAPTION
) == WS_CAPTION
)
3534 adjusted_style
= style
& ~WS_BORDER
; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
3536 adjusted_style
= style
;
3538 get_client_rect( NtUserGetAncestor( hwnd
, GA_PARENT
), &rc
);
3540 user_callbacks
->pAdjustWindowRectEx( &rc
, adjusted_style
,
3541 (style
& WS_POPUP
) && get_menu( hwnd
), exstyle
);
3546 minmax
.ptMaxSize
.x
= rc
.right
- rc
.left
;
3547 minmax
.ptMaxSize
.y
= rc
.bottom
- rc
.top
;
3548 if (style
& (WS_DLGFRAME
| WS_BORDER
))
3550 minmax
.ptMinTrackSize
.x
= get_system_metrics( SM_CXMINTRACK
);
3551 minmax
.ptMinTrackSize
.y
= get_system_metrics( SM_CYMINTRACK
);
3555 minmax
.ptMinTrackSize
.x
= 2 * xinc
;
3556 minmax
.ptMinTrackSize
.y
= 2 * yinc
;
3558 minmax
.ptMaxTrackSize
.x
= get_system_metrics( SM_CXMAXTRACK
);
3559 minmax
.ptMaxTrackSize
.y
= get_system_metrics( SM_CYMAXTRACK
);
3560 minmax
.ptMaxPosition
.x
= -xinc
;
3561 minmax
.ptMaxPosition
.y
= -yinc
;
3563 if ((win
= get_win_ptr( hwnd
)) && win
!= WND_DESKTOP
&& win
!= WND_OTHER_PROCESS
)
3565 if (!empty_point( win
->max_pos
)) minmax
.ptMaxPosition
= win
->max_pos
;
3566 release_win_ptr( win
);
3569 send_message( hwnd
, WM_GETMINMAXINFO
, 0, (LPARAM
)&minmax
);
3571 /* if the app didn't change the values, adapt them for the current monitor */
3573 if (get_work_rect( hwnd
, &rc_work
))
3575 rc_primary
= get_primary_monitor_rect( get_thread_dpi() );
3576 if (minmax
.ptMaxSize
.x
== (rc_primary
.right
- rc_primary
.left
) + 2 * xinc
&&
3577 minmax
.ptMaxSize
.y
== (rc_primary
.bottom
- rc_primary
.top
) + 2 * yinc
)
3579 minmax
.ptMaxSize
.x
= (rc_work
.right
- rc_work
.left
) + 2 * xinc
;
3580 minmax
.ptMaxSize
.y
= (rc_work
.bottom
- rc_work
.top
) + 2 * yinc
;
3582 if (minmax
.ptMaxPosition
.x
== -xinc
&& minmax
.ptMaxPosition
.y
== -yinc
)
3584 minmax
.ptMaxPosition
.x
= rc_work
.left
- xinc
;
3585 minmax
.ptMaxPosition
.y
= rc_work
.top
- yinc
;
3589 TRACE( "%d %d / %d %d / %d %d / %d %d\n",
3590 minmax
.ptMaxSize
.x
, minmax
.ptMaxSize
.y
,
3591 minmax
.ptMaxPosition
.x
, minmax
.ptMaxPosition
.y
,
3592 minmax
.ptMaxTrackSize
.x
, minmax
.ptMaxTrackSize
.y
,
3593 minmax
.ptMinTrackSize
.x
, minmax
.ptMinTrackSize
.y
);
3595 minmax
.ptMaxTrackSize
.x
= max( minmax
.ptMaxTrackSize
.x
, minmax
.ptMinTrackSize
.x
);
3596 minmax
.ptMaxTrackSize
.y
= max( minmax
.ptMaxTrackSize
.y
, minmax
.ptMinTrackSize
.y
);
3598 set_thread_dpi_awareness_context( context
);
3602 static POINT
get_first_minimized_child_pos( const RECT
*parent
, const MINIMIZEDMETRICS
*mm
,
3603 int width
, int height
)
3607 if (mm
->iArrange
& ARW_STARTRIGHT
)
3608 ret
.x
= parent
->right
- mm
->iHorzGap
- width
;
3610 ret
.x
= parent
->left
+ mm
->iHorzGap
;
3611 if (mm
->iArrange
& ARW_STARTTOP
)
3612 ret
.y
= parent
->top
+ mm
->iVertGap
;
3614 ret
.y
= parent
->bottom
- mm
->iVertGap
- height
;
3619 static void get_next_minimized_child_pos( const RECT
*parent
, const MINIMIZEDMETRICS
*mm
,
3620 int width
, int height
, POINT
*pos
)
3624 if (mm
->iArrange
& ARW_UP
) /* == ARW_DOWN */
3626 if (mm
->iArrange
& ARW_STARTTOP
)
3628 pos
->y
+= height
+ mm
->iVertGap
;
3629 if ((next
= pos
->y
+ height
> parent
->bottom
))
3630 pos
->y
= parent
->top
+ mm
->iVertGap
;
3634 pos
->y
-= height
+ mm
->iVertGap
;
3635 if ((next
= pos
->y
< parent
->top
))
3636 pos
->y
= parent
->bottom
- mm
->iVertGap
- height
;
3641 if (mm
->iArrange
& ARW_STARTRIGHT
)
3642 pos
->x
-= width
+ mm
->iHorzGap
;
3644 pos
->x
+= width
+ mm
->iHorzGap
;
3649 if (mm
->iArrange
& ARW_STARTRIGHT
)
3651 pos
->x
-= width
+ mm
->iHorzGap
;
3652 if ((next
= pos
->x
< parent
->left
))
3653 pos
->x
= parent
->right
- mm
->iHorzGap
- width
;
3657 pos
->x
+= width
+ mm
->iHorzGap
;
3658 if ((next
= pos
->x
+ width
> parent
->right
))
3659 pos
->x
= parent
->left
+ mm
->iHorzGap
;
3664 if (mm
->iArrange
& ARW_STARTTOP
)
3665 pos
->y
+= height
+ mm
->iVertGap
;
3667 pos
->y
-= height
+ mm
->iVertGap
;
3672 static POINT
get_minimized_pos( HWND hwnd
, POINT pt
)
3674 RECT rect
, parent_rect
;
3677 MINIMIZEDMETRICS metrics
;
3680 parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
3681 if (parent
== get_desktop_window())
3683 MONITORINFO mon_info
;
3684 HMONITOR monitor
= monitor_from_window( hwnd
, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
3686 mon_info
.cbSize
= sizeof( mon_info
);
3687 get_monitor_info( monitor
, &mon_info
);
3688 parent_rect
= mon_info
.rcWork
;
3690 else get_client_rect( parent
, &parent_rect
);
3692 if (pt
.x
>= parent_rect
.left
&& (pt
.x
+ get_system_metrics( SM_CXMINIMIZED
) < parent_rect
.right
) &&
3693 pt
.y
>= parent_rect
.top
&& (pt
.y
+ get_system_metrics( SM_CYMINIMIZED
) < parent_rect
.bottom
))
3694 return pt
; /* The icon already has a suitable position */
3696 width
= get_system_metrics( SM_CXMINIMIZED
);
3697 height
= get_system_metrics( SM_CYMINIMIZED
);
3699 metrics
.cbSize
= sizeof(metrics
);
3700 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(metrics
), &metrics
, 0 );
3702 /* Check if another icon already occupies this spot */
3703 /* FIXME: this is completely inefficient */
3705 hrgn
= NtGdiCreateRectRgn( 0, 0, 0, 0 );
3706 tmp
= NtGdiCreateRectRgn( 0, 0, 0, 0 );
3707 for (child
= get_window_relative( parent
, GW_CHILD
);
3709 child
= get_window_relative( child
, GW_HWNDNEXT
))
3711 if (child
== hwnd
) continue;
3712 if ((get_window_long( child
, GWL_STYLE
) & (WS_VISIBLE
|WS_MINIMIZE
)) != (WS_VISIBLE
|WS_MINIMIZE
))
3714 if (get_window_rects( child
, COORDS_PARENT
, &rect
, NULL
, get_thread_dpi() ))
3716 NtGdiSetRectRgn( tmp
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
3717 NtGdiCombineRgn( hrgn
, hrgn
, tmp
, RGN_OR
);
3720 NtGdiDeleteObjectApp( tmp
);
3722 pt
= get_first_minimized_child_pos( &parent_rect
, &metrics
, width
, height
);
3725 set_rect( &rect
, pt
.x
, pt
.y
, pt
.x
+ width
, pt
.y
+ height
);
3726 if (!NtGdiRectInRegion( hrgn
, &rect
))
3729 get_next_minimized_child_pos( &parent_rect
, &metrics
, width
, height
, &pt
);
3732 NtGdiDeleteObjectApp( hrgn
);
3736 /***********************************************************************
3737 * window_min_maximize
3739 static UINT
window_min_maximize( HWND hwnd
, UINT cmd
, RECT
*rect
)
3744 WINDOWPLACEMENT wpl
;
3746 TRACE( "%p %u\n", hwnd
, cmd
);
3748 wpl
.length
= sizeof(wpl
);
3749 get_window_placement( hwnd
, &wpl
);
3751 if (call_hooks( WH_CBT
, HCBT_MINMAX
, (WPARAM
)hwnd
, cmd
, TRUE
))
3752 return SWP_NOSIZE
| SWP_NOMOVE
;
3754 if (is_iconic( hwnd
))
3758 case SW_SHOWMINNOACTIVE
:
3759 case SW_SHOWMINIMIZED
:
3760 case SW_FORCEMINIMIZE
:
3762 wpl
.ptMinPosition
= get_minimized_pos( hwnd
, wpl
.ptMinPosition
);
3764 set_rect( rect
, wpl
.ptMinPosition
.x
, wpl
.ptMinPosition
.y
,
3765 wpl
.ptMinPosition
.x
+ get_system_metrics( SM_CXMINIMIZED
),
3766 wpl
.ptMinPosition
.y
+ get_system_metrics( SM_CYMINIMIZED
));
3767 return SWP_NOSIZE
| SWP_NOMOVE
;
3769 if (!send_message( hwnd
, WM_QUERYOPEN
, 0, 0 )) return SWP_NOSIZE
| SWP_NOMOVE
;
3770 swp_flags
|= SWP_NOCOPYBITS
;
3775 case SW_SHOWMINNOACTIVE
:
3776 case SW_SHOWMINIMIZED
:
3777 case SW_FORCEMINIMIZE
:
3779 if (is_zoomed( hwnd
)) win_set_flags( hwnd
, WIN_RESTORE_MAX
, 0 );
3780 else win_set_flags( hwnd
, 0, WIN_RESTORE_MAX
);
3782 if (get_focus() == hwnd
)
3784 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
)
3785 NtUserSetFocus( NtUserGetAncestor( hwnd
, GA_PARENT
));
3787 NtUserSetFocus( 0 );
3790 old_style
= set_window_style( hwnd
, WS_MINIMIZE
, WS_MAXIMIZE
);
3792 wpl
.ptMinPosition
= get_minimized_pos( hwnd
, wpl
.ptMinPosition
);
3794 if (!(old_style
& WS_MINIMIZE
)) swp_flags
|= SWP_STATECHANGED
;
3795 set_rect( rect
, wpl
.ptMinPosition
.x
, wpl
.ptMinPosition
.y
,
3796 wpl
.ptMinPosition
.x
+ get_system_metrics(SM_CXMINIMIZED
),
3797 wpl
.ptMinPosition
.y
+ get_system_metrics(SM_CYMINIMIZED
) );
3798 swp_flags
|= SWP_NOCOPYBITS
;
3802 old_style
= get_window_long( hwnd
, GWL_STYLE
);
3803 if ((old_style
& WS_MAXIMIZE
) && (old_style
& WS_VISIBLE
)) return SWP_NOSIZE
| SWP_NOMOVE
;
3805 minmax
= get_min_max_info( hwnd
);
3807 old_style
= set_window_style( hwnd
, WS_MAXIMIZE
, WS_MINIMIZE
);
3808 if (old_style
& WS_MINIMIZE
)
3809 win_set_flags( hwnd
, WIN_RESTORE_MAX
, 0 );
3811 if (!(old_style
& WS_MAXIMIZE
)) swp_flags
|= SWP_STATECHANGED
;
3812 set_rect( rect
, minmax
.ptMaxPosition
.x
, minmax
.ptMaxPosition
.y
,
3813 minmax
.ptMaxPosition
.x
+ minmax
.ptMaxSize
.x
,
3814 minmax
.ptMaxPosition
.y
+ minmax
.ptMaxSize
.y
);
3817 case SW_SHOWNOACTIVATE
:
3818 win_set_flags( hwnd
, 0, WIN_RESTORE_MAX
);
3822 case SW_SHOWDEFAULT
: /* FIXME: should have its own handler */
3823 old_style
= set_window_style( hwnd
, 0, WS_MINIMIZE
| WS_MAXIMIZE
);
3824 if (old_style
& WS_MINIMIZE
)
3826 if (win_get_flags( hwnd
) & WIN_RESTORE_MAX
)
3828 /* Restore to maximized position */
3829 minmax
= get_min_max_info( hwnd
);
3830 set_window_style( hwnd
, WS_MAXIMIZE
, 0 );
3831 swp_flags
|= SWP_STATECHANGED
;
3832 set_rect( rect
, minmax
.ptMaxPosition
.x
, minmax
.ptMaxPosition
.y
,
3833 minmax
.ptMaxPosition
.x
+ minmax
.ptMaxSize
.x
,
3834 minmax
.ptMaxPosition
.y
+ minmax
.ptMaxSize
.y
);
3838 else if (!(old_style
& WS_MAXIMIZE
)) break;
3840 swp_flags
|= SWP_STATECHANGED
;
3842 /* Restore to normal position */
3844 *rect
= wpl
.rcNormalPosition
;
3851 /* see ArrangeIconicWindows */
3852 static UINT
arrange_iconic_windows( HWND parent
)
3854 int width
, height
, count
= 0;
3855 MINIMIZEDMETRICS metrics
;
3860 metrics
.cbSize
= sizeof(metrics
);
3861 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(metrics
), &metrics
, 0 );
3862 width
= get_system_metrics( SM_CXMINIMIZED
);
3863 height
= get_system_metrics( SM_CYMINIMIZED
);
3865 if (parent
== get_desktop_window())
3867 MONITORINFO mon_info
;
3868 HMONITOR monitor
= monitor_from_window( 0, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
3870 mon_info
.cbSize
= sizeof( mon_info
);
3871 get_monitor_info( monitor
, &mon_info
);
3872 parent_rect
= mon_info
.rcWork
;
3874 else get_client_rect( parent
, &parent_rect
);
3876 pt
= get_first_minimized_child_pos( &parent_rect
, &metrics
, width
, height
);
3878 child
= get_window_relative( parent
, GW_CHILD
);
3881 if (is_iconic( child
))
3883 NtUserSetWindowPos( child
, 0, pt
.x
, pt
.y
, 0, 0,
3884 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
3885 get_next_minimized_child_pos( &parent_rect
, &metrics
, width
, height
, &pt
);
3888 child
= get_window_relative( child
, GW_HWNDNEXT
);
3893 /*******************************************************************
3894 * update_window_state
3896 * Trigger an update of the window's driver state and surface.
3898 void update_window_state( HWND hwnd
)
3900 DPI_AWARENESS_CONTEXT context
;
3901 RECT window_rect
, client_rect
, valid_rects
[2];
3903 if (!is_current_thread_window( hwnd
))
3905 post_message( hwnd
, WM_WINE_UPDATEWINDOWSTATE
, 0, 0 );
3909 context
= set_thread_dpi_awareness_context( get_window_dpi_awareness_context( hwnd
));
3910 get_window_rects( hwnd
, COORDS_PARENT
, &window_rect
, &client_rect
, get_thread_dpi() );
3911 valid_rects
[0] = valid_rects
[1] = client_rect
;
3912 apply_window_pos( hwnd
, 0, SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOCLIENTSIZE
| SWP_NOCLIENTMOVE
|
3913 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOREDRAW
,
3914 &window_rect
, &client_rect
, valid_rects
);
3915 set_thread_dpi_awareness_context( context
);
3918 /***********************************************************************
3921 * Implementation of ShowWindow and ShowWindowAsync.
3923 static BOOL
show_window( HWND hwnd
, INT cmd
)
3927 DPI_AWARENESS_CONTEXT context
;
3928 LONG style
= get_window_long( hwnd
, GWL_STYLE
);
3929 BOOL was_visible
= (style
& WS_VISIBLE
) != 0;
3930 BOOL show_flag
= TRUE
;
3931 RECT newPos
= {0, 0, 0, 0};
3932 UINT new_swp
, swp
= 0;
3934 TRACE( "hwnd=%p, cmd=%d, was_visible %d\n", hwnd
, cmd
, was_visible
);
3936 context
= set_thread_dpi_awareness_context( get_window_dpi_awareness_context( hwnd
));
3941 if (!was_visible
) goto done
;
3943 swp
|= SWP_HIDEWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
3944 if (style
& WS_CHILD
) swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
3947 case SW_SHOWMINNOACTIVE
:
3949 case SW_FORCEMINIMIZE
: /* FIXME: Does not work if thread is hung. */
3950 swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
3952 case SW_SHOWMINIMIZED
:
3953 swp
|= SWP_SHOWWINDOW
| SWP_FRAMECHANGED
;
3954 swp
|= window_min_maximize( hwnd
, cmd
, &newPos
);
3955 if ((style
& WS_MINIMIZE
) && was_visible
) goto done
;
3958 case SW_SHOWMAXIMIZED
: /* same as SW_MAXIMIZE */
3959 if (!was_visible
) swp
|= SWP_SHOWWINDOW
;
3960 swp
|= SWP_FRAMECHANGED
;
3961 swp
|= window_min_maximize( hwnd
, SW_MAXIMIZE
, &newPos
);
3962 if ((style
& WS_MAXIMIZE
) && was_visible
) goto done
;
3966 swp
|= SWP_NOACTIVATE
| SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
3967 if (style
& WS_CHILD
) swp
|= SWP_NOZORDER
;
3971 if (was_visible
) goto done
;
3972 swp
|= SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
;
3973 if (style
& WS_CHILD
) swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
3976 case SW_SHOWNOACTIVATE
:
3977 swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
3981 case SW_SHOWNORMAL
: /* same as SW_NORMAL: */
3982 case SW_SHOWDEFAULT
: /* FIXME: should have its own handler */
3983 if (!was_visible
) swp
|= SWP_SHOWWINDOW
;
3984 if (style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
3986 swp
|= SWP_FRAMECHANGED
;
3987 swp
|= window_min_maximize( hwnd
, cmd
, &newPos
);
3991 if (was_visible
) goto done
;
3992 swp
|= SWP_NOSIZE
| SWP_NOMOVE
;
3994 if (style
& WS_CHILD
&& !(swp
& SWP_STATECHANGED
)) swp
|= SWP_NOACTIVATE
| SWP_NOZORDER
;
4001 if ((show_flag
!= was_visible
|| cmd
== SW_SHOWNA
) && cmd
!= SW_SHOWMAXIMIZED
&& !(swp
& SWP_STATECHANGED
))
4003 send_message( hwnd
, WM_SHOWWINDOW
, show_flag
, 0 );
4004 if (!is_window( hwnd
)) goto done
;
4007 if (IsRectEmpty( &newPos
)) new_swp
= swp
;
4008 else if ((new_swp
= user_driver
->pShowWindow( hwnd
, cmd
, &newPos
, swp
)) == ~0)
4010 if (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) new_swp
= swp
;
4011 else if (is_iconic( hwnd
) && (newPos
.left
!= -32000 || newPos
.top
!= -32000))
4013 offset_rect( &newPos
, -32000 - newPos
.left
, -32000 - newPos
.top
);
4014 new_swp
= swp
& ~(SWP_NOMOVE
| SWP_NOCLIENTMOVE
);
4020 parent
= NtUserGetAncestor( hwnd
, GA_PARENT
);
4021 if (parent
&& !is_window_visible( parent
) && !(swp
& SWP_STATECHANGED
))
4023 /* if parent is not visible simply toggle WS_VISIBLE and return */
4024 if (show_flag
) set_window_style( hwnd
, WS_VISIBLE
, 0 );
4025 else set_window_style( hwnd
, 0, WS_VISIBLE
);
4028 NtUserSetWindowPos( hwnd
, HWND_TOP
, newPos
.left
, newPos
.top
,
4029 newPos
.right
- newPos
.left
, newPos
.bottom
- newPos
.top
, swp
);
4035 /* FIXME: This will cause the window to be activated irrespective
4036 * of whether it is owned by the same thread. Has to be done
4040 if (hwnd
== get_active_window()) activate_other_window( hwnd
);
4042 /* Revert focus to parent */
4043 hFocus
= get_focus();
4046 HWND parent
= NtUserGetAncestor(hwnd
, GA_PARENT
);
4047 if (parent
== get_desktop_window()) parent
= 0;
4048 NtUserSetFocus(parent
);
4053 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
) goto done
;
4055 if (win
->flags
& WIN_NEED_SIZE
)
4057 /* should happen only in CreateWindowEx() */
4058 int wParam
= SIZE_RESTORED
;
4062 get_window_rects( hwnd
, COORDS_PARENT
, NULL
, &client
, get_thread_dpi() );
4063 lparam
= MAKELONG( client
.right
- client
.left
, client
.bottom
- client
.top
);
4064 win
->flags
&= ~WIN_NEED_SIZE
;
4065 if (win
->dwStyle
& WS_MAXIMIZE
) wParam
= SIZE_MAXIMIZED
;
4066 else if (win
->dwStyle
& WS_MINIMIZE
)
4068 wParam
= SIZE_MINIMIZED
;
4071 release_win_ptr( win
);
4073 send_message( hwnd
, WM_SIZE
, wParam
, lparam
);
4074 send_message( hwnd
, WM_MOVE
, 0, MAKELONG( client
.left
, client
.top
));
4076 else release_win_ptr( win
);
4078 /* if previous state was minimized Windows sets focus to the window */
4079 if (style
& WS_MINIMIZE
)
4081 NtUserSetFocus( hwnd
);
4082 /* Send a WM_ACTIVATE message for a top level window, even if the window is already active */
4083 if (NtUserGetAncestor( hwnd
, GA_ROOT
) == hwnd
&& !(swp
& SWP_NOACTIVATE
))
4084 send_message( hwnd
, WM_ACTIVATE
, WA_ACTIVE
, 0 );
4088 set_thread_dpi_awareness_context( context
);
4092 /***********************************************************************
4093 * NtUserShowWindowAsync (win32u.@)
4095 * doesn't wait; returns immediately.
4096 * used by threads to toggle windows in other (possibly hanging) threads
4098 BOOL WINAPI
NtUserShowWindowAsync( HWND hwnd
, INT cmd
)
4102 if (is_broadcast(hwnd
))
4104 SetLastError( ERROR_INVALID_PARAMETER
);
4108 if ((full_handle
= is_current_thread_window( hwnd
)))
4109 return show_window( full_handle
, cmd
);
4111 return NtUserMessageCall( hwnd
, WM_WINE_SHOWWINDOW
, cmd
, 0, 0,
4112 FNID_SENDNOTIFYMESSAGE
, FALSE
);
4115 /***********************************************************************
4116 * NtUserShowWindow (win32u.@)
4118 BOOL WINAPI
NtUserShowWindow( HWND hwnd
, INT cmd
)
4122 if (is_broadcast(hwnd
))
4124 SetLastError( ERROR_INVALID_PARAMETER
);
4127 if ((full_handle
= is_current_thread_window( hwnd
)))
4128 return show_window( full_handle
, cmd
);
4130 if ((cmd
== SW_HIDE
) && !(get_window_long( hwnd
, GWL_STYLE
) & WS_VISIBLE
))
4133 if ((cmd
== SW_SHOW
) && (get_window_long( hwnd
, GWL_STYLE
) & WS_VISIBLE
))
4136 return send_message( hwnd
, WM_WINE_SHOWWINDOW
, cmd
, 0 );
4139 /*******************************************************************
4140 * NtUserFlashWindowEx (win32u.@)
4142 BOOL WINAPI
NtUserFlashWindowEx( FLASHWINFO
*info
)
4146 TRACE( "%p\n", info
);
4150 SetLastError( ERROR_NOACCESS
);
4154 if (!info
->hwnd
|| info
->cbSize
!= sizeof(FLASHWINFO
) || !is_window( info
->hwnd
))
4156 SetLastError( ERROR_INVALID_PARAMETER
);
4159 FIXME( "%p - semi-stub\n", info
);
4161 if (is_iconic( info
->hwnd
))
4163 NtUserRedrawWindow( info
->hwnd
, 0, 0, RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_FRAME
);
4165 win
= get_win_ptr( info
->hwnd
);
4166 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
4167 if (info
->dwFlags
&& !(win
->flags
& WIN_NCACTIVATED
))
4169 win
->flags
|= WIN_NCACTIVATED
;
4173 win
->flags
&= ~WIN_NCACTIVATED
;
4175 release_win_ptr( win
);
4176 user_driver
->pFlashWindowEx( info
);
4182 HWND hwnd
= info
->hwnd
;
4184 win
= get_win_ptr( hwnd
);
4185 if (!win
|| win
== WND_OTHER_PROCESS
|| win
== WND_DESKTOP
) return FALSE
;
4186 hwnd
= win
->obj
.handle
; /* make it a full handle */
4188 if (info
->dwFlags
) wparam
= !(win
->flags
& WIN_NCACTIVATED
);
4189 else wparam
= (hwnd
== NtUserGetForegroundWindow());
4191 release_win_ptr( win
);
4192 send_message( hwnd
, WM_NCACTIVATE
, wparam
, 0 );
4193 user_driver
->pFlashWindowEx( info
);
4198 /* see GetWindowContextHelpId */
4199 static DWORD
get_window_context_help_id( HWND hwnd
)
4202 WND
*win
= get_win_ptr( hwnd
);
4203 if (!win
|| win
== WND_DESKTOP
) return 0;
4204 if (win
== WND_OTHER_PROCESS
)
4206 if (is_window( hwnd
)) FIXME( "not supported on other process window %p\n", hwnd
);
4209 retval
= win
->helpContext
;
4210 release_win_ptr( win
);
4214 /***********************************************************************
4215 * send_destroy_message
4217 static void send_destroy_message( HWND hwnd
)
4221 info
.cbSize
= sizeof(info
);
4222 if (NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info
))
4224 if (hwnd
== info
.hwndCaret
&& user_callbacks
) user_callbacks
->pDestroyCaret();
4225 if (hwnd
== info
.hwndActive
) activate_other_window( hwnd
);
4228 if (hwnd
== NtUserGetClipboardOwner()) release_clipboard_owner( hwnd
);
4230 send_message( hwnd
, WM_DESTROY
, 0, 0);
4233 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
4234 * make sure that the window still exists when we come back.
4236 if (is_window(hwnd
))
4241 if (!(children
= list_window_children( 0, hwnd
, NULL
, 0 ))) return;
4243 for (i
= 0; children
[i
]; i
++)
4245 if (is_window( children
[i
] )) send_destroy_message( children
[i
] );
4250 WARN( "\tdestroyed itself while in WM_DESTROY!\n" );
4253 /***********************************************************************
4254 * free_window_handle
4256 * Free a window handle.
4258 static void free_window_handle( HWND hwnd
)
4264 if ((win
= get_user_handle_ptr( hwnd
, NTUSER_OBJ_WINDOW
)) && win
!= OBJ_OTHER_PROCESS
)
4266 SERVER_START_REQ( destroy_window
)
4268 req
->handle
= wine_server_user_handle( hwnd
);
4269 wine_server_call( req
);
4270 set_user_handle_ptr( hwnd
, NULL
);
4274 if (user_callbacks
) user_callbacks
->free_win_ptr( win
);
4279 /***********************************************************************
4282 LRESULT
destroy_window( HWND hwnd
)
4284 struct window_surface
*surface
;
4285 HMENU menu
= 0, sys_menu
;
4289 TRACE( "%p\n", hwnd
);
4291 /* destroy default IME window */
4292 if (win_set_flags( hwnd
, 0, WIN_HAS_IME_WIN
) & WIN_HAS_IME_WIN
)
4294 TRACE("unregister IME window for %p\n", hwnd
);
4295 if (user_callbacks
) user_callbacks
->unregister_imm( hwnd
);
4298 /* free child windows */
4299 if ((children
= list_window_children( 0, hwnd
, NULL
, 0 )))
4302 for (i
= 0; children
[i
]; i
++)
4304 if (is_current_thread_window( children
[i
] ))
4305 destroy_window( children
[i
] );
4307 NtUserMessageCall( children
[i
], WM_WINE_DESTROYWINDOW
, 0, 0,
4308 0, FNID_SENDNOTIFYMESSAGE
, FALSE
);
4313 /* Unlink now so we won't bother with the children later on */
4314 SERVER_START_REQ( set_parent
)
4316 req
->handle
= wine_server_user_handle( hwnd
);
4318 wine_server_call( req
);
4322 send_message( hwnd
, WM_NCDESTROY
, 0, 0 );
4324 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
4326 /* free resources associated with the window */
4328 if (!(win
= get_win_ptr( hwnd
)) || win
== WND_OTHER_PROCESS
) return 0;
4329 if ((win
->dwStyle
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
)
4330 menu
= (HMENU
)win
->wIDmenu
;
4331 sys_menu
= win
->hSysMenu
;
4332 free_dce( win
->dce
, hwnd
);
4334 NtUserDestroyCursor( win
->hIconSmall2
, 0 );
4335 surface
= win
->surface
;
4336 win
->surface
= NULL
;
4337 release_win_ptr( win
);
4339 NtUserDestroyMenu( menu
);
4340 NtUserDestroyMenu( sys_menu
);
4343 register_window_surface( surface
, NULL
);
4344 window_surface_release( surface
);
4347 user_driver
->pDestroyWindow( hwnd
);
4349 free_window_handle( hwnd
);
4353 /***********************************************************************
4354 * NtUserDestroyWindow (win32u.@)
4356 BOOL WINAPI
NtUserDestroyWindow( HWND hwnd
)
4360 if (!(hwnd
= is_current_thread_window( hwnd
)) || is_desktop_window( hwnd
))
4362 SetLastError( ERROR_ACCESS_DENIED
);
4366 TRACE( "(%p)\n", hwnd
);
4368 if (call_hooks( WH_CBT
, HCBT_DESTROYWND
, (WPARAM
)hwnd
, 0, TRUE
)) return FALSE
;
4370 if (user_callbacks
&& user_callbacks
->is_menu_active() == hwnd
)
4371 user_callbacks
->pEndMenu();
4373 is_child
= (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) != 0;
4377 if (!is_exiting_thread( GetCurrentThreadId() ))
4378 send_parent_notify( hwnd
, WM_DESTROY
);
4380 else if (!get_window_relative( hwnd
, GW_OWNER
))
4382 call_hooks( WH_SHELL
, HSHELL_WINDOWDESTROYED
, (WPARAM
)hwnd
, 0L, TRUE
);
4383 /* FIXME: clean up palette - see "Internals" p.352 */
4386 if (!is_window( hwnd
)) return TRUE
;
4388 /* Hide the window */
4389 if (get_window_long( hwnd
, GWL_STYLE
) & WS_VISIBLE
)
4391 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
4393 NtUserShowWindow( hwnd
, SW_HIDE
);
4395 NtUserSetWindowPos( hwnd
, 0, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
|
4396 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_HIDEWINDOW
);
4399 if (!is_window( hwnd
)) return TRUE
;
4401 /* Recursively destroy child windows */
4406 BOOL got_one
= FALSE
;
4410 if (!(children
= list_window_children( 0, get_desktop_window(), NULL
, 0 ))) break;
4412 for (i
= 0; children
[i
]; i
++)
4414 if (get_window_relative( children
[i
], GW_OWNER
) != hwnd
) continue;
4415 if (is_current_thread_window( children
[i
] ))
4417 NtUserDestroyWindow( children
[i
] );
4421 set_window_owner( children
[i
], 0 );
4424 if (!got_one
) break;
4428 send_destroy_message( hwnd
);
4429 if (!is_window( hwnd
)) return TRUE
;
4431 destroy_window( hwnd
);
4435 /*****************************************************************************
4436 * destroy_thread_windows
4438 * Destroy all window owned by the current thread.
4440 void destroy_thread_windows(void)
4442 WND
*win
, *free_list
= NULL
;
4446 while ((win
= next_thread_window_ptr( &hwnd
)))
4448 free_dce( win
->dce
, win
->obj
.handle
);
4449 set_user_handle_ptr( hwnd
, NULL
);
4450 win
->obj
.handle
= free_list
;
4455 SERVER_START_REQ( destroy_window
)
4457 req
->handle
= 0; /* destroy all thread windows */
4458 wine_server_call( req
);
4464 while ((win
= free_list
))
4466 free_list
= win
->obj
.handle
;
4467 TRACE( "destroying %p\n", win
);
4469 if ((win
->dwStyle
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
&& win
->wIDmenu
)
4470 NtUserDestroyMenu( UlongToHandle(win
->wIDmenu
) );
4471 if (win
->hSysMenu
) NtUserDestroyMenu( win
->hSysMenu
);
4474 register_window_surface( win
->surface
, NULL
);
4475 window_surface_release( win
->surface
);
4477 if (user_callbacks
) user_callbacks
->free_win_ptr( win
);
4482 /***********************************************************************
4483 * create_window_handle
4485 * Create a window handle with the server.
4487 static WND
*create_window_handle( HWND parent
, HWND owner
, UNICODE_STRING
*name
,
4488 HINSTANCE instance
, BOOL ansi
,
4489 DWORD style
, DWORD ex_style
)
4491 DPI_AWARENESS awareness
= get_thread_dpi_awareness();
4492 HWND handle
= 0, full_parent
= 0, full_owner
= 0;
4493 struct tagCLASS
*class = NULL
;
4494 int extra_bytes
= 0;
4498 SERVER_START_REQ( create_window
)
4500 req
->parent
= wine_server_user_handle( parent
);
4501 req
->owner
= wine_server_user_handle( owner
);
4502 req
->instance
= wine_server_client_ptr( instance
);
4503 req
->dpi
= get_system_dpi();
4504 req
->awareness
= awareness
;
4506 req
->ex_style
= ex_style
;
4507 if (!(req
->atom
= get_int_atom_value( name
)) && name
->Length
)
4508 wine_server_add_data( req
, name
->Buffer
, name
->Length
);
4509 if (!wine_server_call_err( req
))
4511 handle
= wine_server_ptr_handle( reply
->handle
);
4512 full_parent
= wine_server_ptr_handle( reply
->parent
);
4513 full_owner
= wine_server_ptr_handle( reply
->owner
);
4514 extra_bytes
= reply
->extra
;
4516 awareness
= reply
->awareness
;
4517 class = wine_server_get_ptr( reply
->class_ptr
);
4524 WARN( "error %d creating window\n", GetLastError() );
4528 if (!(win
= calloc( 1, FIELD_OFFSET(WND
, wExtra
) + extra_bytes
)))
4530 SERVER_START_REQ( destroy_window
)
4532 req
->handle
= wine_server_user_handle( handle
);
4533 wine_server_call( req
);
4536 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
4540 if (!parent
) /* if parent is 0 we don't have a desktop window yet */
4542 struct user_thread_info
*thread_info
= get_user_thread_info();
4544 if (name
->Buffer
== (const WCHAR
*)DESKTOP_CLASS_ATOM
)
4546 if (!thread_info
->top_window
) thread_info
->top_window
= full_parent
? full_parent
: handle
;
4547 else assert( full_parent
== thread_info
->top_window
);
4548 if (full_parent
&& !user_driver
->pCreateDesktopWindow( thread_info
->top_window
))
4549 ERR( "failed to create desktop window\n" );
4550 if (user_callbacks
) user_callbacks
->register_builtin_classes();
4552 else /* HWND_MESSAGE parent */
4554 if (!thread_info
->msg_window
&& !full_parent
) thread_info
->msg_window
= handle
;
4560 win
->obj
.handle
= handle
;
4561 win
->obj
.type
= NTUSER_OBJ_WINDOW
;
4562 win
->parent
= full_parent
;
4563 win
->owner
= full_owner
;
4565 win
->winproc
= get_class_winproc( class );
4566 win
->cbWndExtra
= extra_bytes
;
4568 win
->dpi_awareness
= awareness
;
4569 set_user_handle_ptr( handle
, &win
->obj
);
4570 if (is_winproc_unicode( win
->winproc
, !ansi
)) win
->flags
|= WIN_ISUNICODE
;
4574 static BOOL
is_default_coord( int x
)
4576 return x
== CW_USEDEFAULT
|| x
== 0x8000;
4579 /***********************************************************************
4580 * fix_cs_coordinates
4582 * Fix the coordinates and return default show mode in sw.
4584 static void fix_cs_coordinates( CREATESTRUCTW
*cs
, INT
*sw
)
4586 if (cs
->style
& (WS_CHILD
| WS_POPUP
))
4588 if (is_default_coord(cs
->x
)) cs
->x
= cs
->y
= 0;
4589 if (is_default_coord(cs
->cx
)) cs
->cx
= cs
->cy
= 0;
4591 else /* overlapped window */
4593 RTL_USER_PROCESS_PARAMETERS
*params
= NtCurrentTeb()->Peb
->ProcessParameters
;
4595 MONITORINFO mon_info
;
4597 if (!is_default_coord( cs
->x
) && !is_default_coord( cs
->cx
) && !is_default_coord( cs
->cy
))
4600 monitor
= monitor_from_window( cs
->hwndParent
, MONITOR_DEFAULTTOPRIMARY
, get_thread_dpi() );
4601 mon_info
.cbSize
= sizeof(mon_info
);
4602 get_monitor_info( monitor
, &mon_info
);
4604 if (is_default_coord( cs
->x
))
4606 if (!is_default_coord( cs
->y
)) *sw
= cs
->y
;
4607 cs
->x
= (params
->dwFlags
& STARTF_USEPOSITION
) ? params
->dwX
: mon_info
.rcWork
.left
;
4608 cs
->y
= (params
->dwFlags
& STARTF_USEPOSITION
) ? params
->dwY
: mon_info
.rcWork
.top
;
4611 if (is_default_coord( cs
->cx
))
4613 if (params
->dwFlags
& STARTF_USESIZE
)
4615 cs
->cx
= params
->dwXSize
;
4616 cs
->cy
= params
->dwYSize
;
4620 cs
->cx
= (mon_info
.rcWork
.right
- mon_info
.rcWork
.left
) * 3 / 4 - cs
->x
;
4621 cs
->cy
= (mon_info
.rcWork
.bottom
- mon_info
.rcWork
.top
) * 3 / 4 - cs
->y
;
4624 /* neither x nor cx are default. Check the y values.
4625 * In the trace we see Outlook and Outlook Express using
4626 * cy set to CW_USEDEFAULT when opening the address book.
4628 else if (is_default_coord( cs
->cy
))
4630 FIXME( "Strange use of CW_USEDEFAULT in cy\n" );
4631 cs
->cy
= (mon_info
.rcWork
.bottom
- mon_info
.rcWork
.top
) * 3 / 4 - cs
->y
;
4636 /***********************************************************************
4637 * map_dpi_create_struct
4639 static void map_dpi_create_struct( CREATESTRUCTW
*cs
, UINT dpi_from
, UINT dpi_to
)
4641 if (!dpi_from
&& !dpi_to
) return;
4642 if (!dpi_from
|| !dpi_to
)
4644 POINT pt
= { cs
->x
, cs
->y
};
4645 UINT mon_dpi
= get_monitor_dpi( monitor_from_point( pt
, MONITOR_DEFAULTTONEAREST
, dpi_from
));
4646 if (!dpi_from
) dpi_from
= mon_dpi
;
4647 else dpi_to
= mon_dpi
;
4649 if (dpi_from
== dpi_to
) return;
4650 cs
->x
= muldiv( cs
->x
, dpi_to
, dpi_from
);
4651 cs
->y
= muldiv( cs
->y
, dpi_to
, dpi_from
);
4652 cs
->cx
= muldiv( cs
->cx
, dpi_to
, dpi_from
);
4653 cs
->cy
= muldiv( cs
->cy
, dpi_to
, dpi_from
);
4656 /***********************************************************************
4657 * NtUserCreateWindowEx (win32u.@)
4659 HWND WINAPI
NtUserCreateWindowEx( DWORD ex_style
, UNICODE_STRING
*class_name
,
4660 UNICODE_STRING
*version
, UNICODE_STRING
*window_name
,
4661 DWORD style
, INT x
, INT y
, INT cx
, INT cy
,
4662 HWND parent
, HMENU menu
, HINSTANCE instance
, void *params
,
4663 DWORD flags
, CBT_CREATEWNDW
*cbtc
, DWORD unk
, BOOL ansi
)
4665 CREATESTRUCTW cs
, *client_cs
= cbtc
->lpcs
;
4666 UINT win_dpi
, thread_dpi
= get_thread_dpi();
4667 DPI_AWARENESS_CONTEXT context
;
4668 HWND hwnd
, owner
= 0;
4674 static const WCHAR messageW
[] = {'M','e','s','s','a','g','e'};
4676 cs
.lpCreateParams
= params
;
4677 cs
.hInstance
= client_cs
->hInstance
; /* may be different than instance for win16 */
4679 cs
.hwndParent
= parent
;
4681 cs
.dwExStyle
= ex_style
;
4686 /* We use client_cs to pass original class and name pointers,
4687 * that's probably not how native handles it. */
4688 cs
.lpszName
= client_cs
->lpszName
;
4689 cs
.lpszClass
= client_cs
->lpszClass
;
4691 /* Find the parent window */
4692 if (parent
== HWND_MESSAGE
)
4694 cs
.hwndParent
= parent
= get_hwnd_message_parent();
4698 if ((cs
.style
& (WS_CHILD
|WS_POPUP
)) != WS_CHILD
)
4701 parent
= get_desktop_window();
4705 DWORD parent_style
= get_window_long( parent
, GWL_EXSTYLE
);
4706 if ((parent_style
& WS_EX_LAYOUTRTL
) && !(parent_style
& WS_EX_NOINHERITLAYOUT
))
4707 cs
.dwExStyle
|= WS_EX_LAYOUTRTL
;
4712 if ((cs
.style
& (WS_CHILD
|WS_POPUP
)) == WS_CHILD
)
4714 WARN( "No parent for child window\n" );
4715 SetLastError( ERROR_TLW_WITH_WSCHILD
);
4716 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
4719 /* are we creating the desktop or HWND_MESSAGE parent itself? */
4720 if (class_name
->Buffer
!= (LPCWSTR
)DESKTOP_CLASS_ATOM
&&
4721 (class_name
->Length
!= sizeof(messageW
) ||
4722 wcsnicmp( class_name
->Buffer
, messageW
, ARRAYSIZE(messageW
) )))
4724 parent
= get_desktop_window();
4728 fix_cs_coordinates( &cs
, &sw
);
4729 cs
.dwExStyle
= fix_exstyle( cs
.style
, cs
.dwExStyle
);
4731 /* Create the window structure */
4733 style
= cs
.style
& ~WS_VISIBLE
;
4734 ex_style
= cs
.dwExStyle
& ~WS_EX_LAYERED
;
4735 if (!(win
= create_window_handle( parent
, owner
, class_name
, instance
, ansi
, style
, ex_style
)))
4737 hwnd
= win
->obj
.handle
;
4739 /* Fill the window structure */
4741 win
->tid
= GetCurrentThreadId();
4742 win
->hInstance
= cs
.hInstance
;
4744 win
->dwStyle
= style
;
4745 win
->dwExStyle
= ex_style
;
4747 win
->helpContext
= 0;
4748 win
->pScroll
= NULL
;
4751 win
->hIconSmall
= 0;
4752 win
->hIconSmall2
= 0;
4755 win
->min_pos
.x
= win
->min_pos
.y
= -1;
4756 win
->max_pos
.x
= win
->max_pos
.y
= -1;
4757 SetRect( &win
->normal_rect
, cs
.x
, cs
.y
, cs
.x
+ cs
.cx
, cs
.y
+ cs
.cy
);
4759 if (win
->dwStyle
& WS_SYSMENU
) NtUserSetSystemMenu( hwnd
, 0 );
4761 /* call the WH_CBT hook */
4763 release_win_ptr( win
);
4765 cbtc
->hwndInsertAfter
= HWND_TOP
;
4766 if (call_hooks( WH_CBT
, HCBT_CREATEWND
, (WPARAM
)hwnd
, (LPARAM
)cbtc
, !ansi
))
4768 free_window_handle( hwnd
);
4771 if (!(win
= get_win_ptr( hwnd
))) return 0;
4774 * Correct the window styles.
4776 * It affects only the style loaded into the WND structure.
4779 if ((win
->dwStyle
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
)
4781 win
->dwStyle
|= WS_CLIPSIBLINGS
;
4782 if (!(win
->dwStyle
& WS_POPUP
)) win
->dwStyle
|= WS_CAPTION
;
4785 win
->dwExStyle
= cs
.dwExStyle
;
4786 /* WS_EX_WINDOWEDGE depends on some other styles */
4787 if ((win
->dwStyle
& (WS_DLGFRAME
| WS_THICKFRAME
)) &&
4788 !(win
->dwStyle
& (WS_CHILD
| WS_POPUP
)))
4789 win
->dwExStyle
|= WS_EX_WINDOWEDGE
;
4791 if (!(win
->dwStyle
& (WS_CHILD
| WS_POPUP
))) win
->flags
|= WIN_NEED_SIZE
;
4793 SERVER_START_REQ( set_window_info
)
4795 req
->handle
= wine_server_user_handle( hwnd
);
4796 req
->flags
= SET_WIN_STYLE
| SET_WIN_EXSTYLE
| SET_WIN_INSTANCE
| SET_WIN_UNICODE
;
4797 req
->style
= win
->dwStyle
;
4798 req
->ex_style
= win
->dwExStyle
;
4799 req
->instance
= wine_server_client_ptr( win
->hInstance
);
4800 req
->is_unicode
= (win
->flags
& WIN_ISUNICODE
) != 0;
4801 req
->extra_offset
= -1;
4802 wine_server_call( req
);
4806 /* Set the window menu */
4808 if ((win
->dwStyle
& (WS_CHILD
| WS_POPUP
)) != WS_CHILD
)
4810 if (cs
.hMenu
&& user_callbacks
&& !user_callbacks
->set_menu( hwnd
, cs
.hMenu
))
4812 release_win_ptr( win
);
4813 free_window_handle( hwnd
);
4817 else NtUserSetWindowLongPtr( hwnd
, GWLP_ID
, (ULONG_PTR
)cs
.hMenu
, FALSE
);
4820 release_win_ptr( win
);
4822 if (parent
) map_dpi_create_struct( &cs
, thread_dpi
, win_dpi
);
4824 context
= set_thread_dpi_awareness_context( get_window_dpi_awareness_context( hwnd
));
4826 /* send the WM_GETMINMAXINFO message and fix the size if needed */
4830 if ((cs
.style
& WS_THICKFRAME
) || !(cs
.style
& (WS_POPUP
| WS_CHILD
)))
4832 MINMAXINFO info
= get_min_max_info( hwnd
);
4833 cx
= max( min( cx
, info
.ptMaxTrackSize
.x
), info
.ptMinTrackSize
.x
);
4834 cy
= max( min( cy
, info
.ptMaxTrackSize
.y
), info
.ptMinTrackSize
.y
);
4839 set_rect( &rect
, cs
.x
, cs
.y
, cs
.x
+ cx
, cs
.y
+ cy
);
4840 /* check for wraparound */
4841 if (cs
.x
> 0x7fffffff - cx
) rect
.right
= 0x7fffffff;
4842 if (cs
.y
> 0x7fffffff - cy
) rect
.bottom
= 0x7fffffff;
4843 if (!apply_window_pos( hwnd
, 0, SWP_NOZORDER
| SWP_NOACTIVATE
, &rect
, &rect
, NULL
)) goto failed
;
4845 /* send WM_NCCREATE */
4847 TRACE( "hwnd %p cs %d,%d %dx%d %s\n", hwnd
, cs
.x
, cs
.y
, cs
.cx
, cs
.cy
, wine_dbgstr_rect(&rect
) );
4849 if (!NtUserMessageCall( hwnd
, WM_NCCREATE
, 0, (LPARAM
)client_cs
, (ULONG_PTR
)&result
,
4850 FNID_SENDMESSAGE
, ansi
) || !result
)
4852 WARN( "%p: aborted by WM_NCCREATE\n", hwnd
);
4856 /* create default IME window */
4858 if (!is_desktop_window( hwnd
) && parent
!= get_hwnd_message_parent() &&
4859 user_callbacks
&& user_callbacks
->register_imm( hwnd
))
4861 TRACE( "register IME window for %p\n", hwnd
);
4862 win_set_flags( hwnd
, WIN_HAS_IME_WIN
, 0 );
4865 /* send WM_NCCALCSIZE */
4867 if (get_window_rects( hwnd
, COORDS_PARENT
, &rect
, NULL
, win_dpi
))
4869 /* yes, even if the CBT hook was called with HWND_TOP */
4870 HWND insert_after
= (get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) ? HWND_BOTTOM
: HWND_TOP
;
4871 RECT client_rect
= rect
;
4873 /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
4874 map_window_points( parent
, 0, (POINT
*)&client_rect
, 2, win_dpi
);
4875 send_message( hwnd
, WM_NCCALCSIZE
, FALSE
, (LPARAM
)&client_rect
);
4876 map_window_points( 0, parent
, (POINT
*)&client_rect
, 2, win_dpi
);
4877 apply_window_pos( hwnd
, insert_after
, SWP_NOACTIVATE
, &rect
, &client_rect
, NULL
);
4881 /* send WM_CREATE */
4882 if (!NtUserMessageCall( hwnd
, WM_CREATE
, 0, (LPARAM
)client_cs
, (ULONG_PTR
)&result
,
4883 FNID_SENDMESSAGE
, ansi
) || result
== -1) goto failed
;
4886 /* call the driver */
4888 if (!user_driver
->pCreateWindow( hwnd
)) goto failed
;
4890 NtUserNotifyWinEvent( EVENT_OBJECT_CREATE
, hwnd
, OBJID_WINDOW
, 0 );
4892 /* send the size messages */
4894 if (!(win_get_flags( hwnd
) & WIN_NEED_SIZE
))
4896 get_window_rects( hwnd
, COORDS_PARENT
, NULL
, &rect
, win_dpi
);
4897 send_message( hwnd
, WM_SIZE
, SIZE_RESTORED
,
4898 MAKELONG(rect
.right
-rect
.left
, rect
.bottom
-rect
.top
));
4899 send_message( hwnd
, WM_MOVE
, 0, MAKELONG( rect
.left
, rect
.top
) );
4902 /* Show the window, maximizing or minimizing if needed */
4904 style
= set_window_style( hwnd
, 0, WS_MAXIMIZE
| WS_MINIMIZE
);
4905 if (style
& (WS_MINIMIZE
| WS_MAXIMIZE
))
4908 UINT sw_flags
= (style
& WS_MINIMIZE
) ? SW_MINIMIZE
: SW_MAXIMIZE
;
4910 sw_flags
= window_min_maximize( hwnd
, sw_flags
, &new_pos
);
4911 sw_flags
|= SWP_FRAMECHANGED
; /* Frame always gets changed */
4912 if (!(style
& WS_VISIBLE
) || (style
& WS_CHILD
) || get_active_window())
4913 sw_flags
|= SWP_NOACTIVATE
;
4914 NtUserSetWindowPos( hwnd
, 0, new_pos
.left
, new_pos
.top
, new_pos
.right
- new_pos
.left
,
4915 new_pos
.bottom
- new_pos
.top
, sw_flags
);
4918 /* Notify the parent window only */
4920 send_parent_notify( hwnd
, WM_CREATE
);
4921 if (!is_window( hwnd
))
4923 set_thread_dpi_awareness_context( context
);
4927 if (parent
== get_desktop_window())
4928 post_message( parent
, WM_PARENTNOTIFY
, WM_CREATE
, (LPARAM
)hwnd
);
4930 if (cs
.style
& WS_VISIBLE
)
4932 if (cs
.style
& WS_MAXIMIZE
)
4934 else if (cs
.style
& WS_MINIMIZE
)
4935 sw
= SW_SHOWMINIMIZED
;
4937 NtUserShowWindow( hwnd
, sw
);
4938 if (cs
.dwExStyle
& WS_EX_MDICHILD
)
4940 send_message( cs
.hwndParent
, WM_MDIREFRESHMENU
, 0, 0 );
4941 /* ShowWindow won't activate child windows */
4942 NtUserSetWindowPos( hwnd
, HWND_TOP
, 0, 0, 0, 0, SWP_SHOWWINDOW
| SWP_NOMOVE
| SWP_NOSIZE
);
4946 /* Call WH_SHELL hook */
4948 if (!(get_window_long( hwnd
, GWL_STYLE
) & WS_CHILD
) && !get_window_relative( hwnd
, GW_OWNER
))
4949 call_hooks( WH_SHELL
, HSHELL_WINDOWCREATED
, (WPARAM
)hwnd
, 0, TRUE
);
4951 TRACE( "created window %p\n", hwnd
);
4952 set_thread_dpi_awareness_context( context
);
4956 destroy_window( hwnd
);
4957 set_thread_dpi_awareness_context( context
);
4961 /*****************************************************************************
4962 * NtUserCallHwnd (win32u.@)
4964 ULONG_PTR WINAPI
NtUserCallHwnd( HWND hwnd
, DWORD code
)
4968 case NtUserArrangeIconicWindows
:
4969 return arrange_iconic_windows( hwnd
);
4970 case NtUserGetDpiForWindow
:
4971 return get_dpi_for_window( hwnd
);
4972 case NtUserGetParent
:
4973 return HandleToUlong( get_parent( hwnd
));
4974 case NtUserGetWindowContextHelpId
:
4975 return get_window_context_help_id( hwnd
);
4976 case NtUserGetWindowDpiAwarenessContext
:
4977 return (ULONG_PTR
)get_window_dpi_awareness_context( hwnd
);
4978 case NtUserGetWindowTextLength
:
4979 return get_server_window_text( hwnd
, NULL
, 0 );
4980 case NtUserIsWindow
:
4981 return is_window( hwnd
);
4982 case NtUserIsWindowUnicode
:
4983 return is_window_unicode( hwnd
);
4984 case NtUserIsWindowVisible
:
4985 return is_window_visible( hwnd
);
4987 FIXME( "invalid code %u\n", code
);
4992 /*****************************************************************************
4993 * NtUserCallHwndParam (win32u.@)
4995 ULONG_PTR WINAPI
NtUserCallHwndParam( HWND hwnd
, DWORD_PTR param
, DWORD code
)
4999 case NtUserGetClassLongA
:
5000 return get_class_long( hwnd
, param
, TRUE
);
5001 case NtUserGetClassLongW
:
5002 return get_class_long( hwnd
, param
, FALSE
);
5003 case NtUserGetClassLongPtrA
:
5004 return get_class_long_ptr( hwnd
, param
, TRUE
);
5005 case NtUserGetClassLongPtrW
:
5006 return get_class_long_ptr( hwnd
, param
, FALSE
);
5007 case NtUserGetClassWord
:
5008 return get_class_word( hwnd
, param
);
5009 case NtUserGetClientRect
:
5010 return get_client_rect( hwnd
, (RECT
*)param
);
5011 case NtUserGetMinMaxInfo
:
5012 *(MINMAXINFO
*)param
= get_min_max_info( hwnd
);
5014 case NtUserGetWindowInfo
:
5015 return get_window_info( hwnd
, (WINDOWINFO
*)param
);
5016 case NtUserGetWindowLongA
:
5017 return get_window_long_size( hwnd
, param
, sizeof(LONG
), TRUE
);
5018 case NtUserGetWindowLongW
:
5019 return get_window_long( hwnd
, param
);
5020 case NtUserGetWindowLongPtrA
:
5021 return get_window_long_ptr( hwnd
, param
, TRUE
);
5022 case NtUserGetWindowLongPtrW
:
5023 return get_window_long_ptr( hwnd
, param
, FALSE
);
5024 case NtUserGetWindowPlacement
:
5025 return get_window_placement( hwnd
, (WINDOWPLACEMENT
*)param
);
5026 case NtUserGetWindowRect
:
5027 return get_window_rect( hwnd
, (RECT
*)param
, get_thread_dpi() );
5028 case NtUserGetWindowRelative
:
5029 return HandleToUlong( get_window_relative( hwnd
, param
));
5030 case NtUserGetWindowThread
:
5031 return get_window_thread( hwnd
, (DWORD
*)param
);
5032 case NtUserGetWindowWord
:
5033 return get_window_word( hwnd
, param
);
5035 return is_child( hwnd
, UlongToHandle(param
) );
5036 case NtUserKillSystemTimer
:
5037 return kill_system_timer( hwnd
, param
);
5038 case NtUserMonitorFromWindow
:
5039 return HandleToUlong( monitor_from_window( hwnd
, param
, NtUserMonitorFromWindow
));
5040 case NtUserScreenToClient
:
5041 return screen_to_client( hwnd
, (POINT
*)param
);
5042 case NtUserSetCaptureWindow
:
5043 return set_capture_window( hwnd
, param
, NULL
);
5044 case NtUserSetForegroundWindow
:
5045 return set_foreground_window( hwnd
, param
);
5046 case NtUserSetWindowPixelFormat
:
5047 return set_window_pixel_format( hwnd
, param
);
5048 /* temporary exports */
5049 case NtUserIsWindowDrawable
:
5050 return is_window_drawable( hwnd
, param
);
5051 case NtUserSetWindowStyle
:
5053 STYLESTRUCT
*style
= (void *)param
;
5054 return set_window_style( hwnd
, style
->styleNew
, style
->styleOld
);
5056 case NtUserSpyGetMsgName
:
5057 return (UINT_PTR
)debugstr_msg_name( param
, hwnd
);
5059 FIXME( "invalid code %u\n", code
);