home · contact · privacy
Handle SIGWINCH signals via reset_windows().
authorChristian Heller <c.heller@plomlompom.de>
Wed, 22 Jan 2014 22:00:19 +0000 (23:00 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Wed, 22 Jan 2014 22:00:19 +0000 (23:00 +0100)
src/client/io.c
src/client/io.h
src/client/main.c
src/client/misc.c
src/client/misc.h
src/client/windows.c
src/client/windows.h
src/client/world.h

index 2f7d18ad25f5c6c6fc43db5657700b750cd0b23e..998691cc9637e1b4be8236b79b1fe57d096d4339 100644 (file)
@@ -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();
index 10851d388a247b8cda7a23144b488c369ab16c01..784c681e359ad27687db2bb3cf69e37b2b9cb79f 100644 (file)
@@ -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();
 
index 4fb6b3bce7b282e9ba36040b19fa377946b3abd4..51d5606c8ae9316095f9ee6808cbe0188d1f6d8a 100644 (file)
@@ -1,11 +1,13 @@
 /* main.c */
 
+#include <signal.h> /* struct sigaction, sigaction() */
 #include <stdlib.h> /* exit() */
-#include "../common/rexit.h" /* set_cleanup_func() */
+#include <string.h> /* 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();
 
index be6faeb9c7a0e5e5ddf2a4ce21e998d97bb53df9..7022c6f25c751945dc9b0ea746e16212d49c8767 100644 (file)
@@ -1,18 +1,19 @@
 /* src/client/misc.c */
 
 #include "misc.h"
-#include <ncurses.h> /* delwin(), getmaxy(), getmaxx(), newpad() */
-#include <stdint.h> /* uint8_t, uint16_t, uint32_t */
-#include "../common/rexit.h" /* exit_err() */
+#include <ncurses.h> /* delwin(), endwin(), refresh() */
+#include <stdint.h> /* uint8_t, uint16_t */
+#include <string.h> /* 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(); /* <http://invisible-island.net/ncurses/ncurses-intro.html>.   */
+    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();
index bde51e679afeea5beef4276d1c3e562f5f88ac7f..31e3ee03a3034c1bf0adcf80ad4065829e41c113 100644 (file)
@@ -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);
index b9831100e6df55fe1f19c0e806e18070f142f1e0..1459ec2303c6c3b83946dbc4f94a8bd5252c16a5 100644 (file)
@@ -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)
 {
index 46525132bd4f3611fc727738e7896462283a3473..3b3a7eeb494cae1e20c8ead735b3cdca92896df1 100644 (file)
@@ -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.
  *
index e17ab0960af7725e6d63a36509d652484654e3d9..80fae714974463649060b0672f48ddb68630303c 100644 (file)
@@ -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()*/
 };