1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/gdiimage.cpp
3 // Purpose:     wxGDIImage implementation
4 // Author:      Vadim Zeitlin
5 // Modified by:
6 // Created:     20.11.99
7 // RCS-ID:      $Id: gdiimage.cpp 41689 2006-10-08 08:04:49Z PC $
8 // Copyright:   (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence:     wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11 
12 // ============================================================================
13 // declarations
14 // ============================================================================
15 
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19 
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22 
23 #ifdef __BORLANDC__
24     #pragma hdrstop
25 #endif
26 
27 #ifndef WX_PRECOMP
28     #include "wx/string.h"
29     #include "wx/log.h"
30     #include "wx/app.h"
31     #include "wx/bitmap.h"
32 #endif // WX_PRECOMP
33 
34 #include "wx/msw/private.h"
35 
36 #include "wx/msw/gdiimage.h"
37 
38 #if wxUSE_WXDIB
39 #include "wx/msw/dib.h"
40 #endif
41 
42 #ifdef __WXWINCE__
43 #include <winreg.h>
44 #include <shellapi.h>
45 #endif
46 
47 #include "wx/file.h"
48 
49 #include "wx/listimpl.cpp"
50 WX_DEFINE_LIST(wxGDIImageHandlerList)
51 
52 // ----------------------------------------------------------------------------
53 // private classes
54 // ----------------------------------------------------------------------------
55 
56 #ifndef __WXMICROWIN__
57 
58 // all image handlers are declared/defined in this file because the outside
59 // world doesn't have to know about them (but only about wxBITMAP_TYPE_XXX ids)
60 
61 class WXDLLEXPORT wxBMPFileHandler : public wxBitmapHandler
62 {
63 public:
wxBMPFileHandler()64     wxBMPFileHandler() : wxBitmapHandler(_T("Windows bitmap file"), _T("bmp"),
65                                          wxBITMAP_TYPE_BMP)
66     {
67     }
68 
69     virtual bool LoadFile(wxBitmap *bitmap,
70                           const wxString& name, long flags,
71                           int desiredWidth, int desiredHeight);
72     virtual bool SaveFile(wxBitmap *bitmap,
73                           const wxString& name, int type,
74                           const wxPalette *palette = NULL);
75 
76 private:
77     DECLARE_DYNAMIC_CLASS(wxBMPFileHandler)
78 };
79 
80 class WXDLLEXPORT wxBMPResourceHandler: public wxBitmapHandler
81 {
82 public:
wxBMPResourceHandler()83     wxBMPResourceHandler() : wxBitmapHandler(_T("Windows bitmap resource"),
84                                              wxEmptyString,
85                                              wxBITMAP_TYPE_BMP_RESOURCE)
86     {
87     }
88 
89     virtual bool LoadFile(wxBitmap *bitmap,
90                           const wxString& name, long flags,
91                           int desiredWidth, int desiredHeight);
92 
93 private:
94     DECLARE_DYNAMIC_CLASS(wxBMPResourceHandler)
95 };
96 
97 class WXDLLEXPORT wxIconHandler : public wxGDIImageHandler
98 {
99 public:
wxIconHandler(const wxString & name,const wxString & ext,long type)100     wxIconHandler(const wxString& name, const wxString& ext, long type)
101         : wxGDIImageHandler(name, ext, type)
102     {
103     }
104 
105     // creating and saving icons is not supported
Create(wxGDIImage * WXUNUSED (image),const void * WXUNUSED (data),long WXUNUSED (flags),int WXUNUSED (width),int WXUNUSED (height),int WXUNUSED (depth)=1)106     virtual bool Create(wxGDIImage *WXUNUSED(image),
107                         const void* WXUNUSED(data),
108                         long WXUNUSED(flags),
109                         int WXUNUSED(width),
110                         int WXUNUSED(height),
111                         int WXUNUSED(depth) = 1)
112     {
113         return false;
114     }
115 
Save(wxGDIImage * WXUNUSED (image),const wxString & WXUNUSED (name),int WXUNUSED (type))116     virtual bool Save(wxGDIImage *WXUNUSED(image),
117                       const wxString& WXUNUSED(name),
118                       int WXUNUSED(type))
119     {
120         return false;
121     }
122 
Load(wxGDIImage * image,const wxString & name,long flags,int desiredWidth,int desiredHeight)123     virtual bool Load(wxGDIImage *image,
124                       const wxString& name,
125                       long flags,
126                       int desiredWidth, int desiredHeight)
127     {
128         wxIcon *icon = wxDynamicCast(image, wxIcon);
129         wxCHECK_MSG( icon, false, _T("wxIconHandler only works with icons") );
130 
131         return LoadIcon(icon, name, flags, desiredWidth, desiredHeight);
132     }
133 
134 protected:
135     virtual bool LoadIcon(wxIcon *icon,
136                           const wxString& name, long flags,
137                           int desiredWidth = -1, int desiredHeight = -1) = 0;
138 };
139 
140 class WXDLLEXPORT wxICOFileHandler : public wxIconHandler
141 {
142 public:
wxICOFileHandler()143     wxICOFileHandler() : wxIconHandler(_T("ICO icon file"),
144                                        _T("ico"),
145                                        wxBITMAP_TYPE_ICO)
146     {
147     }
148 
149 protected:
150     virtual bool LoadIcon(wxIcon *icon,
151                           const wxString& name, long flags,
152                           int desiredWidth = -1, int desiredHeight = -1);
153 
154 private:
155     DECLARE_DYNAMIC_CLASS(wxICOFileHandler)
156 };
157 
158 class WXDLLEXPORT wxICOResourceHandler: public wxIconHandler
159 {
160 public:
wxICOResourceHandler()161     wxICOResourceHandler() : wxIconHandler(_T("ICO resource"),
162                                            _T("ico"),
163                                            wxBITMAP_TYPE_ICO_RESOURCE)
164     {
165     }
166 
167 protected:
168     virtual bool LoadIcon(wxIcon *icon,
169                           const wxString& name, long flags,
170                           int desiredWidth = -1, int desiredHeight = -1);
171 
172 private:
173     DECLARE_DYNAMIC_CLASS(wxICOResourceHandler)
174 };
175 
176 // ----------------------------------------------------------------------------
177 // wxWin macros
178 // ----------------------------------------------------------------------------
179 
180 IMPLEMENT_DYNAMIC_CLASS(wxBMPFileHandler, wxBitmapHandler)
181 IMPLEMENT_DYNAMIC_CLASS(wxBMPResourceHandler, wxBitmapHandler)
182 IMPLEMENT_DYNAMIC_CLASS(wxICOFileHandler, wxObject)
183 IMPLEMENT_DYNAMIC_CLASS(wxICOResourceHandler, wxObject)
184 
185 // ----------------------------------------------------------------------------
186 // private functions
187 // ----------------------------------------------------------------------------
188 
189 #endif
190     // __MICROWIN__
191 
192 // ============================================================================
193 // implementation
194 // ============================================================================
195 
196 wxGDIImageHandlerList wxGDIImage::ms_handlers;
197 
198 // ----------------------------------------------------------------------------
199 // wxGDIImage functions forwarded to wxGDIImageRefData
200 // ----------------------------------------------------------------------------
201 
FreeResource(bool WXUNUSED (force))202 bool wxGDIImage::FreeResource(bool WXUNUSED(force))
203 {
204     if ( !IsNull() )
205     {
206         GetGDIImageData()->Free();
207         GetGDIImageData()->m_handle = 0;
208     }
209 
210     return true;
211 }
212 
GetResourceHandle() const213 WXHANDLE wxGDIImage::GetResourceHandle() const
214 {
215     return GetHandle();
216 }
217 
218 // ----------------------------------------------------------------------------
219 // wxGDIImage handler stuff
220 // ----------------------------------------------------------------------------
221 
AddHandler(wxGDIImageHandler * handler)222 void wxGDIImage::AddHandler(wxGDIImageHandler *handler)
223 {
224     ms_handlers.Append(handler);
225 }
226 
InsertHandler(wxGDIImageHandler * handler)227 void wxGDIImage::InsertHandler(wxGDIImageHandler *handler)
228 {
229     ms_handlers.Insert(handler);
230 }
231 
RemoveHandler(const wxString & name)232 bool wxGDIImage::RemoveHandler(const wxString& name)
233 {
234     wxGDIImageHandler *handler = FindHandler(name);
235     if ( handler )
236     {
237         ms_handlers.DeleteObject(handler);
238         return true;
239     }
240     else
241         return false;
242 }
243 
FindHandler(const wxString & name)244 wxGDIImageHandler *wxGDIImage::FindHandler(const wxString& name)
245 {
246     wxGDIImageHandlerList::compatibility_iterator node = ms_handlers.GetFirst();
247     while ( node )
248     {
249         wxGDIImageHandler *handler = node->GetData();
250         if ( handler->GetName() == name )
251             return handler;
252         node = node->GetNext();
253     }
254 
255     return NULL;
256 }
257 
FindHandler(const wxString & extension,long type)258 wxGDIImageHandler *wxGDIImage::FindHandler(const wxString& extension,
259                                            long type)
260 {
261     wxGDIImageHandlerList::compatibility_iterator node = ms_handlers.GetFirst();
262     while ( node )
263     {
264         wxGDIImageHandler *handler = node->GetData();
265         if ( (handler->GetExtension() == extension) &&
266              (type == -1 || handler->GetType() == type) )
267         {
268             return handler;
269         }
270 
271         node = node->GetNext();
272     }
273     return NULL;
274 }
275 
FindHandler(long type)276 wxGDIImageHandler *wxGDIImage::FindHandler(long type)
277 {
278     wxGDIImageHandlerList::compatibility_iterator node = ms_handlers.GetFirst();
279     while ( node )
280     {
281         wxGDIImageHandler *handler = node->GetData();
282         if ( handler->GetType() == type )
283             return handler;
284 
285         node = node->GetNext();
286     }
287 
288     return NULL;
289 }
290 
CleanUpHandlers()291 void wxGDIImage::CleanUpHandlers()
292 {
293     wxGDIImageHandlerList::compatibility_iterator node = ms_handlers.GetFirst();
294     while ( node )
295     {
296         wxGDIImageHandler *handler = node->GetData();
297         wxGDIImageHandlerList::compatibility_iterator next = node->GetNext();
298         delete handler;
299         ms_handlers.Erase( node );
300         node = next;
301     }
302 }
303 
InitStandardHandlers()304 void wxGDIImage::InitStandardHandlers()
305 {
306 #ifndef __WXMICROWIN__
307     AddHandler(new wxBMPResourceHandler);
308     AddHandler(new wxBMPFileHandler);
309     AddHandler(new wxICOResourceHandler);
310     AddHandler(new wxICOFileHandler);
311 #endif
312 }
313 
314 #ifndef __WXMICROWIN__
315 
316 // ----------------------------------------------------------------------------
317 // wxBitmap handlers
318 // ----------------------------------------------------------------------------
319 
LoadFile(wxBitmap * bitmap,const wxString & name,long WXUNUSED (flags),int WXUNUSED (desiredWidth),int WXUNUSED (desiredHeight))320 bool wxBMPResourceHandler::LoadFile(wxBitmap *bitmap,
321                                     const wxString& name, long WXUNUSED(flags),
322                                     int WXUNUSED(desiredWidth),
323                                     int WXUNUSED(desiredHeight))
324 {
325     // TODO: load colourmap.
326     bitmap->SetHBITMAP((WXHBITMAP)::LoadBitmap(wxGetInstance(), name));
327 
328     if ( !bitmap->Ok() )
329     {
330         // it's probably not found
331         wxLogError(wxT("Can't load bitmap '%s' from resources! Check .rc file."),
332                    name.c_str());
333 
334         return false;
335     }
336 
337     BITMAP bm;
338     if ( !::GetObject(GetHbitmapOf(*bitmap), sizeof(BITMAP), (LPSTR) &bm) )
339     {
340         wxLogLastError(wxT("GetObject(HBITMAP)"));
341     }
342 
343     bitmap->SetWidth(bm.bmWidth);
344     bitmap->SetHeight(bm.bmHeight);
345     bitmap->SetDepth(bm.bmBitsPixel);
346 
347     // use 0xc0c0c0 as transparent colour by default
348     bitmap->SetMask(new wxMask(*bitmap, *wxLIGHT_GREY));
349 
350     return true;
351 }
352 
LoadFile(wxBitmap * bitmap,const wxString & name,long WXUNUSED (flags),int WXUNUSED (desiredWidth),int WXUNUSED (desiredHeight))353 bool wxBMPFileHandler::LoadFile(wxBitmap *bitmap,
354                                 const wxString& name, long WXUNUSED(flags),
355                                 int WXUNUSED(desiredWidth),
356                                 int WXUNUSED(desiredHeight))
357 {
358 #if wxUSE_WXDIB
359     wxCHECK_MSG( bitmap, false, _T("NULL bitmap in LoadFile") );
360 
361     wxDIB dib(name);
362 
363     return dib.IsOk() && bitmap->CopyFromDIB(dib);
364 #else
365     return false;
366 #endif
367 }
368 
SaveFile(wxBitmap * bitmap,const wxString & name,int WXUNUSED (type),const wxPalette * WXUNUSED (pal))369 bool wxBMPFileHandler::SaveFile(wxBitmap *bitmap,
370                                 const wxString& name,
371                                 int WXUNUSED(type),
372                                 const wxPalette * WXUNUSED(pal))
373 {
374 #if wxUSE_WXDIB
375     wxCHECK_MSG( bitmap, false, _T("NULL bitmap in SaveFile") );
376 
377     wxDIB dib(*bitmap);
378 
379     return dib.Save(name);
380 #else
381     return false;
382 #endif
383 }
384 
385 // ----------------------------------------------------------------------------
386 // wxIcon handlers
387 // ----------------------------------------------------------------------------
388 
LoadIcon(wxIcon * icon,const wxString & name,long WXUNUSED (flags),int desiredWidth,int desiredHeight)389 bool wxICOFileHandler::LoadIcon(wxIcon *icon,
390                                 const wxString& name,
391                                 long WXUNUSED(flags),
392                                 int desiredWidth, int desiredHeight)
393 {
394     icon->UnRef();
395 
396     // actual size
397     wxSize size;
398 
399     HICON hicon = NULL;
400 
401     // Parse the filename: it may be of the form "filename;n" in order to
402     // specify the nth icon in the file.
403     //
404     // For the moment, ignore the issue of possible semicolons in the
405     // filename.
406     int iconIndex = 0;
407     wxString nameReal(name);
408     wxString strIconIndex = name.AfterLast(wxT(';'));
409     if (strIconIndex != name)
410     {
411         iconIndex = wxAtoi(strIconIndex);
412         nameReal = name.BeforeLast(wxT(';'));
413     }
414 
415 #if 0
416     // If we don't know what size icon we're looking for,
417     // try to find out what's there.
418     // Unfortunately this doesn't work, because ExtractIconEx
419     // will scale the icon to the 'desired' size, even if that
420     // size of icon isn't explicitly stored. So we would have
421     // to parse the icon file outselves.
422     if ( desiredWidth == -1 &&
423          desiredHeight == -1)
424     {
425         // Try loading a large icon first
426         if ( ::ExtractIconEx(nameReal, iconIndex, &hicon, NULL, 1) == 1)
427         {
428         }
429         // Then try loading a small icon
430         else if ( ::ExtractIconEx(nameReal, iconIndex, NULL, &hicon, 1) == 1)
431         {
432         }
433     }
434     else
435 #endif
436         // were we asked for a large icon?
437     if ( desiredWidth == ::GetSystemMetrics(SM_CXICON) &&
438          desiredHeight == ::GetSystemMetrics(SM_CYICON) )
439     {
440         // get the specified large icon from file
441         if ( !::ExtractIconEx(nameReal, iconIndex, &hicon, NULL, 1) )
442         {
443             // it is not an error, but it might still be useful to be informed
444             // about it optionally
445             wxLogTrace(_T("iconload"),
446                        _T("No large icons found in the file '%s'."),
447                        name.c_str());
448         }
449     }
450     else if ( desiredWidth == ::GetSystemMetrics(SM_CXSMICON) &&
451               desiredHeight == ::GetSystemMetrics(SM_CYSMICON) )
452     {
453         // get the specified small icon from file
454         if ( !::ExtractIconEx(nameReal, iconIndex, NULL, &hicon, 1) )
455         {
456             wxLogTrace(_T("iconload"),
457                        _T("No small icons found in the file '%s'."),
458                        name.c_str());
459         }
460     }
461     //else: not standard size, load below
462 
463 #ifndef __WXWINCE__
464     if ( !hicon )
465     {
466         // take any size icon from the file by index
467         hicon = ::ExtractIcon(wxGetInstance(), nameReal, iconIndex);
468     }
469 #endif
470 
471     if ( !hicon )
472     {
473         wxLogSysError(_T("Failed to load icon from the file '%s'"),
474                       name.c_str());
475 
476         return false;
477     }
478 
479     size = wxGetHiconSize(hicon);
480 
481     if ( (desiredWidth != -1 && desiredWidth != size.x) ||
482          (desiredHeight != -1 && desiredHeight != size.y) )
483     {
484         wxLogTrace(_T("iconload"),
485                    _T("Returning false from wxICOFileHandler::Load because of the size mismatch: actual (%d, %d), requested (%d, %d)"),
486                    size.x, size.y,
487                    desiredWidth, desiredHeight);
488 
489         ::DestroyIcon(hicon);
490 
491         return false;
492     }
493 
494     icon->SetHICON((WXHICON)hicon);
495     icon->SetSize(size.x, size.y);
496 
497     return icon->Ok();
498 }
499 
LoadIcon(wxIcon * icon,const wxString & name,long WXUNUSED (flags),int desiredWidth,int desiredHeight)500 bool wxICOResourceHandler::LoadIcon(wxIcon *icon,
501                                     const wxString& name,
502                                     long WXUNUSED(flags),
503                                     int desiredWidth, int desiredHeight)
504 {
505     HICON hicon;
506 
507     // do we need the icon of the specific size or would any icon do?
508     bool hasSize = desiredWidth != -1 || desiredHeight != -1;
509 
510     wxASSERT_MSG( !hasSize || (desiredWidth != -1 && desiredHeight != -1),
511                   _T("width and height should be either both -1 or not") );
512 
513     // try to load the icon from this program first to allow overriding the
514     // standard icons (although why one would want to do it considering that
515     // we already have wxApp::GetStdIcon() is unclear)
516 
517     // note that we can't just always call LoadImage() because it seems to do
518     // some icon rescaling internally which results in very ugly 16x16 icons
519     if ( hasSize )
520     {
521         hicon = (HICON)::LoadImage(wxGetInstance(), name, IMAGE_ICON,
522                                     desiredWidth, desiredHeight,
523                                     LR_DEFAULTCOLOR);
524     }
525     else
526     {
527         hicon = ::LoadIcon(wxGetInstance(), name);
528     }
529 
530     // next check if it's not a standard icon
531 #ifndef __WXWINCE__
532     if ( !hicon && !hasSize )
533     {
534         static const struct
535         {
536             const wxChar *name;
537             LPTSTR id;
538         } stdIcons[] =
539         {
540             { wxT("wxICON_QUESTION"),   IDI_QUESTION    },
541             { wxT("wxICON_WARNING"),    IDI_EXCLAMATION },
542             { wxT("wxICON_ERROR"),      IDI_HAND        },
543             { wxT("wxICON_INFORMATION"),       IDI_ASTERISK    },
544         };
545 
546         for ( size_t nIcon = 0; !hicon && nIcon < WXSIZEOF(stdIcons); nIcon++ )
547         {
548             if ( name == stdIcons[nIcon].name )
549             {
550                 hicon = ::LoadIcon((HINSTANCE)NULL, stdIcons[nIcon].id);
551             }
552         }
553     }
554 #endif
555 
556     wxSize size = wxGetHiconSize(hicon);
557     icon->SetSize(size.x, size.y);
558 
559     icon->SetHICON((WXHICON)hicon);
560 
561     return icon->Ok();
562 }
563 
564 // ----------------------------------------------------------------------------
565 // private functions
566 // ----------------------------------------------------------------------------
567 
wxGetHiconSize(HICON WXUNUSED_IN_WINCE (hicon))568 wxSize wxGetHiconSize(HICON WXUNUSED_IN_WINCE(hicon))
569 {
570     wxSize size;
571 
572 #ifndef __WXWINCE__
573     if ( hicon )
574     {
575         ICONINFO info;
576         if ( !::GetIconInfo(hicon, &info) )
577         {
578             wxLogLastError(wxT("GetIconInfo"));
579         }
580         else
581         {
582             HBITMAP hbmp = info.hbmMask;
583             if ( hbmp )
584             {
585                 BITMAP bm;
586                 if ( ::GetObject(hbmp, sizeof(BITMAP), (LPSTR) &bm) )
587                 {
588                     size = wxSize(bm.bmWidth, bm.bmHeight);
589                 }
590 
591                 ::DeleteObject(info.hbmMask);
592             }
593             if ( info.hbmColor )
594                 ::DeleteObject(info.hbmColor);
595         }
596     }
597 
598     if ( !size.x )
599 #endif // !__WXWINCE__
600     {
601         // use default icon size on this hardware
602         size.x = ::GetSystemMetrics(SM_CXICON);
603         size.y = ::GetSystemMetrics(SM_CYICON);
604     }
605 
606     return size;
607 }
608 
609 #endif // __WXMICROWIN__
610