You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GTKMM 4中XReparentWindow重设父窗口后子窗口装饰丢失求助

解决GTKMM 4中子窗口重设父窗口后装饰丢失的问题

问题背景

我尝试在GTKMM 4中模拟GTKMM 3里被废弃的「将窗口置于父窗口中央」功能,于是用XReparentWindow重设Gtk::Window子窗口的父窗口,还配合了XSetTransientForHint,但运行后子窗口的所有装饰都被移除了——直接显示对话框的话装饰是正常的。

我写的代码

void MyGtk::Window_Centre_Child_On_Parent(
    Gtk::Window *parent,
    Gtk::Window *child
)
{
    int child_height;
    int child_width;
    int parent_height;
    int parent_width;
    int position_x;
    int position_y;

    // 参数校验
    assert(parent);
    assert(child);

    // 获取子窗口大小
    Widget_Get_Size(
        child,
        child_width,
        child_height
    );
    assert(child_height > 0);
    assert(child_width > 0);

    // 获取父窗口大小
    Widget_Get_Size(
        parent,
        parent_width,
        parent_height
    );
    assert(parent_height > 0);
    assert(parent_width > 0);

    // 获取X11窗口ID
    auto child_window = Window_Get_X_Windows_ID(child);
    assert(child_window > 0);
    auto parent_window = Window_Get_X_Windows_ID(parent);
    assert(parent_window > 0);

    // 打开X11显示
    auto display = XOpenDisplay(XDisplayName(nullptr));
    assert(display);

    // 计算居中位置
    position_x = abs(
        std::min(
            parent_width / 2,
            (parent_width - child_width) / 2
        )
    );
    position_y = abs(
        std::min(
            parent_height / 2,
            (parent_height - child_height) / 2
        )
    );

    // 设置transient hint
    XSetTransientForHint(
        display,
        child_window,
        parent_window
    );

    // 重设父窗口
    XReparentWindow(
        display,
        child_window,
        parent_window,
        position_x,
        position_y
    );

    XFlush(display);
    XCloseDisplay(display);
}

问题原因

直接调用XReparentWindow是核心问题:Gtk::Window本身是顶级窗口,重设父窗口后会变成父窗口的子部件,而GTK的子部件默认没有窗口装饰(窗口装饰是窗口管理器给顶级窗口的),所以装饰会直接消失。

解决方法

1. 用GTK原生API实现居中(推荐)

GTKMM 4虽然废弃了旧的居中接口,但可以用原生逻辑替代,完全不需要碰X11底层:

void Window_Centre_Child_On_Parent(Gtk::Window* parent, Gtk::Window* child)
{
    g_return_if_fail(parent && child);

    // 让窗口管理器知道子窗口和父窗口的关联关系
    child->set_transient_for(*parent);

    // 获取父窗口的位置与大小
    int parent_x, parent_y;
    parent->get_position(parent_x, parent_y);
    int parent_w, parent_h;
    parent->get_size(parent_w, parent_h);

    // 获取子窗口的大小
    int child_w, child_h;
    child->get_size(child_w, child_h);

    // 计算居中位置(基于父窗口左上角偏移)
    int x = parent_x + (parent_w - child_w) / 2;
    int y = parent_y + (parent_h - child_h) / 2;

    // 设置子窗口位置
    child->move(x, y);
}

2. 如果是对话框场景,直接用Gtk::Dialog

如果要显示的是对话框,Gtk::Dialog默认就会在父窗口居中,且自带完整装饰,完全不需要手动处理:

auto dialog = Gtk::Dialog::create("对话框标题", *parent, Gtk::DialogFlags::DIALOG_MODAL);
// 添加对话框内容...
dialog->show();

3. 非要用X11底层的话(不推荐)

别调用XReparentWindow,只保留XSetTransientForHint,然后用GTK的child->move(x,y)设置位置——这样子窗口还是顶级窗口,不会丢失装饰。

内容的提问来源于stack exchange,提问作者BRS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 03:43:23