Don't issue error message if message number in application range.
[wine] / windows / caret.c
1 /*
2  * Caret functions
3  *
4  * Copyright 1993 David Metcalfe
5  * Copyright 1996 Frans van Dorsselaer
6  * Copyright 2001 Eric Pouech
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "wine/wingdi16.h"
28 #include "wine/winuser16.h"
29 #include "win.h"
30 #include "wine/debug.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(caret);
33
34 typedef struct
35 {
36     HWND     hwnd;
37     UINT     hidden;
38     BOOL     on;
39     INT      x;
40     INT      y;
41     INT      width;
42     INT      height;
43     HBITMAP  hBmp;
44     UINT     timeout;
45     UINT     timerid;
46 } CARET;
47
48 typedef enum
49 {
50     CARET_OFF = 0,
51     CARET_ON,
52     CARET_TOGGLE
53 } DISPLAY_CARET;
54
55 static CARET Caret = { 0, 0, FALSE, 0, 0, 2, 12, 0, 500, 0 };
56
57 /*****************************************************************
58  *              CARET_GetHwnd
59  */
60 HWND CARET_GetHwnd(void)
61 {
62     return Caret.hwnd;
63 }
64
65 /*****************************************************************
66  *              CARET_GetRect
67  */
68 void CARET_GetRect(LPRECT lprc)
69 {
70     lprc->right = (lprc->left = Caret.x) + Caret.width - 1;
71     lprc->bottom = (lprc->top = Caret.y) + Caret.height - 1;
72 }
73
74 /*****************************************************************
75  *               CARET_DisplayCaret
76  */
77 static void CARET_DisplayCaret( DISPLAY_CARET status )
78 {
79     HDC hdc;
80     HDC hCompDC;
81
82     if (Caret.on && (status == CARET_ON)) return;
83     if (!Caret.on && (status == CARET_OFF)) return;
84
85     /* So now it's always a toggle */
86
87     Caret.on = !Caret.on;
88     /* do not use DCX_CACHE here, for x,y,width,height are in logical units */
89     if (!(hdc = GetDCEx( Caret.hwnd, 0, DCX_USESTYLE /*| DCX_CACHE*/ ))) return;
90     hCompDC = CreateCompatibleDC(hdc);
91     if (hCompDC)
92     {
93         HBITMAP hPrevBmp;
94
95         hPrevBmp = SelectObject(hCompDC, Caret.hBmp);
96         BitBlt(hdc, Caret.x, Caret.y, Caret.width, Caret.height, hCompDC, 0, 0, SRCINVERT);
97         SelectObject(hCompDC, hPrevBmp);
98         DeleteDC(hCompDC);
99     }
100     ReleaseDC( Caret.hwnd, hdc );
101 }
102
103
104 /*****************************************************************
105  *               CARET_Callback
106  */
107 static VOID CALLBACK CARET_Callback( HWND hwnd, UINT msg, UINT id, DWORD ctime)
108 {
109     TRACE("hwnd=%04x, timerid=%d, caret=%d\n",
110                   hwnd, id, Caret.on);
111     CARET_DisplayCaret(CARET_TOGGLE);
112 }
113
114
115 /*****************************************************************
116  *               CARET_SetTimer
117  */
118 static void CARET_SetTimer(void)
119 {
120     if (Caret.timerid) KillSystemTimer( (HWND)0, Caret.timerid );
121     Caret.timerid = SetSystemTimer( (HWND)0, 0, Caret.timeout,
122                                       CARET_Callback );
123 }
124
125
126 /*****************************************************************
127  *               CARET_ResetTimer
128  */
129 static void CARET_ResetTimer(void)
130 {
131     if (Caret.timerid)
132     {
133         KillSystemTimer( (HWND)0, Caret.timerid );
134         Caret.timerid = SetSystemTimer( (HWND)0, 0, Caret.timeout,
135                                           CARET_Callback );
136     }
137 }
138
139
140 /*****************************************************************
141  *               CARET_KillTimer
142  */
143 static void CARET_KillTimer(void)
144 {
145     if (Caret.timerid)
146     {
147         KillSystemTimer( (HWND)0, Caret.timerid );
148         Caret.timerid = 0;
149     }
150 }
151
152
153 /*****************************************************************
154  *              CreateCaret (USER32.@)
155  */
156 BOOL WINAPI CreateCaret( HWND hwnd, HBITMAP bitmap,
157                              INT width, INT height )
158 {
159     TRACE("hwnd=%04x\n", hwnd);
160
161     if (!hwnd) return FALSE;
162
163     /* if cursor already exists, destroy it */
164     if (Caret.hwnd) DestroyCaret();
165
166     if (bitmap && (bitmap != 1))
167     {
168         BITMAP bmp;
169         if (!GetObjectA( bitmap, sizeof(bmp), &bmp )) return FALSE;
170         Caret.width = bmp.bmWidth;
171         Caret.height = bmp.bmHeight;
172         bmp.bmBits = NULL;
173         Caret.hBmp = CreateBitmapIndirect(&bmp);
174
175         if (Caret.hBmp)
176         {
177             /* copy the bitmap */
178             LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, bmp.bmWidthBytes * bmp.bmHeight);
179             GetBitmapBits(bitmap, bmp.bmWidthBytes * bmp.bmHeight, buf);
180             SetBitmapBits(Caret.hBmp, bmp.bmWidthBytes * bmp.bmHeight, buf);
181             HeapFree(GetProcessHeap(), 0, buf);
182         }
183     }
184     else
185     {
186         HDC     hdc;
187
188         Caret.width = width ? width : GetSystemMetrics(SM_CXBORDER);
189         Caret.height = height ? height : GetSystemMetrics(SM_CYBORDER);
190         Caret.hBmp = 0;
191
192         /* create the uniform bitmap on the fly */
193         hdc = GetDC(hwnd);
194         if (hdc)
195         {
196             HDC         hMemDC = CreateCompatibleDC(hdc);
197
198             if (hMemDC)
199             {
200                 RECT    r;
201                 r.left = r.top = 0;
202                 r.right = Caret.width;
203                 r.bottom = Caret.height;
204
205                 if ((Caret.hBmp = CreateCompatibleBitmap(hMemDC, Caret.width, Caret.height)))
206                 {
207                     HBITMAP hPrevBmp = SelectObject(hMemDC, Caret.hBmp);
208                     FillRect(hMemDC, &r, (bitmap ? COLOR_GRAYTEXT : COLOR_WINDOW) + 1);
209                     SelectObject(hMemDC, hPrevBmp);
210                 }
211                 DeleteDC(hMemDC);
212             }
213             ReleaseDC(hwnd, hdc);
214         }
215     }
216
217     Caret.hwnd = WIN_GetFullHandle( hwnd );
218     Caret.hidden = 1;
219     Caret.on = FALSE;
220     Caret.x = 0;
221     Caret.y = 0;
222
223     Caret.timeout = GetProfileIntA( "windows", "CursorBlinkRate", 500 );
224     return TRUE;
225 }
226
227
228 /*****************************************************************
229  *              DestroyCaret (USER.164)
230  */
231 void WINAPI DestroyCaret16(void)
232 {
233     DestroyCaret();
234 }
235
236
237 /*****************************************************************
238  *              DestroyCaret (USER32.@)
239  */
240 BOOL WINAPI DestroyCaret(void)
241 {
242     if (!Caret.hwnd) return FALSE;
243
244     TRACE("hwnd=%04x, timerid=%d\n",
245                 Caret.hwnd, Caret.timerid);
246
247     CARET_KillTimer();
248     CARET_DisplayCaret(CARET_OFF);
249     DeleteObject( Caret.hBmp );
250     Caret.hwnd = 0;
251     return TRUE;
252 }
253
254
255 /*****************************************************************
256  *              SetCaretPos (USER.165)
257  */
258 void WINAPI SetCaretPos16( INT16 x, INT16 y )
259 {
260     SetCaretPos( x, y );
261 }
262
263
264 /*****************************************************************
265  *              SetCaretPos (USER32.@)
266  */
267 BOOL WINAPI SetCaretPos( INT x, INT y)
268 {
269     if (!Caret.hwnd) return FALSE;
270     if ((x == Caret.x) && (y == Caret.y)) return TRUE;
271
272     TRACE("x=%d, y=%d\n", x, y);
273
274     CARET_KillTimer();
275     CARET_DisplayCaret(CARET_OFF);
276     Caret.x = x;
277     Caret.y = y;
278     if (!Caret.hidden)
279     {
280         CARET_DisplayCaret(CARET_ON);
281         CARET_SetTimer();
282     }
283     return TRUE;
284 }
285
286
287 /*****************************************************************
288  *              HideCaret (USER32.@)
289  */
290 BOOL WINAPI HideCaret( HWND hwnd )
291 {
292     if (!Caret.hwnd) return FALSE;
293     if (hwnd && (Caret.hwnd != WIN_GetFullHandle(hwnd))) return FALSE;
294
295     TRACE("hwnd=%04x, hidden=%d\n",
296                   hwnd, Caret.hidden);
297
298     CARET_KillTimer();
299     CARET_DisplayCaret(CARET_OFF);
300     Caret.hidden++;
301     return TRUE;
302 }
303
304
305 /*****************************************************************
306  *              ShowCaret (USER32.@)
307  */
308 BOOL WINAPI ShowCaret( HWND hwnd )
309 {
310     if (!Caret.hwnd) return FALSE;
311     if (hwnd && (Caret.hwnd != WIN_GetFullHandle(hwnd))) return FALSE;
312
313     TRACE("hwnd=%04x, hidden=%d\n",
314                 hwnd, Caret.hidden);
315
316     if (Caret.hidden)
317     {
318         Caret.hidden--;
319         if (!Caret.hidden)
320         {
321             CARET_DisplayCaret(CARET_ON);
322             CARET_SetTimer();
323         }
324     }
325     return TRUE;
326 }
327
328
329 /*****************************************************************
330  *              SetCaretBlinkTime (USER.168)
331  */
332 void WINAPI SetCaretBlinkTime16( UINT16 msecs )
333 {
334     SetCaretBlinkTime( msecs );
335 }
336
337 /*****************************************************************
338  *              SetCaretBlinkTime (USER32.@)
339  */
340 BOOL WINAPI SetCaretBlinkTime( UINT msecs )
341 {
342     if (!Caret.hwnd) return FALSE;
343
344     TRACE("hwnd=%04x, msecs=%d\n",
345                 Caret.hwnd, msecs);
346
347     Caret.timeout = msecs;
348     CARET_ResetTimer();
349     return TRUE;
350 }
351
352
353 /*****************************************************************
354  *              GetCaretBlinkTime (USER.169)
355  */
356 UINT16 WINAPI GetCaretBlinkTime16(void)
357 {
358     return (UINT16)GetCaretBlinkTime();
359 }
360
361
362 /*****************************************************************
363  *              GetCaretBlinkTime (USER32.@)
364  */
365 UINT WINAPI GetCaretBlinkTime(void)
366 {
367     return Caret.timeout;
368 }
369
370
371 /*****************************************************************
372  *              GetCaretPos (USER.183)
373  */
374 VOID WINAPI GetCaretPos16( LPPOINT16 pt )
375 {
376     if (!Caret.hwnd || !pt) return;
377
378     TRACE("hwnd=%04x, pt=%p, x=%d, y=%d\n",
379                   Caret.hwnd, pt, Caret.x, Caret.y);
380     pt->x = (INT16)Caret.x;
381     pt->y = (INT16)Caret.y;
382 }
383
384
385 /*****************************************************************
386  *              GetCaretPos (USER32.@)
387  */
388 BOOL WINAPI GetCaretPos( LPPOINT pt )
389 {
390     if (!Caret.hwnd || !pt) return FALSE;
391     pt->x = Caret.x;
392     pt->y = Caret.y;
393     return TRUE;
394 }