]> git.sesse.net Git - vlc/blob - modules/gui/skins2/win32/win32_factory.cpp
Merge branch 'master' into lpcm_encoder
[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     Win32Factory *pFactory = (Win32Factory*)Win32Factory::instance( p_intf );
57
58     if( hwnd == pFactory->getParentWindow() )
59     {
60         if( uMsg == WM_SYSCOMMAND )
61         {
62             // If closing parent window
63             if( wParam == SC_CLOSE )
64             {
65                 libvlc_Quit( p_intf->p_libvlc );
66                 return 0;
67             }
68             else if( wParam == SC_MINIMIZE )
69             {
70                 pFactory->minimize();
71                 return 0;
72             }
73             else if( wParam == SC_RESTORE )
74             {
75                 pFactory->restore();
76                 return 0;
77             }
78             else
79             {
80                 msg_Dbg( p_intf, "WM_SYSCOMMAND %i", wParam );
81             }
82         }
83         // Handle systray notifications
84         else if( uMsg == MY_WM_TRAYACTION )
85         {
86             if( (UINT)lParam == WM_LBUTTONDOWN )
87             {
88                 p_intf->p_sys->p_theme->getWindowManager().raiseAll();
89                 CmdDlgHidePopupMenu aCmdPopup( p_intf );
90                 aCmdPopup.execute();
91             }
92             else if( (UINT)lParam == WM_RBUTTONDOWN )
93             {
94                 CmdDlgShowPopupMenu aCmdPopup( p_intf );
95                 aCmdPopup.execute();
96             }
97             else if( (UINT)lParam == WM_LBUTTONDBLCLK )
98             {
99                 CmdRestore aCmdRestore( p_intf );
100                 aCmdRestore.execute();
101             }
102         }
103     }
104
105     // If hwnd does not match any window or message not processed
106     return DefWindowProc( hwnd, uMsg, wParam, lParam );
107 }
108
109
110 Win32Factory::Win32Factory( intf_thread_t *pIntf ):
111     OSFactory( pIntf ), TransparentBlt( NULL ), AlphaBlend( NULL ),
112     SetLayeredWindowAttributes( NULL ), m_hParentWindow( NULL ),
113     m_dirSep( "\\" )
114 {
115     // see init()
116 }
117
118
119 bool Win32Factory::init()
120 {
121     // Get instance handle
122     m_hInst = GetModuleHandle( NULL );
123     if( m_hInst == NULL )
124     {
125         msg_Err( getIntf(), "Cannot get module handle" );
126     }
127
128     // Create window class
129     WNDCLASS skinWindowClass;
130     skinWindowClass.style = CS_DBLCLKS;
131     skinWindowClass.lpfnWndProc = (WNDPROC) Win32Proc;
132     skinWindowClass.lpszClassName = _T("SkinWindowClass");
133     skinWindowClass.lpszMenuName = NULL;
134     skinWindowClass.cbClsExtra = 0;
135     skinWindowClass.cbWndExtra = 0;
136     skinWindowClass.hbrBackground = NULL;
137     skinWindowClass.hCursor = LoadCursor( NULL, IDC_ARROW );
138     skinWindowClass.hIcon = LoadIcon( m_hInst, _T("VLC_ICON") );
139     skinWindowClass.hInstance = m_hInst;
140
141     // Register class and check it
142     if( !RegisterClass( &skinWindowClass ) )
143     {
144         WNDCLASS wndclass;
145
146         // Check why it failed. If it's because the class already exists
147         // then fine, otherwise return with an error.
148         if( !GetClassInfo( m_hInst, _T("SkinWindowClass"), &wndclass ) )
149         {
150             msg_Err( getIntf(), "cannot register window class" );
151             return false;
152         }
153     }
154
155     // Create Window
156     m_hParentWindow = CreateWindowEx( WS_EX_TOOLWINDOW, _T("SkinWindowClass"),
157         _T("VLC media player"), WS_POPUP | WS_SYSMENU | WS_MINIMIZEBOX,
158         -200, -200, 0, 0, 0, 0, m_hInst, 0 );
159     if( m_hParentWindow == NULL )
160     {
161         msg_Err( getIntf(), "cannot create parent window" );
162         return false;
163     }
164
165     // Store with it a pointer to the interface thread
166     SetWindowLongPtr( m_hParentWindow, GWLP_USERDATA, (LONG_PTR)getIntf() );
167
168     // We do it this way otherwise CreateWindowEx will fail
169     // if WS_EX_LAYERED is not supported
170     SetWindowLongPtr( m_hParentWindow, GWL_EXSTYLE,
171                       GetWindowLongPtr( m_hParentWindow, GWL_EXSTYLE ) |
172                       WS_EX_LAYERED );
173
174     ShowWindow( m_hParentWindow, SW_SHOW );
175
176     // Initialize the systray icon
177     m_trayIcon.cbSize = sizeof( NOTIFYICONDATA );
178     m_trayIcon.hWnd = m_hParentWindow;
179     m_trayIcon.uID = 42;
180     m_trayIcon.uFlags = NIF_ICON|NIF_TIP|NIF_MESSAGE;
181     m_trayIcon.uCallbackMessage = MY_WM_TRAYACTION;
182     m_trayIcon.hIcon = LoadIcon( m_hInst, _T("VLC_ICON") );
183     strcpy( m_trayIcon.szTip, "VLC media player" );
184
185     // Show the systray icon if needed
186     if( var_InheritBool( getIntf(), "skins2-systray" ) )
187     {
188         addInTray();
189     }
190
191     // Show the task in the task bar if needed
192     if( var_InheritBool( getIntf(), "skins2-taskbar" ) )
193     {
194         addInTaskBar();
195     }
196
197     // Initialize the OLE library (for drag & drop)
198     OleInitialize( NULL );
199
200     // We dynamically load msimg32.dll to get a pointer to TransparentBlt()
201     m_hMsimg32 = LoadLibrary( _T("msimg32.dll") );
202     if( !m_hMsimg32 ||
203         !( TransparentBlt =
204             (BOOL (WINAPI*)(HDC, int, int, int, int,
205                             HDC, int, int, int, int, unsigned int))
206             GetProcAddress( m_hMsimg32, _T("TransparentBlt") ) ) )
207     {
208         TransparentBlt = NULL;
209         msg_Dbg( getIntf(), "couldn't find TransparentBlt(), "
210                  "falling back to BitBlt()" );
211     }
212     if( !m_hMsimg32 ||
213         !( AlphaBlend =
214             (BOOL (WINAPI*)( HDC, int, int, int, int, HDC, int, int,
215                               int, int, BLENDFUNCTION ))
216             GetProcAddress( m_hMsimg32, _T("AlphaBlend") ) ) )
217     {
218         AlphaBlend = NULL;
219         msg_Dbg( getIntf(), "couldn't find AlphaBlend()" );
220     }
221
222     // Idem for user32.dll and SetLayeredWindowAttributes()
223     m_hUser32 = LoadLibrary( _T("user32.dll") );
224     if( !m_hUser32 ||
225         !( SetLayeredWindowAttributes =
226             (BOOL (WINAPI *)(HWND, COLORREF, BYTE, DWORD))
227             GetProcAddress( m_hUser32, _T("SetLayeredWindowAttributes") ) ) )
228     {
229         SetLayeredWindowAttributes = NULL;
230         msg_Dbg( getIntf(), "couldn't find SetLayeredWindowAttributes()" );
231     }
232
233     // Initialize the resource path
234     char *datadir = config_GetUserDir( VLC_DATA_DIR );
235     m_resourcePath.push_back( (string)datadir + "\\skins" );
236     free( datadir );
237     datadir = config_GetDataDir( getIntf() );
238     m_resourcePath.push_back( (string)datadir + "\\skins" );
239     m_resourcePath.push_back( (string)datadir + "\\skins2" );
240     m_resourcePath.push_back( (string)datadir + "\\share\\skins" );
241     m_resourcePath.push_back( (string)datadir + "\\share\\skins2" );
242     free( datadir );
243
244     // All went well
245     return true;
246 }
247
248
249 Win32Factory::~Win32Factory()
250 {
251     // Uninitialize the OLE library
252     OleUninitialize();
253
254     // Remove the systray icon
255     removeFromTray();
256
257     if( m_hParentWindow ) DestroyWindow( m_hParentWindow );
258
259     // Unload msimg32.dll and user32.dll
260     if( m_hMsimg32 )
261         FreeLibrary( m_hMsimg32 );
262     if( m_hUser32 )
263         FreeLibrary( m_hUser32 );
264 }
265
266
267 OSGraphics *Win32Factory::createOSGraphics( int width, int height )
268 {
269     return new Win32Graphics( getIntf(), width, height );
270 }
271
272
273 OSLoop *Win32Factory::getOSLoop()
274 {
275     return Win32Loop::instance( getIntf() );
276 }
277
278
279 void Win32Factory::destroyOSLoop()
280 {
281     Win32Loop::destroy( getIntf() );
282 }
283
284 void Win32Factory::minimize()
285 {
286     /* Make sure no tooltip is visible first */
287     getIntf()->p_sys->p_theme->getWindowManager().hideTooltip();
288
289     ShowWindow( m_hParentWindow, SW_MINIMIZE );
290 }
291
292 void Win32Factory::restore()
293 {
294     ShowWindow( m_hParentWindow, SW_RESTORE );
295 }
296
297 void Win32Factory::addInTray()
298 {
299     Shell_NotifyIcon( NIM_ADD, &m_trayIcon );
300 }
301
302 void Win32Factory::removeFromTray()
303 {
304     Shell_NotifyIcon( NIM_DELETE, &m_trayIcon );
305 }
306
307 void Win32Factory::addInTaskBar()
308 {
309     ShowWindow( m_hParentWindow, SW_HIDE );
310     SetWindowLongPtr( m_hParentWindow, GWL_EXSTYLE,
311                       WS_EX_LAYERED|WS_EX_APPWINDOW );
312     ShowWindow( m_hParentWindow, SW_SHOW );
313 }
314
315 void Win32Factory::removeFromTaskBar()
316 {
317     ShowWindow( m_hParentWindow, SW_HIDE );
318     SetWindowLongPtr( m_hParentWindow, GWL_EXSTYLE,
319                       WS_EX_LAYERED|WS_EX_TOOLWINDOW );
320     ShowWindow( m_hParentWindow, SW_SHOW );
321 }
322
323 OSTimer *Win32Factory::createOSTimer( CmdGeneric &rCmd )
324 {
325     return new Win32Timer( getIntf(), rCmd, m_hParentWindow );
326 }
327
328
329 OSWindow *Win32Factory::createOSWindow( GenericWindow &rWindow, bool dragDrop,
330                                         bool playOnDrop, OSWindow *pParent,
331                                         GenericWindow::WindowType_t type )
332 {
333     return new Win32Window( getIntf(), rWindow, m_hInst, m_hParentWindow,
334                             dragDrop, playOnDrop, (Win32Window*)pParent, type );
335 }
336
337
338 OSTooltip *Win32Factory::createOSTooltip()
339 {
340     return new Win32Tooltip( getIntf(), m_hInst, m_hParentWindow );
341 }
342
343
344 OSPopup *Win32Factory::createOSPopup()
345 {
346     // XXX FIXME: this way of getting the handle really sucks!
347     // In fact, the clean way would be to have in Builder::addPopup() a call
348     // to pPopup->associateToWindow() (to be written)... but the problem is
349     // that there is no way to access the OS-dependent window handle from a
350     // GenericWindow (we cannot even access the OSWindow).
351     if( m_windowMap.begin() == m_windowMap.end() )
352     {
353         msg_Err( getIntf(), "no window has been created before the popup!" );
354         return NULL;
355     }
356
357     return new Win32Popup( getIntf(), m_windowMap.begin()->first );
358 }
359
360
361 int Win32Factory::getScreenWidth() const
362 {
363     return GetSystemMetrics(SM_CXSCREEN);
364
365 }
366
367
368 int Win32Factory::getScreenHeight() const
369 {
370     return GetSystemMetrics(SM_CYSCREEN);
371 }
372
373
374 SkinsRect Win32Factory::getWorkArea() const
375 {
376     RECT r;
377     SystemParametersInfo( SPI_GETWORKAREA, 0, &r, 0 );
378     // Fill a Rect object
379     return  SkinsRect( r.left, r.top, r.right, r.bottom );
380 }
381
382
383 void Win32Factory::getMousePos( int &rXPos, int &rYPos ) const
384 {
385     POINT mousePos;
386     GetCursorPos( &mousePos );
387     rXPos = mousePos.x;
388     rYPos = mousePos.y;
389 }
390
391
392 void Win32Factory::changeCursor( CursorType_t type ) const
393 {
394     LPCTSTR id;
395     switch( type )
396     {
397     default:
398     case kDefaultArrow: id = IDC_ARROW;    break;
399     case kResizeNWSE:   id = IDC_SIZENWSE; break;
400     case kResizeNS:     id = IDC_SIZENS;   break;
401     case kResizeWE:     id = IDC_SIZEWE;   break;
402     case kResizeNESW:   id = IDC_SIZENESW; break;
403     }
404
405     HCURSOR hCurs = LoadCursor( NULL, id );
406     SetCursor( hCurs );
407 }
408
409
410 void Win32Factory::rmDir( const string &rPath )
411 {
412     WIN32_FIND_DATA find;
413     string file;
414     string findFiles = rPath + "\\*";
415     HANDLE handle    = FindFirstFile( findFiles.c_str(), &find );
416
417     while( handle != INVALID_HANDLE_VALUE )
418     {
419         // If file is neither "." nor ".."
420         if( strcmp( find.cFileName, "." ) && strcmp( find.cFileName, ".." ) )
421         {
422             // Set file name
423             file = rPath + "\\" + (string)find.cFileName;
424
425             // If file is a directory, delete it recursively
426             if( find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
427             {
428                 rmDir( file );
429             }
430             // Else, it is a file so simply delete it
431             else
432             {
433                 DeleteFile( file.c_str() );
434             }
435         }
436
437         // If no more file in directory, exit while
438         if( !FindNextFile( handle, &find ) )
439             break;
440     }
441
442     // Now directory is empty so can be removed
443     FindClose( handle );
444     RemoveDirectory( rPath.c_str() );
445 }
446
447 #endif