xpra icon
Bug tracker and wiki

This bug tracker and wiki are being discontinued
please use https://github.com/Xpra-org/xpra instead.


Ticket #2757: replay-scrolls.patch

File replay-scrolls.patch, 5.5 KB (added by Antoine Martin, 11 months ago)

patch to save and replay scrolls later

  • xpra/client/gtk_base/cairo_backing_base.py

     
    1111from xpra.client.window_backing_base import WindowBackingBase, fire_paint_callbacks, SCROLL_ENCODING
    1212from xpra.client.gtk_base.cairo_paint_common import setup_cairo_context, cairo_paint_pointer_overlay
    1313from xpra.os_util import memoryview_to_bytes
    14 from xpra.util import envbool
     14from xpra.util import envbool, csv
    1515from xpra.log import Logger
    1616
    1717log = Logger("paint", "cairo")
     
    145145        if not gc:
    146146            fire_paint_callbacks(callbacks, False, message="no context")
    147147            return
     148        count = getattr(self, "scroll_counter", 0)
     149        old_backing.write_to_png("scroll-%iA.png" % count)
     150        log.error("scrolls %i:", count)
     151        with open("scroll-%i.txt" % count, "wb") as f:
     152            for scroll in scrolls:
     153                log.error(csv(scroll))
     154                f.write(("%s\n" % csv(scroll)).encode())
    148155        gc.set_operator(cairo.OPERATOR_SOURCE)
    149156        for sx,sy,sw,sh,xdelta,ydelta in scrolls:
    150157            gc.set_source_surface(old_backing, xdelta, ydelta)
     
    156163                self.cairo_paint_box(gc, "scroll", x, y, sw, sh)
    157164        del gc
    158165        self._backing.flush()
     166        self._backing.write_to_png("scroll-%iB.png" % count)
     167        self.scroll_counter = count+1
    159168        fire_paint_callbacks(callbacks)
    160169
    161170
  • tests/xpra/clients/cairo_replayscroll.py

     
     1#!/usr/bin/env python
     2# This file is part of Xpra.
     3# Copyright (C) 2020 Antoine Martin <antoine@xpra.org>
     4# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     5# later version. See the file COPYING for details.
     6
     7import sys
     8import cairo
     9from time import sleep
     10
     11import gi
     12gi.require_version("Gtk", "3.0")
     13gi.require_version("Gdk", "3.0")
     14from gi.repository import Gtk, Gdk, GLib
     15
     16
     17class ReplayScroll(Gtk.Window):
     18
     19    def __init__(self):
     20        super().__init__()
     21
     22        self.last = None
     23        self.image = None
     24        self.scrolls = []
     25
     26        self.darea = Gtk.DrawingArea()
     27        self.darea.connect("draw", self.on_draw)
     28        self.darea.set_size_request(1024, 1024)
     29        self.add(self.darea)
     30
     31        self.set_title("Replay Scroll ")
     32        self.set_position(Gtk.WindowPosition.CENTER)
     33        self.connect("delete-event", Gtk.main_quit)
     34        self.show_all()
     35
     36    def load_image(self, filename):
     37        self.last = self.image
     38        self.image = cairo.ImageSurface.create_from_png(filename)
     39        self.resize(self.image.get_width(), self.image.get_height())
     40        self.darea.queue_draw()
     41
     42    def step(self, message):
     43        print(message)
     44        self.darea.queue_draw()
     45
     46    def apply_scroll(self, filename):
     47        with open(filename, "rb") as f:
     48            data = f.read()
     49        self.scrolls = []
     50        for line in data.decode().splitlines():
     51            scroll = [int(x.strip()) for x in line.split(",")]
     52            self.scrolls.append(scroll)
     53        self.clear()
     54
     55    def clear(self):
     56        self.last = self.image
     57        w, h = self.image.get_width(), self.image.get_height()
     58        self.image = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
     59        cr = cairo.Context(self.image)
     60        cr.set_operator(cairo.OPERATOR_CLEAR)
     61        cr.set_source_rgba(1, 1, 1, 1)
     62        cr.rectangle(0, 0, w, h)
     63        cr.fill()
     64        self.image.flush()
     65        self.step("clear")
     66        GLib.timeout_add(1000, self.copy)
     67
     68    def copy(self):
     69        cr = cairo.Context(self.image)
     70        cr.set_operator(cairo.OPERATOR_SOURCE)
     71        cr.set_source_surface(self.last, 0, 0)
     72        cr.paint()
     73        self.image.flush()
     74        self.step("copy")
     75        GLib.timeout_add(1000, self.paint_scroll)
     76
     77    def paint_scroll(self):
     78        if not self.scrolls:
     79            return False
     80        scroll = self.scrolls[0]
     81        sx,sy,sw,sh,xdelta,ydelta = scroll
     82        self.scrolls = self.scrolls[1:]
     83        self.step("scroll: %s" % (scroll))
     84
     85        cr = cairo.Context(self.image)
     86        cr.set_operator(cairo.OPERATOR_SOURCE)
     87        cr.set_source_surface(self.last, xdelta, ydelta)
     88        x = sx+xdelta
     89        y = sy+ydelta
     90        cr.rectangle(x, y, sw, sh)
     91        cr.fill()
     92        if True:
     93            color = 0, 0, 0, 0.6
     94            cr.set_line_width(1)
     95            cr.set_source_rgba(*color)
     96            cr.rectangle(x, y, sw, sh)
     97            cr.stroke()
     98        del cr
     99        self.image.flush()
     100        return bool(self.scrolls)
     101
     102
     103    def on_draw(self, wid, cr):
     104        if self.image:
     105            cr.set_source_surface(self.image, 0, 0)
     106            cr.paint()
     107
     108def main():
     109    app = ReplayScroll()
     110    def update_image():
     111        for x in sys.argv[1:]:
     112            if x.endswith(".png"):
     113                app.load_image(x)
     114            else:
     115                app.apply_scroll(x)
     116    GLib.timeout_add(1000, update_image)
     117    Gtk.main()
     118
     119if __name__ == "__main__":   
     120    main()