Hello community,

here is the log from the commit of package xpra for openSUSE:Factory checked in 
at 2020-09-28 14:29:01
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/xpra (Old)
 and      /work/SRC/openSUSE:Factory/.xpra.new.4249 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "xpra"

Mon Sep 28 14:29:01 2020 rev:26 rq:838116 version:4.0.4

Changes:
--------
--- /work/SRC/openSUSE:Factory/xpra/xpra.changes        2020-09-07 
21:37:09.465430841 +0200
+++ /work/SRC/openSUSE:Factory/.xpra.new.4249/xpra.changes      2020-09-28 
14:29:14.206156584 +0200
@@ -1,0 +2,42 @@
+Sun Sep 27 18:50:56 UTC 2020 - [email protected]
+
+- Update to version 4.0.4
+  * fix memory leak with 'scroll' encoding
+  * fix NVENC encoder (profile errors)
+  * fix unmanaged X11 message call which could cause GTK to
+    crash when it fails
+  * fix missing auto-refresh leaving a blurry image
+  * fix incomplete repaints when window contents have padding
+  * fix missing pixels on the edge of video areas in 'auto'
+    encoding mode
+  * fix connection errors with notifications disabled on the
+    server
+  * fix 'sync-xvfb' option: setup error, non-standard bit depth
+    support
+  * fix shadow server dbus SetRefreshDelay causing all further
+    "xpra info" requests to fail
+  * fix incomplete data in initial packets from shadow servers
+  * fix error in dbus debug logging
+  * fix client invalid list of encodings
+  * fix workspace spurious warnings on 64-bit X11 systems
+  * fix named-pipe server clash
+  * fix syntax error in HTML5 client maximize toggle
+  * fix keysym mapping with Xkb and some specific configurations
+  * fix right click on systray using the gtk StatusIcon
+    implementation
+  * fix small file transfers not showing as completed
+  * fix file-transfer UI for download vs download-and-open not
+    being honoured
+  * fix file-transfer identifiers getting lost
+  * fix websocket compatibility with some client / middleware
+  * fix missing windows due to an error in the named window icon
+    handling
+  * fix hard to trigger mmap memory leak
+  * add support for sm86 architecture with CUDA 11.1
+  * allow 'pager' source indication value to activate window
+    server-side
+  * workaround corruption on some windows when maximized
+  * workaround more pyxdg bugs
+  * make OpenGL probe timeout configurable
+
+-------------------------------------------------------------------

Old:
----
  xpra-4.0.3.tar.xz

New:
----
  xpra-4.0.4.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ xpra.spec ++++++
--- /var/tmp/diff_new_pack.FADjmK/_old  2020-09-28 14:29:15.414157632 +0200
+++ /var/tmp/diff_new_pack.FADjmK/_new  2020-09-28 14:29:15.414157632 +0200
@@ -19,7 +19,7 @@
 
 %global __requires_exclude 
^typelib\\(GtkosxApplication\\)|typelib\\(GdkGLExt\\)|typelib\\(GtkGLExt\\).*$
 Name:           xpra
-Version:        4.0.3
+Version:        4.0.4
 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

++++++ xpra-4.0.3.tar.xz -> xpra-4.0.4.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/NEWS new/xpra-4.0.4/NEWS
--- old/xpra-4.0.3/NEWS 2020-08-08 08:50:20.000000000 +0200
+++ new/xpra-4.0.4/NEWS 2020-09-27 20:11:39.000000000 +0200
@@ -1,3 +1,43 @@
+v4.0.4 (2020-09-26)
+======================
+       -- fix memory leak with 'scroll' encoding
+       -- fix NVENC encoder (profile errors)
+       -- fix unmanaged X11 message call which could cause GTK to crash when 
it fails
+       -- fix missing auto-refresh leaving a blurry image
+       -- fix incomplete repaints when window contents have padding
+       -- fix missing pixels on the edge of video areas in 'auto' encoding mode
+       -- fix connection errors with notifications disabled on the server
+       -- fix 'sync-xvfb' option: setup error, non-standard bit depth support
+       -- fix shadow server dbus SetRefreshDelay causing all further "xpra 
info" requests to fail
+       -- fix incomplete data in initial packets from shadow servers
+       -- fix error in dbus debug logging
+       -- fix client invalid list of encodings
+       -- fix missing system tray on Ubuntu 18.04
+       -- fix workspace spurious warnings on 64-bit X11 systems
+       -- fix event handler with 64-bit MS Windows builds
+       -- fix named-pipe server clash
+       -- fix error handing in MS Windows printer query API
+       -- fix missing 'openssl' dependency in DEB packages
+       -- fix syntax error in HTML5 client maximize toggle
+       -- fix keysym mapping with Xkb and some specific configurations
+       -- fix right click on systray using the gtk StatusIcon implementation
+       -- fix small file transfers not showing as completed
+       -- fix file-transfer UI for download vs download-and-open not being 
honoured
+       -- fix file-transfer identifiers getting lost
+       -- fix int overflow errors on some 64-bit mswindows installations
+       -- fix websocket compatibility with some client / middleware
+       -- fix missing windows due to an error in the named window icon handling
+       -- fix hard to trigger mmap memory leak
+       -- add support for sm86 architecture with CUDA 11.1
+       -- allow 'pager' source indication value to activate window server-side
+       -- switch to Xvfb on Debian and Ubuntu
+       -- workaround corruption on some windows when maximized
+       -- workaround more pyxdg bugs
+       -- make OpenGL probe timeout configurable
+       -- add missing DEB dependency
+       -- MacOS and MS Windows: fix security issue in brotli decompression
+
+
 v4.0.3 (2020-08-07)
 ======================
        -- fix server crash caused by use after free in scrolling code
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/cups/xpraforwarder 
new/xpra-4.0.4/cups/xpraforwarder
--- old/xpra-4.0.3/cups/xpraforwarder   2020-06-10 04:38:16.000000000 +0200
+++ new/xpra-4.0.4/cups/xpraforwarder   2020-09-27 20:11:39.000000000 +0200
@@ -38,7 +38,7 @@
 from urllib.parse import urlparse, parse_qs
 
 
-__version__ = "4.0.3"
+__version__ = "4.0.4"
 
 
 #Writes a syslog entry (msg) at the default facility:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/html5/index.html 
new/xpra-4.0.4/html5/index.html
--- old/xpra-4.0.3/html5/index.html     2020-06-10 04:38:16.000000000 +0200
+++ new/xpra-4.0.4/html5/index.html     2020-09-27 20:11:39.000000000 +0200
@@ -129,7 +129,7 @@
 
                <div id="about">
                        <h2>Xpra HTML5 Client</h2>
-                       <h3>Version 4.0.3</h3>
+                       <h3>Version 4.0.4</h3>
                        <span>
                                Copyright (c) 2013-2020 Antoine Martin 
