Make EDIT_UnlockBuffer cope with destroyed windows.
[wine] / controls / static.c
1 /*
2  * Static control
3  *
4  * Copyright  David W. Metcalfe, 1993
5  *
6  */
7
8 #include "windef.h"
9 #include "wingdi.h"
10 #include "wine/winuser16.h"
11 #include "win.h"
12 #include "cursoricon.h"
13 #include "controls.h"
14 #include "heap.h"
15 #include "user.h"
16 #include "debugtools.h"
17
18 DEFAULT_DEBUG_CHANNEL(static);
19
20 static void STATIC_PaintOwnerDrawfn( WND *wndPtr, HDC hdc );
21 static void STATIC_PaintTextfn( WND *wndPtr, HDC hdc );
22 static void STATIC_PaintRectfn( WND *wndPtr, HDC hdc );
23 static void STATIC_PaintIconfn( WND *wndPtr, HDC hdc );
24 static void STATIC_PaintBitmapfn( WND *wndPtr, HDC hdc );
25 static void STATIC_PaintEtchedfn( WND *wndPtr, HDC hdc );
26 static LRESULT WINAPI StaticWndProcA( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
27 static LRESULT WINAPI StaticWndProcW( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
28
29 static COLORREF color_windowframe, color_background, color_window;
30
31 typedef struct
32 {
33     HFONT16  hFont;   /* Control font (or 0 for system font) */
34     WORD     dummy;   /* Don't know what MS-Windows puts in there */
35     HICON16  hIcon;   /* Icon handle for SS_ICON controls */
36 } STATICINFO;
37
38 typedef void (*pfPaint)( WND *, HDC );
39
40 static pfPaint staticPaintFunc[SS_TYPEMASK+1] =
41 {
42     STATIC_PaintTextfn,      /* SS_LEFT */
43     STATIC_PaintTextfn,      /* SS_CENTER */
44     STATIC_PaintTextfn,      /* SS_RIGHT */
45     STATIC_PaintIconfn,      /* SS_ICON */
46     STATIC_PaintRectfn,      /* SS_BLACKRECT */
47     STATIC_PaintRectfn,      /* SS_GRAYRECT */
48     STATIC_PaintRectfn,      /* SS_WHITERECT */
49     STATIC_PaintRectfn,      /* SS_BLACKFRAME */
50     STATIC_PaintRectfn,      /* SS_GRAYFRAME */
51     STATIC_PaintRectfn,      /* SS_WHITEFRAME */
52     NULL,                    /* Not defined */
53     STATIC_PaintTextfn,      /* SS_SIMPLE */
54     STATIC_PaintTextfn,      /* SS_LEFTNOWORDWRAP */
55     STATIC_PaintOwnerDrawfn, /* SS_OWNERDRAW */
56     STATIC_PaintBitmapfn,    /* SS_BITMAP */
57     NULL,                    /* SS_ENHMETAFILE */
58     STATIC_PaintEtchedfn,    /* SS_ETCHEDHORIZ */
59     STATIC_PaintEtchedfn,    /* SS_ETCHEDVERT */
60     STATIC_PaintEtchedfn,    /* SS_ETCHEDFRAME */
61 };
62
63
64 /*********************************************************************
65  * static class descriptor
66  */
67 const struct builtin_class_descr STATIC_builtin_class =
68 {
69     "Static",            /* name */
70     CS_GLOBALCLASS | CS_DBLCLKS | CS_PARENTDC, /* style  */
71     StaticWndProcA,      /* procA */
72     StaticWndProcW,      /* procW */
73     sizeof(STATICINFO),  /* extra */
74     IDC_ARROWA,          /* cursor */
75     0                    /* brush */
76 };
77
78
79 /***********************************************************************
80  *           STATIC_SetIcon
81  *
82  * Set the icon for an SS_ICON control.
83  */
84 static HICON16 STATIC_SetIcon( WND *wndPtr, HICON16 hicon )
85 {
86     HICON16 prevIcon;
87     STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra;
88     CURSORICONINFO *info = hicon?(CURSORICONINFO *) GlobalLock16( hicon ):NULL;
89
90     if ((wndPtr->dwStyle & SS_TYPEMASK) != SS_ICON) return 0;
91     if (hicon && !info) {
92         ERR("huh? hicon!=0, but info=0???\n");
93         return 0;
94     }
95     prevIcon = infoPtr->hIcon;
96     infoPtr->hIcon = hicon;
97     if (hicon)
98     {
99         SetWindowPos( wndPtr->hwndSelf, 0, 0, 0, info->nWidth, info->nHeight,
100                         SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
101         GlobalUnlock16( hicon );
102     }
103     return prevIcon;
104 }
105
106 /***********************************************************************
107  *           STATIC_SetBitmap
108  *
109  * Set the bitmap for an SS_BITMAP control.
110  */
111 static HBITMAP16 STATIC_SetBitmap( WND *wndPtr, HBITMAP16 hBitmap )
112 {
113     HBITMAP16 hOldBitmap;
114     STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra;
115
116     if ((wndPtr->dwStyle & SS_TYPEMASK) != SS_BITMAP) return 0;
117     if (hBitmap && GetObjectType(hBitmap) != OBJ_BITMAP) {
118         ERR("huh? hBitmap!=0, but not bitmap\n");
119         return 0;
120     }
121     hOldBitmap = infoPtr->hIcon;
122     infoPtr->hIcon = hBitmap;
123     if (hBitmap)
124     {
125         BITMAP bm;
126         GetObjectW(hBitmap, sizeof(bm), &bm);
127         SetWindowPos( wndPtr->hwndSelf, 0, 0, 0, bm.bmWidth, bm.bmHeight,
128                       SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
129     }
130     return hOldBitmap;
131 }
132
133 /***********************************************************************
134  *           STATIC_LoadIconA
135  *
136  * Load the icon for an SS_ICON control.
137  */
138 static HICON STATIC_LoadIconA( WND *wndPtr, LPCSTR name )
139 {
140     HICON hicon = LoadIconA( wndPtr->hInstance, name );
141     if (!hicon) hicon = LoadIconA( 0, name );
142     return hicon;
143 }
144
145 /***********************************************************************
146  *           STATIC_LoadIconW
147  *
148  * Load the icon for an SS_ICON control.
149  */
150 static HICON STATIC_LoadIconW( WND *wndPtr, LPCWSTR name )
151 {
152     HICON hicon = LoadIconW( wndPtr->hInstance, name );
153     if (!hicon) hicon = LoadIconW( 0, name );
154     return hicon;
155 }
156
157 /***********************************************************************
158  *           STATIC_LoadBitmapA
159  *
160  * Load the bitmap for an SS_BITMAP control.
161  */
162 static HBITMAP STATIC_LoadBitmapA( WND *wndPtr, LPCSTR name )
163 {
164     HBITMAP hbitmap = LoadBitmapA( wndPtr->hInstance, name );
165     if (!hbitmap)  /* Try OEM icon (FIXME: is this right?) */
166         hbitmap = LoadBitmapA( 0, name );
167     return hbitmap;
168 }
169
170 /***********************************************************************
171  *           STATIC_LoadBitmapW
172  *
173  * Load the bitmap for an SS_BITMAP control.
174  */
175 static HBITMAP STATIC_LoadBitmapW( WND *wndPtr, LPCWSTR name )
176 {
177     HBITMAP hbitmap = LoadBitmapW( wndPtr->hInstance, name );
178     if (!hbitmap)  /* Try OEM icon (FIXME: is this right?) */
179         hbitmap = LoadBitmapW( 0, name );
180     return hbitmap;
181 }
182
183 /***********************************************************************
184  *           StaticWndProc_locked
185  */
186 static LRESULT StaticWndProc_locked( WND *wndPtr, UINT uMsg, WPARAM wParam,
187                                      LPARAM lParam, BOOL unicode )
188 {
189     LRESULT lResult = 0;
190     LONG style = wndPtr->dwStyle & SS_TYPEMASK;
191     STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra;
192
193     switch (uMsg)
194     {
195     case WM_CREATE:
196         if (style < 0L || style > SS_TYPEMASK)
197         {
198             ERR("Unknown style 0x%02lx\n", style );
199             lResult = -1L;
200             break;
201         }
202         /* initialise colours */
203         color_windowframe  = GetSysColor(COLOR_WINDOWFRAME);
204         color_background   = GetSysColor(COLOR_BACKGROUND);
205         color_window       = GetSysColor(COLOR_WINDOW);
206         break;
207
208     case WM_NCDESTROY:
209         if (style == SS_ICON) {
210 /*
211  * FIXME
212  *           DestroyIcon32( STATIC_SetIcon( wndPtr, 0 ) );
213  * 
214  * We don't want to do this yet because DestroyIcon32 is broken. If the icon
215  * had already been loaded by the application the last thing we want to do is
216  * GlobalFree16 the handle.
217  */
218         } else {
219             lResult = unicode ? DefWindowProcW(wndPtr->hwndSelf, uMsg, wParam, lParam) :
220                                 DefWindowProcA(wndPtr->hwndSelf, uMsg, wParam, lParam);
221         }
222         break;
223
224     case WM_PAINT:
225         {
226             PAINTSTRUCT ps;
227             BeginPaint(wndPtr->hwndSelf, &ps);
228             if (staticPaintFunc[style])
229                 (staticPaintFunc[style])( wndPtr, ps.hdc );
230             EndPaint(wndPtr->hwndSelf, &ps);
231         }
232         break;
233
234     case WM_ENABLE:
235         InvalidateRect(wndPtr->hwndSelf, NULL, FALSE);
236         break;
237
238     case WM_SYSCOLORCHANGE:
239         color_windowframe  = GetSysColor(COLOR_WINDOWFRAME);
240         color_background   = GetSysColor(COLOR_BACKGROUND);
241         color_window       = GetSysColor(COLOR_WINDOW);
242         InvalidateRect(wndPtr->hwndSelf, NULL, TRUE);
243         break;
244
245     case WM_NCCREATE:
246         if ((TWEAK_WineLook > WIN31_LOOK) && (wndPtr->dwStyle & SS_SUNKEN))
247             wndPtr->dwExStyle |= WS_EX_STATICEDGE;
248
249         if(unicode)
250             lParam = (LPARAM)(((LPCREATESTRUCTW)lParam)->lpszName);
251         else
252             lParam = (LPARAM)(((LPCREATESTRUCTA)lParam)->lpszName);
253         /* fall through */
254     case WM_SETTEXT:
255         if (style == SS_ICON)
256         {
257             HICON hIcon;
258             if(unicode)
259                 hIcon = STATIC_LoadIconW(wndPtr, (LPCWSTR)lParam);
260             else
261                 hIcon = STATIC_LoadIconA(wndPtr, (LPCSTR)lParam);
262             /* FIXME : should we also return the previous hIcon here ??? */
263             STATIC_SetIcon(wndPtr, hIcon);
264         }
265         else if (style == SS_BITMAP) 
266         {
267             HBITMAP hBitmap;
268             if(unicode)
269                 hBitmap = STATIC_LoadBitmapW(wndPtr, (LPCWSTR)lParam);
270             else
271                 hBitmap = STATIC_LoadBitmapA(wndPtr, (LPCSTR)lParam);
272             STATIC_SetBitmap(wndPtr, hBitmap);
273         }
274         else if(lParam && HIWORD(lParam))
275         {
276             if(unicode)
277                 DEFWND_SetTextW(wndPtr, (LPCWSTR)lParam);
278             else
279                 DEFWND_SetTextA(wndPtr, (LPCSTR)lParam);
280         }
281         if(uMsg == WM_SETTEXT)
282             InvalidateRect(wndPtr->hwndSelf, NULL, FALSE);
283         lResult = 1; /* success. FIXME: check text length */
284         break;
285
286     case WM_SETFONT:
287         if (style == SS_ICON)
288         {
289             lResult = 0;
290             goto END;
291         }
292         if (style == SS_BITMAP)
293         {
294             lResult = 0;
295             goto END;
296         }
297         infoPtr->hFont = (HFONT16)wParam;
298         if (LOWORD(lParam))
299             InvalidateRect( wndPtr->hwndSelf, NULL, FALSE );
300         break;
301
302     case WM_GETFONT:
303         lResult = infoPtr->hFont;
304         goto END;
305
306     case WM_NCHITTEST:
307         if (wndPtr->dwStyle & SS_NOTIFY)
308            lResult = HTCLIENT;
309         else
310            lResult = HTTRANSPARENT;
311         goto END;
312
313     case WM_GETDLGCODE:
314         lResult = DLGC_STATIC;
315         goto END;
316
317     case STM_GETIMAGE:
318     case STM_GETICON16:
319     case STM_GETICON:
320         lResult = infoPtr->hIcon;
321         goto END;
322
323     case STM_SETIMAGE:
324         switch(wParam) {
325         case IMAGE_BITMAP:
326             lResult = STATIC_SetBitmap( wndPtr, (HBITMAP)lParam );
327             break;
328         case IMAGE_ICON:
329             lResult = STATIC_SetIcon( wndPtr, (HICON16)lParam );
330             break;
331         default:
332             FIXME("STM_SETIMAGE: Unhandled type %x\n", wParam);
333             break;
334         }
335         InvalidateRect( wndPtr->hwndSelf, NULL, FALSE );
336         break;
337
338     case STM_SETICON16:
339     case STM_SETICON:
340         lResult = STATIC_SetIcon( wndPtr, (HICON16)wParam );
341         InvalidateRect( wndPtr->hwndSelf, NULL, FALSE );
342         break;
343
344     default:
345         lResult = unicode ? DefWindowProcW(wndPtr->hwndSelf, uMsg, wParam, lParam) :
346                             DefWindowProcA(wndPtr->hwndSelf, uMsg, wParam, lParam);
347         break;
348     }
349     
350 END:
351     return lResult;
352 }
353
354 /***********************************************************************
355  *           StaticWndProcA
356  */
357 static LRESULT WINAPI StaticWndProcA( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
358 {
359     LRESULT lResult;
360     WND *wndPtr = WIN_FindWndPtr(hWnd);
361
362     lResult = StaticWndProc_locked(wndPtr, uMsg, wParam, lParam, FALSE);
363
364     WIN_ReleaseWndPtr(wndPtr);
365     return lResult;
366 }
367
368 /***********************************************************************
369  *           StaticWndProcW
370  */
371 static LRESULT WINAPI StaticWndProcW( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
372 {
373     LRESULT lResult;
374     WND *wndPtr = WIN_FindWndPtr(hWnd);
375
376     lResult = StaticWndProc_locked(wndPtr, uMsg, wParam, lParam, TRUE);
377
378     WIN_ReleaseWndPtr(wndPtr);
379     return lResult;
380 }
381
382 static void STATIC_PaintOwnerDrawfn( WND *wndPtr, HDC hdc )
383 {
384   DRAWITEMSTRUCT dis;
385
386   dis.CtlType    = ODT_STATIC;
387   dis.CtlID      = wndPtr->wIDmenu;
388   dis.itemID     = 0;
389   dis.itemAction = ODA_DRAWENTIRE;
390   dis.itemState  = 0;
391   dis.hwndItem   = wndPtr->hwndSelf;
392   dis.hDC        = hdc;
393   dis.itemData   = 0;
394   GetClientRect( wndPtr->hwndSelf, &dis.rcItem );
395
396   SendMessageW( GetParent(wndPtr->hwndSelf), WM_CTLCOLORSTATIC, 
397                 hdc, wndPtr->hwndSelf );    
398   SendMessageW( GetParent(wndPtr->hwndSelf), WM_DRAWITEM,
399                 wndPtr->wIDmenu, (LPARAM)&dis );
400 }
401
402 static void STATIC_PaintTextfn( WND *wndPtr, HDC hdc )
403 {
404     RECT rc;
405     HBRUSH hBrush;
406     WORD wFormat;
407
408     LONG style = wndPtr->dwStyle;
409     STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra;
410
411     GetClientRect( wndPtr->hwndSelf, &rc);
412
413     switch (style & SS_TYPEMASK)
414     {
415     case SS_LEFT:
416         wFormat = DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK | DT_NOCLIP;
417         break;
418
419     case SS_CENTER:
420         wFormat = DT_CENTER | DT_EXPANDTABS | DT_WORDBREAK | DT_NOCLIP;
421         break;
422
423     case SS_RIGHT:
424         wFormat = DT_RIGHT | DT_EXPANDTABS | DT_WORDBREAK | DT_NOCLIP;
425         break;
426
427     case SS_SIMPLE:
428         wFormat = DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_NOCLIP;
429         break;
430
431     case SS_LEFTNOWORDWRAP:
432         wFormat = DT_LEFT | DT_EXPANDTABS | DT_VCENTER;
433         break;
434
435     default:
436         return;
437     }
438
439     if (style & SS_NOPREFIX)
440         wFormat |= DT_NOPREFIX;
441
442     if (infoPtr->hFont) SelectObject( hdc, infoPtr->hFont );
443
444     if ((style & SS_NOPREFIX) || ((style & SS_TYPEMASK) != SS_SIMPLE))
445     {
446         hBrush = SendMessageW( GetParent(wndPtr->hwndSelf), WM_CTLCOLORSTATIC,
447                              hdc, wndPtr->hwndSelf );
448         if (!hBrush) hBrush = GetStockObject(WHITE_BRUSH);
449         FillRect( hdc, &rc, hBrush );    
450     }
451     if (!IsWindowEnabled(wndPtr->hwndSelf))
452         SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
453
454     if (wndPtr->text) DrawTextW( hdc, wndPtr->text, -1, &rc, wFormat );
455 }
456
457 static void STATIC_PaintRectfn( WND *wndPtr, HDC hdc )
458 {
459     RECT rc;
460     HBRUSH hBrush;
461
462     GetClientRect( wndPtr->hwndSelf, &rc);
463     
464     switch (wndPtr->dwStyle & SS_TYPEMASK)
465     {
466     case SS_BLACKRECT:
467         hBrush = CreateSolidBrush(color_windowframe);
468         FillRect( hdc, &rc, hBrush );
469         break;
470     case SS_GRAYRECT:
471         hBrush = CreateSolidBrush(color_background);
472         FillRect( hdc, &rc, hBrush );
473         break;
474     case SS_WHITERECT:
475         hBrush = CreateSolidBrush(color_window);
476         FillRect( hdc, &rc, hBrush );
477         break;
478     case SS_BLACKFRAME:
479         hBrush = CreateSolidBrush(color_windowframe);
480         FrameRect( hdc, &rc, hBrush );
481         break;
482     case SS_GRAYFRAME:
483         hBrush = CreateSolidBrush(color_background);
484         FrameRect( hdc, &rc, hBrush );
485         break;
486     case SS_WHITEFRAME:
487         hBrush = CreateSolidBrush(color_window);
488         FrameRect( hdc, &rc, hBrush );
489         break;
490     default:
491         return;
492     }
493     DeleteObject( hBrush );
494 }
495
496
497 static void STATIC_PaintIconfn( WND *wndPtr, HDC hdc )
498 {
499     RECT rc;
500     HBRUSH hbrush;
501     STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra;
502
503     GetClientRect( wndPtr->hwndSelf, &rc );
504     hbrush = SendMessageW( GetParent(wndPtr->hwndSelf), WM_CTLCOLORSTATIC,
505                              hdc, wndPtr->hwndSelf );
506     FillRect( hdc, &rc, hbrush );
507     if (infoPtr->hIcon) DrawIcon( hdc, rc.left, rc.top, infoPtr->hIcon );
508 }
509
510 static void STATIC_PaintBitmapfn(WND *wndPtr, HDC hdc )
511 {
512     RECT rc;
513     HBRUSH hbrush;
514     STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra;
515     HDC hMemDC;
516     HBITMAP oldbitmap;
517
518     GetClientRect( wndPtr->hwndSelf, &rc );
519     hbrush = SendMessageW( GetParent(wndPtr->hwndSelf), WM_CTLCOLORSTATIC,
520                              hdc, wndPtr->hwndSelf );
521     FillRect( hdc, &rc, hbrush );
522
523     if (infoPtr->hIcon) {
524         BITMAP bm;
525         SIZE sz;
526
527         if(GetObjectType(infoPtr->hIcon) != OBJ_BITMAP)
528             return;
529         if (!(hMemDC = CreateCompatibleDC( hdc ))) return;
530         GetObjectW(infoPtr->hIcon, sizeof(bm), &bm);
531         GetBitmapDimensionEx(infoPtr->hIcon, &sz);
532         oldbitmap = SelectObject(hMemDC, infoPtr->hIcon);
533         BitBlt(hdc, sz.cx, sz.cy, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0,
534                SRCCOPY);
535         SelectObject(hMemDC, oldbitmap);
536         DeleteDC(hMemDC);
537     }
538 }
539
540
541 static void STATIC_PaintEtchedfn( WND *wndPtr, HDC hdc )
542 {
543     RECT rc;
544
545     if (TWEAK_WineLook == WIN31_LOOK)
546         return;
547
548     GetClientRect( wndPtr->hwndSelf, &rc );
549     switch (wndPtr->dwStyle & SS_TYPEMASK)
550     {
551         case SS_ETCHEDHORZ:
552             DrawEdge(hdc,&rc,EDGE_ETCHED,BF_TOP|BF_BOTTOM);
553             break;
554         case SS_ETCHEDVERT:
555             DrawEdge(hdc,&rc,EDGE_ETCHED,BF_LEFT|BF_RIGHT);
556             break;
557         case SS_ETCHEDFRAME:
558             DrawEdge (hdc, &rc, EDGE_ETCHED, BF_RECT);
559             break;
560     }
561 }
562