Skip to content

Commit

Permalink
#41 / #1247: generalize window position offsets so that all servers c…
Browse files Browse the repository at this point in the history
…an take advantage of it and re-use the same code - makes it possible to have pointer events work with sharing enabled

git-svn-id: https://xpra.org/svn/Xpra/trunk@14368 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Nov 1, 2016
1 parent 2efc7e3 commit d927993
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 40 deletions.
34 changes: 32 additions & 2 deletions src/xpra/server/server_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from xpra.log import Logger
log = Logger("server")
keylog = Logger("keyboard")
mouselog = Logger("mouse")
focuslog = Logger("focus")
execlog = Logger("exec")
commandlog = Logger("command")
Expand Down Expand Up @@ -2670,11 +2671,26 @@ def _process_key_repeat(self, proto, packet):
def _move_pointer(self, wid, pos):
raise NotImplementedError()

def _adjust_pointer(self, wid, pointer):
def _adjust_pointer(self, proto, wid, pointer):
#the window may not be mapped at the same location by the client:
ss = self._server_sources.get(proto)
window = self._id_to_window.get(wid)
if ss and window:
ws = ss.get_window_source(wid)
if ws:
mapped_at = ws.mapped_at
pos = self.get_window_position(window)
mouselog("client %s: server window position: %s, client window position: %s", ss, pos, mapped_at)
if mapped_at and pos:
wx, wy = pos
cx, cy = mapped_at[:2]
if wx!=cx or wy!=cy:
px, py = pointer
return px+(wx-cx), py+(wy-cy)
return pointer

def _process_mouse_common(self, proto, wid, pointer):
pointer = self._adjust_pointer(wid, pointer)
pointer = self._adjust_pointer(proto, wid, pointer)
self.do_process_mouse_common(proto, wid, pointer)
return pointer

Expand Down Expand Up @@ -2803,6 +2819,20 @@ def _process_min_speed(self, proto, packet):
self._idle_refresh_all_windows(proto)


def get_window_position(self, window):
#where the window is actually mapped on the server screen:
return None

def _window_mapped_at(self, proto, wid, window, coords=None):
#record where a window is mapped by a client
#(in order to support multiple clients and different offsets)
ss = self._server_sources.get(proto)
if not ss:
return
ws = ss.make_window_source(wid, window)
ws.mapped_at = coords
#log("window %i mapped at %s for client %s", wid, coords, ss)

def _process_map_window(self, proto, packet):
log.info("_process_map_window(%s, %s)", proto, packet)

Expand Down
31 changes: 13 additions & 18 deletions src/xpra/server/shadow/shadow_server_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class ShadowServerBase(object):

def __init__(self, root_window):
self.root = root_window
self.mapped_at = None
self.mapped = False
self.pulseaudio = False
self.sharing = False
self.refresh_delay = REFRESH_DELAY
Expand All @@ -47,6 +47,10 @@ def make_hello(self, source):
return {"shadow" : True}


def get_window_position(self, window):
#we export the whole desktop as a window:
return 0, 0

def get_cursor_data(self):
return None

Expand All @@ -65,27 +69,28 @@ def source_remove(self, *args):
# refresh

def start_refresh(self):
self.mapped = True
self.timer = self.timeout_add(self.refresh_delay, self.refresh)

def set_refresh_delay(self, v):
assert v>0 and v<10000
self.refresh_delay = v
if self.mapped_at:
if self.mapped:
if self.timer:
self.source_remove(self.timer)
self.timer = None
self.start_refresh()


def stop_refresh(self):
log("stop_refresh() mapped_at=%s, timer=%s", self.mapped_at, self.timer)
self.mapped_at = None
log("stop_refresh() mapped=%s, timer=%s", self.mapped, self.timer)
self.mapped = False
if self.timer:
self.source_remove(self.timer)
self.timer = None

def refresh(self):
if not self.mapped_at:
if not self.mapped:
self.timer = None
return False
w, h = self.root.get_size()
Expand Down Expand Up @@ -148,16 +153,6 @@ def send_initial_windows(self, ss, sharing=False):
ss.new_window("new-window", wid, window, 0, 0, w, h, self.client_properties.get(ss.uuid))


