[qwaq] Implement resizing

Terminal resize is detected and the views adjust appropriately (well,
those for which I've set grow flags: the window title bar doesn't adjust
yet).
This commit is contained in:
Bill Currie 2020-03-23 20:14:32 +09:00
parent d0c8d75e92
commit 9bc91cd7d1
17 changed files with 339 additions and 6 deletions

View file

@ -16,6 +16,7 @@ typedef enum {
typedef enum {
qe_command = 0x0200, // application level command
qe_broadcast = 0x0400,
qe_resize = 0x0800, // screen resized
} qwaq_message_event;
typedef enum {
@ -46,6 +47,11 @@ typedef struct qwaq_kevent_s {
int shift;
} qwaq_kevent_t;
typedef struct qwaq_resize_s {
int width;
int height;
} qwaq_resize_t;
typedef struct qwaq_message_s {
qwaq_command command;
} qwaq_message_t;
@ -57,6 +63,7 @@ typedef struct qwaq_event_s {
qwaq_kevent_t key;
qwaq_mevent_t mouse;
qwaq_message_t message;
qwaq_resize_t resize;
};
} qwaq_event_t;

View file

@ -4,6 +4,7 @@
#include <Object.h>
#include "event.h"
#include "qwaq-rect.h"
@class Group;
@class TextContext;
@ -16,6 +17,7 @@
Group *objects;
TextContext *screen;
Extent screenSize;
int autocount;
}
-run;

View file

