Printing inside window, not on borders - c

I'm trying to write something inside a curses window, but it seems to write on borders too. How can I fix the code below?
win_self = newwin(LINES / 2, COLS, 0, 0);
box(win_self, 0, 0);
wrefresh(win_self);
wprintw(win_self, "foobar");

In curses, the borders generated by box() are inside borders. As far as I can tell, there's no way to simply say "don't overwrite my border".
Nevertheless, there are three solutions that I can think of right now:
don't overwrite the border characters (use move())
draw the box after you draw window contents, then refresh() the screen (you're probably still overwriting something, but at least it's not the border characters)
create a "border window" with borders and a "content window" inside of it, which of course starts at (border_window_start_y + 1, border_window_start_x + 1) and is two lines/columns smaller than the "border window"
Just to make it more clear: the box() function doesn't add the property "this window has visible borders" to the window, it just prints border characters around the window.
You are:
free to overwrite those border characters
supposed to be cautious if you don't want them overwritten

I'd say the easiest way is to create a window inside of the window borders and print in that window.
win_self = newwin(LINES / 2, COLS, 0, 0);
box(win_self, 0, 0);
derwin_self = derwin(win_self, LINES / 2 - 2, COLS - 2, 0, 0);
wprintw(derwin_self, "foobar");

Related

cairo / xlib not updating window content

I am trying to learn how to use Cairo 2D drawing library with xlib surfaces.
I wrote a little test program that allows creating multiple windows. Each function may have a custom paint() function that is called regularly to add some graphics content to the window, or redraw it completely if desired. There is also an option to define mouse and key listener. The main routine checks for X events (to delegate them to mouse and key listener) and for timeout for periodic call of those paint() functions.
I tried with the 1.14.6 version of Cairo (that is currently available as package in Ubuntu 16.04), and the latest 1.15.12, but the results are the same.
The expected behavior of this demo is to open 3 windows. One will have random rectangles being added, another one random texts, and the third random circles.
In addition, clicking into windows should produce lines (connecting to mouse click, or randomly), and using arrow keys should draw a red line in the window with circles.
The circles and text seem to show up regularly as expected. All three windows should have white background, but two of them are black. And the worst, the window with rectangles does not get updated much (and it does not matter if it is the first window created or not, it is always the rectangles that do not show up properly).
They are only shown when the focus changes to or from that window - then the remaining rectangles that should have been drawn meanwhile suddenly appear.
I am calling cairo_surface_flush() on the surface of each window after adding any content, but that does not help. I also tried posting XEvents to that window of various kind (such as focus), they arrive, but rectangles do not show up.
Furthermore, even though drawing lines with mouse works fine, drawing line with key arrows suffers from the same problem - it is drawn, but not shown properly.
I am obviously wrong in some of my assumptions about what this library can do, but I am not sure where.
It seems that there are some two competing versions of drawing being shown, since it happens sometimes that one or two rectangles, or pieces of the red line are flashing. Some kind of strange buffering, caching?
It may just be some bug in my program, I do not know.
Another observation - the black background is because drawing white background happens before the window is shown, and thus those cairo_paint calls are somehow discarded. I do not know how to make the window appear earlier, it seems it appears only after some later changes on the screen.
I am stuck on this after a couple of desperate days, could you help me out at least in part, please?
The program is here: test_cairo.c
An example screenshot (with a broken red line drawn by keys, and rectangles not showing up properly): test_cairo.png
To compile (on Ubuntu 16.04 or similar system):
gcc -o test_cairo test_cairo.c -I/usr/include/cairo -lX11 -lcairo
X11 does not retain window content for you. When you get an Expose event, you have to repaint the area described by that event completely.
All three windows should have white background, but two of them are black.
You create your window with XCreateSimpleWindow, so their background attribute is set to black. The X11 server will fill exposed areas with black for you before sending an expose event. Since you do not tell cairo to draw a white background, the black stays.
Try this:
--- test_cairo.c.orig 2018-07-28 09:53:10.000000000 +0200
+++ test_cairo.c 2018-07-29 10:52:43.268867754 +0200
## -63,6 +63,7 ## static gui_mouse_callback mouse_callback
static cairo_t *windows[MAX_GUI_WINDOWS_COUNT];
static cairo_surface_t *surfaces[MAX_GUI_WINDOWS_COUNT];
+static cairo_surface_t *real_surfaces[MAX_GUI_WINDOWS_COUNT];
static Window x11windows[MAX_GUI_WINDOWS_COUNT];
static char *window_names[MAX_GUI_WINDOWS_COUNT];
## -79,7 +80,12 ## long long usec()
void repaint_window(int window_handle)
{
draw_callbacks[window_handle](windows[window_handle]);
- cairo_surface_flush(surfaces[window_handle]);
+
+ cairo_t *cr = cairo_create(real_surfaces[window_handle]);
+ cairo_set_source_surface(cr, surfaces[window_handle], 0, 0);
+ cairo_paint(cr);
+ cairo_destroy(cr);
+ cairo_surface_flush(real_surfaces[window_handle]);
}
int gui_cairo_check_event(int *xclick, int *yclick, int *win)
## -149,7 +155,6 ## void draw_windows_title(int window_handl
sprintf(fullname, "Mikes - %d - [%s]", window_handle, context_names[current_context]);
else
sprintf(fullname, "Mikes - %s - [%s]", window_names[window_handle], context_names[current_context]);
- cairo_surface_flush(surfaces[window_handle]);
XStoreName(dsp, x11windows[window_handle], fullname);
}
## -179,20 +184,17 ## int gui_open_window(gui_draw_callback pa
}
if (window_handle < 0) return -1;
- surfaces[window_handle] = gui_cairo_create_x11_surface(&width, &height, window_handle);
+ real_surfaces[window_handle] = gui_cairo_create_x11_surface(&width, &height, window_handle);
+ surfaces[window_handle] = cairo_surface_create_similar(real_surfaces[window_handle], CAIRO_CONTENT_COLOR, width, height);
windows[window_handle] = cairo_create(surfaces[window_handle]);
mouse_callbacks[window_handle] = 0;
draw_callbacks[window_handle] = paint;
window_update_periods[window_handle] = update_period_in_ms;
window_names[window_handle] = 0;
-
- cairo_surface_flush(surfaces[window_handle]);
cairo_set_source_rgb(windows[window_handle], 1, 1, 1);
cairo_paint(windows[window_handle]);
-
- cairo_surface_flush(surfaces[window_handle]);
draw_callbacks[window_handle](windows[window_handle]);
## -201,7 +203,6 ## int gui_open_window(gui_draw_callback pa
else next_window_update[window_handle] = 0;
draw_windows_title(window_handle);
- cairo_surface_flush(surfaces[window_handle]);
window_in_use[window_handle] = 1;
return window_handle;
## -213,6 +214,7 ## void gui_close_window(int window_handle)
cairo_destroy(windows[window_handle]);
cairo_surface_destroy(surfaces[window_handle]);
+ cairo_surface_destroy(real_surfaces[window_handle]);
window_in_use[window_handle] = 0;
int no_more_windows = 1;
for (int i = 0; i < MAX_GUI_WINDOWS_COUNT; i++)

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 can I copy a dialogs position coordinates into another dialogs?

