1

I have a widget on which I am drawing in a python-gtk3 application, and clicking on it triggers a specific action. I want to show some visual feedback on hover, to indicate the widget is interactive. After figuring out cursors are not the way in Gtk3, I am trying to use a border, similar to what happens when hovering buttons.

After a lot of playing around, what I have seems to work when I query the widgets and CSS for what color they should have -- however the visuals are never updated. Here’s a minimal working example:

import gi
import cairo
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk


# Event handlers
def on_da_click(widget, event):
    print('Clicked!')

def on_da_hover(widget, event):
    # Set widget state as this does not happen by default for DrawingArea
    context = widget.get_style_context()
    context.set_state(Gtk.StateFlags.PRELIGHT if event.type == Gdk.EventType.ENTER_NOTIFY else
                      Gtk.StateFlags.NORMAL)

    # Check the color changed
    print('Border color should now be', context.get_property('border-color', context.get_state()))

    # ----- ISSUE IS HERE ----- #
    # Tried various things to get the visual to update, none seem to work:
    context.emit('changed')
    widget.queue_draw()
    widget.show_all()


# Create some widgets
da = Gtk.DrawingArea()
da.add_events(Gdk.EventMask.ENTER_NOTIFY_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK |
              Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK)
da.connect('button-release-event', on_da_click)
da.connect('touch-event', on_da_click)
da.connect('enter-notify-event', on_da_hover)
da.connect('leave-notify-event', on_da_hover)

frame = Gtk.AspectFrame()
frame.set(.5, .5, 16/9, False)
frame.set_shadow_type(Gtk.ShadowType.NONE)
frame.get_style_context().add_class('grid-frame')
frame.add(da)

# Create a Window
win = Gtk.Window(title='Hello World')
win.set_default_size(400, 400)
win.connect('destroy', Gtk.main_quit)
win.add(frame)
win.show_all()

# Load a stylesheet for the whole app
css_loader = Gtk.CssProvider.new()
css_loader.load_from_data('''
.grid-frame > * {
  border-style: solid;
  border-width: 2px;
  border-color: @theme_selected_bg_color;
}

.grid-frame > *:hover {
  border-color: @theme_bg_color;
}
'''.encode())

Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), css_loader,
                                         Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)

# Run
Gtk.main()

When I enter/exit the area I get the expected alternating colors in my messages:

Border color should now be Gdk.RGBA(red=0.000000, green=0.000000, blue=0.196078, alpha=1.000000)
Border color should now be Gdk.RGBA(red=0.000000, green=0.000000, blue=0.913725, alpha=1.000000)
Border color should now be Gdk.RGBA(red=0.000000, green=0.000000, blue=0.196078, alpha=1.000000)
Border color should now be Gdk.RGBA(red=0.000000, green=0.000000, blue=0.913725, alpha=1.000000)

However visually the border never changes color. How can I trigger the updated? The usual queue_draw etc. do not work. My current gtk3 version is 3.24.35, but I’d like this to work over all Gtk 3.x.

Cimbali
  • 11,012
  • 1
  • 39
  • 68

0 Answers0