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" 50WX_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 61class WXDLLEXPORT wxBMPFileHandler : public wxBitmapHandler 62{ 63public: 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 76private: 77 DECLARE_DYNAMIC_CLASS(wxBMPFileHandler) 78}; 79 80class WXDLLEXPORT wxBMPResourceHandler: public wxBitmapHandler 81{ 82public: 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 93private: 94 DECLARE_DYNAMIC_CLASS(wxBMPResourceHandler) 95}; 96 97class WXDLLEXPORT wxIconHandler : public wxGDIImageHandler 98{ 99public: 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 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 116 virtual bool Save(wxGDIImage *WXUNUSED(image), 117 const wxString& WXUNUSED(name), 118 int WXUNUSED(type)) 119 { 120 return false; 121 } 122 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 134protected: 135 virtual bool LoadIcon(wxIcon *icon, 136 const wxString& name, long flags, 137 int desiredWidth = -1, int desiredHeight = -1) = 0; 138}; 139 140class WXDLLEXPORT wxICOFileHandler : public wxIconHandler 141{ 142public: 143 wxICOFileHandler() : wxIconHandler(_T("ICO icon file"), 144 _T("ico"), 145 wxBITMAP_TYPE_ICO) 146 { 147 } 148 149protected: 150 virtual bool LoadIcon(wxIcon *icon, 151 const wxString& name, long flags, 152 int desiredWidth = -1, int desiredHeight = -1); 153 154private: 155 DECLARE_DYNAMIC_CLASS(wxICOFileHandler) 156}; 157 158class WXDLLEXPORT wxICOResourceHandler: public wxIconHandler 159{ 160public: 161 wxICOResourceHandler() : wxIconHandler(_T("ICO resource"), 162 _T("ico"), 163 wxBITMAP_TYPE_ICO_RESOURCE) 164 { 165 } 166 167protected: 168 virtual bool LoadIcon(wxIcon *icon, 169 const wxString& name, long flags, 170 int desiredWidth = -1, int desiredHeight = -1); 171 172private: 173 DECLARE_DYNAMIC_CLASS(wxICOResourceHandler) 174}; 175 176// ---------------------------------------------------------------------------- 177// wxWin macros 178// ---------------------------------------------------------------------------- 179 180IMPLEMENT_DYNAMIC_CLASS(wxBMPFileHandler, wxBitmapHandler) 181IMPLEMENT_DYNAMIC_CLASS(wxBMPResourceHandler, wxBitmapHandler) 182IMPLEMENT_DYNAMIC_CLASS(wxICOFileHandler, wxObject) 183IMPLEMENT_DYNAMIC_CLASS(wxICOResourceHandler, wxObject) 184 185// ---------------------------------------------------------------------------- 186// private functions 187// ---------------------------------------------------------------------------- 188 189#endif 190 // __MICROWIN__ 191 192// ============================================================================ 193// implementation 194// ============================================================================ 195 196wxGDIImageHandlerList wxGDIImage::ms_handlers; 197 198// ---------------------------------------------------------------------------- 199// wxGDIImage functions forwarded to wxGDIImageRefData 200// ---------------------------------------------------------------------------- 201 202bool 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 213WXHANDLE wxGDIImage::GetResourceHandle() const 214{ 215 return GetHandle(); 216} 217 218// ---------------------------------------------------------------------------- 219// wxGDIImage handler stuff 220// ---------------------------------------------------------------------------- 221 222void wxGDIImage::AddHandler(wxGDIImageHandler *handler) 223{ 224 ms_handlers.Append(handler); 225} 226 227void wxGDIImage::InsertHandler(wxGDIImageHandler *handler) 228{ 229 ms_handlers.Insert(handler); 230} 231 232bool 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 244wxGDIImageHandler *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 258wxGDIImageHandler *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 276wxGDIImageHandler *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 291void 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 304void 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 320bool 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 353bool 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 369bool 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 389bool 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 500bool 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 568wxSize 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