I am attempting to re-parent a child window Gtk::Window so that I can emulate the deprecated GTKMM 4 call to position the window in the centre of the parent (which was present in GTKMM 3). I have searched for XReparentWindow posts and the only relevant one advised to use XSetTransientForHint this which did not work for me. The code that I have written is:
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);
}
What I see is that all of the decorations for the child window are removed but if I do not use the above code and simply display the dialog the decorations are rendered correctly. I would very much appreciate any hints on how to solve this problem.
Searched for XReparentWindow within stack overflow and found a possible solution (see link) that did not work for me.
From further research it appears that the reparent and set transient for hint routines will always remove the decorations. So to solve the problem I changed the above code to the below.
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);
So first you obtain your x window coordinates with respect to the root window, perform some calculations to centre the window on the parent and then move the window. Not exactly what I wanted as there is a flicker before the child window centres (due to the realising of the window in gtkmm) but at least I can emulate the obsolete call.