我正在尝试重新设置子窗口 Gtk::Window 的父窗口,以便我可以模拟已弃用的 GTKMM 4 调用,将窗口定位在父窗口的中心(存在于 GTKMM 3 中)。我搜索了 XReparentWindow 帖子,唯一相关的帖子建议使用 XSetTransientForHint this,但这对我不起作用。我写的代码是:
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;
//
//First we must validate all parameters and terminate if any fail.
//
assert(parent);
assert(child);
//
//Now we need to fetch the size of the child window so that we can then
//re-parent the window at the centre of the parent window thus emulating
//the GTKMM 3 set position call. This has been deprecated in GTKMM 4.
//
Widget_Get_Size(
child,
child_width,
child_height
);
//
//Now we need to ensure that the above returned sensible values and we
//terminate if not.
//
assert(child_height > 0);
assert(child_width > 0);
//
//Now we need to fetch the size of the parent window so that we can then
//re-parent the window at the centre of the parent window thus emulating
//the GTKMM 3 set position call. This has been deprecated in GTKMM 4.
//
Widget_Get_Size(
parent,
parent_width,
parent_height
);
//
//Now we need to ensure that the above returned sensible values and we
//terminate if not.
//
assert(parent_height > 0);
assert(parent_width > 0);
//
//Now we need to fetch the X windows ID for the child window. This ID
//is what is used to refer to windows within the X windows library.
//
auto child_window = Window_Get_X_Windows_ID(child);
assert(child_window > 0);
//
//Now we need to fetch the X windows ID for the parent window. This ID
//is what is used to refer to windows within the X windows library.
//
auto parent_window = Window_Get_X_Windows_ID(parent);
assert(parent_window > 0);
//
//Now we need to open the X windows display for the X server instance
//that is running. We could also use the DISPLAY environment variable
//but the below is faster as it does not have to fetch the environment.
//
auto display = XOpenDisplay(XDisplayName(nullptr));
assert(display);
//
//Now we need to calculate where to place the child window within the
//parent window. This depends on the size of the child as using the
//centre of the parent can mean that the child window does not fit on
//the 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
)
);
//
//Now we need to ensure that the child window will be transient for the
//parent window.
//
XSetTransientForHint(
display,
child_window,
parent_window
);
//
//Now we need to re-parent the child window to the parent window and we
//set the (X, Y) co-ordinate such that the top left corner of the child
//window will be in the centre of the parent window.
//
XReparentWindow(
display,
child_window,
parent_window,
position_x,
position_y
);
//
//Now we need to flush any changes made to the display.
//
XFlush(display);
//
//Finally, we need to close the display and thus release any resources
//associated with it.
//
XCloseDisplay(display);
}
我看到的是子窗口的所有装饰都被删除,但如果我不使用上面的代码并简单地显示对话框,装饰就会正确呈现。我非常感谢有关如何解决此问题的任何提示。
在堆栈溢出中搜索 XReparentWindow 并找到了一个可能的解决方案(请参阅链接),但对我来说不起作用。
从进一步的研究看来,提示例程的重新父级和设置瞬态总是会删除装饰。因此,为了解决这个问题,我将上面的代码更改为下面的代码。
int child_height;
int child_width;
int parent_display_x;
int parent_display_y;
int parent_height;
int parent_width;
int move_window_x;
int move_window_y;
int position_x;
int position_y;
Window temp_child;
XWindowAttributes child_window_attributes;
XWindowAttributes parent_window_attributes;
//
//First we must validate all parameters and terminate if any fail.
//
assert(parent);
assert(child);
//
//Now we need to fetch the X windows ID for the child window. This ID
//is what is used to refer to windows within the X windows library.
//
auto child_window = Window_Get_X_Windows_ID(child);
assert(child_window > 0);
//
//Now we need to fetch the X windows ID for the parent window. This ID
//is what is used to refer to windows within the X windows library.
//
auto parent_window = Window_Get_X_Windows_ID(parent);
assert(parent_window > 0);
//
//Now we need to open the X windows display for the X server instance
//that is running. We could also use the DISPLAY environment variable
//but the below is faster as it does not have to fetch the environment.
//
auto display = XOpenDisplay(XDisplayName(nullptr));
assert(display);
//
//Now we need to fetch the root window for the display. This allows us
//to fetch the parent window co-ordinates relative to this window and
//thus have an absolute screen position.
//
auto root_window = XDefaultRootWindow(display);
assert(root_window > 0);
//
//Now that we have the child window, we can now fetch the attributes of
//the window and thus be able to obtain such information as the height
//and width.
//
XGetWindowAttributes(
display,
child_window,
&child_window_attributes
);
//
//Now we need to fetch the size of the child window so that we can then
//re-parent the window at the centre of the parent window thus emulating
//the GTKMM 3 set position call. This has been deprecated in GTKMM 4.
//
child_height = child_window_attributes.height;
child_width = child_window_attributes.width;
//
//Now we need to ensure that the above returned sensible values and we
//terminate if not.
//
assert(child_height > 0);
assert(child_width > 0);
//
//Now that we have the parent window, we can now fetch the attributes of
//the window and thus be able to obtain such information as the height
//and width.
//
XGetWindowAttributes(
display,
parent_window,
&parent_window_attributes
);
//
//Now we need to fetch the size of the parent window so that we can then
//re-parent the window at the centre of the parent window thus emulating
//the GTKMM 3 set position call. This has been deprecated in GTKMM 4.
//
parent_height = parent_window_attributes.height;
parent_width = parent_window_attributes.width;
//
//Now we need to ensure that the above returned sensible values and we
//terminate if not.
//
assert(parent_height > 0);
assert(parent_width > 0);
//
//Now we need to calculate where to place the child window within the
//parent window. This depends on the size of the child as using the
//centre of the parent can mean that the child window does not fit on
//the display.
//
position_x =
std::min(
parent_width / 2,
(parent_width - child_width) / 2
);
position_y =
std::min(
parent_height / 2,
(parent_height - child_height) / 2
);
//
//Now we need to ensure that the child window will be transient for the
//parent window.
//
XSetTransientForHint(
display,
child_window,
parent_window
);
//
//Now we need to re-parent the child window to the parent window and we
//set the (X, Y) co-ordinate such that the top left corner of the child
//window will be in the centre of the parent window.
//
// XReparentWindow(
// display,
// child_window,
// parent_window,
// position_x,
// position_y
// );
//
//Now we need to translate the co-ordinates so that we find the position
//of the parent window with respect to the display's root window and
//thus convert (0, 0) which is the top left of the parent window to the
//actual screen co-ordinates.
//
XTranslateCoordinates(
display,
parent_window,
root_window,
0,
0,
&parent_display_x,
&parent_display_y,
&temp_child
);
//
//Now we need to calculate the co-ordinates of where we wish to move the
//child window to.
//
move_window_x =
parent_display_x -
parent_window_attributes.x +
position_x;
move_window_y =
parent_display_y -
parent_window_attributes.y +
position_y;
//
//Now we must check the X co-ordinate and if it is negative (ie the child
//width is more than the parent width) we will set it to zero.
//
if (move_window_x < 0)
{
move_window_x = 0;
}
//
//Now we must check the Y co-ordinate and if it is negative (ie the child
//height is more than the parent height) we will set it to zero.
//
if (move_window_y < 0)
{
move_window_y = 0;
}
//
//Note: The above call to re-parent the child window to the parent window
//causes the decorations on the child window to be removed and the child
//is drawn as part of the parent. What is required to emulate the GTKMM
//3 function is for the window to be decorated and a separate and moveable
//window. So we will move the child window to the required location. The
//only issue is that we need to determine the position of the parent window
//so that we can move the child relative to this. This step is performed
//above via the XTranslateCoordinates function.
//
XMoveWindow(
display,
child_window,
move_window_x,
move_window_y
);
//
//Now we need to flush any changes made to the display.
//
XFlush(display);
//
//Finally, we need to close the display and thus release any resources
//associated with it.
//
XCloseDisplay(display);
因此,首先获取相对于根窗口的 x 窗口坐标,执行一些计算以使窗口在父窗口上居中,然后移动窗口。不完全是我想要的,因为子窗口中心之前有闪烁(由于 gtkmm 中窗口的实现),但至少我可以模拟过时的调用。