Resizing windows in curses - c

I have several tiled windows in curses, initialized like this
int row, col;
getmaxyx(stdscr, row, col);
WINDOW* a = newwin(row, col/2, 0, 0);
WINDOW* b = newwin(row, col/2, 0, col/2);
box(a, 0, 0);
box(b, 0, 0);
/* Refresh stdscr and windows...
...
*/
If the user resizes the terminal, I would like to resize the windows accordingly, what's the best way to do this? All I can think of is deleting the old windows and making new ones, but that can be kind of tedious when I'm dealing with multiple windows

Related

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).

X11 Why I can't draw any text?

I'm trying to learn X11. It's very hard to me, because I don't have experience with window applications on Linux.
I wrote some simple code and I can't resolve this not visible text problem.
Everything is working good probably, when I was trying to draw rectangle with DrawRectangle function it was working.
Here is the code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <X11/Xlib.h>
int main()
{
Display* myDisplay;
Window myWindow;
int myScreen;
GC myGC;
XEvent myEvent;
unsigned long black, white;
char* hello = "Hello world!";
XFontStruct* myFont;
if((myDisplay = XOpenDisplay(NULL)) == NULL)
{
puts("Error in conneting to X Server!");
return -1;
}
myScreen = DefaultScreen(myDisplay);
black = BlackPixel(myDisplay, myScreen);
white = WhitePixel(myDisplay, myScreen);
myWindow = XCreateSimpleWindow(myDisplay, RootWindow(myDisplay, myScreen), 0, 0, 640, 320, 5, black, white);
XSelectInput(myDisplay, myWindow, ExposureMask);
XClearWindow(myDisplay, myWindow);
XMapWindow(myDisplay, myWindow);
myGC = XCreateGC(myDisplay, myWindow, 0, 0);
XSetForeground(myDisplay, myGC, black);
XSetBackground(myDisplay, myGC, white);
myFont = XLoadQueryFont(myDisplay, "-Misc-Fixed-Medium-R-Normal--7-70-75-75-C-50-ISO10646-1");
XSetFont(myDisplay, myGC, myFont->fid);
while(1)
{
XNextEvent(myDisplay, &myEvent);
if(myEvent.type == Expose)
{
XClearWindow(myDisplay, myWindow);
// HERE I DONT KNOW WHY IT DOESNT WORK!
XDrawString(myDisplay, myWindow, myGC, 0, 0, hello, strlen(hello));
}
}
XFreeGC(myDisplay, myGC);
XDestroyWindow(myDisplay, myWindow);
XCloseDisplay(myDisplay);
return 0;
}
Thank you for help!
Your font path argument to XLoadQueryFont is wrong (on my Linux/Debian desktop). Check with the xlsfonts command the right ones (they are all lowercases).
With
myFont = XLoadQueryFont
(myDisplay,
"-misc-fixed-medium-r-normal--9-90-75-75-c-60-iso10646-1");
it could work better. Try also with "lucidasanstypewriter-bold-14"
And most importantly the coordinates passed to XDrawString are wrong. Remember that they are the coordinates of the baseline of your text. And x=0, y=0 is the top left corner of the window, and y is growing downwards and x is growing to the right. Hence your text is drawn off-window, above its top. So y should be positive and more than the font height.
Try
XDrawString (myDisplay, myWindow, myGC, 15, 20, hello,
strlen (hello));
As I commented, you need to handle a lot more events.
I don't have experience with window applications on Linux.
And to learn about GUI programming, I strongly recommend first using some toolkit like GTK or Qt or perhaps SDL.
Raw X11 programming is too hard (and by the time you'll learn it is will be obsolete, e.g. by Wayland), in particular because an X11 application needs to be ICCCM & EWMH compliant. Notice that the entire X11 documentation requires nearly ten thousand pages.
See also https://tronche.com/gui/x/xlib/
BTW, most Linux GUI applications are drawing pixmap client side and sending it to the X11 server. Read about compositing window managers. Drawing requests like XDrawString are no more used anymore in practice. Recent font related libraries like libfontconfig, libXft, etc are working on the client side.

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.

Why does XWarpPointer only work once (while in a loop)?

Why does XWarpPointer only work once?
When I run:
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
int main()
{
Display *dpy = XOpenDisplay(0);
while (1) {
Window root_window;
root_window = XRootWindow(dpy, 0);
XSelectInput(dpy, root_window, KeyReleaseMask);
XWarpPointer(dpy, None, root_window, 0, 0, 0, 0, 100, 100);
XSync(dpy, False);
}
}
The mouse should appear locked in a single position. But it only moves the mouse once and then lets me move it around while the loop is still runnning. What is causing the XWarpPointer to only run once? Is it some kind of X11 feature to protect the user from the application?
FYI, I am running RHEL 5.2 on VMWare Fusion on Mac OSX 10.6.
Update:
When running the binary, components
like a button or icon flicker, but
the visual mouse cursor stays where I
move it.
After the one time XWarpPointer does
work, when I move the mouse, the
cursor jumps to near where it was
before I warped it. It's as if there
is a (last_x,last_y) that is not
getting updated.
When I change the pointer via
OpenVMTools it seems to make the
pointer stick to the desired location
more, but the visual pointer does not
change.
Thanks,
Chenz
I've no experience here but what happens if you don't discard events in XSync? e.g. XSync(dpy, True);?
After
XWarpPointer(dpy, None, root_window, 0, 0, 0, 0, 100, 100);
Try
XFlush(dpy);
This should solve the problem.

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