xref: /trunk/main/fpicker/source/win32/filepicker/dibpreview.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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_BORDER_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 
CDIBPreview(HINSTANCE instance,HWND parent,sal_Bool bShowWindow)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,"Could 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 
~CDIBPreview()128 CDIBPreview::~CDIBPreview( )
129 {
130     // remember: we don't have to destroy the
131     // preview window because it will be destroyed
132     // by its 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 
getTargetColorDepth()142 sal_Int32 SAL_CALL CDIBPreview::getTargetColorDepth()
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 
getAvailableWidth()157 sal_Int32 SAL_CALL CDIBPreview::getAvailableWidth()
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 
getAvailableHeight()174 sal_Int32 SAL_CALL CDIBPreview::getAvailableHeight()
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 
setImage(sal_Int16 aImageFormat,const Any & aImage)191 void SAL_CALL CDIBPreview::setImage(sal_Int16 aImageFormat, const Any& aImage)
192 {
193     PreviewBase::setImage(aImageFormat,aImage);
194 
195     // if the any has no value we have an
196     // empty Sequence which clears the
197     // preview window
198     osl::ClearableMutexGuard aGuard(m_PaintLock);
199 
200     m_Image.realloc(0);
201     m_ImageData >>= m_Image;
202 
203     aGuard.clear();
204 
205     InvalidateRect(m_Hwnd,NULL,sal_False);
206     UpdateWindow(m_Hwnd);
207 }
208 
209 //-------------------------------
210 //
211 //-------------------------------
212 
setShowState(sal_Bool bShowState)213 sal_Bool SAL_CALL CDIBPreview::setShowState(sal_Bool bShowState)
214 {
215     PreviewBase::setShowState(bShowState);
216     ShowWindow(m_Hwnd, m_bShowState ? SW_SHOW : SW_HIDE);
217     return sal_True;
218 }
219 
220 //-------------------------------
221 //
222 //-------------------------------
223 
getShowState()224 sal_Bool SAL_CALL CDIBPreview::getShowState()
225 {
226     return (sal_Bool)IsWindowVisible(m_Hwnd);
227 }
228 
229 //-------------------------------
230 //
231 //-------------------------------
232 
getWindowHandle() const233 HWND SAL_CALL CDIBPreview::getWindowHandle() const
234 {
235     return m_Hwnd;
236 }
237 
238 //---------------------------------------------------
239 //
240 //---------------------------------------------------
241 
onPaint(HWND hWnd,HDC hDC)242 void SAL_CALL CDIBPreview::onPaint(HWND hWnd, HDC hDC)
243 {
244     BITMAPFILEHEADER*  pbmfh;
245     BITMAPINFO      *  pbmi;
246     sal_uInt8            *  pBits;
247     int                cxDib;
248     int                cyDib;
249 
250     osl::MutexGuard aGuard(m_PaintLock);
251 
252     try
253     {
254         pbmfh = reinterpret_cast<BITMAPFILEHEADER*>(m_Image.getArray());
255 
256         if ( !IsBadReadPtr( pbmfh, sizeof(BITMAPFILEHEADER)) &&
257              (pbmfh->bfType == ('B' | ('M' << 8))) )
258         {
259             pbmi  = reinterpret_cast<BITMAPINFO*>((pbmfh + 1));
260             pBits = reinterpret_cast<sal_uInt8*>(((DWORD)pbmfh) + pbmfh->bfOffBits);
261 
262             cxDib =      pbmi->bmiHeader.biWidth;
263             cyDib = abs (pbmi->bmiHeader.biHeight);
264 
265             SetStretchBltMode(hDC, COLORONCOLOR);
266 
267             int nWidth  = getAvailableWidth();
268             int nHeight = getAvailableHeight();
269 
270             int nX = abs(nWidth - cxDib) / 2;
271             int nY = abs(nHeight - cyDib) / 2;
272 
273             int GDIError = GDI_ERROR;
274             GDIError = StretchDIBits(
275                 hDC, nX, nY, cxDib, cyDib,
276                 0, 0, cxDib, cyDib, pBits, pbmi,
277                 DIB_RGB_COLORS, SRCCOPY);
278 
279             OSL_ASSERT(GDI_ERROR != GDIError);
280 
281             // paint the border
282             RECT rc;
283 
284             if (nY > 0)
285             {
286                 // top
287                 rc.left   = 0;
288                 rc.top    = 0;
289                 rc.right  = nWidth;
290                 rc.bottom = nY;
291                 FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1));
292 
293                 // bottom
294                 rc.left   = 0;
295                 rc.top    = nHeight - nY - 1;
296                 rc.right  = nWidth;
297                 rc.bottom = nHeight;
298                 FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1));
299             }
300 
301             if (nX > 0)
302             {
303                 // left
304                 rc.left   = 0;
305                 rc.top    = nY;
306                 rc.right  = nX;
307                 rc.bottom = nHeight - nY;
308                 FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1));
309 
310                 // right
311                 rc.left   = nWidth - nX - 1;
312                 rc.top    = nY;
313                 rc.right  = nWidth;
314                 rc.bottom = nHeight - nY;
315                 FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1));
316             }
317         }
318         else // clear background
319         {
320             RECT rc;
321             GetClientRect(hWnd,&rc);
322             FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1));
323         }
324     }
325     catch(...)
326     {
327         OSL_ASSERT(sal_False);
328     }
329 }
330 
331 //---------------------------------------------------
332 //
333 //---------------------------------------------------
334 
WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)335 LRESULT CALLBACK CDIBPreview::WndProc(
336     HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
337 {
338     LRESULT lResult = 0;
339 
340     switch(uMsg)
341     {
342 
343     // we connect a pointer to the current instance
344     // with a window instance via SetProp
345     case WM_CREATE:
346         {
347             LPCREATESTRUCT lpcs =
348                 reinterpret_cast< LPCREATESTRUCT >(lParam);
349 
350             OSL_ASSERT(lpcs->lpCreateParams);
351 
352             // connect the instance handle to the window
353             SetProp(hWnd, CURRENT_INSTANCE, lpcs->lpCreateParams);
354         }
355         break;
356 
357     // we remove the window property which connects
358     // a class instance with a window class
359     case WM_NCDESTROY:
360         {
361             // RemoveProp returns the saved value on success
362             if (reinterpret_cast<CDIBPreview*>(
363                     RemoveProp(hWnd, CURRENT_INSTANCE)) == NULL)
364             {
365                 OSL_ASSERT(false);
366             }
367         }
368         break;
369 
370     case WM_PAINT:
371     {
372         CDIBPreview* pImpl = reinterpret_cast<CDIBPreview*>(
373             GetProp(hWnd, CURRENT_INSTANCE));
374 
375         OSL_ASSERT(pImpl);
376 
377         HDC         hDC;
378         PAINTSTRUCT ps;
379 
380         hDC = BeginPaint(hWnd,&ps);
381         pImpl->onPaint(hWnd,hDC);
382         EndPaint(hWnd,&ps);
383     }
384     break;
385 
386     // ignore this message in order to
387     // avoid flickering during paint
388     case WM_ERASEBKGND:
389         lResult = 1;
390         break;
391 
392     default:
393         return DefWindowProc(hWnd, uMsg, wParam, lParam);
394     }
395 
396     return lResult;
397 }
398 
399 //---------------------------------------------------
400 //
401 //---------------------------------------------------
402 
RegisterDibPreviewWindowClass()403 ATOM SAL_CALL CDIBPreview::RegisterDibPreviewWindowClass()
404 {
405     osl::MutexGuard aGuard( s_Mutex );
406 
407     if (0 == s_ClassAtom)
408     {
409         // register the preview window class
410         WNDCLASSEX wndClsEx;
411         ZeroMemory(&wndClsEx, sizeof(wndClsEx));
412 
413         wndClsEx.cbSize        = sizeof(wndClsEx);
414         wndClsEx.style         = CS_HREDRAW | CS_VREDRAW;
415         wndClsEx.lpfnWndProc   = CDIBPreview::WndProc;
416         wndClsEx.hInstance     = m_Instance;
417         wndClsEx.hbrBackground = (HBRUSH)(COLOR_INACTIVEBORDER + 1);
418         wndClsEx.lpszClassName = PREVIEWWND_CLASS_NAME;
419 
420         // register the preview window class
421         // !!! Win95 -   the window class will be unregistered automatically
422         //               if the dll is unloaded
423         //     Win2000 - the window class must be unregistered manually
424         //               if the dll is unloaded
425         s_ClassAtom = RegisterClassEx(&wndClsEx);
426 
427         OSL_POSTCOND(s_ClassAtom,"Could not register preview window class");
428 
429         if (0 == s_ClassAtom)
430             throw std::runtime_error("Preview window class could not be registered");
431     }
432 
433     // increment the register class counter
434     // so that we keep track of the number
435     // of class registrations
436     //if ( 0 != s_ClassAtom )
437     s_RegisterDibPreviewWndCount++;
438 
439     return s_ClassAtom;
440 }
441 
442 //---------------------------------------------------
443 //
444 //---------------------------------------------------
445 
UnregisterDibPreviewWindowClass()446 void SAL_CALL CDIBPreview::UnregisterDibPreviewWindowClass()
447 {
448     osl::MutexGuard aGuard( s_Mutex );
449 
450     OSL_ASSERT( ( (0 != s_ClassAtom) && (s_RegisterDibPreviewWndCount > 0)) ||
451                 ( (0 == s_ClassAtom) && (0 == s_RegisterDibPreviewWndCount) ) );
452 
453     // update the register class counter
454     // and unregister the window class if
455     // counter drops to zero
456     if (0 != s_ClassAtom)
457     {
458         s_RegisterDibPreviewWndCount--;
459         OSL_ASSERT(s_RegisterDibPreviewWndCount >= 0);
460     }
461 
462     if (0 == s_RegisterDibPreviewWndCount)
463     {
464         UnregisterClass((LPCTSTR)MAKELONG(s_ClassAtom,0),m_Instance);
465         s_ClassAtom = 0;
466     }
467 }
468