- New implementation of SendMessage, ReceiveMessage, ReplyMessage functions
[wine] / dlls / comctl32 / status.c
1 /*
2  * Interface code to StatusWindow widget/control
3  *
4  * Copyright 1996 Bruce Milner
5  * Copyright 1998 Eric Kohl
6  */
7
8 #include "commctrl.h"
9 #include "status.h"
10 #include "win.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(wndPtr) ((STATUSWINDOWINFO *)wndPtr->wExtra[0])
33
34
35 static void
36 STATUSBAR_DrawSizeGrip (HDC32 hdc, LPRECT32 lpRect)
37 {
38     HPEN32 hOldPen;
39     POINT32 pt;
40     INT32 i;
41
42     pt.x = lpRect->right - 1;
43     pt.y = lpRect->bottom - 1;
44
45     hOldPen = SelectObject32 (hdc, GetSysColorPen32 (COLOR_3DFACE));
46     MoveToEx32 (hdc, pt.x - 12, pt.y, NULL);
47     LineTo32 (hdc, pt.x, pt.y);
48     LineTo32 (hdc, pt.x, pt.y - 12);
49
50     pt.x--;
51     pt.y--;
52
53     SelectObject32 (hdc, GetSysColorPen32 (COLOR_3DSHADOW));
54     for (i = 1; i < 11; i += 4) {
55         MoveToEx32 (hdc, pt.x - i, pt.y, NULL);
56         LineTo32 (hdc, pt.x, pt.y - i);
57
58         MoveToEx32 (hdc, pt.x - i-1, pt.y, NULL);
59         LineTo32 (hdc, pt.x, pt.y - i-1);
60     }
61
62     SelectObject32 (hdc, GetSysColorPen32 (COLOR_3DHIGHLIGHT));
63     for (i = 3; i < 13; i += 4) {
64         MoveToEx32 (hdc, pt.x - i, pt.y, NULL);
65         LineTo32 (hdc, pt.x, pt.y - i);
66     }
67
68     SelectObject32 (hdc, hOldPen);
69 }
70
71
72 static void 
73 STATUSBAR_DrawPart (HDC32 hdc, STATUSWINDOWPART *part)
74 {
75     RECT32 r = part->bound;
76     UINT32 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     DrawEdge32(hdc, &r, border, BF_RECT|BF_ADJUST);
84
85     /* draw the icon */
86     if (part->hIcon) {
87         INT32 cy = r.bottom - r.top;
88
89         r.left += 2;
90         DrawIconEx32 (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 = SetBkMode32(hdc, TRANSPARENT);
97       LPWSTR p = (LPWSTR)part->text;
98       UINT32 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       DrawText32W (hdc, p, lstrlen32W (p), &r, align|DT_VCENTER|DT_SINGLELINE);
110       if (oldbkmode != TRANSPARENT)
111         SetBkMode32(hdc, oldbkmode);
112     }
113 }
114
115
116 static VOID
117 STATUSBAR_RefreshPart (WND *wndPtr, STATUSWINDOWPART *part, HDC32 hdc)
118 {
119     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
120     HBRUSH32 hbrBk;
121     HFONT32  hOldFont;
122
123     if (!IsWindowVisible32(wndPtr->hwndSelf))
124         return;
125
126     if (self->clrBk != CLR_DEFAULT)
127         hbrBk = CreateSolidBrush32 (self->clrBk);
128     else
129         hbrBk = GetSysColorBrush32 (COLOR_3DFACE);
130     FillRect32(hdc, &part->bound, hbrBk);
131
132     hOldFont = SelectObject32 (hdc, self->hFont ? self->hFont : self->hDefaultFont);
133
134     if (part->style == SBT_OWNERDRAW) {
135         DRAWITEMSTRUCT32 dis;
136
137         dis.CtlID = wndPtr->wIDmenu;
138         dis.itemID = -1;
139         dis.hwndItem = wndPtr->hwndSelf;
140         dis.hDC = hdc;
141         dis.rcItem = part->bound;
142         dis.itemData = (INT32)part->text;
143         SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_DRAWITEM,
144                         (WPARAM32)wndPtr->wIDmenu, (LPARAM)&dis);
145     }
146     else
147         STATUSBAR_DrawPart (hdc, part);
148
149     SelectObject32 (hdc, hOldFont);
150
151     if (self->clrBk != CLR_DEFAULT)
152         DeleteObject32 (hbrBk);
153
154     if (wndPtr->dwStyle & SBARS_SIZEGRIP) {
155         RECT32 rect;
156
157         GetClientRect32 (wndPtr->hwndSelf, &rect);
158         STATUSBAR_DrawSizeGrip (hdc, &rect);
159     }
160 }
161
162
163 static BOOL32
164 STATUSBAR_Refresh (WND *wndPtr, HDC32 hdc)
165 {
166     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
167     int      i;
168     RECT32   rect;
169     HBRUSH32 hbrBk;
170     HFONT32  hOldFont;
171
172     if (!IsWindowVisible32(wndPtr->hwndSelf))
173         return (TRUE);
174
175     GetClientRect32 (wndPtr->hwndSelf, &rect);
176
177     if (self->clrBk != CLR_DEFAULT)
178         hbrBk = CreateSolidBrush32 (self->clrBk);
179     else
180         hbrBk = GetSysColorBrush32 (COLOR_3DFACE);
181     FillRect32(hdc, &rect, hbrBk);
182
183     hOldFont = SelectObject32 (hdc, self->hFont ? self->hFont : self->hDefaultFont);
184
185     if (self->simple) {
186         STATUSBAR_DrawPart (hdc, &self->part0);
187     }
188     else {
189         for (i = 0; i < self->numParts; i++) {
190             if (self->parts[i].style == SBT_OWNERDRAW) {
191                 DRAWITEMSTRUCT32 dis;
192
193                 dis.CtlID = wndPtr->wIDmenu;
194                 dis.itemID = -1;
195                 dis.hwndItem = wndPtr->hwndSelf;
196                 dis.hDC = hdc;
197                 dis.rcItem = self->parts[i].bound;
198                 dis.itemData = (INT32)self->parts[i].text;
199                 SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_DRAWITEM,
200                                 (WPARAM32)wndPtr->wIDmenu, (LPARAM)&dis);
201             }
202             else
203                 STATUSBAR_DrawPart (hdc, &self->parts[i]);
204         }
205     }
206
207     SelectObject32 (hdc, hOldFont);
208
209     if (self->clrBk != CLR_DEFAULT)
210         DeleteObject32 (hbrBk);
211
212     if (wndPtr->dwStyle & SBARS_SIZEGRIP)
213         STATUSBAR_DrawSizeGrip (hdc, &rect);
214
215     return TRUE;
216 }
217
218
219 static void
220 STATUSBAR_SetPartBounds (WND *wndPtr)
221 {
222     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
223     STATUSWINDOWPART *part;
224     RECT32 rect, *r;
225     int i;
226
227     /* get our window size */
228     GetClientRect32 (wndPtr->hwndSelf, &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             TTTOOLINFO32A ti;
252
253             ti.cbSize = sizeof(TTTOOLINFO32A);
254             ti.hwnd = wndPtr->hwndSelf;
255             ti.uId = i;
256             ti.rect = *r;
257             SendMessage32A (self->hwndToolTip, TTM_NEWTOOLRECT32A,
258                             0, (LPARAM)&ti);
259         }
260     }
261 }
262
263
264 static VOID
265 STATUSBAR_RelayEvent (HWND32 hwndTip, HWND32 hwndMsg, UINT32 uMsg,
266                       WPARAM32 wParam, LPARAM lParam)
267 {
268     MSG32 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     SendMessage32A (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
279 }
280
281
282 __inline__ static LRESULT
283 STATUSBAR_GetBorders (LPARAM lParam)
284 {
285     LPINT32 out = (LPINT32) 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 (WND *wndPtr, WPARAM32 wParam)
297 {
298     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
299     INT32 nPart;
300
301     nPart = (INT32)wParam & 0x00ff;
302     if ((nPart < -1) || (nPart >= self->numParts)) return 0;
303
304     if (nPart == -1)
305         return (self->part0.hIcon);
306     else
307         return (self->parts[nPart].hIcon);
308 }
309
310
311 static LRESULT
312 STATUSBAR_GetParts (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
313 {
314     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
315     LPINT32 parts;
316     INT32   num_parts;
317     int     i;
318
319     num_parts = (INT32) wParam;
320     parts = (LPINT32) lParam;
321     if (parts) {
322         return (self->numParts);
323         for (i = 0; i < num_parts; i++) {
324             parts[i] = self->parts[i].x;
325         }
326     }
327     return (self->numParts);
328 }
329
330
331 static LRESULT
332 STATUSBAR_GetRect (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
333 {
334     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
335     int part_num;
336     LPRECT32  rect;
337
338     part_num = ((INT32) wParam) & 0x00ff;
339     rect = (LPRECT32) lParam;
340     if (infoPtr->simple)
341         *rect = infoPtr->part0.bound;
342     else
343         *rect = infoPtr->parts[part_num].bound;
344     return TRUE;
345 }
346
347
348 static LRESULT
349 STATUSBAR_GetText32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
350 {
351     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
352     STATUSWINDOWPART *part;
353     INT32   nPart;
354     LRESULT result;
355
356     nPart = ((INT32) wParam) & 0x00ff;
357     if (self->simple)
358         part = &self->part0;
359     else
360         part = &self->parts[nPart];
361
362     if (part->style == SBT_OWNERDRAW)
363         result = (LRESULT)part->text;
364     else {
365         result = part->text ? lstrlen32W (part->text) : 0;
366         result |= (part->style << 16);
367         if (lParam && LOWORD(result))
368             lstrcpyWtoA ((LPSTR)lParam, part->text);
369     }
370     return result;
371 }
372
373
374 static LRESULT
375 STATUSBAR_GetText32W (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
376 {
377     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
378     STATUSWINDOWPART *part;
379     INT32   nPart;
380     LRESULT result;
381
382     nPart = ((INT32)wParam) & 0x00ff;
383     if (self->simple)
384         part = &self->part0;
385     else
386         part = &self->parts[nPart];
387
388     if (part->style == SBT_OWNERDRAW)
389         result = (LRESULT)part->text;
390     else {
391         result = part->text ? lstrlen32W (part->text) : 0;
392         result |= (part->style << 16);
393         if (lParam)
394             lstrcpy32W ((LPWSTR)lParam, part->text);
395     }
396     return result;
397 }
398
399
400 static LRESULT
401 STATUSBAR_GetTextLength (WND *wndPtr, WPARAM32 wParam)
402 {
403     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
404     STATUSWINDOWPART *part;
405     INT32 part_num;
406     DWORD result;
407
408     part_num = ((INT32) wParam) & 0x00ff;
409
410     if (infoPtr->simple)
411         part = &infoPtr->part0;
412     else
413         part = &infoPtr->parts[part_num];
414
415     if (part->text)
416         result = lstrlen32W(part->text);
417     else
418         result = 0;
419
420     result |= (part->style << 16);
421     return result;
422 }
423
424
425 static LRESULT
426 STATUSBAR_GetTipText32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
427 {
428     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
429
430     if (infoPtr->hwndToolTip) {
431         TTTOOLINFO32A ti;
432         ti.cbSize = sizeof(TTTOOLINFO32A);
433         ti.hwnd = wndPtr->hwndSelf;
434         ti.uId = LOWORD(wParam);
435         SendMessage32A (infoPtr->hwndToolTip, TTM_GETTEXT32A, 0, (LPARAM)&ti);
436
437         if (ti.lpszText)
438             lstrcpyn32A ((LPSTR)lParam, ti.lpszText, HIWORD(wParam));
439     }
440
441     return 0;
442 }
443
444
445 static LRESULT
446 STATUSBAR_GetTipText32W (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
447 {
448     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
449
450     if (infoPtr->hwndToolTip) {
451         TTTOOLINFO32W ti;
452         ti.cbSize = sizeof(TTTOOLINFO32W);
453         ti.hwnd = wndPtr->hwndSelf;
454         ti.uId = LOWORD(wParam);
455         SendMessage32W (infoPtr->hwndToolTip, TTM_GETTEXT32W, 0, (LPARAM)&ti);
456
457         if (ti.lpszText)
458             lstrcpyn32W ((LPWSTR)lParam, ti.lpszText, HIWORD(wParam));
459     }
460
461     return 0;
462 }
463
464
465 __inline__ static LRESULT
466 STATUSBAR_GetUnicodeFormat (WND *wndPtr)
467 {
468     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
469     return infoPtr->bUnicode;
470 }
471
472
473 __inline__ static LRESULT
474 STATUSBAR_IsSimple (WND *wndPtr)
475 {
476     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
477     return infoPtr->simple;
478 }
479
480
481 static LRESULT
482 STATUSBAR_SetBkColor (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
483 {
484     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
485     COLORREF oldBkColor;
486     HDC32    hdc;
487
488     oldBkColor = self->clrBk;
489     self->clrBk = (COLORREF)lParam;
490     hdc = GetDC32 (wndPtr->hwndSelf);
491     STATUSBAR_Refresh (wndPtr, hdc);
492     ReleaseDC32 (wndPtr->hwndSelf, hdc);
493
494     return oldBkColor;
495 }
496
497
498 static LRESULT
499 STATUSBAR_SetIcon (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
500 {
501     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
502     INT32 nPart = (INT32)wParam & 0x00ff;
503     HDC32 hdc; 
504
505     if ((nPart < -1) || (nPart >= self->numParts))
506         return FALSE;
507
508     hdc = GetDC32 (wndPtr->hwndSelf);
509     if (nPart == -1) {
510         self->part0.hIcon = (HICON32)lParam;
511         if (self->simple)
512             STATUSBAR_RefreshPart (wndPtr, &self->part0, hdc);
513     }
514     else {
515         self->parts[nPart].hIcon = (HICON32)lParam;
516         if (!(self->simple))
517             STATUSBAR_RefreshPart (wndPtr, &self->parts[nPart], hdc);
518     }
519     ReleaseDC32 (wndPtr->hwndSelf, hdc);
520
521     return TRUE;
522 }
523
524
525 static LRESULT
526 STATUSBAR_SetMinHeight (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
527 {
528     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
529
530     if (IsWindowVisible32 (wndPtr->hwndSelf)) {
531         HWND32 parent = GetParent32 (wndPtr->hwndSelf);
532         INT32  width, x, y;
533         RECT32 parent_rect;
534
535         GetClientRect32 (parent, &parent_rect);
536         self->height = (INT32)wParam + VERT_BORDER;
537         width = parent_rect.right - parent_rect.left;
538         x = parent_rect.left;
539         y = parent_rect.bottom - self->height;
540         MoveWindow32 (wndPtr->hwndSelf, parent_rect.left,
541                       parent_rect.bottom - self->height,
542                       width, self->height, TRUE);
543         STATUSBAR_SetPartBounds (wndPtr);
544     }
545
546     return TRUE;
547 }
548
549
550 static LRESULT
551 STATUSBAR_SetParts (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
552 {
553     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
554     STATUSWINDOWPART *tmp;
555     HDC32       hdc;
556     LPINT32 parts;
557     int i;
558     int oldNumParts;
559
560     if (self->simple)
561         self->simple = FALSE;
562
563     oldNumParts = self->numParts;
564     self->numParts = (INT32) wParam;
565     parts = (LPINT32) lParam;
566     if (oldNumParts > self->numParts) {
567         for (i = self->numParts ; i < oldNumParts; i++) {
568             if (self->parts[i].text && (self->parts[i].style != SBT_OWNERDRAW))
569                 COMCTL32_Free (self->parts[i].text);
570         }
571     }
572     else if (oldNumParts < self->numParts) {
573         tmp = COMCTL32_Alloc (sizeof(STATUSWINDOWPART) * self->numParts);
574         for (i = 0; i < oldNumParts; i++) {
575             tmp[i] = self->parts[i];
576         }
577         if (self->parts)
578             COMCTL32_Free (self->parts);
579         self->parts = tmp;
580     }
581     
582     for (i = 0; i < self->numParts; i++) {
583         self->parts[i].x = parts[i];
584     }
585
586     if (self->hwndToolTip) {
587         INT32 nTipCount =
588             SendMessage32A (self->hwndToolTip, TTM_GETTOOLCOUNT, 0, 0);
589
590         if (nTipCount < self->numParts) {
591             /* add tools */
592             TTTOOLINFO32A ti;
593             INT32 i;
594
595             ZeroMemory (&ti, sizeof(TTTOOLINFO32A));
596             ti.cbSize = sizeof(TTTOOLINFO32A);
597             ti.hwnd = wndPtr->hwndSelf;
598             for (i = nTipCount; i < self->numParts; i++) {
599                 TRACE (statusbar, "add tool %d\n", i);
600                 ti.uId = i;
601                 SendMessage32A (self->hwndToolTip, TTM_ADDTOOL32A,
602                                 0, (LPARAM)&ti);
603             }
604         }
605         else if (nTipCount > self->numParts) {
606             /* delete tools */
607             INT32 i;
608
609             for (i = nTipCount - 1; i >= self->numParts; i--) {
610
611                 FIXME (statusbar, "delete tool %d\n", i);
612
613             }
614         }
615     }
616
617     STATUSBAR_SetPartBounds (wndPtr);
618
619     hdc = GetDC32 (wndPtr->hwndSelf);
620     STATUSBAR_Refresh (wndPtr, hdc);
621     ReleaseDC32 (wndPtr->hwndSelf, hdc);
622
623     return TRUE;
624 }
625
626
627 static LRESULT
628 STATUSBAR_SetText32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
629 {
630     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
631     STATUSWINDOWPART *part;
632     int part_num;
633     int style;
634     LPSTR text;
635     int len;
636     HDC32 hdc;
637
638     text = (LPSTR) lParam;
639     part_num = ((INT32) wParam) & 0x00ff;
640     style = ((INT32) wParam) & 0xff00;
641
642     if ((self->simple) || (self->parts==NULL) || (part_num==255))
643         part = &self->part0;
644     else
645         part = &self->parts[part_num];
646     if (!part) return FALSE;
647     part->style = style;
648     if (style == SBT_OWNERDRAW) {
649         part->text = (LPWSTR)text;
650     }
651     else {
652         /* duplicate string */
653         if (part->text)
654             COMCTL32_Free (part->text);
655         part->text = 0;
656         if (text && (len = lstrlen32A(text))) {
657             part->text = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
658             lstrcpyAtoW (part->text, text);
659         }
660     }
661
662     hdc = GetDC32 (wndPtr->hwndSelf);
663     STATUSBAR_RefreshPart (wndPtr, part, hdc);
664     ReleaseDC32 (wndPtr->hwndSelf, hdc);
665
666     return TRUE;
667 }
668
669
670 static LRESULT
671 STATUSBAR_SetText32W (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
672 {
673     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
674     STATUSWINDOWPART *part;
675     INT32  part_num, style, len;
676     LPWSTR text;
677     HDC32  hdc;
678
679     text = (LPWSTR) lParam;
680     part_num = ((INT32) wParam) & 0x00ff;
681     style = ((INT32) wParam) & 0xff00;
682
683     if ((self->simple) || (self->parts==NULL) || (part_num==255))
684         part = &self->part0;
685     else
686         part = &self->parts[part_num];
687     if (!part) return FALSE;
688     part->style = style;
689     if (style == SBT_OWNERDRAW) {
690         part->text = text;
691     }
692     else {
693         /* duplicate string */
694         if (part->text)
695             COMCTL32_Free (part->text);
696         part->text = 0;
697         if (text && (len = lstrlen32W(text))) {
698             part->text = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
699             lstrcpy32W(part->text, text);
700         }
701     }
702
703     hdc = GetDC32 (wndPtr->hwndSelf);
704     STATUSBAR_RefreshPart (wndPtr, part, hdc);
705     ReleaseDC32 (wndPtr->hwndSelf, hdc);
706
707     return TRUE;
708 }
709
710
711 static LRESULT
712 STATUSBAR_SetTipText32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
713 {
714     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
715
716     TRACE (statusbar, "part %d: \"%s\"\n", (INT32)wParam, (LPSTR)lParam);
717     if (infoPtr->hwndToolTip) {
718         TTTOOLINFO32A ti;
719         ti.cbSize = sizeof(TTTOOLINFO32A);
720         ti.hwnd = wndPtr->hwndSelf;
721         ti.uId = (INT32)wParam;
722         ti.hinst = 0;
723         ti.lpszText = (LPSTR)lParam;
724         SendMessage32A (infoPtr->hwndToolTip, TTM_UPDATETIPTEXT32A,
725                         0, (LPARAM)&ti);
726     }
727
728     return 0;
729 }
730
731
732 static LRESULT
733 STATUSBAR_SetTipText32W (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
734 {
735     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
736
737     TRACE (statusbar, "part %d: \"%s\"\n", (INT32)wParam, (LPSTR)lParam);
738     if (infoPtr->hwndToolTip) {
739         TTTOOLINFO32W ti;
740         ti.cbSize = sizeof(TTTOOLINFO32W);
741         ti.hwnd = wndPtr->hwndSelf;
742         ti.uId = (INT32)wParam;
743         ti.hinst = 0;
744         ti.lpszText = (LPWSTR)lParam;
745         SendMessage32W (infoPtr->hwndToolTip, TTM_UPDATETIPTEXT32W,
746                         0, (LPARAM)&ti);
747     }
748
749     return 0;
750 }
751
752
753 __inline__ static LRESULT
754 STATUSBAR_SetUnicodeFormat (WND *wndPtr, WPARAM32 wParam)
755 {
756     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
757     BOOL32 bTemp = infoPtr->bUnicode;
758
759     TRACE (statusbar, "(0x%x)\n", (BOOL32)wParam);
760     infoPtr->bUnicode = (BOOL32)wParam;
761
762     return bTemp;
763 }
764
765
766 static LRESULT
767 STATUSBAR_Simple (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
768 {
769     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
770     HDC32  hdc;
771     NMHDR  nmhdr;
772
773     infoPtr->simple = (BOOL32)wParam;
774
775     /* send notification */
776     nmhdr.hwndFrom = wndPtr->hwndSelf;
777     nmhdr.idFrom = wndPtr->wIDmenu;
778     nmhdr.code = SBN_SIMPLEMODECHANGE;
779     SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
780                     0, (LPARAM)&nmhdr);
781
782     hdc = GetDC32 (wndPtr->hwndSelf);
783     STATUSBAR_Refresh (wndPtr, hdc);
784     ReleaseDC32 (wndPtr->hwndSelf, hdc);
785
786     return TRUE;
787 }
788
789
790 static LRESULT
791 STATUSBAR_WMCreate (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
792 {
793     LPCREATESTRUCT32A lpCreate = (LPCREATESTRUCT32A)lParam;
794     NONCLIENTMETRICS32A nclm;
795     RECT32      rect;
796     int         width, len;
797     HDC32       hdc;
798     STATUSWINDOWINFO *self;
799
800     self = (STATUSWINDOWINFO*)COMCTL32_Alloc (sizeof(STATUSWINDOWINFO));
801     wndPtr->wExtra[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     GetClientRect32 (wndPtr->hwndSelf, &rect);
809
810     nclm.cbSize = sizeof(NONCLIENTMETRICS32A);
811     SystemParametersInfo32A (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
812     self->hDefaultFont = CreateFontIndirect32A (&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 (wndPtr->hwndSelf)) {
830         self->bUnicode = TRUE;
831         if ((len = lstrlen32W ((LPCWSTR)lpCreate->lpszName))) {
832             self->parts[0].text = COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
833             lstrcpy32W (self->parts[0].text, (LPCWSTR)lpCreate->lpszName);
834         }
835     }
836     else {
837         if ((len = lstrlen32A ((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 = GetDC32 (0))) {
844         TEXTMETRIC32A tm;
845         HFONT32 hOldFont;
846
847         hOldFont = SelectObject32 (hdc,self->hDefaultFont);
848         GetTextMetrics32A(hdc, &tm);
849         self->textHeight = tm.tmHeight;
850         SelectObject32 (hdc, hOldFont);
851         ReleaseDC32(0, hdc);
852     }
853
854     if (wndPtr->dwStyle & SBT_TOOLTIPS) {
855         self->hwndToolTip =
856             CreateWindowEx32A (0, TOOLTIPS_CLASS32A, NULL, 0,
857                                CW_USEDEFAULT32, CW_USEDEFAULT32,
858                                CW_USEDEFAULT32, CW_USEDEFAULT32,
859                                wndPtr->hwndSelf, 0,
860                                wndPtr->hInstance, NULL);
861
862         if (self->hwndToolTip) {
863             NMTOOLTIPSCREATED nmttc;
864
865             nmttc.hdr.hwndFrom = wndPtr->hwndSelf;
866             nmttc.hdr.idFrom = wndPtr->wIDmenu;
867             nmttc.hdr.code = NM_TOOLTIPSCREATED;
868             nmttc.hwndToolTips = self->hwndToolTip;
869
870             SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
871                             (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmttc);
872         }
873     }
874
875     GetClientRect32 (GetParent32 (wndPtr->hwndSelf), &rect);
876     width = rect.right - rect.left;
877     self->height = self->textHeight + 4 + VERT_BORDER;
878     MoveWindow32 (wndPtr->hwndSelf, lpCreate->x, lpCreate->y-1,
879                   width, self->height, FALSE);
880     STATUSBAR_SetPartBounds (wndPtr);
881
882     return 0;
883 }
884
885
886 static LRESULT
887 STATUSBAR_WMDestroy (WND *wndPtr)
888 {
889     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
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         DeleteObject32 (self->hDefaultFont);
903
904     /* delete tool tip control */
905     if (self->hwndToolTip)
906         DestroyWindow32 (self->hwndToolTip);
907
908     COMCTL32_Free (self);
909
910     return 0;
911 }
912
913
914 static __inline__ LRESULT
915 STATUSBAR_WMGetFont (WND *wndPtr)
916 {
917     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
918     return infoPtr->hFont;
919 }
920
921
922 static LRESULT
923 STATUSBAR_WMGetText (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
924 {
925     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
926     INT32 len;
927
928     if (!(infoPtr->parts[0].text))
929         return 0;
930     len = lstrlen32W (infoPtr->parts[0].text);
931     if (wParam > len) {
932         if (infoPtr->bUnicode)
933             lstrcpy32W ((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 (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
945 {
946     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
947
948     if (infoPtr->hwndToolTip)
949         STATUSBAR_RelayEvent (infoPtr->hwndToolTip, wndPtr->hwndSelf,
950                               WM_MOUSEMOVE, wParam, lParam);
951     return 0;
952 }
953
954
955 static LRESULT
956 STATUSBAR_WMNCHitTest (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
957 {
958     if (wndPtr->dwStyle & SBARS_SIZEGRIP) {
959         RECT32  rect;
960         POINT32 pt;
961
962         GetClientRect32 (wndPtr->hwndSelf, &rect);
963
964         pt.x = (INT32)LOWORD(lParam);
965         pt.y = (INT32)HIWORD(lParam);
966         ScreenToClient32 (wndPtr->hwndSelf, &pt);
967
968         rect.left = rect.right - 13;
969         rect.top += 2;
970
971         if (PtInRect32 (&rect, pt))
972             return HTBOTTOMRIGHT;
973     }
974
975     return DefWindowProc32A (wndPtr->hwndSelf, WM_NCHITTEST, wParam, lParam);
976 }
977
978
979 static __inline__ LRESULT
980 STATUSBAR_WMNCLButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
981 {
982     PostMessage32A (wndPtr->parent->hwndSelf, WM_NCLBUTTONDOWN,
983                     wParam, lParam);
984     return 0;
985 }
986
987
988 static __inline__ LRESULT
989 STATUSBAR_WMNCLButtonUp (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
990 {
991     PostMessage32A (wndPtr->parent->hwndSelf, WM_NCLBUTTONUP,
992                     wParam, lParam);
993     return 0;
994 }
995
996
997 static LRESULT
998 STATUSBAR_WMPaint (WND *wndPtr, WPARAM32 wParam)
999 {
1000     HDC32 hdc;
1001     PAINTSTRUCT32 ps;
1002
1003     hdc = wParam==0 ? BeginPaint32 (wndPtr->hwndSelf, &ps) : (HDC32)wParam;
1004     STATUSBAR_Refresh (wndPtr, hdc);
1005     if (!wParam)
1006         EndPaint32 (wndPtr->hwndSelf, &ps);
1007
1008     return 0;
1009 }
1010
1011
1012 static LRESULT
1013 STATUSBAR_WMSetFont (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1014 {
1015     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
1016
1017     infoPtr->hFont = (HFONT32)wParam;
1018     if (LOWORD(lParam) == TRUE) {
1019         HDC32 hdc = GetDC32 (wndPtr->hwndSelf);
1020         STATUSBAR_Refresh (wndPtr, hdc);
1021         ReleaseDC32 (wndPtr->hwndSelf, hdc);
1022     }
1023
1024     return 0;
1025 }
1026
1027
1028 static LRESULT
1029 STATUSBAR_WMSetText (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1030 {
1031     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
1032     STATUSWINDOWPART *part;
1033     int len;
1034     HDC32 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 = lstrlen32W((LPCWSTR)lParam))) {
1046             part->text = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
1047             lstrcpy32W (part->text, (LPCWSTR)lParam);
1048         }
1049     }
1050     else {
1051         if (lParam && (len = lstrlen32A((LPCSTR)lParam))) {
1052             part->text = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
1053             lstrcpyAtoW (part->text, (LPCSTR)lParam);
1054         }
1055     }
1056
1057     hdc = GetDC32 (wndPtr->hwndSelf);
1058     STATUSBAR_RefreshPart (wndPtr, part, hdc);
1059     ReleaseDC32 (wndPtr->hwndSelf, hdc);
1060
1061     return TRUE;
1062 }
1063
1064
1065 static LRESULT
1066 STATUSBAR_WMSize (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1067 {
1068     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
1069     INT32  width, x, y, flags;
1070     RECT32 parent_rect;
1071     HWND32 parent;
1072
1073     /* Need to resize width to match parent */
1074     flags = (INT32) 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 = GetParent32 (wndPtr->hwndSelf);
1083         GetClientRect32 (parent, &parent_rect);
1084         width = parent_rect.right - parent_rect.left;
1085         x = parent_rect.left;
1086         y = parent_rect.bottom - infoPtr->height;
1087         MoveWindow32 (wndPtr->hwndSelf, parent_rect.left, 
1088                       parent_rect.bottom - infoPtr->height,
1089                       width, infoPtr->height, TRUE);
1090         STATUSBAR_SetPartBounds (wndPtr);
1091     }
1092     return 0;
1093 }
1094
1095
1096 static LRESULT
1097 STATUSBAR_SendNotify (WND *wndPtr, UINT32 code)
1098 {
1099     NMHDR  nmhdr;
1100
1101     nmhdr.hwndFrom = wndPtr->hwndSelf;
1102     nmhdr.idFrom = wndPtr->wIDmenu;
1103     nmhdr.code = code;
1104     SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
1105                     0, (LPARAM)&nmhdr);
1106     return 0;
1107 }
1108
1109
1110
1111 LRESULT WINAPI
1112 StatusWindowProc (HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
1113 {
1114     WND *wndPtr = WIN_FindWndPtr (hwnd);
1115
1116     switch (msg) {
1117         case SB_GETBORDERS:
1118             return STATUSBAR_GetBorders (lParam);
1119
1120         case SB_GETICON:
1121             return STATUSBAR_GetIcon (wndPtr, wParam);
1122
1123         case SB_GETPARTS:
1124             return STATUSBAR_GetParts (wndPtr, wParam, lParam);
1125
1126         case SB_GETRECT:
1127             return STATUSBAR_GetRect (wndPtr, wParam, lParam);
1128
1129         case SB_GETTEXT32A:
1130             return STATUSBAR_GetText32A (wndPtr, wParam, lParam);
1131
1132         case SB_GETTEXT32W:
1133             return STATUSBAR_GetText32W (wndPtr, wParam, lParam);
1134
1135         case SB_GETTEXTLENGTH32A:
1136         case SB_GETTEXTLENGTH32W:
1137             return STATUSBAR_GetTextLength (wndPtr, wParam);
1138
1139         case SB_GETTIPTEXT32A:
1140             return STATUSBAR_GetTipText32A (wndPtr, wParam, lParam);
1141
1142         case SB_GETTIPTEXT32W:
1143             return STATUSBAR_GetTipText32W (wndPtr, wParam, lParam);
1144
1145         case SB_GETUNICODEFORMAT:
1146             return STATUSBAR_GetUnicodeFormat (wndPtr);
1147
1148         case SB_ISSIMPLE:
1149             return STATUSBAR_IsSimple (wndPtr);
1150
1151         case SB_SETBKCOLOR:
1152             return STATUSBAR_SetBkColor (wndPtr, wParam, lParam);
1153
1154         case SB_SETICON:
1155             return STATUSBAR_SetIcon (wndPtr, wParam, lParam);
1156
1157         case SB_SETMINHEIGHT:
1158             return STATUSBAR_SetMinHeight (wndPtr, wParam, lParam);
1159
1160         case SB_SETPARTS:       
1161             return STATUSBAR_SetParts (wndPtr, wParam, lParam);
1162
1163         case SB_SETTEXT32A:
1164             return STATUSBAR_SetText32A (wndPtr, wParam, lParam);
1165
1166         case SB_SETTEXT32W:
1167             return STATUSBAR_SetText32W (wndPtr, wParam, lParam);
1168
1169         case SB_SETTIPTEXT32A:
1170             return STATUSBAR_SetTipText32A (wndPtr, wParam, lParam);
1171
1172         case SB_SETTIPTEXT32W:
1173             return STATUSBAR_SetTipText32W (wndPtr, wParam, lParam);
1174
1175         case SB_SETUNICODEFORMAT:
1176             return STATUSBAR_SetUnicodeFormat (wndPtr, wParam);
1177
1178         case SB_SIMPLE:
1179             return STATUSBAR_Simple (wndPtr, wParam, lParam);
1180
1181
1182         case WM_CREATE:
1183             return STATUSBAR_WMCreate (wndPtr, wParam, lParam);
1184
1185         case WM_DESTROY:
1186             return STATUSBAR_WMDestroy (wndPtr);
1187
1188         case WM_GETFONT:
1189             return STATUSBAR_WMGetFont (wndPtr);
1190
1191         case WM_GETTEXT:
1192             return STATUSBAR_WMGetText (wndPtr, wParam, lParam);
1193
1194         case WM_GETTEXTLENGTH:
1195             return STATUSBAR_GetTextLength (wndPtr, 0);
1196
1197         case WM_LBUTTONDBLCLK:
1198             return STATUSBAR_SendNotify (wndPtr, NM_DBLCLK);
1199
1200         case WM_LBUTTONUP:
1201             return STATUSBAR_SendNotify (wndPtr, NM_CLICK);
1202
1203         case WM_MOUSEMOVE:
1204             return STATUSBAR_WMMouseMove (wndPtr, wParam, lParam);
1205
1206         case WM_NCHITTEST:
1207             return STATUSBAR_WMNCHitTest (wndPtr, wParam, lParam);
1208
1209         case WM_NCLBUTTONDOWN:
1210             return STATUSBAR_WMNCLButtonDown (wndPtr, wParam, lParam);
1211
1212         case WM_NCLBUTTONUP:
1213             return STATUSBAR_WMNCLButtonUp (wndPtr, wParam, lParam);
1214
1215         case WM_PAINT:
1216             return STATUSBAR_WMPaint (wndPtr, wParam);
1217
1218         case WM_RBUTTONDBLCLK:
1219             return STATUSBAR_SendNotify (wndPtr, NM_RDBLCLK);
1220
1221         case WM_RBUTTONUP:
1222             return STATUSBAR_SendNotify (wndPtr, NM_RCLICK);
1223
1224         case WM_SETFONT:
1225             return STATUSBAR_WMSetFont (wndPtr, wParam, lParam);
1226
1227         case WM_SETTEXT:
1228             return STATUSBAR_WMSetText (wndPtr, wParam, lParam);
1229
1230         case WM_SIZE:
1231             return STATUSBAR_WMSize (wndPtr, wParam, lParam);
1232
1233         default:
1234             if (msg >= WM_USER)
1235                 ERR (statusbar, "unknown msg %04x wp=%04x lp=%08lx\n",
1236                      msg, wParam, lParam);
1237             return DefWindowProc32A (hwnd, msg, wParam, lParam);
1238     }
1239     return 0;
1240 }
1241
1242
1243 /***********************************************************************
1244  * STATUS_Register [Internal]
1245  *
1246  * Registers the status window class.
1247  */
1248
1249 VOID
1250 STATUS_Register (VOID)
1251 {
1252     WNDCLASS32A wndClass;
1253
1254     if (GlobalFindAtom32A (STATUSCLASSNAME32A)) return;
1255
1256     ZeroMemory (&wndClass, sizeof(WNDCLASS32A));
1257     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_VREDRAW;
1258     wndClass.lpfnWndProc   = (WNDPROC32)StatusWindowProc;
1259     wndClass.cbClsExtra    = 0;
1260     wndClass.cbWndExtra    = sizeof(STATUSWINDOWINFO *);
1261     wndClass.hCursor       = LoadCursor32A (0, IDC_ARROW32A);
1262     wndClass.hbrBackground = (HBRUSH32)(COLOR_3DFACE + 1);
1263     wndClass.lpszClassName = STATUSCLASSNAME32A;
1264  
1265     RegisterClass32A (&wndClass);
1266 }
1267
1268
1269 /***********************************************************************
1270  * STATUS_Unregister [Internal]
1271  *
1272  * Unregisters the status window class.
1273  */
1274
1275 VOID
1276 STATUS_Unregister (VOID)
1277 {
1278     if (GlobalFindAtom32A (STATUSCLASSNAME32A))
1279         UnregisterClass32A (STATUSCLASSNAME32A, (HINSTANCE32)NULL);
1280 }
1281