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