Skip to content

Commit e946ae5

Browse files
committed
Delay scaling of percentage values.
The config file code now delays calculation of percentage values until `config_fix_percentages()` is called. This allows the config file to be parsed before output configuration is complete, thus allowing `--output` and `--late-keyboard-init` to be specified in the config file.
1 parent c9f1dae commit e946ae5

File tree

11 files changed

+150
-70
lines changed

11 files changed

+150
-70
lines changed

completions/tofi

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,6 @@ _tofi()
5454
;;
5555
--help|-h)
5656
;;
57-
--late-keyboard-init)
58-
;;
5957
--*)
6058
return 0
6159
;;

doc/config

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@
9595
#
9696
### Window positioning
9797
#
98+
# The name of the output to appear on. An empty string will use the
99+
# default output chosen by the compositor.
100+
output = ""
101+
98102
# Location on screen to anchor the window to.
99103
#
100104
# Supported values: top-left, top, top-right, right, bottom-right,
@@ -120,3 +124,9 @@
120124
# If true, directly launch applications on selection when in drun mode.
121125
# Otherwise, just print the command line to stdout.
122126
drun-launch = false
127+
128+
# Delay keyboard initialisation until after the first draw to screen.
129+
# This option is experimental, and will cause tofi to miss keypresses
130+
# for a short time after launch. The only reason to use this option is
131+
# performance on slow systems.
132+
late-keyboard-init = false

doc/tofi.1.md

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,6 @@ a future version of tofi.
4242

4343
> Specify path to custom config file.
4444
45-
**--output** \<name\>
46-
47-
> Select the output to appear on.
48-
49-
**--late-keyboard-init**
50-
51-
> Delay keyboard initialisation until after the first draw to screen.
52-
> This option is experimental, and will cause tofi to miss keypresses
53-
> for a short time after launch. The only reason to use this option is
54-
> performance on slow systems.
55-
5645
All config file options described in **tofi**(5) are also accepted, in
5746
the form **--key=value**.
5847

doc/tofi.1.scd

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,6 @@ nothing, and may be removed in a future version of tofi.
3939
*-c, --config* <path>
4040
Specify path to custom config file.
4141

42-
*--output* <name>
43-
Select the output to appear on.
44-
45-
*--late-keyboard-init*
46-
Delay keyboard initialisation until after the first draw to screen.
47-
This option is experimental, and will cause tofi to miss keypresses
48-
for a short time after launch. The only reason to use this option is
49-
performance on slow systems.
50-
5142
All config file options described in *tofi*(5) are also accepted, in the form
5243
*--key=value*.
5344

doc/tofi.5.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,14 @@ options.
154154
>
155155
> Default: center
156156
157+
**output**=*name*
158+
159+
> The name of the output to appear on, if multiple outputs are present.
160+
> If empty, the compositor will choose which output to display the
161+
> window on (usually the currently focused output).
162+
>
163+
> Default: ""
164+
157165
**margin-top**=*px\|%*
158166

159167
> Offset from top of screen. See **PERCENTAGE VALUES** for more
@@ -256,6 +264,15 @@ options.
256264
>
257265
> Default: true
258266
267+
**late-keyboard-init**=*true\|false*
268+
269+
> Delay keyboard initialisation until after the first draw to screen.
270+
> This option is experimental, and will cause tofi to miss keypresses
271+
> for a short time after launch. The only reason to use this option is
272+
> performance on slow systems.
273+
>
274+
> Default: false
275+
259276
# COLORS
260277

261278
Colors can be specified in the form *RGB*, *RGBA*, *RRGGBB* or

doc/tofi.5.scd

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,13 @@ options.
135135

136136
Default: center
137137

138+
*output*=_name_
139+
The name of the output to appear on, if multiple outputs are present.
140+
If empty, the compositor will choose which output to display the window
141+
on (usually the currently focused output).
142+
143+
Default: ""
144+
138145
*margin-top*=_px|%_
139146
Offset from top of screen. See *PERCENTAGE VALUES* for more
140147
information. Only has an effect when anchored to the top of the screen.
@@ -222,6 +229,14 @@ options.
222229

223230
Default: true
224231

232+
*late-keyboard-init*=_true|false_
233+
Delay keyboard initialisation until after the first draw to screen.
234+
This option is experimental, and will cause tofi to miss keypresses
235+
for a short time after launch. The only reason to use this option is
236+
performance on slow systems.
237+
238+
Default: false
239+
225240
# COLORS
226241

227242
Colors can be specified in the form _RGB_, _RGBA_, _RRGGBB_ or _RRGGBBAA_,

src/config.c

Lines changed: 80 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@
1717
/* Anyone with a 10M config file is doing something very wrong */
1818
#define MAX_CONFIG_SIZE (10*1024*1024)
1919

