如何在Linux上取消焦点(模糊)Python-gi GTK+3窗口

7

我想做什么以及原因

我希望我的窗口失去焦点,所以先前聚焦的窗口被选中。

为什么?我想要与先前从其他程序选择的窗口进行交互。我的当前计划是:使我的窗口失去焦点,使用libxdo模拟按键,然后再次聚焦我的窗口。

我的窗口可以设置在顶部,以帮助避免闪烁。应该足够简单。但是我无法使它工作。

我迄今为止尝试过的内容

使用Gtk.Widget.hide()隐藏窗口,然后再次显示它:该窗口会闪烁太多,并且稍微向上移动了几个像素(可能是由于窗口管理器的顽固性)。

示例测试代码

当前代码调用Gtk.Window.set_focus(None),无法正常工作。我需要将那行替换为其他可以实现我想要的功能的代码。

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>
1个回答

1
一个简单的解决方案是在创建窗口时记录哪个窗口拥有焦点,并在每次 focus-in-event 事件发生时,明确地将焦点放在该窗口上,而不是尝试取消激活的窗口:
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()

非常聪明!感谢您的提示。然而,这在Unity 7中并不能正常工作。前一个窗口在任务栏中被突出显示,但根本没有焦点。 - Jorge Suárez de Lis
1
Unity具有“防止窃取焦点”的功能,它是从compiz继承而来的,旨在防止程序改变焦点,而是在任务栏中突出显示程序。 GDKWindow的focus()方法调用适当的Xlib命令,在Cinnamon中运行良好。我发现有些页面声称您可以使用CCSM →常规选项→焦点和提升行为来调整设置。 - Phillip
很不幸,我需要在Ubuntu上使用开箱即用的东西。 我想向另一个窗口发送按键。由于我知道如何获取另一个窗口的ID,现在我可以使用xdo来获得该窗口的焦点,输入文本,然后恢复焦点。 我在这里发布了一个可行的示例:http://pastebin.com/0BsKYZtP 我尝试使用xdo功能通过窗口ID输入文本,但似乎“XSendEvent”也无法工作。因此,我分别激活窗口,然后输入文本,最后恢复焦点。这样我只依赖于看起来完美无缺的“Xtest”。 - Jorge Suárez de Lis
我应该尝试在Ubuntu软件包python-xdo中使用Python xdo模块,但它似乎已经停止更新并且没有文档。调用“xdotool”也不是太糟糕,对吧? - Jorge Suárez de Lis
1
请注意,如果您直接发送键盘事件,则必须将其发送到输入小部件的Xid,而不是拥有它的窗口。我个人会使用XLib进行此操作,但xdotool也可以胜任。 (我[使用脚本将密码粘贴到活动窗口中](https://github.com/phillipberndt/scripts/blob/master/passwrd/passwrd.py),您可能可以重用其中的部分。) - Phillip
所以小部件也有xids吗?哇,我对此一无所知哈哈。谢谢你的提示,我想我现在会坚持这个了。我会保留那个链接以备将来参考,再次感谢 :)! - Jorge Suárez de Lis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接