Skip to content

Commit

Permalink
Add option to set window size from image
Browse files Browse the repository at this point in the history
Resolves #94.

Signed-off-by: Artem Senichev <[email protected]>
  • Loading branch information
artemsen committed Dec 17, 2023
1 parent 59a25a8 commit 10e91a8
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 70 deletions.
5 changes: 3 additions & 2 deletions extra/bash.completion
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ _swayimg()
-f --fullscreen \
-s --scale \
-b --background \
-w --window \
-g --geometry \
-w --wndbkg \
-p --wndpos \
-g --wndsize \
-i --info \
-e --exec \
-c --class \
Expand Down
22 changes: 14 additions & 8 deletions extra/swayimg.1
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,28 @@ as a path to some file (not a directory), \fBswayimg\fR will add all files
in that directory to the image list.
.IP "\fB\-l\fR, \fB\-\-slideshow\fR"
Activate slideshow mode on startup.
.IP "\fB\-g\fR, \fB\-\-geometry\fR\fB=\fR\fIX,Y,WIDTH,HEIGHT\fR"
Set the absolute position and size of the window. For example, \fI10,20,100,200\fR
creates a window at position 10x20 (top left corner) with a size of
100x200. The comma can be replaced with any non-numeric character. If this
parameter is not specified, the geometry of the currently focused window
will be used.
.IP "\fB\-b\fR, \fB\-\-background\fR\fB=\fR\fIXXXXXX\fR"
Set background for transparent images:
.nf
\fInone\fR: transparent;
\fIgrid\fR: show grid as background (default);
.IP "\fB\-w\fR, \fB\-\-window\fR\fB=\fR\fIXXXXXX\fR"
\fIXXXXXX\fR: hexadecimal RGB color.
.IP "\fB\-w\fR, \fB\-\-wndbkg\fR\fB=\fR\fICOLOR\fR"
Set window background:
.nf
\fInone\fR: transparent (default);
\fI#XXXXXX\fR: hexadecimal RGB color.
\fIXXXXXX\fR: hexadecimal RGB color.
.IP "\fB\-p\fR, \fB\-\-wndpos\fR\fB=\fR\fIPOS\fR"
Set the absolute position of the window:
.nf
\fIparent\fR: set position from parent (currently active) window (default);
\fIX,Y\fR: absolute coordinates of the top left corner.
.IP "\fB\-g\fR, \fB\-\-wndsize\fR\fB=\fR\fISIZE\fR"
Set window size:
.nf
\fIparent\fR: set size from parent (currently active) window (default);
\fIimage\fR: set size from the first image;
\fIWIDTH,HEIGHT\fR: absolute size of the window.
.IP "\fB\-f\fR, \fB\-\-fullscreen\fR"
Start in full screen mode.
.IP "\fB\-s\fR, \fB\-\-scale\fR\fB=\fR\fISCALE\fR"
Expand Down
8 changes: 7 additions & 1 deletion extra/swayimgrc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@ fullscreen = no
background = grid

# Window background mode/color (none or RGB, e.g. #112233)
window = none
wndbkg = none

# Window position (parent or absolute coordiantes, e.g. 100,200)
wndpos = parent

# Window size (parent, image, or absolute size, e.g. 800,600)
wndsize = parent

# Show image info: format, size, EXIF, and current scale (yes/no)
info = no
Expand Down
13 changes: 10 additions & 3 deletions extra/swayimgrc.5
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,18 @@ Empty lines and comments are ignored.
.nf
\fInone\fR: transparent;
\fIgrid\fR: show grid as background (default);
\fI#XXXXXX\fR: hexadecimal RGB color.
.IP "\fBwindow\fR: window background:"
\fIXXXXXX\fR: hexadecimal RGB color.
.IP "\fBwndbkg\fR: window background:"
.nf
\fInone\fR: transparent (default);
\fI#XXXXXX\fR: hexadecimal RGB color.
\fIXXXXXX\fR: hexadecimal RGB color.
.IP "\fBwndpos\fR: window position:"
\fIparent\fR: set position from parent (currently active) window (default);
\fIX,Y\fR: absolute coordinates of the top left corner.
.IP "\fBwndsize\fR: window size:"
\fIparent\fR: set size from parent (currently active) window (default);
\fIimage\fR: set size from the first image;
\fIWIDTH,HEIGHT\fR: absolute size of the window.
.IP "\fBantialiasing\fR: enable/disable anti-aliasing, \fIyes\fR or [\fIno\fR];"
.IP "\fBinfo\fR: show image meta information: format, size, EXIF, and current scale, \fIyes\fR or [\fIno\fR];"
.IP "\fBfont\fR: font name used for printing image meta info, default is \fImonospace\fR;"
Expand Down
5 changes: 3 additions & 2 deletions extra/zsh.completion
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ _arguments \
'(-f --fullscreen)'{-f,--fullscreen}'[show image in full screen mode]' \
'(-s --scale=SCALE)'{-s,--scale=}'[set initial image scale]:scale:(optimal fit fill real)' \
'(-b --background)'{-b,--background=}'[set image background color]:bkg:(none grid)' \
'(-w --window)'{-w,--window=}'[set window background color]:wnd:(none)' \
'(-g --geometry)'{-g,--geometry=}'[set window geometry]:geo' \
'(-w --wndbkg)'{-w,--wndbkg=}'[set window background color]:wndbkg:(none)' \
'(-p --wndpos)'{-p,--wndpos=}'[set window position]:wndpos:(parent)' \
'(-g --wndsize)'{-g,--wndsize=}'[set window size]:wndsize:(parent image)' \
'(-i --info)'{-i,--info}'[show image meta information (name, EXIF, etc)]' \
'(-e --exec)'{-e,--exec=}'[set execution command]' \
'(-c --class)'{-c,--class=}'[set window class/app_id]:class' \
Expand Down
99 changes: 74 additions & 25 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,36 @@ static bool set_color(const char* text, uint32_t* value)
return true;
}

/**
* Parse pair of numbers.
* @param text text to parse
* @param n1,n2 output values
* @return false if values have invalid format
*/
static bool parse_numpair(const char* text, long* n1, long* n2)
{
char* endptr;

errno = 0;

// first number
*n1 = strtol(text, &endptr, 0);
if (errno) {
return false;
}
// skip delimeter
while (*endptr && *endptr == ',') {
++endptr;
}
// second number
*n2 = strtol(endptr, &endptr, 0);
if (errno) {
return false;
}

return *endptr == 0;
}

