1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_fpicker.hxx" 26 27 //------------------------------------------------------------------------ 28 // includes 29 //------------------------------------------------------------------------ 30 31 #include <tchar.h> 32 #include "dibpreview.hxx" 33 #include <osl/diagnose.h> 34 35 #ifndef _COM_SUN_STAR_UI_DIALOG_FILEPREVIEWIMAGEFORMATS_HPP_ 36 #include <com/sun/star/ui/dialogs/FilePreviewImageFormats.hpp> 37 #endif 38 39 #ifndef _USTRING_HXX_ 40 #include <rtl/ustring.hxx> 41 #endif 42 43 #include <stdexcept> 44 #include <string> 45 46 //------------------------------------------------------------------------ 47 // 48 //------------------------------------------------------------------------ 49 50 using ::com::sun::star::uno::Sequence; 51 using ::com::sun::star::uno::RuntimeException; 52 using ::com::sun::star::uno::Any; 53 using ::com::sun::star::lang::IllegalArgumentException; 54 using rtl::OUString; 55 56 //------------------------------------------------------------------------ 57 // 58 //------------------------------------------------------------------------ 59 60 namespace /* private */ 61 { 62 const LPTSTR CURRENT_INSTANCE = TEXT("CurrInst"); 63 }; 64 65 //------------------------------------------------------------------------ 66 // defines 67 //------------------------------------------------------------------------ 68 69 #define PREVIEWWND_CLASS_NAME TEXT("DIBPreviewWnd###") 70 71 // means 3 pixel left and 3 pixel right 72 #define HORZ_BODER_SPACE 6 73 74 // means 3 pixel top and 3 pixel bottom 75 #define VERT_BORDER_SPACE 6 76 77 //--------------------------------------------------- 78 // static member initialization 79 //--------------------------------------------------- 80 81 osl::Mutex CDIBPreview::s_Mutex; 82 ATOM CDIBPreview::s_ClassAtom = 0; 83 sal_Int32 CDIBPreview::s_RegisterDibPreviewWndCount = 0; 84 85 //--------------------------------------------------- 86 // 87 //--------------------------------------------------- 88 89 CDIBPreview::CDIBPreview(HINSTANCE instance,HWND parent,sal_Bool bShowWindow) : 90 m_Instance(instance) 91 { 92 RegisterDibPreviewWindowClass(); 93 94 DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; 95 96 if (bShowWindow) 97 dwStyle |= WS_VISIBLE; 98 99 m_Hwnd = CreateWindowEx( 100 WS_EX_CLIENTEDGE, 101 PREVIEWWND_CLASS_NAME, 102 TEXT(""), 103 dwStyle, 104 0, 0, 0, 0, 105 parent, 106 (HMENU)0x0, // for child windows this will 107 // be used as child window identifier 108 m_Instance, 109 (LPVOID)this // pass a pointer to the current 110 // instance of this class 111 ); 112 113 bool bSuccess = IsWindow(m_Hwnd); 114 115 OSL_POSTCOND(bSuccess,"Coud not create preview window"); 116 117 if (!bSuccess) 118 { 119 UnregisterDibPreviewWindowClass(); 120 throw std::runtime_error("Could not create preview window"); 121 } 122 } 123 124 //--------------------------------------------------- 125 // 126 //--------------------------------------------------- 127 128 CDIBPreview::~CDIBPreview( ) 129 { 130 // remember: we don't have to destroy the 131 // preview window because it will be destroyed 132 // by it's parent window (the FileOpen dialog) 133 // but we have to unregister the window class 134 //if ( m_bWndClassRegistered ) 135 UnregisterDibPreviewWindowClass(); 136 } 137 138 //------------------------------- 139 // 140 //------------------------------- 141 142 sal_Int32 SAL_CALL CDIBPreview::getTargetColorDepth() throw (RuntimeException) 143 { 144 HDC hdc = GetDC(m_Hwnd); 145 int clrRes = 0; 146 147 if (hdc) 148 clrRes = GetDeviceCaps(hdc, COLORRES); 149 150 return clrRes; 151 } 152 153 //------------------------------- 154 // 155 //------------------------------- 156 157 sal_Int32 SAL_CALL CDIBPreview::getAvailableWidth() throw (RuntimeException) 158 { 159 RECT rect; 160 bool bRet = GetClientRect(m_Hwnd,&rect); 161 162 sal_Int32 cx = 0; 163 164 if ( bRet ) 165 cx = rect.right; 166 167 return cx; 168 } 169 170 //------------------------------- 171 // 172 //------------------------------- 173 174 sal_Int32 SAL_CALL CDIBPreview::getAvailableHeight() throw (RuntimeException) 175 { 176 RECT rect; 177 bool bRet = GetClientRect(m_Hwnd,&rect); 178 179 sal_Int32 cy = 0; 180 181 if ( bRet ) 182 cy = rect.bottom; 183 184 return cy; 185 } 186 187 //------------------------------- 188 // 189 //------------------------------- 190 191 void SAL_CALL CDIBPreview::setImage(sal_Int16 aImageFormat, const Any& aImage) 192 throw (IllegalArgumentException, RuntimeException) 193 { 194 PreviewBase::setImage(aImageFormat,aImage); 195 196 // if the any has no value we have an 197 // empty Sequence which clears the 198 // preview window 199 osl::ClearableMutexGuard aGuard(m_PaintLock); 200 201 m_Image.realloc(0); 202 m_ImageData >>= m_Image; 203 204 aGuard.clear(); 205 206 InvalidateRect(m_Hwnd,NULL,sal_False); 207 UpdateWindow(m_Hwnd); 208 } 209 210 //------------------------------- 211 // 212 //------------------------------- 213 214 sal_Bool SAL_CALL CDIBPreview::setShowState(sal_Bool bShowState) throw (RuntimeException) 215 { 216 PreviewBase::setShowState(bShowState); 217 ShowWindow(m_Hwnd, m_bShowState ? SW_SHOW : SW_HIDE); 218 return sal_True; 219 } 220 221 //------------------------------- 222 // 223 //------------------------------- 224 225 sal_Bool SAL_CALL CDIBPreview::getShowState() throw (RuntimeException) 226 { 227 return (sal_Bool)IsWindowVisible(m_Hwnd); 228 } 229 230 //------------------------------- 231 // 232 //------------------------------- 233 234 HWND SAL_CALL CDIBPreview::getWindowHandle() const 235 { 236 return m_Hwnd; 237 } 238 239 //--------------------------------------------------- 240 // 241 //--------------------------------------------------- 242 243 void SAL_CALL CDIBPreview::onPaint(HWND hWnd, HDC hDC) 244 { 245 BITMAPFILEHEADER* pbmfh; 246 BITMAPINFO * pbmi; 247 sal_uInt8 * pBits; 248 int cxDib; 249 int cyDib; 250 251 osl::MutexGuard aGuard(m_PaintLock); 252 253 try 254 { 255 pbmfh = reinterpret_cast<BITMAPFILEHEADER*>(m_Image.getArray()); 256 257 if ( !IsBadReadPtr( pbmfh, sizeof(BITMAPFILEHEADER)) && 258 (pbmfh->bfType == ('B' | ('M' << 8))) ) 259 { 260 pbmi = reinterpret_cast<BITMAPINFO*>((pbmfh + 1)); 261 pBits = reinterpret_cast<sal_uInt8*>(((DWORD)pbmfh) + pbmfh->bfOffBits); 262 263 cxDib = pbmi->bmiHeader.biWidth; 264 cyDib = abs (pbmi->bmiHeader.biHeight); 265 266 SetStretchBltMode(hDC, COLORONCOLOR); 267 268 int nWidth = getAvailableWidth(); 269 int nHeight = getAvailableHeight(); 270 271 int nX = abs(nWidth - cxDib) / 2; 272 int nY = abs(nHeight - cyDib) / 2; 273 274 int GDIError = GDI_ERROR; 275 GDIError = StretchDIBits( 276 hDC, nX, nY, cxDib, cyDib, 277 0, 0, cxDib, cyDib, pBits, pbmi, 278 DIB_RGB_COLORS, SRCCOPY); 279 280 OSL_ASSERT(GDI_ERROR != GDIError); 281 282 // paint the border 283 RECT rc; 284 285 if (nY > 0) 286 { 287 // top 288 rc.left = 0; 289 rc.top = 0; 290 rc.right = nWidth; 291 rc.bottom = nY; 292 FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1)); 293 294 // bottom 295 rc.left = 0; 296 rc.top = nHeight - nY - 1; 297 rc.right = nWidth; 298 rc.bottom = nHeight; 299 FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1)); 300 } 301 302 if (nX > 0) 303 { 304 // left 305 rc.left = 0; 306 rc.top = nY; 307 rc.right = nX; 308 rc.bottom = nHeight - nY; 309 FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1)); 310 311 // right 312 rc.left = nWidth - nX - 1; 313 rc.top = nY; 314 rc.right = nWidth; 315 rc.bottom = nHeight - nY; 316 FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1)); 317 } 318 } 319 else // clear background 320 { 321 RECT rc; 322 GetClientRect(hWnd,&rc); 323 FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1)); 324 } 325 } 326 catch(...) 327 { 328 OSL_ASSERT(sal_False); 329 } 330 } 331 332 //--------------------------------------------------- 333 // 334 //--------------------------------------------------- 335 336 LRESULT CALLBACK CDIBPreview::WndProc( 337 HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 338 { 339 LRESULT lResult = 0; 340 341 switch(uMsg) 342 { 343 344 // we connect a pointer to the current instance 345 // with a window instance via SetProp 346 case WM_CREATE: 347 { 348 LPCREATESTRUCT lpcs = 349 reinterpret_cast< LPCREATESTRUCT >(lParam); 350 351 OSL_ASSERT(lpcs->lpCreateParams); 352 353 // connect the instance handle to the window 354 SetProp(hWnd, CURRENT_INSTANCE, lpcs->lpCreateParams); 355 } 356 break; 357 358 // we remove the window property which connects 359 // a class instance with a window class 360 case WM_NCDESTROY: 361 { 362 // RemoveProp returns the saved value on success 363 if (reinterpret_cast<CDIBPreview*>( 364 RemoveProp(hWnd, CURRENT_INSTANCE)) == NULL) 365 { 366 OSL_ASSERT(false); 367 } 368 } 369 break; 370 371 case WM_PAINT: 372 { 373 CDIBPreview* pImpl = reinterpret_cast<CDIBPreview*>( 374 GetProp(hWnd, CURRENT_INSTANCE)); 375 376 OSL_ASSERT(pImpl); 377 378 HDC hDC; 379 PAINTSTRUCT ps; 380 381 hDC = BeginPaint(hWnd,&ps); 382 pImpl->onPaint(hWnd,hDC); 383 EndPaint(hWnd,&ps); 384 } 385 break; 386 387 // ignore this message in order to 388 // avoid flickering during paint 389 case WM_ERASEBKGND: 390 lResult = 1; 391 break; 392 393 default: 394 return DefWindowProc(hWnd, uMsg, wParam, lParam); 395 } 396 397 return lResult; 398 } 399 400 //--------------------------------------------------- 401 // 402 //--------------------------------------------------- 403 404 ATOM SAL_CALL CDIBPreview::RegisterDibPreviewWindowClass() 405 { 406 osl::MutexGuard aGuard( s_Mutex ); 407 408 if (0 == s_ClassAtom) 409 { 410 // register the preview window class 411 WNDCLASSEX wndClsEx; 412 ZeroMemory(&wndClsEx, sizeof(wndClsEx)); 413 414 wndClsEx.cbSize = sizeof(wndClsEx); 415 wndClsEx.style = CS_HREDRAW | CS_VREDRAW; 416 wndClsEx.lpfnWndProc = CDIBPreview::WndProc; 417 wndClsEx.hInstance = m_Instance; 418 wndClsEx.hbrBackground = (HBRUSH)(COLOR_INACTIVEBORDER + 1); 419 wndClsEx.lpszClassName = PREVIEWWND_CLASS_NAME; 420 421 // register the preview window class 422 // !!! Win95 - the window class will be unregistered automaticly 423 // if the dll is unloaded 424 // Win2000 - the window class must be unregistered manually 425 // if the dll is unloaded 426 s_ClassAtom = RegisterClassEx(&wndClsEx); 427 428 OSL_POSTCOND(s_ClassAtom,"Could not register preview window class"); 429 430 if (0 == s_ClassAtom) 431 throw std::runtime_error("Preview window class could not be registered"); 432 } 433 434 // increment the register class counter 435 // so that we keep track of the number 436 // of class registrations 437 //if ( 0 != s_ClassAtom ) 438 s_RegisterDibPreviewWndCount++; 439 440 return s_ClassAtom; 441 } 442 443 //--------------------------------------------------- 444 // 445 //--------------------------------------------------- 446 447 void SAL_CALL CDIBPreview::UnregisterDibPreviewWindowClass() 448 { 449 osl::MutexGuard aGuard( s_Mutex ); 450 451 OSL_ASSERT( ( (0 != s_ClassAtom) && (s_RegisterDibPreviewWndCount > 0)) || 452 ( (0 == s_ClassAtom) && (0 == s_RegisterDibPreviewWndCount) ) ); 453 454 // update the register class counter 455 // and unregister the window class if 456 // counter drops to zero 457 if (0 != s_ClassAtom) 458 { 459 s_RegisterDibPreviewWndCount--; 460 OSL_ASSERT(s_RegisterDibPreviewWndCount >= 0); 461 } 462 463 if (0 == s_RegisterDibPreviewWndCount) 464 { 465 UnregisterClass((LPCTSTR)MAKELONG(s_ClassAtom,0),m_Instance); 466 s_ClassAtom = 0; 467 } 468 } 469