Rewrote caret implementation to store the information in the server.

diff --git a/dlls/user/Makefile.in b/dlls/user/Makefile.in
index c375c0e..3fe07d9 100644
--- a/dlls/user/Makefile.in
+++ b/dlls/user/Makefile.in
@@ -22,7 +22,6 @@
 	$(TOPOBJDIR)/controls/scroll.c \
 	$(TOPOBJDIR)/controls/static.c \
 	$(TOPOBJDIR)/controls/uitools.c \
-	$(TOPOBJDIR)/windows/caret.c \
 	$(TOPOBJDIR)/windows/class.c \
 	$(TOPOBJDIR)/windows/clipboard.c \
 	$(TOPOBJDIR)/windows/cursoricon.c \
@@ -55,6 +54,7 @@
 	$(TOPOBJDIR)/windows/winpos.c \
 	$(TOPOBJDIR)/windows/winproc.c \
 	cache.c \
+	caret.c \
 	comm16.c \
 	dde/client.c \
 	dde/ddeml16.c \
diff --git a/dlls/user/caret.c b/dlls/user/caret.c
new file mode 100644
index 0000000..bcfa36c
--- /dev/null
+++ b/dlls/user/caret.c
@@ -0,0 +1,408 @@
+/*
+ * Caret functions
+ *
+ * Copyright 1993 David Metcalfe
+ * Copyright 1996 Frans van Dorsselaer
+ * Copyright 2001 Eric Pouech
+ * Copyright 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 "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "wine/server.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(caret);
+
+typedef struct
+{
+    HBITMAP  hBmp;
+    UINT     timeout;
+} CARET;
+
+static CARET Caret = { 0, 500 };
+
+#define TIMERID 0xffff  /* system timer id for the caret */
+
+
+/*****************************************************************
+ *               CARET_DisplayCaret
+ */
+static void CARET_DisplayCaret( HWND hwnd, const RECT *r )
+{
+    HDC hdc;
+    HDC hCompDC;
+
+    /* do not use DCX_CACHE here, for x,y,width,height are in logical units */
+    if (!(hdc = GetDCEx( hwnd, 0, DCX_USESTYLE /*| DCX_CACHE*/ ))) return;
+    hCompDC = CreateCompatibleDC(hdc);
+    if (hCompDC)
+    {
+	HBITMAP	hPrevBmp;
+
+	hPrevBmp = SelectObject(hCompDC, Caret.hBmp);
+	BitBlt(hdc, r->left, r->top, r->right-r->left, r->bottom-r->top, hCompDC, 0, 0, SRCINVERT);
+	SelectObject(hCompDC, hPrevBmp);
+	DeleteDC(hCompDC);
+    }
+    ReleaseDC( hwnd, hdc );
+}
+
+
+/*****************************************************************
+ *               CARET_Callback
+ */
+static void CALLBACK CARET_Callback( HWND hwnd, UINT msg, UINT id, DWORD ctime)
+{
+    BOOL ret;
+    RECT r;
+    int old_state = 0;
+    int hidden = 0;
+
+    SERVER_START_REQ( set_caret_info )
+    {
+        req->flags  = SET_CARET_STATE;
+        req->handle = hwnd;
+        req->x      = 0;
+        req->y      = 0;
+        req->hide   = 0;
+        req->state  = -1;  /* toggle current state */
+        if ((ret = !wine_server_call( req )))
+        {
+            hwnd      = reply->full_handle;
+            r.left    = reply->old_rect.left;
+            r.top     = reply->old_rect.top;
+            r.right   = reply->old_rect.right;
+            r.bottom  = reply->old_rect.bottom;
+            old_state = reply->old_state;
+            hidden    = reply->old_hide;
+        }
+    }
+    SERVER_END_REQ;
+
+    if (ret && !hidden) CARET_DisplayCaret( hwnd, &r );
+}
+
+
+/*****************************************************************
+ *		CreateCaret (USER32.@)
+ */
+BOOL WINAPI CreateCaret( HWND hwnd, HBITMAP bitmap, INT width, INT height )
+{
+    BOOL ret;
+    RECT r;
+    int old_state = 0;
+    int hidden = 0;
+    HBITMAP hBmp = 0;
+    HWND prev = 0;
+
+    TRACE("hwnd=%04x\n", hwnd);
+
+    if (!hwnd) return FALSE;
+
+    if (bitmap && (bitmap != 1))
+    {
+        BITMAP bmp;
+        if (!GetObjectA( bitmap, sizeof(bmp), &bmp )) return FALSE;
+        width = bmp.bmWidth;
+        height = bmp.bmHeight;
+	bmp.bmBits = NULL;
+	hBmp = CreateBitmapIndirect(&bmp);
+	if (hBmp)
+	{
+	    /* copy the bitmap */
+	    LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, bmp.bmWidthBytes * bmp.bmHeight);
+	    GetBitmapBits(bitmap, bmp.bmWidthBytes * bmp.bmHeight, buf);
+	    SetBitmapBits(hBmp, bmp.bmWidthBytes * bmp.bmHeight, buf);
+	    HeapFree(GetProcessHeap(), 0, buf);
+	}
+    }
+    else
+    {
+	HDC hdc;
+
+        if (!width) width = GetSystemMetrics(SM_CXBORDER);
+        if (!height) height = GetSystemMetrics(SM_CYBORDER);
+
+	/* create the uniform bitmap on the fly */
+	hdc = GetDC(hwnd);
+	if (hdc)
+	{
+	    HDC hMemDC = CreateCompatibleDC(hdc);
+	    if (hMemDC)
+	    {
+		if ((hBmp = CreateCompatibleBitmap(hMemDC, width, height )))
+		{
+		    HBITMAP hPrevBmp = SelectObject(hMemDC, hBmp);
+                    SetRect( &r, 0, 0, width, height );
+		    FillRect(hMemDC, &r, (bitmap ? COLOR_GRAYTEXT : COLOR_WINDOW) + 1);
+		    SelectObject(hMemDC, hPrevBmp);
+		}
+		DeleteDC(hMemDC);
+	    }
+	    ReleaseDC(hwnd, hdc);
+	}
+    }
+    if (!hBmp) return FALSE;
+
+    SERVER_START_REQ( set_caret_window )
+    {
+        req->handle = hwnd;
+        req->width  = width;
+        req->height = height;
+        if ((ret = !wine_server_call_err( req )))
+        {
+            prev      = reply->previous;
+            r.left    = reply->old_rect.left;
+            r.top     = reply->old_rect.top;
+            r.right   = reply->old_rect.right;
+            r.bottom  = reply->old_rect.bottom;
+            old_state = reply->old_state;
+            hidden    = reply->old_hide;
+        }
+    }
+    SERVER_END_REQ;
+    if (!ret) return FALSE;
+
+    if (prev && !hidden)  /* hide the previous one */
+    {
+        /* FIXME: won't work if prev belongs to a different process */
+        KillSystemTimer( prev, TIMERID );
+        if (old_state) CARET_DisplayCaret( prev, &r );
+    }
+
+    if (Caret.hBmp) DeleteObject( Caret.hBmp );
+    Caret.hBmp = hBmp;
+    Caret.timeout = GetProfileIntA( "windows", "CursorBlinkRate", 500 );
+    return TRUE;
+}
+
+
+/*****************************************************************
+ *		DestroyCaret (USER32.@)
+ */
+BOOL WINAPI DestroyCaret(void)
+{
+    BOOL ret;
+    HWND prev = 0;
+    RECT r;
+    int old_state = 0;
+    int hidden = 0;
+
+    SERVER_START_REQ( set_caret_window )
+    {
+        req->handle = 0;
+        req->width  = 0;
+        req->height = 0;
+        if ((ret = !wine_server_call_err( req )))
+        {
+            prev      = reply->previous;
+            r.left    = reply->old_rect.left;
+            r.top     = reply->old_rect.top;
+            r.right   = reply->old_rect.right;
+            r.bottom  = reply->old_rect.bottom;
+            old_state = reply->old_state;
+            hidden    = reply->old_hide;
+        }
+    }
+    SERVER_END_REQ;
+
+    if (ret && prev && !hidden)
+    {
+        /* FIXME: won't work if prev belongs to a different process */
+        KillSystemTimer( prev, TIMERID );
+        if (old_state) CARET_DisplayCaret( prev, &r );
+    }
+    if (Caret.hBmp) DeleteObject( Caret.hBmp );
+    Caret.hBmp = 0;
+    return ret;
+}
+
+
+/*****************************************************************
+ *		SetCaretPos (USER32.@)
+ */
+BOOL WINAPI SetCaretPos( INT x, INT y )
+{
+    BOOL ret;
+    HWND hwnd = 0;
+    RECT r;
+    int old_state = 0;
+    int hidden = 0;
+
+    SERVER_START_REQ( set_caret_info )
+    {
+        req->flags  = SET_CARET_POS|SET_CARET_STATE;
+        req->handle = 0;
+        req->x      = x;
+        req->y      = y;
+        req->hide   = 0;
+        req->state  = 1;
+        if ((ret = !wine_server_call_err( req )))
+        {
+            hwnd      = reply->full_handle;
+            r.left    = reply->old_rect.left;
+            r.top     = reply->old_rect.top;
+            r.right   = reply->old_rect.right;
+            r.bottom  = reply->old_rect.bottom;
+            old_state = reply->old_state;
+            hidden    = reply->old_hide;
+        }
+    }
+    SERVER_END_REQ;
+    if (ret && !hidden)
+    {
+        if (old_state) CARET_DisplayCaret( hwnd, &r );
+        r.right += x - r.left;
+        r.bottom += y - r.top;
+        r.left = x;
+        r.top = y;
+        CARET_DisplayCaret( hwnd, &r );
+        SetSystemTimer( hwnd, TIMERID, Caret.timeout, CARET_Callback );
+    }
+    return ret;
+}
+
+
+/*****************************************************************
+ *		HideCaret (USER32.@)
+ */
+BOOL WINAPI HideCaret( HWND hwnd )
+{
+    BOOL ret;
+    RECT r;
+    int old_state = 0;
+    int hidden = 0;
+
+    SERVER_START_REQ( set_caret_info )
+    {
+        req->flags  = SET_CARET_HIDE|SET_CARET_STATE;
+        req->handle = hwnd;
+        req->x      = 0;
+        req->y      = 0;
+        req->hide   = 1;
+        req->state  = 0;
+        if ((ret = !wine_server_call_err( req )))
+        {
+            hwnd      = reply->full_handle;
+            r.left    = reply->old_rect.left;
+            r.top     = reply->old_rect.top;
+            r.right   = reply->old_rect.right;
+            r.bottom  = reply->old_rect.bottom;
+            old_state = reply->old_state;
+            hidden    = reply->old_hide;
+        }
+    }
+    SERVER_END_REQ;
+
+    if (ret && !hidden)
+    {
+        if (old_state) CARET_DisplayCaret( hwnd, &r );
+        KillSystemTimer( hwnd, TIMERID );
+    }
+    return ret;
+}
+
+
+/*****************************************************************
+ *		ShowCaret (USER32.@)
+ */
+BOOL WINAPI ShowCaret( HWND hwnd )
+{
+    BOOL ret;
+    RECT r;
+    int old_state = 0;
+    int hidden = 0;
+
+    SERVER_START_REQ( set_caret_info )
+    {
+        req->flags  = SET_CARET_HIDE|SET_CARET_STATE;
+        req->handle = hwnd;
+        req->x      = 0;
+        req->y      = 0;
+        req->hide   = -1;
+        req->state  = 1;
+        if ((ret = !wine_server_call_err( req )))
+        {
+            hwnd      = reply->full_handle;
+            r.left    = reply->old_rect.left;
+            r.top     = reply->old_rect.top;
+            r.right   = reply->old_rect.right;
+            r.bottom  = reply->old_rect.bottom;
+            old_state = reply->old_state;
+            hidden    = reply->old_hide;
+        }
+    }
+    SERVER_END_REQ;
+
+    if (ret && (hidden == 1))  /* hidden was 1 so it's now 0 */
+    {
+        CARET_DisplayCaret( hwnd, &r );
+        SetSystemTimer( hwnd, TIMERID, Caret.timeout, CARET_Callback );
+    }
+    return ret;
+}
+
+
+/*****************************************************************
+ *		GetCaretPos (USER32.@)
+ */
+BOOL WINAPI GetCaretPos( LPPOINT pt )
+{
+    BOOL ret;
+
+    SERVER_START_REQ( set_caret_info )
+    {
+        req->flags  = 0;  /* don't set anything */
+        req->handle = 0;
+        req->x      = 0;
+        req->y      = 0;
+        req->hide   = 0;
+        req->state  = 0;
+        if ((ret = !wine_server_call_err( req )))
+        {
+            pt->x = reply->old_rect.left;
+            pt->y = reply->old_rect.top;
+        }
+    }
+    SERVER_END_REQ;
+    return ret;
+}
+
+
+/*****************************************************************
+ *		SetCaretBlinkTime (USER32.@)
+ */
+BOOL WINAPI SetCaretBlinkTime( UINT msecs )
+{
+    TRACE("msecs=%d\n", msecs);
+
+    Caret.timeout = msecs;
+/*    if (Caret.hwnd) CARET_SetTimer(); FIXME */
+    return TRUE;
+}
+
+
+/*****************************************************************
+ *		GetCaretBlinkTime (USER32.@)
+ */
+UINT WINAPI GetCaretBlinkTime(void)
+{
+    return Caret.timeout;
+}
diff --git a/dlls/user/user32.spec b/dlls/user/user32.spec
index e7cfc38..70e53a7 100644
--- a/dlls/user/user32.spec
+++ b/dlls/user/user32.spec
@@ -682,7 +682,6 @@
 ################################################################
 # Wine dll separation hacks, these will go away, don't use them
 #
