Manipulate files older than X - windows

I've searched a lot how to delete files older than a number X given but I've only found questions too old to trust.
I have directory filled with files .zip those files are created to make space but one day i won't have anymore space so i've thought that i can choose a number of days (X) to choose when i want to delete some files and which files i want to delete. At the moment i'm searching for a way to select the files from a folder given that are older than Today - X and tha tdelete them.
void fCamImgCanc(long pThreadId)
{
ULARGE_INTEGER rFreeBytesAvailable, rTotalNumberOfBytes, rTotalNumberOfFreeBytes;
if(sys.Logs.CamImgSave && sys.Logs.ImageSMod == 1)
{
if (::GetDiskFreeSpaceEx ("C:\\S\\LOGBOOK\\Cam\\Logfold", &rFreeBytesAvailable, &rTotalNumberOfBytes, &rTotalNumberOfFreeBytes))
{
if (rTotalNumberOfBytes.QuadPart < ((rTotalNumberOfBytes.QuadPart * sys.LogB.FreeSpaceOnDisk) / 100)) //if disk size < __% delete the older day
{
do
{
//Date of the oldest group of files > Today - sys.LogB.OlderThanD setted for example to 13
if("C:\\S\\LOGBOOK\\Cam\\Logfold\\FilenameData" > Today - sys.LogB.OlderThanD)
{
DeleteFile("C:\\S\\LOGBOOK\\Cam\\Logfold");
}
}while(rTotalNumberOfBytes.QuadPart < ((rTotalNumberOfBytes.QuadPart * sys.LogB.FreeSpaceOnDisk) / 100)); //free space till we have the space that we need
}
fAddOnZip("C:\\S\\LOGBOOK\\Cam");
}
}
else //ImageSMod = 0 -> Relative "save of the images of the lot and at the next lot delete of them"
{
DO OTHER THINGS
}
}
I've got the delete function and the zip function yet

Enumerate files in a directory with FindFirstFile and FindNextFile.
Get the current time with GetSystemTime (and convert to "file time" with SystemTimeToFileTime).
Do the approriate math to get the timestamp from N days ago. It's all based on 100ns units. (10 million of those equals "one second").
Then DeleteFile to actually delete the file.
And some helper functions from the Windows SDK to concatenate paths. Link with PatchCch.lib.
Here's some code to get you started. If you invoke:
delete_all_old_files_in_directory(L"C:\\Users\\YourName\\Downloads", 7);
It will delete everything from the Downloads folder older than a week.
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif
#include <windows.h>
#include <strsafe.h>
#include <PathCch.h>
#include <stdint.h>
#pragma comment(lib, "pathcch")
void delete_all_old_files_in_directory(const wchar_t* dir, DWORD dwDays)
{
SYSTEMTIME st = { 0 };
wchar_t szPath[MAX_PATH * 2 + 2];
BOOL succeeded = TRUE;
uint64_t filetimeNow = 0;
uint64_t filetimeCompare = 0;
uint64_t delta;
HANDLE h = INVALID_HANDLE_VALUE;
WIN32_FIND_DATAW data = { 0 };
// dont't try to delete directories or special files
const DWORD dwMask = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
GetSystemTime(&st);
::SystemTimeToFileTime(&st, (FILETIME*)&filetimeNow);
delta = 10000000ULL * dwDays * 60 * 60 * 24;
filetimeCompare = filetimeNow - delta;
StringCchCopy(szPath, ARRAYSIZE(szPath), dir);
PathCchAppend(szPath, ARRAYSIZE(szPath), L"*.*");
h = FindFirstFile(szPath, &data);
succeeded = (h != INVALID_HANDLE_VALUE);
while (succeeded)
{
uint64_t fileTimeThisFile = *(uint64_t*)(&data.ftCreationTime);
wchar_t szDeletePath[MAX_PATH] = { 0 };
StringCchCopy(szDeletePath, ARRAYSIZE(szDeletePath), dir);
PathCchAppend(szDeletePath, ARRAYSIZE(szDeletePath), data.cFileName);
if ((fileTimeThisFile < filetimeCompare) && !(data.dwFileAttributes & dwMask))
{
wprintf(L"Deleting: %ls\n", szDeletePath);
DeleteFile(szDeletePath);
}
else
{
wprintf(L"Keeping: %ls\n", szDeletePath);
}
succeeded = FindNextFile(h, &data);
}
if (h != INVALID_HANDLE_VALUE)
{
FindClose(h);
h = NULL;
}
}
int main()
{
delete_all_old_files_in_directory(L"C:\\Users\\YourName\\Downloads", 7);
return 0;
}

