Skip to content

Commit

Permalink
#1941 expose relative pointer position from clients if the server sup…
Browse files Browse the repository at this point in the history
…ports the new feature 'pointer.relative'

git-svn-id: https://xpra.org/svn/Xpra/trunk@20252 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Aug 31, 2018
1 parent a9e8696 commit 33631bb
Show file tree
Hide file tree
Showing 11 changed files with 71 additions and 37 deletions.
18 changes: 12 additions & 6 deletions src/xpra/client/client_window_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -687,11 +687,14 @@ def get_mouse_event_wid(self, _x, _y):
def do_motion_notify_event(self, event):
if self._client.readonly or self._client.server_readonly or not self._client.server_pointer:
return
pointer, modifiers, buttons = self._pointer_modifiers(event)
pointer, relative_pointer, modifiers, buttons = self._pointer_modifiers(event)
wid = self.get_mouse_event_wid(*pointer)
mouselog("do_motion_notify_event(%s) wid=%s / focus=%s / window wid=%i, device=%s, pointer=%s, modifiers=%s, buttons=%s", event, wid, self._client._focused, self._id, self._device_info(event), pointer, modifiers, buttons)
self._client.send_mouse_position(["pointer-position", wid,
pointer, modifiers, buttons])
mouselog("do_motion_notify_event(%s) wid=%s / focus=%s / window wid=%i, device=%s, pointer=%s, relative pointer=%s, modifiers=%s, buttons=%s", event, wid, self._client._focused, self._id, self._device_info(event), pointer, relative_pointer, modifiers, buttons)
pdata = pointer
if self._client.server_pointer_relative:
pdata = list(pointer)+list(relative_pointer)
packet = ["pointer-position", wid, pdata, modifiers, buttons]
self._client.send_mouse_position(packet)

