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