Skip to content

Commit

Permalink
[x11] [multimon] feature: find the screen a window is on
Browse files Browse the repository at this point in the history
Introduce parity to X11 from Windows. Respect per-monitor bounds.
  • Loading branch information
ajerick authored and dacap committed Sep 12, 2024
1 parent d5b0691 commit a80b525
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 7 deletions.
46 changes: 44 additions & 2 deletions os/x11/monitor.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
#include "monitor.h"
#include "os/x11/monitor.h"
#include "gfx/rect.h"
#include "os/ref.h"
#include "os/screen.h"
#include "os/x11/x11.h"
#include "os/x11/screen.h"

#include <climits>
#include <algorithm>
#include <X11/extensions/Xrandr.h>

namespace os {
Expand All @@ -18,7 +24,43 @@ MonitorsX11::MonitorsX11()

int MonitorsX11::numMonitors() const { return m_numMonitors; }

const XRRMonitorInfo& MonitorsX11::monitor(int monitorNum) const { return m_monitors.get()[monitorNum]; }
const XRRMonitorInfo& MonitorsX11::monitorInfo(int monitorNum) const { return m_monitors.get()[monitorNum]; }

// searches for the monitor containing the most area of the window
ScreenRef MonitorsX11::nearestMonitorOf(const gfx::Rect& frame) const
{
ScreenRef candidate = nullptr;
int most_area = INT_MIN;

for (int nmonitor=0; nmonitor<m_numMonitors; nmonitor++) {
ScreenRef monitor = os::make_ref<ScreenX11>(nmonitor);

const gfx::Rect& bounds = monitor->bounds();
gfx::Rect segment(frame);
if (segment.x < bounds.x) {
segment.w = std::max(0, segment.w - (bounds.x-segment.x));
segment.x = bounds.x;
}
if (segment.x2() > bounds.x2()) {
segment.w = std::max(0, segment.w - (segment.x2()-bounds.x2()));
}
if (segment.y < bounds.y) {
segment.h = std::max(0, segment.h - (bounds.y-segment.y));
segment.y = bounds.y;
}
if (segment.y2() > bounds.y2()) {
segment.h = std::max(0, segment.h - (segment.y2()-bounds.y2()));
}

int area = segment.w*segment.h;
if (area > most_area) {
candidate = monitor;
most_area = area;
}
}

return candidate;
}

} // namespace os

10 changes: 8 additions & 2 deletions os/x11/monitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
#define MONITOR_H
#pragma once

#include <memory>
#include "gfx/fwd.h"
#include "os/screen.h"

#include <X11/extensions/Xrandr.h>
#include <memory>

namespace os {

Expand All @@ -16,8 +19,11 @@ typedef std::unique_ptr<XRRMonitorInfo, MonitorCloser> unique_monitors_ptr;
class MonitorsX11 {
public:
MonitorsX11();

int numMonitors() const;
const XRRMonitorInfo& monitor(int monitorNum) const;
const XRRMonitorInfo& monitorInfo(int monitorNum) const;

ScreenRef nearestMonitorOf(const gfx::Rect& frame) const;

private:
int m_numMonitors;
Expand Down
3 changes: 2 additions & 1 deletion os/x11/screen.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "os/screen.h"
#include "os/x11/monitor.h"
#include "os/x11/x11.h"
#include "os/system.h"

#include <X11/extensions/Xrandr.h>

Expand All @@ -20,7 +21,7 @@ class ScreenX11 : public Screen {
public:
ScreenX11(int monitorNum) : m_monitorNum(monitorNum) {
MonitorsX11* monitors = X11::instance()->monitors();
const XRRMonitorInfo& monitor = monitors->monitor(monitorNum);
const XRRMonitorInfo& monitor = monitors->monitorInfo(monitorNum);

m_bounds.x = monitor.x;
m_bounds.y = monitor.y;
Expand Down
2 changes: 1 addition & 1 deletion os/x11/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class SystemX11 : public CommonSystem {

// we have to search for the primary monitor
for (int monitor=0; monitor<numMonitors; monitor++) {
if (monitors->monitor(monitor).primary) {
if (monitors->monitorInfo(monitor).primary) {
return make_ref<ScreenX11>(monitor);
}
}
Expand Down
6 changes: 5 additions & 1 deletion os/x11/window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,11 @@ WindowX11::~WindowX11()

os::ScreenRef WindowX11::screen() const
{
return os::instance()->mainScreen();
ScreenRef nearestMonitor = X11::instance()->monitors()->nearestMonitorOf(frame());
if (nearestMonitor)
return nearestMonitor;
else
return os::instance()->mainScreen();
}

os::ColorSpaceRef WindowX11::colorSpace() const
Expand Down

0 comments on commit a80b525

Please sign in to comment.