@ -47,11 +47,13 @@ arp_end (void)
init_pair (4, COLOR_YELLOW, COLOR_RED);
screen = [TextContext screen];
screenSize = [screen size];
printf ("screenSize = %d x %d", screenSize.width, screenSize.height);
objects = [[Group alloc] initWithContext: screen owner: nil];
[screen bkgd: COLOR_PAIR (1)];
[screen scrollok: 1];
Rect r = { nil, [screen size] };
Rect r = {nil, screenSize};
r.offset.x = r.extent.width / 4;
r.offset.y = r.extent.height / 4;
r.extent.width /= 2;
@ -88,8 +90,23 @@ arp_end (void)
-handleEvent: (qwaq_event_t *) event
{
if (event.what == qe_resize) {
Extent delta;
delta.width = event.resize.width - screenSize.width;
delta.height = event.resize.height - screenSize.height;
resizeterm (event.resize.width, event.resize.height);
[screen resizeTo: {event.resize.width, event.resize.height}];
screenSize = [screen size];
[screen printf:"resized to %d x %d, delta: %d x %d\n", event.resize.width, event.resize.height, delta.width, delta.height];
[objects resize: delta];
[screen refresh];
event.what = qe_none;
return self;
}
[objects handleEvent: event];
if (event.what == qe_key && event.key.code == '\x18') {
if (event.what == qe_key
&& (event.key.code == '\x18' || event.key.code == '\x11')) {
event.what = qe_command;
event.message.command = qc_exit;
}

View file

@ -66,6 +66,7 @@ typedef enum qwaq_commands_e {
qwaq_cmd_bottom_panel,
qwaq_cmd_move_panel,
qwaq_cmd_panel_window,
qwaq_cmd_replace_panel,
qwaq_cmd_update_panels,
qwaq_cmd_doupdate,
qwaq_cmd_mvwaddstr,
@ -81,6 +82,8 @@ typedef enum qwaq_commands_e {
qwaq_cmd_curs_set,
qwaq_cmd_wborder,
qwaq_cmd_mvwblit_line,
qwaq_cmd_wresize,
qwaq_cmd_resizeterm,
} qwaq_commands;
static const char *qwaq_command_names[]= {
@ -95,6 +98,7 @@ static const char *qwaq_command_names[]= {
"bottom_panel",
"move_panel",
"panel_window",
"replace_panel",
"update_panels",
"doupdate",
"mvwaddstr",
@ -110,6 +114,8 @@ static const char *qwaq_command_names[]= {
"curs_set",
"wborder",
"mvwblit_line",
"wresize",
"resizeterm",
};
static window_t *
@ -398,6 +404,18 @@ cmd_panel_window (qwaq_resources_t *res)
qwaq_submit_result (res, cmd_result, CMD_SIZE (cmd_result));
}
static void
cmd_replace_panel (qwaq_resources_t *res)
{
int panel_id = RB_PEEK_DATA (res->command_queue, 2);
int window_id = RB_PEEK_DATA (res->command_queue, 3);
panel_t *panel = get_panel (res, __FUNCTION__, panel_id);
window_t *window = get_window (res, __FUNCTION__, window_id);
replace_panel (panel->panel, window->win);
}
static void
cmd_update_panels (qwaq_resources_t *res)
{
@ -561,10 +579,30 @@ cmd_mvwblit_line (qwaq_resources_t *res)
release_string (res, chs_id);
}
static void
cmd_wresize (qwaq_resources_t *res)
{
int window_id = RB_PEEK_DATA (res->command_queue, 2);
int width = RB_PEEK_DATA (res->command_queue, 3);
int height = RB_PEEK_DATA (res->command_queue, 4);
window_t *window = get_window (res, __FUNCTION__, window_id);
wresize (window->win, height, width);
}
static void
cmd_resizeterm (qwaq_resources_t *res)
{
int width = RB_PEEK_DATA (res->command_queue, 2);
int height = RB_PEEK_DATA (res->command_queue, 3);
resizeterm (height, width);
}
static void
dump_command (qwaq_resources_t *res, int len)
{
if (0) {
if (1) {
qwaq_commands cmd = RB_PEEK_DATA (res->command_queue, 0);
Sys_Printf ("%s[%d]", qwaq_command_names[cmd], len);
for (int i = 2; i < len; i++) {
@ -642,6 +680,9 @@ process_commands (qwaq_resources_t *res)
case qwaq_cmd_panel_window:
cmd_panel_window (res);
break;
case qwaq_cmd_replace_panel:
cmd_replace_panel (res);
break;
case qwaq_cmd_update_panels:
cmd_update_panels (res);
break;
@ -687,6 +728,12 @@ process_commands (qwaq_resources_t *res)
case qwaq_cmd_mvwblit_line:
cmd_mvwblit_line (res);
break;
case qwaq_cmd_wresize:
cmd_wresize (res);
break;
case qwaq_cmd_resizeterm:
cmd_resizeterm (res);
break;
}
pthread_mutex_lock (&res->command_cond.mut);
RB_DROP_DATA (res->command_queue, len);
@ -892,6 +939,22 @@ bi_panel_window (progs_t *pr)
}
}
static void
bi_replace_panel (progs_t *pr)
{
qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq");
int panel_id = P_INT (pr, 0);
int window_id = P_INT (pr, 1);
if (get_panel (res, __FUNCTION__, panel_id)
&& get_window (res, __FUNCTION__, window_id)) {
int command[] = { qwaq_cmd_replace_panel, 0,
panel_id, window_id};
command[1] = CMD_SIZE(command);
qwaq_submit_command (res, command);
}
}
static void
qwaq_update_panels (progs_t *pr)
{
@ -950,6 +1013,50 @@ bi_waddstr (progs_t *pr)
qwaq_waddstr (pr, window_id, str);
}
static void
qwaq_wresize (progs_t *pr, int window_id, int width, int height)
{
qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq");
if (get_window (res, __FUNCTION__, window_id)) {
int command[] = {
qwaq_cmd_wresize, 0,
window_id, width, height
};
command[1] = CMD_SIZE(command);
qwaq_submit_command (res, command);
}
}
static void
bi_wresize (progs_t *pr)
{
int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window;
int width = P_INT (pr, 1);
int height = P_INT (pr, 2);
qwaq_wresize (pr, window_id, width, height);
}
static void
qwaq_resizeterm (progs_t *pr, int width, int height)
{
qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq");
int command[] = { qwaq_cmd_resizeterm, 0, width, height };
command[1] = CMD_SIZE(command);
qwaq_submit_command (res, command);
}
static void
bi_resizeterm (progs_t *pr)
{
int width = P_INT (pr, 0);
int height = P_INT (pr, 1);
qwaq_resizeterm (pr, width, height);
}
static void
qwaq_mvwaddstr (progs_t *pr, int window_id, int x, int y, const char *str)
{
@ -1572,6 +1679,19 @@ bi_i_TextContext__mvvprintf_ (progs_t *pr)
qwaq_mvwvprintf (pr, pos->x, pos->y, window_id, fmt, args);
}
static void
bi_i_TextContext__resizeTo_ (progs_t *pr)
{
__auto_type self = &P_STRUCT (pr, qwaq_textcontext_t, 0);
int window_id = self->window;
self->size = P_PACKED (pr, Extent, 2);
qwaq_wresize (pr, window_id, self->size.width, self->size.height);
if (window_id == 1) {
qwaq_wbkgd (pr, window_id, self->background);
}
}
static void
bi_c_TextContext__refresh (progs_t *pr)
{
@ -1614,9 +1734,11 @@ bi_i_TextContext__mvaddstr_ (progs_t *pr)
static void
bi_i_TextContext__bkgd_ (progs_t *pr)
{
int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window;
__auto_type self = &P_STRUCT (pr, qwaq_textcontext_t, 0);
int window_id = self->window;
int ch = P_INT (pr, 2);
self->background = ch;
qwaq_wbkgd (pr, window_id, ch);
}
@ -1675,6 +1797,7 @@ static builtin_t builtins[] = {
{"bottom_panel", bi_bottom_panel, -1},
{"move_panel", bi_move_panel, -1},
{"panel_window", bi_panel_window, -1},
{"replace_panel", bi_replace_panel, -1},
{"update_panels", bi_update_panels, -1},
{"doupdate", bi_doupdate, -1},
{"mvwprintf", bi_mvwprintf, -1},
@ -1698,6 +1821,8 @@ static builtin_t builtins[] = {
{"curs_set", bi_curs_set, -1},
{"wborder", bi_wborder, -1},
{"mvwblit_line", bi_mvwblit_line, -1},
{"wresize", bi_wresize, -1},
{"resizeterm", bi_resizeterm, -1},
{"printf", bi_printf, -1},
@ -1715,6 +1840,7 @@ static builtin_t builtins[] = {
{"_i_TextContext__addch_", bi_i_TextContext__addch_, -1},
{"_i_TextContext__addstr_", bi_i_TextContext__addstr_, -1},
{"_i_TextContext__mvvprintf_", bi_i_TextContext__mvvprintf_, -1},
{"_i_TextContext__resizeTo_", bi_i_TextContext__resizeTo_, -1},
{"_c_TextContext__refresh", bi_c_TextContext__refresh, -1},
{"_i_TextContext__refresh", bi_i_TextContext__refresh, -1},
{"_i_TextContext__mvaddch_", bi_i_TextContext__mvaddch_, -1},

View file

@ -109,6 +109,7 @@ typedef struct panel_s *panel_t;
@extern void move_panel (panel_t panel, int x, int y);
@extern window_t panel_window (panel_t panel);
@extern void update_panels (void);
@extern void replace_panel (panel_t panel, window_t window);
@extern void doupdate (void);
@extern int get_event (qwaq_event_t *event);
@ -126,6 +127,8 @@ typedef struct panel_s *panel_t;
@extern void wborder (window_t window,
box_sides_t sides, box_corners_t corners);
@extern void mvwblit_line (window_t window, int x, int y, int *wch, int len);
@extern void wresize (window_t window, int width, int height);
@extern void resizeterm (int width, int height);
@extern Rect getwrect (struct window_s *window);

View file

@ -17,6 +17,7 @@
@protocol TextContext
- blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect;
- (Extent) size;
- (void) resizeTo: (Extent) newSize; // absolute size
- (void) bkgd: (int) ch;
- (void) clear;

View file

@ -25,6 +25,12 @@
return size;
}
- (void) resizeTo: (Extent) newSize
{
size = newSize;
buffer = obj_realloc (buffer, size.width * size.height);
}
- (int *) buffer
{
return buffer;

View file

@ -11,6 +11,7 @@
buffer = [[EditBuffer alloc] initWithFile: filename];
line_count = [buffer countLines: {0, [buffer textSize]}];
linebuffer = [DrawBuffer buffer: { xlen, 1 }];
growMode = gfGrowHi;
return self;
}
@ -28,6 +29,13 @@
return self;
}
-resize: (Extent) delta
{
[super resize: delta];
[linebuffer resizeTo: {xlen, 1}];
return self;
}
-handleEvent:(qwaq_event_t *) event
{
if (event.what & qe_mouse) {

View file

@ -25,6 +25,7 @@
-(Extent) size;
-draw;
-redraw;
-resize: (Extent) delta;
-handleEvent: (qwaq_event_t *) event;
-(void) grabMouse;
-(void) releaseMouse;

View file

@ -100,6 +100,14 @@ not_dont_draw (id aView, void *aGroup)
return self;
}
-resize: (Extent) delta
{
for (int i = [views count]; i-- > 0; ) {
[[views objectAtIndex: i] grow: delta];
}
return self;
}
static View *
find_mouse_view(Group *group, Point pos)
{

View file

@ -31,9 +31,11 @@
# include "config.h"
#endif
#include <sys/ioctl.h>
#include <ctype.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
@ -162,6 +164,16 @@ static qwaq_key_t default_keys[] = {
{ "\033[1;6D", QFK_LEFT, 5 },
};
static struct sigaction save_winch;
static sigset_t winch_mask;
static volatile sig_atomic_t winch_arrived;
static void
handle_winch (int sig)
{
winch_arrived = 1;
}
static void
add_event (qwaq_resources_t *res, qwaq_event_t *event)
{
@ -194,6 +206,20 @@ add_event (qwaq_resources_t *res, qwaq_event_t *event)
pthread_mutex_unlock (&res->event_cond.mut);
}
static void
resize_event (qwaq_resources_t *res)
{
qwaq_event_t event = {};
struct winsize size;
if (ioctl (fileno (stdout), TIOCGWINSZ, &size) != 0) {
return;
}
event.what = qe_resize;
event.resize.width = size.ws_col;
event.resize.height = size.ws_row;
add_event (res, &event);
}
static void
key_event (qwaq_resources_t *res, int key, unsigned shift)
{
@ -396,6 +422,13 @@ void qwaq_input_init (qwaq_resources_t *res)
i++) {
Hash_Add (res->key_sequences, &default_keys[i]);
}
sigemptyset (&winch_mask);
sigaddset (&winch_mask, SIGWINCH);
struct sigaction action = {};
action.sa_handler = handle_winch;
sigaction (SIGWINCH, &action, &save_winch);
// ncurses takes care of input mode for us, so need only tell xterm
// what we need
write(1, MOUSE_MOVES_ON, sizeof (MOUSE_MOVES_ON) - 1);
@ -408,13 +441,24 @@ void qwaq_input_shutdown (qwaq_resources_t *res)
// what we need
write(1, SGR_OFF, sizeof (SGR_OFF) - 1);
write(1, MOUSE_MOVES_OFF, sizeof (MOUSE_MOVES_OFF) - 1);
sigaction (SIGWINCH, &save_winch, 0);
}
void qwaq_process_input (qwaq_resources_t *res)
{
char buf[256];
int len;
sigset_t save_set;
int saw_winch;
pthread_sigmask (SIG_BLOCK, &winch_mask, &save_set);
saw_winch = winch_arrived;
winch_arrived = 0;
pthread_sigmask (SIG_SETMASK, &save_set, 0);
if (saw_winch) {
resize_event (res);
}
while (Sys_CheckInput (1, -1)) {
len = read(0, buf, sizeof (buf));
for (int i = 0; i < len; i++) {

View file

@ -1,12 +1,12 @@
#ifndef __qwaq_rect_h
#define __qwaq_rect_h
typedef struct {
typedef struct Point_s {
int x;
int y;
} Point;
typedef struct {
typedef struct Extent_s {
int width;
int height;
} Extent;

View file

@ -58,6 +58,20 @@
typedef struct qwaq_textcontext_s {
pr_id_t isa;
pointer_t window;
union {
Rect rect;
struct {
Point offset;
Extent size;
};
struct {
int xpos;
int ypos;
int xlen;
int ylen;
};
};
int background;
} qwaq_textcontext_t;
#endif

View file

@ -111,6 +111,7 @@ static TextContext *screen;
- (void) mvaddch: (Point) pos, int ch = #0;
- (void) mvaddstr: (Point) pos, string str = #0;
- (void) resizeTo: (Extent) newSize = #0; // absolute size
- (void) refresh = #0;
+ (void) refresh = #0;
@ -152,6 +153,7 @@ void top_panel (panel_t panel) = #0;
void bottom_panel (panel_t panel) = #0;
void move_panel (panel_t panel, int x, int y) = #0;
window_t panel_window (panel_t panel) = #0;
void replace_panel (panel_t panel, window_t window) = #0;
void update_panels (void) = #0;
void doupdate (void) = #0;
@ -159,6 +161,8 @@ int curs_set (int visibility) = #0;
int move (int x, int y) = #0;
void wborder (window_t window, box_sides_t sides, box_corners_t corners) = #0;
void mvwblit_line (window_t window, int x, int y, int *wch, int len) = #0;
void wresize (window_t window, int width, int height) = #0;
void resizeterm (int width, int height) = #0;
Rect getwrect (window_t window) = #0;
void printf(string fmt, ...) = #0;

View file

@ -31,6 +31,18 @@ enum {
sfLocked =0x0010,
};
enum {
gfGrowLoX = 0x0001,
gfGrowLoY = 0x0002,
gfGrowHiX = 0x0004,
gfGrowHiY = 0x0008,
gfGrowRel = 0x0010,
gfGrowLo = gfGrowLoX | gfGrowLoY,
gfGrowHi = gfGrowHiX | gfGrowHiY,
gfGrowX = gfGrowLoX | gfGrowHiX,
gfGrowY = gfGrowLoY | gfGrowHiY,
gfGrowAll = gfGrowX | gfGrowY,
};
@interface View: Object
{
union {
@ -52,6 +64,7 @@ enum {
id<TextContext> textContext;
int state;
int options;
int growMode;
int cursorState;
Point cursor;
}
@ -73,6 +86,9 @@ enum {
-setContext: (id<TextContext>) context;
-draw;
-redraw;
-move: (Point) delta;
-resize: (Extent) delta;
-grow: (Extent) delta;
-handleEvent: (qwaq_event_t *) event;
- (void) onMouseEnter: (Point) pos;

View file

@ -165,6 +165,69 @@ updateScreenCursor (View *view)
[textContext mvaddch: pos, ch];
}
-move: (Point) delta
{
xpos += delta.x;
ypos += delta.y;
if (xpos + xlen < 1) {
xpos = 1 - xlen;
}
if (ypos < 0) {
ypos = 0;
}
if (owner) {
Extent s = [owner size];
if (xpos > s.width - 1) {
xpos = s.width - 1;
}
if (ypos > s.height - 1) {
ypos = s.height - 1;
}
}
return self;
}
-resize: (Extent) delta
{
xlen += delta.width;
ylen += delta.height;
if (xlen < 1) {
xlen = 1;
}
if (ylen < 1) {
ylen = 1;
}
return self;
}
-grow: (Extent) delta
{
Point dpos = {};
Extent dsize = {};
if (growMode & gfGrowLoX) {
dpos.x += delta.width;
dsize.width -= delta.width;
}
if (growMode & gfGrowHiX) {
dsize.width += delta.width;
}
if (growMode & gfGrowLoY) {
dpos.y += delta.height;
dsize.height -= delta.height;
}
if (growMode & gfGrowHiY) {
dsize.height += delta.height;
}
int save_state = state;
state &= ~sfDrawn;
[self move: dpos];
[self resize: dsize];
state = save_state;
[self redraw];
return self;
}
-handleEvent: (qwaq_event_t *) event
{
return self;

View file

@ -40,6 +40,8 @@
[buf mvaddstr: {0, 0}, "XOX"];
[buf mvaddstr: {0, 1}, "OXO"];
[buf mvaddstr: {0, 2}, "XOX"];
growMode = gfGrowHi;
return self;
}
@ -71,6 +73,17 @@
return self;
}
-resize: (Extent) delta
{
Extent size = self.size;
[super resize:delta];
delta = {self.size.width - size.width, self.size.height - size.height};
[(id)textContext resizeTo: self.size];
replace_panel (panel, [(id)textContext window]);
[objects resize:delta];
return self;
}
-handleEvent: (qwaq_event_t *) event
{
[objects handleEvent: event];