~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/comctl32/imagelist.c

Version: ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*
  2  *  ImageList implementation
  3  *
  4  *  Copyright 1998 Eric Kohl
  5  *  Copyright 2000 Jason Mawdsley
  6  *  Copyright 2001, 2004 Michael Stefaniuc
  7  *  Copyright 2001 Charles Loep for CodeWeavers
  8  *  Copyright 2002 Dimitrie O. Paun
  9  *
 10  * This library is free software; you can redistribute it and/or
 11  * modify it under the terms of the GNU Lesser General Public
 12  * License as published by the Free Software Foundation; either
 13  * version 2.1 of the License, or (at your option) any later version.
 14  *
 15  * This library is distributed in the hope that it will be useful,
 16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 18  * Lesser General Public License for more details.
 19  *
 20  * You should have received a copy of the GNU Lesser General Public
 21  * License along with this library; if not, write to the Free Software
 22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 23  *
 24  * NOTE
 25  *
 26  * This code was audited for completeness against the documented features
 27  * of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun.
 28  *
 29  * Unless otherwise noted, we believe this code to be complete, as per
 30  * the specification mentioned above.
 31  * If you discover missing features, or bugs, please note them below.
 32  *
 33  *  TODO:
 34  *    - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
 35  *    - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE, ILS_ALPHA
 36  *    - Thread-safe locking
 37  */
 38 
 39 #include <stdarg.h>
 40 #include <stdlib.h>
 41 #include <string.h>
 42 
 43 #define COBJMACROS
 44 
 45 #include "winerror.h"
 46 #include "windef.h"
 47 #include "winbase.h"
 48 #include "objbase.h"
 49 #include "wingdi.h"
 50 #include "winuser.h"
 51 #include "commctrl.h"
 52 #include "comctl32.h"
 53 #include "imagelist.h"
 54 #include "wine/debug.h"
 55 
 56 WINE_DEFAULT_DEBUG_CHANNEL(imagelist);
 57 
 58 
 59 #define MAX_OVERLAYIMAGE 15
 60 
 61 /* internal image list data used for Drag & Drop operations */
 62 typedef struct
 63 {
 64     HWND        hwnd;
 65     HIMAGELIST  himl;
 66     /* position of the drag image relative to the window */
 67     INT         x;
 68     INT         y;
 69     /* offset of the hotspot relative to the origin of the image */
 70     INT         dxHotspot;
 71     INT         dyHotspot;
 72     /* is the drag image visible */
 73     BOOL        bShow;
 74     /* saved background */
 75     HBITMAP     hbmBg;
 76 } INTERNALDRAG;
 77 
 78 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 };
 79 
 80 static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count, UINT width);
 81 
 82 static inline BOOL is_valid(HIMAGELIST himl)
 83 {
 84     return himl && himl->magic == IMAGELIST_MAGIC;
 85 }
 86 
 87 /*
 88  * An imagelist with N images is tiled like this:
 89  *
 90  *   N/4 ->
 91  *
 92  * 4 048C..
 93  *   159D..
 94  * | 26AE.N
 95  * V 37BF.
 96  */
 97 
 98 #define TILE_COUNT 4
 99 
