server: Added support for HWND_TOPMOST and HWND_NOTOPMOST.

This commit is contained in:
Alexandre Julliard 2007-10-31 18:12:56 +01:00
parent b843534357
commit c183a9e6e7
2 changed files with 130 additions and 62 deletions

View file

@ -1371,7 +1371,7 @@ static HWND SWP_DoOwnedPopups(HWND hwnd, HWND hwndInsertAfter)
{
/* make sure this popup stays above the owner */
if( hwndInsertAfter != HWND_TOP )
if (hwndInsertAfter != HWND_TOP && hwndInsertAfter != HWND_TOPMOST)
{
HWND hwndLocalPrev = HWND_TOP;
HWND prev = GetWindow( owner, GW_HWNDPREV );
@ -1509,7 +1509,9 @@ static BOOL fixup_flags( WINDOWPOS *winpos )
if ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD)
{
if (!(winpos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW))) /* Bring to the top when activating */
if (!(winpos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)) && /* Bring to the top when activating */
(winpos->flags & SWP_NOZORDER ||
(winpos->hwndInsertAfter != HWND_TOPMOST && winpos->hwndInsertAfter != HWND_NOTOPMOST)))
{
winpos->flags &= ~SWP_NOZORDER;
winpos->hwndInsertAfter = HWND_TOP;
@ -1523,10 +1525,6 @@ static BOOL fixup_flags( WINDOWPOS *winpos )
if (winpos->hwndInsertAfter == (HWND)0xffff) winpos->hwndInsertAfter = HWND_TOPMOST;
else if (winpos->hwndInsertAfter == (HWND)0xfffe) winpos->hwndInsertAfter = HWND_NOTOPMOST;
/* FIXME: TOPMOST not supported yet */
if ((winpos->hwndInsertAfter == HWND_TOPMOST) ||
(winpos->hwndInsertAfter == HWND_NOTOPMOST)) winpos->hwndInsertAfter = HWND_TOP;
/* hwndInsertAfter must be a sibling of the window */
if (winpos->hwndInsertAfter == HWND_TOP)
{
@ -1535,7 +1533,17 @@ static BOOL fixup_flags( WINDOWPOS *winpos )
}
else if (winpos->hwndInsertAfter == HWND_BOTTOM)
{
if (GetWindow(winpos->hwnd, GW_HWNDLAST) == winpos->hwnd)
if (!(wndPtr->dwExStyle & WS_EX_TOPMOST) && GetWindow(winpos->hwnd, GW_HWNDLAST) == winpos->hwnd)
winpos->flags |= SWP_NOZORDER;
}
else if (winpos->hwndInsertAfter == HWND_TOPMOST)
{
if ((wndPtr->dwExStyle & WS_EX_TOPMOST) && GetWindow(winpos->hwnd, GW_HWNDFIRST) == winpos->hwnd)
winpos->flags |= SWP_NOZORDER;
}
else if (winpos->hwndInsertAfter == HWND_NOTOPMOST)
{
if (!(wndPtr->dwExStyle & WS_EX_TOPMOST))
winpos->flags |= SWP_NOZORDER;
}
else

View file

@ -108,6 +108,12 @@ static struct window *shell_listview;
static struct window *progman_window;
static struct window *taskman_window;
/* magic HWND_TOP etc. pointers */
#define WINPTR_TOP ((struct window *)1L)
#define WINPTR_BOTTOM ((struct window *)2L)
#define WINPTR_TOPMOST ((struct window *)3L)
#define WINPTR_NOTOPMOST ((struct window *)4L)
/* retrieve a pointer to a window from its handle */
static inline struct window *get_window( user_handle_t handle )
{
@ -122,42 +128,6 @@ static inline int is_desktop_window( const struct window *win )
return !win->parent; /* only desktop windows have no parent */
}
/* change the parent of a window (or unlink the window if the new parent is NULL) */
static int set_parent_window( struct window *win, struct window *parent )
{
struct window *ptr;
/* make sure parent is not a child of window */
for (ptr = parent; ptr; ptr = ptr->parent)
{
if (ptr == win)
{
set_error( STATUS_INVALID_PARAMETER );
return 0;
}
}
list_remove( &win->entry ); /* unlink it from the previous location */
if (parent)
{
win->parent = parent;
list_add_head( &parent->children, &win->entry );
win->is_linked = 1;
/* if parent belongs to a different thread and the window isn't */
/* top-level, attach the two threads */
if (parent->thread && parent->thread != win->thread && !is_desktop_window(parent))
attach_thread_input( win->thread, parent->thread );
}
else /* move it to parent unlinked list */
{
list_add_head( &win->parent->unlinked, &win->entry );
win->is_linked = 0;
}
return 1;
}
/* get next window in Z-order list */
static inline struct window *get_next_window( struct window *win )
{
@ -186,6 +156,87 @@ static inline struct window *get_last_child( struct window *win )
return ptr ? LIST_ENTRY( ptr, struct window, entry ) : NULL;
}
/* link a window at the right place in the siblings list */
static void link_window( struct window *win, struct window *previous )
{
if (previous == WINPTR_NOTOPMOST)
{
if (!(win->ex_style & WS_EX_TOPMOST) && win->is_linked) return; /* nothing to do */
win->ex_style &= ~WS_EX_TOPMOST;
previous = WINPTR_TOP; /* fallback to the HWND_TOP case */
}
list_remove( &win->entry ); /* unlink it from the previous location */
if (previous == WINPTR_BOTTOM)
{
list_add_tail( &win->parent->children, &win->entry );
win->ex_style &= ~WS_EX_TOPMOST;
}
else if (previous == WINPTR_TOPMOST)
{
list_add_head( &win->parent->children, &win->entry );
win->ex_style |= WS_EX_TOPMOST;
}
else if (previous == WINPTR_TOP)
{
struct list *entry = win->parent->children.next;
if (!(win->ex_style & WS_EX_TOPMOST)) /* put it above the first non-topmost window */
{
while (entry != &win->parent->children &&
LIST_ENTRY( entry, struct window, entry )->ex_style & WS_EX_TOPMOST)
entry = entry->next;
}
list_add_before( entry, &win->entry );
}
else
{
list_add_after( &previous->entry, &win->entry );
if (!(previous->ex_style & WS_EX_TOPMOST)) win->ex_style &= ~WS_EX_TOPMOST;
else
{
struct window *next = get_next_window( win );
if (next && (next->ex_style & WS_EX_TOPMOST)) win->ex_style |= WS_EX_TOPMOST;
}
}
win->is_linked = 1;
}
/* change the parent of a window (or unlink the window if the new parent is NULL) */
static int set_parent_window( struct window *win, struct window *parent )
{
struct window *ptr;
/* make sure parent is not a child of window */
for (ptr = parent; ptr; ptr = ptr->parent)
{
if (ptr == win)
{
set_error( STATUS_INVALID_PARAMETER );
return 0;
}
}
if (parent)
{
win->parent = parent;
link_window( win, WINPTR_TOP );
/* if parent belongs to a different thread and the window isn't */
/* top-level, attach the two threads */
if (parent->thread && parent->thread != win->thread && !is_desktop_window(parent))
attach_thread_input( win->thread, parent->thread );
}
else /* move it to parent unlinked list */
{
list_remove( &win->entry ); /* unlink it from the previous location */
list_add_head( &win->parent->unlinked, &win->entry );
win->is_linked = 0;
}
return 1;
}
/* append a user handle to a handle array */
static int add_handle_to_array( struct user_handle_array *array, user_handle_t handle )
{
@ -1375,13 +1426,7 @@ static void set_window_pos( struct window *win, struct window *previous,
win->window_rect = *window_rect;
win->visible_rect = *visible_rect;
win->client_rect = *client_rect;
if (!(swp_flags & SWP_NOZORDER) && win->parent)
{
list_remove( &win->entry ); /* unlink it from the previous location */
if (previous) list_add_after( &previous->entry, &win->entry );
else list_add_head( &win->parent->children, &win->entry );
win->is_linked = 1;
}
if (!(swp_flags & SWP_NOZORDER) && win->parent) link_window( win, previous );
if (swp_flags & SWP_SHOWWINDOW) win->style |= WS_VISIBLE;
else if (swp_flags & SWP_HIDEWINDOW) win->style &= ~WS_VISIBLE;
@ -1660,7 +1705,12 @@ DECL_HANDLER(set_window_info)
reply->old_instance = win->instance;
reply->old_user_data = win->user_data;
if (req->flags & SET_WIN_STYLE) win->style = req->style;
if (req->flags & SET_WIN_EXSTYLE) win->ex_style = req->ex_style;
if (req->flags & SET_WIN_EXSTYLE)
{
/* WS_EX_TOPMOST can only be changed for unlinked windows */
if (!win->is_linked) win->ex_style = req->ex_style;
else win->ex_style = (req->ex_style & ~WS_EX_TOPMOST) | (win->ex_style & WS_EX_TOPMOST);
}
if (req->flags & SET_WIN_ID) win->id = req->id;
if (req->flags & SET_WIN_INSTANCE) win->instance = req->instance;
if (req->flags & SET_WIN_UNICODE) win->is_unicode = req->is_unicode;
@ -1794,16 +1844,21 @@ DECL_HANDLER(set_window_pos)
if (!(flags & SWP_NOZORDER))
{
if (!req->previous) /* special case: HWND_TOP */
{
if (get_first_child(win->parent) == win) flags |= SWP_NOZORDER;
}
else if (req->previous == (user_handle_t)1) /* special case: HWND_BOTTOM */
{
previous = get_last_child( win->parent );
}
else
switch ((int)(unsigned long)req->previous)
{
case 0: /* HWND_TOP */
previous = WINPTR_TOP;
break;
case 1: /* HWND_BOTTOM */
previous = WINPTR_BOTTOM;
break;
case -1: /* HWND_TOPMOST */
previous = WINPTR_TOPMOST;
break;
case -2: /* HWND_NOTOPMOST */
previous = WINPTR_NOTOPMOST;
break;
default:
if (!(previous = get_window( req->previous ))) return;
/* previous must be a sibling */
if (previous->parent != win->parent)
@ -1811,6 +1866,7 @@ DECL_HANDLER(set_window_pos)
set_error( STATUS_INVALID_PARAMETER );
return;
}
break;
}
if (previous == win) flags |= SWP_NOZORDER; /* nothing to do */
}
@ -2066,8 +2122,12 @@ DECL_HANDLER(update_window_zorder)
if (!intersect_rect( &tmp, &ptr->visible_rect, &req->rect )) continue;
if (ptr->win_region && !rect_in_region( ptr->win_region, &req->rect )) continue;
/* found a window obscuring the rectangle, now move win above this one */
list_remove( &win->entry );
list_add_before( &ptr->entry, &win->entry );
/* making sure to not violate the topmost rule */
if (!(ptr->ex_style & WS_EX_TOPMOST) || (win->ex_style & WS_EX_TOPMOST))
{
list_remove( &win->entry );
list_add_before( &ptr->entry, &win->entry );
}
break;
}
}