-@ cdecl CARET_GetHwnd() CARET_GetHwnd
 @ cdecl CLIPBOARD_DeleteRecord(ptr long) CLIPBOARD_DeleteRecord
 @ cdecl CLIPBOARD_EmptyCache(long) CLIPBOARD_EmptyCache
 @ cdecl CLIPBOARD_GetFormatName(long ptr long) CLIPBOARD_GetFormatName
diff --git a/dlls/user/wnd16.c b/dlls/user/wnd16.c
index ed9de7d..9d2c6a6 100644
--- a/dlls/user/wnd16.c
+++ b/dlls/user/wnd16.c
@@ -879,6 +879,24 @@
 }
 
 
+/*****************************************************************
+ *		DestroyCaret (USER.164)
+ */
+void WINAPI DestroyCaret16(void)
+{
+    DestroyCaret();
+}
+
+
+/*****************************************************************
+ *		SetCaretPos (USER.165)
+ */
+void WINAPI SetCaretPos16( INT16 x, INT16 y )
+{
+    SetCaretPos( x, y );
+}
+
+
 /**************************************************************************
  *              HideCaret   (USER.166)
  */
@@ -897,6 +915,24 @@
 }
 
 
+/*****************************************************************
+ *		SetCaretBlinkTime (USER.168)
+ */
+void WINAPI SetCaretBlinkTime16( UINT16 msecs )
+{
+    SetCaretBlinkTime( msecs );
+}
+
+
+/*****************************************************************
+ *		GetCaretBlinkTime (USER.169)
+ */
+UINT16 WINAPI GetCaretBlinkTime16(void)
+{
+    return GetCaretBlinkTime();
+}
+
+
 /**************************************************************************
  *              ArrangeIconicWindows   (USER.170)
  */
