I am experimenting with some C++ using ncurses and am having trouble showing the window borders, but am having trouble with the following programs.
#include <cstdio>
#include <cstdlib>
#include <ncurses.h>
int main(int argc, char **argv)
{
if(argc != 5)
{
printf("not enough arguments\n");
exit(1);
}
int height = atoi(argv[1]);
int width = atoi(argv[2]);
int y = atoi(argv[3]);
int x = atoi(argv[4]);
initscr();
WINDOW *win = newwin(height, width, y, x);
box(win, 0, 0);
wrefresh(win);
int py, px;
getparyx(win, py, px);
mvprintw(LINES-2, 0, "getparyx: (%d, %d)", py, px);
int by, bx;
getbegyx(win, by, bx);
mvprintw(LINES-1, 0, "getbegyx: (%d, %d)", by, bx);
getch();
delwin(win);
endwin();
}
In the program above I draw the border using box and refresh using wrefresh, but it doesn't show anything. The other stuff that I print to stdscr, however, does show.
In another program however I was able to get the border working.
#include <ncurses.h>
int main()
{
const int height = 6, width = 8;
WINDOW *win;
int starty, startx;
int ch;
initscr();
cbreak();
noecho();
keypad(stdscr, TRUE);
starty = (LINES - height) / 2;
startx = (COLS - width) / 2;
win = newwin(height, width, starty, startx);
box(win, 0, 0);
wrefresh(win);
while((ch = getch()) != KEY_F(1))
{
wborder(win, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
wrefresh(win);
delwin(win);
switch(ch)
{
case KEY_UP:
win = newwin(height, width, --starty, startx);
break;
case KEY_DOWN:
win = newwin(height, width, ++starty, startx);
break;
case KEY_LEFT:
win = newwin(height, width, starty, --startx);
break;
case KEY_RIGHT:
win = newwin(height, width, starty, ++startx);
break;
}
move(starty + (height / 2) - 1, startx + (width / 2) - 1);
box(win, 0, 0);
wrefresh(win);
}
delwin(win);
endwin();
}
The thing is that the border only appears in the loop. In other words the border does not start to show until I press buttons, meaning the initial wrefresh did not work.
After doing some research I this thread which suggested to call refresh after initscr (or at least before wrefresh()) but that did not work. So what am I missing that the border does not show in the first program?
For my tests, that initial refresh() is certainly what is missing. I checked some old code I wrote, and it indeed calls refresh() as part of the ncurses initialisation. Adding this to your code made it work for me. A lot of the curses documentation is still constrained to books, it never really made it onto the web.
initscr();
refresh(); // <-- HERE
WINDOW *win = newwin( height, width, y, x );
box( win, 0, 0 );
wrefresh(win);
I don't think the windowing model is fully initialised until after that first refresh() is called. But I could not find any documentation on exactly why that would be the case.
So not much detail in this answer, sorry... but I hope it helps.
The manual pages answer the question:
initscr
initscr also causes the first call to refresh(3x)
to clear the screen.
getch
If the window is not a pad, and it has been moved or modified since the
last call to wrefresh, wrefresh will be called before another character
is read.
The initscr (clear) and the mvprintw calls update stdscr, which is finally refreshed when you call getch. stdscr is a window, and as noted in the discussion of wrefresh, the physical screen is updated in the order that refreshes are applied (that is, it overlaps with the other window, and if you want the other window to appear, you should refresh stdscr first, to handle the clearing operation).
Related
I am trying to change a mouse cursor for the entire system (for each window on a display) with the help of XCursor and XInput2.
In the code below, the cursor changes. However, only for browser window =>
When I focus on other windows, the cursor is still default.
As I understand, XTranslateCoordinates() function has to return the window which is under the cursor and then I just DefineCursor for this window. It also does not work if I replace XTranslateCoordinates by XGetInputFocus(d, &w, &revert_to).
Probably I do not understand the way cursors are going to be changed on windows. Would be extremely glad for helping!
int main(int argc, char **argv)
{
Display *display;
Window root_window;
display = XOpenDisplay(0);
root_window = XRootWindow(display, 0);
Cursor cursorDefault;
Cursor CursorClickR;
Cursor CursorClickL;
CreateCursor("1.png", cursorDefault, display);
unsigned char mask_bytes[(XI_LASTEVENT + 7) / 8] = {0}; /* must be zeroed! */
XISetMask(mask_bytes, XI_RawMotion);
XIEventMask evmasks[1];
evmasks[0].deviceid = XIAllMasterDevices;
evmasks[0].mask_len = sizeof(mask_bytes);
evmasks[0].mask = mask_bytes;
XISelectEvents(display, root_window, evmasks, 1);
XEvent xevent;
while (1)
{
XNextEvent(display, &xevent);
XGetEventData(display, &xevent.xcookie);
Window root_return, child_return;
int root_x_return, root_y_return;
int win_x_return, win_y_return;
unsigned int mask_return;
XQueryPointer(display, root_window, &root_return, &child_return,
&root_x_return, &root_y_return,
&win_x_return, &win_y_return,
&mask_return);
int local_x, local_y;
XTranslateCoordinates(display, root_window, child_return,
root_x_return, root_y_return,
&local_x, &local_y, &child_return);
if (child_return)
XDefineCursor(display, child_return, cursorDefault);
}
XCloseDisplay(display);
return 0;
}
I'm trying to make smooth animations in the console window in c++. I'm using windows.h for functions like Ellipse, and LineTo. The issue is that the frames are very slow and blink a lot. Sometimes the frames get progressively slower and slower as the program moves along. I tried animating a circle that moves down to the right, and a line that goes from the upper left corner to wherever the circle is. When I used the LineTo function, the line was black. I don't know how to color it. Any help would be appreciated, I just want to be able to draw and animate in the console.
#include <windows.h>
void drawSprt(int x, int y) {
HWND handle = GetConsoleWindow();
HDC dc = GetDC(handle);
int r = 10;
int a;
COLORREF color = 0x00FFFFFF;
Ellipse( dc, x-r,y-r,x+r,y+r);
MoveToEx( dc, 0, 0, NULL);
LineTo( dc, x+r, y+r);
ReleaseDC(handle, dc);
}
int main() {
int x = 100;
int y = 100;
start:
drawSprt(x,y);
Sleep(500);
x+=5;
y+=5;
system("cls");
goto start;
}
I have a simple program that has a main window and a small window on the bottom like (without the lines, thats just so you can see the two windows:
+------------------+
| |
| |
| |
+------------------+
| |
+------------------+
I want the bottom area to be a place where you can type in, and here is my source code:
#include <termios.h>
#include <bits/stdc++.h>
#include <ncurses.h>
int main()
{
int scrx;
int scry;
initscr();
cbreak();
noecho();
clear();
raw();
getmaxyx(stdscr, scrx, scry);
WINDOW* input = newwin(1, scrx, scry, 0);
std::string cmdbuf;
while(true)
{
int newx;
int newy;
getmaxyx(stdscr, newx, newy);
if(newx != scrx || newy != scry)
{
// do stuff;
}
char c = wgetch(input);
cmdbuf.push_back(c);
werase(input);
mvwprintw(input, 0, 0, cmdbuf.c_str());
refresh();
wrefresh(input);
}
}
However, it doesn't seem to print anything, just move my cursor (which gets suck halfway across the screen). How can I make it so that text actually gets printed and that my cursor actually moves across the full screen?
Tidied it up for you a bit. Press 'q' to quit. You get the idea.
#include <termios.h>
#include <bits/stdc++.h>
#include <ncurses.h>
int main()
{
int scrx, scry;
initscr();
getmaxyx(stdscr, scry, scrx);
WINDOW *w = newwin(1, scrx, scry - 1, 0);
std::string cmdbuf {};
char c = '\0';
while (c != 'q')
{
int newx, newy;
getmaxyx(stdscr, newx, newy);
if(newx != scrx || newy != scry)
{
// do stuff;
}
c = wgetch(w);
cmdbuf += c;
mvwprintw(w, 0, 0, "%s", cmdbuf.c_str());
wrefresh(w);
}
delwin(w);
endwin();
}
The refresh is overwriting the mvwprintw because they're different windows. For the given example, there's no reason to refresh stdscr because nothing (except for the initscr call) has updated that window. Moving refresh out of the loop would help (but the "do stuff" can obviously interfere with that).
The newx/newy logic is too fragmentary to comment on (I'd use getbegyx ...).
The declaration of newwin is:
WINDOW *newwin(
int nlines, int ncols,
int begin_y, int begin_x);
You are calling:
newwin(1,scry,scrx,0)
Which sets the size of you window to 1 tall and scry wide, and puts it at coordinates (0,srcx). What you want is:
newwin(1,scry,scrx-1,0)
Where 1 is the height of the window.
Also, cbreak overrides raw, so there is no point to calling both.
I am trying to create a SDL window which keeps its aspect ratio when resize event happens. If user widens the window, the height is increased and vice versa. I catch the SDL_WINDOWEVENT_RESIZED event, calculate new width or height which maintains the aspect ratio and then call SDL_SetWindowSize() with calculated values.
The problem is that calling the SDL_SetWindowSize() function inside the event polling loop does nothing on the screen. SDL does update the window size variables (calling SDL_GetWindowSize() in my main loop returns the updated window dimensions). However, the actual window is not updated.
The only way I can get this to work is to call constantly SDL_SetWindowSize() in the main loop, but I think that is the wrong way of doing things. The code below illustrates my problem. Is there a better and cleaner way to get this to work?
I am using SDL 2.0.3 and 64-bit Ubuntu Linux with GNOME desktop.
#include <SDL2/SDL.h>
static const float ASPECT_RATIO = 16.f/9.f;
SDL_Window* window;
SDL_Renderer* renderer;
uint32_t windowID;
SDL_Rect screen;
bool done = false;
bool resizeDone = false;
void handle_events()
{
SDL_Event e;
while (SDL_PollEvent(&e)) {
switch (e.type) {
case SDL_WINDOWEVENT:
if(e.window.windowID == windowID) {
switch(e.window.event) {
case SDL_WINDOWEVENT_RESIZED: {
int width = e.window.data1;
int height = e.window.data2;
float aspectRatio = (float)width/(float)height;
if(aspectRatio != ASPECT_RATIO) {
if(aspectRatio > ASPECT_RATIO) {
height = (1.f / ASPECT_RATIO) * width;
}
else {
width = ASPECT_RATIO * height;
}
printf("Setting window size to %d, %d, aspect ratio: %f\n",
width, height, (float)width/(float)height);
}
screen.w = width;
screen.h = height;
SDL_SetWindowSize(window, width, height); // <-- does not work
resizeDone = true;
break;
}
}
}
break;
case SDL_QUIT:
done = true;
break;
default:
break;
}
}
}
void run() {
while(!done) {
//SDL_SetWindowSize(window, screen.w, screen.h); // <-- works
handle_events();
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
if(resizeDone) {
int w, h;
SDL_GetWindowSize(window, &w, &h);
printf("SDL_GetWindowSize: %d, %d\n", w, h);
resizeDone = false;
}
}
}
int main(int, char**) {
SDL_Init(SDL_INIT_VIDEO);
uint32_t window_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE;
window = SDL_CreateWindow("Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags);
windowID = SDL_GetWindowID(window);
renderer = SDL_CreateRenderer(window, -1, 0);
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
run();
SDL_Quit();
return 0;
}
Some window managers seems to ignore resize requests made while WM itself resizes window (e.g. while mouse button held). On contrary, SDL_GetWindowSize returns cached values, which in that specific case sometimes happens to be wrong.
I see no platform-independent way to achieve that, other than constantly calling SDL_SetWindowSize on each frame, just in case. It could be achieved using platform-specific APIs, though (like SDL_GetWindowSysWMInfo and then using Xlib).
On macOS, I have solved it like this:
cocoa.m:
#import <Cocoa/Cocoa.h>
void SetWindowRatio(void *window) {
NSWindow *win = (__bridge NSWindow*) window;
win.aspectRatio = NSMakeSize( 1280, 720 );
}
main.cpp:
#include <SDL.h>
#include <SDL_syswm.h>
extern "C" void SetWindowRatio(void *window);
// and later..
SDL_SysWMinfo wmInfo;
SDL_VERSION(&wmInfo.version);
SDL_GetWindowWMInfo(sdl.window, &wmInfo);
SetWindowRatio(wmInfo.info.cocoa.window);
Perhaps something similar could be done on Linux, only access different part of wmInfo.info. and call the native function?
I'm having an issue with a program I'm working on. Occasionally, it will just freeze. No errors or anything.
The game is a multiplayer game where you fly a ship around. Pictures of other players and powerups move in and out of view depending on your location. For the most part, it works great, but under certain circumstances, it locks up.
I've tracked it down to when it BLITs one surface onto another. (SDL_BlitSurface).
If I comment out the single line of code where it blits (SDL_BlitSurface), and replace the graphic with a simple circle, it'll never freeze under any circumstances. But, comment out the circle and replace it with blitting the graphic again, and it'll randomly freeze. The frustrating part is, sometimes it will, sometimes it won't. Sometimes the graphic will sit on screen for a few moments and then freeze, sometimes it'll freeze the moment it shows up. Sometimes, it won't freeze at all. I simply cannot track it down to anything in particular.
I have ample amount of code that checks for NULL surfaces and it doesn't seem to stop it.
I also have it set up to output information about all the graphics to a file (such as width, height, location in memory, x, y, etc) and nothing seems out of the ordinary.
My main questions are, what about surfaces can cause SDL_BlitSurface to freeze? And what other checks can I add for surfaces to make sure it doesn't try to blit bad surfaces?
The code is too long to list, but here is how it works:
class Player
{
Player();
int x;
int y;
int xvel;
int yvel;
SDL_Surface *DrawScreen;
SDL_Surface *ShipPic;
void check_player_dist();
void check_powerup_dist();
void update();
};
class PowerUp
{
int x;
int y;
int type;
SDL_Surface *Powerup_Pic;
};
Player::Player()
{
Apply_Surface(0, 0, PlayerShipPics, ShipPic);
}
Player::Update(Player p[], PowerUp pu[])
{
x += xvel;
y += yvel;
for (int i = 0; i < Num_Players; i++)
{
if (check_on_screen(p[i].x, p[i].y) == true)
{
Apply_Surface(x - p[i].x, y - p[i].y, p[i].ShipPic, DrawScreen);
}
}
for (int i = 0; i < Num_PowerUps; i++)
{
if (check_on_screen(pu[i].x, pu[i].y) == true)
{
Apply_Surface(x - pu[i].x, y - pu[i].y, pu[i].Pic, DrawScreen);
}
}
}
int main()
{
SDL_Surface *Screen;
Player players[4];
PowerUp powerups[200];
Num_Players = 4;
Num_PowerUps = 200;
while (quit == false)
{
for (int i = 0; i < Num_Players; i++)
{
players[i].update(players, powerups);
switch (i)
{
case 0: ScreenX = 0; ScreenY = 0; break;
case 1: ScreenX = ScreenWid / 2; ScreenY = 0; break;
case 2: ScreenX = 0; ScreenY = ScreenHigh / 2; break;
case 3: ScreenX = ScreenWid / 2; ScreenY = ScreenHigh / 2; break;
}
Apply_Surface (ScreenX, ScreenY, players[i].DrawScreen, Screen);
}
if (SDL_Flip(Screen) == -1)
{
return -1;
}
}
}
void Apply_Surface (int x, int y, SDL_Surface* Source, SDL_Surface* Destination, SDL_Rect* Clip)
{
SDL_Rect Offset;
Offset.x = x;
Offset.y = y;
if ((Source != NULL) && (Destination != NULL))
{
SDL_BlitSurface (Source, Clip, Destination, &Offset );
}
}
I've noticed it generally freezes when two or more players are near each other and it tries to draw the same power-up on both of their screens. But again...not always!
Well, I figured out what it was.
I was using the SDL_GFX library along with my game. Many of the images were created using rotozoomSurface(), which is a function of SDL_GFX.
Turns out there's a bug in it where, under certain circumstances that I don't know, it'll create a bad surface that will work "most" of the time, but under the right conditions, will crash. Such as, being placed at a particular x & y coordinate on the screen. (Don't know for sure). The rotated/zoomed images would work about 95% of the time, so it was very difficult to pin point what the issue was.
The work around was, when the image was created, just SDL_BlitSurface() it onto another surface under controlled conditions, such as putting it at coordinates (0, 0). Then, delete the rotated and zoomed surface, and just use the new "safe" surface.
Works great after that.
Hopefully this will help anyone who's using SDL_GFX and cannot figure out why their program is crashing.
Example:
Before:
SDL_Surface *original = SDL_CreateRGBSurface(SDL_SWSURFACE, Ship_Width, Ship_Height, Screen_BPP, 0, 0, 0, 0);
Apply_Surface(0, 0, ShipsPic, original, &bounds);
SDL_Surface *finished = rotozoomSurface(original, pic_angle, zoom, SMOOTHING_ON);
SDL_FreeSurface(original);
return finished;
After (fixed):
SDL_Surface *original = SDL_CreateRGBSurface(SDL_SWSURFACE, Ship_Width, Ship_Height, Screen_BPP, 0, 0, 0, 0);
Apply_Surface(0, 0, ShipsPic, original, &bounds);
SDL_Surface *temp = rotozoomSurface(original, pic_angle, zoom, SMOOTHING_ON);
SDL_Surface *finished = SDL_CreateRGBSurface(SDL_SWSURFACE, temp->w, temp->h, Screen_BPP, 0, 0, 0, 0);
Apply_Surface(0, 0, temp, finished);
SDL_FreeSurface(temp);
SDL_FreeSurface(original);
return finished;
And for what it's worth, the Apply_Surface() function:
void Apply_Surface (int x, int y, SDL_Surface* Source, SDL_Surface* Destination, SDL_Rect* Clip)
{
SDL_Rect Offset;
Offset.x = x;
Offset.y = y;
if ((Source != NULL) && (Destination != NULL))
{
SDL_BlitSurface (Source, Clip, Destination, &Offset );
}
}
There's not really enough information to figure out what exactly is going on. Computers don't like to do things "sometimes," they either do them or not, so it leads me to believe that maybe there's some variable that's doing something it shouldn't.
Just in case, what does your Apply_Surface() function look like? I assume that's where you're doing your actual blitting, and if that's where you're having your problems, that would be useful for those of us trying to figure out your dilemma.