Permalink
Browse files

X11: support multiple xrandr displays

  • Loading branch information...
1 parent 18311d8 commit 0b80d6580d86b09b3d6cb9a4f32d61cd39ad97b6 @elupus committed Jul 15, 2012
Showing with 137 additions and 83 deletions.
  1. +117 −28 xbmc/windowing/X11/WinSystemX11.cpp
  2. +4 −1 xbmc/windowing/X11/WinSystemX11.h
  3. +15 −44 xbmc/windowing/X11/XRandR.cpp
  4. +1 −10 xbmc/windowing/X11/XRandR.h
@@ -43,6 +43,27 @@
using namespace std;
+static bool SetOutputMode(RESOLUTION_INFO& res)
+{
+#if defined(HAS_XRANDR)
+ XOutput out;
+ XMode mode = g_xrandr.GetCurrentMode(res.strOutput);
+
+ /* mode matches so we are done */
+ if(res.strId == mode.id)
+ return false;
+
+ /* set up mode */
+ out.name = res.strOutput;
+ mode.w = res.iWidth;
+ mode.h = res.iHeight;
+ mode.hz = res.fRefreshRate;
+ mode.id = res.strId;
+ g_xrandr.SetMode(out, mode);
+ return true;
+#endif
+}
+
CWinSystemX11::CWinSystemX11() : CWinSystemBase()
{
m_eWindowSystem = WINDOW_SYSTEM_X11;
@@ -55,6 +76,8 @@ CWinSystemX11::CWinSystemX11() : CWinSystemBase()
m_minimized = false;
m_dpyLostTime = 0;
m_invisibleCursor = 0;
+ m_outputName = "";
+ m_outputIndex = 0;
XSetErrorHandler(XErrorHandler);
}
@@ -81,11 +104,9 @@ bool CWinSystemX11::InitWindowSystem()
bool CWinSystemX11::DestroyWindowSystem()
{
-#if defined(HAS_XRANDR)
//restore videomode on exit
if (m_bFullScreen)
- g_xrandr.RestoreState();
-#endif
+ SetOutputMode(g_settings.m_ResInfo[DesktopResolution(m_outputIndex)]);
if (m_visual)
{
@@ -255,6 +276,7 @@ static Pixmap AllocateIconPixmap(Display* dpy, Window w)
bool CWinSystemX11::CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction)
{
+ int x = 0, y = 0;
if (m_wmWindow)
{
@@ -271,6 +293,15 @@ bool CWinSystemX11::CreateNewWindow(const CStdString& name, bool fullScreen, RES
XSetWindowAttributes swa = {0};
+#if defined(HAS_XRANDR)
+ XOutput out = g_xrandr.GetOutput(res.strOutput);
+ if(out.isConnected)
+ {
+ x = out.x;
+ y = out.y;
+ }
+#endif
+
swa.override_redirect = False;
swa.border_pixel = fullScreen ? 0 : 5;
@@ -284,7 +315,7 @@ bool CWinSystemX11::CreateNewWindow(const CStdString& name, bool fullScreen, RES
EnterWindowMask | LeaveWindowMask | ExposureMask;
m_wmWindow = XCreateWindow(m_dpy, RootWindow(m_dpy, m_visual->screen),
- 0, 0,
+ x, y,
res.iWidth, res.iHeight,
0, m_visual->depth,
InputOutput, m_visual->visual,
@@ -394,25 +425,20 @@ bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int n
bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays)
{
+ bool changed = false;
+ /* if we switched outputs or went to desktop, restore old resolution */
+ if(m_bFullScreen && (m_outputName != res.strOutput || !fullScreen))
+ changed |= SetOutputMode(g_settings.m_ResInfo[DesktopResolution(m_outputIndex)]);
-#if defined(HAS_XRANDR)
- XOutput out;
- XMode mode;
- out.name = res.strOutput;
- mode.w = res.iWidth;
- mode.h = res.iHeight;
- mode.hz = res.fRefreshRate;
- mode.id = res.strId;
-
- if(m_bFullScreen)
+ /* setup wanted mode on wanted display */
+ if(fullScreen)
+ changed |= SetOutputMode(res);
+
+ if(changed)
{
+ CLog::Log(LOGNOTICE, "CWinSystemX11::SetFullScreen - modes changed, reset device");
OnLostDevice();
- g_xrandr.SetMode(out, mode);
}
- else
- g_xrandr.RestoreState();
-#endif
-
XSetWindowAttributes attr = {0};
if(fullScreen)
@@ -422,6 +448,14 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl
XChangeWindowAttributes(m_dpy, m_wmWindow, CWBorderPixel, &attr);
int x = 0, y = 0;
+#if defined(HAS_XRANDR)
+ XOutput out = g_xrandr.GetOutput(res.strOutput);
+ if(out.isConnected)
+ {
+ x = out.x;
+ y = out.y;
+ }
+#endif
XWindowAttributes attr2;
XGetWindowAttributes(m_dpy, m_wmWindow, &attr2);
@@ -476,39 +510,56 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl
RefreshWindowState();
m_bFullScreen = fullScreen;
+ m_outputName = res.strOutput;
+ m_outputIndex = res.iScreen;
return true;
}
void CWinSystemX11::UpdateResolutions()
{
CWinSystemBase::UpdateResolutions();
+ // erase previous stored modes
+ if (g_settings.m_ResInfo.size() > (unsigned)RES_DESKTOP)
+ {
+ g_settings.m_ResInfo.erase(g_settings.m_ResInfo.begin()+RES_DESKTOP
+ , g_settings.m_ResInfo.end());
+ }
#if defined(HAS_XRANDR)
- if(g_xrandr.Query())
+ // add desktop modes
+ g_xrandr.Query(true);
+ std::vector<XOutput> outs = g_xrandr.GetModes();
+ if(outs.size() > 0)
{
- XOutput out = g_xrandr.GetCurrentOutput();
- XMode mode = g_xrandr.GetCurrentMode(out.name);
- UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, mode.w, mode.h, mode.hz);
- g_settings.m_ResInfo[RES_DESKTOP].strId = mode.id;
- g_settings.m_ResInfo[RES_DESKTOP].strOutput = out.name;
+ for(unsigned i = 0; i < outs.size(); ++i)
+ {
+ XOutput out = outs[i];
+ XMode mode = g_xrandr.GetCurrentMode(out.name);
+ RESOLUTION_INFO res;
+
+ UpdateDesktopResolution(res, i, mode.w, mode.h, mode.hz);
+ res.strId = mode.id;
+ res.strOutput = out.name;
+ g_settings.m_ResInfo.push_back(res);
+ }
}
else
#endif
{
+ RESOLUTION_INFO res;
int x11screen = DefaultScreen(m_dpy);
int w = DisplayWidth(m_dpy, x11screen);
int h = DisplayHeight(m_dpy, x11screen);
- UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, w, h, 0.0);
+ UpdateDesktopResolution(res, 0, w, h, 0.0);
+ g_settings.m_ResInfo.push_back(res);
}
#if defined(HAS_XRANDR)
CLog::Log(LOGINFO, "Available videomodes (xrandr):");
vector<XOutput>::iterator outiter;
- vector<XOutput> outs;
- outs = g_xrandr.GetModes();
CLog::Log(LOGINFO, "Number of connected outputs: %"PRIdS"", outs.size());
string modename = "";
@@ -536,6 +587,7 @@ void CWinSystemX11::UpdateResolutions()
res.strMode.Format("%s: %s @ %.2fHz", out.name.c_str(), mode.name.c_str(), mode.hz);
res.strOutput = out.name;
res.strId = mode.id;
+ res.iScreen = outiter - outs.begin();
res.iSubtitles = (int)(0.95*mode.h);
res.fRefreshRate = mode.hz;
res.bFullScreen = true;
@@ -553,6 +605,43 @@ void CWinSystemX11::UpdateResolutions()
}
+int CWinSystemX11::GetNumScreens()
+{
+#if defined(HAS_XRANDR)
+ int count = g_xrandr.GetModes().size();
+ if(count > 0)
+ return count;
+ else
+ return 0;
+#else
+ return 1;
+#endif
+}
+
+int CWinSystemX11::GetCurrentScreen()
+{
+
+#if defined(HAS_XRANDR)
+ std::vector<XOutput> outs = g_xrandr.GetModes();
+ int best_index = -1;
+ int best_overlap = 0;
+ for(unsigned i = 0; i < outs.size(); ++i)
+ {
+ XOutput out = outs[i];
+
+ int w = std::max(0, std::min(m_nLeft + m_nWidth , out.x + out.w) - std::max(m_nLeft, out.x));
+ int h = std::max(0, std::min(m_nTop + m_nHeight, out.y + out.h) - std::max(m_nTop , out.y));
+ if(w*h > best_overlap)
+ best_index = i;
+ }
+
+ if(best_index >= 0)
+ return best_index;
+#endif
+
+ return m_outputIndex;
+}
+
void CWinSystemX11::RefreshWindowState()
{
XWindowAttributes attr;
@@ -46,7 +46,8 @@ class CWinSystemX11 : public CWinSystemBase
virtual bool ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop);
virtual bool SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays);
virtual void UpdateResolutions();
- virtual int GetNumScreens() { return 1; }
+ virtual int GetNumScreens();
+ virtual int GetCurrentScreen();
virtual void ShowOSMouse(bool show);
virtual void ResetOSScreensaver();
virtual bool EnableFrameLimiter();
@@ -93,6 +94,8 @@ class CWinSystemX11 : public CWinSystemBase
CCriticalSection m_resourceSection;
std::vector<IDispResource*> m_resources;
uint64_t m_dpyLostTime;
+ CStdString m_outputName;
+ int m_outputIndex;
private:
bool IsSuitableVisual(XVisualInfo *vInfo);
@@ -116,7 +116,6 @@ bool CXRandR::Query(bool force)
xoutput.modes.push_back(xmode);
if (xmode.isCurrent)
{
- m_current.push_back(xoutput);
hascurrent = true;
}
}
@@ -130,41 +129,14 @@ bool CXRandR::Query(bool force)
std::vector<XOutput> CXRandR::GetModes(void)
{
- Query();
return m_outputs;
}
-void CXRandR::SaveState()
-{
- Query(true);
-}
-
-void CXRandR::RestoreState()
-{
- vector<XOutput>::iterator outiter;
- for (outiter=m_current.begin() ; outiter!=m_current.end() ; outiter++)
- {
- vector<XMode> modes = (*outiter).modes;
- vector<XMode>::iterator modeiter;
- for (modeiter=modes.begin() ; modeiter!=modes.end() ; modeiter++)
- {
- XMode mode = *modeiter;
- if (mode.isCurrent)
- {
- SetMode(*outiter, mode);
- return;
- }
- }
- }
-}
-
bool CXRandR::SetMode(XOutput output, XMode mode)
{
- if ((output.name == m_currentOutput && mode.id == m_currentMode) || (output.name == "" && mode.id == ""))
+ if (output.name == "" && mode.id == "")
return true;
- Query();
-
// Make sure the output exists, if not -- complain and exit
bool isOutputFound = false;
XOutput outputFound;
@@ -241,8 +213,6 @@ bool CXRandR::SetMode(XOutput output, XMode mode)
return false;
}
- m_currentOutput = outputFound.name;
- m_currentMode = modeFound.id;
char cmd[255];
if (getenv("XBMC_BIN_HOME"))
snprintf(cmd, sizeof(cmd), "%s/xbmc-xrandr --output %s --mode %s", getenv("XBMC_BIN_HOME"), outputFound.name.c_str(), modeFound.id.c_str());
@@ -259,20 +229,8 @@ bool CXRandR::SetMode(XOutput output, XMode mode)
return true;
}
-XOutput CXRandR::GetCurrentOutput()
-{
- Query();
- for (unsigned int j = 0; j < m_outputs.size(); j++)
- {
- if(m_outputs[j].isConnected)
- return m_outputs[j];
- }
- XOutput empty;
- return empty;
-}
XMode CXRandR::GetCurrentMode(CStdString outputName)
{
- Query();
XMode result;
for (unsigned int j = 0; j < m_outputs.size(); j++)
@@ -295,7 +253,6 @@ XMode CXRandR::GetCurrentMode(CStdString outputName)
void CXRandR::LoadCustomModeLinesToAllOutputs(void)
{
- Query();
CXBMCTinyXML xmlDoc;
if (!xmlDoc.LoadFile("special://xbmc/userdata/ModeLines.xml"))
@@ -343,6 +300,20 @@ void CXRandR::LoadCustomModeLinesToAllOutputs(void)
}
}
+XOutput CXRandR::GetOutput(CStdString outputName)
+{
+ XOutput result;
+ for (unsigned int i = 0; i < m_outputs.size(); ++i)
+ {
+ if (m_outputs[i].name == outputName)
+ {
+ result = m_outputs[i];
+ break;
+ }
+ }
+ return result;
+}
+
CXRandR g_xrandr;
#endif // HAS_XRANDR
Oops, something went wrong.

0 comments on commit 0b80d65

Please sign in to comment.