Reimplemented Get/SetActiveWindow, Get/SetFocus and
Get/SetForegroundWindow by storing the information in the
server. Implemented correct inter-process window activation.

diff --git a/dlls/user/Makefile.in b/dlls/user/Makefile.in
index 8ff5b7d..c375c0e 100644
--- a/dlls/user/Makefile.in
+++ b/dlls/user/Makefile.in
@@ -31,7 +31,6 @@
 	$(TOPOBJDIR)/windows/defwnd.c \
 	$(TOPOBJDIR)/windows/dialog.c \
 	$(TOPOBJDIR)/windows/driver.c \
-	$(TOPOBJDIR)/windows/focus.c \
 	$(TOPOBJDIR)/windows/hook.c \
 	$(TOPOBJDIR)/windows/input.c \
 	$(TOPOBJDIR)/windows/keyboard.c \
@@ -63,6 +62,7 @@
 	dde/server.c \
 	display.c \
 	exticon.c \
+	focus.c \
 	lstr.c \
 	message.c \
 	misc.c \
diff --git a/dlls/user/focus.c b/dlls/user/focus.c
new file mode 100644
index 0000000..cceffa5
--- /dev/null
+++ b/dlls/user/focus.c
@@ -0,0 +1,348 @@
+/*
+ * Focus and activation functions
+ *
+ * Copyright 1993 David Metcalfe
+ * Copyright 1995 Alex Korobka
+ * Copyright 1994, 2002 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "winbase.h"
+#include "winuser.h"
+#include "winerror.h"
+#include "win.h"
+#include "hook.h"
+#include "message.h"
+#include "user.h"
+#include "wine/server.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(win);
+
+
+/*****************************************************************
+ *		set_focus_window
+ *
+ * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages
+ */
+static HWND set_focus_window( HWND hwnd )
+{
+    HWND previous = 0;
+    BOOL ret;
+
+    SERVER_START_REQ( set_focus_window )
+    {
+        req->handle = hwnd;
+        if ((ret = !wine_server_call_err( req ))) previous = reply->previous;
+    }
+    SERVER_END_REQ;
+    if (!ret) return 0;
+    if (previous == hwnd) return previous;
+
+    if (previous)
+    {
+        SendMessageW( previous, WM_KILLFOCUS, (WPARAM)hwnd, 0 );
+        if (hwnd != GetFocus()) return previous;  /* changed by the message */
+    }
+    if (IsWindow(hwnd))
+    {
+        if (USER_Driver.pSetFocus) USER_Driver.pSetFocus(hwnd);
+        SendMessageW( hwnd, WM_SETFOCUS, (WPARAM)previous, 0 );
+    }
+    return previous;
+}
+
+
+/*******************************************************************
+ *		set_active_window
+ */
+static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
+{
+    HWND previous = GetActiveWindow();
+    BOOL ret;
+    DWORD old_thread, new_thread;
+
+    if (previous == hwnd)
+    {
+        if (prev) *prev = hwnd;
+        return TRUE;
+    }
+
+    /* call CBT hook chain */
+    if (HOOK_IsHooked( WH_CBT ))
+    {
+        CBTACTIVATESTRUCT cbt;
+        cbt.fMouse     = mouse;
+        cbt.hWndActive = previous;
+        if (HOOK_CallHooksW( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt )) return FALSE;
+    }
+
+    if (IsWindow(previous))
+    {
+        SendMessageW( previous, WM_NCACTIVATE, FALSE, 0 );
+        SendMessageW( previous, WM_ACTIVATE,
+                      MAKEWPARAM( WA_INACTIVE, IsIconic(previous) ), (LPARAM)hwnd );
+    }
+
+    SERVER_START_REQ( set_active_window )
+    {
+        req->handle = hwnd;
+        if ((ret = !wine_server_call_err( req ))) previous = reply->previous;
+    }
+    SERVER_END_REQ;
+    if (!ret) return FALSE;
+    if (prev) *prev = previous;
+    if (previous == hwnd) return TRUE;
+
+    if (hwnd)
+    {
+        /* send palette messages */
+        if (SendMessageW( hwnd, WM_QUERYNEWPALETTE, 0, 0 ))
+            SendMessageW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0 );
+
+        if (!(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_MANAGED))
+            SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
+
+        if (!IsWindow(hwnd)) return FALSE;
+    }
+
+    old_thread = previous ? GetWindowThreadProcessId( previous, NULL ) : 0;
+    new_thread = hwnd ? GetWindowThreadProcessId( hwnd, NULL ) : 0;
+
+    if (old_thread != new_thread)
+    {
+        HWND *list, *phwnd;
+
+        if ((list = WIN_ListChildren( GetDesktopWindow() )))
+        {
+            if (old_thread)
+            {
+                for (phwnd = list; *phwnd; phwnd++)
+                {
+                    if (GetWindowThreadProcessId( *phwnd, NULL ) == old_thread)
+                        SendMessageW( *phwnd, WM_ACTIVATEAPP, 0, new_thread );
+                }
+            }
+            if (new_thread)
+            {
+                for (phwnd = list; *phwnd; phwnd++)
+                {
+                    if (GetWindowThreadProcessId( *phwnd, NULL ) == new_thread)
+                        SendMessageW( *phwnd, WM_ACTIVATEAPP, 1, old_thread );
+                }
+            }
+            HeapFree( GetProcessHeap(), 0, list );
+        }
+    }
+
+    if (IsWindow(hwnd))
+    {
+        SendMessageW( hwnd, WM_NCACTIVATE, (hwnd == GetForegroundWindow()), 0 );
+        SendMessageW( hwnd, WM_ACTIVATE,
+                      MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, IsIconic(hwnd) ),
+                      (LPARAM)previous );
+    }
+
+    /* now change focus if necessary */
+    if (focus)
+    {
+        HWND curfocus = GetFocus();
+        if (!curfocus || !hwnd || GetAncestor( curfocus, GA_ROOT ) != hwnd)
+            set_focus_window( hwnd );
+    }
+
+    return TRUE;
+}
+
+
+/*******************************************************************
+ *		set_foreground_window
+ */
+static BOOL set_foreground_window( HWND hwnd, BOOL mouse )
+{
+    BOOL ret, send_msg_old = FALSE, send_msg_new = FALSE;
+    HWND previous = 0;
+
+    SERVER_START_REQ( set_foreground_window )
+    {
+        req->handle = hwnd;
+        if ((ret = !wine_server_call_err( req )))
+        {
+            previous = reply->previous;
+            send_msg_old = reply->send_msg_old;
+            send_msg_new = reply->send_msg_new;
+        }
+    }
+    SERVER_END_REQ;
+
+    if (ret)
+    {
+        if (send_msg_old)  /* old window belongs to other thread */
+            SendNotifyMessageW( previous, WM_WINE_SETACTIVEWINDOW, 0, 0 );
+        else if (send_msg_new)  /* old window belongs to us but new one to other thread */
+            ret = set_active_window( 0, NULL, mouse, TRUE );
+
+        if (send_msg_new)  /* new window belongs to other thread */
+            SendNotifyMessageW( hwnd, WM_WINE_SETACTIVEWINDOW, hwnd, 0 );
+        else  /* new window belongs to us */
+            ret = set_active_window( hwnd, NULL, mouse, TRUE );
+    }
+    return ret;
+}
+
+
+/*******************************************************************
+ *		FOCUS_MouseActivate
+ *
+ * Activate a window as a result of a mouse click
+ */
+BOOL FOCUS_MouseActivate( HWND hwnd )
+{
+    return set_foreground_window( hwnd, TRUE );
+}
+
+
+/*******************************************************************
+ *		SetActiveWindow (USER32.@)
+ */
+HWND WINAPI SetActiveWindow( HWND hwnd )
+{
+    HWND prev;
+
+    TRACE( "%x\n", hwnd );
+
+    if (hwnd)
+    {
+        LONG style = GetWindowLongW( hwnd, GWL_STYLE );
+
+        if (!(style & WS_VISIBLE) || (style & (WS_POPUP|WS_CHILD)) == WS_CHILD)
+            return GetActiveWindow();  /* Windows doesn't seem to return an error here */
+
+        hwnd = WIN_GetFullHandle( hwnd );
+    }
+
+    if (!set_active_window( hwnd, &prev, FALSE, TRUE )) return 0;
+    return prev;
+}
+
+
+/*****************************************************************
+ *		SetFocus  (USER32.@)
+ */
+HWND WINAPI SetFocus( HWND hwnd )
+{
+    HWND hwndTop = hwnd;
+    HWND previous = GetFocus();
+
+    TRACE( "%x prev %x\n", hwnd, previous );
+
+    if (hwnd)
+    {
+        /* Check if we can set the focus to this window */
+        hwnd = WIN_GetFullHandle( hwnd );
+        if (hwnd == previous) return previous;  /* nothing to do */
+        for (;;)
+        {
+            HWND parent;
+            LONG style = GetWindowLongW( hwndTop, GWL_STYLE );
+            if (style & (WS_MINIMIZE | WS_DISABLED)) return 0;
+            parent = GetAncestor( hwndTop, GA_PARENT );
+            if (!parent || parent == GetDesktopWindow()) break;
+            hwndTop = parent;
+        }
+
+        /* call hooks */
+        if (HOOK_CallHooksW( WH_CBT, HCBT_SETFOCUS, (WPARAM)hwnd, (LPARAM)previous )) return 0;
+
+        /* activate hwndTop if needed. */
+        if (hwndTop != GetActiveWindow())
+        {
+            if (!set_active_window( hwndTop, NULL, FALSE, FALSE )) return 0;
+            if (!IsWindow( hwnd )) return 0;  /* Abort if window destroyed */
+        }
+    }
+    else /* NULL hwnd passed in */
+    {
+        if (!previous) return 0;  /* nothing to do */
+        if( HOOK_CallHooksW( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)previous ) )
+            return 0;
+    }
+
+    /* change focus and send messages */
+    return set_focus_window( hwnd );
+}
+
+
+/*******************************************************************
+ *		SetForegroundWindow  (USER32.@)
+ */
+BOOL WINAPI SetForegroundWindow( HWND hwnd )
+{
+    TRACE( "%x\n", hwnd );
+    if (hwnd) hwnd = WIN_GetFullHandle( hwnd );
+    return set_foreground_window( hwnd, FALSE );
+}
+
+
+/*******************************************************************
+ *		GetActiveWindow  (USER32.@)
+ */
+HWND WINAPI GetActiveWindow(void)
+{
+    HWND ret = 0;
+
+    SERVER_START_REQ( get_thread_input )
+    {
+        req->tid = GetCurrentThreadId();
+        if (!wine_server_call_err( req )) ret = reply->active;
+    }
+    SERVER_END_REQ;
+    return ret;
+}
+
+
+/*****************************************************************
+ *		GetFocus  (USER32.@)
+ */
+HWND WINAPI GetFocus(void)
+{
+    HWND ret = 0;
+
+    SERVER_START_REQ( get_thread_input )
+    {
+        req->tid = GetCurrentThreadId();
+        if (!wine_server_call_err( req )) ret = reply->focus;
+    }
+    SERVER_END_REQ;
+    return ret;
+}
+
+
+/*******************************************************************
+ *		GetForegroundWindow  (USER32.@)
+ */
+HWND WINAPI GetForegroundWindow(void)
+{
+    HWND ret = 0;
+
+    SERVER_START_REQ( get_thread_input )
+    {
+        req->tid = 0;
+        if (!wine_server_call_err( req )) ret = reply->foreground;
+    }
+    SERVER_END_REQ;
+    return ret;
+}
diff --git a/dlls/user/message.c b/dlls/user/message.c
index 8621241..1b43326 100644
--- a/dlls/user/message.c
+++ b/dlls/user/message.c
@@ -1060,6 +1060,8 @@
         return (LRESULT)SetWindowLongW( hwnd, wparam, lparam );
     case WM_WINE_ENABLEWINDOW:
         return EnableWindow( hwnd, wparam );
