def main(): window = gtk.Window(WINDOW_TOPLEVEL) window.set_size_request(400, 100) window.connect("delete_event", gtk.main_quit) da = gtk.DrawingArea() window.add(da) window.show_all() #self.selectX11FocusChange(self) def focus_in(_window, event): print("focus-in-event") def focus_out(_window, event): print("focus-out-event") def has_toplevel_focus(_window, event): print("has-toplevel-event") window.connect("focus-in-event", focus_in) window.connect("focus-out-event", focus_out) window.connect("notify::has-toplevel-focus", has_toplevel_focus) #x11 focus events: gdk_win = window.get_window() xid = get_xwindow(gdk_win) init_gdk_display_source() os.environ["XPRA_X11_DEBUG_EVENTS"] = "FocusIn,FocusOut" init_x11_filter() with xlog: X11WindowBindings().selectFocusChange(xid) gtk.main() return 0
def check_support(): ptr = get_display_ptr() if not ptr: from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source #@UnresolvedImport, @UnusedImport init_gdk_display_source() return GLContext().check_support()
def test_display(self): if os.environ.get("DISPLAY") and POSIX and not OSX and os.environ.get( "GDK_BACKEND", "x11") == "x11": from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() from xpra.server.mixins.display_manager import DisplayManager from xpra.server.source.clientdisplay_mixin import ClientDisplayMixin opts = AdHocStruct() opts.bell = True opts.cursors = True opts.dpi = 144 opts.opengl = "no" def get_root_window_size(): return 1024, 768 def calculate_workarea(*_args): pass def set_desktop_geometry(*_args): pass def _DisplayManager(): dm = DisplayManager() dm.get_root_window_size = get_root_window_size dm.calculate_workarea = calculate_workarea dm.set_desktop_geometry = set_desktop_geometry return dm self._test_mixin_class(_DisplayManager, opts, {}, ClientDisplayMixin)
def main(argv=()): from xpra.os_util import POSIX, OSX from xpra.platform import program_context from xpra.platform.gui import init, set_default_icon with program_context("Xpra-Bug-Report", "Xpra Bug Report"): from xpra.log import enable_color enable_color() if POSIX and not OSX: from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() set_default_icon("bugs.png") init() from xpra.log import enable_debug_for #logging init: if "-v" in argv: enable_debug_for("util") from xpra.client.gtk_base.bug_report import BugReport from xpra.gtk_common.gobject_compat import register_os_signals app = BugReport() app.close = app.quit app.init(True) register_os_signals(app.quit, "Bug Report") try: from xpra.platform.gui import ready as gui_ready gui_ready() app.show() app.run() except KeyboardInterrupt: pass return 0
def main(): try: from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() except ImportError: pass from xpra.platform.gui import main as gui_main gui_main()
def main(): try: from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() except: pass from xpra.platform.gui import main main()
def main(args): from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() for wid in args[1:]: print("looking for window %s" % wid) if wid.startswith("0x"): dump_xshape(int(wid[2:], 16)) else: dump_xshape(int(wid))
def test_input(self): if os.environ.get("DISPLAY") and POSIX and not OSX and os.environ.get( "GDK_BACKEND", "x11") == "x11": from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() from xpra.server.mixins.input_server import InputServer from xpra.server.source.input_mixin import InputMixin opts = AdHocStruct() self._test_mixin_class(InputServer, opts, {}, InputMixin)
def make_window(): window = Gtk.Window(type=Gtk.WindowType.TOPLEVEL) window.set_title("Window Focus") window.set_size_request(640, 200) window.connect("delete_event", Gtk.main_quit) vbox = Gtk.VBox() N = 8 labels = [] font = Pango.FontDescription("sans 12") for _ in range(N): l = Gtk.Label() l.modify_font(font) labels.append(l) for l in labels: al = Gtk.Alignment(xalign=0, yalign=0.5, xscale=0.0, yscale=0) al.add(l) vbox.add(al) window.add(vbox) window.show_all() text = deque(maxlen=N) def update(s): text.append("%s: %s" % (datetime.now(), s)) for i, t in enumerate(text): labels[i].set_text(t) #self.selectX11FocusChange(self) def focus_in(_window, event): update("focus-in-event") def focus_out(_window, event): update("focus-out-event") def has_toplevel_focus(window, _event): update("has-toplevel-focus: %s" % window.has_toplevel_focus()) window.connect("focus-in-event", focus_in) window.connect("focus-out-event", focus_out) window.connect("notify::has-toplevel-focus", has_toplevel_focus) if POSIX and not OSX: from xpra.gtk_common.error import xlog from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source from xpra.x11.gtk_x11.gdk_bindings import init_x11_filter from xpra.x11.bindings.window_bindings import X11WindowBindings #pylint: disable=no-name-in-module from xpra.os_util import is_Wayland if not is_Wayland(): #x11 focus events: gdk_win = window.get_window() xid = gdk_win.get_xid() init_gdk_display_source() os.environ["XPRA_X11_DEBUG_EVENTS"] = "FocusIn,FocusOut" init_x11_filter() with xlog: X11WindowBindings().selectFocusChange(xid) return window
def __enter__(self): OSEnvContext.__enter__(self) if POSIX and not OSX: ProcessTestUtil.setUpClass() self.stu = ProcessTestUtil() self.stu.setUp() self.xvfb_process = self.stu.start_Xvfb() os.environ["GDK_BACKEND"] = "x11" os.environ["DISPLAY"] = self.xvfb_process.display from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source()
def send_net_showing_desktop(v): from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source from xpra.x11.bindings.window_bindings import constants, X11WindowBindings #@UnresolvedImport init_gdk_display_source() X11Window = X11WindowBindings() root = window.get_window().get_screen().get_root_window() root_xid = root.get_xid() SubstructureNotifyMask = constants["SubstructureNotifyMask"] SubstructureRedirectMask = constants["SubstructureRedirectMask"] event_mask = SubstructureNotifyMask | SubstructureRedirectMask X11Window.sendClientMessage(root_xid, root_xid, False, event_mask, "_NET_SHOWING_DESKTOP", v)
def main(): #use gtk as display source: from xpra.os_util import POSIX if POSIX: from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() from xpra.util import print_nested_dict from xpra.platform import program_context with program_context("GTK-Keyboard", "GTK Keyboard"): x = GTKKeyboardHelper(None, True, "") x.query_xkbmap() print_nested_dict(x.get_keymap_properties())
def test_clipboard(self): with DisplayContext(): if POSIX and not OSX: from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() from xpra.server.mixins.clipboard_server import ClipboardServer from xpra.server.source.clipboard_connection import ClipboardConnection opts = AdHocStruct() opts.clipboard = "yes" opts.clipboard_direction = "both" opts.clipboard_filter_file = None self._test_mixin_class(ClipboardServer, opts, {}, ClipboardConnection)
def moveresize_X11(self, *_args): new_x, new_y, new_width, new_height = self.get_new_geometry() from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() from xpra.x11.bindings.window_bindings import constants, X11WindowBindings #@UnresolvedImport X11Window = X11WindowBindings() root = self.get_window().get_screen().get_root_window() root_xid = root.xid xwin = self.get_window().xid SubstructureNotifyMask = constants["SubstructureNotifyMask"] SubstructureRedirectMask = constants["SubstructureRedirectMask"] event_mask = SubstructureNotifyMask | SubstructureRedirectMask X11Window.sendClientMessage(root_xid, xwin, False, event_mask, "_NET_MOVERESIZE_WINDOW", 1+2**8+2**9+2**10+2**11, new_x, new_y, new_width, new_height)
def initiate(x_root, y_root, direction, button, source_indication): #print("initiate%s" % str((x_root, y_root, direction, button, source_indication))) from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() from xpra.x11.bindings.core_bindings import X11CoreBindings #@UnresolvedImport from xpra.x11.bindings.window_bindings import constants, X11WindowBindings #@UnresolvedImport event_mask = constants["SubstructureNotifyMask"] | constants["SubstructureRedirectMask"] root_xid = get_root_window().get_xid() xwin = window.get_window().get_xid() X11Core = X11CoreBindings() X11Core.UngrabPointer() X11Window = X11WindowBindings() X11Window.sendClientMessage(root_xid, xwin, False, event_mask, "_NET_WM_MOVERESIZE", x_root, y_root, direction, button, source_indication)
def send_maximized_wm_state(mode): from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() from xpra.x11.bindings.window_bindings import constants, X11WindowBindings #@UnresolvedImport X11Window = X11WindowBindings() root = window.get_window().get_screen().get_root_window() root_xid = root.get_xid() xwin = window.get_window().get_xid() SubstructureNotifyMask = constants["SubstructureNotifyMask"] SubstructureRedirectMask = constants["SubstructureRedirectMask"] event_mask = SubstructureNotifyMask | SubstructureRedirectMask X11Window.sendClientMessage(root_xid, xwin, False, event_mask, "_NET_WM_STATE", mode, "_NET_WM_STATE_MAXIMIZED_VERT", "_NET_WM_STATE_MAXIMIZED_HORZ", 0, 0)
def main(): init_gdk_display_source() win = Gtk.Window() win.set_size_request(400, 100) win.set_title("WM_COMMAND test") win.show() def change_wmcommand(): with xsync: prop_set(win.get_window(), "WM_COMMAND", "latin1", "HELLO WORLD") print("WM_COMMAND changed!") GLib.timeout_add(1000, change_wmcommand) Gtk.main() return 0
def main(): from xpra.x11.xsettings_prop import XSettingsNames from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() s = XSettingsHelper().get_settings() assert s seq, data = s print("XSettings: (sequence %i)" % seq) for vtype, prop, value, serial in data: if isinstance(value, bytes): vstr = value.decode() else: vstr = str(value) if serial>0: vstr += " (serial=%#x)" % serial print("%8s: %32s = %-32s" % (XSettingsNames.get(vtype, "?"), prop.decode(), vstr))
def main(): from xpra.log import enable_color from xpra.platform.gui import init, set_default_icon with program_context("Keyboard-Test", "Keyboard Test Tool"): enable_color() set_default_icon("keyboard.png") init() if POSIX and not OSX: from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() w = KeyboardStateInfoWindow() GLib.idle_add(w.show_with_focus) Gtk.main() return 0
def main(): x, y = 0, 0 if len(sys.argv) == 3: x, y = int(sys.argv[1]), int(sys.argv[2]) window = Gtk.Window(type=Gtk.WindowType.TOPLEVEL) window.set_size_request(width, height) window.connect("delete_event", Gtk.main_quit) window.realize() window.move(x, y) from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() from xpra.x11.bindings.window_bindings import X11WindowBindings hints = {"position": (x, y)} X11WindowBindings().setSizeHints(window.get_window().get_xid(), hints) window.show_all() Gtk.main()
def _send_client_message(window, message_type, *values): try: from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() from xpra.x11.bindings.window_bindings import constants #@UnresolvedImport X11Window = X11WindowBindings() root_xid = X11Window.getDefaultRootWindow() if window: xid = get_xwindow(window) else: xid = root_xid SubstructureNotifyMask = constants["SubstructureNotifyMask"] SubstructureRedirectMask = constants["SubstructureRedirectMask"] event_mask = SubstructureNotifyMask | SubstructureRedirectMask X11Window.sendClientMessage(root_xid, xid, False, event_mask, message_type, *values) except Exception as e: log.warn("failed to send client message '%s' with values=%s: %s", message_type, values, e)
def main(): from xpra.platform import program_context from xpra.platform.gui import init as gui_init from xpra.util import print_nested_dict from xpra.log import enable_color with program_context("OpenGL-Check"): gui_init() enable_color() verbose = "-v" in sys.argv or "--verbose" in sys.argv if verbose: log.enable_debug() if POSIX and not OSX: from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() force_enable = "-f" in sys.argv or "--force" in sys.argv from xpra.platform.gl_context import GLContext log("testing %s", GLContext) gl_context = GLContext() log("GLContext=%s", gl_context) #replace ImportError with a log message: global gl_check_error, raise_fatal_error errors = [] def log_error(msg): log.error("ERROR: %s", msg) errors.append(msg) gl_check_error = log_error raise_fatal_error = log_error try: props = gl_context.check_support(force_enable) except Exception as e: props = {} log("check_support", exc_info=True) errors.append(e) log.info("") if len(errors) > 0: log.info("OpenGL errors:") for e in errors: log.info(" %s", e) if props: log.info("") log.info("OpenGL properties:") print_nested_dict(props) return len(errors)
def test_add(w, h): from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() from xpra.x11.bindings.randr_bindings import RandRBindings, log #@UnresolvedImport log.enable_debug() RandR = RandRBindings() screen_sizes = RandR.get_xrr_screen_sizes() print("screen_sizes=%s" % (screen_sizes, )) if (w, h) in screen_sizes: print("resolution %s is already present!" % ((w, h), )) return from xpra.gtk_common.error import xsync with xsync: r = RandR.add_screen_size(w, h) print("add_screen_size(%i, %i)=%s" % (w, h, r)) import time time.sleep(2) screen_sizes = RandR.get_xrr_screen_sizes() print("updated screen_sizes=%s" % (screen_sizes, ))
def populate_form(self): btn = link_btn( "https://github.com/Xpra-org/xpra/blob/master/docs/Features/Keyboard.md", label="Open Keyboard Documentation", icon_name=None) self.vbox.pack_start(btn, expand=True, fill=False, padding=20) tb = self.table() if POSIX and not OSX: try: from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() except Exception: pass from xpra.platform.keyboard import Keyboard kbd = Keyboard() #pylint: disable=not-callable layouts = { "": "auto", } layouts.update(kbd.get_all_x11_layouts()) self.combo(tb, "Keyboard Layout", "keyboard-layout", layouts) self.bool_cb(tb, "State Synchronization", "keyboard-sync") self.bool_cb(tb, "Raw Mode", "keyboard-raw") self.combo( tb, "Input Method", "input-method", { "auto": "auto", "none": "default", "keep": "unchanged", "xim": "xim", "IBus": "IBus", "SCIM": "SCIM", "uim": "uim", }) self.combo( tb, "Shortcut Modifiers", "shortcut-modifiers", { "auto": "auto", "shift + control": "Shift+Control", "control + alt": "Control+Alt", "shift + alt": "Shift+Alt", }) self.vbox.show_all()
def main(): from xpra.log import enable_color from xpra.platform.gui import init, set_default_icon with program_context("Keyboard-Test", "Keyboard Test Tool"): enable_color() set_default_icon("keyboard.png") init() from xpra.gtk_common.gobject_compat import register_os_signals def signal_handler(*_args): Gtk.main_quit() register_os_signals(signal_handler, "test window") if POSIX and not OSX: from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() w = KeyboardStateInfoWindow() GLib.idle_add(w.show_with_focus) Gtk.main() return 0
def main(): init_gdk_display_source() win = Gtk.Window() win.realize() def print_extents(): v = prop_get(win.get_window(), "_NET_FRAME_EXTENTS", ["u32"], ignore_errors=False) print("_NET_FRAME_EXTENTS: %s" % str(v)) with xsync: event_mask = SubstructureNotifyMask | SubstructureRedirectMask X11Window.sendClientMessage(root.xid, win.get_window().xid, False, event_mask, "_NET_REQUEST_FRAME_EXTENTS") print("sending _NET_REQUEST_FRAME_EXTENTS to %#x for %#x" % (root.xid, win.get_window().xid)) return v is None print_extents() GLib.timeout_add(1000, print_extents) Gtk.main() return 0
def do_run_server(error_cb, opts, mode, xpra_file, extra_args, desktop_display=None): try: cwd = os.getcwd() except OSError: cwd = os.path.expanduser("~") warn("current working directory does not exist, using '%s'\n" % cwd) validate_encryption(opts) if opts.encoding == "help" or "help" in opts.encodings: return show_encoding_help(opts) assert mode in ("start", "start-desktop", "upgrade", "shadow", "proxy") starting = mode == "start" starting_desktop = mode == "start-desktop" upgrading = mode == "upgrade" shadowing = mode == "shadow" proxying = mode == "proxy" clobber = upgrading or opts.use_display start_vfb = not shadowing and not proxying and not clobber if shadowing and is_Wayland(): warn("shadow servers do not support Wayland, switch to X11") if opts.bind_rfb and (proxying or starting): get_util_logger().warn( "Warning: bind-rfb sockets cannot be used with '%s' mode" % mode) opts.bind_rfb = "" if not shadowing and not starting_desktop: opts.rfb_upgrade = 0 if upgrading or shadowing: #there should already be one running opts.pulseaudio = False #get the display name: if shadowing and not extra_args: if WIN32 or OSX: #just a virtual name for the only display available: display_name = ":0" else: from xpra.scripts.main import guess_X11_display dotxpra = DotXpra(opts.socket_dir, opts.socket_dirs) display_name = guess_X11_display(dotxpra, desktop_display) elif upgrading and not extra_args: display_name = guess_xpra_display(opts.socket_dir, opts.socket_dirs) else: if len(extra_args) > 1: error_cb( "too many extra arguments (%i): only expected a display number" % len(extra_args)) if len(extra_args) == 1: display_name = extra_args[0] if not shadowing and not proxying and not opts.use_display: display_name_check(display_name) else: if proxying: #find a free display number: dotxpra = DotXpra(opts.socket_dir, opts.socket_dirs) all_displays = dotxpra.sockets() #ie: [("LIVE", ":100"), ("LIVE", ":200"), ...] displays = [v[1] for v in all_displays] display_name = None for x in range(1000, 20000): v = ":%s" % x if v not in displays: display_name = v break if not display_name: error_cb( "you must specify a free virtual display name to use with the proxy server" ) elif opts.use_display: #only use automatic guess for xpra displays and not X11 displays: display_name = guess_xpra_display(opts.socket_dir, opts.socket_dirs) else: # We will try to find one automaticaly # Use the temporary magic value 'S' as marker: display_name = 'S' + str(os.getpid()) if not shadowing and not proxying and not upgrading and opts.exit_with_children and not opts.start_child: error_cb( "--exit-with-children specified without any children to spawn; exiting immediately" ) atexit.register(run_cleanups) # Generate the script text now, because os.getcwd() will # change if/when we daemonize: from xpra.server.server_util import ( xpra_runner_shell_script, write_runner_shell_scripts, write_pidfile, find_log_dir, create_input_devices, ) script = xpra_runner_shell_script(xpra_file, cwd, opts.socket_dir) uid = int(opts.uid) gid = int(opts.gid) username = get_username_for_uid(uid) home = get_home_for_uid(uid) xauth_data = None if start_vfb: xauth_data = get_hex_uuid() ROOT = POSIX and getuid() == 0 protected_fds = [] protected_env = {} stdout = sys.stdout stderr = sys.stderr # Daemonize: if POSIX and opts.daemon: #daemonize will chdir to "/", so try to use an absolute path: if opts.password_file: opts.password_file = tuple( os.path.abspath(x) for x in opts.password_file) from xpra.server.server_util import daemonize daemonize() displayfd = 0 if POSIX and opts.displayfd: try: displayfd = int(opts.displayfd) if displayfd > 0: protected_fds.append(displayfd) except ValueError as e: stderr.write("Error: invalid displayfd '%s':\n" % opts.displayfd) stderr.write(" %s\n" % e) del e # if pam is present, try to create a new session: pam = None PAM_OPEN = POSIX and envbool("XPRA_PAM_OPEN", ROOT and uid != 0) if PAM_OPEN: try: from xpra.server.pam import pam_session #@UnresolvedImport except ImportError as e: stderr.write("Error: failed to import pam module\n") stderr.write(" %s" % e) del e PAM_OPEN = False if PAM_OPEN: fdc = FDChangeCaptureContext() with fdc: pam = pam_session(username) env = { #"XDG_SEAT" : "seat1", #"XDG_VTNR" : "0", "XDG_SESSION_TYPE": "x11", #"XDG_SESSION_CLASS" : "user", "XDG_SESSION_DESKTOP": "xpra", } #maybe we should just bail out instead? if pam.start(): pam.set_env(env) items = {} if display_name.startswith(":"): items["XDISPLAY"] = display_name if xauth_data: items["XAUTHDATA"] = xauth_data pam.set_items(items) if pam.open(): #we can't close it, because we're not going to be root any more, #but since we're the process leader for the session, #terminating will also close the session #add_cleanup(pam.close) protected_env = pam.get_envlist() os.environ.update(protected_env) #closing the pam fd causes the session to be closed, #and we don't want that! protected_fds += fdc.get_new_fds() #get XDG_RUNTIME_DIR from env options, #which may not be have updated os.environ yet when running as root with "--uid=" xrd = os.path.abspath(parse_env(opts.env).get("XDG_RUNTIME_DIR", "")) if ROOT and (uid > 0 or gid > 0): #we're going to chown the directory if we create it, #ensure this cannot be abused, only use "safe" paths: if not any(x for x in ("/run/user/%i" % uid, "/tmp", "/var/tmp") if xrd.startswith(x)): xrd = "" #these paths could cause problems if we were to create and chown them: if xrd.startswith("/tmp/.X11-unix") or xrd.startswith( "/tmp/.XIM-unix"): xrd = "" if not xrd: xrd = os.environ.get("XDG_RUNTIME_DIR") xrd = create_runtime_dir(xrd, uid, gid) if xrd: #this may override the value we get from pam #with the value supplied by the user: protected_env["XDG_RUNTIME_DIR"] = xrd if opts.pidfile: write_pidfile(opts.pidfile, uid, gid) if POSIX and not ROOT: # Write out a shell-script so that we can start our proxy in a clean # environment: write_runner_shell_scripts(script) if start_vfb or opts.daemon: #we will probably need a log dir #either for the vfb, or for our own log file log_dir = opts.log_dir or "" if not log_dir or log_dir.lower() == "auto": log_dir = find_log_dir(username, uid=uid, gid=gid) if not log_dir: raise InitException( "cannot find or create a logging directory") #expose the log-dir as "XPRA_LOG_DIR", #this is used by Xdummy for the Xorg log file if "XPRA_LOG_DIR" not in os.environ: os.environ["XPRA_LOG_DIR"] = log_dir if opts.daemon: from xpra.server.server_util import select_log_file, open_log_file, redirect_std_to_log log_filename0 = osexpand( select_log_file(log_dir, opts.log_file, display_name), username, uid, gid) logfd = open_log_file(log_filename0) if ROOT and (uid > 0 or gid > 0): try: os.fchown(logfd, uid, gid) except: pass stdout, stderr = redirect_std_to_log(logfd, *protected_fds) try: stderr.write("Entering daemon mode; " + "any further errors will be reported to:\n" + (" %s\n" % log_filename0)) except IOError: #we tried our best, logging another error won't help pass #warn early about this: if (starting or starting_desktop ) and desktop_display and opts.notifications and not opts.dbus_launch: print_DE_warnings() log = get_util_logger() sockets, mdns_recs, wrap_socket_fn = create_sockets(opts, error_cb) sanitize_env() if POSIX: if xrd: os.environ["XDG_RUNTIME_DIR"] = xrd os.environ["XDG_SESSION_TYPE"] = "x11" if not starting_desktop: os.environ["XDG_CURRENT_DESKTOP"] = opts.wm_name configure_imsettings_env(opts.input_method) if display_name[0] != 'S': os.environ["DISPLAY"] = display_name os.environ["CKCON_X11_DISPLAY"] = display_name else: try: del os.environ["DISPLAY"] except KeyError: pass os.environ.update(protected_env) log("env=%s", os.environ) UINPUT_UUID_LEN = 12 UINPUT_UUID_MIN_LEN = 12 UINPUT_UUID_MAX_LEN = 32 # Start the Xvfb server first to get the display_name if needed odisplay_name = display_name xvfb = None xvfb_pid = None uinput_uuid = None if start_vfb: assert not proxying and xauth_data pixel_depth = validate_pixel_depth(opts.pixel_depth, starting_desktop) from xpra.x11.vfb_util import start_Xvfb, check_xvfb_process from xpra.server.server_util import has_uinput uinput_uuid = None if has_uinput() and opts.input_devices.lower() in ( "uinput", "auto") and not shadowing: from xpra.os_util import get_rand_chars uinput_uuid = get_rand_chars(UINPUT_UUID_LEN) xvfb, display_name, cleanups = start_Xvfb(opts.xvfb, pixel_depth, display_name, cwd, uid, gid, username, xauth_data, uinput_uuid) for f in cleanups: add_cleanup(f) xvfb_pid = xvfb.pid #always update as we may now have the "real" display name: os.environ["DISPLAY"] = display_name os.environ["CKCON_X11_DISPLAY"] = display_name os.environ.update(protected_env) if display_name != odisplay_name and pam: pam.set_items({"XDISPLAY": display_name}) def check_xvfb(): return check_xvfb_process(xvfb) else: if POSIX and clobber: #if we're meant to be using a private XAUTHORITY file, #make sure to point to it: from xpra.x11.vfb_util import get_xauthority_path xauthority = get_xauthority_path(display_name, username, uid, gid) if os.path.exists(xauthority): os.environ["XAUTHORITY"] = xauthority def check_xvfb(): return True if POSIX and not OSX and displayfd > 0: from xpra.platform.displayfd import write_displayfd try: display = display_name[1:] log("writing display='%s' to displayfd=%i", display, displayfd) assert write_displayfd(displayfd, display), "timeout" except Exception as e: log.error("write_displayfd failed", exc_info=True) log.error("Error: failed to write '%s' to fd=%s", display_name, displayfd) log.error(" %s", str(e) or type(e)) del e try: os.close(displayfd) except IOError: pass kill_display = None if not proxying: add_cleanup(close_gtk_display) if not proxying and not shadowing: def kill_display(): if xvfb_pid: kill_xvfb(xvfb_pid) add_cleanup(kill_display) if opts.daemon: def noerr(fn, *args): try: fn(*args) except: pass log_filename1 = osexpand( select_log_file(log_dir, opts.log_file, display_name), username, uid, gid) if log_filename0 != log_filename1: # we now have the correct log filename, so use it: os.rename(log_filename0, log_filename1) if odisplay_name != display_name: #this may be used by scripts, let's try not to change it: noerr(stderr.write, "Actual display used: %s\n" % display_name) noerr(stderr.write, "Actual log file name is now: %s\n" % log_filename1) noerr(stderr.flush) noerr(stdout.close) noerr(stderr.close) #we should not be using stdout or stderr from this point: del stdout del stderr if not check_xvfb(): #xvfb problem: exit now return 1 #create devices for vfb if needed: devices = {} if not start_vfb and not proxying and not shadowing: #try to find the existing uinput uuid: #use a subprocess to avoid polluting our current process #with X11 connections before we get a chance to change uid prop = "_XPRA_UINPUT_ID" cmd = ["xprop", "-display", display_name, "-root", prop] log("looking for '%s' on display '%s' with XAUTHORITY='%s'", prop, display_name, os.environ.get("XAUTHORITY")) try: code, out, err = get_status_output(cmd) except Exception as e: log("failed to get existing uinput id: %s", e) del e else: log("Popen(%s)=%s", cmd, (code, out, err)) if code == 0 and out.find("=") > 0: uinput_uuid = out.split("=", 1)[1] log("raw uinput uuid=%s", uinput_uuid) uinput_uuid = strtobytes(uinput_uuid.strip('\n\r"\\ ')) if uinput_uuid: if len(uinput_uuid) > UINPUT_UUID_MAX_LEN or len( uinput_uuid) < UINPUT_UUID_MIN_LEN: log.warn("Warning: ignoring invalid uinput id:") log.warn(" '%s'", uinput_uuid) uinput_uuid = None else: log.info("retrieved existing uinput id: %s", bytestostr(uinput_uuid)) if uinput_uuid: devices = create_input_devices(uinput_uuid, uid) if ROOT and (uid != 0 or gid != 0): log("root: switching to uid=%i, gid=%i", uid, gid) setuidgid(uid, gid) os.environ.update({ "HOME": home, "USER": username, "LOGNAME": username, }) shell = get_shell_for_uid(uid) if shell: os.environ["SHELL"] = shell #now we've changed uid, it is safe to honour all the env updates: configure_env(opts.env) os.environ.update(protected_env) if opts.chdir: os.chdir(opts.chdir) display = None if not proxying: no_gtk() if POSIX and not OSX and (starting or starting_desktop or shadowing): #check that we can access the X11 display: from xpra.x11.vfb_util import verify_display_ready if not verify_display_ready(xvfb, display_name, shadowing): return 1 if not PYTHON3: from xpra.x11.gtk2.gdk_display_util import verify_gdk_display #@UnusedImport else: from xpra.x11.gtk3.gdk_display_util import verify_gdk_display #@Reimport display = verify_gdk_display(display_name) if not display: return 1 #on win32, this ensures that we get the correct screen size to shadow: from xpra.platform.gui import init as gui_init gui_init() #setup unix domain socket: from xpra.server.socket_util import get_network_logger, setup_local_sockets netlog = get_network_logger() if not opts.socket_dir and not opts.socket_dirs: #we always need at least one valid socket dir from xpra.platform.paths import get_socket_dirs opts.socket_dirs = get_socket_dirs() local_sockets = setup_local_sockets(opts.bind, opts.socket_dir, opts.socket_dirs, display_name, clobber, opts.mmap_group, opts.socket_permissions, username, uid, gid) netlog("setting up local sockets: %s", local_sockets) ssh_port = get_ssh_port() ssh_access = ssh_port > 0 and opts.ssh.lower().strip() not in FALSE_OPTIONS for rec, cleanup_socket in local_sockets: socktype, socket, sockpath = rec #ie: ("unix-domain", sock, sockpath), cleanup_socket sockets.append(rec) netlog("%s %s : %s", socktype, sockpath, socket) add_cleanup(cleanup_socket) if opts.mdns and ssh_access: netlog("ssh %s:%s : %s", "", ssh_port, socket) add_mdns(mdns_recs, "ssh", "", ssh_port) def b(v): return str(v).lower() not in FALSE_OPTIONS #turn off some server mixins: from xpra.server import server_features impwarned = [] def impcheck(*modules): for mod in modules: try: __import__("xpra.%s" % mod, {}, {}, []) except ImportError: if mod not in impwarned: impwarned.append(mod) log = get_util_logger() log.warn("Warning: missing %s module", mod) return False return True server_features.notifications = opts.notifications and impcheck( "notifications") server_features.webcam = b(opts.webcam) and impcheck("codecs") server_features.clipboard = b(opts.clipboard) and impcheck("clipboard") server_features.audio = (b(opts.speaker) or b(opts.microphone)) and impcheck("sound") server_features.av_sync = server_features.audio and b(opts.av_sync) server_features.fileprint = b(opts.printing) or b(opts.file_transfer) server_features.mmap = b(opts.mmap) server_features.input_devices = not opts.readonly and impcheck("keyboard") server_features.commands = impcheck("server.control_command") server_features.dbus = opts.dbus_proxy and impcheck("dbus") server_features.encoding = impcheck("codecs") server_features.logging = b(opts.remote_logging) #server_features.network_state = ?? server_features.display = opts.windows server_features.windows = opts.windows and impcheck("codecs") server_features.rfb = b(opts.rfb_upgrade) and impcheck("server.rfb") kill_dbus = None if shadowing: app = make_shadow_server() elif proxying: app = make_proxy_server() else: if not check_xvfb(): return 1 assert starting or starting_desktop or upgrading from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source, close_gdk_display_source init_gdk_display_source() insert_cleanup(close_gdk_display_source) #(now we can access the X11 server) #make sure the pid we save is the real one: if not check_xvfb(): return 1 if xvfb_pid is not None: #save the new pid (we should have one): save_xvfb_pid(xvfb_pid) if POSIX: save_uinput_id(uinput_uuid) dbus_pid = -1 dbus_env = {} if clobber: #get the saved pids and env dbus_pid = get_dbus_pid() dbus_env = get_dbus_env() log("retrieved existing dbus attributes") else: assert starting or starting_desktop if xvfb_pid is not None: #save the new pid (we should have one): save_xvfb_pid(xvfb_pid) bus_address = protected_env.get("DBUS_SESSION_BUS_ADDRESS") log("dbus_launch=%s, current DBUS_SESSION_BUS_ADDRESS=%s", opts.dbus_launch, bus_address) if opts.dbus_launch and not bus_address: #start a dbus server: def kill_dbus(): log("kill_dbus: dbus_pid=%s" % dbus_pid) if dbus_pid <= 0: return try: os.kill(dbus_pid, signal.SIGINT) except Exception as e: log.warn( "Warning: error trying to stop dbus with pid %i:", dbus_pid) log.warn(" %s", e) add_cleanup(kill_dbus) #this also updates os.environ with the dbus attributes: dbus_pid, dbus_env = start_dbus(opts.dbus_launch) if dbus_pid > 0: save_dbus_pid(dbus_pid) if dbus_env: save_dbus_env(dbus_env) log("dbus attributes: pid=%s, env=%s", dbus_pid, dbus_env) if dbus_env: os.environ.update(dbus_env) os.environ.update(protected_env) if POSIX: #all unix domain sockets: ud_paths = [ sockpath for (stype, _, sockpath), _ in local_sockets if stype == "unix-domain" ] if ud_paths: #choose one so our xdg-open override script can use to talk back to us: if opts.forward_xdg_open: for x in ("/usr/libexec/xpra", "/usr/lib/xpra"): xdg_override = os.path.join(x, "xdg-open") if os.path.exists(xdg_override): os.environ[ "PATH"] = x + os.pathsep + os.environ.get( "PATH", "") os.environ[ "XPRA_XDG_OPEN_SERVER_SOCKET"] = ud_paths[0] break else: log.warn("Warning: no local server sockets,") if opts.forward_xdg_open: log.warn(" forward-xdg-open cannot be enabled") log.warn(" ssh connections will not be available") log("env=%s", os.environ) try: # This import is delayed because the module depends on gtk: from xpra.x11.bindings.window_bindings import X11WindowBindings X11Window = X11WindowBindings() if (starting or starting_desktop) and not clobber and opts.resize_display: from xpra.x11.vfb_util import set_initial_resolution set_initial_resolution(starting_desktop) except ImportError as e: log.error( "Failed to load Xpra server components, check your installation: %s" % e) return 1 if starting or upgrading: if not X11Window.displayHasXComposite(): log.error( "Xpra 'start' subcommand runs as a compositing manager") log.error( " it cannot use a display which lacks the XComposite extension!" ) return 1 if starting: #check for an existing window manager: from xpra.x11.gtk_x11.wm_check import wm_check if not wm_check(display, opts.wm_name, upgrading): return 1 log("XShape=%s", X11Window.displayHasXShape()) app = make_server(clobber) else: assert starting_desktop app = make_desktop_server() app.init_virtual_devices(devices) if proxying or upgrading: #when proxying or upgrading, don't exec any plain start commands: opts.start = opts.start_child = [] elif opts.exit_with_children: assert opts.start_child, "exit-with-children was specified but start-child is missing!" elif opts.start_child: log.warn("Warning: the 'start-child' option is used,") log.warn(" but 'exit-with-children' is not enabled,") log.warn(" use 'start' instead") try: app._ssl_wrap_socket = wrap_socket_fn app.original_desktop_display = desktop_display app.exec_cwd = opts.chdir or cwd app.init(opts) app.setup() except InitException as e: log.error("xpra server initialization error:") log.error(" %s", e) return 1 except Exception as e: log.error("Error: cannot start the %s server", app.session_type, exc_info=True) log.error(str(e)) log.info("") return 1 #publish mdns records: if opts.mdns: from xpra.platform.info import get_username from xpra.server.socket_util import mdns_publish mdns_info = { "display": display_name, "username": get_username(), "uuid": app.uuid, "platform": sys.platform, "type": app.session_type, } MDNS_EXPOSE_NAME = envbool("XPRA_MDNS_EXPOSE_NAME", True) if MDNS_EXPOSE_NAME and app.session_name: mdns_info["name"] = app.session_name for mode, listen_on in mdns_recs.items(): mdns_publish(display_name, mode, listen_on, mdns_info) del opts log("%s(%s)", app.init_sockets, sockets) app.init_sockets(sockets) log("%s(%s)", app.init_when_ready, _when_ready) app.init_when_ready(_when_ready) try: #from here on, we own the vfb, even if we inherited one: if (starting or starting_desktop or upgrading) and clobber: #and it will be killed if exit cleanly: xvfb_pid = get_xvfb_pid() log("running %s", app.run) r = app.run() log("%s()=%s", app.run, r) except KeyboardInterrupt: log.info("stopping on KeyboardInterrupt") return 0 except Exception: log.error("server error", exc_info=True) return -128 else: if r > 0: # Upgrading/exiting, so leave X and dbus servers running if kill_display: _cleanups.remove(kill_display) if kill_dbus: _cleanups.remove(kill_dbus) from xpra.server import EXITING_CODE if r == EXITING_CODE: log.info("exiting: not cleaning up Xvfb") else: log.info("upgrading: not cleaning up Xvfb") r = 0 return r
# This file is part of Xpra. # Copyright (C) 2011-2018 Antoine Martin <*****@*****.**> # Xpra is released under the terms of the GNU GPL v2, or, at your option, any # later version. See the file COPYING for details. import os import re #ensure that we use gtk as display source: from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() from xpra.util import std, csv from xpra.os_util import bytestostr from xpra.gtk_common.error import xsync from xpra.x11.bindings.keyboard_bindings import X11KeyboardBindings #@UnresolvedImport X11Keyboard = X11KeyboardBindings() from xpra.log import Logger log = Logger("x11", "keyboard") DEBUG_KEYSYMS = [ x for x in os.environ.get("XPRA_DEBUG_KEYSYMS", "").split(",") if len(x) > 0 ] #keys we choose not to map if the free space in the keymap is too limited #this list was generated using: #$ DISPLAY=:1 xmodmap -pke | awk -F= '{print $2}' | xargs -n 1 echo | sort -u | grep XF | xargs OPTIONAL_KEYS = [ "XF86AudioForward", "XF86AudioLowerVolume", "XF86AudioMedia",
def do_main(argv): from xpra.os_util import SIGNAMES from xpra.scripts.main import InitExit, InitInfo from xpra.platform.gui import init as gui_init, ready as gui_ready if POSIX and not OSX: from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source init_gdk_display_source() gui_init() try: from xpra.scripts.parsing import parse_cmdline, fixup_debug_option options, args = parse_cmdline(argv) debug = fixup_debug_option(options.debug) if debug: for x in debug.split(","): enable_debug_for(x) except InitInfo as e: print(str(e)) return 0 except InitExit as e: return e.status except Exception: exception_dialog("Error parsing command line") return 1 #allow config to be debugged: from xpra.scripts import config config.debug = log.debug try: app = ApplicationWindow() def handle_signal(signum): app.show() client = app.client if client: client.cleanup() else: Gtk.main_quit() GLib.timeout_add(1000, app.set_info_text, "got signal %s" % SIGNAMES.get(signum, signum)) GLib.timeout_add(1000, app.set_info_color, True) register_os_signals(handle_signal, "Client Launcher") has_file = len(args) == 1 if has_file: app.update_options_from_file(args[0]) #the compressors and packet encoders cannot be changed from the UI #so apply them now: configure_network(app.config) debug = fixup_debug_option(app.config.debug) if debug: for x in debug.split(","): enable_debug_for(x) app.create_window_with_config() except Exception: exception_dialog("Error creating launcher form") return 1 try: if app.config.autoconnect: #file says we should connect, #do that only (not showing UI unless something goes wrong): GLib.idle_add(app.do_connect) if not has_file: app.reset_errors() if not app.config.autoconnect or app.config.debug: if OSX: from xpra.platform.darwin.gui import wait_for_open_handlers, force_focus if has_file: force_focus() app.show() else: def open_file(filename): log("open_file(%s)", filename) app.update_options_from_file(filename) #the compressors and packet encoders cannot be changed from the UI #so apply them now: configure_network(app.config) app.update_gui_from_config() if app.config.autoconnect: app.__osx_open_signal = True GLib.idle_add(app.do_connect) else: force_focus() app.show() def open_URL(url): log("open_URL(%s)", url) app.__osx_open_signal = True app.update_options_from_URL(url) #the compressors and packet encoders cannot be changed from the UI #so apply them now: configure_network(app.config) app.update_gui_from_config() GLib.idle_add(app.do_connect) wait_for_open_handlers(app.show, open_file, open_URL) else: app.show() gui_ready() app.run() except KeyboardInterrupt: pass return 0
def do_run_server(error_cb, opts, mode, xpra_file, extra_args, desktop_display=None, progress_cb=None): assert mode in ( "start", "start-desktop", "upgrade", "upgrade-desktop", "shadow", "proxy", ) def _progress(i, msg): if progress_cb: progress_cb(i, msg) progress = _progress progress(10, "initializing environment") try: cwd = os.getcwd() except OSError: cwd = os.path.expanduser("~") warn("current working directory does not exist, using '%s'\n" % cwd) validate_encryption(opts) if opts.encoding == "help" or "help" in opts.encodings: return show_encoding_help(opts) #remove anything pointing to dbus from the current env #(so we only detect a dbus instance started by pam, # and override everything else) for k in tuple(os.environ.keys()): if k.startswith("DBUS_"): del os.environ[k] use_display = parse_bool("use-display", opts.use_display) starting = mode == "start" starting_desktop = mode == "start-desktop" upgrading = mode == "upgrade" upgrading_desktop = mode == "upgrade-desktop" shadowing = mode == "shadow" proxying = mode == "proxy" if not proxying and POSIX and not OSX: #we don't support wayland servers, #so make sure GDK will use the X11 backend: from xpra.os_util import saved_env saved_env["GDK_BACKEND"] = "x11" os.environ["GDK_BACKEND"] = "x11" has_child_arg = (opts.start_child or opts.start_child_on_connect or opts.start_child_after_connect or opts.start_child_on_last_client_exit) if proxying or upgrading or upgrading_desktop: #when proxying or upgrading, don't exec any plain start commands: opts.start = opts.start_child = [] elif opts.exit_with_children: assert has_child_arg, "exit-with-children was specified but start-child* is missing!" elif opts.start_child: warn("Warning: the 'start-child' option is used,") warn(" but 'exit-with-children' is not enabled,") warn(" use 'start' instead") if opts.bind_rfb and (proxying or starting): get_util_logger().warn( "Warning: bind-rfb sockets cannot be used with '%s' mode" % mode) opts.bind_rfb = [] if not shadowing and not starting_desktop: opts.rfb_upgrade = 0 if upgrading or upgrading_desktop or shadowing: #there should already be one running #so change None ('auto') to False if opts.pulseaudio is None: opts.pulseaudio = False #get the display name: if shadowing and not extra_args: if WIN32 or OSX: #just a virtual name for the only display available: display_name = "Main" else: from xpra.scripts.main import guess_X11_display dotxpra = DotXpra(opts.socket_dir, opts.socket_dirs) display_name = guess_X11_display(dotxpra, desktop_display) elif (upgrading or upgrading_desktop) and not extra_args: display_name = guess_xpra_display(opts.socket_dir, opts.socket_dirs) else: if len(extra_args) > 1: error_cb( "too many extra arguments (%i): only expected a display number" % len(extra_args)) if len(extra_args) == 1: display_name = extra_args[0] if not shadowing and not upgrading and not use_display: display_name_check(display_name) else: if proxying: #find a free display number: dotxpra = DotXpra(opts.socket_dir, opts.socket_dirs) all_displays = dotxpra.sockets() #ie: [("LIVE", ":100"), ("LIVE", ":200"), ...] displays = [v[1] for v in all_displays] display_name = None for x in range(1000, 20000): v = ":%s" % x if v not in displays: display_name = v break if not display_name: error_cb( "you must specify a free virtual display name to use with the proxy server" ) elif use_display: #only use automatic guess for xpra displays and not X11 displays: display_name = guess_xpra_display(opts.socket_dir, opts.socket_dirs) else: # We will try to find one automaticaly # Use the temporary magic value 'S' as marker: display_name = 'S' + str(os.getpid()) if not (shadowing or proxying or upgrading or upgrading_desktop) and \ opts.exit_with_children and not has_child_arg: error_cb( "--exit-with-children specified without any children to spawn; exiting immediately" ) atexit.register(run_cleanups) # Generate the script text now, because os.getcwd() will # change if/when we daemonize: from xpra.server.server_util import ( xpra_runner_shell_script, write_runner_shell_scripts, find_log_dir, create_input_devices, source_env, ) script = None if POSIX and getuid() != 0: script = xpra_runner_shell_script(xpra_file, cwd, opts.socket_dir) uid = int(opts.uid) gid = int(opts.gid) username = get_username_for_uid(uid) home = get_home_for_uid(uid) ROOT = POSIX and getuid() == 0 protected_fds = [] protected_env = {} stdout = sys.stdout stderr = sys.stderr # Daemonize: if POSIX and opts.daemon: #daemonize will chdir to "/", so try to use an absolute path: if opts.password_file: opts.password_file = tuple( os.path.abspath(x) for x in opts.password_file) from xpra.server.server_util import daemonize daemonize() displayfd = 0 if POSIX and opts.displayfd: try: displayfd = int(opts.displayfd) if displayfd > 0: protected_fds.append(displayfd) except ValueError as e: stderr.write("Error: invalid displayfd '%s':\n" % opts.displayfd) stderr.write(" %s\n" % e) del e clobber = int(upgrading or upgrading_desktop) * CLOBBER_UPGRADE | int( use_display or 0) * CLOBBER_USE_DISPLAY start_vfb = not (shadowing or proxying or clobber) xauth_data = None if start_vfb: xauth_data = get_hex_uuid() # if pam is present, try to create a new session: pam = None PAM_OPEN = POSIX and envbool("XPRA_PAM_OPEN", ROOT and uid != 0) if PAM_OPEN: try: from xpra.server.pam import pam_session #@UnresolvedImport except ImportError as e: stderr.write("Error: failed to import pam module\n") stderr.write(" %s" % e) del e PAM_OPEN = False if PAM_OPEN: fdc = FDChangeCaptureContext() with fdc: pam = pam_session(username) env = { #"XDG_SEAT" : "seat1", #"XDG_VTNR" : "0", "XDG_SESSION_TYPE": "x11", #"XDG_SESSION_CLASS" : "user", "XDG_SESSION_DESKTOP": "xpra", } #maybe we should just bail out instead? if pam.start(): pam.set_env(env) items = {} if display_name.startswith(":"): items["XDISPLAY"] = display_name if xauth_data: items["XAUTHDATA"] = xauth_data pam.set_items(items) if pam.open(): #we can't close it, because we're not going to be root any more, #but since we're the process leader for the session, #terminating will also close the session #add_cleanup(pam.close) protected_env = pam.get_envlist() os.environ.update(protected_env) #closing the pam fd causes the session to be closed, #and we don't want that! protected_fds += fdc.get_new_fds() #get XDG_RUNTIME_DIR from env options, #which may not be have updated os.environ yet when running as root with "--uid=" xrd = os.path.abspath(parse_env(opts.env).get("XDG_RUNTIME_DIR", "")) if ROOT and (uid > 0 or gid > 0): #we're going to chown the directory if we create it, #ensure this cannot be abused, only use "safe" paths: if not any(x for x in ("/run/user/%i" % uid, "/tmp", "/var/tmp") if xrd.startswith(x)): xrd = "" #these paths could cause problems if we were to create and chown them: if xrd.startswith("/tmp/.X11-unix") or xrd.startswith( "/tmp/.XIM-unix"): xrd = "" if not xrd: xrd = os.environ.get("XDG_RUNTIME_DIR") xrd = create_runtime_dir(xrd, uid, gid) if xrd: #this may override the value we get from pam #with the value supplied by the user: protected_env["XDG_RUNTIME_DIR"] = xrd if script: # Write out a shell-script so that we can start our proxy in a clean # environment: write_runner_shell_scripts(script) import datetime extra_expand = { "TIMESTAMP": datetime.datetime.now().strftime("%Y%m%d-%H%M%S") } log_to_file = opts.daemon or os.environ.get("XPRA_LOG_TO_FILE", "") == "1" if start_vfb or log_to_file: #we will probably need a log dir #either for the vfb, or for our own log file log_dir = opts.log_dir or "" if not log_dir or log_dir.lower() == "auto": log_dir = find_log_dir(username, uid=uid, gid=gid) if not log_dir: raise InitException( "cannot find or create a logging directory") #expose the log-dir as "XPRA_LOG_DIR", #this is used by Xdummy for the Xorg log file if "XPRA_LOG_DIR" not in os.environ: os.environ["XPRA_LOG_DIR"] = log_dir if log_to_file: from xpra.server.server_util import select_log_file, open_log_file, redirect_std_to_log log_filename0 = osexpand( select_log_file(log_dir, opts.log_file, display_name), username, uid, gid, extra_expand) if os.path.exists(log_filename0) and not display_name.startswith("S"): #don't overwrite the log file just yet, #as we may still fail to start log_filename0 += ".new" logfd = open_log_file(log_filename0) if POSIX and ROOT and (uid > 0 or gid > 0): try: os.fchown(logfd, uid, gid) except OSError as e: noerr(stderr.write, "failed to chown the log file '%s'\n" % log_filename0) noerr(stderr.flush) stdout, stderr = redirect_std_to_log(logfd, *protected_fds) noerr( stderr.write, "Entering daemon mode; " + "any further errors will be reported to:\n" + (" %s\n" % log_filename0)) noerr(stderr.flush) os.environ["XPRA_SERVER_LOG"] = log_filename0 else: #server log does not exist: os.environ.pop("XPRA_SERVER_LOG", None) #warn early about this: if (starting or starting_desktop ) and desktop_display and opts.notifications and not opts.dbus_launch: print_DE_warnings() if start_vfb and opts.xvfb.find("Xephyr") >= 0 and opts.sync_xvfb <= 0: warn("Warning: using Xephyr as vfb") warn(" you should also enable the sync-xvfb option") warn(" to keep the Xephyr window updated") progress(10, "creating sockets") from xpra.net.socket_util import get_network_logger, setup_local_sockets, create_sockets sockets = create_sockets(opts, error_cb) sanitize_env() os.environ.update(source_env(opts.source)) if POSIX: if xrd: os.environ["XDG_RUNTIME_DIR"] = xrd if not OSX: os.environ["XDG_SESSION_TYPE"] = "x11" if not starting_desktop: os.environ["XDG_CURRENT_DESKTOP"] = opts.wm_name configure_imsettings_env(opts.input_method) if display_name[0] != 'S': os.environ["DISPLAY"] = display_name if POSIX: os.environ["CKCON_X11_DISPLAY"] = display_name elif not start_vfb or opts.xvfb.find("Xephyr") < 0: os.environ.pop("DISPLAY", None) os.environ.update(protected_env) from xpra.log import Logger log = Logger("server") log("env=%s", os.environ) UINPUT_UUID_LEN = 12 UINPUT_UUID_MIN_LEN = 12 UINPUT_UUID_MAX_LEN = 32 # Start the Xvfb server first to get the display_name if needed odisplay_name = display_name xvfb = None xvfb_pid = None uinput_uuid = None if start_vfb and use_display is None: #use-display='auto' so we have to figure out #if we have to start the vfb or not: if not display_name: use_display = False else: progress(20, "connecting to the display") start_vfb = verify_display( None, display_name, log_errors=False, timeout=1) != 0 if start_vfb: progress(20, "starting a virtual display") assert not proxying and xauth_data pixel_depth = validate_pixel_depth(opts.pixel_depth, starting_desktop) from xpra.x11.vfb_util import start_Xvfb, check_xvfb_process, parse_resolution from xpra.server.server_util import has_uinput uinput_uuid = None if has_uinput() and opts.input_devices.lower() in ( "uinput", "auto") and not shadowing: from xpra.os_util import get_rand_chars uinput_uuid = get_rand_chars(UINPUT_UUID_LEN) vfb_geom = "" try: vfb_geom = parse_resolution(opts.resize_display) except Exception: pass xvfb, display_name, cleanups = start_Xvfb(opts.xvfb, vfb_geom, pixel_depth, display_name, cwd, uid, gid, username, xauth_data, uinput_uuid) for f in cleanups: add_cleanup(f) xvfb_pid = xvfb.pid #always update as we may now have the "real" display name: os.environ["DISPLAY"] = display_name os.environ["CKCON_X11_DISPLAY"] = display_name os.environ.update(protected_env) if display_name != odisplay_name and pam: pam.set_items({"XDISPLAY": display_name}) def check_xvfb(timeout=0): return check_xvfb_process(xvfb, timeout=timeout, command=opts.xvfb) else: if POSIX and clobber: #if we're meant to be using a private XAUTHORITY file, #make sure to point to it: from xpra.x11.vfb_util import get_xauthority_path xauthority = get_xauthority_path(display_name, username, uid, gid) if os.path.exists(xauthority): log("found XAUTHORITY=%s", xauthority) os.environ["XAUTHORITY"] = xauthority def check_xvfb(timeout=0): #pylint: disable=unused-argument return True if POSIX and not OSX and displayfd > 0: from xpra.platform.displayfd import write_displayfd try: display_no = display_name[1:] #ensure it is a string containing the number: display_no = str(int(display_no)) log("writing display_no='%s' to displayfd=%i", display_no, displayfd) assert write_displayfd(displayfd, display_no), "timeout" except Exception as e: log.error("write_displayfd failed", exc_info=True) log.error("Error: failed to write '%s' to fd=%s", display_name, displayfd) log.error(" %s", str(e) or type(e)) del e if not check_xvfb(1): noerr(stderr.write, "vfb failed to start, exiting\n") return EXIT_VFB_ERROR if WIN32 and os.environ.get("XPRA_LOG_FILENAME"): os.environ["XPRA_SERVER_LOG"] = os.environ["XPRA_LOG_FILENAME"] if opts.daemon: log_filename1 = osexpand( select_log_file(log_dir, opts.log_file, display_name), username, uid, gid, extra_expand) if log_filename0 != log_filename1: # we now have the correct log filename, so use it: try: os.rename(log_filename0, log_filename1) except (OSError, IOError): pass else: os.environ["XPRA_SERVER_LOG"] = log_filename1 if odisplay_name != display_name: #this may be used by scripts, let's try not to change it: noerr(stderr.write, "Actual display used: %s\n" % display_name) noerr(stderr.write, "Actual log file name is now: %s\n" % log_filename1) noerr(stderr.flush) noerr(stdout.close) noerr(stderr.close) #we should not be using stdout or stderr from this point: del stdout del stderr if not check_xvfb(): noerr(stderr.write, "vfb failed to start, exiting\n") return EXIT_VFB_ERROR #create devices for vfb if needed: devices = {} if not start_vfb and not proxying and not shadowing and envbool( "XPRA_UINPUT", True): #try to find the existing uinput uuid: #use a subprocess to avoid polluting our current process #with X11 connections before we get a chance to change uid prop = "_XPRA_UINPUT_ID" cmd = ["xprop", "-display", display_name, "-root", prop] log("looking for '%s' on display '%s' with XAUTHORITY='%s'", prop, display_name, os.environ.get("XAUTHORITY")) try: code, out, err = get_status_output(cmd) except Exception as e: log("failed to get existing uinput id: %s", e) del e else: log("Popen(%s)=%s", cmd, (code, out, err)) if code == 0 and out.find("=") > 0: uinput_uuid = out.split("=", 1)[1] log("raw uinput uuid=%s", uinput_uuid) uinput_uuid = strtobytes(uinput_uuid.strip('\n\r"\\ ')) if uinput_uuid: if len(uinput_uuid) > UINPUT_UUID_MAX_LEN or len( uinput_uuid) < UINPUT_UUID_MIN_LEN: log.warn("Warning: ignoring invalid uinput id:") log.warn(" '%s'", uinput_uuid) uinput_uuid = None else: log.info("retrieved existing uinput id: %s", bytestostr(uinput_uuid)) if uinput_uuid: devices = create_input_devices(uinput_uuid, uid) if ROOT and (uid != 0 or gid != 0): log("root: switching to uid=%i, gid=%i", uid, gid) setuidgid(uid, gid) os.environ.update({ "HOME": home, "USER": username, "LOGNAME": username, }) shell = get_shell_for_uid(uid) if shell: os.environ["SHELL"] = shell #now we've changed uid, it is safe to honour all the env updates: configure_env(opts.env) os.environ.update(protected_env) if opts.chdir: log("chdir(%s)", opts.chdir) os.chdir(opts.chdir) dbus_pid, dbus_env = 0, {} if not shadowing and POSIX and not OSX and not clobber: no_gtk() assert starting or starting_desktop or proxying try: from xpra.server.dbus.dbus_start import start_dbus except ImportError as e: log("dbus components are not installed: %s", e) else: dbus_pid, dbus_env = start_dbus(opts.dbus_launch) if dbus_env: os.environ.update(dbus_env) if not proxying: if POSIX and not OSX: no_gtk() if starting or starting_desktop or shadowing: r = verify_display(xvfb, display_name, shadowing) if r: return r #on win32, this ensures that we get the correct screen size to shadow: from xpra.platform.gui import init as gui_init log("gui_init()") gui_init() progress(50, "creating local sockets") #setup unix domain socket: netlog = get_network_logger() local_sockets = setup_local_sockets(opts.bind, opts.socket_dir, opts.socket_dirs, display_name, clobber, opts.mmap_group, opts.socket_permissions, username, uid, gid) netlog("setting up local sockets: %s", local_sockets) sockets.update(local_sockets) if POSIX and (starting or upgrading or starting_desktop or upgrading_desktop): #all unix domain sockets: ud_paths = [ sockpath for stype, _, sockpath, _ in local_sockets if stype == "unix-domain" ] if ud_paths: #choose one so our xdg-open override script can use to talk back to us: if opts.forward_xdg_open: for x in ("/usr/libexec/xpra", "/usr/lib/xpra"): xdg_override = os.path.join(x, "xdg-open") if os.path.exists(xdg_override): os.environ["PATH"] = x + os.pathsep + os.environ.get( "PATH", "") os.environ["XPRA_SERVER_SOCKET"] = ud_paths[0] break else: log.warn("Warning: no local server sockets,") if opts.forward_xdg_open: log.warn(" forward-xdg-open cannot be enabled") log.warn(" non-embedded ssh connections will not be available") set_server_features(opts) if not proxying and POSIX and not OSX: if not check_xvfb(): return 1 from xpra.x11.gtk_x11.gdk_display_source import init_gdk_display_source if os.environ.get("NO_AT_BRIDGE") is None: os.environ["NO_AT_BRIDGE"] = "1" init_gdk_display_source() #(now we can access the X11 server) if uinput_uuid: save_uinput_id(uinput_uuid) progress(60, "initializing server") if shadowing: app = make_shadow_server() elif proxying: app = make_proxy_server() else: if starting or upgrading: app = make_server(clobber) else: assert starting_desktop or upgrading_desktop app = make_desktop_server(clobber) app.init_virtual_devices(devices) try: app.exec_cwd = opts.chdir or cwd app.display_name = display_name app.init(opts) progress(70, "initializing sockets") app.init_sockets(sockets) app.init_dbus(dbus_pid, dbus_env) if not shadowing and not proxying: app.init_display_pid(xvfb_pid) app.original_desktop_display = desktop_display del opts if not app.server_ready(): return 1 progress(80, "finalizing") app.server_init() app.setup() app.init_when_ready(_when_ready) except InitException as e: log.error("xpra server initialization error:") log.error(" %s", e) app.cleanup() return 1 except Exception as e: log.error("Error: cannot start the %s server", app.session_type, exc_info=True) log.error(str(e)) log.info("") if upgrading or upgrading_desktop: #something abnormal occurred, #don't kill the vfb on exit: from xpra.server import EXITING_CODE app._upgrading = EXITING_CODE app.cleanup() return 1 try: progress(100, "running") log("running %s", app.run) r = app.run() log("%s()=%s", app.run, r) except KeyboardInterrupt: log.info("stopping on KeyboardInterrupt") app.cleanup() return EXIT_OK except Exception: log.error("server error", exc_info=True) app.cleanup() return -128 else: if r > 0: r = 0 return r