Skip to content

Commit

Permalink
Add timeout option for image info block
Browse files Browse the repository at this point in the history
Create a new timer in viewer to hide image info blocks on trigger; when
set, image info will be displayed on screen until the timeout expires.
When the timeout expires, the UI will redraw and hide info blocks.

The timeout is disabled by default (info block shown forever) but a user
may override it to a fixed time (in seconds) or to a percentage of a
frame time in slideshow mode (eg if slideshow_time=10 and
image_info_timeout=50%, the info block will be hidden after 5 seconds).
  • Loading branch information
nicolasbrailo committed Jun 22, 2024
1 parent f2bbe75 commit b80ea67
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 6 deletions.
2 changes: 2 additions & 0 deletions extra/swayimgrc
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ background = none
slideshow = no
# Slideshow image display time (seconds)
slideshow_time = 3
# Hide image information after a timeout (seconds e.g. `5`, or percent of slideshow_time e.g. `50%`)
image_info_timeout = 50%

################################################################################
# Image list configuration
Expand Down
3 changes: 3 additions & 0 deletions extra/swayimgrc.5
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ Run slideshow at startup, \fIno\fR by default.
.IP "\fBslideshow_time\fR = \fISECONDS\fR"
Set slideshow image duration in seconds, default is \fI3\fR.
.\" ----------------------------------------------------------------------------
.IP "\fBimage_info_timeout\fR = \fISECONDS|PERCENT\fR"
Set timeout of image information displayed on screen. Value is in seconds (e.g. `5`) or in percentage of slideshow_time (e.g. `50%`). `image_info_timeout=0` disables the timeout (info block is shown forever). If set as a percentage of the slideshow time, but slideshow is disabled, this timeout will be disabled too. Default is \fI0\fR.
.\" ----------------------------------------------------------------------------
.IP "\fBapp_id\fR = \fINAME\fR"
Set a constant window class/app_id. Setting this may break the window layout.
.\" ****************************************************************************
Expand Down
25 changes: 25 additions & 0 deletions src/info.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ struct info_block {
/** Info data context. */
struct info_context {
enum info_mode mode;
int timeout;
const char* file;
struct info_line* exif_lines;
size_t exif_num;
Expand Down Expand Up @@ -207,6 +208,24 @@ static enum config_status load_config(const char* key, const char* value)
size_t scheme_sz = 0;
ssize_t index;

if (strcmp(key, VIEWER_CFG_INFO_TIMEOUT) == 0) {
size_t val_sz = strlen(value);
bool timeout_is_rel = false;
if (value[val_sz - 1] == '%') {
val_sz = val_sz - 1;
timeout_is_rel = true;
}

ssize_t num;
const ssize_t maxVal = timeout_is_rel ? 100 : 86400;
if (str_to_num(value, val_sz, &num, 0) && num != 0 && num <= maxVal) {
ctx.timeout = num * (timeout_is_rel ? -1 : 1);
return cfgst_ok;
} else {
return cfgst_invalid_value;
}
}

if (strcmp(key, "mode") == 0) {
index = str_index(mode_names, value, 0);
if (index < 0) {
Expand Down Expand Up @@ -274,6 +293,7 @@ void info_create(void)
{
// set defaults
ctx.mode = info_mode_full;
ctx.timeout = 0;
ctx.frame = UINT32_MAX;
ctx.index = UINT32_MAX;
SET_DEFAULT(info_mode_full, info_top_left, default_full_top_left);
Expand Down Expand Up @@ -530,3 +550,8 @@ const struct info_line* info_lines(enum info_position pos)

return block->lines;
}

int info_timeout(void)
{
return ctx.timeout;
}
10 changes: 10 additions & 0 deletions src/info.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

#include "font.h"

// Config key for info block timeout
#define VIEWER_CFG_INFO_TIMEOUT "timeout"

/** Info block position. */
enum info_position {
info_top_left,
Expand Down Expand Up @@ -69,3 +72,10 @@ size_t info_height(enum info_position pos);
* @return pointer to the lines array
*/
const struct info_line* info_lines(enum info_position pos);

/**
* Get info display timeout.
* @return 0 if timeout disabled, positive number for absolute time in second,
* or negative number for slideshow relative percents.
*/
int info_timeout(void);
59 changes: 53 additions & 6 deletions src/viewer.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ struct viewer {
bool slideshow_enable; ///< Slideshow enable/disable
int slideshow_fd; ///< Slideshow timer
size_t slideshow_time; ///< Slideshow image display time (seconds)

bool info_timedout; ///< Indicates info block shouldn't be displayed anymore
int info_timeout_fd; ///< Info timer
};

static struct viewer ctx = {
Expand All @@ -87,6 +90,8 @@ static struct viewer ctx = {
.slideshow_enable = false,
.slideshow_fd = -1,
.slideshow_time = 3,
.info_timedout = false,
.info_timeout_fd = -1,
};

/**
Expand Down Expand Up @@ -340,12 +345,30 @@ static void reset_state(void)
ctx.img_x = 0;
ctx.img_y = 0;
ctx.scale = 0;
ctx.info_timedout = false;
scale_image(ctx.scale_init);
fixup_position(true);

ui_set_title(entry.image->file_name);
animation_ctl(true);
slideshow_ctl(ctx.slideshow_enable);

// Expire info block after timeout
const int timeout = info_timeout();
if (timeout != 0) {
struct itimerspec info_ts = { 0 };
if (!ctx.slideshow_enable && timeout < 0) {
// If timeout is relative to slideshow, but slideshow is not
// enabled, then disable info timeout too
info_ts.it_value.tv_sec = 0;
} else if (timeout < 0) {
// If timeout < 0 => it's relative to slideshow time
info_ts.it_value.tv_sec = ctx.slideshow_time * -1 * timeout / 100;
} else {
info_ts.it_value.tv_sec = timeout;
}
timerfd_settime(ctx.info_timeout_fd, 0, &info_ts, NULL);
}
}

/**
Expand Down Expand Up @@ -408,6 +431,18 @@ static void on_slideshow_timer(void)
ui_redraw();
}

/**
* Info block timer event handler.
*/
static void on_info_block_timeout(void)
{
// Reset timer to 0, so it won't fire again
struct itimerspec info_ts = { 0 };
timerfd_settime(ctx.info_timeout_fd, 0, &info_ts, NULL);
ctx.info_timedout = true;
ui_redraw();
}

/**
* Execute system command for the current image.
* @param expr command expression
Expand Down Expand Up @@ -588,6 +623,13 @@ void viewer_init(void)
ui_add_event(ctx.slideshow_fd, on_slideshow_timer);
}

// setup info block timer
ctx.info_timeout_fd =
timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
if (ctx.info_timeout_fd != -1) {
ui_add_event(ctx.info_timeout_fd, on_info_block_timeout);
}

// register configuration loader
config_add_loader(GENERAL_CONFIG_SECTION, load_config);
}
Expand All @@ -603,6 +645,9 @@ void viewer_free(void)
if (ctx.slideshow_fd != -1) {
close(ctx.slideshow_fd);
}
if (ctx.info_timeout_fd != -1) {
close(ctx.info_timeout_fd);
}
}

bool viewer_reload(void)
Expand All @@ -628,12 +673,14 @@ void viewer_on_redraw(struct pixmap* window)
draw_image(window);

// put text info blocks on window surface
for (size_t i = 0; i < INFO_POSITION_NUM; ++i) {
const size_t lines_num = info_height(i);
if (lines_num) {
const enum info_position pos = (enum info_position)i;
const struct info_line* lines = info_lines(pos);
text_print(window, pos, lines, lines_num);
if (!ctx.info_timedout) {
for (size_t i = 0; i < INFO_POSITION_NUM; ++i) {
const size_t lines_num = info_height(i);
if (lines_num) {
const enum info_position pos = (enum info_position)i;
const struct info_line* lines = info_lines(pos);
text_print(window, pos, lines, lines_num);
}
}
}
if (ctx.help) {
Expand Down

0 comments on commit b80ea67

Please sign in to comment.