Simple C Program that creates 2 X11 windows - c

I want to create 2 windows in linux that I'll later draw in from a separate thread. I currently have a non-deterministic bug where the second window that I create sometimes doesn't get created (no errors though).
Here is the code.
static void create_x_window(Display *display, Window *win, int width, int height)
{
int screen_num = DefaultScreen(display);
unsigned long background = WhitePixel(display, screen_num);
unsigned long border = BlackPixel(display, screen_num);
*win = XCreateSimpleWindow(display, DefaultRootWindow(display), /* display, parent */
0,0, /* x, y */
width, height, /* width, height */
2, border, /* border width & colour */
background); /* background colour */
XSelectInput(display, *win, ButtonPressMask|StructureNotifyMask);
XMapWindow(display, *win);
}
int main(void) {
XInitThreads(); // prevent threaded XIO errors
local_display = XOpenDisplay(":0.0");
Window self_win, remote_win;
XEvent self_event, remote_event;
create_x_window(local_display, &remote_win, 640,480);
// this line flushes buffer and blocks so that the window doesn't crash for a reason i dont know yet
XNextEvent(local_display, &remote_event);
create_x_window(local_display, &self_win, 320, 240);
// this line flushes buffer and blocks so that the window doesn't crash for a reason i dont know yet
XNextEvent(local_display, &self_event);
while (1) {
}
return 0;
}
I don't really care for capturing input in the windows, but I found a tutorial that had XSelectInput and XNextEvent (in an event loop) and I was having trouble making this work without either.

It's not a bug, it's a feature. You left out the event loop.
Although you cleverly called XNextEvent twice, the X protocol is asynchronous so the server may still be setting up the actual window while you call XNextEvent, so there is nothing to do.
Tutorial here.

Related

Cant fin definition of XMapWindow() in Xlib headers

So i have this simple code that draws a small window using X11
int main(int, char*[])
{
Display* display = XOpenDisplay(NULL);
Window window = XCreateSimpleWindow(
display, XDefaultRootWindow(display),
100, 100, 200, 200, 4, 0, 0);
XEvent event;
XMapWindow(display, window);
XSelectInput(display, window, KeyPressMask | ButtonPressMask | ExposureMask);
while (True) {
XNextEvent(display, &event);
}
return 0;
}
Everything works fine, the window its drawed without problems.
The thing is i really want to understand how X11 works so im reading the source code of the headers but im unable to find the difinition for XMapWindow() i need help.
This was the only similutede i could find in the Xlib.h header file.
extern int XMapWindow(
Display* /* display */,
Window /* w */
);
You can find the implementation of XMapWindow() in the libX11 sources, specifically in src/MapWindow.c:XMapWindow().
It boils down to some locking, and a _XGetRequest(dpy, X_MapWindow, SIZEOF(xResourceReq)) call. That is defined in src/XlibInt.c:_XGetRequest(), and as you can guess by the name, adds the X_MapWindow request to the request queue sent to the X server.
How the X server (which manages the actual display) acts on that, is up to that X server implementation.

Why XServer sends FocusOut notify twice

