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