1
0
mirror of https://github.com/Tha14/toxic.git synced 2025-06-27 14:46:45 +02:00

Compare commits

...

12 Commits

Author SHA1 Message Date
ae94bc593b Rename some build options for naming consistency 2021-01-19 15:21:31 -05:00
81eb58532e Fix bug sometimes causing join message spam on conference join 2021-01-17 17:10:10 -05:00
8464ea9a7a Fix minor display bug with the audio call info box 2021-01-12 19:18:22 -05:00
b77bff35a1 Add config man entries for colour scheme options 2020-12-06 11:52:46 -05:00
eb964b64c2 Fix off by one error and comment magic numbers 2020-12-05 20:53:09 -05:00
2ff9d29491 Custom colors proof of concept
Fix formatting

Fix repeated variable in example config
2020-12-05 17:46:13 -06:00
2640919318 Don't announce when ghost peers leave the group
This appears to be a toxcore bug, but nonetheless it looks ugly. Also changed
group -> conference for join/part messages
2020-12-03 11:49:48 -05:00
2fcbc4fa1c Remove lots of duplicate code related to printing timestamps 2020-11-30 17:55:57 -05:00
4330bf5867 Show peer join/part messages in conferences
Also a couple trivial fixes
2020-11-30 12:06:13 -05:00
3f1b7cdd26 Update config example and some default settings to reflect recent changes 2020-11-30 00:58:43 -05:00
1e985c1456 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
2020-11-29 23:26:51 -05:00
61740bda85 Fix a couple minor issues
Print a warning if remove() fails, and check if the win pointer is null
before using it (this is unnecessary but it's correct and shuts coverity up)
2020-11-26 18:25:37 -05:00
37 changed files with 1009 additions and 584 deletions

View File

@ -18,7 +18,7 @@ OBJ += line_info.o log.o message_queue.o misc_tools.o name_lookup.o notify.o pro
OBJ += term_mplex.o toxic.o toxic_strings.o windows.o OBJ += term_mplex.o toxic.o toxic_strings.o windows.o
# Check if debug build is enabled # Check if debug build is enabled
RELEASE := $(shell if [ -z "$(RELEASE_ENABLED)" ] || [ "$(RELEASE_ENABLED)" = "0" ] ; then echo disabled ; else echo enabled ; fi) RELEASE := $(shell if [ -z "$(ENABLE_RELEASE)" ] || [ "$(ENABLE_RELEASE)" = "0" ] ; then echo disabled ; else echo enabled ; fi)
ifneq ($(RELEASE), enabled) ifneq ($(RELEASE), enabled)
CFLAGS += -O0 -g -DDEBUG CFLAGS += -O0 -g -DDEBUG
LDFLAGS += -O0 LDFLAGS += -O0
@ -28,9 +28,9 @@ else
endif endif
# Check if LLVM Address Sanitizer is enabled # Check if LLVM Address Sanitizer is enabled
ASAN_ENABLED := $(shell if [ -z "$(ENABLE_ASAN)" ] || [ "$(ENABLE_ASAN)" = "0" ] ; then echo disabled ; else echo enabled ; fi) ENABLE_ASAN := $(shell if [ -z "$(ENABLE_ASAN)" ] || [ "$(ENABLE_ASAN)" = "0" ] ; then echo disabled ; else echo enabled ; fi)
ifneq ($(ASAN_ENABLED), disabled) ifneq ($(ENABLE_ASAN), 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 endif
# Check on wich system we are running # 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 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 ## Installation
[See the install instructions](/INSTALL.md) [See the install instructions](/INSTALL.md)

View File

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

View File

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

View File

@ -17,8 +17,8 @@ help:
@echo " DISABLE_QRCODE: Set to \"1\" to force building without QR export support" @echo " DISABLE_QRCODE: Set to \"1\" to force building without QR export support"
@echo " DISABLE_QRPNG: Set to \"1\" to force building without QR exported as PNG support" @echo " DISABLE_QRPNG: Set to \"1\" to force building without QR exported as PNG support"
@echo " ENABLE_PYTHON: Set to \"1\" to enable building with Python scripting support" @echo " ENABLE_PYTHON: Set to \"1\" to enable building with Python scripting support"
@echo " RELEASE_ENABLED: Set to \"1\" to build without debug symbols and with full compiler optimizations" @echo " ENABLE_RELEASE: Set to \"1\" to build without debug symbols and with full compiler optimizations"
@echo " ASAN_ENABLED: Set to \"1\" to build with LLVM address sanitizer enabled. @echo " ENABLE_ASAN: Set to \"1\" to build with LLVM address sanitizer enabled.
@echo " USER_CFLAGS: Add custom flags to default CFLAGS" @echo " USER_CFLAGS: Add custom flags to default CFLAGS"
@echo " USER_LDFLAGS: Add custom flags to default LDFLAGS" @echo " USER_LDFLAGS: Add custom flags to default LDFLAGS"
@echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")" @echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")"

View File

@ -2,12 +2,12 @@
.\" Title: toxic.conf .\" Title: toxic.conf
.\" Author: [see the "AUTHORS" section] .\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/> .\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
.\" Date: 2020-05-07 .\" Date: 2020-11-18
.\" Manual: Toxic Manual .\" Manual: Toxic Manual
.\" Source: toxic __VERSION__ .\" Source: toxic __VERSION__
.\" Language: English .\" Language: English
.\" .\"
.TH "TOXIC\&.CONF" "5" "2020\-05\-07" "toxic __VERSION__" "Toxic Manual" .TH "TOXIC\&.CONF" "5" "2020\-11\-18" "toxic __VERSION__" "Toxic Manual"
.\" ----------------------------------------------------------------- .\" -----------------------------------------------------------------
.\" * Define some portability stuff .\" * Define some portability stuff
.\" ----------------------------------------------------------------- .\" -----------------------------------------------------------------
@ -93,6 +93,26 @@ Enable or disable acoustic alerts on events\&. true or false
Select between native terminal colors and toxic color theme\&. true or false Select between native terminal colors and toxic color theme\&. true or false
.RE .RE
.PP .PP
\fBcolor_bar_bg\fR
.RS 4
set background color of chat status bars\&. (black, white, red, green, blue, cyan, yellow, magenta)
.RE
.PP
\fBcolor_bar_fg\fR
.RS 4
set foreground (text) color of chat status bars\&. (black, white, red, green, blue, cyan, yellow, magenta)
.RE
.PP
\fBcolor_bar_accent\fR
.RS 4
set foreground accent color of chat status bars\&. (black, white, red, green, blue, cyan, yellow, magenta)
.RE
.PP
\fBcolor_bar_notify\fR
.RS 4
set foreground notify (and typing) color in chat status bar\&. (black, white, red, green, blue, cyan, yellow, magenta)
.RE
.PP
\fBautolog\fR \fBautolog\fR
.RS 4 .RS 4
Enable or disable autologging\&. true or false Enable or disable autologging\&. true or false
@ -222,11 +242,6 @@ Audio output device\&. Integer value\&. Number corresponds to
Voice Activity Detection threshold\&. Float value\&. Recommended values are 1\&.0\-40\&.0 Voice Activity Detection threshold\&. Float value\&. Recommended values are 1\&.0\-40\&.0
.RE .RE
.PP .PP
\fBpush_to_talk\fR
.RS 4
Enable/Disable Push\-To\-Talk for conference audio chats (active key is F2)\&. true or false
.RE
.PP
\fBconference_audio_channels\fR \fBconference_audio_channels\fR
.RS 4 .RS 4
Number of channels for conference audio broadcast\&. Integer value\&. 1 (mono) or 2 (stereo) Number of channels for conference audio broadcast\&. Integer value\&. 1 (mono) or 2 (stereo)
@ -236,6 +251,11 @@ Number of channels for conference audio broadcast\&. Integer value\&. 1 (mono) o
.RS 4 .RS 4
Number of channels for 1\-on\-1 audio broadcast\&. Integer value\&. 1 (mono) or 2 (stereo) Number of channels for 1\-on\-1 audio broadcast\&. Integer value\&. 1 (mono) or 2 (stereo)
.RE .RE
.PP
\fBpush_to_talk\fR
.RS 4
Enable/Disable Push\-To\-Talk for conference audio chats (active key is F2)\&. true or false
.RE
.RE .RE
.PP .PP
\fBtox\fR \fBtox\fR

View File

@ -60,6 +60,18 @@ OPTIONS
*native_colors*;; *native_colors*;;
Select between native terminal colors and toxic color theme. true or false Select between native terminal colors and toxic color theme. true or false
*color_bar_bg*;;
set background color of chat status bars. (black, white, red, green, blue, cyan, yellow, magenta)
*color_bar_fg*;;
set foreground (text) color of chat status bars. (black, white, red, green, blue, cyan, yellow, magenta)
*color_bar_accent*;;
set foreground accent color of chat status bars. (black, white, red, green, blue, cyan, yellow, magenta)
*color_bar_notify*;;
set foreground notify (and typing) color in chat status bar. (black, white, red, green, blue, cyan, yellow, magenta)
*autolog*;; *autolog*;;
Enable or disable autologging. true or false Enable or disable autologging. true or false

View File

@ -9,20 +9,32 @@ ui = {
alerts=true; alerts=true;
// Output a bell when receiving a message (see manpage) // Output a bell when receiving a message (see manpage)
bell_on_message=true bell_on_message=true;
// Output a bell when receiving a filetransfer (see manpage) // Output a bell when receiving a filetransfer (see manpage)
bell_on_filetrans=true bell_on_filetrans=true;
// Don't output a bell when a filetransfer was accepted (see manpage) // Don't output a bell when a filetransfer was accepted (see manpage)
bell_on_filetrans_accept=false bell_on_filetrans_accept=false;
// Output a bell when receiving a group/call invite (see manpage) // Output a bell when receiving a group/call invite (see manpage)
bell_on_invite=true bell_on_invite=true;
// true to use native terminal colours, false to use toxic default colour theme // true to use native terminal colours, false to use toxic default colour theme
native_colors=false; native_colors=false;
// set background color of chat status bars (black, white, red, green, blue, cyan, yellow, magenta)
color_bar_bg="blue";
// set foreground (text) color of chat status bars (black, white, red, green, blue, cyan, yellow, magenta)
color_bar_fg="white";
// set foreground accent color of chat status bars (black, white, red, green, blue, cyan, yellow, magenta)
color_bar_accent="cyan";
// set foreground notify (and typing) color in chat status bar (black, white, red, green, blue, cyan, yellow, magenta)
color_bar_notify="yellow";
// true to enable autologging, false to disable // true to enable autologging, false to disable
autolog=false; autolog=false;
@ -30,7 +42,7 @@ ui = {
time_format=24; time_format=24;
// Timestamp format string according to date/strftime format. Overrides time_format setting // 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 // true to show you when others are typing a message in 1-on-1 chats
show_typing_other=true; show_typing_other=true;
@ -54,19 +66,19 @@ ui = {
history_size=700; history_size=700;
// time in milliseconds to display a notification // time in milliseconds to display a notification
notification_timeout=3000; notification_timeout=6000;
// Indicator for display when someone connects or joins a group. // Indicator for display when someone connects or joins a group
line_join="-->"; line_join="-->";
// Indicator for display when someone disconnects or leaves a group. // Indicator for display when someone disconnects or leaves a group
line_quit="<--"; line_quit="<--";
// Indicator for alert messages. // Indicator for alert messages.
line_alert="-!-"; line_alert="-!-";
// Indicator for normal messages. // Indicator for normal messages.
line_normal="---"; line_normal="-";
// true to change status based on screen/tmux attach/detach, false to disable // true to change status based on screen/tmux attach/detach, false to disable
mplex_away=true; mplex_away=true;
@ -131,6 +143,6 @@ keys = {
half_page_up="Ctrl+F"; half_page_up="Ctrl+F";
half_page_down="Ctrl+V"; half_page_down="Ctrl+V";
page_bottom="Ctrl+H"; page_bottom="Ctrl+H";
toggle_peerlist="Ctrl+b"; toggle_peerlist="Ctrl+B";
toggle_paste_mode="Ctrl+T"; toggle_paste_mode="Ctrl+T";
}; };

View File

@ -99,18 +99,16 @@ void api_send(const char *msg)
} }
char *name = api_get_nick(); char *name = api_get_nick();
char timefrmt[TIME_STR_SIZE];
if (name == NULL) { if (name == NULL) {
return; return;
} }
self_window = get_active_window(); self_window = get_active_window();
get_time_str(timefrmt, sizeof(timefrmt));
strncpy((char *) self_window->chatwin->line, msg, sizeof(self_window->chatwin->line)); strncpy((char *) self_window->chatwin->line, msg, sizeof(self_window->chatwin->line));
add_line_to_hist(self_window->chatwin); add_line_to_hist(self_window->chatwin);
int id = line_info_add(self_window, timefrmt, name, NULL, OUT_MSG, 0, 0, "%s", msg); int id = line_info_add(self_window, true, name, NULL, OUT_MSG, 0, 0, "%s", msg);
cqueue_add(self_window->chatwin->cqueue, msg, strlen(msg), OUT_MSG, id); cqueue_add(self_window->chatwin->cqueue, msg, strlen(msg), OUT_MSG, id);
free(name); free(name);
} }
@ -156,7 +154,7 @@ void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
error_str = "Only one argument allowed."; error_str = "Only one argument allowed.";
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, error_str); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, error_str);
return; return;
} }
@ -165,7 +163,7 @@ void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
if (fp == NULL) { if (fp == NULL) {
error_str = "Path does not exist."; error_str = "Path does not exist.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, error_str); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, error_str);
return; return;
} }

View File

@ -90,7 +90,7 @@ void audio_bit_rate_callback(ToxAV *av, uint32_t friend_number, uint32_t audio_b
static void print_err(ToxWindow *self, const char *error_str) static void print_err(ToxWindow *self, const char *error_str)
{ {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str);
} }
ToxAV *init_audio(ToxWindow *self, Tox *tox) ToxAV *init_audio(ToxWindow *self, Tox *tox)
@ -113,13 +113,13 @@ ToxAV *init_audio(ToxWindow *self, Tox *tox)
if (!CallControl.av) { if (!CallControl.av) {
CallControl.audio_errors |= ae_StartingCoreAudio; CallControl.audio_errors |= ae_StartingCoreAudio;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init ToxAV"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to init ToxAV");
return NULL; return NULL;
} }
if (init_devices() == de_InternalError) { if (init_devices() == de_InternalError) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init devices"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to init devices");
toxav_kill(CallControl.av); toxav_kill(CallControl.av);
return CallControl.av = NULL; return CallControl.av = NULL;
@ -200,7 +200,7 @@ static bool cancel_call(Call *call)
static int start_transmission(ToxWindow *self, Call *call) static int start_transmission(ToxWindow *self, Call *call)
{ {
if (!self || !CallControl.av) { if (!self || !CallControl.av) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare audio transmission"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare audio transmission");
return -1; return -1;
} }
@ -209,17 +209,17 @@ static int start_transmission(ToxWindow *self, Call *call)
if (error != de_None) { if (error != de_None) {
if (error == de_FailedStart) { if (error == de_FailedStart) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to start audio input device"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to start audio input device");
} }
if (error == de_InternalError) { if (error == de_InternalError) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Internal error with opening audio input device"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Internal error with opening audio input device");
} }
} }
if (open_output_device(&call->out_idx, if (open_output_device(&call->out_idx,
CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels) != de_None) { CallControl.audio_sample_rate, CallControl.audio_frame_duration, CallControl.audio_channels) != de_None) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open audio output device!"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to open audio output device!");
} }
return 0; return 0;
@ -342,7 +342,7 @@ void on_call_state(ToxAV *av, uint32_t friend_number, uint32_t state, void *user
case TOXAV_FRIEND_CALL_STATE_ERROR: case TOXAV_FRIEND_CALL_STATE_ERROR:
case TOXAV_FRIEND_CALL_STATE_FINISHED: case TOXAV_FRIEND_CALL_STATE_FINISHED:
if (state == TOXAV_FRIEND_CALL_STATE_ERROR) { if (state == TOXAV_FRIEND_CALL_STATE_ERROR) {
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "ToxAV callstate error!"); line_info_add(CallControl.prompt, false, NULL, NULL, SYS_MSG, 0, 0, "ToxAV callstate error!");
} }
if (call->status == cs_Pending) { if (call->status == cs_Pending) {
@ -669,7 +669,7 @@ void cmd_list_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*
} }
else { else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
return; return;
} }
@ -708,7 +708,7 @@ void cmd_change_device(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (
} }
else { else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
return; return;
} }
@ -748,7 +748,7 @@ void cmd_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
} }
else { else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
return; return;
} }
@ -816,7 +816,7 @@ void cmd_bitrate(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
} }
if (argc == 0) { if (argc == 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,
"Current audio encoding bitrate: %u", call->audio_bit_rate); "Current audio encoding bitrate: %u", call->audio_bit_rate);
return; return;
} }

View File