+    case WM_WINE_SETACTIVEWINDOW:
+        return SetActiveWindow( (HWND)wparam );
     default:
         FIXME( "unknown internal message %x\n", msg );
         return 0;
diff --git a/dlls/x11drv/event.c b/dlls/x11drv/event.c
index 10b40ad..4f5993e 100644
--- a/dlls/x11drv/event.c
+++ b/dlls/x11drv/event.c
@@ -364,6 +364,20 @@
 }
 
 
+/*******************************************************************
+ *         can_activate_window
+ *
+ * Check if we can activate the specified window.
+ */
+inline static BOOL can_activate_window( HWND hwnd )
+{
+    LONG style = GetWindowLongW( hwnd, GWL_STYLE );
+    if (!(style & WS_VISIBLE)) return FALSE;
+    if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
+    return !(style & WS_DISABLED);
+}
+
+
 /**********************************************************************
  *              set_focus_error_handler
  *
@@ -380,16 +394,12 @@
  */
 static void set_focus( HWND hwnd, Time time )
 {
-    HWND focus = GetFocus();
+    HWND focus;
     Window win;
 
-    if (hwnd != focus && !IsChild( hwnd, focus ))
-    {
-        TRACE( "changing window focus to %x\n", hwnd );
-        SetFocus( hwnd );
-    }
+    TRACE( "setting foreground window to %x\n", hwnd );
+    SetForegroundWindow( hwnd );
 
-    /* focus window might be changed by the above SetFocus() call */
     focus = GetFocus();
     win = X11DRV_get_whole_window(focus);
 
@@ -430,7 +440,7 @@
                hwnd, IsWindowEnabled(hwnd), GetFocus(), GetActiveWindow(),
                GetForegroundWindow(), last_focus );
 
-        if (IsWindowEnabled(hwnd))
+        if (can_activate_window(hwnd))
         {
             /* simulate a mouse click on the caption to find out
              * whether the window wants to be activated */
@@ -445,7 +455,7 @@
             hwnd = GetFocus();
             if (!hwnd) hwnd = GetActiveWindow();
             if (!hwnd) hwnd = last_focus;
-            if (hwnd && IsWindowEnabled(hwnd)) set_focus( hwnd, event_time );
+            if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
         }
     }
 }
@@ -475,17 +485,14 @@
     if (wmTakeFocus) return;  /* ignore FocusIn if we are using take focus */
     if (event->detail == NotifyPointer) return;
 
-    if (!IsWindowEnabled(hwnd))
+    if (!can_activate_window(hwnd))
     {
         HWND hwnd = GetFocus();
         if (!hwnd) hwnd = GetActiveWindow();
         if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
-        if (hwnd && IsWindowEnabled(hwnd)) set_focus( hwnd, CurrentTime );
+        if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
     }
-    else if (hwnd != GetForegroundWindow())
-    {
-        SetForegroundWindow( hwnd );
-    }
+    else SetForegroundWindow( hwnd );
 }
 
 
