`Gtk.Window.set_attached_to` 真的是在 Wayland 中相对于小部件定位弹出窗口的正确方法吗?

Is `Gtk.Window.set_attached_to` really the correct way to position a popup relative to a widget in wayland?

set_attached_to 似乎是相对于 Wayland 中的小部件定位弹出窗口 window 的正确方法:

Examples of places where specifying this relation is useful are for instance [...] a completion popup window created by Gtk.Entry [...]

不幸的是,这只会产生一个错误

Gdk-Message: 12:13:16.143: Window 0x1822340 is a temporary window without parent, application will not be able to position it on screen.

试图取消注释 popup.set_parent(entry) 行只会添加警告:

(try_entry_popup.py:4539): Gtk-WARNING **: 12:17:34.185: Can't set a parent on a toplevel widget

同样的错误。

这是一个最小的例子:

#!/usr/bin/env python
# stripped down from https://gitlab.gnome.org/GNOME/gtk/issues/1541#note_396391

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

entry = Gtk.Entry()
popup = Gtk.Window(type=Gtk.WindowType.POPUP)
#popup.set_parent(entry)
popup.set_attached_to(entry)
popup.show_all()

layout = Gtk.VBox()
layout.pack_start(entry, False, True, 0)

window = Gtk.Window()
window.connect("destroy", Gtk.main_quit)
window.add(layout)
window.show_all()

Gtk.main()

entry completion source 看来它确实应该有效。 它是否使用私人功能?或者我错过了什么?

嗯,不是真的:gtk_window_set_attached_to 与定位无关,它对可访问性 (a11y) 和以正确的方式应用主题很重要。如果你想定位你的弹出窗口 window 你可以按照它在 https://gitlab.gnome.org/GNOME/gtk/blob/075dcc142aa525778268165095de019b736f3efa/gtk/gtkentrycompletion.c#L1597

中所做的

这是一个非常简单的实现:

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

def on_button_clicked(widget):
  popup = Gtk.Window(type=Gtk.WindowType.POPUP)
  # optionally you may set an appropriate type hint, but it's not required.
  popup.set_attached_to(entry)
  popup.set_transient_for(window)

  gdk_window = entry.get_window()
  gdk_window_origin = gdk_window.get_origin()
  x = gdk_window_origin[1]
  y = gdk_window_origin[2]
  allocation = entry.get_allocation()
  x += allocation.x
  y += allocation.y + allocation.height

  popup.move(x, y)
  popup.show_all()

button = Gtk.Button()
button.connect('clicked', on_button_clicked)
entry = Gtk.Entry()
layout = Gtk.VBox()
layout.pack_start(button, False, True, 0)
layout.pack_start(entry, False, True, 0)

window = Gtk.Window()
window.connect("destroy", Gtk.main_quit)
window.add(layout)
window.show_all()

Gtk.main()