Add partial support for some undocumented toolbar messages.
[wine] / dlls / comctl32 / header.c
1 /*
2  *  Header control
3  *
4  *  Copyright 1998 Eric Kohl
5  *  Copyright 2000 Eric Kohl for CodeWeavers
6  *  Copyright 2003 Maxime Bellenge
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  *  TODO:
23  *   - Imagelist support (partially).
24  *   - Callback items (under construction).
25  *   - Hottrack support (partially).
26  *   - Custom draw support (including Notifications).
27  *   - Drag and Drop support (including Notifications).
28  *   - New messages.
29  *   - Use notification format
30  *   - Correct the order maintenance code to preserve valid order
31  *
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 "imagelist.h"
46 #include "wine/debug.h"
47
48 WINE_DEFAULT_DEBUG_CHANNEL(header);
49
50 typedef struct
51 {
52     INT     cxy;
53     HBITMAP hbm;
54     LPWSTR    pszText;
55     INT     fmt;
56     LPARAM    lParam;
57     INT     iImage;
58     INT     iOrder;             /* see documentation of HD_ITEM */
59
60     BOOL    bDown;              /* is item pressed? (used for drawing) */
61     RECT    rect;               /* bounding rectangle of the item */
62 } HEADER_ITEM;
63
64
65 typedef struct
66 {
67     HWND      hwndNotify;       /* Owner window to send notifications to */
68     INT       nNotifyFormat;    /* format used for WM_NOTIFY messages */
69     UINT      uNumItem;         /* number of items (columns) */
70     INT       nHeight;          /* height of the header (pixels) */
71     HFONT     hFont;            /* handle to the current font */
72     HCURSOR   hcurArrow;        /* handle to the arrow cursor */
73     HCURSOR   hcurDivider;      /* handle to a cursor (used over dividers) <-|-> */
74     HCURSOR   hcurDivopen;      /* handle to a cursor (used over dividers) <-||-> */
75     BOOL      bCaptured;        /* Is the mouse captured? */
76     BOOL      bPressed;         /* Is a header item pressed (down)? */
77     BOOL      bTracking;        /* Is in tracking mode? */
78     BOOL      bUnicode;         /* Unicode flag */
79     INT       iMoveItem;        /* index of tracked item. (Tracking mode) */
80     INT       xTrackOffset;     /* distance between the right side of the tracked item and the cursor */
81     INT       xOldTrack;        /* track offset (see above) after the last WM_MOUSEMOVE */
82     INT       nOldWidth;        /* width of a sizing item after the last WM_MOUSEMOVE */
83     INT       iHotItem;         /* index of hot item (cursor is over this item) */
84     INT       iMargin;          /* width of the margin that surrounds a bitmap */
85
86     HIMAGELIST  himl;           /* handle to a image list (may be 0) */
87     HEADER_ITEM *items;         /* pointer to array of HEADER_ITEM's */
88     BOOL        bRectsValid;    /* validity flag for bounding rectangles */
89 } HEADER_INFO;
90
91
92 #define VERT_BORDER     3
93 #define DIVIDER_WIDTH  10
94
95 #define HEADER_GetInfoPtr(hwnd) ((HEADER_INFO *)GetWindowLongA(hwnd,0))
96
97
98 inline static LRESULT
99 HEADER_IndexToOrder (HWND hwnd, INT iItem)
100 {
101     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
102     HEADER_ITEM *lpItem = &infoPtr->items[iItem];
103     return lpItem->iOrder;
104 }
105
106
107 static INT
108 HEADER_OrderToIndex(HWND hwnd, WPARAM wParam)
109 {
110     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
111     INT i,iorder = (INT)wParam;
112
113
114     if ((iorder <0) || iorder >infoPtr->uNumItem)
115       return iorder;
116     for (i=0; i<infoPtr->uNumItem; i++)
117       if (HEADER_IndexToOrder(hwnd,i) == iorder)
118         return i;
119     return iorder;
120 }
121
122 static void
123 HEADER_SetItemBounds (HWND hwnd)
124 {
125     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
126     HEADER_ITEM *phdi;
127     RECT rect;
128     int i, x;
129
130     infoPtr->bRectsValid = TRUE;
131
132     if (infoPtr->uNumItem == 0)
133         return;
134
135     GetClientRect (hwnd, &rect);
136
137     x = rect.left;
138     for (i = 0; i < infoPtr->uNumItem; i++) {
139         phdi = &infoPtr->items[HEADER_OrderToIndex(hwnd,i)];
140         phdi->rect.top = rect.top;
141         phdi->rect.bottom = rect.bottom;
142         phdi->rect.left = x;
143         phdi->rect.right = phdi->rect.left + ((phdi->cxy>0)?phdi->cxy:0);
144         x = phdi->rect.right;
145     }
146 }
147
148 static LRESULT
149 HEADER_Size (HWND hwnd, WPARAM wParam)
150 {
151     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
152
153     infoPtr->bRectsValid = FALSE;
154
155     return 0;
156 }
157
158
159 static INT
160 HEADER_DrawItem (HWND hwnd, HDC hdc, INT iItem, BOOL bHotTrack)
161 {
162     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
163     HEADER_ITEM *phdi = &infoPtr->items[iItem];
164     RECT r;
165     INT  oldBkMode;
166
167     TRACE("DrawItem(iItem %d bHotTrack %d unicode flag %d)\n", iItem, bHotTrack, infoPtr->bUnicode);
168
169     if (!infoPtr->bRectsValid)
170         HEADER_SetItemBounds(hwnd);
171
172     r = phdi->rect;
173     if (r.right - r.left == 0)
174         return phdi->rect.right;
175
176     if (GetWindowLongA (hwnd, GWL_STYLE) & HDS_BUTTONS) {
177         if (phdi->bDown) {
178             DrawEdge (hdc, &r, BDR_RAISEDOUTER,
179                         BF_RECT | BF_FLAT | BF_MIDDLE | BF_ADJUST);
180             r.left += 2;
181             r.top  += 2;
182         }
183         else
184             DrawEdge (hdc, &r, EDGE_RAISED,
185                         BF_RECT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
186     }
187     else
188         DrawEdge (hdc, &r, EDGE_ETCHED, BF_BOTTOM | BF_RIGHT | BF_ADJUST);
189
190     if (phdi->fmt & HDF_OWNERDRAW) {
191         DRAWITEMSTRUCT dis;
192         dis.CtlType    = ODT_HEADER;
193         dis.CtlID      = GetWindowLongA (hwnd, GWL_ID);
194         dis.itemID     = iItem;
195         dis.itemAction = ODA_DRAWENTIRE;
196         dis.itemState  = phdi->bDown ? ODS_SELECTED : 0;
197         dis.hwndItem   = hwnd;
198         dis.hDC        = hdc;
199         dis.rcItem     = r;
200         dis.itemData   = phdi->lParam;
201         oldBkMode = SetBkMode(hdc, TRANSPARENT);
202         SendMessageA (infoPtr->hwndNotify, WM_DRAWITEM,
203                         (WPARAM)dis.CtlID, (LPARAM)&dis);
204         if (oldBkMode != TRANSPARENT)
205             SetBkMode(hdc, oldBkMode);
206     }
207     else {
208         UINT uTextJustify = DT_LEFT;
209
210         if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_CENTER)
211             uTextJustify = DT_CENTER;
212         else if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_RIGHT)
213             uTextJustify = DT_RIGHT;
214
215         if ((phdi->fmt & HDF_BITMAP) && !(phdi->fmt & HDF_BITMAP_ON_RIGHT) && (phdi->hbm)) {
216             BITMAP bmp;
217             HDC    hdcBitmap;
218             INT    yD, yS, cx, cy, rx, ry;
219
220             GetObjectA (phdi->hbm, sizeof(BITMAP), (LPVOID)&bmp);
221
222             ry = r.bottom - r.top;
223             rx = r.right - r.left;
224
225             if (ry >= bmp.bmHeight) {
226                 cy = bmp.bmHeight;
227                 yD = r.top + (ry - bmp.bmHeight) / 2;
228                 yS = 0;
229             }
230             else {
231                 cy = ry;
232                 yD = r.top;
233                 yS = (bmp.bmHeight - ry) / 2;
234
235             }
236
237             if (rx >= bmp.bmWidth + infoPtr->iMargin) {
238                 cx = bmp.bmWidth;
239             }
240             else {
241                 cx = rx - infoPtr->iMargin;
242             }
243
244             hdcBitmap = CreateCompatibleDC (hdc);
245             SelectObject (hdcBitmap, phdi->hbm);
246             BitBlt (hdc, r.left + infoPtr->iMargin, yD, cx, cy, hdcBitmap, 0, yS, SRCCOPY);
247             DeleteDC (hdcBitmap);
248
249             r.left += (bmp.bmWidth + infoPtr->iMargin);
250         }
251
252
253         if ((phdi->fmt & HDF_BITMAP) && (phdi->fmt & HDF_BITMAP_ON_RIGHT) && (phdi->hbm)) {
254             BITMAP bmp;
255             HDC    hdcBitmap;
256             INT    xD, yD, yS, cx, cy, rx, ry, tx;
257             RECT   textRect;
258
259             GetObjectA (phdi->hbm, sizeof(BITMAP), (LPVOID)&bmp);
260
261             textRect = r;
262             if (phdi->fmt & HDF_STRING) {
263                 DrawTextW (hdc, phdi->pszText, -1,
264                            &textRect, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_CALCRECT);
265                 tx = textRect.right - textRect.left;
266             }
267             else
268                 tx = 0;
269             ry = r.bottom - r.top;
270             rx = r.right - r.left;
271
272             if (ry >= bmp.bmHeight) {
273                 cy = bmp.bmHeight;
274                 yD = r.top + (ry - bmp.bmHeight) / 2;
275                 yS = 0;
276             }
277             else {
278                 cy = ry;
279                 yD = r.top;
280                 yS = (bmp.bmHeight - ry) / 2;
281
282             }
283
284             if (r.left + tx + bmp.bmWidth + 2*infoPtr->iMargin <= r.right) {
285                 cx = bmp.bmWidth;
286                 xD = r.left + tx + infoPtr->iMargin;
287             }
288             else {
289                 if (rx >= bmp.bmWidth + infoPtr->iMargin ) {
290                     cx = bmp.bmWidth;
291                     xD = r.right - bmp.bmWidth - infoPtr->iMargin;
292                     r.right = xD - infoPtr->iMargin;
293                 }
294                 else {
295                     cx = rx - infoPtr->iMargin;
296                     xD = r.left;
297                     r.right = r.left;
298                 }
299             }
300
301             hdcBitmap = CreateCompatibleDC (hdc);
302             SelectObject (hdcBitmap, phdi->hbm);
303             BitBlt (hdc, xD, yD, cx, cy, hdcBitmap, 0, yS, SRCCOPY);
304             DeleteDC (hdcBitmap);
305         }
306
307         if ((phdi->fmt & HDF_IMAGE) && !(phdi->fmt & HDF_BITMAP_ON_RIGHT) && (infoPtr->himl)) {
308             r.left += infoPtr->iMargin;
309             ImageList_DrawEx(infoPtr->himl, phdi->iImage, hdc, r.left, r.top + (r.bottom-r.top- infoPtr->himl->cy)/2,
310                              infoPtr->himl->cx, r.bottom-r.top, CLR_DEFAULT, CLR_DEFAULT, 0); 
311             r.left += infoPtr->himl->cx;
312         }
313
314         if ((phdi->fmt & HDF_IMAGE) && (phdi->fmt & HDF_BITMAP_ON_RIGHT) && (infoPtr->himl)) {
315             RECT textRect;
316             INT  tx;    
317
318             textRect = r;
319             if (phdi->fmt & HDF_STRING) {
320                 DrawTextW (hdc, phdi->pszText, -1,
321                            &textRect, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_CALCRECT);
322                 tx = textRect.right - textRect.left;
323             } 
324             else
325                 tx = 0;
326             ImageList_DrawEx(infoPtr->himl, phdi->iImage, hdc, r.left + tx + 2*infoPtr->iMargin,
327                              r.top + (r.bottom-r.top-infoPtr->himl->cy)/2, infoPtr->himl->cx, r.bottom-r.top, 
328                              CLR_DEFAULT, CLR_DEFAULT, 0);
329         }       
330
331         if (((phdi->fmt & HDF_STRING)
332                 || (!(phdi->fmt & (HDF_OWNERDRAW|HDF_STRING|HDF_BITMAP|
333                                    HDF_BITMAP_ON_RIGHT|HDF_IMAGE)))) /* no explicit format specified? */
334             && (phdi->pszText)) {
335             oldBkMode = SetBkMode(hdc, TRANSPARENT);
336             r.left += infoPtr->iMargin;
337             r.right -= infoPtr->iMargin;
338             SetTextColor (hdc, (bHotTrack) ? COLOR_HIGHLIGHT : COLOR_BTNTEXT);
339             DrawTextW (hdc, phdi->pszText, -1,
340                        &r, uTextJustify|DT_END_ELLIPSIS|DT_VCENTER|DT_SINGLELINE);
341             if (oldBkMode != TRANSPARENT)
342                 SetBkMode(hdc, oldBkMode);
343         }
344     }/*Ownerdrawn*/
345
346     return phdi->rect.right;
347 }
348
349
350 static void
351 HEADER_Refresh (HWND hwnd, HDC hdc)
352 {
353     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
354     HFONT hFont, hOldFont;
355     RECT rect;
356     HBRUSH hbrBk;
357     INT i, x;
358
359     /* get rect for the bar, adjusted for the border */
360     GetClientRect (hwnd, &rect);
361
362     hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
363     hOldFont = SelectObject (hdc, hFont);
364
365     /* draw Background */
366     hbrBk = GetSysColorBrush(COLOR_3DFACE);
367     FillRect(hdc, &rect, hbrBk);
368
369     x = rect.left;
370     for (i = 0; i < infoPtr->uNumItem; i++) {
371         x = HEADER_DrawItem (hwnd, hdc, HEADER_OrderToIndex(hwnd,i), FALSE);
372     }
373
374     if ((x <= rect.right) && (infoPtr->uNumItem > 0)) {
375         rect.left = x;
376         if (GetWindowLongA (hwnd, GWL_STYLE) & HDS_BUTTONS)
377             DrawEdge (hdc, &rect, EDGE_RAISED, BF_TOP|BF_LEFT|BF_BOTTOM|BF_SOFT);
378         else
379             DrawEdge (hdc, &rect, EDGE_ETCHED, BF_BOTTOM);
380     }
381
382     SelectObject (hdc, hOldFont);
383 }
384
385
386 static void
387 HEADER_RefreshItem (HWND hwnd, HDC hdc, INT iItem)
388 {
389     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
390     HFONT hFont, hOldFont;
391
392     hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
393     hOldFont = SelectObject (hdc, hFont);
394     HEADER_DrawItem (hwnd, hdc, iItem, FALSE);
395     SelectObject (hdc, hOldFont);
396 }
397
398
399 static void
400 HEADER_InternalHitTest (HWND hwnd, LPPOINT lpPt, UINT *pFlags, INT *pItem)
401 {
402     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
403     RECT rect, rcTest;
404     INT  iCount, width;
405     BOOL bNoWidth;
406
407     GetClientRect (hwnd, &rect);
408
409     *pFlags = 0;
410     bNoWidth = FALSE;
411     if (PtInRect (&rect, *lpPt))
412     {
413         if (infoPtr->uNumItem == 0) {
414             *pFlags |= HHT_NOWHERE;
415             *pItem = 1;
416             TRACE("NOWHERE\n");
417             return;
418         }
419         else {
420             /* somewhere inside */
421             for (iCount = 0; iCount < infoPtr->uNumItem; iCount++) {
422                 rect = infoPtr->items[iCount].rect;
423                 width = rect.right - rect.left;
424                 if (width == 0) {
425                     bNoWidth = TRUE;
426                     continue;
427                 }
428                 if (PtInRect (&rect, *lpPt)) {
429                     if (width <= 2 * DIVIDER_WIDTH) {
430                         *pFlags |= HHT_ONHEADER;
431                         *pItem = iCount;
432                         TRACE("ON HEADER %d\n", iCount);
433                         return;
434                     }
435                     if (iCount > 0) {
436                         rcTest = rect;
437                         rcTest.right = rcTest.left + DIVIDER_WIDTH;
438                         if (PtInRect (&rcTest, *lpPt)) {
439                             if (bNoWidth) {
440                                 *pFlags |= HHT_ONDIVOPEN;
441                                 *pItem = iCount - 1;
442                                 TRACE("ON DIVOPEN %d\n", *pItem);
443                                 return;
444                             }
445                             else {
446                                 *pFlags |= HHT_ONDIVIDER;
447                                 *pItem = iCount - 1;
448                                 TRACE("ON DIVIDER %d\n", *pItem);
449                                 return;
450                             }
451                         }
452                     }
453                     rcTest = rect;
454                     rcTest.left = rcTest.right - DIVIDER_WIDTH;
455                     if (PtInRect (&rcTest, *lpPt)) {
456                         *pFlags |= HHT_ONDIVIDER;
457                         *pItem = iCount;
458                         TRACE("ON DIVIDER %d\n", *pItem);
459                         return;
460                     }
461
462                     *pFlags |= HHT_ONHEADER;
463                     *pItem = iCount;
464                     TRACE("ON HEADER %d\n", iCount);
465                     return;
466                 }
467             }
468
469             /* check for last divider part (on nowhere) */
470             rect = infoPtr->items[infoPtr->uNumItem-1].rect;
471             rect.left = rect.right;
472             rect.right += DIVIDER_WIDTH;
473             if (PtInRect (&rect, *lpPt)) {
474                 if (bNoWidth) {
475                     *pFlags |= HHT_ONDIVOPEN;
476                     *pItem = infoPtr->uNumItem - 1;
477                     TRACE("ON DIVOPEN %d\n", *pItem);
478                     return;
479                 }
480                 else {
481                     *pFlags |= HHT_ONDIVIDER;
482                     *pItem = infoPtr->uNumItem-1;
483                     TRACE("ON DIVIDER %d\n", *pItem);
484                     return;
485                 }
486             }
487
488             *pFlags |= HHT_NOWHERE;
489             *pItem = 1;
490             TRACE("NOWHERE\n");
491             return;
492         }
493     }
494     else {
495         if (lpPt->x < rect.left) {
496            TRACE("TO LEFT\n");
497            *pFlags |= HHT_TOLEFT;
498         }
499         else if (lpPt->x > rect.right) {
500             TRACE("TO RIGHT\n");
501             *pFlags |= HHT_TORIGHT;
502         }
503
504         if (lpPt->y < rect.top) {
505             TRACE("ABOVE\n");
506             *pFlags |= HHT_ABOVE;
507         }
508         else if (lpPt->y > rect.bottom) {
509             TRACE("BELOW\n");
510             *pFlags |= HHT_BELOW;
511         }
512     }
513
514     *pItem = 1;
515     TRACE("flags=0x%X\n", *pFlags);
516     return;
517 }
518
519
520 static void
521 HEADER_DrawTrackLine (HWND hwnd, HDC hdc, INT x)
522 {
523     RECT rect;
524     HPEN hOldPen;
525     INT  oldRop;
526
527     GetClientRect (hwnd, &rect);
528
529     hOldPen = SelectObject (hdc, GetStockObject (BLACK_PEN));
530     oldRop = SetROP2 (hdc, R2_XORPEN);
531     MoveToEx (hdc, x, rect.top, NULL);
532     LineTo (hdc, x, rect.bottom);
533     SetROP2 (hdc, oldRop);
534     SelectObject (hdc, hOldPen);
535 }
536
537
538 static BOOL
539 HEADER_SendSimpleNotify (HWND hwnd, UINT code)
540 {
541     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
542     NMHDR nmhdr;
543
544     nmhdr.hwndFrom = hwnd;
545     nmhdr.idFrom   = GetWindowLongA (hwnd, GWL_ID);
546     nmhdr.code     = code;
547
548     return (BOOL)SendMessageA (infoPtr->hwndNotify, WM_NOTIFY,
549                                    (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
550 }
551
552 static BOOL
553 HEADER_SendHeaderNotify (HWND hwnd, UINT code, INT iItem, INT mask)
554 {
555     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
556     NMHEADERA nmhdr;
557     HDITEMA nmitem;
558
559     nmhdr.hdr.hwndFrom = hwnd;
560     nmhdr.hdr.idFrom   = GetWindowLongA (hwnd, GWL_ID);
561     nmhdr.hdr.code = code;
562     nmhdr.iItem = iItem;
563     nmhdr.iButton = 0;
564     nmhdr.pitem = &nmitem;
565     nmitem.mask = mask;
566     nmitem.cxy = infoPtr->items[iItem].cxy;
567     nmitem.hbm = infoPtr->items[iItem].hbm;
568     nmitem.pszText = NULL;
569     nmitem.cchTextMax = 0;
570 /*    nmitem.pszText = infoPtr->items[iItem].pszText; */
571 /*    nmitem.cchTextMax = infoPtr->items[iItem].cchTextMax; */
572     nmitem.fmt = infoPtr->items[iItem].fmt;
573     nmitem.lParam = infoPtr->items[iItem].lParam;
574     nmitem.iOrder = infoPtr->items[iItem].iOrder;
575     nmitem.iImage = infoPtr->items[iItem].iImage;
576
577     return (BOOL)SendMessageA (infoPtr->hwndNotify, WM_NOTIFY,
578                                (WPARAM)nmhdr.hdr.idFrom, (LPARAM)&nmhdr);
579 }
580
581
582 static BOOL
583 HEADER_SendClickNotify (HWND hwnd, UINT code, INT iItem)
584 {
585     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
586     NMHEADERA nmhdr;
587
588     nmhdr.hdr.hwndFrom = hwnd;
589     nmhdr.hdr.idFrom   = GetWindowLongA (hwnd, GWL_ID);
590     nmhdr.hdr.code = code;
591     nmhdr.iItem = iItem;
592     nmhdr.iButton = 0;
593     nmhdr.pitem = NULL;
594
595     return (BOOL)SendMessageA (infoPtr->hwndNotify, WM_NOTIFY,
596                                (WPARAM)nmhdr.hdr.idFrom, (LPARAM)&nmhdr);
597 }
598
599
600 static LRESULT
601 HEADER_CreateDragImage (HWND hwnd, WPARAM wParam)
602 {
603     FIXME("empty stub!\n");
604     return 0;
605 }
606
607
608 static LRESULT
609 HEADER_DeleteItem (HWND hwnd, WPARAM wParam)
610 {
611     HEADER_INFO *infoPtr = HEADER_GetInfoPtr(hwnd);
612     INT iItem = (INT)wParam;
613
614     TRACE("[iItem=%d]\n", iItem);
615
616     if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem))
617         return FALSE;
618
619     if (infoPtr->uNumItem == 1) {
620         TRACE("Simple delete!\n");
621         if (infoPtr->items[0].pszText)
622             Free (infoPtr->items[0].pszText);
623         Free (infoPtr->items);
624         infoPtr->items = 0;
625         infoPtr->uNumItem = 0;
626     }
627     else {
628         HEADER_ITEM *oldItems = infoPtr->items;
629         HEADER_ITEM *pItem;
630         INT i;
631         INT iOrder;
632         TRACE("Complex delete! [iItem=%d]\n", iItem);
633
634         if (infoPtr->items[iItem].pszText)
635             Free (infoPtr->items[iItem].pszText);
636         iOrder = infoPtr->items[iItem].iOrder;
637
638         infoPtr->uNumItem--;
639         infoPtr->items = Alloc (sizeof (HEADER_ITEM) * infoPtr->uNumItem);
640         /* pre delete copy */
641         if (iItem > 0) {
642             memcpy (&infoPtr->items[0], &oldItems[0],
643                     iItem * sizeof(HEADER_ITEM));
644         }
645
646         /* post delete copy */
647         if (iItem < infoPtr->uNumItem) {
648             memcpy (&infoPtr->items[iItem], &oldItems[iItem+1],
649                     (infoPtr->uNumItem - iItem) * sizeof(HEADER_ITEM));
650         }
651
652         /* Correct the orders */
653         for (i=infoPtr->uNumItem, pItem = infoPtr->items; i; i--, pItem++)
654         {
655             if (pItem->iOrder > iOrder)
656             pItem->iOrder--;
657         }
658         Free (oldItems);
659     }
660
661     HEADER_SetItemBounds (hwnd);
662
663     InvalidateRect(hwnd, NULL, FALSE);
664
665     return TRUE;
666 }
667
668
669 static LRESULT
670 HEADER_GetImageList (HWND hwnd)
671 {
672     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
673
674     return (LRESULT)infoPtr->himl;
675 }
676
677
678 static LRESULT
679 HEADER_GetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
680 {
681     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
682     HDITEMA   *phdi = (HDITEMA*)lParam;
683     INT       nItem = (INT)wParam;
684     HEADER_ITEM *lpItem;
685
686     if (!phdi)
687         return FALSE;
688     if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem))
689         return FALSE;
690
691     TRACE("[nItem=%d]\n", nItem);
692
693     if (phdi->mask == 0)
694         return TRUE;
695
696     lpItem = &infoPtr->items[nItem];
697     if (phdi->mask & HDI_BITMAP)
698         phdi->hbm = lpItem->hbm;
699
700     if (phdi->mask & HDI_FORMAT)
701         phdi->fmt = lpItem->fmt;
702
703     if (phdi->mask & HDI_WIDTH)
704         phdi->cxy = lpItem->cxy;
705
706     if (phdi->mask & HDI_LPARAM)
707         phdi->lParam = lpItem->lParam;
708
709     if (phdi->mask & HDI_TEXT) {
710         if (lpItem->pszText != LPSTR_TEXTCALLBACKW) {
711             if (lpItem->pszText)
712                 WideCharToMultiByte (CP_ACP, 0, lpItem->pszText, -1,
713                                      phdi->pszText, phdi->cchTextMax, NULL, NULL);
714             else
715                 *phdi->pszText = 0;
716         }
717         else
718             phdi->pszText = LPSTR_TEXTCALLBACKA;
719     }
720
721     if (phdi->mask & HDI_IMAGE)
722         phdi->iImage = lpItem->iImage;
723
724     if (phdi->mask & HDI_ORDER)
725         phdi->iOrder = lpItem->iOrder;
726
727     return TRUE;
728 }
729
730
731 static LRESULT
732 HEADER_GetItemW (HWND hwnd, WPARAM wParam, LPARAM lParam)
733 {
734     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
735     HDITEMW   *phdi = (HDITEMW*)lParam;
736     INT       nItem = (INT)wParam;
737     HEADER_ITEM *lpItem;
738
739     if (!phdi)
740         return FALSE;
741     if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem))
742         return FALSE;
743
744     TRACE("[nItem=%d]\n", nItem);
745
746     if (phdi->mask == 0)
747         return TRUE;
748
749     lpItem = &infoPtr->items[nItem];
750     if (phdi->mask & HDI_BITMAP)
751         phdi->hbm = lpItem->hbm;
752
753     if (phdi->mask & HDI_FORMAT)
754         phdi->fmt = lpItem->fmt;
755
756     if (phdi->mask & HDI_WIDTH)
757         phdi->cxy = lpItem->cxy;
758
759     if (phdi->mask & HDI_LPARAM)
760         phdi->lParam = lpItem->lParam;
761
762     if (phdi->mask & HDI_TEXT) {
763         if (lpItem->pszText != LPSTR_TEXTCALLBACKW) {
764             if (lpItem->pszText)
765                 lstrcpynW (phdi->pszText, lpItem->pszText, phdi->cchTextMax);
766             else
767                 *phdi->pszText = 0;
768         }
769         else
770             phdi->pszText = LPSTR_TEXTCALLBACKW;
771     }
772
773     if (phdi->mask & HDI_IMAGE)
774         phdi->iImage = lpItem->iImage;
775
776     if (phdi->mask & HDI_ORDER)
777         phdi->iOrder = lpItem->iOrder;
778
779     return TRUE;
780 }
781
782
783 inline static LRESULT
784 HEADER_GetItemCount (HWND hwnd)
785 {
786     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
787     return infoPtr->uNumItem;
788 }
789
790
791 static LRESULT
792 HEADER_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
793 {
794     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
795     INT iItem = (INT)wParam;
796     LPRECT lpRect = (LPRECT)lParam;
797
798     if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem))
799         return FALSE;
800
801     lpRect->left   = infoPtr->items[iItem].rect.left;
802     lpRect->right  = infoPtr->items[iItem].rect.right;
803     lpRect->top    = infoPtr->items[iItem].rect.top;
804     lpRect->bottom = infoPtr->items[iItem].rect.bottom;
805
806     return TRUE;
807 }
808
809
810 static LRESULT
811 HEADER_GetOrderArray(HWND hwnd, WPARAM wParam, LPARAM lParam)
812 {
813     int i;
814     LPINT order = (LPINT) lParam;
815     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
816
817     if ((int)wParam <infoPtr->uNumItem)
818       return FALSE;
819     for (i=0; i<(int)wParam; i++)
820       *order++=HEADER_OrderToIndex(hwnd,i);
821     return TRUE;
822 }
823
824 static LRESULT
825 HEADER_SetOrderArray(HWND hwnd, WPARAM wParam, LPARAM lParam)
826 {
827     int i;
828     LPINT order = (LPINT) lParam;
829     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
830     HEADER_ITEM *lpItem;
831
832     if ((int)wParam <infoPtr->uNumItem)
833       return FALSE;
834     for (i=0; i<(int)wParam; i++)
835       {
836         lpItem = &infoPtr->items[*order++];
837         lpItem->iOrder=i;
838       }
839     infoPtr->bRectsValid=0;
840     InvalidateRect(hwnd, NULL, FALSE);
841     return TRUE;
842 }
843
844 inline static LRESULT
845 HEADER_GetUnicodeFormat (HWND hwnd)
846 {
847     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
848     return infoPtr->bUnicode;
849 }
850
851
852 static LRESULT
853 HEADER_HitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
854 {
855     LPHDHITTESTINFO phti = (LPHDHITTESTINFO)lParam;
856
857     HEADER_InternalHitTest (hwnd, &phti->pt, &phti->flags, &phti->iItem);
858
859     if (phti->flags == HHT_ONHEADER)
860         return phti->iItem;
861     else
862         return -1;
863 }
864
865
866 static LRESULT
867 HEADER_InsertItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
868 {
869     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
870     HDITEMA   *phdi = (HDITEMA*)lParam;
871     INT       nItem = (INT)wParam;
872     HEADER_ITEM *lpItem;
873     INT       len, i, iOrder;
874
875     if ((phdi == NULL) || (nItem < 0))
876         return -1;
877
878     if (nItem > infoPtr->uNumItem)
879         nItem = infoPtr->uNumItem;
880
881     iOrder = (phdi->mask & HDI_ORDER) ? phdi->iOrder : nItem;
882
883     if (infoPtr->uNumItem == 0) {
884         infoPtr->items = Alloc (sizeof (HEADER_ITEM));
885         infoPtr->uNumItem++;
886     }
887     else {
888         HEADER_ITEM *oldItems = infoPtr->items;
889
890         infoPtr->uNumItem++;
891         infoPtr->items = Alloc (sizeof (HEADER_ITEM) * infoPtr->uNumItem);
892         if (nItem == 0) {
893             memcpy (&infoPtr->items[1], &oldItems[0],
894                     (infoPtr->uNumItem-1) * sizeof(HEADER_ITEM));
895         }
896         else
897         {
898               /* pre insert copy */
899             if (nItem > 0) {
900                  memcpy (&infoPtr->items[0], &oldItems[0],
901                          nItem * sizeof(HEADER_ITEM));
902             }
903
904             /* post insert copy */
905             if (nItem < infoPtr->uNumItem - 1) {
906                 memcpy (&infoPtr->items[nItem+1], &oldItems[nItem],
907                         (infoPtr->uNumItem - nItem - 1) * sizeof(HEADER_ITEM));
908             }
909         }
910
911         Free (oldItems);
912     }
913
914     for (i=0; i < infoPtr->uNumItem; i++)
915     {
916         if (infoPtr->items[i].iOrder >= iOrder)
917             infoPtr->items[i].iOrder++;
918     }
919
920     lpItem = &infoPtr->items[nItem];
921     lpItem->bDown = FALSE;
922
923     if (phdi->mask & HDI_WIDTH)
924         lpItem->cxy = phdi->cxy;
925
926     if (phdi->mask & HDI_TEXT) {
927         static char empty[] = "";
928         if (!phdi->pszText) /* null pointer check */
929             phdi->pszText = empty;
930         if (phdi->pszText != LPSTR_TEXTCALLBACKA) {
931             len = MultiByteToWideChar(CP_ACP, 0, phdi->pszText, -1, NULL, 0);
932             lpItem->pszText = Alloc( len*sizeof(WCHAR) );
933             MultiByteToWideChar(CP_ACP, 0, phdi->pszText, -1, lpItem->pszText, len);
934         }
935         else
936             lpItem->pszText = LPSTR_TEXTCALLBACKW;
937     }
938
939     if (phdi->mask & HDI_FORMAT)
940         lpItem->fmt = phdi->fmt;
941
942     if (lpItem->fmt == 0)
943         lpItem->fmt = HDF_LEFT;
944
945     if (!(lpItem->fmt & HDF_STRING) && (phdi->mask & HDI_TEXT))
946       {
947         lpItem->fmt |= HDF_STRING;
948       }
949     if (phdi->mask & HDI_BITMAP)
950         lpItem->hbm = phdi->hbm;
951
952     if (phdi->mask & HDI_LPARAM)
953         lpItem->lParam = phdi->lParam;
954
955     if (phdi->mask & HDI_IMAGE)
956         lpItem->iImage = phdi->iImage;
957
958     lpItem->iOrder = iOrder;
959
960     HEADER_SetItemBounds (hwnd);
961
962     InvalidateRect(hwnd, NULL, FALSE);
963
964     return nItem;
965 }
966
967
968 static LRESULT
969 HEADER_InsertItemW (HWND hwnd, WPARAM wParam, LPARAM lParam)
970 {
971     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
972     HDITEMW   *phdi = (HDITEMW*)lParam;
973     INT       nItem = (INT)wParam;
974     HEADER_ITEM *lpItem;
975     INT       len, i, iOrder;
976
977     if ((phdi == NULL) || (nItem < 0))
978         return -1;
979
980     if (nItem > infoPtr->uNumItem)
981         nItem = infoPtr->uNumItem;
982
983     iOrder = (phdi->mask & HDI_ORDER) ? phdi->iOrder : nItem;
984
985     if (infoPtr->uNumItem == 0) {
986         infoPtr->items = Alloc (sizeof (HEADER_ITEM));
987         infoPtr->uNumItem++;
988     }
989     else {
990         HEADER_ITEM *oldItems = infoPtr->items;
991
992         infoPtr->uNumItem++;
993         infoPtr->items = Alloc (sizeof (HEADER_ITEM) * infoPtr->uNumItem);
994         if (nItem == 0) {
995             memcpy (&infoPtr->items[1], &oldItems[0],
996                     (infoPtr->uNumItem-1) * sizeof(HEADER_ITEM));
997         }
998         else
999         {
1000               /* pre insert copy */
1001             if (nItem > 0) {
1002                  memcpy (&infoPtr->items[0], &oldItems[0],
1003                          nItem * sizeof(HEADER_ITEM));
1004             }
1005
1006             /* post insert copy */
1007             if (nItem < infoPtr->uNumItem - 1) {
1008                 memcpy (&infoPtr->items[nItem+1], &oldItems[nItem],
1009                         (infoPtr->uNumItem - nItem - 1) * sizeof(HEADER_ITEM));
1010             }
1011         }
1012
1013         Free (oldItems);
1014     }
1015
1016     for (i=0; i < infoPtr->uNumItem; i++)
1017     {
1018         if (infoPtr->items[i].iOrder >= iOrder)
1019             infoPtr->items[i].iOrder++;
1020     }
1021
1022     lpItem = &infoPtr->items[nItem];
1023     lpItem->bDown = FALSE;
1024
1025     if (phdi->mask & HDI_WIDTH)
1026         lpItem->cxy = phdi->cxy;
1027
1028     if (phdi->mask & HDI_TEXT) {
1029         WCHAR wide_null_char = 0;
1030         if (!phdi->pszText) /* null pointer check */
1031             phdi->pszText = &wide_null_char;
1032         if (phdi->pszText != LPSTR_TEXTCALLBACKW) {
1033             len = strlenW (phdi->pszText);
1034             lpItem->pszText = Alloc ((len+1)*sizeof(WCHAR));
1035             strcpyW (lpItem->pszText, phdi->pszText);
1036         }
1037         else
1038             lpItem->pszText = LPSTR_TEXTCALLBACKW;
1039     }
1040
1041     if (phdi->mask & HDI_FORMAT)
1042         lpItem->fmt = phdi->fmt;
1043
1044     if (lpItem->fmt == 0)
1045         lpItem->fmt = HDF_LEFT;
1046
1047     if (!(lpItem->fmt &HDF_STRING) && (phdi->mask & HDI_TEXT))
1048       {
1049         lpItem->fmt |= HDF_STRING;
1050       }
1051     if (phdi->mask & HDI_BITMAP)
1052         lpItem->hbm = phdi->hbm;
1053
1054     if (phdi->mask & HDI_LPARAM)
1055         lpItem->lParam = phdi->lParam;
1056
1057     if (phdi->mask & HDI_IMAGE)
1058         lpItem->iImage = phdi->iImage;
1059
1060     lpItem->iOrder = iOrder;
1061
1062     HEADER_SetItemBounds (hwnd);
1063
1064     InvalidateRect(hwnd, NULL, FALSE);
1065
1066     return nItem;
1067 }
1068
1069
1070 static LRESULT
1071 HEADER_Layout (HWND hwnd, WPARAM wParam, LPARAM lParam)
1072 {
1073     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1074     LPHDLAYOUT lpLayout = (LPHDLAYOUT)lParam;
1075
1076     lpLayout->pwpos->hwnd = hwnd;
1077     lpLayout->pwpos->hwndInsertAfter = 0;
1078     lpLayout->pwpos->x = lpLayout->prc->left;
1079     lpLayout->pwpos->y = lpLayout->prc->top;
1080     lpLayout->pwpos->cx = lpLayout->prc->right - lpLayout->prc->left;
1081     if (GetWindowLongA (hwnd, GWL_STYLE) & HDS_HIDDEN)
1082         lpLayout->pwpos->cy = 0;
1083     else {
1084         lpLayout->pwpos->cy = infoPtr->nHeight;
1085         lpLayout->prc->top += infoPtr->nHeight;
1086     }
1087     lpLayout->pwpos->flags = SWP_NOZORDER;
1088
1089     TRACE("Layout x=%d y=%d cx=%d cy=%d\n",
1090            lpLayout->pwpos->x, lpLayout->pwpos->y,
1091            lpLayout->pwpos->cx, lpLayout->pwpos->cy);
1092
1093     infoPtr->bRectsValid = FALSE;
1094
1095     return TRUE;
1096 }
1097
1098
1099 static LRESULT
1100 HEADER_SetImageList (HWND hwnd, HIMAGELIST himl)
1101 {
1102     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1103     HIMAGELIST himlOld;
1104
1105     TRACE("(himl 0x%x)\n", (int)himl);
1106     himlOld = infoPtr->himl;
1107     infoPtr->himl = himl;
1108
1109     /* FIXME: Refresh needed??? */
1110
1111     return (LRESULT)himlOld;
1112 }
1113
1114
1115 static LRESULT
1116 HEADER_GetBitmapMargin(HWND hwnd)
1117 {
1118     HEADER_INFO *infoPtr = HEADER_GetInfoPtr(hwnd);
1119     
1120     return infoPtr->iMargin;
1121 }
1122
1123 static LRESULT
1124 HEADER_SetBitmapMargin(HWND hwnd, WPARAM wParam)
1125 {
1126     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1127     INT oldMargin = infoPtr->iMargin;
1128
1129     infoPtr->iMargin = (INT)wParam;
1130
1131     return oldMargin;
1132 }
1133
1134 static LRESULT
1135 HEADER_SetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1136 {
1137     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1138     HDITEMA *phdi = (HDITEMA*)lParam;
1139     INT nItem = (INT)wParam;
1140     HEADER_ITEM *lpItem;
1141
1142     if (phdi == NULL)
1143         return FALSE;
1144     if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem))
1145         return FALSE;
1146
1147     TRACE("[nItem=%d]\n", nItem);
1148
1149         if (HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGINGA, nItem, phdi->mask))
1150         return FALSE;
1151
1152     lpItem = &infoPtr->items[nItem];
1153     if (phdi->mask & HDI_BITMAP)
1154         lpItem->hbm = phdi->hbm;
1155
1156     if (phdi->mask & HDI_FORMAT)
1157         lpItem->fmt = phdi->fmt;
1158
1159     if (phdi->mask & HDI_LPARAM)
1160         lpItem->lParam = phdi->lParam;
1161
1162     if (phdi->mask & HDI_TEXT) {
1163         if (phdi->pszText != LPSTR_TEXTCALLBACKA) {
1164             if (lpItem->pszText) {
1165                 Free (lpItem->pszText);
1166                 lpItem->pszText = NULL;
1167             }
1168             if (phdi->pszText) {
1169                 INT len = MultiByteToWideChar (CP_ACP,0,phdi->pszText,-1,NULL,0);
1170                 lpItem->pszText = Alloc( len*sizeof(WCHAR) );
1171                 MultiByteToWideChar (CP_ACP,0,phdi->pszText,-1,lpItem->pszText,len);
1172             }
1173         }
1174         else
1175             lpItem->pszText = LPSTR_TEXTCALLBACKW;
1176     }
1177
1178     if (phdi->mask & HDI_WIDTH)
1179         lpItem->cxy = phdi->cxy;
1180
1181     if (phdi->mask & HDI_IMAGE)
1182         lpItem->iImage = phdi->iImage;
1183
1184     if (phdi->mask & HDI_ORDER)
1185       {
1186         lpItem->iOrder = phdi->iOrder;
1187       }
1188     else
1189       lpItem->iOrder = nItem;
1190
1191         HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGEDA, nItem, phdi->mask);
1192
1193     HEADER_SetItemBounds (hwnd);
1194
1195     InvalidateRect(hwnd, NULL, FALSE);
1196
1197     return TRUE;
1198 }
1199
1200
1201 static LRESULT
1202 HEADER_SetItemW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1203 {
1204     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1205     HDITEMW *phdi = (HDITEMW*)lParam;
1206     INT nItem = (INT)wParam;
1207     HEADER_ITEM *lpItem;
1208
1209     if (phdi == NULL)
1210         return FALSE;
1211     if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem))
1212         return FALSE;
1213
1214     TRACE("[nItem=%d]\n", nItem);
1215
1216         if (HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGINGW, nItem, phdi->mask))
1217         return FALSE;
1218
1219     lpItem = &infoPtr->items[nItem];
1220     if (phdi->mask & HDI_BITMAP)
1221         lpItem->hbm = phdi->hbm;
1222
1223     if (phdi->mask & HDI_FORMAT)
1224         lpItem->fmt = phdi->fmt;
1225
1226     if (phdi->mask & HDI_LPARAM)
1227         lpItem->lParam = phdi->lParam;
1228
1229     if (phdi->mask & HDI_TEXT) {
1230         if (phdi->pszText != LPSTR_TEXTCALLBACKW) {
1231             if (lpItem->pszText) {
1232                 Free (lpItem->pszText);
1233                 lpItem->pszText = NULL;
1234             }
1235             if (phdi->pszText) {
1236                 INT len = strlenW (phdi->pszText);
1237                 lpItem->pszText = Alloc ((len+1)*sizeof(WCHAR));
1238                 strcpyW (lpItem->pszText, phdi->pszText);
1239             }
1240         }
1241         else
1242             lpItem->pszText = LPSTR_TEXTCALLBACKW;
1243     }
1244
1245     if (phdi->mask & HDI_WIDTH)
1246         lpItem->cxy = phdi->cxy;
1247
1248     if (phdi->mask & HDI_IMAGE)
1249         lpItem->iImage = phdi->iImage;
1250
1251     if (phdi->mask & HDI_ORDER)
1252       {
1253         lpItem->iOrder = phdi->iOrder;
1254       }
1255     else
1256       lpItem->iOrder = nItem;
1257
1258         HEADER_SendHeaderNotify(hwnd, HDN_ITEMCHANGEDW, nItem, phdi->mask);
1259
1260     HEADER_SetItemBounds (hwnd);
1261
1262     InvalidateRect(hwnd, NULL, FALSE);
1263
1264     return TRUE;
1265 }
1266
1267 inline static LRESULT
1268 HEADER_SetUnicodeFormat (HWND hwnd, WPARAM wParam)
1269 {
1270     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1271     BOOL bTemp = infoPtr->bUnicode;
1272
1273     infoPtr->bUnicode = (BOOL)wParam;
1274
1275     return bTemp;
1276 }
1277
1278
1279 static LRESULT
1280 HEADER_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
1281 {
1282     HEADER_INFO *infoPtr;
1283     TEXTMETRICA tm;
1284     HFONT hOldFont;
1285     HDC   hdc;
1286
1287     infoPtr = (HEADER_INFO *)Alloc (sizeof(HEADER_INFO));
1288     SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
1289
1290     infoPtr->hwndNotify = ((LPCREATESTRUCTA)lParam)->hwndParent;
1291     infoPtr->uNumItem = 0;
1292     infoPtr->hFont = 0;
1293     infoPtr->items = 0;
1294     infoPtr->bRectsValid = FALSE;
1295     infoPtr->hcurArrow = LoadCursorA (0, (LPSTR)IDC_ARROW);
1296     infoPtr->hcurDivider = LoadCursorA (COMCTL32_hModule, MAKEINTRESOURCEA(IDC_DIVIDER));
1297     infoPtr->hcurDivopen = LoadCursorA (COMCTL32_hModule, MAKEINTRESOURCEA(IDC_DIVIDEROPEN));
1298     infoPtr->bPressed  = FALSE;
1299     infoPtr->bTracking = FALSE;
1300     infoPtr->iMoveItem = 0;
1301     infoPtr->himl = 0;
1302     infoPtr->iHotItem = -1;
1303     infoPtr->bUnicode = IsWindowUnicode (hwnd);
1304     infoPtr->iMargin = 3*GetSystemMetrics(SM_CXEDGE);
1305     infoPtr->nNotifyFormat =
1306         SendMessageA (infoPtr->hwndNotify, WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY);
1307
1308     hdc = GetDC (0);
1309     hOldFont = SelectObject (hdc, GetStockObject (SYSTEM_FONT));
1310     GetTextMetricsA (hdc, &tm);
1311     infoPtr->nHeight = tm.tmHeight + VERT_BORDER;
1312     SelectObject (hdc, hOldFont);
1313     ReleaseDC (0, hdc);
1314
1315     return 0;
1316 }
1317
1318
1319 static LRESULT
1320 HEADER_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
1321 {
1322     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1323     HEADER_ITEM *lpItem;
1324     INT nItem;
1325
1326     if (infoPtr->items) {
1327         lpItem = infoPtr->items;
1328         for (nItem = 0; nItem < infoPtr->uNumItem; nItem++, lpItem++) {
1329             if ((lpItem->pszText) && (lpItem->pszText != LPSTR_TEXTCALLBACKW))
1330                 Free (lpItem->pszText);
1331         }
1332         Free (infoPtr->items);
1333     }
1334
1335     if (infoPtr->himl)
1336         ImageList_Destroy (infoPtr->himl);
1337
1338     Free (infoPtr);
1339     SetWindowLongA (hwnd, 0, 0);
1340     return 0;
1341 }
1342
1343
1344 static inline LRESULT
1345 HEADER_GetFont (HWND hwnd)
1346 {
1347     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1348
1349     return (LRESULT)infoPtr->hFont;
1350 }
1351
1352
1353 static LRESULT
1354 HEADER_LButtonDblClk (HWND hwnd, WPARAM wParam, LPARAM lParam)
1355 {
1356     POINT pt;
1357     UINT  flags;
1358     INT   nItem;
1359
1360     pt.x = (INT)LOWORD(lParam);
1361     pt.y = (INT)HIWORD(lParam);
1362     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1363
1364     if ((GetWindowLongA (hwnd, GWL_STYLE) & HDS_BUTTONS) && (flags == HHT_ONHEADER))
1365         HEADER_SendHeaderNotify (hwnd, HDN_ITEMDBLCLICKA, nItem,0);
1366     else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN))
1367         HEADER_SendHeaderNotify (hwnd, HDN_DIVIDERDBLCLICKA, nItem,0);
1368
1369     return 0;
1370 }
1371
1372
1373 static LRESULT
1374 HEADER_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
1375 {
1376     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1377     DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1378     POINT pt;
1379     UINT  flags;
1380     INT   nItem;
1381     HDC   hdc;
1382
1383     pt.x = (INT)LOWORD(lParam);
1384     pt.y = (INT)HIWORD(lParam);
1385     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1386
1387     if ((dwStyle & HDS_BUTTONS) && (flags == HHT_ONHEADER)) {
1388         SetCapture (hwnd);
1389         infoPtr->bCaptured = TRUE;
1390         infoPtr->bPressed  = TRUE;
1391         infoPtr->iMoveItem = nItem;
1392
1393         infoPtr->items[nItem].bDown = TRUE;
1394
1395         /* Send WM_CUSTOMDRAW */
1396         hdc = GetDC (hwnd);
1397         HEADER_RefreshItem (hwnd, hdc, nItem);
1398         ReleaseDC (hwnd, hdc);
1399
1400         TRACE("Pressed item %d!\n", nItem);
1401     }
1402     else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN)) {
1403         if (!(HEADER_SendHeaderNotify (hwnd, HDN_BEGINTRACKA, nItem,0))) {
1404             SetCapture (hwnd);
1405             infoPtr->bCaptured = TRUE;
1406             infoPtr->bTracking = TRUE;
1407             infoPtr->iMoveItem = nItem;
1408             infoPtr->nOldWidth = infoPtr->items[nItem].cxy;
1409             infoPtr->xTrackOffset = infoPtr->items[nItem].rect.right - pt.x;
1410
1411             if (!(dwStyle & HDS_FULLDRAG)) {
1412                 infoPtr->xOldTrack = infoPtr->items[nItem].rect.right;
1413                 hdc = GetDC (hwnd);
1414                 HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1415                 ReleaseDC (hwnd, hdc);
1416             }
1417
1418             TRACE("Begin tracking item %d!\n", nItem);
1419         }
1420     }
1421
1422     return 0;
1423 }
1424
1425
1426 static LRESULT
1427 HEADER_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1428 {
1429     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1430     /*
1431      *DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1432      */
1433     POINT pt;
1434     UINT  flags;
1435     INT   nItem, nWidth;
1436     HDC   hdc;
1437
1438     pt.x = (INT)(SHORT)LOWORD(lParam);
1439     pt.y = (INT)(SHORT)HIWORD(lParam);
1440     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1441
1442     if (infoPtr->bPressed) {
1443         if ((nItem == infoPtr->iMoveItem) && (flags == HHT_ONHEADER)) {
1444             infoPtr->items[infoPtr->iMoveItem].bDown = FALSE;
1445             hdc = GetDC (hwnd);
1446             HEADER_RefreshItem (hwnd, hdc, infoPtr->iMoveItem);
1447             ReleaseDC (hwnd, hdc);
1448
1449             HEADER_SendClickNotify (hwnd, HDN_ITEMCLICKA, infoPtr->iMoveItem);
1450         }
1451         else if (flags == HHT_ONHEADER)
1452           {
1453             HEADER_ITEM *lpItem;
1454             INT newindex = HEADER_IndexToOrder(hwnd,nItem);
1455             INT oldindex = HEADER_IndexToOrder(hwnd,infoPtr->iMoveItem);
1456
1457             TRACE("Exchanging [index:order] [%d:%d] [%d:%d]\n",
1458                   infoPtr->iMoveItem,oldindex,nItem,newindex);
1459             lpItem= &infoPtr->items[nItem];
1460             lpItem->iOrder=oldindex;
1461
1462             lpItem= &infoPtr->items[infoPtr->iMoveItem];
1463             lpItem->iOrder = newindex;
1464
1465             infoPtr->bRectsValid = FALSE;
1466             InvalidateRect(hwnd, NULL, FALSE);
1467             /* FIXME: Should some WM_NOTIFY be sent */
1468           }
1469
1470         TRACE("Released item %d!\n", infoPtr->iMoveItem);
1471         infoPtr->bPressed = FALSE;
1472     }
1473     else if (infoPtr->bTracking) {
1474         TRACE("End tracking item %d!\n", infoPtr->iMoveItem);
1475         infoPtr->bTracking = FALSE;
1476
1477         HEADER_SendHeaderNotify (hwnd, HDN_ENDTRACKA, infoPtr->iMoveItem,HDI_WIDTH);
1478
1479          /*
1480           * we want to do this even for HDS_FULLDRAG because this is where
1481           * we send the HDN_ITEMCHANGING and HDN_ITEMCHANGED notifications
1482           *
1483           * if (!(dwStyle & HDS_FULLDRAG)) {
1484           */
1485
1486             hdc = GetDC (hwnd);
1487             HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1488             ReleaseDC (hwnd, hdc);
1489                         if (HEADER_SendHeaderNotify(hwnd, HDN_ITEMCHANGINGA, infoPtr->iMoveItem, HDI_WIDTH))
1490             {
1491                 infoPtr->items[infoPtr->iMoveItem].cxy = infoPtr->nOldWidth;
1492             }
1493             else {
1494                 nWidth = pt.x - infoPtr->items[infoPtr->iMoveItem].rect.left + infoPtr->xTrackOffset;
1495                 if (nWidth < 0)
1496                     nWidth = 0;
1497                 infoPtr->items[infoPtr->iMoveItem].cxy = nWidth;
1498             }
1499
1500                         HEADER_SendHeaderNotify(hwnd, HDN_ITEMCHANGINGA, infoPtr->iMoveItem, HDI_WIDTH);
1501             HEADER_SetItemBounds (hwnd);
1502             InvalidateRect(hwnd, NULL, FALSE);
1503        /*
1504         * }
1505         */
1506     }
1507
1508     if (infoPtr->bCaptured) {
1509         infoPtr->bCaptured = FALSE;
1510         ReleaseCapture ();
1511         HEADER_SendSimpleNotify (hwnd, NM_RELEASEDCAPTURE);
1512     }
1513
1514     return 0;
1515 }
1516
1517
1518 static LRESULT
1519 HEADER_NotifyFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
1520 {
1521     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1522
1523     switch (lParam)
1524     {
1525         case NF_QUERY:
1526             return infoPtr->nNotifyFormat;
1527
1528         case NF_REQUERY:
1529             infoPtr->nNotifyFormat =
1530                 SendMessageA ((HWND)wParam, WM_NOTIFYFORMAT,
1531                               (WPARAM)hwnd, (LPARAM)NF_QUERY);
1532             return infoPtr->nNotifyFormat;
1533     }
1534
1535     return 0;
1536 }
1537
1538
1539 static LRESULT
1540 HEADER_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
1541 {
1542     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1543     DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1544     POINT pt;
1545     UINT  flags;
1546     INT   nItem, nWidth;
1547     HDC   hdc;
1548
1549     pt.x = (INT)(SHORT)LOWORD(lParam);
1550     pt.y = (INT)(SHORT)HIWORD(lParam);
1551     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1552
1553     if ((dwStyle & HDS_BUTTONS) && (dwStyle & HDS_HOTTRACK)) {
1554         if (flags & (HHT_ONHEADER | HHT_ONDIVIDER | HHT_ONDIVOPEN))
1555             infoPtr->iHotItem = nItem;
1556         else
1557             infoPtr->iHotItem = -1;
1558         InvalidateRect(hwnd, NULL, FALSE);
1559     }
1560
1561     if (infoPtr->bCaptured) {
1562         if (infoPtr->bPressed) {
1563             if ((nItem == infoPtr->iMoveItem) && (flags == HHT_ONHEADER))
1564                 infoPtr->items[infoPtr->iMoveItem].bDown = TRUE;
1565             else
1566                 infoPtr->items[infoPtr->iMoveItem].bDown = FALSE;
1567             hdc = GetDC (hwnd);
1568             HEADER_RefreshItem (hwnd, hdc, infoPtr->iMoveItem);
1569             ReleaseDC (hwnd, hdc);
1570
1571             TRACE("Moving pressed item %d!\n", infoPtr->iMoveItem);
1572         }
1573         else if (infoPtr->bTracking) {
1574             if (dwStyle & HDS_FULLDRAG) {
1575                 if (HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGINGA, infoPtr->iMoveItem, HDI_WIDTH))
1576                 {
1577                 nWidth = pt.x - infoPtr->items[infoPtr->iMoveItem].rect.left + infoPtr->xTrackOffset;
1578                 if (nWidth < 0)
1579                   nWidth = 0;
1580                 infoPtr->items[infoPtr->iMoveItem].cxy = nWidth;
1581                         HEADER_SendHeaderNotify(hwnd, HDN_ITEMCHANGEDA, infoPtr->iMoveItem, HDI_WIDTH);
1582                 }
1583                 HEADER_SetItemBounds (hwnd);
1584                 InvalidateRect(hwnd, NULL, FALSE);
1585             }
1586             else {
1587                 hdc = GetDC (hwnd);
1588                 HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1589                 infoPtr->xOldTrack = pt.x + infoPtr->xTrackOffset;
1590                 if (infoPtr->xOldTrack < infoPtr->items[infoPtr->iMoveItem].rect.left)
1591                     infoPtr->xOldTrack = infoPtr->items[infoPtr->iMoveItem].rect.left;
1592                 infoPtr->items[infoPtr->iMoveItem].cxy =
1593                     infoPtr->xOldTrack - infoPtr->items[infoPtr->iMoveItem].rect.left;
1594                 HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1595                 ReleaseDC (hwnd, hdc);
1596             HEADER_SendHeaderNotify (hwnd, HDN_TRACKA, infoPtr->iMoveItem, HDI_WIDTH);
1597             }
1598
1599             TRACE("Tracking item %d!\n", infoPtr->iMoveItem);
1600         }
1601     }
1602
1603     if ((dwStyle & HDS_BUTTONS) && (dwStyle & HDS_HOTTRACK)) {
1604         FIXME("hot track support!\n");
1605     }
1606
1607     return 0;
1608 }
1609
1610
1611 static LRESULT
1612 HEADER_Paint (HWND hwnd, WPARAM wParam)
1613 {
1614     HDC hdc;
1615     PAINTSTRUCT ps;
1616
1617     hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
1618     HEADER_Refresh (hwnd, hdc);
1619     if(!wParam)
1620         EndPaint (hwnd, &ps);
1621     return 0;
1622 }
1623
1624
1625 static LRESULT
1626 HEADER_RButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1627 {
1628     BOOL bRet;
1629     POINT pt;
1630
1631     pt.x = LOWORD(lParam);
1632     pt.y = HIWORD(lParam);
1633
1634     /* Send a Notify message */
1635     bRet = HEADER_SendSimpleNotify (hwnd, NM_RCLICK);
1636
1637     /* Change to screen coordinate for WM_CONTEXTMENU */
1638     ClientToScreen(hwnd, &pt);
1639
1640     /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
1641     SendMessageA( hwnd, WM_CONTEXTMENU, (WPARAM) hwnd, MAKELPARAM(pt.x, pt.y));
1642
1643     return bRet;
1644 }
1645
1646
1647 static LRESULT
1648 HEADER_SetCursor (HWND hwnd, WPARAM wParam, LPARAM lParam)
1649 {
1650     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1651     POINT pt;
1652     UINT  flags;
1653     INT   nItem;
1654
1655     TRACE("code=0x%X  id=0x%X\n", LOWORD(lParam), HIWORD(lParam));
1656
1657     GetCursorPos (&pt);
1658     ScreenToClient (hwnd, &pt);
1659
1660     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1661
1662     if (flags == HHT_ONDIVIDER)
1663         SetCursor (infoPtr->hcurDivider);
1664     else if (flags == HHT_ONDIVOPEN)
1665         SetCursor (infoPtr->hcurDivopen);
1666     else
1667         SetCursor (infoPtr->hcurArrow);
1668
1669     return 0;
1670 }
1671
1672
1673 static LRESULT
1674 HEADER_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
1675 {
1676     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1677     TEXTMETRICA tm;
1678     HFONT hFont, hOldFont;
1679     HDC hdc;
1680
1681     infoPtr->hFont = (HFONT)wParam;
1682
1683     hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
1684
1685     hdc = GetDC (0);
1686     hOldFont = SelectObject (hdc, hFont);
1687     GetTextMetricsA (hdc, &tm);
1688     infoPtr->nHeight = tm.tmHeight + VERT_BORDER;
1689     SelectObject (hdc, hOldFont);
1690     ReleaseDC (0, hdc);
1691
1692     infoPtr->bRectsValid = FALSE;
1693
1694     if (lParam) {
1695         InvalidateRect(hwnd, NULL, FALSE);
1696     }
1697
1698     return 0;
1699 }
1700
1701
1702 static LRESULT WINAPI
1703 HEADER_WindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1704 {
1705     TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx\n", hwnd, msg, wParam, lParam);
1706     if (!HEADER_GetInfoPtr (hwnd) && (msg != WM_CREATE))
1707         return DefWindowProcA (hwnd, msg, wParam, lParam);
1708     switch (msg) {
1709 /*      case HDM_CLEARFILTER: */
1710
1711         case HDM_CREATEDRAGIMAGE:
1712             return HEADER_CreateDragImage (hwnd, wParam);
1713
1714         case HDM_DELETEITEM:
1715             return HEADER_DeleteItem (hwnd, wParam);
1716
1717 /*      case HDM_EDITFILTER: */
1718
1719         case HDM_GETBITMAPMARGIN:
1720             return HEADER_GetBitmapMargin(hwnd);
1721
1722         case HDM_GETIMAGELIST:
1723             return HEADER_GetImageList (hwnd);
1724
1725         case HDM_GETITEMA:
1726             return HEADER_GetItemA (hwnd, wParam, lParam);
1727
1728         case HDM_GETITEMW:
1729             return HEADER_GetItemW (hwnd, wParam, lParam);
1730
1731         case HDM_GETITEMCOUNT:
1732             return HEADER_GetItemCount (hwnd);
1733
1734         case HDM_GETITEMRECT:
1735             return HEADER_GetItemRect (hwnd, wParam, lParam);
1736
1737         case HDM_GETORDERARRAY:
1738             return HEADER_GetOrderArray(hwnd, wParam, lParam);
1739
1740         case HDM_GETUNICODEFORMAT:
1741             return HEADER_GetUnicodeFormat (hwnd);
1742
1743         case HDM_HITTEST:
1744             return HEADER_HitTest (hwnd, wParam, lParam);
1745
1746         case HDM_INSERTITEMA:
1747             return HEADER_InsertItemA (hwnd, wParam, lParam);
1748
1749         case HDM_INSERTITEMW:
1750             return HEADER_InsertItemW (hwnd, wParam, lParam);
1751
1752         case HDM_LAYOUT:
1753             return HEADER_Layout (hwnd, wParam, lParam);
1754
1755         case HDM_ORDERTOINDEX:
1756             return HEADER_OrderToIndex(hwnd, wParam);
1757
1758         case HDM_SETBITMAPMARGIN:
1759             return HEADER_SetBitmapMargin(hwnd, wParam);
1760
1761 /*      case HDM_SETFILTERCHANGETIMEOUT: */
1762
1763 /*      case HDM_SETHOTDIVIDER: */
1764
1765         case HDM_SETIMAGELIST:
1766             return HEADER_SetImageList (hwnd, (HIMAGELIST)lParam);
1767
1768         case HDM_SETITEMA:
1769             return HEADER_SetItemA (hwnd, wParam, lParam);
1770
1771         case HDM_SETITEMW:
1772             return HEADER_SetItemW (hwnd, wParam, lParam);
1773
1774         case HDM_SETORDERARRAY:
1775             return HEADER_SetOrderArray(hwnd, wParam, lParam);
1776
1777         case HDM_SETUNICODEFORMAT:
1778             return HEADER_SetUnicodeFormat (hwnd, wParam);
1779
1780         case WM_CREATE:
1781             return HEADER_Create (hwnd, wParam, lParam);
1782
1783         case WM_DESTROY:
1784             return HEADER_Destroy (hwnd, wParam, lParam);
1785
1786         case WM_ERASEBKGND:
1787             return 1;
1788
1789         case WM_GETDLGCODE:
1790             return DLGC_WANTTAB | DLGC_WANTARROWS;
1791
1792         case WM_GETFONT:
1793             return HEADER_GetFont (hwnd);
1794
1795         case WM_LBUTTONDBLCLK:
1796             return HEADER_LButtonDblClk (hwnd, wParam, lParam);
1797
1798         case WM_LBUTTONDOWN:
1799             return HEADER_LButtonDown (hwnd, wParam, lParam);
1800
1801         case WM_LBUTTONUP:
1802             return HEADER_LButtonUp (hwnd, wParam, lParam);
1803
1804         case WM_MOUSEMOVE:
1805             return HEADER_MouseMove (hwnd, wParam, lParam);
1806
1807         case WM_NOTIFYFORMAT:
1808             return HEADER_NotifyFormat (hwnd, wParam, lParam);
1809
1810         case WM_SIZE:
1811             return HEADER_Size (hwnd, wParam);
1812
1813         case WM_PAINT:
1814             return HEADER_Paint (hwnd, wParam);
1815
1816         case WM_RBUTTONUP:
1817             return HEADER_RButtonUp (hwnd, wParam, lParam);
1818
1819         case WM_SETCURSOR:
1820             return HEADER_SetCursor (hwnd, wParam, lParam);
1821
1822         case WM_SETFONT:
1823             return HEADER_SetFont (hwnd, wParam, lParam);
1824
1825         default:
1826             if ((msg >= WM_USER) && (msg < WM_APP))
1827                 ERR("unknown msg %04x wp=%04x lp=%08lx\n",
1828                      msg, wParam, lParam );
1829             return DefWindowProcA (hwnd, msg, wParam, lParam);
1830     }
1831     return 0;
1832 }
1833
1834
1835 VOID
1836 HEADER_Register (void)
1837 {
1838     WNDCLASSA wndClass;
1839
1840     ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1841     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
1842     wndClass.lpfnWndProc   = (WNDPROC)HEADER_WindowProc;
1843     wndClass.cbClsExtra    = 0;
1844     wndClass.cbWndExtra    = sizeof(HEADER_INFO *);
1845     wndClass.hCursor       = LoadCursorA (0, (LPSTR)IDC_ARROW);
1846     wndClass.lpszClassName = WC_HEADERA;
1847
1848     RegisterClassA (&wndClass);
1849 }
1850
1851
1852 VOID
1853 HEADER_Unregister (void)
1854 {
1855     UnregisterClassA (WC_HEADERA, NULL);
1856 }