@@ -924,6 +960,20 @@
 }
 
 
+/*****************************************************************
+ *		GetCaretPos (USER.183)
+ */
+void WINAPI GetCaretPos16( LPPOINT16 pt16 )
+{
+    POINT pt;
+    if (GetCaretPos( &pt ))
+    {
+        pt16->x = pt.x;
+        pt16->y = pt.y;
+    }
+}
+
+
 /**************************************************************************
  *              SetSysModalWindow   (USER.188)
  */
diff --git a/dlls/x11drv/winpos.c b/dlls/x11drv/winpos.c
index 7edeec3..17f1189 100644
--- a/dlls/x11drv/winpos.c
+++ b/dlls/x11drv/winpos.c
@@ -1012,13 +1012,10 @@
 
     if (wvrFlags & WVR_REDRAW) RedrawWindow( winpos->hwnd, NULL, 0, RDW_INVALIDATE | RDW_ERASE );
 
-    if (winpos->hwnd == CARET_GetHwnd())
-    {
-        if( winpos->flags & SWP_HIDEWINDOW )
-            HideCaret(winpos->hwnd);
-        else if (winpos->flags & SWP_SHOWWINDOW)
-            ShowCaret(winpos->hwnd);
-    }
+    if( winpos->flags & SWP_HIDEWINDOW )
+        HideCaret(winpos->hwnd);
+    else if (winpos->flags & SWP_SHOWWINDOW)
+        ShowCaret(winpos->hwnd);
 
     if (!(winpos->flags & SWP_NOACTIVATE))
     {
diff --git a/include/win.h b/include/win.h
index 7f73559..c682be7 100644
--- a/include/win.h
+++ b/include/win.h
@@ -137,9 +137,6 @@
 
 #define WND_OTHER_PROCESS ((WND *)1)  /* returned by WIN_GetPtr on unknown window handles */
 
-extern HWND CARET_GetHwnd(void);
-extern void CARET_GetRect(LPRECT lprc);  /* windows/caret.c */
-
 extern HBRUSH DEFWND_ControlColor( HDC hDC, UINT ctlType );  /* windows/defwnd.c */
 
 extern BOOL FOCUS_MouseActivate( HWND hwnd );
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 95e538c..23b2bc8 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -2818,6 +2818,48 @@
 #define CAPTURE_MOVESIZE 0x02
 
 
+
+struct set_caret_window_request
+{
+    struct request_header __header;
+    user_handle_t  handle;
+    int            width;
+    int            height;
+};
+struct set_caret_window_reply
+{
+    struct reply_header __header;
+    user_handle_t  previous;
+    rectangle_t    old_rect;
+    int            old_hide;
+    int            old_state;
+};
+
+
+
+struct set_caret_info_request
+{
+    struct request_header __header;
+    unsigned int   flags;
+    user_handle_t  handle;
+    int            x;
+    int            y;
+    int            hide;
+    int            state;
+};
+struct set_caret_info_reply
+{
+    struct reply_header __header;
+    user_handle_t  full_handle;
+    rectangle_t    old_rect;
+    int            old_hide;
+    int            old_state;
+};
+#define SET_CARET_POS        0x01
+#define SET_CARET_HIDE       0x02
+#define SET_CARET_STATE      0x04
+
+
 enum request
 {
     REQ_new_process,
@@ -2982,6 +3024,8 @@
     REQ_set_focus_window,
     REQ_set_active_window,
     REQ_set_capture_window,
+    REQ_set_caret_window,
+    REQ_set_caret_info,
     REQ_NB_REQUESTS
 };
 
@@ -3151,6 +3195,8 @@
     struct set_focus_window_request set_focus_window_request;
     struct set_active_window_request set_active_window_request;
     struct set_capture_window_request set_capture_window_request;
+    struct set_caret_window_request set_caret_window_request;
+    struct set_caret_info_request set_caret_info_request;
 };
 union generic_reply
 {
@@ -3318,8 +3364,10 @@
     struct set_focus_window_reply set_focus_window_reply;
     struct set_active_window_reply set_active_window_reply;
     struct set_capture_window_reply set_capture_window_reply;
+    struct set_caret_window_reply set_caret_window_reply;
+    struct set_caret_info_reply set_caret_info_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 87
+#define SERVER_PROTOCOL_VERSION 88
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/protocol.def b/server/protocol.def
index 3837f39..64e6f52 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1966,3 +1966,35 @@
 @END
 #define CAPTURE_MENU     0x01  /* capture is for a menu */
 #define CAPTURE_MOVESIZE 0x02  /* capture is for moving/resizing */
+
+
+/* Set the current thread caret window */
+@REQ(set_caret_window)
+    user_handle_t  handle;        /* handle to the caret window */
+    int            width;         /* caret width */
+    int            height;        /* caret height */
+@REPLY
+    user_handle_t  previous;      /* handle to the previous caret window */
+    rectangle_t    old_rect;      /* previous caret rectangle */
+    int            old_hide;      /* previous hide count */
+    int            old_state;     /* previous caret state (1=on, 0=off) */
+@END
+
+
+/* Set the current thread caret information */
+@REQ(set_caret_info)
+    unsigned int   flags;         /* caret flags (see below) */
+    user_handle_t  handle;        /* handle to the caret window */
+    int            x;             /* caret x position */
+    int            y;             /* caret y position */
+    int            hide;          /* increment for hide count (can be negative to show it) */
+    int            state;         /* caret state (1=on, 0=off, -1=toggle current state) */
+@REPLY
+    user_handle_t  full_handle;   /* handle to the current caret window */
+    rectangle_t    old_rect;      /* previous caret rectangle */
+    int            old_hide;      /* previous hide count */
+    int            old_state;     /* previous caret state (1=on, 0=off) */
+@END
+#define SET_CARET_POS        0x01  /* set the caret position from x,y */
+#define SET_CARET_HIDE       0x02  /* increment the caret hide count */
+#define SET_CARET_STATE      0x04  /* set the caret on/off state */
diff --git a/server/queue.c b/server/queue.c
index 5332dcf..a4c8b1a 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -98,7 +98,9 @@
     user_handle_t          menu_owner;    /* current menu owner window */
     user_handle_t          move_size;     /* current moving/resizing window */
     user_handle_t          caret;         /* caret window */
-    rectangle_t            rect;          /* caret rectangle */
+    rectangle_t            caret_rect;    /* caret rectangle */
+    int                    caret_hide;    /* caret hide count */
+    int                    caret_state;   /* caret on/off state */
     unsigned char          keystate[256]; /* state of each key */
 };
 
