def make_cursor(self, cursor_data): #if present, try cursor ny name: display = display_get_default() if len(cursor_data)>=9 and cursor_types: cursor_name = bytestostr(cursor_data[8]) if cursor_name: gdk_cursor = cursor_types.get(cursor_name.upper()) if gdk_cursor is not None: cursorlog("setting new cursor by name: %s=%s", cursor_name, gdk_cursor) return new_Cursor_for_display(display, gdk_cursor) else: global missing_cursor_names if cursor_name not in missing_cursor_names: cursorlog("cursor name '%s' not found", cursor_name) missing_cursor_names.add(cursor_name) #create cursor from the pixel data: w, h, xhot, yhot, serial, pixels = cursor_data[2:8] if len(pixels)<w*h*4: import binascii cursorlog.warn("not enough pixels provided in cursor data: %s needed and only %s bytes found (%s)", w*h*4, len(pixels), binascii.hexlify(pixels)[:100]) return pixbuf = get_pixbuf_from_data(pixels, True, w, h, w*4) x = max(0, min(xhot, w-1)) y = max(0, min(yhot, h-1)) csize = display.get_default_cursor_size() cmaxw, cmaxh = display.get_maximal_cursor_size() if len(cursor_data)>=11: ssize = cursor_data[9] smax = cursor_data[10] cursorlog("server cursor sizes: default=%s, max=%s", ssize, smax) cursorlog("new cursor at %s,%s with serial=%s, dimensions: %sx%s, len(pixels)=%s, default cursor size is %s, maximum=%s", xhot,yhot, serial, w,h, len(pixels), csize, (cmaxw, cmaxh)) fw, fh = get_fixed_cursor_size() if fw>0 and fh>0 and (w!=fw or h!=fh): #OS wants a fixed cursor size! (win32 does, and GTK doesn't do this for us) if w<=fw and h<=fh: cursorlog("pasting cursor of size %ix%i onto clear pixbuf of size %ix%i", w, h, fw, fh) cursor_pixbuf = get_pixbuf_from_data("\0"*fw*fh*4, True, fw, fh, fw*4) pixbuf.copy_area(0, 0, w, h, cursor_pixbuf, 0, 0) else: cursorlog("scaling cursor from %ix%i to fixed OS size %ix%i", w, h, fw, fh) cursor_pixbuf = pixbuf.scale_simple(fw, fh, INTERP_BILINEAR) xratio, yratio = float(w)/fw, float(h)/fh x, y = int(x/xratio), int(y/yratio) elif w>cmaxw or h>cmaxh or (csize>0 and (csize<w or csize<h)): ratio = max(float(w)/cmaxw, float(h)/cmaxh, float(max(w,h))/csize) x, y, w, h = int(x/ratio), int(y/ratio), int(w/ratio), int(h/ratio) cursorlog("downscaling cursor %s by %.2f: %sx%s", pixbuf, ratio, w, h) cursor_pixbuf = pixbuf.scale_simple(w, h, INTERP_BILINEAR) else: cursor_pixbuf = pixbuf #clamp to pixbuf size: w = cursor_pixbuf.get_width() h = cursor_pixbuf.get_height() x = max(0, min(x, w-1)) y = max(0, min(y, h-1)) return new_Cursor_from_pixbuf(display, cursor_pixbuf, x, y)
def set_icon_from_data(self, pixels, has_alpha, w, h, rowstride, _options=None): self.clean_last_tmp_icon() #use a temporary file (yuk) from xpra.gtk_common.gtk_util import pixbuf_save_to_memory, get_pixbuf_from_data tray_icon = get_pixbuf_from_data(pixels, has_alpha, w, h, rowstride) png_data = pixbuf_save_to_memory(tray_icon) tmp_dir = osexpand(get_xpra_tmp_dir()) if not os.path.exists(tmp_dir): os.mkdir(tmp_dir, 0o755) fd = None try: fd, self.tmp_filename = tempfile.mkstemp(prefix="tray", suffix=".png", dir=tmp_dir) log("set_icon_from_data%s using temporary file %s", ("%s pixels" % len(pixels), has_alpha, w, h, rowstride), self.tmp_filename) os.write(fd, png_data) except OSError as e: log("error saving temporary file", exc_info=True) log.error("Error saving icon data to temporary file") log.error(" %s", e) return finally: if fd: os.fchmod(fd, 0o644) os.close(fd) self.do_set_icon_from_file(self.tmp_filename)
def cairo_paint_pointer_overlay(context, cursor_data, px: int, py: int, start_time): if not cursor_data: return elapsed = max(0, monotonic_time() - start_time) if elapsed > 6: return cw = cursor_data[3] ch = cursor_data[4] xhot = cursor_data[5] yhot = cursor_data[6] pixels = cursor_data[8] x = px - xhot y = py - yhot alpha = max(0, (5.0 - elapsed) / 5.0) log("cairo_paint_pointer_overlay%s drawing pointer with cairo, alpha=%s", (context, x, y, start_time), alpha) context.translate(x, y) context.rectangle(0, 0, cw, ch) argb = unpremultiply_argb(pixels) img_data = memoryview_to_bytes(argb) pixbuf = get_pixbuf_from_data(img_data, True, cw, ch, cw * 4) context.set_operator(cairo.OPERATOR_OVER) Gdk.cairo_set_source_pixbuf(context, pixbuf, 0, 0) context.paint()
def populate_table(self): commands_info = typedict(self.client.server_last_info).dictget("commands") if self.commands_info!=commands_info and commands_info: log("populate_table() new commands_info=%s", commands_info) self.commands_info = commands_info if self.table: self.alignment.remove(self.table) tb = TableBuilder(rows=1, columns=2, row_spacings=15) self.table = tb.get_table() headers = [gtk.Label(""), gtk.Label("PID"), gtk.Label("Command"), gtk.Label("Exit Code")] if self.client.server_commands_signals: headers.append(gtk.Label("Send Signal")) tb.add_row(*headers) for procinfo in self.commands_info.values(): if not isinstance(procinfo, dict): continue #some records aren't procinfos: pi = typedict(procinfo) command = pi.strlistget("command") pid = pi.intget("pid", 0) returncode = pi.intget("returncode", None) if pid>0 and command: cmd_str = " ".join(command) rstr = "" if returncode is not None: rstr = "%s" % returncode #find the windows matching this pid windows = () from xpra.client import mixin_features if mixin_features.windows: windows = tuple(w for w in self.client._id_to_window.values() if getattr(w, "_metadata", {}).get("pid")==pid) log("windows matching pid=%i: %s", pid, windows) icon = gtk.Label() if windows: try: icons = tuple(getattr(w, "_current_icon", None) for w in windows) icons = tuple(x for x in icons if x is not None) log("icons: %s", icons) if icons: from PIL import Image img = icons[0].resize((24, 24), Image.ANTIALIAS) has_alpha = img.mode=="RGBA" width, height = img.size rowstride = width * (3+int(has_alpha)) pixbuf = get_pixbuf_from_data(img.tobytes(), has_alpha, width, height, rowstride) icon = gtk.Image() icon.set_from_pixbuf(pixbuf) except Exception: log("failed to get window icon", exc_info=True) items = [icon, gtk.Label("%s" % pid), gtk.Label(cmd_str), gtk.Label(rstr)] if self.client.server_commands_signals: if returncode is None: items.append(self.signal_button(pid)) else: items.append(gtk.Label("")) tb.add_row(*items) self.alignment.add(self.table) self.table.show_all() self.client.send_info_request() return True
def set_icon_from_pixbuf(self, tray_icon): if not tray_icon or not self.tray_widget: return tw, th = self.get_geometry()[2:4] if (tw <= 2 or th <= 2) or (tw == 200 and th == 200): log("bogus tray icon size: %ix%i", tw, th) tw = th = 48 w = tray_icon.get_width() h = tray_icon.get_height() log("set_icon_from_pixbuf(%s) geometry=%s, icon size=%s", tray_icon, self.get_geometry(), (w, h)) if tw != w or th != h: if tw != th and not PYTHON3: #paste the scaled icon in the middle of the rectangle: minsize = min(tw, th) new_icon = get_pixbuf_from_data(b"\0" * tw * th * 4, True, tw, th, tw * 4) scaled_w, scaled_h = minsize, minsize if tw == 24 and th == 64: #special case for the gnome-shell dimensions - stretch height.. scaled_w, scaled_h = 24, 48 tray_icon = tray_icon.scale_simple(scaled_w, scaled_h, INTERP_HYPER) tray_icon.copy_area(0, 0, scaled_w, scaled_h, new_icon, (tw - scaled_w) // 2, (th - scaled_h) // 2) tray_icon = new_icon else: tray_icon = tray_icon.scale_simple(tw, th, INTERP_HYPER) self.tray_widget.set_from_pixbuf(tray_icon) self.icon_timestamp = monotonic_time()
def set_icon_from_data(self, pixels, has_alpha, w, h, rowstride, _options={}): tray_icon = get_pixbuf_from_data(pixels, has_alpha, w, h, rowstride) self.set_icon_from_pixbuf(tray_icon)
def set_icon_from_data(self, pixels, has_alpha, w, h, rowstride, options=None): tray_icon = get_pixbuf_from_data(pixels, has_alpha, w, h, rowstride) self.macapp.set_dock_icon_pixbuf(tray_icon) self.icon_timestamp = monotonic()
def get_appimage(app_name, icondata=None, menu_icon_size=24): pixbuf = None if app_name and not icondata: #try to load from our icons: nstr = bytestostr(app_name).lower() icon_filename = os.path.join(get_icon_dir(), "%s.png" % nstr) if os.path.exists(icon_filename): pixbuf = GdkPixbuf.Pixbuf.new_from_file(icon_filename) def err(e): log("failed to load icon", exc_info=True) log.error("Error: failed to load icon data for '%s':", bytestostr(app_name)) log.error(" %s", e) log.error(" data=%s", repr_ellipsized(icondata)) if not pixbuf and icondata: #gtk pixbuf loader: try: pixbuf = load_pixbuf(icondata) except Exception as e: log("pixbuf loader failed", exc_info=True) if re.findall(INKSCAPE_RE, icondata): try: pixbuf = load_pixbuf(re.sub(INKSCAPE_RE, b"", icondata)) e = None except Exception: #there is almost no chance pillow will be able to load it #(it doesn't even have svg support at time of writing) #so don't bother showing another error for the same data: icondata = None if e: err(e) if not pixbuf and icondata: #let's try pillow: try: from xpra.codecs.pillow.decoder import open_only #pylint: disable=import-outside-toplevel img = open_only(icondata) has_alpha = img.mode == "RGBA" width, height = img.size rowstride = width * (3 + int(has_alpha)) pixbuf = get_pixbuf_from_data(img.tobytes(), has_alpha, width, height, rowstride) return scaled_image(pixbuf, icon_size=menu_icon_size) except Exception: err(e) if pixbuf: return scaled_image(pixbuf, icon_size=menu_icon_size) return None
def update_icon(self, width, height, coding, data): coding = bytestostr(coding) iconlog("%s.update_icon(%s, %s, %s, %s bytes)", self, width, height, coding, len(data)) if PYTHON3 and WIN32: iconlog("not setting icon to prevent crashes..") return if coding == "premult_argb32": #we usually cannot do in-place and this is not performance critical data = unpremultiply_argb(data) rgba = memoryview_to_bytes(bgra_to_rgba(data)) pixbuf = get_pixbuf_from_data(rgba, True, width, height, width*4) else: loader = PixbufLoader() loader.write(data) loader.close() pixbuf = loader.get_pixbuf() #for debugging, save to a file so we can see it: #pixbuf.save("C-%s-%s.png" % (self._id, int(time.time())), "png") iconlog("%s.set_icon(%s)", self, pixbuf) self.set_icon(pixbuf)
def update_icon(self, width, height, coding, data): log("%s.update_icon(%s, %s, %s, %s bytes)", self, width, height, coding, len(data)) coding = bytestostr(coding) if coding == "premult_argb32": if unpremultiply_argb is None: #we could use PIL here with mode 'RGBa' log.warn("cannot process premult_argb32 icon without the argb module") return #we usually cannot do in-place and this is not performance critical data = unpremultiply_argb(data) rgba = byte_buffer_to_buffer(bgra_to_rgba(data)) pixbuf = get_pixbuf_from_data(rgba, True, width, height, width*4) else: loader = PixbufLoader() loader.write(data) loader.close() pixbuf = loader.get_pixbuf() log("%s.set_icon(%s)", self, pixbuf) self.set_icon(pixbuf)
def update_icon(self, width, height, coding, data): coding = bytestostr(coding) iconlog("%s.update_icon(%s, %s, %s, %s bytes)", self, width, height, coding, len(data)) if PYTHON3 and WIN32: iconlog("not setting icon to prevent crashes..") return if coding == "premult_argb32": #we usually cannot do in-place and this is not performance critical data = unpremultiply_argb(data) rgba = memoryview_to_bytes(bgra_to_rgba(data)) pixbuf = get_pixbuf_from_data(rgba, True, width, height, width * 4) else: loader = PixbufLoader() loader.write(data) loader.close() pixbuf = loader.get_pixbuf() #for debugging, save to a file so we can see it: #pixbuf.save("C-%s-%s.png" % (self._id, int(time.time())), "png") iconlog("%s.set_icon(%s)", self, pixbuf) self.set_icon(pixbuf)
def get_appimage(app_name, icondata=None, menu_icon_size=24): pixbuf = None if app_name and not icondata: #try to load from our icons: nstr = bytestostr(app_name).lower() icon_filename = os.path.join(get_icon_dir(), "%s.png" % nstr) if os.path.exists(icon_filename): pixbuf = GdkPixbuf.Pixbuf.new_from_file(icon_filename) if not pixbuf and icondata: #gtk pixbuf loader: try: loader = GdkPixbuf.PixbufLoader() loader.write(icondata) loader.close() pixbuf = loader.get_pixbuf() except Exception as e: log("pixbuf loader failed", exc_info=True) log.error("Error: failed to load icon data for '%s':", bytestostr(app_name)) log.error(" %s", e) log.error(" data=%s", repr_ellipsized(icondata)) if not pixbuf and icondata: #let's try pillow: try: from xpra.codecs.pillow.decoder import open_only img = open_only(icondata) has_alpha = img.mode == "RGBA" width, height = img.size rowstride = width * (3 + int(has_alpha)) pixbuf = get_pixbuf_from_data(img.tobytes(), has_alpha, width, height, rowstride) return scaled_image(pixbuf, icon_size=menu_icon_size) except Exception: log.error("Error: failed to load icon data for %s", bytestostr(app_name), exc_info=True) log.error(" data=%s", repr_ellipsized(icondata)) if pixbuf: return scaled_image(pixbuf, icon_size=menu_icon_size) return None
def update_icon(self, width, height, coding, data): log("%s.update_icon(%s, %s, %s, %s bytes)", self, width, height, coding, len(data)) coding = bytestostr(coding) if coding == "premult_argb32": if unpremultiply_argb is None: #we could use PIL here with mode 'RGBa' log.warn( "cannot process premult_argb32 icon without the argb module" ) return #we usually cannot do in-place and this is not performance critical data = unpremultiply_argb(data) rgba = byte_buffer_to_buffer(bgra_to_rgba(data)) pixbuf = get_pixbuf_from_data(rgba, True, width, height, width * 4) else: loader = PixbufLoader() loader.write(data) loader.close() pixbuf = loader.get_pixbuf() log("%s.set_icon(%s)", self, pixbuf) self.set_icon(pixbuf)
def make_cursor(self, cursor_data): #if present, try cursor ny name: display = display_get_default() cursorlog( "make_cursor: has-name=%s, has-cursor-types=%s, xscale=%s, yscale=%s, USE_LOCAL_CURSORS=%s", len(cursor_data) >= 9, bool(cursor_types), self.xscale, self.yscale, USE_LOCAL_CURSORS) #named cursors cannot be scaled (round to 10 to compare so 0.95 and 1.05 are considered the same as 1.0, no scaling): if len(cursor_data) >= 9 and cursor_types and iround( self.xscale * 10) == 10 and iround(self.yscale * 10) == 10: cursor_name = bytestostr(cursor_data[8]) if cursor_name and USE_LOCAL_CURSORS: gdk_cursor = cursor_types.get(cursor_name.upper()) if gdk_cursor is not None: cursorlog("setting new cursor by name: %s=%s", cursor_name, gdk_cursor) return new_Cursor_for_display(display, gdk_cursor) else: global missing_cursor_names if cursor_name not in missing_cursor_names: cursorlog("cursor name '%s' not found", cursor_name) missing_cursor_names.add(cursor_name) #create cursor from the pixel data: w, h, xhot, yhot, serial, pixels = cursor_data[2:8] if len(pixels) < w * h * 4: import binascii cursorlog.warn( "not enough pixels provided in cursor data: %s needed and only %s bytes found (%s)", w * h * 4, len(pixels), binascii.hexlify(pixels)[:100]) return pixbuf = get_pixbuf_from_data(pixels, True, w, h, w * 4) x = max(0, min(xhot, w - 1)) y = max(0, min(yhot, h - 1)) csize = display.get_default_cursor_size() cmaxw, cmaxh = display.get_maximal_cursor_size() if len(cursor_data) >= 11: ssize = cursor_data[9] smax = cursor_data[10] cursorlog("server cursor sizes: default=%s, max=%s", ssize, smax) cursorlog( "new cursor at %s,%s with serial=%s, dimensions: %sx%s, len(pixels)=%s, default cursor size is %s, maximum=%s", xhot, yhot, serial, w, h, len(pixels), csize, (cmaxw, cmaxh)) fw, fh = get_fixed_cursor_size() if fw > 0 and fh > 0 and (w != fw or h != fh): #OS wants a fixed cursor size! (win32 does, and GTK doesn't do this for us) if w <= fw and h <= fh: cursorlog( "pasting cursor of size %ix%i onto clear pixbuf of size %ix%i", w, h, fw, fh) cursor_pixbuf = get_pixbuf_from_data("\0" * fw * fh * 4, True, fw, fh, fw * 4) pixbuf.copy_area(0, 0, w, h, cursor_pixbuf, 0, 0) else: cursorlog("scaling cursor from %ix%i to fixed OS size %ix%i", w, h, fw, fh) cursor_pixbuf = pixbuf.scale_simple(fw, fh, INTERP_BILINEAR) xratio, yratio = float(w) / fw, float(h) / fh x, y = iround(x / xratio), iround(y / yratio) else: sx, sy, sw, sh = x, y, w, h #scale the cursors: if self.xscale != 1 or self.yscale != 1: sx, sy, sw, sh = self.srect(x, y, w, h) sw = max(1, sw) sh = max(1, sh) #ensure we honour the max size if there is one: if (cmaxw > 0 and sw > cmaxw) or (cmaxh > 0 and sh > cmaxh): ratio = 1.0 if cmaxw > 0: ratio = max(ratio, float(w) / cmaxw) if cmaxh > 0: ratio = max(ratio, float(h) / cmaxh) cursorlog("clamping cursor size to %ix%i using ratio=%s", cmaxw, cmaxh, ratio) sx, sy, sw, sh = iround(x / ratio), iround(y / ratio), min( cmaxw, iround(w / ratio)), min(cmaxh, iround(h / ratio)) if sw != w or sh != h: cursorlog( "scaling cursor from %ix%i hotspot at %ix%i to %ix%i hotspot at %ix%i", w, h, x, y, sw, sh, sx, sy) cursor_pixbuf = pixbuf.scale_simple(sw, sh, INTERP_BILINEAR) x, y = sx, sy else: cursor_pixbuf = pixbuf #clamp to pixbuf size: w = cursor_pixbuf.get_width() h = cursor_pixbuf.get_height() x = max(0, min(x, w - 1)) y = max(0, min(y, h - 1)) try: c = new_Cursor_from_pixbuf(display, cursor_pixbuf, x, y) except RuntimeError as e: log.error("Error: failed to create cursor:") log.error(" %s", e) log.error(" using %s of size %ix%i with hotspot at %ix%i", cursor_pixbuf, w, h, x, y) c = None return c
def small_empty_cursor(): #same as xterm when pressing a modifier key w, h = 6, 13 rgb_data = b"\0"*w*h*4 pixbuf = get_pixbuf_from_data(rgb_data, True, w, h, w*4) return Gdk.Cursor(Gdk.display_get_default(), pixbuf, 0, 11)
def set_icon_from_data(self, pixels, has_alpha, w, h, rowstride): tray_icon = get_pixbuf_from_data(pixels, has_alpha, w, h, rowstride) self.set_icon_from_pixbuf(tray_icon)
def make_cursor(self, cursor_data): #if present, try cursor ny name: display = display_get_default() cursorlog("make_cursor: has-name=%s, has-cursor-types=%s, xscale=%s, yscale=%s, USE_LOCAL_CURSORS=%s", len(cursor_data)>=9, bool(cursor_types), self.xscale, self.yscale, USE_LOCAL_CURSORS) #named cursors cannot be scaled (round to 10 to compare so 0.95 and 1.05 are considered the same as 1.0, no scaling): if len(cursor_data)>=9 and cursor_types and iround(self.xscale*10)==10 and iround(self.yscale*10)==10: cursor_name = bytestostr(cursor_data[8]) if cursor_name and USE_LOCAL_CURSORS: gdk_cursor = cursor_types.get(cursor_name.upper()) if gdk_cursor is not None: cursorlog("setting new cursor by name: %s=%s", cursor_name, gdk_cursor) return new_Cursor_for_display(display, gdk_cursor) else: global missing_cursor_names if cursor_name not in missing_cursor_names: cursorlog("cursor name '%s' not found", cursor_name) missing_cursor_names.add(cursor_name) #create cursor from the pixel data: w, h, xhot, yhot, serial, pixels = cursor_data[2:8] if len(pixels)<w*h*4: import binascii cursorlog.warn("not enough pixels provided in cursor data: %s needed and only %s bytes found (%s)", w*h*4, len(pixels), binascii.hexlify(pixels)[:100]) return pixbuf = get_pixbuf_from_data(pixels, True, w, h, w*4) x = max(0, min(xhot, w-1)) y = max(0, min(yhot, h-1)) csize = display.get_default_cursor_size() cmaxw, cmaxh = display.get_maximal_cursor_size() if len(cursor_data)>=11: ssize = cursor_data[9] smax = cursor_data[10] cursorlog("server cursor sizes: default=%s, max=%s", ssize, smax) cursorlog("new cursor at %s,%s with serial=%s, dimensions: %sx%s, len(pixels)=%s, default cursor size is %s, maximum=%s", xhot,yhot, serial, w,h, len(pixels), csize, (cmaxw, cmaxh)) fw, fh = get_fixed_cursor_size() if fw>0 and fh>0 and (w!=fw or h!=fh): #OS wants a fixed cursor size! (win32 does, and GTK doesn't do this for us) if w<=fw and h<=fh: cursorlog("pasting cursor of size %ix%i onto clear pixbuf of size %ix%i", w, h, fw, fh) cursor_pixbuf = get_pixbuf_from_data("\0"*fw*fh*4, True, fw, fh, fw*4) pixbuf.copy_area(0, 0, w, h, cursor_pixbuf, 0, 0) else: cursorlog("scaling cursor from %ix%i to fixed OS size %ix%i", w, h, fw, fh) cursor_pixbuf = pixbuf.scale_simple(fw, fh, INTERP_BILINEAR) xratio, yratio = float(w)/fw, float(h)/fh x, y = iround(x/xratio), iround(y/yratio) else: sx, sy, sw, sh = x, y, w, h #scale the cursors: if self.xscale!=1 or self.yscale!=1: sx, sy, sw, sh = self.srect(x, y, w, h) sw = max(1, sw) sh = max(1, sh) #ensure we honour the max size if there is one: if (cmaxw>0 and sw>cmaxw) or (cmaxh>0 and sh>cmaxh): ratio = 1.0 if cmaxw>0: ratio = max(ratio, float(w)/cmaxw) if cmaxh>0: ratio = max(ratio, float(h)/cmaxh) cursorlog("clamping cursor size to %ix%i using ratio=%s", cmaxw, cmaxh, ratio) sx, sy, sw, sh = iround(x/ratio), iround(y/ratio), min(cmaxw, iround(w/ratio)), min(cmaxh, iround(h/ratio)) if sw!=w or sh!=h: cursorlog("scaling cursor from %ix%i hotspot at %ix%i to %ix%i hotspot at %ix%i", w, h, x, y, sw, sh, sx, sy) cursor_pixbuf = pixbuf.scale_simple(sw, sh, INTERP_BILINEAR) x, y = sx, sy else: cursor_pixbuf = pixbuf #clamp to pixbuf size: w = cursor_pixbuf.get_width() h = cursor_pixbuf.get_height() x = max(0, min(x, w-1)) y = max(0, min(y, h-1)) try: c = new_Cursor_from_pixbuf(display, cursor_pixbuf, x, y) except RuntimeError as e: log.error("Error: failed to create cursor:") log.error(" %s", e) log.error(" using %s of size %ix%i with hotspot at %ix%i", cursor_pixbuf, w, h, x, y) c = None return c
def make_cursor(self, cursor_data): #if present, try cursor ny name: display = display_get_default() if len(cursor_data) >= 9 and cursor_types: cursor_name = bytestostr(cursor_data[8]) if cursor_name: gdk_cursor = cursor_types.get(cursor_name.upper()) if gdk_cursor is not None: cursorlog("setting new cursor by name: %s=%s", cursor_name, gdk_cursor) return new_Cursor_for_display(display, gdk_cursor) else: global missing_cursor_names if cursor_name not in missing_cursor_names: cursorlog("cursor name '%s' not found", cursor_name) missing_cursor_names.add(cursor_name) #create cursor from the pixel data: w, h, xhot, yhot, serial, pixels = cursor_data[2:8] if len(pixels) < w * h * 4: import binascii cursorlog.warn( "not enough pixels provided in cursor data: %s needed and only %s bytes found (%s)", w * h * 4, len(pixels), binascii.hexlify(pixels)[:100]) return pixbuf = get_pixbuf_from_data(pixels, True, w, h, w * 4) x = max(0, min(xhot, w - 1)) y = max(0, min(yhot, h - 1)) csize = display.get_default_cursor_size() cmaxw, cmaxh = display.get_maximal_cursor_size() if len(cursor_data) >= 11: ssize = cursor_data[9] smax = cursor_data[10] cursorlog("server cursor sizes: default=%s, max=%s", ssize, smax) cursorlog( "new cursor at %s,%s with serial=%s, dimensions: %sx%s, len(pixels)=%s, default cursor size is %s, maximum=%s", xhot, yhot, serial, w, h, len(pixels), csize, (cmaxw, cmaxh)) fw, fh = get_fixed_cursor_size() if fw > 0 and fh > 0 and (w != fw or h != fh): #OS wants a fixed cursor size! (win32 does, and GTK doesn't do this for us) if w <= fw and h <= fh: cursorlog( "pasting cursor of size %ix%i onto clear pixbuf of size %ix%i", w, h, fw, fh) cursor_pixbuf = get_pixbuf_from_data("\0" * fw * fh * 4, True, fw, fh, fw * 4) pixbuf.copy_area(0, 0, w, h, cursor_pixbuf, 0, 0) else: cursorlog("scaling cursor from %ix%i to fixed OS size %ix%i", w, h, fw, fh) cursor_pixbuf = pixbuf.scale_simple(fw, fh, INTERP_BILINEAR) xratio, yratio = float(w) / fw, float(h) / fh x, y = int(x / xratio), int(y / yratio) elif w > cmaxw or h > cmaxh or (csize > 0 and (csize < w or csize < h)): ratio = max( float(w) / cmaxw, float(h) / cmaxh, float(max(w, h)) / csize) x, y, w, h = int(x / ratio), int(y / ratio), int(w / ratio), int( h / ratio) cursorlog("downscaling cursor %s by %.2f: %sx%s", pixbuf, ratio, w, h) cursor_pixbuf = pixbuf.scale_simple(w, h, INTERP_BILINEAR) else: cursor_pixbuf = pixbuf #clamp to pixbuf size: w = cursor_pixbuf.get_width() h = cursor_pixbuf.get_height() x = max(0, min(x, w - 1)) y = max(0, min(y, h - 1)) return new_Cursor_from_pixbuf(display, cursor_pixbuf, x, y)