Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
* move input handling to a mixin
* minor fixes to other mixins

git-svn-id: https://xpra.org/svn/Xpra/trunk@18575 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Feb 24, 2018
1 parent 4da5118 commit 00bb620
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 100 deletions.
109 changes: 14 additions & 95 deletions src/xpra/server/source/client_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from xpra.server.source.windows_mixin import WindowsMixin
from xpra.server.source.encodings_mixin import EncodingsMixin
from xpra.server.source.idle_mixin import IdleMixin
from xpra.make_thread import start_thread
from xpra.server.source.input_mixin import InputMixin
from xpra.os_util import monotonic_time
from xpra.util import merge_dicts, flatten_dict, notypedict, get_screen_info, envint, envbool, AtomicInteger

Expand All @@ -60,7 +60,7 @@
items are picked off by the separate 'encode' thread (see 'encode_loop')
and added to the damage_packet_queue.
"""
class ClientConnection(AudioMixin, MMAP_Connection, ClipboardConnection, FilePrintMixin, NetworkStateMixin, ClientInfoMixin, DBUS_Mixin, WindowsMixin, EncodingsMixin, IdleMixin):
class ClientConnection(AudioMixin, MMAP_Connection, ClipboardConnection, FilePrintMixin, NetworkStateMixin, ClientInfoMixin, DBUS_Mixin, WindowsMixin, EncodingsMixin, IdleMixin, InputMixin):

def __init__(self, protocol, disconnect_cb, idle_add, timeout_add, source_remove, setting_changed,
idle_timeout, idle_timeout_cb, idle_grace_timeout_cb,
Expand Down Expand Up @@ -107,19 +107,24 @@ def __init__(self, protocol, disconnect_cb, idle_add, timeout_add, source_remove
WindowsMixin.__init__(self, get_transient_for, get_focus, get_cursor_data_cb, get_window_id, window_filters)
EncodingsMixin.__init__(self, core_encodings, encodings, default_encoding, scaling_control, default_quality, default_min_quality, default_speed, default_min_speed)
IdleMixin.__init__(self, idle_timeout, idle_timeout_cb, idle_grace_timeout_cb)
InputMixin.__init__(self)

global counter
self.counter = counter.increase()
self.connection_time = monotonic_time()
self.close_event = Event()
self.ordinary_packets = []

self.protocol = protocol
self.ordinary_packets = []
self.disconnect = disconnect_cb
self.socket_dir = socket_dir
self.unix_socket_paths = unix_socket_paths
self.log_disconnect = log_disconnect
self.idle_add = idle_add
self.timeout_add = timeout_add
self.source_remove = source_remove

self.setting_changed = setting_changed
self.socket_dir = socket_dir
self.unix_socket_paths = unix_socket_paths
self.log_disconnect = log_disconnect
# network constraints:
self.server_bandwidth_limit = bandwidth_limit

Expand All @@ -131,17 +136,13 @@ def __init__(self, protocol, disconnect_cb, idle_add, timeout_add, source_remove
self.icc = None
self.display_icc = {}

self.connection_time = monotonic_time()

#these statistics are shared by all WindowSource instances:
self.statistics = GlobalPerformanceStatistics()
self.last_user_event = monotonic_time()

self.init_vars()

# ready for processing:
protocol.set_packet_source(self.next_packet)
self.encode_thread = start_thread(self.encode_loop, "encode")


def __repr__(self):
Expand All @@ -164,8 +165,6 @@ def init_vars(self):
self.desktops = 1
self.desktop_names = ()
self.control_commands = ()
self.double_click_time = -1
self.double_click_distance = -1, -1
self.bandwidth_limit = self.server_bandwidth_limit
self.soft_bandwidth_limit = self.bandwidth_limit
self.bandwidth_warnings = True
Expand All @@ -180,8 +179,6 @@ def init_vars(self):
self.wants_events = False
self.wants_default_cursor = False

self.keyboard_config = None


def is_closed(self):
return self.close_event.isSet()
Expand All @@ -191,10 +188,6 @@ def close(self):
for c in ClientConnection.__bases__:
c.cleanup(self)
self.close_event.set()
#it is now safe to add the end of queue marker:
#(all window sources will have stopped queuing data)
self.encode_work_queue.put(None)
self.cancel_recalculate_timer()
self.protocol = None


Expand Down Expand Up @@ -252,6 +245,7 @@ def parse_hello(self, c):
MMAP_Connection.parse_client_caps(self, c)
WindowsMixin.parse_client_caps(self, c)
EncodingsMixin.parse_client_caps(self, c)
InputMixin.parse_client_caps(self, c)

#general features:
self.info_namespace = c.boolget("info-namespace")
Expand All @@ -261,8 +255,6 @@ def parse_hello(self, c):
self.share = c.boolget("share")
self.lock = c.boolget("lock")
self.control_commands = c.strlistget("control_commands")
self.double_click_time = c.intget("double_click.time")
self.double_click_distance = c.intpair("double_click.distance")
bandwidth_limit = c.intget("bandwidth-limit", 0)
if self.server_bandwidth_limit<=0:
self.bandwidth_limit = bandwidth_limit
Expand Down Expand Up @@ -299,10 +291,6 @@ def parse_hello(self, c):
if msg:
proxylog.warn("Warning: proxy version may not be compatible: %s", msg)
self.update_connection_data(c.dictget("connection-data"))

#keyboard is now injected into this class, default to undefined:
self.keyboard_config = None

if self.mmap_size>0:
log("mmap enabled, ignoring bandwidth-limit")
self.bandwidth_limit = 0
Expand Down Expand Up @@ -340,63 +328,6 @@ def update_av_sync_delay_total(self):
ws.set_av_sync_delay(self.av_sync_delay_total)


######################################################################
# keyboard :
def set_layout(self, layout, variant, options):
return self.keyboard_config.set_layout(layout, variant, options)

def keys_changed(self):
if self.keyboard_config:
self.keyboard_config.compute_modifier_map()
self.keyboard_config.compute_modifier_keynames()
keylog("keys_changed() updated keyboard config=%s", self.keyboard_config)

def make_keymask_match(self, modifier_list, ignored_modifier_keycode=None, ignored_modifier_keynames=None):
if self.keyboard_config and self.keyboard_config.enabled:
self.keyboard_config.make_keymask_match(modifier_list, ignored_modifier_keycode, ignored_modifier_keynames)

def set_default_keymap(self):
keylog("set_default_keymap() keyboard_config=%s", self.keyboard_config)
if self.keyboard_config:
self.keyboard_config.set_default_keymap()
return self.keyboard_config


def set_keymap(self, current_keyboard_config, keys_pressed, force=False, translate_only=False):
keylog("set_keymap%s", (current_keyboard_config, keys_pressed, force, translate_only))
if self.keyboard_config and self.keyboard_config.enabled:
current_id = None
if current_keyboard_config and current_keyboard_config.enabled:
current_id = current_keyboard_config.get_hash()
keymap_id = self.keyboard_config.get_hash()
keylog("current keyboard id=%s, new keyboard id=%s", current_id, keymap_id)
if force or current_id is None or keymap_id!=current_id:
self.keyboard_config.keys_pressed = keys_pressed
self.keyboard_config.set_keymap(translate_only)
self.keyboard_config.owner = self.uuid
current_keyboard_config = self.keyboard_config
else:
keylog.info("keyboard mapping already configured (skipped)")
self.keyboard_config = current_keyboard_config
return current_keyboard_config


def get_keycode(self, client_keycode, keyname, modifiers):
if self.keyboard_config is None:
keylog.info("ignoring client key %s / %s since keyboard is not configured", client_keycode, keyname)
return -1
return self.keyboard_config.get_keycode(client_keycode, keyname, modifiers)


def update_mouse(self, wid, x, y, rx, ry):
mouselog("update_mouse(%s, %i, %i, %i, %i) current=%s, client=%i, show=%s", wid, x, y, rx, ry, self.mouse_last_position, self.counter, self.mouse_show)
if not self.mouse_show:
return
if self.mouse_last_position!=(x, y, rx, ry):
self.mouse_last_position = (x, y, rx, ry)
self.send_async("pointer-position", wid, x, y, rx, ry)


######################################################################
# network:
def next_packet(self):
Expand Down Expand Up @@ -441,12 +372,7 @@ def send_hello(self, server_capabilities):
merge_dicts(capabilities, MMAP_Connection.get_caps(self))
merge_dicts(capabilities, WindowsMixin.get_caps(self))
merge_dicts(capabilities, EncodingsMixin.get_caps(self))
#expose the "modifier_client_keycodes" defined in the X11 server keyboard config object,
#so clients can figure out which modifiers map to which keys:
if self.keyboard_config:
mck = getattr(self.keyboard_config, "modifier_client_keycodes", None)
if mck:
capabilities["modifier_keycodes"] = mck
merge_dicts(capabilities, InputMixin.get_caps(self))
self.send("hello", capabilities)
self.hello_sent = True

Expand All @@ -461,7 +387,6 @@ def get_info(self):
"desktop_names" : self.desktop_names,
"connection_time" : int(self.connection_time),
"elapsed_time" : int(monotonic_time()-self.connection_time),
"suspended" : self.suspended,
"counter" : self.counter,
"hello-sent" : self.hello_sent,
"bandwidth-limit" : {
Expand Down Expand Up @@ -509,18 +434,12 @@ def get_features_info(self):
info = {}
def battr(k, prop):
info[k] = bool(getattr(self, prop))
for prop in ("lock", "share", "randr_notify", "system_tray"):
for prop in ("lock", "share", "randr_notify"):
battr(prop, prop)
for prop, name in {
"send_notifications" : "notifications",
}.items():
battr(name, prop)
dcinfo = info.setdefault("double_click", {})
for prop, name in {
"double_click_time" : "time",
"double_click_distance" : "distance",
}.items():
dcinfo[name] = getattr(self, prop)
return info


Expand Down
2 changes: 1 addition & 1 deletion src/xpra/server/source/dbus_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def cleanup(self):
self.dbus_server = None
self.idle_add(ds.cleanup)

def parse_client_caps(self, c):
def parse_client_caps(self, _c):
if self.dbus_control:
from xpra.server.dbus.dbus_common import dbus_exception_wrap
def make_dbus_server():
Expand Down
4 changes: 3 additions & 1 deletion src/xpra/server/source/encodings_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ def __init__(self, core_encodings, encodings, default_encoding, scaling_control,


def cleanup(self):
#it is now safe to add the end of queue marker:
self.cancel_recalculate_timer()
#Warning: this mixin must come AFTER the window mixin!
#to make sure that it is safe to add the end of queue marker:
#(all window sources will have stopped queuing data)
self.encode_work_queue.put(None)
#this should be a noop since we inherit an initialized helper:
Expand Down
101 changes: 101 additions & 0 deletions src/xpra/server/source/input_mixin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# -*- coding: utf-8 -*-
# This file is part of Xpra.
# Copyright (C) 2010-2018 Antoine Martin <antoine@devloop.org.uk>
# Copyright (C) 2008 Nathaniel Smith <njs@pobox.com>
# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
# later version. See the file COPYING for details.

from xpra.log import Logger
log = Logger("keyboard")

from xpra.server.source.stub_source_mixin import StubSourceMixin


"""
Manage input devices (keyboard, mouse, etc)
"""
class InputMixin(StubSourceMixin):

def __init__(self):
self.keyboard_config = None
self.double_click_time = -1
self.double_click_distance = -1, -1

def cleanup(self):
self.keyboard_config = None

def parse_client_caps(self, c):
self.double_click_time = c.intget("double_click.time")
self.double_click_distance = c.intpair("double_click.distance")


def get_info(self):
info = {
"time" : self.double_click_time,
"distance" : self.double_click_distance,
}
return {"double-click" : info}

def get_caps(self):
#expose the "modifier_client_keycodes" defined in the X11 server keyboard config object,
#so clients can figure out which modifiers map to which keys:
if self.keyboard_config:
mck = getattr(self.keyboard_config, "modifier_client_keycodes", None)
if mck:
return {"modifier_keycodes" : mck}
return {}


def set_layout(self, layout, variant, options):
return self.keyboard_config.set_layout(layout, variant, options)

def keys_changed(self):
if self.keyboard_config:
self.keyboard_config.compute_modifier_map()
self.keyboard_config.compute_modifier_keynames()
log("keys_changed() updated keyboard config=%s", self.keyboard_config)

def make_keymask_match(self, modifier_list, ignored_modifier_keycode=None, ignored_modifier_keynames=None):
if self.keyboard_config and self.keyboard_config.enabled:
self.keyboard_config.make_keymask_match(modifier_list, ignored_modifier_keycode, ignored_modifier_keynames)

def set_default_keymap(self):
log("set_default_keymap() keyboard_config=%s", self.keyboard_config)
if self.keyboard_config:
self.keyboard_config.set_default_keymap()
return self.keyboard_config


def set_keymap(self, current_keyboard_config, keys_pressed, force=False, translate_only=False):
log("set_keymap%s", (current_keyboard_config, keys_pressed, force, translate_only))
if self.keyboard_config and self.keyboard_config.enabled:
current_id = None
if current_keyboard_config and current_keyboard_config.enabled:
current_id = current_keyboard_config.get_hash()
keymap_id = self.keyboard_config.get_hash()
log("current keyboard id=%s, new keyboard id=%s", current_id, keymap_id)
if force or current_id is None or keymap_id!=current_id:
self.keyboard_config.keys_pressed = keys_pressed
self.keyboard_config.set_keymap(translate_only)
self.keyboard_config.owner = self.uuid
current_keyboard_config = self.keyboard_config
else:
log.info("keyboard mapping already configured (skipped)")
self.keyboard_config = current_keyboard_config
return current_keyboard_config


def get_keycode(self, client_keycode, keyname, modifiers):
if self.keyboard_config is None:
log.info("ignoring client key %s / %s since keyboard is not configured", client_keycode, keyname)
return -1
return self.keyboard_config.get_keycode(client_keycode, keyname, modifiers)


def update_mouse(self, wid, x, y, rx, ry):
log("update_mouse(%s, %i, %i, %i, %i) current=%s, client=%i, show=%s", wid, x, y, rx, ry, self.mouse_last_position, self.counter, self.mouse_show)
if not self.mouse_show:
return
if self.mouse_last_position!=(x, y, rx, ry):
self.mouse_last_position = (x, y, rx, ry)
self.send_async("pointer-position", wid, x, y, rx, ry)
8 changes: 5 additions & 3 deletions src/xpra/server/source/windows_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,11 @@ def get_caps(self):
# info:
def get_info(self):
info = {
"windows" : self.send_windows,
"cursors" : self.send_cursors,
"bell" : self.send_bell,
"windows" : self.send_windows,
"cursors" : self.send_cursors,
"bell" : self.send_bell,
"suspended" : self.suspended,
"system-tray" : self.system_tray
}
if self.window_frame_sizes:
info.setdefault("window", {}).update({"frame-sizes" : self.window_frame_sizes})
Expand Down

0 comments on commit 00bb620

Please sign in to comment.