def _adjust_pointer(self, wid, pointer):
#adjust pointer position for window position in client:
x, y = pointer
ma = self.mapped_at
if ma:
wx, wy = ma[:2]
pointer = x-wx, y-wy
return pointer


def _add_new_window(self, window):
self._add_new_window_common(window)
self._send_new_window_packet(window)
Expand All @@ -176,7 +171,7 @@ def _process_window_common(self, wid):
def _process_map_window(self, proto, packet):
wid, x, y, width, height = packet[1:6]
window = self._process_window_common(wid)
self.mapped_at = x, y, width, height
self._window_mapped_at(proto, wid, window, (x, y, width, height))
self._damage(window, 0, 0, width, height)
if len(packet)>=7:
self._set_client_properties(proto, wid, self.root_window_model, packet[6])
Expand All @@ -187,13 +182,13 @@ def _process_unmap_window(self, proto, packet):
window = self._process_window_common(wid)
for ss in self._server_sources.values():
ss.unmap_window(wid, window)
self.mapped_at = None
self._window_mapped_at(proto, wid, window, None)
self.root_window_model.suspend()

def _process_configure_window(self, proto, packet):
wid, x, y, w, h = packet[1:6]
window = self._process_window_common(wid)
self.mapped_at = x, y, w, h
self._window_mapped_at(proto, wid, window, (x, y, w, h))
self._damage(window, 0, 0, w, h)
if len(packet)>=7:
self._set_client_properties(proto, wid, self.root_window_model, packet[6])
Expand Down
4 changes: 4 additions & 0 deletions src/xpra/server/source.py
Original file line number Diff line number Diff line change
Expand Up @@ -2084,6 +2084,10 @@ def make_batch_config(self, wid, window):
batch_config.delay = self.global_batch_config.delay * sqrt(ratio)
return batch_config


def get_window_source(self, wid):
return self.window_sources.get(wid)

def make_window_source(self, wid, window):
ws = self.window_sources.get(wid)
if ws is None:
Expand Down
4 changes: 4 additions & 0 deletions src/xpra/server/window/window_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ def __init__(self, queue_size, call_in_encode_thread, queue_packet, compressed_w
self.is_shadow = window.is_shadow()
self.has_alpha = window.has_alpha()
self.window_dimensions = 0, 0
self.mapped_at = None
self.fullscreen = not self.is_tray and window.get("fullscreen")
self.scaling_control = default_encoding_options.intget("scaling.control", 1) #ServerSource sets defaults with the client's scaling.control value
self.scaling = None
Expand Down Expand Up @@ -389,6 +390,9 @@ def get_info(self):
"rgb_formats" : self.rgb_formats,
#"icons" : self.icons_encoding_options,
})
ma = self.mapped_at
if ma:
info["mapped-at"] = ma
now = time.time()
cutoff = now-5
lde = [x for x in self.statistics.last_damage_events if x[0]>=cutoff]
Expand Down
25 changes: 7 additions & 18 deletions src/xpra/x11/desktop_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ class DesktopModel(WindowModelStub, WindowDamageHandler):
def __init__(self, root):
WindowDamageHandler.__init__(self, root)
WindowModelStub.__init__(self)
self.mapped_at = None

def __repr__(self):
return "DesktopModel(%#x)" % (self.client_window.xid)
Expand Down Expand Up @@ -229,10 +228,7 @@ def _window_resized_signaled(self, window, *args):
#the vfb has been resized
wid = self._window_to_id[window]
x, y, w, h = window.get_geometry()
if window.mapped_at:
x, y = window.mapped_at[:2]
window.mapped_at = (x, y, w, h)
windowlog("window_resized_signaled(%s) mapped at=%s", window, window.mapped_at)
windowlog("window_resized_signaled(%s) geometry=%s", window, (x, y, w, h))
for ss in self._server_sources.values():
ss.move_resize_window(wid, window, x, y, w, h)
ss.damage(wid, window, 0, 0, w, h)
Expand Down Expand Up @@ -286,16 +282,9 @@ def get_screen_number(self, wid):
model = self._id_to_window.get(wid)
return model.client_window.get_screen().get_number()

def _adjust_pointer(self, wid, pointer):
#adjust pointer position for window position in client:
x, y = pointer
model = self._id_to_window.get(wid)
if model:
ma = model.mapped_at
if ma:
wx, wy = ma[:2]
pointer = x-wx, y-wy
return pointer
def get_window_position(self, window):
#we export the whole desktop as a window:
return 0, 0