@ -775,7 +775,7 @@ float get_input_volume(void)
void print_al_devices(ToxWindow *self, DeviceType type) void print_al_devices(ToxWindow *self, DeviceType type)
{ {
for (int i = 0; i < audio_state->num_al_devices[type]; ++i) { for (int i = 0; i < audio_state->num_al_devices[type]; ++i) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, line_info_add(self, false, NULL, NULL, SYS_MSG,
audio_state->current_al_device_name[type] audio_state->current_al_device_name[type]
&& strcmp(audio_state->current_al_device_name[type], audio_state->al_device_names[type][i]) == 0 ? 1 : 0, && strcmp(audio_state->current_al_device_name[type], audio_state->al_device_names[type][i]) == 0 ? 1 : 0,
0, "%d: %s", i, audio_state->al_device_names[type][i]); 0, "%d: %s", i, audio_state->al_device_names[type][i]);

View File

@ -45,10 +45,10 @@ static void print_ac_matches(ToxWindow *self, Tox *m, char **list, size_t n_matc
} }
for (size_t i = 0; i < n_matches; ++i) { for (size_t i = 0; i < n_matches; ++i) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", list[i]); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", list[i]);
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "");
} }
/* puts match in match buffer. if more than one match, add first n chars that are identical. /* puts match in match buffer. if more than one match, add first n chars that are identical.

View File

@ -167,11 +167,11 @@ void kill_chat_window(ToxWindow *self, Tox *m)
del_window(self); del_window(self);
} }
static void recv_message_helper(ToxWindow *self, const char *msg, const char *nick, const char *timefrmt) static void recv_message_helper(ToxWindow *self, const char *msg, const char *nick)
{ {
ChatContext *ctx = self->chatwin; ChatContext *ctx = self->chatwin;
line_info_add(self, timefrmt, nick, NULL, IN_MSG, 0, 0, "%s", msg); line_info_add(self, true, nick, NULL, IN_MSG, 0, 0, "%s", msg);
write_to_log(msg, nick, ctx->log, false); write_to_log(msg, nick, ctx->log, false);
if (self->active_box != -1) { if (self->active_box != -1) {
@ -183,11 +183,11 @@ static void recv_message_helper(ToxWindow *self, const char *msg, const char *ni
} }
} }
static void recv_action_helper(ToxWindow *self, const char *action, const char *nick, const char *timefrmt) static void recv_action_helper(ToxWindow *self, const char *action, const char *nick)
{ {
ChatContext *ctx = self->chatwin; ChatContext *ctx = self->chatwin;
line_info_add(self, timefrmt, nick, NULL, IN_ACTION, 0, 0, "%s", action); line_info_add(self, true, nick, NULL, IN_ACTION, 0, 0, "%s", action);
write_to_log(action, nick, ctx->log, true); write_to_log(action, nick, ctx->log, true);
if (self->active_box != -1) { if (self->active_box != -1) {
@ -210,16 +210,13 @@ static void chat_onMessage(ToxWindow *self, Tox *m, uint32_t num, Tox_Message_Ty
char nick[TOX_MAX_NAME_LENGTH]; char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num); get_nick_truncate(m, nick, num);
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
if (type == TOX_MESSAGE_TYPE_NORMAL) { if (type == TOX_MESSAGE_TYPE_NORMAL) {
recv_message_helper(self, msg, nick, timefrmt); recv_message_helper(self, msg, nick);
return; return;
} }
if (type == TOX_MESSAGE_TYPE_ACTION) { if (type == TOX_MESSAGE_TYPE_ACTION) {
recv_action_helper(self, msg, nick, timefrmt); recv_action_helper(self, msg, nick);
return; return;
} }
} }
@ -237,9 +234,6 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, Tox_C
ChatContext *ctx = self->chatwin; ChatContext *ctx = self->chatwin;
const char *msg; const char *msg;
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
char nick[TOX_MAX_NAME_LENGTH]; char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num); get_nick_truncate(m, nick, num);
@ -254,7 +248,7 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, Tox_C
chat_resume_file_senders(self, m, num); chat_resume_file_senders(self, m, num);
msg = "has come online"; msg = "has come online";
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg); line_info_add(self, true, nick, NULL, CONNECTION, 0, GREEN, msg);
write_to_log(msg, nick, ctx->log, true); write_to_log(msg, nick, ctx->log, true);
} else if (connection_status == TOX_CONNECTION_NONE) { } else if (connection_status == TOX_CONNECTION_NONE) {
Friends.list[num].is_typing = false; Friends.list[num].is_typing = false;
@ -266,7 +260,7 @@ static void chat_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, Tox_C
chat_pause_file_transfers(num); chat_pause_file_transfers(num);
msg = "has gone offline"; msg = "has gone offline";
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg); line_info_add(self, true, nick, NULL, DISCONNECTION, 0, RED, msg);
write_to_log(msg, nick, ctx->log, true); write_to_log(msg, nick, ctx->log, true);
} }
} }
@ -509,11 +503,11 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint
/* transfer is accepted */ /* transfer is accepted */
if (ft->state == FILE_TRANSFER_PENDING) { if (ft->state == FILE_TRANSFER_PENDING) {
ft->state = FILE_TRANSFER_STARTED; ft->state = FILE_TRANSFER_STARTED;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%zu] for '%s' accepted.", line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer [%zu] for '%s' accepted.",
ft->index, ft->file_name); ft->index, ft->file_name);
char progline[MAX_STR_SIZE]; char progline[MAX_STR_SIZE];
init_progress_bar(progline); init_progress_bar(progline);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
sound_notify(self, silent, NT_NOFOCUS | user_settings->bell_on_filetrans_accept | NT_WNDALERT_2, NULL); sound_notify(self, silent, NT_NOFOCUS | user_settings->bell_on_filetrans_accept | NT_WNDALERT_2, NULL);
ft->line_id = self->chatwin->hst->line_end->id + 2; ft->line_id = self->chatwin->hst->line_end->id + 2;
} else if (ft->state == FILE_TRANSFER_PAUSED) { /* transfer is resumed */ } else if (ft->state == FILE_TRANSFER_PAUSED) { /* transfer is resumed */
@ -637,14 +631,14 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
if (!ft) { if (!ft) {
tox_file_control(m, friendnum, filenumber, TOX_FILE_CONTROL_CANCEL, NULL); tox_file_control(m, friendnum, filenumber, TOX_FILE_CONTROL_CANCEL, NULL);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,
"File transfer request failed: Too many concurrent file transfers."); "File transfer request failed: Too many concurrent file transfers.");
return; return;
} }
char sizestr[32]; char sizestr[32];
bytes_convert_str(sizestr, sizeof(sizestr), file_size); bytes_convert_str(sizestr, sizeof(sizestr), file_size);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)", filename, sizestr); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer request for '%s' (%s)", filename, sizestr);
if (!valid_file_name(filename, name_length)) { if (!valid_file_name(filename, name_length)) {
close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, "File transfer failed: Invalid file name.", notif_error); close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, "File transfer failed: Invalid file name.", notif_error);
@ -703,7 +697,7 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
} }
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %zu' to accept the file transfer.", ft->index); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Type '/savefile %zu' to accept the file transfer.", ft->index);
ft->file_size = file_size; ft->file_size = file_size;
snprintf(ft->file_path, sizeof(ft->file_path), "%s", file_path); snprintf(ft->file_path, sizeof(ft->file_path), "%s", file_path);
@ -745,21 +739,21 @@ static void chat_onConferenceInvite(ToxWindow *self, Tox *m, int32_t friendnumbe
Friends.list[friendnumber].conference_invite.length = length; Friends.list[friendnumber].conference_invite.length = length;
Friends.list[friendnumber].conference_invite.type = type; 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]; char name[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, name, friendnumber); get_nick_truncate(m, name, friendnumber);
const char *description = type == TOX_CONFERENCE_TYPE_AV ? "an audio conference" : "a conference"; const char *description = type == TOX_CONFERENCE_TYPE_AV ? "an audio conference" : "a conference";
if (self->active_box != -1) { 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 { } 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); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s has invited you to %s.", name, description);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type \"/join\" to join the chat."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Type \"/join\" to join the chat.");
} }
/* AV Stuff */ /* AV Stuff */
@ -777,7 +771,7 @@ void chat_onInvite(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state
/* call is flagged active here */ /* call is flagged active here */
self->is_call = true; self->is_call = true;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Incoming audio call! Type: \"/answer\" or \"/reject\""); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Incoming audio call! Type: \"/answer\" or \"/reject\"");
if (self->ringing_sound == -1) { if (self->ringing_sound == -1) {
sound_notify(self, call_incoming, NT_LOOP | user_settings->bell_on_invite, &self->ringing_sound); sound_notify(self, call_incoming, NT_LOOP | user_settings->bell_on_invite, &self->ringing_sound);
@ -799,7 +793,7 @@ void chat_onRinging(ToxWindow *self, ToxAV *av, uint32_t friend_number, int stat
return; return;
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Ringing...type \"/hangup\" to cancel it."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Ringing...type \"/hangup\" to cancel it.");
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
@ -821,7 +815,7 @@ void chat_onStarting(ToxWindow *self, ToxAV *av, uint32_t friend_number, int sta
init_infobox(self); init_infobox(self);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call started! Type: \"/hangup\" to end it."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Call started! Type: \"/hangup\" to end it.");
/* call is flagged active here */ /* call is flagged active here */
self->is_call = true; self->is_call = true;
@ -841,7 +835,7 @@ void chat_onEnding(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state
} }
kill_infobox(self); kill_infobox(self);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call ended!"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Call ended!");
self->is_call = false; self->is_call = false;
@ -860,7 +854,7 @@ void chat_onError(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
} }
self->is_call = false; self->is_call = false;
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error!"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Error!");
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
stop_sound(self->ringing_sound); stop_sound(self->ringing_sound);
@ -881,7 +875,7 @@ void chat_onStart(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
init_infobox(self); init_infobox(self);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call started! Type: \"/hangup\" to end it."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Call started! Type: \"/hangup\" to end it.");
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
stop_sound(self->ringing_sound); stop_sound(self->ringing_sound);
@ -899,7 +893,7 @@ void chat_onCancel(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state
self->is_call = false; self->is_call = false;
kill_infobox(self); kill_infobox(self);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call canceled!"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Call canceled!");
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
stop_sound(self->ringing_sound); stop_sound(self->ringing_sound);
@ -915,7 +909,7 @@ void chat_onReject(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state
return; return;
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Rejected!"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Rejected!");
self->is_call = false; self->is_call = false;
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
@ -933,7 +927,7 @@ void chat_onEnd(ToxWindow *self, ToxAV *av, uint32_t friend_number, int state)
} }
kill_infobox(self); kill_infobox(self);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Call ended!"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Call ended!");
self->is_call = false; self->is_call = false;
#ifdef SOUND_NOTIFY #ifdef SOUND_NOTIFY
@ -1033,7 +1027,7 @@ static void draw_infobox(ToxWindow *self)
wattroff(infobox->win, A_BOLD); wattroff(infobox->win, A_BOLD);
wprintw(infobox->win, "%.2f\n", (double) infobox->vad_lvl); wprintw(infobox->win, "%.2f\n", (double) infobox->vad_lvl);
wborder(infobox->win, ACS_VLINE, ' ', ACS_HLINE, ACS_HLINE, ACS_TTEE, ' ', ACS_LLCORNER, ' '); wborder(infobox->win, ACS_VLINE, ' ', ACS_HLINE, ACS_HLINE, ACS_ULCORNER, ' ', ACS_LLCORNER, ' ');
wnoutrefresh(infobox->win); wnoutrefresh(infobox->win);
} }
@ -1051,10 +1045,7 @@ static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action)
size_t len = tox_self_get_name_size(m); size_t len = tox_self_get_name_size(m);
selfname[len] = '\0'; selfname[len] = '\0';
char timefrmt[TIME_STR_SIZE]; int id = line_info_add(self, true, selfname, NULL, OUT_ACTION, 0, 0, "%s", action);
get_time_str(timefrmt, sizeof(timefrmt));
int id = line_info_add(self, timefrmt, selfname, NULL, OUT_ACTION, 0, 0, "%s", action);
cqueue_add(ctx->cqueue, action, strlen(action), OUT_ACTION, id); cqueue_add(ctx->cqueue, action, strlen(action), OUT_ACTION, id);
} }
@ -1170,18 +1161,15 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
size_t len = tox_self_get_name_size(m); size_t len = tox_self_get_name_size(m);
selfname[len] = '\0'; selfname[len] = '\0';
char timefrmt[TIME_STR_SIZE]; int id = line_info_add(self, true, selfname, NULL, OUT_MSG, 0, 0, "%s", line);
get_time_str(timefrmt, sizeof(timefrmt));
int id = line_info_add(self, timefrmt, selfname, NULL, OUT_MSG, 0, 0, "%s", line);
cqueue_add(ctx->cqueue, line, strlen(line), OUT_MSG, id); cqueue_add(ctx->cqueue, line, strlen(line), OUT_MSG, id);
} else { } else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to parse message."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Failed to parse message.");
} }
} }
wclear(ctx->linewin); wclear(ctx->linewin);
wmove(self->window, y2 - CURS_Y_OFFSET, 0); wmove(self->window, y2, 0);
reset_buf(ctx); reset_buf(ctx);
} }
@ -1194,7 +1182,8 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
static void chat_onDraw(ToxWindow *self, Tox *m) static void chat_onDraw(ToxWindow *self, Tox *m)
{ {
int x2, y2; int x2;
int y2;
getmaxyx(self->window, y2, x2); getmaxyx(self->window, y2, x2);
if (y2 <= 0 || x2 <= 0) { if (y2 <= 0 || x2 <= 0) {
@ -1209,15 +1198,14 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
wclear(ctx->linewin); wclear(ctx->linewin);
curs_set(1);
if (ctx->len > 0) { 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 */ /* Draw status bar */
StatusBar *statusbar = self->stb; StatusBar *statusbar = self->stb;
mvwhline(statusbar->topline, 1, 0, ACS_HLINE, x2);
wmove(statusbar->topline, 0, 0); wmove(statusbar->topline, 0, 0);
/* Draw name, status and note in statusbar */ /* Draw name, status and note in statusbar */
@ -1227,38 +1215,63 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
switch (status) { switch (status) {
case TOX_USER_STATUS_NONE: case TOX_USER_STATUS_NONE:
colour = GREEN; colour = STATUS_ONLINE;
break; break;
case TOX_USER_STATUS_AWAY: case TOX_USER_STATUS_AWAY:
colour = YELLOW; colour = STATUS_AWAY;
break; break;
case TOX_USER_STATUS_BUSY: case TOX_USER_STATUS_BUSY:
colour = RED; colour = STATUS_ONLINE;
break; break;
} }
wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, " [");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD); 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); wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD);
if (Friends.list[self->num].is_typing) { wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wattron(statusbar->topline, COLOR_PAIR(YELLOW)); wprintw(statusbar->topline, "] ");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
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(BAR_NOTIFY));
} else {
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
} }
wattron(statusbar->topline, A_BOLD); wprintw(statusbar->topline, "%s", statusbar->nick);
wprintw(statusbar->topline, " %s ", statusbar->nick);
wattroff(statusbar->topline, A_BOLD);
if (Friends.list[self->num].is_typing) { if (is_typing) {
wattroff(statusbar->topline, COLOR_PAIR(YELLOW)); wattroff(statusbar->topline, A_BOLD | COLOR_PAIR(BAR_NOTIFY));
} else {
wattroff(statusbar->topline, A_BOLD | COLOR_PAIR(BAR_TEXT));
} }
} else { } else {
wprintw(statusbar->topline, " %s", OFFLINE_CHAR); wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wattron(statusbar->topline, A_BOLD); wprintw(statusbar->topline, " [");
wprintw(statusbar->topline, " %s ", statusbar->nick); wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wattroff(statusbar->topline, A_BOLD);
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
wprintw(statusbar->topline, "%s", OFFLINE_CHAR);
wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, "] ");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
wprintw(statusbar->topline, "%s", statusbar->nick);
wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
} }
/* Reset statusbar->statusmsg on window resize */ /* Reset statusbar->statusmsg on window resize */
@ -1287,30 +1300,51 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
} }
if (statusbar->statusmsg[0]) { if (statusbar->statusmsg[0]) {
wprintw(statusbar->topline, ": %s ", statusbar->statusmsg); wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, " | ");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
wprintw(statusbar->topline, "%s ", statusbar->statusmsg);
} else {
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
} }
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(BAR_TEXT));
wmove(statusbar->topline, 0, x2 - (KEY_IDENT_DIGITS * 2) - 3); wmove(statusbar->topline, 0, x2 - (KEY_IDENT_DIGITS * 2) - 3);
wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, "{"); wprintw(statusbar->topline, "{");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
size_t i; wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
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, "%02X", Friends.list[self->num].pub_key[i] & 0xff);
} }
wprintw(statusbar->topline, "}\n"); wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
mvwhline(self->window, y2 - CHATBOX_HEIGHT, 0, ACS_HLINE, x2); wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, "} ");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
int y, x; int y;
int x;
getyx(self->window, y, x); getyx(self->window, y, x);
UNUSED_VAR(x); UNUSED_VAR(x);
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos)); 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); wnoutrefresh(self->window);
@ -1339,17 +1373,17 @@ static void chat_init_log(ToxWindow *self, Tox *m, const char *self_nick)
tox_self_get_address(m, (uint8_t *) myid); tox_self_get_address(m, (uint8_t *) myid);
if (log_init(ctx->log, self_nick, myid, Friends.list[self->num].pub_key, LOG_TYPE_CHAT) != 0) { if (log_init(ctx->log, self_nick, myid, Friends.list[self->num].pub_key, LOG_TYPE_CHAT) != 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to initialize chat log."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to initialize chat log.");
return; return;
} }
if (load_chat_history(self, ctx->log) != 0) { if (load_chat_history(self, ctx->log) != 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to load chat history."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to load chat history.");
} }
if (Friends.list[self->num].logging_on) { if (Friends.list[self->num].logging_on) {
if (log_enable(ctx->log) != 0) { if (log_enable(ctx->log) != 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to enable chat log."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to enable chat log.");
} }
} }
} }
@ -1357,7 +1391,9 @@ static void chat_init_log(ToxWindow *self, Tox *m, const char *self_nick)
static void chat_onInit(ToxWindow *self, Tox *m) static void chat_onInit(ToxWindow *self, Tox *m)
{ {
curs_set(1); curs_set(1);
int x2, y2;
int x2;
int y2;
getmaxyx(self->window, y2, x2); getmaxyx(self->window, y2, x2);
if (y2 <= 0 || x2 <= 0) { if (y2 <= 0 || x2 <= 0) {
@ -1390,9 +1426,10 @@ static void chat_onInit(ToxWindow *self, Tox *m)
/* Init subwindows */ /* Init subwindows */
ChatContext *ctx = self->chatwin; ChatContext *ctx = self->chatwin;
statusbar->topline = subwin(self->window, 2, x2, 0, 0); statusbar->topline = subwin(self->window, TOP_BAR_HEIGHT, x2, 0, 0);
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);
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);
ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - WINDOW_BAR_HEIGHT, 0);
ctx->hst = calloc(1, sizeof(struct history)); ctx->hst = calloc(1, sizeof(struct history));
ctx->log = calloc(1, sizeof(struct chatlog)); ctx->log = calloc(1, sizeof(struct chatlog));

View File

@ -41,7 +41,7 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
UNUSED_VAR(window); UNUSED_VAR(window);
if (argc < 2) { if (argc < 2) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Requires type in|out and the file ID."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Requires type in|out and the file ID.");
return; return;
} }
@ -50,7 +50,7 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
long int idx = strtol(argv[2], NULL, 10); long int idx = strtol(argv[2], NULL, 10);
if ((idx == 0 && strcmp(argv[2], "0")) || idx >= MAX_FILES || idx < 0) { if ((idx == 0 && strcmp(argv[2], "0")) || idx >= MAX_FILES || idx < 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return; return;
} }
@ -62,17 +62,17 @@ void cmd_cancelfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
} else if (strcasecmp(inoutstr, "out") == 0) { } else if (strcasecmp(inoutstr, "out") == 0) {
ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_SEND); ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_SEND);
} else { } else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type must be 'in' or 'out'."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Type must be 'in' or 'out'.");
return; return;
} }
if (!ft) { if (!ft) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return; return;
} }
if (ft->state == FILE_TRANSFER_INACTIVE) { if (ft->state == FILE_TRANSFER_INACTIVE) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid file ID.");
return; return;
} }
@ -85,25 +85,25 @@ void cmd_conference_invite(WINDOW *window, ToxWindow *self, Tox *m, int argc, ch
UNUSED_VAR(window); UNUSED_VAR(window);
if (argc < 1) { if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference number required."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference number required.");
return; return;
} }
long int conferencenum = strtol(argv[1], NULL, 10); long int conferencenum = strtol(argv[1], NULL, 10);
if ((conferencenum == 0 && strcmp(argv[1], "0")) || conferencenum < 0 || conferencenum == LONG_MAX) { if ((conferencenum == 0 && strcmp(argv[1], "0")) || conferencenum < 0 || conferencenum == LONG_MAX) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid conference number."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid conference number.");
return; return;
} }
Tox_Err_Conference_Invite err; Tox_Err_Conference_Invite err;
if (!tox_conference_invite(m, self->num, conferencenum, &err)) { if (!tox_conference_invite(m, self->num, conferencenum, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to conference (error %d)", err); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to invite contact to conference (error %d)", err);
return; return;
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invited contact to Conference %ld.", conferencenum); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invited contact to Conference %ld.", conferencenum);
} }
void cmd_conference_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_conference_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -113,7 +113,7 @@ void cmd_conference_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char
UNUSED_VAR(argv); UNUSED_VAR(argv);
if (get_num_active_windows() >= MAX_WINDOWS_NUM) { if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
return; return;
} }
@ -122,7 +122,7 @@ void cmd_conference_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char
uint8_t type = Friends.list[self->num].conference_invite.type; uint8_t type = Friends.list[self->num].conference_invite.type;
if (!Friends.list[self->num].conference_invite.pending) { if (!Friends.list[self->num].conference_invite.pending) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending conference invite."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending conference invite.");
return; return;
} }
@ -133,7 +133,7 @@ void cmd_conference_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char
conferencenum = tox_conference_join(m, self->num, (const uint8_t *) conferencekey, length, &err); conferencenum = tox_conference_join(m, self->num, (const uint8_t *) conferencekey, length, &err);
if (err != TOX_ERR_CONFERENCE_JOIN_OK) { if (err != TOX_ERR_CONFERENCE_JOIN_OK) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference instance failed to initialize (error %d)", err); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference instance failed to initialize (error %d)", err);
return; return;
} }
} else if (type == TOX_CONFERENCE_TYPE_AV) { } else if (type == TOX_CONFERENCE_TYPE_AV) {
@ -142,21 +142,21 @@ void cmd_conference_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char
audio_conference_callback, NULL); audio_conference_callback, NULL);
if (conferencenum == (uint32_t) -1) { if (conferencenum == (uint32_t) -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio conference instance failed to initialize"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio conference instance failed to initialize");
return; return;
} }
#else #else
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio support disabled by compile-time option."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio support disabled by compile-time option.");
return; return;
#endif #endif
} else { } else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Unknown conference type %d", type); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Unknown conference type %d", type);
return; return;
} }
if (init_conference_win(m, conferencenum, type, NULL, 0) == -1) { if (init_conference_win(m, conferencenum, type, NULL, 0) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference window failed to initialize."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference window failed to initialize.");
tox_conference_delete(m, conferencenum, NULL); tox_conference_delete(m, conferencenum, NULL);
return; return;
} }
@ -165,7 +165,7 @@ void cmd_conference_join(WINDOW *window, ToxWindow *self, Tox *m, int argc, char
if (type == TOX_CONFERENCE_TYPE_AV) { if (type == TOX_CONFERENCE_TYPE_AV) {
if (!init_conference_audio_input(m, conferencenum)) { if (!init_conference_audio_input(m, conferencenum)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio capture failed; use \"/audio on\" to try again."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio capture failed; use \"/audio on\" to try again.");
} }
} }
@ -177,26 +177,26 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
UNUSED_VAR(window); UNUSED_VAR(window);
if (argc < 1) { if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File ID required."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File ID required.");
return; return;
} }
long int idx = strtol(argv[1], NULL, 10); long int idx = strtol(argv[1], NULL, 10);
if ((idx == 0 && strcmp(argv[1], "0")) || idx < 0 || idx >= MAX_FILES) { if ((idx == 0 && strcmp(argv[1], "0")) || idx < 0 || idx >= MAX_FILES) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
return; return;
} }
struct FileTransfer *ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_RECV); struct FileTransfer *ft = get_file_transfer_struct_index(self->num, idx, FILE_TRANSFER_RECV);
if (!ft) { if (!ft) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
return; return;
} }
if (ft->state != FILE_TRANSFER_PENDING) { if (ft->state != FILE_TRANSFER_PENDING) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending file transfers with that ID.");
return; return;
} }
@ -213,12 +213,12 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
goto on_recv_error; goto on_recv_error;
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%ld] as: '%s'", idx, ft->file_path); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Saving file [%ld] as: '%s'", idx, ft->file_path);
/* prep progress bar line */ /* prep progress bar line */
char progline[MAX_STR_SIZE]; char progline[MAX_STR_SIZE];
init_progress_bar(progline); init_progress_bar(progline);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", progline); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", progline);
ft->line_id = self->chatwin->hst->line_end->id + 2; ft->line_id = self->chatwin->hst->line_end->id + 2;
ft->state = FILE_TRANSFER_STARTED; ft->state = FILE_TRANSFER_STARTED;
@ -229,23 +229,23 @@ on_recv_error:
switch (err) { switch (err) {
case TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND: case TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend not found."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend not found.");
return; return;
case TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED: case TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend is not online."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Friend is not online.");
return; return;
case TOX_ERR_FILE_CONTROL_NOT_FOUND: case TOX_ERR_FILE_CONTROL_NOT_FOUND:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Invalid filenumber."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Invalid filenumber.");
return; return;
case TOX_ERR_FILE_CONTROL_SENDQ: case TOX_ERR_FILE_CONTROL_SENDQ:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Connection error."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed: Connection error.");
return; return;
default: default:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed (error %d)\n", err); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File transfer failed (error %d)\n", err);
return; return;
} }
} }
@ -257,7 +257,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
const char *errmsg = NULL; const char *errmsg = NULL;
if (argc < 1) { if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path required."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File path required.");
return; return;
} }
@ -266,21 +266,21 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
int path_len = strlen(path); int path_len = strlen(path);
if (path_len >= MAX_STR_SIZE) { if (path_len >= MAX_STR_SIZE) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path exceeds character limit."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File path exceeds character limit.");
return; return;
} }
FILE *file_to_send = fopen(path, "r"); FILE *file_to_send = fopen(path, "r");
if (file_to_send == NULL) { if (file_to_send == NULL) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File not found."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "File not found.");
return; return;
} }
off_t filesize = file_size(path); off_t filesize = file_size(path);
if (filesize == 0) { if (filesize == 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid file."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid file.");
fclose(file_to_send); fclose(file_to_send);
return; return;
} }
@ -310,7 +310,7 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
char sizestr[32]; char sizestr[32];
bytes_convert_str(sizestr, sizeof(sizestr), filesize); bytes_convert_str(sizestr, sizeof(sizestr), filesize);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Sending file [%d]: '%s' (%s)", filenum, file_name, sizestr); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Sending file [%d]: '%s' (%s)", filenum, file_name, sizestr);
return; return;
@ -338,7 +338,7 @@ on_send_error:
break; break;
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", errmsg); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", errmsg);
tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_CANCEL, NULL); tox_file_control(m, self->num, filenum, TOX_FILE_CONTROL_CANCEL, NULL);
fclose(file_to_send); fclose(file_to_send);
} }