@@ -503,6 +510,7 @@
     TRACE( "win %x xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
 
     if (event->detail == NotifyPointer) return;
+    x11drv_thread_data()->last_focus = hwnd;
     if (hwnd != GetForegroundWindow()) return;
     SendMessageA( hwnd, WM_CANCELMODE, 0, 0 );
 
@@ -527,7 +535,6 @@
         if (hwnd == GetForegroundWindow())
         {
             TRACE( "lost focus, setting fg to 0\n" );
-            x11drv_thread_data()->last_focus = hwnd;
             SetForegroundWindow( 0 );
         }
     }
diff --git a/dlls/x11drv/winpos.c b/dlls/x11drv/winpos.c
index b279f40..6f0f977 100644
--- a/dlls/x11drv/winpos.c
+++ b/dlls/x11drv/winpos.c
@@ -1025,7 +1025,7 @@
         if ((GetWindowLongW( winpos->hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD)
             SendMessageA( winpos->hwnd, WM_CHILDACTIVATE, 0, 0 );
         else
-            SetActiveWindow( winpos->hwnd );
+            SetForegroundWindow( winpos->hwnd );
     }
 
       /* And last, send the WM_WINDOWPOSCHANGED message */
diff --git a/include/user.h b/include/user.h
index 13fbbd7..69f75cf 100644
--- a/include/user.h
+++ b/include/user.h
@@ -57,7 +57,8 @@
     WM_WINE_SHOWWINDOW,
     WM_WINE_SETPARENT,
     WM_WINE_SETWINDOWLONG,
-    WM_WINE_ENABLEWINDOW
+    WM_WINE_ENABLEWINDOW,
+    WM_WINE_SETACTIVEWINDOW
 };
 
 /* internal SendInput codes (FIXME) */
diff --git a/include/win.h b/include/win.h
index 7c69f62..c83e9e1 100644
--- a/include/win.h
+++ b/include/win.h
@@ -143,6 +143,8 @@
 
 extern HBRUSH DEFWND_ControlColor( HDC hDC, UINT ctlType );  /* windows/defwnd.c */
 
+extern BOOL FOCUS_MouseActivate( HWND hwnd );
+
 /* Classes functions */
 struct tagCLASS;  /* opaque structure */
 struct builtin_class_descr;
@@ -153,7 +155,4 @@
 extern void CLASS_RemoveWindow( struct tagCLASS *cls );
 extern void CLASS_FreeModuleClasses( HMODULE16 hModule );
 
-/* windows/focus.c */
-extern void FOCUS_SwitchFocus( struct tagMESSAGEQUEUE *pMsgQ, HWND , HWND );
-
 #endif  /* __WINE_WIN_H */
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 01b6e19..7e0457d 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -2507,6 +2507,7 @@
 {
     struct reply_header __header;
     user_handle_t  full_handle;
+    user_handle_t  last_active;
     process_id_t   pid;
     thread_id_t    tid;
     atom_t         atom;
@@ -2763,6 +2764,44 @@
 };
 
 
+struct set_foreground_window_request
+{
+    struct request_header __header;
+    user_handle_t  handle;
+};
+struct set_foreground_window_reply
+{
+    struct reply_header __header;
+    user_handle_t  previous;
+    int            send_msg_old;
+    int            send_msg_new;
+};
+
+
+struct set_focus_window_request
+{
+    struct request_header __header;
+    user_handle_t  handle;
+};
+struct set_focus_window_reply
+{
+    struct reply_header __header;
+    user_handle_t  previous;
+};
+
+
+struct set_active_window_request
+{
+    struct request_header __header;
+    user_handle_t  handle;
+};
+struct set_active_window_reply
+{
+    struct reply_header __header;
+    user_handle_t  previous;
+};
+
+
 enum request
 {
     REQ_new_process,
@@ -2923,6 +2962,9 @@
     REQ_get_window_properties,
     REQ_attach_thread_input,
     REQ_get_thread_input,
+    REQ_set_foreground_window,
+    REQ_set_focus_window,
+    REQ_set_active_window,
     REQ_NB_REQUESTS
 };
 
@@ -3088,6 +3130,9 @@
     struct get_window_properties_request get_window_properties_request;
     struct attach_thread_input_request attach_thread_input_request;
     struct get_thread_input_request get_thread_input_request;
+    struct set_foreground_window_request set_foreground_window_request;
+    struct set_focus_window_request set_focus_window_request;
+    struct set_active_window_request set_active_window_request;
 };
 union generic_reply
 {
@@ -3251,8 +3296,11 @@
     struct get_window_properties_reply get_window_properties_reply;
     struct attach_thread_input_reply attach_thread_input_reply;
     struct get_thread_input_reply get_thread_input_reply;
+    struct set_foreground_window_reply set_foreground_window_reply;
+    struct set_focus_window_reply set_focus_window_reply;
+    struct set_active_window_reply set_active_window_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 85
+#define SERVER_PROTOCOL_VERSION 86
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/include/winpos.h b/include/winpos.h
index 3b05228..f972b55 100644
--- a/include/winpos.h
+++ b/include/winpos.h
@@ -39,8 +39,6 @@
 extern BOOL WINPOS_ShowIconTitle( HWND hwnd, BOOL bShow );
 extern void WINPOS_GetMinMaxInfo( HWND hwnd, POINT *maxSize, POINT *maxPos, POINT *minTrack,
                                   POINT *maxTrack );
-extern BOOL WINPOS_SetActiveWindow( HWND hWnd, BOOL fMouse,
-                                      BOOL fChangeFocus );
 extern LONG WINPOS_HandleWindowPosChanging16(HWND hwnd, struct tagWINDOWPOS16 *winpos);
 extern LONG WINPOS_HandleWindowPosChanging(HWND hwnd, WINDOWPOS *winpos);
 extern HWND WINPOS_WindowFromPoint( HWND hwndScope, POINT pt, INT *hittest );
diff --git a/server/protocol.def b/server/protocol.def
index 43f4fa0..6e72e97 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1762,6 +1762,7 @@
     user_handle_t  handle;      /* handle to the window */
 @REPLY
     user_handle_t  full_handle; /* full 32-bit handle */
+    user_handle_t  last_active; /* last active popup */
     process_id_t   pid;         /* process owning the window */
     thread_id_t    tid;         /* thread owning the window */
     atom_t         atom;        /* class atom */
@@ -1931,3 +1932,26 @@
     user_handle_t  caret;         /* handle to the caret window */
     rectangle_t    rect;          /* caret rectangle */
 @END
+
+/* Set the system foreground window */
+@REQ(set_foreground_window)
+    user_handle_t  handle;        /* handle to the foreground window */
+@REPLY
+    user_handle_t  previous;      /* handle to the previous foreground window */
+    int            send_msg_old;  /* whether we have to send a msg to the old window */
+    int            send_msg_new;  /* whether we have to send a msg to the new window */
+@END
+
+/* Set the current thread focus window */
+@REQ(set_focus_window)
+    user_handle_t  handle;        /* handle to the focus window */
+@REPLY
+    user_handle_t  previous;      /* handle to the previous focus window */
+@END
+
+/* Set the current thread active window */
+@REQ(set_active_window)
+    user_handle_t  handle;        /* handle to the active window */
+@REPLY
+    user_handle_t  previous;      /* handle to the previous active window */
+@END
diff --git a/server/queue.c b/server/queue.c
index 5a08668..5d51e62 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -621,6 +621,25 @@
     if (window == input->caret) input->caret = 0;
 }
 
