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:
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:
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:
where are wmctrl sources to eliminate call executable?
how in c++ fast detect is X11 or Wayland? (or this way works also in wayland)
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.