Do a LoadLibraryA of WINMM upon ANIMATE_Create and a FreeLibrary upon
[wine] / dlls / comctl32 / status.c
1 /*
2  * Interface code to StatusWindow widget/control
3  *
4  * Copyright 1996 Bruce Milner
5  * Copyright 1998, 1999 Eric Kohl
6  */
7
8 #include "winbase.h"
9 #include "commctrl.h"
10 #include "status.h"
11 #include "debugtools.h"
12
13 DEFAULT_DEBUG_CHANNEL(statusbar)
14
15 /*
16  * Run tests using Waite Group Windows95 API Bible Vol. 1&2
17  * The second cdrom contains executables drawstat.exe,gettext.exe,
18  * simple.exe, getparts.exe, setparts.exe, statwnd.exe
19  */
20
21 /*
22  * Fixme/Todo
23  * 1) Don't hard code bar to bottom of window, allow CCS_TOP also.
24  * 2) Tooltip support (almost done).
25  */
26
27 #define _MAX(a,b) (((a)>(b))?(a):(b))
28 #define _MIN(a,b) (((a)>(b))?(b):(a))
29
30 #define HORZ_BORDER 0
31 #define VERT_BORDER 2
32 #define HORZ_GAP    2
33
34 #define STATUSBAR_GetInfoPtr(hwnd) ((STATUSWINDOWINFO *)GetWindowLongA (hwnd, 0))
35
36
37 static void
38 STATUSBAR_DrawSizeGrip (HDC hdc, LPRECT lpRect)
39 {
40     HPEN hOldPen;
41     POINT pt;
42     INT i;
43
44     pt.x = lpRect->right - 1;
45     pt.y = lpRect->bottom - 1;
46
47     hOldPen = SelectObject (hdc, GetSysColorPen (COLOR_3DFACE));
48     MoveToEx (hdc, pt.x - 12, pt.y, NULL);
49     LineTo (hdc, pt.x, pt.y);
50     LineTo (hdc, pt.x, pt.y - 12);
51
52     pt.x--;
53     pt.y--;
54
55     SelectObject (hdc, GetSysColorPen (COLOR_3DSHADOW));
56     for (i = 1; i < 11; i += 4) {
57         MoveToEx (hdc, pt.x - i, pt.y, NULL);
58         LineTo (hdc, pt.x, pt.y - i);
59
60         MoveToEx (hdc, pt.x - i-1, pt.y, NULL);
61         LineTo (hdc, pt.x, pt.y - i-1);
62     }
63
64     SelectObject (hdc, GetSysColorPen (COLOR_3DHIGHLIGHT));
65     for (i = 3; i < 13; i += 4) {
66         MoveToEx (hdc, pt.x - i, pt.y, NULL);
67         LineTo (hdc, pt.x, pt.y - i);
68     }
69
70     SelectObject (hdc, hOldPen);
71 }
72
73
74 static void 
75 STATUSBAR_DrawPart (HDC hdc, STATUSWINDOWPART *part)
76 {
77     RECT r = part->bound;
78     UINT border = BDR_SUNKENOUTER;
79
80     if (part->style & SBT_POPOUT)
81       border = BDR_RAISEDOUTER;
82     else if (part->style & SBT_NOBORDERS)
83       border = 0;
84
85     DrawEdge(hdc, &r, border, BF_RECT|BF_ADJUST);
86
87     /* draw the icon */
88     if (part->hIcon) {
89         INT cy = r.bottom - r.top;
90
91         r.left += 2;
92         DrawIconEx (hdc, r.left, r.top, part->hIcon, cy, cy, 0, 0, DI_NORMAL);
93         r.left += cy;
94     }
95
96     /* now draw text */
97     if (part->text) {
98       int oldbkmode = SetBkMode(hdc, TRANSPARENT);
99       LPWSTR p = (LPWSTR)part->text;
100       UINT align = DT_LEFT;
101       if (*p == L'\t') {
102         p++;
103         align = DT_CENTER;
104
105         if (*p == L'\t') {
106           p++;
107           align = DT_RIGHT;
108         }
109       }
110       r.left += 3;
111       DrawTextW (hdc, p, lstrlenW (p), &r, align|DT_VCENTER|DT_SINGLELINE);
112       if (oldbkmode != TRANSPARENT)
113         SetBkMode(hdc, oldbkmode);
114     }
115 }
116
117
118 static VOID
119 STATUSBAR_RefreshPart (HWND hwnd, STATUSWINDOWPART *part, HDC hdc)
120 {
121     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (hwnd);
122     HBRUSH hbrBk;
123     HFONT  hOldFont;
124
125     if (!IsWindowVisible (hwnd))
126         return;
127
128     if (self->clrBk != CLR_DEFAULT)
129         hbrBk = CreateSolidBrush (self->clrBk);
130     else
131         hbrBk = GetSysColorBrush (COLOR_3DFACE);
132     FillRect(hdc, &part->bound, hbrBk);
133
134     hOldFont = SelectObject (hdc, self->hFont ? self->hFont : self->hDefaultFont);
135
136     if (part->style & SBT_OWNERDRAW) {
137         DRAWITEMSTRUCT dis;
138
139         dis.CtlID = GetWindowLongA (hwnd, GWL_ID);
140         dis.itemID = -1;
141         dis.hwndItem = hwnd;
142         dis.hDC = hdc;
143         dis.rcItem = part->bound;
144         dis.itemData = (INT)part->text;
145         SendMessageA (GetParent (hwnd), WM_DRAWITEM,
146                 (WPARAM)dis.CtlID, (LPARAM)&dis);
147     }
148     else
149         STATUSBAR_DrawPart (hdc, part);
150
151     SelectObject (hdc, hOldFont);
152
153     if (self->clrBk != CLR_DEFAULT)
154         DeleteObject (hbrBk);
155
156     if (GetWindowLongA (hwnd, GWL_STYLE) & SBARS_SIZEGRIP) {
157         RECT rect;
158
159         GetClientRect (hwnd, &rect);
160         STATUSBAR_DrawSizeGrip (hdc, &rect);
161     }
162 }
163
164
165 static BOOL
166 STATUSBAR_Refresh (HWND hwnd, HDC hdc)
167 {
168     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
169     int      i;
170     RECT   rect;
171     HBRUSH hbrBk;
172     HFONT  hOldFont;
173
174     if (!IsWindowVisible(hwnd))
175         return (TRUE);
176
177     GetClientRect (hwnd, &rect);
178
179     if (infoPtr->clrBk != CLR_DEFAULT)
180         hbrBk = CreateSolidBrush (infoPtr->clrBk);
181     else
182         hbrBk = GetSysColorBrush (COLOR_3DFACE);
183     FillRect(hdc, &rect, hbrBk);
184
185     hOldFont = SelectObject (hdc, infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont);
186
187     if (infoPtr->simple) {
188         STATUSBAR_DrawPart (hdc, &infoPtr->part0);
189     }
190     else {
191         for (i = 0; i < infoPtr->numParts; i++) {
192             if (infoPtr->parts[i].style & SBT_OWNERDRAW) {
193                 DRAWITEMSTRUCT dis;
194
195                 dis.CtlID = GetWindowLongA (hwnd, GWL_ID);
196                 dis.itemID = -1;
197                 dis.hwndItem = hwnd;
198                 dis.hDC = hdc;
199                 dis.rcItem = infoPtr->parts[i].bound;
200                 dis.itemData = (INT)infoPtr->parts[i].text;
201                 SendMessageA (GetParent (hwnd), WM_DRAWITEM,
202                         (WPARAM)dis.CtlID, (LPARAM)&dis);
203             }
204             else
205                 STATUSBAR_DrawPart (hdc, &infoPtr->parts[i]);
206         }
207     }
208
209     SelectObject (hdc, hOldFont);
210
211     if (infoPtr->clrBk != CLR_DEFAULT)
212         DeleteObject (hbrBk);
213
214     if (GetWindowLongA(hwnd, GWL_STYLE) & SBARS_SIZEGRIP)
215         STATUSBAR_DrawSizeGrip (hdc, &rect);
216
217     return TRUE;
218 }
219
220
221 static void
222 STATUSBAR_SetPartBounds (HWND hwnd)
223 {
224     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (hwnd);
225     STATUSWINDOWPART *part;
226     RECT rect, *r;
227     int i;
228
229     /* get our window size */
230     GetClientRect (hwnd, &rect);
231
232     rect.top += VERT_BORDER;
233
234     /* set bounds for simple rectangle */
235     self->part0.bound = rect;
236
237     /* set bounds for non-simple rectangles */
238     for (i = 0; i < self->numParts; i++) {
239         part = &self->parts[i];
240         r = &self->parts[i].bound;
241         r->top = rect.top;
242         r->bottom = rect.bottom;
243         if (i == 0)
244             r->left = 0;
245         else
246             r->left = self->parts[i-1].bound.right + HORZ_GAP;
247         if (part->x == -1)
248             r->right = rect.right;
249         else
250             r->right = part->x;
251
252         if (self->hwndToolTip) {
253             TTTOOLINFOA ti;
254
255             ti.cbSize = sizeof(TTTOOLINFOA);
256             ti.hwnd = hwnd;
257             ti.uId = i;
258             ti.rect = *r;
259             SendMessageA (self->hwndToolTip, TTM_NEWTOOLRECTA,
260                             0, (LPARAM)&ti);
261         }
262     }
263 }
264
265
266 static VOID
267 STATUSBAR_RelayEvent (HWND hwndTip, HWND hwndMsg, UINT uMsg,
268                       WPARAM wParam, LPARAM lParam)
269 {
270     MSG msg;
271
272     msg.hwnd = hwndMsg;
273     msg.message = uMsg;
274     msg.wParam = wParam;
275     msg.lParam = lParam;
276     msg.time = GetMessageTime ();
277     msg.pt.x = LOWORD(GetMessagePos ());
278     msg.pt.y = HIWORD(GetMessagePos ());
279
280     SendMessageA (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
281 }
282
283
284 inline static LRESULT
285 STATUSBAR_GetBorders (LPARAM lParam)
286 {
287     LPINT out = (LPINT) lParam;
288
289     out[0] = HORZ_BORDER; /* horizontal border width */
290     out[1] = VERT_BORDER; /* vertical border width */
291     out[2] = HORZ_GAP; /* width of border between rectangles */
292
293     return TRUE;
294 }
295
296
297 static LRESULT
298 STATUSBAR_GetIcon (HWND hwnd, WPARAM wParam)
299 {
300     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (hwnd);
301     INT nPart;
302
303     nPart = (INT)wParam & 0x00ff;
304     if ((nPart < -1) || (nPart >= self->numParts))
305         return 0;
306
307     if (nPart == -1)
308         return (self->part0.hIcon);
309     else
310         return (self->parts[nPart].hIcon);
311 }
312
313
314 static LRESULT
315 STATUSBAR_GetParts (HWND hwnd, WPARAM wParam, LPARAM lParam)
316 {
317     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
318     LPINT parts;
319     INT   num_parts;
320     INT   i;
321
322     num_parts = (INT) wParam;
323     parts = (LPINT) lParam;
324     if (parts) {
325         return (infoPtr->numParts);
326         for (i = 0; i < num_parts; i++) {
327             parts[i] = infoPtr->parts[i].x;
328         }
329     }
330     return (infoPtr->numParts);
331 }
332
333
334 static LRESULT
335 STATUSBAR_GetRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
336 {
337     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
338     int part_num;
339     LPRECT  rect;
340
341     part_num = ((INT) wParam) & 0x00ff;
342     rect = (LPRECT) lParam;
343     if (infoPtr->simple)
344         *rect = infoPtr->part0.bound;
345     else
346         *rect = infoPtr->parts[part_num].bound;
347     return TRUE;
348 }
349
350
351 static LRESULT
352 STATUSBAR_GetTextA (HWND hwnd, WPARAM wParam, LPARAM lParam)
353 {
354     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (hwnd);
355     STATUSWINDOWPART *part;
356     INT   nPart;
357     LRESULT result;
358
359     nPart = ((INT) wParam) & 0x00ff;
360     if (self->simple)
361         part = &self->part0;
362     else
363         part = &self->parts[nPart];
364
365     if (part->style & SBT_OWNERDRAW)
366         result = (LRESULT)part->text;
367     else {
368         result = part->text ? lstrlenW (part->text) : 0;
369         result |= (part->style << 16);
370         if (lParam && LOWORD(result))
371             lstrcpyWtoA ((LPSTR)lParam, part->text);
372     }
373     return result;
374 }
375
376
377 static LRESULT
378 STATUSBAR_GetTextW (HWND hwnd, WPARAM wParam, LPARAM lParam)
379 {
380     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
381     STATUSWINDOWPART *part;
382     INT   nPart;
383     LRESULT result;
384
385     nPart = ((INT)wParam) & 0x00ff;
386     if (infoPtr->simple)
387         part = &infoPtr->part0;
388     else
389         part = &infoPtr->parts[nPart];
390
391     if (part->style & SBT_OWNERDRAW)
392         result = (LRESULT)part->text;
393     else {
394         result = part->text ? lstrlenW (part->text) : 0;
395         result |= (part->style << 16);
396         if (lParam)
397             lstrcpyW ((LPWSTR)lParam, part->text);
398     }
399     return result;
400 }
401
402
403 static LRESULT
404 STATUSBAR_GetTextLength (HWND hwnd, WPARAM wParam)
405 {
406     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
407     STATUSWINDOWPART *part;
408     INT part_num;
409     DWORD result;
410
411     part_num = ((INT) wParam) & 0x00ff;
412
413     if (infoPtr->simple)
414         part = &infoPtr->part0;
415     else
416         part = &infoPtr->parts[part_num];
417
418     if (part->text)
419         result = lstrlenW(part->text);
420     else
421         result = 0;
422
423     result |= (part->style << 16);
424     return result;
425 }
426
427
428 static LRESULT
429 STATUSBAR_GetTipTextA (HWND hwnd, WPARAM wParam, LPARAM lParam)
430 {
431     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
432
433     if (infoPtr->hwndToolTip) {
434         TTTOOLINFOA ti;
435         ti.cbSize = sizeof(TTTOOLINFOA);
436         ti.hwnd = hwnd;
437         ti.uId = LOWORD(wParam);
438         SendMessageA (infoPtr->hwndToolTip, TTM_GETTEXTA, 0, (LPARAM)&ti);
439
440         if (ti.lpszText)
441             lstrcpynA ((LPSTR)lParam, ti.lpszText, HIWORD(wParam));
442     }
443
444     return 0;
445 }
446
447
448 static LRESULT
449 STATUSBAR_GetTipTextW (HWND hwnd, WPARAM wParam, LPARAM lParam)
450 {
451     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
452
453     if (infoPtr->hwndToolTip) {
454         TTTOOLINFOW ti;
455         ti.cbSize = sizeof(TTTOOLINFOW);
456         ti.hwnd = hwnd;
457         ti.uId = LOWORD(wParam);
458         SendMessageW (infoPtr->hwndToolTip, TTM_GETTEXTW, 0, (LPARAM)&ti);
459
460         if (ti.lpszText)
461             lstrcpynW ((LPWSTR)lParam, ti.lpszText, HIWORD(wParam));
462     }
463
464     return 0;
465 }
466
467
468 inline static LRESULT
469 STATUSBAR_GetUnicodeFormat (HWND hwnd)
470 {
471     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
472     return infoPtr->bUnicode;
473 }
474
475
476 inline static LRESULT
477 STATUSBAR_IsSimple (HWND hwnd)
478 {
479     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
480     return infoPtr->simple;
481 }
482
483
484 static LRESULT
485 STATUSBAR_SetBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
486 {
487     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (hwnd);
488     COLORREF oldBkColor;
489     HDC    hdc;
490
491     oldBkColor = self->clrBk;
492     self->clrBk = (COLORREF)lParam;
493     hdc = GetDC (hwnd);
494     STATUSBAR_Refresh (hwnd, hdc);
495     ReleaseDC (hwnd, hdc);
496
497     return oldBkColor;
498 }
499
500
501 static LRESULT
502 STATUSBAR_SetIcon (HWND hwnd, WPARAM wParam, LPARAM lParam)
503 {
504     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (hwnd);
505     INT nPart = (INT)wParam & 0x00ff;
506     HDC hdc; 
507
508     if ((nPart < -1) || (nPart >= self->numParts))
509         return FALSE;
510
511     hdc = GetDC (hwnd);
512     if (nPart == -1) {
513         self->part0.hIcon = (HICON)lParam;
514         if (self->simple)
515             STATUSBAR_RefreshPart (hwnd, &self->part0, hdc);
516     }
517     else {
518         self->parts[nPart].hIcon = (HICON)lParam;
519         if (!(self->simple))
520             STATUSBAR_RefreshPart (hwnd, &self->parts[nPart], hdc);
521     }
522     ReleaseDC (hwnd, hdc);
523
524     return TRUE;
525 }
526
527
528 static LRESULT
529 STATUSBAR_SetMinHeight (HWND hwnd, WPARAM wParam, LPARAM lParam)
530 {
531     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (hwnd);
532
533     if (IsWindowVisible (hwnd)) {
534         HWND parent = GetParent (hwnd);
535         INT  width, x, y;
536         RECT parent_rect;
537
538         GetClientRect (parent, &parent_rect);
539         self->height = (INT)wParam + VERT_BORDER;
540         width = parent_rect.right - parent_rect.left;
541         x = parent_rect.left;
542         y = parent_rect.bottom - self->height;
543         MoveWindow (hwnd, parent_rect.left,
544                       parent_rect.bottom - self->height,
545                       width, self->height, TRUE);
546         STATUSBAR_SetPartBounds (hwnd);
547     }
548
549     return TRUE;
550 }
551
552
553 static LRESULT
554 STATUSBAR_SetParts (HWND hwnd, WPARAM wParam, LPARAM lParam)
555 {
556     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (hwnd);
557     STATUSWINDOWPART *tmp;
558     HDC hdc;
559     LPINT parts;
560     int i;
561     int oldNumParts;
562
563     if (self->simple)
564         self->simple = FALSE;
565
566     oldNumParts = self->numParts;
567     self->numParts = (INT) wParam;
568     parts = (LPINT) lParam;
569     if (oldNumParts > self->numParts) {
570         for (i = self->numParts ; i < oldNumParts; i++) {
571             if (self->parts[i].text && !(self->parts[i].style & SBT_OWNERDRAW))
572                 COMCTL32_Free (self->parts[i].text);
573         }
574     }
575     else if (oldNumParts < self->numParts) {
576         tmp = COMCTL32_Alloc (sizeof(STATUSWINDOWPART) * self->numParts);
577         for (i = 0; i < oldNumParts; i++) {
578             tmp[i] = self->parts[i];
579         }
580         if (self->parts)
581             COMCTL32_Free (self->parts);
582         self->parts = tmp;
583     }
584     
585     for (i = 0; i < self->numParts; i++) {
586         self->parts[i].x = parts[i];
587     }
588
589     if (self->hwndToolTip) {
590         INT nTipCount =
591             SendMessageA (self->hwndToolTip, TTM_GETTOOLCOUNT, 0, 0);
592
593         if (nTipCount < self->numParts) {
594             /* add tools */
595             TTTOOLINFOA ti;
596             INT i;
597
598             ZeroMemory (&ti, sizeof(TTTOOLINFOA));
599             ti.cbSize = sizeof(TTTOOLINFOA);
600             ti.hwnd = hwnd;
601             for (i = nTipCount; i < self->numParts; i++) {
602                 TRACE("add tool %d\n", i);
603                 ti.uId = i;
604                 SendMessageA (self->hwndToolTip, TTM_ADDTOOLA,
605                                 0, (LPARAM)&ti);
606             }
607         }
608         else if (nTipCount > self->numParts) {
609             /* delete tools */
610             INT i;
611
612             for (i = nTipCount - 1; i >= self->numParts; i--) {
613
614                 FIXME("delete tool %d\n", i);
615
616             }
617         }
618     }
619
620     STATUSBAR_SetPartBounds (hwnd);
621
622     hdc = GetDC (hwnd);
623     STATUSBAR_Refresh (hwnd, hdc);
624     ReleaseDC (hwnd, hdc);
625
626     return TRUE;
627 }
628
629
630 static LRESULT
631 STATUSBAR_SetTextA (HWND hwnd, WPARAM wParam, LPARAM lParam)
632 {
633     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (hwnd);
634     STATUSWINDOWPART *part;
635     int part_num;
636     int style;
637     LPSTR text;
638     int len;
639     HDC hdc;
640
641     text = (LPSTR) lParam;
642     part_num = ((INT) wParam) & 0x00ff;
643     style = ((INT) wParam) & 0xff00;
644
645     if ((self->simple) || (self->parts==NULL) || (part_num==255))
646         part = &self->part0;
647     else
648         part = &self->parts[part_num];
649     if (!part) return FALSE;
650
651     if (!(part->style & SBT_OWNERDRAW) && part->text)
652         COMCTL32_Free (part->text);
653     part->text = 0;
654
655     if (style & SBT_OWNERDRAW) {
656         part->text = (LPWSTR)text;
657     }
658     else {
659         /* duplicate string */
660         if (text && (len = lstrlenA(text))) {
661             part->text = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
662             lstrcpyAtoW (part->text, text);
663         }
664     }
665     part->style = style;
666
667     hdc = GetDC (hwnd);
668     STATUSBAR_RefreshPart (hwnd, part, hdc);
669     ReleaseDC (hwnd, hdc);
670
671     return TRUE;
672 }
673
674
675 static LRESULT
676 STATUSBAR_SetTextW (HWND hwnd, WPARAM wParam, LPARAM lParam)
677 {
678     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (hwnd);
679     STATUSWINDOWPART *part;
680     INT  part_num, style, len;
681     LPWSTR text;
682     HDC  hdc;
683
684     text = (LPWSTR) lParam;
685     part_num = ((INT) wParam) & 0x00ff;
686     style = ((INT) wParam) & 0xff00;
687
688     if ((self->simple) || (self->parts==NULL) || (part_num==255))
689         part = &self->part0;
690     else
691         part = &self->parts[part_num];
692     if (!part) return FALSE;
693
694     if (!(part->style & SBT_OWNERDRAW) && part->text)
695         COMCTL32_Free (part->text);
696     part->text = 0;
697
698     if (style & SBT_OWNERDRAW) {
699         part->text = text;
700     }
701     else {
702         /* duplicate string */
703         if (text && (len = lstrlenW(text))) {
704             part->text = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
705             lstrcpyW(part->text, text);
706         }
707     }
708     part->style = style;
709
710     hdc = GetDC (hwnd);
711     STATUSBAR_RefreshPart (hwnd, part, hdc);
712     ReleaseDC (hwnd, hdc);
713
714     return TRUE;
715 }
716
717
718 static LRESULT
719 STATUSBAR_SetTipTextA (HWND hwnd, WPARAM wParam, LPARAM lParam)
720 {
721     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
722
723     TRACE("part %d: \"%s\"\n", (INT)wParam, (LPSTR)lParam);
724     if (infoPtr->hwndToolTip) {
725         TTTOOLINFOA ti;
726         ti.cbSize = sizeof(TTTOOLINFOA);
727         ti.hwnd = hwnd;
728         ti.uId = (INT)wParam;
729         ti.hinst = 0;
730         ti.lpszText = (LPSTR)lParam;
731         SendMessageA (infoPtr->hwndToolTip, TTM_UPDATETIPTEXTA,
732                         0, (LPARAM)&ti);
733     }
734
735     return 0;
736 }
737
738
739 static LRESULT
740 STATUSBAR_SetTipTextW (HWND hwnd, WPARAM wParam, LPARAM lParam)
741 {
742     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
743
744     TRACE("part %d: \"%s\"\n", (INT)wParam, (LPSTR)lParam);
745     if (infoPtr->hwndToolTip) {
746         TTTOOLINFOW ti;
747         ti.cbSize = sizeof(TTTOOLINFOW);
748         ti.hwnd = hwnd;
749         ti.uId = (INT)wParam;
750         ti.hinst = 0;
751         ti.lpszText = (LPWSTR)lParam;
752         SendMessageW (infoPtr->hwndToolTip, TTM_UPDATETIPTEXTW,
753                         0, (LPARAM)&ti);
754     }
755
756     return 0;
757 }
758
759
760 inline static LRESULT
761 STATUSBAR_SetUnicodeFormat (HWND hwnd, WPARAM wParam)
762 {
763     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
764     BOOL bTemp = infoPtr->bUnicode;
765
766     TRACE("(0x%x)\n", (BOOL)wParam);
767     infoPtr->bUnicode = (BOOL)wParam;
768
769     return bTemp;
770 }
771
772
773 static LRESULT
774 STATUSBAR_Simple (HWND hwnd, WPARAM wParam, LPARAM lParam)
775 {
776     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
777     HDC  hdc;
778     NMHDR  nmhdr;
779
780     infoPtr->simple = (BOOL)wParam;
781
782     /* send notification */
783     nmhdr.hwndFrom = hwnd;
784     nmhdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
785     nmhdr.code = SBN_SIMPLEMODECHANGE;
786     SendMessageA (GetParent (hwnd), WM_NOTIFY, 0, (LPARAM)&nmhdr);
787
788     hdc = GetDC (hwnd);
789     STATUSBAR_Refresh (hwnd, hdc);
790     ReleaseDC (hwnd, hdc);
791
792     return TRUE;
793 }
794
795
796 static LRESULT
797 STATUSBAR_WMCreate (HWND hwnd, WPARAM wParam, LPARAM lParam)
798 {
799     LPCREATESTRUCTA lpCreate = (LPCREATESTRUCTA)lParam;
800     NONCLIENTMETRICSA nclm;
801     RECT        rect;
802     int         width, len;
803     HDC hdc;
804     STATUSWINDOWINFO *self;
805
806     self = (STATUSWINDOWINFO*)COMCTL32_Alloc (sizeof(STATUSWINDOWINFO));
807     SetWindowLongA (hwnd, 0, (DWORD)self);
808
809     self->numParts = 1;
810     self->parts = 0;
811     self->simple = FALSE;
812     self->clrBk = CLR_DEFAULT;
813     self->hFont = 0;
814     GetClientRect (hwnd, &rect);
815
816     nclm.cbSize = sizeof(NONCLIENTMETRICSA);
817     SystemParametersInfoA (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
818     self->hDefaultFont = CreateFontIndirectA (&nclm.lfStatusFont);
819
820     /* initialize simple case */
821     self->part0.bound = rect;
822     self->part0.text = 0;
823     self->part0.x = 0;
824     self->part0.style = 0;
825     self->part0.hIcon = 0;
826
827     /* initialize first part */
828     self->parts = COMCTL32_Alloc (sizeof(STATUSWINDOWPART));
829     self->parts[0].bound = rect;
830     self->parts[0].text = 0;
831     self->parts[0].x = -1;
832     self->parts[0].style = 0;
833     self->parts[0].hIcon = 0;
834
835     if (IsWindowUnicode (hwnd)) {
836         self->bUnicode = TRUE;
837         if (lpCreate->lpszName &&
838             (len = lstrlenW ((LPCWSTR)lpCreate->lpszName))) {
839             self->parts[0].text = COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
840             lstrcpyW (self->parts[0].text, (LPCWSTR)lpCreate->lpszName);
841         }
842     }
843     else {
844         if (lpCreate->lpszName &&
845             (len = lstrlenA ((LPCSTR)lpCreate->lpszName))) {
846             self->parts[0].text = COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
847             lstrcpyAtoW (self->parts[0].text, (LPCSTR)lpCreate->lpszName);
848         }
849     }
850
851     if ((hdc = GetDC (0))) {
852         TEXTMETRICA tm;
853         HFONT hOldFont;
854
855         hOldFont = SelectObject (hdc,self->hDefaultFont);
856         GetTextMetricsA(hdc, &tm);
857         self->textHeight = tm.tmHeight;
858         SelectObject (hdc, hOldFont);
859         ReleaseDC(0, hdc);
860     }
861
862     if (GetWindowLongA (hwnd, GWL_STYLE) & SBT_TOOLTIPS) {
863         self->hwndToolTip =
864             CreateWindowExA (0, TOOLTIPS_CLASSA, NULL, 0,
865                                CW_USEDEFAULT, CW_USEDEFAULT,
866                                CW_USEDEFAULT, CW_USEDEFAULT,
867                              hwnd, 0,
868                              GetWindowLongA (hwnd, GWL_HINSTANCE), NULL);
869
870         if (self->hwndToolTip) {
871             NMTOOLTIPSCREATED nmttc;
872
873             nmttc.hdr.hwndFrom = hwnd;
874             nmttc.hdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
875             nmttc.hdr.code = NM_TOOLTIPSCREATED;
876             nmttc.hwndToolTips = self->hwndToolTip;
877
878             SendMessageA (GetParent (hwnd), WM_NOTIFY,
879                             (WPARAM)nmttc.hdr.idFrom, (LPARAM)&nmttc);
880         }
881     }
882
883     GetClientRect (GetParent (hwnd), &rect);
884     width = rect.right - rect.left;
885     self->height = self->textHeight + 4 + VERT_BORDER;
886     MoveWindow (hwnd, lpCreate->x, lpCreate->y-1,
887                   width, self->height, FALSE);
888     STATUSBAR_SetPartBounds (hwnd);
889
890     return 0;
891 }
892
893
894 static LRESULT
895 STATUSBAR_WMDestroy (HWND hwnd)
896 {
897     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (hwnd);
898     int i;
899
900     for (i = 0; i < self->numParts; i++) {
901         if (self->parts[i].text && !(self->parts[i].style & SBT_OWNERDRAW))
902             COMCTL32_Free (self->parts[i].text);
903     }
904     if (self->part0.text && !(self->part0.style & SBT_OWNERDRAW))
905         COMCTL32_Free (self->part0.text);
906     COMCTL32_Free (self->parts);
907
908     /* delete default font */
909     if (self->hDefaultFont)
910         DeleteObject (self->hDefaultFont);
911
912     /* delete tool tip control */
913     if (self->hwndToolTip)
914         DestroyWindow (self->hwndToolTip);
915
916     COMCTL32_Free (self);
917
918     return 0;
919 }
920
921
922 static inline LRESULT
923 STATUSBAR_WMGetFont (HWND hwnd)
924 {
925     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
926     return infoPtr->hFont;
927 }
928
929
930 static LRESULT
931 STATUSBAR_WMGetText (HWND hwnd, WPARAM wParam, LPARAM lParam)
932 {
933     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
934     INT len;
935
936     if (!(infoPtr->parts[0].text))
937         return 0;
938     len = lstrlenW (infoPtr->parts[0].text);
939     if (wParam > len) {
940         if (infoPtr->bUnicode)
941             lstrcpyW ((LPWSTR)lParam, infoPtr->parts[0].text);
942         else
943             lstrcpyWtoA ((LPSTR)lParam, infoPtr->parts[0].text);
944         return len;
945     }
946
947     return -1;
948 }
949
950
951 inline static LRESULT
952 STATUSBAR_WMMouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
953 {
954     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
955
956     if (infoPtr->hwndToolTip)
957         STATUSBAR_RelayEvent (infoPtr->hwndToolTip, hwnd,
958                               WM_MOUSEMOVE, wParam, lParam);
959     return 0;
960 }
961
962
963 static LRESULT
964 STATUSBAR_WMNCHitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
965 {
966     if (GetWindowLongA (hwnd, GWL_STYLE) & SBARS_SIZEGRIP) {
967         RECT  rect;
968         POINT pt;
969
970         GetClientRect (hwnd, &rect);
971
972         pt.x = (INT)LOWORD(lParam);
973         pt.y = (INT)HIWORD(lParam);
974         ScreenToClient (hwnd, &pt);
975
976         rect.left = rect.right - 13;
977         rect.top += 2;
978
979         if (PtInRect (&rect, pt))
980             return HTBOTTOMRIGHT;
981     }
982
983     return DefWindowProcA (hwnd, WM_NCHITTEST, wParam, lParam);
984 }
985
986
987 static inline LRESULT
988 STATUSBAR_WMNCLButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
989 {
990     PostMessageA (GetParent (hwnd), WM_NCLBUTTONDOWN, wParam, lParam);
991     return 0;
992 }
993
994
995 static inline LRESULT
996 STATUSBAR_WMNCLButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
997 {
998     PostMessageA (GetParent (hwnd), WM_NCLBUTTONUP, wParam, lParam);
999     return 0;
1000 }
1001
1002
1003 static LRESULT
1004 STATUSBAR_WMPaint (HWND hwnd, WPARAM wParam)
1005 {
1006     HDC hdc;
1007     PAINTSTRUCT ps;
1008
1009     hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
1010     STATUSBAR_Refresh (hwnd, hdc);
1011     if (!wParam)
1012         EndPaint (hwnd, &ps);
1013
1014     return 0;
1015 }
1016
1017
1018 static LRESULT
1019 STATUSBAR_WMSetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
1020 {
1021     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
1022
1023     infoPtr->hFont = (HFONT)wParam;
1024     if (LOWORD(lParam) == TRUE) {
1025         HDC hdc = GetDC (hwnd);
1026         STATUSBAR_Refresh (hwnd, hdc);
1027         ReleaseDC (hwnd, hdc);
1028     }
1029
1030     return 0;
1031 }
1032
1033
1034 static LRESULT
1035 STATUSBAR_WMSetText (HWND hwnd, WPARAM wParam, LPARAM lParam)
1036 {
1037     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
1038     STATUSWINDOWPART *part;
1039     int len;
1040     HDC hdc;
1041
1042     if (infoPtr->numParts == 0)
1043         return FALSE;
1044
1045     part = &infoPtr->parts[0];
1046     /* duplicate string */
1047     if (part->text)
1048         COMCTL32_Free (part->text);
1049     part->text = 0;
1050     if (infoPtr->bUnicode) {
1051         if (lParam && (len = lstrlenW((LPCWSTR)lParam))) {
1052             part->text = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
1053             lstrcpyW (part->text, (LPCWSTR)lParam);
1054         }
1055     }
1056     else {
1057         if (lParam && (len = lstrlenA((LPCSTR)lParam))) {
1058             part->text = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
1059             lstrcpyAtoW (part->text, (LPCSTR)lParam);
1060         }
1061     }
1062
1063     hdc = GetDC (hwnd);
1064     STATUSBAR_RefreshPart (hwnd, part, hdc);
1065     ReleaseDC (hwnd, hdc);
1066
1067     return TRUE;
1068 }
1069
1070
1071 static LRESULT
1072 STATUSBAR_WMSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
1073 {
1074     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
1075     INT  width, x, y, flags;
1076     RECT parent_rect;
1077     HWND parent;
1078
1079     /* Need to resize width to match parent */
1080     flags = (INT) wParam;
1081
1082     /* FIXME for flags =
1083      * SIZE_MAXIMIZED, SIZE_MAXSHOW, SIZE_MINIMIZED, SIZE_RESTORED
1084      */
1085
1086     if (flags == SIZE_RESTORED) {
1087         /* width and height don't apply */
1088         parent = GetParent (hwnd);
1089         GetClientRect (parent, &parent_rect);
1090         width = parent_rect.right - parent_rect.left;
1091         x = parent_rect.left;
1092         y = parent_rect.bottom - infoPtr->height;
1093         MoveWindow (hwnd, parent_rect.left, 
1094                       parent_rect.bottom - infoPtr->height,
1095                       width, infoPtr->height, TRUE);
1096         STATUSBAR_SetPartBounds (hwnd);
1097     }
1098     return 0;
1099 }
1100
1101
1102 static LRESULT
1103 STATUSBAR_SendNotify (HWND hwnd, UINT code)
1104 {
1105     NMHDR  nmhdr;
1106
1107     nmhdr.hwndFrom = hwnd;
1108     nmhdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
1109     nmhdr.code = code;
1110     SendMessageA (GetParent (hwnd), WM_NOTIFY, 0, (LPARAM)&nmhdr);
1111     return 0;
1112 }
1113
1114
1115
1116 static LRESULT WINAPI
1117 StatusWindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1118 {
1119     switch (msg) {
1120         case SB_GETBORDERS:
1121             return STATUSBAR_GetBorders (lParam);
1122
1123         case SB_GETICON:
1124             return STATUSBAR_GetIcon (hwnd, wParam);
1125
1126         case SB_GETPARTS:
1127             return STATUSBAR_GetParts (hwnd, wParam, lParam);
1128
1129         case SB_GETRECT:
1130             return STATUSBAR_GetRect (hwnd, wParam, lParam);
1131
1132         case SB_GETTEXTA:
1133             return STATUSBAR_GetTextA (hwnd, wParam, lParam);
1134
1135         case SB_GETTEXTW:
1136             return STATUSBAR_GetTextW (hwnd, wParam, lParam);
1137
1138         case SB_GETTEXTLENGTHA:
1139         case SB_GETTEXTLENGTHW:
1140             return STATUSBAR_GetTextLength (hwnd, wParam);
1141
1142         case SB_GETTIPTEXTA:
1143             return STATUSBAR_GetTipTextA (hwnd, wParam, lParam);
1144
1145         case SB_GETTIPTEXTW:
1146             return STATUSBAR_GetTipTextW (hwnd, wParam, lParam);
1147
1148         case SB_GETUNICODEFORMAT:
1149             return STATUSBAR_GetUnicodeFormat (hwnd);
1150
1151         case SB_ISSIMPLE:
1152             return STATUSBAR_IsSimple (hwnd);
1153
1154         case SB_SETBKCOLOR:
1155             return STATUSBAR_SetBkColor (hwnd, wParam, lParam);
1156
1157         case SB_SETICON:
1158             return STATUSBAR_SetIcon (hwnd, wParam, lParam);
1159
1160         case SB_SETMINHEIGHT:
1161             return STATUSBAR_SetMinHeight (hwnd, wParam, lParam);
1162
1163         case SB_SETPARTS:       
1164             return STATUSBAR_SetParts (hwnd, wParam, lParam);
1165
1166         case SB_SETTEXTA:
1167             return STATUSBAR_SetTextA (hwnd, wParam, lParam);
1168
1169         case SB_SETTEXTW:
1170             return STATUSBAR_SetTextW (hwnd, wParam, lParam);
1171
1172         case SB_SETTIPTEXTA:
1173             return STATUSBAR_SetTipTextA (hwnd, wParam, lParam);
1174
1175         case SB_SETTIPTEXTW:
1176             return STATUSBAR_SetTipTextW (hwnd, wParam, lParam);
1177
1178         case SB_SETUNICODEFORMAT:
1179             return STATUSBAR_SetUnicodeFormat (hwnd, wParam);
1180
1181         case SB_SIMPLE:
1182             return STATUSBAR_Simple (hwnd, wParam, lParam);
1183
1184
1185         case WM_CREATE:
1186             return STATUSBAR_WMCreate (hwnd, wParam, lParam);
1187
1188         case WM_DESTROY:
1189             return STATUSBAR_WMDestroy (hwnd);
1190
1191         case WM_GETFONT:
1192             return STATUSBAR_WMGetFont (hwnd);
1193
1194         case WM_GETTEXT:
1195             return STATUSBAR_WMGetText (hwnd, wParam, lParam);
1196
1197         case WM_GETTEXTLENGTH:
1198             return STATUSBAR_GetTextLength (hwnd, 0);
1199
1200         case WM_LBUTTONDBLCLK:
1201             return STATUSBAR_SendNotify (hwnd, NM_DBLCLK);
1202
1203         case WM_LBUTTONUP:
1204             return STATUSBAR_SendNotify (hwnd, NM_CLICK);
1205
1206         case WM_MOUSEMOVE:
1207             return STATUSBAR_WMMouseMove (hwnd, wParam, lParam);
1208
1209         case WM_NCHITTEST:
1210             return STATUSBAR_WMNCHitTest (hwnd, wParam, lParam);
1211
1212         case WM_NCLBUTTONDOWN:
1213             return STATUSBAR_WMNCLButtonDown (hwnd, wParam, lParam);
1214
1215         case WM_NCLBUTTONUP:
1216             return STATUSBAR_WMNCLButtonUp (hwnd, wParam, lParam);
1217
1218         case WM_PAINT:
1219             return STATUSBAR_WMPaint (hwnd, wParam);
1220
1221         case WM_RBUTTONDBLCLK:
1222             return STATUSBAR_SendNotify (hwnd, NM_RDBLCLK);
1223
1224         case WM_RBUTTONUP:
1225             return STATUSBAR_SendNotify (hwnd, NM_RCLICK);
1226
1227         case WM_SETFONT:
1228             return STATUSBAR_WMSetFont (hwnd, wParam, lParam);
1229
1230         case WM_SETTEXT:
1231             return STATUSBAR_WMSetText (hwnd, wParam, lParam);
1232
1233         case WM_SIZE:
1234             return STATUSBAR_WMSize (hwnd, wParam, lParam);
1235
1236         default:
1237             if (msg >= WM_USER)
1238                 ERR("unknown msg %04x wp=%04x lp=%08lx\n",
1239                      msg, wParam, lParam);
1240             return DefWindowProcA (hwnd, msg, wParam, lParam);
1241     }
1242     return 0;
1243 }
1244
1245
1246 /***********************************************************************
1247  * STATUS_Register [Internal]
1248  *
1249  * Registers the status window class.
1250  */
1251
1252 VOID
1253 STATUS_Register (void)
1254 {
1255     WNDCLASSA wndClass;
1256
1257     ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1258     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_VREDRAW;
1259     wndClass.lpfnWndProc   = (WNDPROC)StatusWindowProc;
1260     wndClass.cbClsExtra    = 0;
1261     wndClass.cbWndExtra    = sizeof(STATUSWINDOWINFO *);
1262     wndClass.hCursor       = LoadCursorA (0, IDC_ARROWA);
1263     wndClass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
1264     wndClass.lpszClassName = STATUSCLASSNAMEA;
1265  
1266     RegisterClassA (&wndClass);
1267 }
1268
1269
1270 /***********************************************************************
1271  * STATUS_Unregister [Internal]
1272  *
1273  * Unregisters the status window class.
1274  */
1275
1276 VOID
1277 STATUS_Unregister (void)
1278 {
1279     UnregisterClassA (STATUSCLASSNAMEA, (HINSTANCE)NULL);
1280 }
1281