def _process_map_window(self, proto, packet):
Expand All @@ -304,12 +293,12 @@ def _process_map_window(self, proto, packet):
if not window:
windowlog("cannot map window %s: already removed!", wid)
return
window.mapped_at = (x, y, w, h)
geomlog("client mapped window %s - %s, at: %s", wid, window, (x, y, w, h))
if len(packet)>=8:
self._set_window_state(proto, wid, window, packet[7])
if len(packet)>=7:
self._set_client_properties(proto, wid, window, packet[6])
self._window_mapped_at(proto, wid, window, (x, y, w, h))
self._damage(window, 0, 0, w, h)


Expand All @@ -319,12 +308,12 @@ def _process_unmap_window(self, proto, packet):
if not window:
log("cannot map window %s: already removed!", wid)
return
window.mapped_at = None
if len(packet)>=4:
#optional window_state added in 0.15 to update flags
#during iconification events:
self._set_window_state(proto, wid, window, packet[3])
assert not window.is_OR()
self._window_mapped_at(proto, wid, window, None)
#TODO: handle inconification?
#iconified = len(packet)>=3 and bool(packet[2])

Expand All @@ -349,13 +338,13 @@ def _process_configure_window(self, proto, packet):
damage = len(changes)>0
if not skip_geometry:
owx, owy, oww, owh = window.get_geometry()
window.mapped_at = (x, y, w, h)
geomlog("_process_configure_window(%s) old window geometry: %s", packet[1:], (owx, owy, oww, owh))
if len(packet)>=7:
cprops = packet[6]
if cprops:
metadatalog("window client properties updates: %s", cprops)
self._set_client_properties(proto, wid, window, cprops)
self._window_mapped_at(proto, wid, window, (x, y, w, h))
if damage:
self._damage(window, 0, 0, w, h)

Expand Down
14 changes: 12 additions & 2 deletions src/xpra/x11/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,9 @@ def window_size(self, model):
w, h = self._models[model].geom[2:4]
return w, h

def window_position(self, model, w, h):
def window_position(self, model, w=None, h=None):
[x, y, w0, h0] = self._models[model].geom
if abs(w0-w)>1 or abs(h0-h)>1:
if (w is not None and abs(w0-w)>1) or (h is not None and abs(h0-h)>1):
log("Uh-oh, our size doesn't fit window sizing constraints: "
"%sx%s vs %sx%s", w0, h0, w, h)
return x, y
Expand Down Expand Up @@ -746,6 +746,12 @@ def _set_window_state(self, proto, wid, window, new_window_state):
metadatalog("set_window_state: changes=%s", changes)
return changes


def get_window_position(self, window):
#used to adjust the pointer position with multiple clients
return self._desktop_manager.window_position(window)


def _process_map_window(self, proto, packet):
wid, x, y, w, h = packet[1:6]
window = self._id_to_window.get(wid)
Expand All @@ -761,6 +767,7 @@ def _process_map_window(self, proto, packet):
self._desktop_manager.show_window(window)
if len(packet)>=7:
self._set_client_properties(proto, wid, window, packet[6])
self._window_mapped_at(proto, wid, window, (x, y, w, h))
self._damage(window, 0, 0, w, h)


Expand All @@ -783,6 +790,7 @@ def _process_unmap_window(self, proto, packet):
if iconified and not window.get_property("iconic"):
window.set_property("iconic", True)
self._desktop_manager.hide_window(window)
self._window_mapped_at(proto, wid, window, None)
self.repaint_root_overlay()

def _clamp_window(self, proto, wid, window, x, y, w, h, resize_counter=0):
Expand Down Expand Up @@ -843,6 +851,8 @@ def _process_configure_window(self, proto, packet):
metadatalog("window client properties updates: %s", cprops)
self._set_client_properties(proto, wid, window, cprops)
self.repaint_root_overlay()
if not skip_geometry:
self._window_mapped_at(proto, wid, window, (x, y, w, h))
#rate-limit the damage events generated by configure:
if damage:
self.schedule_configure_damage(wid)
Expand Down

0 comments on commit d927993

Please sign in to comment.