How do I bring a processes window to the foreground on X Windows? (C++)

前端 未结 5 2013
小鲜肉
小鲜肉 2020-12-25 08:47

I have the PID for the process (and the name), I want to bring it to the front on linux (ubuntu). On mac I would simply do SetFrontProcess(pid), on windows I\'d

相关标签:
5条回答
  • 2020-12-25 08:55

    There is a command line tool that can do this: wmctrl. The source code of the tool is here (C++): wmctrl sources

    Relevant part of the code (you will need to get some of the functions used here from the project under the link above):

    static int activate_window (Display *disp, Window win, /* {{{ */
        gboolean switch_desktop) {
    unsigned long *desktop;
    
    /* desktop ID */
    if ((desktop = (unsigned long *)get_property(disp, win,
            XA_CARDINAL, "_NET_WM_DESKTOP", NULL)) == NULL) {
        if ((desktop = (unsigned long *)get_property(disp, win,
                XA_CARDINAL, "_WIN_WORKSPACE", NULL)) == NULL) {
            p_verbose("Cannot find desktop ID of the window.\n");
        }
    }
    
    if (switch_desktop && desktop) {
        if (client_msg(disp, DefaultRootWindow(disp), 
                    "_NET_CURRENT_DESKTOP", 
                    *desktop, 0, 0, 0, 0) != EXIT_SUCCESS) {
            p_verbose("Cannot switch desktop.\n");
        }
        g_free(desktop);
    }
    
    client_msg(disp, win, "_NET_ACTIVE_WINDOW", 
            0, 0, 0, 0, 0);
    XMapRaised(disp, win);
    
    return EXIT_SUCCESS;
    }
    

    Hint: remember to call

    XCloseDisplay(display);
    

    Somewhere after the call to this function or you will see no effect.

    0 讨论(0)
  • 2020-12-25 09:02

    I had this issue in my application as well, so here's the solution.

    To raise the window you need not only to raise it, but you also need to notify the WM about it. The following code could be used:

            // This is how to get it in Qt; if you don't use it,
            // you can call XOpenDisplay and get it from there;
            Display * display = x11Info().display();
    
            // Main window identifier of your application
            WId win = winId();
    
            XEvent event = { 0 };
            event.xclient.type = ClientMessage;
            event.xclient.serial = 0;
            event.xclient.send_event = True;
            event.xclient.message_type = XInternAtom( display, "_NET_ACTIVE_WINDOW", False);
            event.xclient.window = win;
            event.xclient.format = 32;
    
            XSendEvent( display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &event );
            XMapRaised( display, win );
    
    0 讨论(0)
  • 2020-12-25 09:05

    I haven't tried this myself, but putting these two methods together may work:

    The XRaiseWindow API Call in xlib lets you raise a Window to the front if you know the Window ID.

    http://www.unix.com/man-page/Linux/3/XRaiseWindow/

    This stackoverflow answer explains how to get a Window ID from a PID:

    How to get an X11 Window from a Process ID?

    EDIT:

    I've had limited success with XRaiseWindow. The Following program does work under twm window manager, but not ion which I usually use. The Window Manager must have ways of preventing applications from 'popping up'. To make this work, i also had to pass it the Window ID of the Window Manager's frame for the window, not the window itself. run xwininfo -frame and click on the window and you get the frame ID instead, compile this program with gcc test.c -lX and pass it that hexid on the command line and it will raise the window.

     #include <stdio.h>
     #include <stdlib.h>
     #include <X11/Xlib.h>
    
     int main(int argc, char **argv)
     {
       Display *dsp = XOpenDisplay(NULL);
       long id = strtol(argv[1], NULL, 16);
       XSetWindowAttributes xswa;
       xswa.override_redirect=True;
       XChangeWindowAttributes (dsp,id,CWOverrideRedirect, &xswa);
       XRaiseWindow ( dsp, id );
       XCloseDisplay ( dsp );
     }
    
    0 讨论(0)
  • 2020-12-25 09:06

    I thought this would be easy since /proc seemingly has the required data but /proc/${pid}/environ doesn't provide the correct window ID since it is usually the child of the parent who really owns the window where the process is running. To get the proper windowid you need to parse the xwininfo output then you can use xdotool to change the focus.

    CMD_PID=<your pid here> && while IFS= read -r -d '' var; do 
    if grep -q "^WINDOWID=" <<< "$var"; then 
     winid=$(printf '0x%x\n' $(sed 's/WINDOWID=//' <<< "${var}"))
     child_cnt=0 && IFS=$(echo -en "\n\b") && for a in $(xwininfo -root -tree | tac | sed -n "/${winid}/,\$p"); do 
     grep -q -i "children" <<< "${a}" && let child_cnt+=1
     ((${child_cnt} == 2)) && real_winid=$(grep -o '0x[^ ]*' <<< "${last_line}") && break
     last_line="${a}"
     done 
     xdotool windowraise ${real_winid} 
     break 
    fi 
    done < /proc/${CMD_PID}/environ
    
    0 讨论(0)
  • 2020-12-25 09:09

    From the bash command line, you could also use the terrific xdotool, which lets you specify the following to raise the XBMC window and type a backslash into it:

    xdotool search --name 'XBMC Media Center' windowactivate  --sync key backslash
    

    This program has an actual library under it, libxdo2, which you could use instead if XRaiseWindow fails you. I understand that libxdo goes to some lengths to always raise the window, regardless of windowmanager.

    0 讨论(0)
提交回复
热议问题