Ticket #1631: uinput-upgrades.patch
File uinput-upgrades.patch, 15.8 KB (added by , 3 years ago) |
---|
-
xpra/os_util.py
182 182 return rel(sys_platform) 183 183 184 184 185 def get_rand_chars(l=16, chars=b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"): 186 import random 187 return b"".join(chars[random.randint(0, len(chars)-1)] for _ in range(l)) 188 185 189 def get_hex_uuid(): 186 190 return uuid.uuid4().hex 187 191 -
xpra/scripts/server.py
91 91 def get_dbus_pid(): 92 92 return _get_int("_XPRA_DBUS_PID") 93 93 94 def save_uinput_id(uuid): 95 _save_str("_XPRA_UINPUT_ID", uuid) 96 97 #def get_uinput_id(): 98 # return _get_str("_XPRA_UINPUT_ID") 99 94 100 def get_dbus_env(): 95 101 env = {} 96 102 for n,load in ( … … 157 163 except: 158 164 pass 159 165 166 def close_gtk_display(): 167 # Close our display(s) first, so the server dying won't kill us. 168 # (if gtk has been loaded) 169 gtk_mod = sys.modules.get("gtk") 170 if gtk_mod: 171 for d in gtk_mod.gdk.display_manager_get().list_displays(): 172 d.close() 160 173 174 def kill_xvfb(xvfb_pid): 175 if xvfb_pid: 176 from xpra.log import Logger 177 log = Logger("server") 178 log.info("killing xvfb with pid %s", xvfb_pid) 179 try: 180 os.kill(xvfb_pid, signal.SIGTERM) 181 except OSError as e: 182 log.info("failed to kill xvfb process with pid %s:", xvfb_pid) 183 log.info(" %s", e) 184 185 161 186 def print_DE_warnings(desktop_display, pulseaudio, notifications, dbus_launch): 162 187 de = os.environ.get("XDG_SESSION_DESKTOP") or os.environ.get("SESSION_DESKTOP") 163 188 if not de: … … 348 373 349 374 350 375 def run_server(error_cb, opts, mode, xpra_file, extra_args, desktop_display=None): 376 from xpra.os_util import strtobytes 351 377 try: 352 378 cwd = os.getcwd() 353 379 except: … … 675 701 os.environ.update(protected_env) 676 702 log("env=%s", os.environ) 677 703 678 #create devices for vfb if needed:679 devices = {}680 if start_vfb and opts.input_devices.lower()=="uinput":681 devices = create_input_devices(uid)682 683 704 # Start the Xvfb server first to get the display_name if needed 684 705 odisplay_name = display_name 685 706 xvfb = None 686 707 xvfb_pid = None 708 uinput_uuid = None 687 709 if start_vfb: 688 710 assert not proxying and xauth_data 689 711 pixel_depth = validate_pixel_depth(opts.pixel_depth) 690 712 from xpra.x11.vfb_util import start_Xvfb 691 xvfb, display_name, cleanups = start_Xvfb(opts.xvfb, pixel_depth, display_name, cwd, uid, gid, username, xauth_data, devices) 713 from xpra.server.server_util import has_uinput 714 uinput_uuid = None 715 if has_uinput() and opts.input_devices.lower() in ("uinput", "auto") and not shadowing: 716 from xpra.os_util import get_rand_chars 717 uinput_uuid = get_rand_chars(8) 718 xvfb, display_name, cleanups = start_Xvfb(opts.xvfb, pixel_depth, display_name, cwd, uid, gid, username, xauth_data, uinput_uuid) 692 719 for f in cleanups: 693 720 add_cleanup(f) 694 721 xvfb_pid = xvfb.pid … … 698 725 os.environ.update(protected_env) 699 726 if display_name!=odisplay_name and pam: 700 727 pam.set_items({"XDISPLAY" : display_name}) 728 701 729 if POSIX and not OSX and displayfd>0: 702 730 from xpra.platform.displayfd import write_displayfd 703 731 try: … … 713 741 except: 714 742 pass 715 743 716 close_display = None717 744 if not proxying: 718 745 def close_display(): 719 # Close our display(s) first, so the server dying won't kill us. 720 # (if gtk has been loaded) 721 gtk_mod = sys.modules.get("gtk") 722 if gtk_mod: 723 for d in gtk_mod.gdk.display_manager_get().list_displays(): 724 d.close() 725 if xvfb_pid: 726 log.info("killing xvfb with pid %s", xvfb_pid) 727 try: 728 os.kill(xvfb_pid, signal.SIGTERM) 729 except OSError as e: 730 log.info("failed to kill xvfb process with pid %s:", xvfb_pid) 731 log.info(" %s", e) 746 close_gtk_display() 747 kill_xvfb(xvfb_pid) 732 748 add_cleanup(close_display) 749 else: 750 close_display = None 733 751 734 752 if opts.daemon: 735 753 def noerr(fn, *args): … … 758 776 #xvfb problem: exit now 759 777 return 1 760 778 779 #create devices for vfb if needed: 780 devices = {} 781 if not start_vfb and not proxying and not shadowing: 782 #try to find the existing uinput uuid: 783 #use a subprocess to avoid polluting our current process 784 #with X11 connections before we get a chance to change uid 785 from xpra.os_util import get_status_output 786 cmd = ["xprop", "-display", display_name, "-root", "_XPRA_UINPUT_ID"] 787 try: 788 code, out, err = get_status_output(cmd) 789 except Exception as e: 790 log("failed to get existing uinput id: %s", e) 791 else: 792 log("Popen(%s)=%s", cmd, (code, out, err)) 793 if code==0 and out.find("=")>0: 794 uinput_uuid = strtobytes(out.split("=", 1)[1]) 795 if uinput_uuid: 796 devices = create_input_devices(uinput_uuid, uid) 797 761 798 if ROOT and (uid!=0 or gid!=0): 762 799 log("root: switching to uid=%i, gid=%i", uid, gid) 763 800 setuidgid(uid, gid) … … 784 821 from xpra.x11.vfb_util import verify_display_ready 785 822 if not verify_display_ready(xvfb, display_name, shadowing): 786 823 return 1 787 from xpra.x11.gtk2.gdk_display_util import verify_gdk_display 824 from xpra.x11.gtk2.gdk_display_util import verify_gdk_display #@Reimport 788 825 display = verify_gdk_display(display_name) 789 826 if not display: 790 827 return 1 … … 833 870 save_xvfb_pid(xvfb_pid) 834 871 835 872 if POSIX: 873 save_uinput_id(uinput_uuid or "") 836 874 dbus_pid = -1 837 875 dbus_env = {} 838 876 if clobber: … … 904 942 905 943 #publish mdns records: 906 944 if opts.mdns: 907 from xpra.os_util import strtobytes908 945 from xpra.platform.info import get_username 909 946 from xpra.server.socket_util import mdns_publish 910 947 mdns_info = { -
xpra/server/server_util.py
295 295 log.error(" %", e) 296 296 return None 297 297 298 def create_uinput_pointer_device(uid, gid):298 def has_uinput(): 299 299 from xpra.log import Logger 300 300 log = Logger("server") 301 301 try: 302 302 import uinput 303 assert uinput 303 304 except (ImportError, NameError) as e: 304 log.error("Error: cannot create uinput devices:") 305 log.info("cannot access python uinput module:") 306 log.info(" %s", e) 307 return False 308 else: 309 return True 310 311 def create_uinput_pointer_device(uuid, uid, gid): 312 from xpra.log import Logger 313 log = Logger("server") 314 try: 315 import uinput 316 except (ImportError, NameError) as e: 317 log.error("Error: cannot access python uinput module:") 305 318 log.error(" %s", e) 306 319 return None 307 320 events = ( … … 320 333 ) 321 334 BUS_USB = 0x03 322 335 #BUS_VIRTUAL = 0x06 336 VENDOR = 0xffff 337 PRODUCT = 0xffff 338 VERSION = 0 339 #name = "Xpra Virtual Pointer %s" % uuid 323 340 name = "Xpra Virtual Pointer" 324 341 try: 325 uinput_pointer = uinput.Device(events, name=name, bustype=BUS_USB, vendor= 0, product=0, version=0)342 uinput_pointer = uinput.Device(events, name=name, bustype=BUS_USB, vendor=VENDOR, product=PRODUCT, version=VERSION) 326 343 except OSError as e: 327 log.error("Error: cannot open uinput,") 328 log.error(" make sure that the kernel module is loaded") 329 log.error(" and that the /dev/uinput device exists:") 330 log.error(" %s", e) 344 log("uinput.Device creation failed", exc_info=True) 345 if os.getuid()==0: 346 #running as root, this should work! 347 log.error("Error: cannot open uinput,") 348 log.error(" make sure that the kernel module is loaded") 349 log.error(" and that the /dev/uinput device exists:") 350 log.error(" %s", e) 351 else: 352 log.info("cannot access uinput: %s", e) 331 353 return None 332 354 dev_path = get_uinput_device_path(uinput_pointer) 333 355 if not dev_path: 334 356 uinput_pointer.destroy() 335 357 return None 336 try: 337 #log("chown%s", (dev_path, uid, gid)) 338 os.lchown(dev_path, uid, gid) 339 #udev rules change the device ownership 340 #FIXME: fix udev or use inotify? (racy) 341 import time 342 time.sleep(1) 343 log("chown%s", (dev_path, uid, gid)) 344 os.lchown(dev_path, uid, gid) 345 #os.lchown("/dev/input/mouse2", uid, gid) 346 except OSError as e: 347 log.error("Error: failed to change ownership of '%s':", name) 348 log.error(" at %s:", dev_path) 349 log.error(" %s", e) 350 return None 358 if False: 359 try: 360 #log("chown%s", (dev_path, uid, gid)) 361 os.lchown(dev_path, uid, gid) 362 #udev rules change the device ownership 363 #FIXME: fix udev or use inotify? (racy) 364 import time 365 time.sleep(1) 366 log("chown%s", (dev_path, uid, gid)) 367 os.lchown(dev_path, uid, gid) 368 #os.lchown("/dev/input/mouse2", uid, gid) 369 except OSError as e: 370 log.error("Error: failed to change ownership of '%s':", name) 371 log.error(" at %s:", dev_path) 372 log.error(" %s", e) 373 return None 351 374 return name, uinput_pointer, dev_path 352 375 353 def create_uinput_devices(ui d, gid):354 d = create_uinput_pointer_device(ui d, gid)376 def create_uinput_devices(uinput_uuid, uid, gid): 377 d = create_uinput_pointer_device(uinput_uuid, uid, gid) 355 378 if not d: 356 379 return {} 357 380 name, uinput_pointer, dev_path = d … … 363 386 } 364 387 } 365 388 366 def create_input_devices(ui d, gid=-1):367 return create_uinput_devices(ui d, gid)389 def create_input_devices(uinput_uuid, uid, gid=-1): 390 return create_uinput_devices(uinput_uuid, uid, gid) -
xpra/x11/vfb_util.py
23 23 assert len(DEFAULT_DESKTOP_VFB_RESOLUTION)==2 24 24 25 25 26 XORG_DEVICE_OPTIONS = { 27 "pointer" : """ 28 MatchIsPointer "True" 29 Driver "libinput" 30 Option "AccelProfile" "flat" 31 """, 32 "keyboard" : 'MatchIsKeyboard "True"', 33 } 34 35 36 def create_xorg_device_configs(xorg_conf_dir, devices, uid, gid): 26 def create_xorg_device_configs(xorg_conf_dir, device_uuid, uid, gid): 37 27 from xpra.log import Logger 38 28 log = Logger("server", "x11") 39 29 cleanups = [] 40 if not device s:30 if not device_uuid: 41 31 return cleanups 42 32 43 33 def makedir(dirname): … … 62 52 for d in dirs: 63 53 makedir(d) 64 54 65 #create individual device files: 55 #create individual device files, 56 #only pointer for now: 66 57 i = 0 67 for dev_type, devdef in devices.items(): 68 #ie: 69 #name = "pointer" 70 #devdef = {"uinput" : uninput.Device, "device" : "/dev/input20" } 71 match_type = XORG_DEVICE_OPTIONS.get(dev_type) 72 uinput = devdef.get("uinput") 73 device = devdef.get("device") 74 name = devdef.get("name") 75 if match_type and uinput and device and name: 76 conf_file = os.path.join(xorg_conf_dir, "%02i-%s.conf" % (i, dev_type)) 77 with open(conf_file, "wb") as f: 78 f.write(""" 79 Section "InputClass" 58 dev_type = "pointer" 59 #name = "Xpra Virtual Pointer %s" % device_uuid 60 name = "Xpra Virtual Pointer" 61 conf_file = os.path.join(xorg_conf_dir, "%02i-%s.conf" % (i, dev_type)) 62 with open(conf_file, "wb") as f: 63 f.write(b"""Section "InputClass" 80 64 Identifier "xpra-virtual-%s" 81 65 MatchProduct "%s" 82 MatchDevicePath "%s" 66 MatchUSBID "ffff:ffff" 67 MatchIsPointer "True" 68 Driver "libinput" 69 Option "AccelProfile" "flat" 83 70 Option "Ignore" "False" 84 %s85 71 EndSection 86 """ % (dev_type, name , device, match_type))87 88 89 90 91 92 93 94 72 """ % (dev_type, name)) 73 os.fchown(f.fileno(), uid, gid) 74 #Option "AccelerationProfile" "-1" 75 #Option "AccelerationScheme" "none" 76 #Option "AccelSpeed" "-1" 77 def cleanup_conf_file(): 78 log("cleanup_conf_file: %s", conf_file) 79 os.unlink(conf_file) 80 cleanups.insert(0, cleanup_conf_file) 95 81 return cleanups 96 82 97 98 def start_Xvfb(xvfb_str, pixel_depth, display_name, cwd, uid, gid, username, xauth_data, devices={}): 83 def start_Xvfb(xvfb_str, pixel_depth, display_name, cwd, uid, gid, username, xauth_data, uinput_uuid=None): 99 84 if not POSIX: 100 85 raise InitException("starting an Xvfb is not supported on %s" % os.name) 101 86 if not xvfb_str: … … 134 119 def pathexpand(s): 135 120 return shellsub(s, subs) 136 121 137 #create uinput device definition files:138 #(we are assuming that Xorg is configured to use this path..)139 xorg_conf_dir = pathexpand(get_Xdummy_confdir())140 cleanups = create_xorg_device_configs(xorg_conf_dir, devices, uid, gid)141 142 122 #identify logfile argument if it exists, 143 123 #as we may have to rename it, or create the directory for it: 144 124 import shlex … … 172 152 if not xvfb_cmd: 173 153 raise InitException("cannot start Xvfb, the command definition is missing!") 174 154 175 if devices: 155 if uinput_uuid: 156 #use uinput: 176 157 #identify -config xorg.conf argument and replace it with the uinput one: 177 158 try: 178 159 config_argindex = xvfb_cmd.index("-config") … … 184 165 xorg_conf = xorg_conf.replace("xorg.conf", "xorg-uinput.conf") 185 166 if os.path.exists(xorg_conf): 186 167 xvfb_cmd[config_argindex+1] = xorg_conf 168 #create uinput device definition files: 169 #(we have to assume that Xorg is configured to use this path..) 170 xorg_conf_dir = pathexpand(get_Xdummy_confdir()) 171 cleanups = create_xorg_device_configs(xorg_conf_dir, uinput_uuid, uid, gid) 187 172 188 173 xvfb_executable = xvfb_cmd[0] 189 174 if (xvfb_executable.endswith("Xorg") or xvfb_executable.endswith("Xdummy")) and pixel_depth>0: -
xpra/x11/x11_server_base.py
178 178 X11ServerCore.last_client_exited(self) 179 179 180 180 def init_virtual_devices(self, devices): 181 #(this runs in the main thread - before the main loop starts) 181 182 #for the time being, we only use the pointer if there is one: 182 183 pointer = devices.get("pointer") 183 184 if pointer: -
udev/rules.d/71-xpra-virtual-pointer.rules
1 1 # allow xpra to use fine grained scrolling 2 2 3 ACTION=="add|change", ATTRS{name}=="Xpra Virtual Pointer", ENV{MOUSE_WHEEL_CLICK_ANGLE}="1", ENV{MOUSE_WHEEL_CLICK_COUNT}="360" 3 ACTION=="add|change", ATTRS{name}=="Xpra Virtual Pointer", ENV{MOUSE_WHEEL_CLICK_ANGLE}="1", ENV{MOUSE_WHEEL_CLICK_COUNT}="360", MODE="0666"