In an embedded Linux system, I'm trying to show a shutdown notification that should override any other windows when shutting down. Now creating the window isn't a problem, but showing the window reliably is. The X server or WM is somehow too busy to draw the notification every time. Considering the limited CPU power we have, its not surprising.
So, I figured I will make it easy to the WM/X by grabbing the X server using gdk_x11_grab_server() (which calls XGrabServer on default display). But when should I call the grab func? If I call it before building my window, prior showing my window or event in expose-event of my window, nothing is drawn to the screen (even in no-load test)!
The documentation says:
The XGrabServer function disables
processing of requests and close downs
on all other connections than the one
this request arrived on.
I suppose that would mean that only requests from my app should be processed, but it seems that is not the case, since nothing is drawn if X is grabbed by my app.
So, how and when should grabbing the X server be used to achieve wanted outcome, or is it totally a wrong tool and I've misunderstood the use (or trying to use it too high level for it to work really).
I'd guess that nothing is being drawn because you're opening a normal top level window, in which case the window manager needs to operate on it before it'll be visible; however you've locked out the window manager by calling XGrabServer().
You could try setting OverrideRedirect on the window, which tells the X server that the window manager shouldn't be involved with this window at all. This also has the effect of removing any decorations (title bar, close button, etc) from the window, which could well be what you want for a shutdown notification.
You may need to follow the call with XSync/XFlush.
Shouldn't you follow up with a call to XUngrabServer so that the X server resumes processing requests? All other connections have already been closed because you called XGrabServer, but you obviously need request handling to resume because you want to make requests on your connection.
There seems to be some confusing as to what XGrabServer actually does precisely, and not just on this question. The man pages are pretty ambiguous about this. We can easily verify though that the server indeed still processes requests from our connection:
// cc grab-test.c `pkg-config --cflags --libs x11`
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <X11/Xlib.h>
int main(void)
{
// Initialize
Display* dpy = XOpenDisplay(NULL);
assert(dpy != NULL);
int s = DefaultScreen(dpy);
// Grab the Server
XGrabServer(dpy); // XFlush(dpy);
// Create some stuffs
Window win = XCreateSimpleWindow(dpy, RootWindow(dpy, s), 10, 10, 640, 480, 1, BlackPixel(dpy, s), WhitePixel(dpy, s));
XSelectInput(dpy, win, ExposureMask);
XMapWindow(dpy, win);
XStoreName(dpy, win, "An X11 window");
// Notice we can query the attributes BEFORE ungrabbing the server
XWindowAttributes wa;
XGetWindowAttributes(dpy, win, &wa);
int width = wa.width;
int height = wa.height;
printf("Current window size: %dx%d\n", width, height);
sleep(2); // Give some time to see the window
XDestroyWindow(dpy, win); XFlush(dpy);
sleep(2); // Give some time to NOT see the window
// Ungrab the server
XUngrabServer(dpy); // XFlush(dpy);
// Shutdown
XCloseDisplay(dpy);
return 0;
}
There is probably a window manager or composite manager preventing the window from being displayed, if I run the above program in Xephyr (without a window manager or composite manager), I can see a white window for 2 seconds followed by a black screen for 2 seconds, after which all other windows are redrawn again.
Related
TL;DR
I'm writing a simple reparenting window manager. I'm testing it with the help of Xephyr. While the window manager is running, any application launched during that time, is not shown (not visible) on the screen, whereas any application launched before the window manager was launched is shown (visible).
Full Question
I'm writing a simple reparenting window manager. Currently I'm handling only two events XCB_CREATE_NOTIFY and XCB_BUTTON_PRESS. I've registered for XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT and XCB_EVENT_MASK_EXPOSURE on the root window.
I'm testing the wm with Xephyr. And while testing any application launched after the wm has launched, is not shown (not visible) on the screen, while applications that have been launched before launching the wm, are shown perfectly (visible).
I read somewhere that registering for EXPOSURE event on the root window will solve the problem, but that doesn't seem the case for me. Below is my code for the CREATE_NOTIFY event, that attempts to reparent the client window and map it on screen (I think this is where I'm doing something wrong):
case XCB_CREATE_NOTIFY:
{
xcb_create_notify_event_t *cre;
cre = (xcb_create_notify_event_t *)evt;
xcb_window_t frame = xcb_generate_id(conn);
uint32_t frameMask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
uint32_t fM_values[2];
fM_values[0] = custTeal->pixel; //custTeal is a custom Teal color that I've defined
fM_values[1] = XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_POINTER_MOTION;
xcb_window_t toBeMapped = cre->window;
xcb_get_geometry_reply_t *tbm_window_geo = xcb_get_geometry_reply(conn,xcb_get_geometry(conn,toBeMapped),NULL);
xcb_create_window(conn,0,frame,screen->root,tbm_window_geo->x,tbm_window_geo->y,(tbm_window_geo->width+4),(tbm_window_geo->height+4),1,XCB_WINDOW_CLASS_INPUT_OUTPUT,screen->root_visual,frameMask,fM_values);
xcb_reparent_window(conn,toBeMapped,frame,2,2);
xcb_map_window(conn,frame);
xcb_map_window(conn,toBeMapped);
xcb_flush(conn);
}
break;
I can't figure out what I'm doing wrong here (I'm pretty new to this). Do I have to handle the EXPOSE event too? How do I handle it?
Testing
Im launching Xephyr with
Xephyr -br -ac -noreset -screen 1240x720 :2 &
and launching new applications with (take xterm as an example):
DISPLAY=:2 xterm &
Now, any application launched before launching the wm (or when the wm is not running) is shown perfectly in Xephyr. But after I launch the wm, any application launched is not showm.
SubstructureRedirect means that when something else tries to map a window, the X11 server instead generated a MapRequest event and sends that to the WM. Thus, you should handle XCB_MAP_REQUEST events. The simplest way to do that would be to xcb_map_window the window from the event.
As long as I understand it, the X11 FocusIn event is triggered whenever the window comes into focused. It the the window that the keyboard input is sent to. I am having trouble triggering this event. I have made sure to give it the FocusChangeMask when creating the window. I have created a breakpoint inside my event handler where the FocusIn event is supposed to happen and it is not stopping.
I have 2 separate window, a transparent one and one non-transparent. Currently I have it so the transparent window is always on top of the non transparent window. Whenever I switch focus and then switch back to the transparent window, the non-transparent window is directly underneath. This causes other windows to be stuck in 'between' the transparent and non-transparent window.
I have noticed that whenever I focus on the non-transparent window that is underneath that triggers the FocusIn event. I can not get the transparent window to trigger the event. Does this have something to do with the window being in 32-bit color?
What am I missing?
while(!renderer->stop)
{
XNextEvent(renderer->x_display, &event);
switch(event.type)
{
case Expose:
if (event.xexpose.window == gstreamer_window)
{
XRaiseWindow(renderer->x_display, renderer->opengl_window);
}
break;
case FocusIn:
if (event.xfocus.window == renderer->opengl_window)
{
XRaiseWindow(renderer->x_display, gstreamer_window);
}
break;
case ConfigureNotify:
if (event.xconfigure.window == renderer->opengl_window)
{
XMoveWindow(renderer->x_display, gstreamer_window,
event.xconfigure.x, event.xconfigure.y - top_border_offset);
}
break;
}
}
Here is how I created the window.
XSetWindowAttributes swa;
swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask | FocusChangeMask;
swa.colormap = XCreateColormap(x_display, XDefaultRootWindow(x_display), visual, AllocNone);
swa.background_pixel = 0;
swa.border_pixel = 0;
/* Create a window */
opengl_window = XCreateWindow (
x_display, parent,
0, 0, m_plane_width, m_plane_height, 0,
depth, InputOutput,
visual, CWEventMask | CWBackPixel | CWColormap | CWBorderPixel,
&swa );
It appears as though I set the FocusChangeMask at the wrong place. By adding the line XSelectInput(x_display, opengl_window, FocusChangeMask)
, it now triggers the FocusIn event. It was triggering the other display because it had the mask but this one didn't.
It's not clear from your question whether the windows referenced in your question are top level application windows, or secondary, ancillary windows that are child windows of your top level application windows.
But in all cases, proper input focus handling requires you to inform the window manager exactly how your application expects to handle input focus.
See section 4.1.7 of the ICCCM specification for more information. Unfortunately, it's not enough just to code an event loop that handles FocusIn messages, and expect them to fall out of the sky. First, you need to tell your window manager how exactly you are going to handle input focus switching, then respond to the window manager's messages, as explained in the ICCCM specification; perhaps by explicitly sending the SetInputFocus requests for your own application windows.
See my post under OP's self accepted answer for background
I had the same problem and it seems if you use XSelectInput it overrides the event mask for a window, instead of adding to it. You need to either:
skip adding XSelectInput and set the event masks on the window when created
or add all of the masks for the window to the XSelectInput command
Here's my similar setup which worked before I added the XSelectInput line:
swa.event_mask = StructureNotifyMask | SubstructureNotifyMask | FocusChangeMask | ExposureMask | KeyPressMask;
wnd = XCreateWindow(disp, wndRoot, left, top, width, height, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &swa);
XMapWindow(disp, wnd);
When I added this for capturing key input:
XSelectInput(disp, wnd, KeyPressMask | KeyReleaseMask);
everything else stopped working, which I didn't realize for a while, until now, because I was just testing keys.
I have a single window application with no controls in the client area, so I don't know what else XSelectInput does for a window that already has the masks, but I do get key up and down messages without it. In the OP's self accepted answer he just goes the other way and adds 'FocusChangeMask' to XSelectInput instead.
The documentation for a lot of X11 is, in my opinion, a lot like the standard Apple documentation where it has the affliction of never saying what the function really actually does or affects, but tells you all about everything else. (See bottom snippet here) To be fair a good portion of the Cocoa docs are pretty decent, but maybe half are not. That goes for many or most of the parameters as well.
From Linux man page which I think is the maybe verbatim the same as the Xlib manual here https://tronche.com/gui/x/xlib/
The XSelectInput function requests that the X server report the events associated with the specified event mask.
Setting the event-mask attribute of a window overrides any previous call for the same window but not for other clients.
(Below is my own perhaps incorrect rewording of the XInputSelect docs)
This can be interpreted as perhaps:
XSelectInput sets the event-mask on a window for a display for events reported to the client. Each client can set its own independent mask for events it wants to receive with the following exceptions (skipping the exceptions).
Now the critical part:
XInputSelect will override and replace for a client any previous event-mask settings for a window on a display, including any event-mask set when creating the window.
And what I wish it was written as to make sure its understood, if true, that the XInputSelect does nothing else like enable key to character interpretation and what not, because I believe the core confusion is that people from all the various examples out there get the impression that there is some other magic besides setting mask. I'm assuming there's not, and the docs speak of no other magic besides the mask.
XInputSelect sets the event-mask for a window and allows for setting an event mask after a window is created.
And my opinion is that that line should have been first.
In one terminal I'm starting a process that looks like this....
// ...
while(true) {
XNextEvent(xw.dpy, &ev);
if(XFilterEvent(&ev, None))
continue;
printf("type: %d\n", ev.type);
if(handler[ev.type])
(handler[ev.type])(&ev);
}
// ...
Then I use xev to monitor this process
xev -i <window>
I then open Chrome, copy some text, then focus the first process and do Shift+Insert. This results in text being pasted into the first process and we see it print '31' (/usr/include/X11/X.h) which indicates SelectionNotify. xev on the other hand doesn't show a SelectionNotify event, but it does show a PropertyNotify event that the first process doesn't show. The PropertyNotify event updates the PRIMARY property.
This is how the copy/paste algorithm is supposed to work: http://en.wikipedia.org/wiki/X_Window_selection#Selections
Thoughts?
From the xev manpage, "Xev ... asks the X server to send it events whenever anything happens to the window (such as it being moved, resized, typed in, clicked in, etc.). You can also attach it to an existing window. It is useful for seeing what causes events to occur and to display the information that they contain; "
Apparently xev doesn't get the actual events that the window it is attached to is getting.
xev code looks like this
case 'i': /* -id */
if (++i >= argc) usage ();
sscanf(argv[i], "0x%lx", &w);
if (!w)
sscanf(argv[i], "%lu", &w);
if (!w)
usage ();
continue;
// ...
if (w) {
XGetWindowAttributes(dpy, w, &wattr);
if (wattr.all_event_masks & ButtonPressMask)
attr.event_mask &= ~ButtonPressMask;
attr.event_mask &= ~SubstructureRedirectMask;
XSelectInput(dpy, w, attr.event_mask);
} else {
// ...
}
//...
for (done = 0; !done; ) {
XEvent event;
XNextEvent (dpy, &event);
switch (event.type) {
// ...
}
}
Presumably XSelectInput and XNextEvent are doing something weird when a process 'attaches' to some window and that window gets a SelectionNotify event.
"Unfortunately, xev is not fool proof if you ask it to track events on a window it does not own (the -id mode). It receives these events by requesting them with Xlib's XSelectInput() function. This technique has three major limitations:
1. grabs - If one client activates a server, pointer, or keyboard grab, then event reporting to all other clients will be affected. xev will not be able to report some (or all) events, even though the client activating the grab may be receiving them.
2. non-maskable events - The X protocol does not allow certain events to be reported to clients other than the one that created the event window. Most of these events deal with selections.
3. redirection events - The X protocol allows only one client to request certain events. xev cannot receive these if another client is receiving them. These events include window manager redirection events (e.g., substructure notify on the root window) and implicit passive grab events (e.g., mouse button presses)." (http://www.rahul.net/kenton/events.html#LimitationsOf)
I know there has been a few of these, but a lot of the answers always to have a lot of buts, ifs, and you shouldn't do that.
What I'm trying to do is have a background program that can monitor the keyboard events from X11. This is on an embedded device, and it will have a main app basically running in something like a kiosk mode. We want to have a background app that manages a few things, and probably a back doors hook. But this app generally will not have focus.
I can't use the main app, because its partially there for a fail safe if the main app ever fails, or to do some dev type things to bypass the main app.
The best question I found is a few years old, so I'm not sure how up to date it is. This was extremely easy to do with windows.
X KeyPress/Release events capturing irrespective of Window in focus
The correct way for doing that is using Xlib. Using this library you can write code like this:
while (1) {
XNextEvent(display, &report);
switch (report.type) {
case KeyPress:
if (XLookupKeysym(&report.xkey, 0) == XK_space) {
fprintf (stdout, "The space bar was pressed.\n");
}
break;
}
}
// This event loop is rather simple. It only checks for an expose event.
// XNextEvent waits for an event to occur. You can use other methods to get events,
// which are documented in the manual page for XNextEvent.
// Now you will learn how to check if an event is a certain key being pressed.
// The first step is to put case KeyPress: in your switch for report.type.
// Place it in a similar manner as case Expose.
Also you could use poll or select on the special device file that is mapped to your keyboard. In my case is /dev/input/event1.
If you have doubts about what's the special file mapped to your keyborad, read the file /var/log/Xorg.0.log (search for the word keyboard).
Here you have another link of interest: Linux keyboard event capturing /dev/inputX
Is there a good library to use for gathering user input in Linux from the mouse/keyboard/joystick that doesn't force you to create a visible window to do so? SDL lets you get user input in a reasonable way, but seems to force you to create a window, which is troublesome if you have abstracted control so the control machine doesn't have to be the same as the render machine. However, if the control and render machines are the same, this results in an ugly little SDL window on top of your display.
Edit To Clarify:
The renderer has an output window, in its normal use case, that window is full screen, except when they are both running on the same computer, just so it is possible to give the controller focus. There can actually be multiple renderers displaying a different view of the same data on different computers all controlled by the same controller, hence the total decoupling of the input from the output (Making taking advantage of the built in X11 client/server stuff for display less useable) Also, multiple controller applications for one renderer is also possible. Communication between the controllers and renderers is via sockets.
OK, if you're under X11 and you want to get the kbd, you need to do a grab.
If you're not, my only good answer is ncurses from a terminal.
Here's how you grab everything from the keyboard and release again:
/* Demo code, needs more error checking, compile
* with "gcc nameofthisfile.c -lX11".
/* weird formatting for markdown follows. argh! */
#include <X11/Xlib.h>
int main(int argc, char **argv)
{
Display *dpy;
XEvent ev;
char *s;
unsigned int kc;
int quit = 0;
if (NULL==(dpy=XOpenDisplay(NULL))) {
perror(argv[0]);
exit(1);
}
/*
* You might want to warp the pointer to somewhere that you know
* is not associated with anything that will drain events.
* (void)XWarpPointer(dpy, None, DefaultRootWindow(dpy), 0, 0, 0, 0, x, y);
*/
XGrabKeyboard(dpy, DefaultRootWindow(dpy),
True, GrabModeAsync, GrabModeAsync, CurrentTime);
printf("KEYBOARD GRABBED! Hit 'q' to quit!\n"
"If this job is killed or you get stuck, use Ctrl-Alt-F1\n"
"to switch to a console (if possible) and run something that\n"
"ungrabs the keyboard.\n");
/* A very simple event loop: start at "man XEvent" for more info. */
/* Also see "apropos XGrab" for various ways to lock down access to
* certain types of info. coming out of or going into the server */
for (;!quit;) {
XNextEvent(dpy, &ev);
switch (ev.type) {
case KeyPress:
kc = ((XKeyPressedEvent*)&ev)->keycode;
s = XKeysymToString(XKeycodeToKeysym(dpy, kc, 0));
/* s is NULL or a static no-touchy return string. */
if (s) printf("KEY:%s\n", s);
if (!strcmp(s, "q")) quit=~0;
break;
case Expose:
/* Often, it's a good idea to drain residual exposes to
* avoid visiting Blinky's Fun Club. */
while (XCheckTypedEvent(dpy, Expose, &ev)) /* empty body */ ;
break;
case ButtonPress:
case ButtonRelease:
case KeyRelease:
case MotionNotify:
case ConfigureNotify:
default:
break;
}
}
XUngrabKeyboard(dpy, CurrentTime);
if (XCloseDisplay(dpy)) {
perror(argv[0]);
exit(1);
}
return 0;
}
Run this from a terminal and all kbd events should hit it. I'm testing it under Xorg
but it uses venerable, stable Xlib mechanisms.
Hope this helps.
BE CAREFUL with grabs under X. When you're new to them, sometimes it's a good
idea to start a time delay process that will ungrab the server when you're
testing code and let it sit and run and ungrab every couple of minutes.
It saves having to kill or switch away from the server to externally reset state.
From here, I'll leave it to you to decide how to multiplex renderes. Read
the XGrabKeyboard docs and XEvent docs to get started.
If you have small windows exposed at the screen corners, you could jam
the pointer into one corner to select a controller. XWarpPointer can
shove the pointer to one of them as well from code.
One more point: you can grab the pointer as well, and other resources. If you had one controller running on the box in front of which you sit, you could use keyboard and mouse input to switch it between open sockets with different renderers. You shouldn't need to resize the output window to less than full screen anymore with this approach, ever. With more work, you could actually drop alpha-blended overlays on top using the SHAPE and COMPOSITE extensions to get a nice overlay feature in response to user input (which might count as gilding the lily).
For the mouse you can use GPM.
I'm not sure off the top of my head for keyboard or joystick.
It probably wouldn't be too bad to read directly off there /dev files if need be.
Hope it helps