Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unfocus (blur) Python-gi GTK+3 window on Linux

What I want to do and why

I want my window to unfocus, so the previous focused window is selected.

Why? I want to interact with the previously selected window (from other programs). My current plan is: unfocus my window, use libxdo to simulate keystrokes, then focus my window again.

My window can be set on top to help avoid flicking. Should be good enough. Looks simple to me. But I can't get it to work.

What I've tried so far

Hiding the window with Gtk.Widget.hide() and then showing it again: The window flickers too much and it's slightly moved some pixels to the top (because of window manager stubbornness, I suppose).

Sample test code

Current code calls Gtk.Window.set_focus(None) that does not work. I need to replace that line with something else that makes what I want it to do.

losefocus.py:

import signal
from gi import require_version
require_version('Gtk', '3.0')
from gi.repository import GLib, Gtk, GObject

class LoseFocusHandler:
  def onClick(self, window):
    print "Losing focus yet?"
    window1 = builder.get_object("window1")
    window1.set_focus(None)

if __name__ == "__main__":
  GObject.threads_init()

  builder = Gtk.Builder()
  builder.add_from_file("losefocus.glade")
  builder.connect_signals(LoseFocusHandler())
  window1 = builder.get_object("window1")
  window1.show_all()

  signal.signal(signal.SIGINT, signal.SIG_DFL)
  Gtk.main()

losefocus.glade:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.16.1 -->
<interface>
  <requires lib="gtk+" version="3.10"/>
  <object class="GtkWindow" id="window1">
    <property name="can_focus">False</property>
    <property name="window_position">center-always</property>
    <property name="gravity">center</property>
    <child>
      <object class="GtkButton" id="button1">
        <property name="label" translatable="yes">Lose Focus!</property>
        <property name="visible">True</property>
        <property name="can_focus">True</property>
        <property name="receives_default">True</property>
        <property name="relief">half</property>
        <signal name="clicked" handler="onClick" swapped="no"/>
      </object>
    </child>
  </object>
</interface>
like image 515
Jorge Suárez de Lis Avatar asked Mar 16 '16 07:03

Jorge Suárez de Lis


1 Answers

A simple solution would be to record which window had focus before, both when creating the window and then on each focus-in-event, and explicitly focus that window instead of trying to unfocus the active one:

import signal
from gi import require_version
require_version('Gtk', '3.0')
from gi.repository import GLib, Gdk, Gtk, GObject

class LoseFocusHandler:
  def onClick(self, window):
    print "Losing focus yet?"
    old_window[0].focus(0)

def focus_handler(gdk_window, event):
    # At this point, our window does not have focus yet, but is
    # about to. This hence works:
    old_window[0] = gdk_window.get_screen().get_active_window()

if __name__ == "__main__":
  GObject.threads_init()

  old_window = [ Gdk.Screen.get_default().get_active_window() ]

  builder = Gtk.Builder()
  builder.add_from_file("losefocus.glade")
  builder.connect_signals(LoseFocusHandler())
  window1 = builder.get_object("window1")
  window1.connect("focus-in-event", focus_handler)
  window1.show_all()

  signal.signal(signal.SIGINT, signal.SIG_DFL)
  Gtk.main()
like image 133
Phillip Avatar answered Oct 06 '22 00:10

Phillip