mirror of
https://github.com/Tha14/toxic.git
synced 2025-07-04 09:36:45 +02:00
Compare commits
36 Commits
v0.9.0
...
TokTok-mas
Author | SHA1 | Date | |
---|---|---|---|
ae94bc593b | |||
81eb58532e | |||
8464ea9a7a | |||
b77bff35a1 | |||
eb964b64c2 | |||
2ff9d29491 | |||
2640919318 | |||
2fcbc4fa1c | |||
4330bf5867 | |||
3f1b7cdd26 | |||
1e985c1456 | |||
61740bda85 | |||
0d8e6d713e | |||
39e4ff8bd6 | |||
0434ac186a | |||
8d9d51640c | |||
c4c0c0d1f4 | |||
3f2826bd66 | |||
7b7ea0e386 | |||
d35a38735b | |||
f0c4906fdc | |||
56ba61e061 | |||
898d89e95a | |||
1fd1e27bdf | |||
8e84ac58d4 | |||
9d65997871 | |||
da2889f3ab | |||
312b38d253 | |||
0554bf0240 | |||
53a7530e8a | |||
41be04a142 | |||
31f36318a2 | |||
f882fdf608 | |||
7e1e410307 | |||
c135c812c2 | |||
6c239193ab |
@ -59,6 +59,8 @@ Run `make doc` in the build directory after editing the asciidoc files to regene
|
|||||||
* `DISABLE_QRPNG` → Disable support for exporting QR as PNG
|
* `DISABLE_QRPNG` → Disable support for exporting QR as PNG
|
||||||
* `DISABLE_DESKTOP_NOTIFY=1` → Disable desktop notifications support
|
* `DISABLE_DESKTOP_NOTIFY=1` → Disable desktop notifications support
|
||||||
* `ENABLE_PYTHON=1` → Build toxic with Python scripting support
|
* `ENABLE_PYTHON=1` → Build toxic with Python scripting support
|
||||||
|
* `ENABLE_RELEASE=1` → Build toxic without debug symbols and with full compiler optimizations
|
||||||
|
* `ENABLE_ASAN=1` → Build toxic with LLVM Address Sanitizer enabled
|
||||||
|
|
||||||
* `DESTDIR=""` Specifies the base install directory for binaries and data files (e.g.: DESTDIR="/tmp/build/pkg")
|
* `DESTDIR=""` Specifies the base install directory for binaries and data files (e.g.: DESTDIR="/tmp/build/pkg")
|
||||||
|
|
||||||
|
19
Makefile
19
Makefile
@ -5,8 +5,7 @@ CFG_DIR = $(BASE_DIR)/cfg
|
|||||||
|
|
||||||
LIBS = toxcore ncursesw libconfig libcurl
|
LIBS = toxcore ncursesw libconfig libcurl
|
||||||
|
|
||||||
CFLAGS ?= -g
|
CFLAGS ?= -std=c99 -pthread -Wall -Wpedantic -Wunused -fstack-protector-all -Wvla -Wno-missing-braces
|
||||||
CFLAGS += -std=c99 -pthread -Wall -Wpedantic -Wunused -fstack-protector-all -Wvla -Wmissing-field-initializers -Wno-missing-braces
|
|
||||||
CFLAGS += '-DTOXICVER="$(VERSION)"' -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED -D_FILE_OFFSET_BITS=64
|
CFLAGS += '-DTOXICVER="$(VERSION)"' -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED -D_FILE_OFFSET_BITS=64
|
||||||
CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"'
|
CFLAGS += '-DPACKAGE_DATADIR="$(abspath $(DATADIR))"'
|
||||||
CFLAGS += ${USER_CFLAGS}
|
CFLAGS += ${USER_CFLAGS}
|
||||||
@ -18,6 +17,22 @@ OBJ += file_transfers.o friendlist.o global_commands.o conference_commands.o con
|
|||||||
OBJ += line_info.o log.o message_queue.o misc_tools.o name_lookup.o notify.o prompt.o qr_code.o settings.o
|
OBJ += line_info.o log.o message_queue.o misc_tools.o name_lookup.o notify.o prompt.o qr_code.o settings.o
|
||||||
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
|
||||||
|
RELEASE := $(shell if [ -z "$(ENABLE_RELEASE)" ] || [ "$(ENABLE_RELEASE)" = "0" ] ; then echo disabled ; else echo enabled ; fi)
|
||||||
|
ifneq ($(RELEASE), enabled)
|
||||||
|
CFLAGS += -O0 -g -DDEBUG
|
||||||
|
LDFLAGS += -O0
|
||||||
|
else
|
||||||
|
CFLAGS += -O2 -flto
|
||||||
|
LDFLAGS += -O2 -flto
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Check if LLVM Address Sanitizer is enabled
|
||||||
|
ENABLE_ASAN := $(shell if [ -z "$(ENABLE_ASAN)" ] || [ "$(ENABLE_ASAN)" = "0" ] ; then echo disabled ; else echo enabled ; fi)
|
||||||
|
ifneq ($(ENABLE_ASAN), disabled)
|
||||||
|
CFLAGS += -fsanitize=address -fno-omit-frame-pointer
|
||||||
|
endif
|
||||||
|
|
||||||
# Check on wich system we are running
|
# Check on wich system we are running
|
||||||
UNAME_S = $(shell uname -s)
|
UNAME_S = $(shell uname -s)
|
||||||
ifeq ($(UNAME_S), Linux)
|
ifeq ($(UNAME_S), Linux)
|
||||||
|
@ -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.
|
||||||
|
|
||||||
[](https://i.imgur.com/san99Z2.png)
|
[](https://i.imgur.com/TwYA8L0.png)
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
[See the install instructions](/INSTALL.md)
|
[See the install instructions](/INSTALL.md)
|
||||||
|
@ -55,9 +55,9 @@ author = 'Jakob Kreuze'
|
|||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '0.9.0'
|
version = '0.10.0'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '0.9.0'
|
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.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Variables for X11 support
|
# Variables for X11 support
|
||||||
X11_LIBS = x11
|
X11_LIBS = x11
|
||||||
X11_CFLAGS = -DX11
|
X11_CFLAGS = -DX11
|
||||||
X11_OBJ = xtra.o
|
X11_OBJ = x11focus.o
|
||||||
|
|
||||||
# Check if we can build X11 support
|
# Check if we can build X11 support
|
||||||
CHECK_X11_LIBS = $(shell $(PKG_CONFIG) --exists $(X11_LIBS) || echo -n "error")
|
CHECK_X11_LIBS = $(shell $(PKG_CONFIG) --exists $(X11_LIBS) || echo -n "error")
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Version
|
# Version
|
||||||
TOXIC_VERSION = 0.9.0
|
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)
|
||||||
|
@ -17,6 +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 " ENABLE_RELEASE: Set to \"1\" to build without debug symbols and with full compiler optimizations"
|
||||||
|
@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))\")"
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
'\" t
|
'\" t
|
||||||
.\" Title: toxic
|
.\" Title: toxic
|
||||||
.\" Author: [see the "AUTHORS" section]
|
.\" Author: [see the "AUTHORS" section]
|
||||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
|
||||||
.\" Date: 2016-09-20
|
.\" Date: 2020-05-04
|
||||||
.\" Manual: Toxic Manual
|
.\" Manual: Toxic Manual
|
||||||
.\" Source: toxic __VERSION__
|
.\" Source: toxic __VERSION__
|
||||||
.\" Language: English
|
.\" Language: English
|
||||||
.\"
|
.\"
|
||||||
.TH "TOXIC" "1" "2016\-09\-20" "toxic __VERSION__" "Toxic Manual"
|
.TH "TOXIC" "1" "2020\-05\-04" "toxic __VERSION__" "Toxic Manual"
|
||||||
.\" -----------------------------------------------------------------
|
.\" -----------------------------------------------------------------
|
||||||
.\" * Define some portability stuff
|
.\" * Define some portability stuff
|
||||||
.\" -----------------------------------------------------------------
|
.\" -----------------------------------------------------------------
|
||||||
|
@ -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: 2018-10-27
|
.\" Date: 2020-11-18
|
||||||
.\" Manual: Toxic Manual
|
.\" Manual: Toxic Manual
|
||||||
.\" Source: toxic __VERSION__
|
.\" Source: toxic __VERSION__
|
||||||
.\" Language: English
|
.\" Language: English
|
||||||
.\"
|
.\"
|
||||||
.TH "TOXIC\&.CONF" "5" "2018\-10\-27" "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
|
||||||
@ -135,7 +155,7 @@ Maximum lines for chat window history\&. Integer value\&. (for example: 700)
|
|||||||
.PP
|
.PP
|
||||||
\fBnotification_timeout\fR
|
\fBnotification_timeout\fR
|
||||||
.RS 4
|
.RS 4
|
||||||
Time in milliseconds to display a notification\&. (for example: 3000)
|
Time in milliseconds to display a notification\&. Integer value\&. (for example: 3000)
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
\fBline_join\fR
|
\fBline_join\fR
|
||||||
@ -219,7 +239,22 @@ Audio output device\&. Integer value\&. Number corresponds to
|
|||||||
.PP
|
.PP
|
||||||
\fBVAD_threshold\fR
|
\fBVAD_threshold\fR
|
||||||
.RS 4
|
.RS 4
|
||||||
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
|
||||||
|
.PP
|
||||||
|
\fBconference_audio_channels\fR
|
||||||
|
.RS 4
|
||||||
|
Number of channels for conference audio broadcast\&. Integer value\&. 1 (mono) or 2 (stereo)
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
\fBchat_audio_channels\fR
|
||||||
|
.RS 4
|
||||||
|
Number of channels for 1\-on\-1 audio broadcast\&. Integer value\&. 1 (mono) or 2 (stereo)
|
||||||
|
.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
|
.RE
|
||||||
.PP
|
.PP
|
||||||
|
@ -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
|
||||||
|
|
||||||
@ -139,6 +151,15 @@ OPTIONS
|
|||||||
Voice Activity Detection threshold. Float value. Recommended values are
|
Voice Activity Detection threshold. Float value. Recommended values are
|
||||||
1.0-40.0
|
1.0-40.0
|
||||||
|
|
||||||
|
*conference_audio_channels*;;
|
||||||
|
Number of channels for conference audio broadcast. Integer value. 1 (mono) or 2 (stereo)
|
||||||
|
|
||||||
|
*chat_audio_channels*;;
|
||||||
|
Number of channels for 1-on-1 audio broadcast. Integer value. 1 (mono) or 2 (stereo)
|
||||||
|
|
||||||
|
*push_to_talk*;;
|
||||||
|
Enable/Disable Push-To-Talk for conference audio chats (active key is F2). true or false
|
||||||
|
|
||||||
*tox*::
|
*tox*::
|
||||||
Configuration related to paths.
|
Configuration related to paths.
|
||||||
|
|
||||||
|
@ -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;
|
||||||
@ -84,6 +96,15 @@ audio = {
|
|||||||
|
|
||||||
// default VAD threshold; float (recommended values are 1.0-40.0)
|
// default VAD threshold; float (recommended values are 1.0-40.0)
|
||||||
VAD_threshold=5.0;
|
VAD_threshold=5.0;
|
||||||
|
|
||||||
|
// Number of channels to use for conference audio broadcasts; 1 for mono, 2 for stereo.
|
||||||
|
conference_audio_channels=1;
|
||||||
|
|
||||||
|
// Number of channels to use for 1-on-1 audio broadcasts; 1 for mono, 2 for stereo.
|
||||||
|
chat_audio_channels=2;
|
||||||
|
|
||||||
|
// toggle conference push-to-talk
|
||||||
|
push_to_talk=false;
|
||||||
};
|
};
|
||||||
|
|
||||||
tox = {
|
tox = {
|
||||||
@ -122,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";
|
||||||
};
|
};
|
||||||
|
30
src/api.c
30
src/api.c
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,36 +173,36 @@ void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
|
|||||||
|
|
||||||
void invoke_autoruns(WINDOW *window, ToxWindow *self)
|
void invoke_autoruns(WINDOW *window, ToxWindow *self)
|
||||||
{
|
{
|
||||||
struct dirent *dir;
|
char abspath_buf[PATH_MAX + 256];
|
||||||
char abspath_buf[PATH_MAX + 1], err_buf[PATH_MAX + 1];
|
char err_buf[PATH_MAX + 128];
|
||||||
size_t path_len;
|
|
||||||
DIR *d;
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
if (user_settings->autorun_path[0] == '\0') {
|
if (user_settings->autorun_path[0] == '\0') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
d = opendir(user_settings->autorun_path);
|
DIR *d = opendir(user_settings->autorun_path);
|
||||||
|
|
||||||
if (d == NULL) {
|
if (d == NULL) {
|
||||||
snprintf(err_buf, PATH_MAX + 1, "Autorun path does not exist: %s", user_settings->autorun_path);
|
snprintf(err_buf, sizeof(err_buf), "Autorun path does not exist: %s", user_settings->autorun_path);
|
||||||
api_display(err_buf);
|
api_display(err_buf);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct dirent *dir = NULL;
|
||||||
|
|
||||||
cur_window = window;
|
cur_window = window;
|
||||||
|
|
||||||
self_window = self;
|
self_window = self;
|
||||||
|
|
||||||
while ((dir = readdir(d)) != NULL) {
|
while ((dir = readdir(d)) != NULL) {
|
||||||
path_len = strlen(dir->d_name);
|
size_t path_len = strlen(dir->d_name);
|
||||||
|
|
||||||
if (!strcmp(dir->d_name + path_len - 3, ".py")) {
|
if (!strcmp(dir->d_name + path_len - 3, ".py")) {
|
||||||
snprintf(abspath_buf, PATH_MAX + 1, "%s%s", user_settings->autorun_path, dir->d_name);
|
snprintf(abspath_buf, sizeof(abspath_buf), "%s%s", user_settings->autorun_path, dir->d_name);
|
||||||
fp = fopen(abspath_buf, "r");
|
FILE *fp = fopen(abspath_buf, "r");
|
||||||
|
|
||||||
if (fp == NULL) {
|
if (fp == NULL) {
|
||||||
snprintf(err_buf, PATH_MAX + 1, "Invalid path: %s", abspath_buf);
|
snprintf(err_buf, sizeof(err_buf), "Invalid path: %s", abspath_buf);
|
||||||
api_display(err_buf);
|
api_display(err_buf);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "line_info.h"
|
#include "line_info.h"
|
||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
|
#include "settings.h"
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
|
|
||||||
@ -64,6 +65,7 @@ extern ToxWindow *windows[MAX_WINDOWS_NUM];
|
|||||||
|
|
||||||
struct CallControl CallControl;
|
struct CallControl CallControl;
|
||||||
|
|
||||||
|
extern struct user_settings *user_settings;
|
||||||
extern struct Winthread Winthread;
|
extern struct Winthread Winthread;
|
||||||
|
|
||||||
void on_call(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled,
|
void on_call(ToxAV *av, uint32_t friend_number, bool audio_enabled, bool video_enabled,
|
||||||
@ -88,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)
|
||||||
@ -103,7 +105,7 @@ ToxAV *init_audio(ToxWindow *self, Tox *tox)
|
|||||||
CallControl.default_audio_bit_rate = 64;
|
CallControl.default_audio_bit_rate = 64;
|
||||||
CallControl.audio_sample_rate = 48000;
|
CallControl.audio_sample_rate = 48000;
|
||||||
CallControl.audio_frame_duration = 20;
|
CallControl.audio_frame_duration = 20;
|
||||||
CallControl.audio_channels = 1;
|
CallControl.audio_channels = user_settings->chat_audio_channels;
|
||||||
|
|
||||||
CallControl.video_enabled = false;
|
CallControl.video_enabled = false;
|
||||||
CallControl.default_video_bit_rate = 0;
|
CallControl.default_video_bit_rate = 0;
|
||||||
@ -111,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;
|
||||||
@ -198,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,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;
|
||||||
@ -340,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) {
|
||||||
@ -667,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -706,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -746,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -814,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;
|
||||||
}
|
}
|
||||||
@ -914,7 +916,7 @@ void stop_current_call(ToxWindow *self)
|
|||||||
*/
|
*/
|
||||||
static void realloc_calls(uint32_t n)
|
static void realloc_calls(uint32_t n)
|
||||||
{
|
{
|
||||||
if (n <= 0) {
|
if (n == 0) {
|
||||||
free(CallControl.calls);
|
free(CallControl.calls);
|
||||||
CallControl.calls = NULL;
|
CallControl.calls = NULL;
|
||||||
return;
|
return;
|
||||||
|
@ -397,7 +397,7 @@ static DeviceError open_source(Device *device)
|
|||||||
alSourcei(device->source, AL_LOOPING, AL_FALSE);
|
alSourcei(device->source, AL_LOOPING, AL_FALSE);
|
||||||
|
|
||||||
const uint32_t frame_size = device->frame_info.samples_per_frame * sample_size(device->frame_info.stereo);
|
const uint32_t frame_size = device->frame_info.samples_per_frame * sample_size(device->frame_info.stereo);
|
||||||
size_t zeros_size = frame_size / 2;
|
size_t zeros_size = frame_size * sizeof(uint16_t);
|
||||||
uint16_t *zeros = calloc(1, zeros_size);
|
uint16_t *zeros = calloc(1, zeros_size);
|
||||||
|
|
||||||
if (zeros == NULL) {
|
if (zeros == NULL) {
|
||||||
@ -407,7 +407,7 @@ static DeviceError open_source(Device *device)
|
|||||||
|
|
||||||
for (int i = 0; i < OPENAL_BUFS; ++i) {
|
for (int i = 0; i < OPENAL_BUFS; ++i) {
|
||||||
alBufferData(device->buffers[i], sound_mode(device->frame_info.stereo), zeros,
|
alBufferData(device->buffers[i], sound_mode(device->frame_info.stereo), zeros,
|
||||||
frame_size, device->frame_info.sample_rate);
|
zeros_size, device->frame_info.sample_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(zeros);
|
free(zeros);
|
||||||
@ -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]);
|
||||||
|
@ -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.
|
||||||
@ -109,7 +109,7 @@ static int complete_line_helper(ToxWindow *self, const char **list, const size_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char *endchrs = " ";
|
const char *endchrs = " ";
|
||||||
char ubuf[MAX_STR_SIZE] = {0};
|
char ubuf[MAX_STR_SIZE];
|
||||||
|
|
||||||
/* work with multibyte string copy of buf for simplicity */
|
/* work with multibyte string copy of buf for simplicity */
|
||||||
if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1) {
|
if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1) {
|
||||||
@ -118,8 +118,8 @@ static int complete_line_helper(ToxWindow *self, const char **list, const size_t
|
|||||||
|
|
||||||
/* isolate substring from space behind pos to pos */
|
/* isolate substring from space behind pos to pos */
|
||||||
char tmp[MAX_STR_SIZE];
|
char tmp[MAX_STR_SIZE];
|
||||||
snprintf(tmp, sizeof(tmp), "%s", ubuf);
|
memcpy(tmp, ubuf, ctx->pos);
|
||||||
tmp[ctx->pos] = '\0';
|
tmp[ctx->pos] = 0;
|
||||||
|
|
||||||
const char *s = dir_search ? strchr(tmp, ' ') : strrchr(tmp, ' ');
|
const char *s = dir_search ? strchr(tmp, ' ') : strrchr(tmp, ' ');
|
||||||
char *sub = calloc(1, strlen(ubuf) + 1);
|
char *sub = calloc(1, strlen(ubuf) + 1);
|
||||||
@ -147,7 +147,7 @@ static int complete_line_helper(ToxWindow *self, const char **list, const size_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sub[0]) {
|
if (!sub[0] && !(dir_search && n_items == 1)) {
|
||||||
free(sub);
|
free(sub);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
256
src/chat.c
256
src/chat.c
@ -128,7 +128,14 @@ static void set_self_typingstatus(ToxWindow *self, Tox *m, bool is_typing)
|
|||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
tox_self_set_typing(m, self->num, is_typing, NULL);
|
TOX_ERR_SET_TYPING err;
|
||||||
|
tox_self_set_typing(m, self->num, is_typing, &err);
|
||||||
|
|
||||||
|
if (err != TOX_ERR_SET_TYPING_OK) {
|
||||||
|
fprintf(stderr, "Warning: tox_self_set_typing() failed with error %d\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ctx->self_is_typing = is_typing;
|
ctx->self_is_typing = is_typing;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,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) {
|
||||||
@ -176,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) {
|
||||||
@ -203,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,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);
|
||||||
|
|
||||||
@ -247,19 +248,19 @@ 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;
|
||||||
|
|
||||||
if (self->chatwin->self_is_typing) {
|
if (self->chatwin->self_is_typing) {
|
||||||
set_self_typingstatus(self, m, 0);
|
set_self_typingstatus(self, m, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -497,18 +498,16 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char msg[MAX_STR_SIZE];
|
|
||||||
|
|
||||||
switch (control) {
|
switch (control) {
|
||||||
case TOX_FILE_CONTROL_RESUME: {
|
case TOX_FILE_CONTROL_RESUME: {
|
||||||
/* 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 */
|
||||||
@ -524,6 +523,7 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, uint32_t friendnum, uint
|
|||||||
}
|
}
|
||||||
|
|
||||||
case TOX_FILE_CONTROL_CANCEL: {
|
case TOX_FILE_CONTROL_CANCEL: {
|
||||||
|
char msg[MAX_STR_SIZE];
|
||||||
snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", ft->file_name);
|
snprintf(msg, sizeof(msg), "File transfer for '%s' was aborted.", ft->file_name);
|
||||||
close_file_transfer(self, m, ft, -1, msg, notif_error);
|
close_file_transfer(self, m, ft, -1, msg, notif_error);
|
||||||
break;
|
break;
|
||||||
@ -631,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);
|
||||||
@ -697,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);
|
||||||
@ -739,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 */
|
||||||
@ -771,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);
|
||||||
@ -793,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
|
||||||
|
|
||||||
@ -815,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;
|
||||||
@ -835,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;
|
||||||
|
|
||||||
@ -854,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);
|
||||||
@ -875,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);
|
||||||
@ -893,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);
|
||||||
@ -909,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
|
||||||
@ -927,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
|
||||||
@ -1027,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1045,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1083,7 +1080,7 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
input_new_char(self, key, x, x2);
|
input_new_char(self, key, x, x2);
|
||||||
|
|
||||||
if (ctx->line[0] != '/' && !ctx->self_is_typing && statusbar->connection != TOX_CONNECTION_NONE) {
|
if (ctx->line[0] != '/' && !ctx->self_is_typing && statusbar->connection != TOX_CONNECTION_NONE) {
|
||||||
set_self_typingstatus(self, m, 1);
|
set_self_typingstatus(self, m, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -1093,11 +1090,7 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input_handle(self, key, x, x2)) {
|
int input_ret = input_handle(self, key, x, x2);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int input_ret = false;
|
|
||||||
|
|
||||||
if (key == L'\t' && ctx->len > 1 && ctx->line[0] == '/') { /* TAB key: auto-complete */
|
if (key == L'\t' && ctx->len > 1 && ctx->line[0] == '/') { /* TAB key: auto-complete */
|
||||||
input_ret = true;
|
input_ret = true;
|
||||||
@ -1146,7 +1139,7 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
|
|
||||||
wstrsubst(ctx->line, L'¶', L'\n');
|
wstrsubst(ctx->line, L'¶', L'\n');
|
||||||
|
|
||||||
char line[MAX_STR_SIZE] = {0};
|
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) {
|
||||||
memset(line, 0, sizeof(line));
|
memset(line, 0, sizeof(line));
|
||||||
@ -1161,28 +1154,27 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
} else {
|
} else {
|
||||||
execute(ctx->history, self, m, line, CHAT_COMMAND_MODE);
|
execute(ctx->history, self, m, line, CHAT_COMMAND_MODE);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (line[0]) {
|
||||||
char selfname[TOX_MAX_NAME_LENGTH];
|
char selfname[TOX_MAX_NAME_LENGTH];
|
||||||
tox_self_get_name(m, (uint8_t *) selfname);
|
tox_self_get_name(m, (uint8_t *) selfname);
|
||||||
|
|
||||||
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 {
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->len <= 0 && ctx->self_is_typing) {
|
if (ctx->len <= 0 && ctx->self_is_typing) {
|
||||||
set_self_typingstatus(self, m, 0);
|
set_self_typingstatus(self, m, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return input_ret;
|
return input_ret;
|
||||||
@ -1190,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) {
|
||||||
@ -1205,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 */
|
||||||
@ -1223,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 */
|
||||||
@ -1283,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);
|
||||||
|
|
||||||
@ -1327,10 +1365,35 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
|
|||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void chat_init_log(ToxWindow *self, Tox *m, const char *self_nick)
|
||||||
|
{
|
||||||
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
|
char myid[TOX_ADDRESS_SIZE];
|
||||||
|
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) {
|
||||||
|
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to initialize chat log.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (load_chat_history(self, ctx->log) != 0) {
|
||||||
|
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to load chat history.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Friends.list[self->num].logging_on) {
|
||||||
|
if (log_enable(ctx->log) != 0) {
|
||||||
|
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to enable chat log.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
@ -1363,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));
|
||||||
@ -1377,19 +1441,9 @@ static void chat_onInit(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
line_info_init(ctx->hst);
|
line_info_init(ctx->hst);
|
||||||
|
|
||||||
char myid[TOX_ADDRESS_SIZE];
|
chat_init_log(self, m, nick);
|
||||||
tox_self_get_address(m, (uint8_t *) myid);
|
|
||||||
|
|
||||||
int log_ret = log_enable(nick, myid, Friends.list[self->num].pub_key, ctx->log, LOG_CHAT);
|
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE); // Print log status to screen
|
||||||
load_chat_history(self, ctx->log);
|
|
||||||
|
|
||||||
if (!Friends.list[self->num].logging_on) {
|
|
||||||
log_disable(ctx->log);
|
|
||||||
} else if (log_ret == -1) {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
|
|
||||||
}
|
|
||||||
|
|
||||||
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
|
|
||||||
|
|
||||||
scrollok(ctx->history, 0);
|
scrollok(ctx->history, 0);
|
||||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
331
src/conference.c
331
src/conference.c
@ -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;
|
||||||
|
|
||||||
@ -100,6 +103,7 @@ static const char *conference_cmd_list[] = {
|
|||||||
"/quit",
|
"/quit",
|
||||||
"/requests",
|
"/requests",
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
|
"/ptt",
|
||||||
"/sense",
|
"/sense",
|
||||||
#endif
|
#endif
|
||||||
"/status",
|
"/status",
|
||||||
@ -114,6 +118,25 @@ static const char *conference_cmd_list[] = {
|
|||||||
|
|
||||||
static ToxWindow *new_conference_chat(uint32_t conferencenum);
|
static ToxWindow *new_conference_chat(uint32_t conferencenum);
|
||||||
|
|
||||||
|
void conference_set_title(ToxWindow *self, uint32_t conferencesnum, const char *title, size_t length)
|
||||||
|
{
|
||||||
|
ConferenceChat *chat = &conferences[conferencesnum];
|
||||||
|
|
||||||
|
if (!chat->active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length > CONFERENCE_MAX_TITLE_LENGTH) {
|
||||||
|
length = CONFERENCE_MAX_TITLE_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(chat->title, title, length);
|
||||||
|
chat->title[length] = 0;
|
||||||
|
chat->title_length = length;
|
||||||
|
|
||||||
|
set_window_title(self, title, length);
|
||||||
|
}
|
||||||
|
|
||||||
static void kill_conference_window(ToxWindow *self)
|
static void kill_conference_window(ToxWindow *self)
|
||||||
{
|
{
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
@ -130,8 +153,35 @@ static void kill_conference_window(ToxWindow *self)
|
|||||||
del_window(self);
|
del_window(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char *title,
|
static void init_conference_logging(ToxWindow *self, Tox *m, uint32_t conferencenum)
|
||||||
size_t title_length)
|
{
|
||||||
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
|
char my_id[TOX_ADDRESS_SIZE];
|
||||||
|
tox_self_get_address(m, (uint8_t *) my_id);
|
||||||
|
|
||||||
|
char conference_id[TOX_CONFERENCE_ID_SIZE];
|
||||||
|
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) {
|
||||||
|
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (load_chat_history(self, ctx->log) != 0) {
|
||||||
|
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to load chat history.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_settings->autolog == AUTOLOG_ON) {
|
||||||
|
if (log_enable(ctx->log) != 0) {
|
||||||
|
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to enable chat log.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE); // print log state to screen
|
||||||
|
}
|
||||||
|
|
||||||
|
int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char *title, size_t length)
|
||||||
{
|
{
|
||||||
if (conferencenum > MAX_CONFERENCE_NUM) {
|
if (conferencenum > MAX_CONFERENCE_NUM) {
|
||||||
return -1;
|
return -1;
|
||||||
@ -154,8 +204,15 @@ int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char
|
|||||||
conferences[i].audio_enabled = false;
|
conferences[i].audio_enabled = false;
|
||||||
conferences[i].last_sent_audio = 0;
|
conferences[i].last_sent_audio = 0;
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
conferences[i].push_to_talk_enabled = user_settings->push_to_talk;
|
||||||
|
#endif
|
||||||
|
|
||||||
set_active_window_index(conferences[i].chatwin);
|
set_active_window_index(conferences[i].chatwin);
|
||||||
set_window_title(self, title, title_length);
|
|
||||||
|
conference_set_title(self, conferencenum, title, length);
|
||||||
|
|
||||||
|
init_conference_logging(self, m, conferencenum);
|
||||||
|
|
||||||
if (i == max_conference_index) {
|
if (i == max_conference_index) {
|
||||||
++max_conference_index;
|
++max_conference_index;
|
||||||
@ -225,6 +282,25 @@ static void delete_conference(ToxWindow *self, Tox *m, uint32_t conferencenum)
|
|||||||
free_conference(self, conferencenum);
|
free_conference(self, conferencenum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void conference_rename_log_path(Tox *m, uint32_t conferencenum, const char *new_title)
|
||||||
|
{
|
||||||
|
ConferenceChat *chat = &conferences[conferencenum];
|
||||||
|
|
||||||
|
if (!chat->active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char myid[TOX_ADDRESS_SIZE];
|
||||||
|
tox_self_get_address(m, (uint8_t *) myid);
|
||||||
|
|
||||||
|
char conference_id[TOX_CONFERENCE_ID_SIZE];
|
||||||
|
tox_conference_get_id(m, conferencenum, (uint8_t *) conference_id);
|
||||||
|
|
||||||
|
if (rename_logfile(chat->title, new_title, myid, conference_id, chat->chatwin) != 0) {
|
||||||
|
fprintf(stderr, "Failed to rename conference log to `%s`\n", new_title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* destroys and re-creates conference window with or without the peerlist */
|
/* destroys and re-creates conference window with or without the peerlist */
|
||||||
void redraw_conference_win(ToxWindow *self)
|
void redraw_conference_win(ToxWindow *self)
|
||||||
{
|
{
|
||||||
@ -234,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;
|
||||||
@ -249,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,
|
||||||
@ -289,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;
|
||||||
@ -302,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,19 +394,24 @@ static void conference_onConferenceTitleChange(ToxWindow *self, Tox *m, uint32_t
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_window_title(self, title, length);
|
ConferenceChat *chat = &conferences[conferencenum];
|
||||||
|
|
||||||
char timefrmt[TIME_STR_SIZE];
|
if (!chat->active) {
|
||||||
get_time_str(timefrmt, sizeof(timefrmt));
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
conference_rename_log_path(m, conferencenum, title); // must be called first
|
||||||
|
|
||||||
|
conference_set_title(self, conferencenum, title, length);
|
||||||
|
|
||||||
/* don't announce title when we join the room */
|
/* don't announce title when we join the room */
|
||||||
if (!timed_out(conferences[self->num].start_time, CONFERENCE_EVENT_WAIT)) {
|
if (!timed_out(conferences[conferencenum].start_time, CONFERENCE_EVENT_WAIT)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
@ -492,6 +572,22 @@ static ConferencePeer *peer_in_conference(uint32_t conferencenum, uint32_t peern
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
|
|
||||||
|
/* Return true if ptt is disabled or enabled and active. */
|
||||||
|
static bool conference_check_push_to_talk(ConferenceChat *chat)
|
||||||
|
{
|
||||||
|
if (!chat->push_to_talk_enabled) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !timed_out(chat->ptt_last_pushed, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void conference_enable_push_to_talk(ConferenceChat *chat)
|
||||||
|
{
|
||||||
|
chat->ptt_last_pushed = get_unix_time();
|
||||||
|
}
|
||||||
|
|
||||||
static void set_peer_audio_position(Tox *m, uint32_t conferencenum, uint32_t peernum)
|
static void set_peer_audio_position(Tox *m, uint32_t conferencenum, uint32_t peernum)
|
||||||
{
|
{
|
||||||
ConferenceChat *chat = &conferences[conferencenum];
|
ConferenceChat *chat = &conferences[conferencenum];
|
||||||
@ -523,7 +619,7 @@ static void set_peer_audio_position(Tox *m, uint32_t conferencenum, uint32_t pee
|
|||||||
const float angle = asinf(peer_posn - (float)(num_posns - 1) / 2);
|
const float angle = asinf(peer_posn - (float)(num_posns - 1) / 2);
|
||||||
set_source_position(peer->audio_out_idx, sinf(angle), cosf(angle), 0);
|
set_source_position(peer->audio_out_idx, sinf(angle), cosf(angle), 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif // AUDIO
|
||||||
|
|
||||||
|
|
||||||
static bool find_peer_by_pubkey(const ConferencePeer *list, uint32_t num_peers, uint8_t *pubkey, uint32_t *idx)
|
static bool find_peer_by_pubkey(const ConferencePeer *list, uint32_t num_peers, uint8_t *pubkey, uint32_t *idx)
|
||||||
@ -532,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -540,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];
|
||||||
|
|
||||||
@ -548,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) {
|
||||||
@ -559,7 +661,11 @@ static void update_peer_list(Tox *m, uint32_t conferencenum, uint32_t num_peers,
|
|||||||
memcpy(old_peer_list, chat->peer_list, old_num_peers * sizeof(ConferencePeer));
|
memcpy(old_peer_list, chat->peer_list, old_num_peers * sizeof(ConferencePeer));
|
||||||
}
|
}
|
||||||
|
|
||||||
realloc_peer_list(chat, num_peers);
|
if (realloc_peer_list(chat, num_peers) != 0) {
|
||||||
|
free(old_peer_list);
|
||||||
|
fprintf(stderr, "Warning: realloc_peer_list() failed in update_peer_list()\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < num_peers; ++i) {
|
for (uint32_t i = 0; i < num_peers; ++i) {
|
||||||
ConferencePeer *peer = &chat->peer_list[i];
|
ConferencePeer *peer = &chat->peer_list[i];
|
||||||
@ -575,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);
|
||||||
@ -601,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)
|
||||||
@ -648,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,
|
||||||
@ -662,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);
|
||||||
@ -688,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -698,7 +823,6 @@ static int sidebar_offset(uint32_t conferencenum)
|
|||||||
return 2 + conferences[conferencenum].audio_enabled;
|
return 2 + conferences[conferencenum].audio_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return true if input is recognized by handler
|
* Return true if input is recognized by handler
|
||||||
*/
|
*/
|
||||||
@ -741,6 +865,15 @@ static bool conference_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
bool input_ret = false;
|
bool input_ret = false;
|
||||||
ConferenceChat *chat = &conferences[self->num];
|
ConferenceChat *chat = &conferences[self->num];
|
||||||
|
|
||||||
|
#ifdef AUDIO
|
||||||
|
|
||||||
|
if (chat->audio_enabled && chat->push_to_talk_enabled && key == KEY_F(2)) {
|
||||||
|
input_ret = true;
|
||||||
|
conference_enable_push_to_talk(chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // AUDIO
|
||||||
|
|
||||||
if (key == L'\t') { /* TAB key: auto-completes peer name or command */
|
if (key == L'\t') { /* TAB key: auto-completes peer name or command */
|
||||||
input_ret = true;
|
input_ret = true;
|
||||||
|
|
||||||
@ -842,17 +975,19 @@ static bool conference_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
} else {
|
} else {
|
||||||
execute(ctx->history, self, m, line, CONFERENCE_COMMAND_MODE);
|
execute(ctx->history, self, m, line, CONFERENCE_COMMAND_MODE);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (line[0]) {
|
||||||
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 {
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -866,15 +1001,9 @@ static void draw_peer(ToxWindow *self, Tox *m, ChatContext *ctx, uint32_t i)
|
|||||||
const uint32_t peernum = conferences[self->num].name_list[peer_idx].peernum;
|
const uint32_t peernum = conferences[self->num].name_list[peer_idx].peernum;
|
||||||
const bool is_self = tox_conference_peer_number_is_ours(m, self->num, peernum, NULL);
|
const bool is_self = tox_conference_peer_number_is_ours(m, self->num, peernum, NULL);
|
||||||
const bool audio = conferences[self->num].audio_enabled;
|
const bool audio = conferences[self->num].audio_enabled;
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
|
||||||
|
|
||||||
/* truncate nick to fit in side panel without modifying list */
|
|
||||||
char tmpnick[TOX_MAX_NAME_LENGTH];
|
|
||||||
int maxlen = SIDEBAR_WIDTH - 2 - 2 * audio;
|
|
||||||
|
|
||||||
if (audio) {
|
if (audio) {
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
|
||||||
const ConferencePeer *peer = peer_in_conference(self->num, peernum);
|
const ConferencePeer *peer = peer_in_conference(self->num, peernum);
|
||||||
const bool audio_active = is_self
|
const bool audio_active = is_self
|
||||||
? !timed_out(conferences[self->num].last_sent_audio, 2)
|
? !timed_out(conferences[self->num].last_sent_audio, 2)
|
||||||
@ -891,8 +1020,14 @@ static void draw_peer(ToxWindow *self, Tox *m, ChatContext *ctx, uint32_t i)
|
|||||||
wattroff(ctx->sidebar, aud_attr);
|
wattroff(ctx->sidebar, aud_attr);
|
||||||
waddch(ctx->sidebar, ' ');
|
waddch(ctx->sidebar, ' ');
|
||||||
#endif
|
#endif
|
||||||
|
} else {
|
||||||
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* truncate nick to fit in side panel without modifying list */
|
||||||
|
char tmpnick[TOX_MAX_NAME_LENGTH];
|
||||||
|
int maxlen = SIDEBAR_WIDTH - 2 - 2 * audio;
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
memcpy(tmpnick, &conferences[self->num].name_list[peer_idx].name, maxlen);
|
memcpy(tmpnick, &conferences[self->num].name_list[peer_idx].name, maxlen);
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
@ -921,6 +1056,12 @@ static void conference_onDraw(ToxWindow *self, Tox *m)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConferenceChat *chat = &conferences[self->num];
|
||||||
|
|
||||||
|
if (!chat->active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ChatContext *ctx = self->chatwin;
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
@ -932,19 +1073,20 @@ 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 = conferences[self->num].num_peers;
|
const uint32_t num_peers = chat->num_peers;
|
||||||
const bool audio = conferences[self->num].audio_enabled;
|
const bool audio = chat->audio_enabled;
|
||||||
const int header_lines = sidebar_offset(self->num);
|
const int header_lines = sidebar_offset(self->num);
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
@ -953,32 +1095,45 @@ static void conference_onDraw(ToxWindow *self, Tox *m)
|
|||||||
if (audio) {
|
if (audio) {
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
const bool mic_on = !device_is_muted(input, conferences[self->num].audio_in_idx);
|
const bool ptt_idle = !conference_check_push_to_talk(chat) && chat->push_to_talk_enabled;
|
||||||
|
const bool mic_on = !device_is_muted(input, chat->audio_in_idx);
|
||||||
const float volume = get_input_volume();
|
const float volume = get_input_volume();
|
||||||
const float threshold = device_get_VAD_threshold(conferences[self->num].audio_in_idx);
|
const float threshold = device_get_VAD_threshold(chat->audio_in_idx);
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
wmove(ctx->sidebar, line, 1);
|
wmove(ctx->sidebar, line, 1);
|
||||||
wattron(ctx->sidebar, A_BOLD);
|
wattron(ctx->sidebar, A_BOLD);
|
||||||
wprintw(ctx->sidebar, "Mic: ");
|
wprintw(ctx->sidebar, "Mic: ");
|
||||||
const int color = mic_on && volume > threshold ? GREEN : RED;
|
|
||||||
wattron(ctx->sidebar, COLOR_PAIR(color));
|
|
||||||
|
|
||||||
if (mic_on) {
|
if (!mic_on) {
|
||||||
|
wattron(ctx->sidebar, COLOR_PAIR(RED));
|
||||||
|
wprintw(ctx->sidebar, "MUTED");
|
||||||
|
wattroff(ctx->sidebar, COLOR_PAIR(RED));
|
||||||
|
} else if (ptt_idle) {
|
||||||
|
wattron(ctx->sidebar, COLOR_PAIR(GREEN));
|
||||||
|
wprintw(ctx->sidebar, "PTT");
|
||||||
|
wattroff(ctx->sidebar, COLOR_PAIR(GREEN));
|
||||||
|
} else {
|
||||||
|
const int color = volume > threshold ? GREEN : RED;
|
||||||
|
wattron(ctx->sidebar, COLOR_PAIR(color));
|
||||||
|
|
||||||
float v = volume;
|
float v = volume;
|
||||||
|
|
||||||
|
if (v <= 0.0f) {
|
||||||
|
wprintw(ctx->sidebar, ".");
|
||||||
|
}
|
||||||
|
|
||||||
while (v > 0.0f) {
|
while (v > 0.0f) {
|
||||||
wprintw(ctx->sidebar, v > 10.0f ? (v > 15.0f ? "*" : "+") : (v > 5.0f ? "-" : "."));
|
wprintw(ctx->sidebar, v > 10.0f ? (v > 15.0f ? "*" : "+") : (v > 5.0f ? "-" : "."));
|
||||||
v -= 20.0f;
|
v -= 20.0f;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
wprintw(ctx->sidebar, "OFF");
|
wattroff(ctx->sidebar, COLOR_PAIR(color));
|
||||||
}
|
}
|
||||||
|
|
||||||
wattroff(ctx->sidebar, COLOR_PAIR(color));
|
|
||||||
wattroff(ctx->sidebar, A_BOLD);
|
wattroff(ctx->sidebar, A_BOLD);
|
||||||
++line;
|
++line;
|
||||||
#endif
|
#endif // AUDIO
|
||||||
}
|
}
|
||||||
|
|
||||||
wmove(ctx->sidebar, line, 1);
|
wmove(ctx->sidebar, line, 1);
|
||||||
@ -987,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;
|
||||||
@ -1005,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);
|
||||||
|
|
||||||
@ -1025,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));
|
||||||
@ -1038,17 +1198,6 @@ static void conference_onInit(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
line_info_init(ctx->hst);
|
line_info_init(ctx->hst);
|
||||||
|
|
||||||
if (user_settings->autolog == AUTOLOG_ON) {
|
|
||||||
char myid[TOX_ADDRESS_SIZE];
|
|
||||||
tox_self_get_address(m, (uint8_t *) myid);
|
|
||||||
|
|
||||||
if (log_enable(self->name, myid, NULL, ctx->log, LOG_CONFERENCE) == -1) {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE);
|
|
||||||
|
|
||||||
scrollok(ctx->history, 0);
|
scrollok(ctx->history, 0);
|
||||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
||||||
}
|
}
|
||||||
@ -1094,7 +1243,6 @@ static ToxWindow *new_conference_chat(uint32_t conferencenum)
|
|||||||
|
|
||||||
#define CONFAV_SAMPLE_RATE 48000
|
#define CONFAV_SAMPLE_RATE 48000
|
||||||
#define CONFAV_FRAME_DURATION 20
|
#define CONFAV_FRAME_DURATION 20
|
||||||
#define CONFAV_AUDIO_CHANNELS 1
|
|
||||||
#define CONFAV_SAMPLES_PER_FRAME (CONFAV_SAMPLE_RATE * CONFAV_FRAME_DURATION / 1000)
|
#define CONFAV_SAMPLES_PER_FRAME (CONFAV_SAMPLE_RATE * CONFAV_FRAME_DURATION / 1000)
|
||||||
|
|
||||||
void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peernum, const int16_t *pcm,
|
void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peernum, const int16_t *pcm,
|
||||||
@ -1131,12 +1279,20 @@ static void conference_read_device_callback(const int16_t *captured, uint32_t si
|
|||||||
|
|
||||||
AudioInputCallbackData *audio_input_callback_data = (AudioInputCallbackData *)data;
|
AudioInputCallbackData *audio_input_callback_data = (AudioInputCallbackData *)data;
|
||||||
|
|
||||||
conferences[audio_input_callback_data->conferencenum].last_sent_audio = get_unix_time();
|
ConferenceChat *chat = &conferences[audio_input_callback_data->conferencenum];
|
||||||
|
|
||||||
|
if (!conference_check_push_to_talk(chat)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
chat->last_sent_audio = get_unix_time();
|
||||||
|
|
||||||
|
int channels = user_settings->conference_audio_channels;
|
||||||
|
|
||||||
toxav_group_send_audio(audio_input_callback_data->tox,
|
toxav_group_send_audio(audio_input_callback_data->tox,
|
||||||
audio_input_callback_data->conferencenum,
|
audio_input_callback_data->conferencenum,
|
||||||
captured, CONFAV_SAMPLES_PER_FRAME,
|
captured, CONFAV_SAMPLES_PER_FRAME,
|
||||||
CONFAV_AUDIO_CHANNELS, CONFAV_SAMPLE_RATE);
|
channels, CONFAV_SAMPLE_RATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool init_conference_audio_input(Tox *tox, uint32_t conferencenum)
|
bool init_conference_audio_input(Tox *tox, uint32_t conferencenum)
|
||||||
@ -1150,9 +1306,11 @@ bool init_conference_audio_input(Tox *tox, uint32_t conferencenum)
|
|||||||
const AudioInputCallbackData audio_input_callback_data = { tox, conferencenum };
|
const AudioInputCallbackData audio_input_callback_data = { tox, conferencenum };
|
||||||
chat->audio_input_callback_data = audio_input_callback_data;
|
chat->audio_input_callback_data = audio_input_callback_data;
|
||||||
|
|
||||||
|
int channels = user_settings->conference_audio_channels;
|
||||||
|
|
||||||
bool success = (open_input_device(&chat->audio_in_idx,
|
bool success = (open_input_device(&chat->audio_in_idx,
|
||||||
conference_read_device_callback, &chat->audio_input_callback_data, true,
|
conference_read_device_callback, &chat->audio_input_callback_data, true,
|
||||||
CONFAV_SAMPLE_RATE, CONFAV_FRAME_DURATION, CONFAV_AUDIO_CHANNELS)
|
CONFAV_SAMPLE_RATE, CONFAV_FRAME_DURATION, channels)
|
||||||
== de_None);
|
== de_None);
|
||||||
|
|
||||||
chat->audio_enabled = success;
|
chat->audio_enabled = success;
|
||||||
@ -1160,6 +1318,19 @@ bool init_conference_audio_input(Tox *tox, uint32_t conferencenum)
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool toggle_conference_push_to_talk(uint32_t conferencenum, bool enabled)
|
||||||
|
{
|
||||||
|
ConferenceChat *chat = &conferences[conferencenum];
|
||||||
|
|
||||||
|
if (!chat->active) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
chat->push_to_talk_enabled = enabled;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool enable_conference_audio(Tox *tox, uint32_t conferencenum)
|
bool enable_conference_audio(Tox *tox, uint32_t conferencenum)
|
||||||
{
|
{
|
||||||
if (!toxav_groupchat_av_enabled(tox, conferencenum)) {
|
if (!toxav_groupchat_av_enabled(tox, conferencenum)) {
|
||||||
@ -1244,4 +1415,4 @@ float conference_get_VAD_threshold(uint32_t conferencenum)
|
|||||||
|
|
||||||
return device_get_VAD_threshold(chat->audio_in_idx);
|
return device_get_VAD_threshold(chat->audio_in_idx);
|
||||||
}
|
}
|
||||||
#endif
|
#endif // AUDIO
|
||||||
|
@ -26,9 +26,8 @@
|
|||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
|
|
||||||
|
#define CONFERENCE_MAX_TITLE_LENGTH TOX_MAX_NAME_LENGTH
|
||||||
#define SIDEBAR_WIDTH 16
|
#define SIDEBAR_WIDTH 16
|
||||||
#define MAX_CONFERENCE_NUM MAX_WINDOWS_NUM - 2
|
|
||||||
#define CONFERENCE_EVENT_WAIT 3
|
|
||||||
|
|
||||||
typedef struct ConferencePeer {
|
typedef struct ConferencePeer {
|
||||||
bool active;
|
bool active;
|
||||||
@ -64,12 +63,18 @@ typedef struct {
|
|||||||
int side_pos; /* current position of the sidebar - used for scrolling up and down */
|
int side_pos; /* current position of the sidebar - used for scrolling up and down */
|
||||||
time_t start_time;
|
time_t start_time;
|
||||||
|
|
||||||
|
char title[CONFERENCE_MAX_TITLE_LENGTH + 1];
|
||||||
|
size_t title_length;
|
||||||
|
|
||||||
ConferencePeer *peer_list;
|
ConferencePeer *peer_list;
|
||||||
uint32_t max_idx;
|
uint32_t max_idx;
|
||||||
|
|
||||||
NameListEntry *name_list;
|
NameListEntry *name_list;
|
||||||
uint32_t num_peers;
|
uint32_t num_peers;
|
||||||
|
|
||||||
|
bool push_to_talk_enabled;
|
||||||
|
time_t ptt_last_pushed;
|
||||||
|
|
||||||
bool audio_enabled;
|
bool audio_enabled;
|
||||||
time_t last_sent_audio;
|
time_t last_sent_audio;
|
||||||
uint32_t audio_in_idx;
|
uint32_t audio_in_idx;
|
||||||
@ -79,11 +84,15 @@ typedef struct {
|
|||||||
/* Frees all Toxic associated data structures for a conference (does not call tox_conference_delete() ) */
|
/* Frees all Toxic associated data structures for a conference (does not call tox_conference_delete() ) */
|
||||||
void free_conference(ToxWindow *self, uint32_t conferencenum);
|
void free_conference(ToxWindow *self, uint32_t conferencenum);
|
||||||
|
|
||||||
int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char *title, size_t title_length);
|
int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char *title, size_t length);
|
||||||
|
|
||||||
/* destroys and re-creates conference window with or without the peerlist */
|
/* destroys and re-creates conference window with or without the peerlist */
|
||||||
void redraw_conference_win(ToxWindow *self);
|
void redraw_conference_win(ToxWindow *self);
|
||||||
|
|
||||||
|
void conference_set_title(ToxWindow *self, uint32_t conferencesnum, const char *title, size_t length);
|
||||||
|
void conference_rename_log_path(Tox *m, uint32_t conferencenum, const char *new_title);
|
||||||
|
int conference_enable_logging(ToxWindow *self, Tox *m, uint32_t conferencenum, struct chatlog *log);
|
||||||
|
|
||||||
/* Puts `(NameListEntry *)`s in `entries` for each matched peer, up to a maximum
|
/* Puts `(NameListEntry *)`s in `entries` for each matched peer, up to a maximum
|
||||||
* of `maxpeers`.
|
* of `maxpeers`.
|
||||||
* Maches each peer whose name or pubkey begins with `prefix`.
|
* Maches each peer whose name or pubkey begins with `prefix`.
|
||||||
@ -96,6 +105,7 @@ uint32_t get_name_list_entries_by_prefix(uint32_t conferencenum, const char *pre
|
|||||||
bool init_conference_audio_input(Tox *tox, uint32_t conferencenum);
|
bool init_conference_audio_input(Tox *tox, uint32_t conferencenum);
|
||||||
bool enable_conference_audio(Tox *tox, uint32_t conferencenum);
|
bool enable_conference_audio(Tox *tox, uint32_t conferencenum);
|
||||||
bool disable_conference_audio(Tox *tox, uint32_t conferencenum);
|
bool disable_conference_audio(Tox *tox, uint32_t conferencenum);
|
||||||
|
bool toggle_conference_push_to_talk(uint32_t conferencenum, bool enabled);
|
||||||
void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peernum,
|
void audio_conference_callback(void *tox, uint32_t conferencenum, uint32_t peernum,
|
||||||
const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t
|
const int16_t *pcm, unsigned int samples, uint8_t channels, uint32_t
|
||||||
sample_rate, void *userdata);
|
sample_rate, void *userdata);
|
||||||
|
@ -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])
|
||||||
@ -40,7 +40,7 @@ void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc,
|
|||||||
UNUSED_VAR(window);
|
UNUSED_VAR(window);
|
||||||
|
|
||||||
Tox_Err_Conference_Title err;
|
Tox_Err_Conference_Title err;
|
||||||
char title[MAX_STR_SIZE];
|
char title[CONFERENCE_MAX_TITLE_LENGTH + 1];
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
size_t tlen = tox_conference_get_title_size(m, self->num, &err);
|
size_t tlen = tox_conference_get_title_size(m, self->num, &err);
|
||||||
@ -56,31 +56,36 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t len = strlen(argv[1]);
|
||||||
|
|
||||||
|
if (len >= sizeof(title)) {
|
||||||
|
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title: max length exceeded.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(title, sizeof(title), "%s", argv[1]);
|
snprintf(title, sizeof(title), "%s", argv[1]);
|
||||||
int len = strlen(title);
|
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_window_title(self, title, len);
|
conference_rename_log_path(m, self->num, title); // must be called first
|
||||||
|
|
||||||
|
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);
|
||||||
@ -104,7 +109,8 @@ void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (enable ? enable_conference_audio(m, self->num) : disable_conference_audio(m, self->num)) {
|
if (enable ? enable_conference_audio(m, self->num) : disable_conference_audio(m, self->num)) {
|
||||||
print_err(self, enable ? "Enabled conference audio" : "Disabled conference audio");
|
print_err(self, enable ? "Enabled conference audio. Use the '/ptt' command to toggle Push-To-Talk."
|
||||||
|
: "Disabled conference audio");
|
||||||
} else {
|
} else {
|
||||||
print_err(self, enable ? "Failed to enable audio" : "Failed to disable audio");
|
print_err(self, enable ? "Failed to enable audio" : "Failed to disable audio");
|
||||||
}
|
}
|
||||||
@ -133,16 +139,16 @@ 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, "No such audio peer");
|
print_err(self, "Peer is not on the call");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -153,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;
|
||||||
}
|
}
|
||||||
@ -172,9 +178,33 @@ 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.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cmd_conference_push_to_talk(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||||
|
{
|
||||||
|
UNUSED_VAR(window);
|
||||||
|
UNUSED_VAR(m);
|
||||||
|
|
||||||
|
bool enable;
|
||||||
|
|
||||||
|
if (argc == 1 && !strcasecmp(argv[1], "on")) {
|
||||||
|
enable = true;
|
||||||
|
} else if (argc == 1 && !strcasecmp(argv[1], "off")) {
|
||||||
|
enable = false;
|
||||||
|
} else {
|
||||||
|
print_err(self, "Please specify: on | off");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!toggle_conference_push_to_talk(self->num, enable)) {
|
||||||
|
print_err(self, "Failed to toggle push to talk.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_err(self, enable ? "Push-To-Talk is enabled. Push F2 to activate" : "Push-To-Talk is disabled");
|
||||||
|
}
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
|
@ -30,5 +30,6 @@ void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc,
|
|||||||
void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_enable_audio(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
void cmd_conference_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_conference_mute(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
void cmd_conference_sense(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
void cmd_conference_push_to_talk(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||||
|
|
||||||
#endif /* CONFERENCE_COMMANDS_H */
|
#endif /* CONFERENCE_COMMANDS_H */
|
||||||
|
@ -105,6 +105,7 @@ static struct cmd_func conference_commands[] = {
|
|||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
{ "/audio", cmd_enable_audio },
|
{ "/audio", cmd_enable_audio },
|
||||||
{ "/mute", cmd_conference_mute },
|
{ "/mute", cmd_conference_mute },
|
||||||
|
{ "/ptt", cmd_conference_push_to_talk },
|
||||||
{ "/sense", cmd_conference_sense },
|
{ "/sense", cmd_conference_sense },
|
||||||
#endif /* AUDIO */
|
#endif /* AUDIO */
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
@ -270,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.");
|
||||||
}
|
}
|
||||||
|
@ -60,13 +60,15 @@ void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t l
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char pct_str[STR_BUF_SIZE] = {0};
|
char pct_str[STR_BUF_SIZE];
|
||||||
snprintf(pct_str, sizeof(pct_str), "%.1f%%", pct_done);
|
snprintf(pct_str, sizeof(pct_str), "%.1f%%", pct_done);
|
||||||
|
|
||||||
char bps_str[STR_BUF_SIZE] = {0};
|
char bps_str[STR_BUF_SIZE];
|
||||||
bytes_convert_str(bps_str, sizeof(bps_str), bps);
|
bytes_convert_str(bps_str, sizeof(bps_str), bps);
|
||||||
|
|
||||||
char prog_line[NUM_PROG_MARKS + 1] = {0};
|
char prog_line[NUM_PROG_MARKS + 1];
|
||||||
|
prog_line[0] = 0;
|
||||||
|
|
||||||
int n = pct_done / (100 / NUM_PROG_MARKS);
|
int n = pct_done / (100 / NUM_PROG_MARKS);
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
@ -272,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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,7 +450,9 @@ static void friendlist_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const
|
|||||||
tox_self_get_address(m, (uint8_t *) myid);
|
tox_self_get_address(m, (uint8_t *) myid);
|
||||||
|
|
||||||
if (strcmp(oldname, newnamecpy) != 0) {
|
if (strcmp(oldname, newnamecpy) != 0) {
|
||||||
rename_logfile(oldname, newnamecpy, myid, Friends.list[num].pub_key, Friends.list[num].chatwin);
|
if (rename_logfile(oldname, newnamecpy, myid, Friends.list[num].pub_key, Friends.list[num].chatwin) != 0) {
|
||||||
|
fprintf(stderr, "Failed to rename friend chat log from `%s` to `%s`\n", oldname, newnamecpy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sort_friendlist_index();
|
sort_friendlist_index();
|
||||||
@ -609,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);
|
||||||
@ -640,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);
|
||||||
@ -805,7 +804,7 @@ static void delete_blocked_friend(uint32_t bnum)
|
|||||||
/* deletes contact from friendlist and puts in blocklist */
|
/* deletes contact from friendlist and puts in blocklist */
|
||||||
void block_friend(Tox *m, uint32_t fnum)
|
void block_friend(Tox *m, uint32_t fnum)
|
||||||
{
|
{
|
||||||
if (Friends.num_friends <= 0) {
|
if (Friends.num_friends == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -852,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -921,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1020,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;
|
||||||
@ -1055,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;
|
||||||
@ -1096,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, " > ");
|
||||||
@ -1245,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;
|
||||||
@ -1263,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;
|
||||||
@ -1288,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);
|
||||||
}
|
}
|
||||||
@ -1341,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;
|
||||||
@ -1376,6 +1393,6 @@ ToxWindow *new_friendlist(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret->help = help;
|
ret->help = help;
|
||||||
strcpy(ret->name, "contacts");
|
strcpy(ret->name, "Contacts");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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,11 +361,11 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t conferencenum;
|
uint32_t conferencenum = 0;
|
||||||
|
|
||||||
if (type == TOX_CONFERENCE_TYPE_TEXT) {
|
if (type == TOX_CONFERENCE_TYPE_TEXT) {
|
||||||
Tox_Err_Conference_New err;
|
Tox_Err_Conference_New err;
|
||||||
@ -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,21 +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
|
||||||
} else {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Unknown conference type %d", type);
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
@ -404,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])
|
||||||
@ -427,29 +424,15 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *swch = argv[1];
|
const char *swch = argv[1];
|
||||||
|
|
||||||
if (!strcmp(swch, "1") || !strcmp(swch, "on")) {
|
if (!strcmp(swch, "1") || !strcmp(swch, "on")) {
|
||||||
char myid[TOX_ADDRESS_SIZE];
|
msg = log_enable(log) == 0 ? "Logging enabled." : "Warning: Failed to enable log.";
|
||||||
tox_self_get_address(m, (uint8_t *) myid);
|
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, msg);
|
||||||
|
|
||||||
int log_ret = -1;
|
|
||||||
|
|
||||||
if (self->type == WINDOW_TYPE_CHAT) {
|
|
||||||
Friends.list[self->num].logging_on = true;
|
|
||||||
log_ret = log_enable(self->name, myid, Friends.list[self->num].pub_key, log, LOG_CHAT);
|
|
||||||
} else if (self->type == WINDOW_TYPE_PROMPT) {
|
|
||||||
log_ret = log_enable(self->name, myid, NULL, log, LOG_PROMPT);
|
|
||||||
} else if (self->type == WINDOW_TYPE_CONFERENCE) {
|
|
||||||
log_ret = log_enable(self->name, myid, NULL, log, LOG_CONFERENCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
msg = log_ret == 0 ? "Logging enabled." : "Warning: Log failed to initialize.";
|
|
||||||
line_info_add(self, NULL, 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) {
|
||||||
@ -459,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])
|
||||||
@ -478,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
|
||||||
@ -495,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -508,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -517,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")) {
|
||||||
@ -527,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;
|
||||||
}
|
}
|
||||||
@ -535,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);
|
||||||
|
|
||||||
@ -551,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;
|
||||||
}
|
}
|
||||||
@ -559,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;
|
||||||
}
|
}
|
||||||
@ -586,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -613,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -628,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -636,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -673,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -693,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, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -712,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -727,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:
|
||||||
|
@ -306,7 +306,7 @@ static void help_draw_conference(ToxWindow *self)
|
|||||||
wprintw(win, "Conference commands:\n");
|
wprintw(win, "Conference commands:\n");
|
||||||
wattroff(win, A_BOLD | COLOR_PAIR(RED));
|
wattroff(win, A_BOLD | COLOR_PAIR(RED));
|
||||||
|
|
||||||
wprintw(win, " /title <msg> : Set conference title (show current title if no msg)\n");
|
wprintw(win, " /title <msg> : Show/set conference title\n");
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
wattron(win, A_BOLD);
|
wattron(win, A_BOLD);
|
||||||
wprintw(win, "\n Audio:\n");
|
wprintw(win, "\n Audio:\n");
|
||||||
@ -314,6 +314,7 @@ static void help_draw_conference(ToxWindow *self)
|
|||||||
wprintw(win, " /audio <on> or <off> : Enable/disable audio in an audio conference\n");
|
wprintw(win, " /audio <on> or <off> : Enable/disable audio in an audio conference\n");
|
||||||
wprintw(win, " /mute : Toggle self audio mute status\n");
|
wprintw(win, " /mute : Toggle self audio mute status\n");
|
||||||
wprintw(win, " /mute <nick> or <pubkey> : Toggle peer audio mute status\n");
|
wprintw(win, " /mute <nick> or <pubkey> : Toggle peer audio mute status\n");
|
||||||
|
wprintw(win, " /ptt <on> or <off> : Toggle audio input Push-To-Talk (F2 to activate)\n");
|
||||||
wprintw(win, " /sense <n> : VAD sensitivity threshold\n\n");
|
wprintw(win, " /sense <n> : VAD sensitivity threshold\n\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -403,7 +404,7 @@ void help_onKey(ToxWindow *self, wint_t key)
|
|||||||
case L'o':
|
case L'o':
|
||||||
height = 6;
|
height = 6;
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
height += 5;
|
height += 7;
|
||||||
#endif
|
#endif
|
||||||
help_init_window(self, height, 80);
|
help_init_window(self, height, 80);
|
||||||
self->help->type = HELP_CONFERENCE;
|
self->help->type = HELP_CONFERENCE;
|
||||||
|
514
src/line_info.c
514
src/line_info.c
@ -46,7 +46,7 @@ void line_info_init(struct history *hst)
|
|||||||
|
|
||||||
hst->line_start = hst->line_root;
|
hst->line_start = hst->line_root;
|
||||||
hst->line_end = hst->line_start;
|
hst->line_end = hst->line_start;
|
||||||
hst->queue_sz = 0;
|
hst->queue_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* resets line_start (moves to end of chat history) */
|
/* resets line_start (moves to end of chat history) */
|
||||||
@ -54,27 +54,28 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
int y2, x2;
|
int y2;
|
||||||
|
int x2;
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
|
UNUSED_VAR(x2);
|
||||||
|
|
||||||
int side_offst = self->show_peerlist ? SIDEBAR_WIDTH : 0;
|
int top_offst = (self->type == WINDOW_TYPE_CHAT) || (self->type == WINDOW_TYPE_PROMPT) ? TOP_BAR_HEIGHT : 0;
|
||||||
int top_offst = (self->type == WINDOW_TYPE_CHAT) || (self->type == WINDOW_TYPE_PROMPT) ? 2 : 0;
|
int max_y = y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT - top_offst;
|
||||||
int max_y = (y2 - CHATBOX_HEIGHT - top_offst);
|
|
||||||
|
|
||||||
int curlines = 0;
|
uint16_t curlines = 0;
|
||||||
int nxtlines = line->newlines + (line->len / (x2 - side_offst));
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
curlines += 1 + nxtlines;
|
curlines += line->format_lines;
|
||||||
line = line->prev;
|
line = line->prev;
|
||||||
nxtlines = line->newlines + (line->len / (x2 - side_offst));
|
} while (line->prev && curlines + line->format_lines <= max_y);
|
||||||
} while (line->prev && curlines + nxtlines < 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)
|
||||||
@ -87,9 +88,7 @@ void line_info_cleanup(struct history *hst)
|
|||||||
tmp1 = tmp2;
|
tmp1 = tmp2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i;
|
for (size_t i = 0; i < hst->queue_size; ++i) {
|
||||||
|
|
||||||
for (i = 0; i < hst->queue_sz; ++i) {
|
|
||||||
if (hst->queue[i]) {
|
if (hst->queue[i]) {
|
||||||
free(hst->queue[i]);
|
free(hst->queue[i]);
|
||||||
}
|
}
|
||||||
@ -117,29 +116,230 @@ static void line_info_root_fwd(struct history *hst)
|
|||||||
/* returns ptr to queue item 0 and removes it from queue. Returns NULL if queue is empty. */
|
/* returns ptr to queue item 0 and removes it from queue. Returns NULL if queue is empty. */
|
||||||
static struct line_info *line_info_ret_queue(struct history *hst)
|
static struct line_info *line_info_ret_queue(struct history *hst)
|
||||||
{
|
{
|
||||||
if (hst->queue_sz <= 0) {
|
if (hst->queue_size == 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct line_info *line = hst->queue[0];
|
struct line_info *line = hst->queue[0];
|
||||||
|
|
||||||
int i;
|
for (size_t i = 0; i < hst->queue_size; ++i) {
|
||||||
|
|
||||||
for (i = 0; i < hst->queue_sz; ++i) {
|
|
||||||
hst->queue[i] = hst->queue[i + 1];
|
hst->queue[i] = hst->queue[i + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
--hst->queue_sz;
|
--hst->queue_size;
|
||||||
|
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Prints a maximum of `n` chars from `s` to `win`.
|
||||||
|
*
|
||||||
|
* 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 int print_n_chars(WINDOW *win, const char *s, size_t n, int max_y)
|
||||||
|
{
|
||||||
|
bool newline = false;
|
||||||
|
char ch;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n && (ch = s[i]); ++i) {
|
||||||
|
if (ch == '\n') {
|
||||||
|
newline = true;
|
||||||
|
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
UNUSED_VAR(x);
|
||||||
|
getyx(win, y, x);
|
||||||
|
|
||||||
|
// make sure cursor will wrap correctly after newline to prevent display bugs
|
||||||
|
if (y + 1 >= max_y) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (win) {
|
||||||
|
wprintw(win, "%c", ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the index of the last space character in `s` found before `limit`.
|
||||||
|
* Returns -1 if no space is found.
|
||||||
|
*/
|
||||||
|
static int rspace_index(const char *s, int limit)
|
||||||
|
{
|
||||||
|
for (int i = limit; i >= 0; --i) {
|
||||||
|
if (s[i] == ' ') {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the first index in `s` containing a newline byte found before `limit`.
|
||||||
|
* Returns -1 if no newline is found.
|
||||||
|
*/
|
||||||
|
static int newline_index(const char *s, int limit)
|
||||||
|
{
|
||||||
|
char ch;
|
||||||
|
|
||||||
|
for (int i = 0; i < limit && (ch = s[i]); ++i) {
|
||||||
|
if (ch == '\n') {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the number of newline bytes in `s` */
|
||||||
|
static unsigned int newline_count(const char *s)
|
||||||
|
{
|
||||||
|
char ch;
|
||||||
|
unsigned int count = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; (ch = s[i]); ++i) {
|
||||||
|
if (ch == '\n') {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prints `line` message to window, wrapping at the last word that fits on the current line.
|
||||||
|
* This function updates the `format_lines` field of `line` according to current window dimensions.
|
||||||
|
*
|
||||||
|
* If `win` is null nothing will be printed to the window. This is useful to set the
|
||||||
|
* `format_lines` field on initialization.
|
||||||
|
*
|
||||||
|
* Return 0 on success.
|
||||||
|
* Return -1 if not all characters in line's message were printed to screen.
|
||||||
|
*/
|
||||||
|
static int print_wrap(WINDOW *win, struct line_info *line, int max_x, int max_y)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
UNUSED_VAR(y);
|
||||||
|
|
||||||
|
const char *msg = line->msg;
|
||||||
|
uint16_t length = line->msg_len;
|
||||||
|
uint16_t lines = 0;
|
||||||
|
const int x_start = line->len - line->msg_len - 1; // manually keep track of x position because ncurses sucks
|
||||||
|
int x_limit = max_x - x_start;
|
||||||
|
|
||||||
|
if (x_limit <= 1) {
|
||||||
|
fprintf(stderr, "Warning: x_limit <= 0 in print_wrap(): %d\n", x_limit);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (msg) {
|
||||||
|
getyx(win, y, x);
|
||||||
|
|
||||||
|
// next line would print past window limit so we abort; we don't want to update format_lines
|
||||||
|
if (x > x_start) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length < x_limit) {
|
||||||
|
int p_ret = print_n_chars(win, msg, length, max_y);
|
||||||
|
|
||||||
|
if (p_ret == 1) {
|
||||||
|
lines += newline_count(msg);
|
||||||
|
} else if (p_ret == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
++lines;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int newline_idx = newline_index(msg, x_limit - 1);
|
||||||
|
|
||||||
|
if (newline_idx >= 0) {
|
||||||
|
if (print_n_chars(win, msg, newline_idx + 1, max_y) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg += (newline_idx + 1);
|
||||||
|
length -= (newline_idx + 1);
|
||||||
|
x_limit = max_x; // if we find a newline we stop adding column padding for rest of message
|
||||||
|
++lines;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int space_idx = rspace_index(msg, x_limit - 1);
|
||||||
|
|
||||||
|
if (space_idx >= 1) {
|
||||||
|
if (print_n_chars(win, msg, space_idx, max_y) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg += space_idx + 1;
|
||||||
|
length -= (space_idx + 1);
|
||||||
|
|
||||||
|
if (win) {
|
||||||
|
waddch(win, '\n');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (print_n_chars(win, msg, x_limit, max_y) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg += x_limit;
|
||||||
|
length -= x_limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add padding to the start of the next line
|
||||||
|
if (win && x_limit < max_x) {
|
||||||
|
for (size_t i = 0; i < x_start; ++i) {
|
||||||
|
waddch(win, ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (win && line->noread_flag) {
|
||||||
|
getyx(win, y, x);
|
||||||
|
|
||||||
|
if (x >= max_x - 1 || x == x_start) {
|
||||||
|
++lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
wattron(win, COLOR_PAIR(RED));
|
||||||
|
wprintw(win, " x");
|
||||||
|
wattroff(win, COLOR_PAIR(RED));
|
||||||
|
}
|
||||||
|
|
||||||
|
line->format_lines = lines;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void line_info_init_line(ToxWindow *self, struct line_info *line)
|
||||||
|
{
|
||||||
|
int y2;
|
||||||
|
int x2;
|
||||||
|
UNUSED_VAR(y2);
|
||||||
|
|
||||||
|
getmaxyx(self->window, y2, x2);
|
||||||
|
|
||||||
|
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.
|
||||||
*
|
*
|
||||||
* 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) {
|
||||||
@ -148,7 +348,7 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
|
|||||||
|
|
||||||
struct history *hst = self->chatwin->hst;
|
struct history *hst = self->chatwin->hst;
|
||||||
|
|
||||||
if (hst->queue_sz >= MAX_LINE_INFO_QUEUE) {
|
if (hst->queue_size >= MAX_LINE_INFO_QUEUE) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,7 +358,8 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
|
|||||||
exit_toxic_err("failed in line_info_add", FATALERR_MEMORY);
|
exit_toxic_err("failed in line_info_add", FATALERR_MEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
char frmt_msg[MAX_LINE_INFO_MSG_SIZE] = {0};
|
char frmt_msg[MAX_LINE_INFO_MSG_SIZE];
|
||||||
|
frmt_msg[0] = 0;
|
||||||
|
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, msg);
|
va_start(args, msg);
|
||||||
@ -173,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:
|
||||||
@ -207,21 +408,16 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t msg_len = 0;
|
||||||
|
|
||||||
if (frmt_msg[0]) {
|
if (frmt_msg[0]) {
|
||||||
snprintf(new_line->msg, sizeof(new_line->msg), "%s", frmt_msg);
|
snprintf(new_line->msg, sizeof(new_line->msg), "%s", frmt_msg);
|
||||||
len += strlen(new_line->msg);
|
msg_len = strlen(new_line->msg);
|
||||||
|
len += msg_len;
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; frmt_msg[i]; ++i) {
|
|
||||||
if (frmt_msg[i] == '\n') {
|
|
||||||
++new_line->newlines;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,15 +431,18 @@ int line_info_add(ToxWindow *self, const char *timestr, const char *name1, const
|
|||||||
len += strlen(new_line->name2);
|
len += strlen(new_line->name2);
|
||||||
}
|
}
|
||||||
|
|
||||||
new_line->id = (hst->line_end->id + 1 + hst->queue_sz) % INT_MAX;
|
new_line->id = (hst->line_end->id + 1 + hst->queue_size) % INT_MAX;
|
||||||
new_line->len = len;
|
new_line->len = len;
|
||||||
|
new_line->msg_len = msg_len;
|
||||||
new_line->type = type;
|
new_line->type = type;
|
||||||
new_line->bold = bold;
|
new_line->bold = bold;
|
||||||
new_line->colour = colour;
|
new_line->colour = colour;
|
||||||
new_line->noread_flag = false;
|
new_line->noread_flag = false;
|
||||||
new_line->timestamp = get_unix_time();
|
new_line->timestamp = get_unix_time();
|
||||||
|
|
||||||
hst->queue[hst->queue_sz++] = new_line;
|
line_info_init_line(self, new_line);
|
||||||
|
|
||||||
|
hst->queue[hst->queue_size++] = new_line;
|
||||||
|
|
||||||
return new_line->id;
|
return new_line->id;
|
||||||
}
|
}
|
||||||
@ -267,27 +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, y2, x, x2;
|
if (!self->scroll_pause) {
|
||||||
getmaxyx(self->window, y2, x2);
|
line_info_reset_start(self, hst);
|
||||||
getyx(self->chatwin->history, y, x);
|
|
||||||
|
|
||||||
UNUSED_VAR(x);
|
|
||||||
|
|
||||||
if (x2 <= SIDEBAR_WIDTH) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int offst = self->show_peerlist ? SIDEBAR_WIDTH : 0; /* offset width of conference sidebar */
|
|
||||||
int lines = 1 + line->newlines + (line->len / (x2 - offst));
|
|
||||||
int max_y = y2 - CHATBOX_HEIGHT;
|
|
||||||
|
|
||||||
/* move line_start forward proportionate to the number of new lines */
|
|
||||||
if (y + lines - 1 >= max_y) {
|
|
||||||
while (lines > 0 && hst->line_start->next) {
|
|
||||||
lines -= 1 + hst->line_start->next->newlines + (hst->line_start->next->len / (x2 - offst));
|
|
||||||
hst->line_start = hst->line_start->next;
|
|
||||||
++hst->start_id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,25 +490,44 @@ void line_info_print(ToxWindow *self)
|
|||||||
|
|
||||||
wclear(win);
|
wclear(win);
|
||||||
|
|
||||||
int y2, x2;
|
int y2;
|
||||||
|
|
||||||
|
int x2;
|
||||||
|
|
||||||
getmaxyx(self->window, y2, x2);
|
getmaxyx(self->window, y2, x2);
|
||||||
|
|
||||||
if (x2 <= SIDEBAR_WIDTH) {
|
if (x2 - 1 <= SIDEBAR_WIDTH) { // leave room on x axis for sidebar padding
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
int numlines = 0;
|
if (!line) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int max_y = y2 - CHATBOX_HEIGHT - WINDOW_BAR_HEIGHT;
|
||||||
|
const int max_x = self->show_peerlist ? x2 - 1 - SIDEBAR_WIDTH : x2;
|
||||||
|
uint16_t numlines = line->format_lines;
|
||||||
|
int print_ret = 0;
|
||||||
|
|
||||||
|
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) {
|
||||||
@ -355,43 +554,32 @@ void line_info_print(ToxWindow *self)
|
|||||||
wprintw(win, "%s %s: ", user_settings->line_normal, line->name1);
|
wprintw(win, "%s %s: ", user_settings->line_normal, line->name1);
|
||||||
wattroff(win, COLOR_PAIR(nameclr));
|
wattroff(win, COLOR_PAIR(nameclr));
|
||||||
|
|
||||||
char *msg = line->msg;
|
if (line->msg[0] == 0) {
|
||||||
|
waddch(win, '\n');
|
||||||
while (msg) {
|
break;
|
||||||
char *line = strsep(&msg, "\n");
|
|
||||||
|
|
||||||
if (line[0] == '>') {
|
|
||||||
wattron(win, COLOR_PAIR(GREEN));
|
|
||||||
} else if (line[0] == '<') {
|
|
||||||
wattron(win, COLOR_PAIR(RED));
|
|
||||||
}
|
|
||||||
|
|
||||||
wprintw(win, "%s%c", line, msg ? '\n' : '\0');
|
|
||||||
|
|
||||||
if (line[0] == '>') {
|
|
||||||
wattroff(win, COLOR_PAIR(GREEN));
|
|
||||||
} else if (line[0] == '<') {
|
|
||||||
wattroff(win, COLOR_PAIR(RED));
|
|
||||||
}
|
|
||||||
|
|
||||||
// change the \0 set by strsep back to \n
|
|
||||||
if (msg) {
|
|
||||||
msg[-1] = '\n';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == OUT_MSG && timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
|
if (line->msg[0] == '>') {
|
||||||
|
wattron(win, COLOR_PAIR(GREEN));
|
||||||
|
} else if (line->msg[0] == '<') {
|
||||||
wattron(win, COLOR_PAIR(RED));
|
wattron(win, COLOR_PAIR(RED));
|
||||||
wprintw(win, " x");
|
}
|
||||||
wattroff(win, COLOR_PAIR(RED));
|
|
||||||
|
|
||||||
if (line->noread_flag == false) {
|
print_ret = print_wrap(win, line, max_x, max_y);
|
||||||
|
|
||||||
|
if (line->msg[0] == '>') {
|
||||||
|
wattroff(win, COLOR_PAIR(GREEN));
|
||||||
|
} else if (line->msg[0] == '<') {
|
||||||
|
wattroff(win, COLOR_PAIR(RED));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == OUT_MSG && !line->read_flag) {
|
||||||
|
if (timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
|
||||||
line->noread_flag = true;
|
line->noread_flag = true;
|
||||||
line->len += 2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wprintw(win, "\n");
|
waddch(win, '\n');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OUT_ACTION_READ:
|
case OUT_ACTION_READ:
|
||||||
@ -406,21 +594,17 @@ void line_info_print(ToxWindow *self)
|
|||||||
wattroff(win, COLOR_PAIR(BLUE));
|
wattroff(win, COLOR_PAIR(BLUE));
|
||||||
|
|
||||||
wattron(win, COLOR_PAIR(YELLOW));
|
wattron(win, COLOR_PAIR(YELLOW));
|
||||||
wprintw(win, "%s %s %s", user_settings->line_normal, line->name1, line->msg);
|
wprintw(win, "%s %s ", user_settings->line_normal, line->name1);
|
||||||
|
print_ret = print_wrap(win, line, max_x, max_y);
|
||||||
wattroff(win, COLOR_PAIR(YELLOW));
|
wattroff(win, COLOR_PAIR(YELLOW));
|
||||||
|
|
||||||
if (type == OUT_ACTION && timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
|
if (type == OUT_ACTION && !line->read_flag) {
|
||||||
wattron(win, COLOR_PAIR(RED));
|
if (timed_out(line->timestamp, NOREAD_FLAG_TIMEOUT)) {
|
||||||
wprintw(win, " x");
|
|
||||||
wattroff(win, COLOR_PAIR(RED));
|
|
||||||
|
|
||||||
if (line->noread_flag == false) {
|
|
||||||
line->noread_flag = true;
|
line->noread_flag = true;
|
||||||
line->len += 2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wprintw(win, "\n");
|
waddch(win, '\n');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SYS_MSG:
|
case SYS_MSG:
|
||||||
@ -438,7 +622,8 @@ void line_info_print(ToxWindow *self)
|
|||||||
wattron(win, COLOR_PAIR(line->colour));
|
wattron(win, COLOR_PAIR(line->colour));
|
||||||
}
|
}
|
||||||
|
|
||||||
wprintw(win, "%s\n", line->msg);
|
print_ret = print_wrap(win, line, max_x, max_y);
|
||||||
|
waddch(win, '\n');
|
||||||
|
|
||||||
if (line->bold) {
|
if (line->bold) {
|
||||||
wattroff(win, A_BOLD);
|
wattroff(win, A_BOLD);
|
||||||
@ -456,10 +641,10 @@ void line_info_print(ToxWindow *self)
|
|||||||
wattroff(win, COLOR_PAIR(GREEN));
|
wattroff(win, COLOR_PAIR(GREEN));
|
||||||
|
|
||||||
if (line->msg[0]) {
|
if (line->msg[0]) {
|
||||||
wprintw(win, "%s", line->msg);
|
print_ret = print_wrap(win, line, max_x, max_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
wprintw(win, "\n");
|
waddch(win, '\n');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CONNECTION:
|
case CONNECTION:
|
||||||
@ -474,7 +659,9 @@ void line_info_print(ToxWindow *self)
|
|||||||
wprintw(win, "%s ", line->name1);
|
wprintw(win, "%s ", line->name1);
|
||||||
wattroff(win, A_BOLD);
|
wattroff(win, A_BOLD);
|
||||||
|
|
||||||
wprintw(win, "%s\n", line->msg);
|
print_ret = print_wrap(win, line, max_x, max_y);
|
||||||
|
waddch(win, '\n');
|
||||||
|
|
||||||
wattroff(win, COLOR_PAIR(line->colour));
|
wattroff(win, COLOR_PAIR(line->colour));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -491,7 +678,9 @@ void line_info_print(ToxWindow *self)
|
|||||||
wprintw(win, "%s ", line->name1);
|
wprintw(win, "%s ", line->name1);
|
||||||
wattroff(win, A_BOLD);
|
wattroff(win, A_BOLD);
|
||||||
|
|
||||||
wprintw(win, "%s\n", line->msg);
|
print_ret = print_wrap(win, line, max_x, max_y);
|
||||||
|
waddch(win, '\n');
|
||||||
|
|
||||||
wattroff(win, COLOR_PAIR(line->colour));
|
wattroff(win, COLOR_PAIR(line->colour));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -507,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);
|
||||||
|
|
||||||
wprintw(win, "%s", line->msg);
|
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);
|
||||||
@ -521,11 +710,43 @@ void line_info_print(ToxWindow *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* keep calling until queue is empty */
|
/* keep calling until queue is empty */
|
||||||
if (hst->queue_sz > 0) {
|
if (hst->queue_size > 0) {
|
||||||
line_info_print(self);
|
line_info_print(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)
|
||||||
{
|
{
|
||||||
@ -533,6 +754,9 @@ void line_info_set(ToxWindow *self, uint32_t id, char *msg)
|
|||||||
|
|
||||||
while (line) {
|
while (line) {
|
||||||
if (line->id == id) {
|
if (line->id == id) {
|
||||||
|
size_t new_len = strlen(msg);
|
||||||
|
line->len = line->len - line->msg_len + new_len;
|
||||||
|
line->msg_len = new_len;
|
||||||
snprintf(line->msg, sizeof(line->msg), "%s", msg);
|
snprintf(line->msg, sizeof(line->msg), "%s", msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -541,56 +765,74 @@ void line_info_set(ToxWindow *self, uint32_t id, char *msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static void line_info_goto_root(struct history *hst)
|
static void line_info_scroll_up(ToxWindow *self, struct history *hst)
|
||||||
{
|
|
||||||
hst->line_start = hst->line_root;
|
|
||||||
} */
|
|
||||||
|
|
||||||
static void line_info_scroll_up(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);
|
||||||
|
|
||||||
int jump_dist = y2 / 2;
|
const int top_offset = (self->type == WINDOW_TYPE_CHAT) || (self->type == WINDOW_TYPE_PROMPT) ? TOP_BAR_HEIGHT : 0;
|
||||||
int i;
|
const int max_y = y2 - top_offset;
|
||||||
|
size_t jump_dist = max_y / 2;
|
||||||
|
|
||||||
for (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);
|
||||||
|
|
||||||
int jump_dist = y2 / 2;
|
const int top_offset = (self->type == WINDOW_TYPE_CHAT) || (self->type == WINDOW_TYPE_PROMPT) ? TOP_BAR_HEIGHT : 0;
|
||||||
int i;
|
const int max_y = y2 - top_offset;
|
||||||
|
size_t jump_dist = max_y / 2;
|
||||||
|
|
||||||
for (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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -604,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 {
|
||||||
|
@ -29,9 +29,9 @@
|
|||||||
#define MAX_HISTORY 100000
|
#define MAX_HISTORY 100000
|
||||||
#define MIN_HISTORY 40
|
#define MIN_HISTORY 40
|
||||||
#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,
|
||||||
@ -54,10 +54,12 @@ struct line_info {
|
|||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint8_t bold;
|
uint8_t bold;
|
||||||
uint8_t colour;
|
uint8_t colour;
|
||||||
uint8_t noread_flag; /* true if a line should be flagged as unread */
|
bool noread_flag; /* true if a line should be flagged as unread */
|
||||||
|
bool read_flag; /* true if a message has been flagged as read */
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
uint16_t len; /* combined len of entire line */
|
uint16_t len; /* combined length of entire line */
|
||||||
uint8_t newlines;
|
uint16_t msg_len; /* length of the message */
|
||||||
|
uint16_t format_lines; /* number of lines the combined string takes up (dynamically set) */
|
||||||
|
|
||||||
struct line_info *prev;
|
struct line_info *prev;
|
||||||
struct line_info *next;
|
struct line_info *next;
|
||||||
@ -71,7 +73,7 @@ struct history {
|
|||||||
uint32_t start_id; /* keeps track of where line_start should be when at bottom of history */
|
uint32_t start_id; /* keeps track of where line_start should be when at bottom of history */
|
||||||
|
|
||||||
struct line_info *queue[MAX_LINE_INFO_QUEUE];
|
struct line_info *queue[MAX_LINE_INFO_QUEUE];
|
||||||
int queue_sz;
|
size_t queue_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* creates new line_info line and puts it in the queue.
|
/* creates new line_info line and puts it in the queue.
|
||||||
@ -79,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 */
|
||||||
|
256
src/log.c
256
src/log.c
@ -35,29 +35,33 @@
|
|||||||
|
|
||||||
extern struct user_settings *user_settings;
|
extern struct user_settings *user_settings;
|
||||||
|
|
||||||
/* There are three types of logs: chat logs, conference logs, and prompt logs (see LOG_TYPE in log.h)
|
/* Creates a log path and puts it in `dest.
|
||||||
A prompt log is in the format: LOGDIR/selfkey-home.log
|
*
|
||||||
A chat log is in the format: LOGDIR/selfkey-friendname-otherkey.log
|
* There are two types of logs: chat logs and prompt logs (see LOG_TYPE in log.h)
|
||||||
A conference log is in the format: LOGDIR/selfkey-conferencename-date[time].log
|
* A prompt log is in the format: LOGDIR/selfkey-home.log
|
||||||
|
* A chat log is in the format: LOGDIR/selfkey-name-otherkey.log
|
||||||
Only the first (KEY_IDENT_DIGITS * 2) numbers of the key are used.
|
*
|
||||||
|
* For friend chats `otherkey` is the first 6 bytes of the friend's Tox ID.
|
||||||
Returns 0 on success, -1 if the path is too long */
|
* For Conferences/groups `otherkey` is the first 6 bytes of the group's unique ID.
|
||||||
static int get_log_path(char *dest, int destsize, char *name, const char *selfkey, const char *otherkey, int logtype)
|
*
|
||||||
|
* Return path length on success.
|
||||||
|
* Return -1 if the path is too long.
|
||||||
|
*/
|
||||||
|
static int get_log_path(char *dest, int destsize, const char *name, const char *selfkey, const char *otherkey)
|
||||||
{
|
{
|
||||||
if (!valid_nick(name)) {
|
if (!valid_nick(name)) {
|
||||||
name = UNKNOWN_NAME;
|
name = UNKNOWN_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *namedash = logtype == LOG_PROMPT ? "" : "-";
|
const char *namedash = otherkey ? "-" : "";
|
||||||
const char *set_path = user_settings->chatlogs_path;
|
const char *set_path = user_settings->chatlogs_path;
|
||||||
|
|
||||||
char *user_config_dir = get_user_config_dir();
|
char *user_config_dir = get_user_config_dir();
|
||||||
int path_len = strlen(name) + strlen(".log") + strlen("-") + strlen(namedash);
|
int path_len = strlen(name) + strlen(".log") + strlen("-") + strlen(namedash);
|
||||||
path_len += strlen(set_path) ? *set_path : strlen(user_config_dir) + strlen(LOGDIR);
|
path_len += strlen(set_path) ? *set_path : strlen(user_config_dir) + strlen(LOGDIR);
|
||||||
|
|
||||||
/* first 6 digits of selfkey */
|
/* first 6 bytes of selfkey */
|
||||||
char self_id[32];
|
char self_id[32] = {0};
|
||||||
path_len += KEY_IDENT_DIGITS * 2;
|
path_len += KEY_IDENT_DIGITS * 2;
|
||||||
sprintf(&self_id[0], "%02X", selfkey[0] & 0xff);
|
sprintf(&self_id[0], "%02X", selfkey[0] & 0xff);
|
||||||
sprintf(&self_id[2], "%02X", selfkey[1] & 0xff);
|
sprintf(&self_id[2], "%02X", selfkey[1] & 0xff);
|
||||||
@ -66,19 +70,13 @@ static int get_log_path(char *dest, int destsize, char *name, const char *selfke
|
|||||||
|
|
||||||
char other_id[32] = {0};
|
char other_id[32] = {0};
|
||||||
|
|
||||||
switch (logtype) {
|
if (otherkey) {
|
||||||
case LOG_CHAT:
|
/* first 6 bytes of otherkey */
|
||||||
path_len += KEY_IDENT_DIGITS * 2;
|
path_len += KEY_IDENT_DIGITS * 2;
|
||||||
sprintf(&other_id[0], "%02X", otherkey[0] & 0xff);
|
sprintf(&other_id[0], "%02X", otherkey[0] & 0xff);
|
||||||
sprintf(&other_id[2], "%02X", otherkey[1] & 0xff);
|
sprintf(&other_id[2], "%02X", otherkey[1] & 0xff);
|
||||||
sprintf(&other_id[4], "%02X", otherkey[2] & 0xff);
|
sprintf(&other_id[4], "%02X", otherkey[2] & 0xff);
|
||||||
other_id[KEY_IDENT_DIGITS * 2] = '\0';
|
other_id[KEY_IDENT_DIGITS * 2] = '\0';
|
||||||
break;
|
|
||||||
|
|
||||||
case LOG_CONFERENCE:
|
|
||||||
strftime(other_id, sizeof(other_id), "%Y-%m-%d[%H:%M:%S]", get_time());
|
|
||||||
path_len += strlen(other_id);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path_len >= destsize) {
|
if (path_len >= destsize) {
|
||||||
@ -94,28 +92,35 @@ static int get_log_path(char *dest, int destsize, char *name, const char *selfke
|
|||||||
|
|
||||||
free(user_config_dir);
|
free(user_config_dir);
|
||||||
|
|
||||||
return 0;
|
return path_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opens log file or creates a new one */
|
/* Initializes log path for `log`.
|
||||||
static int init_logging_session(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype)
|
*
|
||||||
|
* Return 0 on success.
|
||||||
|
* Return -1 on failure.
|
||||||
|
*/
|
||||||
|
static int init_logging_session(const char *name, const char *selfkey, const char *otherkey, struct chatlog *log,
|
||||||
|
LOG_TYPE type)
|
||||||
{
|
{
|
||||||
if (selfkey == NULL || (logtype == LOG_CHAT && otherkey == NULL)) {
|
if (log == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selfkey == NULL || (type == LOG_TYPE_CHAT && otherkey == NULL)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char log_path[MAX_STR_SIZE];
|
char log_path[MAX_STR_SIZE];
|
||||||
|
|
||||||
if (get_log_path(log_path, sizeof(log_path), name, selfkey, otherkey, logtype) == -1) {
|
int path_len = get_log_path(log_path, sizeof(log_path), name, selfkey, otherkey);
|
||||||
|
|
||||||
|
if (path_len == -1 || path_len >= sizeof(log->path)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
log->file = fopen(log_path, "a+");
|
memcpy(log->path, log_path, path_len);
|
||||||
snprintf(log->path, sizeof(log->path), "%s", log_path);
|
log->path[path_len] = 0;
|
||||||
|
|
||||||
if (log->file == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -124,6 +129,10 @@ static int init_logging_session(char *name, const char *selfkey, const char *oth
|
|||||||
|
|
||||||
void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event)
|
void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event)
|
||||||
{
|
{
|
||||||
|
if (log == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!log->log_on) {
|
if (!log->log_on) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -154,94 +163,162 @@ void write_to_log(const char *msg, const char *name, struct chatlog *log, bool e
|
|||||||
|
|
||||||
void log_disable(struct chatlog *log)
|
void log_disable(struct chatlog *log)
|
||||||
{
|
{
|
||||||
if (log->file != NULL) {
|
if (log == NULL) {
|
||||||
fclose(log->file);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
*log = (struct chatlog) {
|
if (log->file != NULL) {
|
||||||
0
|
fclose(log->file);
|
||||||
};
|
log->file = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
log->lastwrite = 0;
|
||||||
|
log->log_on = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int log_enable(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype)
|
int log_enable(struct chatlog *log)
|
||||||
{
|
{
|
||||||
log->log_on = true;
|
if (log == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (log->file != NULL) {
|
if (log->log_on) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (init_logging_session(name, selfkey, otherkey, log, logtype) == -1) {
|
if (*log->path == 0) {
|
||||||
log_disable(log);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (log->file != NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
log->file = fopen(log->path, "a+");
|
||||||
|
|
||||||
|
if (log->file == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
log->log_on = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loads previous history from chat log */
|
/* Initializes a log. This function must be called before any other logging operations.
|
||||||
void load_chat_history(ToxWindow *self, struct chatlog *log)
|
*
|
||||||
|
* Return 0 on success.
|
||||||
|
* Return -1 on failure.
|
||||||
|
*/
|
||||||
|
int log_init(struct chatlog *log, const char *name, const char *selfkey, const char *otherkey, LOG_TYPE type)
|
||||||
{
|
{
|
||||||
if (log->file == NULL) {
|
if (log == NULL) {
|
||||||
return;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log->file != NULL || log->log_on) {
|
||||||
|
fprintf(stderr, "Warning: Called log_init() on an already initialized log\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (init_logging_session(name, selfkey, otherkey, log, type) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_disable(log);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loads chat log history and prints it to `self` window.
|
||||||
|
*
|
||||||
|
* Return 0 on success or if log file doesn't exist.
|
||||||
|
* Return -1 on failure.
|
||||||
|
*/
|
||||||
|
int load_chat_history(ToxWindow *self, struct chatlog *log)
|
||||||
|
{
|
||||||
|
if (log == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*log->path == 0) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
off_t sz = file_size(log->path);
|
off_t sz = file_size(log->path);
|
||||||
|
|
||||||
if (sz <= 0) {
|
if (sz <= 0) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *hstbuf = malloc(sz + 1);
|
FILE *fp = fopen(log->path, "r");
|
||||||
|
|
||||||
if (hstbuf == NULL) {
|
if (fp == NULL) {
|
||||||
exit_toxic_err("failed in load_chat_history", FATALERR_MEMORY);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fseek(log->file, 0L, SEEK_SET) == -1) {
|
char *buf = malloc(sz + 1);
|
||||||
free(hstbuf);
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to read log file");
|
if (buf == NULL) {
|
||||||
return;
|
fclose(fp);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fread(hstbuf, sz, 1, log->file) != 1) {
|
if (fseek(fp, 0L, SEEK_SET) == -1) {
|
||||||
free(hstbuf);
|
free(buf);
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to read log file");
|
fclose(fp);
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
hstbuf[sz] = '\0';
|
if (fread(buf, sz, 1, fp) != 1) {
|
||||||
|
free(buf);
|
||||||
|
fclose(fp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
buf[sz] = 0;
|
||||||
|
|
||||||
/* Number of history lines to load: must not be larger than MAX_LINE_INFO_QUEUE - 2 */
|
/* Number of history lines to load: must not be larger than MAX_LINE_INFO_QUEUE - 2 */
|
||||||
int L = MIN(MAX_LINE_INFO_QUEUE - 2, user_settings->history_size);
|
int L = MIN(MAX_LINE_INFO_QUEUE - 2, user_settings->history_size);
|
||||||
int start, count = 0;
|
|
||||||
|
int start = 0;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
/* start at end and backtrace L lines or to the beginning of buffer */
|
/* start at end and backtrace L lines or to the beginning of buffer */
|
||||||
for (start = sz - 1; start >= 0 && count < L; --start) {
|
for (start = sz - 1; start >= 0 && count < L; --start) {
|
||||||
if (hstbuf[start] == '\n') {
|
if (buf[start] == '\n') {
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *line = strtok(&hstbuf[start + 1], "\n");
|
char *tmp = NULL;
|
||||||
|
const char *line = strtok_r(&buf[start + 1], "\n", &tmp);
|
||||||
|
|
||||||
if (line == NULL) {
|
if (line == NULL) {
|
||||||
free(hstbuf);
|
free(buf);
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
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(NULL, "\n");
|
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(hstbuf);
|
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* renames chatlog file replacing src with dest.
|
/* Renames chatlog file `src` to `dest`.
|
||||||
Returns 0 on success or if no log exists, -1 on failure. */
|
*
|
||||||
int rename_logfile(char *src, char *dest, const char *selfkey, const char *otherkey, int winnum)
|
* Return 0 on success or if no log exists.
|
||||||
|
* Return -1 on failure.
|
||||||
|
*/
|
||||||
|
int rename_logfile(const char *src, const char *dest, const char *selfkey, const char *otherkey, int winnum)
|
||||||
{
|
{
|
||||||
ToxWindow *toxwin = get_window_ptr(winnum);
|
ToxWindow *toxwin = get_window_ptr(winnum);
|
||||||
struct chatlog *log = NULL;
|
struct chatlog *log = NULL;
|
||||||
@ -250,6 +327,11 @@ int rename_logfile(char *src, char *dest, const char *selfkey, const char *other
|
|||||||
/* disable log if necessary and save its state */
|
/* disable log if necessary and save its state */
|
||||||
if (toxwin != NULL) {
|
if (toxwin != NULL) {
|
||||||
log = toxwin->chatwin->log;
|
log = toxwin->chatwin->log;
|
||||||
|
|
||||||
|
if (log == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
log_on = log->log_on;
|
log_on = log->log_on;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,24 +342,36 @@ int rename_logfile(char *src, char *dest, const char *selfkey, const char *other
|
|||||||
char newpath[MAX_STR_SIZE];
|
char newpath[MAX_STR_SIZE];
|
||||||
char oldpath[MAX_STR_SIZE];
|
char oldpath[MAX_STR_SIZE];
|
||||||
|
|
||||||
if (get_log_path(oldpath, sizeof(oldpath), src, selfkey, otherkey, LOG_CHAT) == -1) {
|
if (get_log_path(oldpath, sizeof(oldpath), src, selfkey, otherkey) == -1) {
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file_exists(oldpath)) {
|
if (!file_exists(oldpath)) {
|
||||||
|
init_logging_session(dest, selfkey, otherkey, log, LOG_TYPE_CHAT); // still need to rename path
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_log_path(newpath, sizeof(newpath), dest, selfkey, otherkey, LOG_CHAT) == -1) {
|
int new_path_len = get_log_path(newpath, sizeof(newpath), dest, selfkey, otherkey);
|
||||||
|
|
||||||
|
if (new_path_len == -1 || new_path_len >= MAX_STR_SIZE) {
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rename(oldpath, newpath) != 0) {
|
if (file_exists(newpath)) {
|
||||||
|
if (remove(oldpath) != 0) {
|
||||||
|
fprintf(stderr, "Warning: remove() failed to remove log path `%s`\n", oldpath);
|
||||||
|
}
|
||||||
|
} else if (rename(oldpath, newpath) != 0) {
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log_on) {
|
if (log != NULL) {
|
||||||
log_enable(dest, selfkey, otherkey, log, LOG_CHAT);
|
memcpy(log->path, newpath, new_path_len);
|
||||||
|
log->path[new_path_len] = 0;
|
||||||
|
|
||||||
|
if (log_on) {
|
||||||
|
log_enable(log);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -285,7 +379,7 @@ int rename_logfile(char *src, char *dest, const char *selfkey, const char *other
|
|||||||
on_error:
|
on_error:
|
||||||
|
|
||||||
if (log_on) {
|
if (log_on) {
|
||||||
log_enable(src, selfkey, otherkey, log, LOG_CHAT);
|
log_enable(log);
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
35
src/log.h
35
src/log.h
@ -30,30 +30,43 @@ struct chatlog {
|
|||||||
bool log_on; /* specific to current chat window */
|
bool log_on; /* specific to current chat window */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum LOG_TYPE {
|
||||||
LOG_CONFERENCE,
|
LOG_TYPE_PROMPT,
|
||||||
LOG_PROMPT,
|
LOG_TYPE_CHAT,
|
||||||
LOG_CHAT,
|
|
||||||
} LOG_TYPE;
|
} LOG_TYPE;
|
||||||
|
|
||||||
|
/* Initializes a log. This function must be called before any other logging operations.
|
||||||
|
*
|
||||||
|
* Return 0 on success.
|
||||||
|
* Return -1 on failure.
|
||||||
|
*/
|
||||||
|
int log_init(struct chatlog *log, const char *name, const char *selfkey, const char *otherkey, LOG_TYPE type);
|
||||||
|
|
||||||
/* formats/writes line to log file */
|
/* formats/writes line to log file */
|
||||||
void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event);
|
void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event);
|
||||||
|
|
||||||
/* enables logging for specified log and creates/fetches file if necessary.
|
/* enables logging for specified log.
|
||||||
*
|
*
|
||||||
* Returns 0 on success.
|
* Returns 0 on success.
|
||||||
* Returns -1 on failure.
|
* Returns -1 on failure.
|
||||||
*/
|
*/
|
||||||
int log_enable(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype);
|
int log_enable(struct chatlog *log);
|
||||||
|
|
||||||
/* disables logging for specified log and closes file */
|
/* disables logging for specified log and closes file */
|
||||||
void log_disable(struct chatlog *log);
|
void log_disable(struct chatlog *log);
|
||||||
|
|
||||||
/* Loads previous history from chat log */
|
/* Loads chat log history and prints it to `self` window.
|
||||||
void load_chat_history(ToxWindow *self, struct chatlog *log);
|
*
|
||||||
|
* Return 0 on success or if log file doesn't exist.
|
||||||
|
* Return -1 on failure.
|
||||||
|
*/
|
||||||
|
int load_chat_history(ToxWindow *self, struct chatlog *log);
|
||||||
|
|
||||||
/* renames chatlog file replacing src with dest.
|
/* Renames chatlog file `src` to `dest`.
|
||||||
Returns 0 on success or if no log exists, -1 on failure. */
|
*
|
||||||
int rename_logfile(char *src, char *dest, const char *selfkey, const char *otherkey, int winnum);
|
* Return 0 on success or if no log exists.
|
||||||
|
* Return -1 on failure.
|
||||||
|
*/
|
||||||
|
int rename_logfile(const char *src, const char *dest, const char *selfkey, const char *otherkey, int winnum);
|
||||||
|
|
||||||
#endif /* LOG_H */
|
#endif /* LOG_H */
|
||||||
|
@ -86,9 +86,9 @@ static void cqueue_mark_read(ToxWindow *self, struct cqueue_msg *msg)
|
|||||||
|
|
||||||
line->type = msg->type == OUT_ACTION ? OUT_ACTION_READ : OUT_MSG_READ;
|
line->type = msg->type == OUT_ACTION ? OUT_ACTION_READ : OUT_MSG_READ;
|
||||||
|
|
||||||
if (line->noread_flag == true) {
|
if (line->noread_flag) {
|
||||||
line->len -= 2;
|
|
||||||
line->noread_flag = false;
|
line->noread_flag = false;
|
||||||
|
line->read_flag = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -584,7 +592,7 @@ void set_window_title(ToxWindow *self, const char *title, int len)
|
|||||||
|
|
||||||
char cpy[TOXIC_MAX_NAME_LENGTH + 1];
|
char cpy[TOXIC_MAX_NAME_LENGTH + 1];
|
||||||
|
|
||||||
if (self->type == WINDOW_TYPE_CONFERENCE) { /* keep conferencenumber in title */
|
if (self->type == WINDOW_TYPE_CONFERENCE) { /* keep conferencenumber in title for invites */
|
||||||
snprintf(cpy, sizeof(cpy), "%u %s", self->num, title);
|
snprintf(cpy, sizeof(cpy), "%u %s", self->num, title);
|
||||||
} else {
|
} else {
|
||||||
snprintf(cpy, sizeof(cpy), "%s", title);
|
snprintf(cpy, sizeof(cpy), "%s", title);
|
||||||
|
@ -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 */
|
||||||
|
@ -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;
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
#include "misc_tools.h"
|
#include "misc_tools.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "xtra.h"
|
#include "x11focus.h"
|
||||||
|
|
||||||
#if defined(AUDIO) || defined(SOUND_NOTIFY)
|
#if defined(AUDIO) || defined(SOUND_NOTIFY)
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
@ -126,6 +126,8 @@ static void tab_notify(ToxWindow *self, uint64_t flags)
|
|||||||
} else if ((flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1)) {
|
} else if ((flags & NT_WNDALERT_2) && (!self->alert || self->alert > WINDOW_ALERT_1)) {
|
||||||
self->alert = WINDOW_ALERT_2;
|
self->alert = WINDOW_ALERT_2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
++self->pending_messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool notifications_are_disabled(uint64_t flags)
|
static bool notifications_are_disabled(uint64_t flags)
|
||||||
|
171
src/prompt.c
171
src/prompt.c
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,18 +281,18 @@ static bool prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
|||||||
add_line_to_hist(ctx);
|
add_line_to_hist(ctx);
|
||||||
wstrsubst(ctx->line, L'¶', L'\n');
|
wstrsubst(ctx->line, L'¶', L'\n');
|
||||||
|
|
||||||
char line[MAX_STR_SIZE] = {0};
|
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) {
|
||||||
memset(line, 0, sizeof(line));
|
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, " * Failed to parse message.");
|
||||||
|
} else {
|
||||||
|
line_info_add(self, false, NULL, NULL, PROMPT, 0, 0, "%s", line);
|
||||||
|
execute(ctx->history, self, m, line, GLOBAL_COMMAND_MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
line_info_add(self, NULL, NULL, NULL, PROMPT, 0, 0, "%s", line);
|
|
||||||
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,29 +562,50 @@ 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)
|
||||||
|
{
|
||||||
|
ChatContext *ctx = self->chatwin;
|
||||||
|
|
||||||
|
char myid[TOX_ADDRESS_SIZE];
|
||||||
|
tox_self_get_address(m, (uint8_t *) myid);
|
||||||
|
|
||||||
|
if (log_init(ctx->log, self->name, myid, NULL, LOG_TYPE_PROMPT) != 0) {
|
||||||
|
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_settings->autolog == AUTOLOG_ON) {
|
||||||
|
if (log_enable(ctx->log) == -1) {
|
||||||
|
line_info_add(self, false, NULL, NULL, SYS_MSG, 0, 0, "Warning: Failed to enable log.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
@ -565,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));
|
||||||
@ -577,14 +627,7 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
line_info_init(ctx->hst);
|
line_info_init(ctx->hst);
|
||||||
|
|
||||||
if (user_settings->autolog == AUTOLOG_ON) {
|
prompt_init_log(self, m, self->name);
|
||||||
char myid[TOX_ADDRESS_SIZE];
|
|
||||||
tox_self_get_address(m, (uint8_t *) myid);
|
|
||||||
|
|
||||||
if (log_enable(self->name, myid, NULL, ctx->log, LOG_PROMPT) == -1) {
|
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollok(ctx->history, 0);
|
scrollok(ctx->history, 0);
|
||||||
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
wmove(self->window, y2 - CURS_Y_OFFSET, 0);
|
||||||
@ -611,7 +654,7 @@ ToxWindow *new_prompt(void)
|
|||||||
ret->onConnectionChange = &prompt_onConnectionChange;
|
ret->onConnectionChange = &prompt_onConnectionChange;
|
||||||
ret->onFriendRequest = &prompt_onFriendRequest;
|
ret->onFriendRequest = &prompt_onFriendRequest;
|
||||||
|
|
||||||
strcpy(ret->name, "home");
|
strcpy(ret->name, "Home");
|
||||||
|
|
||||||
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
|
ChatContext *chatwin = calloc(1, sizeof(ChatContext));
|
||||||
StatusBar *stb = calloc(1, sizeof(StatusBar));
|
StatusBar *stb = calloc(1, sizeof(StatusBar));
|
||||||
|
@ -114,25 +114,23 @@ static PyObject *python_api_get_status_message(PyObject *self, PyObject *args)
|
|||||||
|
|
||||||
static PyObject *python_api_get_all_friends(PyObject *self, PyObject *args)
|
static PyObject *python_api_get_all_friends(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
size_t i, ii;
|
|
||||||
FriendsList friends;
|
FriendsList friends;
|
||||||
PyObject *cur, *ret;
|
char pubkey_buf[TOX_PUBLIC_KEY_SIZE * 2 + 1];
|
||||||
char pubkey_buf[TOX_PUBLIC_KEY_SIZE * 2 + 1];
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "")) {
|
if (!PyArg_ParseTuple(args, "")) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
friends = api_get_friendslist();
|
friends = api_get_friendslist();
|
||||||
ret = PyList_New(0);
|
PyObject *ret = PyList_New(0);
|
||||||
|
|
||||||
for (i = 0; i < friends.num_friends; i++) {
|
for (size_t i = 0; i < friends.num_friends; i++) {
|
||||||
for (ii = 0; ii < TOX_PUBLIC_KEY_SIZE; ii++) {
|
for (size_t ii = 0; ii < TOX_PUBLIC_KEY_SIZE; ii++) {
|
||||||
snprintf(pubkey_buf + ii * 2, 3, "%02X", friends.list[i].pub_key[ii] & 0xff);
|
snprintf(pubkey_buf + ii * 2, 3, "%02X", friends.list[i].pub_key[ii] & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
pubkey_buf[TOX_PUBLIC_KEY_SIZE * 2] = '\0';
|
pubkey_buf[TOX_PUBLIC_KEY_SIZE * 2] = '\0';
|
||||||
cur = Py_BuildValue("(s,s)", friends.list[i].name, pubkey_buf);
|
PyObject *cur = Py_BuildValue("(s,s)", friends.list[i].name, pubkey_buf);
|
||||||
PyList_Append(ret, cur);
|
PyList_Append(ret, cur);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,14 +262,14 @@ PyMODINIT_FUNC PyInit_toxic_api(void)
|
|||||||
|
|
||||||
void terminate_python(void)
|
void terminate_python(void)
|
||||||
{
|
{
|
||||||
struct python_registered_func *cur, *old;
|
|
||||||
|
|
||||||
if (python_commands.name != NULL) {
|
if (python_commands.name != NULL) {
|
||||||
free(python_commands.name);
|
free(python_commands.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct python_registered_func *cur = NULL;
|
||||||
|
|
||||||
for (cur = python_commands.next; cur != NULL;) {
|
for (cur = python_commands.next; cur != NULL;) {
|
||||||
old = cur;
|
struct python_registered_func *old = cur;
|
||||||
cur = cur->next;
|
cur = cur->next;
|
||||||
free(old->name);
|
free(old->name);
|
||||||
free(old);
|
free(old);
|
||||||
|
@ -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 {
|
||||||
@ -205,11 +211,17 @@ static const struct audio_strings {
|
|||||||
const char *input_device;
|
const char *input_device;
|
||||||
const char *output_device;
|
const char *output_device;
|
||||||
const char *VAD_threshold;
|
const char *VAD_threshold;
|
||||||
|
const char *conference_audio_channels;
|
||||||
|
const char *chat_audio_channels;
|
||||||
|
const char *push_to_talk;
|
||||||
} audio_strings = {
|
} audio_strings = {
|
||||||
"audio",
|
"audio",
|
||||||
"input_device",
|
"input_device",
|
||||||
"output_device",
|
"output_device",
|
||||||
"VAD_threshold",
|
"VAD_threshold",
|
||||||
|
"conference_audio_channels",
|
||||||
|
"chat_audio_channels",
|
||||||
|
"push_to_talk",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void audio_defaults(struct user_settings *settings)
|
static void audio_defaults(struct user_settings *settings)
|
||||||
@ -217,6 +229,9 @@ static void audio_defaults(struct user_settings *settings)
|
|||||||
settings->audio_in_dev = 0;
|
settings->audio_in_dev = 0;
|
||||||
settings->audio_out_dev = 0;
|
settings->audio_out_dev = 0;
|
||||||
settings->VAD_threshold = 5.0;
|
settings->VAD_threshold = 5.0;
|
||||||
|
settings->conference_audio_channels = 1;
|
||||||
|
settings->chat_audio_channels = 2;
|
||||||
|
settings->push_to_talk = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -330,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]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -339,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);
|
||||||
}
|
}
|
||||||
@ -506,6 +537,15 @@ int settings_load(struct user_settings *s, const char *patharg)
|
|||||||
s->audio_out_dev = s->audio_out_dev < 0 || s->audio_out_dev > MAX_DEVICES ? 0 : s->audio_out_dev;
|
s->audio_out_dev = s->audio_out_dev < 0 || s->audio_out_dev > MAX_DEVICES ? 0 : s->audio_out_dev;
|
||||||
|
|
||||||
config_setting_lookup_float(setting, audio_strings.VAD_threshold, &s->VAD_threshold);
|
config_setting_lookup_float(setting, audio_strings.VAD_threshold, &s->VAD_threshold);
|
||||||
|
|
||||||
|
config_setting_lookup_int(setting, audio_strings.conference_audio_channels, &s->conference_audio_channels);
|
||||||
|
s->conference_audio_channels = s->conference_audio_channels <= 0
|
||||||
|
|| s->conference_audio_channels > 2 ? 1 : s->conference_audio_channels;
|
||||||
|
|
||||||
|
config_setting_lookup_int(setting, audio_strings.chat_audio_channels, &s->chat_audio_channels);
|
||||||
|
s->chat_audio_channels = s->chat_audio_channels <= 0 || s->chat_audio_channels > 2 ? 2 : s->chat_audio_channels;
|
||||||
|
|
||||||
|
config_setting_lookup_bool(setting, audio_strings.push_to_talk, &s->push_to_talk);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -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;
|
||||||
@ -85,6 +90,9 @@ struct user_settings {
|
|||||||
int audio_in_dev;
|
int audio_in_dev;
|
||||||
int audio_out_dev;
|
int audio_out_dev;
|
||||||
double VAD_threshold;
|
double VAD_threshold;
|
||||||
|
int conference_audio_channels;
|
||||||
|
int chat_audio_channels;
|
||||||
|
int push_to_talk; /* boolean */
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -119,10 +127,10 @@ enum settings_values {
|
|||||||
#define LINE_JOIN "-->"
|
#define LINE_JOIN "-->"
|
||||||
#define LINE_QUIT "<--"
|
#define LINE_QUIT "<--"
|
||||||
#define LINE_ALERT "-!-"
|
#define LINE_ALERT "-!-"
|
||||||
#define LINE_NORMAL "---"
|
#define LINE_NORMAL "-"
|
||||||
#define TIMESTAMP_DEFAULT "%H:%M:%S"
|
#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);
|
||||||
|
|
||||||
|
156
src/toxic.c
156
src/toxic.c
@ -66,7 +66,7 @@
|
|||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
|
|
||||||
#ifdef X11
|
#ifdef X11
|
||||||
#include "xtra.h"
|
#include "x11focus.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef AUDIO
|
#ifdef AUDIO
|
||||||
@ -205,10 +205,7 @@ void exit_toxic_success(Tox *m)
|
|||||||
curl_global_cleanup();
|
curl_global_cleanup();
|
||||||
|
|
||||||
#ifdef X11
|
#ifdef X11
|
||||||
/* We have to terminate xtra last coz reasons
|
terminate_x11focus();
|
||||||
* Please don't call this anywhere else coz trust me
|
|
||||||
*/
|
|
||||||
terminate_xtra();
|
|
||||||
#endif /* X11 */
|
#endif /* X11 */
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
@ -259,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) {
|
||||||
@ -271,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();
|
||||||
@ -1350,21 +1456,6 @@ static void init_default_data_files(void)
|
|||||||
free(user_config_dir);
|
free(user_config_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this doesn't do anything (yet)
|
|
||||||
#ifdef X11
|
|
||||||
void DnD_callback(const char *asdv, DropType dt)
|
|
||||||
{
|
|
||||||
UNUSED_VAR(asdv);
|
|
||||||
UNUSED_VAR(dt);
|
|
||||||
// if (dt != DT_plain)
|
|
||||||
// return;
|
|
||||||
|
|
||||||
// pthread_mutex_lock(&Winthread.lock);
|
|
||||||
// line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, asdv);
|
|
||||||
// pthread_mutex_unlock(&Winthread.lock);
|
|
||||||
}
|
|
||||||
#endif /* X11 */
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
/* Make sure all written files are read/writeable only by the current user. */
|
/* Make sure all written files are read/writeable only by the current user. */
|
||||||
@ -1422,7 +1513,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
#ifdef X11
|
#ifdef X11
|
||||||
|
|
||||||
if (init_xtra(DnD_callback) == -1) {
|
if (init_x11focus() == -1) {
|
||||||
queue_init_message("X failed to initialize");
|
queue_init_message("X failed to initialize");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1439,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);
|
||||||
@ -1521,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);
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
180
src/windows.c
180
src/windows.c
@ -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,82 +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)
|
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;
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
pthread_mutex_unlock(&Winthread.lock);
|
||||||
|
|
||||||
clrtoeol();
|
WINDOW_TYPE type = toxwin->type;
|
||||||
printw(" [%s]", toxwin->name);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
if (active_window) {
|
||||||
|
wattron(win, A_BOLD | COLOR_PAIR(BAR_ACCENT));
|
||||||
if (toxwin->alert != WINDOW_ALERT_NONE) {
|
wprintw(win, " [");
|
||||||
attroff(COLOR_PAIR(toxwin->alert));
|
wattroff(win, COLOR_PAIR(BAR_ACCENT));
|
||||||
|
wattron(win, COLOR_PAIR(BAR_TEXT));
|
||||||
|
} else {
|
||||||
|
if (has_alert) {
|
||||||
|
wattron(win, COLOR_PAIR(BAR_ACCENT));
|
||||||
|
wprintw(win, " [");
|
||||||
|
wattroff(win, COLOR_PAIR(BAR_ACCENT));
|
||||||
|
wattron(win, A_BOLD | COLOR_PAIR(toxwin->alert));
|
||||||
|
} else {
|
||||||
|
wattron(win, COLOR_PAIR(BAR_ACCENT));
|
||||||
|
wprintw(win, " [");
|
||||||
|
wattroff(win, COLOR_PAIR(BAR_ACCENT));
|
||||||
|
wattron(win, COLOR_PAIR(BAR_TEXT));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&Winthread.lock);
|
if (active_window || (type == WINDOW_TYPE_PROMPT || type == WINDOW_TYPE_FRIEND_LIST)) {
|
||||||
|
wprintw(win, "%s", toxwin->name);
|
||||||
|
} else {
|
||||||
|
if (pending_messages > 0) {
|
||||||
|
wprintw(win, "%u", pending_messages);
|
||||||
|
} else {
|
||||||
|
wprintw(win, "-");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == active_window_index) {
|
bool active_window = i == active_window_index;
|
||||||
|
draw_window_tab(win, windows[i], active_window);
|
||||||
#ifdef URXVT_FIX
|
|
||||||
attron(A_BOLD | COLOR_PAIR(GREEN));
|
|
||||||
} else {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
attron(A_BOLD);
|
|
||||||
}
|
|
||||||
|
|
||||||
draw_window_tab(windows[i]);
|
|
||||||
|
|
||||||
if (i == active_window_index) {
|
|
||||||
|
|
||||||
#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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -666,10 +699,9 @@ void draw_active_window(Tox *m)
|
|||||||
|
|
||||||
pthread_mutex_lock(&Winthread.lock);
|
pthread_mutex_lock(&Winthread.lock);
|
||||||
a->alert = WINDOW_ALERT_NONE;
|
a->alert = WINDOW_ALERT_NONE;
|
||||||
|
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);
|
||||||
|
@ -36,12 +36,14 @@
|
|||||||
|
|
||||||
#include "toxic.h"
|
#include "toxic.h"
|
||||||
|
|
||||||
#define MAX_WINDOWS_NUM 16
|
#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,8 @@ 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 */
|
||||||
int x;
|
int x;
|
||||||
|
|
||||||
WINDOW_TYPE type;
|
WINDOW_TYPE type;
|
||||||
@ -180,6 +194,7 @@ struct ToxWindow {
|
|||||||
Help *help;
|
Help *help;
|
||||||
|
|
||||||
WINDOW *window;
|
WINDOW *window;
|
||||||
|
WINDOW *window_bar;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* statusbar info holder */
|
/* statusbar info holder */
|
||||||
@ -263,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 */
|
||||||
|
87
src/x11focus.c
Normal file
87
src/x11focus.c
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/* x11focus.c
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Toxic All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This file is part of Toxic.
|
||||||
|
*
|
||||||
|
* Toxic is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Toxic is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "x11focus.h"
|
||||||
|
|
||||||
|
#ifndef __APPLE__
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
static struct Focus {
|
||||||
|
Display *display;
|
||||||
|
Window terminal_window;
|
||||||
|
} Focus;
|
||||||
|
|
||||||
|
static long unsigned int focused_window_id(void)
|
||||||
|
{
|
||||||
|
if (!Focus.display) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Window focus;
|
||||||
|
int revert;
|
||||||
|
|
||||||
|
XLockDisplay(Focus.display);
|
||||||
|
XGetInputFocus(Focus.display, &focus, &revert);
|
||||||
|
XUnlockDisplay(Focus.display);
|
||||||
|
|
||||||
|
return focus;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_focused(void)
|
||||||
|
{
|
||||||
|
if (!Focus.display) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Focus.terminal_window == focused_window_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
int init_x11focus(void)
|
||||||
|
{
|
||||||
|
if (XInitThreads() == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Focus.display = XOpenDisplay(NULL);
|
||||||
|
|
||||||
|
if (!Focus.display) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Focus.terminal_window = focused_window_id();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void terminate_x11focus(void)
|
||||||
|
{
|
||||||
|
if (!Focus.display || !Focus.terminal_window) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
XLockDisplay(Focus.display);
|
||||||
|
XCloseDisplay(Focus.display);
|
||||||
|
XUnlockDisplay(Focus.display);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !__APPLE__ */
|
@ -1,7 +1,7 @@
|
|||||||
/* xtra.h
|
/* xtra.h
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Toxic All Rights Reserved.
|
* Copyright (C) 2020 Toxic All Rights Reserved.
|
||||||
*
|
*
|
||||||
* This file is part of Toxic.
|
* This file is part of Toxic.
|
||||||
*
|
*
|
||||||
@ -20,21 +20,15 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef XTRA_H
|
#ifndef X11FOCUS_H
|
||||||
#define XTRA_H
|
#define X11FOCUS_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
/* NOTE: If no xlib present don't compile */
|
/* NOTE: If no xlib present don't compile */
|
||||||
|
|
||||||
typedef enum {
|
int init_x11focus(void);
|
||||||
DT_plain,
|
void terminate_x11focus(void);
|
||||||
DT_file_list
|
bool is_focused(void);
|
||||||
}
|
|
||||||
DropType;
|
|
||||||
|
|
||||||
typedef void (*drop_callback)(const char *, DropType);
|
#endif /* X11FOCUS */
|
||||||
|
|
||||||
int init_xtra(drop_callback d);
|
|
||||||
void terminate_xtra(void);
|
|
||||||
int is_focused(void); /* returns bool */
|
|
||||||
|
|
||||||
#endif /* XTRA_H */
|
|
425
src/xtra.c
425
src/xtra.c
@ -1,425 +0,0 @@
|
|||||||
/* xtra.c
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Copyright (C) 2014 Toxic All Rights Reserved.
|
|
||||||
*
|
|
||||||
* This file is part of Toxic.
|
|
||||||
*
|
|
||||||
* Toxic is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Toxic is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "misc_tools.h"
|
|
||||||
#include "xtra.h"
|
|
||||||
|
|
||||||
#ifndef __APPLE__
|
|
||||||
|
|
||||||
#include <X11/Xatom.h>
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
|
|
||||||
const Atom XtraTerminate = 1;
|
|
||||||
const Atom XtraNil = 0;
|
|
||||||
|
|
||||||
static Atom XdndAware;
|
|
||||||
static Atom XdndEnter;
|
|
||||||
static Atom XdndLeave;
|
|
||||||
static Atom XdndPosition;
|
|
||||||
static Atom XdndStatus;
|
|
||||||
static Atom XdndDrop;
|
|
||||||
static Atom XdndSelection;
|
|
||||||
static Atom XdndDATA;
|
|
||||||
static Atom XdndTypeList;
|
|
||||||
static Atom XdndActionCopy;
|
|
||||||
static Atom XdndFinished;
|
|
||||||
|
|
||||||
struct Xtra {
|
|
||||||
drop_callback on_drop;
|
|
||||||
Display *display;
|
|
||||||
Window terminal_window;
|
|
||||||
Window proxy_window;
|
|
||||||
Window source_window; /* When we have a drop */
|
|
||||||
Atom handling_version;
|
|
||||||
Atom expecting_type;
|
|
||||||
} Xtra;
|
|
||||||
|
|
||||||
typedef struct Property {
|
|
||||||
unsigned char *data;
|
|
||||||
int read_format;
|
|
||||||
unsigned long read_num;
|
|
||||||
Atom read_type;
|
|
||||||
} Property;
|
|
||||||
|
|
||||||
static Property read_property(Window s, Atom p)
|
|
||||||
{
|
|
||||||
Atom read_type;
|
|
||||||
int read_format;
|
|
||||||
unsigned long read_num;
|
|
||||||
unsigned long left_bytes;
|
|
||||||
unsigned char *data = NULL;
|
|
||||||
|
|
||||||
int read_bytes = 1024;
|
|
||||||
|
|
||||||
/* Keep trying to read the property until there are no bytes unread */
|
|
||||||
do {
|
|
||||||
if (data) {
|
|
||||||
XFree(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
XGetWindowProperty(Xtra.display, s,
|
|
||||||
p, 0,
|
|
||||||
read_bytes,
|
|
||||||
False, AnyPropertyType,
|
|
||||||
&read_type, &read_format,
|
|
||||||
&read_num, &left_bytes,
|
|
||||||
&data);
|
|
||||||
|
|
||||||
read_bytes *= 2;
|
|
||||||
} while (left_bytes != 0);
|
|
||||||
|
|
||||||
Property property = {data, read_format, read_num, read_type};
|
|
||||||
return property;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Atom get_dnd_type(long *a, int l)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
for (; i < l; i ++) {
|
|
||||||
if (a[i] != XtraNil) {
|
|
||||||
return a[i]; /* Get first valid */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return XtraNil;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO maybe support only certain types in the future */
|
|
||||||
static void handle_xdnd_enter(XClientMessageEvent *e)
|
|
||||||
{
|
|
||||||
Xtra.handling_version = (e->data.l[1] >> 24);
|
|
||||||
|
|
||||||
if ((e->data.l[1] & 1)) {
|
|
||||||
// Fetch the list of possible conversions
|
|
||||||
Property p = read_property(e->data.l[0], XdndTypeList);
|
|
||||||
Xtra.expecting_type = get_dnd_type((long *)p.data, p.read_num);
|
|
||||||
XFree(p.data);
|
|
||||||
} else {
|
|
||||||
// Use the available list
|
|
||||||
Xtra.expecting_type = get_dnd_type(e->data.l + 2, 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_xdnd_position(XClientMessageEvent *e)
|
|
||||||
{
|
|
||||||
XEvent ev = {
|
|
||||||
.xclient = {
|
|
||||||
.type = ClientMessage,
|
|
||||||
.display = e->display,
|
|
||||||
.window = e->data.l[0],
|
|
||||||
.message_type = XdndStatus,
|
|
||||||
.format = 32,
|
|
||||||
.data = {
|
|
||||||
.l = {
|
|
||||||
Xtra.proxy_window,
|
|
||||||
(Xtra.expecting_type != XtraNil),
|
|
||||||
0, 0,
|
|
||||||
XdndActionCopy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
XSendEvent(Xtra.display, e->data.l[0], False, NoEventMask, &ev);
|
|
||||||
XFlush(Xtra.display);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_xdnd_drop(XClientMessageEvent *e)
|
|
||||||
{
|
|
||||||
/* Not expecting any type */
|
|
||||||
if (Xtra.expecting_type == XtraNil) {
|
|
||||||
XEvent ev = {
|
|
||||||
.xclient = {
|
|
||||||
.type = ClientMessage,
|
|
||||||
.display = e->display,
|
|
||||||
.window = e->data.l[0],
|
|
||||||
.message_type = XdndFinished,
|
|
||||||
.format = 32,
|
|
||||||
.data = {
|
|
||||||
.l = {Xtra.proxy_window, 0, 0}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
XSendEvent(Xtra.display, e->data.l[0], False, NoEventMask, &ev);
|
|
||||||
} else {
|
|
||||||
Xtra.source_window = e->data.l[0];
|
|
||||||
XConvertSelection(Xtra.display,
|
|
||||||
XdndSelection,
|
|
||||||
Xtra.expecting_type,
|
|
||||||
XdndSelection,
|
|
||||||
Xtra.proxy_window,
|
|
||||||
Xtra.handling_version >= 1 ? e->data.l[2] : CurrentTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_xdnd_selection(XSelectionEvent *e)
|
|
||||||
{
|
|
||||||
UNUSED_VAR(e);
|
|
||||||
|
|
||||||
/* DnD succesfully finished, send finished and call callback */
|
|
||||||
XEvent ev = {
|
|
||||||
.xclient = {
|
|
||||||
.type = ClientMessage,
|
|
||||||
.display = Xtra.display,
|
|
||||||
.window = Xtra.source_window,
|
|
||||||
.message_type = XdndFinished,
|
|
||||||
.format = 32,
|
|
||||||
.data = {
|
|
||||||
.l = {Xtra.proxy_window, 1, XdndActionCopy}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
XSendEvent(Xtra.display, Xtra.source_window, False, NoEventMask, &ev);
|
|
||||||
|
|
||||||
Property p = read_property(Xtra.proxy_window, XdndSelection);
|
|
||||||
DropType dt;
|
|
||||||
|
|
||||||
if (strcmp(XGetAtomName(Xtra.display, p.read_type), "text/uri-list") == 0) {
|
|
||||||
dt = DT_file_list;
|
|
||||||
} else { /* text/uri-list */
|
|
||||||
dt = DT_plain;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Call callback for every entry */
|
|
||||||
if (Xtra.on_drop && p.read_num) {
|
|
||||||
char *sptr;
|
|
||||||
char *str = strtok_r((char *) p.data, "\n\r", &sptr);
|
|
||||||
|
|
||||||
if (str) {
|
|
||||||
Xtra.on_drop(str, dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((str = strtok_r(NULL, "\n\r", &sptr))) {
|
|
||||||
Xtra.on_drop(str, dt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p.data) {
|
|
||||||
XFree(p.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void *event_loop(void *p)
|
|
||||||
{
|
|
||||||
/* Handle events like a real nigga */
|
|
||||||
|
|
||||||
UNUSED_VAR(p); /* DINDUNOTHIN */
|
|
||||||
|
|
||||||
XEvent event;
|
|
||||||
int pending;
|
|
||||||
|
|
||||||
while (Xtra.display) {
|
|
||||||
/* NEEDMOEVENTSFODEMPROGRAMS */
|
|
||||||
|
|
||||||
XLockDisplay(Xtra.display);
|
|
||||||
|
|
||||||
if ((pending = XPending(Xtra.display))) {
|
|
||||||
XNextEvent(Xtra.display, &event);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pending) {
|
|
||||||
XUnlockDisplay(Xtra.display);
|
|
||||||
sleep_thread(10000L);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.type == ClientMessage) {
|
|
||||||
Atom type = event.xclient.message_type;
|
|
||||||
|
|
||||||
if (type == XdndEnter) {
|
|
||||||
handle_xdnd_enter(&event.xclient);
|
|
||||||
} else if (type == XdndPosition) {
|
|
||||||
handle_xdnd_position(&event.xclient);
|
|
||||||
} else if (type == XdndDrop) {
|
|
||||||
handle_xdnd_drop(&event.xclient);
|
|
||||||
} else if (type == XtraTerminate) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (event.type == SelectionNotify) {
|
|
||||||
handle_xdnd_selection(&event.xselection);
|
|
||||||
}
|
|
||||||
/* AINNOBODYCANHANDLEDEMEVENTS*/
|
|
||||||
else {
|
|
||||||
XSendEvent(Xtra.display, Xtra.terminal_window, 0, 0, &event);
|
|
||||||
}
|
|
||||||
|
|
||||||
XUnlockDisplay(Xtra.display);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Actual XTRA termination
|
|
||||||
* Please call xtra_terminate() at exit
|
|
||||||
* otherwise HEWUSAGUDBOI happens
|
|
||||||
*/
|
|
||||||
if (Xtra.display) {
|
|
||||||
XCloseDisplay(Xtra.display);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (Xtra.display = NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static long unsigned int focused_window_id(void)
|
|
||||||
{
|
|
||||||
if (!Xtra.display) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Window focus;
|
|
||||||
int revert;
|
|
||||||
XLockDisplay(Xtra.display);
|
|
||||||
XGetInputFocus(Xtra.display, &focus, &revert);
|
|
||||||
XUnlockDisplay(Xtra.display);
|
|
||||||
return focus;
|
|
||||||
}
|
|
||||||
|
|
||||||
int is_focused(void)
|
|
||||||
{
|
|
||||||
return Xtra.display && (Xtra.proxy_window == focused_window_id() || Xtra.terminal_window == focused_window_id());
|
|
||||||
}
|
|
||||||
|
|
||||||
int init_xtra(drop_callback d)
|
|
||||||
{
|
|
||||||
if (!d) {
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
Xtra.on_drop = d;
|
|
||||||
}
|
|
||||||
|
|
||||||
XInitThreads();
|
|
||||||
|
|
||||||
if (!(Xtra.display = XOpenDisplay(NULL))) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Xtra.terminal_window = focused_window_id();
|
|
||||||
|
|
||||||
/* OSX: if focused window is 0, it means toxic is ran from
|
|
||||||
* native terminal and not X11 terminal window, silently exit */
|
|
||||||
if (!Xtra.terminal_window) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
/* Create an invisible window which will act as proxy for the DnD operation. */
|
|
||||||
XSetWindowAttributes attr = {0};
|
|
||||||
attr.event_mask = EnterWindowMask |
|
|
||||||
LeaveWindowMask |
|
|
||||||
ButtonMotionMask |
|
|
||||||
ButtonPressMask |
|
|
||||||
ButtonReleaseMask |
|
|
||||||
ResizeRedirectMask;
|
|
||||||
|
|
||||||
attr.do_not_propagate_mask = NoEventMask;
|
|
||||||
|
|
||||||
Window root;
|
|
||||||
int x, y;
|
|
||||||
unsigned int wht, hht, b, d;
|
|
||||||
|
|
||||||
/* Since we cannot capture resize events for parent window we will have to create
|
|
||||||
* this window to have maximum size as defined in root window
|
|
||||||
*/
|
|
||||||
XGetGeometry(Xtra.display,
|
|
||||||
XDefaultRootWindow(Xtra.display),
|
|
||||||
&root, &x, &y, &wht, &hht, &b, &d);
|
|
||||||
|
|
||||||
if (!(Xtra.proxy_window = XCreateWindow
|
|
||||||
(Xtra.display, Xtra.terminal_window, /* Parent */
|
|
||||||
0, 0, /* Position */
|
|
||||||
wht, hht, /* Width + height */
|
|
||||||
0, /* Border width */
|
|
||||||
CopyFromParent, /* Depth */
|
|
||||||
InputOnly, /* Class */
|
|
||||||
CopyFromParent, /* Visual */
|
|
||||||
CWEventMask | CWCursor, /* Value mask */
|
|
||||||
&attr))) { /* Attributes for value mask */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
XMapWindow(Xtra.display, Xtra.proxy_window); /* Show window (sandwich) */
|
|
||||||
XLowerWindow(Xtra.display, Xtra.proxy_window); /* Don't interfere with parent lmao */
|
|
||||||
|
|
||||||
XdndAware = XInternAtom(Xtra.display, "XdndAware", False);
|
|
||||||
XdndEnter = XInternAtom(Xtra.display, "XdndEnter", False);
|
|
||||||
XdndLeave = XInternAtom(Xtra.display, "XdndLeave", False);
|
|
||||||
XdndPosition = XInternAtom(Xtra.display, "XdndPosition", False);
|
|
||||||
XdndStatus = XInternAtom(Xtra.display, "XdndStatus", False);
|
|
||||||
XdndDrop = XInternAtom(Xtra.display, "XdndDrop", False);
|
|
||||||
XdndSelection = XInternAtom(Xtra.display, "XdndSelection", False);
|
|
||||||
XdndDATA = XInternAtom(Xtra.display, "XdndDATA", False);
|
|
||||||
XdndTypeList = XInternAtom(Xtra.display, "XdndTypeList", False);
|
|
||||||
XdndActionCopy = XInternAtom(Xtra.display, "XdndActionCopy", False);
|
|
||||||
XdndFinished = XInternAtom(Xtra.display, "XdndFinished", False);
|
|
||||||
|
|
||||||
/* Inform my nigga windows that we are aware of dnd */
|
|
||||||
Atom XdndVersion = 3;
|
|
||||||
XChangeProperty(Xtra.display,
|
|
||||||
Xtra.proxy_window,
|
|
||||||
XdndAware,
|
|
||||||
XA_ATOM,
|
|
||||||
32,
|
|
||||||
PropModeReplace,
|
|
||||||
(unsigned char *)&XdndVersion, 1);
|
|
||||||
|
|
||||||
pthread_t id;
|
|
||||||
|
|
||||||
if (pthread_create(&id, NULL, event_loop, NULL) != 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_detach(id);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void terminate_xtra(void)
|
|
||||||
{
|
|
||||||
if (!Xtra.display || !Xtra.terminal_window) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
XEvent terminate = {
|
|
||||||
.xclient = {
|
|
||||||
.type = ClientMessage,
|
|
||||||
.display = Xtra.display,
|
|
||||||
.message_type = XtraTerminate,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
XLockDisplay(Xtra.display);
|
|
||||||
XDeleteProperty(Xtra.display, Xtra.proxy_window, XdndAware);
|
|
||||||
XSendEvent(Xtra.display, Xtra.proxy_window, 0, NoEventMask, &terminate);
|
|
||||||
XUnlockDisplay(Xtra.display);
|
|
||||||
|
|
||||||
while (Xtra.display); /* Wait for termination */
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !__APPLE__ */
|
|
Reference in New Issue
Block a user