&lt;[email protected]&gt;
                                <br />
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/html5/js/Utilities.js 
new/xpra-4.0.4/html5/js/Utilities.js
--- old/xpra-4.0.3/html5/js/Utilities.js        2020-06-10 04:38:16.000000000 
+0200
+++ new/xpra-4.0.4/html5/js/Utilities.js        2020-09-27 20:11:39.000000000 
+0200
@@ -10,7 +10,7 @@
 'use strict';
 
 const Utilities = {
-       VERSION : "4.0.3",
+       VERSION : "4.0.4",
        REVISION : "0",
        LOCAL_MODIFICATIONS : "0",
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/html5/js/Window.js 
new/xpra-4.0.4/html5/js/Window.js
--- old/xpra-4.0.3/html5/js/Window.js   2020-07-09 18:46:42.000000000 +0200
+++ new/xpra-4.0.4/html5/js/Window.js   2020-09-27 20:11:39.000000000 +0200
@@ -692,7 +692,7 @@
  */
 XpraWindow.prototype.toggle_minimized = function() {
        if (!this.minimized) {
-               this.client.send(["unmap-window", this.wid, True]);
+               this.client.send(["unmap-window", this.wid, true]);
        }
        else {
                const geom = this.get_internal_geometry();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/setup.py new/xpra-4.0.4/setup.py
--- old/xpra-4.0.3/setup.py     2020-07-09 18:46:42.000000000 +0200
+++ new/xpra-4.0.4/setup.py     2020-09-27 20:11:39.000000000 +0200
@@ -2089,6 +2089,8 @@
             comp_code_options.append((75, 75))
         if version>=(11, 0):
             comp_code_options.append((80, 80))
+        if version>=(11, 1):
+            comp_code_options.append((86, 86))
         for arch, code in comp_code_options:
             cmd.append("-gencode=arch=compute_%s,code=sm_%s" % (arch, code))
         print("CUDA compiling %s (%s)" % (kernel.ljust(16), reason))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/svn-info new/xpra-4.0.4/svn-info
--- old/xpra-4.0.3/svn-info     2020-08-08 08:50:24.000000000 +0200
+++ new/xpra-4.0.4/svn-info     2020-09-27 20:11:46.000000000 +0200
@@ -4,10 +4,10 @@
 Relative URL: ^/tags/v4.0.x/src
 Repository Root: file:///var/svn/repos/Xpra
 Repository UUID: 3bb7dfac-3a0b-4e04-842a-767bc560f471
-Revision: 27083
+Revision: 27557
 Node Kind: directory
 Schedule: normal
 Last Changed Author: antoine
-Last Changed Rev: 27082
-Last Changed Date: 2020-08-07 17:40:37 +0100 (Fri, 07 Aug 2020)
+Last Changed Rev: 27557
+Last Changed Date: 2020-09-27 18:17:12 +0100 (Sun, 27 Sep 2020)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/svn-version new/xpra-4.0.4/svn-version
--- old/xpra-4.0.3/svn-version  2020-08-08 08:50:24.000000000 +0200
+++ new/xpra-4.0.4/svn-version  2020-09-27 20:11:46.000000000 +0200
@@ -1 +1 @@
-27083
+27557
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/win32/xpra.iss 
new/xpra-4.0.4/win32/xpra.iss
--- old/xpra-4.0.3/win32/xpra.iss       2020-06-10 04:38:16.000000000 +0200
+++ new/xpra-4.0.4/win32/xpra.iss       2020-09-27 20:11:39.000000000 +0200
@@ -1,9 +1,9 @@
 [Setup]
 AppName=Xpra
 AppId=Xpra_is1
-AppVersion=4.0.3
-AppVerName=Xpra 4.0.3
-UninstallDisplayName=Xpra 4.0.3
+AppVersion=4.0.4
+AppVerName=Xpra 4.0.4
+UninstallDisplayName=Xpra 4.0.4
 AppPublisher=xpra.org
 AppPublisherURL=http:;xpra.org/
 DefaultDirName={pf}\Xpra
@@ -16,7 +16,7 @@
 Compression=lzma2/max
 SolidCompression=yes
 AllowUNCPath=false
-VersionInfoVersion=4.0.3
+VersionInfoVersion=4.0.4
 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-4.0.3/xpra/__init__.py 
new/xpra-4.0.4/xpra/__init__.py
--- old/xpra-4.0.3/xpra/__init__.py     2020-08-08 08:50:26.000000000 +0200
+++ new/xpra-4.0.4/xpra/__init__.py     2020-09-27 20:11:48.000000000 +0200
@@ -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__ = "4.0.3"
+__version__ = "4.0.4"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/client/client_window_base.py 
new/xpra-4.0.4/xpra/client/client_window_base.py
--- old/xpra-4.0.3/xpra/client/client_window_base.py    2020-05-10 
19:00:53.000000000 +0200
+++ new/xpra-4.0.4/xpra/client/client_window_base.py    2020-09-27 
20:11:39.000000000 +0200
@@ -711,9 +711,9 @@
         self.pending_refresh = []
         for x, y, w, h in pr:
             rx, ry, rw, rh = self._client.srect(x, y, w, h)
-            #if self.window_offset:
-            #    rx -= self.window_offset[0]
-            #    ry -= self.window_offset[1]
+            if self.window_offset:
+                rx += self.window_offset[0]
+                ry += self.window_offset[1]
             self.idle_add(self.queue_draw_area, rx, ry, rw, rh)
 
     def eos(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/xpra-4.0.3/xpra/client/gtk_base/gtk_client_window_base.py 
new/xpra-4.0.4/xpra/client/gtk_base/gtk_client_window_base.py
--- old/xpra-4.0.3/xpra/client/gtk_base/gtk_client_window_base.py       
2020-05-10 19:00:53.000000000 +0200
+++ new/xpra-4.0.4/xpra/client/gtk_base/gtk_client_window_base.py       
2020-09-27 20:11:39.000000000 +0200
@@ -99,6 +99,8 @@
 DRAGNDROP = envbool("XPRA_DRAGNDROP", True)
 CLAMP_WINDOW_TO_SCREEN = envbool("XPRA_CLAMP_WINDOW_TO_SCREEN", True)
 FOCUS_RECHECK_DELAY = envint("XPRA_FOCUS_RECHECK_DELAY", 0)
+REPAINT_MAXIMIZED = envint("XPRA_REPAINT_MAXIMIZED", 0)
+REFRESH_MAXIMIZED = envbool("XPRA_REFRESH_MAXIMIZED", True)
 
 WINDOW_OVERFLOW_TOP = envbool("XPRA_WINDOW_OVERFLOW_TOP", False)
 AWT_RECENTER = envbool("XPRA_AWT_RECENTER", True)
@@ -826,6 +828,17 @@
                 self.process_map_event()
         statelog("window_state_updated(..) state updates: %s, actual updates: 
%s, server updates: %s",
                  state_updates, actual_updates, server_updates)
+        if "maximized" in state_updates:
+            if REPAINT_MAXIMIZED>0:
+                def repaint_maximized():
+                    widget = self.drawing_area
+                    if not self._backing or not widget:
+                        return
+                    ww, wh = self.get_size()
+                    widget.queue_draw_area(0, 0, ww, wh)
+                self.timeout_add(REPAINT_MAXIMIZED, repaint_maximized)
+            if REFRESH_MAXIMIZED:
+                self._client.send_refresh(self._id)
         self._window_state.update(server_updates)
         self.emit("state-updated")
         #if we have state updates, send them back to the server using a 
configure window packet:
@@ -1222,6 +1235,9 @@
             #which will look at the window metadata again
             workspacelog("workspace=%s will be set when the window is mapped", 
wn(workspace))
             return
+        workspace = workspace
+        if workspace is not None:
+            workspace = workspace & 0xffffffff
         desktop = self.get_desktop_workspace()
         ndesktops = self.get_workspace_count()
         current = self.get_window_workspace()
@@ -1278,7 +1294,7 @@
         if value is not None:
             workspacelog("do_get_workspace %s=%s on window %i: %#x",
                          prop, wn(value), self._id, target.get_xid())
-            return value
+            return value & 0xffffffff
         workspacelog("do_get_workspace %s unset on window %i: %#x, returning 
default value=%s",
                      prop, self._id, target.get_xid(), wn(default_value))
         return  default_value
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/xpra-4.0.3/xpra/client/gtk_base/gtk_tray_menu_base.py 
new/xpra-4.0.4/xpra/client/gtk_base/gtk_tray_menu_base.py
--- old/xpra-4.0.3/xpra/client/gtk_base/gtk_tray_menu_base.py   2020-05-10 
19:00:53.000000000 +0200
+++ new/xpra-4.0.4/xpra/client/gtk_base/gtk_tray_menu_base.py   2020-09-27 
20:11:39.000000000 +0200
@@ -6,7 +6,7 @@
 
 import os
 import re
-from gi.repository import GLib, Gtk
+from gi.repository import GLib, Gtk, GdkPixbuf
 
 from xpra.util import CLIENT_EXIT, iround, envbool, repr_ellipsized, 
reverse_dict, typedict
 from xpra.os_util import bytestostr, OSX, WIN32
@@ -1690,7 +1690,6 @@
         if not pixbuf and icondata:
             #gtk pixbuf loader:
             try:
-                from gi.repository import GdkPixbuf
                 loader = GdkPixbuf.PixbufLoader()
                 loader.write(icondata)
                 loader.close()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/client/gtk_base/open_requests.py 
new/xpra-4.0.4/xpra/client/gtk_base/open_requests.py
--- old/xpra-4.0.3/xpra/client/gtk_base/open_requests.py        2020-05-10 
19:00:53.000000000 +0200
+++ new/xpra-4.0.4/xpra/client/gtk_base/open_requests.py        2020-09-27 
20:11:39.000000000 +0200
@@ -167,28 +167,29 @@
             else:
                 self.populate_table()
                 self.window.resize(1, 1)
-        def ok(*_args):
-            remove_entry(False)
-            cb_answer(ACCEPT, False)
-        def okopen(*_args):
+        def cancel(*_args):
             remove_entry(True)
+            cb_answer(DENY)
+        def accept(*_args):
+            remove_entry(False)
             cb_answer(ACCEPT, True)
+        def download(*_args):
+            remove_entry(False)
+            cb_answer(ACCEPT, False)
         def remote(*_args):
             remove_entry(True)
             cb_answer(OPEN)
-        def cancel(*_args):
-            remove_entry(True)
-            cb_answer(DENY)
-        hbox.pack_start(self.btn("Cancel", None, cancel, "close.png"))
+        cancel_btn = self.btn("Cancel", None, cancel, "close.png")
+        hbox.pack_start(cancel_btn)
         if bytestostr(dtype)=="url":
-            hbox.pack_start(self.btn("Open Locally", None, ok, "open.png"))
+            hbox.pack_start(self.btn("Open Locally", None, accept, "open.png"))
             hbox.pack_start(self.btn("Open on server", None, remote))
         elif printit:
-            hbox.pack_start(self.btn("Print", None, ok, "printer.png"))
+            hbox.pack_start(self.btn("Print", None, accept, "printer.png"))
         else:
-            hbox.pack_start(self.btn("Download", None, ok, "download.png"))
+            hbox.pack_start(self.btn("Download", None, download, 
"download.png"))
             if openit:
-                hbox.pack_start(self.btn("Download and Open", None, okopen, 
"open.png"))
+                hbox.pack_start(self.btn("Download and Open", None, accept, 
"open.png"))
                 hbox.pack_start(self.btn("Open on server", None, remote))
         return hbox
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/client/gtk_base/statusicon_tray.py 
new/xpra-4.0.4/xpra/client/gtk_base/statusicon_tray.py
--- old/xpra-4.0.3/xpra/client/gtk_base/statusicon_tray.py      2020-05-10 
19:00:53.000000000 +0200
+++ new/xpra-4.0.4/xpra/client/gtk_base/statusicon_tray.py      2020-09-27 
20:11:39.000000000 +0200
@@ -53,7 +53,7 @@
         modifiers_mask = get_default_root_window().get_pointer()[-1]
         log("activate_menu(%s) modifiers_mask=%s", widget, modifiers_mask)
         if (modifiers_mask & Gdk.ModifierType.SHIFT_MASK) ^ OSX:
-            self.handle_click(2)
+            self.handle_click(3)
         else:
             self.handle_click(1)
 
@@ -63,7 +63,7 @@
         if (modifiers_mask & Gdk.ModifierType.SHIFT_MASK) ^ OSX:
             self.handle_click(1)
         else:
-            self.handle_click(2)
+            self.handle_click(3)
 
     def handle_click(self, button, event_time=0):
         log("handle_click(%i, %i)", button, event_time)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/client/mixins/encodings.py 
new/xpra-4.0.4/xpra/client/mixins/encodings.py
--- old/xpra-4.0.3/xpra/client/mixins/encodings.py      2020-05-10 
19:00:53.000000000 +0200
+++ new/xpra-4.0.4/xpra/client/mixins/encodings.py      2020-09-27 
20:11:39.000000000 +0200
@@ -236,7 +236,7 @@
             and the actual encoding used ("rgb24" or "rgb32") depends on the 
window's bit depth.
             ("rgb32" if there is an alpha channel, and if the client supports 
it)
         """
-        cenc = self.get_core_encodings()
+        cenc = list(self.get_core_encodings())
         if ("rgb24" in cenc or "rgb32" in cenc) and "rgb" not in cenc:
             cenc.append("rgb")
         return [x for x in PREFERED_ENCODING_ORDER if x in cenc and x not in 
("rgb32", "rgb24")]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/client/mixins/window_manager.py 
new/xpra-4.0.4/xpra/client/mixins/window_manager.py
--- old/xpra-4.0.3/xpra/client/mixins/window_manager.py 2020-05-10 
19:00:53.000000000 +0200
+++ new/xpra-4.0.4/xpra/client/mixins/window_manager.py 2020-09-27 
20:11:39.000000000 +0200
@@ -1422,7 +1422,7 @@
         if not window:
             #window is gone
             def draw_cleanup():
-                if bytestostr(coding)==b"mmap":
+                if bytestostr(coding)=="mmap":
                     assert self.mmap_enabled
                     from xpra.net.mmap_pipe import int_from_buffer
                     #we need to ack the data to free the space!
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/codecs/argb/argb.pyx 
new/xpra-4.0.4/xpra/codecs/argb/argb.pyx
--- old/xpra-4.0.3/xpra/codecs/argb/argb.pyx    2020-05-10 19:00:54.000000000 
+0200
+++ new/xpra-4.0.4/xpra/codecs/argb/argb.pyx    2020-09-27 20:11:39.000000000 
+0200
@@ -276,6 +276,33 @@
     return bgra_to_rgba(buf)
 
 
+def bgra_to_rgbx(buf):
+    assert len(buf) % 4 == 0, "invalid buffer size: %s is not a multiple of 4" 
% len(buf)
+    # buf is a Python buffer object
+    cdef unsigned char * bgra_buf = NULL
+    cdef Py_ssize_t bgra_buf_len = 0
+    assert as_buffer(buf, <const void**> &bgra_buf, &bgra_buf_len)==0, "cannot 
convert %s to a readable buffer" % type(buf)
+    return bgradata_to_rgbx(bgra_buf, bgra_buf_len)
+
+cdef bgradata_to_rgbx(const unsigned char* bgra, const int bgra_len):
+    if bgra_len <= 0:
+        return None
+    assert bgra_len>0 and bgra_len % 4 == 0, "invalid buffer size: %s is not a 
multiple of 4" % bgra_len
+    #same number of bytes:
+    cdef MemBuf output_buf = getbuf(bgra_len)
+    cdef unsigned char* rgbx = <unsigned char*> output_buf.get_mem()
+    cdef int i = 0                      #@DuplicateSignature
+    while i < bgra_len:
+        rgbx[i]   = bgra[i+2]           #R
+        rgbx[i+1] = bgra[i+1]           #G
+        rgbx[i+2] = bgra[i]             #B
+        rgbx[i+3] = 0xff                #X
+        i += 4
+    return memoryview(output_buf)
+
+
+
+
 def premultiply_argb(buf):
     # b is a Python buffer object
     cdef unsigned int * argb = <unsigned int *> 0   #@DuplicateSignature
@@ -460,6 +487,11 @@
             image.set_pixel_format("RGB")
             image.set_rowstride(rs*3//4)
             return True
+        if "RGBX" in rgb_formats:
+            log("argb_swap: bgra_to_rgbx for %s on %s", pixel_format, 
type(pixels))
+            image.set_pixels(bgra_to_rgbx(pixels))
+            image.set_pixel_format("RGBX")
+            return True
     elif pixel_format in ("XRGB", "ARGB"):
         if supports_transparency and "RGBA" in rgb_formats:
             log("argb_swap: argb_to_rgba for %s on %s", pixel_format, 
type(pixels))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/xpra-4.0.3/xpra/codecs/csc_libyuv/colorspace_converter.pyx 
new/xpra-4.0.4/xpra/codecs/csc_libyuv/colorspace_converter.pyx
--- old/xpra-4.0.3/xpra/codecs/csc_libyuv/colorspace_converter.pyx      
2020-05-10 19:00:54.000000000 +0200
+++ new/xpra-4.0.4/xpra/codecs/csc_libyuv/colorspace_converter.pyx      
2020-09-27 20:11:39.000000000 +0200
@@ -182,6 +182,7 @@
         divs = get_subsampling_divs(self.dst_format)
         for i in range(3):
             xdiv, ydiv = divs[i]
+            #we don't scale, so the size is the src size:
             self.out_width[i]   = src_width // xdiv
             self.out_height[i]  = src_height // ydiv
             self.out_stride[i]  = roundup(self.out_width[i], 
MEMALIGN_ALIGNMENT)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/xpra-4.0.3/xpra/codecs/csc_swscale/colorspace_converter.pyx 
new/xpra-4.0.4/xpra/codecs/csc_swscale/colorspace_converter.pyx
--- old/xpra-4.0.3/xpra/codecs/csc_swscale/colorspace_converter.pyx     
2020-06-30 17:12:41.000000000 +0200
+++ new/xpra-4.0.4/xpra/codecs/csc_swscale/colorspace_converter.pyx     
2020-09-27 20:11:39.000000000 +0200
@@ -10,7 +10,6 @@
 import time
 
 from xpra.log import Logger
-from xpra.codecs.codec_checks import do_testcsc
 log = Logger("csc", "swscale")
 
 from xpra.util import envbool
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/codecs/nvenc/encoder.pyx 
new/xpra-4.0.4/xpra/codecs/nvenc/encoder.pyx
--- old/xpra-4.0.3/xpra/codecs/nvenc/encoder.pyx        2020-08-07 
11:17:40.000000000 +0200
+++ new/xpra-4.0.4/xpra/codecs/nvenc/encoder.pyx        2020-09-27 
20:11:39.000000000 +0200
@@ -18,7 +18,7 @@
 
 from xpra.os_util import WIN32, OSX, LINUX, strtobytes
 from xpra.make_thread import start_thread
-from xpra.util import AtomicInteger, engs, csv, pver, envint, envbool, 
first_time
+from xpra.util import AtomicInteger, engs, csv, pver, envint, envbool, 
first_time, typedict
 from xpra.codecs.cuda_common.cuda_context import (
     init_all_devices, get_devices, select_device, get_device_info, 
get_device_name,
     get_cuda_info, get_pycuda_info, device_info, reset_state,
@@ -1597,7 +1597,7 @@
         #use the environment as default if present:
         profile = os.environ.get("XPRA_NVENC_%s_PROFILE" % csc_mode, "")
         #now see if the client has requested a different value:
-        profile = options.strget("h264.%s.profile" % csc_mode, profile)
+        profile = typedict(options).strget("h264.%s.profile" % csc_mode, 
profile)
         return profile
 
 
@@ -1846,7 +1846,7 @@
         log("init_params(%s) using preset=%s", codecstr(codec), 
presetstr(preset))
         profiles = self.query_profiles(codec)
         if self.profile_name and profiles and self.profile_name not in 
profiles:
-            self.profile_name = profiles[0]
+            self.profile_name = tuple(profiles.keys())[0]
         profile_guidstr = profiles.get(self.profile_name)
         cdef GUID profile
         if profile_guidstr:
@@ -2254,6 +2254,7 @@
     cdef flushEncoder(self):
         cdef NV_ENC_PIC_PARAMS picParams
         cdef NVENCSTATUS r                          #@DuplicatedSignature
+        assert not self.closed, "encoder context is closed"
         assert self.context, "context is not initialized"
         memset(&picParams, 0, sizeof(NV_ENC_PIC_PARAMS))
         picParams.version = NV_ENC_PIC_PARAMS_VER
@@ -2265,6 +2266,7 @@
         raiseNVENC(r, "flushing encoder buffer")
 
     def compress_image(self, image, quality=-1, speed=-1, options={}, retry=0):
+        assert not self.closed, "encoder context is closed"
         self.cuda_context.push()
         try:
             try:
@@ -2288,7 +2290,6 @@
     cdef do_compress_image(self, image, options={}):
         cdef unsigned int stride, w, h
         assert self.context, "context is not initialized"
-        assert self.context!=NULL, "context is not initialized"
         w = image.get_width()
         h = image.get_height()
         gpu_buffer = image.get_gpu_buffer()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/net/file_transfer.py 
new/xpra-4.0.4/xpra/net/file_transfer.py
--- old/xpra-4.0.3/xpra/net/file_transfer.py    2020-06-30 17:12:41.000000000 
+0200
+++ new/xpra-4.0.4/xpra/net/file_transfer.py    2020-09-27 20:11:39.000000000 
+0200
@@ -262,10 +262,11 @@
 
     def _process_send_file_chunk(self, packet):
         chunk_id, chunk, file_data, has_more = packet[1:5]
+        chunk_id = bytestostr(chunk_id)
         filelog("_process_send_file_chunk%s", (chunk_id, chunk, "%i bytes" % 
len(file_data), has_more))
         chunk_state = self.receive_chunks_in_progress.get(chunk_id)
         if not chunk_state:
-            filelog.error("Error: cannot find the file transfer id '%s'", 
nonl(bytestostr(chunk_id)))
+            filelog.error("Error: cannot find the file transfer id '%s'", 
nonl(chunk_id))
             self.send("ack-file-chunk", chunk_id, False, "file transfer id not 
found", chunk)
             return
         fd = chunk_state[1]
@@ -317,9 +318,7 @@
         elapsed = monotonic_time()-start_time
         mimetype = bytestostr(mimetype)
         filelog("%i bytes received in %i chunks, took %ims", filesize, chunk, 
elapsed*1000)
-        t = start_thread(self.do_process_downloaded_file, "process-download", 
daemon=False,
-                         args=(filename, mimetype, printit, openit, filesize, 
options))
-        filelog("started process-download thread: %s", t)
+        self.process_downloaded_file(filename, mimetype, printit, openit, 
filesize, options)
 
     def accept_data(self, send_id, dtype, basefilename, printit, openit):
         #subclasses should check the flags,
@@ -343,6 +342,7 @@
 
     def _process_send_file(self, packet):
         #the remote end is sending us a file
+        start = monotonic_time()
         basefilename, mimetype, printit, openit, filesize, file_data, options 
= packet[1:8]
         send_id = ""
         if len(packet)>=9:
@@ -384,7 +384,6 @@
             return
         self.file_descriptors.add(fd)
         if chunk_id:
-            chunk_id = strtobytes(chunk_id)
             l = len(self.receive_chunks_in_progress)
             if l>=MAX_CONCURRENT_FILES:
                 self.send("ack-file-chunk", chunk_id, False, "too many file 
transfers in progress: %i" % l, 0)
@@ -422,7 +421,14 @@
             os.write(fd, file_data)
         finally:
             os.close(fd)
-        self.do_process_downloaded_file(filename, mimetype, printit, openit, 
filesize, options)
+        self.transfer_progress_update(False, send_id, monotonic_time()-start, 
filesize, filesize, None)
+        self.process_downloaded_file(filename, mimetype, printit, openit, 
filesize, options)
+
+
+    def process_downloaded_file(self, filename, mimetype, printit, openit, 
filesize, options):
+        t = start_thread(self.do_process_downloaded_file, "process-download", 
daemon=False,
+                         args=(filename, mimetype, printit, openit, filesize, 
options))
+        filelog("started process-download thread: %s", t)
 
     def do_process_downloaded_file(self, filename, mimetype, printit, openit, 
filesize, options):
         filelog("do_process_downloaded_file%s", (filename, mimetype, printit, 
openit, filesize, options))
@@ -803,12 +809,12 @@
         #send some more file data
         filelog("ack-file-chunk: %s", packet[1:])
         chunk_id, state, error_message, chunk = packet[1:5]
+        chunk_id = bytestostr(chunk_id)
         if not state:
             filelog.error("Error: remote end is cancelling the file transfer:")
             filelog.error(" %s", error_message)
             del self.send_chunks_in_progress[chunk_id]
             return
-        chunk_id = bytestostr(chunk_id)
         chunk_state = self.send_chunks_in_progress.get(chunk_id)
         if not chunk_state:
             filelog.error("Error: cannot find the file transfer id '%s'", 
nonl(chunk_id))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/net/websockets/common.py 
new/xpra-4.0.4/xpra/net/websockets/common.py
--- old/xpra-4.0.3/xpra/net/websockets/common.py        2020-05-10 
19:00:54.000000000 +0200
+++ new/xpra-4.0.4/xpra/net/websockets/common.py        2020-09-27 
20:11:39.000000000 +0200
@@ -6,6 +6,7 @@
 import uuid
 from hashlib import sha1
 from base64 import b64encode
+from requests.structures import CaseInsensitiveDict
 
 from xpra.os_util import strtobytes, bytestostr, monotonic_time
 from xpra.log import Logger
@@ -49,7 +50,7 @@
 
     now = monotonic_time()
     response = b""
-    while response.find(b"Sec-WebSocket-Protocol")<0 and 
monotonic_time()-now<MAX_READ_TIME:
+    while ("Sec-WebSocket-Protocol".lower() not in 
response.decode("utf-8").lower()) and monotonic_time()-now<MAX_READ_TIME:
         response += read(READ_CHUNK_SIZE)
     headers = parse_response_header(response)
     verify_response_headers(headers, key)
@@ -70,6 +71,7 @@
     log("verify_response_headers(%s)", headers)
     if not headers:
         raise Exception("no http headers found in response")
+    headers = CaseInsensitiveDict(headers)
     upgrade = headers.get(b"Upgrade", b"")
     if upgrade!=b"websocket":
         raise Exception("invalid http upgrade: '%s'" % upgrade)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/platform/win32/common.py 
new/xpra-4.0.4/xpra/platform/win32/common.py
--- old/xpra-4.0.3/xpra/platform/win32/common.py        2020-05-10 
19:00:55.000000000 +0200
+++ new/xpra-4.0.4/xpra/platform/win32/common.py        2020-09-27 
20:11:39.000000000 +0200
@@ -17,7 +17,7 @@
 from ctypes.wintypes import (
     HANDLE, LPSTR, LPCWSTR, UINT, INT, BOOL, WORD, HGDIOBJ,
     LONG, LPVOID, HBITMAP, LPCSTR, LPWSTR, HWINSTA,
-    HINSTANCE, HMENU, ULONG,
+    HINSTANCE, HMENU, ULONG, HHOOK,
     )
 #imported from this module but not used here:
 assert GetLastError
@@ -240,7 +240,7 @@
 UnregisterClassW.argtypes = [LPCWSTR, HINSTANCE]
 CreateWindowExA = user32.CreateWindowExA
 CreateWindowExA.restype = HWND
-#CreateWindowExA.argtypes = [DWORD, ATOM, LPCTSTR, DWORD, c_int, c_int, c_int, 
c_int, HWND, HMENU, HINSTANCE, LPVOID]
+CreateWindowExA.argtypes = [DWORD, ATOM, LPCWSTR, DWORD, c_int, c_int, c_int, 
c_int, HWND, HMENU, HINSTANCE, LPVOID]
 CreateWindowExW = user32.CreateWindowExW
 CreateWindowExW.restype = HWND
 CreateWindowExW.argtypes = [DWORD, ATOM, LPCWSTR, DWORD, c_int, c_int, c_int, 
c_int, HWND, HMENU, HINSTANCE, LPVOID]
@@ -248,7 +248,11 @@
 DestroyWindow.restype = BOOL
 DestroyWindow.argtypes = [HWND]
 DefWindowProcA = user32.DefWindowProcA
+DefWindowProcA.argtypes = [HWND, UINT, WPARAM, LPARAM]
+DefWindowProcA.restype = INT
 DefWindowProcW = user32.DefWindowProcW
+DefWindowProcW.argtypes = [HWND, UINT, WPARAM, LPARAM]
+DefWindowProcW.restype = INT
 MessageBoxA = user32.MessageBoxA
 MessageBoxA.restype = INT
 MessageBoxA.argtypes = [HWND, LPCTSTR, LPCTSTR, UINT]
@@ -287,6 +291,8 @@
 UnhookWindowsHookEx = user32.UnhookWindowsHookEx
 CallNextHookEx = user32.CallNextHookEx
 SetWindowsHookExA = user32.SetWindowsHookExA
+SetWindowsHookExA.restype = HHOOK
+SetWindowsHookExA.argtypes = [INT, HANDLE, HINSTANCE, DWORD]
 GetMessageA = user32.GetMessageA
 TranslateMessage = user32.TranslateMessage
 DispatchMessageA = user32.DispatchMessageA
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/platform/win32/win32_NotifyIcon.py 
new/xpra-4.0.4/xpra/platform/win32/win32_NotifyIcon.py
--- old/xpra-4.0.3/xpra/platform/win32/win32_NotifyIcon.py      2020-05-10 
19:00:55.000000000 +0200
+++ new/xpra-4.0.4/xpra/platform/win32/win32_NotifyIcon.py      2020-08-11 
14:52:59.000000000 +0200
@@ -256,9 +256,9 @@
         self.hwnd = CreateWindowExA(0, NIclassAtom, window_name, style,
             win32con.CW_USEDEFAULT, win32con.CW_USEDEFAULT, 0, 0, \
             0, 0, NIwc.hInstance, None)
-        if self.hwnd==0:
+        log("create_window() hwnd=%#x", self.hwnd or 0)
+        if not self.hwnd:
             raise ctypes.WinError(ctypes.get_last_error())
-        log("create_window() hwnd=%#x", self.hwnd)
         UpdateWindow(self.hwnd)
         #register callbacks:
         win32NotifyIcon.instances[self.hwnd] = self
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/platform/win32/win32_printing.py 
new/xpra-4.0.4/xpra/platform/win32/win32_printing.py
--- old/xpra-4.0.3/xpra/platform/win32/win32_printing.py        2020-05-10 
19:00:55.000000000 +0200
+++ new/xpra-4.0.4/xpra/platform/win32/win32_printing.py        2020-08-11 
14:52:59.000000000 +0200
@@ -134,7 +134,7 @@
                log("GetPrinter: PRINTER_INFO_1 size=%#x", size.value)
                self.info1 = msvcrt.malloc(size.value)
                if not GetPrinterA(self.handle, 1, self.info1, size.value, 
pointer(size)):
-                       raise Exception("GetPrinterA PRINTER_INFO_1 failed for 
'%s'", self.printer_name)
+                       raise Exception("GetPrinterA PRINTER_INFO_1 failed for 
'%s'" % self.printer_name)
                info = cast(self.info1, POINTER(PRINTER_INFO_1))
                log(" flags=%#x" % info[0].Flags)
                log(" name=%#s" % info[0].pName)
@@ -144,7 +144,7 @@
                size = DWORD(0)
                GetPrinterA(self.handle, 2, None, 0, pointer(size))
                if size.value==0:
-                       raise Exception("GetPrinterA PRINTER_INFO_2 failed for 
'%s'", self.printer_name)
+                       raise Exception("GetPrinterA PRINTER_INFO_2 failed for 
'%s'" % self.printer_name)
                log("GetPrinter: PRINTER_INFO_2 size=%#x", size.value)
                self.info2 = msvcrt.malloc(size.value)
                if GetPrinterA(self.handle, 2, self.info2, size.value, 
pointer(size)):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/platform/xposix/gui.py 
new/xpra-4.0.4/xpra/platform/xposix/gui.py
--- old/xpra-4.0.3/xpra/platform/xposix/gui.py  2020-08-08 08:50:20.000000000 
+0200
+++ new/xpra-4.0.4/xpra/platform/xposix/gui.py  2020-09-27 20:11:39.000000000 
+0200
@@ -476,7 +476,9 @@
         SubstructureNotifyMask = constants["SubstructureNotifyMask"]
         SubstructureRedirectMask = constants["SubstructureRedirectMask"]
         event_mask = SubstructureNotifyMask | SubstructureRedirectMask
-        X11Window.sendClientMessage(root_xid, xid, False, event_mask, 
message_type, *values)
+        from xpra.gtk_common.error import xsync
+        with xsync:
+            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)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/platform/xposix/xdg_helper.py 
new/xpra-4.0.4/xpra/platform/xposix/xdg_helper.py
--- old/xpra-4.0.3/xpra/platform/xposix/xdg_helper.py   2020-06-05 
11:40:11.000000000 +0200
+++ new/xpra-4.0.4/xpra/platform/xposix/xdg_helper.py   2020-09-27 
20:11:39.000000000 +0200
@@ -263,7 +263,7 @@
                 try:
                     menu = parse()
                     break
-                except (ParsingError, AttributeError) as e:
+                except Exception as e:
                     log("do_load_xdg_menu_data()", exc_info=True)
                     error = e
                     menu = None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/scripts/config.py 
new/xpra-4.0.4/xpra/scripts/config.py
--- old/xpra-4.0.3/xpra/scripts/config.py       2020-05-10 19:00:55.000000000 
+0200
+++ new/xpra-4.0.4/xpra/scripts/config.py       2020-09-27 20:11:39.000000000 
+0200
@@ -11,7 +11,7 @@
 from xpra.os_util import (
     WIN32, OSX, POSIX,
     osexpand, getuid, getgid, get_username_for_uid,
-    is_Debian, is_arm,
+    is_Debian, is_Ubuntu, is_arm,
     )
 
 def warn(msg):
@@ -133,6 +133,10 @@
     if is_arm():
         #arm struggles to launch Xdummy, so use Xvfb:
         return get_Xvfb_command()
+    if is_Ubuntu() or is_Debian():
+        #These distros do weird things and this can cause the real X11 server 
to crash
+        #see ticket #2834
+        return get_Xvfb_command()
 
     xorg_bin = get_xorg_bin()
     def Xorg_suid_check():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/scripts/main.py 
new/xpra-4.0.4/xpra/scripts/main.py
--- old/xpra-4.0.3/xpra/scripts/main.py 2020-08-07 11:17:40.000000000 +0200
+++ new/xpra-4.0.4/xpra/scripts/main.py 2020-09-27 20:11:39.000000000 +0200
@@ -54,6 +54,7 @@
 CLIPBOARD_CLASS = os.environ.get("XPRA_CLIPBOARD_CLASS")
 WAIT_SERVER_TIMEOUT = envint("WAIT_SERVER_TIMEOUT", 90)
 CONNECT_TIMEOUT = envint("XPRA_CONNECT_TIMEOUT", 20)
+OPENGL_PROBE_TIMEOUT = envint("XPRA_OPENGL_PROBE_TIMEOUT", 5)
 SYSTEMD_RUN = envbool("XPRA_SYSTEMD_RUN", True)
 LOG_SYSTEMD_WRAP = envbool("XPRA_LOG_SYSTEMD_WRAP", True)
 VERIFY_X11_SOCKET_TIMEOUT = envint("XPRA_VERIFY_X11_SOCKET_TIMEOUT", 1)
@@ -1776,7 +1777,7 @@
         log.warn("Warning: failed to execute OpenGL probe command")
         log.warn(" %s", e)
         return "probe-failed:%s" % e
-    r = pollwait(proc)
+    r = pollwait(proc, OPENGL_PROBE_TIMEOUT)
     log("OpenGL probe command returned %s for command=%s", r, cmd)
     end = monotonic_time()
     log("probe took %ims", 1000*(end-start))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/server/dbus/dbus_server.py 
new/xpra-4.0.4/xpra/server/dbus/dbus_server.py
--- old/xpra-4.0.3/xpra/server/dbus/dbus_server.py      2020-05-10 
19:00:55.000000000 +0200
+++ new/xpra-4.0.4/xpra/server/dbus/dbus_server.py      2020-09-27 
20:11:39.000000000 +0200
@@ -251,7 +251,7 @@
     @dbus.service.method(INTERFACE, in_signature='is')
     def SetWindowEncoding(self, wid, encoding):
         wid, encoding = ni(wid), ns(encoding)
-        self.log(".SetWindowEncoding(%i, %i)", wid, encoding)
+        self.log(".SetWindowEncoding(%i, %s)", wid, encoding)
         self.server.control_command_encoding(encoding, wid)
 
     @dbus.service.method(INTERFACE, in_signature='i')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/xpra-4.0.3/xpra/server/shadow/gtk_shadow_server_base.py 
new/xpra-4.0.4/xpra/server/shadow/gtk_shadow_server_base.py
--- old/xpra-4.0.3/xpra/server/shadow/gtk_shadow_server_base.py 2020-05-10 
19:00:56.000000000 +0200
+++ new/xpra-4.0.4/xpra/server/shadow/gtk_shadow_server_base.py 2020-09-27 
20:11:39.000000000 +0200
@@ -72,7 +72,8 @@
 
 
     def make_hello(self, source):
-        caps = super().make_hello(source)
+        caps = ShadowServerBase.make_hello(self, source)
+        caps.update(GTKServerBase.make_hello(self, source))
         if source.wants_features:
             caps["screen_sizes"] = get_screen_sizes()
         return caps
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/server/shadow/shadow_dbus_server.py 
new/xpra-4.0.4/xpra/server/shadow/shadow_dbus_server.py
--- old/xpra-4.0.3/xpra/server/shadow/shadow_dbus_server.py     2020-05-10 
19:00:56.000000000 +0200
+++ new/xpra-4.0.4/xpra/server/shadow/shadow_dbus_server.py     2020-09-27 
20:11:39.000000000 +0200
@@ -1,12 +1,12 @@
 #!/usr/bin/env python
 # This file is part of Xpra.
-# Copyright (C) 2015-2019 Antoine Martin <[email protected]>
+# Copyright (C) 2015-2020 Antoine Martin <[email protected]>
 # 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 dbus.service
 
-from xpra.server.dbus.dbus_server import DBUS_Server, INTERFACE
+from xpra.server.dbus.dbus_server import DBUS_Server, INTERFACE, ni
 from xpra.log import Logger
 log = Logger("dbus", "server")
 
@@ -15,4 +15,5 @@
 
     @dbus.service.method(INTERFACE, in_signature='i')
     def SetRefreshDelay(self, milliseconds):
-        return self.server.set_refresh_delay(milliseconds)
+        log("SetRefreshDelay(%i)", milliseconds)
+        return self.server.set_refresh_delay(ni(milliseconds))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/server/source/windows_mixin.py 
new/xpra-4.0.4/xpra/server/source/windows_mixin.py
--- old/xpra-4.0.3/xpra/server/source/windows_mixin.py  2020-05-10 
19:00:56.000000000 +0200
+++ new/xpra-4.0.4/xpra/server/source/windows_mixin.py  2020-09-27 
20:11:39.000000000 +0200
@@ -138,8 +138,8 @@
         self.window_frame_sizes = typedict(c.dictget("window.frame_sizes", {}))
         self.window_min_size = c.inttupleget("window.min-size", (0, 0))
         self.window_max_size = c.inttupleget("window.max-size", (0, 0))
-        log("cursors=%s (encodings=%s), bell=%s, notifications=%s",
-            self.send_cursors, self.cursor_encodings, self.send_bell, 
self.send_notifications)
+        log("cursors=%s (encodings=%s)",
+            self.send_cursors, self.cursor_encodings)
         log("client uuid %s", self.uuid)
 
         #window filters:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/server/window/window_source.py 
new/xpra-4.0.4/xpra/server/window/window_source.py
--- old/xpra-4.0.3/xpra/server/window/window_source.py  2020-07-09 
18:46:42.000000000 +0200
+++ new/xpra-4.0.4/xpra/server/window/window_source.py  2020-09-27 
20:11:39.000000000 +0200
@@ -1314,9 +1314,16 @@
 
     def do_damage(self, ww, wh, x, y, w, h, options):
         now = monotonic_time()
-        if self.refresh_timer and (w*h>=ww*wh//4 or w*h>=512*1024):
-            #large enough screen update: cancel refresh timer
-            self.cancel_refresh_timer()
+        if self.refresh_timer and options.get("quality", 
self._current_quality)<self.refresh_quality:
+            rr = tuple(self.refresh_regions)
+            if rr:
+                #does this screen update intersect with
+                #the areas that are due to be refreshed?
+                overlap = sum(rect.width*rect.height for rect in rr)
+                if overlap>0:
+                    pct = int(min(100, 100*overlap//(ww*wh)) * 
(1+self.global_statistics.congestion_value))
+                    sched_delay = max(self.min_auto_refresh_delay, 
int(self.base_auto_refresh_delay * pct // 100))
+                    self.refresh_target_time = max(self.refresh_target_time, 
now + sched_delay/1000.0)
 
         delayed = self._damage_delayed
         if delayed:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/server/window/window_video_source.py 
new/xpra-4.0.4/xpra/server/window/window_video_source.py
--- old/xpra-4.0.3/xpra/server/window/window_video_source.py    2020-08-07 
11:17:40.000000000 +0200
+++ new/xpra-4.0.4/xpra/server/window/window_video_source.py    2020-09-27 
20:11:39.000000000 +0200
@@ -578,6 +578,11 @@
             damage_options["novideo"] = True
         super().full_quality_refresh(damage_options)
 
+    def timer_full_refresh(self):
+        self.free_scroll_data()
+        self.last_scroll_time = 0
+        super().timer_full_refresh()
+
 
     def quality_changed(self, window, *args):
         super().quality_changed(window, args)
@@ -875,7 +880,8 @@
         # * we want av-sync
         # * the video encoder needs a thread safe image
         #   (the xshm backing may change from underneath us if we don't freeze 
it)
-        must_freeze = av_delay>0 or ((coding in self.video_encodings or 
coding=="auto") and not image.is_thread_safe())
+        video_mode = coding in self.video_encodings or coding=="auto"
+        must_freeze = av_delay>0 or (video_mode and not image.is_thread_safe())
         log("process_damage_region: av_delay=%s, must_freeze=%s, size=%s, 
encoding=%s",
             av_delay, must_freeze, (w, h), coding)
         if must_freeze:
@@ -896,7 +902,7 @@
                 self.encode_queue.append(item)
                 self.schedule_encode_from_queue(av_delay)
         #now figure out if we need to send edges separately:
-        if coding in self.video_encodings and self.edge_encoding and not 
VIDEO_SKIP_EDGE:
+        if video_mode and self.edge_encoding and not VIDEO_SKIP_EDGE:
             dw = w - (w & self.width_mask)
             dh = h - (h & self.height_mask)
             if dw>0 and h>0:
@@ -1913,6 +1919,7 @@
                 assert encoding, "no nonvideo encoding found for %ix%i screen 
update" % (w, sh)
                 encode_fn = self._encoders[encoding]
                 ret = encode_fn(encoding, sub, options)
+                self.free_image_wrapper(sub)
                 if not ret:
                     #cancelled?
                     return None
@@ -1943,6 +1950,7 @@
         assert flush==0
         self.last_scroll_time = monotonic_time()
         scrolllog("scroll encoding total time: %ims", 
(self.last_scroll_time-start)*1000)
+        self.free_image_wrapper(image)
 
     def do_schedule_auto_refresh(self, encoding, data, region, client_options, 
options):
         #for scroll encoding, data is a LargeStructure wrapper:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/src_info.py 
new/xpra-4.0.4/xpra/src_info.py
--- old/xpra-4.0.3/xpra/src_info.py     2020-08-08 08:50:24.000000000 +0200
+++ new/xpra-4.0.4/xpra/src_info.py     2020-09-27 20:11:46.000000000 +0200
@@ -1,2 +1,2 @@
 LOCAL_MODIFICATIONS=0
-REVISION=27083
+REVISION=27557
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/x11/bindings/ximage.pyx 
new/xpra-4.0.4/xpra/x11/bindings/ximage.pyx
--- old/xpra-4.0.3/xpra/x11/bindings/ximage.pyx 2020-05-10 19:00:56.000000000 
+0200
+++ new/xpra-4.0.4/xpra/x11/bindings/ximage.pyx 2020-09-27 20:11:39.000000000 
+0200
@@ -459,6 +459,10 @@
         if posix_memalign(<void **> &self.pixels, 64, buf_len):
             raise Exception("posix_memalign failed!")
         assert self.pixels!=NULL
+        #from now on, we own the buffer,
+        #so we're no longer a direct sub-image,
+        #and we must free the buffer later:
+        self.sub = False
         if self.image==NULL:
             self.thread_safe = 1
             #we can now mark this object as thread safe
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/x11/gtk_x11/selection.py 
new/xpra-4.0.4/xpra/x11/gtk_x11/selection.py
--- old/xpra-4.0.3/xpra/x11/gtk_x11/selection.py        2020-05-10 
19:00:56.000000000 +0200
+++ new/xpra-4.0.4/xpra/x11/gtk_x11/selection.py        2020-08-11 
14:52:59.000000000 +0200
@@ -162,10 +162,10 @@
             #log("_owner_change(..) not our selection: %s vs %s", 
event.selection, self.atom)
             return
         if event.owner:
-               owner = event.owner.get_xid()
-               if owner==self._xwindow:
-                   log("_owner_change(..) we still own %s", event.selection)
-                   return
+            owner = event.owner.get_xid()
+            if owner==self._xwindow:
+                log("_owner_change(..) we still own %s", event.selection)
+                return
         if self._xwindow:
             self._xwindow = None
             self.emit("selection-lost")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/x11/models/base.py 
new/xpra-4.0.4/xpra/x11/models/base.py
--- old/xpra-4.0.3/xpra/x11/models/base.py      2020-05-17 18:12:15.000000000 
+0200
+++ new/xpra-4.0.4/xpra/x11/models/base.py      2020-09-27 20:11:39.000000000 
+0200
@@ -625,7 +625,10 @@
             log("_NET_WM_MOVERESIZE: %s", event)
             self.emit("initiate-moveresize", event)
             return True
-        if event.message_type=="_NET_ACTIVE_WINDOW" and event.data[0] in (0, 
1):
+        if event.message_type=="_NET_ACTIVE_WINDOW":
+            #to filter based on the source indication:
+            #ACTIVE_WINDOW_SOURCE = tuple(int(x) for x in 
os.environ.get("XPRA_ACTIVE_WINDOW_SOURCE", "0,1").split(","))
+            #if event.data[0] in ACTIVE_WINDOW_SOURCE:
             log("_NET_ACTIVE_WINDOW: %s", event)
             self.set_active()
             self.emit("raised", event)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/x11/server.py 
new/xpra-4.0.4/xpra/x11/server.py
--- old/xpra-4.0.3/xpra/x11/server.py   2020-08-07 11:17:40.000000000 +0200
+++ new/xpra-4.0.4/xpra/x11/server.py   2020-09-27 20:11:39.000000000 +0200
@@ -9,11 +9,11 @@
 import os
 import signal
 import math
-from collections import deque, namedtuple
-from gi.repository import GObject, Gtk, Gdk
+from collections import deque
+from gi.repository import GObject, Gtk, Gdk, GdkX11
 
 from xpra.version_util import XPRA_VERSION
-from xpra.util import updict, rindex, envbool, envint, typedict, 
WORKSPACE_NAMES
+from xpra.util import updict, rindex, envbool, envint, typedict, AdHocStruct, 
WORKSPACE_NAMES
 from xpra.os_util import memoryview_to_bytes, strtobytes, bytestostr, 
monotonic_time
 from xpra.common import CLOBBER_UPGRADE, MAX_WINDOW_SIZE
 from xpra.server import server_features
@@ -244,10 +244,12 @@
                 with xsync:
                     self.root_overlay = 
X11Window.XCompositeGetOverlayWindow(xid)
                     if self.root_overlay:
-                        #ugly: API expects a window object with a ".xid"
-                        X11WindowModel = namedtuple("X11WindowModel", "xid")
-                        root_overlay = X11WindowModel(xid=self.root_overlay)
-                        prop_set(root_overlay, "WM_TITLE", "latin1", 
"RootOverlay")
+                        #ugly: API expects a window object with a ".get_xid()" 
method
+                        window = AdHocStruct()
+                        def get_xid():
+                            return self.root_overlay
+                        window.get_xid = root.get_xid
+                        prop_set(window, "WM_TITLE", "latin1", "RootOverlay")
                         X11Window.AllowInputPassthrough(self.root_overlay)
             except Exception as e:
                 log("XCompositeGetOverlayWindow(%#x)", xid, exc_info=True)
@@ -1160,8 +1162,8 @@
     #
 
     def update_root_overlay(self, window, x, y, image):
-        overlaywin = Gdk.window_foreign_new(self.root_overlay)
-        gc = overlaywin.new_gc()
+        display = Gdk.Display.get_default()
+        overlaywin = GdkX11.X11Window.foreign_new_for_display(display, 
self.root_overlay)
         wx, wy = window.get_property("geometry")[:2]
         #FIXME: we should paint the root overlay directly
         # either using XCopyArea or XShmPutImage,
@@ -1170,29 +1172,39 @@
         height = image.get_height()
         rowstride = image.get_rowstride()
         img_data = image.get_pixels()
-        if image.get_pixel_format().startswith("BGR"):
-            try:
-                from xpra.codecs.argb.argb import unpremultiply_argb, 
bgra_to_rgba  #@UnresolvedImport
-                if image.get_pixel_format()=="BGRA":
-                    img_data = unpremultiply_argb(img_data)
-                img_data = bgra_to_rgba(img_data)
-            except:
-                pass
+        rgb_format = image.get_pixel_format()
+        from xpra.codecs.argb.argb import ( #@UnresolvedImport
+            unpremultiply_argb, bgra_to_rgba, bgra_to_rgbx, r210_to_rgbx, 
bgr565_to_rgbx  #@UnresolvedImport
+            )
+        from cairo import OPERATOR_OVER, OPERATOR_SOURCE  #pylint: 
disable=no-name-in-module
+        log("update_root_overlay%s rgb_format=%s, img_data=%i (%s)",
+                 (window, x, y, image), rgb_format, len(img_data), 
type(img_data))
+        operator = OPERATOR_SOURCE
+        if rgb_format=="BGRA":
+            img_data = unpremultiply_argb(img_data)
+            img_data = bgra_to_rgba(img_data)
+            operator = OPERATOR_OVER
+        elif rgb_format=="BGRX":
+            img_data = bgra_to_rgbx(img_data)
+        elif rgb_format=="r210":
+            #lossy...
+            img_data = r210_to_rgbx(img_data, width, height, rowstride, 
width*4)
+            rowstride = width*4
+        elif rgb_format=="BGR565":
+            img_data = bgr565_to_rgbx(img_data)
+            rowstride *= 2
+        else:
+            raise Exception("xync-xvfb root overlay paint code does not handle 
%s pixel format" % image.get_pixel_format())
         img_data = memoryview_to_bytes(img_data)
-        has_alpha = image.get_pixel_format().find("A")>=0
         log("update_root_overlay%s painting rectangle %s", (window, x, y, 
image), (wx+x, wy+y, width, height))
-        if has_alpha:
-            import cairo
-            pixbuf = get_pixbuf_from_data(img_data, True, width, height, 
rowstride)
-            cr = overlaywin.cairo_create()
-            cr.new_path()
-            cr.rectangle(wx+x, wy+y, width, height)
-            cr.clip()
-            cr.set_source_pixbuf(pixbuf, wx+x, wy+y)
-            cr.set_operator(cairo.OPERATOR_OVER)
-            cr.paint()
-        else:
-            overlaywin.draw_rgb_32_image(gc, wx+x, wy+y, width, height, 
Gdk.RGB_DITHER_NONE, img_data, rowstride)
+        pixbuf = get_pixbuf_from_data(img_data, True, width, height, rowstride)
+        cr = overlaywin.cairo_create()
+        cr.new_path()
+        cr.rectangle(wx+x, wy+y, width, height)
+        cr.clip()
+        Gdk.cairo_set_source_pixbuf(cr, pixbuf, wx+x, wy+y)
+        cr.set_operator(operator)
+        cr.paint()
         image.free()
 
     def repaint_root_overlay(self):
@@ -1213,7 +1225,8 @@
     def do_repaint_root_overlay(self):
         self.repaint_root_overlay_timer = None
         root_width, root_height = self.get_root_window_size()
-        overlaywin = Gdk.window_foreign_new(self.root_overlay)
+        display = Gdk.Display.get_default()
+        overlaywin = GdkX11.X11Window.foreign_new_for_display(display, 
self.root_overlay)
         log("overlaywin: %s", overlaywin.get_geometry())
         cr = overlaywin.cairo_create()
         def fill_grey_rect(shade, x, y, w, h):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xpra-4.0.3/xpra/x11/server_keyboard_config.py 
new/xpra-4.0.4/xpra/x11/server_keyboard_config.py
--- old/xpra-4.0.3/xpra/x11/server_keyboard_config.py   2020-06-05 
11:40:13.000000000 +0200
+++ new/xpra-4.0.4/xpra/x11/server_keyboard_config.py   2020-09-27 
20:11:39.000000000 +0200
@@ -499,9 +499,11 @@
                     if self.xkbmap_raw:
                         break
                     level0 = levels[0]
-                    if len(keysyms)>level0 and keysyms[level0]=="":
+                    uq_keysyms = set(keysyms)
+                    if len(uq_keysyms)<=1 or (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 "")
+                        #same if there's only one actual keysym for this 
keycode
                         kmlog("not toggling any modifiers state for 
keysyms=%s", keysyms)
                         break
                     def toggle_modifier(mod):



Reply via email to