Skip to content

Commit

Permalink
#899 / #391:
Browse files Browse the repository at this point in the history
* damage notifications for the osx shadow server - with fallback to the old timer method
* moved pointer position adjustement code to superclass

git-svn-id: https://xpra.org/svn/Xpra/trunk@12252 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Mar 28, 2016
1 parent d67de19 commit fae9a6a
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 18 deletions.
16 changes: 12 additions & 4 deletions src/xpra/platform/darwin/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,11 +256,19 @@ def get_menu_support_function():
CG = None


def get_CG_imagewrapper():
def roundup(n, m):
return (n + m - 1) & ~(m - 1)

def get_CG_imagewrapper(rect=None):
from xpra.codecs.image_wrapper import ImageWrapper
assert CG, "cannot capture without Quartz.CoreGraphics"
#region = CG.CGRectMake(0, 0, 100, 100)
region = CG.CGRectInfinite
if rect is None:
x = 0
y = 0
region = CG.CGRectInfinite
else:
x, y, w, h = rect
region = CG.CGRectMake(x, y, roundup(w, 2), roundup(h, 2))
image = CG.CGWindowListCreateImage(region,
CG.kCGWindowListOptionOnScreenOnly,
CG.kCGNullWindowID,
Expand All @@ -275,7 +283,7 @@ def get_CG_imagewrapper():
log("get_CG_imagewrapper(..) image size: %sx%s, bpc=%s, bpp=%s, rowstride=%s, alpha=%s", width, height, bpc, bpp, rowstride, alpha_str)
prov = CG.CGImageGetDataProvider(image)
argb = CG.CGDataProviderCopyData(prov)
return ImageWrapper(0, 0, width, height, argb, "BGRX", 24, rowstride)
return ImageWrapper(x, y, width, height, argb, "BGRX", 24, rowstride)

def take_screenshot():
log("grabbing screenshot")
Expand Down
60 changes: 55 additions & 5 deletions src/xpra/platform/darwin/shadow_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
class OSXRootWindowModel(RootWindowModel):

def get_image(self, x, y, width, height, logger=None):
return get_CG_imagewrapper()
rect = (x, y, width, height)
return get_CG_imagewrapper(rect)

def take_screenshot(self):
log("grabbing screenshot")
Expand All @@ -47,6 +48,9 @@ def __init__(self):
from xpra.scripts.config import InitExit
log("cannot grab test screenshot - maybe you need to run this command whilst logged in via the UI")
raise InitExit(1, "cannot grab pixels from the screen, make sure this command is launched from a GUI session")
self.refresh_count = 0
self.refresh_rectangle_count = 0
self.refresh_registered = False
GTKShadowServerBase.__init__(self)

def init(self, opts):
Expand All @@ -60,11 +64,51 @@ def make_tray_widget(self):
def makeRootWindowModel(self):
return OSXRootWindowModel(self.root)

def last_client_exited(self):
self.stop_refresh()
GTKServerBase.last_client_exited(self)

def _process_mouse_common(self, proto, wid, pointer, modifiers):
def screen_refresh_callback(self, count, rects, info):
#log("screen_refresh_callback%s mapped=%s", (count, rects, info), self.mapped_at)
if not self.mapped_at:
return
self.refresh_count += 1
for r in rects:
assert isinstance(r, CG.CGRect), "invalid rectangle in list: %s" % r
self.refresh_rectangle_count += 1
self.idle_add(self._damage, self.root_window_model, r.origin.x, r.origin.y, r.size.width, r.size.height)

def start_refresh(self):
#don't use the timer, get damage notifications:
if self.refresh_registered:
log.warn("Warning: screen refresh callback already registered!")
return
err = CG.CGRegisterScreenRefreshCallback(self.screen_refresh_callback, None)
log("CGRegisterScreenRefreshCallback(%s)=%s", self.screen_refresh_callback, err)
if err!=0:
log.warn("Warning: CGRegisterScreenRefreshCallback failed with error %i", err)
log.warn(" using fallback timer method")
GTKShadowServerBase.start_refresh(self)
else:
self.refresh_registered = True

def stop_refresh(self):
log("stop_refresh() mapped_at=%s, timer=%s", self.mapped_at, self.timer)
if self.refresh_registered:
self.mapped_at = None
try:
err = CG.CGUnregisterScreenRefreshCallback(self.screen_refresh_callback, None)
log("CGUnregisterScreenRefreshCallback(%s)=%s", self.screen_refresh_callback, err)
if err:
log.warn(" unregistering the existing one returned %s", {0 : "OK"}.get(err, err))
else:
self.refresh_registered = False
except ValueError as e:
log.warn("Error unregistering screen refresh callback:")
log.warn(" %s", e)
else:
#may stop the timer fallback:
GTKShadowServerBase.stop_refresh(self)


def do_process_mouse_common(self, proto, wid, pointer, modifiers):
CG.CGWarpMouseCursorPosition(pointer)

def get_keycode(self, ss, client_keycode, keyname, modifiers):
Expand All @@ -84,6 +128,7 @@ def _process_button_action(self, proto, packet):
wid, button, pressed, pointer, modifiers = packet[1:6]
log("process_button_action(%s, %s)", proto, packet)
self._process_mouse_common(proto, wid, pointer, modifiers)
pointer = self._adjust_pointer(pointer)
if button<=3:
#we should be using CGEventCreateMouseEvent
#instead we clear previous clicks when a "higher" button is pressed... oh well
Expand Down Expand Up @@ -118,4 +163,9 @@ def get_info(self, proto):
info = GTKServerBase.get_info(self, proto)
info.setdefault("features", {})["shadow"] = True
info.setdefault("server", {})["type"] = "Python/gtk2/osx-shadow"
info.setdefault("damage", {}).update({
"notifications" : self.refresh_registered,
"count" : self.refresh_count,
"rectangles" : self.refresh_rectangle_count,
})
return info
7 changes: 2 additions & 5 deletions src/xpra/platform/win32/shadow_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,12 +267,9 @@ def refresh(self):
log("refresh()=%s", v)
return v

def _process_mouse_common(self, proto, wid, pointer, modifiers):
def do_process_mouse_common(self, proto, wid, pointer, modifiers):
#adjust pointer position for offset in client:
x, y = pointer
wx, wy = self.mapped_at[:2]
rx, ry = x-wx, y-wy
win32api.SetCursorPos((rx, ry))
win32api.SetCursorPos(pointer)

def get_keyboard_config(self, props):
return KeyboardConfig()
Expand Down
18 changes: 18 additions & 0 deletions src/xpra/server/shadow/shadow_server_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,24 @@ def send_windows_and_cursors(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, pointer):
#adjust pointer position for offset in client:
x, y = pointer
ma = self.mapped_at
if ma:
wx, wy = ma[:2]
pointer = x-wx, y-wy
return pointer

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

def do_process_mouse_common(self, proto, wid, pointer, modifiers):
#actuallly move the mouse here in subclasses
pass


def _add_new_window(self, window):
self._add_new_window_common(window)
self._send_new_window_packet(window)
Expand Down
6 changes: 2 additions & 4 deletions src/xpra/x11/shadow_x11_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,10 @@ def last_client_exited(self):
X11ServerBase.last_client_exited(self)

def _process_mouse_common(self, proto, wid, pointer, modifiers):
#adjust pointer position for offset in client:
x, y = pointer
wx, wy = self.mapped_at[:2]
pointer = x-wx, y-wy
pointer = self._adjust_pointer(pointer)
X11ServerBase._process_mouse_common(self, proto, wid, pointer, modifiers)


def make_hello(self, source):
capabilities = X11ServerBase.make_hello(self, source)
capabilities.update(GTKShadowServerBase.make_hello(self, source))
Expand Down

0 comments on commit fae9a6a

Please sign in to comment.