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