-
-
Notifications
You must be signed in to change notification settings - Fork 180
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#1761: move display management code to a mixin
git-svn-id: https://xpra.org/svn/Xpra/trunk@18555 3bb7dfac-3a0b-4e04-842a-767bc560f471
- Loading branch information
Showing
2 changed files
with
252 additions
and
217 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,243 @@ | ||
# -*- coding: utf-8 -*- | ||
# This file is part of Xpra. | ||
# Copyright (C) 2010-2018 Antoine Martin <antoine@devloop.org.uk> | ||
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any | ||
# later version. See the file COPYING for details. | ||
|
||
import os | ||
|
||
from xpra.log import Logger | ||
log = Logger("screen") | ||
|
||
from xpra.util import iround, log_screen_sizes, engs | ||
from xpra.server.mixins.stub_server_mixin import StubServerMixin | ||
from xpra.scripts.config import parse_bool_or_int | ||
|
||
|
||
SAVE_PRINT_JOBS = os.environ.get("XPRA_SAVE_PRINT_JOBS", None) | ||
|
||
|
||
""" | ||
Mixin for servers that can handle mmap transfers | ||
""" | ||
class DisplayManager(StubServerMixin): | ||
|
||
def __init__(self): | ||
self.randr = False | ||
self.bell = False | ||
self.cursors = False | ||
self.default_dpi = 96 | ||
self.dpi = 0 | ||
self.xdpi = 0 | ||
self.ydpi = 0 | ||
self.antialias = {} | ||
self.cursor_size = 0 | ||
self.double_click_time = -1 | ||
self.double_click_distance = -1, -1 | ||
self.scaling_control = False | ||
|
||
def init(self, opts): | ||
self.bell = opts.bell | ||
self.cursors = opts.cursors | ||
self.default_dpi = int(opts.dpi) | ||
self.scaling_control = parse_bool_or_int("video-scaling", opts.video_scaling) | ||
|
||
|
||
def get_info(self, _proto): | ||
return {} | ||
|
||
|
||
###################################################################### | ||
# display / screen / root window: | ||
def set_screen_geometry_attributes(self, w, h): | ||
#by default, use the screen as desktop area: | ||
self.set_desktop_geometry_attributes(w, h) | ||
|
||
def set_desktop_geometry_attributes(self, w, h): | ||
self.calculate_desktops() | ||
self.calculate_workarea(w, h) | ||
self.set_desktop_geometry(w, h) | ||
|
||
|
||
def parse_screen_info(self, ss): | ||
return self.do_parse_screen_info(ss, ss.desktop_size) | ||
|
||
def do_parse_screen_info(self, ss, desktop_size): | ||
log("do_parse_screen_info%s", (ss, desktop_size)) | ||
dw, dh = None, None | ||
if desktop_size: | ||
try: | ||
dw, dh = desktop_size | ||
if not ss.screen_sizes: | ||
log.info(" client root window size is %sx%s", dw, dh) | ||
else: | ||
log.info(" client root window size is %sx%s with %s display%s:", dw, dh, len(ss.screen_sizes), engs(ss.screen_sizes)) | ||
log_screen_sizes(dw, dh, ss.screen_sizes) | ||
except: | ||
dw, dh = None, None | ||
sw, sh = self.configure_best_screen_size() | ||
log("configure_best_screen_size()=%s", (sw, sh)) | ||
#we will tell the client about the size chosen in the hello we send back, | ||
#so record this size as the current server desktop size to avoid change notifications: | ||
ss.desktop_size_server = sw, sh | ||
#prefer desktop size, fallback to screen size: | ||
w = dw or sw | ||
h = dh or sh | ||
#clamp to max supported: | ||
maxw, maxh = self.get_max_screen_size() | ||
w = min(w, maxw) | ||
h = min(h, maxh) | ||
self.set_desktop_geometry_attributes(w, h) | ||
self.set_icc_profile() | ||
return w, h | ||
|
||
|
||
def set_icc_profile(self): | ||
log("set_icc_profile() not implemented") | ||
|
||
def reset_icc_profile(self): | ||
log("reset_icc_profile() not implemented") | ||
|
||
def _screen_size_changed(self, screen): | ||
log("_screen_size_changed(%s)", screen) | ||
#randr has resized the screen, tell the client (if it supports it) | ||
w, h = screen.get_width(), screen.get_height() | ||
log("new screen dimensions: %ix%i", w, h) | ||
self.set_screen_geometry_attributes(w, h) | ||
self.idle_add(self.send_updated_screen_size) | ||
|
||
def get_root_window_size(self): | ||
raise NotImplementedError() | ||
|
||
def send_updated_screen_size(self): | ||
max_w, max_h = self.get_max_screen_size() | ||
root_w, root_h = self.get_root_window_size() | ||
root_w = min(root_w, max_w) | ||
root_h = min(root_h, max_h) | ||
count = 0 | ||
for ss in self._server_sources.values(): | ||
if ss.updated_desktop_size(root_w, root_h, max_w, max_h): | ||
count +=1 | ||
if count>0: | ||
log.info("sent updated screen size to %s client%s: %sx%s (max %sx%s)", count, engs(count), root_w, root_h, max_w, max_h) | ||
|
||
def get_max_screen_size(self): | ||
max_w, max_h = self.get_root_window_size() | ||
return max_w, max_h | ||
|
||
def _get_desktop_size_capability(self, server_source, root_w, root_h): | ||
client_size = server_source.desktop_size | ||
log("client resolution is %s, current server resolution is %sx%s", client_size, root_w, root_h) | ||
if not client_size: | ||
""" client did not specify size, just return what we have """ | ||
return root_w, root_h | ||
client_w, client_h = client_size | ||
w = min(client_w, root_w) | ||
h = min(client_h, root_h) | ||
return w, h | ||
|
||
def configure_best_screen_size(self): | ||
root_w, root_h = self.get_root_window_size() | ||
return root_w, root_h | ||
|
||
def _process_desktop_size(self, proto, packet): | ||
width, height = packet[1:3] | ||
ss = self._server_sources.get(proto) | ||
if ss is None: | ||
return | ||
ss.desktop_size = (width, height) | ||
if len(packet)>=10: | ||
#added in 0.16 for scaled client displays: | ||
xdpi, ydpi = packet[8:10] | ||
if xdpi!=self.xdpi or ydpi!=self.ydpi: | ||
self.xdpi, self.ydpi = xdpi, ydpi | ||
log("new dpi: %ix%i", self.xdpi, self.ydpi) | ||
self.dpi = iround((self.xdpi + self.ydpi)/2.0) | ||
self.dpi_changed() | ||
if len(packet)>=8: | ||
#added in 0.16 for scaled client displays: | ||
ss.desktop_size_unscaled = packet[6:8] | ||
if len(packet)>=6: | ||
desktops, desktop_names = packet[4:6] | ||
ss.set_desktops(desktops, desktop_names) | ||
self.calculate_desktops() | ||
if len(packet)>=4: | ||
ss.set_screen_sizes(packet[3]) | ||
log("client requesting new size: %sx%s", width, height) | ||
self.set_screen_size(width, height) | ||
if len(packet)>=4: | ||
log.info("received updated display dimensions") | ||
log.info("client display size is %sx%s with %s screen%s:", width, height, len(ss.screen_sizes), engs(ss.screen_sizes)) | ||
log_screen_sizes(width, height, ss.screen_sizes) | ||
self.calculate_workarea(width, height) | ||
#ensures that DPI and antialias information gets reset: | ||
self.update_all_server_settings() | ||
|
||
def dpi_changed(self): | ||
pass | ||
|
||
def calculate_desktops(self): | ||
count = 1 | ||
for ss in self._server_sources.values(): | ||
if ss.desktops: | ||
count = max(count, ss.desktops) | ||
count = max(1, min(20, count)) | ||
names = [] | ||
for i in range(count): | ||
if i==0: | ||
name = "Main" | ||
else: | ||
name = "Desktop %s" % (i+1) | ||
for ss in self._server_sources.values(): | ||
if ss.desktops and i<len(ss.desktop_names) and ss.desktop_names[i]: | ||
name = ss.desktop_names[i] | ||
names.append(name) | ||
self.set_desktops(names) | ||
|
||
def set_desktops(self, names): | ||
pass | ||
|
||
def calculate_workarea(self, w, h): | ||
raise NotImplementedError() | ||
|
||
def set_workarea(self, workarea): | ||
pass | ||
|
||
|
||
###################################################################### | ||
# screenshots: | ||
def _process_screenshot(self, proto, _packet): | ||
packet = self.make_screenshot_packet() | ||
ss = self._server_sources.get(proto) | ||
if packet and ss: | ||
ss.send(*packet) | ||
|
||
def make_screenshot_packet(self): | ||
try: | ||
return self.do_make_screenshot_packet() | ||
except: | ||
log.error("make_screenshot_packet()", exc_info=True) | ||
return None | ||
|
||
def do_make_screenshot_packet(self): | ||
raise NotImplementedError("no screenshot capability in %s" % type(self)) | ||
|
||
def send_screenshot(self, proto): | ||
#this is a screenshot request, handle it and disconnect | ||
try: | ||
packet = self.make_screenshot_packet() | ||
if not packet: | ||
self.send_disconnect(proto, "screenshot failed") | ||
return | ||
proto.send_now(packet) | ||
self.timeout_add(5*1000, self.send_disconnect, proto, "screenshot sent") | ||
except Exception as e: | ||
log.error("failed to capture screenshot", exc_info=True) | ||
self.send_disconnect(proto, "screenshot failed: %s" % e) | ||
|
||
|
||
def init_packet_handlers(self): | ||
self._authenticated_ui_packet_handlers.update({ | ||
"desktop_size": self._process_desktop_size, | ||
"screenshot": self._process_screenshot, | ||
}) |
Oops, something went wrong.