Related

How to produce same mfcc result as librosa using aubio?

I am trying to calculate Mfcc feature in C++. And I found Aubio (https://github.com/aubio/aubio) but I cannot produce same result as Librosa of Python (this is important).
Librosa code:
X, sample_rate = sf.read(file_name, dtype='float32')
mfccs = librosa.feature.mfcc(y=X, sr=sample_rate, n_mfcc=40)
Aubio code:
#include "utils.h"
#include "parse_args.h"
#include <stdlib.h>
aubio_pvoc_t *pv; // a phase vocoder
cvec_t *fftgrain; // outputs a spectrum
aubio_mfcc_t * mfcc; // which the mfcc will process
fvec_t * mfcc_out; // to get the output coefficients
uint_t n_filters = 128;
uint_t n_coefs = 40;
void process_block (fvec_t *ibuf, fvec_t *obuf)
{
fvec_zeros(obuf);
//compute mag spectrum
aubio_pvoc_do (pv, ibuf, fftgrain);
//compute mfccs
aubio_mfcc_do(mfcc, fftgrain, mfcc_out);
}
void process_print (void)
{
/* output times in selected format */
print_time (blocks * hop_size);
outmsg ("\t");
/* output extracted mfcc */
fvec_print (mfcc_out);
}
int main(int argc, char **argv) {
int ret = 0;
// change some default params
buffer_size = 2048;
hop_size = 512;
examples_common_init(argc,argv);
verbmsg ("using source: %s at %dHz\n", source_uri, samplerate);
verbmsg ("buffer_size: %d, ", buffer_size);
verbmsg ("hop_size: %d\n", hop_size);
pv = new_aubio_pvoc (buffer_size, hop_size);
fftgrain = new_cvec (buffer_size);
mfcc = new_aubio_mfcc(buffer_size, n_filters, n_coefs, samplerate);
mfcc_out = new_fvec(n_coefs);
if (pv == NULL || fftgrain == NULL || mfcc == NULL || mfcc_out == NULL) {
ret = 1;
goto beach;
}
examples_common_process(process_block, process_print);
printf("\nlen=%u\n", mfcc_out->length);
del_aubio_pvoc (pv);
del_cvec (fftgrain);
del_aubio_mfcc(mfcc);
del_fvec(mfcc_out);
beach:
examples_common_del();
return ret;
}
Please help to obtain same result of Librosa or suggest any C++ library do this well.
Thanks
This might be what you are looking for: C Speech Features
The library is a complete port of python_speech_features to C and according to the documentation, you should be able to use it in a C++ projects. The results will not be the same of Librosa, here is why but you should be able to work with them.

X11: Get the list of main windows using xcb

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

show location of biggest memory leak on Windows

My program has big leaks. I am using the debug heap by putting this in my stdafx.h:
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
Then I'm capturing all the leaks in a text file by putting this code just before exit:
HANDLE hLogFile;
hLogFile = CreateFile( "T:\\MyProject\\heap.txt", GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, hLogFile);
_CrtDumpMemoryLeaks();
exit( EXIT_SUCCESS );
However even then the data is leak by leak, which is far too low-level information.
Stepping into _CrtDumpMemoryLeaks(), the code is actually easy to follow. I wrote my own function that summarizes the data, reporting bytes leaked for each line of code and sorting by leak size.
However it requires a static variable inside dbgheap.c in order to work. I've tried to make a version of dbgheap.c that doesn't have these as static symbols and tried to make a mini-DLL out of it (but it complains about a missing symbol I can't find anywhere in the MSFT code, _heap_regions). Instead what I've settled on is putting this code right before the code above calling _CrtDumpMemoryLeaks():
// Put a breakpoint here; step INTO the malloc, then in variable watch
// window evaluate: _CrtDumpMemoryLeakSummary( _pFirstBlock );
void* pvAccess = malloc(1);
And in turn this is the code for the _CrtDumpMemoryLeakSummary function:
#define _CRTBLD
#include "C:\Program Files\Microsoft Visual Studio 9.0\VC\crt\src\dbgint.h"
typedef struct {
const char* pszFileName;
int iLine;
int iTotal;
} Location_T;
#define MAX_SUMMARY 5000
static Location_T aloc[ MAX_SUMMARY ];
static int CompareFn( const void* pv1, const void* pv2 ) {
Location_T* ploc1 = (Location_T*) pv1;
Location_T* ploc2 = (Location_T*) pv2;
if ( ploc1->iTotal > ploc2->iTotal )
return -1;
if ( ploc1->iTotal < ploc2->iTotal )
return 1;
return 0;
}
void _CrtDumpMemoryLeakSummary( _CrtMemBlockHeader* pHead )
{
int iLocUsed = 0, iUnbucketed = 0, i;
for ( /*pHead = _pFirstBlock */;
pHead != NULL && /* pHead != _pLastBlock && */ iLocUsed < MAX_SUMMARY;
pHead = pHead->pBlockHeaderNext ) {
const char* pszFileName = pHead->szFileName ? pHead->szFileName : "<UNKNOWN>";
// Linear search is theoretically horribly slow but saves trouble of
// avoiding heap use while measuring heap use.
int i;
for ( i = 0; i < iLocUsed; i++ ) {
// To speed search, compare line number (fast) before strcmp() (slow).
// If szFileName were guaranteed to be __LINE__ then we could take advantage
// of __LINE__ always having the same address for any given file, and just
// compare pointers rather than using strcmp(). However, szFileName could
// be something else.
if ( pHead->nLine == aloc[i].iLine &&
strcmp( pszFileName, aloc[i].pszFileName ) == 0 ) {
aloc[i].iTotal += pHead->nDataSize;
break;
}
}
if ( i == iLocUsed ) {
aloc[i].pszFileName = pszFileName;
aloc[i].iLine = pHead->nLine;
aloc[i].iTotal = pHead->nDataSize;
iLocUsed++;
}
}
if ( iLocUsed == MAX_SUMMARY )
_RPT0( _CRT_WARN, "\n\n\nARNING: RAN OUT OF BUCKETS! DATA INCOMPLETE!!!\n\n\n" );
qsort( aloc, iLocUsed, sizeof( Location_T ), CompareFn );
_RPT0(_CRT_WARN, "SUMMARY OF LEAKS\n" );
_RPT0(_CRT_WARN, "\n" );
_RPT0(_CRT_WARN, "bytes leaked code location\n" );
_RPT0(_CRT_WARN, "------------ -------------\n" );
for ( i = 0; i < iLocUsed; i++ )
_RPT3(_CRT_WARN, "%12d %s:%d\n", aloc[i].iTotal, aloc[i].pszFileName, aloc[i].iLine );
}
It produces output like this:
SUMMARY OF LEAKS
bytes leaked code location
------------ -------------
912997 <UNKNOWN>:0
377800 ..\MyProject\foo.h:205
358400 ..\MyProject\A.cpp:959
333672 ..\MyProject\B.cpp:359
8192 f:\dd\vctools\crt_bld\self_x86\crt\src\_getbuf.c:58
6144 ..\MyProject\Interpreter.cpp:196
4608 ..\MyProject\Interpreter.cpp:254
3634 f:\dd\vctools\crt_bld\self_x86\crt\src\stdenvp.c:126
2960 ..\MyProject\C.cpp:947
2089 ..\MyProject\D.cpp:1031
2048 f:\dd\vctools\crt_bld\self_x86\crt\src\ioinit.c:136
2048 f:\dd\vctools\crt_bld\self_x86\crt\src\_file.c:133

What Time Is This Returning

Deep in the sauce here. I haven't worked with time to much so I'm a little confused here. I know there is FILETIME and SYSTEMTIME. What I am trying to get at this point (because it might change) are file that are less than a 20 seconds old. This returning the files and their size and something in seconds, What I'd like to know is where it is filtering by time if it is, and how can I adjust it to suit my needs. Thank you.
using namespace std;
typedef vector<WIN32_FIND_DATA> tFoundFilesVector;
std::wstring LastWriteTime;
int getFileList(wstring filespec, tFoundFilesVector &foundFiles)
{
WIN32_FIND_DATA findData;
HANDLE h;
int validResult=true;
int numFoundFiles = 0;
h = FindFirstFile(filespec.c_str(), &findData);
if (h == INVALID_HANDLE_VALUE)
return 0;
while (validResult)
{
numFoundFiles++;
foundFiles.push_back(findData);
validResult = FindNextFile(h, &findData);
}
return numFoundFiles;
}
void showFileAge(tFoundFilesVector &fileList)
{
unsigned _int64 fileTime, curTime, age;
tFoundFilesVector::iterator iter;
FILETIME ftNow;
//__int64 nFileSize;
//LARGE_INTEGER li;
//li.LowPart = ftNow.dwLowDateTime;
//li.HighPart = ftNow.dwHighDateTime;
CoFileTimeNow(&ftNow);
curTime = ((_int64) ftNow.dwHighDateTime << 32) + ftNow.dwLowDateTime;
for (iter=fileList.begin(); iter<fileList.end(); iter++)
{
fileTime = ((_int64)iter->ftLastWriteTime.dwHighDateTime << 32) + iter->ftLastWriteTime.dwLowDateTime;
age = curTime - fileTime;
cout << "FILE: '" << iter->cFileName << "', AGE: " << (_int64)age/10000000UL << " seconds" << endl;
}
}
int main()
{
string fileSpec = "*.*";
tFoundFilesVector foundFiles;
tFoundFilesVector::iterator iter;
int foundCount = 0;
getFileList(L"c:\\Mapper\\*.txt", foundFiles);
getFileList(L"c:\\Mapper\\*.jpg", foundFiles);
foundCount = foundFiles.size();
if (foundCount)
{
cout << "Found "<<foundCount<<" matching files.\n";
showFileAge(foundFiles);
}
system("pause");
return 0;
}
I don't know what you've done to try to debug this but your code doesn't work at all. The reason is you're passing getFileList() a wstring but then passing that to the ANSI version of FindFirstFile(). Unless you #define UNICODE or use the appropriate compiler option, all system calls will expect char *, not UNICODE.
The easiest fix is to simply change the declaration of getFileList() to this:
int getFileList(const char * filespec, tFoundFilesVector &foundFiles)
Change the call to FindFirstFile() to this:
h = FindFirstFile((LPCSTR)filespec, &findData);
And then change the calls to it to this:
getFileList("c:\\Mapper\\*.txt", foundFiles);
getFileList("c:\\Mapper\\*.jpg", foundFiles);
Your other option is to switch all char strings to wide chars, but either way you need to be consistent throughout. Once you do that the program works as expected.
As for your final question, your program is not filtering by time at all.
Not quite an answer, but you might want to read about file system tunneling.
It may prevent you from what you're trying to do in some situations.

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