View File

@ -65,6 +65,9 @@
extern char *DATA_FILE; extern char *DATA_FILE;
#define MAX_CONFERENCE_NUM (MAX_WINDOWS_NUM - 2)
#define CONFERENCE_EVENT_WAIT 30
static ConferenceChat conferences[MAX_CONFERENCE_NUM]; static ConferenceChat conferences[MAX_CONFERENCE_NUM];
static int max_conference_index = 0; static int max_conference_index = 0;
@ -161,17 +164,17 @@ static void init_conference_logging(ToxWindow *self, Tox *m, uint32_t conference
tox_conference_get_id(m, conferencenum, (uint8_t *) conference_id); tox_conference_get_id(m, conferencenum, (uint8_t *) conference_id);
if (log_init(ctx->log, conferences[self->num].title, my_id, conference_id, LOG_TYPE_CHAT) != 0) { if (log_init(ctx->log, conferences[self->num].title, my_id, conference_id, LOG_TYPE_CHAT) != 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
return; return;
} }
if (load_chat_history(self, ctx->log) != 0) { if (load_chat_history(self, ctx->log) != 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to load chat history."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to load chat history.");
} }
if (user_settings->autolog == AUTOLOG_ON) { if (user_settings->autolog == AUTOLOG_ON) {
if (log_enable(ctx->log) != 0) { if (log_enable(ctx->log) != 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to enable chat log."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to enable chat log.");
} }
} }
@ -307,9 +310,9 @@ void redraw_conference_win(ToxWindow *self)
refresh(); refresh();
clear(); clear();
int x2, y2; int x2;
getmaxyx(stdscr, y2, x2); int y2;
y2 -= 2; getmaxyx(self->window, y2, x2);
if (y2 <= 0 || x2 <= 0) { if (y2 <= 0 || x2 <= 0) {
return; return;
@ -322,20 +325,22 @@ void redraw_conference_win(ToxWindow *self)
delwin(ctx->linewin); delwin(ctx->linewin);
delwin(ctx->history); delwin(ctx->history);
delwin(self->window_bar);
delwin(self->window); delwin(self->window);
self->window = newwin(y2, x2, 0, 0); self->window = newwin(y2, x2, 0, 0);
ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 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) { if (self->show_peerlist) {
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);
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);
} else { } 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); 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, 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 */ /* Only play sound if mentioned by someone else */
if (strcasestr(msg, selfnick) && strcmp(selfnick, nick)) { 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) { 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 { } 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; nick_clr = RED;
@ -375,10 +380,7 @@ static void conference_onConferenceMessage(ToxWindow *self, Tox *m, uint32_t con
sound_notify(self, silent, NT_WNDALERT_1, NULL); sound_notify(self, silent, NT_WNDALERT_1, NULL);
} }
char timefrmt[TIME_STR_SIZE]; line_info_add(self, true, nick, NULL, type == TOX_MESSAGE_TYPE_NORMAL ? IN_MSG : IN_ACTION, 0, nick_clr, "%s", msg);
get_time_str(timefrmt, sizeof(timefrmt));
line_info_add(self, timefrmt, nick, NULL, type == TOX_MESSAGE_TYPE_NORMAL ? IN_MSG : IN_ACTION, 0, nick_clr, "%s", msg);
write_to_log(msg, nick, ctx->log, false); write_to_log(msg, nick, ctx->log, false);
} }
@ -402,9 +404,6 @@ static void conference_onConferenceTitleChange(ToxWindow *self, Tox *m, uint32_t
conference_set_title(self, conferencenum, title, length); conference_set_title(self, conferencenum, title, length);
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
/* don't announce title when we join the room */ /* don't announce title when we join the room */
if (!timed_out(conferences[conferencenum].start_time, CONFERENCE_EVENT_WAIT)) { if (!timed_out(conferences[conferencenum].start_time, CONFERENCE_EVENT_WAIT)) {
return; return;
@ -412,7 +411,7 @@ static void conference_onConferenceTitleChange(ToxWindow *self, Tox *m, uint32_t
char nick[TOX_MAX_NAME_LENGTH]; char nick[TOX_MAX_NAME_LENGTH];
get_conference_nick_truncate(m, nick, peernum, conferencenum); get_conference_nick_truncate(m, nick, peernum, conferencenum);
line_info_add(self, timefrmt, nick, NULL, NAME_CHANGE, 0, 0, " set the conference title to: %s", title); line_info_add(self, true, nick, NULL, NAME_CHANGE, 0, 0, " set the conference title to: %s", title);
char tmp_event[MAX_STR_SIZE]; char tmp_event[MAX_STR_SIZE];
snprintf(tmp_event, sizeof(tmp_event), "set title to %s", title); snprintf(tmp_event, sizeof(tmp_event), "set title to %s", title);
@ -629,7 +628,10 @@ static bool find_peer_by_pubkey(const ConferencePeer *list, uint32_t num_peers,
const ConferencePeer *peer = &list[i]; const ConferencePeer *peer = &list[i];
if (peer->active && memcmp(peer->pubkey, pubkey, TOX_PUBLIC_KEY_SIZE) == 0) { if (peer->active && memcmp(peer->pubkey, pubkey, TOX_PUBLIC_KEY_SIZE) == 0) {
*idx = i; if (idx) {
*idx = i;
}
return true; return true;
} }
} }
@ -637,7 +639,8 @@ static bool find_peer_by_pubkey(const ConferencePeer *list, uint32_t num_peers,
return false; 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]; ConferenceChat *chat = &conferences[conferencenum];
@ -645,6 +648,8 @@ static void update_peer_list(Tox *m, uint32_t conferencenum, uint32_t num_peers,
return; return;
} }
ChatContext *ctx = self->chatwin;
ConferencePeer *old_peer_list = malloc(old_num_peers * sizeof(ConferencePeer)); ConferencePeer *old_peer_list = malloc(old_num_peers * sizeof(ConferencePeer));
if (!old_peer_list) { if (!old_peer_list) {
@ -676,12 +681,14 @@ static void update_peer_list(Tox *m, uint32_t conferencenum, uint32_t num_peers,
continue; continue;
} }
bool new_peer = true;
uint32_t j; uint32_t j;
if (find_peer_by_pubkey(old_peer_list, old_num_peers, peer->pubkey, &j)) { if (find_peer_by_pubkey(old_peer_list, old_num_peers, peer->pubkey, &j)) {
ConferencePeer *old_peer = &old_peer_list[j]; ConferencePeer *old_peer = &old_peer_list[j];
memcpy(peer, old_peer, sizeof(ConferencePeer)); memcpy(peer, old_peer, sizeof(ConferencePeer));
old_peer->active = false; old_peer->active = false;
new_peer = false;
} }
size_t length = tox_conference_peer_get_name_size(m, conferencenum, i, &err); size_t length = tox_conference_peer_get_name_size(m, conferencenum, i, &err);
@ -702,22 +709,34 @@ static void update_peer_list(Tox *m, uint32_t conferencenum, uint32_t num_peers,
peer->name_length = length; peer->name_length = length;
peer->peernum = i; peer->peernum = i;
if (new_peer && peer->name_length > 0 && timed_out(chat->start_time, CONFERENCE_EVENT_WAIT)) {
const char *msg = "has joined the conference";
line_info_add(self, true, peer->name, NULL, CONNECTION, 0, GREEN, msg);
write_to_log(msg, peer->name, ctx->log, true);
}
#ifdef AUDIO #ifdef AUDIO
set_peer_audio_position(m, conferencenum, i); set_peer_audio_position(m, conferencenum, i);
#endif #endif
} }
conference_update_name_list(conferencenum);
for (uint32_t i = 0; i < old_num_peers; ++i) { for (uint32_t i = 0; i < old_num_peers; ++i) {
ConferencePeer *old_peer = &old_peer_list[i]; ConferencePeer *old_peer = &old_peer_list[i];
if (old_peer->active) { if (old_peer->active) {
if (old_peer->name_length > 0 && !find_peer_by_pubkey(chat->peer_list, chat->num_peers, old_peer->pubkey, NULL)) {
const char *msg = "has left the conference";
line_info_add(self, true, old_peer->name, NULL, DISCONNECTION, 0, RED, msg);
write_to_log(msg, old_peer->name, ctx->log, true);
}
free_peer(old_peer); free_peer(old_peer);
} }
} }
free(old_peer_list); free(old_peer_list);
conference_update_name_list(conferencenum);
} }
static void conference_onConferenceNameListChange(ToxWindow *self, Tox *m, uint32_t conferencenum) static void conference_onConferenceNameListChange(ToxWindow *self, Tox *m, uint32_t conferencenum)
@ -749,7 +768,7 @@ static void conference_onConferenceNameListChange(ToxWindow *self, Tox *m, uint3
chat->num_peers = num_peers; chat->num_peers = num_peers;
chat->max_idx = 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, static void conference_onConferencePeerNameChange(ToxWindow *self, Tox *m, uint32_t conferencenum, uint32_t peernum,
@ -763,17 +782,22 @@ static void conference_onConferencePeerNameChange(ToxWindow *self, Tox *m, uint3
const ConferencePeer *peer = peer_in_conference(conferencenum, peernum); const ConferencePeer *peer = peer_in_conference(conferencenum, peernum);
if (peer != NULL && peer->name_length > 0) { if (peer != NULL) {
ChatContext *ctx = self->chatwin; ChatContext *ctx = self->chatwin;
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
char tmp_event[TOXIC_MAX_NAME_LENGTH * 2 + 32]; if (peer->name_length > 0) {
snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", (const char *) name); char log_event[TOXIC_MAX_NAME_LENGTH * 2 + 32];
line_info_add(self, true, peer->name, (const char *) name, NAME_CHANGE, 0, 0, " is now known as ");
write_to_log(tmp_event, peer->name, ctx->log, true); snprintf(log_event, sizeof(log_event), "is now known as %s", (const char *) name);
line_info_add(self, timefrmt, peer->name, (const char *) name, NAME_CHANGE, 0, 0, " is now known as "); write_to_log(log_event, peer->name, ctx->log, true);
// this is kind of a hack; peers always join a group with no name set and then set it after
} else if (timed_out(conferences[conferencenum].start_time, CONFERENCE_EVENT_WAIT)) {
const char *msg = "has joined the conference";
line_info_add(self, true, name, NULL, CONNECTION, 0, GREEN, msg);
write_to_log(msg, name, ctx->log, true);
}
} }
conference_onConferenceNameListChange(self, m, conferencenum); conference_onConferenceNameListChange(self, m, conferencenum);
@ -789,7 +813,7 @@ static void send_conference_action(ToxWindow *self, ChatContext *ctx, Tox *m, ch
Tox_Err_Conference_Send_Message err; Tox_Err_Conference_Send_Message err;
if (!tox_conference_send_message(m, self->num, TOX_MESSAGE_TYPE_ACTION, (uint8_t *) action, strlen(action), &err)) { if (!tox_conference_send_message(m, self->num, TOX_MESSAGE_TYPE_ACTION, (uint8_t *) action, strlen(action), &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send action (error %d)", err); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send action (error %d)", err);
} }
} }
@ -955,15 +979,15 @@ static bool conference_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
Tox_Err_Conference_Send_Message err; Tox_Err_Conference_Send_Message err;
if (!tox_conference_send_message(m, self->num, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *) line, strlen(line), &err)) { if (!tox_conference_send_message(m, self->num, TOX_MESSAGE_TYPE_NORMAL, (uint8_t *) line, strlen(line), &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send message (error %d)", err); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send message (error %d)", err);
} }
} else { } else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to parse message."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Failed to parse message.");
} }
} }
wclear(ctx->linewin); wclear(ctx->linewin);
wmove(self->window, y2 - CURS_Y_OFFSET, 0); wmove(self->window, y2, 0);
reset_buf(ctx); reset_buf(ctx);
} }
@ -1049,15 +1073,16 @@ static void conference_onDraw(ToxWindow *self, Tox *m)
curs_set(1); curs_set(1);
if (ctx->len > 0) { 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); wclear(ctx->sidebar);
mvwhline(self->window, y2 - CHATBOX_HEIGHT, 0, ACS_HLINE, x2);
if (self->show_peerlist) { if (self->show_peerlist) {
wattron(ctx->sidebar, COLOR_PAIR(BLUE));
mvwvline(ctx->sidebar, 0, 0, ACS_VLINE, y2 - CHATBOX_HEIGHT); mvwvline(ctx->sidebar, 0, 0, ACS_VLINE, y2 - CHATBOX_HEIGHT);
mvwaddch(ctx->sidebar, y2 - CHATBOX_HEIGHT, 0, ACS_BTEE); mvwaddch(ctx->sidebar, y2 - CHATBOX_HEIGHT, 0, ACS_BTEE);
wattroff(ctx->sidebar, COLOR_PAIR(BLUE));
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
const uint32_t num_peers = chat->num_peers; const uint32_t num_peers = chat->num_peers;
@ -1117,8 +1142,10 @@ static void conference_onDraw(ToxWindow *self, Tox *m)
wattroff(ctx->sidebar, A_BOLD); wattroff(ctx->sidebar, A_BOLD);
++line; ++line;
wattron(ctx->sidebar, COLOR_PAIR(BLUE));
mvwaddch(ctx->sidebar, line, 0, ACS_LTEE); mvwaddch(ctx->sidebar, line, 0, ACS_LTEE);
mvwhline(ctx->sidebar, line, 1, ACS_HLINE, SIDEBAR_WIDTH - 1); mvwhline(ctx->sidebar, line, 1, ACS_HLINE, SIDEBAR_WIDTH - 1);
wattroff(ctx->sidebar, COLOR_PAIR(BLUE));
++line; ++line;
for (uint32_t i = 0; for (uint32_t i = 0;
@ -1135,7 +1162,9 @@ static void conference_onDraw(ToxWindow *self, Tox *m)
UNUSED_VAR(x); UNUSED_VAR(x);
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos)); 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); wnoutrefresh(self->window);
@ -1155,9 +1184,10 @@ static void conference_onInit(ToxWindow *self, Tox *m)
ChatContext *ctx = self->chatwin; 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->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->hst = calloc(1, sizeof(struct history));
ctx->log = calloc(1, sizeof(struct chatlog)); ctx->log = calloc(1, sizeof(struct chatlog));

View File

@ -26,10 +26,8 @@
#include "toxic.h" #include "toxic.h"
#include "windows.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 CONFERENCE_MAX_TITLE_LENGTH TOX_MAX_NAME_LENGTH
#define SIDEBAR_WIDTH 16
typedef struct ConferencePeer { typedef struct ConferencePeer {
bool active; bool active;

View File

@ -32,7 +32,7 @@
static void print_err(ToxWindow *self, const char *error_str) static void print_err(ToxWindow *self, const char *error_str)
{ {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str);
} }
void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -56,7 +56,7 @@ void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc,
} }
title[tlen] = '\0'; title[tlen] = '\0';
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Title is set to: %s", title); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Title is set to: %s", title);
return; return;
} }
@ -64,14 +64,14 @@ void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc,
size_t len = strlen(argv[1]); size_t len = strlen(argv[1]);
if (len >= sizeof(title)) { if (len >= sizeof(title)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title: max length exceeded."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title: max length exceeded.");
return; return;
} }
snprintf(title, sizeof(title), "%s", argv[1]); snprintf(title, sizeof(title), "%s", argv[1]);
if (!tox_conference_set_title(m, self->num, (uint8_t *) title, len, &err)) { if (!tox_conference_set_title(m, self->num, (uint8_t *) title, len, &err)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title (error %d)", err); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title (error %d)", err);
return; return;
} }
@ -79,16 +79,13 @@ void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc,
conference_set_title(self, self->num, title, len); conference_set_title(self, self->num, title, len);
char timefrmt[TIME_STR_SIZE];
char selfnick[TOX_MAX_NAME_LENGTH]; char selfnick[TOX_MAX_NAME_LENGTH];
get_time_str(timefrmt, sizeof(timefrmt));
tox_self_get_name(m, (uint8_t *) selfnick); tox_self_get_name(m, (uint8_t *) selfnick);
size_t sn_len = tox_self_get_name_size(m); size_t sn_len = tox_self_get_name_size(m);
selfnick[sn_len] = '\0'; selfnick[sn_len] = '\0';
line_info_add(self, timefrmt, selfnick, NULL, NAME_CHANGE, 0, 0, " set the conference title to: %s", title); line_info_add(self, true, selfnick, NULL, NAME_CHANGE, 0, 0, " set the conference title to: %s", title);
char tmp_event[MAX_STR_SIZE + 20]; char tmp_event[MAX_STR_SIZE + 20];
snprintf(tmp_event, sizeof(tmp_event), "set title to %s", title); snprintf(tmp_event, sizeof(tmp_event), "set title to %s", title);
@ -142,14 +139,14 @@ void cmd_conference_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char
print_err(self, "Multiple matching peers (use /mute [public key] to disambiguate):"); print_err(self, "Multiple matching peers (use /mute [public key] to disambiguate):");
for (uint32_t i = 0; i < n; ++i) { for (uint32_t i = 0; i < n; ++i) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s: %s", entries[i]->pubkey_str, entries[i]->name); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s: %s", entries[i]->pubkey_str, entries[i]->name);
} }
return; return;
} }
if (conference_mute_peer(m, self->num, entries[0]->peernum)) { if (conference_mute_peer(m, self->num, entries[0]->peernum)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Toggled audio mute status of %s", entries[0]->name); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Toggled audio mute status of %s", entries[0]->name);
} else { } else {
print_err(self, "Peer is not on the call"); print_err(self, "Peer is not on the call");
} }
@ -162,7 +159,7 @@ void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, cha
UNUSED_VAR(m); UNUSED_VAR(m);
if (argc == 0) { if (argc == 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Current VAD threshold: %.1f", line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Current VAD threshold: %.1f",
(double) conference_get_VAD_threshold(self->num)); (double) conference_get_VAD_threshold(self->num));
return; return;
} }
@ -181,7 +178,7 @@ void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, cha
} }
if (conference_set_VAD_threshold(self->num, value)) { if (conference_set_VAD_threshold(self->num, value)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Set VAD threshold to %.1f", (double) value); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Set VAD threshold to %.1f", (double) value);
} else { } else {
print_err(self, "Failed to set conference audio input sensitivity."); print_err(self, "Failed to set conference audio input sensitivity.");
} }

