0

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.

BRS
  • 1
  • 2

1 Answers1

0

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.

SRB
  • 1
  • 2