I write dummy window for software KVM. Idea is when user switches to another machine, previous machine opens dummy window beyond the screen bounds, so emulates focus lost. Windows without focus are transparent on my system (awesome wm). If I just use XSetInputFocus(dpy, None, RevertToNone, CurrentTime) current window loses focus but doesn't become transparent. That is why I use dummy window.
Come to the point. My program saves focused window before opens dummy window. When dummy window loses focus program restores saved. So It needs to catch FocusOut event and then call XSetInputFocus function to restore focus. Problem is that xserver sends FocusOut notify twice. If I handle it only once program works incorrect.
Code is below.
#include <X11/Xlib.h>
#include <X11/Xatom.h>
int x = 100, y = 100, height = 200, width = 200;
typedef struct {
Window win;
int notify;
} wait_arg;
Bool xevent_handler(Display *dpy, XEvent *ev, XPointer arg) {
wait_arg *a = (wait_arg *) arg;
return (ev->type == a->notify) && (ev->xvisibility.window == a->win);
}
int main(int argc, char *argv[]) {
Display *dpy;
Window focused;
int revert_to;
Window win;
wait_arg arg;
XEvent ev;
dpy = XOpenDisplay(NULL);
// Save window which has focus now
XGetInputFocus(dpy, &focused, &revert_to);
int s = DefaultScreen(dpy);
win = XCreateSimpleWindow(dpy, RootWindow(dpy, s), 0, 0, height, width, 0,
CopyFromParent, CopyFromParent);
// Set DIALOG type for window
Atom type = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
long value = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
XChangeProperty(dpy, win, type, XA_ATOM, 32, PropModeReplace,
(unsigned char *) &value, 1);
// Set events to handle
XSelectInput(dpy, win, VisibilityChangeMask | FocusChangeMask);
// Draw window
XMapWindow(dpy, win);
// Wait until window stands visible, otherwise will get
// "Error of failed request: BadMatch"
arg.win = win;
arg.notify = VisibilityNotify;
XIfEvent(dpy, &ev, &xevent_handler, (XPointer) &arg);
XSetInputFocus(dpy, win, RevertToNone, CurrentTime);
XSync(dpy, False);
XMoveWindow(dpy, win, x, y);
// Wait until focus lost
arg.win = win;
arg.notify = FocusOut;
XIfEvent(dpy, &ev, &xevent_handler, (XPointer) &arg);
// Why I should handle this event twice?
XIfEvent(dpy, &ev, &xevent_handler, (XPointer) &arg);
// Restore focus
XSetInputFocus(dpy, focused, revert_to, CurrentTime);
XSync(dpy, False);
}
How to check incorrect behavior:
I comment second FocusOut handling. I use two monitors: left and right. I start program in terminal on right monitor. Program opens dummy window on left monitor. When dummy window loses focus another window on left monitor obtains it. Not terminal window on right monitor!
Why xserver sends FocusOut twice? Or it is bug/feature of my window manager?
Without your implementation it is really impossible to know exactly what the driver is for the behavior you are seeing, but the man pages do provide some insight into what may be happening.
This particular behavior may be the result of the last-focus-change time. From this man page:
...The XSetInputFocus() function changes the input focus and the last-focus-change time. It has no effect if the specified time is earlier than the current
last-focus-change time or is later than the current X server time.

How box() is adopting max width after resizing terminal

I don't know how reexecuting the function box() is adopting max width automatically and here is test code :
getmaxyx(stdscr,y,x);
WINDOW *titleWin = update_title_win(NULL,2,x,0,0);
while((ch = getch()) != 27) {
if(ch == KEY_RESIZE) {
update_title_win(titleWin);
}
}
update_title_win() code :
WINDOW* update_title_win(WINDOW *win, int height, int width, int y, int x)
{
if(!win)
win = newwin(height,width,y,x);
box(win,0,0);
refresh();
wrefresh(win);
return win;
}
The ncurses library uses resizeterm to do the adjustments when getch returns KEY_RESIZE. That function will reduce the size of windows if the (terminal/screen) shrinks, but the behavior when the screen increases in size is less apparent.
The manual page for resizeterm does not mention this, but a comment in the source code explains the behavior:
/*
* If we're increasing size, recursively search for windows that have no
* parent, increase those to fit, then increase the contained window, etc.
*/
A window created with newwin has no parent (unlike something made with subwin). Since the titleWin started off with the full width of the screen, as the screen width changes, ncurses will attempt to keep the title window full-width.

ncurses child window not keeping fixed width

I have an ncurses program, with multiple child windows acting as columns. Each child window has a fixed width and the height of the parent terminal window.
However I've found that if the width of the terminal is reduced then one of the windows loses their fixed width and seems to "overflow" their previously set bounds, using the entire remaining width of the terminal.
This is hard to explain so I made a quick gif showing the problem:
This is the code I've used for the above:
#include <ncurses.h>
int main() {
WINDOW * winA, * winB;
int i = 0, width = 30;
initscr();
// Suppress stdout
noecho();
// Enable keypad
keypad(stdscr, true);
// interrupt, quit, suspend, and flow control characters are all passed through uninterpreted
raw();
winA = newwin(0, width, 0, 0);
winB = newwin(0, width, 0, width);
timeout(50);
while(getch() != 'q') {
i = width * getmaxy(stdscr);
werase(winA);
werase(winB);
while (i--) {
waddstr(winA, "0");
waddstr(winB, "1");
}
wnoutrefresh(stdscr);
wnoutrefresh(winA);
wnoutrefresh(winB);
doupdate();
}
endwin();
return 0;
}
Here is another screenshot showing the issue in my actual program. The terminal on the left is correct, the one on the right shows the result after resizing the window and triggering this issue:
How can I prevent windows from losing their fixed-width-ness when the terminal is resized to a small width?
Rather than using windows for everything, you could use pads. Windows are limited to the screen-size, while pads are not.
When ncurses gets a SIGWINCH, it resizes stdscr and everything contained within stdscr, shrinking those windows as needed to fit in the new screen-size, or (if their margins match the old screen-size), increasing their size. That's automatic. Your program could check for KEY_RESIZE returned by getch and call wresize to change window sizes (and redraw their contents).
If you used pads, those do not get resized (pads are shown through a viewport that the caller can adjust).