View File

@ -271,5 +271,5 @@ void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
#endif #endif
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid command."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid command.");
} }

View File

@ -274,7 +274,7 @@ void close_file_transfer(ToxWindow *self, Tox *m, struct FileTransfer *ft, int C
box_notify(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", message); box_notify(self, sound_type, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", message);
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", message); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", message);
} }
clear_file_transfer(ft); clear_file_transfer(ft);

View File

@ -397,11 +397,8 @@ static void friendlist_onMessage(ToxWindow *self, Tox *m, uint32_t num, Tox_Mess
char nick[TOX_MAX_NAME_LENGTH]; char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num); get_nick_truncate(m, nick, num);
char timefrmt[TIME_STR_SIZE]; line_info_add(prompt, true, nick, NULL, IN_MSG, 0, 0, "%s", str);
get_time_str(timefrmt, sizeof(timefrmt)); line_info_add(prompt, false, NULL, NULL, SYS_MSG, 0, RED, "* Warning: Too many windows are open.");
line_info_add(prompt, timefrmt, nick, NULL, IN_MSG, 0, 0, "%s", str);
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "* Warning: Too many windows are open.");
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL); sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
} }
@ -611,7 +608,7 @@ static void friendlist_onFileRecv(ToxWindow *self, Tox *m, uint32_t num, uint32_
char nick[TOX_MAX_NAME_LENGTH]; char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num); get_nick_truncate(m, nick, num);
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, line_info_add(prompt, false, NULL, NULL, SYS_MSG, 0, RED,
"* File transfer from %s failed: too many windows are open.", nick); "* File transfer from %s failed: too many windows are open.", nick);
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL); sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
@ -642,7 +639,7 @@ static void friendlist_onConferenceInvite(ToxWindow *self, Tox *m, int32_t num,
char nick[TOX_MAX_NAME_LENGTH]; char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, num); get_nick_truncate(m, nick, num);
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, line_info_add(prompt, false, NULL, NULL, SYS_MSG, 0, RED,
"* Conference chat invite from %s failed: too many windows are open.", nick); "* Conference chat invite from %s failed: too many windows are open.", nick);
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL); sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
@ -854,7 +851,7 @@ static void unblock_friend(Tox *m, uint32_t bnum)
uint32_t friendnum = tox_friend_add_norequest(m, (uint8_t *) Blocked.list[bnum].pub_key, &err); uint32_t friendnum = tox_friend_add_norequest(m, (uint8_t *) Blocked.list[bnum].pub_key, &err);
if (err != TOX_ERR_FRIEND_ADD_OK) { if (err != TOX_ERR_FRIEND_ADD_OK) {
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to unblock friend (error %d)", err); line_info_add(prompt, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to unblock friend (error %d)", err);
return; return;
} }
@ -923,7 +920,7 @@ static bool friendlist_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
set_active_window_index(Friends.list[f].chatwin); set_active_window_index(Friends.list[f].chatwin);
} else { } else {
const char *msg = "* Warning: Too many windows are open."; const char *msg = "* Warning: Too many windows are open.";
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, msg); line_info_add(prompt, false, NULL, NULL, SYS_MSG, 0, RED, msg);
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL); sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
} }
@ -1022,7 +1019,7 @@ static void blocklist_onDraw(ToxWindow *self, Tox *m, int y2, int x2)
wmove(self->window, y2 - 1, 1); wmove(self->window, y2 - 1, 1);
wattron(self->window, A_BOLD); wattron(self->window, A_BOLD);
wprintw(self->window, "Key: "); wprintw(self->window, "Public key: ");
wattroff(self->window, A_BOLD); wattroff(self->window, A_BOLD);
int i; int i;
@ -1057,6 +1054,8 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wprintw(self->window, "key for help\n\n"); wprintw(self->window, "key for help\n\n");
wattroff(self->window, COLOR_PAIR(CYAN)); wattroff(self->window, COLOR_PAIR(CYAN));
draw_window_bar(self);
if (blocklist_view == 1) { if (blocklist_view == 1) {
blocklist_onDraw(self, m, y2, x2); blocklist_onDraw(self, m, y2, x2);
return; return;
@ -1098,9 +1097,9 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
int num_selected = Friends.num_selected; int num_selected = Friends.num_selected;
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
bool f_selected = false;
if (is_active) { if (is_active) {
bool f_selected = false;
if (i == num_selected) { if (i == num_selected) {
wattron(self->window, A_BOLD); wattron(self->window, A_BOLD);
wprintw(self->window, " > "); wprintw(self->window, " > ");
@ -1247,7 +1246,7 @@ static void friendlist_onDraw(ToxWindow *self, Tox *m)
wmove(self->window, y2 - 1, 1); wmove(self->window, y2 - 1, 1);
wattron(self->window, A_BOLD); wattron(self->window, A_BOLD);
wprintw(self->window, "Key: "); wprintw(self->window, "Public key: ");
wattroff(self->window, A_BOLD); wattroff(self->window, A_BOLD);
int i; int i;
@ -1265,6 +1264,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) void disable_chatwin(uint32_t f_num)
{ {
Friends.list[f_num].chatwin = -1; Friends.list[f_num].chatwin = -1;
@ -1290,10 +1304,10 @@ static void friendlist_onAV(ToxWindow *self, ToxAV *av, uint32_t friend_number,
} else { } else {
char nick[TOX_MAX_NAME_LENGTH]; char nick[TOX_MAX_NAME_LENGTH];
get_nick_truncate(m, nick, Friends.list[friend_number].num); get_nick_truncate(m, nick, Friends.list[friend_number].num);
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio action from: %s!", nick); line_info_add(prompt, false, NULL, NULL, SYS_MSG, 0, 0, "Audio action from: %s!", nick);
const char *errmsg = "* Warning: Too many windows are open."; const char *errmsg = "* Warning: Too many windows are open.";
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg); line_info_add(prompt, false, NULL, NULL, SYS_MSG, 0, RED, errmsg);
sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL); sound_notify(prompt, notif_error, NT_WNDALERT_1, NULL);
} }
@ -1343,6 +1357,7 @@ ToxWindow *new_friendlist(void)
ret->type = WINDOW_TYPE_FRIEND_LIST; ret->type = WINDOW_TYPE_FRIEND_LIST;
ret->onInit = &friendlist_onInit;
ret->onKey = &friendlist_onKey; ret->onKey = &friendlist_onKey;
ret->onDraw = &friendlist_onDraw; ret->onDraw = &friendlist_onDraw;
ret->onFriendAdded = &friendlist_onFriendAdded; ret->onFriendAdded = &friendlist_onFriendAdded;

View File

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

View File

@ -49,19 +49,19 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
UNUSED_VAR(window); UNUSED_VAR(window);
if (argc < 1) { if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Request ID required."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Request ID required.");
return; return;
} }
long int req = strtol(argv[1], NULL, 10); long int req = strtol(argv[1], NULL, 10);
if ((req == 0 && strcmp(argv[1], "0")) || req < 0 || req >= MAX_FRIEND_REQUESTS) { if ((req == 0 && strcmp(argv[1], "0")) || req < 0 || req >= MAX_FRIEND_REQUESTS) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
return; return;
} }
if (!FrndRequests.request[req].active) { if (!FrndRequests.request[req].active) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
return; return;
} }
@ -69,10 +69,10 @@ void cmd_accept(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
uint32_t friendnum = tox_friend_add_norequest(m, FrndRequests.request[req].key, &err); uint32_t friendnum = tox_friend_add_norequest(m, FrndRequests.request[req].key, &err);
if (err != TOX_ERR_FRIEND_ADD_OK) { if (err != TOX_ERR_FRIEND_ADD_OK) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to add friend (error %d\n)", err); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to add friend (error %d\n)", err);
return; return;
} else { } else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Friend request accepted."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Friend request accepted.");
on_friend_added(m, friendnum, true); on_friend_added(m, friendnum, true);
} }
@ -141,7 +141,7 @@ void cmd_add_helper(ToxWindow *self, Tox *m, const char *id_bin, const char *msg
break; break;
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, errmsg);
} }
void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -149,7 +149,7 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
UNUSED_VAR(window); UNUSED_VAR(window);
if (argc < 1) { if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Tox ID or address required."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Tox ID or address required.");
return; return;
} }
@ -158,7 +158,7 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
if (argc > 1) { if (argc > 1) {
if (argv[2][0] != '\"') { if (argv[2][0] != '\"') {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Message must be enclosed in quotes."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Message must be enclosed in quotes.");
return; return;
} }
@ -192,7 +192,7 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
xx[2] = '\0'; xx[2] = '\0';
if (sscanf(xx, "%02x", &x) != 1) { if (sscanf(xx, "%02x", &x) != 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid Tox ID."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid Tox ID.");
return; return;
} }
@ -200,7 +200,7 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
} }
if (friend_is_blocked(id_bin)) { if (friend_is_blocked(id_bin)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Friend is in your block list."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Friend is in your block list.");
return; return;
} }
@ -216,7 +216,7 @@ void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
if (argc != 1 || strlen(argv[1]) < 3) { if (argc != 1 || strlen(argv[1]) < 3) {
avatar_unset(m); avatar_unset(m);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Avatar has been unset."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Avatar has been unset.");
return; return;
} }
@ -225,7 +225,7 @@ void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
int len = strlen(path); int len = strlen(path);
if (len <= 0) { if (len <= 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid path."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid path.");
return; return;
} }
@ -234,13 +234,13 @@ void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
get_file_name(filename, sizeof(filename), path); get_file_name(filename, sizeof(filename), path);
if (avatar_set(m, path, len) == -1) { if (avatar_set(m, path, len) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,
"Failed to set avatar. Avatars must be in PNG format and may not exceed %d bytes.", "Failed to set avatar. Avatars must be in PNG format and may not exceed %d bytes.",
MAX_AVATAR_FILE_SIZE); MAX_AVATAR_FILE_SIZE);
return; return;
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Avatar set to '%s'", filename); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Avatar set to '%s'", filename);
} }
void cmd_clear(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_clear(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -258,7 +258,7 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
UNUSED_VAR(window); UNUSED_VAR(window);
if (argc != 3) { if (argc != 3) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Require: <ip> <port> <key>"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Require: <ip> <port> <key>");
return; return;
} }
@ -269,14 +269,14 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
long int port = strtol(port_str, NULL, 10); long int port = strtol(port_str, NULL, 10);
if (port <= 0 || port > MAX_PORT_RANGE) { if (port <= 0 || port > MAX_PORT_RANGE) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid port."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid port.");
return; return;
} }
char key_binary[TOX_PUBLIC_KEY_SIZE * 2 + 1]; char key_binary[TOX_PUBLIC_KEY_SIZE * 2 + 1];
if (hex_string_to_bin(ascii_key, strlen(ascii_key), key_binary, TOX_PUBLIC_KEY_SIZE) == -1) { if (hex_string_to_bin(ascii_key, strlen(ascii_key), key_binary, TOX_PUBLIC_KEY_SIZE) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid key."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid key.");
return; return;
} }
@ -286,15 +286,15 @@ void cmd_connect(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
switch (err) { switch (err) {
case TOX_ERR_BOOTSTRAP_BAD_HOST: case TOX_ERR_BOOTSTRAP_BAD_HOST:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed: Invalid IP."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed: Invalid IP.");
break; break;
case TOX_ERR_BOOTSTRAP_BAD_PORT: case TOX_ERR_BOOTSTRAP_BAD_PORT:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed: Invalid port."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed: Invalid port.");
break; break;
case TOX_ERR_BOOTSTRAP_NULL: case TOX_ERR_BOOTSTRAP_NULL:
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Bootstrap failed.");
break; break;
default: default:
@ -308,19 +308,19 @@ void cmd_decline(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)
UNUSED_VAR(m); UNUSED_VAR(m);
if (argc < 1) { if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Request ID required."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Request ID required.");
return; return;
} }
long int req = strtol(argv[1], NULL, 10); long int req = strtol(argv[1], NULL, 10);
if ((req == 0 && strcmp(argv[1], "0")) || req < 0 || req >= MAX_FRIEND_REQUESTS) { if ((req == 0 && strcmp(argv[1], "0")) || req < 0 || req >= MAX_FRIEND_REQUESTS) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
return; return;
} }
if (!FrndRequests.request[req].active) { if (!FrndRequests.request[req].active) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending friend request with that ID.");
return; return;
} }
@ -345,12 +345,12 @@ void cmd_conference(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
UNUSED_VAR(window); UNUSED_VAR(window);
if (get_num_active_windows() >= MAX_WINDOWS_NUM) { if (get_num_active_windows() >= MAX_WINDOWS_NUM) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Warning: Too many windows are open.");
return; return;
} }
if (argc < 1) { if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Please specify conference type: text | audio"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Please specify conference type: text | audio");
return; return;
} }
@ -361,7 +361,7 @@ void cmd_conference(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
} else if (!strcasecmp(argv[1], "text")) { } else if (!strcasecmp(argv[1], "text")) {
type = TOX_CONFERENCE_TYPE_TEXT; type = TOX_CONFERENCE_TYPE_TEXT;
} else { } else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Valid conference types are: text | audio"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Valid conference types are: text | audio");
return; return;
} }
@ -373,7 +373,7 @@ void cmd_conference(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
conferencenum = tox_conference_new(m, &err); conferencenum = tox_conference_new(m, &err);
if (err != TOX_ERR_CONFERENCE_NEW_OK) { if (err != TOX_ERR_CONFERENCE_NEW_OK) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference instance failed to initialize (error %d)", err); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference instance failed to initialize (error %d)", err);
return; return;
} }
} else if (type == TOX_CONFERENCE_TYPE_AV) { } else if (type == TOX_CONFERENCE_TYPE_AV) {
@ -381,18 +381,18 @@ void cmd_conference(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
conferencenum = toxav_add_av_groupchat(m, audio_conference_callback, NULL); conferencenum = toxav_add_av_groupchat(m, audio_conference_callback, NULL);
if (conferencenum == (uint32_t) -1) { if (conferencenum == (uint32_t) -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio conference instance failed to initialize"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio conference instance failed to initialize");
return; return;
} }
#else #else
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio support disabled by compile-time option."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio support disabled by compile-time option.");
return; return;
#endif #endif
} }
if (init_conference_win(m, conferencenum, type, NULL, 0) == -1) { if (init_conference_win(m, conferencenum, type, NULL, 0) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference window failed to initialize."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference window failed to initialize.");
tox_conference_delete(m, conferencenum, NULL); tox_conference_delete(m, conferencenum, NULL);
return; return;
} }
@ -401,13 +401,13 @@ void cmd_conference(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*ar
if (type == TOX_CONFERENCE_TYPE_AV) { if (type == TOX_CONFERENCE_TYPE_AV) {
if (!init_conference_audio_input(m, conferencenum)) { if (!init_conference_audio_input(m, conferencenum)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Audio capture failed; use \"/audio on\" to try again."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Audio capture failed; use \"/audio on\" to try again.");
} }
} }
#endif #endif
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Conference [%d] created.", conferencenum); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Conference [%d] created.", conferencenum);
} }
void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -424,7 +424,7 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
msg = "Logging for this window is OFF; type \"/log on\" to enable."; msg = "Logging for this window is OFF; type \"/log on\" to enable.";
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, msg);
return; return;
} }
@ -432,7 +432,7 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
if (!strcmp(swch, "1") || !strcmp(swch, "on")) { if (!strcmp(swch, "1") || !strcmp(swch, "on")) {
msg = log_enable(log) == 0 ? "Logging enabled." : "Warning: Failed to enable log."; msg = log_enable(log) == 0 ? "Logging enabled." : "Warning: Failed to enable log.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, msg);
return; return;
} else if (!strcmp(swch, "0") || !strcmp(swch, "off")) { } else if (!strcmp(swch, "0") || !strcmp(swch, "off")) {
if (self->type == WINDOW_TYPE_CHAT) { if (self->type == WINDOW_TYPE_CHAT) {
@ -442,12 +442,12 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
log_disable(log); log_disable(log);
msg = "Logging disabled."; msg = "Logging disabled.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, msg);
return; return;
} }
msg = "Invalid option. Use \"/log on\" and \"/log off\" to toggle logging."; msg = "Invalid option. Use \"/log on\" and \"/log off\" to toggle logging.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, msg);
} }
void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
@ -461,11 +461,11 @@ void cmd_myid(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
tox_self_get_address(m, (uint8_t *) bin_id); tox_self_get_address(m, (uint8_t *) bin_id);
if (bin_id_to_string(bin_id, sizeof(bin_id), id_string, sizeof(id_string)) == -1) { if (bin_id_to_string(bin_id, sizeof(bin_id), id_string, sizeof(id_string)) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to print ID."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to print ID.");
return; return;
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", id_string); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", id_string);
} }
#ifdef QRCODE #ifdef QRCODE
@ -478,7 +478,7 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
tox_self_get_address(m, (uint8_t *) bin_id); tox_self_get_address(m, (uint8_t *) bin_id);
if (bin_id_to_string(bin_id, sizeof(bin_id), id_string, sizeof(id_string)) == -1) { if (bin_id_to_string(bin_id, sizeof(bin_id), id_string, sizeof(id_string)) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
return; return;
} }
@ -491,7 +491,7 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
char *dir = malloc(data_file_len + 1); char *dir = malloc(data_file_len + 1);
if (dir == NULL) { if (dir == NULL) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory.");
return; return;
} }
@ -500,7 +500,7 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
#ifdef QRPNG #ifdef QRPNG
if (argc == 0) { if (argc == 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Required 'txt' or 'png'"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Required 'txt' or 'png'");
free(dir); free(dir);
return; return;
} else if (!strcmp(argv[1], "txt")) { } else if (!strcmp(argv[1], "txt")) {
@ -510,7 +510,7 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
char *qr_path = malloc(qr_path_buf_size); char *qr_path = malloc(qr_path_buf_size);
if (qr_path == NULL) { if (qr_path == NULL) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory");
free(dir); free(dir);
return; return;
} }
@ -518,13 +518,13 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
snprintf(qr_path, qr_path_buf_size, "%s%s%s", dir, nick, QRCODE_FILENAME_EXT); snprintf(qr_path, qr_path_buf_size, "%s%s%s", dir, nick, QRCODE_FILENAME_EXT);
if (ID_to_QRcode_txt(id_string, qr_path) == -1) { if (ID_to_QRcode_txt(id_string, qr_path) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
free(dir); free(dir);
free(qr_path); free(qr_path);
return; return;
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
free(qr_path); free(qr_path);
@ -534,7 +534,7 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
char *qr_path = malloc(qr_path_buf_size); char *qr_path = malloc(qr_path_buf_size);
if (qr_path == NULL) { if (qr_path == NULL) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code: Out of memory");
free(dir); free(dir);
return; return;
} }
@ -542,18 +542,18 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
snprintf(qr_path, qr_path_buf_size, "%s%s%s", dir, nick, QRCODE_FILENAME_EXT_PNG); snprintf(qr_path, qr_path_buf_size, "%s%s%s", dir, nick, QRCODE_FILENAME_EXT_PNG);
if (ID_to_QRcode_png(id_string, qr_path) == -1) { if (ID_to_QRcode_png(id_string, qr_path) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to create QR code.");
free(dir); free(dir);
free(qr_path); free(qr_path);
return; return;
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "QR code has been printed to the file '%s'", qr_path);
free(qr_path); free(qr_path);
} else { } else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Unknown option '%s' -- Required 'txt' or 'png'", argv[1]); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Unknown option '%s' -- Required 'txt' or 'png'", argv[1]);
free(dir); free(dir);
return; return;
} }
@ -569,7 +569,7 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
UNUSED_VAR(window); UNUSED_VAR(window);
if (argc < 1) { if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Input required."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Input required.");
return; return;
} }
@ -578,7 +578,7 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
size_t len = strlen(nick); size_t len = strlen(nick);
if (!valid_nick(nick)) { if (!valid_nick(nick)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid name."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid name.");
return; return;
} }
@ -596,7 +596,7 @@ void cmd_note(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
UNUSED_VAR(window); UNUSED_VAR(window);
if (argc < 1) { if (argc < 1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Input required."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Input required.");
return; return;
} }
@ -611,7 +611,7 @@ void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
nospam = strtol(argv[1], NULL, 16); nospam = strtol(argv[1], NULL, 16);
if ((nospam == 0 && strcmp(argv[1], "0")) || nospam < 0) { if ((nospam == 0 && strcmp(argv[1], "0")) || nospam < 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid nospam value."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid nospam value.");
return; return;
} }
} }
@ -619,12 +619,12 @@ void cmd_nospam(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
uint32_t old_nospam = tox_self_get_nospam(m); uint32_t old_nospam = tox_self_get_nospam(m);
tox_self_set_nospam(m, (uint32_t) nospam); tox_self_set_nospam(m, (uint32_t) nospam);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your new Tox ID is:"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Your new Tox ID is:");
cmd_myid(window, self, m, 0, NULL); cmd_myid(window, self, m, 0, NULL);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "");
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,
"Any services that relied on your old ID will need to be updated manually."); "Any services that relied on your old ID will need to be updated manually.");
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "If you ever want your old Tox ID back, type '/nospam %X'", line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "If you ever want your old Tox ID back, type '/nospam %X'",
old_nospam); old_nospam);
} }
@ -656,7 +656,7 @@ void cmd_requests(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
UNUSED_VAR(argv); UNUSED_VAR(argv);
if (FrndRequests.num_requests == 0) { if (FrndRequests.num_requests == 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "No pending friend requests."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "No pending friend requests.");
return; return;
} }
@ -676,11 +676,11 @@ void cmd_requests(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv
strcat(id, d); strcat(id, d);
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%d : %s", i, id); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%d : %s", i, id);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", FrndRequests.request[i].msg); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", FrndRequests.request[i].msg);
if (++count < FrndRequests.num_requests) { if (++count < FrndRequests.num_requests) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "");
} }
} }
} }
@ -695,7 +695,7 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
if (argc < 1) { if (argc < 1) {
errmsg = "Require a status. Statuses are: online, busy and away."; errmsg = "Require a status. Statuses are: online, busy and away.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, errmsg);
goto finish; goto finish;
} }
@ -710,13 +710,13 @@ void cmd_status(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[
status = TOX_USER_STATUS_BUSY; status = TOX_USER_STATUS_BUSY;
} else { } else {
errmsg = "Invalid status. Valid statuses are: online, busy and away."; errmsg = "Invalid status. Valid statuses are: online, busy and away.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, errmsg);
goto finish; goto finish;
} }
tox_self_set_status(m, status); tox_self_set_status(m, status);
prompt_update_status(prompt, status); prompt_update_status(prompt, status);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Your status has been changed to %s.", status_str); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Your status has been changed to %s.", status_str);
finish: finish:

