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