X11: Get the list of main windows using xcb - x11

I'm trying to get the list of the main windows of already launched X applications, with a C program using xcb library. It seems these windows are the "top-level windows" according to this question: X11: list top level windows
So my program asks Openbox window manager to give the list of these windows, and then asks the name of each window, but it doesn't work. I'm using EWMH atoms, and I have read that Openbox is EWMH compliant.
Edit: And when I run the console command: xprop -root _NET_CLIENT_LIST, it gives the identifier of a few windows. So it seems Openbox support this atom. I looked at the code of xprop, but it is written with Xlib, and I need to use xcb because of multithreading support.
When My program get a reply from Openbox, the length of the reply is 0.
Here is the source code:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <xcb/xcb.h>
xcb_atom_t getatom(xcb_connection_t* c, char *atom_name)
{
xcb_intern_atom_cookie_t atom_cookie;
xcb_atom_t atom;
xcb_intern_atom_reply_t *rep;
atom_cookie = xcb_intern_atom(c, 0, strlen(atom_name), atom_name);
rep = xcb_intern_atom_reply(c, atom_cookie, NULL);
if (NULL != rep)
{
atom = rep->atom;
free(rep);
printf("\natom: %ld",atom);
fflush(stdout);
return atom;
}
printf("\nError getting atom.\n");
exit(1);
}
int main() {
xcb_generic_error_t *e;
int i,j,k;
xcb_connection_t* c = xcb_connect(NULL, NULL);
xcb_atom_t net_client_list = getatom(c,"_NET_CLIENT_LIST");
xcb_atom_t net_wm_visible_name = getatom(c,"_NET_WM_VISIBLE_NAME");
xcb_screen_t* screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
xcb_get_property_cookie_t prop_cookie_list,prop_cookie;
xcb_get_property_reply_t *reply_prop_list,*reply_prop;
prop_cookie_list = xcb_get_property(c, 0, screen->root, net_client_list, XCB_GET_PROPERTY_TYPE_ANY, 0, 0);
reply_prop_list = xcb_get_property_reply(c, prop_cookie_list, &e);
if(e) {
printf("\nError: %d",e->error_code);
free(e);
}
if(reply_prop_list) {
int value_len = xcb_get_property_value_length(reply_prop_list);
printf("\nvalue_len: %d",value_len);
if(value_len) {
xcb_window_t* win = xcb_get_property_value(reply_prop_list);
for(i=0; i<value_len; i++) {
prop_cookie = xcb_get_property(c, 0, win[i], net_wm_visible_name, XCB_GET_PROPERTY_TYPE_ANY, 0, 0);
reply_prop = xcb_get_property_reply(c, prop_cookie, &e);
if(e) {
printf("\nError: %d",e->error_code);
free(e);
}
if(reply_prop) {
int value_len2 = xcb_get_property_value_length(reply_prop);
printf("\nvalue_len2: %d",value_len2);
if(value_len2) {
char* name = xcb_get_property_value(reply_prop);
printf("\nName: %s",name);
fflush(stdout);
}
free(reply_prop);
}
}
}
free(reply_prop_list);
}
printf("\n\n");
fflush(stdout);
exit(0);
}

I finally found the problem, in the examples I have read on internet, the field long_length of xcb_get_property() was set to 0, but it seems that to get a consistant reply, the field must have a value higher or equal to the number of 32 bits words that the reply will have. So I have chosen 100 for my test, but if there is more than 100 top-level windows in the children tree of the specified root window, then the reply will be truncated to the 100 first windows.
I also had to divide value_len by 4 to get the number of elements in the reply, because value_len is in bytes, and the reply value is an array of xcb_window_t elements, each beiing 4 bytes long.
To get the name of each top-level window, I have chosen to set to 1000 the field long_length of xcb_get_property(), in order to be sure to have the complete name. But it seems that in the reply, the true size of the string is allocated without the final \0 character, so I had to allocate a memory block of length value_len2 + 1, and then use strncpy() to copy the string to this new location. And finally, add the final \0 character.
Here is the correct code to get the property:
prop_cookie_list = xcb_get_property(c, 0, screen->root, net_client_list, XCB_GET_PROPERTY_TYPE_ANY, 0, 100);
reply_prop_list = xcb_get_property_reply(c, prop_cookie_list, &e);
if(e) {
printf("\nError: %d",e->error_code);
free(e);
}
if(reply_prop_list) {
int value_len = xcb_get_property_value_length(reply_prop_list);
printf("\nvalue_len: %d",value_len);
if(value_len) {
xcb_window_t* win = xcb_get_property_value(reply_prop_list);
for(i=0; i<value_len/4; i++) {
printf("\n--------------------------------\nwin id: %d",win[i]);
prop_cookie = xcb_get_property(c, 0, win[i], net_wm_visible_name, XCB_GET_PROPERTY_TYPE_ANY, 0, 1000);
reply_prop = xcb_get_property_reply(c, prop_cookie, &e);
if(e) {
printf("\nError: %d",e->error_code);
free(e);
}
if(reply_prop) {
int value_len2 = xcb_get_property_value_length(reply_prop);
printf("\nvalue_len2: %d",value_len2);
if(value_len2) {
char* name = malloc(value_len2+1);
strncpy(name,xcb_get_property_value(reply_prop),value_len2);
name[value_len2] = '\0';
printf("\nName: %s",name);
fflush(stdout);
free(name);
}
free(reply_prop);
}
}
}
free(reply_prop_list);
}

