Ошибка сегментации при использовании cairo.Region в Python3 на Fedora 24

Я пытаюсь получить форму ввода для применения к окну, поэтому у меня может быть прозрачная рамка, в которой можно щелкнуть только интересные части и т. д.

Я использую графику Cairo с PyGObject (Python 3).

Объект — это обычный объект Gtk Windows, который затем определяет область рисования Cairo:

class Face(Gtk.Window):
    def __init__(self):
        super(Face, self).__init__()
        self.init_ui()

    def init_ui(self):
        [...]
        self.darea = Gtk.DrawingArea()
        self.darea.connect("draw", self.on_draw)
        self.add(self.darea)

    def on_draw(self, widget, cr):
        [... (drawing a couple shapes into the context)]
        sface = cr.get_group_target()
        mregion = Gdk.cairo_region_create_from_surface(sface)
        # the above line produces the error
        # the following lines is wishful thinking at this point...
        #self.get_window().input_shape_combine_region(mregion, 0, 0)

Таким образом, функция on_draw() вызывается всякий раз, когда необходимо перерисовать область рисования, то есть когда окно перемещается, изменяется его размер, открывается после того, как оно было скрыто, и так далее.

большая часть окна на самом деле пуста, поскольку предполагается, что это в основном полупрозрачная рамка, и только видимые части должны быть кликабельными. Однако я получаю следующую ошибку:

Traceback (most recent call last):
  File "./lsc.py", line 236, in on_draw
    mregion = Gdk.cairo_region_create_from_surface(sface)
TypeError: Couldn't find foreign struct converter for 'cairo.Region'
python3: cairo-surface.c:953: cairo_surface_destroy: Assertion `CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count)' failed.
zsh: abort (core dumped)  ./lsc.py

Пакеты для Python3, библиотеки PyGObject и Cairo установлены, и я также импортировал обе части Cairo:

from gi.repository import Gtk, Gdk, cairo
import cairo

На данный момент я не совсем уверен, является ли это проблемой Python или ошибкой с моей стороны. Я не уверен, применимо ли даже использование cairo.Region, пример, который я привожу, таков: http://www.programcreek.com/python/example/81481/cairo.Регион


Редактировать

В этот момент я серьезно озадачен тем, что происходит. Я немного изучал это, и вот что я узнал:

Кажется, есть какая-то ошибка с PyGI и Cairo.

Когда я использую только часть самоанализа cairo:

from gi.repository import Gtk, Gdk, cairo
#import cairo

И затем запустите мой скрипт, я получаю эту ошибку:

raceback (most recent call last):
  File "./lsc.py", line 164, in on_draw
    cr.set_operator(cairo.OPERATOR_SOURCE)
  File "/usr/lib64/python3.5/site-packages/gi/module.py", line 139, in __getattr__
    self.__name__, name))
AttributeError: 'gi.repository.cairo' object has no attribute 'OPERATOR_SOURCE'

Очевидно, я использую cairo.OPERATOR_SOURCE в своем коде, чтобы рисовать в контексте cairo. Однако интроспективный пакет, по-видимому, даже не содержит операторов, используемых для рисования на поверхности. Очень странный.

Когда я использую просто неинтроспективный модуль:

from gi.repository import Gtk, Gdk
import cairo

Я получаю ту же ошибку, что и в моей первой части вопроса.

для завершения это список пакетов cairo, которые я сейчас установил:

cairo-devel-1.14.6-1.fc24.x86_64
pycairo-devel-1.10.0-4.fc24.x86_64
cairo-gobject-1.14.6-1.fc24.i686
mingw32-cairo-1.14.6-1.fc24.noarch
python3-cairocffi-0.7.2-5.fc24.noarch
cairo-1.14.6-1.fc24.i686
cairo-1.14.6-1.fc24.x86_64
pycairo-1.10.0-4.fc24.x86_64
python3-cairosvg-1.0.19-3.fc24.noarch
cairomm-devel-1.12.0-2.fc24.x86_64
cairo-clock-0.3.4-17.fc24.x86_64
cairomm-1.12.0-2.fc24.x86_64
cairo-gobject-1.14.6-1.fc24.x86_64
python3-cairo-1.10.0-15.fc24.x86_64
mingw32-cairomm-1.12.0-2.fc24.noarch
python3-cairo-devel-1.10.0-15.fc24.x86_64
cairo-gobject-devel-1.14.6-1.fc24.x86_64

Я думаю, вы обнаружите, что все они появились совсем недавно и соответствуют требованиям, указанным в примере, который я привел выше.

Также обратите внимание на строки 268–274 документа countdown.py:

# make window click-through, this needs pycairo 1.10.0 for python3
# to work
rect = cairo.RectangleInt (0, 0, 1, 1)
region = cairo.Region (rect)
if (not region.is_empty ()):
    self.window.input_shape_combine_region (None)
    self.window.input_shape_combine_region (region)

Автор не использует интроспективный cairo, он просто делает import cairo, что наводит меня на мысль, что это, возможно, более правильный способ.

В любом случае, весь сценарий тоже не работает.

В этот момент я снова застрял. Кажется, я не могу найти недавний и/или рабочий пример того, как использовать эту функциональность.

Пока кажется, что использование интроспективной версии cairo бесполезно, в ней почти не определяются элементы оригинала. Однако при использовании обычного pycairo (путем импорта с import cairo) я получаю сообщение об ошибке, которое заставило меня опубликовать этот вопрос в первую очередь.

Я начинаю верить, что у меня концептуальная ошибка, может быть?


person polemon    schedule 10.07.2016    source источник
comment
Какую версию pycairo вы используете? Вы смотрели ссылку в пример?   -  person oldtechaa    schedule 10.07.2016
comment
@oldtechaa Казалось бы, так: pycairo-1.10.0-4.fc24.x86_64 (версия 1.10.0). Однако я повнимательнее рассмотрю пример, ссылка на который была указана в отчете об ошибке.   -  person polemon    schedule 10.07.2016
comment
@oldtechaa хорошо, у меня правильная версия или я соответствую требованиям к версии соответственно, но ошибка все еще возникает. Так что я не знаю...   -  person polemon    schedule 11.07.2016
comment
@oldtechaa dnf install pycairo pycairo-devel обычные репозитории Fedora и т. д.   -  person polemon    schedule 11.07.2016
comment
Извините, я пропустил тот факт, что это достаточно ново, согласно странице с ошибками. Это последняя версия, выпущенная в 2011 году.   -  person oldtechaa    schedule 11.07.2016
comment
Я мало использовал cairo, но могу подтвердить, что from gi.repository import cairo совершенно бесполезен. Кроме того, я заметил это в документации cairo: [the surface] can be a "nil" surface if cr is already in an error state, так что, возможно, стоит проверить, так ли это.   -  person Aran-Fey    schedule 16.07.2016


Ответы (1)


Хорошо... Я знаю, что этот пост немного устарел, но я нашел его, когда искал ответ на тот же вопрос. (Это мой первый вклад в переполнение стека, так что будьте терпеливы со мной). Я хотел создать непрямоугольное окно в GTK 3, и у меня тоже ничего не вышло после нескольких часов исследований.

В конце концов, я нашел тот же пример программы, о котором упоминал Полемон, и прочитал документацию Cairo и Gdk. В конце концов, две функции, которые достигают цели создания непрямоугольного окна, которое реагирует на ввод только в непрозрачных областях поверхности Cairo, это Gdk.cairo_region_create_from_surface(), за которым следует GdkWindow.input_shape_combine_region().

Теперь мое приложение сосредоточено на создании средство запуска приложений, использующее окно GtkDialog, но этот код можно применить и к стандартному GTKWindow.

Вот шаги, которые я выполнил для достижения этого эффекта. Во-первых, я добавил следующие строки в конструктор моего диалогового окна:

    self.set_decorated(False)  # Creates a borderless window without a title bar
    self.set_app_paintable(True) # Tells GTK not to redraw the window area but let the application handle the drawing
    self.connect('draw', self.draw) # Registers a callback function for the draw signal

Затем я определил функцию обратного вызова, отвечающую за обработку сигнала отрисовки. В него я вложил следующее:

    # Create a Cairo surface from a PNG image
    self.image = cairo.ImageSurface.create_from_png("image-with-transparent-regions.png")
    # Create a new Cairo region based on this Cairo surface
    region = Gdk.cairo_region_create_from_surface(self.image)
    # Combine this region with the window dialog window region.
    # Input area is now restricted to non-transparent areas of the dialog window 
    self.input_shape_combine_region(region)

    # Sets the Cairo compositing Operator to replace the contents of the window background
    context.set_operator(cairo.OPERATOR_SOURCE)
    # Sets the Cairo surface as the pattern to be drawn on the window background
    context.set_source_surface(self.image, 0, 0)
    # Paints the background image with the Cairo surface pattern
    context.paint()
    # Restores the default state of the Cairo compositing operator to draw the source layer on top of the destination window layer.
    # This prevents the background image from being erased by alpha component of the widgets being drawn on top of it.
    context.set_operator(cairo.OPERATOR_OVER)

Для всех, кто хочет попробовать готовый к запуску код, ознакомьтесь с моей полной программой.

person Praxis    schedule 11.04.2020