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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 id, DWORD ctime)
83 SERVER_START_REQ( set_caret_info )
85 req->flags = SET_CARET_STATE;
90 req->state = -1; /* toggle current state */
91 if ((ret = !wine_server_call( req )))
93 hwnd = reply->full_handle;
94 r.left = reply->old_rect.left;
95 r.top = reply->old_rect.top;
96 r.right = reply->old_rect.right;
97 r.bottom = reply->old_rect.bottom;
98 old_state = reply->old_state;
99 hidden = reply->old_hide;
104 if (ret && !hidden) CARET_DisplayCaret( hwnd, &r );
108 /*****************************************************************
109 * CreateCaret (USER32.@)
111 BOOL WINAPI CreateCaret( HWND hwnd, HBITMAP bitmap, INT width, INT height )
120 TRACE("hwnd=%p\n", hwnd);
122 if (!hwnd) return FALSE;
124 if (bitmap && (bitmap != (HBITMAP)1))
127 if (!GetObjectA( bitmap, sizeof(bmp), &bmp )) return FALSE;
129 height = bmp.bmHeight;
131 hBmp = CreateBitmapIndirect(&bmp);
134 /* copy the bitmap */
135 LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, bmp.bmWidthBytes * bmp.bmHeight);
136 GetBitmapBits(bitmap, bmp.bmWidthBytes * bmp.bmHeight, buf);
137 SetBitmapBits(hBmp, bmp.bmWidthBytes * bmp.bmHeight, buf);
138 HeapFree(GetProcessHeap(), 0, buf);
145 if (!width) width = GetSystemMetrics(SM_CXBORDER);
146 if (!height) height = GetSystemMetrics(SM_CYBORDER);
148 /* create the uniform bitmap on the fly */
152 HDC hMemDC = CreateCompatibleDC(hdc);
155 if ((hBmp = CreateCompatibleBitmap(hMemDC, width, height )))
157 HBITMAP hPrevBmp = SelectObject(hMemDC, hBmp);
158 SetRect( &r, 0, 0, width, height );
159 FillRect(hMemDC, &r, (HBRUSH)((bitmap ? COLOR_GRAYTEXT : COLOR_WINDOW) + 1));
160 SelectObject(hMemDC, hPrevBmp);
164 ReleaseDC(hwnd, hdc);
167 if (!hBmp) return FALSE;
169 SERVER_START_REQ( set_caret_window )
173 req->height = height;
174 if ((ret = !wine_server_call_err( req )))
176 prev = reply->previous;
177 r.left = reply->old_rect.left;
178 r.top = reply->old_rect.top;
179 r.right = reply->old_rect.right;
180 r.bottom = reply->old_rect.bottom;
181 old_state = reply->old_state;
182 hidden = reply->old_hide;
186 if (!ret) return FALSE;
188 if (prev && !hidden) /* hide the previous one */
190 /* FIXME: won't work if prev belongs to a different process */
191 KillSystemTimer( prev, TIMERID );
192 if (old_state) CARET_DisplayCaret( prev, &r );
195 if (Caret.hBmp) DeleteObject( Caret.hBmp );
197 Caret.timeout = GetProfileIntA( "windows", "CursorBlinkRate", 500 );
202 /*****************************************************************
203 * DestroyCaret (USER32.@)
205 BOOL WINAPI DestroyCaret(void)
213 SERVER_START_REQ( set_caret_window )
218 if ((ret = !wine_server_call_err( req )))
220 prev = reply->previous;
221 r.left = reply->old_rect.left;
222 r.top = reply->old_rect.top;
223 r.right = reply->old_rect.right;
224 r.bottom = reply->old_rect.bottom;
225 old_state = reply->old_state;
226 hidden = reply->old_hide;
231 if (ret && prev && !hidden)
233 /* FIXME: won't work if prev belongs to a different process */
234 KillSystemTimer( prev, TIMERID );
235 if (old_state) CARET_DisplayCaret( prev, &r );
237 if (Caret.hBmp) DeleteObject( Caret.hBmp );
243 /*****************************************************************
244 * SetCaretPos (USER32.@)
246 BOOL WINAPI SetCaretPos( INT x, INT y )
254 SERVER_START_REQ( set_caret_info )
256 req->flags = SET_CARET_POS|SET_CARET_STATE;
262 if ((ret = !wine_server_call_err( req )))
264 hwnd = reply->full_handle;
265 r.left = reply->old_rect.left;
266 r.top = reply->old_rect.top;
267 r.right = reply->old_rect.right;
268 r.bottom = reply->old_rect.bottom;
269 old_state = reply->old_state;
270 hidden = reply->old_hide;
276 if (old_state) CARET_DisplayCaret( hwnd, &r );
277 r.right += x - r.left;
278 r.bottom += y - r.top;
281 CARET_DisplayCaret( hwnd, &r );
282 SetSystemTimer( hwnd, TIMERID, Caret.timeout, CARET_Callback );
288 /*****************************************************************
289 * HideCaret (USER32.@)
291 BOOL WINAPI HideCaret( HWND hwnd )
298 SERVER_START_REQ( set_caret_info )
300 req->flags = SET_CARET_HIDE|SET_CARET_STATE;
306 if ((ret = !wine_server_call_err( req )))
308 hwnd = reply->full_handle;
309 r.left = reply->old_rect.left;
310 r.top = reply->old_rect.top;
311 r.right = reply->old_rect.right;
312 r.bottom = reply->old_rect.bottom;
313 old_state = reply->old_state;
314 hidden = reply->old_hide;
321 if (old_state) CARET_DisplayCaret( hwnd, &r );
322 KillSystemTimer( hwnd, TIMERID );
328 /*****************************************************************
329 * ShowCaret (USER32.@)
331 BOOL WINAPI ShowCaret( HWND hwnd )
338 SERVER_START_REQ( set_caret_info )
340 req->flags = SET_CARET_HIDE|SET_CARET_STATE;
346 if ((ret = !wine_server_call_err( req )))
348 hwnd = reply->full_handle;
349 r.left = reply->old_rect.left;
350 r.top = reply->old_rect.top;
351 r.right = reply->old_rect.right;
352 r.bottom = reply->old_rect.bottom;
353 old_state = reply->old_state;
354 hidden = reply->old_hide;
359 if (ret && (hidden == 1)) /* hidden was 1 so it's now 0 */
361 CARET_DisplayCaret( hwnd, &r );
362 SetSystemTimer( hwnd, TIMERID, Caret.timeout, CARET_Callback );
368 /*****************************************************************
369 * GetCaretPos (USER32.@)
371 BOOL WINAPI GetCaretPos( LPPOINT pt )
375 SERVER_START_REQ( set_caret_info )
377 req->flags = 0; /* don't set anything */
383 if ((ret = !wine_server_call_err( req )))
385 pt->x = reply->old_rect.left;
386 pt->y = reply->old_rect.top;
394 /*****************************************************************
395 * SetCaretBlinkTime (USER32.@)
397 BOOL WINAPI SetCaretBlinkTime( UINT msecs )
399 TRACE("msecs=%d\n", msecs);
401 Caret.timeout = msecs;
402 /* if (Caret.hwnd) CARET_SetTimer(); FIXME */
407 /*****************************************************************
408 * GetCaretBlinkTime (USER32.@)
410 UINT WINAPI GetCaretBlinkTime(void)
412 return Caret.timeout;