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