20+
struct uint32_percent {
21+
uint32_t value;
22+
bool percent;
23+
};
24+
2025
static char *strip(const char *str);
2126
static bool parse_option(struct tofi *tofi, const char *filename, size_t lineno, const char *option, const char *value);
2227
static char *get_config_path(void);
@@ -26,7 +31,7 @@ static bool parse_bool(const char *filename, size_t lineno, const char *str, boo
2631
static struct color parse_color(const char *filename, size_t lineno, const char *str, bool *err);
2732
static uint32_t parse_uint32(const char *filename, size_t lineno, const char *str, bool *err);
2833
static int32_t parse_int32(const char *filename, size_t lineno, const char *str, bool *err);
29-
static uint32_t parse_uint32_percent(const char *filename, size_t lineno, const char *str, bool *err, uint32_t max);
34+
static struct uint32_percent parse_uint32_percent(const char *filename, size_t lineno, const char *str, bool *err);
3035

3136
/*
3237
* Function-like macro. Yuck.
@@ -231,6 +236,7 @@ char *strip(const char *str)
231236
bool parse_option(struct tofi *tofi, const char *filename, size_t lineno, const char *option, const char *value)
232237
{
233238
bool err = false;
239+
struct uint32_percent percent;
234240
if (strcasecmp(option, "anchor") == 0) {
235241
tofi->anchor = parse_anchor(filename, lineno, value, &err);
236242
} else if (strcasecmp(option, "background-color") == 0) {
@@ -270,25 +276,45 @@ bool parse_option(struct tofi *tofi, const char *filename, size_t lineno, const
270276
} else if (strcasecmp(option, "selection-background") == 0) {
271277
tofi->window.entry.selection_background_color = parse_color(filename, lineno, value, &err);
272278
} else if (strcasecmp(option, "width") == 0) {
273-
tofi->window.width = parse_uint32_percent(filename, lineno, value, &err, tofi->output_width);
279+
percent = parse_uint32_percent(filename, lineno, value, &err);
280+
tofi->window.width = percent.value;
281+
tofi->window.width_is_percent = percent.percent;
274282
} else if (strcasecmp(option, "height") == 0) {
275-
tofi->window.height = parse_uint32_percent(filename, lineno, value, &err, tofi->output_height);
283+
percent = parse_uint32_percent(filename, lineno, value, &err);
284+
tofi->window.height = percent.value;
285+
tofi->window.height_is_percent = percent.percent;
276286
} else if (strcasecmp(option, "margin-top") == 0) {
277-
tofi->window.margin_top = parse_uint32_percent(filename, lineno, value, &err, tofi->output_height);
287+
percent = parse_uint32_percent(filename, lineno, value, &err);
288+
tofi->window.margin_top = percent.value;
289+
tofi->window.margin_top_is_percent = percent.percent;
278290
} else if (strcasecmp(option, "margin-bottom") == 0) {
279-
tofi->window.margin_bottom = parse_uint32_percent(filename, lineno, value, &err, tofi->output_height);
291+
percent = parse_uint32_percent(filename, lineno, value, &err);
292+
tofi->window.margin_bottom = percent.value;
293+
tofi->window.margin_bottom_is_percent = percent.percent;
280294
} else if (strcasecmp(option, "margin-left") == 0) {
281-
tofi->window.margin_left = parse_uint32_percent(filename, lineno, value, &err, tofi->output_width);
295+
percent = parse_uint32_percent(filename, lineno, value, &err);
296+
tofi->window.margin_left = percent.value;
297+
tofi->window.margin_left_is_percent = percent.percent;
282298
} else if (strcasecmp(option, "margin-right") == 0) {
283-
tofi->window.margin_right = parse_uint32_percent(filename, lineno, value, &err, tofi->output_width);
299+
percent = parse_uint32_percent(filename, lineno, value, &err);
300+
tofi->window.margin_right = percent.value;
301+
tofi->window.margin_right_is_percent = percent.percent;
284302
} else if (strcasecmp(option, "padding-top") == 0) {
285-
tofi->window.entry.padding_top = parse_uint32_percent(filename, lineno, value, &err, tofi->output_height);
303+
percent = parse_uint32_percent(filename, lineno, value, &err);
304+
tofi->window.entry.padding_top = percent.value;
305+
tofi->window.entry.padding_top_is_percent = percent.percent;
286306
} else if (strcasecmp(option, "padding-bottom") == 0) {
287-
tofi->window.entry.padding_bottom = parse_uint32_percent(filename, lineno, value, &err, tofi->output_height);
307+
percent = parse_uint32_percent(filename, lineno, value, &err);
308+
tofi->window.entry.padding_bottom = percent.value;
309+
tofi->window.entry.padding_bottom_is_percent = percent.percent;
288310
} else if (strcasecmp(option, "padding-left") == 0) {
289-
tofi->window.entry.padding_left = parse_uint32_percent(filename, lineno, value, &err, tofi->output_width);
311+
percent = parse_uint32_percent(filename, lineno, value, &err);
312+
tofi->window.entry.padding_left = percent.value;
313+
tofi->window.entry.padding_left_is_percent = percent.percent;
290314
} else if (strcasecmp(option, "padding-right") == 0) {
291-
tofi->window.entry.padding_right = parse_uint32_percent(filename, lineno, value, &err, tofi->output_width);
315+
percent = parse_uint32_percent(filename, lineno, value, &err);
316+
tofi->window.entry.padding_right = percent.value;
317+
tofi->window.entry.padding_right_is_percent = percent.percent;
292318
} else if (strcasecmp(option, "horizontal") == 0) {
293319
tofi->window.entry.horizontal = parse_bool(filename, lineno, value, &err);
294320
} else if (strcasecmp(option, "hide-cursor") == 0) {
@@ -304,20 +330,56 @@ bool parse_option(struct tofi *tofi, const char *filename, size_t lineno, const
304330
tofi->window.entry.harfbuzz.disable_hinting = !parse_bool(filename, lineno, value, &err);
305331
} else if (strcasecmp(option, "late-keyboard-init") == 0) {
306332
tofi->late_keyboard_init = parse_bool(filename, lineno, value, &err);
333+
} else if (strcasecmp(option, "output") == 0) {
334+
snprintf(tofi->target_output_name, N_ELEM(tofi->target_output_name), "%s", value);
307335
} else {
308336
PARSE_ERROR(filename, lineno, "Unknown option \"%s\"\n", option);
309337
err = true;
310338
}
311339
return !err;
312340
}
313341

314-
void apply_option(struct tofi *tofi, const char *option, const char *value)
342+
void config_apply(struct tofi *tofi, const char *option, const char *value)
315343
{
316344
if (!parse_option(tofi, "", 0, option, value)) {
317345
exit(EXIT_FAILURE);
318346
};
319347
}
320348

349+
void config_fix_percentages(struct tofi *tofi)
350+
{
351+
if (tofi->window.width_is_percent) {
352+
tofi->window.width = tofi->window.width * tofi->output_width / 100;
353+
}
354+
if (tofi->window.height_is_percent) {
355+
tofi->window.height = tofi->window.height * tofi->output_height / 100;
356+
}
357+
if (tofi->window.margin_top_is_percent) {
358+
tofi->window.margin_top = tofi->window.margin_top * tofi->output_height / 100;
359+
}
360+
if (tofi->window.margin_bottom_is_percent) {
361+
tofi->window.margin_bottom = tofi->window.margin_bottom * tofi->output_height / 100;
362+
}
363+
if (tofi->window.margin_left_is_percent) {
364+
tofi->window.margin_left = tofi->window.margin_left * tofi->output_width / 100;
365+
}
366+
if (tofi->window.margin_right_is_percent) {
367+
tofi->window.margin_right = tofi->window.margin_right * tofi->output_width / 100;
368+
}
369+
if (tofi->window.entry.padding_top_is_percent) {
370+
tofi->window.entry.padding_top = tofi->window.entry.padding_top * tofi->output_height / 100;
371+
}
372+
if (tofi->window.entry.padding_bottom_is_percent) {
373+
tofi->window.entry.padding_bottom = tofi->window.entry.padding_bottom * tofi->output_height / 100;
374+
}
375+
if (tofi->window.entry.padding_left_is_percent) {
376+
tofi->window.entry.padding_left = tofi->window.entry.padding_left * tofi->output_width / 100;
377+
}
378+
if (tofi->window.entry.padding_right_is_percent) {
379+
tofi->window.entry.padding_right = tofi->window.entry.padding_right * tofi->output_width / 100;
380+
}
381+
}
382+
321383
char *get_config_path()
322384
{
323385
char *base_dir = getenv("XDG_CONFIG_HOME");
@@ -450,26 +512,27 @@ int32_t parse_int32(const char *filename, size_t lineno, const char *str, bool *
450512
return ret;
451513
}
452514

453-
uint32_t parse_uint32_percent(const char *filename, size_t lineno, const char *str, bool *err, uint32_t max)
515+
struct uint32_percent parse_uint32_percent(const char *filename, size_t lineno, const char *str, bool *err)
454516
{
455517
errno = 0;
456518
char *endptr;
457-
int32_t ret = strtoul(str, &endptr, 0);
519+
int32_t val = strtoul(str, &endptr, 0);
520+
bool percent = false;
458521
if (endptr == str) {
459522
PARSE_ERROR(filename, lineno, "Failed to parse \"%s\" as unsigned int.\n", str);
460523
if (err) {
461524
*err = true;
462525
}
463-
} else if (errno || ret < 0) {
526+
} else if (errno || val < 0) {
464527
PARSE_ERROR(filename, lineno, "Unsigned int value \"%s\" out of range.\n", str);
465528
if (err) {
466529
*err = true;
467530
}
468531
}
469532
if (!err || !*err) {
470533
if (*endptr == '%') {
471-
ret = max * ret / 100;
534+
percent = true;
472535
}
473536
}
474-
return ret;
537+
return (struct uint32_percent){ val, percent };
475538
}

src/config.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "tofi.h"
55

66
void config_load(struct tofi *tofi, const char *filename);
7-
void apply_option(struct tofi *tofi, const char *option, const char *value);
7+
void config_apply(struct tofi *tofi, const char *option, const char *value);
8+
void config_fix_percentages(struct tofi *tofi);
89

910
#endif /* TOFI_CONFIG_H */

src/entry.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ struct entry {
6161
uint32_t padding_bottom;
6262
uint32_t padding_left;
6363
uint32_t padding_right;
64+
bool padding_top_is_percent;
65+
bool padding_bottom_is_percent;
66+
bool padding_left_is_percent;
67+
bool padding_right_is_percent;
6468
int32_t selection_background_padding;
6569
uint32_t input_width;
6670
uint32_t border_width;

src/main.c

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -824,33 +824,12 @@ const struct option long_options[] = {
824824
{"drun-launch", required_argument, NULL, 0},
825825
{"drun-print-exec", required_argument, NULL, 0},
826826
{"hint-font", required_argument, NULL, 0},
827-
{"output", required_argument, NULL, 'o'},
828-
{"late-keyboard-init", no_argument, NULL, 'k'},
827+
{"output", required_argument, NULL, 0},
828+
{"late-keyboard-init", optional_argument, NULL, 'k'},
829829
{NULL, 0, NULL, 0}
830830
};
831831
const char *short_options = ":hc:";
832832

833-
static void parse_early_args(struct tofi *tofi, int argc, char *argv[])
834-
{
835-
/* Handle errors ourselves (i.e. ignore them for now). */
836-
opterr = 0;
837-
838-
/* Just check for help, late-keyboard-init and output */
839-
optind = 1;
840-
int opt = getopt_long(argc, argv, short_options, long_options, NULL);
841-
while (opt != -1) {
842-
if (opt == 'h') {
843-
usage();
844-
exit(EXIT_SUCCESS);
845-
} else if (opt == 'k') {
846-
tofi->late_keyboard_init = true;
847-
} else if (opt == 'o') {
848-
snprintf(tofi->target_output_name, N_ELEM(tofi->target_output_name), "%s", optarg);
849-
}
850-
opt = getopt_long(argc, argv, short_options, long_options, NULL);
851-
}
852-
}
853-
854833
static void parse_args(struct tofi *tofi, int argc, char *argv[])
855834
{
856835

@@ -894,7 +873,17 @@ static void parse_args(struct tofi *tofi, int argc, char *argv[])
894873
opt = getopt_long(argc, argv, short_options, long_options, &option_index);
895874
while (opt != -1) {
896875
if (opt == 0) {
897-
apply_option(tofi, long_options[option_index].name, optarg);
876+
config_apply(tofi, long_options[option_index].name, optarg);
877+
} else if (opt == 'k') {
878+
/*
879+
* Backwards compatibility for --late-keyboard-init not
880+
* taking an argument.
881+
*/
882+
if (optarg) {
883+
config_apply(tofi, long_options[option_index].name, optarg);
884+
} else {
885+
tofi->late_keyboard_init = true;
886+
}
898887
}
899888
opt = getopt_long(argc, argv, short_options, long_options, &option_index);
900889
}
@@ -983,7 +972,7 @@ int main(int argc, char *argv[])
983972
};
984973
wl_list_init(&tofi.output_list);
985974

986-
parse_early_args(&tofi, argc, argv);
975+
parse_args(&tofi, argc, argv);
987976

988977
/*
989978
* Initial Wayland & XKB setup.
@@ -1148,11 +1137,8 @@ int main(int argc, char *argv[])
11481137
log_debug("Selected output %s.\n", el->name);
11491138
}
11501139

1151-
/*
1152-
* We can now parse our arguments and config file, as we know the
1153-
* output size required for specifying window sizes in percent.
1154-
*/
1155-
parse_args(&tofi, argc, argv);
1140+
/* We can now calculate any percentages, as we know the output size. */
1141+
config_fix_percentages(&tofi);
11561142

11571143
/* Scale fonts to the correct size. */
11581144
tofi.window.entry.font_size *= tofi.window.scale;

0 commit comments

Comments
 (0)