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