I am using "XGrabPointer" to get the mouse click events when ever they occured in the active window.But my requirement is to detect the clicks globally i.e in any application on the X11 desktop.
XGrabPointer blocks the active window so i can not move to other applications and detect the mouse click events.
Here are the codes:
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
int main(int argc, char **argv)
{
Display *display;
XEvent xevent;
Window window;
int grb;
int scr;
if( (display = XOpenDisplay(NULL)) == NULL )
return -1;
unsigned int t_new=0,t_prev=0,t_diff=0;
scr = DefaultScreen(display);
window = RootWindow(display, scr);
while(1) {
XGrabPointer(display,
window,
True,
PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
GrabModeAsync,
GrabModeAsync,
None,
None,
CurrentTime);
XAllowEvents(display,AsyncPointer, CurrentTime);
XNextEvent(display, &xevent);
switch (xevent.type) {
case MotionNotify:{
printf("motion event\n");
break;
}
case ButtonPress:{
switch (xevent.xbutton.button) {
case 1:
printf("Left Click\n");
t_prev=t_new;
printf("Click Occured : [%d, %d]\n",
xevent.xbutton.x_root,
xevent.xbutton.y_root);
break;
case 2:
printf("Grabed\n");
printf("Middle Click\n");
break;
case 3:
printf("Right Click\n");
break;
case 4:
printf("Grabed\n");
printf("Scroll UP\n");
break;
case 5:
printf("Scroll Down\n");
break;
}
break;
}
}
}
XUngrabPointer(display,CurrentTime);
return 0;
}
Couldn't find an answer on how to listen to mouse events in the background as well. It's impossible to do it with mouse grabbing and you won't be able to click anywhere outside of your program.
So the solution is to read linux's /dev/input/mice device for the raw mouse input (we want button clicks) and when a low-level event occur we query X server for mouse position (can't query mouse key presses from X this way).
Display *display;
Window root_window;
XEvent event;
display = XOpenDisplay(0);
root_window = DefaultRootWindow(display);
int fd, bytes;
unsigned char data[3];
const char *pDevice = "/dev/input/mice";
// Open Mouse
fd = open(pDevice, O_RDWR);
if (fd == -1) {
printf("ERROR Opening %s\n", pDevice);
return -1;
}
int left, middle, right;
while (1) {
// Read Mouse
bytes = read(fd, data, sizeof(data));
if (bytes > 0) {
left = data[0] & 0x1;
right = data[0] & 0x2;
middle = data[0] & 0x4;
XQueryPointer(
display,
root_window,
&event.xbutton.root,
&event.xbutton.subwindow,
&event.xbutton.x_root,
&event.xbutton.y_root,
&event.xbutton.x,
&event.xbutton.y,
&event.xbutton.state
);
printf("x=%d, y=%d, left=%d, middle=%d, right=%d\n", event.xmotion.x, event.xmotion.y, left, middle, right);
}
}
Sample output
x=470, y=969, left=1, middle=0, right=0
x=470, y=969, left=0, middle=0, right=0
x=467, y=969, left=0, middle=4, right=0
x=463, y=969, left=0, middle=0, right=0
x=444, y=971, left=0, middle=0, right=2
x=441, y=971, left=0, middle=0, right=0
Related
Hi everyone! I've created such a window (thanks to X11/Xlib: Create "GlassPane"-Window), that is on always on top, semitransparent, and doesn't consume any events. It works fine on some distributions, for example, on ubuntu or debian (after proper set of composite manager). On some distro mouse events can't penetrate through my window (with GNOME WM), on others both mouse and keyboard events can't go through. I am still testing os dependance of my app. Could you give me any tips, why my program is os dependant, is it only wm problem? Is there other way to solve my task and create universal utility that works on all linux distro? Appreciate any help!
/* for corrent exit on termination */
#include <signal.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/shape.h>
#include <X11/extensions/Xfixes.h>
#include <stdio.h>
#include <string.h> // strncmp
#include <unistd.h> // usleep
// all required elements for drawing
struct TXLibConfig
{
Display *dpy;
Window w;
XSetWindowAttributes attr;
XGCValues gcv;
XVisualInfo vinfo;
GC gc;
XserverRegion region;
int winWidth, winHeight;
};
int must_quit = 0;
// Define the function to be called when ctrl-c (SIGINT) is sent to process
void signal_callback_handler(int signum) {
must_quit = 1;
}
int XInit(TXLibConfig *txlibPtr);
int main(int argc, char *argv[]) {
// exit by Ctrl+C and pkill
signal(SIGINT, signal_callback_handler);
signal(SIGTERM, signal_callback_handler);
TXLibConfig tXlibCfg = {0};
XInit(&tXlibCfg);
int ctr = 0;
while(1) {
XClearWindow(tXlibCfg.dpy,tXlibCfg.w);
XSetForeground(tXlibCfg.dpy, tXlibCfg.gc, 0x01808020);
XRectangle rct[] = {300, 300, 200, 200};
XFillRectangles(tXlibCfg.dpy, tXlibCfg.w, tXlibCfg.gc, rct, 1);
XSetForeground(tXlibCfg.dpy, tXlibCfg.gc, 0xf0010140);
XRectangle rectan[] = {350, 350, 10*(ctr % 10 + 1), 10*(ctr % 10 + 1)};
XFillRectangles(tXlibCfg.dpy, tXlibCfg.w, tXlibCfg.gc, rectan, 1);
XFlush(tXlibCfg.dpy);
XSync(tXlibCfg.dpy, True);
ctr++;
usleep(200000);
if (must_quit == 1) break;
}
XClearWindow(tXlibCfg.dpy,tXlibCfg.w);
XDestroyWindow(tXlibCfg.dpy, tXlibCfg.w);
XCloseDisplay(tXlibCfg.dpy);
return 0;
}
int XInit(TXLibConfig *txlibPtr)
{
txlibPtr->dpy = XOpenDisplay(NULL);
if (!txlibPtr->dpy) printf("cannot open display '%s'", XDisplayName(0));
// Get screen resolution >>>>>
int snum;
snum = DefaultScreen(txlibPtr->dpy);
txlibPtr->winWidth = DisplayWidth(txlibPtr->dpy, snum);
txlibPtr->winHeight = DisplayHeight(txlibPtr->dpy, snum);
// Get screen resolution <<<<<
XMatchVisualInfo(txlibPtr->dpy, DefaultScreen(txlibPtr->dpy), 32, TrueColor, &txlibPtr->vinfo);
txlibPtr->attr.colormap = XCreateColormap(txlibPtr->dpy, DefaultRootWindow(txlibPtr->dpy), txlibPtr->vinfo.visual, AllocNone);
txlibPtr->attr.border_pixel = 0;
txlibPtr->attr.background_pixel = 0;
txlibPtr->w = XCreateWindow(txlibPtr->dpy, DefaultRootWindow(txlibPtr->dpy), 0, 0,
txlibPtr->winWidth, txlibPtr->winHeight, 10, txlibPtr->vinfo.depth,
NoEventMask, txlibPtr->vinfo.visual, CWColormap | CWBorderPixel | CWBackPixel, &txlibPtr->attr);
// Ignore any input for passing events to other windows >>>>>
txlibPtr->region = XFixesCreateRegion (txlibPtr->dpy, NULL, 0);
XFixesSetWindowShapeRegion (txlibPtr->dpy, txlibPtr->w, ShapeBounding, 0, 0, 0);
XFixesSetWindowShapeRegion (txlibPtr->dpy, txlibPtr->w, ShapeInput, 0, 0, txlibPtr->region);
XFixesDestroyRegion (txlibPtr->dpy, txlibPtr->region);
// Ignore any input for passing events to other windows <<<<<
txlibPtr->gcv.line_width = 1;
txlibPtr->gc = XCreateGC(txlibPtr->dpy, txlibPtr->w, GCLineWidth, &txlibPtr->gcv);
XSelectInput(txlibPtr->dpy, txlibPtr->w, ExposureMask);
long value = XInternAtom(txlibPtr->dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);
XChangeProperty(txlibPtr->dpy, txlibPtr->w, XInternAtom(txlibPtr->dpy, "_NET_WM_WINDOW_TYPE", False),
6, 32, PropModeReplace, (unsigned char *) &value, 1);
XMapWindow(txlibPtr->dpy, txlibPtr->w);
XFlush(txlibPtr->dpy);
usleep(100000);
return 0;
};
I'm using WinAPI, with C++, I want to make a right click simulation with SendInput, but I'm not sure of what's going wrong.
My test program should work like that: when i press middle button of mouse, it perform a right click.
#include <iostream>
#include <windows.h>
#include <stdio.h>
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
// Fetch tab key state.
while (1)
{
SHORT tabKeyState = GetAsyncKeyState(4); // Mouse mid button
// Test high bit - if set, button was down when GetAsyncKeyState was called.
if (tabKeyState < 0)
{
INPUT Input[2] = { 0 };
// left down
Input[0].type = INPUT_MOUSE;
Input[0].mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;
Input[0].mi.time = 500;
// left up
Input[1].type = INPUT_MOUSE;
Input[1].mi.dwFlags = MOUSEEVENTF_RIGHTUP;
Input[1].mi.time = 500;
::SendInput(2, Input, sizeof(INPUT));
}
}
return 0;
}
In the code to set the properties for the second event record you use index 0 instead of index 1.
Input[1].type = INPUT_MOUSE;
Input[0].mi.dwFlags = MOUSEEVENTF_LEFTUP;
Input[0].mi.time = 100;
Use index 1 rather than 0 in the final two lines.
By the by, it's easier to write the if statement like this
if (tabKeyState < 0)
I solve this question using Sleep to make what i wanted to do and I discovered that the sendinput was not working cause I was executing this inside the VS. This question can be closed now.
I would like to make a key press translator that would "convert" one key press to another, eg. Ctrl+T would be translated to Ctrl+X. I would like it to make "gobal"; to make it work in any application.
As a proof of concept I'm experimenting with the code below but it doesn't work. The problem is that when I capture a key press I send out another key press that is again captured by my code... I'm getting an infinite loop (the counter is there only to break out of the infinite loop).
How should I send out key press event from a key press event handler?
#include <stdio.h>
#include <X11/Xlib.h>
#include <xdo.h>
#include <X11/extensions/XTest.h>
int main(void)
{
Display *dpy = XOpenDisplay(0x0);
XEvent ev;
int counter;
xdo_t *xdo = xdo_new(NULL);
XGrabKeyboard(dpy, DefaultRootWindow(dpy), False,
GrabModeAsync, GrabModeAsync,CurrentTime);
for(counter = 0; counter < 10; counter++)
{
XNextEvent(dpy, &ev);
if(ev.type == KeyPress) {
XUngrabKeyboard(dpy, CurrentTime);
printf("%d %d\n", ev.xkey.keycode, ev.xany.send_event);
xdo_keysequence(xdo, CURRENTWINDOW, "A", 0);
}
}
return 0;
}
I have been playing with OpenCV (I am pretty new to it) to display live camera. What I wanted to do next was to draw lines on it with my mouse. Does anyone know how to do this? So far, what I have is:
#include "stdafx.h"
#include <stdio.h>
#include "cv.h"
#include "highgui.h"
int main( int argc, char **argv )
{
CvCapture *capture = 0;
IplImage *frame = 0;
int key = 0;
/* initialize camera */
capture = cvCaptureFromCAM( 0 );
/* always check */
if ( !capture ) {
fprintf( stderr, "Cannot open initialize webcam!\n" );
return 1;
}
/* create a window for the video */
cvNamedWindow( "Testing", CV_WINDOW_AUTOSIZE );
while( key != 'q' ) {
/* get a frame */
frame = cvQueryFrame( capture );
/* always check */
if( !frame ) break;
/* display current frame */
cvShowImage( "result", frame );
/* exit if user press 'q' */
key = cvWaitKey( 1 );
}
/* free memory */
cvDestroyWindow( "result" );
cvReleaseCapture( &capture );
return 0;
}
If anyone could help me draw lines on the live video, or if anyone knows of any tips, I'd greatly appreciate it! Thanks!
If it helps, here is my code for drawing rectangles on multiple sized video streams
#include "stdafx.h"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#define SSTR( x ) dynamic_cast< std::ostringstream & >(( std::ostringstream() << std::dec << x ) ).str()
using namespace std;
using namespace cv;
Rect box; //global structures needed for drawing
bool drawing_box = false;
struct mousecallbackstruct{
Mat* src;
Mat* overlay;
string windowname;
};
Mat srcoverlay,smallsrcoverlay; //an overlay must be created for each window you want to draw on
void onMouse(int event, int x, int y, int flags, void* param) //it seems the only way to use this is by keeping different globals for different windows - meaning you have to set up all thise ahead of time, and keep track of it and not mix/match windows/frames!! horrible design here.
{
cout << event;
mousecallbackstruct mousestruct;
mousestruct = *((mousecallbackstruct*)param);
Mat* srcp = mousestruct.src;
Mat* overlayp = mousestruct.overlay; // yeah, yeah, i use 7 lines where I could use 3, so sue me
Mat src = *srcp;
Mat overlay = *overlayp;
if(!src.data){
cout << "your void * cast didn't work :(\n";
return;
}
switch( event ){
case CV_EVENT_MOUSEMOVE:
if( drawing_box ){
box.width = x-box.x;
box.height = y-box.y;
}
break;
case CV_EVENT_LBUTTONDOWN: //start drawing
drawing_box = true;
box = cvRect( x, y, 0, 0 );
break;
case CV_EVENT_LBUTTONDBLCLK: //double click to clear
drawing_box = false;
overlay.setTo(cv::Scalar::all(0)); //clear it
break;
case CV_EVENT_LBUTTONUP: //draw what we created with Lbuttondown
drawing_box = false;
if( box.width < 0 ){
box.x += box.width;
box.width *= -1;
}
if( box.height < 0 ){
box.y += box.height;
box.height *= -1;
}
rectangle( overlay, Point(box.x, box.y), Point(box.x+box.width,box.y+box.height),CV_RGB(100,200,100),4); //draw rectangle. You can change this to line or circle or whatever. Maybe with the Right mouse button.
break;
}
}
void iimshow(mousecallbackstruct* mystructp){ //this is where we add the text/drawing created in the mouse handler to the actual image (since mouse handler events do not coincide with the drawing events)
mousecallbackstruct mystruct = *mystructp; //custom struct made for the mouse callback - very handy for other functions too
Mat overlay, src;
Mat* srcp = mystruct.src;
Mat* overlayp = mystruct.overlay;
src = *srcp; // yeah, yeah, i use 9 lines where I could use 3, so sue me
overlay = *overlayp;
string name = mystruct.windowname;
Mat added,imageROI;
try{
//cout << "tch:" << overlay.rows << "," << src.rows << ";" << overlay.cols << "," << src.cols << ";" << src.channels() << "," << overlay.channels() <<"," << src.type() << "," << overlay.type() << "\n";
if(overlay.data && overlay.rows == src.rows && overlay.cols == src.cols && overlay.channels() == src.channels()){ //basic error checking
add(src,overlay,added);
}else{
//try to resize it
imageROI= overlay(Rect(0,0,src.cols,src.rows));
add(src,imageROI,added);
}
imshow(name,added);// the actual draw moment
}catch(...){ //if resize didn't work then this should catch it and you can see what didn't match up
cout << "Error. Mismatch:" << overlay.rows << "," << src.rows << ";" << overlay.cols << "," << src.cols << ";" << src.channels() << "," << overlay.channels() <<"," << src.type() << "," << overlay.type() << "\n";
imshow(name + "overlay",overlay);
imshow(name+"source",src);
}
}
int _tmain(int argc, _TCHAR* argv[]){
VideoCapture cap(0); // open the default camera
if(!cap.isOpened()) { // check if we succeeded
cout << "NO camera found \n";
return -1;
}
Mat src,smallsrc,overlay;
cap >> src; //grab 1 frame to build our preliminary Mats and overlays
srcoverlay.create(src.rows,src.cols,src.type()); //create overlays
smallsrcoverlay.create(src.rows,src.cols,src.type());
srcoverlay.setTo(cv::Scalar::all(0)); //clear it
smallsrcoverlay.setTo(cv::Scalar::all(0)); //clear it
namedWindow( "smallsrc", CV_WINDOW_AUTOSIZE );
namedWindow( "source", CV_WINDOW_AUTOSIZE ); //these must be created early for the setmousecallback, AND you have to know what Mats will be using them and not switch them around :(
moveWindow("smallsrc",1000,100); //create a small original capture off to the side of screen
////////////// for each window/mat that uses a mouse handler, you must create one of these structures for it and pass it into the mouse handler, and add a global mat for overlays (at top of code)
mousecallbackstruct srcmousestruct,smallsrcmousestruct; //these get passed into the mouse callback function. Hopefully they update their contents automatically for the callback? :(
srcmousestruct.overlay = &srcoverlay; //fill our custom struct
srcmousestruct.src = &src;
srcmousestruct.windowname = "source";
smallsrcmousestruct.overlay = &smallsrcoverlay; //the small window
smallsrcmousestruct.src = &smallsrc;
smallsrcmousestruct.windowname = "smallsrc";
setMouseCallback(smallsrcmousestruct.windowname, onMouse, (void*)&smallsrcmousestruct); //the actual 'set mouse callback' call
setMouseCallback(srcmousestruct.windowname, onMouse, (void*)&srcmousestruct);
for(;;){ //main loop
/// Load an image
cap >> src;
if( !src.data )
{ return -1; }
resize(src,smallsrc,Size(),.5,.5); //smaller scale window of original
overlay = *srcmousestruct.overlay;
src = *srcmousestruct.src;
iimshow(&srcmousestruct); //my imshow replacement. uses structs
iimshow(&smallsrcmousestruct);
if(waitKey(30) == 27) cin.get(); //esc pauses
}
cin.get();
return 0;
}
You will have to be more clear as to what you mean by drawing on the video.
One option is to handle the mouse positions, by drawing the lines between them, on a black/blank "mask" image, and "apply" this image to each video frame before it is displayed.
To capture mouse events you need to create a callback. This callback will be tied to a specific named window. The documentation for the call cvSetMouseCallback is pretty good. The callback function will know current position and button click information. From there you can capture points on mouse clicks and use those points with cvLine to draw on your frame.
Under Linux, my C++ application is using fork() and execv() to launch multiple instances of OpenOffice so as to view some powerpoint slide shows. This part works.
Next I want to be able to move the OpenOffice windows to specific locations on the display. I can do that with the XMoveResizeWindow() function but I need to find the Window for each instance.
I have the process ID of each instance, how can I find the X11 Window from that ?
UPDATE - Thanks to Andy's suggestion, I have pulled this off. I'm posting the code here to share it with the Stack Overflow community.
Unfortunately Open Office does not seem to set the _NET_WM_PID property so this doesn't ultimately solve my problem but it does answer the question.
// Attempt to identify a window by name or attribute.
// by Adam Pierce <adam#doctort.org>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <iostream>
#include <list>
using namespace std;
class WindowsMatchingPid
{
public:
WindowsMatchingPid(Display *display, Window wRoot, unsigned long pid)
: _display(display)
, _pid(pid)
{
// Get the PID property atom.
_atomPID = XInternAtom(display, "_NET_WM_PID", True);
if(_atomPID == None)
{
cout << "No such atom" << endl;
return;
}
search(wRoot);
}
const list<Window> &result() const { return _result; }
private:
unsigned long _pid;
Atom _atomPID;
Display *_display;
list<Window> _result;
void search(Window w)
{
// Get the PID for the current Window.
Atom type;
int format;
unsigned long nItems;
unsigned long bytesAfter;
unsigned char *propPID = 0;
if(Success == XGetWindowProperty(_display, w, _atomPID, 0, 1, False, XA_CARDINAL,
&type, &format, &nItems, &bytesAfter, &propPID))
{
if(propPID != 0)
{
// If the PID matches, add this window to the result set.
if(_pid == *((unsigned long *)propPID))
_result.push_back(w);
XFree(propPID);
}
}
// Recurse into child windows.
Window wRoot;
Window wParent;
Window *wChild;
unsigned nChildren;
if(0 != XQueryTree(_display, w, &wRoot, &wParent, &wChild, &nChildren))
{
for(unsigned i = 0; i < nChildren; i++)
search(wChild[i]);
}
}
};
int main(int argc, char **argv)
{
if(argc < 2)
return 1;
int pid = atoi(argv[1]);
cout << "Searching for windows associated with PID " << pid << endl;
// Start with the root window.
Display *display = XOpenDisplay(0);
WindowsMatchingPid match(display, XDefaultRootWindow(display), pid);
// Print the result.
const list<Window> &result = match.result();
for(list<Window>::const_iterator it = result.begin(); it != result.end(); it++)
cout << "Window #" << (unsigned long)(*it) << endl;
return 0;
}
The only way I know to do this is to traverse the tree of windows until you find what you're looking for. Traversing isn't hard (just see what xwininfo -root -tree does by looking at xwininfo.c if you need an example).
But how do you identify the window you are looking for? Some applications set a window property called _NET_WM_PID.
I believe that OpenOffice is one of the applications that sets that property (as do most Gnome apps), so you're in luck.
Check if /proc/PID/environ contains a variable called WINDOWID
Bit late to the party. However:
Back in 2004, Harald Welte posted a code snippet that wraps the XCreateWindow() call via LD_PRELOAD and stores the process id in _NET_WM_PID. This makes sure that each window created has a PID entry.
http://www.mail-archive.com/devel#xfree86.org/msg05806.html
Try installing xdotool, then:
#!/bin/bash
# --any and --name present only as a work-around, see: https://github.com/jordansissel/xdotool/issues/14
ids=$(xdotool search --any --pid "$1" --name "dummy")
I do get a lot of ids. I use this to set a terminal window as urgent when it is done with a long command, with the program seturgent. I just loop through all the ids I get from xdotool and run seturgent on them.
There is no good way. The only real options I see, are:
You could look around in the process's address space to find the connection information and window ID.
You could try to use netstat or lsof or ipcs to map the connections to the Xserver, and then (somehow! you'll need root at least) look at its connection info to find them.
When spawning an instance you can wait until another window is mapped, assume it's the right one, and `move on.
I took the freedom to re-implement the OP's code using some modern C++ features. It maintains the same functionalities but I think that it reads a bit better. Also it does not leak even if the vector insertion happens to throw.
// Attempt to identify a window by name or attribute.
// originally written by Adam Pierce <adam#doctort.org>
// revised by Dario Pellegrini <pellegrini.dario#gmail.com>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <iostream>
#include <vector>
std::vector<Window> pid2windows(pid_t pid, Display* display, Window w) {
struct implementation {
struct FreeWrapRAII {
void * data;
FreeWrapRAII(void * data): data(data) {}
~FreeWrapRAII(){ XFree(data); }
};
std::vector<Window> result;
pid_t pid;
Display* display;
Atom atomPID;
implementation(pid_t pid, Display* display): pid(pid), display(display) {
// Get the PID property atom
atomPID = XInternAtom(display, "_NET_WM_PID", True);
if(atomPID == None) {
throw std::runtime_error("pid2windows: no such atom");
}
}
std::vector<Window> getChildren(Window w) {
Window wRoot;
Window wParent;
Window *wChild;
unsigned nChildren;
std::vector<Window> children;
if(0 != XQueryTree(display, w, &wRoot, &wParent, &wChild, &nChildren)) {
FreeWrapRAII tmp( wChild );
children.insert(children.end(), wChild, wChild+nChildren);
}
return children;
}
void emplaceIfMatches(Window w) {
// Get the PID for the given Window
Atom type;
int format;
unsigned long nItems;
unsigned long bytesAfter;
unsigned char *propPID = 0;
if(Success == XGetWindowProperty(display, w, atomPID, 0, 1, False, XA_CARDINAL,
&type, &format, &nItems, &bytesAfter, &propPID)) {
if(propPID != 0) {
FreeWrapRAII tmp( propPID );
if(pid == *reinterpret_cast<pid_t*>(propPID)) {
result.emplace_back(w);
}
}
}
}
void recurse( Window w) {
emplaceIfMatches(w);
for (auto & child: getChildren(w)) {
recurse(child);
}
}
std::vector<Window> operator()( Window w ) {
result.clear();
recurse(w);
return result;
}
};
//back to pid2windows function
return implementation{pid, display}(w);
}
std::vector<Window> pid2windows(const size_t pid, Display* display) {
return pid2windows(pid, display, XDefaultRootWindow(display));
}
int main(int argc, char **argv) {
if(argc < 2)
return 1;
int pid = atoi(argv[1]);
std::cout << "Searching for windows associated with PID " << pid << std::endl;
// Start with the root window.
Display *display = XOpenDisplay(0);
auto res = pid2windows(pid, display);
// Print the result.
for( auto & w: res) {
std::cout << "Window #" << static_cast<unsigned long>(w) << std::endl;
}
XCloseDisplay(display);
return 0;
}
Are you sure you have the process ID of each instance? My experience with OOo has been that trying to run a second instance of OOo merely converses with the first instance of OOo, and tells that to open the additional file.
I think you're going to need to use the message-sending capabilities of X to ask it nicely for its window. I would hope that OOo documents its coversations somewhere.
If you use python, I found a way here, the idea is from BurntSushi
If you launched the application, then you should know its cmd string, with which you can reduce calls to xprop, you can always loop through all the xids and check if the pid is the same as the pid you want
import subprocess
import re
import struct
import xcffib as xcb
import xcffib.xproto
def get_property_value(property_reply):
assert isinstance(property_reply, xcb.xproto.GetPropertyReply)
if property_reply.format == 8:
if 0 in property_reply.value:
ret = []
s = ''
for o in property_reply.value:
if o == 0:
ret.append(s)
s = ''
else:
s += chr(o)
else:
ret = str(property_reply.value.buf())
return ret
elif property_reply.format in (16, 32):
return list(struct.unpack('I' * property_reply.value_len,
property_reply.value.buf()))
return None
def getProperty(connection, ident, propertyName):
propertyType = eval(' xcb.xproto.Atom.%s' % propertyName)
try:
return connection.core.GetProperty(False, ident, propertyType,
xcb.xproto.GetPropertyType.Any,
0, 2 ** 32 - 1)
except:
return None
c = xcb.connect()
root = c.get_setup().roots[0].root
_NET_CLIENT_LIST = c.core.InternAtom(True, len('_NET_CLIENT_LIST'),
'_NET_CLIENT_LIST').reply().atom
raw_clientlist = c.core.GetProperty(False, root, _NET_CLIENT_LIST,
xcb.xproto.GetPropertyType.Any,
0, 2 ** 32 - 1).reply()
clientlist = get_property_value(raw_clientlist)
cookies = {}
for ident in clientlist:
wm_command = getProperty(c, ident, 'WM_COMMAND')
cookies[ident] = (wm_command)
xids=[]
for ident in cookies:
cmd = get_property_value(cookies[ident].reply())
if cmd and spref in cmd:
xids.append(ident)
for xid in xids:
pid = subprocess.check_output('xprop -id %s _NET_WM_PID' % xid, shell=True)
pid = re.search('(?<=\s=\s)\d+', pid).group()
if int(pid) == self.pid:
print 'found pid:', pid
break
print 'your xid:', xid