]> git.sesse.net Git - vlc/blob - modules/gui/skins2/win32/win32_factory.cpp
07b6325f488e0ff7c96c88b0c87d73cff21fd127
[vlc] / modules / gui / skins2 / win32 / win32_factory.cpp
1 /*****************************************************************************
2  * win32_factory.cpp
3  *****************************************************************************
4  * Copyright (C) 2003 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Cyril Deguet     <asmax@via.ecp.fr>
8  *          Olivier Teulière <ipkiss@via.ecp.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #ifdef WIN32_SKINS
26
27 #include "win32_factory.hpp"
28 #include "win32_graphics.hpp"
29 #include "win32_timer.hpp"
30 #include "win32_window.hpp"
31 #include "win32_tooltip.hpp"
32 #include "win32_popup.hpp"
33 #include "win32_loop.hpp"
34 #include "../src/theme.hpp"
35 #include "../src/window_manager.hpp"
36 #include "../src/generic_window.hpp"
37 #include "../commands/cmd_dialogs.hpp"
38 #include "../commands/cmd_minimize.hpp"
39
40 // Custom message for the notifications of the system tray
41 #define MY_WM_TRAYACTION (WM_APP + 1)
42
43
44 LRESULT CALLBACK Win32Proc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
45 {
46     // Get pointer to thread info: should only work with the parent window
47     intf_thread_t *p_intf = (intf_thread_t *)GetWindowLongPtr( hwnd,
48         GWLP_USERDATA );
49
50     // If doesn't exist, treat windows message normally
51     if( p_intf == NULL || p_intf->p_sys->p_osFactory == NULL )
52     {
53         return DefWindowProc( hwnd, uMsg, wParam, lParam );
54     }
55
56     // Here we know we are getting a message for the parent window, since it is
57     // the only one to store p_intf...
58     // Yes, it is a kludge :)
59
60 //Win32Factory *pFactory = (Win32Factory*)Win32Factory::instance( p_intf );
61 //msg_Err( p_intf, "Parent window %p %p %u %i\n", pFactory->m_hParentWindow, hwnd, uMsg, wParam );
62     // If Window is parent window
63     // XXX: this test isn't needed, see the kludge above...
64 //    if( hwnd == pFactory->m_hParentWindow )
65     {
66         if( uMsg == WM_SYSCOMMAND )
67         {
68             // If closing parent window
69             if( wParam == SC_CLOSE )
70             {
71                 Win32Loop *pLoop = (Win32Loop*)Win32Loop::instance( p_intf );
72                 pLoop->exit();
73                 return 0;
74             }
75             else
76             {
77                 msg_Dbg( p_intf, "WM_SYSCOMMAND %i", wParam );
78             }
79         }
80         // Handle systray notifications
81         else if( uMsg == MY_WM_TRAYACTION )
82         {
83             if( (UINT)lParam == WM_LBUTTONDOWN )
84             {
85                 p_intf->p_sys->p_theme->getWindowManager().raiseAll();
86             }
87             else if( (UINT)lParam == WM_RBUTTONDOWN )
88             {
89                 CmdDlgShowPopupMenu aCmdPopup( p_intf );
90                 aCmdPopup.execute();
91             }
92             else if( (UINT)lParam == WM_LBUTTONDBLCLK )
93             {
94                 CmdRestore aCmdRestore( p_intf );
95                 aCmdRestore.execute();
96             }
97         }
98     }
99
100     // If hwnd does not match any window or message not processed
101     return DefWindowProc( hwnd, uMsg, wParam, lParam );
102 }
103
104
105 Win32Factory::Win32Factory( intf_thread_t *pIntf ):
106     OSFactory( pIntf ), TransparentBlt( NULL ), AlphaBlend( NULL ),
107     SetLayeredWindowAttributes( NULL ), m_hParentWindow( NULL ),
108     m_dirSep( "\\" )
109 {
110     // see init()
111 }
112
113
114 bool Win32Factory::init()
115 {
116     // Get instance handle
117     m_hInst = GetModuleHandle( NULL );
118     if( m_hInst == NULL )
119     {
120         msg_Err( getIntf(), "Cannot get module handle" );
121     }
122
123     // Create window class
124     WNDCLASS skinWindowClass;
125     skinWindowClass.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
126     skinWindowClass.lpfnWndProc = (WNDPROC) Win32Proc;
127     skinWindowClass.lpszClassName = _T("SkinWindowClass");
128     skinWindowClass.lpszMenuName = NULL;
129     skinWindowClass.cbClsExtra = 0;
130     skinWindowClass.cbWndExtra = 0;
131     skinWindowClass.hbrBackground = NULL;
132     skinWindowClass.hCursor = LoadCursor( NULL , IDC_ARROW );
133     skinWindowClass.hIcon = LoadIcon( m_hInst, _T("VLC_ICON") );
134     skinWindowClass.hInstance = m_hInst;
135
136     // Register class and check it
137     if( !RegisterClass( &skinWindowClass ) )
138     {
139         WNDCLASS wndclass;
140
141         // Check why it failed. If it's because the class already exists
142         // then fine, otherwise return with an error.
143         if( !GetClassInfo( m_hInst, _T("SkinWindowClass"), &wndclass ) )
144         {
145             msg_Err( getIntf(), "cannot register window class" );
146             return false;
147         }
148     }
149
150     // Create Window
151     m_hParentWindow = CreateWindowEx( WS_EX_TOOLWINDOW, _T("SkinWindowClass"),
152         _T("VLC media player"), WS_SYSMENU|WS_POPUP,
153         -200, -200, 0, 0, 0, 0, m_hInst, 0 );
154     if( m_hParentWindow == NULL )
155     {
156         msg_Err( getIntf(), "cannot create parent window" );
157         return false;
158     }
159
160     // Store with it a pointer to the interface thread
161     SetWindowLongPtr( m_hParentWindow, GWLP_USERDATA, (LONG_PTR)getIntf() );
162
163     // We do it this way otherwise CreateWindowEx will fail
164     // if WS_EX_LAYERED is not supported
165     SetWindowLongPtr( m_hParentWindow, GWL_EXSTYLE,
166                       GetWindowLong( m_hParentWindow, GWL_EXSTYLE ) |
167                       WS_EX_LAYERED );
168
169     ShowWindow( m_hParentWindow, SW_SHOW );
170
171     // Initialize the systray icon
172     m_trayIcon.cbSize = sizeof( NOTIFYICONDATA );
173     m_trayIcon.hWnd = m_hParentWindow;
174     m_trayIcon.uID = 42;
175     m_trayIcon.uFlags = NIF_ICON|NIF_TIP|NIF_MESSAGE;
176     m_trayIcon.uCallbackMessage = MY_WM_TRAYACTION;
177     m_trayIcon.hIcon = LoadIcon( m_hInst, _T("VLC_ICON") );
178     strcpy( m_trayIcon.szTip, "VLC media player" );
179
180     // Show the systray icon if needed
181     if( config_GetInt( getIntf(), "skins2-systray" ) )
182     {
183         addInTray();
184     }
185
186     // Show the task in the task bar if needed
187     if( config_GetInt( getIntf(), "skins2-taskbar" ) )
188     {
189         addInTaskBar();
190     }
191
192     // Initialize the OLE library (for drag & drop)
193     OleInitialize( NULL );
194
195     // We dynamically load msimg32.dll to get a pointer to TransparentBlt()
196     m_hMsimg32 = LoadLibrary( _T("msimg32.dll") );
197     if( !m_hMsimg32 ||
198         !( TransparentBlt =
199             (BOOL (WINAPI*)(HDC, int, int, int, int,
200                             HDC, int, int, int, int, unsigned int))
201             GetProcAddress( m_hMsimg32, _T("TransparentBlt") ) ) )
202     {
203         TransparentBlt = NULL;
204         msg_Dbg( getIntf(), "couldn't find TransparentBlt(), "
205                  "falling back to BitBlt()" );
206     }
207     if( !m_hMsimg32 ||
208         !( AlphaBlend =
209             (BOOL (WINAPI*)( HDC, int, int, int, int, HDC, int, int,
210                               int, int, BLENDFUNCTION ))
211             GetProcAddress( m_hMsimg32, _T("AlphaBlend") ) ) )
212     {
213         AlphaBlend = NULL;
214         msg_Dbg( getIntf(), "couldn't find AlphaBlend()" );
215     }
216
217     // Idem for user32.dll and SetLayeredWindowAttributes()
218     m_hUser32 = LoadLibrary( _T("user32.dll") );
219     if( !m_hUser32 ||
220         !( SetLayeredWindowAttributes =
221             (BOOL (WINAPI *)(HWND, COLORREF, BYTE, DWORD))
222             GetProcAddress( m_hUser32, _T("SetLayeredWindowAttributes") ) ) )
223     {
224         SetLayeredWindowAttributes = NULL;
225         msg_Dbg( getIntf(), "couldn't find SetLayeredWindowAttributes()" );
226     }
227
228     // Initialize the resource path
229     char *datadir = config_GetUserDir( VLC_DATA_DIR );
230     m_resourcePath.push_back( (string)datadir + "\\skins" );
231     free( datadir );
232     m_resourcePath.push_back( (string)config_GetDataDir() +
233                               "\\skins" );
234     m_resourcePath.push_back( (string)config_GetDataDir() +
235                               "\\skins2" );
236     m_resourcePath.push_back( (string)config_GetDataDir() +
237                               "\\share\\skins" );
238     m_resourcePath.push_back( (string)config_GetDataDir() +
239                               "\\share\\skins2" );
240
241     // All went well
242     return true;
243 }
244
245
246 Win32Factory::~Win32Factory()
247 {
248     // Uninitialize the OLE library
249     OleUninitialize();
250
251     // Remove the systray icon
252     removeFromTray();
253
254     if( m_hParentWindow ) DestroyWindow( m_hParentWindow );
255
256     // Unload msimg32.dll and user32.dll
257     if( m_hMsimg32 )
258         FreeLibrary( m_hMsimg32 );
259     if( m_hUser32 )
260         FreeLibrary( m_hUser32 );
261 }
262
263
264 OSGraphics *Win32Factory::createOSGraphics( int width, int height )
265 {
266     return new Win32Graphics( getIntf(), width, height );
267 }
268
269
270 OSLoop *Win32Factory::getOSLoop()
271 {
272     return Win32Loop::instance( getIntf() );
273 }
274
275
276 void Win32Factory::destroyOSLoop()
277 {
278     Win32Loop::destroy( getIntf() );
279 }
280
281 void Win32Factory::minimize()
282 {
283     /* Make sure no tooltip is visible first */
284     getIntf()->p_sys->p_theme->getWindowManager().hideTooltip();
285
286     ShowWindow( m_hParentWindow, SW_MINIMIZE );
287 }
288
289 void Win32Factory::restore()
290 {
291     ShowWindow( m_hParentWindow, SW_RESTORE );
292 }
293
294 void Win32Factory::addInTray()
295 {
296     Shell_NotifyIcon( NIM_ADD, &m_trayIcon );
297 }
298
299 void Win32Factory::removeFromTray()
300 {
301     Shell_NotifyIcon( NIM_DELETE, &m_trayIcon );
302 }
303
304 void Win32Factory::addInTaskBar()
305 {
306     ShowWindow( m_hParentWindow, SW_HIDE );
307     SetWindowLongPtr( m_hParentWindow, GWL_EXSTYLE,
308                       WS_EX_LAYERED|WS_EX_APPWINDOW );
309     ShowWindow( m_hParentWindow, SW_SHOW );
310 }
311
312 void Win32Factory::removeFromTaskBar()
313 {
314     ShowWindow( m_hParentWindow, SW_HIDE );
315     SetWindowLongPtr( m_hParentWindow, GWL_EXSTYLE,
316                       WS_EX_LAYERED|WS_EX_TOOLWINDOW );
317     ShowWindow( m_hParentWindow, SW_SHOW );
318 }
319
320 OSTimer *Win32Factory::createOSTimer( CmdGeneric &rCmd )
321 {
322     return new Win32Timer( getIntf(), rCmd, m_hParentWindow );
323 }
324
325
326 OSWindow *Win32Factory::createOSWindow( GenericWindow &rWindow, bool dragDrop,
327                                         bool playOnDrop, OSWindow *pParent,
328                                         GenericWindow::WindowType_t type )
329 {
330     return new Win32Window( getIntf(), rWindow, m_hInst, m_hParentWindow,
331                             dragDrop, playOnDrop, (Win32Window*)pParent );
332 }
333
334
335 OSTooltip *Win32Factory::createOSTooltip()
336 {
337     return new Win32Tooltip( getIntf(), m_hInst, m_hParentWindow );
338 }
339
340
341 OSPopup *Win32Factory::createOSPopup()
342 {
343     // XXX FIXME: this way of getting the handle really sucks!
344     // In fact, the clean way would be to have in Builder::addPopup() a call
345     // to pPopup->associateToWindow() (to be written)... but the problem is
346     // that there is no way to access the OS-dependent window handle from a
347     // GenericWindow (we cannot even access the OSWindow).
348     if( m_windowMap.begin() == m_windowMap.end() )
349     {
350         msg_Err( getIntf(), "no window has been created before the popup!" );
351         return NULL;
352     }
353
354     return new Win32Popup( getIntf(), m_windowMap.begin()->first );
355 }
356
357
358 int Win32Factory::getScreenWidth() const
359 {
360     return GetSystemMetrics(SM_CXSCREEN);
361
362 }
363
364
365 int Win32Factory::getScreenHeight() const
366 {
367     return GetSystemMetrics(SM_CYSCREEN);
368 }
369
370
371 SkinsRect Win32Factory::getWorkArea() const
372 {
373     RECT r;
374     SystemParametersInfo( SPI_GETWORKAREA, 0, &r, 0 );
375     // Fill a Rect object
376     return  SkinsRect( r.left, r.top, r.right, r.bottom );
377 }
378
379
380 void Win32Factory::getMousePos( int &rXPos, int &rYPos ) const
381 {
382     POINT mousePos;
383     GetCursorPos( &mousePos );
384     rXPos = mousePos.x;
385     rYPos = mousePos.y;
386 }
387
388
389 void Win32Factory::changeCursor( CursorType_t type ) const
390 {
391     LPCTSTR id;
392     switch( type )
393     {
394     default:
395     case kDefaultArrow: id = IDC_ARROW;    break;
396     case kResizeNWSE:   id = IDC_SIZENWSE; break;
397     case kResizeNS:     id = IDC_SIZENS;   break;
398     case kResizeWE:     id = IDC_SIZEWE;   break;
399     case kResizeNESW:   id = IDC_SIZENESW; break;
400     }
401
402     HCURSOR hCurs = LoadCursor( NULL, id );
403     SetCursor( hCurs );
404 }
405
406
407 void Win32Factory::rmDir( const string &rPath )
408 {
409     WIN32_FIND_DATA find;
410     string file;
411     string findFiles = rPath + "\\*";
412     HANDLE handle    = FindFirstFile( findFiles.c_str(), &find );
413
414     while( handle != INVALID_HANDLE_VALUE )
415     {
416         // If file is neither "." nor ".."
417         if( strcmp( find.cFileName, "." ) && strcmp( find.cFileName, ".." ) )
418         {
419             // Set file name
420             file = rPath + "\\" + (string)find.cFileName;
421
422             // If file is a directory, delete it recursively
423             if( find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
424             {
425                 rmDir( file );
426             }
427             // Else, it is a file so simply delete it
428             else
429             {
430                 DeleteFile( file.c_str() );
431             }
432         }
433
434         // If no more file in directory, exit while
435         if( !FindNextFile( handle, &find ) )
436             break;
437     }
438
439     // Now directory is empty so can be removed
440     FindClose( handle );
441     RemoveDirectory( rPath.c_str() );
442 }
443
444 #endif