Pycairo:如何正确实例化 cairo.XlibSurface()?

Pycairo: How to correctly instance cairo.XlibSurface()?

我正在尝试使用 Pycairo 创建小部件来监控系统,例如 Conky。 我正在尝试直接在 X 上绘图,使用带有 Xlib 的 Cairo Surface。

当我尝试实例化 cairo.XlibSurface() class 时,返回错误:

TypeError: The XlibSurface type cannot be directly instantiated

我的简单代码:

import cairo
surface = cairo.XlibSurface()

如何正确实例化 cairo.XlibSurface() ?

提前致谢

[不完整的答案] 我有足够的片段,这可能作为答案比作为评论更有用。很抱歉没能追根究底。

documentation for PyCairo XlibSurface 本身只提到它可以通过对 GTK 的某些调用来实例化 - 我不确定这是否只是对 GTK2 的旧绑定。我可以找到一个片段来使用 GTK +3 为我获取 Cairo 上下文,但如果不求助于 ctypes,从 Cairo 上下文返回到它使用的 Surface 似乎是不可行的。

因此,您基本上需要使用 Python ctypes 调用 Cairo's C cairo_xlib_surface_create,并找到一种使用 ctypes 从指针创建 Python cairo.XlibSurface 实例的方法由上面的函数返回。那就是您可能必须在 C 中的 pygtk 遗留代码库中找到的“缺失 link”,并在 Python 代码中使用 ctypes 进行复制。

至于首先调用 cairo_xlib_surface_create 所需的参数,您可能可以使用 Python XLib 获取它们 - 下面的代码片段为您提供了 Window GID 和 Python X 显示器和 Window:

的包装器
from Xlib import X, display
pd = display.Display()
win = pd.screen().root.create_window(0, 0, 640, 480, 0, pd.screen().root_depth, X.InputOutput, X.CopyFromParent)
win.map()
pd.sync()

xid = xx.__resource__()

没有解决问题:How to use Pycairo with Xlib,但是使用 Gtk 和 Pycairo 的优雅替代方案。

如何将 Pycairo 与 Xlib 一起使用的谜团仍在继续。

将 Gtk window 与 Gdk.WindowTypeHint.DESKTOP 结合使用,获得优雅的输出。

import gi
gi.require_versions({
    'Gdk':  '3.0',
    'Gtk':  '3.0',
    'Wnck': '3.0',
    'Gst':  '1.0',
    'AppIndicator3': '0.1',
})

from gi.repository import Gtk, Gdk
import cairo


class Example(Gtk.Window):

    def __init__(self):
        super(Example, self).__init__()

        self.tran_setup()
        self.init_ui()

    def init_ui(self):
        self.connect("draw", self.on_draw)
        # self.set_title("Transparent window")
        self.resize(300, 250)
        self.set_position(Gtk.WindowPosition.NONE)
        self.move(0, 40)
        self.connect("delete-event", Gtk.main_quit)
        
        # The magic is here
        self.set_type_hint(Gdk.WindowTypeHint.DESKTOP)

        self.show_all()

    def tran_setup(self):
        self.set_app_paintable(True)
        screen = self.get_screen()

        #print(self.get_type_hint())

        visual = screen.get_rgba_visual()
        if visual != None and screen.is_composited():
            self.set_visual(visual)

    def on_draw(self, wid, cr):
        cr.set_source_rgba(0.2, 0.2, 0.2, 0.4)
        cr.set_operator(cairo.OPERATOR_SOURCE)
        cr.paint()

        cr.set_source_rgb(0.6, 0.6, 0.6)

        cr.rectangle(20, 20, 120, 80)
        cr.fill()

        self.draw(cr)

    def draw(self, cr):
        cr.set_source_rgb(0, 256, 256)
        cr.rectangle(180, 20, 80, 80)
        cr.fill()


def main():
    app = Example()
    Gtk.main()


if __name__ == "__main__":
    main()

输出: