Search code examples
pythongtkpygtk

Paint on Transparent window with HeaderBar Python and Gtk3


I have a little problem with the following code. It creates a GtkWindow, make it paintable so I can draw on it with cairo on draw events. Then I add a GtkHeaderBar and a simple button widget.

from gi.repository import Gtk
import cairo

def draw_callback(widget,cr):
  if widget.transparency:
    cr.set_source_rgba(0,0,0,0.5)
  else:
    cr.set_source_rgb(0,0,0)   

  cr.set_operator(cairo.OPERATOR_SOURCE)
  cr.paint()
  cr.set_operator(cairo.OPERATOR_OVER)

win= Gtk.Window()
win.connect('delete-event', Gtk.main_quit)
win.set_app_paintable(True)
screen = win.get_screen()
visual = screen.get_rgba_visual()
win.transparency = False

if visual and screen.is_composited():
  win.set_visual(visual)
  win.transparency = True
else:
  print('System doesn\'t support transparency')
  win.set_visual(screen.get_system_visual)

win.connect('draw', draw_callback)

win.add(Gtk.Button(label='test'))
bar = Gtk.HeaderBar(title='title')
bar.set_has_subtitle(False)
bar.set_show_close_button(True)
win.set_titlebar(bar)
win.show_all()

Gtk.main()

The draw_callback paint the window background but this background looks like this :

enter image description here

It is like the cairo context doesn't have the same size of the window. The part that is draw and that is outside the window doesn't seems to answer to mouse event ( I cannot grab the window from this part for example)

If I don't use an HeaderBar, I don't have this problem.

This works with ruby 2.2 and the Gtk3 bindings.

My python Version is python 3 and the up to date Gtk modules

Edit:

Problem still exist with :

def size_allocation_cb(widget, rectangle):
  widget.x = rectangle.x
  widget.y = rectangle.y
  widget.width = rectangle.width
  widget.height = rectangle.height

win.connect('size-allocate', size_allocation_cb)

def draw_callback(widget,cr):
  if widget.transparency:
    cr.set_source_rgba(0,0,0,0.5)
  else:
    cr.set_source_rgb(0,0,0)   

  cr.set_operator(cairo.OPERATOR_SOURCE)
  cr.rectangle(widget.x, widget.y, widget.width, widget.height)
  cr.fill()
  cr.set_operator(cairo.OPERATOR_OVER)

Solution

  • When you have a header bar, your window is drawn entirely on the client side, including shadows (for some reason). You will need to call cairo_rectangle() or some other function, preferably with the size allocation (not size request!) of the child of the GtkWindow, to clip cairo_paint() to the correct size.