+/* check if the specified window can be set in the input data of a given queue */
+static int check_queue_input_window( struct msg_queue *queue, user_handle_t window )
+{
+    struct thread *thread;
+    int ret = 0;
+
+    if (!window) return 1;  /* we can always clear the data */
+
+    if ((thread = get_window_thread( window )))
+    {
+        ret = (queue->input == thread->queue->input);
+        if (!ret) set_error( STATUS_ACCESS_DENIED );
+        release_object( thread );
+    }
+    else set_error( STATUS_INVALID_HANDLE );
+
+    return ret;
+}
+
 /* attach two thread input data structures */
 int attach_thread_input( struct thread *thread_from, struct thread *thread_to )
 {
@@ -1292,3 +1311,61 @@
     reply->foreground = foreground_input ? foreground_input->active : 0;
     if (thread) release_object( thread );
 }
+
+
+/* set the system foreground window */
+DECL_HANDLER(set_foreground_window)
+{
+    struct msg_queue *queue = get_current_queue();
+
+    reply->previous = foreground_input ? foreground_input->active : 0;
+    reply->send_msg_old = (reply->previous && foreground_input != queue->input);
+    reply->send_msg_new = FALSE;
+
+    if (req->handle)
+    {
+        struct thread *thread;
+
+        if (is_top_level_window( req->handle ) &&
+            ((thread = get_window_thread( req->handle ))))
+        {
+            foreground_input = thread->queue->input;
+            reply->send_msg_new = (foreground_input != queue->input);
+            release_object( thread );
+        }
+        else set_error( STATUS_INVALID_HANDLE );
+    }
+    else foreground_input = NULL;
+}
+
+
+/* set the current thread focus window */
+DECL_HANDLER(set_focus_window)
+{
+    struct msg_queue *queue = get_current_queue();
+
+    reply->previous = 0;
+    if (queue && check_queue_input_window( queue, req->handle ))
+    {
+        reply->previous = queue->input->focus;
+        queue->input->focus = get_user_full_handle( req->handle );
+    }
+}
+
+
+/* set the current thread active window */
+DECL_HANDLER(set_active_window)
+{
+    struct msg_queue *queue = get_current_queue();
+
+    reply->previous = 0;
+    if (queue && check_queue_input_window( queue, req->handle ))
+    {
+        if (!req->handle || make_window_active( req->handle ))
+        {
+            reply->previous = queue->input->active;
+            queue->input->active = get_user_full_handle( req->handle );
+        }
+        else set_error( STATUS_INVALID_HANDLE );
+    }
+}
diff --git a/server/request.h b/server/request.h
index 3f1a036..a6076d7 100644
--- a/server/request.h
+++ b/server/request.h
@@ -261,6 +261,9 @@
 DECL_HANDLER(get_window_properties);
 DECL_HANDLER(attach_thread_input);
 DECL_HANDLER(get_thread_input);
+DECL_HANDLER(set_foreground_window);
+DECL_HANDLER(set_focus_window);
+DECL_HANDLER(set_active_window);
 
 #ifdef WANT_REQUEST_HANDLERS
 
@@ -425,6 +428,9 @@
     (req_handler)req_get_window_properties,
     (req_handler)req_attach_thread_input,
     (req_handler)req_get_thread_input,
+    (req_handler)req_set_foreground_window,
+    (req_handler)req_set_focus_window,
+    (req_handler)req_set_active_window,
 };
 #endif  /* WANT_REQUEST_HANDLERS */
 
diff --git a/server/trace.c b/server/trace.c
index 776370f..e680e58 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2005,6 +2005,7 @@
 static void dump_get_window_info_reply( const struct get_window_info_reply *req )
 {
     fprintf( stderr, " full_handle=%08x,", req->full_handle );
+    fprintf( stderr, " last_active=%08x,", req->last_active );
     fprintf( stderr, " pid=%08x,", req->pid );
     fprintf( stderr, " tid=%08x,", req->tid );
     fprintf( stderr, " atom=%04x", req->atom );
@@ -2200,6 +2201,38 @@
     dump_rectangle( &req->rect );
 }
 
+static void dump_set_foreground_window_request( const struct set_foreground_window_request *req )
+{
+    fprintf( stderr, " handle=%08x", req->handle );
+}
+
+static void dump_set_foreground_window_reply( const struct set_foreground_window_reply *req )
+{
+    fprintf( stderr, " previous=%08x,", req->previous );
+    fprintf( stderr, " send_msg_old=%d,", req->send_msg_old );
+    fprintf( stderr, " send_msg_new=%d", req->send_msg_new );
+}
+
+static void dump_set_focus_window_request( const struct set_focus_window_request *req )
+{
+    fprintf( stderr, " handle=%08x", req->handle );
+}
+
+static void dump_set_focus_window_reply( const struct set_focus_window_reply *req )
+{
+    fprintf( stderr, " previous=%08x", req->previous );
+}
+
+static void dump_set_active_window_request( const struct set_active_window_request *req )
+{
+    fprintf( stderr, " handle=%08x", req->handle );
+}
+
+static void dump_set_active_window_reply( const struct set_active_window_reply *req )
+{
+    fprintf( stderr, " previous=%08x", req->previous );
+}
+
 static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_new_process_request,
     (dump_func)dump_get_new_process_info_request,
@@ -2359,6 +2392,9 @@
     (dump_func)dump_get_window_properties_request,
     (dump_func)dump_attach_thread_input_request,
     (dump_func)dump_get_thread_input_request,
+    (dump_func)dump_set_foreground_window_request,
+    (dump_func)dump_set_focus_window_request,
+    (dump_func)dump_set_active_window_request,
 };
 
 static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -2520,6 +2556,9 @@
     (dump_func)dump_get_window_properties_reply,
     (dump_func)0,
     (dump_func)dump_get_thread_input_reply,
+    (dump_func)dump_set_foreground_window_reply,
+    (dump_func)dump_set_focus_window_reply,
+    (dump_func)dump_set_active_window_reply,
 };
 
 static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -2681,6 +2720,9 @@
     "get_window_properties",
     "attach_thread_input",
     "get_thread_input",
+    "set_foreground_window",
+    "set_focus_window",
+    "set_active_window",
 };
 
 /* ### make_requests end ### */
diff --git a/server/user.h b/server/user.h
index b1cc439..c153d78 100644
--- a/server/user.h
+++ b/server/user.h
@@ -54,6 +54,8 @@
 
 extern void destroy_thread_windows( struct thread *thread );
 extern int is_child_window( user_handle_t parent, user_handle_t child );
+extern int is_top_level_window( user_handle_t window );
+extern int make_window_active( user_handle_t window );
 extern struct thread *get_window_thread( user_handle_t handle );
 extern user_handle_t find_window_to_repaint( user_handle_t parent, struct thread *thread );
 
diff --git a/server/window.c b/server/window.c
index ad51288..4631707 100644
--- a/server/window.c
+++ b/server/window.c
@@ -62,6 +62,7 @@
     user_handle_t    handle;          /* full handle for this window */
     struct thread   *thread;          /* thread owning the window */
     atom_t           atom;            /* class atom */
+    user_handle_t    last_active;     /* last active popup */
     rectangle_t      window_rect;     /* window rectangle */
     rectangle_t      client_rect;     /* client rectangle */
     unsigned int     style;           /* window style */
@@ -268,6 +269,7 @@
     win->first_unlinked = NULL;
     win->thread         = current;
     win->atom           = atom;
+    win->last_active    = win->handle;
     win->style          = 0;
     win->ex_style       = 0;
     win->id             = 0;
@@ -321,6 +323,27 @@
     return 0;
 }
 
