This source file includes following definitions.
- PixelsToMillimeters
- Refresh
- Release
- GetIdForMode
- GetOutput
- GetCrtc
- GetOutputInfo
- get
- exact_resize_
- GetCurrentResolution
- GetSupportedResolutions
- SetResolution
- RestoreResolution
- CreateMode
- DeleteMode
- SwitchToMode
- Create
#include "remoting/host/desktop_resizer.h"
#include "remoting/host/linux/x11_util.h"
#include <string.h>
#include <X11/extensions/Xrandr.h>
#include <X11/Xlib.h>
#include "base/command_line.h"
#include "remoting/base/logging.h"
namespace {
int PixelsToMillimeters(int pixels, int dpi) {
DCHECK(dpi != 0);
const double kMillimetersPerInch = 25.4;
return static_cast<int>(kMillimetersPerInch * pixels / dpi);
}
const int kDefaultDPI = 96;
}
namespace remoting {
class ScreenResources {
public:
ScreenResources() : resources_(NULL) {
}
~ScreenResources() {
Release();
}
bool Refresh(Display* display, Window window) {
Release();
resources_ = XRRGetScreenResources(display, window);
return resources_ != NULL;
}
void Release() {
if (resources_) {
XRRFreeScreenResources(resources_);
resources_ = NULL;
}
}
RRMode GetIdForMode(const char* name) {
CHECK(resources_);
for (int i = 0; i < resources_->nmode; ++i) {
const XRRModeInfo& mode = resources_->modes[i];
if (strcmp(mode.name, name) == 0) {
return mode.id;
}
}
return 0;
}
RROutput GetOutput() {
CHECK(resources_);
return resources_->outputs[0];
}
RRCrtc GetCrtc() {
CHECK(resources_);
return resources_->crtcs[0];
}
XRROutputInfo* GetOutputInfo(Display* display, RROutput output_id) {
CHECK(resources_);
return XRRGetOutputInfo(display, resources_, output_id);
}
XRRScreenResources* get() { return resources_; }
private:
XRRScreenResources* resources_;
};
class DesktopResizerLinux : public DesktopResizer {
public:
DesktopResizerLinux();
virtual ~DesktopResizerLinux();
virtual ScreenResolution GetCurrentResolution() OVERRIDE;
virtual std::list<ScreenResolution> GetSupportedResolutions(
const ScreenResolution& preferred) OVERRIDE;
virtual void SetResolution(const ScreenResolution& resolution) OVERRIDE;
virtual void RestoreResolution(const ScreenResolution& original) OVERRIDE;
private:
void CreateMode(const char* name, int width, int height);
void DeleteMode(const char* name);
void SwitchToMode(const char* name);
Display* display_;
int screen_;
Window root_;
ScreenResources resources_;
bool exact_resize_;
DISALLOW_COPY_AND_ASSIGN(DesktopResizerLinux);
};
DesktopResizerLinux::DesktopResizerLinux()
: display_(XOpenDisplay(NULL)),
screen_(DefaultScreen(display_)),
root_(RootWindow(display_, screen_)),
exact_resize_(CommandLine::ForCurrentProcess()->
HasSwitch("server-supports-exact-resize")) {
XRRSelectInput (display_, root_, RRScreenChangeNotifyMask);
}
DesktopResizerLinux::~DesktopResizerLinux() {
XCloseDisplay(display_);
}
ScreenResolution DesktopResizerLinux::GetCurrentResolution() {
if (!exact_resize_) {
return ScreenResolution();
}
while (XEventsQueued(display_, QueuedAlready)) {
XEvent event;
XNextEvent(display_, &event);
XRRUpdateConfiguration(&event);
}
ScreenResolution result(
webrtc::DesktopSize(
DisplayWidth(display_, DefaultScreen(display_)),
DisplayHeight(display_, DefaultScreen(display_))),
webrtc::DesktopVector(kDefaultDPI, kDefaultDPI));
return result;
}
std::list<ScreenResolution> DesktopResizerLinux::GetSupportedResolutions(
const ScreenResolution& preferred) {
std::list<ScreenResolution> result;
if (exact_resize_) {
int min_width = 0, min_height = 0, max_width = 0, max_height = 0;
XRRGetScreenSizeRange(display_, root_,
&min_width, &min_height,
&max_width, &max_height);
int width = std::min(std::max(preferred.dimensions().width(), min_width),
max_width);
int height = std::min(std::max(preferred.dimensions().height(), min_height),
max_height);
ScreenResolution actual(
webrtc::DesktopSize(std::max(640, width), std::max(480, height)),
webrtc::DesktopVector(kDefaultDPI, kDefaultDPI));
result.push_back(actual);
} else {
}
return result;
}
void DesktopResizerLinux::SetResolution(const ScreenResolution& resolution) {
if (!exact_resize_) {
return;
}
ScopedXErrorHandler handler(ScopedXErrorHandler::Ignore());
ScopedXGrabServer grabber(display_);
const char* kModeName = "Chrome Remote Desktop client resolution";
const char* kTempModeName = "Chrome Remote Desktop temporary mode";
HOST_LOG << "Changing desktop size to " << resolution.dimensions().width()
<< "x" << resolution.dimensions().height();
int width_mm = PixelsToMillimeters(resolution.dimensions().width(),
kDefaultDPI);
int height_mm = PixelsToMillimeters(resolution.dimensions().height(),
kDefaultDPI);
CreateMode(kTempModeName, resolution.dimensions().width(),
resolution.dimensions().height());
SwitchToMode(NULL);
XRRSetScreenSize(display_, root_, resolution.dimensions().width(),
resolution.dimensions().height(), width_mm, height_mm);
SwitchToMode(kTempModeName);
DeleteMode(kModeName);
CreateMode(kModeName, resolution.dimensions().width(),
resolution.dimensions().height());
SwitchToMode(kModeName);
DeleteMode(kTempModeName);
}
void DesktopResizerLinux::RestoreResolution(const ScreenResolution& original) {
}
void DesktopResizerLinux::CreateMode(const char* name, int width, int height) {
XRRModeInfo mode;
memset(&mode, 0, sizeof(mode));
mode.width = width;
mode.height = height;
mode.name = const_cast<char*>(name);
mode.nameLength = strlen(name);
XRRCreateMode(display_, root_, &mode);
if (!resources_.Refresh(display_, root_)) {
return;
}
RRMode mode_id = resources_.GetIdForMode(name);
if (!mode_id) {
return;
}
XRRAddOutputMode(display_, resources_.GetOutput(), mode_id);
}
void DesktopResizerLinux::DeleteMode(const char* name) {
RRMode mode_id = resources_.GetIdForMode(name);
if (mode_id) {
XRRDeleteOutputMode(display_, resources_.GetOutput(), mode_id);
XRRDestroyMode(display_, mode_id);
resources_.Refresh(display_, root_);
}
}
void DesktopResizerLinux::SwitchToMode(const char* name) {
RRMode mode_id = None;
RROutput* outputs = NULL;
int number_of_outputs = 0;
if (name) {
mode_id = resources_.GetIdForMode(name);
CHECK(mode_id);
outputs = resources_.get()->outputs;
number_of_outputs = resources_.get()->noutput;
}
XRRSetCrtcConfig(display_, resources_.get(), resources_.GetCrtc(),
CurrentTime, 0, 0, mode_id, 1, outputs, number_of_outputs);
}
scoped_ptr<DesktopResizer> DesktopResizer::Create() {
return scoped_ptr<DesktopResizer>(new DesktopResizerLinux);
}
}