Skip to content

Commit

Permalink
#1761: move display management code to a mixin
Browse files Browse the repository at this point in the history
git-svn-id: https://xpra.org/svn/Xpra/trunk@18555 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Feb 23, 2018
1 parent e966c9e commit f518d53
Show file tree
Hide file tree
Showing 2 changed files with 252 additions and 217 deletions.
243 changes: 243 additions & 0 deletions src/xpra/server/mixins/display_manager.py
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,
})
Loading

0 comments on commit f518d53

Please sign in to comment.