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