mirror of
https://github.com/Tha14/toxic.git
synced 2025-06-28 03:16:46 +02:00
Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
4330bf5867 | |||
3f1b7cdd26 | |||
1e985c1456 | |||
61740bda85 |
2
Makefile
2
Makefile
@ -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
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Toxic is a [Tox](https://tox.chat)-based instant messaging and video chat client.
|
||||
|
||||
[](https://i.imgur.com/5S577z6.png)
|
||||
[](https://i.imgur.com/TwYA8L0.png)
|
||||
|
||||
## Installation
|
||||
[See the install instructions](/INSTALL.md)
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -30,7 +30,7 @@ ui = {
|
||||
time_format=24;
|
||||
|
||||
// Timestamp format string according to date/strftime format. Overrides time_format setting
|
||||
timestamp_format="%H:%M:%S";
|
||||
timestamp_format="%H:%M";
|
||||
|
||||
// true to show you when others are typing a message in 1-on-1 chats
|
||||
show_typing_other=true;
|
||||
@ -54,7 +54,7 @@ ui = {
|
||||
history_size=700;
|
||||
|
||||
// time in milliseconds to display a notification
|
||||
notification_timeout=3000;
|
||||
notification_timeout=6000;
|
||||
|
||||
// Indicator for display when someone connects or joins a group.
|
||||
line_join="-->";
|
||||
@ -66,7 +66,7 @@ ui = {
|
||||
line_alert="-!-";
|
||||
|
||||
// Indicator for normal messages.
|
||||
line_normal="---";
|
||||
line_normal="-";
|
||||
|
||||
// true to change status based on screen/tmux attach/detach, false to disable
|
||||
mplex_away=true;
|
||||
|
123
src/chat.c
123
src/chat.c
@ -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));
|
||||
|
@ -65,6 +65,9 @@
|
||||
|
||||
extern char *DATA_FILE;
|
||||
|
||||
#define MAX_CONFERENCE_NUM (MAX_WINDOWS_NUM - 2)
|
||||
#define CONFERENCE_EVENT_WAIT 30
|
||||
|
||||
static ConferenceChat conferences[MAX_CONFERENCE_NUM];
|
||||
static int max_conference_index = 0;
|
||||
|
||||
@ -307,9 +310,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 +325,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 +367,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;
|
||||
@ -629,7 +634,10 @@ static bool find_peer_by_pubkey(const ConferencePeer *list, uint32_t num_peers,
|
||||
const ConferencePeer *peer = &list[i];
|
||||
|
||||
if (peer->active && memcmp(peer->pubkey, pubkey, TOX_PUBLIC_KEY_SIZE) == 0) {
|
||||
*idx = i;
|
||||
if (idx) {
|
||||
*idx = i;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -637,7 +645,8 @@ static bool find_peer_by_pubkey(const ConferencePeer *list, uint32_t num_peers,
|
||||
return false;
|
||||
}
|
||||
|
||||
static void update_peer_list(Tox *m, uint32_t conferencenum, uint32_t num_peers, uint32_t old_num_peers)
|
||||
static void update_peer_list(ToxWindow *self, Tox *m, uint32_t conferencenum, uint32_t num_peers,
|
||||
uint32_t old_num_peers)
|
||||
{
|
||||
ConferenceChat *chat = &conferences[conferencenum];
|
||||
|
||||
@ -645,6 +654,8 @@ static void update_peer_list(Tox *m, uint32_t conferencenum, uint32_t num_peers,
|
||||
return;
|
||||
}
|
||||
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
ConferencePeer *old_peer_list = malloc(old_num_peers * sizeof(ConferencePeer));
|
||||
|
||||
if (!old_peer_list) {
|
||||
@ -662,6 +673,8 @@ static void update_peer_list(Tox *m, uint32_t conferencenum, uint32_t num_peers,
|
||||
return;
|
||||
}
|
||||
|
||||
char timefrmt[TIME_STR_SIZE];
|
||||
|
||||
for (uint32_t i = 0; i < num_peers; ++i) {
|
||||
ConferencePeer *peer = &chat->peer_list[i];
|
||||
|
||||
@ -676,12 +689,14 @@ static void update_peer_list(Tox *m, uint32_t conferencenum, uint32_t num_peers,
|
||||
continue;
|
||||
}
|
||||
|
||||
bool new_peer = true;
|
||||
uint32_t j;
|
||||
|
||||
if (find_peer_by_pubkey(old_peer_list, old_num_peers, peer->pubkey, &j)) {
|
||||
ConferencePeer *old_peer = &old_peer_list[j];
|
||||
memcpy(peer, old_peer, sizeof(ConferencePeer));
|
||||
old_peer->active = false;
|
||||
new_peer = false;
|
||||
}
|
||||
|
||||
size_t length = tox_conference_peer_get_name_size(m, conferencenum, i, &err);
|
||||
@ -702,22 +717,37 @@ static void update_peer_list(Tox *m, uint32_t conferencenum, uint32_t num_peers,
|
||||
peer->name_length = length;
|
||||
peer->peernum = i;
|
||||
|
||||
if (new_peer && peer->name_length > 0 && timed_out(chat->start_time, CONFERENCE_EVENT_WAIT)) {
|
||||
const char *msg = "has joined the group";
|
||||
get_time_str(timefrmt, sizeof(timefrmt));
|
||||
line_info_add(self, timefrmt, peer->name, NULL, CONNECTION, 0, GREEN, msg);
|
||||
write_to_log(msg, peer->name, ctx->log, true);
|
||||
}
|
||||
|
||||
#ifdef AUDIO
|
||||
set_peer_audio_position(m, conferencenum, i);
|
||||
#endif
|
||||
}
|
||||
|
||||
conference_update_name_list(conferencenum);
|
||||
|
||||
for (uint32_t i = 0; i < old_num_peers; ++i) {
|
||||
ConferencePeer *old_peer = &old_peer_list[i];
|
||||
|
||||
if (old_peer->active) {
|
||||
if (!find_peer_by_pubkey(chat->peer_list, chat->num_peers, old_peer->pubkey, NULL)) {
|
||||
const char *msg = "has left the group";
|
||||
get_time_str(timefrmt, sizeof(timefrmt));
|
||||
|
||||
line_info_add(self, timefrmt, old_peer->name, NULL, DISCONNECTION, 0, RED, msg);
|
||||
write_to_log(msg, old_peer->name, ctx->log, true);
|
||||
}
|
||||
|
||||
free_peer(old_peer);
|
||||
}
|
||||
}
|
||||
|
||||
free(old_peer_list);
|
||||
|
||||
conference_update_name_list(conferencenum);
|
||||
}
|
||||
|
||||
static void conference_onConferenceNameListChange(ToxWindow *self, Tox *m, uint32_t conferencenum)
|
||||
@ -749,7 +779,7 @@ static void conference_onConferenceNameListChange(ToxWindow *self, Tox *m, uint3
|
||||
|
||||
chat->num_peers = num_peers;
|
||||
chat->max_idx = num_peers;
|
||||
update_peer_list(m, conferencenum, num_peers, old_num);
|
||||
update_peer_list(self, m, conferencenum, num_peers, old_num);
|
||||
}
|
||||
|
||||
static void conference_onConferencePeerNameChange(ToxWindow *self, Tox *m, uint32_t conferencenum, uint32_t peernum,
|
||||
@ -763,17 +793,24 @@ static void conference_onConferencePeerNameChange(ToxWindow *self, Tox *m, uint3
|
||||
|
||||
const ConferencePeer *peer = peer_in_conference(conferencenum, peernum);
|
||||
|
||||
if (peer != NULL && peer->name_length > 0) {
|
||||
if (peer != NULL) {
|
||||
ChatContext *ctx = self->chatwin;
|
||||
|
||||
char timefrmt[TIME_STR_SIZE];
|
||||
get_time_str(timefrmt, sizeof(timefrmt));
|
||||
|
||||
char tmp_event[TOXIC_MAX_NAME_LENGTH * 2 + 32];
|
||||
snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", (const char *) name);
|
||||
if (peer->name_length > 0) {
|
||||
char log_event[TOXIC_MAX_NAME_LENGTH * 2 + 32];
|
||||
line_info_add(self, timefrmt, peer->name, (const char *) name, NAME_CHANGE, 0, 0, " is now known as ");
|
||||
|
||||
write_to_log(tmp_event, peer->name, ctx->log, true);
|
||||
line_info_add(self, timefrmt, peer->name, (const char *) name, NAME_CHANGE, 0, 0, " is now known as ");
|
||||
snprintf(log_event, sizeof(log_event), "is now known as %s", (const char *) name);
|
||||
write_to_log(log_event, peer->name, ctx->log, true);
|
||||
|
||||
} else { // this is kind of a hack; peers always join a group with no name set and then set it after
|
||||
const char *msg = "has joined the group";
|
||||
line_info_add(self, timefrmt, name, NULL, CONNECTION, 0, GREEN, msg);
|
||||
write_to_log(msg, name, ctx->log, true);
|
||||
}
|
||||
}
|
||||
|
||||
conference_onConferenceNameListChange(self, m, conferencenum);
|
||||
@ -963,7 +1000,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 +1086,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 +1155,10 @@ 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 +1175,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 +1197,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));
|
||||
|
@ -26,10 +26,8 @@
|
||||
#include "toxic.h"
|
||||
#include "windows.h"
|
||||
|
||||
#define SIDEBAR_WIDTH 16
|
||||
#define MAX_CONFERENCE_NUM (MAX_WINDOWS_NUM - 2)
|
||||
#define CONFERENCE_EVENT_WAIT 3
|
||||
#define CONFERENCE_MAX_TITLE_LENGTH TOX_MAX_NAME_LENGTH
|
||||
#define SIDEBAR_WIDTH 16
|
||||
|
||||
typedef struct ConferencePeer {
|
||||
bool active;
|
||||
|
@ -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;
|
||||
@ -1098,9 +1100,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
|
||||
int num_selected = Friends.num_selected;
|
||||
pthread_mutex_unlock(&Winthread.lock);
|
||||
|
||||
bool f_selected = false;
|
||||
|
||||
if (is_active) {
|
||||
bool f_selected = false;
|
||||
|
||||
if (i == num_selected) {
|
||||
wattron(self->window, A_BOLD);
|
||||
wprintw(self->window, " > ");
|
||||
@ -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;
|
||||
|
@ -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);
|
||||
|
256
src/line_info.c
256
src/line_info.c
@ -54,7 +54,7 @@ void line_info_reset_start(ToxWindow *self, struct history *hst)
|
||||
{
|
||||
struct line_info *line = hst->line_end;
|
||||
|
||||
if (line->prev == NULL) {
|
||||
if (line == NULL || line->prev == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -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,12 +274,21 @@ 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);
|
||||
waddch(win, '\n');
|
||||
|
||||
if (win) {
|
||||
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;
|
||||
}
|
||||
@ -260,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) {
|
||||
@ -276,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.
|
||||
@ -355,7 +400,7 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
|
||||
break;
|
||||
|
||||
case PROMPT:
|
||||
++len;
|
||||
len += 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -395,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;
|
||||
|
||||
@ -421,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -479,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) {
|
||||
@ -526,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));
|
||||
@ -556,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) {
|
||||
@ -583,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) {
|
||||
@ -602,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');
|
||||
@ -620,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));
|
||||
@ -639,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));
|
||||
@ -657,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);
|
||||
@ -676,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)
|
||||
{
|
||||
@ -694,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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -750,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 {
|
||||
|
@ -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);
|
||||
|
||||
@ -358,7 +358,9 @@ int rename_logfile(const char *src, const char *dest, const char *selfkey, const
|
||||
}
|
||||
|
||||
if (file_exists(newpath)) {
|
||||
remove(oldpath);
|
||||
if (remove(oldpath) != 0) {
|
||||
fprintf(stderr, "Warning: remove() failed to remove log path `%s`\n", oldpath);
|
||||
}
|
||||
} else if (rename(oldpath, newpath) != 0) {
|
||||
goto on_error;
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
96
src/prompt.c
96
src/prompt.c
@ -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));
|
||||
|
@ -116,7 +116,7 @@ static void ui_defaults(struct user_settings *settings)
|
||||
settings->bell_on_invite = 0;
|
||||
settings->colour_theme = DFLT_COLS;
|
||||
settings->history_size = 700;
|
||||
settings->notification_timeout = 3000;
|
||||
settings->notification_timeout = 6000;
|
||||
settings->show_typing_self = SHOW_TYPING_ON;
|
||||
settings->show_typing_other = SHOW_TYPING_ON;
|
||||
settings->show_welcome_msg = SHOW_WELCOME_MSG_ON;
|
||||
@ -130,10 +130,7 @@ static void ui_defaults(struct user_settings *settings)
|
||||
snprintf(settings->line_normal, LINE_HINT_MAX + 1, "%s", LINE_NORMAL);
|
||||
|
||||
settings->mplex_away = MPLEX_ON;
|
||||
snprintf(settings->mplex_away_note,
|
||||
sizeof(settings->mplex_away_note),
|
||||
"%s",
|
||||
MPLEX_AWAY_NOTE);
|
||||
snprintf(settings->mplex_away_note, sizeof(settings->mplex_away_note), "%s", MPLEX_AWAY_NOTE);
|
||||
}
|
||||
|
||||
static const struct keys_strings {
|
||||
@ -339,7 +336,7 @@ int settings_load(struct user_settings *s, const char *patharg)
|
||||
|
||||
if (config_setting_lookup_int(setting, ui_strings.time_format, &time)) {
|
||||
if (time == 12) {
|
||||
snprintf(s->timestamp_format, sizeof(s->timestamp_format), "%s", "%I:%M:%S %p");
|
||||
snprintf(s->timestamp_format, sizeof(s->timestamp_format), "%s", "%I:%M %p");
|
||||
snprintf(s->log_timestamp_format, sizeof(s->log_timestamp_format), "%s", "%Y/%m/%d [%I:%M:%S %p]");
|
||||
}
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ enum settings_values {
|
||||
#define LINE_NORMAL "-"
|
||||
#define TIMESTAMP_DEFAULT "%H:%M"
|
||||
#define LOG_TIMESTAMP_DEFAULT "%Y/%m/%d [%H:%M:%S]"
|
||||
#define MPLEX_AWAY_NOTE "Detached from screen"
|
||||
#define MPLEX_AWAY_NOTE "Away from keyboard, be back soon!"
|
||||
|
||||
int settings_load(struct user_settings *s, const char *patharg);
|
||||
|
||||
|
30
src/toxic.c
30
src/toxic.c
@ -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();
|
||||
|
@ -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 {
|
||||
|
178
src/windows.c
178
src/windows.c
@ -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);
|
||||
|
@ -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 */
|
||||
|
Reference in New Issue
Block a user