@@ -167,6 +169,19 @@
     thread_input_destroy          /* destroy */
 };
 
+
+/* set the caret window in a given thread input */
+static void set_caret_window( struct thread_input *input, user_handle_t win )
+{
+    input->caret             = win;
+    input->caret_rect.left   = 0;
+    input->caret_rect.top    = 0;
+    input->caret_rect.right  = 0;
+    input->caret_rect.bottom = 0;
+    input->caret_hide        = 1;
+    input->caret_state       = 0;
+}
+
 /* create a thread input object */
 static struct thread_input *create_thread_input(void)
 {
@@ -179,11 +194,7 @@
         input->active      = 0;
         input->menu_owner  = 0;
         input->move_size   = 0;
-        input->caret       = 0;
-        input->rect.left   = 0;
-        input->rect.top    = 0;
-        input->rect.right  = 0;
-        input->rect.bottom = 0;
+        set_caret_window( input, 0 );
         memset( input->keystate, 0, sizeof(input->keystate) );
     }
     return input;
@@ -618,7 +629,7 @@
     if (window == input->active) input->active = 0;
     if (window == input->menu_owner) input->menu_owner = 0;
     if (window == input->move_size) input->move_size = 0;
-    if (window == input->caret) input->caret = 0;
+    if (window == input->caret) set_caret_window( input, 0 );
 }
 
 /* check if the specified window can be set in the input data of a given queue */