def _device_info(self, event):
try:
Expand All @@ -702,7 +705,7 @@ def _device_info(self, event):
def _button_action(self, button, event, depressed, *args):
if self._client.readonly or self._client.server_readonly or not self._client.server_pointer:
return
pointer, modifiers, buttons = self._pointer_modifiers(event)
pointer, relative_pointer, modifiers, buttons = self._pointer_modifiers(event)
wid = self.get_mouse_event_wid(*pointer)
mouselog("_button_action(%s, %s, %s) wid=%s / focus=%s / window wid=%i, device=%s, pointer=%s, modifiers=%s, buttons=%s", button, event, depressed, wid, self._client._focused, self._id, self._device_info(event), pointer, modifiers, buttons)
#map wheel buttons via translation table to support inverted axes:
Expand All @@ -719,8 +722,11 @@ def _button_action(self, button, event, depressed, *args):
continue
b = sb
server_buttons.append(b)
pdata = pointer
if self._client.server_pointer_relative:
pdata = list(pointer)+list(relative_pointer)
def send_button(pressed):
self._client.send_button(wid, server_button, pressed, pointer, modifiers, server_buttons, *args)
self._client.send_button(wid, server_button, pressed, pdata, modifiers, server_buttons, *args)
pressed_state = self.button_state.get(button, False)
if SIMULATE_MOUSE_DOWN and pressed_state is False and depressed is False:
mouselog("button action: simulating a missing mouse-down event for window %s before sending the mouse-up event", wid)
Expand Down
1 change: 1 addition & 0 deletions src/xpra/client/gtk_base/gtk_client_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,7 @@ def make_hello(self):
capabilities["metadata.supported"] = ms
updict(capabilities, "pointer", {
"grabs" : True,
"relative" : True,
})
updict(capabilities, "window", {
"initiate-moveresize" : True,
Expand Down
12 changes: 9 additions & 3 deletions src/xpra/client/gtk_base/gtk_client_window_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1832,7 +1832,7 @@ def do_delete_event(self, event):
return True


def _pointer(self, x, y):
def _offset_pointer(self, x, y):
if self.window_offset:
x -= self.window_offset[0]
y -= self.window_offset[1]
Expand All @@ -1841,13 +1841,19 @@ def _pointer(self, x, y):
def _get_pointer(self, event):
return event.x_root, event.y_root

def _get_relative_pointer(self, event):
return event.x, event.y

def _pointer_modifiers(self, event):
x, y = self._get_pointer(event)
pointer = self._pointer(x, y)
rx, ry = self._get_relative_pointer(event)
#adjust for window offset:
pointer = self._offset_pointer(x, y)
relative_pointer = self._offset_pointer(rx, ry)
#FIXME: state is used for both mods and buttons??
modifiers = self._client.mask_to_names(event.state)
buttons = self._event_buttons(event)
v = pointer, modifiers, buttons
v = pointer, relative_pointer, modifiers, buttons
mouselog("pointer_modifiers(%s)=%s (x_root=%s, y_root=%s, window_offset=%s)", event, v, event.x_root, event.y_root, self.window_offset)
return v

Expand Down
2 changes: 2 additions & 0 deletions src/xpra/client/mixins/window_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ def __init__(self):

self.server_input_devices = None
self.server_precise_wheel = False
self.server_pointer_relative = False
self.input_devices = "auto"

self.overlay_image = None
Expand Down Expand Up @@ -305,6 +306,7 @@ def parse_server_capabilities(self):
#input devices:
self.server_input_devices = c.strget("input-devices")
self.server_precise_wheel = c.boolget("wheel.precise", False)
self.server_pointer_relative = c.boolget("pointer.relative", False)
return True


Expand Down
6 changes: 3 additions & 3 deletions src/xpra/platform/darwin/shadow_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ def stop_refresh(self, wid):
def do_process_mouse_common(self, proto, wid, pointer, *args):
assert proto in self._server_sources
assert wid in self._id_to_window
CG.CGWarpMouseCursorPosition(pointer)
CG.CGWarpMouseCursorPosition(pointer[:2])
return pointer

def fake_key(self, keycode, press):
Expand All @@ -187,8 +187,8 @@ def button_action(self, pointer, button, pressed, _deviceid=-1, *args):
args = []
for i in range(button):
args.append(i==(button-1) and pressed)
log("CG.CGPostMouseEvent(%s, %s, %s, %s)", pointer, 1, button, args)
CG.CGPostMouseEvent(pointer, 1, button, *args)
log("CG.CGPostMouseEvent(%s, %s, %s, %s)", pointer[:2], 1, button, args)
CG.CGPostMouseEvent(pointer[:2], 1, button, *args)
else:
if not pressed:
#we don't simulate press/unpress
Expand Down
4 changes: 2 additions & 2 deletions src/xpra/platform/win32/shadow_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ def get_pointer_position(self):
def do_process_mouse_common(self, proto, wid, pointer, *_args):
#adjust pointer position for offset in client:
try:
x, y = pointer
x, y = pointer[:2]
assert SetPhysicalCursorPos(x, y)
except Exception as e:
log("SetPhysicalCursorPos%s failed", pointer, exc_info=True)
Expand Down Expand Up @@ -521,7 +521,7 @@ def button_action(self, pointer, button, pressed, deviceid=-1, *args):
elif event is NOEVENT:
return
dwFlags, dwData = event
x, y = pointer
x, y = pointer[:2]
mouse_event(dwFlags, x, y, dwData, 0)

def make_hello(self, source):
Expand Down
7 changes: 5 additions & 2 deletions src/xpra/platform/xposix/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,7 @@ def do_xi_motion(self, event, device):
client = window._client
if client.readonly:
return
pointer, modifiers, buttons = window._pointer_modifiers(event)
pointer, relative_pointer, modifiers, buttons = window._pointer_modifiers(event)
wid = self.window.get_mouse_event_wid(*pointer)
#log("server_input_devices=%s, server_precise_wheel=%s", client.server_input_devices, client.server_precise_wheel)
valuators = event.valuators
Expand Down Expand Up @@ -701,7 +701,10 @@ def do_xi_motion(self, event, device):
#send plain motion first, if any:
if unused_valuators:
xinputlog("do_xi_motion(%s, %s) wid=%s / focus=%s / window wid=%i, device=%s, pointer=%s, modifiers=%s, buttons=%s", event, device, wid, window._client._focused, window._id, event.device, pointer, modifiers, buttons)
packet = ["pointer-position", wid, pointer, modifiers, buttons] + self.get_pointer_extra_args(event)
pdata = pointer
if client.server_pointer_relative:
pdata = list(pointer)+list(relative_pointer)
packet = ["pointer-position", wid, pdata, modifiers, buttons] + self.get_pointer_extra_args(event)
client.send_mouse_position(packet)
#now see if we have anything to send as a wheel event:
if dx!=0 or dy!=0:
Expand Down
12 changes: 8 additions & 4 deletions src/xpra/server/mixins/input_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,11 @@ def get_ui_info(self, proto, client_uuids=None, *args):
}
return info

def get_server_features(self, source=None):
def get_server_features(self, _source=None):
return {
"toggle_keyboard_sync" : True,
"input-devices" : self.input_devices,
"pointer.relative" : True,
}

def get_caps(self, _source):
Expand Down Expand Up @@ -339,7 +340,7 @@ def _adjust_pointer(self, proto, wid, pointer):
if wx!=cx or wy!=cy:
dx, dy = wx-cx, wy-cy
if dx!=0 or dy!=0:
px, py = pointer
px, py = pointer[:2]
ax, ay = px+dx, py+dy
mouselog("client %2i: server window position: %12s, client window position: %24s, pointer=%s, adjusted: %s", ss.counter, pos, mapped_at, pointer, (ax, ay))
return ax, ay
Expand Down Expand Up @@ -382,12 +383,15 @@ def _process_pointer_position(self, proto, packet):
ss = self._server_sources.get(proto)
if ss is None:
return
wid, pointer, modifiers = packet[1:4]
wid, pdata, modifiers = packet[1:4]
pointer = pdata[:2]
if ss.pointer_relative and len(pdata)>=4:
ss.mouse_last_relative_position = pdata[2:4]
ss.mouse_last_position = pointer
if self.ui_driver and self.ui_driver!=ss.uuid:
return
ss.user_event()
if self._process_mouse_common(proto, wid, pointer, *packet[5:]):
if self._process_mouse_common(proto, wid, pdata, *packet[5:]):
self._update_modifiers(proto, wid, modifiers)


Expand Down
5 changes: 0 additions & 5 deletions src/xpra/server/source/windows_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@ def init_from(self, _protocol, server):
def init_state(self):
#WindowSource for each Window ID
self.window_sources = {}
# mouse echo:
self.mouse_show = False
self.mouse_last_position = None

self.window_frame_sizes = {}
self.suspended = False
Expand Down Expand Up @@ -123,8 +120,6 @@ def parse_client_caps(self, c):
self.send_cursors = self.send_windows and c.boolget("cursors")
self.cursor_encodings = c.strlistget("encodings.cursor")
self.send_bell = c.boolget("bell")
self.mouse_show = c.boolget("mouse.show")
self.mouse_last_position = c.intpair("mouse.initial-position")
self.window_initiate_moveresize = c.boolget("window.initiate-moveresize")
self.system_tray = c.boolget("system_tray")
self.metadata_supported = c.strlistget("metadata.supported", DEFAULT_METADATA_SUPPORTED)
Expand Down
18 changes: 10 additions & 8 deletions src/xpra/x11/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -1211,14 +1211,16 @@ def paint_grey_rect(shade, x, y, w, h):
else:
cr.stroke()
#FIXME: use server mouse position, and use current cursor shape
if ss and ss.mouse_last_position and ss.mouse_last_position!=(0, 0):
x, y = ss.mouse_last_position
cr.set_source_rgb(1.0, 0.5, 0.7)
cr.new_path()
cr.arc(x, y, 10.0, 0, 2.0 * math.pi)
cr.stroke_preserve()
cr.set_source_rgb(0.3, 0.4, 0.6)
cr.fill()
if ss:
mlp = getattr(ss, "mouse_last_position", (0, 0))
if mlp!=(0, 0):
x, y = mlp
cr.set_source_rgb(1.0, 0.5, 0.7)
cr.new_path()
cr.arc(x, y, 10.0, 0, 2.0 * math.pi)
cr.stroke_preserve()
cr.set_source_rgb(0.3, 0.4, 0.6)
cr.fill()
return False


Expand Down
23 changes: 19 additions & 4 deletions src/xpra/x11/x11_server_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -868,20 +868,35 @@ def get_pointer_device(self, deviceid):
return device


def _get_pointer_abs_coordinates(self, wid, pos):
#simple absolute coordinates
x, y = pos[:2]
from xpra.server.mixins.window_server import WindowServer
if len(pos)>=4 and isinstance(self, WindowServer):
#relative coordinates
model = self._id_to_window.get(wid)
if model:
rx, ry = pos[2:4]
geom = model.get_geometry()
x = geom[0]+rx
y = geom[1]+ry
log("_get_pointer_abs_coordinates(%i, %s)=%s window geometry=%s", wid, pos, (x, y), geom)
return x, y

def _move_pointer(self, wid, pos, deviceid=-1, *args):
#(this is called within an xswallow context)
screen_no = self.get_screen_number(wid)
device = self.get_pointer_device(deviceid)
mouselog("move_pointer(%s, %s, %s) screen_no=%i, device=%s", wid, pos, deviceid, screen_no, device)
x, y = pos
x, y = self._get_pointer_abs_coordinates(wid, pos)
mouselog("move_pointer(%s, %s, %s) screen_no=%i, device=%s, position=%s", wid, pos, deviceid, screen_no, device, (x, y))
try:
device.move_pointer(screen_no, x, y, *args)
except Exception as e:
mouselog.error("Error: failed to move the pointer to %sx%s using %s", x, y, device)
mouselog.error(" %s", e)

def do_process_mouse_common(self, proto, wid, pointer, deviceid=-1, *args):
log("do_process_mouse_common%s", tuple([proto, wid, pointer, deviceid]+list(args)))
mouselog("do_process_mouse_common%s", tuple([proto, wid, pointer, deviceid]+list(args)))
if self.readonly:
return None
pos = self.root_window.get_pointer()[-3:-1]
Expand All @@ -890,7 +905,7 @@ def do_process_mouse_common(self, proto, wid, pointer, deviceid=-1, *args):
ss = self._server_sources.get(proto)
if ss:
uuid = ss.uuid
if pos!=pointer or self.input_devices=="xi":
if pos!=pointer[:2] or self.input_devices=="xi":
self.last_mouse_user = uuid
with xswallow:
self._move_pointer(wid, pointer, deviceid, *args)
Expand Down

0 comments on commit 33631bb

Please sign in to comment.