Interface improvements and bump to v0.10.0

- Give window tab and statusbar a make over
- Place window tab above input field
- Reduce input field to one square in height
- Refactor window tab so that it's now a subwin of its parent ToxWindow
- Fix bug causing notification counter to sometimes increment by 2
- No longer scroll on output when output is not at bottom of screen
- Show a small indicator on far left of window tab when output is
  not at bottom of screen
- Reduce ncurses/UI thread sleep time by half
- Handle nanosleep errors better
This commit is contained in:
jfreegman 2020-11-29 23:26:51 -05:00
parent 61740bda85
commit 1e985c1456
No known key found for this signature in database
GPG Key ID: 3627F3144076AE63
17 changed files with 519 additions and 272 deletions

View File

@ -30,7 +30,7 @@ endif
# Check if LLVM Address Sanitizer is enabled
ASAN_ENABLED := $(shell if [ -z "$(ENABLE_ASAN)" ] || [ "$(ENABLE_ASAN)" = "0" ] ; then echo disabled ; else echo enabled ; fi)
ifneq ($(ASAN_ENABLED), disabled)
CFLAGS += -fsanitize=address -fno-omit-frame-pointer -mllvm -asan-use-private-alias=1 -Wno-unused-command-line-argument
CFLAGS += -fsanitize=address -fno-omit-frame-pointer
endif
# Check on wich system we are running

View File