@@ -1295,7 +1306,7 @@
         reply->menu_owner = input->menu_owner;
         reply->move_size  = input->move_size;
         reply->caret      = input->caret;
-        reply->rect       = input->rect;
+        reply->rect       = input->caret_rect;
     }
     else
     {
@@ -1388,3 +1399,63 @@
         reply->full_handle = input->capture;
     }
 }
+
+
+/* Set the current thread caret window */
+DECL_HANDLER(set_caret_window)
+{
+    struct msg_queue *queue = get_current_queue();
+
+    reply->previous = 0;
+    if (queue && check_queue_input_window( queue, req->handle ))
+    {
+        struct thread_input *input = queue->input;
+
+        reply->previous  = input->caret;
+        reply->old_rect  = input->caret_rect;
+        reply->old_hide  = input->caret_hide;
+        reply->old_state = input->caret_state;
+
+        set_caret_window( input, get_user_full_handle(req->handle) );
+        input->caret_rect.right  = req->width;
+        input->caret_rect.bottom = req->height;
+    }
+}
+
+
+/* Set the current thread caret information */
+DECL_HANDLER(set_caret_info)
+{
+    struct msg_queue *queue = get_current_queue();
+    struct thread_input *input;
+
+    if (!queue) return;
+    input = queue->input;
+    reply->full_handle = input->caret;
+    reply->old_rect    = input->caret_rect;
+    reply->old_hide    = input->caret_hide;
+    reply->old_state   = input->caret_state;
+
+    if (req->handle && get_user_full_handle(req->handle) != input->caret)
+    {
+        set_error( STATUS_ACCESS_DENIED );
+        return;
+    }
+    if (req->flags & SET_CARET_POS)
+    {
+        input->caret_rect.right  += req->x - input->caret_rect.left;
+        input->caret_rect.bottom += req->y - input->caret_rect.top;
+        input->caret_rect.left = req->x;
+        input->caret_rect.top  = req->y;
+    }
+    if (req->flags & SET_CARET_HIDE)
+    {
+        input->caret_hide += req->hide;
+        if (input->caret_hide < 0) input->caret_hide = 0;
+    }
+    if (req->flags & SET_CARET_STATE)
+    {
+        if (req->state == -1) input->caret_state = !input->caret_state;
+        else input->caret_state = !!req->state;
+    }
+}
diff --git a/server/request.h b/server/request.h
index 63aea54..7051e88 100644
--- a/server/request.h
+++ b/server/request.h
@@ -265,6 +265,8 @@
 DECL_HANDLER(set_focus_window);
 DECL_HANDLER(set_active_window);
 DECL_HANDLER(set_capture_window);
+DECL_HANDLER(set_caret_window);
+DECL_HANDLER(set_caret_info);
 
 #ifdef WANT_REQUEST_HANDLERS
 
@@ -433,6 +435,8 @@
     (req_handler)req_set_focus_window,
     (req_handler)req_set_active_window,
     (req_handler)req_set_capture_window,
+    (req_handler)req_set_caret_window,
+    (req_handler)req_set_caret_info,
 };
 #endif  /* WANT_REQUEST_HANDLERS */
 
diff --git a/server/trace.c b/server/trace.c
index 9487057..1673213 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2245,6 +2245,43 @@
     fprintf( stderr, " full_handle=%08x", req->full_handle );
 }
 