View File

@ -54,7 +54,7 @@ void line_info_reset_start(ToxWindow *self, struct history *hst)
{ {
struct line_info *line = hst->line_end; struct line_info *line = hst->line_end;
if (line->prev == NULL) { if (line == NULL || line->prev == NULL) {
return; return;
} }
@ -63,10 +63,10 @@ void line_info_reset_start(ToxWindow *self, struct history *hst)
getmaxyx(self->window, y2, x2); getmaxyx(self->window, y2, x2);
UNUSED_VAR(x2); UNUSED_VAR(x2);
int top_offst = (self->type == WINDOW_TYPE_CHAT) || (self->type == WINDOW_TYPE_PROMPT) ? 2 : 0; int top_offst = (self->type == WINDOW_TYPE_CHAT) || (self->type == WINDOW_TYPE_PROMPT) ? TOP_BAR_HEIGHT : 0;
int max_y = y2 - CHATBOX_HEIGHT - top_offst; int max_y = y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT - top_offst;
int curlines = 0; uint16_t curlines = 0;
do { do {
curlines += line->format_lines; 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); } while (line->prev && curlines + line->format_lines <= max_y);
hst->line_start = line; hst->line_start = line;
self->scroll_pause = false;
} }
void line_info_cleanup(struct history *hst) 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`. /* 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; bool newline = false;
char ch; char ch;
for (size_t i = 0; i < n && (ch = s[i]); ++i) { for (size_t i = 0; i < n && (ch = s[i]); ++i) {
if (win) {
wprintw(win, "%c", ch);
}
if (ch == '\n') { if (ch == '\n') {
newline = true; 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 * If `win` is null nothing will be printed to the window. This is useful to set the
* `format_lines` field on initialization. * `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; const char *msg = line->msg;
uint16_t length = line->msg_len; uint16_t length = line->msg_len;
uint16_t lines = 0; uint16_t lines = 0;
const int x_start = line->len - line->msg_len - 1; // manually keep track of x position because ncurses sucks 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; 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); fprintf(stderr, "Warning: x_limit <= 0 in print_wrap(): %d\n", x_limit);
return; return -1;
} }
while (msg) { 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 (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); lines += newline_count(msg);
} else if (p_ret == -1) {
return -1;
} }
++lines; ++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); int newline_idx = newline_index(msg, x_limit - 1);
if (newline_idx >= 0) { if (newline_idx >= 0) {
print_n_chars(win, msg, newline_idx + 1); if (print_n_chars(win, msg, newline_idx + 1, max_y) == -1) {
msg += newline_idx + 1; return -1;
}
msg += (newline_idx + 1);
length -= (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 x_limit = max_x; // if we find a newline we stop adding column padding for rest of message
++lines; ++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); int space_idx = rspace_index(msg, x_limit - 1);
if (space_idx >= 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; msg += space_idx + 1;
length -= (space_idx + 1); length -= (space_idx + 1);
waddch(win, '\n');
if (win) {
waddch(win, '\n');
}
} else { } else {
print_n_chars(win, msg, x_limit); if (print_n_chars(win, msg, x_limit, max_y) == -1) {
return -1;
}
msg += x_limit; msg += x_limit;
length -= 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) { if (win && line->noread_flag) {
int x;
int y;
UNUSED_VAR(y);
getyx(win, y, x); getyx(win, y, x);
if (x >= max_x - 1 || x == x_start) { 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; 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 y2;
int max_x; int x2;
UNUSED_VAR(max_y); 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. /* creates new line_info line and puts it in the queue.
@ -294,7 +339,7 @@ static void line_info_init_line(WINDOW *win, struct line_info *line)
* Returns the id of the new line. * Returns the id of the new line.
* Returns -1 on failure. * Returns -1 on failure.
*/ */
int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type, int line_info_add(ToxWindow *self, bool show_timestamp, const char *name1, const char *name2, LINE_TYPE type,
uint8_t bold, uint8_t colour, const char *msg, ...) uint8_t bold, uint8_t colour, const char *msg, ...)
{ {
if (!self) { if (!self) {
@ -329,33 +374,33 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
/* fallthrough */ /* fallthrough */
case OUT_ACTION: case OUT_ACTION:
len += strlen(user_settings->line_normal) + 2; len += strlen(user_settings->line_normal) + 2; // two spaces
break; break;
case IN_MSG: case IN_MSG:
/* fallthrough */ /* fallthrough */
case OUT_MSG: case OUT_MSG:
len += strlen(user_settings->line_normal) + 3; len += strlen(user_settings->line_normal) + 3; // two spaces and a ':' char
break; break;
case CONNECTION: case CONNECTION:
len += strlen(user_settings->line_join) + 2; len += strlen(user_settings->line_join) + 2; // two spaces
break; break;
case DISCONNECTION: case DISCONNECTION:
len += strlen(user_settings->line_quit) + 2; len += strlen(user_settings->line_quit) + 2; // two spaces
break; break;
case SYS_MSG: case SYS_MSG:
break; break;
case NAME_CHANGE: case NAME_CHANGE:
len += strlen(user_settings->line_alert) + 1; len += strlen(user_settings->line_alert) + 2; // two spaces
break; break;
case PROMPT: case PROMPT:
++len; len += 2; // '$' char and a space
break; break;
default: default:
@ -371,8 +416,8 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
len += msg_len; len += msg_len;
} }
if (timestr) { if (show_timestamp) {
snprintf(new_line->timestr, sizeof(new_line->timestr), "%s", timestr); get_time_str(new_line->timestr, sizeof(new_line->timestr));
len += strlen(new_line->timestr) + 1; len += strlen(new_line->timestr) + 1;
} }
@ -395,7 +440,7 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
new_line->noread_flag = false; new_line->noread_flag = false;
new_line->timestamp = get_unix_time(); 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; 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 = line;
hst->line_end->id = line->id; hst->line_end->id = line->id;
int y; if (!self->scroll_pause) {
int y2; line_info_reset_start(self, hst);
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;
}
} }
} }
@ -479,16 +503,31 @@ void line_info_print(ToxWindow *self)
if (self->type == WINDOW_TYPE_CONFERENCE) { if (self->type == WINDOW_TYPE_CONFERENCE) {
wmove(win, 0, 0); wmove(win, 0, 0);
} else { } else {
wmove(win, 2, 0); wmove(win, TOP_BAR_HEIGHT, 0);
} }
struct line_info *line = hst->line_start->next; 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; 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; uint8_t type = line->type;
switch (type) { switch (type) {
@ -526,7 +565,7 @@ void line_info_print(ToxWindow *self)
wattron(win, COLOR_PAIR(RED)); 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] == '>') { if (line->msg[0] == '>') {
wattroff(win, COLOR_PAIR(GREEN)); wattroff(win, COLOR_PAIR(GREEN));
@ -556,7 +595,7 @@ void line_info_print(ToxWindow *self)
wattron(win, COLOR_PAIR(YELLOW)); wattron(win, COLOR_PAIR(YELLOW));
wprintw(win, "%s %s ", user_settings->line_normal, line->name1); 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)); wattroff(win, COLOR_PAIR(YELLOW));
if (type == OUT_ACTION && !line->read_flag) { if (type == OUT_ACTION && !line->read_flag) {
@ -583,7 +622,7 @@ void line_info_print(ToxWindow *self)
wattron(win, COLOR_PAIR(line->colour)); 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'); waddch(win, '\n');
if (line->bold) { if (line->bold) {
@ -602,7 +641,7 @@ void line_info_print(ToxWindow *self)
wattroff(win, COLOR_PAIR(GREEN)); wattroff(win, COLOR_PAIR(GREEN));
if (line->msg[0]) { if (line->msg[0]) {
print_wrap(win, line, max_x); print_ret = print_wrap(win, line, max_x, max_y);
} }
waddch(win, '\n'); waddch(win, '\n');
@ -620,7 +659,7 @@ void line_info_print(ToxWindow *self)
wprintw(win, "%s ", line->name1); wprintw(win, "%s ", line->name1);
wattroff(win, A_BOLD); wattroff(win, A_BOLD);
print_wrap(win, line, max_x); print_ret = print_wrap(win, line, max_x, max_y);
waddch(win, '\n'); waddch(win, '\n');
wattroff(win, COLOR_PAIR(line->colour)); wattroff(win, COLOR_PAIR(line->colour));
@ -639,7 +678,7 @@ void line_info_print(ToxWindow *self)
wprintw(win, "%s ", line->name1); wprintw(win, "%s ", line->name1);
wattroff(win, A_BOLD); wattroff(win, A_BOLD);
print_wrap(win, line, max_x); print_ret = print_wrap(win, line, max_x, max_y);
waddch(win, '\n'); waddch(win, '\n');
wattroff(win, COLOR_PAIR(line->colour)); wattroff(win, COLOR_PAIR(line->colour));
@ -657,7 +696,7 @@ void line_info_print(ToxWindow *self)
wprintw(win, "%s", line->name1); wprintw(win, "%s", line->name1);
wattroff(win, A_BOLD); wattroff(win, A_BOLD);
print_wrap(win, line, max_x); print_ret = print_wrap(win, line, max_x, max_y);
wattron(win, A_BOLD); wattron(win, A_BOLD);
wprintw(win, "%s\n", line->name2); 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 */ /* puts msg in specified line_info msg buffer */
void line_info_set(ToxWindow *self, uint32_t id, char *msg) 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) { if (hst->line_start->prev) {
hst->line_start = hst->line_start->prev; hst->line_start = hst->line_start->prev;
} else { self->scroll_pause = true;
sound_notify(NULL, notif_error, NT_ALWAYS, NULL);
} }
} }
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) { struct line_info *next = hst->line_start->next;
hst->line_start = 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 { } 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) static void line_info_page_up(ToxWindow *self, struct history *hst)
{ {
int x2, y2; int x2;
int y2;
getmaxyx(self->window, y2, x2); getmaxyx(self->window, y2, x2);
UNUSED_VAR(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) { for (size_t i = 0; i < jump_dist && hst->line_start->prev; ++i) {
hst->line_start = hst->line_start->prev; hst->line_start = hst->line_start->prev;
} }
self->scroll_pause = true;
} }
static void line_info_page_down(ToxWindow *self, struct history *hst) static void line_info_page_down(ToxWindow *self, struct history *hst)
{ {
int x2, y2; if (!self->scroll_pause) {
getmaxyx(self->window, y2, x2); return;
}
int x2;
int y2;
getmaxyx(self->chatwin->history, y2, x2);
UNUSED_VAR(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) { struct line_info *next = hst->line_start->next;
hst->line_start = 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) { } else if (key == user_settings->key_half_page_down) {
line_info_page_down(self, hst); line_info_page_down(self, hst);
} else if (key == user_settings->key_scroll_line_up) { } 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) { } 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) { } else if (key == user_settings->key_page_bottom) {
line_info_reset_start(self, hst); line_info_reset_start(self, hst);
} else { } else {

View File

@ -31,7 +31,7 @@
#define MAX_LINE_INFO_QUEUE 1024 #define MAX_LINE_INFO_QUEUE 1024
#define MAX_LINE_INFO_MSG_SIZE (MAX_STR_SIZE + TOXIC_MAX_NAME_LENGTH + 32) /* needs extra room for log loading */ #define MAX_LINE_INFO_MSG_SIZE (MAX_STR_SIZE + TOXIC_MAX_NAME_LENGTH + 32) /* needs extra room for log loading */
typedef enum { typedef enum LINE_TYPE {
SYS_MSG, SYS_MSG,
IN_MSG, IN_MSG,
OUT_MSG, OUT_MSG,
@ -81,7 +81,7 @@ struct history {
* Returns the id of the new line. * Returns the id of the new line.
* Returns -1 on failure. * Returns -1 on failure.
*/ */
int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const char *name2, uint8_t type, int line_info_add(ToxWindow *self, bool show_timestamp, const char *name1, const char *name2, LINE_TYPE type,
uint8_t bold, uint8_t colour, const char *msg, ...); uint8_t bold, uint8_t colour, const char *msg, ...);
/* Prints a section of history starting at line_start */ /* Prints a section of history starting at line_start */

View File

@ -302,11 +302,11 @@ int load_chat_history(ToxWindow *self, struct chatlog *log)
} }
while (line != NULL && count--) { while (line != NULL && count--) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", line); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", line);
line = strtok_r(NULL, "\n", &tmp); line = strtok_r(NULL, "\n", &tmp);
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, YELLOW, "---");
free(buf); free(buf);
@ -358,7 +358,9 @@ int rename_logfile(const char *src, const char *dest, const char *selfkey, const
} }
if (file_exists(newpath)) { 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) { } else if (rename(oldpath, newpath) != 0) {
goto on_error; goto on_error;
} }

