Search code examples
c#linuxmonox11

Cannot get window to permanently reparent using XReparentWindow


I'm working on a WinForms mono application for personal use that manages remote connections. I've been trying to figure out a way to reparent certain X11 windows into my WinForms application. I have this functionality working perfectly on windows however the X11 API in linux is giving me issues.

I understand this is probably a waste of time as there are better solutions however I am deep into it now and would at least like to know why this is not working and maybe if there is a solution.

I would like to reparent Putty SSH terminal window into a WinForms panel (the WinForms program is running in mono). I am able to accomplish this using XReparentWindow however after a second the Putty window will unparent back to the root window. It will not stay parented to the WinForms panel.

These are the API calls I am using to reparent the Putty window:

private static void ReparentWindow()
{
    IntPtr display = XOpenDisplay(Environment.GetEnvironmentVariable("DISPLAY"));
    IntPtr puttyWindowHandle = [handle_of_putty_window]; //I have a function here that finds a window by title and returns the handle
    IntPtr panelHandle = panTestPanel.Handle;

    XReparentWindow(display, puttyWindowHandle, panelHandle, 0, 0);
    XMapWindow(display, puttyWindowHandle);
    XFlush(display);
    XSync(display, false);
}

I have tried this with other program as well and have found that some will parent just find (calculator, gedit) and others, notably terminal applications, will not stay parented at all. I do not know enough about X11 to understand why this is and if there is a solution. I suspect it has something to do with the terminal applications waiting for input though I also tried to reparent gxlgears as a test and it has the same issue and so I'm not sure.

Any help or suggestions would be appreciated.

Updated solution:

private static void ReparentWindow()
{
    IntPtr display = XOpenDisplay(Environment.GetEnvironmentVariable("DISPLAY"));
    IntPtr puttyWindowHandle = [handle_of_putty_window]; //I have a function here that finds a window by title and returns the handle
    IntPtr panelHandle = panTestPanel.Handle;

    //Set the override redirect flag on the window we want to reparent
    XSetWindowAttributes xSetWindowAttributes = new XSetWindowAttributes();
    xSetWindowAttributes.override_redirect = true;

    IntPtr attr = Marshal.AllocHGlobal (Marshal.SizeOf (xSetWindowAttributes));
    Marshal.StructureToPtr (xSetWindowAttributes, attr, false);

    XChangeWindowAttributes (display, puttyWindowHandle, XWindowAttributeFlags.CWOverrideRedirect, attr);

    Marshal.FreeHGlobal (attr);

    //Reparent the window
    XReparentWindow(display, puttyWindowHandle, panelHandle, 0, 0);
    XReparentWindow(display, puttyWindowHandle, panelHandle, 0, 0);
    XMapWindow(display, puttyWindowHandle);
    XFlush(display);
    XSync(display, false);
}

Solution

  • Alright I found the solution to my question. Most likely it was Cinnamon and it's window manager causing issues when ever I would reparent the window. To stop Cinnamon from unparenting I had to set the override redirect flag to True on the window I wanted to reparent. Oddly enough though I needed to do XReparentWindow twice after setting the flag in order to get the window to properly reparent. Not sure why this is but it works. However after the window reparents it no longer updates graphically. I'm still working on this issue.

    I have updated the original post with the modified code.