100 static inline UINT imagelist_height( UINT count )
101 {
102     return ((count + TILE_COUNT - 1)/TILE_COUNT);
103 }
104 
105 static inline void imagelist_point_from_index( HIMAGELIST himl, UINT index, LPPOINT pt )
106 {
107     pt->x = (index%TILE_COUNT) * himl->cx;
108     pt->y = (index/TILE_COUNT) * himl->cy;
109 }
110 
111 static inline void imagelist_get_bitmap_size( HIMAGELIST himl, UINT count, UINT cx, SIZE *sz )
112 {
113     sz->cx = cx * TILE_COUNT;
114     sz->cy = imagelist_height( count ) * himl->cy;
115 }
116 
117 /*
118  * imagelist_copy_images()
119  *
120  * Copies a block of count images from offset src in the list to offset dest.
121  * Images are copied a row at at time. Assumes hdcSrc and hdcDest are different.
122  */
123 static inline void imagelist_copy_images( HIMAGELIST himl, HDC hdcSrc, HDC hdcDest,
124                                           UINT src, UINT count, UINT dest )
125 {
126     POINT ptSrc, ptDest;
127     SIZE sz;
128     UINT i;
129 
130     for ( i=0; i<TILE_COUNT; i++ )
131     {
132         imagelist_point_from_index( himl, src+i, &ptSrc );
133         imagelist_point_from_index( himl, dest+i, &ptDest );
134         sz.cx = himl->cx;
135         sz.cy = himl->cy * imagelist_height( count - i );
136 
137         BitBlt( hdcDest, ptDest.x, ptDest.y, sz.cx, sz.cy,
138                 hdcSrc, ptSrc.x, ptSrc.y, SRCCOPY );
139     }
140 }
141 
142 /*************************************************************************
143  * IMAGELIST_InternalExpandBitmaps [Internal]
144  *
145  * Expands the bitmaps of an image list by the given number of images.
146  *
147  * PARAMS
148  *     himl        [I] handle to image list
149  *     nImageCount [I] number of images to add
150  *
151  * RETURNS
152  *     nothing
153  *
154  * NOTES
155  *     This function CANNOT be used to reduce the number of images.
156  */
157 static void
158 IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy)
159 {
160     HDC     hdcBitmap;
161     HBITMAP hbmNewBitmap, hbmNull;
162     INT     nNewCount;
163     SIZE    sz;
164 
165     if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
166         && (himl->cy >= cy))
167         return;
168 
169     if (cx == 0) cx = himl->cx;
170     nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
171 
172     imagelist_get_bitmap_size(himl, nNewCount, cx, &sz);
173 
174     TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, sz.cx, cy, nNewCount);
175     hdcBitmap = CreateCompatibleDC (0);
176 
177     hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount, cx);
178 
179     if (hbmNewBitmap == 0)
180         ERR("creating new image bitmap (x=%d y=%d)!\n", sz.cx, cy);
181 
182     if (himl->cCurImage)
183     {
184         hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
185         BitBlt (hdcBitmap, 0, 0, sz.cx, sz.cy,
186                 himl->hdcImage, 0, 0, SRCCOPY);
187         SelectObject (hdcBitmap, hbmNull);
188     }
189     SelectObject (himl->hdcImage, hbmNewBitmap);
190     DeleteObject (himl->hbmImage);
191     himl->hbmImage = hbmNewBitmap;
192 
193     if (himl->flags & ILC_MASK)
194     {
195         hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
196 
197         if (hbmNewBitmap == 0)
198             ERR("creating new mask bitmap!\n");
199 
200         if(himl->cCurImage)
201         {
202             hbmNull = SelectObject (hdcBitmap, hbmNewBitmap);
203             BitBlt (hdcBitmap, 0, 0, sz.cx, sz.cy,
204                     himl->hdcMask, 0, 0, SRCCOPY);
205             SelectObject (hdcBitmap, hbmNull);
206         }
207         SelectObject (himl->hdcMask, hbmNewBitmap);
208         DeleteObject (himl->hbmMask);
209         himl->hbmMask = hbmNewBitmap;
210     }
211 
212     himl->cMaxImage = nNewCount;
213 
214     DeleteDC (hdcBitmap);
215 }
216 
217 
218 /*************************************************************************
219  * ImageList_Add [COMCTL32.@]
220  *
221  * Add an image or images to an image list.
222  *
223  * PARAMS
224  *     himl     [I] handle to image list
225  *     hbmImage [I] handle to image bitmap
226  *     hbmMask  [I] handle to mask bitmap
227  *
228  * RETURNS
229  *     Success: Index of the first new image.
230  *     Failure: -1
231  */
232 
233 INT WINAPI
234 ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
235 {
236     HDC     hdcBitmap, hdcTemp;
237     INT     nFirstIndex, nImageCount, i;
238     BITMAP  bmp;
239     HBITMAP hOldBitmap, hOldBitmapTemp;
240     POINT   pt;
241 
242     TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
243     if (!is_valid(himl))
244         return -1;
245 
246     if (!GetObjectW(hbmImage, sizeof(BITMAP), (LPVOID)&bmp))
247         return -1;
248 
249     nImageCount = bmp.bmWidth / himl->cx;
250 
251     IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
252 
253     hdcBitmap = CreateCompatibleDC(0);
254 
255     hOldBitmap = SelectObject(hdcBitmap, hbmImage);
256 
257     for (i=0; i<nImageCount; i++)
258     {
259         imagelist_point_from_index( himl, himl->cCurImage + i, &pt );
260 
261         /* Copy result to the imagelist
262         */
263         BitBlt( himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
264                 hdcBitmap, i*himl->cx, 0, SRCCOPY );
265 
266         if (!himl->hbmMask)
267              continue;
268 
269         hdcTemp   = CreateCompatibleDC(0);
270         hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
271 
272         BitBlt( himl->hdcMask, pt.x, pt.y, himl->cx, bmp.bmHeight,
273                 hdcTemp, i*himl->cx, 0, SRCCOPY );
274 
275         SelectObject(hdcTemp, hOldBitmapTemp);
276         DeleteDC(hdcTemp);
277 
278         /* Remove the background from the image
279         */
280         BitBlt( himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
281                 himl->hdcMask, pt.x, pt.y, 0x220326 ); /* NOTSRCAND */
282     }
283 
284     SelectObject(hdcBitmap, hOldBitmap);
285     DeleteDC(hdcBitmap);
286 
287     nFirstIndex = himl->cCurImage;
288     himl->cCurImage += nImageCount;
289 
290     return nFirstIndex;
291 }
292 
293 
294 /*************************************************************************
295  * ImageList_AddIcon [COMCTL32.@]
296  *
297  * Adds an icon to an image list.
298  *
299  * PARAMS
300  *     himl  [I] handle to image list
301  *     hIcon [I] handle to icon
302  *
303  * RETURNS
304  *     Success: index of the new image
305  *     Failure: -1
306  */
307 #undef ImageList_AddIcon
308 INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon)
309 {
310     return ImageList_ReplaceIcon (himl, -1, hIcon);
311 }
312 
313 
314 /*************************************************************************
315  * ImageList_AddMasked [COMCTL32.@]
316  *
317  * Adds an image or images to an image list and creates a mask from the
318  * specified bitmap using the mask color.
319  *
320  * PARAMS
321  *     himl    [I] handle to image list.
322  *     hBitmap [I] handle to bitmap
323  *     clrMask [I] mask color.
324  *
325  * RETURNS
326  *     Success: Index of the first new image.
327  *     Failure: -1
328  */
329 
330 INT WINAPI
331 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
332 {
333     HDC    hdcMask, hdcBitmap;
334     INT    i, nIndex, nImageCount;
335     BITMAP bmp;
336     HBITMAP hOldBitmap;
337     HBITMAP hMaskBitmap=0;
338     COLORREF bkColor;
339     POINT  pt;
340 
341     TRACE("himl=%p hbitmap=%p clrmask=%x\n", himl, hBitmap, clrMask);
342     if (!is_valid(himl))
343         return -1;
344 
345     if (!GetObjectW(hBitmap, sizeof(BITMAP), &bmp))
346         return -1;
347 
348     if (himl->cx > 0)
349         nImageCount = bmp.bmWidth / himl->cx;
350     else
351         nImageCount = 0;
352 
353     IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight);
354 
355     nIndex = himl->cCurImage;
356     himl->cCurImage += nImageCount;
357 
358     hdcBitmap = CreateCompatibleDC(0);
359     hOldBitmap = SelectObject(hdcBitmap, hBitmap);
360 
361     /* Create a temp Mask so we can remove the background of the Image */
362     hdcMask = CreateCompatibleDC(0);
363     hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL);
364     SelectObject(hdcMask, hMaskBitmap);
365 
366     /* create monochrome image to the mask bitmap */
367     bkColor = (clrMask != CLR_DEFAULT) ? clrMask : GetPixel (hdcBitmap, 0, 0);
368     SetBkColor (hdcBitmap, bkColor);
369     BitBlt (hdcMask, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcBitmap, 0, 0, SRCCOPY);
370 
371     SetBkColor(hdcBitmap, RGB(255,255,255));
372 
373     /*
374      * Remove the background from the image
375      *
376      * WINDOWS BUG ALERT!!!!!!
377      *  The statement below should not be done in common practice
378      *  but this is how ImageList_AddMasked works in Windows.
379      *  It overwrites the original bitmap passed, this was discovered
380      *  by using the same bitmap to iterate the different styles
381      *  on windows where it failed (BUT ImageList_Add is OK)
382      *  This is here in case some apps rely on this bug
383      *
384      *  Blt mode 0x220326 is NOTSRCAND
385      */
386     BitBlt(hdcBitmap, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcMask, 0, 0, 0x220326);
387 
388     /* Copy result to the imagelist */
389     for (i=0; i<nImageCount; i++)
390     {
391         imagelist_point_from_index( himl, nIndex + i, &pt );
392         BitBlt(himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
393                 hdcBitmap, i*himl->cx, 0, SRCCOPY);
394         BitBlt(himl->hdcMask, pt.x, pt.y, himl->cx, bmp.bmHeight,
395                 hdcMask, i*himl->cx, 0, SRCCOPY);
396     }
397 
398     /* Clean up */
399     SelectObject(hdcBitmap, hOldBitmap);
400     DeleteDC(hdcBitmap);
401     DeleteObject(hMaskBitmap);
402     DeleteDC(hdcMask);
403 
404     return nIndex;
405 }
406 
407 
408 /*************************************************************************
409  * ImageList_BeginDrag [COMCTL32.@]
410  *
411  * Creates a temporary image list that contains one image. It will be used
412  * as a drag image.
413  *
414  * PARAMS
415  *     himlTrack [I] handle to the source image list
416  *     iTrack    [I] index of the drag image in the source image list
417  *     dxHotspot [I] X position of the hot spot of the drag image
418  *     dyHotspot [I] Y position of the hot spot of the drag image
419  *
420  * RETURNS
421  *     Success: TRUE
422  *     Failure: FALSE
423  */
424 
425 BOOL WINAPI
426 ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack,
427                      INT dxHotspot, INT dyHotspot)
428 {
429     INT cx, cy;
430 
431     TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack,
432           dxHotspot, dyHotspot);
433 
434     if (!is_valid(himlTrack))
435         return FALSE;
436 
437     if (InternalDrag.himl)
438         ImageList_EndDrag ();
439 
440     cx = himlTrack->cx;
441     cy = himlTrack->cy;
442 
443     InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1);
444     if (InternalDrag.himl == NULL) {
445         WARN("Error creating drag image list!\n");
446         return FALSE;
447     }
448 
449     InternalDrag.dxHotspot = dxHotspot;
450     InternalDrag.dyHotspot = dyHotspot;
451 
452     /* copy image */
453     BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY);
454 
455     /* copy mask */
456     BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY);
457 
458     InternalDrag.himl->cCurImage = 1;
459 
460     return TRUE;
461 }
462 
463 
464 /*************************************************************************
465  * ImageList_Copy [COMCTL32.@]
466  *
467  *  Copies an image of the source image list to an image of the
468  *  destination image list. Images can be copied or swapped.
469  *
470  * PARAMS
471  *     himlDst [I] handle to the destination image list
472  *     iDst    [I] destination image index.
473  *     himlSrc [I] handle to the source image list
474  *     iSrc    [I] source image index
475  *     uFlags  [I] flags for the copy operation
476  *
477  * RETURNS
478  *     Success: TRUE
479  *     Failure: FALSE
480  *
481  * NOTES
482  *     Copying from one image list to another is possible. The original
483  *     implementation just copies or swaps within one image list.
484  *     Could this feature become a bug??? ;-)
485  */
486 
487 BOOL WINAPI
488 ImageList_Copy (HIMAGELIST himlDst, INT iDst,   HIMAGELIST himlSrc,
489                 INT iSrc, UINT uFlags)
490 {
491     POINT ptSrc, ptDst;
492 
493     TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst, iDst, himlSrc, iSrc);
494 
495     if (!is_valid(himlSrc) || !is_valid(himlDst))
496         return FALSE;
497     if ((iDst < 0) || (iDst >= himlDst->cCurImage))
498         return FALSE;
499     if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage))
500         return FALSE;
501 
502     imagelist_point_from_index( himlDst, iDst, &ptDst );
503     imagelist_point_from_index( himlSrc, iSrc, &ptSrc );
504 
505     if (uFlags & ILCF_SWAP) {
506         /* swap */
507         HDC     hdcBmp;
508         HBITMAP hbmTempImage, hbmTempMask;
509 
510         hdcBmp = CreateCompatibleDC (0);
511 
512         /* create temporary bitmaps */
513         hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
514                                        himlSrc->uBitsPixel, NULL);
515         hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1,
516                                       1, NULL);
517 
518         /* copy (and stretch) destination to temporary bitmaps.(save) */
519         /* image */
520         SelectObject (hdcBmp, hbmTempImage);
521         StretchBlt   (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
522                       himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
523                       SRCCOPY);
524         /* mask */
525         SelectObject (hdcBmp, hbmTempMask);
526         StretchBlt   (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy,
527                       himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
528                       SRCCOPY);
529 
530         /* copy (and stretch) source to destination */
531         /* image */
532         StretchBlt   (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
533                       himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
534                       SRCCOPY);
535         /* mask */
536         StretchBlt   (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
537                       himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
538                       SRCCOPY);
539 
540         /* copy (without stretching) temporary bitmaps to source (restore) */
541         /* mask */
542         BitBlt       (himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
543                       hdcBmp, 0, 0, SRCCOPY);
544 
545         /* image */
546         BitBlt       (himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
547                       hdcBmp, 0, 0, SRCCOPY);
548         /* delete temporary bitmaps */
549         DeleteObject (hbmTempMask);
550         DeleteObject (hbmTempImage);
551         DeleteDC(hdcBmp);
552     }
553     else {
554         /* copy image */
555         StretchBlt   (himlDst->hdcImage, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
556                       himlSrc->hdcImage, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
557                       SRCCOPY);
558 
559         /* copy mask */
560         StretchBlt   (himlDst->hdcMask, ptDst.x, ptDst.y, himlDst->cx, himlDst->cy,
561                       himlSrc->hdcMask, ptSrc.x, ptSrc.y, himlSrc->cx, himlSrc->cy,
562                       SRCCOPY);
563     }
564 
565     return TRUE;
566 }
567 
568 
569 /*************************************************************************
570  * ImageList_Create [COMCTL32.@]
571  *
572  * Creates a new image list.
573  *
574  * PARAMS
575  *     cx       [I] image height
576  *     cy       [I] image width
577  *     flags    [I] creation flags
578  *     cInitial [I] initial number of images in the image list
579  *     cGrow    [I] number of images by which image list grows
580  *
581  * RETURNS
582  *     Success: Handle to the created image list
583  *     Failure: NULL
584  */
585 HIMAGELIST WINAPI
586 ImageList_Create (INT cx, INT cy, UINT flags,
587                   INT cInitial, INT cGrow)
588 {
589     HIMAGELIST himl;
590     INT      nCount;
591     HBITMAP  hbmTemp;
592     UINT     ilc = (flags & 0xFE);
593     static const WORD aBitBlend25[] =
594         {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00};
595 
596     static const WORD aBitBlend50[] =
597         {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
598 
599     TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
600 
601     himl = (HIMAGELIST)Alloc (sizeof(struct _IMAGELIST));
602     if (!himl)
603         return NULL;
604 
605     cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3;
606 
607     himl->magic     = IMAGELIST_MAGIC;
608     himl->cx        = cx;
609     himl->cy        = cy;
610     himl->flags     = flags;
611     himl->cMaxImage = cInitial + 1;
612     himl->cInitial  = cInitial;
613     himl->cGrow     = cGrow;
614     himl->clrFg     = CLR_DEFAULT;
615     himl->clrBk     = CLR_NONE;
616 
617     /* initialize overlay mask indices */
618     for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
619         himl->nOvlIdx[nCount] = -1;
620 
621     /* Create Image & Mask DCs */
622     himl->hdcImage = CreateCompatibleDC (0);
623     if (!himl->hdcImage)
624         goto cleanup;
625     if (himl->flags & ILC_MASK){
626         himl->hdcMask = CreateCompatibleDC(0);
627         if (!himl->hdcMask)
628             goto cleanup;
629     }
630 
631     /* Default to ILC_COLOR4 if none of the ILC_COLOR* flags are specified */
632     if (ilc == ILC_COLOR)
633         ilc = ILC_COLOR4;
634 
635     if (ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32)
636         himl->uBitsPixel = ilc;
637     else
638         himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
639 
640     if (himl->cMaxImage > 0) {
641         himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, cx);
642         SelectObject(himl->hdcImage, himl->hbmImage);
643     } else
644         himl->hbmImage = 0;
645 
646     if ((himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
647         SIZE sz;
648 
649         imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cx, &sz);
650         himl->hbmMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
651         if (himl->hbmMask == 0) {
652             ERR("Error creating mask bitmap!\n");
653             goto cleanup;
654         }
655         SelectObject(himl->hdcMask, himl->hbmMask);
656     }
657     else
658         himl->hbmMask = 0;
659 
660     /* create blending brushes */
661     hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25);
662     himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
663     DeleteObject (hbmTemp);
664 
665     hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50);
666     himl->hbrBlend50 = CreatePatternBrush (hbmTemp);
667     DeleteObject (hbmTemp);
668 
669     TRACE("created imagelist %p\n", himl);
670     return himl;
671 
672 cleanup:
673     if (himl) ImageList_Destroy(himl);
674     return NULL;
675 }
676 
677 
678 /*************************************************************************
679  * ImageList_Destroy [COMCTL32.@]
680  *
681  * Destroys an image list.
682  *
683  * PARAMS
684  *     himl [I] handle to image list
685  *
686  * RETURNS
687  *     Success: TRUE
688  *     Failure: FALSE
689  */
690 
691 BOOL WINAPI
692 ImageList_Destroy (HIMAGELIST himl)
693 {
694     if (!is_valid(himl))
695         return FALSE;
696 
697     /* delete image bitmaps */
698     if (himl->hbmImage)
699         DeleteObject (himl->hbmImage);
700     if (himl->hbmMask)
701         DeleteObject (himl->hbmMask);
702 
703     /* delete image & mask DCs */
704     if (himl->hdcImage)
705         DeleteDC(himl->hdcImage);
706     if (himl->hdcMask)
707         DeleteDC(himl->hdcMask);
708 
709     /* delete blending brushes */
710     if (himl->hbrBlend25)
711         DeleteObject (himl->hbrBlend25);
712     if (himl->hbrBlend50)
713         DeleteObject (himl->hbrBlend50);
714 
715     ZeroMemory(himl, sizeof(*himl));
716     Free (himl);
717 
718     return TRUE;
719 }
720 
721 
722 /*************************************************************************
723  * ImageList_DragEnter [COMCTL32.@]
724  *
725  * Locks window update and displays the drag image at the given position.
726  *
727  * PARAMS
728  *     hwndLock [I] handle of the window that owns the drag image.
729  *     x        [I] X position of the drag image.
730  *     y        [I] Y position of the drag image.
731  *
732  * RETURNS
733  *     Success: TRUE
734  *     Failure: FALSE
735  *
736  * NOTES
737  *     The position of the drag image is relative to the window, not
738  *     the client area.
739  */
740 
741 BOOL WINAPI
742 ImageList_DragEnter (HWND hwndLock, INT x, INT y)
743 {
744     TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y);
745 
746     if (!is_valid(InternalDrag.himl))
747         return FALSE;
748 
749     if (hwndLock)
750         InternalDrag.hwnd = hwndLock;
751     else
752         InternalDrag.hwnd = GetDesktopWindow ();
753 
754     InternalDrag.x = x;
755     InternalDrag.y = y;
756 
757     /* draw the drag image and save the background */
758     if (!ImageList_DragShowNolock(TRUE)) {
759         return FALSE;
760     }
761 
762     return TRUE;
763 }
764 
765 
766 /*************************************************************************
767  * ImageList_DragLeave [COMCTL32.@]
768  *
769  * Unlocks window update and hides the drag image.
770  *
771  * PARAMS
772  *     hwndLock [I] handle of the window that owns the drag image.
773  *
774  * RETURNS
775  *     Success: TRUE
776  *     Failure: FALSE
777  */
778 
779 BOOL WINAPI
780 ImageList_DragLeave (HWND hwndLock)
781 {
782     /* As we don't save drag info in the window this can lead to problems if
783        an app does not supply the same window as DragEnter */
784     /* if (hwndLock)
785         InternalDrag.hwnd = hwndLock;
786     else
787         InternalDrag.hwnd = GetDesktopWindow (); */
788     if(!hwndLock)
789         hwndLock = GetDesktopWindow();
790     if(InternalDrag.hwnd != hwndLock)
791         FIXME("DragLeave hWnd != DragEnter hWnd\n");
792 
793     ImageList_DragShowNolock (FALSE);
794 
795     return TRUE;
796 }
797 
798 
799 /*************************************************************************
800  * ImageList_InternalDragDraw [Internal]
801  *
802  * Draws the drag image.
803  *
804  * PARAMS
805  *     hdc [I] device context to draw into.
806  *     x   [I] X position of the drag image.
807  *     y   [I] Y position of the drag image.
808  *
809  * RETURNS
810  *     Success: TRUE
811  *     Failure: FALSE
812  *
813  * NOTES
814  *     The position of the drag image is relative to the window, not
815  *     the client area.
816  *
817  */
818 
819 static inline void
820 ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
821 {
822     IMAGELISTDRAWPARAMS imldp;
823 
824     ZeroMemory (&imldp, sizeof(imldp));
825     imldp.cbSize  = sizeof(imldp);
826     imldp.himl    = InternalDrag.himl;
827     imldp.i       = 0;
828     imldp.hdcDst  = hdc,
829     imldp.x       = x;
830     imldp.y       = y;
831     imldp.rgbBk   = CLR_DEFAULT;
832     imldp.rgbFg   = CLR_DEFAULT;
833     imldp.fStyle  = ILD_NORMAL;
834     imldp.fState  = ILS_ALPHA;
835     imldp.Frame   = 128;
836 
837     /* FIXME: instead of using the alpha blending, we should
838      * create a 50% mask, and draw it semitransparantly that way */
839     ImageList_DrawIndirect (&imldp);
840 }
841 
842 /*************************************************************************
843  * ImageList_DragMove [COMCTL32.@]
844  *
845  * Moves the drag image.
846  *
847  * PARAMS
848  *     x [I] X position of the drag image.
849  *     y [I] Y position of the drag image.
850  *
851  * RETURNS
852  *     Success: TRUE
853  *     Failure: FALSE
854  *
855  * NOTES
856  *     The position of the drag image is relative to the window, not
857  *     the client area.
858  *
859  * BUGS
860  *     The drag image should be drawn semitransparent.
861  */
862 
863 BOOL WINAPI
864 ImageList_DragMove (INT x, INT y)
865 {
866     TRACE("(x=%d y=%d)\n", x, y);
867 
868     if (!is_valid(InternalDrag.himl))
869         return FALSE;
870 
871     /* draw/update the drag image */
872     if (InternalDrag.bShow) {
873         HDC hdcDrag;
874         HDC hdcOffScreen;
875         HDC hdcBg;
876         HBITMAP hbmOffScreen;
877         INT origNewX, origNewY;
878         INT origOldX, origOldY;
879         INT origRegX, origRegY;
880         INT sizeRegX, sizeRegY;
881 
882 
883         /* calculate the update region */
884         origNewX = x - InternalDrag.dxHotspot;
885         origNewY = y - InternalDrag.dyHotspot;
886         origOldX = InternalDrag.x - InternalDrag.dxHotspot;
887         origOldY = InternalDrag.y - InternalDrag.dyHotspot;
888         origRegX = min(origNewX, origOldX);
889         origRegY = min(origNewY, origOldY);
890         sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x);
891         sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y);
892 
893         hdcDrag = GetDCEx(InternalDrag.hwnd, 0,
894                           DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
895         hdcOffScreen = CreateCompatibleDC(hdcDrag);
896         hdcBg = CreateCompatibleDC(hdcDrag);
897 
898         hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY);
899         SelectObject(hdcOffScreen, hbmOffScreen);
900         SelectObject(hdcBg, InternalDrag.hbmBg);
901 
902         /* get the actual background of the update region */
903         BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag,
904                origRegX, origRegY, SRCCOPY);
905         /* erase the old image */
906         BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY,
907                InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0,
908                SRCCOPY);
909         /* save the background */
910         BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
911                hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY);
912         /* draw the image */
913         ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX, 
914                                    origNewY - origRegY);
915         /* draw the update region to the screen */
916         BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY,
917                hdcOffScreen, 0, 0, SRCCOPY);
918 
919         DeleteDC(hdcBg);
920         DeleteDC(hdcOffScreen);
921         DeleteObject(hbmOffScreen);
922         ReleaseDC(InternalDrag.hwnd, hdcDrag);
923     }
924 
925     /* update the image position */
926     InternalDrag.x = x;
927     InternalDrag.y = y;
928 
929     return TRUE;
930 }
931 
932 
933 /*************************************************************************
934  * ImageList_DragShowNolock [COMCTL32.@]
935  *
936  * Shows or hides the drag image.
937  *
938  * PARAMS
939  *     bShow [I] TRUE shows the drag image, FALSE hides it.
940  *
941  * RETURNS
942  *     Success: TRUE
943  *     Failure: FALSE
944  *
945  * BUGS
946  *     The drag image should be drawn semitransparent.
947  */
948 
949 BOOL WINAPI
950 ImageList_DragShowNolock (BOOL bShow)
951 {
952     HDC hdcDrag;
953     HDC hdcBg;
954     INT x, y;
955 
956     if (!is_valid(InternalDrag.himl))
957         return FALSE;
958     
959     TRACE("bShow=0x%X!\n", bShow);
960 
961     /* DragImage is already visible/hidden */
962     if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) {
963         return FALSE;
964     }
965 
966     /* position of the origin of the DragImage */
967     x = InternalDrag.x - InternalDrag.dxHotspot;
968     y = InternalDrag.y - InternalDrag.dyHotspot;
969 
970     hdcDrag = GetDCEx (InternalDrag.hwnd, 0,
971                          DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
972     if (!hdcDrag) {
973         return FALSE;
974     }
975 
976     hdcBg = CreateCompatibleDC(hdcDrag);
977     if (!InternalDrag.hbmBg) {
978         InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag,
979                     InternalDrag.himl->cx, InternalDrag.himl->cy);
980     }
981     SelectObject(hdcBg, InternalDrag.hbmBg);
982 
983     if (bShow) {
984         /* save the background */
985         BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy,
986                hdcDrag, x, y, SRCCOPY);
987         /* show the image */
988         ImageList_InternalDragDraw(hdcDrag, x, y);
989     } else {
990         /* hide the image */
991         BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy,
992                hdcBg, 0, 0, SRCCOPY);