4 * Copyright 1993 David Metcalfe
5 * Copyright 1996 Frans van Dorsselaer
6 * Copyright 2001 Eric Pouech
7 * Copyright 2002 Alexandre Julliard
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
33 #include "wine/server.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(caret);
44 static CARET Caret = { 0, 500 };
46 #define TIMERID 0xffff /* system timer id for the caret */
49 /*****************************************************************
52 static void CARET_DisplayCaret( HWND hwnd, const RECT *r )
57 /* do not use DCX_CACHE here, for x,y,width,height are in logical units */
58 if (!(hdc = GetDCEx( hwnd, 0, DCX_USESTYLE /*| DCX_CACHE*/ ))) return;
59 hCompDC = CreateCompatibleDC(hdc);
64 hPrevBmp = SelectObject(hCompDC, Caret.hBmp);
65 BitBlt(hdc, r->left, r->top, r->right-r->left, r->bottom-r->top, hCompDC, 0, 0, SRCINVERT);
66 SelectObject(hCompDC, hPrevBmp);
69 ReleaseDC( hwnd, hdc );
73 /*****************************************************************
76 static void CALLBACK CARET_Callback( HWND hwnd, UINT msg, UINT_PTR id, DWORD ctime)
82 SERVER_START_REQ( set_caret_info )
84 req->flags = SET_CARET_STATE;
85 req->handle = wine_server_user_handle( hwnd );
89 req->state = -1; /* toggle current state */
90 if ((ret = !wine_server_call( req )))
92 hwnd = wine_server_ptr_handle( reply->full_handle );
93 r.left = reply->old_rect.left;
94 r.top = reply->old_rect.top;
95 r.right = reply->old_rect.right;
96 r.bottom = reply->old_rect.bottom;
97 hidden = reply->old_hide;
102 if (ret && !hidden) CARET_DisplayCaret( hwnd, &r );
106 /*****************************************************************
107 * CreateCaret (USER32.@)
109 BOOL WINAPI CreateCaret( HWND hwnd, HBITMAP bitmap, INT width, INT height )
118 TRACE("hwnd=%p\n", hwnd);
120 if (!hwnd) return FALSE;
122 if (bitmap && (bitmap != (HBITMAP)1))
125 if (!GetObjectA( bitmap, sizeof(bmp), &bmp )) return FALSE;
127 height = bmp.bmHeight;
129 hBmp = CreateBitmapIndirect(&bmp);
132 /* copy the bitmap */
133 LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, bmp.bmWidthBytes * bmp.bmHeight);
134 GetBitmapBits(bitmap, bmp.bmWidthBytes * bmp.bmHeight, buf);
135 SetBitmapBits(hBmp, bmp.bmWidthBytes * bmp.bmHeight, buf);
136 HeapFree(GetProcessHeap(), 0, buf);
143 if (!width) width = GetSystemMetrics(SM_CXBORDER);
144 if (!height) height = GetSystemMetrics(SM_CYBORDER);
146 /* create the uniform bitmap on the fly */
150 HDC hMemDC = CreateCompatibleDC(hdc);
153 if ((hBmp = CreateCompatibleBitmap(hMemDC, width, height )))
155 HBITMAP hPrevBmp = SelectObject(hMemDC, hBmp);
156 SetRect( &r, 0, 0, width, height );
157 FillRect(hMemDC, &r, bitmap ? GetStockObject(GRAY_BRUSH) : GetStockObject(WHITE_BRUSH));
158 SelectObject(hMemDC, hPrevBmp);
162 ReleaseDC(hwnd, hdc);
165 if (!hBmp) return FALSE;
167 SERVER_START_REQ( set_caret_window )
169 req->handle = wine_server_user_handle( hwnd );
171 req->height = height;
172 if ((ret = !wine_server_call_err( req )))
174 prev = wine_server_ptr_handle( reply->previous );
175 r.left = reply->old_rect.left;
176 r.top = reply->old_rect.top;
177 r.right = reply->old_rect.right;
178 r.bottom = reply->old_rect.bottom;
179 old_state = reply->old_state;
180 hidden = reply->old_hide;
184 if (!ret) return FALSE;
186 if (prev && !hidden) /* hide the previous one */
188 /* FIXME: won't work if prev belongs to a different process */
189 KillSystemTimer( prev, TIMERID );
190 if (old_state) CARET_DisplayCaret( prev, &r );
193 if (Caret.hBmp) DeleteObject( Caret.hBmp );
195 Caret.timeout = GetProfileIntA( "windows", "CursorBlinkRate", 500 );
200 /*****************************************************************
201 * DestroyCaret (USER32.@)
203 BOOL WINAPI DestroyCaret(void)
211 SERVER_START_REQ( set_caret_window )
216 if ((ret = !wine_server_call_err( req )))
218 prev = wine_server_ptr_handle( reply->previous );
219 r.left = reply->old_rect.left;
220 r.top = reply->old_rect.top;
221 r.right = reply->old_rect.right;
222 r.bottom = reply->old_rect.bottom;
223 old_state = reply->old_state;
224 hidden = reply->old_hide;
229 if (ret && prev && !hidden)
231 /* FIXME: won't work if prev belongs to a different process */
232 KillSystemTimer( prev, TIMERID );
233 if (old_state) CARET_DisplayCaret( prev, &r );
235 if (Caret.hBmp) DeleteObject( Caret.hBmp );
241 /*****************************************************************
242 * SetCaretPos (USER32.@)
244 BOOL WINAPI SetCaretPos( INT x, INT y )
252 SERVER_START_REQ( set_caret_info )
254 req->flags = SET_CARET_POS|SET_CARET_STATE;
260 if ((ret = !wine_server_call_err( req )))
262 hwnd = wine_server_ptr_handle( reply->full_handle );
263 r.left = reply->old_rect.left;
264 r.top = reply->old_rect.top;
265 r.right = reply->old_rect.right;
266 r.bottom = reply->old_rect.bottom;
267 old_state = reply->old_state;
268 hidden = reply->old_hide;
272 if (ret && !hidden && (x != r.left || y != r.top))
274 if (old_state) CARET_DisplayCaret( hwnd, &r );
275 r.right += x - r.left;
276 r.bottom += y - r.top;
279 CARET_DisplayCaret( hwnd, &r );
280 SetSystemTimer( hwnd, TIMERID, Caret.timeout, CARET_Callback );
286 /*****************************************************************
287 * HideCaret (USER32.@)
289 BOOL WINAPI HideCaret( HWND hwnd )
296 SERVER_START_REQ( set_caret_info )
298 req->flags = SET_CARET_HIDE|SET_CARET_STATE;
299 req->handle = wine_server_user_handle( hwnd );
304 if ((ret = !wine_server_call_err( req )))
306 hwnd = wine_server_ptr_handle( reply->full_handle );
307 r.left = reply->old_rect.left;
308 r.top = reply->old_rect.top;
309 r.right = reply->old_rect.right;
310 r.bottom = reply->old_rect.bottom;
311 old_state = reply->old_state;
312 hidden = reply->old_hide;
319 if (old_state) CARET_DisplayCaret( hwnd, &r );
320 KillSystemTimer( hwnd, TIMERID );
326 /*****************************************************************
327 * ShowCaret (USER32.@)
329 BOOL WINAPI ShowCaret( HWND hwnd )
335 SERVER_START_REQ( set_caret_info )
337 req->flags = SET_CARET_HIDE|SET_CARET_STATE;
338 req->handle = wine_server_user_handle( hwnd );
343 if ((ret = !wine_server_call_err( req )))
345 hwnd = wine_server_ptr_handle( reply->full_handle );
346 r.left = reply->old_rect.left;
347 r.top = reply->old_rect.top;
348 r.right = reply->old_rect.right;
349 r.bottom = reply->old_rect.bottom;
350 hidden = reply->old_hide;
355 if (ret && (hidden == 1)) /* hidden was 1 so it's now 0 */
357 CARET_DisplayCaret( hwnd, &r );
358 SetSystemTimer( hwnd, TIMERID, Caret.timeout, CARET_Callback );
364 /*****************************************************************
365 * GetCaretPos (USER32.@)
367 BOOL WINAPI GetCaretPos( LPPOINT pt )
371 SERVER_START_REQ( set_caret_info )
373 req->flags = 0; /* don't set anything */
379 if ((ret = !wine_server_call_err( req )))
381 pt->x = reply->old_rect.left;
382 pt->y = reply->old_rect.top;
390 /*****************************************************************
391 * SetCaretBlinkTime (USER32.@)
393 BOOL WINAPI SetCaretBlinkTime( UINT msecs )
395 TRACE("msecs=%d\n", msecs);
397 Caret.timeout = msecs;
398 /* if (Caret.hwnd) CARET_SetTimer(); FIXME */
403 /*****************************************************************
404 * GetCaretBlinkTime (USER32.@)
406 UINT WINAPI GetCaretBlinkTime(void)
408 return Caret.timeout;