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