+/* check whether window is a top-level window */
+int is_top_level_window( user_handle_t window )
+{
+    struct window *win = get_user_object( window, USER_WINDOW );
+    return (win && win->parent == top_window);
+}
+
+/* make a window active if possible */
+int make_window_active( user_handle_t window )
+{
+    struct window *owner, *win = get_window( window );
+
+    if (!win) return 0;
+
+    /* set last active for window and its owner */
+    win->last_active = win->handle;
+    if ((owner = get_user_object( win->owner, USER_WINDOW ))) owner->last_active = win->handle;
+    return 1;
+}
+
+
 /* return the thread owning a window */
 struct thread *get_window_thread( user_handle_t handle )
 {
@@ -478,6 +501,8 @@
     if (win)
     {
         reply->full_handle = win->handle;
+        reply->last_active = win->handle;
+        if (get_user_object( win->last_active, USER_WINDOW )) reply->last_active = win->last_active;
         if (win->thread)
         {
             reply->tid  = get_thread_id( win->thread );
diff --git a/windows/focus.c b/windows/focus.c
deleted file mode 100644
index 61898da..0000000
--- a/windows/focus.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Focus functions
- *
- * Copyright 1993 David Metcalfe
- *           1994 Alexandre Julliard
- * 	     1995 Alex Korobka
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include "windef.h"
-#include "wingdi.h"
-#include "wine/winuser16.h"
-#include "win.h"
-#include "winpos.h"
-#include "hook.h"
-#include "message.h"
-#include "queue.h"
-#include "user.h"
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(win);
-
-
-/*****************************************************************
- *	         FOCUS_SwitchFocus
- * pMsgQ is the queue whose perQData focus is to be modified
- */
-void FOCUS_SwitchFocus( MESSAGEQUEUE *pMsgQ, HWND hFocusFrom, HWND hFocusTo )
-{
-    PERQDATA_SetFocusWnd( pMsgQ->pQData, hFocusTo );
-
-    if (hFocusFrom)
-        SendNotifyMessageA( hFocusFrom, WM_KILLFOCUS, (WPARAM)hFocusTo, 0 );
-
-    if( !hFocusTo || hFocusTo != PERQDATA_GetFocusWnd( pMsgQ->pQData ) )
-    {
-        return;
-    }
-
-    /* According to API docs, the WM_SETFOCUS message is sent AFTER the window
-       has received the keyboard focus. */
-    if (USER_Driver.pSetFocus) USER_Driver.pSetFocus(hFocusTo);
-
-    SendMessageA( hFocusTo, WM_SETFOCUS, (WPARAM)hFocusFrom, 0 );
-}
-
-
-/*****************************************************************
- *		SetFocus (USER32.@)
- */
-HWND WINAPI SetFocus( HWND hwnd )
-{
-    HWND hWndFocus = 0, hwndTop = hwnd;
-    MESSAGEQUEUE *pMsgQ = 0, *pCurMsgQ = 0;
-    BOOL bRet = 0;
-
-    /* Get the messageQ for the current thread */
-    if (!(pCurMsgQ = QUEUE_Current()))
-    {
-        WARN("\tCurrent message queue not found. Exiting!\n" );
-        return 0;
-    }
-
-    if (hwnd)
-    {
-        /* Check if we can set the focus to this window */
-        WND *wndPtr;
-
-        hwnd = WIN_GetFullHandle( hwnd );
-        for (;;)
-        {
-            HWND parent;
-            LONG style = GetWindowLongW( hwndTop, GWL_STYLE );
-            if (style & (WS_MINIMIZE | WS_DISABLED)) return 0;
-            parent = GetAncestor( hwndTop, GA_PARENT );
-            if (!parent || parent == GetDesktopWindow()) break;
-            hwndTop = parent;
-        }
-
-        if (!(wndPtr = WIN_FindWndPtr( hwndTop ))) return 0;
-
-        /* Retrieve the message queue associated with this window */
-        pMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( wndPtr->hmemTaskQ );
-        WIN_ReleaseWndPtr( wndPtr );
-        if ( !pMsgQ )
-        {
-            WARN("\tMessage queue not found. Exiting!\n" );
-            return 0;
-        }
-
-        /* Make sure that message queue for the window we are setting focus to
-         * shares the same perQ data as the current threads message queue.
-         * In other words you can't set focus to a window owned by a different
-         * thread unless AttachThreadInput has been called previously.
-         * (see AttachThreadInput and SetFocus docs)
-         */
-        if ( pCurMsgQ->pQData != pMsgQ->pQData )
-            goto CLEANUP;
-
-        /* Get the current focus window from the perQ data */
-        hWndFocus = PERQDATA_GetFocusWnd( pMsgQ->pQData );
-
-        if( hwnd == hWndFocus )
-        {
-	    bRet = 1;      /* Success */
-	    goto CLEANUP;  /* Nothing to do */
-        }
-
-	/* call hooks */
-	if( HOOK_CallHooksA( WH_CBT, HCBT_SETFOCUS, (WPARAM)hwnd, (LPARAM)hWndFocus) )
-	    goto CLEANUP;
-
-        /* activate hwndTop if needed. */
-	if (hwndTop != GetActiveWindow())
-	{
-	    if (!WINPOS_SetActiveWindow(hwndTop, 0, 0)) goto CLEANUP;
-
-	    if (!IsWindow( hwnd )) goto CLEANUP;  /* Abort if window destroyed */
-	}
-
-        /* Get the current focus window from the perQ data */
-        hWndFocus = PERQDATA_GetFocusWnd( pMsgQ->pQData );
-
-        /* Change focus and send messages */
-        FOCUS_SwitchFocus( pMsgQ, hWndFocus, hwnd );
-    }
-    else /* NULL hwnd passed in */
-    {
-        if( HOOK_CallHooksA( WH_CBT, HCBT_SETFOCUS, 0, (LPARAM)hWndFocus ) )
-            return 0;
-
-        /* Get the current focus from the perQ data of the current message Q */
-        hWndFocus = PERQDATA_GetFocusWnd( pCurMsgQ->pQData );
-
-      /* Change focus and send messages */
-        FOCUS_SwitchFocus( pCurMsgQ, hWndFocus, hwnd );
-    }
-
-    bRet = 1;      /* Success */
-
-CLEANUP:
-
-    /* Unlock the queues before returning */
-    if ( pMsgQ )
-        QUEUE_Unlock( pMsgQ );
-
-    return bRet ? hWndFocus : 0;
-}
-
-
-/*****************************************************************
- *		GetFocus (USER32.@)
- */
-HWND WINAPI GetFocus(void)
-{
-    MESSAGEQUEUE *pCurMsgQ = 0;
-
-    /* Get the messageQ for the current thread */
-    if (!(pCurMsgQ = QUEUE_Current()))
-    {
-        WARN("\tCurrent message queue not found. Exiting!\n" );
-        return 0;
-    }
-
-    /* Get the current focus from the perQ data of the current message Q */
-    return PERQDATA_GetFocusWnd( pCurMsgQ->pQData );
-}
diff --git a/windows/message.c b/windows/message.c
index 5951bff..f789f26 100644
--- a/windows/message.c
+++ b/windows/message.c
@@ -512,8 +512,6 @@
         (raw_message == WM_RBUTTONDOWN) ||
         (raw_message == WM_MBUTTONDOWN))
     {
-        HWND hwndTop = GetAncestor( msg->hwnd, GA_ROOT );
-
         /* Send the WM_PARENTNOTIFY,
          * note that even for double/nonclient clicks
          * notification message is still WM_L/M/RBUTTONDOWN.
@@ -522,32 +520,37 @@
 
         /* Activate the window if needed */
 
-        if (msg->hwnd != GetActiveWindow() && hwndTop != GetDesktopWindow())
+        if (msg->hwnd != GetActiveWindow())
         {
-            LONG ret = SendMessageA( msg->hwnd, WM_MOUSEACTIVATE, (WPARAM)hwndTop,
-                                     MAKELONG( hittest, raw_message ) );
-
-            switch(ret)
+            HWND hwndTop = msg->hwnd;
+            while (hwndTop)
             {
-            case MA_NOACTIVATEANDEAT:
-                eatMsg = TRUE;
-                /* fall through */
-            case MA_NOACTIVATE:
-                break;
-            case MA_ACTIVATEANDEAT:
-                eatMsg = TRUE;
-                /* fall through */
-            case MA_ACTIVATE:
-            case 0:
-                if (hwndTop != GetForegroundWindow() )
+                if ((GetWindowLongW( hwndTop, GWL_STYLE ) & (WS_POPUP|WS_CHILD)) != WS_CHILD) break;
+                hwndTop = GetParent( hwndTop );
+            }
+
+            if (hwndTop && hwndTop != GetDesktopWindow())
+            {
+                LONG ret = SendMessageA( msg->hwnd, WM_MOUSEACTIVATE, (WPARAM)hwndTop,
+                                         MAKELONG( hittest, raw_message ) );
+                switch(ret)
                 {
-                    if (!WINPOS_SetActiveWindow( hwndTop, TRUE , TRUE ))
-                        eatMsg = TRUE;
+                case MA_NOACTIVATEANDEAT:
+                    eatMsg = TRUE;
+                    /* fall through */
+                case MA_NOACTIVATE:
+                    break;
+                case MA_ACTIVATEANDEAT:
+                    eatMsg = TRUE;
+                    /* fall through */
+                case MA_ACTIVATE:
+                case 0:
+                    if (!FOCUS_MouseActivate( hwndTop )) eatMsg = TRUE;
+                    break;
+                default:
+                    WARN( "unknown WM_MOUSEACTIVATE code %ld\n", ret );
+                    break;
                 }
-                break;
-            default:
-                WARN( "unknown WM_MOUSEACTIVATE code %ld\n", ret );
-                break;
             }
         }
     }
diff --git a/windows/nonclient.c b/windows/nonclient.c
index dbf1270..180547b 100644
--- a/windows/nonclient.c
+++ b/windows/nonclient.c
@@ -1999,7 +1999,7 @@
         {
             HWND top = GetAncestor( hwnd, GA_ROOT );
 
-            if( WINPOS_SetActiveWindow(top, TRUE, TRUE) || (GetActiveWindow() == top) )
+            if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
                 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
             break;
         }
diff --git a/windows/win.c b/windows/win.c
index 782d29e..516f644 100644
--- a/windows/win.c
+++ b/windows/win.c
@@ -1479,7 +1479,10 @@
 
       /* Hide the window */
 
-    ShowWindow( hwnd, SW_HIDE );
+    if (!ShowWindow( hwnd, SW_HIDE ))
+    {
+        if (hwnd == GetActiveWindow()) WINPOS_ActivateOtherWindow( hwnd );
+    }
     if (!IsWindow(hwnd)) return TRUE;
 
       /* Recursively destroy owned windows */
@@ -1510,8 +1513,6 @@
             if (!got_one) break;
         }
 
-        WINPOS_ActivateOtherWindow( hwnd );
-
         if ((owner = GetWindow( hwnd, GW_OWNER )))
         {
             WND *ptr = WIN_FindWndPtr( owner );
@@ -3109,7 +3110,7 @@
     {
         WPARAM16 wparam;
         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
-        else wparam = (hWnd == GetActiveWindow());
+        else wparam = (hWnd == GetForegroundWindow());
 
         WIN_ReleaseWndPtr(wndPtr);
         SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
diff --git a/windows/winpos.c b/windows/winpos.c
index f27fdea..cc26357 100644
--- a/windows/winpos.c
+++ b/windows/winpos.c
@@ -69,14 +69,12 @@
 
 /* ----- internal variables ----- */
 
-static HWND hwndPrevActive  = 0;  /* Previously active window */
 static HWND hGlobalShellWindow=0; /*the shell*/
 static HWND hGlobalTaskmanWindow=0;
 static HWND hGlobalProgmanWindow=0;
 
 static LPCSTR atomInternalPos;
 
-extern HQUEUE16 hActiveQueue;
 
 /***********************************************************************
  *           WINPOS_CreateInternalPosAtom
@@ -95,30 +93,7 @@
  */
 void WINPOS_CheckInternalPos( HWND hwnd )
 {
-    LPINTERNALPOS lpPos;
-    MESSAGEQUEUE *pMsgQ = 0;
-    WND *wndPtr = WIN_GetPtr( hwnd );
-
-    if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return;
-
-    lpPos = (LPINTERNALPOS) GetPropA( hwnd, atomInternalPos );
-
-    /* Retrieve the message queue associated with this window */
-    pMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( wndPtr->hmemTaskQ );
-    if ( !pMsgQ )
-    {
-        WARN("\tMessage queue not found. Exiting!\n" );
-        WIN_ReleasePtr( wndPtr );
-        return;
-    }
-
-    if( hwnd == hwndPrevActive ) hwndPrevActive = 0;
-
-    if( hwnd == PERQDATA_GetActiveWnd( pMsgQ->pQData ) )
-    {
-        PERQDATA_SetActiveWnd( pMsgQ->pQData, 0 );
-	WARN("\tattempt to activate destroyed window!\n");
-    }
+    LPINTERNALPOS lpPos = (LPINTERNALPOS) GetPropA( hwnd, atomInternalPos );
 
     if( lpPos )
     {
@@ -126,9 +101,6 @@
 	    DestroyWindow( lpPos->hwndIconTitle );
 	HeapFree( GetProcessHeap(), 0, lpPos );
     }
-
-    QUEUE_Unlock( pMsgQ );
-    WIN_ReleasePtr( wndPtr );
 }
 
 /***********************************************************************
@@ -641,132 +613,6 @@
 
 
 /*******************************************************************
- *		GetActiveWindow (USER32.@)
- */
-HWND WINAPI GetActiveWindow(void)
-{
-    MESSAGEQUEUE *pCurMsgQ = 0;
-
-    /* Get the messageQ for the current thread */
-    if (!(pCurMsgQ = QUEUE_Current()))
-{
-        WARN("\tCurrent message queue not found. Exiting!\n" );
-        return 0;
-    }
-
-    /* Return the current active window from the perQ data of the current message Q */
-    return PERQDATA_GetActiveWnd( pCurMsgQ->pQData );
-}
-
-
-/*******************************************************************
- *         WINPOS_CanActivate
- */
-static BOOL WINPOS_CanActivate(HWND hwnd)
-{
-    if (!hwnd) return FALSE;
-    return ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_DISABLED|WS_CHILD)) == 0);
-}
-
-/*******************************************************************
- *         WINPOS_IsVisible
- */
-static BOOL WINPOS_IsVisible(HWND hwnd)
-{
-    if (!hwnd) return FALSE;
-    return ((GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE) == WS_VISIBLE);
-}
-
-
-/*******************************************************************
- *		SetActiveWindow (USER32.@)
- */
-HWND WINAPI SetActiveWindow( HWND hwnd )
-{
-    HWND prev = 0;
-    WND *wndPtr = WIN_FindWndPtr( hwnd );
-    MESSAGEQUEUE *pMsgQ = 0, *pCurMsgQ = 0;
-
-    if (!wndPtr) return 0;
-
-    if (wndPtr->dwStyle & (WS_DISABLED | WS_CHILD)) goto error;
-
-    /* Get the messageQ for the current thread */
-    if (!(pCurMsgQ = QUEUE_Current()))
-    {
-        WARN("\tCurrent message queue not found. Exiting!\n" );
-        goto error;
-    }
-
-    /* Retrieve the message queue associated with this window */
-    pMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( wndPtr->hmemTaskQ );
-    if ( !pMsgQ )
-    {
-        WARN("\tWindow message queue not found. Exiting!\n" );
-        goto error;
-    }
-
-    /* Make sure that the window is associated with the calling threads
-     * message queue. It must share the same perQ data.
-     */
-    if ( pCurMsgQ->pQData != pMsgQ->pQData )
-    {
-        QUEUE_Unlock( pMsgQ );
-        goto error;
-    }
-
-    /* Save current active window */
-    prev = PERQDATA_GetActiveWnd( pMsgQ->pQData );
-    QUEUE_Unlock( pMsgQ );
-    WIN_ReleaseWndPtr(wndPtr);
-    WINPOS_SetActiveWindow( hwnd, FALSE, TRUE );
-    return prev;
-
- error:
-    WIN_ReleaseWndPtr(wndPtr);
-    return 0;
-}
-
-
-/*******************************************************************
- *		GetForegroundWindow (USER32.@)
- */
-HWND WINAPI GetForegroundWindow(void)
-{
-    HWND hwndActive = 0;
-
-    /* Get the foreground window (active window of hActiveQueue) */
-    if ( hActiveQueue )
-    {
-        MESSAGEQUEUE *pActiveQueue = QUEUE_Lock( hActiveQueue );
-        if ( pActiveQueue )
-            hwndActive = PERQDATA_GetActiveWnd( pActiveQueue->pQData );
-
-        QUEUE_Unlock( pActiveQueue );
-    }
-
-    return hwndActive;
-}
-
-/*******************************************************************
- *		SetForegroundWindow (USER32.@)
- */
-BOOL WINAPI SetForegroundWindow( HWND hwnd )
-{
-    if (!hwnd) return WINPOS_SetActiveWindow( 0, FALSE, TRUE );
-
-    /* child windows get WM_CHILDACTIVATE message */
-    if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD)
-        return SendMessageA( hwnd, WM_CHILDACTIVATE, 0, 0 );
-
-    hwnd = WIN_GetFullHandle( hwnd );
-    if( hwnd == GetForegroundWindow() ) return FALSE;
-
-    return WINPOS_SetActiveWindow( hwnd, FALSE, TRUE );
-}
-
-
-/*******************************************************************
  *		AllowSetForegroundWindow (USER32.@)
  */
 BOOL WINAPI AllowSetForegroundWindow( DWORD procid )