View File

@ -71,16 +71,19 @@ int timed_out(time_t timestamp, time_t timeout)
return timestamp + timeout <= get_unix_time(); 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) void sleep_thread(long int usec)
{ {
struct timespec req; struct timespec req;
struct timespec rem;
req.tv_sec = 0; req.tv_sec = 0;
req.tv_nsec = usec * 1000L; req.tv_nsec = usec * 1000L;
if (nanosleep(&req, NULL) == -1) { if (nanosleep(&req, &rem) == -1) {
fprintf(stderr, "nanosleep() returned -1\n"); if (nanosleep(&rem, NULL) == -1) {
fprintf(stderr, "nanosleep() returned -1\n");
}
} }
} }
@ -93,11 +96,16 @@ struct tm *get_time(void)
return timeinfo; return timeinfo;
} }
/*Puts the current time in buf in the format of [HH:mm:ss] */ /* Puts the current time in buf in the format of specified by the config */
void get_time_str(char *buf, int bufsize) void get_time_str(char *buf, size_t bufsize)
{ {
if (buf == NULL || bufsize == 0) {
return;
}
*buf = 0;
if (user_settings->timestamps == TIMESTAMPS_OFF) { if (user_settings->timestamps == TIMESTAMPS_OFF) {
buf[0] = '\0';
return; return;
} }

View File

@ -81,8 +81,8 @@ int bin_pubkey_to_string(const uint8_t *bin_pubkey, size_t bin_pubkey_size, char
/* get the current unix time (not thread safe) */ /* get the current unix time (not thread safe) */
time_t get_unix_time(void); time_t get_unix_time(void);
/* Puts the current time in buf in the format of [HH:mm:ss] (not thread safe) */ /* Puts the current time in buf in the format of specified by the config */
void get_time_str(char *buf, int bufsize); void get_time_str(char *buf, size_t bufsize);
/* Converts seconds to string in format HH:mm:ss; truncates hours and minutes when necessary */ /* Converts seconds to string in format HH:mm:ss; truncates hours and minutes when necessary */
void get_elapsed_time_str(char *buf, int bufsize, time_t secs); void get_elapsed_time_str(char *buf, int bufsize, time_t secs);
@ -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 */ /* Returns 1 if connection has timed out, 0 otherwise */
int timed_out(time_t timestamp, time_t timeout); 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); void sleep_thread(long int usec);
/* Colours the window tab according to type. Beeps if is_beep is true */ /* Colours the window tab according to type. Beeps if is_beep is true */

View File

@ -80,7 +80,7 @@ static int lookup_error(ToxWindow *self, const char *errmsg, ...)
va_end(args); va_end(args);
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "name lookup failed: %s", frmt_msg); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "name lookup failed: %s", frmt_msg);
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
return -1; return -1;
@ -365,12 +365,12 @@ on_exit:
void name_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *message) void name_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr, const char *message)
{ {
if (t_data.disabled) { if (t_data.disabled) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "name lookups are disabled."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "name lookups are disabled.");
return; return;
} }
if (t_data.busy) { if (t_data.busy) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Please wait for previous name lookup to finish."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Please wait for previous name lookup to finish.");
return; return;
} }
@ -382,20 +382,20 @@ void name_lookup(ToxWindow *self, Tox *m, const char *id_bin, const char *addr,
t_data.busy = true; t_data.busy = true;
if (pthread_attr_init(&lookup_thread.attr) != 0) { if (pthread_attr_init(&lookup_thread.attr) != 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread attr failed to init"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread attr failed to init");
clear_thread_data(); clear_thread_data();
return; return;
} }
if (pthread_attr_setdetachstate(&lookup_thread.attr, PTHREAD_CREATE_DETACHED) != 0) { if (pthread_attr_setdetachstate(&lookup_thread.attr, PTHREAD_CREATE_DETACHED) != 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread attr failed to set"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread attr failed to set");
pthread_attr_destroy(&lookup_thread.attr); pthread_attr_destroy(&lookup_thread.attr);
clear_thread_data(); clear_thread_data();
return; return;
} }
if (pthread_create(&lookup_thread.tid, &lookup_thread.attr, lookup_thread_func, NULL) != 0) { if (pthread_create(&lookup_thread.tid, &lookup_thread.attr, lookup_thread_func, NULL) != 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread failed to init"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, "Error: lookup thread failed to init");
pthread_attr_destroy(&lookup_thread.attr); pthread_attr_destroy(&lookup_thread.attr);
clear_thread_data(); clear_thread_data();
return; return;

View File

@ -144,7 +144,7 @@ void prompt_update_statusmessage(ToxWindow *prompt, Tox *m, const char *statusms
tox_self_set_status_message(m, (const uint8_t *) statusmsg, len, &err); tox_self_set_status_message(m, (const uint8_t *) statusmsg, len, &err);
if (err != TOX_ERR_SET_INFO_OK) { if (err != TOX_ERR_SET_INFO_OK) {
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set note (error %d)\n", err); line_info_add(prompt, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to set note (error %d)\n", err);
} }
} }
@ -284,15 +284,15 @@ static bool prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
char line[MAX_STR_SIZE]; char line[MAX_STR_SIZE];
if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) { if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to parse message."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Failed to parse message.");
} else { } else {
line_info_add(self, NULL, NULL, NULL, PROMPT, 0, 0, "%s", line); line_info_add(self, false, NULL, NULL, PROMPT, 0, 0, "%s", line);
execute(ctx->history, self, m, line, GLOBAL_COMMAND_MODE); execute(ctx->history, self, m, line, GLOBAL_COMMAND_MODE);
} }
} }
wclear(ctx->linewin); wclear(ctx->linewin);
wmove(self->window, y2 - CURS_Y_OFFSET, 0); wmove(self->window, y2, 0);
reset_buf(ctx); 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) static void prompt_onDraw(ToxWindow *self, Tox *m)
{ {
int x2, y2; int x2;
int y2;
getmaxyx(self->window, y2, x2); getmaxyx(self->window, y2, x2);
if (y2 <= 0 || x2 <= 0) { if (y2 <= 0 || x2 <= 0) {
@ -316,64 +317,88 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
wclear(ctx->linewin); wclear(ctx->linewin);
curs_set(1);
if (ctx->len > 0) { 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; StatusBar *statusbar = self->stb;
mvwhline(statusbar->topline, 1, 0, ACS_HLINE, x2);
wmove(statusbar->topline, 0, 0); wmove(statusbar->topline, 0, 0);
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
Tox_Connection connection = statusbar->connection; Tox_Connection connection = statusbar->connection;
Tox_User_Status status = statusbar->status;
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
if (connection != TOX_CONNECTION_NONE) { if (connection != TOX_CONNECTION_NONE) {
int colour = MAGENTA; int colour = MAGENTA;
const char *status_text = "ERROR"; const char *status_text = "ERROR";
pthread_mutex_lock(&Winthread.lock);
Tox_User_Status status = statusbar->status;
pthread_mutex_unlock(&Winthread.lock);
switch (status) { switch (status) {
case TOX_USER_STATUS_NONE: case TOX_USER_STATUS_NONE:
status_text = "Online"; status_text = "Online";
colour = GREEN; colour = STATUS_ONLINE;
break; break;
case TOX_USER_STATUS_AWAY: case TOX_USER_STATUS_AWAY:
status_text = "Away"; status_text = "Away";
colour = YELLOW; colour = STATUS_AWAY;
break; break;
case TOX_USER_STATUS_BUSY: case TOX_USER_STATUS_BUSY:
status_text = "Busy"; status_text = "Busy";
colour = RED; colour = STATUS_BUSY;
break; break;
} }
wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD); wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, " [%s]", status_text); wprintw(statusbar->topline, " [");
wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD); wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
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(BAR_ACCENT));
wprintw(statusbar->topline, "]");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
wattron(statusbar->topline, A_BOLD);
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
wprintw(statusbar->topline, " %s", statusbar->nick); wprintw(statusbar->topline, " %s", statusbar->nick);
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
wattroff(statusbar->topline, A_BOLD);
} else { } else {
wprintw(statusbar->topline, " [Offline]"); wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wattron(statusbar->topline, A_BOLD); wprintw(statusbar->topline, " [");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
wprintw(statusbar->topline, "Offline");
wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, "]");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
wprintw(statusbar->topline, " %s", statusbar->nick); wprintw(statusbar->topline, " %s", statusbar->nick);
pthread_mutex_unlock(&Winthread.lock); 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(BAR_TEXT));
/* Reset statusbar->statusmsg on window resize */ /* Reset statusbar->statusmsg on window resize */
if (x2 != self->x) { if (x2 != self->x) {
char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH]; char statusmsg[TOX_MAX_STATUS_MESSAGE_LENGTH];
@ -401,20 +426,27 @@ static void prompt_onDraw(ToxWindow *self, Tox *m)
} }
if (statusbar->statusmsg[0]) { if (statusbar->statusmsg[0]) {
wprintw(statusbar->topline, " : %s", statusbar->statusmsg); wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wprintw(statusbar->topline, " | ");
wattroff(statusbar->topline, COLOR_PAIR(BAR_ACCENT));
wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT));
wprintw(statusbar->topline, "%s", statusbar->statusmsg);
wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT));
} }
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
mvwhline(self->window, y2 - CHATBOX_HEIGHT, 0, ACS_HLINE, x2); int y;
int x;
int y, x;
getyx(self->window, y, x); getyx(self->window, y, x);
UNUSED_VAR(x); UNUSED_VAR(x);
int new_x = ctx->start ? x2 - 1 : MAX(0, wcswidth(ctx->line, ctx->pos)); 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); wnoutrefresh(self->window);
@ -434,8 +466,6 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnu
snprintf(nick, sizeof(nick), "%s", UNKNOWN_NAME); snprintf(nick, sizeof(nick), "%s", UNKNOWN_NAME);
} }
char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt));
const char *msg; const char *msg;
if (user_settings->show_connection_msg == SHOW_WELCOME_MSG_OFF) { if (user_settings->show_connection_msg == SHOW_WELCOME_MSG_OFF) {
@ -444,7 +474,7 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnu
if (connection_status != TOX_CONNECTION_NONE && Friends.list[friendnum].connection_status == TOX_CONNECTION_NONE) { if (connection_status != TOX_CONNECTION_NONE && Friends.list[friendnum].connection_status == TOX_CONNECTION_NONE) {
msg = "has come online"; msg = "has come online";
line_info_add(self, timefrmt, nick, NULL, CONNECTION, 0, GREEN, msg); line_info_add(self, true, nick, NULL, CONNECTION, 0, GREEN, msg);
write_to_log(msg, nick, ctx->log, true); write_to_log(msg, nick, ctx->log, true);
if (self->active_box != -1) { if (self->active_box != -1) {
@ -456,7 +486,7 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnu
} }
} else if (connection_status == TOX_CONNECTION_NONE) { } else if (connection_status == TOX_CONNECTION_NONE) {
msg = "has gone offline"; msg = "has gone offline";
line_info_add(self, timefrmt, nick, NULL, DISCONNECTION, 0, RED, msg); line_info_add(self, true, nick, NULL, DISCONNECTION, 0, RED, msg);
write_to_log(msg, nick, ctx->log, true); write_to_log(msg, nick, ctx->log, true);
if (self->active_box != -1) { if (self->active_box != -1) {
@ -476,21 +506,18 @@ static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, con
ChatContext *ctx = self->chatwin; ChatContext *ctx = self->chatwin;
char timefrmt[TIME_STR_SIZE]; line_info_add(self, true, NULL, NULL, SYS_MSG, 0, 0, "Friend request with the message '%s'", data);
get_time_str(timefrmt, sizeof(timefrmt));
line_info_add(self, timefrmt, NULL, NULL, SYS_MSG, 0, 0, "Friend request with the message '%s'", data);
write_to_log("Friend request with the message '%s'", "", ctx->log, true); write_to_log("Friend request with the message '%s'", "", ctx->log, true);
int n = add_friend_request(key, data); int n = add_friend_request(key, data);
if (n == -1) { if (n == -1) {
const char *errmsg = "Friend request queue is full. Discarding request."; const char *errmsg = "Friend request queue is full. Discarding request.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, errmsg);
return; return;
} }
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Type \"/accept %d\" or \"/decline %d\"", n, n); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Type \"/accept %d\" or \"/decline %d\"", n, n);
sound_notify(self, generic_message, NT_WNDALERT_1 | NT_NOTIFWND, NULL); sound_notify(self, generic_message, NT_WNDALERT_1 | NT_NOTIFWND, NULL);
} }
@ -535,23 +562,23 @@ void prompt_init_statusbar(ToxWindow *self, Tox *m, bool first_time_run)
prompt_update_nick(prompt, nick); prompt_update_nick(prompt, nick);
/* Init statusbar subwindow */ /* 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) static void print_welcome_msg(ToxWindow *self)
{ {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, BLUE, " _____ _____ _____ ____ "); line_info_add(self, false, NULL, NULL, SYS_MSG, 1, BLUE, " _____ _____ _____ ____ ");
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, BLUE, " |_ _/ _ \\ \\/ /_ _/ ___|"); line_info_add(self, false, NULL, NULL, SYS_MSG, 1, BLUE, " |_ _/ _ \\ \\/ /_ _/ ___|");
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, BLUE, " | || | | \\ / | | | "); line_info_add(self, false, NULL, NULL, SYS_MSG, 1, BLUE, " | || | | \\ / | | | ");
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, BLUE, " | || |_| / \\ | | |___ "); line_info_add(self, false, NULL, NULL, SYS_MSG, 1, BLUE, " | || |_| / \\ | | |___ ");
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, BLUE, " |_| \\___/_/\\_\\___\\____| v." TOXICVER); line_info_add(self, false, NULL, NULL, SYS_MSG, 1, BLUE, " |_| \\___/_/\\_\\___\\____| v." TOXICVER);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "");
const char *msg = "Welcome to Toxic, a free, open source Tox-based instant messaging client."; const char *msg = "Welcome to Toxic, a free, open source Tox-based instant messaging client.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, CYAN, msg); line_info_add(self, false, NULL, NULL, SYS_MSG, 1, CYAN, msg);
msg = "Type \"/help\" for assistance. Further help may be found via the man page."; msg = "Type \"/help\" for assistance. Further help may be found via the man page.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 1, CYAN, msg); line_info_add(self, false, NULL, NULL, SYS_MSG, 1, CYAN, msg);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "");
} }
static void prompt_init_log(ToxWindow *self, Tox *m, const char *self_name) static void prompt_init_log(ToxWindow *self, Tox *m, const char *self_name)
@ -562,13 +589,13 @@ static void prompt_init_log(ToxWindow *self, Tox *m, const char *self_name)
tox_self_get_address(m, (uint8_t *) myid); tox_self_get_address(m, (uint8_t *) myid);
if (log_init(ctx->log, self->name, myid, NULL, LOG_TYPE_PROMPT) != 0) { if (log_init(ctx->log, self->name, myid, NULL, LOG_TYPE_PROMPT) != 0) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
return; return;
} }
if (user_settings->autolog == AUTOLOG_ON) { if (user_settings->autolog == AUTOLOG_ON) {
if (log_enable(ctx->log) == -1) { if (log_enable(ctx->log) == -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Failed to enable log."); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Warning: Failed to enable log.");
} }
} }
} }
@ -576,7 +603,9 @@ static void prompt_init_log(ToxWindow *self, Tox *m, const char *self_name)
static void prompt_onInit(ToxWindow *self, Tox *m) static void prompt_onInit(ToxWindow *self, Tox *m)
{ {
curs_set(1); curs_set(1);
int y2, x2;
int y2;
int x2;
getmaxyx(self->window, y2, x2); getmaxyx(self->window, y2, x2);
if (y2 <= 0 || x2 <= 0) { if (y2 <= 0 || x2 <= 0) {
@ -584,8 +613,10 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
} }
ChatContext *ctx = self->chatwin; 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->log = calloc(1, sizeof(struct chatlog));
ctx->hst = calloc(1, sizeof(struct history)); ctx->hst = calloc(1, sizeof(struct history));

View File

@ -73,6 +73,11 @@ static struct ui_strings {
const char *mplex_away; const char *mplex_away;
const char *mplex_away_note; const char *mplex_away_note;
const char *color_bar_bg;
const char *color_bar_fg;
const char *color_bar_accent;
const char *color_bar_notify;
} ui_strings = { } ui_strings = {
"ui", "ui",
"timestamps", "timestamps",
@ -100,6 +105,10 @@ static struct ui_strings {
"line_normal", "line_normal",
"mplex_away", "mplex_away",
"mplex_away_note", "mplex_away_note",
"color_bar_bg",
"color_bar_fg",
"color_bar_accent",
"color_bar_notify",
}; };
static void ui_defaults(struct user_settings *settings) static void ui_defaults(struct user_settings *settings)
@ -116,7 +125,7 @@ static void ui_defaults(struct user_settings *settings)
settings->bell_on_invite = 0; settings->bell_on_invite = 0;
settings->colour_theme = DFLT_COLS; settings->colour_theme = DFLT_COLS;
settings->history_size = 700; settings->history_size = 700;
settings->notification_timeout = 3000; settings->notification_timeout = 6000;
settings->show_typing_self = SHOW_TYPING_ON; settings->show_typing_self = SHOW_TYPING_ON;
settings->show_typing_other = SHOW_TYPING_ON; settings->show_typing_other = SHOW_TYPING_ON;
settings->show_welcome_msg = SHOW_WELCOME_MSG_ON; settings->show_welcome_msg = SHOW_WELCOME_MSG_ON;
@ -130,10 +139,7 @@ static void ui_defaults(struct user_settings *settings)
snprintf(settings->line_normal, LINE_HINT_MAX + 1, "%s", LINE_NORMAL); snprintf(settings->line_normal, LINE_HINT_MAX + 1, "%s", LINE_NORMAL);
settings->mplex_away = MPLEX_ON; settings->mplex_away = MPLEX_ON;
snprintf(settings->mplex_away_note, snprintf(settings->mplex_away_note, sizeof(settings->mplex_away_note), "%s", MPLEX_AWAY_NOTE);
sizeof(settings->mplex_away_note),
"%s",
MPLEX_AWAY_NOTE);
} }
static const struct keys_strings { static const struct keys_strings {
@ -339,7 +345,7 @@ int settings_load(struct user_settings *s, const char *patharg)
if (config_setting_lookup_int(setting, ui_strings.time_format, &time)) { if (config_setting_lookup_int(setting, ui_strings.time_format, &time)) {
if (time == 12) { 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]"); snprintf(s->log_timestamp_format, sizeof(s->log_timestamp_format), "%s", "%Y/%m/%d [%I:%M:%S %p]");
} }
} }
@ -348,6 +354,22 @@ int settings_load(struct user_settings *s, const char *patharg)
snprintf(s->timestamp_format, sizeof(s->timestamp_format), "%s", str); snprintf(s->timestamp_format, sizeof(s->timestamp_format), "%s", str);
} }
if (config_setting_lookup_string(setting, ui_strings.color_bar_bg, &str)) {
snprintf(s->color_bar_bg, sizeof(s->color_bar_bg), "%s", str);
}
if (config_setting_lookup_string(setting, ui_strings.color_bar_fg, &str)) {
snprintf(s->color_bar_fg, sizeof(s->color_bar_fg), "%s", str);
}
if (config_setting_lookup_string(setting, ui_strings.color_bar_accent, &str)) {
snprintf(s->color_bar_accent, sizeof(s->color_bar_accent), "%s", str);
}
if (config_setting_lookup_string(setting, ui_strings.color_bar_notify, &str)) {
snprintf(s->color_bar_notify, sizeof(s->color_bar_notify), "%s", str);
}
if (config_setting_lookup_string(setting, ui_strings.log_timestamp_format, &str)) { if (config_setting_lookup_string(setting, ui_strings.log_timestamp_format, &str)) {
snprintf(s->log_timestamp_format, sizeof(s->log_timestamp_format), "%s", str); snprintf(s->log_timestamp_format, sizeof(s->log_timestamp_format), "%s", str);
} }

View File

@ -68,6 +68,11 @@ struct user_settings {
char autorun_path[PATH_MAX]; char autorun_path[PATH_MAX];
char password_eval[PASSWORD_EVAL_MAX]; char password_eval[PASSWORD_EVAL_MAX];
char color_bar_bg[COLOR_STR_SIZE];
char color_bar_fg[COLOR_STR_SIZE];
char color_bar_accent[COLOR_STR_SIZE];
char color_bar_notify[COLOR_STR_SIZE];
int key_next_tab; int key_next_tab;
int key_prev_tab; int key_prev_tab;
int key_scroll_line_up; int key_scroll_line_up;
@ -125,7 +130,7 @@ enum settings_values {
#define LINE_NORMAL "-" #define LINE_NORMAL "-"
#define TIMESTAMP_DEFAULT "%H:%M" #define TIMESTAMP_DEFAULT "%H:%M"
#define LOG_TIMESTAMP_DEFAULT "%Y/%m/%d [%H:%M:%S]" #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); int settings_load(struct user_settings *s, const char *patharg);

View File

@ -256,10 +256,14 @@ static void init_term(void)
keypad(stdscr, 1); keypad(stdscr, 1);
noecho(); noecho();
nonl(); nonl();
timeout(100); timeout(50);
if (has_colors()) { if (has_colors()) {
short bg_color = COLOR_BLACK; short bg_color = COLOR_BLACK;
short bar_bg_color = COLOR_BLUE;
short bar_fg_color = COLOR_WHITE;
short bar_accent_color = COLOR_CYAN;
short bar_notify_color = COLOR_YELLOW;
start_color(); start_color();
if (user_settings->colour_theme == NATIVE_COLS) { if (user_settings->colour_theme == NATIVE_COLS) {
@ -268,15 +272,120 @@ static void init_term(void)
} }
} }
init_pair(0, COLOR_WHITE, COLOR_BLACK); if (!string_is_empty(user_settings->color_bar_bg)) {
init_pair(1, COLOR_GREEN, bg_color); if (strcmp(user_settings->color_bar_bg, "black") == 0) {
init_pair(2, COLOR_CYAN, bg_color); bar_bg_color = COLOR_BLACK;
init_pair(3, COLOR_RED, bg_color); } else if (strcmp(user_settings->color_bar_bg, "red") == 0) {
init_pair(4, COLOR_BLUE, bg_color); bar_bg_color = COLOR_RED;
init_pair(5, COLOR_YELLOW, bg_color); } else if (strcmp(user_settings->color_bar_bg, "blue") == 0) {
init_pair(6, COLOR_MAGENTA, bg_color); bar_bg_color = COLOR_BLUE;
init_pair(7, COLOR_BLACK, COLOR_BLACK); } else if (strcmp(user_settings->color_bar_bg, "cyan") == 0) {
init_pair(8, COLOR_BLACK, COLOR_WHITE); bar_bg_color = COLOR_CYAN;
} else if (strcmp(user_settings->color_bar_bg, "green") == 0) {
bar_bg_color = COLOR_GREEN;
} else if (strcmp(user_settings->color_bar_bg, "yellow") == 0) {
bar_bg_color = COLOR_YELLOW;
} else if (strcmp(user_settings->color_bar_bg, "magenta") == 0) {
bar_bg_color = COLOR_MAGENTA;
} else if (strcmp(user_settings->color_bar_bg, "white") == 0) {
bar_bg_color = COLOR_WHITE;
} else {
bar_bg_color = COLOR_BLUE;
}
} else {
bar_bg_color = COLOR_BLUE;
}
if (!string_is_empty(user_settings->color_bar_fg)) {
if (strcmp(user_settings->color_bar_fg, "black") == 0) {
bar_fg_color = COLOR_BLACK;
} else if (strcmp(user_settings->color_bar_fg, "red") == 0) {
bar_fg_color = COLOR_RED;
} else if (strcmp(user_settings->color_bar_fg, "blue") == 0) {
bar_fg_color = COLOR_BLUE;
} else if (strcmp(user_settings->color_bar_fg, "cyan") == 0) {
bar_fg_color = COLOR_CYAN;
} else if (strcmp(user_settings->color_bar_fg, "green") == 0) {
bar_fg_color = COLOR_GREEN;
} else if (strcmp(user_settings->color_bar_fg, "yellow") == 0) {
bar_fg_color = COLOR_YELLOW;
} else if (strcmp(user_settings->color_bar_fg, "magenta") == 0) {
bar_fg_color = COLOR_MAGENTA;
} else if (strcmp(user_settings->color_bar_fg, "white") == 0) {
bar_fg_color = COLOR_WHITE;
} else {
bar_fg_color = COLOR_WHITE;
}
} else {
bar_fg_color = COLOR_WHITE;
}
if (!string_is_empty(user_settings->color_bar_accent)) {
if (strcmp(user_settings->color_bar_accent, "black") == 0) {
bar_accent_color = COLOR_BLACK;
} else if (strcmp(user_settings->color_bar_accent, "red") == 0) {
bar_accent_color = COLOR_RED;
} else if (strcmp(user_settings->color_bar_accent, "blue") == 0) {
bar_accent_color = COLOR_BLUE;
} else if (strcmp(user_settings->color_bar_accent, "cyan") == 0) {
bar_accent_color = COLOR_CYAN;
} else if (strcmp(user_settings->color_bar_accent, "green") == 0) {
bar_accent_color = COLOR_GREEN;
} else if (strcmp(user_settings->color_bar_accent, "yellow") == 0) {
bar_accent_color = COLOR_YELLOW;
} else if (strcmp(user_settings->color_bar_accent, "magenta") == 0) {
bar_accent_color = COLOR_MAGENTA;
} else if (strcmp(user_settings->color_bar_accent, "white") == 0) {
bar_accent_color = COLOR_WHITE;
} else {
bar_accent_color = COLOR_CYAN;
}
} else {
bar_accent_color = COLOR_CYAN;
}
if (!string_is_empty(user_settings->color_bar_notify)) {
if (strcmp(user_settings->color_bar_notify, "black") == 0) {
bar_notify_color = COLOR_BLACK;
} else if (strcmp(user_settings->color_bar_notify, "red") == 0) {
bar_notify_color = COLOR_RED;
} else if (strcmp(user_settings->color_bar_notify, "blue") == 0) {
bar_notify_color = COLOR_BLUE;
} else if (strcmp(user_settings->color_bar_notify, "cyan") == 0) {
bar_notify_color = COLOR_CYAN;
} else if (strcmp(user_settings->color_bar_notify, "green") == 0) {
bar_notify_color = COLOR_GREEN;
} else if (strcmp(user_settings->color_bar_notify, "yellow") == 0) {
bar_notify_color = COLOR_YELLOW;
} else if (strcmp(user_settings->color_bar_notify, "magenta") == 0) {
bar_notify_color = COLOR_MAGENTA;
} else if (strcmp(user_settings->color_bar_notify, "white") == 0) {
bar_notify_color = COLOR_WHITE;
} else {
bar_notify_color = COLOR_YELLOW;
}
} else {
bar_notify_color = COLOR_YELLOW;
}
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(BLACK_BG, COLOR_BLACK, bar_bg_color);
init_pair(PURPLE_BG, COLOR_MAGENTA, bar_bg_color);
init_pair(BAR_TEXT, bar_fg_color, bar_bg_color);
init_pair(BAR_ACCENT, bar_accent_color, bar_bg_color);
init_pair(BAR_NOTIFY, bar_notify_color, bar_bg_color);
init_pair(STATUS_ONLINE, COLOR_GREEN, bar_bg_color);
init_pair(STATUS_AWAY, COLOR_YELLOW, bar_bg_color);
init_pair(STATUS_BUSY, COLOR_RED, bar_bg_color);
} }
refresh(); refresh();
@ -1421,6 +1530,7 @@ int main(int argc, char **argv)
prompt = init_windows(m); prompt = init_windows(m);
prompt_init_statusbar(prompt, m, !datafile_exists); prompt_init_statusbar(prompt, m, !datafile_exists);
load_conferences(m); load_conferences(m);
set_active_window_index(0);
if (pthread_mutex_init(&Winthread.lock, NULL) != 0) { if (pthread_mutex_init(&Winthread.lock, NULL) != 0) {
exit_toxic_err("failed in main", FATALERR_MUTEX_INIT); exit_toxic_err("failed in main", FATALERR_MUTEX_INIT);
@ -1483,7 +1593,6 @@ int main(int argc, char **argv)
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
print_init_messages(prompt); print_init_messages(prompt);
set_active_window_index(0);
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
cleanup_init_messages(); cleanup_init_messages();
@ -1504,7 +1613,7 @@ int main(int argc, char **argv)
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
if (store_data(m, DATA_FILE) != 0) { if (store_data(m, DATA_FILE) != 0) {
line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "WARNING: Failed to save to data file"); line_info_add(prompt, false, NULL, NULL, SYS_MSG, 0, RED, "WARNING: Failed to save to data file");
} }
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);

View File

@ -48,6 +48,7 @@
#define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */ #define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */
#define KEY_IDENT_DIGITS 3 /* number of hex digits to display for the pub-key based identifier */ #define KEY_IDENT_DIGITS 3 /* number of hex digits to display for the pub-key based identifier */
#define TIME_STR_SIZE 32 #define TIME_STR_SIZE 32
#define COLOR_STR_SIZE 10 /* should fit every color option */
#ifndef MAX_PORT_RANGE #ifndef MAX_PORT_RANGE
#define MAX_PORT_RANGE 65535 #define MAX_PORT_RANGE 65535
@ -75,7 +76,7 @@
#define T_KEY_C_DOWN 0x20D /* ctrl-down arrow */ #define T_KEY_C_DOWN 0x20D /* ctrl-down arrow */
#define T_KEY_TAB 0x09 /* TAB key */ #define T_KEY_TAB 0x09 /* TAB key */
#define ONLINE_CHAR "*" #define ONLINE_CHAR "o"
#define OFFLINE_CHAR "o" #define OFFLINE_CHAR "o"
typedef enum _FATAL_ERRS { typedef enum _FATAL_ERRS {

View File

@ -52,7 +52,7 @@ void on_video_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rat
static void print_err(ToxWindow *self, const char *error_str) static void print_err(ToxWindow *self, const char *error_str)
{ {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%s", error_str);
} }
ToxAV *init_video(ToxWindow *self, Tox *tox) ToxAV *init_video(ToxWindow *self, Tox *tox)
@ -66,13 +66,13 @@ ToxAV *init_video(ToxWindow *self, Tox *tox)
CallControl.video_frame_duration = 10; CallControl.video_frame_duration = 10;
if (!CallControl.av) { if (!CallControl.av) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Video failed to init with ToxAV instance"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Video failed to init with ToxAV instance");
return NULL; return NULL;
} }
if (init_video_devices(CallControl.av) == vde_InternalError) { if (init_video_devices(CallControl.av) == vde_InternalError) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init video devices"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to init video devices");
return NULL; return NULL;
} }
@ -110,17 +110,17 @@ void read_video_device_callback(int16_t width, int16_t height, const uint8_t *y,
/* Drop frame if video sending is disabled */ /* Drop frame if video sending is disabled */
if (this_call->video_bit_rate == 0 || this_call->status != cs_Active || this_call->vin_idx == -1) { if (this_call->video_bit_rate == 0 || this_call->status != cs_Active || this_call->vin_idx == -1) {
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Video frame dropped."); line_info_add(CallControl.prompt, false, NULL, NULL, SYS_MSG, 0, 0, "Video frame dropped.");
return; return;
} }
if (toxav_video_send_frame(CallControl.av, friend_number, width, height, y, u, v, &error) == false) { if (toxav_video_send_frame(CallControl.av, friend_number, width, height, y, u, v, &error) == false) {
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to send video frame"); line_info_add(CallControl.prompt, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to send video frame");
if (error == TOXAV_ERR_SEND_FRAME_NULL) { if (error == TOXAV_ERR_SEND_FRAME_NULL) {
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to capture video frame"); line_info_add(CallControl.prompt, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to capture video frame");
} else if (error == TOXAV_ERR_SEND_FRAME_INVALID) { } else if (error == TOXAV_ERR_SEND_FRAME_INVALID) {
line_info_add(CallControl.prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare video frame"); line_info_add(CallControl.prompt, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare video frame");
} }
} }
} }
@ -138,22 +138,22 @@ void write_video_device_callback(uint32_t friend_number, uint16_t width, uint16_
int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call) int start_video_transmission(ToxWindow *self, ToxAV *av, Call *call)
{ {
if (!self || !av) { if (!self || !av) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare video transmission"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to prepare video transmission");
return -1; return -1;
} }
if (open_primary_video_device(vdt_input, &call->vin_idx, &call->video_width, &call->video_height) != vde_None) { if (open_primary_video_device(vdt_input, &call->vin_idx, &call->video_width, &call->video_height) != vde_None) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to open input video device!"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to open input video device!");
return -1; return -1;
} }
if (register_video_device_callback(self->num, call->vin_idx, read_video_device_callback, &self->num) != vde_None) { if (register_video_device_callback(self->num, call->vin_idx, read_video_device_callback, &self->num) != vde_None) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input video handler!"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to register input video handler!");
return -1; return -1;
} }
if (!toxav_video_set_bit_rate(CallControl.av, self->num, call->video_bit_rate, NULL)) { if (!toxav_video_set_bit_rate(CallControl.av, self->num, call->video_bit_rate, NULL)) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set video bit rate"); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to set video bit rate");
return -1; return -1;
} }
@ -347,11 +347,11 @@ void cmd_res(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
if (argc == 0) { if (argc == 0) {
if (call->status == cs_Active && call->vin_idx != -1) { if (call->status == cs_Active && call->vin_idx != -1) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,
"Resolution of current call: %u x %u", "Resolution of current call: %u x %u",
call->video_width, call->video_height); call->video_width, call->video_height);
} else { } else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0,
"Initial resolution for video calls: %u x %u", "Initial resolution for video calls: %u x %u",
CallControl.default_video_width, CallControl.default_video_height); CallControl.default_video_width, CallControl.default_video_height);
} }
@ -411,7 +411,7 @@ void cmd_list_video_devices(WINDOW *window, ToxWindow *self, Tox *m, int argc, c
} }
else { else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
return; return;
} }
@ -447,7 +447,7 @@ void cmd_change_video_device(WINDOW *window, ToxWindow *self, Tox *m, int argc,
} }
else { else {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Invalid type: %s", argv[1]);
return; return;
} }

