Fix signed/unsigned compilation warnings.
[wine] / dlls / user / caret.c
1 /*
2  * Caret functions
3  *
4  * Copyright 1993 David Metcalfe
5  * Copyright 1996 Frans van Dorsselaer
6  * Copyright 2001 Eric Pouech
7  * Copyright 2002 Alexandre Julliard
8  *
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.
13  *
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.
18  *
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
22  */
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "wine/server.h"
29 #include "wine/debug.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(caret);
32
33 typedef struct
34 {
35     HBITMAP  hBmp;
36     UINT     timeout;
37 } CARET;
38
39 static CARET Caret = { 0, 500 };
40
41 #define TIMERID 0xffff  /* system timer id for the caret */
42
43
44 /*****************************************************************
45  *               CARET_DisplayCaret
46  */
47 static void CARET_DisplayCaret( HWND hwnd, const RECT *r )
48 {
49     HDC hdc;
50     HDC hCompDC;
51
52     /* do not use DCX_CACHE here, for x,y,width,height are in logical units */
53     if (!(hdc = GetDCEx( hwnd, 0, DCX_USESTYLE /*| DCX_CACHE*/ ))) return;
54     hCompDC = CreateCompatibleDC(hdc);
55     if (hCompDC)
56     {
57         HBITMAP hPrevBmp;
58
59         hPrevBmp = SelectObject(hCompDC, Caret.hBmp);
60         BitBlt(hdc, r->left, r->top, r->right-r->left, r->bottom-r->top, hCompDC, 0, 0, SRCINVERT);
61         SelectObject(hCompDC, hPrevBmp);
62         DeleteDC(hCompDC);
63     }
64     ReleaseDC( hwnd, hdc );
65 }
66
67
68 /*****************************************************************
69  *               CARET_Callback
70  */
71 static void CALLBACK CARET_Callback( HWND hwnd, UINT msg, UINT id, DWORD ctime)
72 {
73     BOOL ret;
74     RECT r;
75     int old_state = 0;
76     int hidden = 0;
77
78     SERVER_START_REQ( set_caret_info )
79     {
80         req->flags  = SET_CARET_STATE;
81         req->handle = hwnd;
82         req->x      = 0;
83         req->y      = 0;
84         req->hide   = 0;
85         req->state  = -1;  /* toggle current state */
86         if ((ret = !wine_server_call( req )))
87         {
88             hwnd      = reply->full_handle;
89             r.left    = reply->old_rect.left;
90             r.top     = reply->old_rect.top;
91             r.right   = reply->old_rect.right;
92             r.bottom  = reply->old_rect.bottom;
93             old_state = reply->old_state;
94             hidden    = reply->old_hide;
95         }
96     }
97     SERVER_END_REQ;
98
99     if (ret && !hidden) CARET_DisplayCaret( hwnd, &r );
100 }
101
102
103 /*****************************************************************
104  *              CreateCaret (USER32.@)
105  */
106 BOOL WINAPI CreateCaret( HWND hwnd, HBITMAP bitmap, INT width, INT height )
107 {
108     BOOL ret;
109     RECT r;
110     int old_state = 0;
111     int hidden = 0;
112     HBITMAP hBmp = 0;
113     HWND prev = 0;
114
115     TRACE("hwnd=%p\n", hwnd);
116
117     if (!hwnd) return FALSE;
118
119     if (bitmap && (bitmap != (HBITMAP)1))
120     {
121         BITMAP bmp;
122         if (!GetObjectA( bitmap, sizeof(bmp), &bmp )) return FALSE;
123         width = bmp.bmWidth;
124         height = bmp.bmHeight;
125         bmp.bmBits = NULL;
126         hBmp = CreateBitmapIndirect(&bmp);
127         if (hBmp)
128         {
129             /* copy the bitmap */
130             LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, bmp.bmWidthBytes * bmp.bmHeight);
131             GetBitmapBits(bitmap, bmp.bmWidthBytes * bmp.bmHeight, buf);
132             SetBitmapBits(hBmp, bmp.bmWidthBytes * bmp.bmHeight, buf);
133             HeapFree(GetProcessHeap(), 0, buf);
134         }
135     }
136     else
137     {
138         HDC hdc;
139
140         if (!width) width = GetSystemMetrics(SM_CXBORDER);
141         if (!height) height = GetSystemMetrics(SM_CYBORDER);
142
143         /* create the uniform bitmap on the fly */
144         hdc = GetDC(hwnd);
145         if (hdc)
146         {
147             HDC hMemDC = CreateCompatibleDC(hdc);
148             if (hMemDC)
149             {
150                 if ((hBmp = CreateCompatibleBitmap(hMemDC, width, height )))
151                 {
152                     HBITMAP hPrevBmp = SelectObject(hMemDC, hBmp);
153                     SetRect( &r, 0, 0, width, height );
154                     FillRect(hMemDC, &r, (HBRUSH)((bitmap ? COLOR_GRAYTEXT : COLOR_WINDOW) + 1));
155                     SelectObject(hMemDC, hPrevBmp);
156                 }
157                 DeleteDC(hMemDC);
158             }
159             ReleaseDC(hwnd, hdc);
160         }
161     }
162     if (!hBmp) return FALSE;
163
164     SERVER_START_REQ( set_caret_window )
165     {
166         req->handle = hwnd;
167         req->width  = width;
168         req->height = height;
169         if ((ret = !wine_server_call_err( req )))
170         {
171             prev      = reply->previous;
172             r.left    = reply->old_rect.left;
173             r.top     = reply->old_rect.top;
174             r.right   = reply->old_rect.right;
175             r.bottom  = reply->old_rect.bottom;
176             old_state = reply->old_state;
177             hidden    = reply->old_hide;
178         }
179     }
180     SERVER_END_REQ;
181     if (!ret) return FALSE;
182
183     if (prev && !hidden)  /* hide the previous one */
184     {
185         /* FIXME: won't work if prev belongs to a different process */
186         KillSystemTimer( prev, TIMERID );
187         if (old_state) CARET_DisplayCaret( prev, &r );
188     }
189
190     if (Caret.hBmp) DeleteObject( Caret.hBmp );
191     Caret.hBmp = hBmp;
192     Caret.timeout = GetProfileIntA( "windows", "CursorBlinkRate", 500 );
193     return TRUE;
194 }
195
196
197 /*****************************************************************
198  *              DestroyCaret (USER32.@)
199  */
200 BOOL WINAPI DestroyCaret(void)
201 {
202     BOOL ret;
203     HWND prev = 0;
204     RECT r;
205     int old_state = 0;
206     int hidden = 0;
207
208     SERVER_START_REQ( set_caret_window )
209     {
210         req->handle = 0;
211         req->width  = 0;
212         req->height = 0;
213         if ((ret = !wine_server_call_err( req )))
214         {
215             prev      = reply->previous;
216             r.left    = reply->old_rect.left;
217             r.top     = reply->old_rect.top;
218             r.right   = reply->old_rect.right;
219             r.bottom  = reply->old_rect.bottom;
220             old_state = reply->old_state;
221             hidden    = reply->old_hide;
222         }
223     }
224     SERVER_END_REQ;
225
226     if (ret && prev && !hidden)
227     {
228         /* FIXME: won't work if prev belongs to a different process */
229         KillSystemTimer( prev, TIMERID );
230         if (old_state) CARET_DisplayCaret( prev, &r );
231     }
232     if (Caret.hBmp) DeleteObject( Caret.hBmp );
233     Caret.hBmp = 0;
234     return ret;
235 }
236
237
238 /*****************************************************************
239  *              SetCaretPos (USER32.@)
240  */
241 BOOL WINAPI SetCaretPos( INT x, INT y )
242 {
243     BOOL ret;
244     HWND hwnd = 0;
245     RECT r;
246     int old_state = 0;
247     int hidden = 0;
248
249     SERVER_START_REQ( set_caret_info )
250     {
251         req->flags  = SET_CARET_POS|SET_CARET_STATE;
252         req->handle = 0;
253         req->x      = x;
254         req->y      = y;
255         req->hide   = 0;
256         req->state  = 1;
257         if ((ret = !wine_server_call_err( req )))
258         {
259             hwnd      = reply->full_handle;
260             r.left    = reply->old_rect.left;
261             r.top     = reply->old_rect.top;
262             r.right   = reply->old_rect.right;
263             r.bottom  = reply->old_rect.bottom;
264             old_state = reply->old_state;
265             hidden    = reply->old_hide;
266         }
267     }
268     SERVER_END_REQ;
269     if (ret && !hidden)
270     {
271         if (old_state) CARET_DisplayCaret( hwnd, &r );
272         r.right += x - r.left;
273         r.bottom += y - r.top;
274         r.left = x;
275         r.top = y;
276         CARET_DisplayCaret( hwnd, &r );
277         SetSystemTimer( hwnd, TIMERID, Caret.timeout, CARET_Callback );
278     }
279     return ret;
280 }
281
282
283 /*****************************************************************
284  *              HideCaret (USER32.@)
285  */
286 BOOL WINAPI HideCaret( HWND hwnd )
287 {
288     BOOL ret;
289     RECT r;
290     int old_state = 0;
291     int hidden = 0;
292
293     SERVER_START_REQ( set_caret_info )
294     {
295         req->flags  = SET_CARET_HIDE|SET_CARET_STATE;
296         req->handle = hwnd;
297         req->x      = 0;
298         req->y      = 0;
299         req->hide   = 1;
300         req->state  = 0;
301         if ((ret = !wine_server_call_err( req )))
302         {
303             hwnd      = reply->full_handle;
304             r.left    = reply->old_rect.left;
305             r.top     = reply->old_rect.top;
306             r.right   = reply->old_rect.right;
307             r.bottom  = reply->old_rect.bottom;
308             old_state = reply->old_state;
309             hidden    = reply->old_hide;
310         }
311     }
312     SERVER_END_REQ;
313
314     if (ret && !hidden)
315     {
316         if (old_state) CARET_DisplayCaret( hwnd, &r );
317         KillSystemTimer( hwnd, TIMERID );
318     }
319     return ret;
320 }
321
322
323 /*****************************************************************
324  *              ShowCaret (USER32.@)
325  */
326 BOOL WINAPI ShowCaret( HWND hwnd )
327 {
328     BOOL ret;
329     RECT r;
330     int old_state = 0;
331     int hidden = 0;
332
333     SERVER_START_REQ( set_caret_info )
334     {
335         req->flags  = SET_CARET_HIDE|SET_CARET_STATE;
336         req->handle = hwnd;
337         req->x      = 0;
338         req->y      = 0;
339         req->hide   = -1;
340         req->state  = 1;
341         if ((ret = !wine_server_call_err( req )))
342         {
343             hwnd      = reply->full_handle;
344             r.left    = reply->old_rect.left;
345             r.top     = reply->old_rect.top;
346             r.right   = reply->old_rect.right;
347             r.bottom  = reply->old_rect.bottom;
348             old_state = reply->old_state;
349             hidden    = reply->old_hide;
350         }
351     }
352     SERVER_END_REQ;
353
354     if (ret && (hidden == 1))  /* hidden was 1 so it's now 0 */
355     {
356         CARET_DisplayCaret( hwnd, &r );
357         SetSystemTimer( hwnd, TIMERID, Caret.timeout, CARET_Callback );
358     }
359     return ret;
360 }
361
362
363 /*****************************************************************
364  *              GetCaretPos (USER32.@)
365  */
366 BOOL WINAPI GetCaretPos( LPPOINT pt )
367 {
368     BOOL ret;
369
370     SERVER_START_REQ( set_caret_info )
371     {
372         req->flags  = 0;  /* don't set anything */
373         req->handle = 0;
374         req->x      = 0;
375         req->y      = 0;
376         req->hide   = 0;
377         req->state  = 0;
378         if ((ret = !wine_server_call_err( req )))
379         {
380             pt->x = reply->old_rect.left;
381             pt->y = reply->old_rect.top;
382         }
383     }
384     SERVER_END_REQ;
385     return ret;
386 }
387
388
389 /*****************************************************************
390  *              SetCaretBlinkTime (USER32.@)
391  */
392 BOOL WINAPI SetCaretBlinkTime( UINT msecs )
393 {
394     TRACE("msecs=%d\n", msecs);
395
396     Caret.timeout = msecs;
397 /*    if (Caret.hwnd) CARET_SetTimer(); FIXME */
398     return TRUE;
399 }
400
401
402 /*****************************************************************
403  *              GetCaretBlinkTime (USER32.@)
404  */
405 UINT WINAPI GetCaretBlinkTime(void)
406 {
407     return Caret.timeout;
408 }