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