Hello community, here is the log from the commit of package xpra for openSUSE:Factory checked in at 2020-03-16 10:17:40 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/xpra (Old) and /work/SRC/openSUSE:Factory/.xpra.new.3160 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "xpra" Mon Mar 16 10:17:40 2020 rev:16 rq:784854 version:3.0.7 Changes: -------- --- /work/SRC/openSUSE:Factory/xpra/xpra.changes 2020-02-10 21:54:43.898234379 +0100 +++ /work/SRC/openSUSE:Factory/.xpra.new.3160/xpra.changes 2020-03-16 10:18:13.447584445 +0100 @@ -1,0 +2,51 @@ +Sat Mar 14 07:50:10 UTC 2020 - [email protected] + +- Update to version 3.0.7 + * fix avcodec2 race condition crash + * fix errors when re-initializing windows (ie: toggling OpenGL + on or off) + * fix deiconification error when there are system trays + forwarded + * fix missing alpha channel when some windows are first shown + * fix systemd-run errors: verify it does work before trying to + use it + * fix server crashes on SIGINT: shutdown cleanly + * fix proxy server client connection setup error hanlder + * fix file authentication handler using a default password + filename + * fix directshow errors on local mingw installations + * fix opengl properties missing from server hello packet + * fix HTML5 sound-control errors when speaker forwarding is + disabled + * fix HTML5 "Terminate" options wrongly enabled in "Connect" + mode + * fix clipboard sharing with the MacOS shadow server + * fix MS Windows clipboard access denied errors + * fix X11 clipboard error handling: continue processing + * fix unit tests failures (clipboard, etc) + * fix bug report clipboard copy and screnshots + * fix clipboard timeouts when a client disconnects + * fix mdns cleanup done twice on server exit, causing errors + * fix malformed XSettings due to invalid color data format + * fix HMAC hashes exposed, keep only valid options + * fix 'showconfig' output for boolean values set to 'auto' + * fix parsing of client display information in legacy format + * fix validation of size-hints + * fix cursor saving debug code with GTK3 + * fix keyboard layout group not getting reset on client exit + * fix some empty keyboard layout group strings parsed as + non-empty + * fix keyboard-sync mode not being honoured by servers + * fix keyboard raw mode + * fix missing 'perispomeni' key mapping with Python 2 servers + * add missing debug logging to keyboard mapping + * more reliable lookup of keycodes when translating (non-X11 + clients) + * skip bundling some external test modules with binary + installers + * avoid spurious background worker warnings on exit + * make unavoidable comtypes error less scary + * add 'libreoffice' to the text mode whitelist + * packaging workarounds for setuptools breakage + +------------------------------------------------------------------- Old: ---- xpra-3.0.6.tar.xz New: ---- xpra-3.0.7.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ xpra.spec ++++++ --- /var/tmp/diff_new_pack.OzzrMA/_old 2020-03-16 10:18:14.039584686 +0100 +++ /var/tmp/diff_new_pack.OzzrMA/_new 2020-03-16 10:18:14.039584686 +0100 @@ -19,7 +19,7 @@ %global __requires_exclude ^typelib\\(GtkosxApplication\\)|typelib\\(GdkGLExt\\)|typelib\\(GtkGLExt\\).*$ Name: xpra -Version: 3.0.6 +Version: 3.0.7 Release: 0 Summary: Remote display server for applications and desktops License: GPL-2.0-or-later AND BSD-3-Clause AND LGPL-3.0-or-later AND MIT @@ -40,6 +40,7 @@ BuildRequires: python3-Cython >= 0.20.0 BuildRequires: python3-devel BuildRequires: python3-gobject-devel +BuildRequires: python3-setuptools BuildRequires: update-desktop-files BuildRequires: pkgconfig(gtk+-3.0) BuildRequires: pkgconfig(libavcodec) >= 58 ++++++ xpra-3.0.6.tar.xz -> xpra-3.0.7.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/NEWS new/xpra-3.0.7/NEWS --- old/xpra-3.0.6/NEWS 2020-02-07 12:19:08.000000000 +0100 +++ new/xpra-3.0.7/NEWS 2020-03-13 17:51:18.000000000 +0100 @@ -1,3 +1,52 @@ +v3.0.7 (2020-03-02) +====================== + -- fix avcodec2 race condition crash + -- fix errors when re-initializing windows (ie: toggling OpenGL on or off) + -- fix deiconification error when there are system trays forwarded + -- fix missing alpha channel when some windows are first shown + -- fix systemd-run errors: verify it does work before trying to use it + -- fix debug builds compilation error on MS Windows + -- fix server crashes on SIGINT: shutdown cleanly + -- fix proxy server client connection setup error hanlder + -- fix file authentication handler using a default password filename + -- fix directshow errors on local mingw installations + -- fix opengl properties missing from server hello packet + -- fix HTML5 sound-control errors when speaker forwarding is disabled + -- fix HTML5 "Terminate" options wrongly enabled in "Connect" mode + -- fix clipboard sharing with the MacOS shadow server + -- fix MS Windows clipboard access denied errors + -- fix X11 clipboard error handling: continue processing + -- fix unit tests failures (clipboard, etc) + -- fix bug report clipboard copy and screnshots + -- fix clipboard timeouts when a client disconnects + -- fix mdns cleanup done twice on server exit, causing errors + -- fix malformed XSettings due to invalid color data format + -- fix FreeBSD builds + -- fix MS Windows packaging missing a codec DLL, Plink DLL + -- fix HMAC hashes exposed, keep only valid options + -- fix 'showconfig' output for boolean values set to 'auto' + -- fix parsing of client display information in legacy format + -- fix validation of size-hints + -- fix cursor saving debug code with GTK3 + -- fix keyboard layout group not getting reset on client exit + -- fix some empty keyboard layout group strings parsed as non-empty + -- fix keyboard-sync mode not being honoured by servers + -- fix keyboard raw mode + -- fix missing 'perispomeni' key mapping with Python 2 servers + -- add missing debug logging to keyboard mapping + -- more reliable lookup of keycodes when translating (non-X11 clients) + -- add missing dependency for printer forwarding on Debian + -- packaging for Ubuntu Focal Fossa + -- skip bundling some external test modules with binary installers + -- more correct code for locating the 'Downloads' folder on MS Windows + -- avoid spurious background worker warnings on exit + -- make unavoidable comtypes error less scary + -- add 'libreoffice' to the text mode whitelist + -- library updates: Python 3.8.2, etc + -- packaging workarounds for setuptools breakage + + + v3.0.6 (2020-02-05) ====================== -- fix UDP with Python3 @@ -21,13 +70,17 @@ -- fix MS Windows packaging workarounds for TK -- fix for crashes on X11 displays lacking RandR support -- fix handling of non 24/32-bit png window icons + -- fix 'User' not honoured in ssh_config + -- fix X11 server initiate move-resize -- man page connection string fixes -- disable cpuinfo module - known to cause problems on various platforms -- ignore error and continue when loading version information from invalid builds + -- prettier format for new connection information -- remove executable file permissions on files uploaded to the server -- blacklist 'Intel(R) UHD Graphics 620' -- use correct location for appdata.xml -- use Debian location for systemd service config file + -- Debian packaging: prefer python3 installations -- ensure emacs, gvim and xxdiff always use 'text' mode -- re-enable pulseaudio memfd (was wrongly disabled in v3.0.0) -- remove remnants of GTK2 dependencies from non-GTK2 components diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/content-type/50_class.conf new/xpra-3.0.7/content-type/50_class.conf --- old/xpra-3.0.6/content-type/50_class.conf 2020-01-25 11:03:50.000000000 +0100 +++ new/xpra-3.0.7/content-type/50_class.conf 2020-03-08 03:21:09.000000000 +0100 @@ -12,6 +12,7 @@ class-instance:emacs=text class-instance:gvim=text +class-instance:libreoffice=text class-instance:vlc=video class-instance:VirtualBox Machine=picture diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/cups/xpraforwarder new/xpra-3.0.7/cups/xpraforwarder --- old/xpra-3.0.6/cups/xpraforwarder 2020-01-20 20:48:07.000000000 +0100 +++ new/xpra-3.0.7/cups/xpraforwarder 2020-02-18 06:58:41.000000000 +0100 @@ -42,7 +42,7 @@ from urllib.parse import urlparse, parse_qs -__version__ = "3.0.6" +__version__ = "3.0.7" #Writes a syslog entry (msg) at the default facility: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/html5/connect.html new/xpra-3.0.7/html5/connect.html --- old/xpra-3.0.6/html5/connect.html 2019-11-18 16:50:49.000000000 +0100 +++ new/xpra-3.0.7/html5/connect.html 2020-03-13 17:51:18.000000000 +0100 @@ -417,7 +417,6 @@ var action = $(this).val(); set_exit_actions(action=="connect"); }); - set_exit_actions(action=="connect" || action=="") $('input:radio[value="'+action+'"]').click(); var encoding = getparam("encoding") || "auto"; @@ -544,6 +543,9 @@ floating_menu_checkbox.change(set_menu_attributes_visibility); set_menu_attributes_visibility(); + //this may override default values (ie: terminate flags are off for connect mode): + set_exit_actions(action=="connect" || action=="") + $("#expandopts").click(function() { $("#hiddenopts").slideToggle(); }); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/html5/index.html new/xpra-3.0.7/html5/index.html --- old/xpra-3.0.6/html5/index.html 2020-02-07 12:19:08.000000000 +0100 +++ new/xpra-3.0.7/html5/index.html 2020-03-13 17:51:18.000000000 +0100 @@ -986,18 +986,23 @@ $("#sound_button").attr("data-icon", data_icon); $("#sound_button").attr("title", tooltip); }; - $("#sound_button").click(function() { - clog("speaker icon clicked"); - if (client.audio_state=="playing" || client.audio_state=="waiting") { - client.on_audio_state_change("stopped", "user action"); - client.close_audio(); - } - else { - client.on_audio_state_change("waiting", "user action"); - client._audio_start_stream(); - client._sound_start_receiving(); - } - }) + if (client.audio_enabled) { + $("#sound_button").click(function() { + clog("speaker icon clicked, audio_enabled=", client.audio_enabled); + if (client.audio_state=="playing" || client.audio_state=="waiting") { + client.on_audio_state_change("stopped", "user action"); + client.close_audio(); + } + else { + client.on_audio_state_change("waiting", "user action"); + client._audio_start_stream(); + client._sound_start_receiving(); + } + }) + } + else { + $("#sound_button").hide(); + } document.addEventListener("visibilitychange", function (e) { window_ids = Object.keys(client.id_to_window).map(Number); clog("visibilitychange hidden=", document.hidden, "connected=", client.connected); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/html5/js/Utilities.js new/xpra-3.0.7/html5/js/Utilities.js --- old/xpra-3.0.6/html5/js/Utilities.js 2020-01-20 20:48:07.000000000 +0100 +++ new/xpra-3.0.7/html5/js/Utilities.js 2020-02-18 06:58:41.000000000 +0100 @@ -10,7 +10,7 @@ 'use strict'; var Utilities = { - VERSION : "3.0.6", + VERSION : "3.0.7", exc : function() { console.error.apply(console, arguments); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/setup.py new/xpra-3.0.7/setup.py --- old/xpra-3.0.6/setup.py 2020-02-07 12:19:08.000000000 +0100 +++ new/xpra-3.0.7/setup.py 2020-03-13 17:51:18.000000000 +0100 @@ -165,7 +165,7 @@ minify_ENABLED = html5_ENABLED pam_ENABLED = DEFAULT and (server_ENABLED or proxy_ENABLED) and POSIX and not OSX and (os.path.exists("/usr/include/pam/pam_misc.h") or os.path.exists("/usr/include/security/pam_misc.h")) -xdg_open_ENABLED = LINUX and DEFAULT +xdg_open_ENABLED = (LINUX or FREEBSD) and DEFAULT netdev_ENABLED = LINUX and DEFAULT vsock_ENABLED = LINUX and os.path.exists("/usr/include/linux/vm_sockets.h") bencode_ENABLED = DEFAULT @@ -373,7 +373,9 @@ "curses", "pdb", "tty", "setuptools", "doctest" - "_pytest", "pluggy", "more_itertools", "apipkg", "py", "funcsigs", + "nose", "pytest", "_pytest", "pluggy", "more_itertools", "apipkg", "py", "funcsigs", + "Cython", "cython", "pyximport", + "pydoc_data", ] if not PYTHON3: external_excludes.append("cpuinfo") @@ -704,7 +706,7 @@ if debug_ENABLED: add_to_keywords(kw, 'extra_compile_args', '-g') add_to_keywords(kw, 'extra_compile_args', '-ggdb') - if get_gcc_version()>=[4, 8]: + if get_gcc_version()>=[4, 8] and not WIN32: add_to_keywords(kw, 'extra_compile_args', '-fsanitize=address') add_to_keywords(kw, 'extra_link_args', '-fsanitize=address') if rpath and kw.get("libraries"): @@ -1219,6 +1221,10 @@ #svg pixbuf loader: add_DLLs("rsvg", "croco") + if dec_avcodec2_ENABLED: + #why isn't this one picked up automatically? + add_DLLs("x265") + if sound_ENABLED: add_dir("share", ["gst-plugins-bad", "gst-plugins-base", "gstreamer-1.0"]) add_gi("Gst-1.0", "GstAllocators-1.0", "GstAudio-1.0", "GstBase-1.0", @@ -1481,14 +1487,14 @@ #******************************************************************************* else: #OSX and *nix: + if is_Fedora() or is_CentOS() or is_RedHat() or FREEBSD: + libexec = "libexec" + else: + libexec = "lib" if LINUX: if scripts_ENABLED: scripts += ["scripts/xpra_udev_product_version", "scripts/xpra_signal_listener"] libexec_scripts = [] - if is_Fedora() or is_CentOS() or is_RedHat(): - libexec = "libexec" - else: - libexec = "lib" if xdg_open_ENABLED: libexec_scripts += ["scripts/xdg-open", "scripts/gnome-open", "scripts/gvfs-open"] if server_ENABLED: @@ -1497,7 +1503,7 @@ add_data_files("%s/xpra/" % libexec, libexec_scripts) if data_ENABLED: man_path = "share/man" - if OPENBSD: + if OPENBSD or FREEBSD: man_path = "man" add_data_files("%s/man1" % man_path, ["man/xpra.1", "man/xpra_launcher.1"]) add_data_files("share/applications", glob.glob("xdg/*.desktop")) @@ -1551,7 +1557,10 @@ if printing_ENABLED and POSIX: #install "/usr/lib/cups/backend" with 0700 permissions: - copytodir("cups/xpraforwarder", "lib/cups/backend", chmod=0o700) + lib_cups = "lib/cups" + if FREEBSD: + lib_cups = "libexec/cups" + copytodir("cups/xpraforwarder", "%s/backend" % lib_cups, chmod=0o700) if x11_ENABLED: #install xpra_Xdummy if we need it: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/svn-info new/xpra-3.0.7/svn-info --- old/xpra-3.0.6/svn-info 2020-02-07 12:24:52.000000000 +0100 +++ new/xpra-3.0.7/svn-info 2020-03-13 18:03:50.000000000 +0100 @@ -4,10 +4,10 @@ Relative URL: ^/tags/v3.0.x/src Repository Root: file:///var/svn/repos/Xpra Repository UUID: 3bb7dfac-3a0b-4e04-842a-767bc560f471 -Revision: 25177 +Revision: 25629 Node Kind: directory Schedule: normal Last Changed Author: antoine -Last Changed Rev: 25156 -Last Changed Date: 2020-02-05 12:06:46 +0000 (Wed, 05 Feb 2020) +Last Changed Rev: 25627 +Last Changed Date: 2020-03-12 15:57:01 +0000 (Thu, 12 Mar 2020) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/svn-version new/xpra-3.0.7/svn-version --- old/xpra-3.0.6/svn-version 2020-02-07 12:24:52.000000000 +0100 +++ new/xpra-3.0.7/svn-version 2020-03-13 18:03:50.000000000 +0100 @@ -1 +1 @@ -25177 +25629 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/unittests/unit/client/mixins/webcam_test.py new/xpra-3.0.7/unittests/unit/client/mixins/webcam_test.py --- old/xpra-3.0.6/unittests/unit/client/mixins/webcam_test.py 2019-09-24 15:53:57.000000000 +0200 +++ new/xpra-3.0.7/unittests/unit/client/mixins/webcam_test.py 2020-02-26 16:43:23.000000000 +0100 @@ -22,14 +22,16 @@ "virtual-video-devices" : 1, }) x = self.mixin - if x.webcam_forwarding>0: - self.glib.timeout_add(2500, x.stop_sending_webcam) - self.glib.timeout_add(5000, self.stop) - self.main_loop.run() - assert len(self.packets)>2 - self.verify_packet(0, ("webcam-start", 0, )) - self.verify_packet(1, ("webcam-frame", 0, )) - self.verify_packet(-1, ("webcam-stop", 0, )) + if not x.webcam_device: + print("no webcam device found, test skipped") + return + self.glib.timeout_add(2500, x.stop_sending_webcam) + self.glib.timeout_add(5000, self.stop) + self.main_loop.run() + assert len(self.packets)>2 + self.verify_packet(0, ("webcam-start", 0, )) + self.verify_packet(1, ("webcam-frame", 0, )) + self.verify_packet(-1, ("webcam-stop", 0, )) def main(): unittest.main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/unittests/unit/client/x11_clipboard_test_util.py new/xpra-3.0.7/unittests/unit/client/x11_clipboard_test_util.py --- old/xpra-3.0.6/unittests/unit/client/x11_clipboard_test_util.py 2019-09-24 15:53:57.000000000 +0200 +++ new/xpra-3.0.7/unittests/unit/client/x11_clipboard_test_util.py 2020-03-13 17:51:18.000000000 +0100 @@ -58,6 +58,14 @@ assert pollwait(client, 2) is None, "client has exited with return code %s" % client.poll() client_display = xvfb.display + #wait for client to own the clipboard: + cmd = self.get_xpra_cmd()+["info", server_display] + for _ in range(10): + out = self.get_command_output(cmd) + if out.find(b"clipboard.client=")>0: + break + time.sleep(1) + if SANITY_CHECKS: log("sanity checks") #xclip sanity check: retrieve from the same display: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/unittests/unit/net/protocol_test.py new/xpra-3.0.7/unittests/unit/net/protocol_test.py --- old/xpra-3.0.6/unittests/unit/net/protocol_test.py 2019-09-24 15:53:57.000000000 +0200 +++ new/xpra-3.0.7/unittests/unit/net/protocol_test.py 2020-02-18 06:58:42.000000000 +0100 @@ -152,7 +152,7 @@ p.enable_compressor("lz4") #catch network packets before we write them: data = [] - def raw_write(items, *_args): + def raw_write(_packet_type, items, *_args): for item in items: data.append(item) p.raw_write = raw_write diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/unittests/unit/run.py new/xpra-3.0.7/unittests/unit/run.py --- old/xpra-3.0.6/unittests/unit/run.py 2019-09-24 15:53:57.000000000 +0200 +++ new/xpra-3.0.7/unittests/unit/run.py 2020-02-26 16:43:23.000000000 +0100 @@ -39,8 +39,8 @@ cmd = ["python%s" % sys.version_info[0], p] try: proc = subprocess.Popen(cmd) - except OSError: - write("failed to execute %s" % p) + except OSError as e: + write("failed to execute %s: %s" % (p, e)) return 1 v = proc.wait() if v!=0: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/unittests/unit/server/server_sockets_test.py new/xpra-3.0.7/unittests/unit/server/server_sockets_test.py --- old/xpra-3.0.6/unittests/unit/server/server_sockets_test.py 2019-09-24 15:53:58.000000000 +0200 +++ new/xpra-3.0.7/unittests/unit/server/server_sockets_test.py 2020-02-18 06:58:42.000000000 +0100 @@ -11,7 +11,7 @@ from xpra.util import repr_ellipsized from xpra.os_util import load_binary_file, pollwait, OSX, POSIX -from xpra.exit_codes import EXIT_OK, EXIT_CONNECTION_LOST, EXIT_SSL_FAILURE, EXIT_STR +from xpra.exit_codes import EXIT_OK, EXIT_CONNECTION_LOST, EXIT_CONNECTION_FAILED, EXIT_SSL_FAILURE, EXIT_STR, EXIT_SSL_CERTIFICATE_VERIFY_FAILURE from xpra.net.net_util import get_free_tcp_port from unit.server_test_util import ServerTestUtil, log @@ -27,7 +27,7 @@ def start_server(self, *args): server_proc = self.run_xpra(["start", "--no-daemon"]+list(args)) - if pollwait(server_proc, 5) is not None: + if pollwait(server_proc, 10) is not None: r = server_proc.poll() raise Exception("server failed to start with args=%s, returned %s" % (args, estr(r))) return server_proc @@ -61,6 +61,7 @@ server.terminate() if r!=exit_code: raise Exception("expected info client to return %s but got %s" % (estr(exit_code), estr(r))) + pollwait(server, 10) def test_default_socket(self): self._test_connect([], "allow", [], b"hello", ":", EXIT_OK) @@ -68,6 +69,7 @@ def test_tcp_socket(self): port = get_free_tcp_port() self._test_connect(["--bind-tcp=0.0.0.0:%i" % port], "allow", [], b"hello", "tcp://127.0.0.1:%i/" % port, EXIT_OK) + port = get_free_tcp_port() self._test_connect(["--bind-tcp=0.0.0.0:%i" % port], "allow", [], b"hello", "ws://127.0.0.1:%i/" % port, EXIT_OK) def test_ws_socket(self): @@ -145,10 +147,10 @@ test_connect("wss://127.0.0.1:%i/" % ws_port, EXIT_OK, noverify) #self signed cert should fail without noverify: - test_connect("ssl://127.0.0.1:%i/" % ssl_port, EXIT_SSL_FAILURE) - test_connect("ssl://127.0.0.1:%i/" % tcp_port, EXIT_SSL_FAILURE) - test_connect("wss://127.0.0.1:%i/" % ws_port, EXIT_SSL_FAILURE) - test_connect("wss://127.0.0.1:%i/" % wss_port, EXIT_SSL_FAILURE) + test_connect("ssl://127.0.0.1:%i/" % ssl_port, EXIT_SSL_CERTIFICATE_VERIFY_FAILURE) + test_connect("ssl://127.0.0.1:%i/" % tcp_port, EXIT_SSL_CERTIFICATE_VERIFY_FAILURE) + test_connect("wss://127.0.0.1:%i/" % ws_port, EXIT_SSL_CERTIFICATE_VERIFY_FAILURE) + test_connect("wss://127.0.0.1:%i/" % wss_port, EXIT_SSL_CERTIFICATE_VERIFY_FAILURE) finally: shutil.rmtree(tmpdir) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/win32/MINGW_BUILD.sh new/xpra-3.0.7/win32/MINGW_BUILD.sh --- old/xpra-3.0.6/win32/MINGW_BUILD.sh 2019-12-10 12:20:42.000000000 +0100 +++ new/xpra-3.0.7/win32/MINGW_BUILD.sh 2020-03-13 17:51:18.000000000 +0100 @@ -348,6 +348,9 @@ fi fi cp -fn "${TORTOISESVN}/bin/TortoisePlink.exe" "${DIST}/Plink.exe" + for dll in vcruntime140.dll msvcp140.dll vcruntime140_1.dll; do + cp "/c/Windows/System32/$dll" "${DIST}/" + done #are we meant to include those DLLs? #rsync -rplogt "${TORTOISESVN}/bin/"*dll "${DIST}/" fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/win32/xpra.iss new/xpra-3.0.7/win32/xpra.iss --- old/xpra-3.0.6/win32/xpra.iss 2020-01-20 20:48:07.000000000 +0100 +++ new/xpra-3.0.7/win32/xpra.iss 2020-02-18 06:58:42.000000000 +0100 @@ -1,9 +1,9 @@ [Setup] AppName=Xpra AppId=Xpra_is1 -AppVersion=3.0.6 -AppVerName=Xpra 3.0.6 -UninstallDisplayName=Xpra 3.0.6 +AppVersion=3.0.7 +AppVerName=Xpra 3.0.7 +UninstallDisplayName=Xpra 3.0.7 AppPublisher=xpra.org AppPublisherURL=http:;xpra.org/ DefaultDirName={pf}\Xpra @@ -16,7 +16,7 @@ Compression=lzma2/max SolidCompression=yes AllowUNCPath=false -VersionInfoVersion=3.0.6 +VersionInfoVersion=3.0.7 VersionInfoCompany=xpra.org VersionInfoDescription=multi-platform screen and application forwarding system WizardImageFile=win32\xpra-logo.bmp diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/__init__.py new/xpra-3.0.7/xpra/__init__.py --- old/xpra-3.0.6/xpra/__init__.py 2020-02-07 12:24:56.000000000 +0100 +++ new/xpra-3.0.7/xpra/__init__.py 2020-03-13 18:03:50.000000000 +0100 @@ -4,4 +4,4 @@ # Xpra is released under the terms of the GNU GPL v2, or, at your option, any # later version. See the file COPYING for details. -__version__ = "3.0.6" +__version__ = "3.0.7" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/client/auth/file_handler.py new/xpra-3.0.7/xpra/client/auth/file_handler.py --- old/xpra-3.0.6/xpra/client/auth/file_handler.py 2019-09-24 15:53:58.000000000 +0200 +++ new/xpra-3.0.7/xpra/client/auth/file_handler.py 2020-02-18 06:58:42.000000000 +0100 @@ -17,7 +17,6 @@ if client.password_file: self.password_file = client.password_file[0] client.password_file = client.password_file[1:] - self.password_file = "password.txt" def __repr__(self): return "file" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/client/gtk_base/bug_report.py new/xpra-3.0.7/xpra/client/gtk_base/bug_report.py --- old/xpra-3.0.6/xpra/client/gtk_base/bug_report.py 2019-12-08 12:59:03.000000000 +0100 +++ new/xpra-3.0.7/xpra/client/gtk_base/bug_report.py 2020-03-08 03:21:09.000000000 +0100 @@ -16,7 +16,7 @@ JUSTIFY_LEFT, WIN_POS_CENTER, FILE_CHOOSER_ACTION_SAVE, ) from xpra.util import nonl, envint, repr_ellipsized -from xpra.os_util import strtobytes +from xpra.os_util import strtobytes, hexstr, PYTHON3 from xpra.log import Logger log = Logger("util") @@ -212,9 +212,7 @@ 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("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") @@ -235,12 +233,14 @@ def hide(self): log("hide()") - self.window.hide() + if self.window: + self.window.hide() def close(self, *args): log("close%s", args) - self.hide() - self.window = None + if self.window: + self.hide() + self.window = None return True def destroy(self, *args): @@ -269,8 +269,8 @@ return None - def get_text_data(self): - log("get_text_data() collecting bug report data") + def get_data(self): + log("get_data() collecting bug report data") data = [] tb = self.description.get_buffer() buf = tb.get_text(*tb.get_bounds(), include_hidden_chars=False) @@ -304,15 +304,19 @@ elif isinstance(value, (list, tuple)): s = os.linesep.join(str(x) for x in value) else: - s = str(value) + s = value log("%s (%s) %s: %s", title, tooltip, dtype, repr_ellipsized(s)) data.append((title, tooltip, dtype, s)) time.sleep(STEP_DELAY) return data def copy_clicked(self, *_args): - data = self.get_text_data() - text = os.linesep.join("%s: %s%s%s%s" % (title, tooltip, os.linesep, v, os.linesep) + data = self.get_data() + def cdata(v): + if isinstance(v, bytes): + return hexstr(v) + return str(v) + text = os.linesep.join("%s: %s%s%s%s" % (title, tooltip, os.linesep, cdata(v), os.linesep) for (title,tooltip,dtype,v) in data if dtype=="txt") clipboard = gtk.clipboard_get(gdk.SELECTION_CLIPBOARD) clipboard.set_text(text) @@ -329,7 +333,7 @@ if not filename.lower().endswith(".zip"): filename = filename+".zip" basenoext = os.path.splitext(os.path.basename(filename))[0] - data = self.get_text_data() + data = self.get_data() import zipfile zf = zipfile.ZipFile(filename, mode='w', compression=zipfile.ZIP_DEFLATED) try: @@ -340,6 +344,23 @@ #very poorly documented: info.external_attr = 0o644 << 16 info.comment = strtobytes(tooltip) - zf.writestr(info, s) + if PYTHON3 and isinstance(s, bytes): + try: + try: + import tempfile + temp = tempfile.NamedTemporaryFile(prefix="xpra.", suffix=".screenshot", delete=False) + with temp: + temp.write(s) + temp.flush() + except OSError as e: + log.error("Error: cannot create mmap file:") + log.error(" %s", e) + else: + zf.write(temp.name, cfile, zipfile.ZIP_STORED, 0) + finally: + if temp: + os.unlink(temp.name) + else: + zf.writestr(info, str(s)) finally: zf.close() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/client/gtk_base/gtk_client_base.py new/xpra-3.0.7/xpra/client/gtk_base/gtk_client_base.py --- old/xpra-3.0.6/xpra/client/gtk_base/gtk_client_base.py 2020-01-08 12:52:06.000000000 +0100 +++ new/xpra-3.0.7/xpra/client/gtk_base/gtk_client_base.py 2020-03-08 03:21:09.000000000 +0100 @@ -664,7 +664,7 @@ def make_hello(self): capabilities = UIXpraClient.make_hello(self) capabilities["named_cursors"] = len(cursor_types)>0 - capabilities["transparency"] = self.has_transparency() + capabilities["encoding.transparency"] = self.has_transparency() capabilities.update(flatten_dict(get_gtk_version_info())) if EXPORT_ICON_DATA: #tell the server which icons GTK can use @@ -866,7 +866,10 @@ else: cursor_pixbuf = pixbuf if SAVE_CURSORS: - cursor_pixbuf.save("cursor-%#x.png" % serial, "png") + if PYTHON3: + cursor_pixbuf.savev("cursor-%#x.png" % serial, "png", [], []) + else: + cursor_pixbuf.save("cursor-%#x.png" % serial, "png") #clamp to pixbuf size: w = cursor_pixbuf.get_width() h = cursor_pixbuf.get_height() @@ -1113,7 +1116,7 @@ self.opengl_enabled = not self.opengl_enabled opengllog("opengl_toggled: %s", self.opengl_enabled) #now replace all the windows with new ones: - for wid, window in self._id_to_window.items(): + for wid, window in tuple(self._id_to_window.items()): self.reinit_window(wid, window) opengllog("replaced all the windows with opengl=%s: %s", self.opengl_enabled, self._id_to_window) self.reinit_window_icons() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/client/mixins/window_manager.py new/xpra-3.0.7/xpra/client/mixins/window_manager.py --- old/xpra-3.0.6/xpra/client/mixins/window_manager.py 2020-02-07 12:19:09.000000000 +0100 +++ new/xpra-3.0.7/xpra/client/mixins/window_manager.py 2020-03-08 03:21:09.000000000 +0100 @@ -879,7 +879,9 @@ def deiconify_windows(self): log("deiconify_windows()") for window in self._id_to_window.values(): - window.deiconify() + deiconify = getattr(window, "deiconify", None) + if deiconify: + deiconify() def resize_windows(self, new_size_fn): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/clipboard/clipboard_core.py new/xpra-3.0.7/xpra/clipboard/clipboard_core.py --- old/xpra-3.0.6/xpra/clipboard/clipboard_core.py 2019-09-24 15:53:59.000000000 +0200 +++ new/xpra-3.0.7/xpra/clipboard/clipboard_core.py 2020-03-08 03:21:09.000000000 +0100 @@ -539,6 +539,7 @@ #clients that need a new token for every owner-change: (ie: win32 and osx) #(forces the client to request new contents - prevents stale clipboard data) self._greedy_client = False + self._want_targets = False #semaphore to block the sending of the token when we change the owner ourselves: self._block_owner_change = False self._last_emit_token = 0 @@ -564,6 +565,10 @@ self._can_send = can_send self._can_receive = can_receive + def set_want_targets(self, want_targets): + self._want_targets = want_targets + + def get_info(self): info = { "have_token" : self._have_token, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/clipboard/clipboard_timeout_helper.py new/xpra-3.0.7/xpra/clipboard/clipboard_timeout_helper.py --- old/xpra-3.0.6/xpra/clipboard/clipboard_timeout_helper.py 2019-09-24 15:53:59.000000000 +0200 +++ new/xpra-3.0.7/xpra/clipboard/clipboard_timeout_helper.py 2020-03-13 17:51:18.000000000 +0100 @@ -5,7 +5,7 @@ from xpra.gtk_common.gobject_compat import import_glib from xpra.clipboard.clipboard_core import ClipboardProtocolHelperCore -from xpra.util import repr_ellipsized, envint +from xpra.util import repr_ellipsized, envint, engs from xpra.log import Logger from xpra.platform.features import CLIPBOARD_GREEDY @@ -113,3 +113,13 @@ (request_id, dtype, dformat, repr_ellipsized(str(data))), proxy, selection) if proxy: proxy.got_contents(target, dtype, dformat, data) + + def client_reset(self): + super().client_reset() + #timeout all pending requests + cor = self._clipboard_outstanding_requests + if cor: + log.info("cancelling %i clipboard request%s", len(cor), engs(cor)) + self._clipboard_outstanding_requests = {} + for request_id in cor: + self._clipboard_got_contents(request_id) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/codecs/dec_avcodec2/decoder.pyx new/xpra-3.0.7/xpra/codecs/dec_avcodec2/decoder.pyx --- old/xpra-3.0.6/xpra/codecs/dec_avcodec2/decoder.pyx 2019-09-24 15:53:59.000000000 +0200 +++ new/xpra-3.0.7/xpra/codecs/dec_avcodec2/decoder.pyx 2020-03-08 03:21:09.000000000 +0100 @@ -254,7 +254,8 @@ log("%s.free() context=%#x, frame=%#x", self, <uintptr_t> self.avctx, <uintptr_t> self.frame) if self.avctx!=NULL and self.frame!=NULL: av_frame_unref(self.frame) - self.frame = NULL + av_frame_free(&self.frame) + self.frame = NULL #should be redundant self.avctx = NULL @@ -375,13 +376,6 @@ log.error("could not open codec: %s", av_error_str(r)) self.clean_decoder() return False - #up to 3 AVFrame objects used: - self.av_frame = av_frame_alloc() - log("av_frame_alloc()=%#x", <uintptr_t> self.av_frame) - if self.av_frame==NULL: - log.error("could not allocate an AVFrame for decoding") - self.clean_decoder() - return False self.frames = 0 #to keep track of images not freed yet: #(we want a weakref.WeakSet() but this is python2.7+ only..) @@ -397,7 +391,6 @@ self.actual_pix_fmt = 0 self.colorspace = "" self.weakref_images = [] - self.av_frame = NULL #should be redundant self.frames = 0 self.width = 0 self.height = 0 @@ -418,12 +411,6 @@ for img in images: if not img.freed: img.clone_pixel_data() - - if self.av_frame!=NULL: - log("clean_decoder() freeing AVFrame: %#x", <uintptr_t> self.av_frame) - av_frame_free(&self.av_frame) - #redundant: self.frame = NULL - log("clean_decoder() freeing AVCodecContext: %#x", <uintptr_t> self.codec_ctx) if self.codec_ctx!=NULL: r = avcodec_close(self.codec_ctx) @@ -511,6 +498,13 @@ assert self.codec_ctx!=NULL, "no codec context! (not initialized or already closed)" assert self.codec!=NULL + av_frame = av_frame_alloc() + log("av_frame_alloc()=%#x", <uintptr_t> av_frame) + if av_frame==NULL: + log.error("could not allocate an AVFrame for decoding") + self.clean_decoder() + return None + #copy the whole input buffer into a padded C buffer: assert object_as_buffer(input, <const void**> &buf, &buf_len)==0 padded_buf = <unsigned char *> memalign(buf_len+128) @@ -524,7 +518,7 @@ outsize = 0 #ensure we can detect if the frame buffer got allocated: - clear_frame(self.av_frame) + clear_frame(av_frame) #now safe to run without gil: with nogil: av_init_packet(&avpkt) @@ -537,7 +531,7 @@ self.log_av_error(buf_len, ret, options) return None with nogil: - ret = avcodec_receive_frame(self.codec_ctx, self.av_frame) + ret = avcodec_receive_frame(self.codec_ctx, av_frame) free(padded_buf) if ret==-errno.EAGAIN: d = options.intget("delayed", 0) @@ -547,19 +541,21 @@ self.log_error(buf_len, "no picture", options) return None if ret!=0: - av_frame_unref(self.av_frame) + av_frame_unref(av_frame) + av_frame_free(&av_frame) log("%s.decompress_image(%s:%s, %s) avcodec_decode_video2 failure: %s", self, type(input), buf_len, options, av_error_str(ret)) self.log_av_error(buf_len, ret, options) return None log("avcodec_decode_video2 returned %i", ret) - if self.actual_pix_fmt!=self.av_frame.format: - if self.av_frame.format==-1: + if self.actual_pix_fmt!=av_frame.format: + if av_frame.format==-1: self.log_error(buf_len, "unknown format returned") return None - self.actual_pix_fmt = self.av_frame.format + self.actual_pix_fmt = av_frame.format if self.actual_pix_fmt not in ENUM_TO_FORMAT: - av_frame_unref(self.av_frame) + av_frame_unref(av_frame) + av_frame_free(&av_frame) log.error("unknown output pixel format: %s, expected %s (%s)", self.actual_pix_fmt, self.pix_fmt, self.colorspace) return None log("avcodec actual output pixel format is %s (%s), expected %s (%s)", self.actual_pix_fmt, self.get_actual_colorspace(), self.pix_fmt, self.colorspace) @@ -575,32 +571,34 @@ elif dy==2: height = (self.codec_ctx.height+1)>>1 else: - av_frame_unref(self.av_frame) + av_frame_unref(av_frame) + av_frame_free(&av_frame) raise Exception("invalid height divisor %s" % dy) - stride = self.av_frame.linesize[i] + stride = av_frame.linesize[i] size = height * stride outsize += size - out.append(memory_as_pybuffer(<void *>self.av_frame.data[i], size, True)) + out.append(memory_as_pybuffer(<void *>av_frame.data[i], size, True)) strides.append(stride) log("decompress_image() read back yuv plane %s: %s bytes", i, size) else: #RGB mode: "out" is a single buffer - strides = self.av_frame.linesize[0]+self.av_frame.linesize[1]+self.av_frame.linesize[2] + strides = av_frame.linesize[0]+av_frame.linesize[1]+av_frame.linesize[2] outsize = self.codec_ctx.height * strides - out = memory_as_pybuffer(<void *>self.av_frame.data[0], outsize, True) + out = memory_as_pybuffer(<void *>av_frame.data[0], outsize, True) nplanes = 0 log("decompress_image() read back rgb buffer: %s bytes", outsize) if outsize==0: - av_frame_unref(self.av_frame) + av_frame_unref(av_frame) + av_frame_free(&av_frame) raise Exception("output size is zero!") if self.codec_ctx.width<self.width or self.codec_ctx.height<self.height: raise Exception("%s context dimension %ix%i is smaller than the codec's expected size of %ix%i for frame %i" % (self.encoding, self.codec_ctx.width, self.codec_ctx.height, self.width, self.height, self.frames+1)) bpp = BYTES_PER_PIXEL.get(self.actual_pix_fmt, 0) framewrapper = AVFrameWrapper() - framewrapper.set_context(self.codec_ctx, self.av_frame) + framewrapper.set_context(self.codec_ctx, av_frame) img = AVImageWrapper(0, 0, self.width, self.height, out, cs, 24, strides, bpp, nplanes, thread_safe=False) img.av_frame = framewrapper self.frames += 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/keyboard/layouts.py new/xpra-3.0.7/xpra/keyboard/layouts.py --- old/xpra-3.0.6/xpra/keyboard/layouts.py 2020-01-25 11:03:51.000000000 +0100 +++ new/xpra-3.0.7/xpra/keyboard/layouts.py 2020-03-08 03:21:09.000000000 +0100 @@ -396,7 +396,7 @@ m = opt_re.match(line) if m: v = m.group(2).strip() - if v!=",": + if v.strip(","): settings[m.group(1)] = v return settings diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/net/bytestreams.py new/xpra-3.0.7/xpra/net/bytestreams.py --- old/xpra-3.0.6/xpra/net/bytestreams.py 2019-10-20 14:13:42.000000000 +0200 +++ new/xpra-3.0.7/xpra/net/bytestreams.py 2020-02-10 16:32:04.000000000 +0100 @@ -600,7 +600,7 @@ try: peername = sock.getpeername() except socket.error: - peername = str(address) + peername = address try: sockname = sock.getsockname() except AttributeError: @@ -611,7 +611,7 @@ if peername: frominfo = pretty_socket(peername) log.info("New %s connection received", socktype) - log.info(" from '%s'", frominfo) + log.info(" from '%s'", pretty_socket(frominfo)) if socket_info: log.info(" on '%s'", pretty_socket(socket_info)) elif socktype=="unix-domain": diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/net/digest.py new/xpra-3.0.7/xpra/net/digest.py --- old/xpra-3.0.6/xpra/net/digest.py 2019-09-24 15:54:00.000000000 +0200 +++ new/xpra-3.0.7/xpra/net/digest.py 2020-02-26 16:43:23.000000000 +0100 @@ -30,7 +30,7 @@ #python versions older than 2.7.9 may not have this attribute: #(in which case, your options will be more limited) if algorithms_available: - digests += ["hmac+%s" % x for x in tuple(reversed(sorted(algorithms_available)))] + digests += ["hmac+%s" % x for x in tuple(reversed(sorted(algorithms_available))) if not x.startswith("shake_") and getattr(hashlib, x, None) is not None] try: from xpra.net import d3des assert d3des @@ -87,7 +87,7 @@ return memoryview_to_bytes(v) digestmod = get_digest_module(digest) if not digestmod: - log("invalid digest module '%s': %s", digest) + log("invalid digest module '%s'", digest) return None #warn_server_and_exit(EXIT_UNSUPPORTED, "server requested digest '%s' but it is not supported" % digest, "invalid digest") v = hmac.HMAC(strtobytes(password), strtobytes(salt), digestmod=digestmod).hexdigest() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/net/ssh.py new/xpra-3.0.7/xpra/net/ssh.py --- old/xpra-3.0.6/xpra/net/ssh.py 2019-11-05 18:31:07.000000000 +0100 +++ new/xpra-3.0.7/xpra/net/ssh.py 2020-02-10 16:32:04.000000000 +0100 @@ -258,7 +258,7 @@ host_config = ssh_config.lookup(host) if host_config: host = host_config.get("hostname", host) - username = host_config.get("username", username) + username = host_config.get("user", username) port = host_config.get("port", port) try: port = int(port) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/platform/win32/clipboard.py new/xpra-3.0.7/xpra/platform/win32/clipboard.py --- old/xpra-3.0.6/xpra/platform/win32/clipboard.py 2019-10-28 16:04:05.000000000 +0100 +++ new/xpra-3.0.7/xpra/platform/win32/clipboard.py 2020-03-08 03:21:09.000000000 +0100 @@ -9,11 +9,11 @@ WinError, FormatError, ) from xpra.platform.win32.common import ( - WNDCLASSEX, GetLastError, ERROR_ACCESS_DENIED, WNDPROC, LPCWSTR, LPWSTR, + WNDCLASSEX, GetLastError, WNDPROC, LPCWSTR, LPWSTR, DefWindowProcW, GetModuleHandleA, RegisterClassExW, UnregisterClassA, CreateWindowExW, DestroyWindow, - OpenClipboard, EmptyClipboard, CloseClipboard, GetClipboardData, + OpenClipboard, EmptyClipboard, CloseClipboard, GetClipboardData, GetClipboardOwner, GlobalLock, GlobalUnlock, GlobalAlloc, GlobalFree, WideCharToMultiByte, MultiByteToWideChar, AddClipboardFormatListener, RemoveClipboardFormatListener, @@ -147,28 +147,22 @@ self.send_clipboard_token_handler = send_clipboard_token_handler ClipboardProxyCore.__init__(self, selection) - def set_want_targets(self, want_targets): - self._want_targets = want_targets - def with_clipboard_lock(self, success_callback, failure_callback, retries=5, delay=5): r = OpenClipboard(self.window) - log("OpenClipboard(%#x)=%s", self.window, r) if r: + log("OpenClipboard(%#x)=%s", self.window, r) try: success_callback() return finally: CloseClipboard() - if GetLastError()!=ERROR_ACCESS_DENIED: - failure_callback("OpenClipboard: access denied") - return - log("clipboard lock: access denied") + log("OpenClipboard(%#x)=%s, owner=%#x", self.window, WinError(GetLastError()), GetClipboardOwner()) if retries<=0: failure_callback("OpenClipboard: too many failed attemps, giving up") return #try again later: glib.timeout_add(delay, self.with_clipboard_lock, - success_callback, failure_callback, retries-1, delay) + success_callback, failure_callback, retries-1, delay+5) def clear(self): def clear_error(error_text=""): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/platform/win32/namedpipes/common.py new/xpra-3.0.7/xpra/platform/win32/namedpipes/common.py --- old/xpra-3.0.6/xpra/platform/win32/namedpipes/common.py 2019-09-24 15:54:00.000000000 +0200 +++ new/xpra-3.0.7/xpra/platform/win32/namedpipes/common.py 2020-02-10 16:32:04.000000000 +0100 @@ -76,7 +76,7 @@ CreateNamedPipeA.argtypes = [LPCSTR, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, LPSECURITY_ATTRIBUTES] CreateNamedPipeA.restype = HANDLE ConnectNamedPipe = kernel32.ConnectNamedPipe -ConnectNamedPipe.argtypes = [HANDLE, OVERLAPPED] +ConnectNamedPipe.argtypes = [HANDLE, LPOVERLAPPED] ConnectNamedPipe.restype = BOOL DisconnectNamedPipe = kernel32.DisconnectNamedPipe DisconnectNamedPipe.argtypes = [HANDLE] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/platform/win32/netdev_query.py new/xpra-3.0.7/xpra/platform/win32/netdev_query.py --- old/xpra-3.0.6/xpra/platform/win32/netdev_query.py 2019-09-24 15:54:00.000000000 +0200 +++ new/xpra-3.0.7/xpra/platform/win32/netdev_query.py 2020-03-13 17:51:19.000000000 +0100 @@ -47,8 +47,8 @@ log("get_interface_info(%s)", iface, exc_info=True) from xpra.util import first_time if first_time("win32-network-query"): - log.error("Error: failed to query network interface:") - log.error(" %s", e) + log.info("cannot query network interface:") + log.info(" %s", e) return {} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/platform/win32/paths.py new/xpra-3.0.7/xpra/platform/win32/paths.py --- old/xpra-3.0.6/xpra/platform/win32/paths.py 2019-09-24 15:54:00.000000000 +0200 +++ new/xpra-3.0.7/xpra/platform/win32/paths.py 2020-03-08 03:21:09.000000000 +0100 @@ -134,22 +134,15 @@ def do_get_download_dir(): - #TODO: use "FOLDERID_Downloads": - # FOLDERID_Downloads = "{374DE290-123F-4565-9164-39C4925E467B}" - # maybe like here: - # https://gist.github.com/mkropat/7550097 - #from win32com.shell import shell, shellcon - #shell.SHGetFolderPath(0, shellcon.CSIDL_MYDOCUMENTS, None, 0) try: try: import _winreg as winreg except ImportError: import winreg #@UnresolvedImport @Reimport - #use the internet explorer registry key: - #HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer - key_path = 'Software\\Microsoft\\Internet Explorer' - key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, 0, winreg.KEY_READ) #@UndefinedVariable - DOWNLOAD_PATH = winreg.QueryValueEx(key, 'Download Directory')[0] #@UndefinedVariable + sub_key = r'SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders' + downloads_guid = '{374DE290-123F-4565-9164-39C4925E467B}' + with winreg.OpenKey(winreg.HKEY_CURRENT_USER, sub_key) as key: + DOWNLOAD_PATH = winreg.QueryValueEx(key, downloads_guid)[0] except: #fallback to what the documentation says is the default: DOWNLOAD_PATH = os.path.join(os.environ.get("USERPROFILE", "~"), "My Documents", "Downloads") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/platform/win32/win32_webcam.py new/xpra-3.0.7/xpra/platform/win32/win32_webcam.py --- old/xpra-3.0.6/xpra/platform/win32/win32_webcam.py 2019-09-24 15:54:00.000000000 +0200 +++ new/xpra-3.0.7/xpra/platform/win32/win32_webcam.py 2020-02-26 16:43:23.000000000 +0100 @@ -32,9 +32,16 @@ #try to load directshow tlb from various directories, -#depending on how xpra was packaged, or even run from the source directory: -dirs = [app_dir, os.path.join(app_dir, "win32"), os.path.join(app_dir, "share", "xpra")] +#depending on how xpra was packaged, installed locally, +#or even run from the source directory: +dirs = [ + app_dir, + os.path.join(app_dir, "win32"), + os.path.join(app_dir, "share", "xpra"), + os.path.join(os.environ.get("MINGW_PREFIX", ""), "share", "xpra"), + ] filenames = [os.environ.get("XPRA_DIRECTSHOW_TLB")] + [os.path.join(d, "DirectShow.tlb") for d in dirs] +directshow_tlb = None for filename in filenames: if filename and os.path.exists(filename): directshow_tlb = filename diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/scripts/main.py new/xpra-3.0.7/xpra/scripts/main.py --- old/xpra-3.0.6/xpra/scripts/main.py 2019-12-29 17:24:22.000000000 +0100 +++ new/xpra-3.0.7/xpra/scripts/main.py 2020-03-13 17:51:19.000000000 +0100 @@ -21,7 +21,7 @@ from xpra.util import csv, envbool, envint, unsetenv, repr_ellipsized, nonl, pver, DEFAULT_PORT, DEFAULT_PORTS from xpra.exit_codes import EXIT_SSL_FAILURE, EXIT_STR, EXIT_UNSUPPORTED from xpra.os_util import ( - get_util_logger, getuid, getgid, + get_util_logger, getuid, getgid, pollwait, monotonic_time, setsid, bytestostr, use_tty, WIN32, OSX, POSIX, PYTHON2, PYTHON3, SIGNAMES, is_Ubuntu, getUbuntuVersion, ) @@ -299,7 +299,18 @@ systemd_run = False else: from xpra.os_util import is_systemd_pid1 - systemd_run = is_systemd_pid1() + if is_systemd_pid1(): + cmd = ["systemd-run", "--quiet", "--user", "--scope", "--", "true"] + proc = Popen(cmd, stdin=None, stdout=None, stderr=None, shell=False) + r = pollwait(proc, timeout=1) + if r is None: + try: + proc.terminate() + except: + pass + systemd_run = r==0 + else: + systemd_run = False if systemd_run: #check if we have wrapped it already (or if disabled via env var) if SYSTEMD_RUN: @@ -2639,9 +2650,10 @@ from xpra.platform.pycups_printing import get_printer_definition for mimetype in ("pdf", "postscript"): pdef = get_printer_definition(mimetype) - #ie: d.pdf_printer = "/usr/share/ppd/cupsfilters/Generic-PDF_Printer-PDF.ppd" - setattr(d, "%s_printer" % mimetype, pdef) - except: + if pdef: + #ie: d.pdf_printer = "/usr/share/ppd/cupsfilters/Generic-PDF_Printer-PDF.ppd" + setattr(d, "%s_printer" % mimetype, pdef) + except Exception: pass VIRTUAL = ["mode"] #no such option! (it's a virtual one for the launch by config files) #hide irrelevant options: @@ -2664,7 +2676,7 @@ HIDDEN += ["lpadmin", "daemon", "use-display", "mmap-group", "mdns"] if not OSX: HIDDEN += ["dock-icon", "swap-keys"] - for opt in sorted(OPTION_TYPES.keys()): + for opt, otype in sorted(OPTION_TYPES.items()): if opt in VIRTUAL: continue i = log.info @@ -2679,19 +2691,21 @@ dv = getattr(d, k) cv = getattr(options, k, dv) if cv!=dv: - w("%-20s (used) = %-32s %s", opt, vstr(cv), type(cv)) - w("%-20s (default) = %-32s %s", opt, vstr(dv), type(dv)) + w("%-20s (used) = %-32s %s", opt, vstr(otype, cv), type(cv)) + w("%-20s (default) = %-32s %s", opt, vstr(otype, dv), type(dv)) else: - i("%-20s = %s", opt, vstr(cv)) + i("%-20s = %s", opt, vstr(otype, cv)) -def vstr(v): +def vstr(otype, v): #just used to quote all string values if v is None: + if otype==bool: + return "auto" return "" if isinstance(v, str): return "'%s'" % nonl(v) if isinstance(v, (tuple, list)): - return csv(vstr(x) for x in v) + return csv(vstr(otype, x) for x in v) return str(v) def run_showsetting(options, args): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/server/background_worker.py new/xpra-3.0.7/xpra/server/background_worker.py --- old/xpra-3.0.6/xpra/server/background_worker.py 2019-09-24 15:54:01.000000000 +0200 +++ new/xpra-3.0.7/xpra/server/background_worker.py 2020-03-13 17:51:19.000000000 +0100 @@ -32,16 +32,17 @@ def stop(self, force=False): if self.exit: return + items = tuple(x for x in tuple(self.items.queue) if x is not None) + log("Worker_Thread.stop(%s) %i items still in work queue: %s", force, len(items), items) if force: - if self.items.qsize()>0: - log.warn("Worker stop: %s items in the queue will not be run!", self.items.qsize()) + if items: + log.warn("Worker stop: %s items in the queue will not be run!", len(items)) self.items.put(None) self.items = Queue() self.exit = True else: - if self.items.qsize()>0: - log.info("waiting for %s items in work queue to complete", self.items.qsize()) - debug("Worker_Thread.stop(%s) %s items in work queue", force, self.items) + if items: + log.info("waiting for %s items in work queue to complete", len(items)) self.items.put(None) def add(self, item): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/server/mixins/clipboard_server.py new/xpra-3.0.7/xpra/server/mixins/clipboard_server.py --- old/xpra-3.0.6/xpra/server/mixins/clipboard_server.py 2019-09-24 15:54:01.000000000 +0200 +++ new/xpra-3.0.7/xpra/server/mixins/clipboard_server.py 2020-03-13 17:51:19.000000000 +0100 @@ -56,7 +56,11 @@ def get_info(self, _proto): if self._clipboard_helper is None: return {} - return {"clipboard" : self._clipboard_helper.get_info()} + ci = self._clipboard_helper.get_info() + cc = self._clipboard_client + if cc: + ci["client"] = cc.uuid + return {"clipboard" : ci} def get_server_features(self, server_source=None): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/server/mixins/input_server.py new/xpra-3.0.7/xpra/server/mixins/input_server.py --- old/xpra-3.0.6/xpra/server/mixins/input_server.py 2020-01-25 11:03:51.000000000 +0100 +++ new/xpra-3.0.7/xpra/server/mixins/input_server.py 2020-03-08 03:21:09.000000000 +0100 @@ -154,7 +154,7 @@ if ss is None: return keyname = bytestostr(keyname) - modifiers = tuple(bytestostr(x) for x in modifiers) + modifiers = list(bytestostr(x) for x in modifiers) self.set_ui_driver(ss) if group>=0: self.set_keyboard_layout_group(group) @@ -235,7 +235,7 @@ delay_ms = min(1500, max(250, delay_ms)) keylog("scheduling key repeat timer with delay %s for %s / %s", delay_ms, keyname, keycode) now = monotonic_time() - self.key_repeat_timer = self.timeout_add(0, self._key_repeat_timeout, now, delay_ms, wid, keyname, keyval, keycode, modifiers, is_mod) + self.key_repeat_timer = self.timeout_add(delay_ms, self._key_repeat_timeout, now, delay_ms, wid, keyname, keyval, keycode, modifiers, is_mod) def _key_repeat_timeout(self, when, delay_ms, wid, keyname, keyval, keycode, modifiers, is_mod): self.key_repeat_timer = None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/server/proxy/proxy_server.py new/xpra-3.0.7/xpra/server/proxy/proxy_server.py --- old/xpra-3.0.6/xpra/server/proxy/proxy_server.py 2019-09-24 15:54:01.000000000 +0200 +++ new/xpra-3.0.7/xpra/server/proxy/proxy_server.py 2020-03-13 17:51:19.000000000 +0100 @@ -432,6 +432,7 @@ def start_proxy_process(): log("start_proxy_process()") message_queue = MQueue() + client_conn = None try: #no other packets should be arriving until the proxy instance responds to the initial hello packet def unexpected_packet(packet): @@ -474,7 +475,8 @@ finally: #now we can close our handle on the connection: log("handover complete: closing connection from proxy server") - client_conn.close() + if client_conn: + client_conn.close() server_conn.close() log("sending socket-handover-complete") message_queue.put("socket-handover-complete") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/server/server_core.py new/xpra-3.0.7/xpra/server/server_core.py --- old/xpra-3.0.6/xpra/server/server_core.py 2019-11-26 16:58:06.000000000 +0100 +++ new/xpra-3.0.7/xpra/server/server_core.py 2020-03-13 17:51:19.000000000 +0100 @@ -438,7 +438,7 @@ p.quit() netlog("cleanup will disconnect: %s", self._potential_protocols) self.cancel_touch_timer() - if self.mdns: + if self.mdns_publishers: add_work_item(self.mdns_cleanup) if self._upgrading: reason = SERVER_UPGRADE diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/server/source/encodings_mixin.py new/xpra-3.0.7/xpra/server/source/encodings_mixin.py --- old/xpra-3.0.6/xpra/server/source/encodings_mixin.py 2019-09-24 15:54:01.000000000 +0200 +++ new/xpra-3.0.7/xpra/server/source/encodings_mixin.py 2020-03-08 03:21:09.000000000 +0100 @@ -277,7 +277,9 @@ if send_ui and not self.core_encodings: raise ClientException("client failed to specify any supported encodings") self.window_icon_encodings = c.strlistget("encodings.window-icon", ["premult_argb32"]) - self.rgb_formats = c.strlistget("encodings.rgb_formats", ["RGB"]) + #try both spellings for older versions: + for x in ("encodings", "encoding",): + self.rgb_formats = c.strlistget(x+".rgb_formats", self.rgb_formats) #skip all other encoding related settings if we don't send pixels: if not send_ui: log("windows/pixels forwarding is disabled for this client") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/src_info.py new/xpra-3.0.7/xpra/src_info.py --- old/xpra-3.0.6/xpra/src_info.py 2020-02-07 12:24:52.000000000 +0100 +++ new/xpra-3.0.7/xpra/src_info.py 2020-03-13 18:03:50.000000000 +0100 @@ -1,2 +1,2 @@ LOCAL_MODIFICATIONS=0 -REVISION=25177 +REVISION=25629 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/x11/fakeXinerama.py new/xpra-3.0.7/xpra/x11/fakeXinerama.py --- old/xpra-3.0.6/xpra/x11/fakeXinerama.py 2019-12-26 21:19:44.000000000 +0100 +++ new/xpra-3.0.7/xpra/x11/fakeXinerama.py 2020-03-08 03:21:09.000000000 +0100 @@ -67,10 +67,10 @@ return delfile("cannot save fake xinerama settings: no display found") if len(ss)>1: return delfile("cannot save fake xinerama settings: more than one display found") - if len(ss)==2 and isinstance(ss[0], int) and isinstance(ss[1], int): + display_info = ss[0] + if len(display_info)==2 and isinstance(display_info[0], int) and isinstance(display_info[1], int): #just WxH, not enough display information return delfile("cannot save fake xinerama settings: missing display data from client %s" % source) - display_info = ss[0] if len(display_info)<10: return delfile("cannot save fake xinerama settings: incomplete display data from client %s" % source) #display_name, width, height, width_mm, height_mm, \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/x11/gtk_x11/clipboard.py new/xpra-3.0.7/xpra/x11/gtk_x11/clipboard.py --- old/xpra-3.0.6/xpra/x11/gtk_x11/clipboard.py 2019-11-18 16:50:50.000000000 +0100 +++ new/xpra-3.0.7/xpra/x11/gtk_x11/clipboard.py 2020-03-08 03:21:09.000000000 +0100 @@ -20,6 +20,7 @@ init_x11_filter, cleanup_x11_filter, ) +from xpra.gtk_common.error import XError from xpra.clipboard.clipboard_core import ( ClipboardProtocolHelperCore, ClipboardProxyCore, TEXT_TARGETS, must_discard, must_discard_extra, _filter_targets, @@ -260,10 +261,6 @@ ClipboardProxyCore.init_uuid(self) self.claim() - def set_want_targets(self, want_targets): - self._want_targets = want_targets - - def got_token(self, targets, target_data=None, claim=True, synchronous_client=False): # the remote end now owns the clipboard self.cancel_emit_token() @@ -432,15 +429,22 @@ log("set_selection_response(%s, %s, %s, %s, %s, %r, %i)", requestor, target, prop, dtype, dformat, repr_ellipsized(bytestostr(data)), time) #answer the selection request: - with xsync: - xid = get_xwindow(requestor) - if data is not None: - X11Window.XChangeProperty(xid, prop, dtype, dformat, data) - else: - #maybe even delete the property? - #X11Window.XDeleteProperty(xid, prop) - prop = None - X11Window.sendSelectionNotify(xid, self._selection, target, prop, time) + try: + with xsync: + xid = get_xwindow(requestor) + if data is not None: + X11Window.XChangeProperty(xid, prop, dtype, dformat, data) + else: + #maybe even delete the property? + #X11Window.XDeleteProperty(xid, prop) + prop = None + X11Window.sendSelectionNotify(xid, self._selection, target, prop, time) + except XError as e: + log("failed to set selection", exc_info=True) + log.warn("Warning: failed to set selection for target '%s'", target) + log.warn(" on requestor %s", self.get_wininfo(xid)) + log.warn(" property '%s'", prop) + log.warn(" %s", e) def got_contents(self, target, dtype=None, dformat=None, data=None): #if this is the special target 'TARGETS', cache the result: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/x11/models/size_hints_util.py new/xpra-3.0.7/xpra/x11/models/size_hints_util.py --- old/xpra-3.0.6/xpra/x11/models/size_hints_util.py 2019-09-24 15:54:02.000000000 +0200 +++ new/xpra-3.0.7/xpra/x11/models/size_hints_util.py 2020-03-08 03:21:09.000000000 +0100 @@ -45,21 +45,13 @@ if v is not None: try: w,h = v + int(w) + int(h) except (ValueError, TypeError): w,h = None,None if (w is None or h is None) or w>=MAX_WINDOW_SIZE or h>=MAX_WINDOW_SIZE: log("clearing invalid size hint value for %s: %s", attr, v) del size_hints[attr] - for attr in ("minimum-aspect-ratio", "maximum-aspect-ratio"): - v = size_hints.get(attr) - if v is not None: - try: - w,h = v - except (ValueError, TypeError): - w,h = None,None - if (not w or not h) or w>=MAX_WINDOW_SIZE or h>=MAX_WINDOW_SIZE: - log.warn("Warning: clearing invalid size hint value for %s: %s", attr, v) - del size_hints[attr] #if max-size is smaller than min-size (bogus), clamp it.. mins = size_hints.get("minimum-size") maxs = size_hints.get("maximum-size") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/x11/server.py new/xpra-3.0.7/xpra/x11/server.py --- old/xpra-3.0.6/xpra/x11/server.py 2020-01-25 11:03:51.000000000 +0100 +++ new/xpra-3.0.7/xpra/x11/server.py 2020-02-10 16:32:04.000000000 +0100 @@ -829,7 +829,8 @@ #x_root, y_root, direction, button, source_indication = event.data wid = self._window_to_id[window] #find clients that handle windows: - wsources = [ss for ss in self._server_sources.values() is isinstance(ss, WindowsMixin)] + from xpra.server.source.windows_mixin import WindowsMixin + wsources = [ss for ss in self._server_sources.values() if isinstance(ss, WindowsMixin)] if not wsources: return #prefer the "UI driver" if we find it: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/x11/server_keyboard_config.py new/xpra-3.0.7/xpra/x11/server_keyboard_config.py --- old/xpra-3.0.6/xpra/x11/server_keyboard_config.py 2020-01-25 11:03:51.000000000 +0100 +++ new/xpra-3.0.7/xpra/x11/server_keyboard_config.py 2020-03-13 17:51:19.000000000 +0100 @@ -20,6 +20,7 @@ get_modifiers_from_meanings, get_modifiers_from_keycodes, clear_modifiers, set_modifiers, map_missing_modifiers, clean_keyboard_state, + DEBUG_KEYSYMS, ) from xpra.x11.bindings.keyboard_bindings import X11KeyboardBindings #@UnresolvedImport from xpra.log import Logger @@ -29,6 +30,7 @@ X11Keyboard = X11KeyboardBindings() MAP_MISSING_MODIFIERS = envbool("XPRA_MAP_MISSING_MODIFIERS", True) +SIMULATE_MODIFIERS = envbool("XPRA_SIMULATE_MODIFIERS", True) ALL_X11_MODIFIERS = { "shift" : 0, @@ -69,6 +71,7 @@ self.modifier_client_keycodes = {} self.compute_modifier_map() self.modifiers_filter = [] + self.keycode_mappings = {} def __repr__(self): return "KeyboardConfig(%s / %s / %s)" % (self.xkbmap_layout, self.xkbmap_variant, self.xkbmap_options) @@ -320,6 +323,7 @@ self.compute_modifiers() self.compute_modifier_keynames() self.compute_client_modifier_keycodes() + self.update_keycode_mappings() return with xlog: @@ -367,6 +371,7 @@ self.compute_client_modifier_keycodes() log("keyname_for_mod=%s", self.keynames_for_mod) clean_keyboard_state() + self.update_keycode_mappings() def add_gtk_keynames(self): #add the keynames we find via gtk @@ -375,6 +380,19 @@ for _, keyname, keycode, _, _ in get_gtk_keymap(): if keyname not in self.keycode_translation: self.keycode_translation[keyname] = keycode + if keyname in DEBUG_KEYSYMS: + log.info("add_gtk_keynames: %s=%s", keyname, keycode) + #some keys may still be missing with GTK2: + for keyname, equiv in { + "dead_perispomeni" : "dead_tilde", + }.items(): + if keyname not in self.keycode_translation: + keycode = self.keycode_translation.get(equiv) + if keycode: + self.keycode_translation[keyname] = keycode + if keyname in DEBUG_KEYSYMS: + log.info("add_gtk_keynames: %s=%s", keyname, keycode) + def set_default_keymap(self): """ assign a default keymap based on the current X11 server keymap @@ -388,9 +406,21 @@ #keycodes: keycode_to_keynames = X11Keyboard.get_keycode_mappings() self.keycode_translation = {} + #prefer keycodes that don't use the lowest level+mode: + default_for_keyname = {} for keycode, keynames in keycode_to_keynames.items(): - for keyname in keynames: - self.keycode_translation[keyname] = keycode + for i, keyname in enumerate(keynames): + self.keycode_translation[(keyname, i)] = keycode + if keyname in DEBUG_KEYSYMS: + log.info("set_default_keymap: %s=%s", (keyname, i), keycode) + kd = default_for_keyname.get(keyname) + if kd is None or kd[1]>i: + default_for_keyname[keyname] = (keycode, i) + for keyname, kd in default_for_keyname.items(): + keycode = kd[0] + self.keycode_translation[keyname] = keycode + if keyname in DEBUG_KEYSYMS: + log.info("set_default_keymap: %s=%s", keyname, keycode) self.add_gtk_keynames() log("set_default_keymap: keycode_translation=%s", self.keycode_translation) #modifiers: @@ -409,6 +439,10 @@ log("set_default_keymap: keynames_for_mod=%s", self.keynames_for_mod) log("set_default_keymap: keycodes_for_modifier_keynames=%s", self.keycodes_for_modifier_keynames) log("set_default_keymap: modifier_map=%s", self.modifier_map) + self.update_keycode_mappings() + + def update_keycode_mappings(self): + self.keycode_mappings = X11Keyboard.get_keycode_mappings() def do_get_keycode(self, client_keycode, keyname, pressed, modifiers, group): @@ -417,11 +451,15 @@ return -1 if keyname=="0xffffff": return -1 + if self.xkbmap_raw: + return client_keycode keycode = None if self.xkbmap_query: keycode = self.keycode_translation.get((client_keycode, keyname)) or client_keycode log("get_keycode(%s, %s, %s)=%s (native keymap)", client_keycode, keyname, modifiers, keycode) else: + if SIMULATE_MODIFIERS: + return self.do_get_keycode_new(client_keycode, keyname, pressed, modifiers, group) #non-native: try harder to find matching keysym #first, try to honour shift state: shift = ("shift" in modifiers) ^ ("lock" in modifiers) @@ -452,6 +490,85 @@ log("get_keycode(%s, %s)=%i (keyname translation)", client_keycode, keyname, keycode) return keycode + def do_get_keycode_new(self, client_keycode, keyname, pressed, modifiers, group): + #non-native: try harder to find matching keysym + def kmlog(msg, *args): + if keyname in DEBUG_KEYSYMS: + l = log.info + else: + l = log + l(msg, *args) + def klog(msg, *args): + kmlog("do_get_keycode%s"+msg, (client_keycode, keyname, pressed, modifiers, group), *args) + #first, try to honour shift state: + shift = ("shift" in modifiers) ^ ("lock" in modifiers) + mode = 0 + for mod in modifiers: + names = self.keynames_for_mod.get(mod, []) + for name in names: + if name in ("ISO_Level3_Shift", "Mode_switch"): + mode = 1 + break + level = int(shift) + int(mode)*2 + levels = [] + #first, match with group if set: + if group: + levels.append(level+4) + #then try exact match without group: + levels.append(level) + #try default group: + for i in range(2): + level = int(shift) + i*2 + if level not in levels: + levels.append(level) + #catch all: + for level in range(8): + if level not in levels: + levels.append(level) + kmlog("will try levels: %s", levels) + for level in levels: + keycode = self.keycode_translation.get((keyname, level)) + if keycode: + klog("=%i (level=%i, shift=%s, mode=%i)", keycode, level, shift, mode) + if self.xkbmap_raw: + break + keysyms = self.keycode_mappings.get(keycode) + level0 = levels[0] + if len(keysyms)>level0 and keysyms[level0]=="": + #if the keysym we would match for this keycode is 'NoSymbol', + #then we can probably ignore it ('NoSymbol' shows up as "") + kmlog("not toggling any modifiers state for keysyms=%s", keysyms) + break + def toggle_modifier(mod): + keynames = self.keynames_for_mod.get(mod) + if keyname in keynames: + kmlog("not toggling '%s' since '%s' should deal with it", mod, keyname) + #the keycode we're returning is for this modifier, + #assume that this will end up doing what is needed + return + if mod in modifiers: + kmlog("removing '%s' from modifiers", mod) + modifiers.remove(mod) + else: + kmlog("adding '%s' to modifiers", mod) + modifiers.append(mod) + if (level & 1) ^ shift: + #shift state does not match + toggle_modifier("shift") + if (level & 2) ^ mode: + #try to set / unset mode: + for mod, keynames in self.keynames_for_mod.items(): + if "ISO_Level3_Shift" in keynames or "Mode_switch" in keynames: + #found mode switch modified + toggle_modifier(mod) + break + break + #this should not find anything new?: + if keycode is None: + keycode = self.keycode_translation.get(keyname, -1) + klog("=%i (keyname translation)", keycode) + return keycode + def get_current_mask(self): current_mask = get_default_root_window().get_pointer()[-1] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/x11/vfb_util.py new/xpra-3.0.7/xpra/x11/vfb_util.py --- old/xpra-3.0.6/xpra/x11/vfb_util.py 2019-09-24 15:54:02.000000000 +0200 +++ new/xpra-3.0.7/xpra/x11/vfb_util.py 2020-02-18 06:58:42.000000000 +0100 @@ -242,7 +242,7 @@ xvfb_cmd += ["-displayfd", str(w_pipe)] xvfb_cmd[0] = "%s-for-Xpra-%s" % (xvfb_executable, display_name) def preexec(): - setsid() + os.setpgrp() if getuid()==0 and uid: setuidgid(uid, gid) close_fds([0, 1, 2, r_pipe, w_pipe]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/x11/x11_server_core.py new/xpra-3.0.7/xpra/x11/x11_server_core.py --- old/xpra-3.0.6/xpra/x11/x11_server_core.py 2020-02-07 12:19:10.000000000 +0100 +++ new/xpra-3.0.7/xpra/x11/x11_server_core.py 2020-03-08 03:21:10.000000000 +0100 @@ -369,6 +369,8 @@ capabilities["screen-sizes"] = sizes if self.default_cursor_image and source.wants_default_cursor: capabilities["cursor.default"] = self.default_cursor_image + if self.opengl_props: + capabilities["opengl"] = self.opengl_props return capabilities def do_get_info(self, proto, server_sources): @@ -500,8 +502,7 @@ self.keys_pressed = {} #this will take care of any remaining ones we are not aware of: #(there should not be any - but we want to be certain) - with xswallow: - X11Keyboard.unpress_all_keys() + clean_keyboard_state() def get_cursor_sizes(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/x11/xkbhelper.py new/xpra-3.0.7/xpra/x11/xkbhelper.py --- old/xpra-3.0.6/xpra/x11/xkbhelper.py 2019-09-24 15:54:02.000000000 +0200 +++ new/xpra-3.0.7/xpra/x11/xkbhelper.py 2020-03-08 03:21:10.000000000 +0100 @@ -50,6 +50,8 @@ with xlog: X11Keyboard.ungrab_all_keys() with xlog: + X11Keyboard.set_layout_group(0) + with xlog: X11Keyboard.unpress_all_keys() ################################################################################ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/xpra-3.0.6/xpra/x11/xsettings_prop.py new/xpra-3.0.7/xpra/x11/xsettings_prop.py --- old/xpra-3.0.6/xpra/x11/xsettings_prop.py 2019-10-20 14:13:42.000000000 +0200 +++ new/xpra-3.0.7/xpra/x11/xsettings_prop.py 2020-03-13 17:51:19.000000000 +0100 @@ -142,7 +142,7 @@ x += b'\0'*pad_len elif setting_type==XSettingsTypeColor: red, blue, green, alpha = value - x = struct.pack(b"=HHHH", red, blue, green, alpha) + x += struct.pack(b"=HHHH", red, blue, green, alpha) else: log.error("Error: invalid type %i for xsetting property '%s'", setting_type, prop_name) continue