+static void dump_set_caret_window_request( const struct set_caret_window_request *req )
+{
+    fprintf( stderr, " handle=%08x,", req->handle );
+    fprintf( stderr, " width=%d,", req->width );
+    fprintf( stderr, " height=%d", req->height );
+}
+
+static void dump_set_caret_window_reply( const struct set_caret_window_reply *req )
+{
+    fprintf( stderr, " previous=%08x,", req->previous );
+    fprintf( stderr, " old_rect=" );
+    dump_rectangle( &req->old_rect );
+    fprintf( stderr, "," );
+    fprintf( stderr, " old_hide=%d,", req->old_hide );
+    fprintf( stderr, " old_state=%d", req->old_state );
+}
+
+static void dump_set_caret_info_request( const struct set_caret_info_request *req )
+{
+    fprintf( stderr, " flags=%08x,", req->flags );
+    fprintf( stderr, " handle=%08x,", req->handle );
+    fprintf( stderr, " x=%d,", req->x );
+    fprintf( stderr, " y=%d,", req->y );
+    fprintf( stderr, " hide=%d,", req->hide );
+    fprintf( stderr, " state=%d", req->state );
+}
+
+static void dump_set_caret_info_reply( const struct set_caret_info_reply *req )
+{
+    fprintf( stderr, " full_handle=%08x,", req->full_handle );
+    fprintf( stderr, " old_rect=" );
+    dump_rectangle( &req->old_rect );
+    fprintf( stderr, "," );
+    fprintf( stderr, " old_hide=%d,", req->old_hide );
+    fprintf( stderr, " old_state=%d", req->old_state );
+}
+
 static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_new_process_request,
     (dump_func)dump_get_new_process_info_request,
@@ -2408,6 +2445,8 @@
     (dump_func)dump_set_focus_window_request,
     (dump_func)dump_set_active_window_request,
     (dump_func)dump_set_capture_window_request,
+    (dump_func)dump_set_caret_window_request,
+    (dump_func)dump_set_caret_info_request,
 };
 
 static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -2573,6 +2612,8 @@
     (dump_func)dump_set_focus_window_reply,
     (dump_func)dump_set_active_window_reply,
     (dump_func)dump_set_capture_window_reply,
+    (dump_func)dump_set_caret_window_reply,
+    (dump_func)dump_set_caret_info_reply,
 };
 
 static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -2738,6 +2779,8 @@
     "set_focus_window",
     "set_active_window",
     "set_capture_window",
+    "set_caret_window",
+    "set_caret_info",
 };
 
 /* ### make_requests end ### */
