When window class has CS_CLASSDC style we should not remove the DC
[wine] / windows / caret.c
1 /*
2  * Caret functions
3  *
4  * Copyright 1993 David Metcalfe
5  * Copyright 1996 Frans van Dorsselaer
6  */
7
8 #include "wine/wingdi16.h"
9 #include "wine/winuser16.h"
10 #include "module.h"
11 #include "win.h"
12 #include "winuser.h"
13 #include "debugtools.h"
14
15 DEFAULT_DEBUG_CHANNEL(caret)
16
17 typedef struct
18 {
19     HWND     hwnd;
20     UINT     hidden;
21     BOOL     on;
22     INT      x;
23     INT      y;
24     INT      width;
25     INT      height;
26     HBRUSH16   hBrush;
27     UINT     timeout;
28     UINT     timerid;
29 } CARET;
30
31 typedef enum
32 {
33     CARET_OFF = 0,
34     CARET_ON,
35     CARET_TOGGLE
36 } DISPLAY_CARET;
37
38 static CARET Caret = { 0, 0, FALSE, 0, 0, 2, 12, 0, 500, 0 };
39
40 /*****************************************************************
41  *              CARET_GetHwnd
42  */
43 HWND CARET_GetHwnd(void)
44 {
45     return Caret.hwnd;
46 }
47
48 /*****************************************************************
49  *              CARET_GetRect
50  */
51 void CARET_GetRect(LPRECT lprc)
52 {
53     lprc->right = (lprc->left = Caret.x) + Caret.width - 1;
54     lprc->bottom = (lprc->top = Caret.y) + Caret.height - 1;
55 }
56
57 /*****************************************************************
58  *               CARET_DisplayCaret
59  */
60 static void CARET_DisplayCaret( DISPLAY_CARET status )
61 {
62     HDC hdc;
63     HBRUSH16 hPrevBrush;
64
65     if (Caret.on && (status == CARET_ON)) return;
66     if (!Caret.on && (status == CARET_OFF)) return;
67
68     /* So now it's always a toggle */
69
70     Caret.on = !Caret.on;
71     /* do not use DCX_CACHE here, for x,y,width,height are in logical units */
72     if (!(hdc = GetDCEx( Caret.hwnd, 0, DCX_USESTYLE /*| DCX_CACHE*/ ))) return;
73     hPrevBrush = SelectObject( hdc, Caret.hBrush );
74     PatBlt( hdc, Caret.x, Caret.y, Caret.width, Caret.height, PATINVERT );
75     SelectObject( hdc, hPrevBrush );
76     ReleaseDC( Caret.hwnd, hdc );
77 }
78
79   
80 /*****************************************************************
81  *               CARET_Callback
82  */
83 static VOID CALLBACK CARET_Callback( HWND hwnd, UINT msg, UINT id, DWORD ctime)
84 {
85     TRACE("hwnd=%04x, timerid=%d, caret=%d\n",
86                   hwnd, id, Caret.on);
87     CARET_DisplayCaret(CARET_TOGGLE);
88 }
89
90
91 /*****************************************************************
92  *               CARET_SetTimer
93  */
94 static void CARET_SetTimer(void)
95 {
96     if (Caret.timerid) KillSystemTimer( (HWND)0, Caret.timerid );
97     Caret.timerid = SetSystemTimer( (HWND)0, 0, Caret.timeout,
98                                       CARET_Callback );
99 }
100
101
102 /*****************************************************************
103  *               CARET_ResetTimer
104  */
105 static void CARET_ResetTimer(void)
106 {
107     if (Caret.timerid) 
108     {
109         KillSystemTimer( (HWND)0, Caret.timerid );
110         Caret.timerid = SetSystemTimer( (HWND)0, 0, Caret.timeout,
111                                           CARET_Callback );
112     }
113 }
114
115
116 /*****************************************************************
117  *               CARET_KillTimer
118  */
119 static void CARET_KillTimer(void)
120 {
121     if (Caret.timerid) 
122     {
123         KillSystemTimer( (HWND)0, Caret.timerid );
124         Caret.timerid = 0;
125     }
126 }
127
128
129 /*****************************************************************
130  *           CreateCaret16   (USER.163)
131  */
132 void WINAPI CreateCaret16( HWND16 hwnd, HBITMAP16 bitmap,
133                            INT16 width, INT16 height )
134 {
135     CreateCaret( hwnd, bitmap, width, height );
136 }
137
138 /*****************************************************************
139  *           CreateCaret32   (USER32.66)
140  */
141 BOOL WINAPI CreateCaret( HWND hwnd, HBITMAP bitmap,
142                              INT width, INT height )
143 {
144     TRACE("hwnd=%04x\n", hwnd);
145
146     if (!hwnd) return FALSE;
147
148     /* if cursor already exists, destroy it */
149     if (Caret.hwnd) DestroyCaret();
150
151     if (bitmap && (bitmap != 1))
152     {
153         BITMAP16 bmp;
154         if (!GetObject16( bitmap, sizeof(bmp), &bmp )) return FALSE;
155         Caret.width = bmp.bmWidth;
156         Caret.height = bmp.bmHeight;
157         /* FIXME: we should make a copy of the bitmap instead of a brush */
158         Caret.hBrush = CreatePatternBrush( bitmap );
159     }
160     else
161     {
162         Caret.width = width ? width : GetSystemMetrics(SM_CXBORDER);
163         Caret.height = height ? height : GetSystemMetrics(SM_CYBORDER);
164         Caret.hBrush = CreateSolidBrush(bitmap ?
165                                           GetSysColor(COLOR_GRAYTEXT) :
166                                           GetSysColor(COLOR_WINDOW) );
167     }
168
169     Caret.hwnd = hwnd;
170     Caret.hidden = 1;
171     Caret.on = FALSE;
172     Caret.x = 0;
173     Caret.y = 0;
174
175     Caret.timeout = GetProfileIntA( "windows", "CursorBlinkRate", 500 );
176     return TRUE;
177 }
178    
179
180 /*****************************************************************
181  *           DestroyCaret16   (USER.164)
182  */
183 void WINAPI DestroyCaret16(void)
184 {
185     DestroyCaret();
186 }
187
188
189 /*****************************************************************
190  *           DestroyCaret32   (USER32.131)
191  */
192 BOOL WINAPI DestroyCaret(void)
193 {
194     if (!Caret.hwnd) return FALSE;
195
196     TRACE("hwnd=%04x, timerid=%d\n",
197                 Caret.hwnd, Caret.timerid);
198
199     CARET_KillTimer();
200     CARET_DisplayCaret(CARET_OFF);
201     DeleteObject( Caret.hBrush );
202     Caret.hwnd = 0;
203     return TRUE;
204 }
205
206
207 /*****************************************************************
208  *           SetCaretPos16   (USER.165)
209  */
210 void WINAPI SetCaretPos16( INT16 x, INT16 y )
211 {
212     SetCaretPos( x, y );
213 }
214
215
216 /*****************************************************************
217  *           SetCaretPos32   (USER32.466)
218  */
219 BOOL WINAPI SetCaretPos( INT x, INT y)
220 {
221     if (!Caret.hwnd) return FALSE;
222     if ((x == Caret.x) && (y == Caret.y)) return TRUE;
223
224     TRACE("x=%d, y=%d\n", x, y);
225
226     CARET_KillTimer();
227     CARET_DisplayCaret(CARET_OFF);
228     Caret.x = x;
229     Caret.y = y;
230     if (!Caret.hidden)
231     {
232         CARET_DisplayCaret(CARET_ON);
233         CARET_SetTimer();
234     }
235     return TRUE;
236 }
237
238
239 /*****************************************************************
240  *           HideCaret16   (USER.166)
241  */
242 void WINAPI HideCaret16( HWND16 hwnd )
243 {
244     HideCaret( hwnd );
245 }
246
247
248 /*****************************************************************
249  *           HideCaret32   (USER32.317)
250  */
251 BOOL WINAPI HideCaret( HWND hwnd )
252 {
253     if (!Caret.hwnd) return FALSE;
254     if (hwnd && (Caret.hwnd != hwnd)) return FALSE;
255
256     TRACE("hwnd=%04x, hidden=%d\n",
257                   hwnd, Caret.hidden);
258
259     CARET_KillTimer();
260     CARET_DisplayCaret(CARET_OFF);
261     Caret.hidden++;
262     return TRUE;
263 }
264
265
266 /*****************************************************************
267  *           ShowCaret16   (USER.167)
268  */
269 void WINAPI ShowCaret16( HWND16 hwnd )
270 {
271     ShowCaret( hwnd );
272 }
273
274
275 /*****************************************************************
276  *           ShowCaret32   (USER32.529)
277  */
278 BOOL WINAPI ShowCaret( HWND hwnd )
279 {
280     if (!Caret.hwnd) return FALSE;
281     if (hwnd && (Caret.hwnd != hwnd)) return FALSE;
282
283     TRACE("hwnd=%04x, hidden=%d\n",
284                 hwnd, Caret.hidden);
285
286     if (Caret.hidden)
287     {
288         Caret.hidden--;
289         if (!Caret.hidden)
290         {
291             CARET_DisplayCaret(CARET_ON);
292             CARET_SetTimer();
293         }
294     }
295     return TRUE;
296 }
297
298
299 /*****************************************************************
300  *           SetCaretBlinkTime16   (USER.168)
301  */
302 void WINAPI SetCaretBlinkTime16( UINT16 msecs )
303 {
304     SetCaretBlinkTime( msecs );
305 }
306
307 /*****************************************************************
308  *           SetCaretBlinkTime32   (USER32.465)
309  */
310 BOOL WINAPI SetCaretBlinkTime( UINT msecs )
311 {
312     if (!Caret.hwnd) return FALSE;
313
314     TRACE("hwnd=%04x, msecs=%d\n",
315                 Caret.hwnd, msecs);
316
317     Caret.timeout = msecs;
318     CARET_ResetTimer();
319     return TRUE;
320 }
321
322
323 /*****************************************************************
324  *           GetCaretBlinkTime16   (USER.169)
325  */
326 UINT16 WINAPI GetCaretBlinkTime16(void)
327 {
328     return (UINT16)GetCaretBlinkTime();
329 }
330
331
332 /*****************************************************************
333  *           GetCaretBlinkTime32   (USER32.209)
334  */
335 UINT WINAPI GetCaretBlinkTime(void)
336 {
337     return Caret.timeout;
338 }
339
340
341 /*****************************************************************
342  *           GetCaretPos16   (USER.183)
343  */
344 VOID WINAPI GetCaretPos16( LPPOINT16 pt )
345 {
346     if (!Caret.hwnd || !pt) return;
347
348     TRACE("hwnd=%04x, pt=%p, x=%d, y=%d\n",
349                   Caret.hwnd, pt, Caret.x, Caret.y);
350     pt->x = (INT16)Caret.x;
351     pt->y = (INT16)Caret.y;
352 }
353
354
355 /*****************************************************************
356  *           GetCaretPos32   (USER32.210)
357  */
358 BOOL WINAPI GetCaretPos( LPPOINT pt )
359 {
360     if (!Caret.hwnd || !pt) return FALSE;
361     pt->x = Caret.x;
362     pt->y = Caret.y;
363     return TRUE;
364 }