@ -5,7 +5,7 @@
Toxic is a [Tox](https://tox.chat)-based instant messaging and video chat client.
[![Toxic Screenshot](https://i.imgur.com/5S577z6.png "Toxic Audio Conference")](https://i.imgur.com/5S577z6.png)
[![Toxic Screenshot](https://i.imgur.com/TwYA8L0.png "Toxic Home Screen")](https://i.imgur.com/TwYA8L0.png)
## Installation
[See the install instructions](/INSTALL.md)

View File

@ -55,9 +55,9 @@ author = 'Jakob Kreuze'
# built documents.
#
# The short X.Y version.
version = '0.9.1'
version = '0.10.0'
# The full version, including alpha/beta/rc tags.
release = '0.9.1'
release = '0.10.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View File

@ -1,5 +1,5 @@
# Version
TOXIC_VERSION = 0.9.1
TOXIC_VERSION = 0.10.0
REV = $(shell git rev-list HEAD --count 2>/dev/null || echo -n "error")
ifneq (, $(findstring error, $(REV)))
VERSION = $(TOXIC_VERSION)

View File

@ -745,17 +745,17 @@ static void chat_onConferenceInvite(ToxWindow *self, Tox *m, int32_t friendnumbe
Friends.list[friendnumber].conference_invite.length = length;
Friends.list[friendnumber].conference_invite.type = type;
sound_notify(self, generic_message, NT_WNDALERT_2 | user_settings->bell_on_invite, NULL);
char name[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, name, friendnumber);
const char *description = type == TOX_CONFERENCE_TYPE_AV ? "an audio conference" : "a conference";
if (self->active_box != -1) {
box_silent_notify2(self, NT_WNDALERT_2 | NT_NOFOCUS, self->active_box, "invites you to join %s", description);
box_notify2(self, generic_message, NT_WNDALERT_2 | user_settings->bell_on_invite, self->active_box,
"invites you to join %s", description);
} else {
box_silent_notify(self, NT_WNDALERT_2 | NT_NOFOCUS, &self->active_box, name, "invites you to join %s", description);
box_notify(self, generic_message, NT_WNDALERT_2 | user_settings->bell_on_invite, &self->active_box, name,
"invites you to join %s", description);
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s has invited you to %s.", name, description);
@ -1181,7 +1181,7 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
}
wclear(ctx->linewin);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
wmove(self->window, y2, 0);
reset_buf(ctx);
}
@ -1194,7 +1194,8 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
static void chat_onDraw(ToxWindow *self, Tox *m)
{
int x2, y2;
int x2;
int y2;
getmaxyx(self->window, y2, x2);
if (y2 <= 0 || x2 <= 0) {
@ -1209,15 +1210,14 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
wclear(ctx->linewin);
curs_set(1);
if (ctx->len > 0) {
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
mvwprintw(ctx->linewin, 0, 0, "%ls", &ctx->line[ctx->start]);
}
curs_set(1);
/* Draw status bar */
StatusBar *statusbar = self->stb;
mvwhline(statusbar->topline, 1, 0, ACS_HLINE, x2);
wmove(statusbar->topline, 0, 0);
/* Draw name, status and note in statusbar */
@ -1227,38 +1227,63 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
switch (status) {
case TOX_USER_STATUS_NONE:
colour = GREEN;
colour = GREEN_BLUE;
break;
case TOX_USER_STATUS_AWAY:
colour = YELLOW;
colour = YELLOW_BLUE;
break;
case TOX_USER_STATUS_BUSY:
colour = RED;
colour = RED_BLUE;
break;
}
wattron(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wprintw(statusbar->topline, " [");
wattroff(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
wprintw(statusbar->topline, " %s", ONLINE_CHAR);
wprintw(statusbar->topline, "%s", ONLINE_CHAR);
wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
if (Friends.list[self->num].is_typing) {
wattron(statusbar->topline, COLOR_PAIR(YELLOW));
wattron(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wprintw(statusbar->topline, "] ");
wattroff(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
pthread_mutex_lock(&Winthread.lock);
const bool is_typing = Friends.list[self->num].is_typing;
pthread_mutex_unlock(&Winthread.lock);
if (is_typing) {
wattron(statusbar->topline, A_BOLD | COLOR_PAIR(YELLOW_BLUE));
} else {
wattron(statusbar->topline, COLOR_PAIR(WHITE_BLUE));
}
wattron(statusbar->topline, A_BOLD);
wprintw(statusbar->topline, " %s ", statusbar->nick);
wattroff(statusbar->topline, A_BOLD);
wprintw(statusbar->topline, "%s", statusbar->nick);
if (Friends.list[self->num].is_typing) {
wattroff(statusbar->topline, COLOR_PAIR(YELLOW));
if (is_typing) {
wattroff(statusbar->topline, A_BOLD | COLOR_PAIR(YELLOW_BLUE));
} else {
wattroff(statusbar->topline, A_BOLD | COLOR_PAIR(WHITE_BLUE));
}
} else {
wprintw(statusbar->topline, " %s", OFFLINE_CHAR);
wattron(statusbar->topline, A_BOLD);
wprintw(statusbar->topline, " %s ", statusbar->nick);
wattroff(statusbar->topline, A_BOLD);
wattron(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wprintw(statusbar->topline, " [");
wattroff(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wattron(statusbar->topline, COLOR_PAIR(WHITE_BLUE));
wprintw(statusbar->topline, "%s", OFFLINE_CHAR);
wattroff(statusbar->topline, COLOR_PAIR(WHITE_BLUE));
wattron(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wprintw(statusbar->topline, "] ");
wattroff(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wattron(statusbar->topline, COLOR_PAIR(WHITE_BLUE));
wprintw(statusbar->topline, "%s", statusbar->nick);
wattroff(statusbar->topline, COLOR_PAIR(WHITE_BLUE));
}
/* Reset statusbar->statusmsg on window resize */
@ -1287,30 +1312,51 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
}
if (statusbar->statusmsg[0]) {
wprintw(statusbar->topline, ": %s ", statusbar->statusmsg);
wattron(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wprintw(statusbar->topline, " | ");
wattroff(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wattron(statusbar->topline, COLOR_PAIR(WHITE_BLUE));
wprintw(statusbar->topline, "%s ", statusbar->statusmsg);
} else {
wattron(statusbar->topline, COLOR_PAIR(WHITE_BLUE));
}
wclrtoeol(statusbar->topline);
int s_y;
int s_x;
getyx(statusbar->topline, s_y, s_x);
mvwhline(statusbar->topline, s_y, s_x, ' ', x2 - s_x - (KEY_IDENT_DIGITS * 2) - 3);
wattroff(statusbar->topline, COLOR_PAIR(WHITE_BLUE));
wmove(statusbar->topline, 0, x2 - (KEY_IDENT_DIGITS * 2) - 3);
wattron(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wprintw(statusbar->topline, "{");
wattroff(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
size_t i;
wattron(statusbar->topline, COLOR_PAIR(WHITE_BLUE));
for (i = 0; i < KEY_IDENT_DIGITS; ++i) {
for (size_t i = 0; i < KEY_IDENT_DIGITS; ++i) {
wprintw(statusbar->topline, "%02X", Friends.list[self->num].pub_key[i] & 0xff);
}
wprintw(statusbar->topline, "}\n");
wattroff(statusbar->topline, COLOR_PAIR(WHITE_BLUE));
mvwhline(self->window, y2 - CHATBOX_HEIGHT, 0, ACS_HLINE, x2);
wattron(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wprintw(statusbar->topline, "} ");
wattroff(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
int y, x;
int y;
int x;
getyx(self->window, y, x);
UNUSED_VAR(x);
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
wmove(self->window, y + 1, new_x);
wmove(self->window, y, new_x);
draw_window_bar(self);
wnoutrefresh(self->window);
@ -1357,7 +1403,9 @@ static void chat_init_log(ToxWindow *self, Tox *m, const char *self_nick)
static void chat_onInit(ToxWindow *self, Tox *m)
{
curs_set(1);
int x2, y2;
int x2;
int y2;
getmaxyx(self->window, y2, x2);
if (y2 <= 0 || x2 <= 0) {
@ -1390,9 +1438,10 @@ static void chat_onInit(ToxWindow *self, Tox *m)
/* Init subwindows */
ChatContext *ctx = self->chatwin;
statusbar->topline = subwin(self->window, 2, x2, 0, 0);
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
statusbar->topline = subwin(self->window, TOP_BAR_HEIGHT, x2, 0, 0);
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, x2, 0, 0);
self->window_bar = subwin(self->window, WINDOW_BAR_HEIGHT, x2, y2 - (CHATBOX_HEIGHT + WINDOW_BAR_HEIGHT), 0);
ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - WINDOW_BAR_HEIGHT, 0);
ctx->hst = calloc(1, sizeof(struct history));
ctx->log = calloc(1, sizeof(struct chatlog));

View File

@ -307,9 +307,9 @@ void redraw_conference_win(ToxWindow *self)
refresh();
clear();
int x2, y2;
getmaxyx(stdscr, y2, x2);
y2 -= 2;
int x2;
int y2;
getmaxyx(self->window, y2, x2);
if (y2 <= 0 || x2 <= 0) {
return;
@ -322,20 +322,22 @@ void redraw_conference_win(ToxWindow *self)
delwin(ctx->linewin);
delwin(ctx->history);
delwin(self->window_bar);
delwin(self->window);
self->window = newwin(y2, x2, 0, 0);
ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
self->window_bar = subwin(self->window, WINDOW_BAR_HEIGHT, x2, y2 - (CHATBOX_HEIGHT + WINDOW_BAR_HEIGHT), 0);
if (self->show_peerlist) {
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2 - SIDEBAR_WIDTH - 1, 0, 0);
ctx->sidebar = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, x2 - SIDEBAR_WIDTH - 1, 0, 0);
ctx->sidebar = subwin(self->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
} else {
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, x2, 0, 0);
}
scrollok(ctx->history, 0);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
}
static void conference_onConferenceMessage(ToxWindow *self, Tox *m, uint32_t conferencenum, uint32_t peernum,
@ -362,12 +364,12 @@ static void conference_onConferenceMessage(ToxWindow *self, Tox *m, uint32_t con
/* Only play sound if mentioned by someone else */
if (strcasestr(msg, selfnick) && strcmp(selfnick, nick)) {
sound_notify(self, generic_message, NT_WNDALERT_0 | user_settings->bell_on_message, NULL);
if (self->active_box != -1) {
box_silent_notify2(self, NT_NOFOCUS, self->active_box, "%s %s", nick, msg);
box_notify2(self, generic_message, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_message,
self->active_box, "%s %s", nick, msg);
} else {
box_silent_notify(self, NT_NOFOCUS, &self->active_box, self->name, "%s %s", nick, msg);
box_notify(self, generic_message, NT_WNDALERT_0 | NT_NOFOCUS | user_settings->bell_on_message,
&self->active_box, self->name, "%s %s", nick, msg);
}
nick_clr = RED;
@ -963,7 +965,7 @@ static bool conference_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
}
wclear(ctx->linewin);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
wmove(self->window, y2, 0);
reset_buf(ctx);
}
@ -1049,15 +1051,16 @@ static void conference_onDraw(ToxWindow *self, Tox *m)
curs_set(1);
if (ctx->len > 0) {
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
mvwprintw(ctx->linewin, 0, 0, "%ls", &ctx->line[ctx->start]);
}
wclear(ctx->sidebar);
mvwhline(self->window, y2 - CHATBOX_HEIGHT, 0, ACS_HLINE, x2);
if (self->show_peerlist) {
wattron(ctx->sidebar, COLOR_PAIR(BLUE));
mvwvline(ctx->sidebar, 0, 0, ACS_VLINE, y2 - CHATBOX_HEIGHT);
mvwaddch(ctx->sidebar, y2 - CHATBOX_HEIGHT, 0, ACS_BTEE);
wattroff(ctx->sidebar, COLOR_PAIR(BLUE));
pthread_mutex_lock(&Winthread.lock);
const uint32_t num_peers = chat->num_peers;
@ -1117,8 +1120,11 @@ static void conference_onDraw(ToxWindow *self, Tox *m)
wattroff(ctx->sidebar, A_BOLD);
++line;
wattron(ctx->sidebar, COLOR_PAIR(BLUE));
mvwaddch(ctx->sidebar, line, 0, ACS_LTEE);
mvwhline(ctx->sidebar, line, 1, ACS_HLINE, SIDEBAR_WIDTH - 1);
wattroff(ctx->sidebar, COLOR_PAIR(BLUE));
++line;
for (uint32_t i = 0;
@ -1135,7 +1141,9 @@ static void conference_onDraw(ToxWindow *self, Tox *m)
UNUSED_VAR(x);
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
wmove(self->window, y + 1, new_x);
wmove(self->window, y, new_x);
draw_window_bar(self);
wnoutrefresh(self->window);
@ -1155,9 +1163,10 @@ static void conference_onInit(ToxWindow *self, Tox *m)
ChatContext *ctx = self->chatwin;
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2 - SIDEBAR_WIDTH - 1, 0, 0);
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, x2 - SIDEBAR_WIDTH - 1, 0, 0);
self->window_bar = subwin(self->window, WINDOW_BAR_HEIGHT, x2, y2 - (CHATBOX_HEIGHT + WINDOW_BAR_HEIGHT), 0);
ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
ctx->sidebar = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
ctx->sidebar = subwin(self->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
ctx->hst = calloc(1, sizeof(struct history));
ctx->log = calloc(1, sizeof(struct chatlog));

View File

@ -1022,7 +1022,7 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
wmove(self->window, y2 - 1, 1);
wattron(self->window, A_BOLD);
wprintw(self->window, "Key: ");
wprintw(self->window, "Public key: ");
wattroff(self->window, A_BOLD);
int i;
@ -1057,6 +1057,8 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wprintw(self->window, "key for help\n\n");
wattroff(self->window, COLOR_PAIR(CYAN));
draw_window_bar(self);
if (blocklist_view == 1) {
blocklist_onDraw(self, m, y2, x2);
return;
@ -1247,7 +1249,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wmove(self->window, y2 - 1, 1);
wattron(self->window, A_BOLD);
wprintw(self->window, "Key: ");
wprintw(self->window, "Public key: ");
wattroff(self->window, A_BOLD);
int i;
@ -1265,6 +1267,21 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
}
}
void friendlist_onInit(ToxWindow *self, Tox *m)
{
UNUSED_VAR(m);
int x2;
int y2;
getmaxyx(self->window, y2, x2);
if (y2 <= 0 || x2 <= 0) {
exit_toxic_err("failed in friendlist_onInit", FATALERR_CURSES);
}
self->window_bar = subwin(self->window, WINDOW_BAR_HEIGHT, x2, y2 - 2, 0);
}
void disable_chatwin(uint32_t f_num)
{
Friends.list[f_num].chatwin = -1;
@ -1343,6 +1360,7 @@ ToxWindow *new_friendlist(void)
ret->type = WINDOW_TYPE_FRIEND_LIST;
ret->onInit = &friendlist_onInit;
ret->onKey = &friendlist_onKey;
ret->onDraw = &friendlist_onDraw;
ret->onFriendAdded = &friendlist_onFriendAdded;

View File

@ -82,6 +82,7 @@ typedef struct {
} FriendsList;
ToxWindow *new_friendlist(void);
void friendlist_onInit(ToxWindow *self, Tox *m);
void disable_chatwin(uint32_t f_num);
int get_friendnum(uint8_t *name);
int load_blocklist(char *data);

View File

@ -63,10 +63,10 @@ void line_info_reset_start(ToxWindow *self, struct history *hst)
getmaxyx(self->window, y2, x2);
UNUSED_VAR(x2);
int top_offst = (self->type == WINDOW_TYPE_CHAT) || (self->type == WINDOW_TYPE_PROMPT) ? 2 : 0;
int max_y = y2 - CHATBOX_HEIGHT - top_offst;
int top_offst = (self->type == WINDOW_TYPE_CHAT) || (self->type == WINDOW_TYPE_PROMPT) ? TOP_BAR_HEIGHT : 0;
int max_y = y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT - top_offst;
int curlines = 0;
uint16_t curlines = 0;
do {
curlines += line->format_lines;
@ -74,6 +74,8 @@ void line_info_reset_start(ToxWindow *self, struct history *hst)
} while (line->prev && curlines + line->format_lines <= max_y);
hst->line_start = line;
self->scroll_pause = false;
}
void line_info_cleanup(struct history *hst)
@ -131,20 +133,32 @@ static struct line_info *line_info_ret_queue(struct history *hst)
/* Prints a maximum of `n` chars from `s` to `win`.
*
* Return true if the string contains a newline or tab byte.
* Return 1 if the string contains a newline byte.
* Return 0 if string does not contain a newline byte.
* Return -1 if printing was aborted.
*/
static bool print_n_chars(WINDOW *win, const char *s, size_t n)
static int print_n_chars(WINDOW *win, const char *s, size_t n, int max_y)
{
bool newline = false;
char ch;
for (size_t i = 0; i < n && (ch = s[i]); ++i) {
if (win) {
wprintw(win, "%c", ch);
}
if (ch == '\n') {
newline = true;
int x;
int y;
UNUSED_VAR(x);
getyx(win, y, x);
// make sure cursor will wrap correctly after newline to prevent display bugs
if (y + 1 >= max_y) {
return -1;
}
}
if (win) {
wprintw(win, "%c", ch);
}
}
@ -201,24 +215,42 @@ static unsigned int newline_count(const char *s)
*
* If `win` is null nothing will be printed to the window. This is useful to set the
* `format_lines` field on initialization.
*
* Return 0 on success.
* Return -1 if not all characters in line's message were printed to screen.
*/
static void print_wrap(WINDOW *win, struct line_info *line, int max_x)
static int print_wrap(WINDOW *win, struct line_info *line, int max_x, int max_y)
{
int x;
int y;
UNUSED_VAR(y);
const char *msg = line->msg;
uint16_t length = line->msg_len;
uint16_t lines = 0;
const int x_start = line->len - line->msg_len - 1; // manually keep track of x position because ncurses sucks
int x_limit = max_x - x_start;
if (x_limit <= 0) {
if (x_limit <= 1) {
fprintf(stderr, "Warning: x_limit <= 0 in print_wrap(): %d\n", x_limit);
return;
return -1;
}
while (msg) {
getyx(win, y, x);
// next line would print past window limit so we abort; we don't want to update format_lines
if (x > x_start) {
return -1;
}
if (length < x_limit) {
if (print_n_chars(win, msg, length)) {
int p_ret = print_n_chars(win, msg, length, max_y);
if (p_ret == 1) {
lines += newline_count(msg);
} else if (p_ret == -1) {
return -1;
}
++lines;
@ -228,8 +260,11 @@ static void print_wrap(WINDOW *win, struct line_info *line, int max_x)
int newline_idx = newline_index(msg, x_limit - 1);
if (newline_idx >= 0) {
print_n_chars(win, msg, newline_idx + 1);
msg += newline_idx + 1;
if (print_n_chars(win, msg, newline_idx + 1, max_y) == -1) {
return -1;
}
msg += (newline_idx + 1);
length -= (newline_idx + 1);
x_limit = max_x; // if we find a newline we stop adding column padding for rest of message
++lines;
@ -239,7 +274,10 @@ static void print_wrap(WINDOW *win, struct line_info *line, int max_x)
int space_idx = rspace_index(msg, x_limit - 1);
if (space_idx >= 1) {
print_n_chars(win, msg, space_idx);
if (print_n_chars(win, msg, space_idx, max_y) == -1) {
return -1;
}
msg += space_idx + 1;
length -= (space_idx + 1);
@ -247,7 +285,10 @@ static void print_wrap(WINDOW *win, struct line_info *line, int max_x)
waddch(win, '\n');
}
} else {
print_n_chars(win, msg, x_limit);
if (print_n_chars(win, msg, x_limit, max_y) == -1) {
return -1;
}
msg += x_limit;
length -= x_limit;
}
@ -263,10 +304,6 @@ static void print_wrap(WINDOW *win, struct line_info *line, int max_x)
}
if (win && line->noread_flag) {
int x;
int y;
UNUSED_VAR(y);
getyx(win, y, x);
if (x >= max_x - 1 || x == x_start) {
@ -279,17 +316,22 @@ static void print_wrap(WINDOW *win, struct line_info *line, int max_x)
}
line->format_lines = lines;
return 0;
}
static void line_info_init_line(WINDOW *win, struct line_info *line)
static void line_info_init_line(ToxWindow *self, struct line_info *line)
{
int max_y;
int max_x;
UNUSED_VAR(max_y);
int y2;
int x2;
UNUSED_VAR(y2);
getmaxyx(win, max_y, max_x);
getmaxyx(self->window, y2, x2);
print_wrap(NULL, line, max_x);
const int max_y = y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT;
const int max_x = self->show_peerlist ? x2 - 1 - SIDEBAR_WIDTH : x2;
print_wrap(NULL, line, max_x, max_y);
}
/* creates new line_info line and puts it in the queue.
@ -358,7 +400,7 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
break;
case PROMPT:
++len;
len += 2;
break;
default:
@ -398,7 +440,7 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
new_line->noread_flag = false;
new_line->timestamp = get_unix_time();
line_info_init_line(self->chatwin->history, new_line);
line_info_init_line(self, new_line);
hst->queue[hst->queue_size++] = new_line;
@ -424,29 +466,8 @@ static void line_info_check_queue(ToxWindow *self)
hst->line_end = line;
hst->line_end->id = line->id;
int y;
int y2;
int x;
int x2;
getmaxyx(self->window, y2, x2);
getyx(self->chatwin->history, y, x);
UNUSED_VAR(x);
if (x2 <= SIDEBAR_WIDTH) {
return;
}
int lines = line->format_lines;
int max_y = y2 - CHATBOX_HEIGHT;
/* move line_start forward proportionate to the number of new lines */
if (y + lines > max_y) {
while (lines > 0 && hst->line_start->next) {
lines -= hst->line_start->next->format_lines;
hst->line_start = hst->line_start->next;
++hst->start_id;
}
if (!self->scroll_pause) {
line_info_reset_start(self, hst);
}
}
@ -482,16 +503,31 @@ void line_info_print(ToxWindow *self)
if (self->type == WINDOW_TYPE_CONFERENCE) {
wmove(win, 0, 0);
} else {
wmove(win, 2, 0);
wmove(win, TOP_BAR_HEIGHT, 0);
}
struct line_info *line = hst->line_start->next;
if (!line) {
return;
}
const int max_y = y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT;
const int max_x = self->show_peerlist ? x2 - 1 - SIDEBAR_WIDTH : x2;
uint16_t numlines = line->format_lines;
int print_ret = 0;
int numlines = 0;
while (line && numlines++ <= max_y && print_ret == 0) {
int y;
int x;
UNUSED_VAR(y);
getyx(win, y, x);
if (x > 0) { // Prevents us from printing off the screen
break;
}
while (line && numlines++ <= y2) {
uint8_t type = line->type;
switch (type) {
@ -529,7 +565,7 @@ void line_info_print(ToxWindow *self)
wattron(win, COLOR_PAIR(RED));
}
print_wrap(win, line, max_x);
print_ret = print_wrap(win, line, max_x, max_y);
if (line->msg[0] == '>') {
wattroff(win, COLOR_PAIR(GREEN));
@ -559,7 +595,7 @@ void line_info_print(ToxWindow *self)
wattron(win, COLOR_PAIR(YELLOW));
wprintw(win, "%s %s ", user_settings->line_normal, line->name1);
print_wrap(win, line, max_x);
print_ret = print_wrap(win, line, max_x, max_y);
wattroff(win, COLOR_PAIR(YELLOW));
if (type == OUT_ACTION && !line->read_flag) {
@ -586,7 +622,7 @@ void line_info_print(ToxWindow *self)
wattron(win, COLOR_PAIR(line->colour));
}
print_wrap(win, line, max_x);
print_ret = print_wrap(win, line, max_x, max_y);
waddch(win, '\n');
if (line->bold) {
@ -605,7 +641,7 @@ void line_info_print(ToxWindow *self)
wattroff(win, COLOR_PAIR(GREEN));
if (line->msg[0]) {
print_wrap(win, line, max_x);
print_ret = print_wrap(win, line, max_x, max_y);
}
waddch(win, '\n');
@ -623,7 +659,7 @@ void line_info_print(ToxWindow *self)
wprintw(win, "%s ", line->name1);
wattroff(win, A_BOLD);
print_wrap(win, line, max_x);
print_ret = print_wrap(win, line, max_x, max_y);
waddch(win, '\n');
wattroff(win, COLOR_PAIR(line->colour));
@ -642,7 +678,7 @@ void line_info_print(ToxWindow *self)
wprintw(win, "%s ", line->name1);
wattroff(win, A_BOLD);
print_wrap(win, line, max_x);
print_ret = print_wrap(win, line, max_x, max_y);
waddch(win, '\n');
wattroff(win, COLOR_PAIR(line->colour));
@ -660,7 +696,7 @@ void line_info_print(ToxWindow *self)
wprintw(win, "%s", line->name1);
wattroff(win, A_BOLD);
print_wrap(win, line, max_x);
print_ret = print_wrap(win, line, max_x, max_y);
wattron(win, A_BOLD);
wprintw(win, "%s\n", line->name2);
@ -679,6 +715,38 @@ void line_info_print(ToxWindow *self)
}
}
/*
* Return true if all lines starting from `line` can fit on the screen.
*/
static bool line_info_screen_fit(ToxWindow *self, struct line_info *line)
{
if (!line) {
return true;
}
int x2;
int y2;
getmaxyx(self->chatwin->history, y2, x2);
UNUSED_VAR(x2);
const int top_offset = (self->type == WINDOW_TYPE_CHAT) || (self->type == WINDOW_TYPE_PROMPT) ? TOP_BAR_HEIGHT : 0;
const int max_y = y2 - top_offset;
uint16_t lines = line->format_lines;
while (line) {
if (lines > max_y) {
return false;
}
lines += line->format_lines;
line = line->next;
}
return true;
}
/* puts msg in specified line_info msg buffer */
void line_info_set(ToxWindow *self, uint32_t id, char *msg)
{
@ -697,49 +765,74 @@ void line_info_set(ToxWindow *self, uint32_t id, char *msg)
}
}
static void line_info_scroll_up(struct history *hst)
static void line_info_scroll_up(ToxWindow *self, struct history *hst)
{
if (hst->line_start->prev) {
hst->line_start = hst->line_start->prev;
} else {
sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
self->scroll_pause = true;
}
}
static void line_info_scroll_down(struct history *hst)
static void line_info_scroll_down(ToxWindow *self, struct history *hst)
{
if (hst->line_start->next) {
hst->line_start = hst->line_start->next;
struct line_info *next = hst->line_start->next;
if (next && self->scroll_pause) {
if (line_info_screen_fit(self, next->next)) {
line_info_reset_start(self, hst);
} else {
hst->line_start = next;
}
} else {
sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
line_info_reset_start(self, hst);
}
}
static void line_info_page_up(ToxWindow *self, struct history *hst)
{
int x2, y2;
int x2;
int y2;
getmaxyx(self->window, y2, x2);
UNUSED_VAR(x2);
size_t jump_dist = y2 / 2;
const int top_offset = (self->type == WINDOW_TYPE_CHAT) || (self->type == WINDOW_TYPE_PROMPT) ? TOP_BAR_HEIGHT : 0;
const int max_y = y2 - top_offset;
size_t jump_dist = max_y / 2;
for (size_t i = 0; i < jump_dist && hst->line_start->prev; ++i) {
hst->line_start = hst->line_start->prev;
}
self->scroll_pause = true;
}
static void line_info_page_down(ToxWindow *self, struct history *hst)
{
int x2, y2;
getmaxyx(self->window, y2, x2);
if (!self->scroll_pause) {
return;
}
int x2;
int y2;
getmaxyx(self->chatwin->history, y2, x2);
UNUSED_VAR(x2);
size_t jump_dist = y2 / 2;
const int top_offset = (self->type == WINDOW_TYPE_CHAT) || (self->type == WINDOW_TYPE_PROMPT) ? TOP_BAR_HEIGHT : 0;
const int max_y = y2 - top_offset;
size_t jump_dist = max_y / 2;
for (size_t i = 0; i < jump_dist && hst->line_start->next; ++i) {
hst->line_start = hst->line_start->next;
struct line_info *next = hst->line_start->next;
for (size_t i = 0; i < jump_dist && next; ++i) {
if (line_info_screen_fit(self, next->next)) {
line_info_reset_start(self, hst);
break;
}
hst->line_start = next;
next = hst->line_start->next;
}
}
@ -753,9 +846,9 @@ bool line_info_onKey(ToxWindow *self, wint_t key)
} else if (key == user_settings->key_half_page_down) {
line_info_page_down(self, hst);
} else if (key == user_settings->key_scroll_line_up) {
line_info_scroll_up(hst);
line_info_scroll_up(self, hst);
} else if (key == user_settings->key_scroll_line_down) {
line_info_scroll_down(hst);
line_info_scroll_down(self, hst);
} else if (key == user_settings->key_page_bottom) {
line_info_reset_start(self, hst);
} else {

View File

@ -306,7 +306,7 @@ int load_chat_history(ToxWindow *self, struct chatlog *log)
line = strtok_r(NULL, "\n", &tmp);
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, YELLOW, "---");
free(buf);

View File

@ -71,16 +71,19 @@ int timed_out(time_t timestamp, time_t timeout)
return timestamp + timeout <= get_unix_time();
}
/* Sleeps the caller's thread for `usec` microseconds */
/* Attempts to sleep the caller's thread for `usec` microseconds */
void sleep_thread(long int usec)
{
struct timespec req;
struct timespec rem;
req.tv_sec = 0;
req.tv_nsec = usec * 1000L;
if (nanosleep(&req, NULL) == -1) {
fprintf(stderr, "nanosleep() returned -1\n");
if (nanosleep(&req, &rem) == -1) {
if (nanosleep(&rem, NULL) == -1) {
fprintf(stderr, "nanosleep() returned -1\n");
}
}
}

View File

@ -108,7 +108,7 @@ int mbs_to_wcs_buf(wchar_t *buf, const char *string, size_t n);
/* Returns 1 if connection has timed out, 0 otherwise */
int timed_out(time_t timestamp, time_t timeout);
/* Sleeps the caller's thread for `usec` microseconds */
/* Attempts to sleep the caller's thread for `usec` microseconds */
void sleep_thread(long int usec);
/* Colours the window tab according to type. Beeps if is_beep is true */

View File

@ -292,7 +292,7 @@ static bool prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
}
wclear(ctx->linewin);
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
wmove(self->window, y2, 0);
reset_buf(ctx);
}
@ -301,7 +301,8 @@ static bool prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
static void prompt_onDraw(ToxWindow *self, Tox *m)
{
int x2, y2;
int x2;
int y2;
getmaxyx(self->window, y2, x2);
if (y2 <= 0 || x2 <= 0) {
@ -316,64 +317,88 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
wclear(ctx->linewin);
curs_set(1);
if (ctx->len > 0) {
mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]);
mvwprintw(ctx->linewin, 0, 0, "%ls", &ctx->line[ctx->start]);
}
mvwhline(ctx->linewin, 0, ctx->len, ' ', x2 - ctx->len);
curs_set(1);
StatusBar *statusbar = self->stb;
mvwhline(statusbar->topline, 1, 0, ACS_HLINE, x2);
wmove(statusbar->topline, 0, 0);
pthread_mutex_lock(&Winthread.lock);
Tox_Connection connection = statusbar->connection;
Tox_User_Status status = statusbar->status;
pthread_mutex_unlock(&Winthread.lock);
if (connection != TOX_CONNECTION_NONE) {
int colour = MAGENTA;
const char *status_text = "ERROR";
pthread_mutex_lock(&Winthread.lock);
Tox_User_Status status = statusbar->status;
pthread_mutex_unlock(&Winthread.lock);
switch (status) {
case TOX_USER_STATUS_NONE:
status_text = "Online";
colour = GREEN;
colour = GREEN_BLUE;
break;
case TOX_USER_STATUS_AWAY:
status_text = "Away";
colour = YELLOW;
colour = YELLOW_BLUE;
break;
case TOX_USER_STATUS_BUSY:
status_text = "Busy";
colour = RED;
colour = RED_BLUE;
break;
}
wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
wprintw(statusbar->topline, " [%s]", status_text);
wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
wattron(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wprintw(statusbar->topline, " [");
wattroff(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wattron(statusbar->topline, A_BOLD | COLOR_PAIR(colour));
wprintw(statusbar->topline, "%s", status_text);
wattroff(statusbar->topline, A_BOLD | COLOR_PAIR(colour));
wattron(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wprintw(statusbar->topline, "]");
wattroff(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wattron(statusbar->topline, COLOR_PAIR(WHITE_BLUE));
wattron(statusbar->topline, A_BOLD);
pthread_mutex_lock(&Winthread.lock);
wprintw(statusbar->topline, " %s", statusbar->nick);
pthread_mutex_unlock(&Winthread.lock);
wattroff(statusbar->topline, A_BOLD);
} else {
wprintw(statusbar->topline, " [Offline]");
wattron(statusbar->topline, A_BOLD);
wattron(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wprintw(statusbar->topline, " [");
wattroff(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wattron(statusbar->topline, COLOR_PAIR(WHITE_BLUE));
wprintw(statusbar->topline, "Offline");
wattroff(statusbar->topline, COLOR_PAIR(WHITE_BLUE));
wattron(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wprintw(statusbar->topline, "]");
wattroff(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wattron(statusbar->topline, COLOR_PAIR(WHITE_BLUE));
pthread_mutex_lock(&Winthread.lock);
wprintw(statusbar->topline, " %s", statusbar->nick);
pthread_mutex_unlock(&Winthread.lock);
wattroff(statusbar->topline, A_BOLD);
}
int s_y;
int s_x;
getyx(statusbar->topline, s_y, s_x);
mvwhline(statusbar->topline, s_y, s_x, ' ', x2 - s_x);
wattroff(statusbar->topline, COLOR_PAIR(WHITE_BLUE));
/* Reset statusbar->statusmsg on window resize */
if (x2 != self->x) {
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
@ -401,20 +426,27 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
}
if (statusbar->statusmsg[0]) {
wprintw(statusbar->topline, " : %s", statusbar->statusmsg);
wattron(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wprintw(statusbar->topline, " | ");
wattroff(statusbar->topline, COLOR_PAIR(CYAN_BLUE));
wattron(statusbar->topline, COLOR_PAIR(WHITE_BLUE));
wprintw(statusbar->topline, "%s", statusbar->statusmsg);
wattroff(statusbar->topline, COLOR_PAIR(WHITE_BLUE));
}
pthread_mutex_unlock(&Winthread.lock);
mvwhline(self->window, y2 - CHATBOX_HEIGHT, 0, ACS_HLINE, x2);
int y, x;
int y;
int x;
getyx(self->window, y, x);
UNUSED_VAR(x);
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos));
wmove(self->window, y + 1, new_x);
wmove(self->window, y, new_x);
draw_window_bar(self);
wnoutrefresh(self->window);
@ -535,7 +567,7 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m, bool first_time_run)
prompt_update_nick(prompt, nick);
/* Init statusbar subwindow */
statusbar->topline = subwin(self->window, 2, x2, 0, 0);
statusbar->topline = subwin(self->window, TOP_BAR_HEIGHT, x2, 0, 0);
}
static void print_welcome_msg(ToxWindow *self)
@ -576,7 +608,9 @@ static void prompt_init_log(ToxWindow *self, Tox *m, const char *self_name)
static void prompt_onInit(ToxWindow *self, Tox *m)
{
curs_set(1);
int y2, x2;
int y2;
int x2;
getmaxyx(self->window, y2, x2);
if (y2 <= 0 || x2 <= 0) {
@ -584,8 +618,10 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
}
ChatContext *ctx = self->chatwin;
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
ctx->history = subwin(self->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, x2, 0, 0);
self->window_bar = subwin(self->window, WINDOW_BAR_HEIGHT, x2, y2 - (CHATBOX_HEIGHT + WINDOW_BAR_HEIGHT), 0);
ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - WINDOW_BAR_HEIGHT, 0);
ctx->log = calloc(1, sizeof(struct chatlog));
ctx->hst = calloc(1, sizeof(struct history));

View File

@ -256,7 +256,7 @@ static void init_term(void)
keypad(stdscr, 1);
noecho();
nonl();
timeout(100);
timeout(50);
if (has_colors()) {
short bg_color = COLOR_BLACK;
@ -268,15 +268,23 @@ static void init_term(void)
}
}
init_pair(0, COLOR_WHITE, COLOR_BLACK);
init_pair(1, COLOR_GREEN, bg_color);
init_pair(2, COLOR_CYAN, bg_color);
init_pair(3, COLOR_RED, bg_color);
init_pair(4, COLOR_BLUE, bg_color);
init_pair(5, COLOR_YELLOW, bg_color);
init_pair(6, COLOR_MAGENTA, bg_color);
init_pair(7, COLOR_BLACK, COLOR_BLACK);
init_pair(8, COLOR_BLACK, COLOR_WHITE);
init_pair(WHITE, COLOR_WHITE, COLOR_BLACK);
init_pair(GREEN, COLOR_GREEN, bg_color);
init_pair(CYAN, COLOR_CYAN, bg_color);
init_pair(RED, COLOR_RED, bg_color);
init_pair(BLUE, COLOR_BLUE, bg_color);
init_pair(YELLOW, COLOR_YELLOW, bg_color);
init_pair(MAGENTA, COLOR_MAGENTA, bg_color);
init_pair(BLACK, COLOR_BLACK, COLOR_BLACK);
init_pair(BLUE_BLACK, COLOR_BLUE, COLOR_BLACK);
init_pair(BLACK_WHITE, COLOR_BLACK, COLOR_WHITE);
init_pair(WHITE_BLUE, COLOR_WHITE, COLOR_BLUE);
init_pair(CYAN_BLUE, COLOR_CYAN, COLOR_BLUE);
init_pair(GREEN_BLUE, COLOR_GREEN, COLOR_BLUE);
init_pair(PURPLE_BLUE, COLOR_MAGENTA, COLOR_BLUE);
init_pair(BLACK_BLUE, COLOR_BLACK, COLOR_BLUE);
init_pair(YELLOW_BLUE, COLOR_YELLOW, COLOR_BLUE);
init_pair(RED_BLUE, COLOR_RED, COLOR_BLUE);
}
refresh();
@ -1421,6 +1429,7 @@ int main(int argc, char **argv)
prompt = init_windows(m);
prompt_init_statusbar(prompt, m, !datafile_exists);
load_conferences(m);
set_active_window_index(0);
if (pthread_mutex_init(&Winthread.lock, NULL) != 0) {
exit_toxic_err("failed in main", FATALERR_MUTEX_INIT);
@ -1483,7 +1492,6 @@ int main(int argc, char **argv)
pthread_mutex_lock(&Winthread.lock);
print_init_messages(prompt);
set_active_window_index(0);
pthread_mutex_unlock(&Winthread.lock);
cleanup_init_messages();

View File

@ -75,7 +75,7 @@
#define T_KEY_C_DOWN 0x20D /* ctrl-down arrow */
#define T_KEY_TAB 0x09 /* TAB key */
#define ONLINE_CHAR "*"
#define ONLINE_CHAR "o"
#define OFFLINE_CHAR "o"
typedef enum _FATAL_ERRS {

View File

@ -336,7 +336,7 @@ int add_window(Tox *m, ToxWindow *w)
}
w->index = i;
w->window = newwin(LINES - 2, COLS, 0, 0);
w->window = newwin(LINES, COLS, 0, 0);
if (w->window == NULL) {
return -1;
@ -397,8 +397,9 @@ void del_window(ToxWindow *w)
set_active_window_index(0);
uint8_t idx = w->index;
delwin(w->window_bar);
delwin(w->window);
free(windows[idx]);
free(w);
windows[idx] = NULL;
clear();
@ -408,7 +409,12 @@ void del_window(ToxWindow *w)
ToxWindow *init_windows(Tox *m)
{
if (COLS <= CHATBOX_HEIGHT + WINDOW_BAR_HEIGHT) {
exit_toxic_err("add_window() for prompt failed in init_windows", FATALERR_WININIT);
}
prompt = new_prompt();
int n_prompt = add_window(m, prompt);
if (n_prompt < 0) {
@ -430,25 +436,18 @@ void on_window_resize(void)
refresh();
clear();
/* equivalent to LINES and COLS */
int x2, y2;
getmaxyx(stdscr, y2, x2);
y2 -= 2;
if (y2 <= 0 || x2 <= 0) {
return;
}
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] == NULL) {
ToxWindow *w = windows[i];
if (w == NULL) {
continue;
}
ToxWindow *w = windows[i];
if (windows[i]->type == WINDOW_TYPE_FRIEND_LIST) {
if (w->type == WINDOW_TYPE_FRIEND_LIST) {
delwin(w->window_bar);
delwin(w->window);
w->window = newwin(y2, x2, 0, 0);
w->window = newwin(LINES, COLS, 0, 0);
w->window_bar = subwin(w->window, WINDOW_BAR_HEIGHT, COLS, LINES - 2, 0);
continue;
}
@ -465,22 +464,35 @@ void on_window_resize(void)
delwin(w->chatwin->linewin);
delwin(w->chatwin->history);
delwin(w->window_bar);
delwin(w->window);
w->window = newwin(y2, x2, 0, 0);
w->chatwin->linewin = subwin(w->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 0);
w->window = newwin(LINES, COLS, 0, 0);
int x2;
int y2;
getmaxyx(w->window, y2, x2);
if (y2 <= 0 || x2 <= 0) {
fprintf(stderr, "Failed to resize window: max_x: %d, max_y: %d\n", x2, y2);
delwin(w->window);
return;
}
if (w->show_peerlist) {
w->chatwin->history = subwin(w->window, y2 - CHATBOX_HEIGHT + 1, x2 - SIDEBAR_WIDTH - 1, 0, 0);
w->chatwin->sidebar = subwin(w->window, y2 - CHATBOX_HEIGHT + 1, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
w->chatwin->history = subwin(w->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, x2 - SIDEBAR_WIDTH - 1, 0, 0);
w->chatwin->sidebar = subwin(w->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
} else {
w->chatwin->history = subwin(w->window, y2 - CHATBOX_HEIGHT + 1, x2, 0, 0);
w->chatwin->history = subwin(w->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, x2, 0, 0);
if (w->type != WINDOW_TYPE_CONFERENCE) {
w->stb->topline = subwin(w->window, 2, x2, 0, 0);
w->stb->topline = subwin(w->window, TOP_BAR_HEIGHT, x2, 0, 0);
}
}
w->window_bar = subwin(w->window, WINDOW_BAR_HEIGHT, x2, y2 - (CHATBOX_HEIGHT + WINDOW_BAR_HEIGHT), 0);
w->chatwin->linewin = subwin(w->window, CHATBOX_HEIGHT, x2, y2 - WINDOW_BAR_HEIGHT, 0);
#ifdef AUDIO
if (w->chatwin->infobox.active) {
@ -491,97 +503,103 @@ void on_window_resize(void)
#endif /* AUDIO */
scrollok(w->chatwin->history, 0);
wmove(w->window, y2 - CURS_Y_OFFSET, 0);
}
}
static void draw_window_tab(ToxWindow *toxwin, bool active_window)
static void draw_window_tab(WINDOW *win, ToxWindow *toxwin, bool active_window)
{
pthread_mutex_lock(&Winthread.lock);
if (toxwin->alert != WINDOW_ALERT_NONE) {
attron(COLOR_PAIR(toxwin->alert));
}
bool has_alert = toxwin->alert != WINDOW_ALERT_NONE;
unsigned int pending_messages = toxwin->pending_messages;
pthread_mutex_unlock(&Winthread.lock);
clrtoeol();
WINDOW_TYPE type = toxwin->type;
if (active_window || (type == WINDOW_TYPE_PROMPT || type == WINDOW_TYPE_FRIEND_LIST)) {
printw(" [%s]", toxwin->name);
if (active_window) {
wattron(win, A_BOLD | COLOR_PAIR(CYAN_BLUE));
wprintw(win, " [");
wattroff(win, COLOR_PAIR(CYAN_BLUE));
wattron(win, COLOR_PAIR(WHITE_BLUE));
} else {
if (pending_messages > 0) {
printw(" [%u]", pending_messages);
if (has_alert) {
wattron(win, COLOR_PAIR(CYAN_BLUE));
wprintw(win, " [");
wattroff(win, COLOR_PAIR(CYAN_BLUE));
wattron(win, A_BOLD | COLOR_PAIR(toxwin->alert));
} else {
printw(" [*]");
wattron(win, COLOR_PAIR(CYAN_BLUE));
wprintw(win, " [");
wattroff(win, COLOR_PAIR(CYAN_BLUE));
wattron(win, COLOR_PAIR(WHITE_BLUE));
}
}
pthread_mutex_lock(&Winthread.lock);
if (toxwin->alert != WINDOW_ALERT_NONE) {
attroff(COLOR_PAIR(toxwin->alert));
if (active_window || (type == WINDOW_TYPE_PROMPT || type == WINDOW_TYPE_FRIEND_LIST)) {
wprintw(win, "%s", toxwin->name);
} else {
if (pending_messages > 0) {
wprintw(win, "%u", pending_messages);
} else {
wprintw(win, "-");
}
}
pthread_mutex_unlock(&Winthread.lock);
if (active_window) {
wattroff(win, COLOR_PAIR(WHITE_BLUE));
wattron(win, COLOR_PAIR(CYAN_BLUE));
wprintw(win, "]");
wattroff(win, A_BOLD | COLOR_PAIR(CYAN_BLUE));
} else {
if (has_alert) {
wattroff(win, A_BOLD | COLOR_PAIR(toxwin->alert));
wattron(win, COLOR_PAIR(CYAN_BLUE));
wprintw(win, "]");
wattroff(win, COLOR_PAIR(CYAN_BLUE));
} else {
wattroff(win, COLOR_PAIR(WHITE_BLUE));
wattron(win, COLOR_PAIR(CYAN_BLUE));
wprintw(win, "]");
wattroff(win, COLOR_PAIR(CYAN_BLUE));
}
}
}
static void draw_bar(void)
void draw_window_bar(ToxWindow *self)
{
int y, x;
WINDOW *win = self->window_bar;
wclear(win);
ToxWindow *w = windows[active_window_index];
if (w == NULL) {
return;
if (self->scroll_pause) {
wattron(win, A_BLINK | A_BOLD | COLOR_PAIR(YELLOW_BLUE));
wprintw(win, "^");
wattroff(win, A_BLINK | A_BOLD | COLOR_PAIR(YELLOW_BLUE));
} else {
wattron(win, COLOR_PAIR(WHITE_BLUE));
wprintw(win, " ");
wattroff(win, COLOR_PAIR(WHITE_BLUE));
}
// save current cursor position
getyx(w->window, y, x);
attron(COLOR_PAIR(BLUE));
mvhline(LINES - 2, 0, '_', COLS);
attroff(COLOR_PAIR(BLUE));
move(LINES - 1, 0);
for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] == NULL) {
continue;
}
bool active_window = i == active_window_index;
if (active_window) {
#ifdef URXVT_FIX
attron(A_BOLD | COLOR_PAIR(GREEN));
} else {
#endif
attron(A_BOLD);
}
draw_window_tab(windows[i], active_window);
if (active_window) {
#ifdef URXVT_FIX
attroff(A_BOLD | COLOR_PAIR(GREEN));
} else {
#endif
attroff(A_BOLD);
}
draw_window_tab(win, windows[i], active_window);
}
// restore cursor position after drawing
move(y, x);
int cur_x;
int cur_y;
UNUSED_VAR(cur_y);
refresh();
getyx(win, cur_y, cur_x);
wattron(win, COLOR_PAIR(WHITE_BLUE));
mvwhline(win, 0, cur_x, ' ', COLS - cur_x);
wattroff(win, COLOR_PAIR(WHITE_BLUE));
}
/*
@ -684,8 +702,6 @@ void draw_active_window(Tox *m)
a->pending_messages = 0;
pthread_mutex_unlock(&Winthread.lock);
draw_bar();
touchwin(a->window);
a->onDraw(a, m);
wrefresh(a->window);

View File

@ -39,9 +39,11 @@
#define MAX_WINDOWS_NUM 20
#define MAX_WINDOW_NAME_LENGTH 22
#define CURS_Y_OFFSET 1 /* y-axis cursor offset for chat contexts */
#define CHATBOX_HEIGHT 2
#define CHATBOX_HEIGHT 1
#define TOP_BAR_HEIGHT 1
#define WINDOW_BAR_HEIGHT 1
/* Curses foreground colours (background is black) */
/* ncurses colour pairs as FOREGROUND_BACKGROUND. No background defaults to black. */
typedef enum {
WHITE,
GREEN,
@ -51,14 +53,23 @@ typedef enum {
YELLOW,
MAGENTA,
BLACK,
BLUE_BLACK,
BLACK_WHITE,
WHITE_BLUE,
GREEN_BLUE,
CYAN_BLUE,
PURPLE_BLUE,
BLACK_BLUE,
RED_BLUE,
YELLOW_BLUE,
} C_COLOURS;
/* tab alert types: lower types take priority (this relies on the order of C_COLOURS) */
typedef enum {
WINDOW_ALERT_NONE = 0,
WINDOW_ALERT_0 = GREEN,
WINDOW_ALERT_1 = RED,
WINDOW_ALERT_2 = MAGENTA,
WINDOW_ALERT_0 = GREEN_BLUE,
WINDOW_ALERT_1 = CYAN_BLUE,
WINDOW_ALERT_2 = PURPLE_BLUE,
} WINDOW_ALERTS;
typedef enum {
@ -167,6 +178,7 @@ struct ToxWindow {
char name[TOXIC_MAX_NAME_LENGTH + 1];
uint32_t num; /* corresponds to friendnumber in chat windows */
uint8_t index; /* This window's index in the windows array */
bool scroll_pause; /* true if this window is not scrolled to the bottom */
unsigned int pending_messages; /* # of new messages in this window since the last time it was focused */
int x;
@ -181,6 +193,7 @@ struct ToxWindow {
Help *help;
WINDOW *window;
WINDOW *window_bar;
};
/* statusbar info holder */
@ -264,6 +277,7 @@ void on_window_resize(void);
void force_refresh(WINDOW *w);
ToxWindow *get_window_ptr(size_t i);
ToxWindow *get_active_window(void);
void draw_window_bar(ToxWindow *self);
/* refresh inactive windows to prevent scrolling bugs.
call at least once per second */