diff --git a/windows/caret.c b/windows/caret.c
deleted file mode 100644
index 1d278ab..0000000
--- a/windows/caret.c
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- * Caret functions
- *
- * Copyright 1993 David Metcalfe
- * Copyright 1996 Frans van Dorsselaer
- * Copyright 2001 Eric Pouech
- *
- * 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 "winbase.h"
-#include "wingdi.h"
-#include "winuser.h"
-#include "wine/wingdi16.h"
-#include "wine/winuser16.h"
-#include "win.h"
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(caret);
-
-typedef struct
-{
-    HWND     hwnd;
-    UINT     hidden;
-    BOOL     on;
-    INT      x;
-    INT      y;
-    INT      width;
-    INT      height;
-    HBITMAP  hBmp;
-    UINT     timeout;
-    UINT     timerid;
-} CARET;
-
-typedef enum
-{
-    CARET_OFF = 0,
-    CARET_ON,
-    CARET_TOGGLE
-} DISPLAY_CARET;
-
-static CARET Caret = { 0, 0, FALSE, 0, 0, 2, 12, 0, 500, 0 };
-
-/*****************************************************************
- *              CARET_GetHwnd
- */
-HWND CARET_GetHwnd(void)
-{
-    return Caret.hwnd;
-}
-
-/*****************************************************************
- *              CARET_GetRect
- */
-void CARET_GetRect(LPRECT lprc)
-{
-    lprc->right = (lprc->left = Caret.x) + Caret.width - 1;
-    lprc->bottom = (lprc->top = Caret.y) + Caret.height - 1;
-}
-
-/*****************************************************************
- *               CARET_DisplayCaret
- */
-static void CARET_DisplayCaret( DISPLAY_CARET status )
-{
-    HDC hdc;
-    HDC hCompDC;
-
-    if (Caret.on && (status == CARET_ON)) return;
-    if (!Caret.on && (status == CARET_OFF)) return;
-
-    /* So now it's always a toggle */
-
-    Caret.on = !Caret.on;
-    /* do not use DCX_CACHE here, for x,y,width,height are in logical units */
-    if (!(hdc = GetDCEx( Caret.hwnd, 0, DCX_USESTYLE /*| DCX_CACHE*/ ))) return;
-    hCompDC = CreateCompatibleDC(hdc);
-    if (hCompDC)
-    {
-	HBITMAP	hPrevBmp;
-
-	hPrevBmp = SelectObject(hCompDC, Caret.hBmp);
-	BitBlt(hdc, Caret.x, Caret.y, Caret.width, Caret.height, hCompDC, 0, 0, SRCINVERT);
-	SelectObject(hCompDC, hPrevBmp);
-	DeleteDC(hCompDC);
-    }
-    ReleaseDC( Caret.hwnd, hdc );
-}
-
-
-/*****************************************************************
- *               CARET_Callback
- */
-static VOID CALLBACK CARET_Callback( HWND hwnd, UINT msg, UINT id, DWORD ctime)
-{
-    TRACE("hwnd=%04x, timerid=%d, caret=%d\n",
-                  hwnd, id, Caret.on);
-    CARET_DisplayCaret(CARET_TOGGLE);
-}
-
-
-/*****************************************************************
- *               CARET_SetTimer
- */
-static void CARET_SetTimer(void)
-{
-    if (Caret.timerid) KillSystemTimer( (HWND)0, Caret.timerid );
-    Caret.timerid = SetSystemTimer( (HWND)0, 0, Caret.timeout,
-                                      CARET_Callback );
-}
-
-
-/*****************************************************************
- *               CARET_ResetTimer
- */
-static void CARET_ResetTimer(void)
-{
-    if (Caret.timerid)
-    {
-	KillSystemTimer( (HWND)0, Caret.timerid );
-	Caret.timerid = SetSystemTimer( (HWND)0, 0, Caret.timeout,
-                                          CARET_Callback );
-    }
-}
-
-
-/*****************************************************************
- *               CARET_KillTimer
- */
-static void CARET_KillTimer(void)
-{
-    if (Caret.timerid)
-    {
-	KillSystemTimer( (HWND)0, Caret.timerid );
-	Caret.timerid = 0;
-    }
-}
-
-
-/*****************************************************************
- *		CreateCaret (USER32.@)
- */
-BOOL WINAPI CreateCaret( HWND hwnd, HBITMAP bitmap,
-                             INT width, INT height )
-{
-    TRACE("hwnd=%04x\n", hwnd);
-
-    if (!hwnd) return FALSE;
-
-    /* if cursor already exists, destroy it */
-    if (Caret.hwnd) DestroyCaret();
-
-    if (bitmap && (bitmap != 1))
-    {
-        BITMAP bmp;
-        if (!GetObjectA( bitmap, sizeof(bmp), &bmp )) return FALSE;
-        Caret.width = bmp.bmWidth;
-        Caret.height = bmp.bmHeight;
-	bmp.bmBits = NULL;
-	Caret.hBmp = CreateBitmapIndirect(&bmp);
-
-	if (Caret.hBmp)
-	{
-	    /* copy the bitmap */
-	    LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, bmp.bmWidthBytes * bmp.bmHeight);
-	    GetBitmapBits(bitmap, bmp.bmWidthBytes * bmp.bmHeight, buf);
-	    SetBitmapBits(Caret.hBmp, bmp.bmWidthBytes * bmp.bmHeight, buf);
-	    HeapFree(GetProcessHeap(), 0, buf);
-	}
-    }
-    else
-    {
-	HDC	hdc;
-
-        Caret.width = width ? width : GetSystemMetrics(SM_CXBORDER);
-        Caret.height = height ? height : GetSystemMetrics(SM_CYBORDER);
-	Caret.hBmp = 0;
-
-	/* create the uniform bitmap on the fly */
-	hdc = GetDC(hwnd);
-	if (hdc)
-	{
-	    HDC		hMemDC = CreateCompatibleDC(hdc);
-
-	    if (hMemDC)
-	    {
-		RECT	r;
-		r.left = r.top = 0;
-		r.right = Caret.width;
-		r.bottom = Caret.height;
-
-		if ((Caret.hBmp = CreateCompatibleBitmap(hMemDC, Caret.width, Caret.height)))
-		{
-		    HBITMAP hPrevBmp = SelectObject(hMemDC, Caret.hBmp);
-		    FillRect(hMemDC, &r, (bitmap ? COLOR_GRAYTEXT : COLOR_WINDOW) + 1);
-		    SelectObject(hMemDC, hPrevBmp);
-		}
-		DeleteDC(hMemDC);
-	    }
-	    ReleaseDC(hwnd, hdc);
-	}
-    }
-
-    Caret.hwnd = WIN_GetFullHandle( hwnd );
-    Caret.hidden = 1;
-    Caret.on = FALSE;
-    Caret.x = 0;
-    Caret.y = 0;
-
-    Caret.timeout = GetProfileIntA( "windows", "CursorBlinkRate", 500 );
-    return TRUE;
-}
-
-
-/*****************************************************************
- *		DestroyCaret (USER.164)
- */
-void WINAPI DestroyCaret16(void)
-{
-    DestroyCaret();
-}
-
-
-/*****************************************************************
- *		DestroyCaret (USER32.@)
- */
-BOOL WINAPI DestroyCaret(void)
-{
-    if (!Caret.hwnd) return FALSE;
-
-    TRACE("hwnd=%04x, timerid=%d\n",
-		Caret.hwnd, Caret.timerid);
-
-    CARET_KillTimer();
-    CARET_DisplayCaret(CARET_OFF);
-    DeleteObject( Caret.hBmp );
-    Caret.hwnd = 0;
-    return TRUE;
-}
-
-
-/*****************************************************************
- *		SetCaretPos (USER.165)
- */
-void WINAPI SetCaretPos16( INT16 x, INT16 y )
-{
-    SetCaretPos( x, y );
-}
-
-
-/*****************************************************************
- *		SetCaretPos (USER32.@)
- */
-BOOL WINAPI SetCaretPos( INT x, INT y)
-{
-    if (!Caret.hwnd) return FALSE;
-    if ((x == Caret.x) && (y == Caret.y)) return TRUE;
-
-    TRACE("x=%d, y=%d\n", x, y);
-
-    CARET_KillTimer();
-    CARET_DisplayCaret(CARET_OFF);
-    Caret.x = x;
-    Caret.y = y;
-    if (!Caret.hidden)
-    {
-	CARET_DisplayCaret(CARET_ON);
-	CARET_SetTimer();
-    }
-    return TRUE;
-}
-
-
-/*****************************************************************
- *		HideCaret (USER32.@)
- */
-BOOL WINAPI HideCaret( HWND hwnd )
-{
-    if (!Caret.hwnd) return FALSE;
-    if (hwnd && (Caret.hwnd != WIN_GetFullHandle(hwnd))) return FALSE;
-
-    TRACE("hwnd=%04x, hidden=%d\n",
-                  hwnd, Caret.hidden);
-
-    CARET_KillTimer();
-    CARET_DisplayCaret(CARET_OFF);
-    Caret.hidden++;
-    return TRUE;
-}
-
-
-/*****************************************************************
- *		ShowCaret (USER32.@)
- */
-BOOL WINAPI ShowCaret( HWND hwnd )
-{
-    if (!Caret.hwnd) return FALSE;
-    if (hwnd && (Caret.hwnd != WIN_GetFullHandle(hwnd))) return FALSE;
-
-    TRACE("hwnd=%04x, hidden=%d\n",
-		hwnd, Caret.hidden);
-
-    if (Caret.hidden)
-    {
-	Caret.hidden--;
-	if (!Caret.hidden)
-	{
-	    CARET_DisplayCaret(CARET_ON);
-	    CARET_SetTimer();
-	}
-    }
-    return TRUE;
-}
-
-
-/*****************************************************************
- *		SetCaretBlinkTime (USER.168)
- */
-void WINAPI SetCaretBlinkTime16( UINT16 msecs )
-{
-    SetCaretBlinkTime( msecs );
-}
-
-/*****************************************************************
- *		SetCaretBlinkTime (USER32.@)
- */
-BOOL WINAPI SetCaretBlinkTime( UINT msecs )
-{
-    if (!Caret.hwnd) return FALSE;
-
-    TRACE("hwnd=%04x, msecs=%d\n",
-		Caret.hwnd, msecs);
-
-    Caret.timeout = msecs;
-    CARET_ResetTimer();
-    return TRUE;
-}
-
-
-/*****************************************************************
- *		GetCaretBlinkTime (USER.169)
- */
-UINT16 WINAPI GetCaretBlinkTime16(void)
-{
-    return (UINT16)GetCaretBlinkTime();
-}
-
-
-/*****************************************************************
- *		GetCaretBlinkTime (USER32.@)
- */
-UINT WINAPI GetCaretBlinkTime(void)
-{
-    return Caret.timeout;
-}
-
-
-/*****************************************************************
- *		GetCaretPos (USER.183)
- */
-VOID WINAPI GetCaretPos16( LPPOINT16 pt )
-{
-    if (!Caret.hwnd || !pt) return;
-
-    TRACE("hwnd=%04x, pt=%p, x=%d, y=%d\n",
-                  Caret.hwnd, pt, Caret.x, Caret.y);
-    pt->x = (INT16)Caret.x;
-    pt->y = (INT16)Caret.y;
-}
-
-
-/*****************************************************************
- *		GetCaretPos (USER32.@)
- */
-BOOL WINAPI GetCaretPos( LPPOINT pt )
-{
-    if (!Caret.hwnd || !pt) return FALSE;
-    pt->x = Caret.x;
-    pt->y = Caret.y;
-    return TRUE;
-}
diff --git a/windows/scroll.c b/windows/scroll.c
index 6be5d6b..1db4859 100644
--- a/windows/scroll.c
+++ b/windows/scroll.c
@@ -36,29 +36,26 @@
  */
 static HWND fix_caret(HWND hWnd, LPRECT lprc, UINT flags)
 {
-   HWND hCaret = CARET_GetHwnd();
+    GUITHREADINFO info;
 
-   if( hCaret )
-   {
-       RECT rc;
-       CARET_GetRect( &rc );
-       if( hCaret == hWnd ||
-          (flags & SW_SCROLLCHILDREN && IsChild(hWnd, hCaret)) )
-       {
-           POINT pt;
-           pt.x = rc.left;
-           pt.y = rc.top;
-           MapWindowPoints( hCaret, hWnd, (LPPOINT)&rc, 2 );
-           if( IntersectRect(lprc, lprc, &rc) )
-           {
-               HideCaret(hCaret);
-               lprc->left = pt.x;
-               lprc->top = pt.y;
-               return hCaret;
-           }
-       }
-   }
-   return 0;
+    if (!GetGUIThreadInfo( GetCurrentThreadId(), &info )) return 0;
+    if (!info.hwndCaret) return 0;
+    if (info.hwndCaret == hWnd ||
+        ((flags & SW_SCROLLCHILDREN) && IsChild(hWnd, info.hwndCaret)))
+    {
+        POINT pt;
+        pt.x = info.rcCaret.left;
+        pt.y = info.rcCaret.top;
+        MapWindowPoints( info.hwndCaret, hWnd, (LPPOINT)&info.rcCaret, 2 );
+        if( IntersectRect(lprc, lprc, &info.rcCaret) )
+        {
+            HideCaret(0);
+            lprc->left = pt.x;
+            lprc->top = pt.y;
+            return info.hwndCaret;
+        }
+    }
+    return 0;
 }
 
 
diff --git a/windows/win.c b/windows/win.c
index d19cc09..a7e0c4e 100644
--- a/windows/win.c
+++ b/windows/win.c
@@ -1392,7 +1392,12 @@
  */
 static void WIN_SendDestroyMsg( HWND hwnd )
 {
-    if( CARET_GetHwnd() == hwnd) DestroyCaret();
+    GUITHREADINFO info;
+
+    if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
+    {
+        if (hwnd == info.hwndCaret) DestroyCaret();
+    }
     if (USER_Driver.pResetSelectionOwner)
         USER_Driver.pResetSelectionOwner( hwnd, TRUE );