View File

@ -852,7 +852,7 @@ void print_video_devices(ToxWindow *self, VideoDeviceType type)
int i; int i;
for (i = 0; i < size[type]; ++i) { for (i = 0; i < size[type]; ++i) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%d: %s", i, video_devices_names[type][i]); line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "%d: %s", i, video_devices_names[type][i]);
} }
return; return;

View File

@ -336,7 +336,7 @@ int add_window(Tox *m, ToxWindow *w)
} }
w->index = i; w->index = i;
w->window = newwin(LINES - 2, COLS, 0, 0); w->window = newwin(LINES, COLS, 0, 0);
if (w->window == NULL) { if (w->window == NULL) {
return -1; return -1;
@ -397,8 +397,9 @@ void del_window(ToxWindow *w)
set_active_window_index(0); set_active_window_index(0);
uint8_t idx = w->index; uint8_t idx = w->index;
delwin(w->window_bar);
delwin(w->window); delwin(w->window);
free(windows[idx]); free(w);
windows[idx] = NULL; windows[idx] = NULL;
clear(); clear();
@ -408,7 +409,12 @@ void del_window(ToxWindow *w)
ToxWindow *init_windows(Tox *m) 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(); prompt = new_prompt();
int n_prompt = add_window(m, prompt); int n_prompt = add_window(m, prompt);
if (n_prompt < 0) { if (n_prompt < 0) {
@ -430,25 +436,18 @@ void on_window_resize(void)
refresh(); refresh();
clear(); 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) { for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] == NULL) { ToxWindow *w = windows[i];
if (w == NULL) {
continue; continue;
} }
ToxWindow *w = windows[i]; if (w->type == WINDOW_TYPE_FRIEND_LIST) {
delwin(w->window_bar);
if (windows[i]->type == WINDOW_TYPE_FRIEND_LIST) {
delwin(w->window); 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; continue;
} }
@ -465,22 +464,35 @@ void on_window_resize(void)
delwin(w->chatwin->linewin); delwin(w->chatwin->linewin);
delwin(w->chatwin->history); delwin(w->chatwin->history);
delwin(w->window_bar);
delwin(w->window); delwin(w->window);
w->window = newwin(y2, x2, 0, 0); w->window = newwin(LINES, COLS, 0, 0);
w->chatwin->linewin = subwin(w->window, CHATBOX_HEIGHT, x2, y2 - CHATBOX_HEIGHT, 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) { if (w->show_peerlist) {
w->chatwin->history = subwin(w->window, y2 - CHATBOX_HEIGHT + 1, x2 - SIDEBAR_WIDTH - 1, 0, 0); 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 + 1, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH); w->chatwin->sidebar = subwin(w->window, y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT, SIDEBAR_WIDTH, 0, x2 - SIDEBAR_WIDTH);
} else { } 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) { 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 #ifdef AUDIO
if (w->chatwin->infobox.active) { if (w->chatwin->infobox.active) {
@ -491,97 +503,103 @@ void on_window_resize(void)
#endif /* AUDIO */ #endif /* AUDIO */
scrollok(w->chatwin->history, 0); 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); pthread_mutex_lock(&Winthread.lock);
if (toxwin->alert != WINDOW_ALERT_NONE) { bool has_alert = toxwin->alert != WINDOW_ALERT_NONE;
attron(COLOR_PAIR(toxwin->alert));
}
unsigned int pending_messages = toxwin->pending_messages; unsigned int pending_messages = toxwin->pending_messages;
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
clrtoeol();
WINDOW_TYPE type = toxwin->type; WINDOW_TYPE type = toxwin->type;
if (active_window || (type == WINDOW_TYPE_PROMPT || type == WINDOW_TYPE_FRIEND_LIST)) { if (active_window) {
printw(" [%s]", toxwin->name); wattron(win, A_BOLD | COLOR_PAIR(BAR_ACCENT));
wprintw(win, " [");
wattroff(win, COLOR_PAIR(BAR_ACCENT));
wattron(win, COLOR_PAIR(BAR_TEXT));
} else { } else {
if (pending_messages > 0) { if (has_alert) {
printw(" [%u]", pending_messages); wattron(win, COLOR_PAIR(BAR_ACCENT));
wprintw(win, " [");
wattroff(win, COLOR_PAIR(BAR_ACCENT));
wattron(win, A_BOLD | COLOR_PAIR(toxwin->alert));
} else { } else {
printw(" [*]"); wattron(win, COLOR_PAIR(BAR_ACCENT));
wprintw(win, " [");
wattroff(win, COLOR_PAIR(BAR_ACCENT));
wattron(win, COLOR_PAIR(BAR_TEXT));
} }
} }
pthread_mutex_lock(&Winthread.lock); if (active_window || (type == WINDOW_TYPE_PROMPT || type == WINDOW_TYPE_FRIEND_LIST)) {
wprintw(win, "%s", toxwin->name);
if (toxwin->alert != WINDOW_ALERT_NONE) { } else {
attroff(COLOR_PAIR(toxwin->alert)); if (pending_messages > 0) {
wprintw(win, "%u", pending_messages);
} else {
wprintw(win, "-");
}
} }
pthread_mutex_unlock(&Winthread.lock); if (active_window) {
wattroff(win, COLOR_PAIR(BAR_TEXT));
wattron(win, COLOR_PAIR(BAR_ACCENT));
wprintw(win, "]");
wattroff(win, A_BOLD | COLOR_PAIR(BAR_ACCENT));
} else {
if (has_alert) {
wattroff(win, A_BOLD | COLOR_PAIR(toxwin->alert));
wattron(win, COLOR_PAIR(BAR_ACCENT));
wprintw(win, "]");
wattroff(win, COLOR_PAIR(BAR_ACCENT));
} else {
wattroff(win, COLOR_PAIR(BAR_TEXT));
wattron(win, COLOR_PAIR(BAR_ACCENT));
wprintw(win, "]");
wattroff(win, COLOR_PAIR(BAR_ACCENT));
}
}
} }
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 (self->scroll_pause) {
wattron(win, A_BLINK | A_BOLD | COLOR_PAIR(BAR_NOTIFY));
if (w == NULL) { wprintw(win, "^");
return; wattroff(win, A_BLINK | A_BOLD | COLOR_PAIR(BAR_NOTIFY));
} else {
wattron(win, COLOR_PAIR(BAR_TEXT));
wprintw(win, " ");
wattroff(win, COLOR_PAIR(BAR_TEXT));
} }
// 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) { for (uint8_t i = 0; i < MAX_WINDOWS_NUM; ++i) {
if (windows[i] == NULL) { if (windows[i] == NULL) {
continue; continue;
} }
bool active_window = i == active_window_index; bool active_window = i == active_window_index;
draw_window_tab(win, windows[i], active_window);
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);
}
} }
// restore cursor position after drawing int cur_x;
move(y, x); int cur_y;
UNUSED_VAR(cur_y);
refresh(); getyx(win, cur_y, cur_x);
wattron(win, COLOR_PAIR(BAR_TEXT));
mvwhline(win, 0, cur_x, ' ', COLS - cur_x);
wattroff(win, COLOR_PAIR(BAR_TEXT));
} }
/* /*
@ -684,8 +702,6 @@ void draw_active_window(Tox *m)
a->pending_messages = 0; a->pending_messages = 0;
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
draw_bar();
touchwin(a->window); touchwin(a->window);
a->onDraw(a, m); a->onDraw(a, m);
wrefresh(a->window); wrefresh(a->window);

View File

@ -39,9 +39,11 @@
#define MAX_WINDOWS_NUM 20 #define MAX_WINDOWS_NUM 20
#define MAX_WINDOW_NAME_LENGTH 22 #define MAX_WINDOW_NAME_LENGTH 22
#define CURS_Y_OFFSET 1 /* y-axis cursor offset for chat contexts */ #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 { typedef enum {
WHITE, WHITE,
GREEN, GREEN,
@ -51,14 +53,24 @@ typedef enum {
YELLOW, YELLOW,
MAGENTA, MAGENTA,
BLACK, BLACK,
BLUE_BLACK,
BLACK_WHITE,
BAR_TEXT,
STATUS_ONLINE,
BAR_ACCENT,
PURPLE_BG,
BLACK_BG,
STATUS_BUSY,
STATUS_AWAY,
BAR_NOTIFY,
} C_COLOURS; } C_COLOURS;
/* tab alert types: lower types take priority (this relies on the order of C_COLOURS) */ /* tab alert types: lower types take priority (this relies on the order of C_COLOURS) */
typedef enum { typedef enum {
WINDOW_ALERT_NONE = 0, WINDOW_ALERT_NONE = 0,
WINDOW_ALERT_0 = GREEN, WINDOW_ALERT_0 = STATUS_ONLINE,
WINDOW_ALERT_1 = RED, WINDOW_ALERT_1 = BAR_ACCENT,
WINDOW_ALERT_2 = MAGENTA, WINDOW_ALERT_2 = PURPLE_BG,
} WINDOW_ALERTS; } WINDOW_ALERTS;
typedef enum { typedef enum {
@ -167,6 +179,7 @@ struct ToxWindow {
char name[TOXIC_MAX_NAME_LENGTH + 1]; char name[TOXIC_MAX_NAME_LENGTH + 1];
uint32_t num; /* corresponds to friendnumber in chat windows */ uint32_t num; /* corresponds to friendnumber in chat windows */
uint8_t index; /* This window's index in the windows array */ 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 */ unsigned int pending_messages; /* # of new messages in this window since the last time it was focused */
int x; int x;
@ -181,6 +194,7 @@ struct ToxWindow {
Help *help; Help *help;
WINDOW *window; WINDOW *window;
WINDOW *window_bar;
}; };
/* statusbar info holder */ /* statusbar info holder */
@ -264,6 +278,7 @@ void on_window_resize(void);
void force_refresh(WINDOW *w); void force_refresh(WINDOW *w);
ToxWindow *get_window_ptr(size_t i); ToxWindow *get_window_ptr(size_t i);
ToxWindow *get_active_window(void); ToxWindow *get_active_window(void);
void draw_window_bar(ToxWindow *self);
/* refresh inactive windows to prevent scrolling bugs. /* refresh inactive windows to prevent scrolling bugs.
call at least once per second */ call at least once per second */