From: Christian Heller Date: Wed, 22 Jan 2014 22:00:19 +0000 (+0100) Subject: Handle SIGWINCH signals via reset_windows(). X-Git-Tag: tce~874 X-Git-Url: https://plomlompom.com/repos/%7B%7Bdb.prefix%7D%7D/%7B%7B%20web_path%20%7D%7D/decks/%7B%7Bprefix%7D%7D/process?a=commitdiff_plain;h=0b7798939c0193fd794985b503737e40d8602313;p=plomrogue Handle SIGWINCH signals via reset_windows(). --- diff --git a/src/client/io.c b/src/client/io.c index 2f7d18a..998691c 100644 --- a/src/client/io.c +++ b/src/client/io.c @@ -18,6 +18,7 @@ */ #include "control.h" /* try_key() */ #include "map_window.h" /* for map_center() */ +#include "misc.h" /* reset_windows() */ #include "windows.h" /* draw_all_wins() */ #include "world.h" /* world global */ @@ -257,6 +258,12 @@ extern char * io_loop() uint8_t change_in_client = 0; while (1) { + if (world.winch) + { + reset_windows(); + world.winch = 0; + change_in_client++; + } if (read_world() || change_in_client) { draw_all_wins(); diff --git a/src/client/io.h b/src/client/io.h index 10851d3..784c681 100644 --- a/src/client/io.h +++ b/src/client/io.h @@ -21,6 +21,7 @@ extern void try_send(char * msg); * library. On each change / activity, re-draw the windows with draw_all_wins(). * When the loop ends regularly (due to the user sending a quit command), return * an appropriate quit message to write to stdout when the client winds down. + * Also call reset_windows() on receiving a SIGWINCH. */ extern char * io_loop(); diff --git a/src/client/main.c b/src/client/main.c index 4fb6b3b..51d5606 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -1,11 +1,13 @@ /* main.c */ +#include /* struct sigaction, sigaction() */ #include /* exit() */ -#include "../common/rexit.h" /* set_cleanup_func() */ +#include /* memset() */ +#include "../common/rexit.h" /* set_cleanup_func(), exit_trouble() */ #include "cleanup.h" /* cleanup() */ #include "command_db.h" /* init_command_db() */ #include "io.h" /* io_loop(), try_send() */ -#include "misc.h" /* load_interface_conf() */ +#include "misc.h" /* load_interface_conf(), winch_called() */ #include "windows.h" /* init_wmeta_and_ncurses(); */ #include "world.h" /* struct World */ @@ -17,6 +19,8 @@ struct World world; int main() { + char * f_name = "main()"; + /* Declare hard-coded paths here. */ world.path_server_in = "server/in"; @@ -29,6 +33,12 @@ int main() init_command_db(); /* The command DB needs to be initialized before */ load_interface_conf(); /* the interface, whose keybindings depend on it. */ + /* Set handler for terminal window resizing. */ + struct sigaction act; + memset(&act, 0, sizeof(act)); + act.sa_handler = &winch_called; + exit_trouble(sigaction(SIGWINCH, &act, NULL), f_name, "sigaction()"); + /* This is where most everything happens. */ char * quit_msg = io_loop(); diff --git a/src/client/misc.c b/src/client/misc.c index be6faeb..7022c6f 100644 --- a/src/client/misc.c +++ b/src/client/misc.c @@ -1,18 +1,19 @@ /* src/client/misc.c */ #include "misc.h" -#include /* delwin(), getmaxy(), getmaxx(), newpad() */ -#include /* uint8_t, uint16_t, uint32_t */ -#include "../common/rexit.h" /* exit_err() */ +#include /* delwin(), endwin(), refresh() */ +#include /* uint8_t, uint16_t */ +#include /* memset(), strlen() */ #include "cleanup.h" /* for set_cleanup_flag() */ #include "keybindings.h" /* init_keybindings(), free_keybindings(), * save_keybindings() */ #include "map_window.h" /* for map_center() */ -#include "wincontrol.h" /* init_winconfs(), init_wins(), - * sorted_wintoggle_and_activate() +#include "wincontrol.h" /* struct WinConf, init_winconfs(), init_wins(), + * sorted_wintoggle_and_activate(), get_win_by_id(), + * get_winconf_by_win(), toggle_window() */ -#include "windows.h" /* suspend_win() */ +#include "windows.h" /* struct Win, make_pad(), suspend_win(), free_win() */ #include "world.h" /* global world */ @@ -33,15 +34,7 @@ extern void load_interface_conf() init_keybindings("confclient/keybindings_wingeom", &world.kb_wingeom); init_keybindings("confclient/keybindings_winkeys", &world.kb_winkeys); init_winconfs(); - char * err_s = "load_interface_conf() makes illegaly large virtual screen."; - char * err_m = "load_interface_conf(): memory alloc error via newpad()."; - uint32_t maxy_test = getmaxy(world.wmeta.screen); - uint32_t maxx_test = getmaxx(world.wmeta.screen); - exit_err(maxy_test > UINT16_MAX || maxx_test > UINT16_MAX, err_s); - world.wmeta.padsize.y = maxy_test; - world.wmeta.padsize.x = maxx_test; - world.wmeta.pad = newpad(world.wmeta.padsize.y, 1); - exit_err(NULL == world.wmeta.pad, err_m); + make_pad(); init_wins(); sorted_wintoggle_and_activate(); set_cleanup_flag(CLEANUP_INTERFACE); @@ -64,6 +57,56 @@ extern void unload_interface_conf() +extern void winch_called(int signal) +{ + world.winch = 1; +} + + + +extern void reset_windows() +{ + endwin(); /* "[S]tandard way" to recalibrate ncurses post SIGWINCH, says */ + refresh(); /* . */ + struct Win * w_p = world.wmeta.chain_start; + char win_ids[strlen(world.winconf_db.winconf_ids) + 1]; + memset(win_ids, '\0', strlen(world.winconf_db.winconf_ids) + 1); + uint8_t i = 0; + char active = '\0'; + for (; NULL != w_p; w_p = w_p->next, i++) + { + struct WinConf * wc_p = get_winconf_by_win(w_p); + win_ids[i] = wc_p->id; + if (w_p == world.wmeta.active) + { + active = wc_p->id; + } + } + while (0 != world.wmeta.active) + { + w_p = world.wmeta.active; + suspend_win(w_p); + free_win(w_p); + } + delwin(world.wmeta.pad); + make_pad(); + init_wins(); + if (strlen(win_ids) < 1) + { + return; + } + for (i = 0; i < strlen(win_ids); i++) + { + toggle_window(win_ids[i]); + if (active == win_ids[i]) + { + world.wmeta.active = get_win_by_id(win_ids[i]); + } + } +} + + + extern void reload_interface_conf() { unload_interface_conf(); diff --git a/src/client/misc.h b/src/client/misc.h index bde51e6..31e3ee0 100644 --- a/src/client/misc.h +++ b/src/client/misc.h @@ -22,6 +22,13 @@ extern void load_interface_conf(); extern void unload_interface_conf(); extern void reload_interface_conf(); +/* The SIGWINCH handler winch_called() merely sets world.winch to 1. This info + * is used by io_loop() to call reset_windows(), which adapts the currently + * loaded interface configuration to the new screen size. + */ +extern void winch_called(); +extern void reset_windows(); + /* Return offset into center map of "mapsize" on "position" in "framesize". */ extern uint16_t center_offset(uint16_t position, uint16_t mapsize, uint16_t framesize); diff --git a/src/client/windows.c b/src/client/windows.c index b983110..1459ec2 100644 --- a/src/client/windows.c +++ b/src/client/windows.c @@ -440,6 +440,21 @@ extern void init_wmeta_and_ncurses() +extern void make_pad() +{ + char * err_s = "make_pad() creates an illegaly large virtual screen."; + char * err_m = "make_pad() triggers memory allocation error via newpad()."; + uint32_t maxy_test = getmaxy(world.wmeta.screen); + uint32_t maxx_test = getmaxx(world.wmeta.screen); + exit_err(maxy_test > UINT16_MAX || maxx_test > UINT16_MAX, err_s); + world.wmeta.padsize.y = maxy_test; + world.wmeta.padsize.x = maxx_test; + world.wmeta.pad = newpad(world.wmeta.padsize.y, 1); + exit_err(NULL == world.wmeta.pad, err_m); +} + + + extern void init_win(struct Win ** wp, char * title, int16_t height, int16_t width, void * func) { diff --git a/src/client/windows.h b/src/client/windows.h index 4652513..3b3a7ee 100644 --- a/src/client/windows.h +++ b/src/client/windows.h @@ -71,6 +71,9 @@ struct WinMeta */ extern void init_wmeta_and_ncurses(); +/* Builds world.wmeta.pad from the sizes of the current terminal screen. */ +extern void make_pad(); + /* Initialize a Win child "wp" of "wmeta" to "title", "height" and "width" and * appoint "func"() as its .draw. Initialize other members to 0. * diff --git a/src/client/world.h b/src/client/world.h index e17ab09..80fae71 100644 --- a/src/client/world.h +++ b/src/client/world.h @@ -36,6 +36,7 @@ struct World uint8_t halfdelay; uint8_t player_inventory_select; uint8_t player_lifepoints; + uint8_t winch; /* if set, SIGWINCH was registered; trigger reset_windows()*/ };