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