Commit d7615a6e authored by Erwan Tulou's avatar Erwan Tulou

skins2: fullscreen support for multiple screens (both Linux and Win32)

- by default, fullscreen is performed on the same monitor as the one
  where the video is currently being played back.
- support for --qt-fullscreen-screennumber if the user wishes to force
  fullscreen on a given monitor.

This fixes trac #4712. Tested on Linux. Tests needed for Windows.
parent ba0677ca
......@@ -3678,10 +3678,11 @@ AS_IF([test "${enable_skins2}" = "yes"], [
], [
PKG_CHECK_MODULES([XPM], [xpm])
PKG_CHECK_MODULES([XINERAMA], [xinerama])
PKG_CHECK_MODULES([XEXT], [xext])
VLC_ADD_CPPFLAGS([skins2],[-Imodules/gui/skins2 ${X_CFLAGS} ${XEXT_CFLAGS} ${XPM_CFLAGS} -DX11_SKINS])
VLC_ADD_CXXFLAGS([skins2],[-O2 -fno-rtti])
VLC_ADD_LIBS([skins2],[${X_LIBS} ${X_PRE_LIBS} ${XEXT_LIBS} ${XPM_LIBS} -lX11])
VLC_ADD_LIBS([skins2],[${X_LIBS} ${X_PRE_LIBS} ${XEXT_LIBS} ${XPM_LIBS} ${XINERAMA_LIBS} -lX11])
])
VLC_ADD_PLUGIN([skins2])
......
......@@ -169,6 +169,16 @@ void FscWindow::innerHide()
}
void FscWindow::moveTo( int x, int y, int width, int height )
{
// relocate the fs controller
// (centered horizontally and lowered vertically with a 3% margin)
int x_fsc = x + ( width - getWidth() ) / 2;
int y_fsc = y + height - getHeight() - height * 3 / 100;
move( x_fsc, y_fsc );
}
void FscWindow::CmdFscHide::execute()
{
m_pParent->onTimerExpired();
......
......@@ -57,6 +57,9 @@ public:
/// Action for each transition of fading out
virtual void onTimerExpired();
/// Relocate fsc into new area
virtual void moveTo( int x, int y, int width, int height );
private:
/// Timer for fsc fading-out
OSTimer *m_pTimer;
......
......@@ -199,3 +199,10 @@ void GenericWindow::invalidateRect( int left, int top, int width, int height )
refresh( left, top, width, height );
}
}
void GenericWindow::getMonitorInfo( int* x, int* y, int* width, int* height ) const
{
OSFactory *pOsFactory = OSFactory::instance( getIntf() );
pOsFactory->getMonitorInfo( *this, x, y, width, height );
}
......@@ -103,6 +103,7 @@ public:
int getTop() const { return m_top; }
int getWidth() const { return m_width; }
int getHeight() const { return m_height; }
void getMonitorInfo( int* x, int* y, int* width, int* height ) const;
/// Give access to the visibility variable
VarBool &getVisibleVar() { return *m_pVarVisible; }
......
......@@ -120,6 +120,15 @@ public:
virtual int getScreenWidth() const = 0;
virtual int getScreenHeight() const = 0;
/// Get Monitor Information for a given Window
virtual void getMonitorInfo( const GenericWindow &rWindow,
int* x, int* y,
int* width, int* height ) const = 0;
/// Get Monitor Information (screens numbered from 0 upwards.)
virtual void getMonitorInfo( int num, int* x, int* y,
int* width, int* height ) const = 0;
/// Get the work area (screen area without taskbars)
virtual SkinsRect getWorkArea() const = 0;
......
......@@ -277,6 +277,22 @@ void VoutManager::setFullscreenWnd( vout_window_t *pWnd, bool b_fullscreen )
msg_Dbg( pWnd, "setFullscreen (%i) received from vout thread",
b_fullscreen );
// reconfigure the fullscreen window (multiple screens)
if( b_fullscreen )
{
vector<SavedWnd>::iterator it;
for( it = m_SavedWndVec.begin(); it != m_SavedWndVec.end(); ++it )
{
if( (*it).pWnd == pWnd )
{
VoutWindow* pVoutWindow = it->pVoutWindow;
configureFullscreen( *pVoutWindow );
}
break;
}
}
// set fullscreen
VlcProc::instance( getIntf() )->setFullscreenVar( b_fullscreen );
}
......@@ -294,3 +310,36 @@ void VoutManager::onUpdate( Subject<VarBool> &rVariable, void *arg )
}
}
void VoutManager::configureFullscreen( VoutWindow& rWindow )
{
int numScr = var_InheritInteger( getIntf(), "qt-fullscreen-screennumber" );
int x0 = m_pVoutMainWindow->getTop();
int y0 = m_pVoutMainWindow->getLeft();
int x, y, w, h;
if( numScr >= 0 )
{
// select screen requested by user
OSFactory *pOsFactory = OSFactory::instance( getIntf() );
pOsFactory->getMonitorInfo( numScr, &x, &y, &w, &h );
}
else
{
// select screen where display is already occurring
rWindow.getMonitorInfo( &x, &y, &w, &h );
}
if( x != x0 || y != y0 )
{
// move and resize fullscreen
m_pVoutMainWindow->move( x, y );
m_pVoutMainWindow->resize( w, h );
// ensure the fs controller is also moved
if( m_pFscWindow )
{
m_pFscWindow->moveTo( x, y, w, h );
}
}
}
......@@ -34,6 +34,7 @@
#include "../controls/ctrl_video.hpp"
#include "../events/evt_key.hpp"
#include "../events/evt_scroll.hpp"
#include "../src/fsc_window.hpp"
class VarBool;
class GenericWindow;
......@@ -147,6 +148,9 @@ public:
/// called when fullscreen variable changed
virtual void onUpdate( Subject<VarBool> &rVariable , void* );
/// reconfigure fullscreen (multiple screens)
virtual void configureFullscreen( VoutWindow& rWindow );
protected:
// Protected because it is a singleton
VoutManager( intf_thread_t *pIntf );
......
......@@ -47,6 +47,7 @@ public:
using GenericWindow::move;
using GenericWindow::resize;
using GenericWindow::getOSHandle;
using GenericWindow::getMonitorInfo;
//@}
/// get the parent window
......
......@@ -127,6 +127,16 @@ LRESULT CALLBACK Win32Factory::Win32Proc( HWND hwnd, UINT uMsg,
}
BOOL CALLBACK Win32Factory::MonitorEnumProc( HMONITOR hMonitor, HDC hdcMonitor,
LPRECT lprcMonitor, LPARAM dwData )
{
(void)hdcMonitor; (void)lprcMonitor;
list<HMONITOR>* pList = (list<HMONITOR>*)dwData;
pList->push_back( hMonitor );
return TRUE;
}
Win32Factory::Win32Factory( intf_thread_t *pIntf ):
OSFactory( pIntf ), m_hParentWindow( NULL ),
m_dirSep( "\\" )
......@@ -231,6 +241,24 @@ bool Win32Factory::init()
m_resourcePath.push_back( (string)datadir + "\\share\\skins2" );
free( datadir );
// Enumerate all monitors available
EnumDisplayMonitors( NULL, NULL, MonitorEnumProc, (LPARAM)&m_monitorList );
int num = 0;
for( list<HMONITOR>::iterator it = m_monitorList.begin();
it != m_monitorList.end(); ++it, num++ )
{
MONITORINFO mi;
mi.cbSize = sizeof( MONITORINFO );
if( GetMonitorInfo( *it, &mi ) )
{
msg_Dbg( getIntf(), "monitor #%i, %ldx%ld at +%ld+%ld", num,
mi.rcMonitor.right - mi.rcMonitor.left,
mi.rcMonitor.bottom - mi.rcMonitor.top,
mi.rcMonitor.left,
mi.rcMonitor.top );
}
}
// All went well
return true;
}
......@@ -354,6 +382,63 @@ int Win32Factory::getScreenHeight() const
}
void Win32Factory::getMonitorInfo( const GenericWindow &rWindow,
int* p_x, int* p_y,
int* p_width, int* p_height ) const
{
HWND wnd = (HWND)rWindow.getOSHandle();
HMONITOR hmon = MonitorFromWindow( wnd, MONITOR_DEFAULTTONEAREST );
MONITORINFO mi;
mi.cbSize = sizeof( MONITORINFO );
if( hmon && GetMonitorInfo( hmon, &mi ) )
{
*p_x = mi.rcMonitor.left;
*p_y = mi.rcMonitor.top;
*p_width = mi.rcMonitor.right - mi.rcMonitor.left;
*p_height = mi.rcMonitor.bottom - mi.rcMonitor.top;
}
else
{
*p_x = 0;
*p_y = 0;
*p_width = getScreenWidth();
*p_height = getScreenHeight();
}
}
void Win32Factory::getMonitorInfo( int numScreen, int* p_x, int* p_y,
int* p_width, int* p_height ) const
{
HMONITOR hmon = NULL;
list<HMONITOR>::const_iterator it = m_monitorList.begin();
for( int i = 0; it != m_monitorList.end(); ++it, i++ )
{
if( i == numScreen )
{
hmon = *it;
break;
}
}
MONITORINFO mi;
mi.cbSize = sizeof( MONITORINFO );
if( hmon && GetMonitorInfo( hmon, &mi ) )
{
*p_x = mi.rcMonitor.left;
*p_y = mi.rcMonitor.top;
*p_width = mi.rcMonitor.right - mi.rcMonitor.left;
*p_height = mi.rcMonitor.bottom - mi.rcMonitor.top;
}
else
{
*p_x = 0;
*p_y = 0;
*p_width = getScreenWidth();
*p_height = getScreenHeight();
}
}
SkinsRect Win32Factory::getWorkArea() const
{
RECT r;
......
......@@ -101,6 +101,14 @@ public:
virtual int getScreenWidth() const;
virtual int getScreenHeight() const;
/// Get Monitor Information
virtual void getMonitorInfo( const GenericWindow &rWindow,
int* x, int* y,
int* width, int* height ) const;
virtual void getMonitorInfo( int numScreen,
int* x, int* y,
int* width, int* height ) const;
/// Get the work area (screen area without taskbars)
virtual SkinsRect getWorkArea() const;
......@@ -122,6 +130,9 @@ public:
static LRESULT CALLBACK Win32Proc( HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam );
/// Callback (enumerate multiple screens)
static BOOL CALLBACK MonitorEnumProc( HMONITOR hMonitor, HDC hdcMonitor,
LPRECT lprcMonitor, LPARAM dwData );
private:
/// Handle of the instance
HINSTANCE m_hInst;
......@@ -137,6 +148,8 @@ private:
const string m_dirSep;
/// Resource path
list<string> m_resourcePath;
/// Monitors detected
list<HMONITOR> m_monitorList;
};
......
......@@ -28,6 +28,7 @@
#include <dirent.h>
#include <sys/stat.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xinerama.h>
#include "x11_factory.hpp"
#include "x11_display.hpp"
......@@ -90,6 +91,9 @@ bool X11Factory::init()
m_resourcePath.push_back( (string)datadir + "/skins2" );
free( datadir );
// Determine the monitor geometry
getDefaultGeometry( &m_screenWidth, &m_screenHeight );
return true;
}
......@@ -171,17 +175,130 @@ OSPopup *X11Factory::createOSPopup()
int X11Factory::getScreenWidth() const
{
Display *pDisplay = m_pDisplay->getDisplay();
int screen = DefaultScreen( pDisplay );
return DisplayWidth( pDisplay, screen );
return m_screenWidth;
}
int X11Factory::getScreenHeight() const
{
return m_screenHeight;
}
void X11Factory::getMonitorInfo( const GenericWindow &rWindow,
int* p_x, int* p_y,
int* p_width, int* p_height ) const
{
// initialize to default geometry
*p_x = 0;
*p_y = 0;
*p_width = getScreenWidth();
*p_height = getScreenHeight();
// Use Xinerama to determine the monitor where the video
// mostly resides (biggest surface)
Display *pDisplay = m_pDisplay->getDisplay();
Window wnd = (Window)rWindow.getOSHandle();
Window root = DefaultRootWindow( pDisplay );
Window child_wnd;
int x, y;
unsigned int w, h, border, depth;
XGetGeometry( pDisplay, wnd, &root, &x, &y, &w, &h, &border, &depth );
XTranslateCoordinates( pDisplay, wnd, root, 0, 0, &x, &y, &child_wnd );
int num;
XineramaScreenInfo* info = XineramaQueryScreens( pDisplay, &num );
if( info )
{
unsigned int surface = 0;
for( int i = 0; i < num; i++ )
{
Region reg1 = XCreateRegion();
XRectangle rect1 = { info[i].x_org, info[i].y_org,
info[i].width, info[i].height };
XUnionRectWithRegion( &rect1, reg1, reg1 );
Region reg2 = XCreateRegion();
XRectangle rect2 = { x, y, w, h };
XUnionRectWithRegion( &rect2, reg2, reg2 );
Region reg = XCreateRegion();
XIntersectRegion( reg1, reg2, reg );
XRectangle rect;
XClipBox( reg, &rect );
unsigned int surf = rect.width * rect.height;
if( surf > surface )
{
surface = surf;
*p_x = info[i].x_org;
*p_y = info[i].y_org;
*p_width = info[i].width;
*p_height = info[i].height;
}
}
XFree( info );
}
}
void X11Factory::getMonitorInfo( int numScreen,
int* p_x, int* p_y,
int* p_width, int* p_height ) const
{
// initialize to default geometry
*p_x = 0;
*p_y = 0;
*p_width = getScreenWidth();
*p_height = getScreenHeight();
// try to detect the requested screen via Xinerama
if( numScreen >= 0 )
{
int num;
Display *pDisplay = m_pDisplay->getDisplay();
XineramaScreenInfo* info = XineramaQueryScreens( pDisplay, &num );
if( info )
{
if( numScreen < num )
{
*p_x = info[numScreen].x_org;
*p_y = info[numScreen].y_org;
*p_width = info[numScreen].width;
*p_height = info[numScreen].height;
}
XFree( info );
}
}
}
void X11Factory::getDefaultGeometry( int* p_width, int* p_height ) const
{
Display *pDisplay = m_pDisplay->getDisplay();
// Initialize to defaults
int screen = DefaultScreen( pDisplay );
return DisplayHeight( pDisplay, screen );
*p_width = DisplayWidth( pDisplay, screen );
*p_height = DisplayHeight( pDisplay, screen );
// Use Xinerama to restrain to the first monitor instead of the full
// virtual screen
int num;
XineramaScreenInfo* info = XineramaQueryScreens( pDisplay, &num );
if( info )
{
for( int i = 0; i < num; i++ )
{
if( info[i].x_org == 0 && info[i].y_org == 0 )
{
*p_width = info[i].width;
*p_height = info[i].height;
break;
}
}
XFree( info );
}
}
......@@ -244,5 +361,4 @@ void X11Factory::rmDir( const string &rPath )
rmdir( rPath.c_str() );
}
#endif
......@@ -127,6 +127,16 @@ public:
virtual int getScreenWidth() const;
virtual int getScreenHeight() const;
/// Get Monitor Information
virtual void getMonitorInfo( const GenericWindow &rWindow,
int* x, int* y,
int* width, int* height ) const;
virtual void getMonitorInfo( int numScreen,
int* x, int* y,
int* width, int* height ) const;
virtual void getDefaultGeometry( int* width, int* height ) const;
/// Get the work area (screen area without taskbars)
virtual SkinsRect getWorkArea() const;
......@@ -152,6 +162,8 @@ private:
const string m_dirSep;
/// Resource path
list<string> m_resourcePath;
/// Monitor geometry
int m_screenWidth, m_screenHeight;
};
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment