comctl32/header: Check Null before accessing struct member.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 <stdlib.h>
36 #include <string.h>
37
38 #include "windef.h"
39 #include "winbase.h"
40 #include "wine/unicode.h"
41 #include "wingdi.h"
42 #include "winuser.h"
43 #include "winnls.h"
44 #include "commctrl.h"
45 #include "comctl32.h"
46 #include "imagelist.h"
47 #include "tmschema.h"
48 #include "uxtheme.h"
49 #include "wine/debug.h"
50
51 WINE_DEFAULT_DEBUG_CHANNEL(header);
52
53 typedef struct
54 {
55     INT     cxy;
56     HBITMAP hbm;
57     LPWSTR    pszText;
58     INT     fmt;
59     LPARAM    lParam;
60     INT     iImage;
61     INT     iOrder;             /* see documentation of HD_ITEM */
62
63     BOOL    bDown;              /* is item pressed? (used for drawing) */
64     RECT    rect;               /* bounding rectangle of the item */
65     DWORD   callbackMask;       /* HDI_* flags for items that are callback */
66 } HEADER_ITEM;
67
68
69 typedef struct
70 {
71     HWND      hwndNotify;       /* Owner window to send notifications to */
72     INT       nNotifyFormat;    /* format used for WM_NOTIFY messages */
73     UINT      uNumItem;         /* number of items (columns) */
74     INT       nHeight;          /* height of the header (pixels) */
75     HFONT     hFont;            /* handle to the current font */
76     HCURSOR   hcurArrow;        /* handle to the arrow cursor */
77     HCURSOR   hcurDivider;      /* handle to a cursor (used over dividers) <-|-> */
78     HCURSOR   hcurDivopen;      /* handle to a cursor (used over dividers) <-||-> */
79     BOOL      bCaptured;        /* Is the mouse captured? */
80     BOOL      bPressed;         /* Is a header item pressed (down)? */
81     BOOL      bDragging;        /* Are we dragging an item? */
82     BOOL      bTracking;        /* Is in tracking mode? */
83     POINT     ptLButtonDown;    /* The point where the left button was pressed */
84     INT       iMoveItem;        /* index of tracked item. (Tracking mode) */
85     INT       xTrackOffset;     /* distance between the right side of the tracked item and the cursor */
86     INT       xOldTrack;        /* track offset (see above) after the last WM_MOUSEMOVE */
87     INT       nOldWidth;        /* width of a sizing item after the last WM_MOUSEMOVE */
88     INT       iHotItem;         /* index of hot item (cursor is over this item) */
89     INT       iHotDivider;      /* index of the hot divider (used while dragging an item or by HDM_SETHOTDIVIDER) */
90     INT       iMargin;          /* width of the margin that surrounds a bitmap */
91
92     HIMAGELIST  himl;           /* handle to an image list (may be 0) */
93     HEADER_ITEM *items;         /* pointer to array of HEADER_ITEM's */
94     INT         *order;         /* array of item IDs indexed by order */
95     BOOL        bRectsValid;    /* validity flag for bounding rectangles */
96 } HEADER_INFO;
97
98
99 #define VERT_BORDER     4
100 #define DIVIDER_WIDTH  10
101 #define HOT_DIVIDER_WIDTH 2
102 #define MAX_HEADER_TEXT_LEN 260
103 #define HDN_UNICODE_OFFSET 20
104 #define HDN_FIRST_UNICODE (HDN_FIRST-HDN_UNICODE_OFFSET)
105
106 #define HDI_SUPPORTED_FIELDS (HDI_WIDTH|HDI_TEXT|HDI_FORMAT|HDI_LPARAM|HDI_BITMAP|HDI_IMAGE|HDI_ORDER)
107 #define HDI_UNSUPPORTED_FIELDS (HDI_FILTER)
108 #define HDI_UNKNOWN_FIELDS (~(HDI_SUPPORTED_FIELDS|HDI_UNSUPPORTED_FIELDS|HDI_DI_SETITEM))
109 #define HDI_COMCTL32_4_0_FIELDS (HDI_WIDTH|HDI_TEXT|HDI_FORMAT|HDI_LPARAM|HDI_BITMAP)
110
111 #define HEADER_GetInfoPtr(hwnd) ((HEADER_INFO *)GetWindowLongPtrW(hwnd,0))
112
113 static BOOL HEADER_PrepareCallbackItems(HWND hwnd, INT iItem, INT reqMask);
114 static void HEADER_FreeCallbackItems(HEADER_ITEM *lpItem);
115
116 static const WCHAR themeClass[] = {'H','e','a','d','e','r',0};
117 static WCHAR emptyString[] = {0};
118
119 static void HEADER_DisposeItem(HEADER_ITEM *lpItem)
120 {
121     if (lpItem->pszText)
122     {
123         Free(lpItem->pszText);
124     }
125 }
126
127 static void HEADER_StoreHDItemInHeader(HEADER_ITEM *lpItem, UINT mask, HDITEMW *phdi, BOOL fUnicode)
128 {
129     if (mask & HDI_UNSUPPORTED_FIELDS)
130         FIXME("unsupported header fields %x\n", (mask & HDI_UNSUPPORTED_FIELDS));
131     
132     if (mask & HDI_BITMAP)
133         lpItem->hbm = phdi->hbm;
134
135     if (mask & HDI_FORMAT)
136         lpItem->fmt = phdi->fmt;
137
138     if (mask & HDI_LPARAM)
139         lpItem->lParam = phdi->lParam;
140
141     if (mask & HDI_WIDTH)
142         lpItem->cxy = phdi->cxy;
143
144     if (mask & HDI_IMAGE) 
145     {
146         lpItem->iImage = phdi->iImage;
147         if (phdi->iImage == I_IMAGECALLBACK)
148             lpItem->callbackMask |= HDI_IMAGE;
149         else
150             lpItem->callbackMask &= ~HDI_IMAGE;
151     }
152
153     if (mask & HDI_TEXT)
154     {
155         if (lpItem->pszText)
156         {
157             Free(lpItem->pszText);
158             lpItem->pszText = NULL;
159         }
160
161         if (phdi->pszText != LPSTR_TEXTCALLBACKW) /* covers != TEXTCALLBACKA too */
162         {
163             LPWSTR pszText = (phdi->pszText != NULL ? phdi->pszText : emptyString);
164             if (fUnicode)
165                 Str_SetPtrW(&lpItem->pszText, pszText);
166             else
167                 Str_SetPtrAtoW(&lpItem->pszText, (LPSTR)pszText);
168             lpItem->callbackMask &= ~HDI_TEXT;
169         }
170         else
171         {
172             lpItem->pszText = NULL;
173             lpItem->callbackMask |= HDI_TEXT;
174         }  
175     }
176 }
177
178 inline static LRESULT
179 HEADER_IndexToOrder (HWND hwnd, INT iItem)
180 {
181     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
182     HEADER_ITEM *lpItem = &infoPtr->items[iItem];
183     return lpItem->iOrder;
184 }
185
186
187 static INT
188 HEADER_OrderToIndex(HWND hwnd, WPARAM wParam)
189 {
190     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
191     INT iorder = (INT)wParam;
192
193     if ((iorder <0) || iorder >= infoPtr->uNumItem)
194       return iorder;
195     return infoPtr->order[iorder];
196 }
197
198 static void
199 HEADER_ChangeItemOrder(HEADER_INFO *infoPtr, INT iItem, INT iNewOrder)
200 {
201     HEADER_ITEM *lpItem = &infoPtr->items[iItem];
202     INT i, nMin, nMax;
203
204     TRACE("%d: %d->%d\n", iItem, lpItem->iOrder, iNewOrder);
205     if (lpItem->iOrder < iNewOrder)
206     {
207         memmove(&infoPtr->order[lpItem->iOrder],
208                &infoPtr->order[lpItem->iOrder + 1],
209                (iNewOrder - lpItem->iOrder) * sizeof(INT));
210     }
211     if (iNewOrder < lpItem->iOrder)
212     {
213         memmove(&infoPtr->order[iNewOrder + 1],
214                 &infoPtr->order[iNewOrder],
215                 (lpItem->iOrder - iNewOrder) * sizeof(INT));
216     }
217     infoPtr->order[iNewOrder] = iItem;
218     nMin = min(lpItem->iOrder, iNewOrder);
219     nMax = max(lpItem->iOrder, iNewOrder);
220     for (i = nMin; i <= nMax; i++)
221         infoPtr->items[infoPtr->order[i]].iOrder = i;
222 }
223
224 /* Note: if iItem is the last item then this function returns infoPtr->uNumItem */
225 static INT
226 HEADER_NextItem(HWND hwnd, INT iItem)
227 {
228     return HEADER_OrderToIndex(hwnd, HEADER_IndexToOrder(hwnd, iItem)+1);
229 }
230
231 static INT
232 HEADER_PrevItem(HWND hwnd, INT iItem)
233 {
234     return HEADER_OrderToIndex(hwnd, HEADER_IndexToOrder(hwnd, iItem)-1);
235 }
236
237 static void
238 HEADER_SetItemBounds (HWND hwnd)
239 {
240     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
241     HEADER_ITEM *phdi;
242     RECT rect;
243     unsigned int i;
244     int x;
245
246     infoPtr->bRectsValid = TRUE;
247
248     if (infoPtr->uNumItem == 0)
249         return;
250
251     GetClientRect (hwnd, &rect);
252
253     x = rect.left;
254     for (i = 0; i < infoPtr->uNumItem; i++) {
255         phdi = &infoPtr->items[HEADER_OrderToIndex(hwnd,i)];
256         phdi->rect.top = rect.top;
257         phdi->rect.bottom = rect.bottom;
258         phdi->rect.left = x;
259         phdi->rect.right = phdi->rect.left + ((phdi->cxy>0)?phdi->cxy:0);
260         x = phdi->rect.right;
261     }
262 }
263
264 static LRESULT
265 HEADER_Size (HWND hwnd, WPARAM wParam)
266 {
267     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
268
269     infoPtr->bRectsValid = FALSE;
270
271     return 0;
272 }
273
274 static void HEADER_GetHotDividerRect(HWND hwnd, HEADER_INFO *infoPtr, RECT *r)
275 {
276     INT iDivider = infoPtr->iHotDivider;
277     if (infoPtr->uNumItem > 0)
278     {
279         HEADER_ITEM *lpItem;
280         
281         if (iDivider < infoPtr->uNumItem)
282         {
283             lpItem = &infoPtr->items[iDivider];
284             r->left  = lpItem->rect.left - HOT_DIVIDER_WIDTH/2;
285             r->right = lpItem->rect.left + HOT_DIVIDER_WIDTH/2;
286         }
287         else
288         {
289             lpItem = &infoPtr->items[HEADER_OrderToIndex(hwnd, infoPtr->uNumItem-1)];
290             r->left  = lpItem->rect.right - HOT_DIVIDER_WIDTH/2;
291             r->right = lpItem->rect.right + HOT_DIVIDER_WIDTH/2;
292         }
293         r->top    = lpItem->rect.top;
294         r->bottom = lpItem->rect.bottom;
295     }
296     else
297     {
298         RECT clientRect;
299         GetClientRect(hwnd, &clientRect);
300         *r = clientRect;
301         r->right = r->left + HOT_DIVIDER_WIDTH/2;
302     }
303 }
304
305
306 static INT
307 HEADER_DrawItem (HWND hwnd, HDC hdc, INT iItem, BOOL bHotTrack)
308 {
309     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
310     HEADER_ITEM *phdi = &infoPtr->items[iItem];
311     RECT r;
312     INT  oldBkMode, cxEdge = GetSystemMetrics(SM_CXEDGE);
313     HTHEME theme = GetWindowTheme (hwnd);
314     NMCUSTOMDRAW nmcd;
315
316     TRACE("DrawItem(iItem %d bHotTrack %d unicode flag %d)\n", iItem, bHotTrack, (infoPtr->nNotifyFormat == NFR_UNICODE));
317
318     if (!infoPtr->bRectsValid)
319         HEADER_SetItemBounds(hwnd);
320
321     r = phdi->rect;
322     if (r.right - r.left == 0)
323         return phdi->rect.right;
324
325     if (theme != NULL) {
326         int state = (phdi->bDown) ? HIS_PRESSED :
327             (bHotTrack ? HIS_HOT : HIS_NORMAL);
328         DrawThemeBackground (theme, hdc, HP_HEADERITEM, state,
329             &r, NULL);
330         GetThemeBackgroundContentRect (theme, hdc, HP_HEADERITEM, state,
331             &r, &r);
332     }
333     else {
334         if (GetWindowLongW (hwnd, GWL_STYLE) & HDS_BUTTONS) {
335             if (phdi->bDown) {
336                 DrawEdge (hdc, &r, BDR_RAISEDOUTER,
337                             BF_RECT | BF_FLAT | BF_MIDDLE | BF_ADJUST);
338             }
339             else
340                 DrawEdge (hdc, &r, EDGE_RAISED,
341                             BF_RECT | BF_SOFT | BF_MIDDLE | BF_ADJUST);
342         }
343         else
344             DrawEdge (hdc, &r, EDGE_ETCHED, BF_BOTTOM | BF_RIGHT | BF_ADJUST);
345     }
346     if (phdi->bDown) {
347         r.left += 2;
348         r.top  += 2;
349     }
350
351     r.left  -= cxEdge;
352     r.right += cxEdge;
353
354     /* Set the colors before sending NM_CUSTOMDRAW so that it can change them */
355     SetTextColor (hdc, (bHotTrack && !theme) ? COLOR_HIGHLIGHT : COLOR_BTNTEXT);
356     SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
357
358     nmcd.hdr.hwndFrom = hwnd;
359     nmcd.hdr.idFrom   = GetWindowLongPtrW (hwnd, GWLP_ID);
360     nmcd.hdr.code     = NM_CUSTOMDRAW;
361     nmcd.dwDrawStage  = CDDS_PREPAINT | CDDS_ITEM | CDDS_ITEMPOSTERASE;
362     nmcd.hdc          = hdc;
363     nmcd.dwItemSpec   = iItem;
364     nmcd.rc           = r;
365     nmcd.uItemState   = phdi->bDown ? CDIS_SELECTED : 0;
366     nmcd.lItemlParam  = phdi->lParam;
367
368     SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, nmcd.hdr.idFrom, (LPARAM)&nmcd);
369
370     if (phdi->fmt & HDF_OWNERDRAW) {
371         DRAWITEMSTRUCT dis;
372
373         dis.CtlType    = ODT_HEADER;
374         dis.CtlID      = GetWindowLongPtrW (hwnd, GWLP_ID);
375         dis.itemID     = iItem;
376         dis.itemAction = ODA_DRAWENTIRE;
377         dis.itemState  = phdi->bDown ? ODS_SELECTED : 0;
378         dis.hwndItem   = hwnd;
379         dis.hDC        = hdc;
380         dis.rcItem     = r;
381         dis.itemData   = phdi->lParam;
382         oldBkMode = SetBkMode(hdc, TRANSPARENT);
383         SendMessageW (infoPtr->hwndNotify, WM_DRAWITEM,
384                         (WPARAM)dis.CtlID, (LPARAM)&dis);
385         if (oldBkMode != TRANSPARENT)
386             SetBkMode(hdc, oldBkMode);
387     }
388     else {
389         UINT rw, rh, /* width and height of r */
390              *x = NULL, *w = NULL; /* x and width of the pic (bmp or img) which is part of cnt */
391           /* cnt,txt,img,bmp */
392         UINT cx, tx, ix, bx,
393              cw, tw, iw, bw;
394         BITMAP bmp;
395
396         HEADER_PrepareCallbackItems(hwnd, iItem, HDI_TEXT|HDI_IMAGE);
397         cw = tw = iw = bw = 0;
398         rw = r.right - r.left;
399         rh = r.bottom - r.top;
400
401         if (theme == NULL) {
402             HBRUSH hbr = CreateSolidBrush(GetBkColor(hdc));
403             RECT rcBackground = r;
404
405             rcBackground.right -= cxEdge;
406             rcBackground.left += cxEdge;
407             FillRect(hdc, &rcBackground, hbr);
408             DeleteObject(hbr);
409         }
410         if (phdi->fmt & HDF_STRING) {
411             RECT textRect;
412
413             DrawTextW (hdc, phdi->pszText, -1,
414                        &textRect, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_CALCRECT);
415             cw = textRect.right - textRect.left + 2 * infoPtr->iMargin;
416         }
417
418         if ((phdi->fmt & HDF_IMAGE) && (infoPtr->himl)) {
419             iw = infoPtr->himl->cx + 2 * infoPtr->iMargin;
420             x = &ix;
421             w = &iw;
422         }
423
424         if ((phdi->fmt & HDF_BITMAP) && (phdi->hbm)) {
425             GetObjectW (phdi->hbm, sizeof(BITMAP), (LPVOID)&bmp);
426             bw = bmp.bmWidth + 2 * infoPtr->iMargin;
427             if (!iw) {
428                 x = &bx;
429                 w = &bw;
430             }
431         }
432
433         if (bw || iw)
434             cw += *w; 
435
436         /* align cx using the unclipped cw */
437         if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_LEFT)
438             cx = r.left;
439         else if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_CENTER)
440             cx = r.left + rw / 2 - cw / 2;
441         else /* HDF_RIGHT */
442             cx = r.right - cw;
443         
444         /* clip cx & cw */
445         if (cx < r.left)
446             cx = r.left;
447         if (cx + cw > r.right)
448             cw = r.right - cx;
449         
450         tx = cx + infoPtr->iMargin;
451         /* since cw might have changed we have to recalculate tw */
452         tw = cw - infoPtr->iMargin * 2;
453                         
454         if (iw || bw) {
455             tw -= *w;
456             if (phdi->fmt & HDF_BITMAP_ON_RIGHT) {
457                 /* put pic behind text */
458                 *x = cx + tw + infoPtr->iMargin * 3;
459             } else {
460                 *x = cx + infoPtr->iMargin;
461                 /* move text behind pic */
462                 tx += *w;
463             }
464         }
465
466         if (iw && bw) {
467             /* since we're done with the layout we can
468                now calculate the position of bmp which
469                has no influence on alignment and layout
470                because of img */
471             if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_RIGHT)
472                 bx = cx - bw + infoPtr->iMargin;
473             else
474                 bx = cx + cw + infoPtr->iMargin;
475         }
476
477         if (iw || bw) {
478             HDC hClipDC = GetDC(hwnd);
479             HRGN hClipRgn = CreateRectRgn(r.left, r.top, r.right, r.bottom);
480             SelectClipRgn(hClipDC, hClipRgn);
481             
482             if (bw) {
483                 HDC hdcBitmap = CreateCompatibleDC (hClipDC);
484                 SelectObject (hdcBitmap, phdi->hbm);
485                 BitBlt (hClipDC, bx, r.top + ((INT)rh - bmp.bmHeight) / 2, 
486                         bmp.bmWidth, bmp.bmHeight, hdcBitmap, 0, 0, SRCCOPY);
487                 DeleteDC (hdcBitmap);
488             }
489
490             if (iw) {
491                 ImageList_DrawEx (infoPtr->himl, phdi->iImage, hClipDC, 
492                                   ix, r.top + ((INT)rh - infoPtr->himl->cy) / 2,
493                                   infoPtr->himl->cx, infoPtr->himl->cy, CLR_DEFAULT, CLR_DEFAULT, 0);
494             }
495
496             DeleteObject(hClipRgn);
497             ReleaseDC(hwnd, hClipDC);
498         }
499         
500         if (((phdi->fmt & HDF_STRING)
501                 || (!(phdi->fmt & (HDF_OWNERDRAW|HDF_STRING|HDF_BITMAP|
502                                    HDF_BITMAP_ON_RIGHT|HDF_IMAGE)))) /* no explicit format specified? */
503             && (phdi->pszText)) {
504             oldBkMode = SetBkMode(hdc, TRANSPARENT);
505             r.left  = tx;
506             r.right = tx + tw;
507             DrawTextW (hdc, phdi->pszText, -1,
508                        &r, DT_LEFT|DT_END_ELLIPSIS|DT_VCENTER|DT_SINGLELINE);
509             if (oldBkMode != TRANSPARENT)
510                 SetBkMode(hdc, oldBkMode);
511         }
512         HEADER_FreeCallbackItems(phdi);
513     }/*Ownerdrawn*/
514
515     return phdi->rect.right;
516 }
517
518 static void
519 HEADER_DrawHotDivider(HWND hwnd, HDC hdc)
520 {
521     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
522     HBRUSH brush;
523     RECT r;
524     
525     HEADER_GetHotDividerRect(hwnd, infoPtr, &r);
526     brush = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
527     FillRect(hdc, &r, brush);
528     DeleteObject(brush);
529 }
530
531 static void
532 HEADER_Refresh (HWND hwnd, HDC hdc)
533 {
534     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
535     HFONT hFont, hOldFont;
536     RECT rect;
537     HBRUSH hbrBk;
538     UINT i;
539     INT x;
540     HTHEME theme = GetWindowTheme (hwnd);
541
542     if (!infoPtr->bRectsValid)
543         HEADER_SetItemBounds(hwnd);
544
545     /* get rect for the bar, adjusted for the border */
546     GetClientRect (hwnd, &rect);
547     
548     if (infoPtr->bDragging)
549         ImageList_DragShowNolock(FALSE);
550
551     hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
552     hOldFont = SelectObject (hdc, hFont);
553
554     /* draw Background */
555     if (infoPtr->uNumItem == 0 && theme == NULL) {
556         hbrBk = GetSysColorBrush(COLOR_3DFACE);
557         FillRect(hdc, &rect, hbrBk);
558     }
559
560     x = rect.left;
561     for (i = 0; x <= rect.right && i < infoPtr->uNumItem; i++) {
562         int idx = HEADER_OrderToIndex(hwnd,i);
563         if (RectVisible(hdc, &infoPtr->items[idx].rect))
564             HEADER_DrawItem (hwnd, hdc, idx, infoPtr->iHotItem == i);
565         x = infoPtr->items[idx].rect.right;
566     }
567
568     if ((x <= rect.right) && (infoPtr->uNumItem > 0)) {
569         rect.left = x;
570         if (theme != NULL) {
571             DrawThemeBackground (theme, hdc, HP_HEADERITEM, HIS_NORMAL, &rect,
572                 NULL);
573         }
574         else {
575             if (GetWindowLongW (hwnd, GWL_STYLE) & HDS_BUTTONS)
576                 DrawEdge (hdc, &rect, EDGE_RAISED, BF_TOP|BF_LEFT|BF_BOTTOM|BF_SOFT|BF_MIDDLE);
577             else
578                 DrawEdge (hdc, &rect, EDGE_ETCHED, BF_BOTTOM|BF_MIDDLE);
579         }
580     }
581     
582     if (infoPtr->iHotDivider != -1)
583         HEADER_DrawHotDivider(hwnd, hdc);
584
585     if (infoPtr->bDragging)
586         ImageList_DragShowNolock(TRUE);
587     SelectObject (hdc, hOldFont);
588 }
589
590
591 static void
592 HEADER_RefreshItem (HWND hwnd, HDC hdc, INT iItem)
593 {
594     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
595     HFONT hFont, hOldFont;
596
597     hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
598     hOldFont = SelectObject (hdc, hFont);
599     HEADER_DrawItem (hwnd, hdc, iItem, infoPtr->iHotItem == iItem);
600     SelectObject (hdc, hOldFont);
601 }
602
603
604 static void
605 HEADER_InternalHitTest (HWND hwnd, LPPOINT lpPt, UINT *pFlags, INT *pItem)
606 {
607     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
608     RECT rect, rcTest;
609     UINT iCount;
610     INT width;
611     BOOL bNoWidth;
612
613     GetClientRect (hwnd, &rect);
614
615     *pFlags = 0;
616     bNoWidth = FALSE;
617     if (PtInRect (&rect, *lpPt))
618     {
619         if (infoPtr->uNumItem == 0) {
620             *pFlags |= HHT_NOWHERE;
621             *pItem = 1;
622             TRACE("NOWHERE\n");
623             return;
624         }
625         else {
626             /* somewhere inside */
627             for (iCount = 0; iCount < infoPtr->uNumItem; iCount++) {
628                 rect = infoPtr->items[iCount].rect;
629                 width = rect.right - rect.left;
630                 if (width == 0) {
631                     bNoWidth = TRUE;
632                     continue;
633                 }
634                 if (PtInRect (&rect, *lpPt)) {
635                     if (width <= 2 * DIVIDER_WIDTH) {
636                         *pFlags |= HHT_ONHEADER;
637                         *pItem = iCount;
638                         TRACE("ON HEADER %d\n", iCount);
639                         return;
640                     }
641                     if (HEADER_IndexToOrder(hwnd, iCount) > 0) {
642                         rcTest = rect;
643                         rcTest.right = rcTest.left + DIVIDER_WIDTH;
644                         if (PtInRect (&rcTest, *lpPt)) {
645                             if (bNoWidth) {
646                                 *pFlags |= HHT_ONDIVOPEN;
647                                 *pItem = HEADER_PrevItem(hwnd, iCount);
648                                 TRACE("ON DIVOPEN %d\n", *pItem);
649                                 return;
650                             }
651                             else {
652                                 *pFlags |= HHT_ONDIVIDER;
653                                 *pItem = HEADER_PrevItem(hwnd, iCount);
654                                 TRACE("ON DIVIDER %d\n", *pItem);
655                                 return;
656                             }
657                         }
658                     }
659                     rcTest = rect;
660                     rcTest.left = rcTest.right - DIVIDER_WIDTH;
661                     if (PtInRect (&rcTest, *lpPt)) {
662                         *pFlags |= HHT_ONDIVIDER;
663                         *pItem = iCount;
664                         TRACE("ON DIVIDER %d\n", *pItem);
665                         return;
666                     }
667
668                     *pFlags |= HHT_ONHEADER;
669                     *pItem = iCount;
670                     TRACE("ON HEADER %d\n", iCount);
671                     return;
672                 }
673             }
674
675             /* check for last divider part (on nowhere) */
676             rect = infoPtr->items[infoPtr->uNumItem-1].rect;
677             rect.left = rect.right;
678             rect.right += DIVIDER_WIDTH;
679             if (PtInRect (&rect, *lpPt)) {
680                 if (bNoWidth) {
681                     *pFlags |= HHT_ONDIVOPEN;
682                     *pItem = infoPtr->uNumItem - 1;
683                     TRACE("ON DIVOPEN %d\n", *pItem);
684                     return;
685                 }
686                 else {
687                     *pFlags |= HHT_ONDIVIDER;
688                     *pItem = infoPtr->uNumItem-1;
689                     TRACE("ON DIVIDER %d\n", *pItem);
690                     return;
691                 }
692             }
693
694             *pFlags |= HHT_NOWHERE;
695             *pItem = 1;
696             TRACE("NOWHERE\n");
697             return;
698         }
699     }
700     else {
701         if (lpPt->x < rect.left) {
702            TRACE("TO LEFT\n");
703            *pFlags |= HHT_TOLEFT;
704         }
705         else if (lpPt->x > rect.right) {
706             TRACE("TO RIGHT\n");
707             *pFlags |= HHT_TORIGHT;
708         }
709
710         if (lpPt->y < rect.top) {
711             TRACE("ABOVE\n");
712             *pFlags |= HHT_ABOVE;
713         }
714         else if (lpPt->y > rect.bottom) {
715             TRACE("BELOW\n");
716             *pFlags |= HHT_BELOW;
717         }
718     }
719
720     *pItem = 1;
721     TRACE("flags=0x%X\n", *pFlags);
722     return;
723 }
724
725
726 static void
727 HEADER_DrawTrackLine (HWND hwnd, HDC hdc, INT x)
728 {
729     RECT rect;
730     HPEN hOldPen;
731     INT  oldRop;
732
733     GetClientRect (hwnd, &rect);
734
735     hOldPen = SelectObject (hdc, GetStockObject (BLACK_PEN));
736     oldRop = SetROP2 (hdc, R2_XORPEN);
737     MoveToEx (hdc, x, rect.top, NULL);
738     LineTo (hdc, x, rect.bottom);
739     SetROP2 (hdc, oldRop);
740     SelectObject (hdc, hOldPen);
741 }
742
743 /***
744  * DESCRIPTION:
745  * Convert a HDITEM into the correct format (ANSI/Unicode) to send it in a notify
746  *
747  * PARAMETER(S):
748  * [I] infoPtr : the header that wants to send the notify
749  * [O] dest : The buffer to store the HDITEM for notify. It may be set to a HDITEMA of HDITEMW
750  * [I] src  : The source HDITEM. It may be a HDITEMA or HDITEMW
751  * [I] fSourceUnicode : is src a HDITEMW or HDITEMA
752  * [O] ppvScratch : a pointer to a scratch buffer that needs to be freed after
753  *                  the HDITEM is no longer in use or NULL if none was needed
754  * 
755  * NOTE: We depend on HDITEMA and HDITEMW having the same structure
756  */
757 static void HEADER_CopyHDItemForNotify(HEADER_INFO *infoPtr, HDITEMW *dest,
758     HDITEMW *src, BOOL fSourceUnicode, LPVOID *ppvScratch)
759 {
760     *ppvScratch = NULL;
761     *dest = *src;
762     
763     if (src->mask & HDI_TEXT && src->pszText != LPSTR_TEXTCALLBACKW) /* covers TEXTCALLBACKA as well */
764     {
765         if (fSourceUnicode && infoPtr->nNotifyFormat != NFR_UNICODE)
766         {
767             dest->pszText = NULL;
768             Str_SetPtrWtoA((LPSTR *)&dest->pszText, src->pszText);
769             *ppvScratch = dest->pszText;
770         }
771         
772         if (!fSourceUnicode && infoPtr->nNotifyFormat == NFR_UNICODE)
773         {
774             dest->pszText = NULL;
775             Str_SetPtrAtoW(&dest->pszText, (LPSTR)src->pszText);
776             *ppvScratch = dest->pszText;
777         }
778     }
779 }
780
781 static UINT HEADER_NotifyCodeWtoA(UINT code)
782 {
783     /* we use the fact that all the unicode messages are in HDN_FIRST_UNICODE..HDN_LAST*/
784     if (code >= HDN_LAST && code <= HDN_FIRST_UNICODE)
785         return code + HDN_UNICODE_OFFSET;
786     else
787         return code;
788 }
789
790 static BOOL
791 HEADER_SendSimpleNotify (HWND hwnd, UINT code)
792 {
793     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
794     NMHDR nmhdr;
795
796     nmhdr.hwndFrom = hwnd;
797     nmhdr.idFrom   = GetWindowLongPtrW (hwnd, GWLP_ID);
798     nmhdr.code     = code;
799
800     return (BOOL)SendMessageW (infoPtr->hwndNotify, WM_NOTIFY,
801                                    (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
802 }
803
804 static BOOL
805 HEADER_SendHeaderNotifyT (HWND hwnd, UINT code, INT iItem, INT mask, HDITEMW *lpItem)
806 {
807     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
808     NMHEADERW nmhdr;
809     HDITEMW nmitem;
810     
811     if (lpItem == NULL)
812     {
813         /* lpItem == NULL means that we should take the actual data from the item */
814         if (mask & HDI_TEXT)
815         {
816             FIXME("(): invalid parameters - lpItem == NULL and (mask & HDI_TEXT)\n");
817             mask &= ~HDI_TEXT;
818         }
819         nmitem.mask = mask;
820         nmitem.cxy = infoPtr->items[iItem].cxy;
821         nmitem.hbm = infoPtr->items[iItem].hbm;
822         nmitem.pszText = NULL;
823         nmitem.cchTextMax = 0;
824         nmitem.fmt = infoPtr->items[iItem].fmt;
825         nmitem.lParam = infoPtr->items[iItem].lParam;
826         nmitem.iOrder = infoPtr->items[iItem].iOrder;
827         nmitem.iImage = infoPtr->items[iItem].iImage;
828         lpItem = &nmitem;
829     }
830
831     nmhdr.hdr.hwndFrom = hwnd;
832     nmhdr.hdr.idFrom   = GetWindowLongPtrW (hwnd, GWLP_ID);
833     nmhdr.hdr.code = (infoPtr->nNotifyFormat == NFR_UNICODE ? code : HEADER_NotifyCodeWtoA(code));
834     nmhdr.iItem = iItem;
835     nmhdr.iButton = 0;
836     nmhdr.pitem = lpItem;
837
838     return (BOOL)SendMessageW (infoPtr->hwndNotify, WM_NOTIFY,
839                                (WPARAM)nmhdr.hdr.idFrom, (LPARAM)&nmhdr);
840 }
841
842 /**
843  * Prepare callback items
844  *   depends on NMHDDISPINFOW having same structure as NMHDDISPINFOA 
845  *   (so we handle the two cases only doing a specific cast for pszText).
846  * Checks if any of the required field are callback. If there are sends a 
847  * NMHDISPINFO notify to retrieve these items. The items are stored in the
848  * HEADER_ITEM pszText and iImage fields. They should be freed with
849  * HEADER_FreeCallbackItems.
850  *
851  * @param hwnd : hwnd header container handler
852  * @param iItem : the header item id
853  * @param reqMask : required fields. If any of them is callback this function will fetch it
854  *
855  * @return TRUE on success, else FALSE
856  */
857 static BOOL
858 HEADER_PrepareCallbackItems(HWND hwnd, INT iItem, INT reqMask)
859 {
860     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
861     HEADER_ITEM *lpItem = &infoPtr->items[iItem];
862     DWORD mask = reqMask & lpItem->callbackMask;
863     NMHDDISPINFOW dispInfo;
864     void *pvBuffer = NULL;
865
866     if (mask == 0)
867         return TRUE;
868     if (mask&HDI_TEXT && lpItem->pszText != NULL)
869     {
870         ERR("(): function called without a call to FreeCallbackItems\n");
871         Free(lpItem->pszText);
872         lpItem->pszText = NULL;
873     }
874     
875     memset(&dispInfo, 0, sizeof(NMHDDISPINFOW));
876     dispInfo.hdr.hwndFrom = hwnd;
877     dispInfo.hdr.idFrom   = GetWindowLongPtrW (hwnd, GWLP_ID);
878     if (infoPtr->nNotifyFormat == NFR_UNICODE)
879     {
880         dispInfo.hdr.code = HDN_GETDISPINFOW;
881         if (mask & HDI_TEXT)
882             pvBuffer = Alloc(MAX_HEADER_TEXT_LEN * sizeof(WCHAR));
883     }
884     else
885     {
886         dispInfo.hdr.code = HDN_GETDISPINFOA;
887         if (mask & HDI_TEXT)
888             pvBuffer = Alloc(MAX_HEADER_TEXT_LEN * sizeof(CHAR));
889     }
890     dispInfo.pszText      = (LPWSTR)pvBuffer;
891     dispInfo.cchTextMax   = (pvBuffer!=NULL?MAX_HEADER_TEXT_LEN:0);
892     dispInfo.iItem        = iItem;
893     dispInfo.mask         = mask;
894     dispInfo.lParam       = lpItem->lParam;
895     
896     TRACE("Sending HDN_GETDISPINFO%c\n", infoPtr->nNotifyFormat == NFR_UNICODE?'W':'A');
897     SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, 
898                  (WPARAM) dispInfo.hdr.idFrom, 
899                  (LPARAM) &dispInfo);
900
901     TRACE("SendMessage returns(mask:0x%x,str:%s,lParam:%p)\n", 
902           dispInfo.mask,
903           (infoPtr->nNotifyFormat == NFR_UNICODE ? debugstr_w(dispInfo.pszText) : (LPSTR) dispInfo.pszText),
904           (void*) dispInfo.lParam);
905           
906     if (mask & HDI_IMAGE)
907         lpItem->iImage = dispInfo.iImage;
908     if (mask & HDI_TEXT)
909     {
910         if (infoPtr->nNotifyFormat == NFR_UNICODE)
911         {
912             lpItem->pszText = (LPWSTR)pvBuffer;
913
914             /* the user might have used his own buffer */
915             if (dispInfo.pszText != lpItem->pszText)
916                 Str_GetPtrW(dispInfo.pszText, lpItem->pszText, MAX_HEADER_TEXT_LEN);
917         }
918         else
919         {
920             Str_SetPtrAtoW(&lpItem->pszText, (LPSTR)dispInfo.pszText);
921             Free(pvBuffer);
922         }
923     }
924         
925     if (dispInfo.mask & HDI_DI_SETITEM) 
926     {
927         /* make the items permanent */
928         lpItem->callbackMask &= ~dispInfo.mask;
929     }
930     
931     return TRUE;
932 }
933
934 /***
935  * DESCRIPTION:
936  * Free the items that might be allocated with HEADER_PrepareCallbackItems
937  *
938  * PARAMETER(S):
939  * [I] lpItem : the item to free the data
940  *
941  */
942 static void
943 HEADER_FreeCallbackItems(HEADER_ITEM *lpItem)
944 {
945     if (lpItem->callbackMask&HDI_TEXT && lpItem->pszText != NULL)
946     {
947         Free(lpItem->pszText);
948         lpItem->pszText = NULL;
949     }
950     
951     if (lpItem->callbackMask&HDI_IMAGE)
952         lpItem->iImage = I_IMAGECALLBACK;
953 }
954
955 static BOOL
956 HEADER_SendClickNotify (HWND hwnd, UINT code, INT iItem)
957 {
958     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
959     NMHEADERA nmhdr;
960
961     nmhdr.hdr.hwndFrom = hwnd;
962     nmhdr.hdr.idFrom   = GetWindowLongPtrW (hwnd, GWLP_ID);
963     nmhdr.hdr.code = code;
964     nmhdr.iItem = iItem;
965     nmhdr.iButton = 0;
966     nmhdr.pitem = NULL;
967
968     return (BOOL)SendMessageA (infoPtr->hwndNotify, WM_NOTIFY,
969                                (WPARAM)nmhdr.hdr.idFrom, (LPARAM)&nmhdr);
970 }
971
972 static LRESULT
973 HEADER_CreateDragImage (HWND hwnd, WPARAM wParam)
974 {
975     HEADER_INFO *infoPtr = HEADER_GetInfoPtr(hwnd);
976     HEADER_ITEM *lpItem;
977     HIMAGELIST himl;
978     HBITMAP hMemory, hOldBitmap;
979     HDC hMemoryDC;
980     HDC hDeviceDC;
981     int height, width;
982     
983     if (wParam < 0 || wParam >= infoPtr->uNumItem)
984         return FALSE;
985     lpItem = &infoPtr->items[wParam];
986     width = lpItem->rect.right - lpItem->rect.left;
987     height = lpItem->rect.bottom - lpItem->rect.top;
988     
989     hDeviceDC = GetDC(NULL);
990     hMemoryDC = CreateCompatibleDC(hDeviceDC);
991     hMemory = CreateCompatibleBitmap(hDeviceDC, width, height);
992     ReleaseDC(NULL, hDeviceDC);
993     hOldBitmap = SelectObject(hMemoryDC, hMemory);
994     SetViewportOrgEx(hMemoryDC, -lpItem->rect.left, -lpItem->rect.top, NULL);
995     HEADER_DrawItem(hwnd, hMemoryDC, wParam, FALSE);
996     hMemory = SelectObject(hMemoryDC, hOldBitmap);
997     DeleteDC(hMemoryDC);
998     
999     if (hMemory == NULL)    /* if anything failed */
1000         return FALSE;
1001     
1002     himl = ImageList_Create(width, height, ILC_COLORDDB, 1, 1);
1003     ImageList_Add(himl, hMemory, NULL);
1004     DeleteObject(hMemory);
1005     return (LRESULT)himl;
1006 }
1007
1008 static LRESULT
1009 HEADER_SetHotDivider(HWND hwnd, WPARAM wParam, LPARAM lParam)
1010 {
1011     HEADER_INFO *infoPtr = HEADER_GetInfoPtr(hwnd);
1012     INT iDivider;
1013     RECT r;
1014     
1015     if (wParam)
1016     {
1017         POINT pt;
1018         UINT flags;
1019         pt.x = (INT)(SHORT)LOWORD(lParam);
1020         pt.y = 0;
1021         HEADER_InternalHitTest (hwnd, &pt, &flags, &iDivider);
1022         
1023         if (flags & HHT_TOLEFT)
1024             iDivider = 0;
1025         else if (flags & HHT_NOWHERE || flags & HHT_TORIGHT)
1026             iDivider = infoPtr->uNumItem;
1027         else
1028         {
1029             HEADER_ITEM *lpItem = &infoPtr->items[iDivider];
1030             if (pt.x > (lpItem->rect.left+lpItem->rect.right)/2)
1031                 iDivider = HEADER_NextItem(hwnd, iDivider);
1032         }
1033     }
1034     else
1035         iDivider = (INT)lParam;
1036         
1037     /* Note; wParam==FALSE, lParam==-1 is valid and is used to clear the hot divider */
1038     if (iDivider<-1 || iDivider>(int)infoPtr->uNumItem)
1039         return iDivider;
1040
1041     if (iDivider != infoPtr->iHotDivider)
1042     {
1043         if (infoPtr->iHotDivider != -1)
1044         {
1045             HEADER_GetHotDividerRect(hwnd, infoPtr, &r);
1046             InvalidateRect(hwnd, &r, FALSE);
1047         }
1048         infoPtr->iHotDivider = iDivider;
1049         if (iDivider != -1)
1050         {
1051             HEADER_GetHotDividerRect(hwnd, infoPtr, &r);
1052             InvalidateRect(hwnd, &r, FALSE);
1053         }
1054     }
1055     return iDivider;
1056 }
1057
1058 static LRESULT
1059 HEADER_DeleteItem (HWND hwnd, WPARAM wParam)
1060 {
1061     HEADER_INFO *infoPtr = HEADER_GetInfoPtr(hwnd);
1062     INT iItem = (INT)wParam;
1063
1064     TRACE("[iItem=%d]\n", iItem);
1065
1066     if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem))
1067         return FALSE;
1068
1069     if (infoPtr->uNumItem == 1) {
1070         TRACE("Simple delete!\n");
1071         HEADER_DisposeItem(&infoPtr->items[0]);
1072         Free (infoPtr->items);
1073         Free(infoPtr->order);
1074         infoPtr->items = 0;
1075         infoPtr->order = 0;
1076         infoPtr->uNumItem = 0;
1077     }
1078     else {
1079         HEADER_ITEM *oldItems = infoPtr->items;
1080         INT i;
1081         INT iOrder;
1082         TRACE("Complex delete! [iItem=%d]\n", iItem);
1083
1084         for (i = 0; i < infoPtr->uNumItem; i++)
1085            TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i, infoPtr->order[i], infoPtr->items[i].iOrder, infoPtr->items[infoPtr->order[i]].iOrder);
1086         HEADER_DisposeItem(&infoPtr->items[iItem]);
1087         iOrder = infoPtr->items[iItem].iOrder;
1088
1089         infoPtr->uNumItem--;
1090         infoPtr->items = Alloc (sizeof (HEADER_ITEM) * infoPtr->uNumItem);
1091         /* pre delete copy */
1092         if (iItem > 0) {
1093             memcpy (&infoPtr->items[0], &oldItems[0],
1094                     iItem * sizeof(HEADER_ITEM));
1095         }
1096
1097         /* post delete copy */
1098         if (iItem < infoPtr->uNumItem) {
1099             memcpy (&infoPtr->items[iItem], &oldItems[iItem+1],
1100                     (infoPtr->uNumItem - iItem) * sizeof(HEADER_ITEM));
1101         }
1102
1103         /* Correct the orders */
1104         if (iOrder < infoPtr->uNumItem)
1105         {
1106             memmove(&infoPtr->order[iOrder], &infoPtr->order[iOrder + 1],
1107                    (infoPtr->uNumItem - iOrder) * sizeof(INT));
1108             for (i = 0; i < infoPtr->uNumItem; i++)
1109             {
1110                 if (infoPtr->order[i] > iItem)
1111                     infoPtr->order[i]--;
1112                 if (i >= iOrder)
1113                     infoPtr->items[infoPtr->order[i]].iOrder = infoPtr->order[i];
1114             }
1115         }
1116
1117         for (i = 0; i < infoPtr->uNumItem; i++)
1118            TRACE("%d: order=%d, iOrder=%d, ->iOrder=%d\n", i, infoPtr->order[i], infoPtr->items[i].iOrder, infoPtr->items[infoPtr->order[i]].iOrder);
1119         Free (oldItems);
1120     }
1121
1122     HEADER_SetItemBounds (hwnd);
1123
1124     InvalidateRect(hwnd, NULL, FALSE);
1125
1126     return TRUE;
1127 }
1128
1129
1130 static LRESULT
1131 HEADER_GetImageList (HWND hwnd)
1132 {
1133     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1134
1135     return (LRESULT)infoPtr->himl;
1136 }
1137
1138
1139 static LRESULT
1140 HEADER_GetItemT (HWND hwnd, INT nItem, LPHDITEMW phdi, BOOL bUnicode)
1141 {
1142     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1143     HEADER_ITEM *lpItem;
1144     UINT mask;
1145
1146     if (!phdi)
1147         return FALSE;
1148
1149     TRACE("[nItem=%d]\n", nItem);
1150
1151     mask = phdi->mask;
1152     if (mask == 0)
1153         return TRUE;
1154
1155     if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem))
1156         return FALSE;
1157
1158     if (mask & HDI_UNKNOWN_FIELDS)
1159     {
1160         TRACE("mask %x contains unknown fields. Using only comctl32 4.0 fields\n", mask);
1161         mask &= HDI_COMCTL32_4_0_FIELDS;
1162     }
1163     
1164     lpItem = &infoPtr->items[nItem];
1165     HEADER_PrepareCallbackItems(hwnd, nItem, mask);
1166
1167     if (mask & HDI_BITMAP)
1168         phdi->hbm = lpItem->hbm;
1169
1170     if (mask & HDI_FORMAT)
1171         phdi->fmt = lpItem->fmt;
1172
1173     if (mask & HDI_WIDTH)
1174         phdi->cxy = lpItem->cxy;
1175
1176     if (mask & HDI_LPARAM)
1177         phdi->lParam = lpItem->lParam;
1178
1179     if (mask & HDI_IMAGE) 
1180         phdi->iImage = lpItem->iImage;
1181
1182     if (mask & HDI_ORDER)
1183         phdi->iOrder = lpItem->iOrder;
1184
1185     if (mask & HDI_TEXT)
1186     {
1187         if (bUnicode)
1188             Str_GetPtrW (lpItem->pszText, phdi->pszText, phdi->cchTextMax);
1189         else
1190             Str_GetPtrWtoA (lpItem->pszText, (LPSTR)phdi->pszText, phdi->cchTextMax);
1191     }
1192
1193     HEADER_FreeCallbackItems(lpItem);
1194     return TRUE;
1195 }
1196
1197
1198 inline static LRESULT
1199 HEADER_GetItemCount (HWND hwnd)
1200 {
1201     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1202     return infoPtr->uNumItem;
1203 }
1204
1205
1206 static LRESULT
1207 HEADER_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
1208 {
1209     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1210     INT iItem = (INT)wParam;
1211     LPRECT lpRect = (LPRECT)lParam;
1212
1213     if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem))
1214         return FALSE;
1215
1216     lpRect->left   = infoPtr->items[iItem].rect.left;
1217     lpRect->right  = infoPtr->items[iItem].rect.right;
1218     lpRect->top    = infoPtr->items[iItem].rect.top;
1219     lpRect->bottom = infoPtr->items[iItem].rect.bottom;
1220
1221     return TRUE;
1222 }
1223
1224
1225 static LRESULT
1226 HEADER_GetOrderArray(HWND hwnd, WPARAM wParam, LPARAM lParam)
1227 {
1228     LPINT order = (LPINT) lParam;
1229     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1230
1231     if ((unsigned int)wParam <infoPtr->uNumItem)
1232       return FALSE;
1233
1234     memcpy(order, infoPtr->order, infoPtr->uNumItem * sizeof(INT));
1235     return TRUE;
1236 }
1237
1238 static LRESULT
1239 HEADER_SetOrderArray(HWND hwnd, WPARAM wParam, LPARAM lParam)
1240 {
1241     int i;
1242     LPINT order = (LPINT) lParam;
1243     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1244     HEADER_ITEM *lpItem;
1245
1246     if ((unsigned int)wParam <infoPtr->uNumItem)
1247       return FALSE;
1248     memcpy(infoPtr->order, order, infoPtr->uNumItem * sizeof(INT));
1249     for (i=0; i<(int)wParam; i++)
1250       {
1251         lpItem = &infoPtr->items[*order++];
1252         lpItem->iOrder=i;
1253       }
1254     infoPtr->bRectsValid=0;
1255     InvalidateRect(hwnd, NULL, FALSE);
1256     return TRUE;
1257 }
1258
1259 inline static LRESULT
1260 HEADER_GetUnicodeFormat (HWND hwnd)
1261 {
1262     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1263     return (infoPtr->nNotifyFormat == NFR_UNICODE);
1264 }
1265
1266
1267 static LRESULT
1268 HEADER_HitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
1269 {
1270     LPHDHITTESTINFO phti = (LPHDHITTESTINFO)lParam;
1271
1272     HEADER_InternalHitTest (hwnd, &phti->pt, &phti->flags, &phti->iItem);
1273
1274     if (phti->flags == HHT_NOWHERE)
1275         return -1;
1276     else
1277         return phti->iItem;
1278 }
1279
1280
1281 static LRESULT
1282 HEADER_InsertItemT (HWND hwnd, INT nItem, LPHDITEMW phdi, BOOL bUnicode)
1283 {
1284     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1285     HEADER_ITEM *lpItem;
1286     INT       iOrder;
1287     UINT      i;
1288     UINT      copyMask;
1289
1290     if ((phdi == NULL) || (nItem < 0) || (phdi->mask == 0))
1291         return -1;
1292
1293     if (nItem > infoPtr->uNumItem)
1294         nItem = infoPtr->uNumItem;
1295
1296     iOrder = (phdi->mask & HDI_ORDER) ? phdi->iOrder : nItem;
1297     if (iOrder < 0)
1298         iOrder = 0;
1299     else if (infoPtr->uNumItem < iOrder)
1300         iOrder = infoPtr->uNumItem;
1301
1302     if (infoPtr->uNumItem == 0) {
1303         infoPtr->items = Alloc (sizeof (HEADER_ITEM));
1304         infoPtr->order = Alloc(sizeof(INT));
1305         infoPtr->uNumItem++;
1306     }
1307     else {
1308         HEADER_ITEM *oldItems = infoPtr->items;
1309         INT *oldOrder = infoPtr->order;
1310
1311         infoPtr->uNumItem++;
1312         infoPtr->items = Alloc (sizeof (HEADER_ITEM) * infoPtr->uNumItem);
1313         if (nItem == 0) {
1314             memcpy (&infoPtr->items[1], &oldItems[0],
1315                     (infoPtr->uNumItem-1) * sizeof(HEADER_ITEM));
1316         }
1317         else
1318         {
1319               /* pre insert copy */
1320             if (nItem > 0) {
1321                  memcpy (&infoPtr->items[0], &oldItems[0],
1322                          nItem * sizeof(HEADER_ITEM));
1323             }
1324
1325             /* post insert copy */
1326             if (nItem < infoPtr->uNumItem - 1) {
1327                 memcpy (&infoPtr->items[nItem+1], &oldItems[nItem],
1328                         (infoPtr->uNumItem - nItem - 1) * sizeof(HEADER_ITEM));
1329             }
1330         }
1331
1332         infoPtr->order = Alloc(sizeof(INT) * infoPtr->uNumItem);
1333         memcpy(infoPtr->order, oldOrder, iOrder * sizeof(INT));
1334         infoPtr->order[iOrder] = nItem;
1335         memcpy(&infoPtr->order[iOrder + 1], &oldOrder[iOrder],
1336                (infoPtr->uNumItem - iOrder - 1) * sizeof(INT));
1337
1338         Free (oldItems);
1339         Free(oldOrder);
1340     }
1341
1342     for (i = 0; i < infoPtr->uNumItem; i++)
1343     {
1344         if (i != iOrder && infoPtr->order[i] >= nItem)
1345             infoPtr->order[i]++;
1346         infoPtr->items[infoPtr->order[i]].iOrder = infoPtr->order[i];
1347     }
1348
1349     lpItem = &infoPtr->items[nItem];
1350     ZeroMemory(lpItem, sizeof(HEADER_ITEM));
1351     /* cxy, fmt and lParam are copied even if not in the HDITEM mask */
1352     copyMask = phdi->mask | HDI_WIDTH | HDI_FORMAT | HDI_LPARAM;
1353     HEADER_StoreHDItemInHeader(lpItem, copyMask, phdi, bUnicode);
1354
1355     /* set automatically some format bits */
1356     if (phdi->mask & HDI_TEXT)
1357         lpItem->fmt |= HDF_STRING;
1358     else
1359         lpItem->fmt &= ~HDF_STRING;
1360
1361     if (lpItem->hbm != NULL)
1362         lpItem->fmt |= HDF_BITMAP;
1363     else
1364         lpItem->fmt &= ~HDF_BITMAP;
1365
1366     if (phdi->mask & HDI_IMAGE)
1367         lpItem->fmt |= HDF_IMAGE;
1368
1369     lpItem->iOrder = iOrder;
1370
1371     HEADER_SetItemBounds (hwnd);
1372
1373     InvalidateRect(hwnd, NULL, FALSE);
1374
1375     return nItem;
1376 }
1377
1378
1379 static LRESULT
1380 HEADER_Layout (HWND hwnd, WPARAM wParam, LPARAM lParam)
1381 {
1382     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1383     LPHDLAYOUT lpLayout = (LPHDLAYOUT)lParam;
1384
1385     lpLayout->pwpos->hwnd = hwnd;
1386     lpLayout->pwpos->hwndInsertAfter = 0;
1387     lpLayout->pwpos->x = lpLayout->prc->left;
1388     lpLayout->pwpos->y = lpLayout->prc->top;
1389     lpLayout->pwpos->cx = lpLayout->prc->right - lpLayout->prc->left;
1390     if (GetWindowLongW (hwnd, GWL_STYLE) & HDS_HIDDEN)
1391         lpLayout->pwpos->cy = 0;
1392     else {
1393         lpLayout->pwpos->cy = infoPtr->nHeight;
1394         lpLayout->prc->top += infoPtr->nHeight;
1395     }
1396     lpLayout->pwpos->flags = SWP_NOZORDER;
1397
1398     TRACE("Layout x=%d y=%d cx=%d cy=%d\n",
1399            lpLayout->pwpos->x, lpLayout->pwpos->y,
1400            lpLayout->pwpos->cx, lpLayout->pwpos->cy);
1401
1402     infoPtr->bRectsValid = FALSE;
1403
1404     return TRUE;
1405 }
1406
1407
1408 static LRESULT
1409 HEADER_SetImageList (HWND hwnd, HIMAGELIST himl)
1410 {
1411     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1412     HIMAGELIST himlOld;
1413
1414     TRACE("(himl %p)\n", himl);
1415     himlOld = infoPtr->himl;
1416     infoPtr->himl = himl;
1417
1418     /* FIXME: Refresh needed??? */
1419
1420     return (LRESULT)himlOld;
1421 }
1422
1423
1424 static LRESULT
1425 HEADER_GetBitmapMargin(HWND hwnd)
1426 {
1427     HEADER_INFO *infoPtr = HEADER_GetInfoPtr(hwnd);
1428     
1429     return infoPtr->iMargin;
1430 }
1431
1432 static LRESULT
1433 HEADER_SetBitmapMargin(HWND hwnd, WPARAM wParam)
1434 {
1435     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1436     INT oldMargin = infoPtr->iMargin;
1437
1438     infoPtr->iMargin = (INT)wParam;
1439
1440     return oldMargin;
1441 }
1442
1443 static LRESULT
1444 HEADER_SetItemT (HWND hwnd, INT nItem, LPHDITEMW phdi, BOOL bUnicode)
1445 {
1446     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1447     HEADER_ITEM *lpItem;
1448     HDITEMW hdNotify;
1449     void *pvScratch;
1450
1451     if (phdi == NULL)
1452         return FALSE;
1453     if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem))
1454         return FALSE;
1455
1456     TRACE("[nItem=%d]\n", nItem);
1457
1458     HEADER_CopyHDItemForNotify(infoPtr, &hdNotify, phdi, bUnicode, &pvScratch);
1459     if (HEADER_SendHeaderNotifyT (hwnd, HDN_ITEMCHANGINGW, nItem, phdi->mask, &hdNotify))
1460     {
1461         if (pvScratch) Free(pvScratch);
1462         return FALSE;
1463     }
1464
1465     lpItem = &infoPtr->items[nItem];
1466     HEADER_StoreHDItemInHeader(lpItem, phdi->mask, phdi, bUnicode);
1467
1468     if (phdi->mask & HDI_ORDER)
1469         if (phdi->iOrder >= 0 && phdi->iOrder < infoPtr->uNumItem)
1470             HEADER_ChangeItemOrder(infoPtr, nItem, phdi->iOrder);
1471
1472     HEADER_SendHeaderNotifyT (hwnd, HDN_ITEMCHANGEDW, nItem, phdi->mask, &hdNotify);
1473
1474     HEADER_SetItemBounds (hwnd);
1475
1476     InvalidateRect(hwnd, NULL, FALSE);
1477
1478     if (pvScratch != NULL)
1479         Free(pvScratch);
1480     return TRUE;
1481 }
1482
1483 inline static LRESULT
1484 HEADER_SetUnicodeFormat (HWND hwnd, WPARAM wParam)
1485 {
1486     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1487     BOOL bTemp = (infoPtr->nNotifyFormat == NFR_UNICODE);
1488
1489     infoPtr->nNotifyFormat = ((BOOL)wParam ? NFR_UNICODE : NFR_ANSI);
1490
1491     return bTemp;
1492 }
1493
1494
1495 static LRESULT
1496 HEADER_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
1497 {
1498     HEADER_INFO *infoPtr;
1499     TEXTMETRICW tm;
1500     HFONT hOldFont;
1501     HDC   hdc;
1502
1503     infoPtr = (HEADER_INFO *)Alloc (sizeof(HEADER_INFO));
1504     SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
1505
1506     infoPtr->hwndNotify = ((LPCREATESTRUCTA)lParam)->hwndParent;
1507     infoPtr->uNumItem = 0;
1508     infoPtr->hFont = 0;
1509     infoPtr->items = 0;
1510     infoPtr->order = 0;
1511     infoPtr->bRectsValid = FALSE;
1512     infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW);
1513     infoPtr->hcurDivider = LoadCursorW (COMCTL32_hModule, MAKEINTRESOURCEW(IDC_DIVIDER));
1514     infoPtr->hcurDivopen = LoadCursorW (COMCTL32_hModule, MAKEINTRESOURCEW(IDC_DIVIDEROPEN));
1515     infoPtr->bPressed  = FALSE;
1516     infoPtr->bTracking = FALSE;
1517     infoPtr->iMoveItem = 0;
1518     infoPtr->himl = 0;
1519     infoPtr->iHotItem = -1;
1520     infoPtr->iHotDivider = -1;
1521     infoPtr->iMargin = 3*GetSystemMetrics(SM_CXEDGE);
1522     infoPtr->nNotifyFormat =
1523         SendMessageW (infoPtr->hwndNotify, WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY);
1524
1525     hdc = GetDC (0);
1526     hOldFont = SelectObject (hdc, GetStockObject (SYSTEM_FONT));
1527     GetTextMetricsW (hdc, &tm);
1528     infoPtr->nHeight = tm.tmHeight + VERT_BORDER;
1529     SelectObject (hdc, hOldFont);
1530     ReleaseDC (0, hdc);
1531
1532     OpenThemeData(hwnd, themeClass);
1533
1534     return 0;
1535 }
1536
1537
1538 static LRESULT
1539 HEADER_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
1540 {
1541     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1542     HEADER_ITEM *lpItem;
1543     INT nItem;
1544     HTHEME theme;
1545
1546     if (infoPtr->items) {
1547         lpItem = infoPtr->items;
1548         for (nItem = 0; nItem < infoPtr->uNumItem; nItem++, lpItem++) {
1549             HEADER_DisposeItem(lpItem);
1550         }
1551         Free (infoPtr->items);
1552     }
1553
1554     if (infoPtr->order)
1555         Free(infoPtr->order);
1556
1557     if (infoPtr->himl)
1558         ImageList_Destroy (infoPtr->himl);
1559
1560     SetWindowLongPtrW (hwnd, 0, 0);
1561     Free (infoPtr);
1562
1563     theme = GetWindowTheme(hwnd);
1564     CloseThemeData(theme);
1565     return 0;
1566 }
1567
1568
1569 static inline LRESULT
1570 HEADER_GetFont (HWND hwnd)
1571 {
1572     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1573
1574     return (LRESULT)infoPtr->hFont;
1575 }
1576
1577
1578 static BOOL
1579 HEADER_IsDragDistance(HEADER_INFO *infoPtr, POINT *pt)
1580 {
1581     /* Windows allows for a mouse movement before starting the drag. We use the
1582      * SM_CXDOUBLECLICK/SM_CYDOUBLECLICK as that distance.
1583      */
1584     return (abs(infoPtr->ptLButtonDown.x - pt->x)>GetSystemMetrics(SM_CXDOUBLECLK) ||
1585             abs(infoPtr->ptLButtonDown.y - pt->y)>GetSystemMetrics(SM_CYDOUBLECLK));
1586 }
1587
1588 static LRESULT
1589 HEADER_LButtonDblClk (HWND hwnd, WPARAM wParam, LPARAM lParam)
1590 {
1591     POINT pt;
1592     UINT  flags;
1593     INT   nItem;
1594
1595     pt.x = (INT)LOWORD(lParam);
1596     pt.y = (INT)HIWORD(lParam);
1597     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1598
1599     if ((GetWindowLongW (hwnd, GWL_STYLE) & HDS_BUTTONS) && (flags == HHT_ONHEADER))
1600         HEADER_SendHeaderNotifyT (hwnd, HDN_ITEMDBLCLICKW, nItem, 0, NULL);
1601     else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN))
1602         HEADER_SendHeaderNotifyT (hwnd, HDN_DIVIDERDBLCLICKW, nItem, 0, NULL);
1603
1604     return 0;
1605 }
1606
1607
1608 static LRESULT
1609 HEADER_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
1610 {
1611     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1612     DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE);
1613     POINT pt;
1614     UINT  flags;
1615     INT   nItem;
1616     HDC   hdc;
1617
1618     pt.x = (INT)LOWORD(lParam);
1619     pt.y = (INT)HIWORD(lParam);
1620     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1621
1622     if ((dwStyle & HDS_BUTTONS) && (flags == HHT_ONHEADER)) {
1623         SetCapture (hwnd);
1624         infoPtr->bCaptured = TRUE;
1625         infoPtr->bPressed  = TRUE;
1626         infoPtr->bDragging = FALSE;
1627         infoPtr->iMoveItem = nItem;
1628         infoPtr->ptLButtonDown = pt;
1629
1630         infoPtr->items[nItem].bDown = TRUE;
1631
1632         /* Send WM_CUSTOMDRAW */
1633         hdc = GetDC (hwnd);
1634         HEADER_RefreshItem (hwnd, hdc, nItem);
1635         ReleaseDC (hwnd, hdc);
1636
1637         TRACE("Pressed item %d!\n", nItem);
1638     }
1639     else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN)) {
1640         if (!(HEADER_SendHeaderNotifyT (hwnd, HDN_BEGINTRACKW, nItem, HDI_WIDTH, NULL))) {
1641             SetCapture (hwnd);
1642             infoPtr->bCaptured = TRUE;
1643             infoPtr->bTracking = TRUE;
1644             infoPtr->iMoveItem = nItem;
1645             infoPtr->nOldWidth = infoPtr->items[nItem].cxy;
1646             infoPtr->xTrackOffset = infoPtr->items[nItem].rect.right - pt.x;
1647
1648             if (!(dwStyle & HDS_FULLDRAG)) {
1649                 infoPtr->xOldTrack = infoPtr->items[nItem].rect.right;
1650                 hdc = GetDC (hwnd);
1651                 HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1652                 ReleaseDC (hwnd, hdc);
1653             }
1654
1655             TRACE("Begin tracking item %d!\n", nItem);
1656         }
1657     }
1658
1659     return 0;
1660 }
1661
1662
1663 static LRESULT
1664 HEADER_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1665 {
1666     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1667     DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE);
1668     POINT pt;
1669     UINT  flags;
1670     INT   nItem, nWidth;
1671     HDC   hdc;
1672
1673     pt.x = (INT)(SHORT)LOWORD(lParam);
1674     pt.y = (INT)(SHORT)HIWORD(lParam);
1675     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1676
1677     if (infoPtr->bPressed) {
1678         if (infoPtr->bDragging)
1679         {
1680             HEADER_ITEM *lpItem = &infoPtr->items[infoPtr->iMoveItem];
1681             INT iNewOrder;
1682             
1683             ImageList_DragShowNolock(FALSE);
1684             ImageList_EndDrag();
1685             lpItem->bDown=FALSE;
1686             
1687             if (infoPtr->iHotDivider == -1)
1688                 iNewOrder = -1;
1689             else if (infoPtr->iHotDivider == infoPtr->uNumItem)
1690                 iNewOrder = infoPtr->uNumItem-1;
1691             else
1692             {
1693                 iNewOrder = HEADER_IndexToOrder(hwnd, infoPtr->iHotDivider);
1694                 if (iNewOrder > lpItem->iOrder)
1695                     iNewOrder--;
1696             }
1697
1698             /* FIXME: the new order field should be sent, not the old one */
1699             if (iNewOrder != -1 &&
1700                 !HEADER_SendHeaderNotifyT(hwnd, HDN_ENDDRAG, infoPtr->iMoveItem, HDI_ORDER, NULL))
1701             {
1702                 HEADER_ChangeItemOrder(infoPtr, infoPtr->iMoveItem, iNewOrder);
1703                 infoPtr->bRectsValid = FALSE;
1704                 InvalidateRect(hwnd, NULL, FALSE);
1705             }
1706             else
1707                 InvalidateRect(hwnd, &infoPtr->items[infoPtr->iMoveItem].rect, FALSE);
1708                 
1709             HEADER_SetHotDivider(hwnd, FALSE, -1);
1710         }
1711         else if (!(dwStyle&HDS_DRAGDROP) || !HEADER_IsDragDistance(infoPtr, &pt))
1712         {
1713             infoPtr->items[infoPtr->iMoveItem].bDown = FALSE;
1714             hdc = GetDC (hwnd);
1715             HEADER_RefreshItem (hwnd, hdc, infoPtr->iMoveItem);
1716             ReleaseDC (hwnd, hdc);
1717
1718             HEADER_SendClickNotify (hwnd, HDN_ITEMCLICKA, infoPtr->iMoveItem);
1719         }
1720
1721         TRACE("Released item %d!\n", infoPtr->iMoveItem);
1722         infoPtr->bPressed = FALSE;
1723     }
1724     else if (infoPtr->bTracking) {
1725         TRACE("End tracking item %d!\n", infoPtr->iMoveItem);
1726         infoPtr->bTracking = FALSE;
1727
1728         HEADER_SendHeaderNotifyT (hwnd, HDN_ENDTRACKW, infoPtr->iMoveItem, HDI_WIDTH, NULL);
1729
1730         if (!(dwStyle & HDS_FULLDRAG)) {
1731             hdc = GetDC (hwnd);
1732             HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1733             ReleaseDC (hwnd, hdc);
1734         }
1735           
1736         if (HEADER_SendHeaderNotifyT(hwnd, HDN_ITEMCHANGINGW, infoPtr->iMoveItem, HDI_WIDTH, NULL))
1737         {
1738             infoPtr->items[infoPtr->iMoveItem].cxy = infoPtr->nOldWidth;
1739         }
1740         else {
1741             nWidth = pt.x - infoPtr->items[infoPtr->iMoveItem].rect.left + infoPtr->xTrackOffset;
1742             if (nWidth < 0)
1743                 nWidth = 0;
1744             infoPtr->items[infoPtr->iMoveItem].cxy = nWidth;
1745         }
1746
1747         HEADER_SetItemBounds (hwnd);
1748         InvalidateRect(hwnd, NULL, TRUE);
1749         HEADER_SendHeaderNotifyT(hwnd, HDN_ITEMCHANGEDW, infoPtr->iMoveItem, HDI_WIDTH, NULL);
1750     }
1751
1752     if (infoPtr->bCaptured) {
1753         infoPtr->bCaptured = FALSE;
1754         ReleaseCapture ();
1755         HEADER_SendSimpleNotify (hwnd, NM_RELEASEDCAPTURE);
1756     }
1757
1758     return 0;
1759 }
1760
1761
1762 static LRESULT
1763 HEADER_NotifyFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
1764 {
1765     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1766
1767     switch (lParam)
1768     {
1769         case NF_QUERY:
1770             return infoPtr->nNotifyFormat;
1771
1772         case NF_REQUERY:
1773             infoPtr->nNotifyFormat =
1774                 SendMessageW ((HWND)wParam, WM_NOTIFYFORMAT,
1775                               (WPARAM)hwnd, (LPARAM)NF_QUERY);
1776             return infoPtr->nNotifyFormat;
1777     }
1778
1779     return 0;
1780 }
1781
1782 static LRESULT
1783 HEADER_MouseLeave (HWND hwnd, WPARAM wParam, LPARAM lParam)
1784 {
1785     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1786     /* Reset hot-tracked item when mouse leaves control. */
1787     INT oldHotItem = infoPtr->iHotItem;
1788     HDC hdc = GetDC (hwnd);
1789
1790     infoPtr->iHotItem = -1;
1791     if (oldHotItem != -1) HEADER_RefreshItem (hwnd, hdc, oldHotItem);
1792     ReleaseDC (hwnd, hdc);
1793
1794     return 0;
1795 }
1796
1797
1798 static LRESULT
1799 HEADER_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
1800 {
1801     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1802     DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE);
1803     POINT pt;
1804     UINT  flags;
1805     INT   nItem, nWidth;
1806     HDC   hdc;
1807     /* With theming, hottracking is always enabled */
1808     BOOL  hotTrackEnabled =
1809         ((dwStyle & HDS_BUTTONS) && (dwStyle & HDS_HOTTRACK))
1810         || (GetWindowTheme (hwnd) != NULL);
1811     INT oldHotItem = infoPtr->iHotItem;
1812
1813     pt.x = (INT)(SHORT)LOWORD(lParam);
1814     pt.y = (INT)(SHORT)HIWORD(lParam);
1815     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1816
1817     if (hotTrackEnabled) {
1818         if (flags & (HHT_ONHEADER | HHT_ONDIVIDER | HHT_ONDIVOPEN))
1819             infoPtr->iHotItem = nItem;
1820         else
1821             infoPtr->iHotItem = -1;
1822     }
1823
1824     if (infoPtr->bCaptured) {
1825         /* check if we should drag the header */
1826         if (infoPtr->bPressed && !infoPtr->bDragging && dwStyle&HDS_DRAGDROP
1827             && HEADER_IsDragDistance(infoPtr, &pt))
1828         {
1829             if (!HEADER_SendHeaderNotifyT(hwnd, HDN_BEGINDRAG, infoPtr->iMoveItem, 0, NULL))
1830             {
1831                 HIMAGELIST hDragItem = (HIMAGELIST)HEADER_CreateDragImage(hwnd, infoPtr->iMoveItem);
1832                 if (hDragItem != NULL)
1833                 {
1834                     HEADER_ITEM *lpItem = &infoPtr->items[infoPtr->iMoveItem];
1835                     TRACE("Starting item drag\n");
1836                     ImageList_BeginDrag(hDragItem, 0, pt.x - lpItem->rect.left, 0);
1837                     ImageList_DragShowNolock(TRUE);
1838                     ImageList_Destroy(hDragItem);
1839                     infoPtr->bDragging = TRUE;
1840                 }
1841             }
1842         }
1843         
1844         if (infoPtr->bDragging)
1845         {
1846             POINT drag;
1847             drag.x = pt.x;
1848             drag.y = 0;
1849             ClientToScreen(hwnd, &drag);
1850             ImageList_DragMove(drag.x, drag.y);
1851             HEADER_SetHotDivider(hwnd, TRUE, lParam);
1852         }
1853         
1854         if (infoPtr->bPressed && !infoPtr->bDragging) {
1855             BOOL oldState = infoPtr->items[infoPtr->iMoveItem].bDown;
1856             if ((nItem == infoPtr->iMoveItem) && (flags == HHT_ONHEADER))
1857                 infoPtr->items[infoPtr->iMoveItem].bDown = TRUE;
1858             else
1859                 infoPtr->items[infoPtr->iMoveItem].bDown = FALSE;
1860             if (oldState != infoPtr->items[infoPtr->iMoveItem].bDown) {
1861                 hdc = GetDC (hwnd);
1862                 HEADER_RefreshItem (hwnd, hdc, infoPtr->iMoveItem);
1863                 ReleaseDC (hwnd, hdc);
1864             }
1865
1866             TRACE("Moving pressed item %d!\n", infoPtr->iMoveItem);
1867         }
1868         else if (infoPtr->bTracking) {
1869             if (dwStyle & HDS_FULLDRAG) {
1870                 if (!HEADER_SendHeaderNotifyT (hwnd, HDN_ITEMCHANGINGW, infoPtr->iMoveItem, HDI_WIDTH, NULL))
1871                 {
1872                     HEADER_ITEM *lpItem = &infoPtr->items[infoPtr->iMoveItem];
1873                     INT nOldWidth = lpItem->rect.right - lpItem->rect.left;
1874                     RECT rcClient;
1875                     RECT rcScroll;
1876                     
1877                     nWidth = pt.x - lpItem->rect.left + infoPtr->xTrackOffset;
1878                     if (nWidth < 0) nWidth = 0;
1879                     infoPtr->items[infoPtr->iMoveItem].cxy = nWidth;
1880                     HEADER_SetItemBounds(hwnd);
1881                     
1882                     GetClientRect(hwnd, &rcClient);
1883                     rcScroll = rcClient;
1884                     rcScroll.left = lpItem->rect.left + nOldWidth;
1885                     ScrollWindowEx(hwnd, nWidth - nOldWidth, 0, &rcScroll, &rcClient, NULL, NULL, 0);
1886                     InvalidateRect(hwnd, &lpItem->rect, FALSE);
1887                     UpdateWindow(hwnd);
1888                     
1889                     HEADER_SendHeaderNotifyT(hwnd, HDN_ITEMCHANGEDW, infoPtr->iMoveItem, HDI_WIDTH, NULL);
1890                 }
1891             }
1892             else {
1893                 hdc = GetDC (hwnd);
1894                 HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1895                 infoPtr->xOldTrack = pt.x + infoPtr->xTrackOffset;
1896                 if (infoPtr->xOldTrack < infoPtr->items[infoPtr->iMoveItem].rect.left)
1897                     infoPtr->xOldTrack = infoPtr->items[infoPtr->iMoveItem].rect.left;
1898                 infoPtr->items[infoPtr->iMoveItem].cxy =
1899                     infoPtr->xOldTrack - infoPtr->items[infoPtr->iMoveItem].rect.left;
1900                 HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack);
1901                 ReleaseDC (hwnd, hdc);
1902                 HEADER_SendHeaderNotifyT (hwnd, HDN_TRACKW, infoPtr->iMoveItem, HDI_WIDTH, NULL);
1903             }
1904
1905             TRACE("Tracking item %d!\n", infoPtr->iMoveItem);
1906         }
1907     }
1908
1909     if (hotTrackEnabled) {
1910         TRACKMOUSEEVENT tme;
1911         if (oldHotItem != infoPtr->iHotItem && !infoPtr->bDragging) {
1912             hdc = GetDC (hwnd);
1913             if (oldHotItem != -1) HEADER_RefreshItem (hwnd, hdc, oldHotItem);
1914             if (infoPtr->iHotItem != -1) HEADER_RefreshItem (hwnd, hdc, infoPtr->iHotItem);
1915             ReleaseDC (hwnd, hdc);
1916         }
1917         tme.cbSize = sizeof( tme );
1918         tme.dwFlags = TME_LEAVE;
1919         tme.hwndTrack = hwnd;
1920         TrackMouseEvent( &tme );
1921     }
1922
1923     return 0;
1924 }
1925
1926
1927 static LRESULT
1928 HEADER_Paint (HWND hwnd, WPARAM wParam)
1929 {
1930     HDC hdc;
1931     PAINTSTRUCT ps;
1932
1933     hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
1934     HEADER_Refresh (hwnd, hdc);
1935     if(!wParam)
1936         EndPaint (hwnd, &ps);
1937     return 0;
1938 }
1939
1940
1941 static LRESULT
1942 HEADER_RButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1943 {
1944     BOOL bRet;
1945     POINT pt;
1946
1947     pt.x = LOWORD(lParam);
1948     pt.y = HIWORD(lParam);
1949
1950     /* Send a Notify message */
1951     bRet = HEADER_SendSimpleNotify (hwnd, NM_RCLICK);
1952
1953     /* Change to screen coordinate for WM_CONTEXTMENU */
1954     ClientToScreen(hwnd, &pt);
1955
1956     /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
1957     SendMessageW( hwnd, WM_CONTEXTMENU, (WPARAM) hwnd, MAKELPARAM(pt.x, pt.y));
1958
1959     return bRet;
1960 }
1961
1962
1963 static LRESULT
1964 HEADER_SetCursor (HWND hwnd, WPARAM wParam, LPARAM lParam)
1965 {
1966     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1967     POINT pt;
1968     UINT  flags;
1969     INT   nItem;
1970
1971     TRACE("code=0x%X  id=0x%X\n", LOWORD(lParam), HIWORD(lParam));
1972
1973     GetCursorPos (&pt);
1974     ScreenToClient (hwnd, &pt);
1975
1976     HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem);
1977
1978     if (flags == HHT_ONDIVIDER)
1979         SetCursor (infoPtr->hcurDivider);
1980     else if (flags == HHT_ONDIVOPEN)
1981         SetCursor (infoPtr->hcurDivopen);
1982     else
1983         SetCursor (infoPtr->hcurArrow);
1984
1985     return 0;
1986 }
1987
1988
1989 static LRESULT
1990 HEADER_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
1991 {
1992     HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd);
1993     TEXTMETRICW tm;
1994     HFONT hFont, hOldFont;
1995     HDC hdc;
1996
1997     infoPtr->hFont = (HFONT)wParam;
1998
1999     hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
2000
2001     hdc = GetDC (0);
2002     hOldFont = SelectObject (hdc, hFont);
2003     GetTextMetricsW (hdc, &tm);
2004     infoPtr->nHeight = tm.tmHeight + VERT_BORDER;
2005     SelectObject (hdc, hOldFont);
2006     ReleaseDC (0, hdc);
2007
2008     infoPtr->bRectsValid = FALSE;
2009
2010     if (lParam) {
2011         InvalidateRect(hwnd, NULL, FALSE);
2012     }
2013
2014     return 0;
2015 }
2016
2017 /* Update the theme handle after a theme change */
2018 static LRESULT HEADER_ThemeChanged(HWND hwnd)
2019 {
2020     HTHEME theme = GetWindowTheme(hwnd);
2021     CloseThemeData(theme);
2022     OpenThemeData(hwnd, themeClass);
2023     InvalidateRect(hwnd, NULL, FALSE);
2024     return 0;
2025 }
2026
2027
2028 static LRESULT WINAPI
2029 HEADER_WindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
2030 {
2031     TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx\n", hwnd, msg, wParam, lParam);
2032     if (!HEADER_GetInfoPtr (hwnd) && (msg != WM_CREATE))
2033         return DefWindowProcW (hwnd, msg, wParam, lParam);
2034     switch (msg) {
2035 /*      case HDM_CLEARFILTER: */
2036
2037         case HDM_CREATEDRAGIMAGE:
2038             return HEADER_CreateDragImage (hwnd, wParam);
2039
2040         case HDM_DELETEITEM:
2041             return HEADER_DeleteItem (hwnd, wParam);
2042
2043 /*      case HDM_EDITFILTER: */
2044
2045         case HDM_GETBITMAPMARGIN:
2046             return HEADER_GetBitmapMargin(hwnd);
2047
2048         case HDM_GETIMAGELIST:
2049             return HEADER_GetImageList (hwnd);
2050
2051         case HDM_GETITEMA:
2052         case HDM_GETITEMW:
2053             return HEADER_GetItemT (hwnd, (INT)wParam, (LPHDITEMW)lParam, msg == HDM_GETITEMW);
2054
2055         case HDM_GETITEMCOUNT:
2056             return HEADER_GetItemCount (hwnd);
2057
2058         case HDM_GETITEMRECT:
2059             return HEADER_GetItemRect (hwnd, wParam, lParam);
2060
2061         case HDM_GETORDERARRAY:
2062             return HEADER_GetOrderArray(hwnd, wParam, lParam);
2063
2064         case HDM_GETUNICODEFORMAT:
2065             return HEADER_GetUnicodeFormat (hwnd);
2066
2067         case HDM_HITTEST:
2068             return HEADER_HitTest (hwnd, wParam, lParam);
2069
2070         case HDM_INSERTITEMA:
2071         case HDM_INSERTITEMW:
2072             return HEADER_InsertItemT (hwnd, (INT)wParam, (LPHDITEMW)lParam, msg == HDM_INSERTITEMW);
2073
2074         case HDM_LAYOUT:
2075             return HEADER_Layout (hwnd, wParam, lParam);
2076
2077         case HDM_ORDERTOINDEX:
2078             return HEADER_OrderToIndex(hwnd, wParam);
2079
2080         case HDM_SETBITMAPMARGIN:
2081             return HEADER_SetBitmapMargin(hwnd, wParam);
2082
2083 /*      case HDM_SETFILTERCHANGETIMEOUT: */
2084
2085         case HDM_SETHOTDIVIDER:
2086             return HEADER_SetHotDivider(hwnd, wParam, lParam);
2087
2088         case HDM_SETIMAGELIST:
2089             return HEADER_SetImageList (hwnd, (HIMAGELIST)lParam);
2090
2091         case HDM_SETITEMA:
2092         case HDM_SETITEMW:
2093             return HEADER_SetItemT (hwnd, (INT)wParam, (LPHDITEMW)lParam, msg == HDM_SETITEMW);
2094
2095         case HDM_SETORDERARRAY:
2096             return HEADER_SetOrderArray(hwnd, wParam, lParam);
2097
2098         case HDM_SETUNICODEFORMAT:
2099             return HEADER_SetUnicodeFormat (hwnd, wParam);
2100
2101         case WM_CREATE:
2102             return HEADER_Create (hwnd, wParam, lParam);
2103
2104         case WM_DESTROY:
2105             return HEADER_Destroy (hwnd, wParam, lParam);
2106
2107         case WM_ERASEBKGND:
2108             return 1;
2109
2110         case WM_GETDLGCODE:
2111             return DLGC_WANTTAB | DLGC_WANTARROWS;
2112
2113         case WM_GETFONT:
2114             return HEADER_GetFont (hwnd);
2115
2116         case WM_LBUTTONDBLCLK:
2117             return HEADER_LButtonDblClk (hwnd, wParam, lParam);
2118
2119         case WM_LBUTTONDOWN:
2120             return HEADER_LButtonDown (hwnd, wParam, lParam);
2121
2122         case WM_LBUTTONUP:
2123             return HEADER_LButtonUp (hwnd, wParam, lParam);
2124
2125         case WM_MOUSELEAVE:
2126             return HEADER_MouseLeave (hwnd, wParam, lParam);
2127
2128         case WM_MOUSEMOVE:
2129             return HEADER_MouseMove (hwnd, wParam, lParam);
2130
2131         case WM_NOTIFYFORMAT:
2132             return HEADER_NotifyFormat (hwnd, wParam, lParam);
2133
2134         case WM_SIZE:
2135             return HEADER_Size (hwnd, wParam);
2136
2137         case WM_THEMECHANGED:
2138             return HEADER_ThemeChanged (hwnd);
2139
2140         case WM_PRINTCLIENT:
2141         case WM_PAINT:
2142             return HEADER_Paint (hwnd, wParam);
2143
2144         case WM_RBUTTONUP:
2145             return HEADER_RButtonUp (hwnd, wParam, lParam);
2146
2147         case WM_SETCURSOR:
2148             return HEADER_SetCursor (hwnd, wParam, lParam);
2149
2150         case WM_SETFONT:
2151             return HEADER_SetFont (hwnd, wParam, lParam);
2152
2153         default:
2154             if ((msg >= WM_USER) && (msg < WM_APP))
2155                 ERR("unknown msg %04x wp=%04x lp=%08lx\n",
2156                      msg, wParam, lParam );
2157             return DefWindowProcA (hwnd, msg, wParam, lParam);
2158     }
2159 }
2160
2161
2162 VOID
2163 HEADER_Register (void)
2164 {
2165     WNDCLASSW wndClass;
2166
2167     ZeroMemory (&wndClass, sizeof(WNDCLASSW));
2168     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
2169     wndClass.lpfnWndProc   = HEADER_WindowProc;
2170     wndClass.cbClsExtra    = 0;
2171     wndClass.cbWndExtra    = sizeof(HEADER_INFO *);
2172     wndClass.hCursor       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
2173     wndClass.lpszClassName = WC_HEADERW;
2174
2175     RegisterClassW (&wndClass);
2176 }
2177
2178
2179 VOID
2180 HEADER_Unregister (void)
2181 {
2182     UnregisterClassW (WC_HEADERW, NULL);
2183 }