/**
* Set (replace) string in config parameter.
* @param src source string
Expand Down Expand Up @@ -248,8 +278,12 @@ static bool apply_conf(struct config* ctx, const char* key, const char* value)
return set_boolean(value, &ctx->fullscreen);
} else if (strcmp(key, "background") == 0) {
return config_set_background(ctx, value);
} else if (strcmp(key, "window") == 0) {
return config_set_window(ctx, value);
} else if (strcmp(key, "wndbkg") == 0) {
return config_set_wndbkg(ctx, value);
} else if (strcmp(key, "wndpos") == 0) {
return config_set_wndpos(ctx, value);
} else if (strcmp(key, "wndsize") == 0) {
return config_set_wndsize(ctx, value);
} else if (strcmp(key, "info") == 0) {
return set_boolean(value, &ctx->show_info);
} else if (strcmp(key, "font") == 0) {
Expand Down Expand Up @@ -356,6 +390,10 @@ static struct config* default_config(void)
ctx->background = BACKGROUND_GRID;
ctx->window = COLOR_TRANSPARENT;
ctx->sway_wm = true;
ctx->geometry.x = SAME_AS_PARENT;
ctx->geometry.y = SAME_AS_PARENT;
ctx->geometry.width = SAME_AS_PARENT;
ctx->geometry.height = SAME_AS_PARENT;
config_set_font_name(ctx, "monospace");
ctx->font_color = 0xcccccc;
ctx->font_size = 14;
Expand Down Expand Up @@ -549,7 +587,7 @@ bool config_set_background(struct config* ctx, const char* val)
return true;
}

bool config_set_window(struct config* ctx, const char* val)
bool config_set_wndbkg(struct config* ctx, const char* val)
{
if (strcmp(val, "none") == 0) {
ctx->window = COLOR_TRANSPARENT;
Expand All @@ -561,35 +599,46 @@ bool config_set_window(struct config* ctx, const char* val)
return true;
}

bool config_set_geometry(struct config* ctx, const char* val)
bool config_set_wndpos(struct config* ctx, const char* val)
{
long nums[4]; // x,y,width,height
const char* ptr = val;
size_t idx;

for (idx = 0; *ptr && idx < sizeof(nums) / sizeof(nums[0]); ++idx) {
char* endptr;
nums[idx] = strtol(ptr, &endptr, 0);
if (ptr == endptr) {
break;
}
ptr = endptr;
while (*ptr && *ptr == ',') {
++ptr;
if (strcmp(val, "parent") == 0) {
ctx->geometry.x = SAME_AS_PARENT;
ctx->geometry.y = SAME_AS_PARENT;
return true;
} else {
long x, y;
if (parse_numpair(val, &x, &y)) {
ctx->geometry.x = (ssize_t)x;
ctx->geometry.y = (ssize_t)y;
return true;
}
}
fprintf(stderr, "Invalid window position: %s\n", val);
fprintf(stderr, "Expected 'parent' or X,Y.\n");
return false;
}

if (idx == sizeof(nums) / sizeof(nums[0]) && !*ptr &&
nums[2 /*width*/] > 0 && nums[3 /*height*/] > 0) {
ctx->geometry.x = (ssize_t)nums[0];
ctx->geometry.y = (ssize_t)nums[1];
ctx->geometry.width = (size_t)nums[2];
ctx->geometry.height = (size_t)nums[3];
bool config_set_wndsize(struct config* ctx, const char* val)
{
if (strcmp(val, "parent") == 0) {
ctx->geometry.width = SAME_AS_PARENT;
ctx->geometry.height = SAME_AS_PARENT;
return true;
} else if (strcmp(val, "image") == 0) {
ctx->geometry.width = SAME_AS_IMAGE;
ctx->geometry.height = SAME_AS_IMAGE;
return true;
} else {
long width, height;
if (parse_numpair(val, &width, &height) && width > 0 && height > 0) {
ctx->geometry.width = (size_t)width;
ctx->geometry.height = (size_t)height;
return true;
}
}

fprintf(stderr, "Invalid window geometry: %s\n", val);
fprintf(stderr, "Expected X,Y,W,H format.\n");
fprintf(stderr, "Invalid window size: %s\n", val);
fprintf(stderr, "Expected 'parent', 'image', or WIDTH,HEIGHT.\n");
return false;
}

Expand Down
10 changes: 8 additions & 2 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
#define COLOR_TRANSPARENT 0xff000000
#define BACKGROUND_GRID 0xfe000000

// Copy position or size from parent window
#define SAME_AS_PARENT 0xffffffff
// Copy size from image
#define SAME_AS_IMAGE 0

// Max number of key bindings
#define MAX_KEYBINDINGS 128

Expand Down Expand Up @@ -111,8 +116,9 @@ void config_free(struct config* ctx);
// Configuration setters
bool config_set_scale(struct config* ctx, const char* val);
bool config_set_background(struct config* ctx, const char* val);
bool config_set_window(struct config* ctx, const char* val);
bool config_set_geometry(struct config* ctx, const char* val);
bool config_set_wndbkg(struct config* ctx, const char* val);
bool config_set_wndpos(struct config* ctx, const char* val);
bool config_set_wndsize(struct config* ctx, const char* val);
bool config_set_font_name(struct config* ctx, const char* val);
bool config_set_font_size(struct config* ctx, const char* val);
bool config_set_order(struct config* ctx, const char* val);
Expand Down
66 changes: 39 additions & 27 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ static const struct cmdarg arguments[] = {
{ 'l', "slideshow", NULL, "activate slideshow mode on startup" },
{ 'f', "fullscreen", NULL, "show image in full screen mode" },
{ 's', "scale", "SCALE", "set initial image scale: [optimal]/fit/fill/real" },
{ 'b', "background", "XXXXXX", "set image background color: none/[grid]/RGB" },
{ 'w', "window", "XXXXXX", "set window background color: [none]/RGB" },
{ 'g', "geometry", "X,Y,W,H", "set window geometry" },
{ 'b', "background", "COLOR", "set image background color: none/[grid]/RGB" },
{ 'w', "wndbkg", "COLOR", "set window background color: [none]/RGB" },
{ 'p', "wndpos", "POS", "set window position [parent]/X,Y" },
{ 'g', "wndsize", "SIZE", "set window size: [parent]/image/W,H" },
{ 'i', "info", NULL, "show image meta information (name, EXIF, etc)" },
{ 'e', "exec", "CMD", "set execution command" },
{ 'c', "class", "NAME", "set window class/app_id" },
Expand All @@ -47,12 +48,14 @@ static const struct cmdarg arguments[] = {
static void print_help(void)
{
char buf_lopt[32];

puts("Usage: " APP_NAME " [OPTION]... [FILE]...");
puts("Show images from FILE(s).");
puts("If FILE is -, read standard input.");
puts("If no FILE specified - read all files from the current directory.\n");
puts("Mandatory arguments to long options are mandatory for short options "
"too.");

for (size_t i = 0; i < sizeof(arguments) / sizeof(arguments[0]); ++i) {
const struct cmdarg* arg = &arguments[i];
strcpy(buf_lopt, arg->long_opt);
Expand Down Expand Up @@ -127,12 +130,17 @@ static int parse_cmdargs(int argc, char* argv[], struct config* cfg)
}
break;
case 'w':
if (!config_set_window(cfg, optarg)) {
if (!config_set_wndbkg(cfg, optarg)) {
return -1;
}
break;
case 'p':
if (!config_set_wndpos(cfg, optarg)) {
return -1;
}
break;
case 'g':
if (!config_set_geometry(cfg, optarg)) {
if (!config_set_wndsize(cfg, optarg)) {
return -1;
}
break;
Expand Down Expand Up @@ -174,21 +182,29 @@ static int parse_cmdargs(int argc, char* argv[], struct config* cfg)
*/
static void sway_setup(struct config* cfg)
{
const bool absolute = cfg->geometry.width;
const int ipc = sway_connect();
int ipc;
struct rect wnd_parent;
bool wnd_fullscreen = false;
const bool absolute =
cfg->geometry.x != SAME_AS_PARENT && cfg->geometry.y != SAME_AS_PARENT;

if (ipc == -1) {
ipc = sway_connect();
if (ipc == INVALID_SWAY_IPC) {
return;
}

if (!absolute) {
bool fullscreen = false;
// get coordinates and size of the currently focused window
if (!sway_current(ipc, &cfg->geometry, &fullscreen)) {
sway_disconnect(ipc);
return;
if (sway_current(ipc, &wnd_parent, &wnd_fullscreen)) {
cfg->fullscreen |= wnd_fullscreen;
if (cfg->geometry.x == SAME_AS_PARENT &&
cfg->geometry.y == SAME_AS_PARENT) {
cfg->geometry.x = wnd_parent.x;
cfg->geometry.y = wnd_parent.y;
}
if (cfg->geometry.width == SAME_AS_PARENT &&
cfg->geometry.height == SAME_AS_PARENT) {
cfg->geometry.width = wnd_parent.width;
cfg->geometry.height = wnd_parent.height;
}
cfg->fullscreen |= fullscreen;
}

if (!cfg->fullscreen) {
Expand Down Expand Up @@ -227,24 +243,20 @@ int main(int argc, char* argv[])
goto done;
}

// check configuration
if (cfg->geometry.width) {
if (!cfg->sway_wm) {
fprintf(stderr,
"Warning: unable to set window geometry without sway\n");
}
if (cfg->fullscreen) {
fprintf(stderr,
"Warning: window geometry used in fullscreen mode\n");
}
}

// compose file list
list = image_list_init((const char**)&argv[index], argc - index, cfg);
if (!list) {
goto done;
}

// set window size form the first image
if (cfg->geometry.width == SAME_AS_IMAGE ||
cfg->geometry.height == SAME_AS_IMAGE) {
struct image_entry first = image_list_current(list);
cfg->geometry.width = first.image->frames[0].width;
cfg->geometry.height = first.image->frames[0].height;
}

if (cfg->sway_wm && !cfg->fullscreen) {
sway_setup(cfg);
}
Expand Down

0 comments on commit 10e91a8

Please sign in to comment.