When i build my program, i get this output:
https://i.stack.imgur.com/8zdq5.png][1]
here is the code for creating the window:
main.c:
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "RenderWindow.h"
int main(int argc, char *args[])
{
if(SDL_Init(SDL_INIT_VIDEO) > 0)
printf("ERROR: %s",SDL_GetError());
if(!IMG_Init(IMG_INIT_PNG))
printf("ERROR: %s",SDL_GetError());
CreateWindow("M64!", 1280, 720);
int gameRunning = 1;
SDL_Event event;
while(gameRunning == 1){
while(SDL_PollEvent(&event)){
if(event.type == SDL_QUIT)
gameRunning = 0;
}
}
cleanUp();
SDL_Quit();
return 0;
}
Here is RenderWindow.h:
#ifndef RENDERWINDOW_H
#define RENDERWINDOW_H
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
int CreateWindow(const char* title, int p_w, int p_h);
int RenderWindow();
void cleanUp();
SDL_Window* window;
SDL_Renderer* renderer;
#endif
And here is RenderWindow.c:
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <stdio.h>
#include "RenderWindow.h"
int CreateWindow(const char* title, int p_w, int p_h)
{
window = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, p_w, p_h, SDL_WINDOW_SHOWN);
if(window == NULL)
printf("ERROR: %s", SDL_GetError());
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
return 0;
}
void cleanUp()
{
SDL_DestroyWindow(window);
}
Is this a software issue, or is it a hardware one? cause my PC is pretty old.
Edit:This is solved, for anyone having the same question the answer to this is is that you have to write: SDL_RenderClear(your_renderer); and SDL_RenderPresent(your_renderer); where the first one clears the renderer, and the second one updates it
Related
I'm trying to listen to pointer motion events on an already created window (not by me), so first I got the window id using xwininfo and hardcoded it for testing, I tested it with different windows ids and for some windows it worked and for others it didn't.
alacritty window id: not working
mpv window id: working
Compile with: gcc pointermotion.c -o pointermotion -lxcb
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <xcb/xcb.h>
#include <xcb/xproto.h>
int
main(int argc, char **argv) {
xcb_connection_t *connection;
xcb_generic_event_t *ev;
xcb_motion_notify_event_t *mnev;
xcb_get_window_attributes_cookie_t cookie;
xcb_get_window_attributes_reply_t *reply;
xcb_window_t window;
connection = xcb_connect(NULL, NULL);
window = 0x3000002;
xcb_change_window_attributes(connection, window, XCB_CW_EVENT_MASK, (const uint32_t [1]) { XCB_EVENT_MASK_POINTER_MOTION });
xcb_flush(connection);
cookie = xcb_get_window_attributes_unchecked(connection, window);
reply = xcb_get_window_attributes_reply(connection, cookie, NULL);
assert(reply->your_event_mask == XCB_EVENT_MASK_POINTER_MOTION);
free(reply);
while (1) {
while ((ev = xcb_poll_for_event(connection))) {
switch (ev->response_type & ~0x80) {
case XCB_MOTION_NOTIFY:
mnev = (xcb_motion_notify_event_t *)(ev);
printf("%d, %d\n", mnev->event_x, mnev->event_y);
break;
default:
break;
}
free(ev);
}
}
return 0;
}
I'm trying to get the terminal window size, even when I resize the window, I'm using termcaps for this, the problem is when I resize the window, the values of lines and columns stays the same instead of updating, I also tried using ncurses's LINES and COLS globals, but the same thing happens.
Here is a minimal reproductible example:
#include <ncurses.h>
#include <term.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char * term_type = getenv("TERM");
int ret;
int li_cap;
int co_cap;
if (!term_type)
{
write(2, "TERM env must be set\n", 21);
return (-1);
}
if ((ret = tgetent(NULL, term_type)) == -1)
{
write(2, "Could not access to the termcap database\n", 41);
return (-1);
}
if (!ret)
{
write(2, "This terminal is not supported by termcaps\n", 43);
return (-1);
}
while (1)
{
sleep(1);
li_cap = tgetnum("li");
co_cap = tgetnum("co");
printf("%d %d\n", li_cap, co_cap);
}
return (0);
}
So when I resize the window inside the loop, the values stay the same, I want to get the lines and colums in real time, how could I do this with termcaps?
The termcap data and the environment variables COLUMNS and LINES are unreliable and aren't updated upon terminal resizing, especially during program execution. There is another solution for POSIX systems where you can:
retrieve the size of the terminal window with ioctl(0, TIOCGWINSZ, &ws)
register a signal handler to get notified of terminal size changes.
Here is a demonstration program:
#include <stdio.h>
#include <signal.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <unistd.h>
static volatile unsigned char term_size_updated;
static void term_resize() {
term_size_updated = 1;
}
static void term_get_size(int *cols, int *rows) {
struct winsize ws;
/* get screen dimensions from (pseudo) tty ioctl */
if (ioctl(0, TIOCGWINSZ, &ws) == 0) {
*cols = ws.ws_col;
*rows = ws.ws_row;
} else {
*cols = *rows = -1;
}
}
int main() {
struct sigaction sig;
int cols, rows;
/* set up terminal resize callback */
sig.sa_handler = term_resize;
sigemptyset(&sig.sa_mask);
sig.sa_flags = 0;
sigaction(SIGWINCH, &sig, NULL);
term_size_updated = 1;
for (;;) {
if (term_size_updated) {
term_size_updated = 0;
term_get_size(&cols, &rows);
fprintf(stderr, "term_resize: cols=%d, rows=%d\n", cols, rows);
}
sleep(1);
}
return 0;
}
I am trying to setup a SDL2 project on Eclipse on Mac.
I tried the following code and I have no errors reported. However, the window does not open but the icon of a "ghost" program that opens.
The "ghost" program:
#include <stdio.h>
#include <SDL2/SDL.h>
int main(int argc, char** argv)
{
if (SDL_Init(SDL_INIT_VIDEO) != 0 )
{
fprintf(stdout,"Failed to initialize the SDL (%s)\n",SDL_GetError());
return -1;
}
{
SDL_Window* pWindow = NULL;
pWindow = SDL_CreateWindow("My first SDL2 application",SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640,
480,
SDL_WINDOW_SHOWN);
if( pWindow )
{
SDL_Delay(3000);
SDL_DestroyWindow(pWindow);
}
else
{
fprintf(stderr,"Error creating the window: %s\n",SDL_GetError());
}
}
SDL_Quit();
return 0;
}
SDL overwrites the main but it expects main to be declared as
int main(int argc, char* argv[])
if you declare it as char** instead of char* argv[], the template will not be picked up.
The delay won't do very much: all you will get is a title and a frame. Change the SDL_Delay to an event handler like this
bool running = true;
while (running)
{
SDL_Event e;
while (SDL_PollEvent(&e) != 0)
{
if (e.type == SDL_QUIT)
{
running = false;
break;
}
}
}
You can then drag the window around. It will contain the the background.
I am trying to read mouse events from the /dev/input/mice file. I am able to parse the 3 byte mouse input for getting the three button states and the increments in X and Y coordinates. However, the mouse input when I scroll up is identical to that when I scroll down. How do I distinguish a scroll up event from a scroll down event? Are there any ioctls that can do any required configuration so that I get different inputs from the mouse on these two events?
The following is a simple program to see the input from a mouse when a mouse event occurs. Scroll up and scroll down events cause the same output to be printed by this program (namely, 8 0 0).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
int main(void) {
int mouse_fd = open("/dev/input/mice", O_RDONLY | O_NONBLOCK);
signed char input[4];
ssize_t rd_cnt;
if(mouse_fd < 0)
{
perror("Could not open /dev/input/mice");
exit(EXIT_FAILURE);
}
while(true)
{
errno = 0;
rd_cnt = read(mouse_fd, input, 4);
if(rd_cnt <= 0 && errno != EAGAIN)
{
perror("Mouse read error:");
exit(EXIT_FAILURE);
}
else
{
for(int i = 0; i < rd_cnt; i++)
{
printf("%d", input[i]);
if(i == rd_cnt - 1)
{
printf("\n");
}
else
{
printf("\t");
}
}
}
}
return 0;
}
An alternative would be to use SDL2.
I've managed to mash together an example of reading mouse inputs with SDL, so take what you like from it.
#include <SDL2/SDL.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
char* itoa(int i, char b[]){
char const digit[] = "0123456789";
char* p = b;
if(i<0){
*p++ = '-';
i *= -1;
}
int shifter = i;
do{ //Move to where representation ends
++p;
shifter = shifter/10;
}while(shifter);
*p = '\0';
do{ //Move back, inserting digits as u go
*--p = digit[i%10];
i = i/10;
}while(i);
return b;
}
int main()
{
//initialize the window
bool quit = false;
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindow("Mouse Events", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0);
// the event that will occur when a mouse event happens
SDL_Event event;
while(!quit)
{
while (SDL_PollEvent(&event)) //returns one is there is a pending event (if an event happens)
{
switch(event.type)
{
case SDL_QUIT: //if the window is exited
quit = true;
break;
case SDL_MOUSEBUTTONDOWN:
switch (event.button.button)
{
case SDL_BUTTON_LEFT:
SDL_ShowSimpleMessageBox(0, "Click", "Left button was pressed!", window);
break;
case SDL_BUTTON_RIGHT:
SDL_ShowSimpleMessageBox(0, "Click", "Right button was pressed!", window);
break;
}
break;
case SDL_MOUSEWHEEL:
if(event.wheel.y == -1) //negative means the scroll wheel has gone away from the user
{
SDL_ShowSimpleMessageBox(0, "Wheel Event", "You rolled away from yourself!", window);
} else if (event.wheel.y == 1) //vice-versa
{
SDL_ShowSimpleMessageBox(0, "Wheel Event", "You rolled towards yourself!", window);
}
}
}
//do some SDL cleanup
SDL_Rect dstrect = { 288, 208, 64, 64 };
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
}
}
The event.wheel type can be found here: https://wiki.libsdl.org/SDL_MouseWheelEvent
Hope this is of some use to you!
If you don't want to use SDL2, it may be worth have a look in the source of the library to see what it's doing.
I want to log my mouse click positions. I have tried this;
#include <stdio.h>
#include <stddef.h>
#include <X11/Xlib.h>
#include <assert.h>
#include <unistd.h>
#include <signal.h>
int working = 1;
void signal_callback_handler(int signum) {
working = 0;
}
int main () {
signal(SIGINT, signal_callback_handler);
signal(SIGTSTP, signal_callback_handler);
signal(SIGTERM, signal_callback_handler);
Display *d = XOpenDisplay(NULL);
assert(d);
XSelectInput(d, DefaultRootWindow(d), ButtonPressMask);
while(working) {
XEvent e;
XNextEvent(d,&e);
if (e.type == ButtonPress) {
printf("%dx%d",e.xbutton.x,e.xbutton.y);
}
}
return 0;
}
But I am seeing this error:
X Error of failed request: BadAccess (attempt to access private resource denied)
Major opcode of failed request: 2 (X_ChangeWindowAttributes)
Serial number of failed request: 7
Current serial number in output stream: 7
What is wrong with my code, and how can I fix it?
Update
I have researched this a little bit more, and got some help from the folks in #xorg-dev. It seems like it is impossible to do with regular Xlib, because only one client can register for button press on a window. In this case, my WM already registered, therefore I get bad access. It seems like this can be done using X input extensions and by listening XI_RawButtonPress Event, which I am still trying to figure out how to do. Here is what I have so far;
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/extensions/XInput2.h>
#include <signal.h>
#include <assert.h>
int working = 1;
void signal_callback_handler(int signum) {
working = 0;
}
int main() {
signal(SIGINT, signal_callback_handler);
signal(SIGTSTP, signal_callback_handler);
signal(SIGTERM, signal_callback_handler);
/* Connect to the X server */
Display *dpy = XOpenDisplay(NULL);
assert(dpy);
/* XInput Extension available? */
int opcode, event, error;
if (!XQueryExtension(dpy, "XInputExtension", &opcode, &event, &error)) {
printf("X Input extension not available.\n");
return -1;
}
/* Which version of XI2? We support 2.0 */
int major = 2, minor = 0;
if (XIQueryVersion(dpy, &major, &minor) == BadRequest) {
printf("XI2 not available. Server supports %d.%d\n", major, minor);
return -1;
}
XIEventMask eventmask;
unsigned char mask[1] = { 0 }; /* the actual mask */
eventmask.deviceid = 2;
eventmask.mask_len = sizeof(mask); /* always in bytes */
eventmask.mask = mask;
/* now set the mask */
XISetMask(mask, XI_RawButtonPress);
/* select on the window */
XISelectEvents(dpy, DefaultRootWindow(dpy), &eventmask, 1);
while(working) {
XEvent ev;
XNextEvent(dpy, &ev);
if (ev.xcookie.type == GenericEvent &&
ev.xcookie.extension == opcode &&
XGetEventData(dpy, &ev.xcookie))
{
switch(ev.xcookie.evtype)
{
case XI_RawButtonPress:
printf("RawButtonPress");
break;
}
}
XFreeEventData(dpy, &ev.xcookie);
}
}
However, I get this error;
X Error of failed request: XI_BadDevice (invalid Device parameter)
Major opcode of failed request: 131 (XInputExtension)
Minor opcode of failed request: 46 ()
Device id in failed request: 0xad
Serial number of failed request: 15
Current serial number in output stream: 15
Update 2
I have tried to do this with ButtonRelaseEvent, but I am not getting any event. XNextEvent blocks forever, no matter where I click/relase button. Here are the codes;
#include <stdio.h>
#include <stddef.h>
#include <X11/Xlib.h>
#include <assert.h>
#include <unistd.h>
#include <signal.h>
int working = 1;
void signal_callback_handler(int signum) {
working = 0;
}
int main () {
signal(SIGINT, signal_callback_handler);
signal(SIGTSTP, signal_callback_handler);
signal(SIGTERM, signal_callback_handler);
Display *d = XOpenDisplay(NULL);
assert(d);
XSelectInput(d,DefaultRootWindow(d), ButtonReleaseMask);
while(working) {
XEvent e;
XNextEvent(d, &e);
printf("Something Occured");
if (e.type == ButtonRelease) {
printf("%dx%d",e.xbutton.x,e.xbutton.y);
}
}
return 0;
}
Try XWindowEvent instead of XNextEvent.
For example to grab mouse you can do this:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
int main(){
Display* display;
int screen_num;
Screen *screen;
Window root_win;
XEvent report;
XButtonEvent *xb = (XButtonEvent *)&report;
int i;
Cursor cursor;
display = XOpenDisplay(0);
if (display == NULL){
perror("Cannot connect to X server");
exit (-1);
}
screen_num = DefaultScreen(display);
screen = XScreenOfDisplay(display, screen_num);
root_win = RootWindow(display, XScreenNumberOfScreen(screen));
cursor = XCreateFontCursor(display, XC_crosshair);
i = XGrabPointer(display, root_win, False,
ButtonReleaseMask | ButtonPressMask|Button1MotionMask, GrabModeSync,
GrabModeAsync, root_win, cursor, CurrentTime);
if(i != GrabSuccess){
perror("Can't grab the mouse");
exit(-1);
}
for(i = 0; i < 10; i++){
XAllowEvents(display, SyncPointer, CurrentTime);
XWindowEvent(display, root_win, ButtonPressMask | ButtonReleaseMask, &report);
switch(report.type){
case ButtonPress:
printf("Press # (%d, %d)\n", xb->x_root, xb->y_root);
break;
case ButtonRelease:
printf("Release # (%d, %d)\n", xb->x_root, xb->y_root);
break;
}
}
XFlush(display);
XUngrabServer(display);
XCloseDisplay( display );
return 0;
}
Yes, from x11 protocol spec:
Multiple clients can select input on the same window; their
event-masks are disjoint. When an event is generated, it will be
reported to all interested clients. However, only one client at a time
can select for SubstructureRedirect, only one client at a time can
select for ResizeRedirect, and only one client at a time can select
for ButtonPress. An attempt to violate these restrictions results in
an Access error.
However, it is allowed for multiple clients to select ButtonRelease event - I just checked with two clients and both receive events.