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