xpra icon
Bug tracker and wiki

Ticket #90: cairo-repaint.patch

File cairo-repaint.patch, 12.6 KB (added by Antoine Martin, 5 years ago)

getting cairo to paint rgb pixels with python3 / gi is a nightmare, this almost does it

  • xpra/client/gtk2/client_window.py

     
    4444            #plain GTK2 window needs to use CSC modules to paint video
    4545            #so calculate the server CSC modes the server is allowed to use
    4646            #based on the client CSC modes we can convert to RGB(A):
    47             target_rgb_modes = ["RGB", "RGBX"]
    48             if HAS_ALPHA:
    49                 target_rgb_modes.append("RGBA")
     47            target_rgb_modes = BACKING_CLASS.RGB_MODES
     48            if not HAS_ALPHA:
     49                target_rgb_modes = [x for x in target_rgb_modes if x.find("A")<0]
    5050            ClientWindow.full_csc_modes = getVideoHelper().get_server_full_csc_modes_for_rgb(*target_rgb_modes)
    5151            log("full csc modes (%s)=%s", target_rgb_modes, ClientWindow.full_csc_modes)
    5252        return ClientWindow.full_csc_modes
  • xpra/client/gtk2/gtk2_window_base.py

     
    8181    WINDOW_STATE_MAXIMIZED  = gdk.WINDOW_STATE_MAXIMIZED
    8282    WINDOW_STATE_ICONIFIED  = gdk.WINDOW_STATE_ICONIFIED
    8383
    84     #must be overriden by subclasses
    85     BACKING_CLASS = None
    8684
    8785    def init_window(self, metadata):
    8886        if self._override_redirect:
  • xpra/client/gtk2/pixmap_backing.py

     
    1919"""
    2020class PixmapBacking(GTK2WindowBacking):
    2121
     22    RGB_MODES = ["RGB", "RGBX", "RGBA"]
     23
    2224    def __repr__(self):
    2325        return "PixmapBacking(%s)" % self._backing
    2426
  • xpra/client/gtk_base/cairo_backing.py

     
    44# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
    55# later version. See the file COPYING for details.
    66
    7 import cairo
    8 
    9 from xpra.gtk_common.gobject_compat import import_gdk, import_gobject, import_pixbufloader
     7from xpra.gtk_common.gobject_compat import import_gdk, import_gobject, import_pixbufloader, import_cairo, is_gtk3
    108gdk = import_gdk()
    119gobject = import_gobject()
     10cairo = import_cairo()
    1211PixbufLoader = import_pixbufloader()
    1312
    1413from xpra.os_util import BytesIOClass
     
    1514from xpra.gtk_common.gtk_util import pixbuf_new_from_data, cairo_set_source_pixbuf, gdk_cairo_context, COLORSPACE_RGB
    1615from xpra.client.gtk_base.gtk_window_backing_base import GTKWindowBacking
    1716from xpra.client.window_backing_base import fire_paint_callbacks
     17from xpra.codecs.loader import get_codec
    1818from xpra.os_util import builtins
    1919_memoryview = builtins.__dict__.get("memoryview")
    2020
     
    3434"""
    3535class CairoBacking(GTKWindowBacking):
    3636
     37    RGB_MODES = ["ARGB", "XRGB", "RGBA", "RGBX", "RGB"]
     38
    3739    def __init__(self, wid, w, h, has_alpha):
    3840        GTKWindowBacking.__init__(self, wid)
    3941
     
    133135
    134136    def _do_paint_rgb24(self, img_data, x, y, width, height, rowstride, options, callbacks):
    135137        log("_do_paint_rgb24")
    136         return self._do_paint_rgb(False, img_data, x, y, width, height, rowstride, options, callbacks)
     138        self._do_paint_rgb(cairo.FORMAT_RGB24, False, img_data, x, y, width, height, rowstride, options, callbacks)
     139        return False
    137140
    138141    def _do_paint_rgb32(self, img_data, x, y, width, height, rowstride, options, callbacks):
    139142        log("_do_paint_rgb32")
    140         return self._do_paint_rgb(True, img_data, x, y, width, height, rowstride, options, callbacks)
     143        self._do_paint_rgb(cairo.FORMAT_ARGB32, True, img_data, x, y, width, height, rowstride, options, callbacks)
     144        return False
    141145
    142     def _do_paint_rgb(self, has_alpha, img_data, x, y, width, height, rowstride, options, callbacks):
     146    def _do_paint_rgb(self, cairo_format, has_alpha, img_data, x, y, width, height, rowstride, options, callbacks):
    143147        """ must be called from UI thread """
    144148        log("cairo._do_paint_rgb(%s, %s bytes,%s,%s,%s,%s,%s,%s,%s)", has_alpha, len(img_data), x, y, width, height, rowstride, options, callbacks)
    145149        rgb_format = options.strget("rgb_format", "RGB")
    146         if rgb_format in ("RGBA", ):
    147             img_data = self.unpremultiply(img_data)
    148150        if _memoryview and isinstance(img_data, _memoryview):
    149151            #Pixbuf cannot use the memoryview directly:
    150152            img_data = img_data.tobytes()
    151         pixbuf = pixbuf_new_from_data(img_data, COLORSPACE_RGB, has_alpha, 8, width, height, rowstride)
    152         return self.cairo_paint_pixbuf(pixbuf, x, y)
     153        success = False
     154        try:
     155            try:
     156                if rgb_format in ("ARGB", "XRGB"):
     157                    #the pixel format is also what cairo expects
     158                    #maybe also check that the stride is acceptable for cairo?
     159                    #cairo_stride = cairo.ImageSurface.format_stride_for_width(cairo_format, width)
     160                    #log("cairo_stride=%s, stride=%s", cairo_stride, rowstride)
     161                    img_surface = cairo.ImageSurface.create_for_data(img_data, cairo_format, width, height, rowstride)
     162                    success = self.cairo_paint_surface(img_surface, x, y)
     163                elif not is_gtk3() and rgb_format in ("RGBA", "RGBX"):
     164                    #with GTK2, we can use a pixbuf from RGB(A) pixels
     165                    #
     166                    #This code does not work with GTK3! ARGH!
     167                    # http://cairographics.org/documentation/pycairo/3/reference/surfaces.html#cairo.ImageSurface.create_for_data
     168                    # "Not yet available in Python 3"
     169                    #It is available in the cffi cairo bindings, which can be used instead of pycairo
     170                    # but then we can't use it from the draw callbacks:
     171                    # https://mail.gnome.org/archives/python-hackers-list/2011-December/msg00004.html
     172                    # "PyGObject just lacks the glue code that allows it to pass the statically-wrapped
     173                    # cairo.Pattern to introspected methods"
     174                    if rgb_format=="RGBA":
     175                        #we have to unpremultiply for pixbuf!
     176                        img_data = self.unpremultiply(img_data)
     177                    pixbuf = pixbuf_new_from_data(img_data, COLORSPACE_RGB, has_alpha, 8, width, height, rowstride)
     178                    success = self.cairo_paint_pixbuf(pixbuf, x, y)
     179                else:
     180                    #PIL fallback: use it to convert to RGB(A)
     181                    PIL = get_codec("PIL")
     182                    if has_alpha:
     183                        oformat = "RGBA"
     184                    else:
     185                        oformat = "RGBX"
     186                    img = PIL.Image.frombuffer(oformat, (width,height), img_data, "raw", rgb_format, 0, 1)
     187                    img_data = bytearray(img.tostring('raw', oformat, 0, 1))
     188                    pixbuf = pixbuf_new_from_data(img_data, COLORSPACE_RGB, True, 8, width, height, width*4)
     189                    success = self.cairo_paint_pixbuf(pixbuf, x, y)
     190            except:
     191                log.warn("cairo paint error", exc_info=True)
     192                success = False
     193        finally:
     194            fire_paint_callbacks(callbacks, success)
    153195
     196
    154197    def cairo_draw(self, context):
    155198        log("cairo_draw(%s) backing=%s", context, self._backing)
    156199        if self._backing is None:
  • xpra/client/gtk_base/gtk_client_window_base.py

     
    1212keylog = Logger("window", "keyboard")
    1313
    1414from xpra.util import AdHocStruct, nn
    15 from xpra.gtk_common.gobject_compat import import_gtk, import_gdk
     15from xpra.gtk_common.gobject_compat import import_gtk, import_gdk, import_cairo
    1616from xpra.client.client_window_base import ClientWindowBase
    1717gtk = import_gtk()
    1818gdk = import_gdk()
     19cairo = import_cairo()
    1920
    2021import os
    21 import cairo
    2222import time
    2323import math
    2424
  • xpra/client/gtk_base/gtk_window_backing_base.py

     
    55# later version. See the file COPYING for details.
    66
    77#pygtk3 vs pygtk2 (sigh)
    8 from xpra.gtk_common.gobject_compat import import_gobject
     8from xpra.gtk_common.gobject_compat import import_gobject, import_cairo
    99gobject = import_gobject()
     10cairo = import_cairo()
    1011
    1112from xpra.client.window_backing_base import WindowBackingBase
    1213from xpra.log import Logger
     
    2930    def cairo_draw_from_drawable(self, context, drawable):
    3031        if drawable is None:
    3132            return
    32         import cairo
    3333        try:
    3434            context.set_source_pixmap(drawable, 0, 0)
    3535            context.set_operator(cairo.OPERATOR_SOURCE)
  • xpra/client/window_backing_base.py

     
    395395
    396396    def draw_region(self, x, y, width, height, coding, img_data, rowstride, options, callbacks):
    397397        """ dispatches the paint to one of the paint_XXXX methods """
    398         log("draw_region(%s, %s, %s, %s, %s, %s bytes, %s, %s, %s)", x, y, width, height, coding, len(img_data), rowstride, options, callbacks)
     398        log.info("draw_region(%s, %s, %s, %s, %s, %s bytes, %s, %s, %s)", x, y, width, height, coding, len(img_data), rowstride, options, callbacks)
    399399        coding = bytestostr(coding)
    400400        if coding == "mmap":
    401401            self.idle_add(self.paint_mmap, img_data, x, y, width, height, rowstride, options, callbacks)
  • xpra/gtk_common/gobject_compat.py

     
    9999    return Pango
    100100def import_pango():
    101101    return  _try_import(import_pango3, import_pango2)
     102
     103def import_cairo():
     104    try:
     105        err
     106        import cairocffi                            #@UnresolvedImport
     107        cairocffi.install_as_pycairo()
     108        cairo = cairocffi
     109    except:
     110        import cairo
     111    return cairo
  • xpra/gtk_common/gtk_spinner.py

     
    77# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
    88# later version. See the file COPYING for details.
    99
    10 from xpra.gtk_common.gobject_compat import import_gtk, import_gobject
     10from xpra.gtk_common.gobject_compat import import_gtk, import_gobject, import_cairo
    1111gtk = import_gtk()
    1212gobject = import_gobject()
    13 import cairo
     13cairo = import_cairo()
    1414import math
    1515
    1616
  • xpra/server/source.py

     
    159159    return w, h, "png", str(raw_data)
    160160
    161161def make_argb32_window_icon(pixel_data, pixel_format, stride, w, h):
    162     import cairo
     162    from xpra.gtk_common.gobject_compat import import_cairo
     163    cairo = import_cairo()
    163164    assert pixel_format == cairo.FORMAT_ARGB32
    164165    assert stride == 4 * w
    165166    return w, h, "premult_argb32", str(pixel_data)
  • xpra/x11/gtk_x11/prop.py

     
    1111
    1212import struct
    1313import gtk.gdk
    14 import cairo
     14from xpra.gtk_common.gobject_compat import import_cairo
     15cairo = import_cairo()
    1516
    1617from xpra.x11.gtk_x11.gdk_bindings import (
    1718                get_xatom, get_pyatom,      #@UnresolvedImport
  • xpra/x11/gtk_x11/window.py

     
    1616
    1717import gobject
    1818import gtk.gdk
    19 import cairo
     19from xpra.gtk_common.gobject_compat import import_cairo
     20cairo = import_cairo()
    2021
    2122from xpra.util import nonl
    2223from xpra.x11.bindings.window_bindings import constants, X11WindowBindings #@UnresolvedImport