]> git.sesse.net Git - vlc/commitdiff
skins2: fullscreen support for multiple screens (both Linux and Win32)
authorErwan Tulou <erwan10@videolan.org>
Thu, 9 Jun 2011 16:17:14 +0000 (18:17 +0200)
committerErwan Tulou <erwan10@videolan.org>
Thu, 9 Jun 2011 19:45:37 +0000 (21:45 +0200)
- 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.

13 files changed:
configure.ac
modules/gui/skins2/src/fsc_window.cpp
modules/gui/skins2/src/fsc_window.hpp
modules/gui/skins2/src/generic_window.cpp
modules/gui/skins2/src/generic_window.hpp
modules/gui/skins2/src/os_factory.hpp
modules/gui/skins2/src/vout_manager.cpp
modules/gui/skins2/src/vout_manager.hpp
modules/gui/skins2/src/vout_window.hpp
modules/gui/skins2/win32/win32_factory.cpp
modules/gui/skins2/win32/win32_factory.hpp
modules/gui/skins2/x11/x11_factory.cpp
modules/gui/skins2/x11/x11_factory.hpp

index b4f7a480d82a9800bb2ddeb82e53a4102bb46a66..f7eeb3c8ed754b7f7f1401a5a2e6d06df683797b 100644 (file)
@@ -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])
index d490f67611ab4538424f649d94f45de612c21424..ed368af0aa15f25a14c2956e0b9a3b4c3653a752 100644 (file)
@@ -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();
index 93b40b325ee33371e9c5bb41306cbbf731d60f1e..92244900484fdf05cec0343bf312114663a349b8 100644 (file)
@@ -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;
index fce0b2a4fbd8de1f7f3ddaf6161d7edb7760b893..445a3a2824696f19a90709c0b8f841b63549923c 100644 (file)
@@ -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 );
+}
index 48f9a72bd4f57bda1513ac8181678469a2301580..058dd52ecf04d2883911e33435cafb97faee669e 100644 (file)
@@ -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; }
index c4f3a8cfd5ad751579c64a37251124e1daaa756e..4dd4f5bf2cecee12b618c88834bf34fe040114fe 100644 (file)
@@ -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;
 
index 7ba61c5b5af361d29102a192a51e70c39886484d..23cb909ddc7e16ddbd453b11b41c672f61181827 100644 (file)
@@ -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 );
+        }
+    }
+}
index 60f473e6cd231b0155449f9528951cfe02dfbd6c..3d0bf39cf3b951f9d2fc75d62f2aadae7db85711 100644 (file)
@@ -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 );
index f64d033809bc2a7c812cee0a5487d2c398ddc7ab..bdd2fe62ed2b568d9f4e5267e98f1ca7b9288272 100644 (file)
@@ -47,6 +47,7 @@ public:
     using GenericWindow::move;
     using GenericWindow::resize;
     using GenericWindow::getOSHandle;
+    using GenericWindow::getMonitorInfo;
     //@}
 
     /// get the parent  window
index bf778727b619eeb5f654c81b084600b8d63ce55b..6d8e2d95257bb1f7e45d8bb4dd1ace6058611bd1 100644 (file)
@@ -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;
index 030a0d3c3cee0626839fa74ad9b57f4e1621e31e..c192cd26a0b88e95eab0422ffb1baa0335efa4ed 100644 (file)
@@ -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;
 };
 
 
index 9a28a7f9d3eed8bb723c15d46db34442af80abe9..fca747eece453f5eaed66dd34e88d07251f17913 100644 (file)
@@ -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
index e6d98c90b8cabba8732e1be3909a158c3e62e87b..3660bc1f71e6f59b474d8d973cb56d24fd9e7469 100644 (file)
@@ -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