Ncurses menu out of borders - c

I am trying to do simple menu, but I just can't get it to fit into box. Can you tell me what am I doing wrong?
// main
ITEM** items = // items initialization
WINDOW* menuWindow = create_newwin(itemsCount + 2, 38, 3, 5, true);
keypad(menuWindow, TRUE);
MENU* menu = create_menu(itemsCount, menuWindow, items, 2, 2, 5);
refresh();
post_menu(menu);
wrefresh(menuWindow);
// create win
WINDOW *create_newwin(const int height, const int width, const int starty, const int startx, const bool framed){
WINDOW *local_win = newwin(height, width, starty, startx);
if (framed) box(local_win, 0 , 0);
wrefresh(local_win);
return local_win;
}
//create menu
MENU* create_menu(const unsigned int count, WINDOW* window, ITEM** items, const unsigned int startx, const unsigned int starty, const unsigned int length){
MENU* local = new_menu((ITEM **)items);
menu_opts_off(local, O_ONEVALUE);
set_menu_win(local, window);
set_menu_sub(local, derwin(window, count + 2, length, startx, starty));
set_menu_format(local, count, 1);
set_menu_mark(local, " ");
return local;
}
This is how my menu looks like:

It would probably be helpful if you'd post the actual code that gives you the result in the screencap, because I can't reproduce it.
I do see a couple problems here, though. First, this line:
set_menu_sub(local, derwin(window, count + 2, length, startx, starty));
Notice the count + 2 attempts to make a subwindow with height greater than its parent. According to the curs_window(3X) man page, derwin():
returns an error if the parent window pointer is null, or if any of its ordinates or dimensions is negative, or if the resulting window does not fit inside the parent window.
It's worth noting that on my machine, derwin() returns NULL on failure and doesn't set errno, so the documentation isn't necessarily all there.
The other thing that looks strange is this:
MENU* menu = create_menu(itemsCount, menuWindow, items, 2, 2, 5);
Curses windows are 0-addressed from their origin, so with the rest of your code, that's going to attempt to put your menu at {2,2} of the menuWindow. That is, even if you fix the above, it's still going to write over the bottom border of your box with the last menu entry. What's more, your last parameter being 5 means your menu is only going to have five columns including the menu_mark string.
For further reading, I would encourage you to look at the documentation for menu.h because they cover nearly this exact scenario.

You need to create a subwindow for the menu. So you can move it around in the parent-window.

Related

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.

Simple C Program that creates 2 X11 windows

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.

Xlib: window is created in wrong position

I have simple xlib program which creates window. I think it has to show window on the upper-left corner of the screen because I pass 0, 0 to XCreateSimpleWindow function, but it's in upper-middle side. Why ?
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char* argv[])
{
Display* display;
int screen_num;
Window win;
unsigned int display_width,display_height;
unsigned int width, height;
char *display_name = getenv("DISPLAY");
display = XOpenDisplay(display_name);
screen_num = DefaultScreen(display);
display_width = DisplayWidth(display, screen_num);
display_height = DisplayHeight(display, screen_num);
width = (display_width / 3);
height = (display_height / 3);
win = XCreateSimpleWindow(display, RootWindow(display, screen_num), 0, 0, width, height, 1, BlackPixel(display, screen_num), WhitePixel(display, screen_num));
XMapWindow(display, win);
XSync(display, False);
while(1) { }
}
The top level windows are placed (and dimensioned) by the window manager which does whatever it suit it. Often the size is respected but the position not (in order to leave place for decoration, in order to respect placement policy of leaving toolbars clear, ...)
Try on a display without a window manager if you want your request to be respected (use VNC or similar to get such a display, don't try to use your desktop like this)

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