xlib_playground

Xlib playground for experiments.
Log | Files | Refs

commit dccf869678b3b7517425a0043f0e6a599fa6e47e
parent 2d2e38d5781ca2237479a9f57979f08aa3d77be9
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Fri, 30 Dec 2022 14:48:27 +0900

copy and add linked list

Diffstat:
Aex8/Makefile | 14++++++++++++++
Aex8/main.c | 489+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aex8/main.h | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aex8/physics.c | 133+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aex8/world_map.h | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aex8/x.c | 137+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 930 insertions(+), 0 deletions(-)

diff --git a/ex8/Makefile b/ex8/Makefile @@ -0,0 +1,14 @@ +INCS=-I/usr/X11R6/include +CFLAGS=-Wall -W -Wextra -Wpointer-arith -Wbad-function-cast -std=c11 +LIBS=-L/usr/X11R6/lib -lX11 -lXext -lm +IN=*.c +OUT=main + +all: $(IN) + $(CC) $(INCS) $(CFLAGS) -o $(OUT) $(IN) $(LIBS) + +run: all + ./$(OUT) + +clean: + rm -f $(OUT) diff --git a/ex8/main.c b/ex8/main.c @@ -0,0 +1,489 @@ +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> +#include <string.h> + +#include "main.h" +#include "world_map.h" + +/* macros */ +#define FPS (60) +#define SUB_TICK (4) +#define NUM_BLOCK (200) +#define GRAVITY (1000) + +/* +#define COUNT_FPS +*/ + +enum keys { + KEY_D, + KEY_S, + KEY_A, + KEY_W, + KEY_Q, + KEY_SPACE, + NUM_KEY, //number of keys in this enum +}; +enum key_state { + KEY_UP, + KEY_DOWN, +}; +enum next_menu { + START_MENU, + GAME_PLAY, + GAME_OVER, + QUIT, +}; + +/* variables */ +struct Object block[NUM_BLOCK]; +struct Object player; +int player_is_falling; +enum next_menu next_menu = START_MENU; + + +/* function prototypes */ +/* menus */ +void start_menu(void); +void game_play(void); +void game_over(void); +/* events */ +void receive_events(enum key_state[]); +void handle_inputs(enum key_state[]); +/* sort */ +void sort_blocks(int colliding_blocks[], int distance[], int count); + +void +start_menu(void) +{ + char *menu_char_q = "press q to quit."; + char *menu_char_s = "press <space> to start."; + + x_clear_area(); + x_draw_string(0x00FFFF, + WORLD_WIDTH * BLOCK_SIZE/2 - 10 * strlen(menu_char_q)/2, + WORLD_HEIGHT * BLOCK_SIZE/2, + menu_char_q, strlen(menu_char_q)); + x_draw_string(0x00FFFF, + WORLD_WIDTH * BLOCK_SIZE/2 - 10 * strlen(menu_char_s)/2, + WORLD_HEIGHT * BLOCK_SIZE/2 + 20, + menu_char_s, strlen(menu_char_s)); + + while (next_menu == START_MENU) { + char c; + int event = x_next_event(&c); + + switch (event) { + case XEXPOSE: + x_draw_string(0x00FFFF, + WORLD_WIDTH * BLOCK_SIZE/2 - 10 * strlen(menu_char_q)/2, + WORLD_HEIGHT * BLOCK_SIZE/2, + menu_char_q, strlen(menu_char_q)); + x_draw_string(0x00FFFF, + WORLD_WIDTH * BLOCK_SIZE/2 - 10 * strlen(menu_char_s)/2, + WORLD_HEIGHT * BLOCK_SIZE/2 + 20, + menu_char_s, strlen(menu_char_s)); + + break; + case XWINDEL: + next_menu = QUIT; + break; + case XKEYPRESS: + switch (c) { + case 'q': + next_menu = QUIT; + break; + case ' ': + next_menu = GAME_PLAY; + break; + default: + break; + } + break; + default: + break; + } + } +} + +void +game_play(void) +{ + enum key_state key_state[NUM_KEY]; + long t0, t1, dt; +#ifdef COUNT_FPS + int fps_count = 0; +#endif + struct timespec ts; + + int bi = 0; + for (int i = 0; i < WORLD_WIDTH * WORLD_HEIGHT; i++) { + if (world_map[i] == 'b') { + block[bi].pp.x = block[bi].p.x = i % WORLD_WIDTH * BLOCK_SIZE; + block[bi].pp.y = block[bi].p.y = i / WORLD_WIDTH * BLOCK_SIZE; + block[bi].a.x = 0; + block[bi].a.y = 0; + block[bi].v.x = 0; + block[bi].v.y = 0; + block[bi].body.rectangle.w = BLOCK_SIZE; + block[bi].body.rectangle.h = BLOCK_SIZE; + block[bi].m = block[bi].body.rectangle.w * + block[bi].body.rectangle.h; + bi++; + } else if (world_map[i] == 'p') { + player.pp.x = player.p.x = i % WORLD_WIDTH * BLOCK_SIZE; + player.pp.y = player.p.y = i / WORLD_WIDTH * BLOCK_SIZE; + player.v.x = 0; + player.v.y = 0; + player.a.x = 0; + player.a.y = GRAVITY; + player.body.rectangle.w = player.body.rectangle.h = BLOCK_SIZE; + player.m = player.body.rectangle.w * player.body.rectangle.h; + } + } + + while (next_menu == GAME_PLAY){ + clock_gettime(CLOCK_MONOTONIC, &ts); + t0 = ts.tv_nsec; + receive_events(key_state); + handle_inputs(key_state); + + + clock_gettime(CLOCK_MONOTONIC, &ts); + t0 = ts.tv_nsec; + + for (int k = 0; k < SUB_TICK; k++) { + player_is_falling = object_is_falling(&player, block, NUM_BLOCK); + if (player_is_falling) + player.a.y = GRAVITY; + else + player.a.y = 0; + next_tick(&player, 1e9 / FPS / SUB_TICK); + + // game over when fall out of the screen + if (player.p.y > WORLD_HEIGHT * BLOCK_SIZE) { + next_menu = GAME_OVER; + break; + } + // bind within the world + if (player.p.x < 0) { + player.p.x = 0; + } + if (WORLD_WIDTH * BLOCK_SIZE < player.p.x + + player.body.rectangle.w) { + player.p.x = WORLD_WIDTH * BLOCK_SIZE - + player.body.rectangle.w; + } + + + for (int i = 0; i < NUM_BLOCK; i++) + next_tick(&block[i], 1e9 / FPS / SUB_TICK); + + int colliding_blocks[9]; + int distance[9]; + int j = 0; + for (int i = 0; i < NUM_BLOCK; i++) + if (test_collision(&player, &block[i])) { + colliding_blocks[j] = i; + distance[j] = (player.p.x - block[i].p.x) * + (player.p.x - block[i].p.x) + + (player.p.y - block[i].p.y) * + (player.p.y - block[i].p.y); + j++; + } + sort_blocks(colliding_blocks, distance, j); + for (int i = 0; i < j; i++) + handle_collision_mf(&player, &block[colliding_blocks[i]]); + } + + // fix fps + // TODO: This method create some strange stripe when + // rendered in 60fps on a 60fps monitor. + dt = 0; + while (dt < 1.0 * 1e9 / FPS){ + clock_gettime(CLOCK_MONOTONIC, &ts); + t1 = ts.tv_nsec; + dt = t1 > t0 ? t1 - t0 : t1 - t0 + 1e9; + } +#ifdef COUNT_FPS + // count fps. + fps_count++; + if (t1 < t0){ + printf("fps: %u\n", fps_count); + fps_count = 0; + } +#endif + + x_clear_area(); + for (int i = 0; i < NUM_BLOCK; i++) { + x_draw_rectangle(0x00FF00, + block[i].p.x, block[i].p.y, // position + block[i].body.rectangle.w, + block[i].body.rectangle.h); + } + x_draw_rectangle(0x009FFF, + player.p.x, player.p.y, // position + player.body.rectangle.w, player.body.rectangle.h); + char status_string[128]; + snprintf(status_string, 128, "falling: %d", player_is_falling); + x_draw_string(0x00FFFF, + 0, 20, + status_string, + strlen(status_string)); + } +} + +void +game_over(void) +{ + char *menu_char = "GAME OVER"; + + x_clear_area(); + x_draw_string(0x00FFFF, + WORLD_WIDTH * BLOCK_SIZE/2 - 10 * strlen(menu_char)/2, + WORLD_HEIGHT * BLOCK_SIZE/2, + menu_char, strlen(menu_char)); + x_flush(); + + sleep(1); + next_menu = START_MENU; +} + +void +receive_events(enum key_state key_state[]) +{ + while (x_pending() > 0) { + char c; + int event = x_next_event(&c); + + switch (event) { + case XWINDEL: + next_menu = QUIT; + break; + case XKEYPRESS: + switch (c) { + case 'q': + key_state[KEY_Q] = KEY_DOWN; + break; + case 'd': + key_state[KEY_D] = KEY_DOWN; + break; + case 'a': + key_state[KEY_A] = KEY_DOWN; + break; + case 'w': + key_state[KEY_W] = KEY_DOWN; + break; + case 's': + key_state[KEY_S] = KEY_DOWN; + break; + case ' ': + key_state[KEY_SPACE] = KEY_DOWN; + break; + default: + break; + } + break; + case XKEYRELEASE: + switch (c) { + case 'q': + key_state[KEY_Q] = KEY_UP; + break; + case 'd': + key_state[KEY_D] = KEY_UP; + break; + case 'a': + key_state[KEY_A] = KEY_UP; + break; + case 'w': + key_state[KEY_W] = KEY_UP; + break; + case 's': + key_state[KEY_S] = KEY_UP; + break; + case ' ': + key_state[KEY_SPACE] = KEY_UP; + break; + default: + break; + } + break; + } + } +} + +void +handle_inputs(enum key_state key_state[]) +{ + if (key_state[KEY_Q] == KEY_DOWN){ + next_menu = GAME_OVER; + return; + } + if (key_state[KEY_D] == KEY_DOWN) { + if (player.v.x > 0) { + player.a.x = 500; + } else { + player.a.x = 1000; + } + } else if (key_state[KEY_A] == KEY_DOWN) { + if (player.v.x > 0) { + player.a.x = -1000; + } else { + player.a.x = -500; + } + } else { + if (player_is_falling) + player.a.x = -player.v.x; + else + player.a.x = -3 * player.v.x; + } + + if (player.v.x < -200) player.v.x = -200; + if (player.v.x > 200) player.v.x = 200; + /* + if (key_state[KEY_S] == KEY_DOWN) + player.v.y += 300; + if (key_state[KEY_W] == KEY_DOWN) + player.v.y += -300; + */ + if (!player_is_falling && key_state[KEY_SPACE] == KEY_DOWN) + player.v.y = -450; +} + +void +swap(int list[], int i, int j) +{ + int tmp = list[i]; + list[i] = list[j]; + list[j] = tmp; +} + +void +sort_blocks(int colliding_blocks[], int distance[], int count) +{ + for (int i = 0; i < count - 1; i++) { + for (int j = i + 1; j < count; j++) { + if (distance[i] > distance[j]) { + swap(colliding_blocks, i, j); + swap(distance, i, j); + } + } + } +} + +void +swap_ll(struct ObjectList *oi, struct ObjectList *oj) +{ + struct Object *tmp; + tmp = oi->o; + oi->o = oj->o; + oj->o = tmp; +} + +int +object_dist(struct Object *o1, struct Object *o2) +{ + return (o1->p.x - o2->p.x) * (o1->p.x - o2->p.x) + + (o1->p.y - o2->p.y) * (o1->p.y - o2->p.y); +} + +void +sort_ll(struct ObjectList *ol, struct Object *player) +{ + struct ObjectList *oi, *oj; + for (oi = ol; oi->next != NULL; oi = oi->next) { + for (oj = oi->next; oj != NULL; oj = oj->next) { + if (object_dist(oj->o, player) < object_dist(oi->o, player)) + swap_ll(oi, oj); + } + } +} + +int +main(void) +{ + struct ObjectList *blh, *blc; + int bi = 0; + + blh = (struct ObjectList *) malloc(sizeof(struct ObjectList)); + blc = blh; + + for (int i = 0; i < WORLD_WIDTH * WORLD_HEIGHT; i++) { + if (world_map[i] == 'b') { + if (bi > 0) { + blc->next = (struct ObjectList *)malloc(sizeof(struct ObjectList)); + blc = blc->next; + } + struct Object *block; + // TODO: don't forget to free these things. + block = (struct Object *)malloc(sizeof(struct Object)); + block->pp.x = block->p.x = i % WORLD_WIDTH * BLOCK_SIZE; + block->pp.y = block->p.y = i / WORLD_WIDTH * BLOCK_SIZE; + block->a.x = 0; + block->a.y = 0; + block->v.x = 0; + block->v.y = 0; + block->body.rectangle.w = BLOCK_SIZE; + block->body.rectangle.h = BLOCK_SIZE; + block->m = block->body.rectangle.w * + block->body.rectangle.h; + blc->o = block; + bi++; + } else if (world_map[i] == 'p') { + player.pp.x = player.p.x = i % WORLD_WIDTH * BLOCK_SIZE; + player.pp.y = player.p.y = i / WORLD_WIDTH * BLOCK_SIZE; + player.v.x = 0; + player.v.y = 0; + player.a.x = 0; + player.a.y = GRAVITY; + player.body.rectangle.w = player.body.rectangle.h = BLOCK_SIZE; + player.m = player.body.rectangle.w * player.body.rectangle.h; + } + } + + + blc = blh; + while (blc != NULL) { + printf("blc->o->p: (%f, %f)\n", blc->o->p.x, blc->o->p.y); + blc = blc->next; + } + + sort_ll(blh, &player); + blc = blh; + printf("blc: %p", blc); + while (blc != NULL) { + printf("blc->o->p: (%4.0f, %4.0f) %d\n", blc->o->p.x, blc->o->p.y, + object_dist(blc->o, &player)); + blc = blc->next; + } + + return 0; +} + +int +main2(void) +{ + x_setup_window(0, 0, + WORLD_WIDTH * BLOCK_SIZE, WORLD_HEIGHT * BLOCK_SIZE, + 0x000000, "UNKO"); + while (next_menu != QUIT){ + switch (next_menu){ + case START_MENU: + start_menu(); + break; + case GAME_PLAY: + game_play(); + break; + case GAME_OVER: + game_over(); + break; + default: + break; + } + } + + x_clean_up(); + return 0; +} diff --git a/ex8/main.h b/ex8/main.h @@ -0,0 +1,92 @@ +/* + * physics.c + */ +enum object_shape { + SRECTANGLE, + STRIANGLE, + SCIRCLE, +}; + +struct Point { + float x; + float y; +}; + +struct Rectangle { // origin is top left corner + int w, h; +}; + +struct Triangle { + struct Point v2; + struct Point v3; +}; + +struct Circle { // origin is center + float r; +}; + +union Body { + struct Circle circle; + struct Triangle triangle; + struct Rectangle rectangle; +}; + +struct Object { + enum object_shape shape; + struct Point pp; + struct Point p; + struct Point v; + struct Point a; + union Body body; + int m; +}; + +struct ObjectList { + struct Object *o; + struct ObjectList *next; +}; + +struct rect { + struct Point pp; + struct Point p; + struct Point v; + struct Point a; + int w, h; + int m; +}; + +struct circle { + struct Point pp; + struct Point p; + struct Point v; + struct Point a; + int r; + int m; +}; + +int test_collision(struct Object *, struct Object *); // 1 if collide, 0 if not +void next_tick(struct Object *o, long); +void handle_collision_mf(struct Object *, struct Object *); +int object_is_falling(struct Object *o, struct Object *fb, int num_f); + +/* + * x.c + */ +enum event_type { + XKEYPRESS, + XKEYRELEASE, + XEXPOSE, + XWINDEL, + NOEVENT, +}; + +int x_setup_window(int, int, unsigned int, unsigned int, unsigned long, char *); +void x_clear_area(void); +void x_draw_string(unsigned long color, int x, int y, const char *str, int length); +void x_draw_rectangle(unsigned long color, int x, int y, + unsigned int w, unsigned int h); +void x_flush(void); +void x_clean_up(void); +int x_next_event(char *c); +int x_pending(void); +void x_get_win_wh(int *, int *); diff --git a/ex8/physics.c b/ex8/physics.c @@ -0,0 +1,133 @@ +#include <stdio.h> + +#include "main.h" + +static int test_collision_rr(struct Object *, struct Object *); +static void rect_next_tick(struct Object *, long); +static void rect_handle_collision_mf(struct Object *, struct Object *); + +/* + * 1 if collide, 0 if not + */ +int +test_collision(struct Object *o1, struct Object *o2) +{ + if (o1->shape == SRECTANGLE && o2->shape == SRECTANGLE) + return test_collision_rr(o1, o2); + else { + fprintf(stderr, "test_collision for other shapes is not implemented yet\n"); + return -1; + } +} + +static int +test_collision_rr(struct Object *o1, struct Object *o2) +{ + if (o1->shape != SRECTANGLE || o2->shape != SRECTANGLE) { + fprintf(stderr, "test_collision_rr: invalid objects\n"); + return -1; + } + return o1->p.x < o2->p.x + o2->body.rectangle.w && + o2->p.x < o1->p.x + o1->body.rectangle.w && + o2->p.y < o1->p.y + o1->body.rectangle.h && + o1->p.y < o2->p.y + o2->body.rectangle.h; +} + +void +next_tick(struct Object *o, long ndt) +{ + switch (o->shape) { + case SRECTANGLE: + rect_next_tick(o, ndt); + break; + default: + fprintf(stderr, "next_tick: not implemented for other shapes\n"); + break; + } +} + +static void +rect_next_tick(struct Object *o, long ndt) +{ + if (o->shape != SRECTANGLE) { + fprintf(stderr, "rect_next_tick: invalid object shape\n"); + return; + } + o->pp.x = o->p.x; + o->pp.y = o->p.y; + o->v.x += o->a.x * ndt / 1e9; + o->v.y += o->a.y * ndt / 1e9; + o->p.x += o->v.x * ndt / 1e9; + o->p.y += o->v.y * ndt / 1e9; +} + +void +handle_collision_mf(struct Object *om, struct Object *of) +{ + // TODO: too many testing? + if (!test_collision(om, of)) + return; + if (om->shape == SRECTANGLE && of->shape == SRECTANGLE) + rect_handle_collision_mf(om, of); + else { + fprintf(stderr, "handle_collision_mf: not implemented for other shapes\n"); + return; + } +} + +/* + * Handle collision of a moving rect against fixed rect + */ +static void +rect_handle_collision_mf(struct Object *om, struct Object *of) +{ + // TODO: too many testing? + if (!test_collision(om, of)) + return; + if (om->pp.x + om->body.rectangle.w <= of->pp.x && + of->p.x < om->p.x + om->body.rectangle.w) { + // collisioin from left to right + om->p.x = of->p.x - om->body.rectangle.w; + om->v.x = 0; + } + if (of->pp.x + of->body.rectangle.w <= om->pp.x && + om->p.x < of->p.x + of->body.rectangle.w) { + // collision from right to left + om->p.x = of->p.x + of->body.rectangle.w; + om->v.x = 0; + } + + if (om->pp.y + om->body.rectangle.h <= of->pp.y && + of->p.y < om->p.y + om->body.rectangle.h) { + // collision from up to down + om->p.y = of->p.y - om->body.rectangle.h; + om->v.y = 0; + } + if (of->pp.y + of->body.rectangle.h <= om->pp.y && + om->p.y < of->p.y + of->body.rectangle.h) { + // collision from down to up + om->p.y = of->p.y + of->body.rectangle.h; + om->v.y = 0; + } + +} + +/* + * Test if object o is not on top of one of fb (floor blocks). + * o: object to be tested, fb: floor blocks, num_f: count of fb. + */ +int +object_is_falling(struct Object *o, struct Object *fb, int num_f) +{ + struct Object p = *o; + + p.v.x = 0; p.v.y = 1; + p.a.x = 0; p.a.y = 0; + + next_tick(&p, 1e9); + + for (int i = 0; i < num_f; i++) + if (test_collision(&p, &fb[i])) + return 0; + return 1; +} diff --git a/ex8/world_map.h b/ex8/world_map.h @@ -0,0 +1,65 @@ +#define WORLD_WIDTH (80) +#define WORLD_HEIGHT (60) +#define BLOCK_SIZE (10) + +char world_map[WORLD_WIDTH * WORLD_HEIGHT + 1] = +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"................b..............................................................." +"..........................................................b..........b.........." +"................................................................................" +".......................b........................................................" +"...........................................b...................................." +"...........................................b...................................." +"................................................................................" +"..................b............................................................." +"................................................................................" +"...........................................b...................................." +"................................................................................" +"................................................................................" +"...........................b...................................................." +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"....................................bbbbbbbbbb.................................." +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"..............................................bbbbbbbbbb........................" +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"....................................bbbbbbbbbb.................................." +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"..........................bbbbbbbbbb............................................" +"................................................................................" +"................................................................................" +"................................................................................" +"................................................................................" +"................bbbbbbbbbb......................................................" +"................................................................................" +"................................................................................" +"...p............................................................................" +"bbbbbbbbbbbbbbbbbbbbbbbbb.......bbbbbbbbbbbbbbbbbbbbbbbb...bbbbbbbbbbbbbbbbbbbbb" +"........................b.......b......................b...b...................." +"........................b.......b......................b...b...................." +"........................b.......b......................b...b...................." +"........................b.......b......................b...b...................."; diff --git a/ex8/x.c b/ex8/x.c @@ -0,0 +1,137 @@ +#include <stdio.h> + +#include <X11/Xlib.h> + +#include "main.h" + +Display *display; +Atom wm_delete_window; +GC gc; +Window window; +unsigned int win_width, win_height; + +/* + * Creates a window + * If succeeded, returns 0 + * If error occured, returns -1 + */ +int +x_setup_window(int x, int y, + unsigned int w, unsigned int h, + unsigned long bc, char *win_name) +{ + if ((display = XOpenDisplay(NULL)) == NULL){ + fprintf(stderr, "ERROR: could not open display\n"); + return -1; + } + window = XCreateSimpleWindow( + display, + XDefaultRootWindow(display), + x, y, + w, h, + 0, 0, // I don't need border? + bc); + win_width = w; + win_height = h; + + XStoreName(display, window, win_name); + gc = XCreateGC(display, window, 0, NULL); + + wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False); + XSetWMProtocols(display, window, &wm_delete_window, 1); + + XSelectInput(display, window, + ExposureMask | KeyPressMask | KeyReleaseMask); + + XMapWindow(display, window); + return 0; +} + +/* + * Clears the window with the background color. + * I don't know what the return value of XClearArea means... + */ +void +x_clear_area(void) +{ + XClearArea(display, window, + 0, 0, + win_width, win_height, + False); +} + +/* + * Draws a string with specified color. + */ +void +x_draw_string(unsigned long color, int x, int y, const char *str, int length) +{ + XSetForeground(display, gc, color); + XDrawString(display, window, gc, x, y, str, length); +} + +void +x_draw_rectangle(unsigned long color, int x, int y, + unsigned int w, unsigned int h) +{ + XSetForeground(display, gc, color); + XDrawRectangle(display, window, gc, x, y, w, h); +} + +void +x_flush(void) +{ + XFlush(display); +} + +void +x_clean_up(void) +{ + XCloseDisplay(display); +} + +int +x_next_event(char *c) +{ + XEvent event; + XWindowAttributes wattr; + + XNextEvent(display, &event); + switch (event.type) { + case Expose: + XGetWindowAttributes(display, window, &wattr); + win_width = wattr.width; + win_height = wattr.height; + return XEXPOSE; + break; + case ClientMessage: + if ((Atom) event.xclient.data.l[0] == wm_delete_window) { + return XWINDEL; + } + break; + case KeyPress: + *c = XLookupKeysym(&event.xkey, 0); + return XKEYPRESS; + break; + case KeyRelease: + *c = XLookupKeysym(&event.xkey, 0); + return XKEYRELEASE; + break; + default: + break; + } + return NOEVENT; +} + +int +x_pending(void) +{ + return XPending(display); +} + +void +x_get_win_wh(int *w, int *h) +{ + *w = win_width; + *h = win_height; +}