I have a few unique push buttons and I only want to show one of them at a time. I want them to be centered, so I have the first push button centered on the dialog. If I want to show the 3rd push button, I want to give it the first buttons coordinates and hide the 1st button.
How can I copy a buttons coordinates and set another buttons coordinates to the copied values?
Ex. Lets say I have...
PB_ONE
PB_TWO
How can I grab PB_ONE's coordinates and set PB_TWO's coordinates to PB_ONE?
RECT rcButton;
GetWindowRect(GetDlgItem(hDlg, PB_ONE), &rcButton);
The above code grabs the dialog item I want to copy the coordinates from. Is there a simple command that sets another dialog button to this dialogs coordinates?
something like SetDlgItem()?
UPDATED WITH THE NEW CODE I TRIED BASED OFF THE ANSWER
GetWindowRect(GetDlgItem(hDlg, PB_ONE), &rcButton);
ClientToScreen(hDlg, &p);
OffsetRect(&rcButton, -p.x, -p.y);
SetWindowPos(GetDlgItem(hDlg, PB_TWO), 0, rcButton.left, rcButton.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
ShowWindow(GetDlgItem(hDlg, PB_TWO), SW_SHOW);
have to current replace rcButton.left and rcButton.top with p.x and a hard value for rcButton.top to get the button to position on the dialog screen.
This returns an error in SetWindowPos where parameter 3 cannot convert a LONG * into an INT.
GetWindowRect gives the rectangle in screen coordinates. You can convert this to client coordinates using ScreenToClient(HWND hWnd, LPPOINT lpPoint).
Edit:
RECT rcButton;
HWND hbutton1 = GetDlgItem(hDlg, PB_ONE);
HWND hbutton2 = GetDlgItem(hDlg, PB_TWO);
//if(!hbutton1 || !hbutton2) {error...}
GetWindowRect(hbutton1, &rcButton);
//Test
char buf[50];
sprintf(buf, "%d %d", rcButton.left, rcButton.top);
MessageBoxA(0, buf, "screen coord", 0);
//Note, this will only convert the top-left corner, not right-bottom corner
//but that's okay because we only want top-left corner in this case
ScreenToClient(hDlg, (POINT*)&rcButton);
//Test
sprintf(buf, "%d %d", rcButton.left, rcButton.top);
MessageBoxA(0, buf, "client coord", 0);
ShowWindow(hbutton1, SW_HIDE);
SetWindowPos(hbutton2, 0, rcButton.left, rcButton.top, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW);
A slightly simpler way is to use ClientToScreen(HWND hWnd, LPPOINT lpPoint) as follows:
RECT rcButton;
GetWindowRect(GetDlgItem(hDlg, PB_ONE), &rcButton);
POINT p{ 0 };
ClientToScreen(hDlg, &p);
//p is now (0,0) of parent window in screen coordinates
OffsetRect(&rcButton, -p.x, -p.y);
rcButton is now the coordinates relative to top-left of parent window. You can use that in SetWindowPos.

Why doesn't this code draw a triangle?

I'm very new to OpenGL and I just wrote up a section of code using SDL 2 that to my knowledge should have drawn a triangle, but this code doesn't seem to work and so I am not done learning. I've got all the initialization code SDL 2 documentation says I need already written in, and the functions returned by dynamic loading ARE callable. When I execute this code instead of a triangle I get a black (but cleared) window. Why does this code not draw the triangle I want, and why is the window cleared to black by this code? I want to know the technical details behind mainly the first question so I can depend on it later.
(*main_context.glViewport)(0, 0, 100, 100);
(*main_context.glBegin)(GL_TRIANGLES);
(*main_context.glColor4d)(255, 255, 255, 255);
(*main_context.glVertex3d)(1, 1, -50);
(*main_context.glVertex3d)(1, 30, 1);
(*main_context.glVertex3d)(30, 1, 1);
(*main_context.glEnd)();
(*main_context.glFinish)();
(*main_context.glFlush)();
SDL_GL_SwapWindow(window);
Update:
I've revised my code to include different coordinates and I got the triangle to draw, but I cannot get it to draw when farther away. Why is that?
(*main_context.glVertex3d)(2, -1, 1); /* Works. */
(*main_context.glVertex3d)(2, -1, 3); /* Doesn't work. */
Unless you are setting up a projection and/or modelview matrix elsewhere in your code, it's using the default (identity matrix) transform, which is an orthographic projection with (-1, -1) at the bottom left and (1, 1) at the top right. glViewport only changes the portion of the default framebuffer being rendered to, it has no bearing on the projection whatsoever.
With an orthographic projection, the Z coordinate does not affect the screen-space position of a point, except that points outside the Z clipping planes will not be rendered. In this case, that's everything outside of -1 <= z <= 1. Given that one of your points is (1, 1, -50), this seems to be your problem.

WinAPI get mouse cursor icon

I want to get the cursor icon in Windows.
I think language I use isn't very important here, so I will just write pseudo code with WinAPI functions I'm trying to use:
c = CURSORINFO.new(20, 1, 1, POINT.new(1,1));
GetCursorInfo(c); #provides correctly filled structure with hCursor
DrawIcon(GetWindowDC(GetForegroundWindow()), 1, 1, c.hCursor);
So this part works fine, it draws current cursor on active window.
But that's not what I want. I want to get an array of pixels, so I should draw it in memory.
I'm trying to do it like this:
hdc = CreateCompatibleDC(GetDC(0)); #returns non-zero int
canvas = CreateCompatibleBitmap(hdc, 256, 256); #returns non-zero int too
c = CURSORINFO.new(20, 1, 1, POINT.new(1,1));
GetCursorInfo(c);
DrawIcon(hdc, 1, 1, c.hCursor); #returns 1
GetPixel(hdc, 1, 1); #returns -1
Why doesn't GetPixel() return COLORREF? What am I missing?
I'm not very experienced with WinAPI, so I'm probably doing some stupid mistake.
You have to select the bitmap you create into the device context. If not, the GetPixel function will return CLR_INVALID (0xFFFFFFFF):
A bitmap must be selected within the device context, otherwise, CLR_INVALID is returned on all pixels.
Also, the pseudo-code you've shown is leaking objects badly. Whenever you call GetDC, you must call ReleaseDC when you're finished using it. And whenever you create a GDI object, you must destroy it when you're finished using it.
Finally, you appear to be assuming that the coordinates for the point of origin—that is, the upper left point—are (1, 1). They are actually (0, 0).
Here's the code I would write (error checking omitted for brevity):
// Get your device contexts.
HDC hdcScreen = GetDC(NULL);
HDC hdcMem = CreateCompatibleDC(hdcScreen);
// Create the bitmap to use as a canvas.
HBITMAP hbmCanvas = CreateCompatibleBitmap(hdcScreen, 256, 256);
// Select the bitmap into the device context.
HGDIOBJ hbmOld = SelectObject(hdcMem, hbmCanvas);
// Get information about the global cursor.
CURSORINFO ci;
ci.cbSize = sizeof(ci);
GetCursorInfo(&ci);
// Draw the cursor into the canvas.
DrawIcon(hdcMem, 0, 0, ci.hCursor);
// Get the color of the pixel you're interested in.
COLORREF clr = GetPixel(hdcMem, 0, 0);
// Clean up after yourself.
SelectObject(hdcMem, hbmOld);
DeleteObject(hbmCanvas);
DeleteDC(hdcMem);
ReleaseDC(hdcScreen);
But one final caveat—the DrawIcon function will probably not work as you expect. It is limited to drawing an icon or cursor at the default size. On most systems, that will be 32x32. From the documentation:
DrawIcon draws the icon or cursor using the width and height specified by the system metric values for icons; for more information, see GetSystemMetrics.
Instead, you probably want to use the DrawIconEx function. The following code will draw the cursor at the actual size of the resource:
DrawIconEx(hdcMem, 0, 0, ci.hCursor, 0, 0, 0, NULL, DI_NORMAL);

Resources