How to set mouse cursor position in C on linux?

how can I set the mouse cursor position in an X window using a C program under Linux?
thanks :)
(like setcursorpos() in WIN)
EDIT:
I've tried this code, but doesn't work:
#include <curses.h>
main(){
move(100, 100);
refresh();
}
12.4 - Moving the Pointer
Although movement of the pointer
normally should be left to the control
of the end user, sometimes it is
necessary to move the pointer to a new
position under program control.
To move the pointer to an arbitrary
point in a window, use XWarpPointer().
Example:
Display *dpy;
Window root_window;
dpy = XOpenDisplay(0);
root_window = XRootWindow(dpy, 0);
XSelectInput(dpy, root_window, KeyReleaseMask);
XWarpPointer(dpy, None, root_window, 0, 0, 0, 0, 100, 100);
XFlush(dpy); // Flushes the output buffer, therefore updates the cursor's position. Thanks to Achernar.
This is old, but in case someone else comes across this issue. The answer provided by tusbar was correct but the command XFlush(dpy) must be added at the end to update the cursor's position. The libraries needed are: X11/X.h, X11/Xlib.h, X11/Xutil.h.
int main(int argc, char *argv[]){
//Get system window
Display *dpy;
Window root_window;
dpy = XOpenDisplay(0);
root_window = XRootWindow(dpy, 0);
XSelectInput(dpy, root_window, KeyReleaseMask);
XWarpPointer(dpy, None, root_window, 0, 0, 0, 0, 100, 100);
XFlush(dpy);
return 0;}
PS: You can use this command to build the code gcc main.c -lX11
You want to write a X11 program that uses the call XWarpPointer function to move the point to a relative or global position. (Xlib Programming Manual, Vol 1)
In general, using Xlib for programming the X Window System, is the most basic, and quite low-level interface for graphical programming on a Unix or Linux system. Most applications developed nowadays using a higher level library such as GTK or Qt for developing their GUI applications.
Curses or NCurses (New Curses) is for programming terminal-oriented interfaces, so are not useful in this case.
use Jordan Sissel's excellent utility xdotool.
http://www.semicomplete.com/projects/xdotool/
it provide XWarpPointer wrapper function like xdo_mousemove(), here is some example:
Display *display = NULL;
xdo_t *xdo = NULL;
void mouse_left_down(int x, int y)
{
xdo_mousemove(xdo, x, y, 0)
xdo_mousedown(xdo, CURRENTWINDOW, Button1);
}
void mouse_left_up(int x, int y)
{
xdo_mouseup(xdo, CURRENTWINDOW, Button1, 1, 0);
}
void mouse_left_double_click(int x, int y)
{
xdo_mousemove(xdo, x, y, 0);
xdo_click_multiple(xdo, CURRENTWINDOW, Button1, 1, 0);
doubleclick = TRUE;
}
int main()
{
display = XOpenDisplay(NULL);
if(display == NULL)
{
fprintf(stderr, "can't open display!\n");
return -1;
}
xdo = xdo_new((char*) display);
//some task here
// ...
return 0;
}
You can use XWarpPointer to move the mouse cursor in an X window.
XWarpPointer(display, src_w, dest_w, src_x, src_y, src_width, src_height, dest_x,
dest_y)
Display *display;
Window src_w, dest_w;
int src_x, src_y;
unsigned int src_width, src_height;
int dest_x, dest_y;
All modern terminals should support ANSI escape sequences. For anything more complicated (and more portable), however, you should look into using a library such as ncurses.

Resources