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