Related

linux X11, how to create transparent and insensitive to events window, non-dependant of window manager

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;
};

How can I force all events from one device to be handled by one window, while allowing all other events from all other devices to be handled normally?

I have an application that is used as a control system for a presentation, under Linux and using X11. I have a USB presentation remote that acts as a very miniature keyboard (four buttons: Page Up, Page Down, and two others) which can be used to advance and go back in the presentation. I would like to have my presentation application to receive all of the events from this remote regardless of where the mouse focus is. But I would also like to be able to receive the normal mouse and keyboard events if the current window focus is on the presentation application. Using XIGrabDevice() I was able to receive all events from the remote in the presentation application regardless of the current focus but I was not able to receive any events from the mouse or keyboard while the grab was active.
I ended up setting up a separate program to capture the remote's keys, then I relay those keys to my main program. I did it this way because the original program was using the older XInput extension, and I needed to use the newer XInput2 extension, and they do not exist well together. Here's some C++ code (it doesn't do any error checking, but this should be done in a real program):
// Open connection to X Server
Display *dpy = XOpenDisplay(NULL);
// Get opcode for XInput Extension; we'll need it for processing events
int xi_opcode = -1, event, error;
XQueryExtension(dpy, "XInputExtension", &xi_opcode, &event, &error);
// Allow user to select a device
int num_devices;
XIDeviceInfo *info = XIQueryDevice(dpy, XIAllDevices, &num_devices);
for (int i = 0; i < num_devices; ++i)
{
XIDeviceInfo *dev = &info[i];
std::cout << dev->deviceid << " " << dev->name << "\n";
}
XIFreeDeviceInfo(info);
std::cout << "Enter the device number: ";
std::string input;
std::cin >> input;
int deviceid = -1;
std::istringstream istr(input);
istr >> deviceid;
// Create an InputOnly window that is just used to grab events from this device
XSetWindowAttributes attrs;
long attrmask = 0;
memset(&attrs, 0, sizeof(attrs));
attrs.override_redirect = True; // Required to grab device
attrmask |= CWOverrideRedirect;
Window win = XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, 1, 1, 0, 0, InputOnly, CopyFromParent, attrmask, &attrs);
// Make window without decorations
PropMotifWmHints hints;
hints.flags = 2;
hints.decorations = 0;
Atom property = XInternAtom(dpy, "_MOTIF_WM_HINTS", True);
XChangeProperty(dpy, win, property, property, 32, PropModeReplace, (unsigned char *)&hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
// We are interested in key presses and hierarchy changes. We also need to get key releases or else we get an infinite stream of key presses.
XIEventMask evmasks[1];
unsigned char mask0[XIMaskLen(XI_LASTEVENT)];
memset(mask0, 0, sizeof(mask0));
XISetMask(mask0, XI_KeyPress);
XISetMask(mask0, XI_KeyRelease);
XISetMask(mask0, XI_HierarchyChanged);
evmasks[0].deviceid = XIAllDevices;
evmasks[0].mask_len = sizeof(mask0);
evmasks[0].mask = mask0;
XISelectEvents(dpy, win, evmasks, 1);
XMapWindow(dpy, win);
XFlush(dpy);
XEvent ev;
bool grab_success = false, grab_changed;
while (1)
{
grab_changed = false;
if (!grab_success)
{
XIEventMask masks[1];
unsigned char mask0[XIMaskLen(XI_LASTEVENT)];
memset(mask0, 0, sizeof(mask0));
XISetMask(mask0, XI_KeyPress);
masks[0].deviceid = deviceid;
masks[0].mask_len = sizeof(mask0);
masks[0].mask = mask0;
XIGrabDevice(dpy, deviceid, win, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, XIOwnerEvents, masks);
}
XNextEvent(dpy, &ev);
XGenericEventCookie *cookie = &ev.xcookie;
if (cookie->type == GenericEvent && cookie->extension == xi_opcode && XGetEventData(dpy, cookie))
{
if (cookie->evtype == XI_KeyPress)
{
XIDeviceEvent *de = (XIDeviceEvent*)cookie->data;
std::cout << "found XI_KeyPress event: keycode " << de->detail << "\n";
}
else if (cookie->evtype == XI_HierarchyChanged)
{
// Perhaps a device was unplugged. The client is expected to re-read the list of devices to find out what changed.
std::cout << "found XI_HierarchyChanged event.\n";
grab_changed = true;
}
XFreeEventData(dpy, cookie);
}
if (grab_changed)
{
XIUngrabDevice(dpy, deviceid, CurrentTime);
grab_success = false;
break;
}
}
I found the following links helpful:
Peter Hutterer's 6-part blog on XInput2: 1 2 3 4 5 6
This blog entry was useful to determine which class to cast the cookie->data pointer to, depending on the cookie->evtype: 7

DICOM Convert 16 bit to 8bit

Big Trees:
I deeply want to find the solution of follow question:
I want to convert the pixeldata of dicom file to 8bit(byte[]) which the file BitsAllocated was 16bit.
whatever it's the Grayscale or Color.
also I know the Color's SimplePerPixel is 3.
3Q!!!!
You cannot simply take the pixel data and transform it to 8 bit (unless you are sure that all the values are ALREADY in the range supported by a byte).
This because you would alter important data: the Dicom file may store the pixel data in visual density units or Hounsfield units, and modifying the values may screw up things.
You can apply the transformation to 8 bits to the presentation data, the values resulting from the modality VOI/LUT and presentation VOI/LUT transformations.
This example that uses the imebra library uses the presentation data to obtain a 8 bits per color channel image, that is then saved in jpeg format.
Modify the color space from YBR_FULL to RGB in both the color transform and the image allocation in order to get an RGB image.
Example (in case the link changes):
/*
Imebra 2011 build 2013-07-16_08-42-08
Imebra: a C++ Dicom library
Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 by Paolo Brandoli/Binarno s.p.
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as published by
the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-------------------
If you want to use Imebra commercially then you have to buy the commercial
support available at http://imebra.com
After you buy the commercial support then you can use Imebra according
to the terms described in the Imebra Commercial License Version 1.
A copy of the Imebra Commercial License Version 1 is available in the
documentation pages.
Imebra is available at http://imebra.com
The author can be contacted by email at info#binarno.com or by mail at
the following address:
Paolo Brandoli
Rakuseva 14
1000 Ljubljana
Slovenia
*/
#include <iostream>
#include "../../library/imebra/include/imebra.h"
#include <sstream>
#ifdef PUNTOEXE_WINDOWS
#include <process.h>
#else
#include <spawn.h>
#include <sys/wait.h>
#endif
#include <memory>
#include <list>
using namespace puntoexe;
using namespace puntoexe::imebra;
int findArgument(const char* argument, int argc, char* argv[])
{
for(int scanArg(0); scanArg != argc; ++scanArg)
{
if(std::string(argv[scanArg]) == argument)
{
return scanArg;
}
}
return -1;
}
int main(int argc, char* argv[])
{
std::wstring version(L"1.0.0.1");
std::wcout << L"dicom2jpeg version " << version << std::endl;
try
{
if(argc < 3)
{
std::wcout << L"Usage: dicom2jpeg dicomFileName jpegFileName [-ffmpeg FFMPEGPATH FFMPEGOPT]" << std::endl;
std::wcout << "dicomFileName = name of the dicom file" << std::endl;
std::wcout << "jpegFileName = name of the final jpeg file" << std::endl;
std::wcout << "-ffmpeg FFMPEGPATH = launches FFMPEG after generating the jpeg images." << std::endl;
std::wcout << " FFMPEGPATH is the path to FFMPEG" << std::endl;
std::wcout << " FFMPEGOPT are the options for ffmpeg" << std::endl;
std::wcout << " The input images and the frame rate are added automatically to the options" << std::endl;
return 1;
}
// Separate the extension from the file name
std::string outputFileName(argv[2]);
std::string extension;
size_t dotPos(outputFileName.rfind('.'));
if(dotPos != outputFileName.npos)
{
extension = outputFileName.substr(dotPos);
outputFileName.erase(dotPos);
}
else
{
extension = ".jpg";
}
// Check for the -ffmpeg flag
int ffmpegFlag(findArgument("-ffmpeg", argc, argv));
size_t framesCount(0);
ptr<dataSet> loadedDataSet;
try
{
// Open the file containing the dicom dataset
ptr<puntoexe::stream> inputStream(new puntoexe::stream);
inputStream->openFile(argv[1], std::ios_base::in);
// Connect a stream reader to the dicom stream. Several stream reader
// can share the same stream
ptr<puntoexe::streamReader> reader(new streamReader(inputStream));
// Get a codec factory and let it use the right codec to create a dataset
// from the input stream
ptr<codecs::codecFactory> codecsFactory(codecs::codecFactory::getCodecFactory());
loadedDataSet = codecsFactory->load(reader, 2048);
// Get the first image. We use it in case there isn't any presentation VOI/LUT
// and we have to calculate the optimal one
ptr<image> dataSetImage(loadedDataSet->getImage(0));
imbxUint32 width, height;
dataSetImage->getSize(&width, &height);
// Build the transforms chain
ptr<transforms::transformsChain> chain(new transforms::transformsChain);
ptr<transforms::modalityVOILUT> modalityVOILUT(new transforms::modalityVOILUT(loadedDataSet));
chain->addTransform(modalityVOILUT);
ptr<transforms::colorTransforms::colorTransformsFactory> colorFactory(transforms::colorTransforms::colorTransformsFactory::getColorTransformsFactory());
if(colorFactory->isMonochrome(dataSetImage->getColorSpace()))
{
// Convert to MONOCHROME2 if a modality transform is not present
if(modalityVOILUT->isEmpty())
{
ptr<transforms::colorTransforms::colorTransform> monochromeColorTransform(colorFactory->getTransform(dataSetImage->getColorSpace(), L"MONOCHROME2"));
if(monochromeColorTransform != 0)
{
chain->addTransform(monochromeColorTransform);
}
}
ptr<transforms::VOILUT> presentationVOILUT(new transforms::VOILUT(loadedDataSet));
imbxUint32 firstVOILUTID(presentationVOILUT->getVOILUTId(0));
if(firstVOILUTID != 0)
{
presentationVOILUT->setVOILUT(firstVOILUTID);
}
else
{
// Run the transform on the first image
ptr<image> temporaryImage = chain->allocateOutputImage(dataSetImage, width, height);
chain->runTransform(dataSetImage, 0, 0, width, height, temporaryImage, 0, 0);
// Now find the optimal VOILUT
presentationVOILUT->applyOptimalVOI(temporaryImage, 0, 0, width, height);
}
chain->addTransform(presentationVOILUT);
}
std::wstring initialColorSpace;
if(chain->isEmpty())
{
initialColorSpace = dataSetImage->getColorSpace();
}
else
{
ptr<image> startImage(chain->allocateOutputImage(dataSetImage, 1, 1));
initialColorSpace = startImage->getColorSpace();
}
// Color transform to YCrCb
ptr<transforms::colorTransforms::colorTransform> colorTransform(colorFactory->getTransform(initialColorSpace, L"YBR_FULL"));
if(colorTransform != 0)
{
chain->addTransform((colorTransform));
}
ptr<image> finalImage(new image);
finalImage->create(width, height, image::depthU8, L"YBR_FULL", 7);
// Scan through the frames
for(imbxUint32 frameNumber(0); ; ++frameNumber)
{
if(frameNumber != 0)
{
dataSetImage = loadedDataSet->getImage(frameNumber);
}
if(chain->isEmpty() && dataSetImage->getDepth() != finalImage->getDepth() && dataSetImage->getHighBit() != finalImage->getHighBit())
{
chain->addTransform(new transforms::transformHighBit);
}
if(!chain->isEmpty())
{
chain->runTransform(dataSetImage, 0, 0, width, height, finalImage, 0, 0);
}
else
{
finalImage = dataSetImage;
}
// Open a stream for the jpeg
const std::wstring jpegTransferSyntax(L"1.2.840.10008.1.2.4.50");
std::ostringstream jpegFileName;
jpegFileName << outputFileName;
if(frameNumber != 0 || ffmpegFlag >= 0)
{
jpegFileName << "_" << frameNumber;
}
jpegFileName << extension;
ptr<puntoexe::stream> jpegStream(new puntoexe::stream);
jpegStream->openFile(jpegFileName.str(), std::ios_base::out | std::ios_base::trunc);
ptr<puntoexe::streamWriter> jpegWriter(new streamWriter(jpegStream));
ptr<codecs::codec> outputCodec(codecsFactory->getCodec(jpegTransferSyntax));
// Write the jpeg image to the stream
outputCodec->setImage(jpegWriter, finalImage, jpegTransferSyntax, codecs::codec::veryHigh,
"OB", 8, false, false, false, false);
++framesCount;
}
}
catch(dataSetImageDoesntExist&)
{
// Ignore this exception. It is thrown when we reach the
// end of the images list
exceptionsManager::getMessage();
}
// All the images have been generated.
// Should we launch FFMPEG?
if(ffmpegFlag >= 0 && framesCount != 0)
{
// List of arguments to be passed to ffmpeg
typedef std::list<std::string> tOptionsList;
tOptionsList options;
// The first argument is the application's name
options.push_back(argv[ffmpegFlag + 1]);
// Calculate the frames per second from the available tags
double framesPerSecond(0);
double frameTime(loadedDataSet->getDouble(0x0018, 0, 0x1063, 0));
if(frameTime > 0.1)
{
framesPerSecond = 1000 / frameTime;
}
if(framesPerSecond < 0.1)
{
framesPerSecond = loadedDataSet->getUnsignedLong(0x0018, 0x0, 0x0040, 0x0);
}
if(framesPerSecond < 0.1)
{
framesPerSecond = loadedDataSet->getUnsignedLong(0x0008, 0x0, 0x2144, 0x0);
}
// Add the ffmpeg argument for the frames per second
if(framesPerSecond > 0.1)
{
options.push_back("-r");
std::ostringstream frameRate;
frameRate << framesPerSecond;
options.push_back(frameRate.str());
}
// Add the ffmpeg argument for the input files
options.push_back("-i");
options.push_back(outputFileName + "_%d" + extension);
// Add the ffmpeg argument for the number of frames
options.push_back("-dframes");
std::ostringstream frameCount;
frameCount << (unsigned long)framesCount;
options.push_back(frameCount.str());
// Add the arguments specified when dicom2jpeg was launched
for(int copyArguments(ffmpegFlag + 2); copyArguments < argc; ++copyArguments)
{
options.push_back(argv[copyArguments]);
}
// Build the arguments array
std::auto_ptr<const char*> ffArgv(new const char*[options.size() + 1]);
size_t insertPosition(0);
for(tOptionsList::iterator scanOptions(options.begin()); scanOptions != options.end(); ++scanOptions, ++insertPosition)
{
ffArgv.get()[insertPosition] = (*scanOptions).c_str();
}
ffArgv.get()[options.size()] = 0;
// Launch ffmpeg
#ifdef PUNTOEXE_WINDOWS
return (int)_spawnvp(_P_WAIT , argv[ffmpegFlag + 1], ffArgv.get());
#else
char *environment[] = {0};
pid_t process_id;
posix_spawnp (&process_id, argv[ffmpegFlag + 1],
0, 0, (char* const*)ffArgv.get(), (char* const*)environment);
wait(0);
#endif
}
return 0;
}
catch(...)
{
std::wcout << exceptionsManager::getMessage();
return 1;
}
}

Pipe and select : sample code not working

Am I missing something ?
I want to come out of select by calling write in another thread... It never comes out of select.
Code is tested on OSX snow.
fd_set rio, wio;
int pfd[2];
void test(int sleep_time)
{
sleep(sleep_time);
char buf[] = "1";
write(pfd[1], buf, 1);
}
int main(int argc, char* argv[])
{
char buff[80];
int ended = 0;
pipe(pfd);
FD_ZERO(&rio);
FD_ZERO(&wio);
FD_SET(pfd[1], &wio);
FD_SET(pfd[0], &rio);
pthread_t tid; /* the thread identifier */
pthread_attr_t attr; /* set of thread attributes */
pthread_attr_init(&attr);
pthread_create(tid, NULL, test, 3);
while (!ended)
{
// Check my numbers ... they do not go over 1 ... so 2
if (select(2, &rio, &wio, NULL, 0) < 0)
perror("select");
else
{
if (FD_ISSET(pfd[1], &wio))
{
if ((read(pfd[0], &buff, 80))<0)
perror("read");
ended = 1;
}
}
}
I believe you have 2 errors:
1 - your select call is limiting the check to a max of fd 2, where the pipe will probably have larger FDs since 0, 1, and 2 are already opened for stdin, stdout, stderr. The pipe FDs will presumably have fds 3 and 4 so you actually need to determine the larger of the 2 pipe FDs and use that for the limit in the select instead of 2.
int maxfd = pfd[1];
if( pfd[0] > maxfd ) {
maxfd = pfd[0];
}
...
2 - After select returns, you are looking at the wio and pipe write FD when you need to instead look to see if there is anything available to READ:
if (FD_ISSET(pfd[0], &rio)) {

How to get an X11 Window from a Process ID?

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

Resources