@@ -1191,221 +1037,24 @@
     }
 }
 
+
 /*******************************************************************
- *	   WINPOS_SetActiveWindow
+ *         can_activate_window
  *
- * SetActiveWindow() back-end. This is the only function that
- * can assign active status to a window. It must be called only
- * for the top level windows.
+ * Check if we can activate the specified window.
  */
-BOOL WINPOS_SetActiveWindow( HWND hWnd, BOOL fMouse, BOOL fChangeFocus)
+static BOOL can_activate_window( HWND hwnd )
 {
-    WND*     wndPtr=0, *wndTemp;
-    HQUEUE16 hOldActiveQueue, hNewActiveQueue;
-    MESSAGEQUEUE *pOldActiveQueue = 0, *pNewActiveQueue = 0;
-    WORD     wIconized = 0;
-    HWND     hwndActive = 0;
-    BOOL     bRet = 0;
+    LONG style;
 
-    TRACE("(%04x, %d, %d)\n", hWnd, fMouse, fChangeFocus );
-
-    /* Get current active window from the active queue */
-    if ( hActiveQueue )
-    {
-        pOldActiveQueue = QUEUE_Lock( hActiveQueue );
-        if ( pOldActiveQueue )
-            hwndActive = PERQDATA_GetActiveWnd( pOldActiveQueue->pQData );
-    }
-
-    if ((wndPtr = WIN_FindWndPtr(hWnd)))
-        hWnd = wndPtr->hwndSelf;  /* make it a full handle */
-
-    /* paranoid checks */
-    if( hWnd == GetDesktopWindow() || (bRet = (hWnd == hwndActive)) )
-	goto CLEANUP_END;
-
-/*  if (wndPtr && (GetFastQueue16() != wndPtr->hmemTaskQ))
- *	return 0;
- */
-    hOldActiveQueue = hActiveQueue;
-
-    if( (wndTemp = WIN_FindWndPtr(hwndActive)) )
-    {
-	wIconized = HIWORD(wndTemp->dwStyle & WS_MINIMIZE);
-        WIN_ReleaseWndPtr(wndTemp);
-    }
-    else
-	TRACE("no current active window.\n");
-
-    /* call CBT hook chain */
-    if (HOOK_IsHooked( WH_CBT ))
-    {
-        CBTACTIVATESTRUCT cbt;
-        cbt.fMouse     = fMouse;
-        cbt.hWndActive = hwndActive;
-        if (HOOK_CallHooksA( WH_CBT, HCBT_ACTIVATE, (WPARAM)hWnd, (LPARAM)&cbt )) goto CLEANUP_END;
-    }
-
-    /* set prev active wnd to current active wnd and send notification */
-    if ((hwndPrevActive = hwndActive) && IsWindow(hwndPrevActive))
-    {
-        MESSAGEQUEUE *pTempActiveQueue = 0;
-
-        SendNotifyMessageA( hwndPrevActive, WM_NCACTIVATE, FALSE, 0 );
-        SendNotifyMessageA( hwndPrevActive, WM_ACTIVATE,
-                        MAKEWPARAM( WA_INACTIVE, wIconized ),
-                        (LPARAM)hWnd );
-
-        /* check if something happened during message processing
-         * (global active queue may have changed)
-         */
-        pTempActiveQueue = QUEUE_Lock( hActiveQueue );
-	if(!pTempActiveQueue)
-	    goto CLEANUP_END;
-
-        hwndActive = PERQDATA_GetActiveWnd( pTempActiveQueue->pQData );
-        QUEUE_Unlock( pTempActiveQueue );
-        if( hwndPrevActive != hwndActive )
-            goto CLEANUP_END;
-    }
-
-    /* Set new active window in the message queue */
-    hwndActive = hWnd;
-    if ( wndPtr )
-    {
-        pNewActiveQueue = QUEUE_Lock( wndPtr->hmemTaskQ );
-        if ( pNewActiveQueue )
-            PERQDATA_SetActiveWnd( pNewActiveQueue->pQData, hwndActive );
-    }
-    else /* have to do this or MDI frame activation goes to hell */
-	if( pOldActiveQueue )
-	    PERQDATA_SetActiveWnd( pOldActiveQueue->pQData, 0 );
-
-    /* send palette messages */
-    if (hWnd && SendMessageW( hWnd, WM_QUERYNEWPALETTE, 0, 0L))
-        SendMessageW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hWnd, 0 );
-
-    /* if prev wnd is minimized redraw icon title */
-    if( IsIconic( hwndPrevActive ) ) WINPOS_RedrawIconTitle(hwndPrevActive);
-
-    /* managed windows will get ConfigureNotify event */
-    if (wndPtr && !(wndPtr->dwStyle & WS_CHILD) && !(wndPtr->dwExStyle & WS_EX_MANAGED))
-    {
-	/* check Z-order and bring hWnd to the top */
-        HWND tmp = GetTopWindow(0);
-        while (tmp && !(GetWindowLongA( tmp, GWL_STYLE ) & WS_VISIBLE))
-            tmp = GetWindow( tmp, GW_HWNDNEXT );
-
-        if( tmp != hWnd )
-	    SetWindowPos(hWnd, HWND_TOP, 0,0,0,0,
-			   SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
-        if (!IsWindow(hWnd))
-	    goto CLEANUP;
-    }
-
-    /* Get a handle to the new active queue */
-    hNewActiveQueue = wndPtr ? wndPtr->hmemTaskQ : 0;
-
-    /* send WM_ACTIVATEAPP if necessary */
-    if (hOldActiveQueue != hNewActiveQueue)
-    {
-        HWND *list, *phwnd;
-        DWORD old_thread = GetWindowThreadProcessId( hwndPrevActive, NULL );
-        DWORD new_thread = GetWindowThreadProcessId( hwndActive, NULL );
-
-        if ((list = WIN_ListChildren( GetDesktopWindow() )))
-        {
-            for (phwnd = list; *phwnd; phwnd++)
-            {
-                if (!IsWindow( *phwnd )) continue;
-                if (GetWindowThreadProcessId( *phwnd, NULL ) == old_thread)
-                    SendNotifyMessageW( *phwnd, WM_ACTIVATEAPP, 0, new_thread );
-            }
-            HeapFree( GetProcessHeap(), 0, list );
-        }
-
-	hActiveQueue = hNewActiveQueue;
-
-        if ((list = WIN_ListChildren( GetDesktopWindow() )))
-        {
-            for (phwnd = list; *phwnd; phwnd++)
-            {
-                if (!IsWindow( *phwnd )) continue;
-                if (GetWindowThreadProcessId( *phwnd, NULL ) == new_thread)
-                    SendMessageW( *phwnd, WM_ACTIVATEAPP, 1, old_thread );
-            }
-            HeapFree( GetProcessHeap(), 0, list );
-        }
-
-	if (hWnd && !IsWindow(hWnd)) goto CLEANUP;
-    }
-
-    if (hWnd)
-    {
-        /* walk up to the first unowned window */
-        HWND tmp = GetAncestor( hWnd, GA_ROOTOWNER );
-        if ((wndTemp = WIN_FindWndPtr( tmp )))
-        {
-            /* and set last active owned popup */
-            wndTemp->hwndLastActive = hWnd;
-
-            wIconized = HIWORD(wndTemp->dwStyle & WS_MINIMIZE);
-            WIN_ReleaseWndPtr(wndTemp);
-        }
-        SendMessageA( hWnd, WM_NCACTIVATE, TRUE, 0 );
-        SendMessageA( hWnd, WM_ACTIVATE,
-		 MAKEWPARAM( (fMouse) ? WA_CLICKACTIVE : WA_ACTIVE, wIconized),
-		 (LPARAM)hwndPrevActive );
-        if( !IsWindow(hWnd) ) goto CLEANUP;
-    }
-
-    /* change focus if possible */
-    if ( fChangeFocus )
-    {
-        if ( pNewActiveQueue )
-        {
-            HWND hOldFocus = PERQDATA_GetFocusWnd( pNewActiveQueue->pQData );
-
-            if ( !hOldFocus || GetAncestor( hOldFocus, GA_ROOT ) != hwndActive )
-                FOCUS_SwitchFocus( pNewActiveQueue, hOldFocus,
-                                   (wndPtr && (wndPtr->dwStyle & WS_MINIMIZE))?
-                                   0 : hwndActive );
-        }
-
-        if ( pOldActiveQueue &&
-             ( !pNewActiveQueue ||
-                pNewActiveQueue->pQData != pOldActiveQueue->pQData ) )
-        {
-            HWND hOldFocus = PERQDATA_GetFocusWnd( pOldActiveQueue->pQData );
-            if ( hOldFocus )
-                FOCUS_SwitchFocus( pOldActiveQueue, hOldFocus, 0 );
-        }
-    }
-
-    if( !hwndPrevActive && wndPtr )
-    {
-        if (USER_Driver.pForceWindowRaise) USER_Driver.pForceWindowRaise( wndPtr->hwndSelf );
-    }
-
-    /* if active wnd is minimized redraw icon title */
-    if( IsIconic(hwndActive) ) WINPOS_RedrawIconTitle(hwndActive);
-
-    bRet = (hWnd == hwndActive);  /* Success? */
-
-CLEANUP: /* Unlock the message queues before returning */
-
-    if ( pNewActiveQueue )
-        QUEUE_Unlock( pNewActiveQueue );
-
-CLEANUP_END:
-
-    if ( pOldActiveQueue )
-        QUEUE_Unlock( pOldActiveQueue );
-
-    WIN_ReleaseWndPtr(wndPtr);
-    return bRet;
+    if (!hwnd) return FALSE;
+    style = GetWindowLongW( hwnd, GWL_STYLE );
+    if (!(style & WS_VISIBLE)) return FALSE;
+    if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
+    return !(style & WS_DISABLED);
 }
 
