1 /*****************************************************************************
2 * win32_factory.cpp
3 *****************************************************************************
4 * Copyright (C) 2003 the VideoLAN team
5 * $Id: a357276f29a5ce4a16a14c7447f7d1bf0a3e0ec8 $
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 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <windows.h>
32 #include <winuser.h>
33 #include <wingdi.h>
34 #include <tchar.h>
35 #include <shellapi.h>
36
37 #include "win32_factory.hpp"
38 #include "win32_graphics.hpp"
39 #include "win32_timer.hpp"
40 #include "win32_window.hpp"
41 #include "win32_tooltip.hpp"
42 #include "win32_popup.hpp"
43 #include "win32_loop.hpp"
44 #include "../src/theme.hpp"
45 #include "../src/window_manager.hpp"
46 #include "../src/generic_window.hpp"
47 #include "../commands/cmd_dialogs.hpp"
48 #include "../commands/cmd_minimize.hpp"
49
50 // Custom message for the notifications of the system tray
51 #define MY_WM_TRAYACTION (WM_APP + 1)
52
53
Win32Proc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)54 LRESULT CALLBACK Win32Factory::Win32Proc( HWND hwnd, UINT uMsg,
55 WPARAM wParam, LPARAM lParam )
56 {
57 // Get pointer to thread info: should only work with the parent window
58 intf_thread_t *p_intf = (intf_thread_t *)GetWindowLongPtr( hwnd,
59 GWLP_USERDATA );
60
61 // If doesn't exist, treat windows message normally
62 if( p_intf == NULL || p_intf->p_sys->p_osFactory == NULL )
63 {
64 return DefWindowProc( hwnd, uMsg, wParam, lParam );
65 }
66
67 Win32Factory *pFactory = (Win32Factory*)Win32Factory::instance( p_intf );
68 GenericWindow *pWin = pFactory->m_windowMap[hwnd];
69
70 if( hwnd == pFactory->getParentWindow() )
71 {
72 if( uMsg == WM_SYSCOMMAND )
73 {
74 // If closing parent window
75 if( (wParam & 0xFFF0) == SC_CLOSE )
76 {
77 libvlc_Quit( p_intf->obj.libvlc );
78 return 0;
79 }
80 else if( (wParam & 0xFFF0) == SC_MINIMIZE )
81 {
82 pFactory->minimize();
83 return 0;
84 }
85 else if( (wParam & 0xFFF0) == SC_RESTORE )
86 {
87 pFactory->restore();
88 return 0;
89 }
90 else
91 {
92 msg_Dbg( p_intf, "WM_SYSCOMMAND %i", (wParam & 0xFFF0) );
93 }
94 }
95 // Handle systray notifications
96 else if( uMsg == MY_WM_TRAYACTION )
97 {
98 if( (UINT)lParam == WM_LBUTTONDOWN )
99 {
100 p_intf->p_sys->p_theme->getWindowManager().raiseAll();
101 CmdDlgHidePopupMenu aCmdPopup( p_intf );
102 aCmdPopup.execute();
103 return 0;
104 }
105 else if( (UINT)lParam == WM_RBUTTONDOWN )
106 {
107 CmdDlgShowPopupMenu aCmdPopup( p_intf );
108 aCmdPopup.execute();
109 return 0;
110 }
111 else if( (UINT)lParam == WM_LBUTTONDBLCLK )
112 {
113 CmdRestore aCmdRestore( p_intf );
114 aCmdRestore.execute();
115 return 0;
116 }
117 }
118 }
119 else if( pWin )
120 {
121 Win32Loop* pLoop =
122 (Win32Loop*) OSFactory::instance( p_intf )->getOSLoop();
123 if( pLoop )
124 return pLoop->processEvent( hwnd, uMsg, wParam, lParam );
125 }
126
127 // If hwnd does not match any window or message not processed
128 return DefWindowProc( hwnd, uMsg, wParam, lParam );
129 }
130
131
MonitorEnumProc(HMONITOR hMonitor,HDC hdcMonitor,LPRECT lprcMonitor,LPARAM dwData)132 BOOL CALLBACK Win32Factory::MonitorEnumProc( HMONITOR hMonitor, HDC hdcMonitor,
133 LPRECT lprcMonitor, LPARAM dwData )
134 {
135 (void)hdcMonitor; (void)lprcMonitor;
136 std::list<HMONITOR>* pList = (std::list<HMONITOR>*)dwData;
137 pList->push_back( hMonitor );
138
139 return TRUE;
140 }
141
Win32Factory(intf_thread_t * pIntf)142 Win32Factory::Win32Factory( intf_thread_t *pIntf ):
143 OSFactory( pIntf ), m_hParentWindow( NULL ),
144 m_dirSep( "\\" )
145 {
146 // see init()
147 }
148
149
init()150 bool Win32Factory::init()
151 {
152 LPCTSTR vlc_name = TEXT("VLC Media Player");
153 LPCTSTR vlc_icon = TEXT("VLC_ICON");
154 LPCTSTR vlc_class = TEXT("SkinWindowClass");
155
156 // Get instance handle
157 m_hInst = GetModuleHandle( NULL );
158 if( m_hInst == NULL )
159 {
160 msg_Err( getIntf(), "Cannot get module handle" );
161 }
162
163 // Create window class
164 WNDCLASS skinWindowClass;
165 skinWindowClass.style = CS_DBLCLKS;
166 skinWindowClass.lpfnWndProc = (WNDPROC)Win32Factory::Win32Proc;
167 skinWindowClass.lpszClassName = vlc_class;
168 skinWindowClass.lpszMenuName = NULL;
169 skinWindowClass.cbClsExtra = 0;
170 skinWindowClass.cbWndExtra = 0;
171 skinWindowClass.hbrBackground = NULL;
172 skinWindowClass.hCursor = LoadCursor( NULL, IDC_ARROW );
173 skinWindowClass.hIcon = LoadIcon( m_hInst, vlc_icon );
174 skinWindowClass.hInstance = m_hInst;
175
176 // Register class and check it
177 if( !RegisterClass( &skinWindowClass ) )
178 {
179 WNDCLASS wndclass;
180
181 // Check why it failed. If it's because the class already exists
182 // then fine, otherwise return with an error.
183 if( !GetClassInfo( m_hInst, vlc_class, &wndclass ) )
184 {
185 msg_Err( getIntf(), "cannot register window class" );
186 return false;
187 }
188 }
189
190 // Create Window
191 m_hParentWindow = CreateWindowEx( WS_EX_TOOLWINDOW, vlc_class,
192 vlc_name, WS_POPUP | WS_SYSMENU | WS_MINIMIZEBOX,
193 -200, -200, 0, 0, 0, 0, m_hInst, 0 );
194 if( m_hParentWindow == NULL )
195 {
196 msg_Err( getIntf(), "cannot create parent window" );
197 return false;
198 }
199
200 // Store with it a pointer to the interface thread
201 SetWindowLongPtr( m_hParentWindow, GWLP_USERDATA, (LONG_PTR)getIntf() );
202
203 // We do it this way otherwise CreateWindowEx will fail
204 // if WS_EX_LAYERED is not supported
205 SetWindowLongPtr( m_hParentWindow, GWL_EXSTYLE,
206 GetWindowLongPtr( m_hParentWindow, GWL_EXSTYLE ) |
207 WS_EX_LAYERED );
208
209 ShowWindow( m_hParentWindow, SW_SHOW );
210
211 // Initialize the systray icon
212 m_trayIcon.cbSize = sizeof( NOTIFYICONDATA );
213 m_trayIcon.hWnd = m_hParentWindow;
214 m_trayIcon.uID = 42;
215 m_trayIcon.uFlags = NIF_ICON|NIF_TIP|NIF_MESSAGE;
216 m_trayIcon.uCallbackMessage = MY_WM_TRAYACTION;
217 m_trayIcon.hIcon = LoadIcon( m_hInst, vlc_icon );
218 _tcscpy( m_trayIcon.szTip, vlc_name );
219
220 // Show the systray icon if needed
221 if( var_InheritBool( getIntf(), "skins2-systray" ) )
222 {
223 addInTray();
224 }
225
226 // Show the task in the task bar if needed
227 if( var_InheritBool( getIntf(), "skins2-taskbar" ) )
228 {
229 addInTaskBar();
230 }
231
232 // Initialize the OLE library (for drag & drop)
233 OleInitialize( NULL );
234
235 // Initialize the resource path
236 char *datadir = config_GetUserDir( VLC_DATA_DIR );
237 m_resourcePath.push_back( (std::string)datadir + "\\skins" );
238 free( datadir );
239 datadir = config_GetDataDir();
240 m_resourcePath.push_back( (std::string)datadir + "\\skins" );
241 m_resourcePath.push_back( (std::string)datadir + "\\skins2" );
242 m_resourcePath.push_back( (std::string)datadir + "\\share\\skins" );
243 m_resourcePath.push_back( (std::string)datadir + "\\share\\skins2" );
244 free( datadir );
245
246 // Enumerate all monitors available
247 EnumDisplayMonitors( NULL, NULL, MonitorEnumProc, (LPARAM)&m_monitorList );
248 int num = 0;
249 for( std::list<HMONITOR>::iterator it = m_monitorList.begin();
250 it != m_monitorList.end(); ++it, num++ )
251 {
252 MONITORINFO mi;
253 mi.cbSize = sizeof( MONITORINFO );
254 if( GetMonitorInfo( *it, &mi ) )
255 {
256 msg_Dbg( getIntf(), "monitor #%i, %ldx%ld at +%ld+%ld", num,
257 mi.rcMonitor.right - mi.rcMonitor.left,
258 mi.rcMonitor.bottom - mi.rcMonitor.top,
259 mi.rcMonitor.left,
260 mi.rcMonitor.top );
261 }
262 }
263
264 // All went well
265 return true;
266 }
267
268
~Win32Factory()269 Win32Factory::~Win32Factory()
270 {
271 // Uninitialize the OLE library
272 OleUninitialize();
273
274 // Remove the systray icon
275 removeFromTray();
276
277 if( m_hParentWindow ) DestroyWindow( m_hParentWindow );
278 }
279
280
createOSGraphics(int width,int height)281 OSGraphics *Win32Factory::createOSGraphics( int width, int height )
282 {
283 return new Win32Graphics( getIntf(), width, height );
284 }
285
286
getOSLoop()287 OSLoop *Win32Factory::getOSLoop()
288 {
289 return Win32Loop::instance( getIntf() );
290 }
291
292
destroyOSLoop()293 void Win32Factory::destroyOSLoop()
294 {
295 Win32Loop::destroy( getIntf() );
296 }
297
minimize()298 void Win32Factory::minimize()
299 {
300 /* Make sure no tooltip is visible first */
301 getIntf()->p_sys->p_theme->getWindowManager().hideTooltip();
302
303 ShowWindow( m_hParentWindow, SW_MINIMIZE );
304 }
305
restore()306 void Win32Factory::restore()
307 {
308 ShowWindow( m_hParentWindow, SW_RESTORE );
309 }
310
addInTray()311 void Win32Factory::addInTray()
312 {
313 Shell_NotifyIcon( NIM_ADD, &m_trayIcon );
314 }
315
removeFromTray()316 void Win32Factory::removeFromTray()
317 {
318 Shell_NotifyIcon( NIM_DELETE, &m_trayIcon );
319 }
320
addInTaskBar()321 void Win32Factory::addInTaskBar()
322 {
323 ShowWindow( m_hParentWindow, SW_HIDE );
324 SetWindowLongPtr( m_hParentWindow, GWL_EXSTYLE,
325 WS_EX_LAYERED|WS_EX_APPWINDOW );
326 ShowWindow( m_hParentWindow, SW_SHOW );
327 }
328
removeFromTaskBar()329 void Win32Factory::removeFromTaskBar()
330 {
331 ShowWindow( m_hParentWindow, SW_HIDE );
332 SetWindowLongPtr( m_hParentWindow, GWL_EXSTYLE,
333 WS_EX_LAYERED|WS_EX_TOOLWINDOW );
334 ShowWindow( m_hParentWindow, SW_SHOW );
335 }
336
createOSTimer(CmdGeneric & rCmd)337 OSTimer *Win32Factory::createOSTimer( CmdGeneric &rCmd )
338 {
339 return new Win32Timer( getIntf(), rCmd, m_hParentWindow );
340 }
341
342
createOSWindow(GenericWindow & rWindow,bool dragDrop,bool playOnDrop,OSWindow * pParent,GenericWindow::WindowType_t type)343 OSWindow *Win32Factory::createOSWindow( GenericWindow &rWindow, bool dragDrop,
344 bool playOnDrop, OSWindow *pParent,
345 GenericWindow::WindowType_t type )
346 {
347 return new Win32Window( getIntf(), rWindow, m_hInst, m_hParentWindow,
348 dragDrop, playOnDrop, (Win32Window*)pParent, type );
349 }
350
351
createOSTooltip()352 OSTooltip *Win32Factory::createOSTooltip()
353 {
354 return new Win32Tooltip( getIntf(), m_hInst, m_hParentWindow );
355 }
356
357
createOSPopup()358 OSPopup *Win32Factory::createOSPopup()
359 {
360 // XXX FIXME: this way of getting the handle really sucks!
361 // In fact, the clean way would be to have in Builder::addPopup() a call
362 // to pPopup->associateToWindow() (to be written)... but the problem is
363 // that there is no way to access the OS-dependent window handle from a
364 // GenericWindow (we cannot even access the OSWindow).
365 if( m_windowMap.begin() == m_windowMap.end() )
366 {
367 msg_Err( getIntf(), "no window has been created before the popup!" );
368 return NULL;
369 }
370
371 return new Win32Popup( getIntf(), m_windowMap.begin()->first );
372 }
373
374
getScreenWidth() const375 int Win32Factory::getScreenWidth() const
376 {
377 return GetSystemMetrics(SM_CXSCREEN);
378 }
379
380
getScreenHeight() const381 int Win32Factory::getScreenHeight() const
382 {
383 return GetSystemMetrics(SM_CYSCREEN);
384 }
385
386
getMonitorInfo(const GenericWindow & rWindow,int * p_x,int * p_y,int * p_width,int * p_height) const387 void Win32Factory::getMonitorInfo( const GenericWindow &rWindow,
388 int* p_x, int* p_y,
389 int* p_width, int* p_height ) const
390 {
391 HWND wnd = (HWND)rWindow.getOSHandle();
392 HMONITOR hmon = MonitorFromWindow( wnd, MONITOR_DEFAULTTONEAREST );
393 MONITORINFO mi;
394 mi.cbSize = sizeof( MONITORINFO );
395 if( hmon && GetMonitorInfo( hmon, &mi ) )
396 {
397 *p_x = mi.rcMonitor.left;
398 *p_y = mi.rcMonitor.top;
399 *p_width = mi.rcMonitor.right - mi.rcMonitor.left;
400 *p_height = mi.rcMonitor.bottom - mi.rcMonitor.top;
401 }
402 else
403 {
404 *p_x = 0;
405 *p_y = 0;
406 *p_width = getScreenWidth();
407 *p_height = getScreenHeight();
408 }
409 }
410
411
getMonitorInfo(int numScreen,int * p_x,int * p_y,int * p_width,int * p_height) const412 void Win32Factory::getMonitorInfo( int numScreen, int* p_x, int* p_y,
413 int* p_width, int* p_height ) const
414 {
415 HMONITOR hmon = NULL;
416 std::list<HMONITOR>::const_iterator it = m_monitorList.begin();
417 for( int i = 0; it != m_monitorList.end(); ++it, i++ )
418 {
419 if( i == numScreen )
420 {
421 hmon = *it;
422 break;
423 }
424 }
425 MONITORINFO mi;
426 mi.cbSize = sizeof( MONITORINFO );
427 if( hmon && GetMonitorInfo( hmon, &mi ) )
428 {
429 *p_x = mi.rcMonitor.left;
430 *p_y = mi.rcMonitor.top;
431 *p_width = mi.rcMonitor.right - mi.rcMonitor.left;
432 *p_height = mi.rcMonitor.bottom - mi.rcMonitor.top;
433 }
434 else
435 {
436 *p_x = 0;
437 *p_y = 0;
438 *p_width = getScreenWidth();
439 *p_height = getScreenHeight();
440 }
441 }
442
443
getWorkArea() const444 SkinsRect Win32Factory::getWorkArea() const
445 {
446 RECT r;
447 SystemParametersInfo( SPI_GETWORKAREA, 0, &r, 0 );
448 // Fill a Rect object
449 return SkinsRect( r.left, r.top, r.right, r.bottom );
450 }
451
452
getMousePos(int & rXPos,int & rYPos) const453 void Win32Factory::getMousePos( int &rXPos, int &rYPos ) const
454 {
455 POINT mousePos;
456 GetCursorPos( &mousePos );
457 rXPos = mousePos.x;
458 rYPos = mousePos.y;
459 }
460
461
changeCursor(CursorType_t type) const462 void Win32Factory::changeCursor( CursorType_t type ) const
463 {
464 LPCTSTR id;
465 switch( type )
466 {
467 default:
468 case kDefaultArrow: id = IDC_ARROW; break;
469 case kResizeNWSE: id = IDC_SIZENWSE; break;
470 case kResizeNS: id = IDC_SIZENS; break;
471 case kResizeWE: id = IDC_SIZEWE; break;
472 case kResizeNESW: id = IDC_SIZENESW; break;
473 }
474
475 HCURSOR hCurs = LoadCursor( NULL, id );
476 SetCursor( hCurs );
477 }
478
479
rmDir(const std::string & rPath)480 void Win32Factory::rmDir( const std::string &rPath )
481 {
482 LPWSTR dir_temp = ToWide( rPath.c_str() );
483 size_t len = wcslen( dir_temp );
484
485 LPWSTR dir = (wchar_t *)vlc_alloc( len + 2, sizeof (wchar_t) );
486 wcsncpy( dir, dir_temp, len + 2);
487
488 SHFILEOPSTRUCTW file_op = {
489 NULL,
490 FO_DELETE,
491 dir,
492 NULL,
493 FOF_NOCONFIRMATION |
494 FOF_NOERRORUI |
495 FOF_SILENT,
496 false,
497 NULL,
498 L"" };
499
500 SHFileOperationW(&file_op);
501
502 free(dir_temp);
503 free(dir);
504 }
505
506 #endif
507