def _do_paint_rgb(self, cairo_format, has_alpha, img_data, x, y, width, height, rowstride, options): """ must be called from UI thread """ log("cairo._do_paint_rgb(%s, %s, %s bytes,%s,%s,%s,%s,%s,%s)", cairo_format, has_alpha, len(img_data), x, y, width, height, rowstride, options) rgb_format = options.strget("rgb_format", "RGB") if _memoryview and isinstance(img_data, _memoryview): #Pixbuf cannot use the memoryview directly: img_data = img_data.tobytes() #"cairo.ImageSurface.create_for_data" is not implemented in GTK3! ARGH! # http://cairographics.org/documentation/pycairo/3/reference/surfaces.html#cairo.ImageSurface.create_for_data # "Not yet available in Python 3" # #It is available in the cffi cairo bindings, which can be used instead of pycairo # but then we can't use it from the draw callbacks: # https://mail.gnome.org/archives/python-hackers-list/2011-December/msg00004.html # "PyGObject just lacks the glue code that allows it to pass the statically-wrapped # cairo.Pattern to introspected methods" if not is_gtk3() and rgb_format in ("ARGB", "XRGB"): #the pixel format is also what cairo expects #maybe we should also check that the stride is acceptable for cairo? #cairo_stride = cairo.ImageSurface.format_stride_for_width(cairo_format, width) #log("cairo_stride=%s, stride=%s", cairo_stride, rowstride) img_surface = cairo.ImageSurface.create_for_data(img_data, cairo_format, width, height, rowstride) return self.cairo_paint_surface(img_surface, x, y) if not is_gtk3() and rgb_format in ("RGBA", "RGBX"): #with GTK2, we can use a pixbuf from RGB(A) pixels if rgb_format=="RGBA": #we have to unpremultiply for pixbuf! img_data = self.unpremultiply(img_data) pixbuf = pixbuf_new_from_data(img_data, COLORSPACE_RGB, has_alpha, 8, width, height, rowstride) return self.cairo_paint_pixbuf(pixbuf, x, y) #PIL fallback PIL = get_codec("PIL") if has_alpha: oformat = "RGBA" else: oformat = "RGB" img = PIL.Image.frombuffer(oformat, (width,height), img_data, "raw", rgb_format, rowstride, 1) #This is insane, the code below should work, but it doesn't: # img_data = bytearray(img.tostring('raw', oformat, 0, 1)) # pixbuf = pixbuf_new_from_data(img_data, COLORSPACE_RGB, True, 8, width, height, rowstride) # success = self.cairo_paint_pixbuf(pixbuf, x, y) #So we still rountrip via PNG: png = BytesIOClass() img.save(png, format="PNG") reader = BytesIOClass(png.getvalue()) png.close() img = cairo.ImageSurface.create_from_png(reader) return self.cairo_paint_surface(img, x, y)
def get_preferred_size(widget): if is_gtk3(): #ignore "min", we only care about "natural": _, w = widget.get_preferred_width() _, h = widget.get_preferred_height() return w, h return widget.size_request()
def get_pixbuf_from_data(rgb_data, has_alpha, w, h, rowstride): if is_gtk3(): data = array.array('B', strtobytes(rgb_data)) return GdkPixbuf.Pixbuf.new_from_data(data, GdkPixbuf.Colorspace.RGB, True, 8, w, h, rowstride, None, None) return gdk.pixbuf_new_from_data(rgb_data, gdk.COLORSPACE_RGB, has_alpha, 8, w, h, rowstride)
def add_close_accel(window, callback): if is_gtk3(): return #TODO: implement accel for gtk3 accel_group = gtk.AccelGroup() accel_group.connect_group(ord('w'), gdk.CONTROL_MASK, gtk.ACCEL_LOCKED, callback) window.add_accel_group(accel_group) accel_group = gtk.AccelGroup() key, mod = gtk.accelerator_parse('<Alt>F4') accel_group.connect_group(key, mod, gtk.ACCEL_LOCKED, callback) escape_key, modifier = gtk.accelerator_parse('Escape') accel_group.connect_group(escape_key, modifier, gtk.ACCEL_LOCKED | gtk.ACCEL_VISIBLE, callback) window.add_accel_group(accel_group)
def owner_changed(self, cb, event): r = {} if not is_gtk3(): r = {gtk.gdk.OWNER_CHANGE_CLOSE : "close", gtk.gdk.OWNER_CHANGE_DESTROY : "destroy", gtk.gdk.OWNER_CHANGE_NEW_OWNER : "new owner"} owner = self.clipboard.get_owner() #print("xid=%s, owner=%s" % (self.value_entry.get_window().xid, event.owner)) weownit = (owner is not None) if weownit: owner_info="(us)" else: owner_info = hex(event.owner) self.log("Owner changed, reason: %s, new owner=%s" % ( r.get(event.reason, event.reason), owner_info))
def add_close_accel(window, callback): if is_gtk3(): def connect(ag, *args): ag.connect(*args) else: def connect(ag, *args): ag.connect_group(*args) accel_group = gtk.AccelGroup() key, mod = gtk.accelerator_parse('<control>F4') connect(accel_group, key, mod, ACCEL_LOCKED, callback) window.add_accel_group(accel_group) accel_group = gtk.AccelGroup() key, mod = gtk.accelerator_parse('<Alt>F4') connect(accel_group, key, mod, ACCEL_LOCKED, callback) escape_key, modifier = gtk.accelerator_parse('Escape') connect(accel_group, escape_key, modifier, ACCEL_LOCKED | ACCEL_VISIBLE, callback) window.add_accel_group(accel_group)
def about(on_close=None): global about_dialog if about_dialog: about_dialog.show() about_dialog.present() return from xpra.platform.paths import get_icon xpra_icon = get_icon("xpra.png") dialog = gtk.AboutDialog() if not is_gtk3(): def on_website_hook(dialog, web, *args): ''' called when the website item is selected ''' webbrowser.open(SITE_URL) def on_email_hook(dialog, mail, *args): webbrowser.open("mailto://[email protected]") gtk.about_dialog_set_url_hook(on_website_hook) gtk.about_dialog_set_email_hook(on_email_hook) if xpra_icon: dialog.set_icon(xpra_icon) dialog.set_name("Xpra") dialog.set_version(__version__) dialog.set_authors(('Antoine Martin <*****@*****.**>', 'Nathaniel Smith <*****@*****.**>', 'Serviware - Arthur Huillet <*****@*****.**>')) _license = load_license() dialog.set_license(_license or "Your installation may be corrupted," + " the license text for GPL version 2 could not be found," + "\nplease refer to:\nhttp://www.gnu.org/licenses/gpl-2.0.txt") dialog.set_comments("\n".join(get_build_info())) dialog.set_website(SITE_URL) dialog.set_website_label(SITE_DOMAIN) if xpra_icon: dialog.set_logo(xpra_icon) if hasattr(dialog, "set_program_name"): dialog.set_program_name(APPLICATION_NAME) def close(*args): close_about() #the about function may be called as a widget callback #so avoid calling the widget as if it was a function! if on_close and hasattr(on_close, '__call__'): on_close() dialog.connect("response", close) add_close_accel(dialog, close) about_dialog = dialog dialog.show()
def make_client(error_cb, opts): app = None if not opts.client_toolkit: from xpra.gtk_common.gobject_compat import import_gobject, is_gtk3 import_gobject() if is_gtk3(): opts.client_toolkit = "gtk3" else: opts.client_toolkit = "gtk2" ct = opts.client_toolkit.lower() toolkits = {} try: import gtk.gdk #@UnusedImport import xpra.client.gtk2 #@UnusedImport toolkits["gtk2"] = "xpra.client.gtk2.client" except Exception, e: print("cannot load gtk2: %s" % e)
def do_setup_xprops(self, *args): log("do_setup_xprops(%s)", args) if is_gtk3(): log("x11 root properties and XSETTINGS are not supported yet with GTK3") return ROOT_PROPS = ["RESOURCE_MANAGER", "_NET_WORKAREA", "_NET_CURRENT_DESKTOP"] try: from xpra.x11.xsettings import XSettingsWatcher from xpra.x11.xroot_props import XRootPropWatcher if self._xsettings_watcher is None: self._xsettings_watcher = XSettingsWatcher() self._xsettings_watcher.connect("xsettings-changed", self._handle_xsettings_changed) self._handle_xsettings_changed() if self._root_props_watcher is None: self._root_props_watcher = XRootPropWatcher(ROOT_PROPS) self._root_props_watcher.connect("root-prop-changed", self._handle_root_prop_changed) #ensure we get the initial value: self._root_props_watcher.do_notify("RESOURCE_MANAGER") except ImportError as e: log.error("failed to load X11 properties/settings bindings: %s - root window properties will not be propagated", e)
def get_gtk_version_info(): #update props given: global GTK_VERSION_INFO def av(k, v): GTK_VERSION_INFO.setdefault(k, {})["version"] = v if not GTK_VERSION_INFO: if hasattr(gtk, "pygtk_version"): av("pygtk", gtk.pygtk_version) if hasattr(gtk, "gtk_version"): #GTK2: av("gtk", gtk.gtk_version) elif hasattr(gtk, "_version"): #GTK3: av("gtk", gtk._version) if hasattr(gdk, "__version__"): #GTK2: av("gdk", gdk.__version__) elif hasattr(gdk, "_version"): #GTK3: av("gdk", gdk._version) if is_gtk3(): try: import gi av("gi", gi.__version__) except: pass if hasattr(gobject, "pygobject_version"): av("gobject", gobject.pygobject_version) elif hasattr(gobject, "_version"): av("gobject", gobject._version) if hasattr(cairo, "version"): av("cairo", cairo.version) if hasattr(pango, "version_string"): av("pango", pango.version_string()) try: import glib av("glib", glib.glib_version) av("pyglib", glib.pyglib_version) except: pass return GTK_VERSION_INFO.copy()
def grok_modifier_map(display, meanings): """Return an dict mapping modifier names to corresponding X modifier bitmasks.""" #TODO: needs fixing for GTK3 from xpra.keyboard.mask import MODIFIER_MAP modifier_map = MODIFIER_MAP.copy() modifier_map.update({ "scroll": 0, "num": 0, "meta": 0, "super": 0, "hyper": 0, "alt": 0, }) if not meanings: meanings = DEFAULT_MODIFIER_MEANINGS (max_keypermod, keycodes) = X11Keyboard.get_modifier_map() assert len(keycodes) == 8 * max_keypermod keymap = keymap_get_for_display(display) for i in range(8): for j in range(max_keypermod): keycode = keycodes[i * max_keypermod + j] if keycode: entries = keymap.get_entries_for_keycode(keycode) if entries is None: # This keycode has no entry in the keymap: continue if is_gtk3(): found, _, keyvals = entries if not found: continue else: #(keyval, _, _, _) in entries keyvals = [x[0] for x in entries] for keyval in keyvals: keyval_name = gdk.keyval_name(keyval) modifier = meanings.get(keyval_name) if modifier: modifier_map[modifier] |= (1 << i) return modifier_map
def get_gtk_version_info(): #update props given: global GTK_VERSION_INFO if not GTK_VERSION_INFO: if hasattr(gtk, "pygtk_version"): GTK_VERSION_INFO["pygtk.version"] = gtk.pygtk_version if hasattr(gtk, "gtk_version"): #GTK2: GTK_VERSION_INFO["gtk.version"] = gtk.gtk_version elif hasattr(gtk, "_version"): #GTK3: GTK_VERSION_INFO["gtk.version"] = gtk._version if hasattr(gdk, "__version__"): #GTK2: GTK_VERSION_INFO["gdk.version"] = gdk.__version__ elif hasattr(gdk, "_version"): #GTK3: GTK_VERSION_INFO["gdk.version"] = gdk._version if is_gtk3(): try: import gi GTK_VERSION_INFO["gi.version"] = gi.__version__ except: pass if hasattr(gobject, "pygobject_version"): GTK_VERSION_INFO["gobject.version"] = gobject.pygobject_version elif hasattr(gobject, "_version"): GTK_VERSION_INFO["gobject.version"] = gobject._version if hasattr(cairo, "version"): GTK_VERSION_INFO["cairo.version"] = cairo.version if hasattr(pango, "version_string"): GTK_VERSION_INFO["pango.version"] = pango.version_string() try: import glib GTK_VERSION_INFO["glib.version"] = glib.glib_version GTK_VERSION_INFO["pyglib.version"] = glib.pyglib_version except: pass return GTK_VERSION_INFO.copy()
def __init__(self): self.window = gtk.Window() self.window.connect("destroy", self.destroy) self.window.set_default_size(540, 800) self.window.set_border_width(20) self.window.set_title("Keyboard State Tool") # Title vbox = gtk.VBox(False, 0) vbox.set_spacing(15) label = gtk.Label("Keyboard State") label.modify_font(pango.FontDescription("sans 13")) vbox.pack_start(label) self.modifiers = gtk.Label() vbox.add(self.modifiers) self.mouse = gtk.Label() vbox.add(self.mouse) self.keys = gtk.Label() fixed = pango.FontDescription('monospace 9') self.keys.modify_font(fixed) vbox.add(self.keys) self.window.add(vbox) self.window.show_all() gobject.timeout_add(100, self.populate_modifiers) self.key_events = maxdeque(maxlen=35) self.window.connect("key-press-event", self.key_press) self.window.connect("key-release-event", self.key_release) if not is_gtk3(): self.window.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2)) icon = get_icon("keyboard.png") if icon: self.window.set_icon(icon)
def imagebutton(title, icon, tooltip=None, clicked_callback=None, icon_size=32, default=False, min_size=None, label_color=None): button = gtk.Button(title) settings = button.get_settings() settings.set_property('gtk-button-images', True) if icon: button.set_image(scaled_image(icon, icon_size)) if tooltip: button.set_tooltip_text(tooltip) if min_size: button.set_size_request(min_size, min_size) if clicked_callback: button.connect("clicked", clicked_callback) if default: if is_gtk3(): button.set_can_default(True) else: button.set_flags(gtk.CAN_DEFAULT) if label_color: alignment = button.get_children()[0] b_hbox = alignment.get_children()[0] label = b_hbox.get_children()[1] label.modify_fg(STATE_NORMAL, label_color) return button
import os import sys #pygtk3 vs pygtk2 (sigh) from xpra.gtk_common.gobject_compat import import_gobject, import_cairo, is_gtk3 gobject = import_gobject() cairo = import_cairo() from xpra.client.window_backing_base import WindowBackingBase, unpremultiply_argb from xpra.log import Logger log = Logger("paint") #transparency with GTK: # - on MS Windows: not supported # - on OSX: only with gtk3 DEFAULT_HAS_ALPHA = not sys.platform.startswith("win") and (not sys.platform.startswith("darwin") or is_gtk3()) GTK_ALPHA_SUPPORTED = (unpremultiply_argb is not None) and os.environ.get("XPRA_ALPHA", DEFAULT_HAS_ALPHA) in (True, "1") """ Generic GTK superclass for Backing code (for both GTK2 and GTK3), see CairoBacking, PixmapBacking and TrayBacking for actual implementations. (some may override HAS_ALPHA, TrayBacking does) """ class GTKWindowBacking(WindowBackingBase): HAS_ALPHA = GTK_ALPHA_SUPPORTED def __init__(self, wid, window_alpha): WindowBackingBase.__init__(self, wid, window_alpha and self.HAS_ALPHA, gobject.idle_add)
def init_opengl(self, enable_opengl): opengllog("init_opengl(%s)", enable_opengl) #enable_opengl can be True, False or None (auto-detect) if enable_opengl is False: self.opengl_props["info"] = "disabled by configuration" return from xpra.scripts.config import OpenGL_safety_check from xpra.platform.gui import gl_check as platform_gl_check warnings = [] for check in (OpenGL_safety_check, platform_gl_check): opengllog("checking with %s", check) warning = check() opengllog("%s()=%s", check, warning) if warning: warnings.append(warning) self.opengl_props["info"] = "" if warnings: if enable_opengl is True: opengllog.warn("OpenGL safety warning (enabled at your own risk):") for warning in warnings: opengllog.warn(" %s", warning) self.opengl_props["info"] = "forced enabled despite: %s" % (", ".join(warnings)) else: opengllog.warn("OpenGL disabled:", warning) for warning in warnings: opengllog.warn(" %s", warning) self.opengl_props["info"] = "disabled: %s" % (", ".join(warnings)) return try: opengllog("init_opengl: going to import xpra.client.gl") __import__("xpra.client.gl", {}, {}, []) __import__("xpra.client.gl.gtk_compat", {}, {}, []) gl_check = __import__("xpra.client.gl.gl_check", {}, {}, ["check_support"]) opengllog("init_opengl: gl_check=%s", gl_check) self.opengl_props = gl_check.check_support(force_enable=(enable_opengl is True)) opengllog("init_opengl: found props %s", self.opengl_props) GTK_GL_CLIENT_WINDOW_MODULE = "xpra.client.gl.gtk%s.gl_client_window" % (2+int(is_gtk3())) opengllog("init_opengl: trying to load GL client window module '%s'", GTK_GL_CLIENT_WINDOW_MODULE) gl_client_window = __import__(GTK_GL_CLIENT_WINDOW_MODULE, {}, {}, ["GLClientWindow"]) self.GLClientWindowClass = gl_client_window.GLClientWindow self.client_supports_opengl = True #only enable opengl by default if force-enabled or if safe to do so: self.opengl_enabled = (enable_opengl is True) or self.opengl_props.get("safe", False) self.gl_texture_size_limit = self.opengl_props.get("texture-size-limit", 16*1024) self.gl_max_viewport_dims = self.opengl_props.get("max-viewport-dims", (self.gl_texture_size_limit, self.gl_texture_size_limit)) if min(self.gl_max_viewport_dims)<4*1024: opengllog.warn("Warning: OpenGL is disabled:") opengllog.warn(" the maximum viewport size is too low: %s", self.gl_max_viewport_dims) self.opengl_enabled = False elif self.gl_texture_size_limit<4*1024: opengllog.warn("Warning: OpenGL is disabled:") opengllog.warn(" the texture size limit is too low: %s", self.gl_texture_size_limit) self.opengl_enabled = False self.GLClientWindowClass.MAX_VIEWPORT_DIMS = self.gl_max_viewport_dims self.GLClientWindowClass.MAX_BACKING_DIMS = self.gl_texture_size_limit, self.gl_texture_size_limit self.GLClientWindowClass.MAX_VIEWPORT_DIMS = 8192, 8192 self.GLClientWindowClass.MAX_BACKING_DIMS = 4096, 4096 mww, mwh = self.max_window_size opengllog("OpenGL: enabled=%s, texture-size-limit=%s, max-window-size=%s", self.opengl_enabled, self.gl_texture_size_limit, self.max_window_size) if self.opengl_enabled and self.gl_texture_size_limit<16*1024 and (mww==0 or mwh==0 or self.gl_texture_size_limit<mww or self.gl_texture_size_limit<mwh): #log at warn level if the limit is low: #(if we're likely to hit it - if the screen is as big or bigger) w, h = self.get_root_size() l = opengllog.info if w>=self.gl_texture_size_limit or h>=self.gl_texture_size_limit: l = log.warn l("Warning: OpenGL windows will be clamped to the maximum texture size %ix%i", self.gl_texture_size_limit, self.gl_texture_size_limit) l(" for OpenGL %s renderer '%s'", pver(self.opengl_props.get("opengl", "")), self.opengl_props.get("renderer", "unknown")) driver_info = self.opengl_props.get("renderer") or self.opengl_props.get("vendor") or "unknown card" if self.opengl_enabled: opengllog.info("OpenGL enabled with %s", driver_info) elif self.client_supports_opengl: opengllog("OpenGL supported with %s, but not enabled", driver_info) except ImportError as e: opengllog.warn("OpenGL support is missing:") opengllog.warn(" %s", e) self.opengl_props["info"] = str(e) except RuntimeError as e: opengllog.warn("OpenGL support could not be enabled on this hardware:") opengllog.warn(" %s", e) self.opengl_props["info"] = str(e) except Exception as e: opengllog.error("Error loading OpenGL support:") opengllog.error(" %s", e, exc_info=True) self.opengl_props["info"] = str(e)
# later version. See the file COPYING for details. # A tray implemented using gtk.StatusIcon import os import sys from xpra.util import envbool from xpra.gtk_common.gobject_compat import import_gtk, import_gdk, is_gtk3 gtk = import_gtk() gdk = import_gdk() from xpra.client.tray_base import TrayBase, log from xpra.gtk_common.gtk_util import get_icon_from_file, get_pixbuf_from_data, INTERP_HYPER ORIENTATION = {} if not is_gtk3(): #where was this moved to?? ORIENTATION[gtk.ORIENTATION_HORIZONTAL] = "HORIZONTAL" ORIENTATION[gtk.ORIENTATION_VERTICAL] = "VERTICAL" GUESS_GEOMETRY = sys.platform.startswith("win") or sys.platform.startswith("darwin") GUESS_GEOMETRY = envbool("XPRA_GUESS_ICON_GEOMETRY", GUESS_GEOMETRY) log("tray GUESS_GEOMETRY=%s", GUESS_GEOMETRY) class GTKStatusIconTray(TrayBase): def __init__(self, *args, **kwargs): TrayBase.__init__(self, *args, **kwargs) self.tray_widget = gtk.StatusIcon() self.tray_widget.set_tooltip_text(self.tooltip or "Xpra")
def get_group_leader(self, wid, metadata, override_redirect): transient_for = metadata.intget("transient-for", -1) log("get_group_leader: transient_for=%s", transient_for) if transient_for>0: client_window = self._id_to_window.get(transient_for) if client_window: gdk_window = client_window.get_window() if gdk_window: return gdk_window pid = metadata.intget("pid", -1) leader_xid = metadata.intget("group-leader-xid", -1) leader_wid = metadata.intget("group-leader-wid", -1) group_leader_window = self._id_to_window.get(leader_wid) if group_leader_window: #leader is another managed window log("found group leader window %s for wid=%s", group_leader_window, leader_wid) return group_leader_window log("get_group_leader: leader pid=%s, xid=%s, wid=%s", pid, leader_xid, leader_wid) reftype = "xid" ref = leader_xid if ref<0: reftype = "leader-wid" ref = leader_wid if ref<0: ci = metadata.strlistget("class-instance") if ci: reftype = "class" ref = "|".join(ci) elif pid>0: reftype = "pid" ref = pid elif transient_for>0: #this should have matched a client window above.. #but try to use it anyway: reftype = "transient-for" ref = transient_for else: #no reference to use return None refkey = "%s:%s" % (reftype, ref) group_leader_window = self._ref_to_group_leader.get(refkey) if group_leader_window: log("found existing group leader window %s using ref=%s", group_leader_window, refkey) return group_leader_window #we need to create one: title = "%s group leader for %s" % (self.session_name or "Xpra", pid) #group_leader_window = gdk.Window(None, 1, 1, gdk.WINDOW_TOPLEVEL, 0, gdk.INPUT_ONLY, title) #static new(parent, attributes, attributes_mask) if is_gtk3(): #long winded and annoying attributes = gdk.WindowAttr() attributes.width = 1 attributes.height = 1 attributes.title = title attributes.wclass = gdk.WindowWindowClass.INPUT_ONLY attributes.event_mask = 0 attributes_mask = gdk.WindowAttributesType.TITLE | gdk.WindowAttributesType.WMCLASS group_leader_window = gdk.Window(None, attributes, attributes_mask) group_leader_window.resize(1, 1) else: #gtk2: group_leader_window = gdk.Window(None, 1, 1, gdk.WINDOW_TOPLEVEL, 0, gdk.INPUT_ONLY, title) self._ref_to_group_leader[refkey] = group_leader_window #avoid warning on win32... if not sys.platform.startswith("win"): #X11 spec says window should point to itself: group_leader_window.set_group(group_leader_window) log("new hidden group leader window %s for ref=%s", group_leader_window, refkey) self._group_leader_wids.setdefault(group_leader_window, []).append(wid) return group_leader_window
def setup_window(self): self.window = gtk.Window() self.window.connect("destroy", self.close) self.window.set_default_size(400, 300) self.window.set_border_width(20) self.window.set_title("Xpra Bug Report") self.window.modify_bg(STATE_NORMAL, gdk.Color(red=65535, green=65535, blue=65535)) icon_pixbuf = self.get_icon("bugs.png") if icon_pixbuf: self.window.set_icon(icon_pixbuf) self.window.set_position(WIN_POS_CENTER) vbox = gtk.VBox(False, 0) vbox.set_spacing(15) # Title hbox = gtk.HBox(False, 0) icon_pixbuf = self.get_icon("xpra.png") if icon_pixbuf and self.show_about: from xpra.gtk_common.about import about logo_button = gtk.Button("") settings = logo_button.get_settings() settings.set_property('gtk-button-images', True) logo_button.connect("clicked", about) logo_button.set_tooltip_text("About") image = gtk.Image() image.set_from_pixbuf(icon_pixbuf) logo_button.set_image(image) hbox.pack_start(logo_button, expand=False, fill=False) label = gtk.Label("Xpra Bug Report Tool") label.modify_font(pango.FontDescription("sans 14")) hbox.pack_start(label, expand=True, fill=True) vbox.pack_start(hbox) #the box containing all the input: ibox = gtk.VBox(False, 0) ibox.set_spacing(3) vbox.pack_start(ibox) # Description al = gtk.Alignment(xalign=0, yalign=0.5, xscale=0.0, yscale=0) al.add(gtk.Label("Please describe the problem:")) ibox.pack_start(al) #self.description = gtk.Entry(max=128) #self.description.set_width_chars(40) self.description = gtk.TextView() self.description.set_accepts_tab(True) self.description.set_justification(JUSTIFY_LEFT) self.description.set_border_width(2) self.description.set_size_request(300, 80) self.description.modify_bg( STATE_NORMAL, gdk.Color(red=32768, green=32768, blue=32768)) ibox.pack_start(self.description, expand=False, fill=False) # Toggles: al = gtk.Alignment(xalign=0, yalign=0.5, xscale=0.0, yscale=0) al.add(gtk.Label("Include:")) ibox.pack_start(al) #generic toggles: from xpra.gtk_common.keymap import get_gtk_keymap from xpra.codecs.loader import codec_versions, load_codecs load_codecs() try: from xpra.sound.wrapper import query_sound def get_sound_info(): return query_sound() except: get_sound_info = None def get_gl_info(): if self.opengl_info: return self.opengl_info try: from xpra.client.gl.gl_check import check_support return check_support(force_enable=True) except Exception as e: return {"error": str(e)} from xpra.net.net_util import get_info as get_net_info from xpra.platform.paths import get_info as get_path_info from xpra.platform.gui import get_info as get_gui_info from xpra.version_util import get_version_info, get_platform_info, get_host_info def get_sys_info(): from xpra.platform.info import get_user_info from xpra.scripts.config import read_xpra_defaults return { "argv": sys.argv, "path": sys.path, "exec_prefix": sys.exec_prefix, "executable": sys.executable, "version": get_version_info(), "platform": get_platform_info(), "host": get_host_info(), "paths": get_path_info(), "gtk": get_gtk_version_info(), "gui": get_gui_info(), "display": get_display_info(), "user": get_user_info(), "env": os.environ, "config": read_xpra_defaults(), } get_screenshot, take_screenshot_fn = None, None #screenshot: may have OS-specific code try: from xpra.platform.gui import take_screenshot take_screenshot_fn = take_screenshot except: log("failed to load platfrom specific screenshot code", exc_info=True) if not take_screenshot_fn: #try with Pillow: try: from PIL import ImageGrab #@UnresolvedImport from xpra.os_util import StringIOClass def pillow_imagegrab_screenshot(): img = ImageGrab.grab() out = StringIOClass() img.save(out, format="PNG") v = out.getvalue() out.close() return (img.width, img.height, "png", img.width * 3, v) take_screenshot_fn = pillow_imagegrab_screenshot except Exception as e: log("cannot use Pillow's ImageGrab: %s", e) if not take_screenshot_fn: #default: gtk screen capture try: from xpra.server.shadow.gtk_root_window_model import GTKRootWindowModel rwm = GTKRootWindowModel(gtk.gdk.get_default_root_window()) take_screenshot_fn = rwm.take_screenshot except: log("failed to load gtk screenshot code", exc_info=True) log("take_screenshot_fn=%s", take_screenshot_fn) if take_screenshot_fn: def get_screenshot(): #take_screenshot() returns: w, h, "png", rowstride, data return take_screenshot_fn()[4] self.toggles = ( ("system", "txt", "System", get_sys_info, "Xpra version, platform and host information"), ("network", "txt", "Network", get_net_info, "Compression, packet encoding and encryption"), ("encoding", "txt", "Encodings", codec_versions, "Picture encodings supported"), ("opengl", "txt", "OpenGL", get_gl_info, "OpenGL driver and features"), ("sound", "txt", "Sound", get_sound_info, "Sound codecs and GStreamer version information"), ("keyboard", "txt", "Keyboard Mapping", get_gtk_keymap, "Keyboard layout and key mapping"), ("xpra-info", "txt", "Server Info", self.get_server_info, "Full server information from 'xpra info'"), ("screenshot", "png", "Screenshot", get_screenshot, ""), ) for name, _, title, value_cb, tooltip in self.toggles: cb = gtk.CheckButton(title + [" (not available)", ""][bool(value_cb)]) cb.set_active(self.includes.get(name, True)) cb.set_sensitive(bool(value_cb)) cb.set_tooltip_text(tooltip) ibox.pack_start(cb) setattr(self, name, cb) # Buttons: hbox = gtk.HBox(False, 20) vbox.pack_start(hbox) def btn(label, tooltip, callback, icon_name=None): btn = gtk.Button(label) btn.set_tooltip_text(tooltip) btn.connect("clicked", callback) if icon_name: icon = self.get_icon(icon_name) if icon: btn.set_image(scaled_image(icon, 24)) hbox.pack_start(btn) return btn if not is_gtk3(): #clipboard does not work in gtk3.. btn("Copy to clipboard", "Copy all data to clipboard", self.copy_clicked, "clipboard.png") btn("Save", "Save Bug Report", self.save_clicked, "download.png") btn("Cancel", "", self.close, "quit.png") def accel_close(*args): self.close() add_close_accel(self.window, accel_close) vbox.show_all() self.window.vbox = vbox self.window.add(vbox)
#pygtk3 vs pygtk2 (sigh) from xpra.gtk_common.gobject_compat import import_glib, import_cairo, is_gtk3 glib = import_glib() cairo = import_cairo() from xpra.util import envbool from xpra.os_util import WIN32, OSX from xpra.client.window_backing_base import WindowBackingBase from xpra.log import Logger log = Logger("paint") #transparency with GTK: # - on MS Windows: not supported # - on OSX: only with gtk3 DEFAULT_HAS_ALPHA = not WIN32 and (not OSX or is_gtk3()) GTK_ALPHA_SUPPORTED = envbool("XPRA_ALPHA", DEFAULT_HAS_ALPHA) """ Generic GTK superclass for Backing code (for both GTK2 and GTK3), see CairoBacking, PixmapBacking and TrayBacking for actual implementations. (some may override HAS_ALPHA, TrayBacking does) """ class GTKWindowBacking(WindowBackingBase): HAS_ALPHA = GTK_ALPHA_SUPPORTED def __init__(self, wid, window_alpha): WindowBackingBase.__init__(self, wid, window_alpha and self.HAS_ALPHA, glib.idle_add)
gtk = import_gtk() gdk = import_gdk() from xpra.log import Logger log = Logger("gtk", "util") GTK_VERSION_INFO = {} if hasattr(gtk, "pygtk_version"): GTK_VERSION_INFO["pygtk_version"] = gtk.pygtk_version if hasattr(gtk, "gtk_version"): GTK_VERSION_INFO["gtk_version"] = gtk.gtk_version elif hasattr(gtk, "_version"): GTK_VERSION_INFO["gtk_version"] = gtk._version if is_gtk3(): #where is this gone now? FILL = None else: FILL = gtk.FILL def add_gtk_version_info(props, gtk, prefix="", new_namespace=False): #update props given: global GTK_VERSION_INFO for k,v in GTK_VERSION_INFO.items(): if new_namespace: k = k.replace("_", ".") props[prefix+k] = v
gtk = import_gtk() gdk = import_gdk() from xpra.gtk_common.gtk_util import get_xwindow from xpra.log import Logger log = Logger("x11", "window") try: from xpra.x11.gtk2.gdk_bindings import ( get_pywindow, #@UnresolvedImport get_xvisual, #@UnresolvedImport ) except ImportError as e: #we should only ever be missing the gdk_bindings with GTK3 builds: log("cannot import gdk bindings", exc_info=True) assert is_gtk3() def missing_fn(*args): raise NotImplementedError() get_pywindow, get_xvisual = missing_fn, missing_fn from xpra.x11.bindings.window_bindings import ( constants, #@UnresolvedImport X11WindowBindings, #@UnresolvedImport PropertyError) #@UnresolvedImport X11Window = X11WindowBindings() from xpra.os_util import StringIOClass from xpra.gtk_common.error import xsync, XError from xpra.codecs.argb.argb import premultiply_argb_in_place #@UnresolvedImport
def main(): from xpra.platform import program_context with program_context("Xpra-Sound-Source"): import os.path if "-v" in sys.argv: log.enable_debug() sys.argv.remove("-v") if len(sys.argv) not in (2, 3): log.error("usage: %s filename [codec] [--encoder=rencode]", sys.argv[0]) return 1 filename = sys.argv[1] if filename=="-": from xpra.os_util import disable_stdout_buffering disable_stdout_buffering() elif os.path.exists(filename): log.error("file %s already exists", filename) return 1 codec = None codecs = get_codecs() if len(sys.argv)==3: codec = sys.argv[2] if codec not in codecs: log.error("invalid codec: %s, codecs supported: %s", codec, codecs) return 1 else: parts = filename.split(".") if len(parts)>1: extension = parts[-1] if extension.lower() in codecs: codec = extension.lower() log.info("guessed codec %s from file extension %s", codec, extension) if codec is None: codec = MP3 log.info("using default codec: %s", codec) #in case we're running against pulseaudio, #try to setup the env: try: from xpra.platform.paths import get_icon_filename f = get_icon_filename("xpra.png") from xpra.sound.pulseaudio.pulseaudio_util import add_audio_tagging_env add_audio_tagging_env(icon_path=f) except Exception as e: log.warn("failed to setup pulseaudio tagging: %s", e) from threading import Lock if filename=="-": f = sys.stdout else: f = open(filename, "wb") ss = SoundSource(codecs=[codec]) lock = Lock() def new_buffer(ss, data, metadata): log.info("new buffer: %s bytes (%s), metadata=%s", len(data), type(data), metadata) with lock: if f: f.write(data) f.flush() from xpra.gtk_common.gobject_compat import import_glib glib = import_glib() glib_mainloop = glib.MainLoop() ss.connect("new-buffer", new_buffer) ss.start() import signal def deadly_signal(sig, frame): log.warn("got deadly signal %s", SIGNAMES.get(sig, sig)) glib.idle_add(ss.stop) glib.idle_add(glib_mainloop.quit) def force_quit(sig, frame): sys.exit() signal.signal(signal.SIGINT, force_quit) signal.signal(signal.SIGTERM, force_quit) from xpra.gtk_common.gobject_compat import is_gtk3 if not is_gtk3(): signal.signal(signal.SIGINT, deadly_signal) signal.signal(signal.SIGTERM, deadly_signal) try: glib_mainloop.run() except Exception as e: log.error("main loop error: %s", e) ss.stop() f.flush() if f!=sys.stdout: log.info("wrote %s bytes to %s", f.tell(), filename) with lock: f.close() f = None return 0
def import_gst(): global gst, has_gst, gst_vinfo, gst_major_version if has_gst is not None: return gst from xpra.gtk_common.gobject_compat import is_gtk3 if is_gtk3(): imports = [(import_gst1, 1)] else: imports = [ (import_gst0_10, 0), (import_gst1, 1), ] if GSTREAMER1: imports.reverse() #try gst1 first: errs = {} saved_sys_path = sys.path[:] saved_os_environ = os.environ.copy() for import_function, MV in imports: #restore os.environ and sys.path sys.path = saved_sys_path[:] os.environ.clear() os.environ.update(saved_os_environ) vstr = get_version_str(MV) #hacks to locate gstreamer plugins on win32 and osx: if WIN32: frozen = hasattr( sys, "frozen") and sys.frozen in ("windows_exe", "console_exe", True) log("gstreamer_util: frozen=%s", frozen) if frozen: #on win32, we keep separate trees #because GStreamer 0.10 and 1.x were built using different and / or incompatible version of the same libraries: from xpra.platform.paths import get_app_dir gst_dir = os.path.join( get_app_dir(), "gstreamer-%s" % vstr) #ie: C:\Program Files\Xpra\gstreamer-0.10 os.environ["GST_PLUGIN_PATH"] = gst_dir if MV == 1: gst_bin_dir = os.path.join( gst_dir, "bin") #ie: C:\Program Files\Xpra\gstreamer-0.10\bin os.environ["PATH"] = os.pathsep.join( x for x in (gst_bin_dir, os.environ.get("PATH", "")) if x) sys.path.insert(0, gst_bin_dir) scanner = os.path.join(gst_bin_dir, "gst-plugin-scanner.exe") if os.path.exists(scanner): os.environ["GST_PLUGIN_SCANNER"] = scanner gi_dir = os.path.join(get_app_dir(), "girepository-%s" % vstr) os.environ["GI_TYPELIB_PATH"] = gi_dir elif OSX: bundle_contents = os.environ.get("GST_BUNDLE_CONTENTS") log("OSX: GST_BUNDLE_CONTENTS=%s", bundle_contents) if bundle_contents: os.environ["GST_PLUGIN_PATH"] = os.path.join( bundle_contents, "Resources", "lib", "gstreamer-%s" % vstr) os.environ["GST_PLUGIN_SCANNER"] = os.path.join( bundle_contents, "Helpers", "gst-plugin-scanner-%s" % vstr) if MV == 1: gi_dir = os.path.join(bundle_contents, "Resources", "lib", "girepository-%s" % vstr) os.environ["GI_TYPELIB_PATH"] = gi_dir if MV < 1: #we should not be loading the gi bindings try: del os.environ["GI_TYPELIB_PATH"] except: pass log( "GStreamer %s environment: %s", vstr, dict( (k, v) for k, v in os.environ.items() if (k.startswith("GST") or k.startswith("GI") or k == "PATH"))) log("GStreamer %s sys.path=%s", vstr, csv(sys.path)) try: log("trying to import GStreamer %s using %s", get_version_str(MV), import_function) _gst = import_function() v = _gst.version() if v[-1] == 0: v = v[:-1] gst_vinfo = ".".join((str(x) for x in v)) gst_major_version = MV gst = _gst break except Exception as e: log("Warning failed to import GStreamer %s", vstr, exc_info=True) errs[vstr] = e if gst: log("Python GStreamer version %s for Python %s.%s", gst_vinfo, sys.version_info[0], sys.version_info[1]) else: log.warn("Warning: failed to import GStreamer:") for vstr, e in errs.items(): log.warn(" %s failed with: %s", vstr, e) has_gst = gst is not None return gst
def add_window_hooks(window): log("add_window_hooks(%s) WINDOW_HOOKS=%s, GROUP_LEADER=%s, UNDECORATED_STYLE=%s, MAX_SIZE_HINT=%s, GEOMETRY=%s", window, WINDOW_HOOKS, GROUP_LEADER, UNDECORATED_STYLE, MAX_SIZE_HINT, GEOMETRY) if not WINDOW_HOOKS: #allows us to disable the win32 hooks for testing return try: gdk_window = window.get_window() #win32 cannot use set_group by default: gdk_window.set_group = noop except: gdk_window = None #window handle: try: handle = gdk_window.handle except: handle = None if not handle: from xpra.gtk_common.gobject_compat import is_gtk3 if is_gtk3(): #access the missing gdk_win32_window_get_handle function using ctypes: try: ctypes.pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p ctypes.pythonapi.PyCapsule_GetPointer.argtypes = [ctypes.py_object] gdkwin_gpointer = ctypes.pythonapi.PyCapsule_GetPointer(gdk_window.__gpointer__, None) gdkdll = ctypes.CDLL ("libgdk-3-0.dll") handle = gdkdll.gdk_win32_window_get_handle(gdkwin_gpointer) except Exception as e: log.warn("failed to get window handle", exc_info=True) if not handle: log.warn("Warning: cannot add window hooks without a window handle!") return log("add_window_hooks(%s) gdk window=%s, hwnd=%#x", window, gdk_window, handle) if GROUP_LEADER: #windows 7 onwards can use AppUserModel to emulate the group leader stuff: propsys = get_propsys() log("win32 hooks: propsys=%s", propsys) if propsys: gdk_window.set_group = types.MethodType(win32_propsys_set_group_leader, gdk_window) log("hooked group leader override using %s", propsys) if UNDECORATED_STYLE: #OR windows never have any decorations or taskbar menu if not window._override_redirect: #the method to call to fix things up: window.fixup_window_style = types.MethodType(fixup_window_style, window) #override set_decorated so we can preserve the taskbar menu for undecorated windows window.__set_decorated = window.set_decorated window.set_decorated = types.MethodType(set_decorated, window) #override after_window_state_updated so we can re-add the missing style options #(somehow doing it from on_realize which calls add_window_hooks is not enough) window.connect("state-updated", window_state_updated) #call it at least once: window.fixup_window_style() if CLIP_CURSOR: window.pointer_grab = types.MethodType(pointer_grab, window) window.pointer_ungrab = types.MethodType(pointer_ungrab, window) if MAX_SIZE_HINT or LANGCHANGE: #glue code for gtk to win32 APIs: #add event hook class: win32hooks = Win32Hooks(handle) log("add_window_hooks(%s) added hooks for hwnd %#x: %s", window, handle, win32hooks) window.win32hooks = win32hooks win32hooks.max_size = None win32hooks.setup() if GEOMETRY: #save original geometry function: window.__apply_geometry_hints = window.apply_geometry_hints window.apply_geometry_hints = types.MethodType(apply_geometry_hints, window) #apply current max-size from hints, if any: if window.geometry_hints: apply_maxsize_hints(window, window.geometry_hints) if LANGCHANGE: def inputlangchange(hwnd, event, wParam, lParam): log("WM_INPUTLANGCHANGE: character set: %i, input locale identifier: %i", wParam, lParam) window.keyboard_layout_changed("WM_INPUTLANGCHANGE", wParam, lParam) win32hooks.add_window_event_handler(win32con.WM_INPUTLANGCHANGE, inputlangchange) if WHEEL: VERTICAL = "vertical" HORIZONTAL = "horizontal" class WheelEvent(AdHocStruct): pass def handle_wheel(orientation, wParam, lParam): distance = wParam>>16 keys = wParam & 0xFFFF y = lParam>>16 x = lParam & 0xFFFF cval = getattr(window, "_win32_%swheel" % orientation, 0) nval = cval + distance units = nval // WHEEL_DELTA client = getattr(window, "_client") wid = getattr(window, "_id", 0) mouselog("mousewheel: orientation=%s distance=%.1f, units=%i, new value=%.1f, keys=%#x, x=%i, y=%i, client=%s, wid=%i", orientation, distance, units, nval, keys, x, y, client, wid) if units!=0 and client and wid>0: if orientation==VERTICAL: button = 4 + int(units<0) #4 for UP, 5 for DOWN else: button = 7 - int(units<0) #6 for LEFT, 7 for RIGHT buttons = [] modifiers = client.get_current_modifiers() def send_button(pressed): client.send_button(wid, button, pressed, (x, y), modifiers, buttons) count = 0 v = nval while abs(v)>=WHEEL_DELTA: send_button(True) send_button(False) if v>0: v -= WHEEL_DELTA else: v += WHEEL_DELTA count += 1 mouselog("mousewheel: send %i wheel events to the server for distance=%s, remainder=%s", count, nval, v) setattr(window, "_win32_%swheel" % orientation, v) def mousewheel(hwnd, event, wParam, lParam): handle_wheel(VERTICAL, wParam, lParam) return 0 def mousehwheel(hwnd, event, wParam, lParam): handle_wheel(HORIZONTAL, wParam, lParam) return 0 WM_MOUSEHWHEEL = 0x020E win32hooks.add_window_event_handler(win32con.WM_MOUSEWHEEL, mousewheel) win32hooks.add_window_event_handler(WM_MOUSEHWHEEL, mousehwheel) def reset_wheel_counters(*args): mouselog("window lost focus, resetting current wheel deltas") for orientation in (VERTICAL, HORIZONTAL): setattr(window, "_win32_%swheel" % orientation, 0) window.connect("focus-out-event", reset_wheel_counters)
def get_display_info(): display = display_get_default() info = { "root" : get_default_root_window().get_geometry(), "root-size" : get_root_size(), "screens" : display.get_n_screens(), "name" : display.get_name(), "pointer" : display.get_pointer()[1:3], "devices" : len(display.list_devices()), "default_cursor_size" : display.get_default_cursor_size(), "maximal_cursor_size" : display.get_maximal_cursor_size(), "pointer_is_grabbed" : display.pointer_is_grabbed(), } sinfo = info.setdefault("supports", {}) for x in ("composite", "cursor_alpha", "cursor_color", "selection_notification", "clipboard_persistence", "shapes"): f = "supports_"+x if hasattr(display, f): fn = getattr(display, f) sinfo[x] = fn() info["screens"] = get_screens_info() if is_gtk3(): dm = display.get_device_manager() for dt, name in {gdk.DeviceType.MASTER : "master", gdk.DeviceType.SLAVE : "slave", gdk.DeviceType.FLOATING: "floating"}.items(): dinfo = info.setdefault("device", {}) dtinfo = dinfo.setdefault(name, {}) devices = dm.list_devices(dt) for i, d in enumerate(devices): dtinfo[i] = d.get_name() else: devices = display.list_devices() for i, d in enumerate(devices): dinfo = info.setdefault("device", {}).setdefault(i, {}) dinfo[""] = d.get_name() AXES_STR = { gdk.AXIS_IGNORE : "IGNORE", gdk.AXIS_X : "X", gdk.AXIS_Y : "Y", gdk.AXIS_PRESSURE : "PRESSURE", gdk.AXIS_XTILT : "XTILT", gdk.AXIS_YTILT : "YTILT", gdk.AXIS_WHEEL : "WHEEL", gdk.AXIS_LAST : "LAST", } MODE_STR = { gdk.MODE_DISABLED : "DISABLED", gdk.MODE_SCREEN : "SCREEN", gdk.MODE_WINDOW : "WINDOW", } SOURCE_STR = { gdk.SOURCE_MOUSE : "MOUSE", gdk.SOURCE_PEN : "PEN", gdk.SOURCE_ERASER : "ERASER", gdk.SOURCE_CURSOR : "CURSOR", } def notrans(v, d): return v MOD_STR = { gdk.SHIFT_MASK : "SHIFT", gdk.LOCK_MASK : "LOCK", gdk.CONTROL_MASK : "CONTROL", gdk.MOD1_MASK : "MOD1", gdk.MOD2_MASK : "MOD2", gdk.MOD3_MASK : "MOD3", gdk.MOD4_MASK : "MOD4", gdk.MOD5_MASK : "MOD5", gdk.BUTTON1_MASK : "BUTTON1", gdk.BUTTON2_MASK : "BUTTON2", gdk.BUTTON3_MASK : "BUTTON3", gdk.BUTTON4_MASK : "BUTTON4", gdk.BUTTON5_MASK : "BUTTON5", gdk.RELEASE_MASK : "RELEASE", } def modtrans(mod): return [v for k,v in MOD_STR.items() if k&mod] def keys_trans(l, d): #GdkModifierType can be converted to an int return [(k,modtrans(v)) for (k,v) in l] for name, trans in {"axes" : AXES_STR.get, "has_cursor" : notrans, "keys" : keys_trans, "mode" : MODE_STR.get, "num_axes" : notrans, "num_keys" : notrans, "source" : SOURCE_STR.get}.items(): try: v = getattr(d, name) dinfo[name] = trans(v, v) except: pass return info
def get_screen_info(display, screen): info = {} try: w = screen.get_root_window() info["root"] = w.get_geometry() except: pass info["name"] = screen.make_display_name() for x in ("width", "height", "width_mm", "height_mm", "resolution", "primary_monitor"): fn = getattr(screen, "get_"+x) try: info[x] = int(fn()) except: pass info["monitors"] = screen.get_n_monitors() m_info = info.setdefault("monitor", {}) for i in range(screen.get_n_monitors()): m_info[i] = get_monitor_info(display, screen, i) try: import cairo fo = screen.get_font_options() #win32 and osx return nothing here... if fo: fontoptions = info.setdefault("fontoptions", {}) for x,vdict in { "antialias" : {cairo.ANTIALIAS_DEFAULT : "default", cairo.ANTIALIAS_NONE : "none", cairo.ANTIALIAS_GRAY : "gray", cairo.ANTIALIAS_SUBPIXEL : "subpixel"}, "hint_metrics" : {cairo.HINT_METRICS_DEFAULT : "default", cairo.HINT_METRICS_OFF : "off", cairo.HINT_METRICS_ON : "on"}, "hint_style" : {cairo.HINT_STYLE_DEFAULT : "default", cairo.HINT_STYLE_NONE : "none", cairo.HINT_STYLE_SLIGHT : "slight", cairo.HINT_STYLE_MEDIUM : "medium", cairo.HINT_STYLE_FULL : "full"}, "subpixel_order": {cairo.SUBPIXEL_ORDER_DEFAULT : "default", cairo.SUBPIXEL_ORDER_RGB : "RGB", cairo.SUBPIXEL_ORDER_BGR : "BGR", cairo.SUBPIXEL_ORDER_VRGB : "VRGB", cairo.SUBPIXEL_ORDER_VBGR : "VBGR"}, }.items(): fn = getattr(fo, "get_"+x) val = fn() fontoptions[x] = vdict.get(val, val) except: pass vinfo = info.setdefault("visual", {}) def visual(name, v): if not v: return for x, vdict in {"bits_per_rgb" : {}, "byte_order" : {LSB_FIRST : "LSB", MSB_FIRST : "MSB"}, "colormap_size": {}, "depth" : {}, "red_pixel_details" : {}, "green_pixel_details" : {}, "blue_pixel_details" : {}, "visual_type" : {STATIC_GRAY : "STATIC_GRAY", GRAYSCALE : "GRAYSCALE", STATIC_COLOR : "STATIC_COLOR", PSEUDO_COLOR : "PSEUDO_COLOR", TRUE_COLOR : "TRUE_COLOR", DIRECT_COLOR : "DIRECT_COLOR"}, }.items(): val = None try: val = getattr(v, x.replace("visual_")) #ugly workaround for "visual_type" -> "type" for GTK2... except: try: fn = getattr(v, "get_"+x) val = fn() except: pass if val is not None: vinfo.setdefault(name, {})[x] = vdict.get(val, val) try: visual("rgb", screen.get_rgb_visual()) except: pass #not in gtk3? visual("rgba", screen.get_rgba_visual()) visual("system_visual", screen.get_system_visual()) if SHOW_ALL_VISUALS: for i, v in enumerate(screen.list_visuals()): visual(i, v) #gtk.settings if is_gtk3(): def get_setting(key): #try string first, then int for t in (gobject.TYPE_STRING, gobject.TYPE_INT): v = gobject.Value() v.init(t) if screen.get_setting(key, v): return v.get_value() return None else: settings = gtk.settings_get_for_screen(screen) def get_setting(key): return settings.get_property(key) sinfo = info.setdefault("settings", {}) try: for x in ("antialias", "dpi", "hinting", "hintstyle", "rgba"): try: v = get_setting("gtk-xft-"+x) except: continue if v is None: v = "" sinfo[x] = v except: pass return info
def __init__(self, client, session_name, window_icon_pixbuf, conn, get_pixbuf): gtk.Window.__init__(self) self.client = client self.session_name = session_name self.connection = conn self.last_populate_time = 0 self.last_populate_statistics = 0 self.is_closed = False self.get_pixbuf = get_pixbuf if not self.session_name or self.session_name=="Xpra": title = "Session Info" else: title = "%s: Session Info" % self.session_name self.set_title(title) self.set_destroy_with_parent(True) self.set_resizable(True) self.set_decorated(True) if window_icon_pixbuf: self.set_icon(window_icon_pixbuf) self.set_position(WIN_POS_CENTER) #tables on the left in a vbox with buttons at the top: self.tab_box = gtk.VBox(False, 0) self.tab_button_box = gtk.HBox(True, 0) self.tabs = [] #pairs of button, table self.populate_cb = None self.tab_box.pack_start(self.tab_button_box, expand=False, fill=True, padding=0) #Package Table: tb, _ = self.table_tab("package.png", "Software", self.populate_package) #title row: tb.attach(title_box(""), 0, xoptions=EXPAND|FILL, xpadding=0) tb.attach(title_box("Client"), 1, xoptions=EXPAND|FILL, xpadding=0) tb.attach(title_box("Server"), 2, xoptions=EXPAND|FILL, xpadding=0) tb.inc() def make_os_str(*args): s = os_info(*args) return "\n".join(s) distro = "" if hasattr(python_platform, "linux_distribution"): distro = python_platform.linux_distribution() LOCAL_PLATFORM_NAME = make_os_str(sys.platform, python_platform.release(), python_platform.platform(), distro) SERVER_PLATFORM_NAME = make_os_str(self.client._remote_platform, self.client._remote_platform_release, self.client._remote_platform_platform, self.client._remote_platform_linux_distribution) tb.new_row("Operating System", label(LOCAL_PLATFORM_NAME), label(SERVER_PLATFORM_NAME)) scaps = self.client.server_capabilities from xpra.__init__ import __version__ tb.new_row("Xpra", label(__version__), label(self.client._remote_version or "unknown")) cl_rev, cl_ch, cl_date = "unknown", "", "" try: from xpra.build_info import BUILD_DATE as cl_date, BUILD_TIME as cl_time from xpra.src_info import REVISION as cl_rev, LOCAL_MODIFICATIONS as cl_ch #@UnresolvedImport except: pass def make_version_str(version): if version and type(version) in (tuple, list): version = ".".join([str(x) for x in version]) return version or "unknown" def server_info(*prop_names): for x in prop_names: v = scaps.capsget(x) if v is not None: return v if self.client.server_last_info: v = self.client.server_last_info.get(x) if v is not None: return v return None def server_version_info(*prop_names): return make_version_str(server_info(*prop_names)) def make_revision_str(rev, changes): if not changes: return rev return "%s (%s changes)" % (rev, changes) def make_datetime(date, time): if not time: return date return "%s %s" % (date, time) tb.new_row("Revision", label(make_revision_str(cl_rev, cl_ch)), label(make_revision_str(self.client._remote_revision, server_version_info("build.local_modifications", "local_modifications")))) tb.new_row("Build date", label(make_datetime(cl_date, cl_time)), label(make_datetime(server_info("build_date", "build.date"), server_info("build.time")))) gtk_version_info = get_gtk_version_info() def client_vinfo(prop, fallback="unknown"): k = "%s.version" % prop return label(make_version_str(gtk_version_info.get(k, fallback))) def server_vinfo(prop): k = "%s.version" % prop fk = "%s_version" % prop return label(server_version_info(k, fk)) tb.new_row("Glib", client_vinfo("glib"), server_vinfo("glib")) tb.new_row("PyGlib", client_vinfo("pyglib"), server_vinfo("pyglib")) tb.new_row("Gobject", client_vinfo("gobject"), server_vinfo("gobject")) tb.new_row("PyGTK", client_vinfo("pygtk", ""), server_vinfo("pygtk")) tb.new_row("GTK", client_vinfo("gtk"), server_vinfo("gtk")) tb.new_row("GDK", client_vinfo("gdk"), server_vinfo("gdk")) tb.new_row("Cairo", client_vinfo("cairo"), server_vinfo("cairo")) tb.new_row("Pango", client_vinfo("pango"), server_vinfo("pango")) tb.new_row("Python", label(python_platform.python_version()), label(server_version_info("server.python.version", "python_version", "python.version"))) cl_gst_v, cl_pygst_v = "", "" try: from xpra.sound.gstreamer_util import gst_version as cl_gst_v, pygst_version as cl_pygst_v except Exception as e: log("cannot load gstreamer: %s", e) tb.new_row("GStreamer", label(make_version_str(cl_gst_v)), label(server_version_info("sound.gst.version", "gst_version"))) tb.new_row("pygst", label(make_version_str(cl_pygst_v)), label(server_version_info("sound.pygst.version", "pygst_version"))) tb.new_row("OpenGL", label(make_version_str(self.client.opengl_props.get("opengl", "n/a"))), label("n/a")) tb.new_row("OpenGL Vendor", label(make_version_str(self.client.opengl_props.get("vendor", ""))), label("n/a")) tb.new_row("PyOpenGL", label(make_version_str(self.client.opengl_props.get("pyopengl", "n/a"))), label("n/a")) # Features Table: vbox = self.vbox_tab("features.png", "Features", self.populate_features) #add top table: tb = TableBuilder(rows=1, columns=2) table = tb.get_table() al = gtk.Alignment(xalign=0.5, yalign=0.5, xscale=0.0, yscale=1.0) al.add(table) vbox.pack_start(al, expand=True, fill=False, padding=10) #top table contents: randr_box = gtk.HBox(False, 20) self.server_randr_label = label() self.server_randr_icon = gtk.Image() randr_box.add(self.server_randr_icon) randr_box.add(self.server_randr_label) tb.new_row("RandR Support", randr_box) opengl_box = gtk.HBox(False, 20) self.client_opengl_label = label() self.client_opengl_label.set_line_wrap(True) self.client_opengl_icon = gtk.Image() opengl_box.add(self.client_opengl_icon) opengl_box.add(self.client_opengl_label) tb.new_row("Client OpenGL", opengl_box) self.opengl_buffering = label() tb.new_row("OpenGL Buffering", self.opengl_buffering) self.server_mmap_icon = gtk.Image() tb.new_row("Memory Mapped Transfers", self.server_mmap_icon) self.server_clipboard_icon = gtk.Image() tb.new_row("Clipboard", self.server_clipboard_icon) self.server_notifications_icon = gtk.Image() tb.new_row("Notification Forwarding", self.server_notifications_icon) self.server_bell_icon = gtk.Image() tb.new_row("Bell Forwarding", self.server_bell_icon) self.server_cursors_icon = gtk.Image() tb.new_row("Cursor Forwarding", self.server_cursors_icon) speaker_box = gtk.HBox(False, 20) self.server_speaker_icon = gtk.Image() speaker_box.add(self.server_speaker_icon) self.speaker_codec_label = label() speaker_box.add(self.speaker_codec_label) tb.new_row("Speaker Forwarding", speaker_box) microphone_box = gtk.HBox(False, 20) self.server_microphone_icon = gtk.Image() microphone_box.add(self.server_microphone_icon) self.microphone_codec_label = label() microphone_box.add(self.microphone_codec_label) tb.new_row("Microphone Forwarding", microphone_box) #add bottom table: tb = TableBuilder(rows=1, columns=3) table = tb.get_table() vbox.pack_start(table, expand=True, fill=True, padding=20) #bottom table headings: tb.attach(title_box(""), 0, xoptions=EXPAND|FILL, xpadding=0) tb.attach(title_box("Client"), 1, xoptions=EXPAND|FILL, xpadding=0) tb.attach(title_box("Server"), 2, xoptions=EXPAND|FILL, xpadding=0) tb.inc() #bottom table contents: self.client_encodings_label = label() self.client_encodings_label.set_line_wrap(True) self.client_encodings_label.set_size_request(250, -1) self.server_encodings_label = label() self.server_encodings_label.set_line_wrap(True) self.server_encodings_label.set_size_request(250, -1) tb.new_row("Encodings", self.client_encodings_label, self.server_encodings_label) self.client_speaker_codecs_label = label() self.server_speaker_codecs_label = label() tb.new_row("Speaker Codecs", self.client_speaker_codecs_label, self.server_speaker_codecs_label) self.client_microphone_codecs_label = label() self.server_microphone_codecs_label = label() tb.new_row("Microphone Codecs", self.client_microphone_codecs_label, self.server_microphone_codecs_label) self.client_packet_encoders_label = label() self.server_packet_encoders_label = label() tb.new_row("Packet Encoders", self.client_packet_encoders_label, self.server_packet_encoders_label) self.client_packet_compressors_label = label() self.server_packet_compressors_label = label() tb.new_row("Packet Compressors", self.client_packet_compressors_label, self.server_packet_compressors_label) # Connection Table: tb, _ = self.table_tab("connect.png", "Connection", self.populate_connection) tb.new_row("Server Endpoint", label(self.connection.target)) if self.client.server_display: tb.new_row("Server Display", label(prettify_plug_name(self.client.server_display))) hostname = scaps.strget("hostname") if hostname: tb.new_row("Server Hostname", label(hostname)) if self.client.server_platform: tb.new_row("Server Platform", label(self.client.server_platform)) self.server_load_label = label() tb.new_row("Server Load", self.server_load_label, label_tooltip="Average over 1, 5 and 15 minutes") self.session_started_label = label() tb.new_row("Session Started", self.session_started_label) self.session_connected_label = label() tb.new_row("Session Connected", self.session_connected_label) self.input_packets_label = label() tb.new_row("Packets Received", self.input_packets_label) self.input_bytes_label = label() tb.new_row("Bytes Received", self.input_bytes_label) self.output_packets_label = label() tb.new_row("Packets Sent", self.output_packets_label) self.output_bytes_label = label() tb.new_row("Bytes Sent", self.output_bytes_label) self.compression_label = label() tb.new_row("Encoding + Compression", self.compression_label) self.connection_type_label = label() tb.new_row("Connection Type", self.connection_type_label) self.input_encryption_label = label() tb.new_row("Input Encryption", self.input_encryption_label) self.output_encryption_label = label() tb.new_row("Output Encryption", self.output_encryption_label) self.speaker_label = label() self.speaker_details = label(font="monospace 10") tb.new_row("Speaker", self.speaker_label, self.speaker_details) self.microphone_label = label() tb.new_row("Microphone", self.microphone_label) # Details: tb, stats_box = self.table_tab("browse.png", "Statistics", self.populate_statistics) tb.widget_xalign = 1.0 tb.attach(title_box(""), 0, xoptions=EXPAND|FILL, xpadding=0) tb.attach(title_box("Latest"), 1, xoptions=EXPAND|FILL, xpadding=0) tb.attach(title_box("Minimum"), 2, xoptions=EXPAND|FILL, xpadding=0) tb.attach(title_box("Average"), 3, xoptions=EXPAND|FILL, xpadding=0) tb.attach(title_box("90 percentile"), 4, xoptions=EXPAND|FILL, xpadding=0) tb.attach(title_box("Maximum"), 5, xoptions=EXPAND|FILL, xpadding=0) tb.inc() def maths_labels(): return label(), label(), label(), label(), label() self.server_latency_labels = maths_labels() tb.add_row(label("Server Latency (ms)", "The time it takes for the server to respond to pings"), *self.server_latency_labels) self.client_latency_labels = maths_labels() tb.add_row(label("Client Latency (ms)", "The time it takes for the client to respond to pings, as measured by the server"), *self.client_latency_labels) if self.client.windows_enabled: if self.client.server_info_request: self.batch_labels = maths_labels() tb.add_row(label("Batch Delay (ms)", "How long the server waits for new screen updates to accumulate before processing them"), *self.batch_labels) self.damage_labels = maths_labels() tb.add_row(label("Damage Latency (ms)", "The time it takes to compress a frame and pass it to the OS network layer"), *self.damage_labels) self.quality_labels = maths_labels() tb.add_row(label("Encoding Quality (pct)"), *self.quality_labels) self.speed_labels = maths_labels() tb.add_row(label("Encoding Speed (pct)"), *self.speed_labels) self.decoding_labels = maths_labels() tb.add_row(label("Decoding Latency (ms)", "How long it takes the client to decode a screen update"), *self.decoding_labels) self.regions_per_second_labels = maths_labels() tb.add_row(label("Regions/s", "The number of screen updates per second (includes both partial and full screen updates)"), *self.regions_per_second_labels) self.regions_sizes_labels = maths_labels() tb.add_row(label("Pixels/region", "The number of pixels per screen update"), *self.regions_sizes_labels) self.pixels_per_second_labels = maths_labels() tb.add_row(label("Pixels/s", "The number of pixels processed per second"), *self.pixels_per_second_labels) #Window count stats: wtb = TableBuilder() stats_box.add(wtb.get_table()) #title row: wtb.attach(title_box(""), 0, xoptions=EXPAND|FILL, xpadding=0) wtb.attach(title_box("Regular"), 1, xoptions=EXPAND|FILL, xpadding=0) wtb.attach(title_box("Transient"), 2, xoptions=EXPAND|FILL, xpadding=0) wtb.attach(title_box("Trays"), 3, xoptions=EXPAND|FILL, xpadding=0) if self.client.client_supports_opengl: wtb.attach(title_box("OpenGL"), 4, xoptions=EXPAND|FILL, xpadding=0) wtb.inc() wtb.attach(label("Windows:"), 0, xoptions=EXPAND|FILL, xpadding=0) self.windows_managed_label = label() wtb.attach(self.windows_managed_label, 1) self.transient_managed_label = label() wtb.attach(self.transient_managed_label, 2) self.trays_managed_label = label() wtb.attach(self.trays_managed_label, 3) if self.client.client_supports_opengl: self.opengl_label = label() wtb.attach(self.opengl_label, 4) #add encoder info: etb = TableBuilder() stats_box.add(etb.get_table()) self.encoder_info_box = gtk.HBox(spacing=4) etb.new_row("Window Encoders", self.encoder_info_box) if not is_gtk3(): #needs porting to cairo... self.graph_box = gtk.VBox(False, 10) self.add_tab("statistics.png", "Graphs", self.populate_graphs, self.graph_box) bandwidth_label = "Bandwidth used" if SHOW_PIXEL_STATS: bandwidth_label += ",\nand number of pixels rendered" self.bandwidth_graph = self.add_graph_button(bandwidth_label, self.save_graphs) self.connect("realize", self.populate_graphs) self.latency_graph = self.add_graph_button(None, self.save_graphs) self.pixel_in_data = deque(maxlen=N_SAMPLES+4) self.net_in_bytecount = deque(maxlen=N_SAMPLES+4) self.net_out_bytecount = deque(maxlen=N_SAMPLES+4) self.sound_in_bytecount = deque(maxlen=N_SAMPLES+4) self.sound_out_bytecount = deque(maxlen=N_SAMPLES+4) self.set_border_width(15) self.add(self.tab_box) if not is_gtk3(): self.set_geometry_hints(self.tab_box) def window_deleted(*args): self.is_closed = True self.connect('delete_event', window_deleted) self.show_tab(self.tabs[0][2]) self.set_size_request(-1, 480) self.init_counters() self.populate() self.populate_all() gobject.timeout_add(1000, self.populate) gobject.timeout_add(100, self.populate_tab) add_close_accel(self, self.destroy)
def get_display_info(): display = display_get_default() info = { "root" : get_default_root_window().get_geometry(), "root-size" : get_root_size(), "screens" : display.get_n_screens(), "name" : display.get_name(), "pointer" : display.get_pointer()[1:3], "devices" : len(display.list_devices()), "default_cursor_size" : display.get_default_cursor_size(), "maximal_cursor_size" : display.get_maximal_cursor_size(), "pointer_is_grabbed" : display.pointer_is_grabbed(), } for x in ("composite", "cursor_alpha", "cursor_color", "selection_notification", "clipboard_persistence", "shapes"): f = "supports_"+x if hasattr(display, f): fn = getattr(display, f) info[x] = fn() for i in range(display.get_n_screens()): screen = display.get_screen(i) sk = "screen[%s]" % i try: w = screen.get_root_window() info[sk+".root"] = w.get_geometry() except: pass info[sk+".name"] = screen.make_display_name() for x in ("width", "height", "width_mm", "height_mm", "resolution", "primary_monitor"): fn = getattr(screen, "get_"+x) try: info[sk+"."+x] = int(fn()) except: pass info[sk+".monitors"] = screen.get_n_monitors() for j in range(screen.get_n_monitors()): mk = "screen[%s].monitor[%s]" % (i, j) geom = screen.get_monitor_geometry(j) for x in ("x", "y", "width", "height"): info[mk+"."+x] = getattr(geom, x) if hasattr(screen, "get_monitor_plug_name"): info[mk+".plug_name"] = screen.get_monitor_plug_name(j) or "" for x in ("scale_factor", "width_mm", "height_mm"): try: fn = getattr(screen, "get_monitor_"+x) info[mk+"."+x] = int(fn(j)) except: pass if hasattr(screen, "get_monitor_workarea"): #GTK3.4: rectangle = screen.get_monitor_workarea(j) for x in ("x", "y", "width", "height"): info[mk+".workarea."+x] = getattr(rectangle, x) try: import cairo fo = screen.get_font_options() #win32 and osx return nothing here... if fo: fk = sk+".fontoptions" for x,vdict in { "antialias" : {cairo.ANTIALIAS_DEFAULT : "default", cairo.ANTIALIAS_NONE : "none", cairo.ANTIALIAS_GRAY : "gray", cairo.ANTIALIAS_SUBPIXEL : "subpixel"}, "hint_metrics" : {cairo.HINT_METRICS_DEFAULT : "default", cairo.HINT_METRICS_OFF : "off", cairo.HINT_METRICS_ON : "on"}, "hint_style" : {cairo.HINT_STYLE_DEFAULT : "default", cairo.HINT_STYLE_NONE : "none", cairo.HINT_STYLE_SLIGHT : "slight", cairo.HINT_STYLE_MEDIUM : "medium", cairo.HINT_STYLE_FULL : "full"}, "subpixel_order": {cairo.SUBPIXEL_ORDER_DEFAULT : "default", cairo.SUBPIXEL_ORDER_RGB : "RGB", cairo.SUBPIXEL_ORDER_BGR : "BGR", cairo.SUBPIXEL_ORDER_VRGB : "VRGB", cairo.SUBPIXEL_ORDER_VBGR : "VBGR"}, }.items(): fn = getattr(fo, "get_"+x) val = fn() info[fk+"."+x] = vdict.get(val, val) except: pass def visual(k, v): if not v: return vk = sk+"."+k #ie: screen[0].rgb for x, vdict in {"bits_per_rgb" : {}, "byte_order" : {LSB_FIRST : "LSB", MSB_FIRST : "MSB"}, "colormap_size": {}, "depth" : {}, "red_pixel_details" : {}, "green_pixel_details" : {}, "blue_pixel_details" : {}, "visual_type" : {STATIC_GRAY : "STATIC_GRAY", GRAYSCALE : "GRAYSCALE", STATIC_COLOR : "STATIC_COLOR", PSEUDO_COLOR : "PSEUDO_COLOR", TRUE_COLOR : "TRUE_COLOR", DIRECT_COLOR : "DIRECT_COLOR"}, }.items(): val = None try: val = getattr(v, x.replace("visual_")) #ugly workaround for "visual_type" -> "type" for GTK2... except: try: fn = getattr(v, "get_"+x) val = fn() except: pass if val is not None: info[vk+"."+x] = vdict.get(val, val) try: visual("rgb", screen.get_rgb_visual()) except: pass #not in gtk3? visual("rgba", screen.get_rgba_visual()) visual("system_visual", screen.get_system_visual()) visuals = screen.list_visuals() info[sk+".visuals"] = len(visuals) #gtk.settings if is_gtk3(): def get_setting(key): #try string first, then int for t in (gobject.TYPE_STRING, gobject.TYPE_INT): v = gobject.Value() v.init(t) if screen.get_setting(key, v): return v.get_value() return None else: settings = gtk.settings_get_for_screen(screen) def get_setting(key): return settings.get_property(key) try: ssk = "%s.settings" % sk for x in ("antialias", "dpi", "hinting", "hintstyle", "rgba"): try: v = get_setting("gtk-xft-"+x) except: continue if v is None: v = "" info[ssk+"."+x] = v except: pass if is_gtk3(): dm = display.get_device_manager() for dt, name in {gdk.DeviceType.MASTER : "master", gdk.DeviceType.SLAVE : "slave", gdk.DeviceType.FLOATING: "floating"}.items(): dk = "devices.%s" % name devices = dm.list_devices(dt) info[dk] = len(devices) for i, d in enumerate(devices): info[dk+"[%s]" % i] = d.get_name() else: devices = display.list_devices() info["devices"] = len(devices) for i, d in enumerate(devices): info["device[%s]" % i] = d.get_name() return info
def setup_window(self): self.window = gtk.Window() self.window.connect("destroy", self.close) self.window.set_default_size(400, 300) self.window.set_border_width(20) self.window.set_title("Xpra Bug Report") self.window.modify_bg(STATE_NORMAL, gdk.Color(red=65535, green=65535, blue=65535)) icon_pixbuf = self.get_icon("bugs.png") if icon_pixbuf: self.window.set_icon(icon_pixbuf) self.window.set_position(WIN_POS_CENTER) vbox = gtk.VBox(False, 0) vbox.set_spacing(15) # Title hbox = gtk.HBox(False, 0) icon_pixbuf = self.get_icon("xpra.png") if icon_pixbuf and self.show_about: from xpra.gtk_common.about import about logo_button = gtk.Button("") settings = logo_button.get_settings() settings.set_property('gtk-button-images', True) logo_button.connect("clicked", about) logo_button.set_tooltip_text("About") image = gtk.Image() image.set_from_pixbuf(icon_pixbuf) logo_button.set_image(image) hbox.pack_start(logo_button, expand=False, fill=False) label = gtk.Label("Xpra Bug Report Tool") label.modify_font(pango.FontDescription("sans 14")) hbox.pack_start(label, expand=True, fill=True) vbox.pack_start(hbox) #the box containing all the input: ibox = gtk.VBox(False, 0) ibox.set_spacing(3) vbox.pack_start(ibox) # Description al = gtk.Alignment(xalign=0, yalign=0.5, xscale=0.0, yscale=0) al.add(gtk.Label("Please describe the problem:")) ibox.pack_start(al) #self.description = gtk.Entry(max=128) #self.description.set_width_chars(40) self.description = gtk.TextView() self.description.set_accepts_tab(True) self.description.set_justification(JUSTIFY_LEFT) self.description.set_border_width(2) self.description.set_size_request(300, 80) self.description.modify_bg(STATE_NORMAL, gdk.Color(red=32768, green=32768, blue=32768)) ibox.pack_start(self.description, expand=False, fill=False) # Toggles: al = gtk.Alignment(xalign=0, yalign=0.5, xscale=0.0, yscale=0) al.add(gtk.Label("Include:")) ibox.pack_start(al) #generic toggles: from xpra.gtk_common.keymap import get_gtk_keymap from xpra.codecs.loader import codec_versions, load_codecs load_codecs() try: from xpra.sound.wrapper import query_sound def get_sound_info(): return query_sound() except: get_sound_info = None if self.opengl_info: def get_gl_info(): return self.opengl_info else: try: from xpra.client.gl.gl_check import check_support def get_gl_info(): return check_support(force_enable=True) except: get_gl_info = None from xpra.net.net_util import get_info as get_net_info from xpra.platform.paths import get_info as get_path_info from xpra.platform.gui import get_info as get_gui_info from xpra.version_util import get_version_info, get_platform_info, get_host_info def get_sys_info(): from xpra.platform.info import get_user_info from xpra.scripts.config import read_xpra_defaults return { "argv" : sys.argv, "path" : sys.path, "exec_prefix" : sys.exec_prefix, "executable" : sys.executable, "version" : get_version_info(), "platform" : get_platform_info(), "host" : get_host_info(), "paths" : get_path_info(), "gtk" : get_gtk_version_info(), "gui" : get_gui_info(), "display" : get_display_info(), "user" : get_user_info(), "env" : os.environ, "config" : read_xpra_defaults(), } get_screenshot, take_screenshot_fn = None, None #screenshot: may have OS-specific code try: from xpra.platform.gui import take_screenshot take_screenshot_fn = take_screenshot except: log("failed to load platfrom specific screenshot code", exc_info=True) if not take_screenshot_fn: #try with Pillow: try: from PIL import ImageGrab #@UnresolvedImport from xpra.os_util import StringIOClass def pillow_imagegrab_screenshot(): img = ImageGrab.grab() out = StringIOClass() img.save(out, format="PNG") v = out.getvalue() out.close() return (img.width, img.height, "png", img.width*3, v) take_screenshot_fn = pillow_imagegrab_screenshot except Exception as e: log("cannot use Pillow's ImageGrab: %s", e) if not take_screenshot_fn: #default: gtk screen capture try: from xpra.server.shadow.gtk_root_window_model import GTKRootWindowModel rwm = GTKRootWindowModel(gtk.gdk.get_default_root_window()) take_screenshot_fn = rwm.take_screenshot except: log("failed to load gtk screenshot code", exc_info=True) log("take_screenshot_fn=%s", take_screenshot_fn) if take_screenshot_fn: def get_screenshot(): #take_screenshot() returns: w, h, "png", rowstride, data return take_screenshot_fn()[4] self.toggles = ( ("system", "txt", "System", get_sys_info, "Xpra version, platform and host information"), ("network", "txt", "Network", get_net_info, "Compression, packet encoding and encryption"), ("encoding", "txt", "Encodings", codec_versions, "Picture encodings supported"), ("opengl", "txt", "OpenGL", get_gl_info, "OpenGL driver and features"), ("sound", "txt", "Sound", get_sound_info, "Sound codecs and GStreamer version information"), ("keyboard", "txt", "Keyboard Mapping", get_gtk_keymap, "Keyboard layout and key mapping"), ("xpra-info", "txt", "Server Info", self.get_server_info, "Full server information from 'xpra info'"), ("screenshot", "png", "Screenshot", get_screenshot, ""), ) for name, _, title, value_cb, tooltip in self.toggles: cb = gtk.CheckButton(title+[" (not available)", ""][bool(value_cb)]) cb.set_active(self.includes.get(name, True)) cb.set_sensitive(bool(value_cb)) cb.set_tooltip_text(tooltip) ibox.pack_start(cb) setattr(self, name, cb) # Buttons: hbox = gtk.HBox(False, 20) vbox.pack_start(hbox) def btn(label, tooltip, callback, icon_name=None): btn = gtk.Button(label) btn.set_tooltip_text(tooltip) btn.connect("clicked", callback) if icon_name: icon = self.get_icon(icon_name) if icon: btn.set_image(scaled_image(icon, 24)) hbox.pack_start(btn) return btn if not is_gtk3(): #clipboard does not work in gtk3.. btn("Copy to clipboard", "Copy all data to clipboard", self.copy_clicked, "clipboard.png") btn("Save", "Save Bug Report", self.save_clicked, "download.png") btn("Cancel", "", self.close, "quit.png") def accel_close(*args): self.close() add_close_accel(self.window, accel_close) vbox.show_all() self.window.vbox = vbox self.window.add(vbox)
def popup_menu_workaround(self, menu): #win32 workaround: if sys.platform.startswith("win") and not is_gtk3(): self.add_popup_menu_workaround(menu)
def main(): from xpra.platform import init, clean init("Sound-Record") try: from xpra.gtk_common.gobject_compat import import_glib glib = import_glib() args = sys.argv log.enable_debug() import os.path if len(args) not in (2, 3): print("usage: %s [-v|--verbose] filename [codec]" % sys.argv[0]) return 1 filename = args[1] if not os.path.exists(filename): print("file %s does not exist" % filename) return 2 codecs = get_codecs() if len(args)==3: codec = args[2] if codec not in codecs: print("invalid codec: %s" % codec) print("only supported: %s" % str(codecs.keys())) return 2 codecs = [codec] else: codec = None parts = filename.split(".") if len(parts)>1: extension = parts[-1] if extension.lower() in codecs: codec = extension.lower() print("guessed codec %s from file extension %s" % (codec, extension)) if codec is None: print("assuming this is an mp3 file...") codec = MP3 codecs = [codec] log.enable_debug() with open(filename, "rb") as f: data = f.read() print("loaded %s bytes from %s" % (len(data), filename)) #force no leak since we push all the data at once global QUEUE_LEAK, QUEUE_SILENT QUEUE_LEAK = GST_QUEUE_NO_LEAK QUEUE_SILENT = 1 ss = SoundSink(codecs=codecs) def eos(*args): print("eos") glib.idle_add(glib_mainloop.quit) ss.connect("eos", eos) ss.start() glib_mainloop = glib.MainLoop() import signal def deadly_signal(*args): glib.idle_add(ss.stop) glib.idle_add(glib_mainloop.quit) def force_quit(sig, frame): sys.exit() signal.signal(signal.SIGINT, force_quit) signal.signal(signal.SIGTERM, force_quit) from xpra.gtk_common.gobject_compat import is_gtk3 if not is_gtk3(): signal.signal(signal.SIGINT, deadly_signal) signal.signal(signal.SIGTERM, deadly_signal) def check_for_end(*args): qtime = ss.queue.get_property("current-level-time")//MS_TO_NS if qtime<=0: log.info("underrun (end of stream)") thread.start_new_thread(ss.stop, ()) glib.timeout_add(500, glib_mainloop.quit) return False return True glib.timeout_add(1000, check_for_end) glib.idle_add(ss.add_data, data) glib_mainloop.run() return 0 finally: clean()
def main(): from xpra.platform import program_context with program_context("Sound-Record"): from xpra.gtk_common.gobject_compat import import_glib glib = import_glib() args = sys.argv log.enable_debug() import os.path if len(args) not in (2, 3): print("usage: %s [-v|--verbose] filename [codec]" % sys.argv[0]) return 1 filename = args[1] if not os.path.exists(filename): print("file %s does not exist" % filename) return 2 codecs = get_codecs() if len(args)==3: codec = args[2] if codec not in codecs: print("invalid codec: %s" % codec) print("only supported: %s" % str(codecs.keys())) return 2 codecs = [codec] else: codec = None parts = filename.split(".") if len(parts)>1: extension = parts[-1] if extension.lower() in codecs: codec = extension.lower() print("guessed codec %s from file extension %s" % (codec, extension)) if codec is None: print("assuming this is an mp3 file...") codec = MP3 codecs = [codec] log.enable_debug() with open(filename, "rb") as f: data = f.read() print("loaded %s bytes from %s" % (len(data), filename)) #force no leak since we push all the data at once global QUEUE_LEAK, QUEUE_SILENT QUEUE_LEAK = GST_QUEUE_NO_LEAK QUEUE_SILENT = 1 ss = SoundSink(codecs=codecs) def eos(*args): print("eos") glib.idle_add(glib_mainloop.quit) ss.connect("eos", eos) ss.start() glib_mainloop = glib.MainLoop() import signal def deadly_signal(*args): glib.idle_add(ss.stop) glib.idle_add(glib_mainloop.quit) def force_quit(sig, frame): sys.exit() signal.signal(signal.SIGINT, force_quit) signal.signal(signal.SIGTERM, force_quit) from xpra.gtk_common.gobject_compat import is_gtk3 if not is_gtk3(): signal.signal(signal.SIGINT, deadly_signal) signal.signal(signal.SIGTERM, deadly_signal) def check_for_end(*args): qtime = ss.queue.get_property("current-level-time")//MS_TO_NS if qtime<=0: log.info("underrun (end of stream)") thread.start_new_thread(ss.stop, ()) glib.timeout_add(500, glib_mainloop.quit) return False return True glib.timeout_add(1000, check_for_end) glib.idle_add(ss.add_data, data) glib_mainloop.run() return 0