I have an unrepeatable bug of unknown origin in my single threaded window manager that occurs fairly infrequently (once every 2-3 weeks). Something happens that causes me to lose keyboard input. Mouse events are still handled properly so I know the event loop is still running, but the key press event is no longer triggered. Actually, the key is no longer grabbed. When I press XCB_MOD_MASK_4+2 to switch to desktop 2, the 2 will show up in the text editor or terminal that currently has the input focus, instead of being grabbed by the window manager. I thought maybe it was related to xcb_allow_events, so via IPC I can execute these three tests (from within the window manager, cmd is received from an external process):
if (strcmp(cmd,"test0")==0)
xcb_allow_events(wm.conn, XCB_ALLOW_ASYNC_KEYBOARD, XCB_CURRENT_TIME);
else if (strcmp(cmd,"test1")==0)
xcb_allow_events(wm.conn, XCB_ALLOW_SYNC_KEYBOARD, XCB_CURRENT_TIME);
else if (strcmp(cmd,"test2")==0)
keyboard();
void keyboard()
{
int i,m,k;
xcb_void_cookie_t cookie;
spawn("/usr/bin/xmodmap -e 'keycode 108 = Super_L'");
spawn("/usr/bin/xmodmap -e 'remove mod1 = Super_L'");
for (i=0; i<LENGTH(key_bindings); i++)
{
m = key_bindings[i].mod;
k = keysc(key_bindings[i].keysym);
info("grabbing key: %s (%d), mod: %d",key_bindings[i].keysym,k,m);
cookie = xcb_grab_key_checked(wm.conn, 0, wm.root, m, k, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
if (xcb_request_check (wm.conn, cookie))
error("can't grab key");
}
}
None of these tests help. I know the keyboard function works properly because it works on window manager startup. Also I can see in the log file that the key grabs in the keyboard function are actually being executed (without error) when prompted via IPC. The current workaround is to send sigterm to the window manager process, and then restart the wm. At that point everything works fine again.
I'm looking for techniques that might be helpful in tracking down the source of this problem, or in correcting the problem once it occurs (another test). Unfortunately, since I have no clue of the source of this problem, or what triggers it, I cannot make a simple test case to demonstrate. BTW I check the log files when this happens, and I don't see any pattern leading up to the problem. Each function logs an entry on entrance and exit.
Update 2021-02-12: I thought a restart would be a good workaround until I found the root cause of this problem. My restart function contains only one line:
execvp(lwm_argv[0], lwm_argv);
where lwm_argv is the argv provided as an argument to main.
I was very surprised to see that this did not alleviate the problem. I have to completely kill the old process then launch an new one to alleviate the problem. So this problem is PID dependant??? Further, I'm fairly convinced that this problem is somehow related to the stdout/stderr output of other applications launched from within the window manager using execvp. I've stopped launching applications from within the window manager and the problem went away. Any ideas of how launching other applications (and their output) could be affecting the keygrabs within the window manager would be appreciated.
You could try using strace or perf trace on the X server to see what it is doing with the key events. It ought to read them from somewhere in /dev/input and send them as events to connected clients.
If it isn't sending you events, then you might need to dig into its internal state, perhaps by building a debug server and connecting to it with GDB, to see why it isn't sending those events.
But if it is sending events to your WM then they're getting lost somewhere in the library stack.
Related
The Context
I'm using the HTML video element to play HLS+Fairplay streams (VOD and live) in Safari.
My application is a Netflix-like. You can watch a video, stop, and watch another one.
Concretly, the <video> tag is created upon each play and destroyed when the player exits.
The Problem
Sometimes, after exiting the player, launching a new video causes a MEDIA_ERR_DECODE error without anymore explation.
I can trace in my code that the Fairplay certificate and the CKC have been correctly retrieved and that the media session has been created and updated (with the CKC).
In fact, when I log everything, I see the exact same logs as when it works. Except the final MEDIA_ERR_DECODE error.
When I get this error, if I immediately retry to play, the same error happens, but if I wait about 5~10 seconds, it successfully plays. It's like some resource is waiting to be garbage-collected.
What I tried
I tried playing non-DRMed videos and it works perfectly: I could play, stop, play, etc. without any issue.
So my guess is something is happening at the EME level.
I've browse the whole Internet (twice) and couldn't come up with a clear explanation.
Most of the hints I found couldn't explain my issue (e.g. bad DRM-encryption, but how could it work the first time?) or solve it (e.g. videoElement.src = "").
I'm throwing a bottle into the sea, here...
I want to log if a customer tries to force close the application. I'm aware of having no chance to catch a process kill. But it should be possible through the main form closing event to get informed about the 'CloseReason.TaskManagerClosing' reason.
But any tests I did under Windows 8.1 I always got a CloseReason.UserClosing reason. But in this case (compared to a normals CloseReason.UserClosing) I've about 0.2s to run user code afterwards my program is killed!
Is this a new behavior in Windows 8.1?
Yes, I see this. And yes, this is a Windows change, previous versions of Task Manager sent the window the WM_CLOSE notification directly. I now see it issue the exact same command that's issued when you close the window with the Close button (WM_SYSCOMMAND, SC_CLOSE). Or press Alt+F4 or use the system menu. So Winforms can no longer tell the difference between the Task Manager and the user closing the window and you do get CloseReason.UserClosing.
What happens next is expected, if you don't respond to the close command quickly enough then Task Manager summarily assassinates your program with TerminateProcess().
Do keep in mind that trying to save data when the user aborts your program through Task Manager is a bad practice. Your user will normally use this if your program is malfunctioning, you can't really trust the data anymore and you risk writing garbage. This is now compounded by your saving code being aborted, high odds for a partially written file or dbase data that isn't usable anymore.
There is no simple workaround for this, the odds that Windows is going to be patched to restore old behavior are very close to zero. It is very important that you save your data in a transactional way so you don't destroy valuable data if the saving code is aborted. Use File.Replace() for file data, use a dbase transaction for dbase writes.
An imperfect way to detect this condition is by using the Form.Deactivate and Activate events. If you saw the Deactivate event and the FormClosing event fires then reasonable odds that another program is terminating yours.
But the normal way you deal with this is the common one, if the user ends the program without saving data then you display a dialog that asks whether to save data. Task Manager ensures that this doesn't go further than that.
Another solution for determining when the Task Manager is closing the program is by checking if the main form, or any of its controls, has focus. When you close via the Task Manager, the application is not focused, whereas if you close via the close button or Alt+F4, the application does have focus. I used a simple if check:
private void MyForm_Closing(object sender, FormClosingEventArgs e)
{
if (this.ContainsFocus)
{
// Put user close code here
}
}
I am replacing many batch files, that do almost the exact same thing, with one WPF executable. I have the program written, but I am having troubles with my "console" like display.
Within the program I call an executable to perform a task. This executable sends it's output messages to the console. I am able to redirect those to my "console" like display with the following.
Process p = new Process();
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.FileName = MyExecutable;
p.StartInfo.Arguments = MyArguments;
p.Start();
while (!p.StandardOutput.EndOfStream)
{
string _output = p.StandardOutput.ReadLine();
// This is my display string ObservableCollection
_displayString.Add(new DisplayData { _string = _output, _color = System.Windows.Media.Brushes.Black, _fontSize = 12 });
// This is to redirect to a Console & what I want to get rid of
Console.WriteLine(_output);
}
p.WaitForExit();
When the executable is done running I use a MessageBox to ask the user if they want to run the executable again. The problem is that when the MessageBox is up the user is unable to scroll on my "console" like window to make an informative decision. To temporarily work around this I launch a console at start up, see this, and write the output stream from the process running the executable to the console so the user can scroll through the information and make a decision.
I am using a listbox to display a collection of textblocks, see this. I am not attached to anything for making the display, or MessageBox'es.
How can I make a "console" like display that will take a user input (MessageBox, direct input, etc...), but also allow them to scroll through the data before they make their decision?
EDIT:
As to the comments I have been receiving I am not clear on what I am trying to accomplish. I have a batch file that runs a executable multiple times with different arguments per run. There is a lot of setup before and between the executable calls. I have created an executable to replace many flavors of a similar batch file with drop down menus for the user to change settings at run time. When the user likes their settings they click a "Start" button, and away it goes doing setups and prompting questions as it goes and then finally runs executable for the first time.
My issue is when the called executable, inside mine, is done running the user needs to decide if they want to run it again for different reasons. I need to prompt the user "Run again - 'Yes' or 'No'?", and that is where I am running into problems. A MessageBox doesn't allow me to scroll on my Progress Window. I have tried a Modeless dialog box, but with Show() the program continues on, and ShowDialog() is the same issue as the MessageBox.
Any suggestions on how to do this would be appreciated.
You are in Windows, but trying to use DOS paradigm. Windows is event-based system! You need to write "event handlers" but not put all your code in one function.
However, there is a trick, which allows to show Modal (read "blocking your code") dialog in Modeless (read "not blocking your window"). Not sure how to implement this in WPF, but idea is to re-enable your window (which acts as parent for your dialog). You need to do this in your dialog event handler (WM_INITDIALOG equivalent?).
Also (in WinAPI) you may run dialog with NULL as parent window.
Almost every tutorial I find tells me to do this for my event loop:
XEvent event;
while (true)
{
XNextEvent(display, &event);
switch (event.type)
{
case Expose:
printf("Expose\n");
break;
default:
break;
}
}
However, clicking the X to close the program results in this message.
XIO: fatal IO error 11 (Resource temporarily unavailable) on X server ":0"
after 10 requests (10 known processed) with 0 events remaining.
It is indeed strange to me that the examples suggest using an infinite loop. That doesn't sound natural, and my other X11 programs don't do that. So I searched around. I found out how to capture the window close event.
Atom wmDeleteMessage = XInternAtom(mDisplay, "WM_DELETE_WINDOW", False);
XSetWMProtocols(display, window, &wmDeleteMessage, 1);
XEvent event;
bool running = true;
while (running)
{
XNextEvent(display, &event);
switch (event.type)
{
case Expose:
printf("Expose\n");
break;
case ClientMessage:
if (event.xclient.data.l[0] == wmDeleteMessage)
running = false;
break;
default:
break;
}
}
That works. It exits without errors. ... But I refuse to believe this is the normal way to do things. I mean, is this the only way to properly exit an X11 app? It seems like a lot of work just to capture the close event. How do I make a 'proper' event loop? Why is the close event so deeply buried? What am I missing?
The problem lays in the communication between X Server and the Window Manager.
When you call XCreateWindow or XCreateSimpleWindow, the X Server creates your window (not showing it until you explicitly map it on the screen by calling XMapWindow), and then the Window Manager is responsible for attaching all the decorations and buttons and system menu around your window.
You can call XDestroyWindow on your own to remove the window, and this usually means it just disappears from the screen, but your program is still running and the connection to the X Server is still open, so you can send it some more requests.
The problem begins when the user clicks that little X button attached to your window by the Window Manager, because it is not created by the X Server and it is not his business to decide what to do then. Now it's all in hands of Window Manager.
If the Window Manager simply called XDestroyWindow on your window, it would cause a problem if your application wanted to capture the closing event to do something before the window gets destroyed. So the convention has been established between the X Server and the Window Managers to handle this process.
The default behavior of most Window Managers is to destroy the window and close the connection with the X server, because this is what most users of Window Managers would expect: that when they close the window, the program will end (and the connection to the X Server will close with the closed window). And then, when you try to call XCloseDisplay(display), it will cause the IO error you've mentioned, because the connection to the server is already closed and the display structure is invalid.
Here's an excerpt from the Xlib documentation which explains this:
Clients that choose not to include WM_DELETE_WINDOW in the WM_PROTOCOLS property may be disconnected from the server if the user asks for one of the client's top-level windows to be deleted.
Yeah, it would be great if they didn't hide it so deep in their docs, though :-P
But when you already find it, fortunately it also hints for the solution.
If you want a different behavior (that is, to capture the closing event from the Window Manager), you need to use the WM_DESTROY_WINDOW protocol.
Another excerpt from the docs:
Clients, usually those with multiple top-level windows, whose server connection must survive the deletion of some of their top-level windows, should include the atom WM_DELETE_WINDOW in the WM_PROTOCOLS property on each such window. They will receive a ClientMessage event as described above whose data[0] field is WM_DELETE_WINDOW.
I had the same error and I wanted to know exactly what causes it and why. It took me some time to figure it out and find the proper explanation in the doc, so I put my explanation here to save the time of others uninformed.
There are no such things as "exit button" or "application" or "close event" in X11. This is by design.
Window decorations, exit buttons and many the other things we depend upon are not built into X11. They are implemented on top of the core X11 instead. The name of the particular set of conventions responsible for wmDeleteMessage is ICCCM, look it up.
Xlib only deals with the core X11 protocol. No built-in close event there.
There are toolkits that make dealing with ICCCM and all other things that are not built into X11 easier (GTK, wxWindows, Qt, ...) You probably want to use one of those.
This is a question which follows on from my previously answered question here
At first I assumed I had a problem with the way I was creating my events due to the handles for OpenEvent returning NULL, I have managed to find the real cause however I am not sure how to go about it.
Basically I use Visual Studio to launch both Process A and B at the same time, in the past my OpenEvent handle wouldn't work due to Process A looking for the address of the event a fraction of a second before Process B had time to make it.
My solution was to simply allow Process B to run before Process A, fixing the error.
The problem I have now is that Process B now reads events from Process A and as you expect it too returns a null handle when trying to open the events from Process A.
I am creating the events in WM_CREATE message of both processes, furthermore I also create a thread at the same time to open/read/act upon the events.
It seems if I run them at the same time they don't get chance to see each other, alternatively if I run one before the other one of them misses out and can't open a Handle.
Can anyone suggest a solution?
Thanks.
Just replace OpenEvent with CreateEvent. CreateEvent will open an Event instead of creating a new one it finds an existing event with the name passed to CreateEvent.