Converted to the new debugging interface (done with the help of the
[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 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 (statusbar, "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 (statusbar, "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     part->style = style;
651     if (style == SBT_OWNERDRAW) {
652         part->text = (LPWSTR)text;
653     }
654     else {
655         /* duplicate string */
656         if (part->text)
657             COMCTL32_Free (part->text);
658         part->text = 0;
659         if (text && (len = lstrlenA(text))) {
660             part->text = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
661             lstrcpyAtoW (part->text, text);
662         }
663     }
664
665     hdc = GetDC (hwnd);
666     STATUSBAR_RefreshPart (hwnd, part, hdc);
667     ReleaseDC (hwnd, hdc);
668
669     return TRUE;
670 }
671
672
673 static LRESULT
674 STATUSBAR_SetTextW (HWND hwnd, WPARAM wParam, LPARAM lParam)
675 {
676     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (hwnd);
677     STATUSWINDOWPART *part;
678     INT  part_num, style, len;
679     LPWSTR text;
680     HDC  hdc;
681
682     text = (LPWSTR) lParam;
683     part_num = ((INT) wParam) & 0x00ff;
684     style = ((INT) wParam) & 0xff00;
685
686     if ((self->simple) || (self->parts==NULL) || (part_num==255))
687         part = &self->part0;
688     else
689         part = &self->parts[part_num];
690     if (!part) return FALSE;
691     part->style = style;
692     if (style == SBT_OWNERDRAW) {
693         part->text = text;
694     }
695     else {
696         /* duplicate string */
697         if (part->text)
698             COMCTL32_Free (part->text);
699         part->text = 0;
700         if (text && (len = lstrlenW(text))) {
701             part->text = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
702             lstrcpyW(part->text, text);
703         }
704     }
705
706     hdc = GetDC (hwnd);
707     STATUSBAR_RefreshPart (hwnd, part, hdc);
708     ReleaseDC (hwnd, hdc);
709
710     return TRUE;
711 }
712
713
714 static LRESULT
715 STATUSBAR_SetTipTextA (HWND hwnd, WPARAM wParam, LPARAM lParam)
716 {
717     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
718
719     TRACE (statusbar, "part %d: \"%s\"\n", (INT)wParam, (LPSTR)lParam);
720     if (infoPtr->hwndToolTip) {
721         TTTOOLINFOA ti;
722         ti.cbSize = sizeof(TTTOOLINFOA);
723         ti.hwnd = hwnd;
724         ti.uId = (INT)wParam;
725         ti.hinst = 0;
726         ti.lpszText = (LPSTR)lParam;
727         SendMessageA (infoPtr->hwndToolTip, TTM_UPDATETIPTEXTA,
728                         0, (LPARAM)&ti);
729     }
730
731     return 0;
732 }
733
734
735 static LRESULT
736 STATUSBAR_SetTipTextW (HWND hwnd, WPARAM wParam, LPARAM lParam)
737 {
738     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
739
740     TRACE (statusbar, "part %d: \"%s\"\n", (INT)wParam, (LPSTR)lParam);
741     if (infoPtr->hwndToolTip) {
742         TTTOOLINFOW ti;
743         ti.cbSize = sizeof(TTTOOLINFOW);
744         ti.hwnd = hwnd;
745         ti.uId = (INT)wParam;
746         ti.hinst = 0;
747         ti.lpszText = (LPWSTR)lParam;
748         SendMessageW (infoPtr->hwndToolTip, TTM_UPDATETIPTEXTW,
749                         0, (LPARAM)&ti);
750     }
751
752     return 0;
753 }
754
755
756 __inline__ static LRESULT
757 STATUSBAR_SetUnicodeFormat (HWND hwnd, WPARAM wParam)
758 {
759     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
760     BOOL bTemp = infoPtr->bUnicode;
761
762     TRACE (statusbar, "(0x%x)\n", (BOOL)wParam);
763     infoPtr->bUnicode = (BOOL)wParam;
764
765     return bTemp;
766 }
767
768
769 static LRESULT
770 STATUSBAR_Simple (HWND hwnd, WPARAM wParam, LPARAM lParam)
771 {
772     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
773     HDC  hdc;
774     NMHDR  nmhdr;
775
776     infoPtr->simple = (BOOL)wParam;
777
778     /* send notification */
779     nmhdr.hwndFrom = hwnd;
780     nmhdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
781     nmhdr.code = SBN_SIMPLEMODECHANGE;
782     SendMessageA (GetParent (hwnd), WM_NOTIFY, 0, (LPARAM)&nmhdr);
783
784     hdc = GetDC (hwnd);
785     STATUSBAR_Refresh (hwnd, hdc);
786     ReleaseDC (hwnd, hdc);
787
788     return TRUE;
789 }
790
791
792 static LRESULT
793 STATUSBAR_WMCreate (HWND hwnd, WPARAM wParam, LPARAM lParam)
794 {
795     LPCREATESTRUCTA lpCreate = (LPCREATESTRUCTA)lParam;
796     NONCLIENTMETRICSA nclm;
797     RECT        rect;
798     int         width, len;
799     HDC hdc;
800     STATUSWINDOWINFO *self;
801
802     self = (STATUSWINDOWINFO*)COMCTL32_Alloc (sizeof(STATUSWINDOWINFO));
803     SetWindowLongA (hwnd, 0, (DWORD)self);
804
805     self->numParts = 1;
806     self->parts = 0;
807     self->simple = FALSE;
808     self->clrBk = CLR_DEFAULT;
809     self->hFont = 0;
810     GetClientRect (hwnd, &rect);
811
812     nclm.cbSize = sizeof(NONCLIENTMETRICSA);
813     SystemParametersInfoA (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
814     self->hDefaultFont = CreateFontIndirectA (&nclm.lfStatusFont);
815
816     /* initialize simple case */
817     self->part0.bound = rect;
818     self->part0.text = 0;
819     self->part0.x = 0;
820     self->part0.style = 0;
821     self->part0.hIcon = 0;
822
823     /* initialize first part */
824     self->parts = COMCTL32_Alloc (sizeof(STATUSWINDOWPART));
825     self->parts[0].bound = rect;
826     self->parts[0].text = 0;
827     self->parts[0].x = -1;
828     self->parts[0].style = 0;
829     self->parts[0].hIcon = 0;
830
831     if (IsWindowUnicode (hwnd)) {
832         self->bUnicode = TRUE;
833         if ((len = lstrlenW ((LPCWSTR)lpCreate->lpszName))) {
834             self->parts[0].text = COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
835             lstrcpyW (self->parts[0].text, (LPCWSTR)lpCreate->lpszName);
836         }
837     }
838     else {
839         if ((len = lstrlenA ((LPCSTR)lpCreate->lpszName))) {
840             self->parts[0].text = COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
841             lstrcpyAtoW (self->parts[0].text, (LPCSTR)lpCreate->lpszName);
842         }
843     }
844
845     if ((hdc = GetDC (0))) {
846         TEXTMETRICA tm;
847         HFONT hOldFont;
848
849         hOldFont = SelectObject (hdc,self->hDefaultFont);
850         GetTextMetricsA(hdc, &tm);
851         self->textHeight = tm.tmHeight;
852         SelectObject (hdc, hOldFont);
853         ReleaseDC(0, hdc);
854     }
855
856     if (GetWindowLongA (hwnd, GWL_STYLE) & SBT_TOOLTIPS) {
857         self->hwndToolTip =
858             CreateWindowExA (0, TOOLTIPS_CLASSA, NULL, 0,
859                                CW_USEDEFAULT, CW_USEDEFAULT,
860                                CW_USEDEFAULT, CW_USEDEFAULT,
861                              hwnd, 0,
862                              GetWindowLongA (hwnd, GWL_HINSTANCE), NULL);
863
864         if (self->hwndToolTip) {
865             NMTOOLTIPSCREATED nmttc;
866
867             nmttc.hdr.hwndFrom = hwnd;
868             nmttc.hdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
869             nmttc.hdr.code = NM_TOOLTIPSCREATED;
870             nmttc.hwndToolTips = self->hwndToolTip;
871
872             SendMessageA (GetParent (hwnd), WM_NOTIFY,
873                             (WPARAM)nmttc.hdr.idFrom, (LPARAM)&nmttc);
874         }
875     }
876
877     GetClientRect (GetParent (hwnd), &rect);
878     width = rect.right - rect.left;
879     self->height = self->textHeight + 4 + VERT_BORDER;
880     MoveWindow (hwnd, lpCreate->x, lpCreate->y-1,
881                   width, self->height, FALSE);
882     STATUSBAR_SetPartBounds (hwnd);
883
884     return 0;
885 }
886
887
888 static LRESULT
889 STATUSBAR_WMDestroy (HWND hwnd)
890 {
891     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (hwnd);
892     int i;
893
894     for (i = 0; i < self->numParts; i++) {
895         if (self->parts[i].text && (self->parts[i].style != SBT_OWNERDRAW))
896             COMCTL32_Free (self->parts[i].text);
897     }
898     if (self->part0.text && (self->part0.style != SBT_OWNERDRAW))
899         COMCTL32_Free (self->part0.text);
900     COMCTL32_Free (self->parts);
901
902     /* delete default font */
903     if (self->hDefaultFont)
904         DeleteObject (self->hDefaultFont);
905
906     /* delete tool tip control */
907     if (self->hwndToolTip)
908         DestroyWindow (self->hwndToolTip);
909
910     COMCTL32_Free (self);
911
912     return 0;
913 }
914
915
916 static __inline__ LRESULT
917 STATUSBAR_WMGetFont (HWND hwnd)
918 {
919     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
920     return infoPtr->hFont;
921 }
922
923
924 static LRESULT
925 STATUSBAR_WMGetText (HWND hwnd, WPARAM wParam, LPARAM lParam)
926 {
927     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
928     INT len;
929
930     if (!(infoPtr->parts[0].text))
931         return 0;
932     len = lstrlenW (infoPtr->parts[0].text);
933     if (wParam > len) {
934         if (infoPtr->bUnicode)
935             lstrcpyW ((LPWSTR)lParam, infoPtr->parts[0].text);
936         else
937             lstrcpyWtoA ((LPSTR)lParam, infoPtr->parts[0].text);
938         return len;
939     }
940
941     return -1;
942 }
943
944
945 __inline__ static LRESULT
946 STATUSBAR_WMMouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
947 {
948     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
949
950     if (infoPtr->hwndToolTip)
951         STATUSBAR_RelayEvent (infoPtr->hwndToolTip, hwnd,
952                               WM_MOUSEMOVE, wParam, lParam);
953     return 0;
954 }
955
956
957 static LRESULT
958 STATUSBAR_WMNCHitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
959 {
960     if (GetWindowLongA (hwnd, GWL_STYLE) & SBARS_SIZEGRIP) {
961         RECT  rect;
962         POINT pt;
963
964         GetClientRect (hwnd, &rect);
965
966         pt.x = (INT)LOWORD(lParam);
967         pt.y = (INT)HIWORD(lParam);
968         ScreenToClient (hwnd, &pt);
969
970         rect.left = rect.right - 13;
971         rect.top += 2;
972
973         if (PtInRect (&rect, pt))
974             return HTBOTTOMRIGHT;
975     }
976
977     return DefWindowProcA (hwnd, WM_NCHITTEST, wParam, lParam);
978 }
979
980
981 static __inline__ LRESULT
982 STATUSBAR_WMNCLButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
983 {
984     PostMessageA (GetParent (hwnd), WM_NCLBUTTONDOWN, wParam, lParam);
985     return 0;
986 }
987
988
989 static __inline__ LRESULT
990 STATUSBAR_WMNCLButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
991 {
992     PostMessageA (GetParent (hwnd), WM_NCLBUTTONUP, wParam, lParam);
993     return 0;
994 }
995
996
997 static LRESULT
998 STATUSBAR_WMPaint (HWND hwnd, WPARAM wParam)
999 {
1000     HDC hdc;
1001     PAINTSTRUCT ps;
1002
1003     hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
1004     STATUSBAR_Refresh (hwnd, hdc);
1005     if (!wParam)
1006         EndPaint (hwnd, &ps);
1007
1008     return 0;
1009 }
1010
1011
1012 static LRESULT
1013 STATUSBAR_WMSetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
1014 {
1015     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
1016
1017     infoPtr->hFont = (HFONT)wParam;
1018     if (LOWORD(lParam) == TRUE) {
1019         HDC hdc = GetDC (hwnd);
1020         STATUSBAR_Refresh (hwnd, hdc);
1021         ReleaseDC (hwnd, hdc);
1022     }
1023
1024     return 0;
1025 }
1026
1027
1028 static LRESULT
1029 STATUSBAR_WMSetText (HWND hwnd, WPARAM wParam, LPARAM lParam)
1030 {
1031     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
1032     STATUSWINDOWPART *part;
1033     int len;
1034     HDC hdc;
1035
1036     if (infoPtr->numParts == 0)
1037         return FALSE;
1038
1039     part = &infoPtr->parts[0];
1040     /* duplicate string */
1041     if (part->text)
1042         COMCTL32_Free (part->text);
1043     part->text = 0;
1044     if (infoPtr->bUnicode) {
1045         if (lParam && (len = lstrlenW((LPCWSTR)lParam))) {
1046             part->text = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
1047             lstrcpyW (part->text, (LPCWSTR)lParam);
1048         }
1049     }
1050     else {
1051         if (lParam && (len = lstrlenA((LPCSTR)lParam))) {
1052             part->text = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
1053             lstrcpyAtoW (part->text, (LPCSTR)lParam);
1054         }
1055     }
1056
1057     hdc = GetDC (hwnd);
1058     STATUSBAR_RefreshPart (hwnd, part, hdc);
1059     ReleaseDC (hwnd, hdc);
1060
1061     return TRUE;
1062 }
1063
1064
1065 static LRESULT
1066 STATUSBAR_WMSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
1067 {
1068     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (hwnd);
1069     INT  width, x, y, flags;
1070     RECT parent_rect;
1071     HWND parent;
1072
1073     /* Need to resize width to match parent */
1074     flags = (INT) wParam;
1075
1076     /* FIXME for flags =
1077      * SIZE_MAXIMIZED, SIZE_MAXSHOW, SIZE_MINIMIZED, SIZE_RESTORED
1078      */
1079
1080     if (flags == SIZE_RESTORED) {
1081         /* width and height don't apply */
1082         parent = GetParent (hwnd);
1083         GetClientRect (parent, &parent_rect);
1084         width = parent_rect.right - parent_rect.left;
1085         x = parent_rect.left;
1086         y = parent_rect.bottom - infoPtr->height;
1087         MoveWindow (hwnd, parent_rect.left, 
1088                       parent_rect.bottom - infoPtr->height,
1089                       width, infoPtr->height, TRUE);
1090         STATUSBAR_SetPartBounds (hwnd);
1091     }
1092     return 0;
1093 }
1094
1095
1096 static LRESULT
1097 STATUSBAR_SendNotify (HWND hwnd, UINT code)
1098 {
1099     NMHDR  nmhdr;
1100
1101     nmhdr.hwndFrom = hwnd;
1102     nmhdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
1103     nmhdr.code = code;
1104     SendMessageA (GetParent (hwnd), WM_NOTIFY, 0, (LPARAM)&nmhdr);
1105     return 0;
1106 }
1107
1108
1109
1110 LRESULT WINAPI
1111 StatusWindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1112 {
1113     switch (msg) {
1114         case SB_GETBORDERS:
1115             return STATUSBAR_GetBorders (lParam);
1116
1117         case SB_GETICON:
1118             return STATUSBAR_GetIcon (hwnd, wParam);
1119
1120         case SB_GETPARTS:
1121             return STATUSBAR_GetParts (hwnd, wParam, lParam);
1122
1123         case SB_GETRECT:
1124             return STATUSBAR_GetRect (hwnd, wParam, lParam);
1125
1126         case SB_GETTEXTA:
1127             return STATUSBAR_GetTextA (hwnd, wParam, lParam);
1128
1129         case SB_GETTEXTW:
1130             return STATUSBAR_GetTextW (hwnd, wParam, lParam);
1131
1132         case SB_GETTEXTLENGTHA:
1133         case SB_GETTEXTLENGTHW:
1134             return STATUSBAR_GetTextLength (hwnd, wParam);
1135
1136         case SB_GETTIPTEXTA:
1137             return STATUSBAR_GetTipTextA (hwnd, wParam, lParam);
1138
1139         case SB_GETTIPTEXTW:
1140             return STATUSBAR_GetTipTextW (hwnd, wParam, lParam);
1141
1142         case SB_GETUNICODEFORMAT:
1143             return STATUSBAR_GetUnicodeFormat (hwnd);
1144
1145         case SB_ISSIMPLE:
1146             return STATUSBAR_IsSimple (hwnd);
1147
1148         case SB_SETBKCOLOR:
1149             return STATUSBAR_SetBkColor (hwnd, wParam, lParam);
1150
1151         case SB_SETICON:
1152             return STATUSBAR_SetIcon (hwnd, wParam, lParam);
1153
1154         case SB_SETMINHEIGHT:
1155             return STATUSBAR_SetMinHeight (hwnd, wParam, lParam);
1156
1157         case SB_SETPARTS:       
1158             return STATUSBAR_SetParts (hwnd, wParam, lParam);
1159
1160         case SB_SETTEXTA:
1161             return STATUSBAR_SetTextA (hwnd, wParam, lParam);
1162
1163         case SB_SETTEXTW:
1164             return STATUSBAR_SetTextW (hwnd, wParam, lParam);
1165
1166         case SB_SETTIPTEXTA:
1167             return STATUSBAR_SetTipTextA (hwnd, wParam, lParam);
1168
1169         case SB_SETTIPTEXTW:
1170             return STATUSBAR_SetTipTextW (hwnd, wParam, lParam);
1171
1172         case SB_SETUNICODEFORMAT:
1173             return STATUSBAR_SetUnicodeFormat (hwnd, wParam);
1174
1175         case SB_SIMPLE:
1176             return STATUSBAR_Simple (hwnd, wParam, lParam);
1177
1178
1179         case WM_CREATE:
1180             return STATUSBAR_WMCreate (hwnd, wParam, lParam);
1181
1182         case WM_DESTROY:
1183             return STATUSBAR_WMDestroy (hwnd);
1184
1185         case WM_GETFONT:
1186             return STATUSBAR_WMGetFont (hwnd);
1187
1188         case WM_GETTEXT:
1189             return STATUSBAR_WMGetText (hwnd, wParam, lParam);
1190
1191         case WM_GETTEXTLENGTH:
1192             return STATUSBAR_GetTextLength (hwnd, 0);
1193
1194         case WM_LBUTTONDBLCLK:
1195             return STATUSBAR_SendNotify (hwnd, NM_DBLCLK);
1196
1197         case WM_LBUTTONUP:
1198             return STATUSBAR_SendNotify (hwnd, NM_CLICK);
1199
1200         case WM_MOUSEMOVE:
1201             return STATUSBAR_WMMouseMove (hwnd, wParam, lParam);
1202
1203         case WM_NCHITTEST:
1204             return STATUSBAR_WMNCHitTest (hwnd, wParam, lParam);
1205
1206         case WM_NCLBUTTONDOWN:
1207             return STATUSBAR_WMNCLButtonDown (hwnd, wParam, lParam);
1208
1209         case WM_NCLBUTTONUP:
1210             return STATUSBAR_WMNCLButtonUp (hwnd, wParam, lParam);
1211
1212         case WM_PAINT:
1213             return STATUSBAR_WMPaint (hwnd, wParam);
1214
1215         case WM_RBUTTONDBLCLK:
1216             return STATUSBAR_SendNotify (hwnd, NM_RDBLCLK);
1217
1218         case WM_RBUTTONUP:
1219             return STATUSBAR_SendNotify (hwnd, NM_RCLICK);
1220
1221         case WM_SETFONT:
1222             return STATUSBAR_WMSetFont (hwnd, wParam, lParam);
1223
1224         case WM_SETTEXT:
1225             return STATUSBAR_WMSetText (hwnd, wParam, lParam);
1226
1227         case WM_SIZE:
1228             return STATUSBAR_WMSize (hwnd, wParam, lParam);
1229
1230         default:
1231             if (msg >= WM_USER)
1232                 ERR (statusbar, "unknown msg %04x wp=%04x lp=%08lx\n",
1233                      msg, wParam, lParam);
1234             return DefWindowProcA (hwnd, msg, wParam, lParam);
1235     }
1236     return 0;
1237 }
1238
1239
1240 /***********************************************************************
1241  * STATUS_Register [Internal]
1242  *
1243  * Registers the status window class.
1244  */
1245
1246 VOID
1247 STATUS_Register (VOID)
1248 {
1249     WNDCLASSA wndClass;
1250
1251     if (GlobalFindAtomA (STATUSCLASSNAMEA)) return;
1252
1253     ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1254     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_VREDRAW;
1255     wndClass.lpfnWndProc   = (WNDPROC)StatusWindowProc;
1256     wndClass.cbClsExtra    = 0;
1257     wndClass.cbWndExtra    = sizeof(STATUSWINDOWINFO *);
1258     wndClass.hCursor       = LoadCursorA (0, IDC_ARROWA);
1259     wndClass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
1260     wndClass.lpszClassName = STATUSCLASSNAMEA;
1261  
1262     RegisterClassA (&wndClass);
1263 }
1264
1265
1266 /***********************************************************************
1267  * STATUS_Unregister [Internal]
1268  *
1269  * Unregisters the status window class.
1270  */
1271
1272 VOID
1273 STATUS_Unregister (VOID)
1274 {
1275     if (GlobalFindAtomA (STATUSCLASSNAMEA))
1276         UnregisterClassA (STATUSCLASSNAMEA, (HINSTANCE)NULL);
1277 }
1278