xlib_playground

Xlib playground for experiments.
Log | Files | Refs

commit 6533d405743a388096f4ca2c1afbfad1a9ebdffd
parent bb2c7d6509bd44795b856e6e639c0d41f053db13
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Wed,  4 Jan 2023 10:19:43 +0900

copy ex8 to ex9

Diffstat:
Aex9/Makefile | 14++++++++++++++
Aex9/main.c | 407+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aex9/main.h | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aex9/util.c | 260+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aex9/world_map.h | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aex9/x.c | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 994 insertions(+), 0 deletions(-)

diff --git a/ex9/Makefile b/ex9/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/ex9/main.c b/ex9/main.c @@ -0,0 +1,407 @@ +#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 *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_ll(struct OL *ol, struct Object *player); + +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; + struct OH *blh[WORLD_WIDTH]; // block list header + struct OL *blc; + + for (int xi = 0; xi < WORLD_WIDTH; xi++) + blh[xi] = create_ol(); + + for (int i = 0; i < WORLD_WIDTH * WORLD_HEIGHT; i++) { + if (world_map[i] == 'b') { + int xi = i % WORLD_WIDTH; + // TODO: don't forget to free these things. + append_ol(blh[xi], create_object(i % WORLD_WIDTH * BLOCK_SIZE, + i / WORLD_WIDTH * BLOCK_SIZE, + 0, 0, 0, 0, + BLOCK_SIZE, BLOCK_SIZE, + BLOCK_SIZE * BLOCK_SIZE)); + } else if (world_map[i] == 'p') { + player = create_object(i % WORLD_WIDTH * BLOCK_SIZE, + i / WORLD_WIDTH * BLOCK_SIZE, + 0, 0, 0, GRAVITY, + BLOCK_SIZE, BLOCK_SIZE, + BLOCK_SIZE * BLOCK_SIZE); + } + } + + while (next_menu == GAME_PLAY){ + 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++) { + next_tick(player, 1e9 / FPS / SUB_TICK); + + // game over when fall out of the world + 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; + } + + struct OH *collidings; + collidings = create_ol(); + + player_is_falling = 1; + for (int xi = (int) player->p.x / BLOCK_SIZE; + xi <= (int) player->p.x / BLOCK_SIZE + 1 && xi < WORLD_WIDTH; + xi++) { + blc = blh[xi]->first; + while (blc != NULL) { + if (is_on_floor_before(player, blc->o)) { + player_is_falling = 0; + } + if (test_collision(player, blc->o)) + append_ol(collidings, blc->o); + blc = blc->next; + } + } + if (collidings->first != NULL) { + sort_ol(collidings, player); + blc = collidings->first; + while (blc != NULL) { + handle_collision_mf(player, blc->o); + blc = blc->next; + } + } + free_ol(collidings); + } + + // 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 xi = 0; xi < WORLD_WIDTH; xi++) { + blc = blh[xi]->first; + while (blc != NULL) { + x_draw_rectangle(0x00FF00, + blc->o->p.x, blc->o->p.y, // position + blc->o->body.rectangle.w, + blc->o->body.rectangle.h); + blc = blc->next; + } + } + 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)); + } + for (int xi = 0; xi < WORLD_WIDTH; xi++) + free_obj_and_ol(blh[xi]); +} + +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); + while(x_pending() > 0) { + x_next_event(NULL); + } + 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 && key_state[KEY_A] != KEY_DOWN) { + if (player->v.x > 0) { + player->a.x = 500; + } else { + player->a.x = 1000; + } + } else if (key_state[KEY_A] == KEY_DOWN && key_state[KEY_D] != 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_ll(struct OL *oi, struct OL *oj) +{ + struct Object *tmp; + tmp = oi->o; + oi->o = oj->o; + oj->o = tmp; +} + +void +sort_ll(struct OL *ol, struct Object *player) +{ + if (ol == NULL) + return; + struct OL *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) +{ + 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/ex9/main.h b/ex9/main.h @@ -0,0 +1,109 @@ +/* + * util.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 OH { + struct OL *first; +}; + +/* + * linked list which starts with OH and + * terminates with ->next == NULL + */ +struct OL { + struct Object *o; + struct OL *next; +}; +struct OH *create_ol(void); +void free_ol(struct OH *); +void free_obj_and_ol(struct OH *); +void append_ol(struct OH *, struct Object *); +void swap_ol(struct OL *, struct OL *); +void sort_ol(struct OH *, struct Object *); +int object_dist(struct Object *, struct Object *); + +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); +struct Object *create_object(float, float, float, float, float, float, + int, int, int); +int is_on_floor_before(struct Object *, struct Object *); +/* + * 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/ex9/util.c b/ex9/util.c @@ -0,0 +1,260 @@ +#include <stdio.h> +#include <stdlib.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 *); + +struct Object * +create_object(float px, float py, float vx, float vy, float ax, float ay, + int w, int h, int m) +{ + struct Object *o; + o = (struct Object *)malloc(sizeof(struct Object)); + o->pp.x = o->p.x = px; + o->pp.y = o->p.y = py; + o->v.x = vx; + o->v.y = vy; + o->a.x = ax; + o->a.y = ay; + o->shape = SRECTANGLE; + o->body.rectangle.w = w; + o->body.rectangle.h = h; + o->m = m; + return o; +} + +void +free_object(struct Object *o) +{ + free(o); +} + +/* + * 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; +} + +struct OH * +create_ol(void) +{ + struct OH *oh; + oh = (struct OH *)malloc(sizeof(struct OH)); + oh->first = NULL; + return oh; +} + +void +free_ol(struct OH *oh) +{ + if (oh == NULL) + return; + struct OL *ol0, *ol1; + ol0 = ol1 = oh->first; + while (ol1 != NULL) { + ol1 = ol0->next; + free(ol0); + ol0 = ol1; + } + free(oh); +} + +void +free_obj_and_ol(struct OH *oh) +{ + if (oh == NULL) + return; + struct OL *ol0, *ol1; + ol0 = ol1 = oh->first; + while (ol1 != NULL) { + ol1 = ol0->next; + free(ol0->o); + free(ol0); + ol0 = ol1; + } + +} + +void +append_ol(struct OH *oh, struct Object *o) +{ + struct OL *cur; + + if (oh->first == NULL) { + oh->first = (struct OL *)malloc(sizeof(struct OL)); + cur = oh->first; + } else { + cur = oh->first; + while (cur->next != NULL) + cur = cur->next; + cur->next = (struct OL *)malloc(sizeof(struct OL)); + cur = cur->next; + } + cur->o = o; + cur->next = NULL; +} + +void +swap_ol(struct OL *ol0, struct OL *ol1) +{ + struct Object *tmp; + tmp = ol0->o; + ol0->o = ol1->o; + ol1->o = tmp; +} + +void +sort_ol(struct OH *oh, struct Object *player) +{ + if (oh == NULL) + return; + struct OL *oi, *oj; + for (oi = oh->first; 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_ol(oi, oj); + } + } +} + +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); +} + +int +is_on_floor_before(struct Object *player, struct Object *floor) +{ + struct Object o = *player; + o.p.x = o.pp.x; o.p.y = o.pp.y; + o.v.x = 0; o.v.y = 5; + o.a.x = 0; o.a.y = 0; + next_tick(&o, 1e9); + int col = test_collision(&o, floor); + return col; +} diff --git a/ex9/world_map.h b/ex9/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/ex9/x.c b/ex9/x.c @@ -0,0 +1,139 @@ +#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); + if (c == NULL) + return NOEVENT; + 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; +}