X11 DestroyNotify event returns wrong window parameter - c++

I'm currently working on writing a reparenting window manager using C++ and the XCB library. I unmanage windows when I recieve an UnmapNotify event; in this case the code is very simple:
if (unmap_ignore > 0) {
unmap_ignore--;
return;
}
client *cl = nullptr;
size_t idx = 0;
for (client &c : clients) {
if (c.window == ev->window) {
cl = &c;
break;
}
idx++;
}
if (!cl)
return;
xcb_unmap_window(conn, cl->frame);
clients.erase(clients.begin() + idx);
However, this does not work for some clients that don't bother unmapping the window (usually happens when you force kill the process). Then instead a DestroyNotify is sent. However the ev->window field there (typeof ev = xcb_destroy_notify_event_t) is some value that isn't what I want... here are some example logs (also note each line is a new DestroyNotify event, I get it twice for some reason and each time the #window field is different but not correct):
Found a client window: 4194307 but this was destroyed: 4194305
Found a client window: 4194307 but this was destroyed: 4194313
I remember before I tried to write a window manager in Xlib and had this exact same issue. I must be missing something obvious though, but if I look at the code of other reparenting window managers like Awesome or Herbsluftwm they just use the window field and have no problems. What am I doing wrong?
(my full code is here: http://ix.io/3yDj)
One thing I suspect is that it is just giving me two children windows of the destroyed parent instead of sending the actual parent. no idea why, but it is the most logical thing I can come up with. I just want to be able to handle this so I can unmap the frame for things that don't send UnmapNotify events.
I also first thought that it may report DestroyNotify on the parent window instead of the client reparented one, so I tried checking the frame but to no avail:
Found a client window: 2097152 but this was destroyed: 4194305
Found a client window: 2097152 but this was destroyed: 4194313
I've been truly stumped on this so any help is appreciated, thanks!
Awesome for example does the exact same thing as I tried with ev->window:
static void
event_handle_destroynotify(xcb_destroy_notify_event_t *ev)
{
client_t *c;
if((c = client_getbywin(ev->window)))
client_unmanage(c, CLIENT_UNMANAGE_DESTROYED);
else
for(int i = 0; i < globalconf.embedded.len; i++)
if(globalconf.embedded.tab[i].win == ev->window)
{
xembed_window_array_take(&globalconf.embedded, i);
luaA_systray_invalidate();
}
}

Related

Reparenting wm and BadWindow errors

I'm writing a reparenting window manager in XCB and C++:http://ix.io/3yNo
At the moment it works pretty well, but occasionally when I close a window, all the windows of that application close because the process exits with a BadWindow. For example if I have a couple xfce4-terminal windows open, all managed by one process,and I close one, occasionally the application will close and I will get a BadWindow (invalid window parameter) error (in the app, not my wm). The very interesting thing is that this is not reproducible but kind of rare, probably a race condition between reporting the error and closing the window due to X11's asynchoronous nature.I have no clue where to begin debugging this, any tips?I kind of suspect it might be something in the Unmap O
Your link contains almost 500 lines of code. I am not going to try to fully understand that. Instead, I'll just randomly guess.
auto window_manager::handle_unmap_notify(xcb_unmap_notify_event_t *ev) -> void {
if (unmap_ignore > 0) {
unmap_ignore--;
return;
}
client *cl = nullptr;
size_t idx = 0;
for (client &c : clients) {
if (c.window == ev->window) {
cl = &c;
break;
}
idx++;
}
if (not cl)
return;
xcb_destroy_window(conn, cl->frame);
clients.erase(clients.begin() + idx);
}
You are destroying windows that are not yours. When the owner of the window accesses it the next time, it will get a BadWindow error.
Instead, you should check a window's WM_PROTOCOLS property and check for WM_DELETE_WINDOW. If that is present, you are supposed to send a WM_DELETE_WINDOW message to the window. See ICCCM § 4.2.8.1: https://tronche.com/gui/x/icccm/sec-4.html#s-4.2.8.1

Cannot set Scanner Capability because L_TwainStartCapsNeg returns error -84

I'm trying to use the Leadtools API version 21 for automatically scanning some documents and here is a sudo code of what I have done (it runs in a secondary thread and the unlock has been done in the main thread):
void CheckRetCode(int rc)
{
if (SUCCESS != rc)
{
L_TCHAR errMsg[1024];
memset(errMsg, 0, sizeof(errMsg));
L_GetFriendlyErrorMessage(rc, errMsg, 1024, L_FALSE);
throw TLeadException(errMsg, rc);
}
}
void OnThreadExecute(void)
{
HTWAINSESSION hSession = nullptr;
APPLICATIONDATA appData;
L_INT nRet;
L_TCHAR pszTwnSourceName[1024];
LTWAINSOURCE sInfo;
memset(&appData, 0, sizeof(APPLICATIONDATA));
appData.uStructSize = sizeof(APPLICATIONDATA);
appData.hWnd = hWnd;// hWnd is valid handle of my main window
appData.uLanguage = TWLG_ENGLISH_USA;
appData.uCountry = TWCY_USA;
wcscpy(appData.szManufacturerName, L"MyCompanyName");
wcscpy(appData.szAppProductFamily, L"MyProductName");
wcscpy(appData.szAppName, appData.szAppProductFamily);
wcscpy(appData.szVersionInfo, L"Version 0.1.0.1");
nRet = L_TwainInitSession2(&hSession, &appData, LTWAIN_INIT_MULTI_THREADED);
CheckRetCode(nRet);// the exception gets catched elsewhere but no error reported here
memset(pszTwnSourceName, 0, sizeof(pszTwnSourceName));
wcscpy(pszTwnSourceName, L"EPSON Artisan837/PX830"); // the name of the scanner is verifyed
sInfo.uStructSize = sizeof(LTWAINSOURCE);
sInfo.pszTwainSourceName = pszTwnSourceName;
CheckRetCode(L_TwainSelectSource(hSession, &sInfo)); // No error reported here
CheckRetCode(L_TwainStartCapsNeg(hSession)); // in here I get the return value -84 which is reported as "TWAIN DS or DSM reported error, app shouldn't (no need for your app to report the error)."
// the rest of the code but we cannot get there since above code reports error
}
Can anyone tell me what I'm doing wrong? Is there a step that I'm missing here?
EditThe function L_TwainSelectSource() make no effort to make sure the supplied source is valid and does not even return an error. As result, if you set the selected source to a garbage name, it will act as if it accepted it. From that point on if you try to Get/Set anything or try to acquire an image, every function returns -84.
Thank you
Sam
To test your code, I put the main window’s handle in a global variable:
globalhWnd = hWnd;
And modified your function to use that handle like this:
void OnThreadExecute(void *)
{
...
appData.hWnd = globalhWnd; // hWnd is valid handle of my main window
...
}
Then created a thread for it from the main program like this:
globalhWnd = hWnd;
_beginthread(OnThreadExecute, 0, 0);
I tried this with 5 different Twain sources: 2 virtual and 3 physical scanners (one of them an old Epson). All 5 drivers returned SUCCESS when calling L_TwainStartCapsNeg() from within the thread.
Two possibilities come to mind:
The problem might be caused by something else in your code other than the thread function.
Or the problem could be specific to your Twain driver.
To rule out the first possibility, I suggest creating a small test project that only creates a similar thread and does nothing else and trying it with different scanners. If it causes the same problem with all scanners, send that test project (not your full application) to support#leadtools.com and our support engineers with test it for you.
If the problem only happens with a specific Twain driver, try contacting the scanner’s vendor to see if they have an updated driver.

Why does SDL doesn't emit SDL_QUIT when last windows closed

I'm writing a Game Engine just for practice but I still stuck with the first chellange. The Window Manager.
https://github.com/thebenius/SDL
I've created a GitHub Repo to show you the code but don't worry. Its not much. But I absolutely don't know where is my mistake.
In the Code I create three Windows and I Manage the input for SDL_QUIT to stop the game loop and for SDL_WINDOWEVENT_CLOSE to close the windows.
Everything works fine until the last window is closed. As far as I know, now the SDL_QUIT Event must be emitted by SDL. But the Gameloop goes on.
I think I maybe have a kind of memory leak and there is still a windows saved. But I checked the window stack (Window::windows hashmap) it is empty. And also the variables in main are cleared.
I also tried to additionally clear the window and renderer variable in the hash map
Window::~Window() {
// Delete Window and Renderer
SDL_DestroyRenderer(Window::windows[this->windowID]->renderer);
SDL_DestroyWindow(Window::windows[this->windowID]->window);
Window::windows[this->windowID]->renderer = nullptr;
Window::windows[this->windowID]->window = nullptr;
// Delete Window from map
Window::windows.erase(this->windowID);
// Delete Window and Renderer
SDL_DestroyRenderer(this->renderer);
SDL_DestroyWindow(this->window);
// Reset Pointer
this->renderer = nullptr;
this->window = nullptr;
Nothing worked.
I'm new in C++ and SDL. I hope you can help me out.
Thank you o11c,
Your answer was the riddles solution.
I just put SDL_Quit() out of the Destructor. This obviously blocked the Event Handler to catch SDL_QUIT. So I put it to the constructor in atexit()
After that (don't know why before not) I got an Segfault when deleting the window pointer in main. I deleted that and just set them all to nullptr.
Now the WindowManager works properly. Thank you for your help
I think SDL_QUIT is only an hook called if you call SDL_Quit(), to give the user the opportunity to do some quit stuff, the manual:
You should call this function even if you have already shutdown each initialized subsystem with SDL_QuitSubSystem(). It is safe to call this function even in the case of errors in initialization
You can use this function with atexit() to ensure that it is run when your application is shutdown, but it is not wise to do this from a library or other dynamically loaded code
To catch a window close event see SDL_WindowEvent, SDL_WINDOWEVENT and SDL_WINDOWEVENT_CLOSE, the id of the closing window is given as argument.
* \file SDL_quit.h
*
* An ::SDL_QUIT event is generated when the user tries to close the application
* window. If it is ignored or filtered out, the window will remain open.
* If it is not ignored or filtered, it is queued normally and the window
* is allowed to close. When the window is closed, screen updates will
* complete, but have no effect.
*
* SDL_Init() installs signal handlers for SIGINT (keyboard interrupt)
* and SIGTERM (system termination request), if handlers do not already
* exist, that generate ::SDL_QUIT events as well. There is no way
* to determine the cause of an ::SDL_QUIT event, but setting a signal
* handler in your application will override the default generation of
* quit events for that signal.
*
* \sa SDL_Quit()
SDL_EventType#SDL_QUIT
An SDL_QUIT event is generated when the user clicks on the close button of the last existing window.
You shouldn't call SDL_Quit() in the destructor, but only once before leaving the application (is suggested to use it with atexit())
--- a/main.cpp
+++ b/main.cpp
## -32,17 +32,18 ## int main() {
}
-
// Delete Windows
- delete window;
- delete window2;
- delete window3;
+ // delete window;
+ // delete window2;
+ // delete window3;
// reset pointer
window = nullptr;
window2 = nullptr;
window3 = nullptr;
+ SDL_Quit();
+
// Close Program properly
return 0;
}
--- a/video/window.cpp
+++ b/video/window.cpp
## -51,7 +51,7 ## Window::~Window() {
// Shutdown if last window closed
if(this->windows.empty()) {
// Shutdown Video System
- SDL_Quit();
+ // SDL_Quit();
std::cout << "shuted down Video" << std::endl;
}
}

Sharing opengl resources (OpenGL ES 2.0 Multithreading)

I have developed an OpenGL ES 2.0 win32 application, that works fine in a single thread. But I also understand that UI thread and a rendering thread should be separate.
Currently my game loop looks something like that:
done = 0;
while(!done)
{
msg = GetMessage(..); // getting messages from OS
if(msg == QUIT) // the window has been closed
{
done = 1;
}
DispatchMessage(msg,..); //Calling KeyDown, KeyUp events to handle user input;
DrawCall(...); //Render a frame
Update(..); // Update
}
Please view it as a pseudo code, cause i don't want to bother you with details at this point.
So my next step was to turn done into an std::atomic_int and create a function
RenderThreadMain()
{
while(!done.load())
{
Draw(...);
}
}
and create a std::unique_ptr<std::thread> m_renderThread variable. As you can guess nothing has worked for me so far, so i made my code as stupid and simple as possible in order to make sure i don't break anything with the order i call methods in. So right now my game loop works like this.
done.store(0);
bool created = false;
while(!done)
{
msg = GetMessage(..); // getting messages from OS
if(msg == QUIT) // the window has been closed
{
done.store(1);
}
DispatchMessage(msg,..); //Calling KeyDown, KeyUp events to handle user input;
// to make sure, that my problem is not related to the fact, that i'm rendering too early.
if(!created)
{
m_renderThread = std::make_unique<std::thread>(RenderThreadMain, ...);
created = true;
}
Update(..); // Update
}
But this doesn't work. On every draw call, when i try to somehow access or use my buffers \ textures anything else, i get the GL_INVALID_OPERATION error code.
So my guess would be, that the problem is in me calling glGenBuffers(mk_bufferNumber, m_bufferIds); in the main thread during initialization and then calling glBindBuffer(GL_ARRAY_BUFFER, m_bufferIds[0]); in a render thread during the draw call. (the same applies to every openGL object i have)
But I don't now if i'm right or wrong.

Exeception in application when Threading used to saveImage simultaneously from multiple IP Camera

I am working on application where I connect the application and display multiple video feed from IP cameras. I am able to get the video feed which is too laggy(working to get solution to remove the lag). And in the application I have Button which when clicked it takes 50 pictures from all the IP cameras connected. But the code I have implemented gives an exception when threading is implemented. When used without threading it works fine.Heres the code for the Button Event.
void CDialogBasedVideoDlg::OnBnClickedButtonTakePic()
{
int nIndex = m_CamListBox.GetCurSel();
CStaticEx *objStaticEx = (CStaticEx*)m_StaticArray.GetAt(nIndex);
objStaticEx->StartThreadToCaptureUSBCam();//threading implementation gives exception.
//objStaticEx->CapturePicture();//this func works fine(without threading)
// TODO: Add your control notification handler code here
}
I have overrriden Static class which dynamically creates a picture control and displays the live video feed, threading is implemented in this class where the images are saved. Here's the code for capturing images and threading function.
void CStaticEx::CapturePicture(void)
{
CString csFileDir;
CString csFileName;
csFileDir.Format(DIR_USB_CAM_NAME,m_IpAddr);
if(IsDirExist(csFileDir)== false){
CreateDirectory(csFileDir, NULL);
}
CString csStr = csFileDir;
csStr += RANDOM_FILE_SEARCH;
int nNoOfFile = CountFileNumInDir((char*)csStr.GetBuffer());
csFileDir += DBL_SLASH;
int i = 0;
do{
csFileName.Format(FILE_NAME, csFileDir, (m_nCamID+1));
CString csCount;
csCount.Format(_T("%d"),(nNoOfFile+1));
csFileName += csCount;
csFileName += JPG;
m_pFrameImg = cvQueryFrame( m_pCamera ); //<----Exception come at this point
if(m_pFrameImg){
cvSaveImage(csFileName, m_pFrameImg);
i++;
nNoOfFile++;
csFileName = _T("");
}
}while(i < 50);
}
Threading Control function.
void CStaticEx::StartThreadToCaptureUSBCam(){
THREADSTRUCT *_param = new THREADSTRUCT;
_param->_this = this;
AfxBeginThread(StartThread,_param);
}
UINT CStaticEx::StartThread (LPVOID param)
{
THREADSTRUCT* ts = (THREADSTRUCT*)param;
//AfxMessageBox("Thread Started");
ts->_this->CapturePicture();
return 1;
}
Exception thrown is as follows.
Windows has treggered a breakpoint in DialogBasedVideo.exe.
This may be due to a corruption of heap, which indicates a bug in DialogBasedVideo.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while dialogbasedvideo.exe has focus.
The output window may have more diagnostic information. How do i get rid of this exception.
All the experts out their please help me.I am using VS2010 and Windows7, OpenCv2.4.6 Thanks in advance.