+
 /*******************************************************************
  *         WINPOS_ActivateOtherWindow
  *
@@ -1413,54 +1062,29 @@
  */
 void WINPOS_ActivateOtherWindow(HWND hwnd)
 {
-    HWND hwndActive = 0;
-    HWND hwndTo = 0;
-    HWND hwndDefaultTo = 0;
-    HWND owner;
+    HWND hwndTo, fg;
 
-    /* Get current active window from the active queue */
-    if ( hActiveQueue )
+    if ((GetWindowLongW( hwnd, GWL_STYLE ) & WS_POPUP) && (hwndTo = GetWindow( hwnd, GW_OWNER )))
     {
-        MESSAGEQUEUE *pActiveQueue = QUEUE_Lock( hActiveQueue );
-        if ( pActiveQueue )
-        {
-            hwndActive = PERQDATA_GetActiveWnd( pActiveQueue->pQData );
-            QUEUE_Unlock( pActiveQueue );
-        }
+        hwndTo = GetAncestor( hwndTo, GA_ROOT );
+        if (can_activate_window( hwndTo )) goto done;
     }
 
-    if (!(hwnd = WIN_IsCurrentThread( hwnd ))) return;
-
-    if( hwnd == hwndPrevActive )
-        hwndPrevActive = 0;
-
-    if( hwndActive != hwnd && (hwndActive || USER_IsExitingThread( GetCurrentThreadId() )))
-        return;
-
-    if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_POPUP) ||
-        !(owner = GetWindow( hwnd, GW_OWNER )) ||
-        !WINPOS_CanActivate((hwndTo = GetAncestor( owner, GA_ROOT ))) ||
-        !WINPOS_IsVisible(hwndTo))
+    hwndTo = hwnd;
+    for (;;)
     {
-        HWND tmp = GetAncestor( hwnd, GA_ROOT );
-        hwndTo = hwndPrevActive;
-
-        while( !WINPOS_CanActivate(hwndTo) || !WINPOS_IsVisible(hwndTo))
-        {
-            /* by now owned windows should've been taken care of */
-            if(!hwndDefaultTo && WINPOS_CanActivate(hwndTo))
-            	hwndDefaultTo = hwndTo;
-            tmp = hwndTo = GetWindow( tmp, GW_HWNDNEXT );
-            if( !hwndTo )
-            {
-            	hwndTo = hwndDefaultTo;
-            	break;
-            }
-        }
+        if (!(hwndTo = GetWindow( hwndTo, GW_HWNDNEXT ))) break;
+        if (can_activate_window( hwndTo )) break;
     }
 
-    SetActiveWindow( hwndTo );
-    hwndPrevActive = 0;
+ done:
+    fg = GetForegroundWindow();
+    TRACE("win = %x fg = %x\n", hwndTo, fg);
+    if (!fg || (hwnd == fg))
+    {
+        if (SetForegroundWindow( hwndTo )) return;
+    }
+    if (!SetActiveWindow( hwndTo )) SetActiveWindow(0);
 }