简体   繁体   中英

Bring my application window to screen front in Mint

I am writing multi-document text editor. When is called second instance, first instance must go to front. I have Linux Mint 21 and Cinnamon. I tried:

void BringToFront() {
    int pid = getpid();
// Start with the root window.
    Display *display = XOpenDisplay(0);
    WindowsMatchingPid match(display, XDefaultRootWindow(display), pid);
    Display *dsp = XOpenDisplay(NULL);
    long id = match.result()[0];
    XRaiseWindow ( dsp, id );
    XCloseDisplay ( dsp );
}

void MyFrame::OnPoke(wxCommandEvent &event) {
    SetFocus();
    CmdStruct cmdStruct;
    char *data = (char*)event.GetClientData();
    auto argv = cmdStruct.unpack(data);
    for (int i=1; i<argv.size(); i++)
        OpenOrActivate(argv[i]);
    BringToFront();
}

but (especially XRaiseWindow ) it is not enough, my window don't go to front, I must go with Alt+Tab

I see similar topics:

  • X11 How to restore/raise another application window using xcb?
  • How do I bring a processes window to the foreground on X Windows? (C++)
  • X11: Get the list of main windows using xcb
  • How to get an X11 Window from a Process ID?

and I try:

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <unistd.h>
#include <cstdlib>

bool searchHelper(Display* display, Window w, Atom& atomPID, unsigned long pid, Window& result)
{
    bool ret = false;

    Atom atomType;
    int format;
    unsigned long nItems;
    unsigned long bytesAfter;
    unsigned char* propPID = 0;
    if (Success == XGetWindowProperty(display,w,atomPID,0,1,False,XA_CARDINAL,&atomType,&format,&nItems,&bytesAfter,&propPID))
    {
        if (propPID != 0)
        {
            if (pid == *((unsigned long *)propPID))
            {
                result = w;
                ret = true;
            }
            XFree(propPID);
        }
    }

    if (ret)
        return ret; //we found we can stop

    //check the children of the window
    Window wRoot;
    Window wParent;
    Window *wChild=NULL;
    unsigned nChildren=0;
    if (XQueryTree(display, w, &wRoot, &wParent, &wChild, &nChildren) != 0 )
    {
        for (unsigned i=0; i<nChildren; ++i)
        {
            ret = searchHelper(display, wChild[i], atomPID, pid, result);
            if (ret)
                break;
        }
    }
    return ret;
}

bool getWindowFromPid(unsigned long pid, Display* display, Window& result)
{
    Window window = XDefaultRootWindow(display);
    Atom atomPID = XInternAtom(display, "_NET_WM_PID", true);
    if (atomPID == None)
    {
 //       qDebug("XInternAtom failure");
        exit(1);
        return false;
    }
    return searchHelper(display, window, atomPID, pid, result);
}

void BringToFront() {
    Display *display = XOpenDisplay(0);
    // Main window identifier of your application
    Window window;
    int pid = getpid();
    if (getWindowFromPid(pid,display,window))
    {
        //qDebug("Found window ID:%d", window);
        //Need the windowmanger frame (or parent) id not window id
        Window root, parent;
        Window *childlist;
        unsigned int ujunk;
        int status = XQueryTree(display, window, &root, &parent, &childlist, &ujunk);
        if (status && parent && parent != root)
        {
          //  qDebug("Found frame window ID:%d",parent);
            window = parent;
        }

        XSetWindowAttributes xswa;
        xswa.override_redirect=True;
        int result = XChangeWindowAttributes (display,window,CWOverrideRedirect,&xswa);
        //qDebug("XChangeWindowAttributes returned:%d", result);
        result = XRaiseWindow(display,window);

        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 = window;
        event.xclient.format = 32;

        XSendEvent( display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &event );
        XMapRaised( display, window );
        //qDebug("XRaiseWindow returned:%d", result);
    }
    else exit(1);
        //qDebug("unable to find the window for the pid");
}

This brings to front with disadvantages:

  • I must four times call this:
void MyFrame::OnPoke(wxCommandEvent &event) {
    CmdStruct cmdStruct;
    char *data = (char*)event.GetClientData();
    auto argv = cmdStruct.unpack(data);
    for (int i=1; i<argv.size(); i++)
        OpenOrActivate(argv[i]);
    Iconize(false); // restore the window if minimized
    SetFocus();  // focus on my window
    Raise();  // bring window to front
    Show(true); // show the window
    BringToFront();
    BringToFront();
    BringToFront();
    BringToFront();
}

Second: only window is bringing to front, not keyboard focus: If I call my editor from DoubleCommander, my editor is bring to front, but keyboard (for example closing by Alt-F4) is attached to DoubleCommander.

My near quite solution: In Linux, wmctrl command can raise window; need find windows for pid, a call wmctrl.

#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <iostream>

bool searchHelper(Display* display, Window w, Atom& atomPID, unsigned long pid, Window& result)
{
    bool ret = false;

    Atom atomType;
    int format;
    unsigned long nItems;
    unsigned long bytesAfter;
    unsigned char* propPID = 0;
    if (Success == XGetWindowProperty(display,w,atomPID,0,1,False,XA_CARDINAL,&atomType,&format,&nItems,&bytesAfter,&propPID))
    {
        if (propPID != 0)
        {
            if (pid == *((unsigned long *)propPID))
            {
                result = w;
                ret = true;
            }
            XFree(propPID);
        }
    }

    if (ret)
        return result; //we found we can stop

//check the children of the window
    Window wRoot;
    Window wParent;
    Window *wChild=NULL;
    unsigned nChildren=0;
    if (XQueryTree(display, w, &wRoot, &wParent, &wChild, &nChildren) != 0 )
    {
        for (unsigned i=0; i<nChildren; ++i)
        {   //<------------always last found ret?
            ret = searchHelper(display, wChild[i], atomPID, pid, result);
        }
    }
    return result;
}

int pid2wid(int pid) {
    Display *display = XOpenDisplay(0);
    Window window = XDefaultRootWindow(display);
    Atom atomPID = XInternAtom(display, "_NET_WM_PID", true);
    if (atomPID == None)
    {
        return 1;
    }
    Window result;
    searchHelper(display, window, atomPID, pid, result);
    return (int)result;
}

int main(int argc, char **argv) {
    int pid = strtol(argv[1], NULL, 0);
    int wid = pid2wid(pid);
    char buf[20];
    sprintf(buf, "%x", wid);
    std::string strwid = (std::string)"0x" + buf;
    std::cout << "winid=" << strwid << std::endl;
    std::string cmdline = "wmctrl -i -R "+ strwid;
    system(cmdline.c_str());
    return 0;
}

cmake

cmake_minimum_required(VERSION 3.17)
project(pidraiser)

set(CMAKE_CXX_STANDARD 14)

add_executable(pidraiser main.cpp)
target_link_libraries(${PROJECT_NAME}  X11)

Still three questions:

  1. where are wmctrl sources to eliminate call executable?

  2. how in c++ fast detect is X11 or Wayland? (or this way works also in wayland)

  3. in loop

     for (unsigned i=0; i<nChildren; ++i) { //<------------always last found ret? ret = searchHelper(display, wChild[i], atomPID, pid, result); }

correct answer is always found last in loop?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM