diff --git a/CHANGELOG.md b/CHANGELOG.md index bdbc634d..d0ea8732 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,7 +56,14 @@ character width of 1. Must be explicitly enabled with `tweak.allow-overflowing-double-width-glyphs` (https://codeberg.org/dnkl/foot/issues/116). - +* **initial-window-size-pixels** options to `foot.ini` and + `-w,--window-size-pixels` command line option to `foot`. This option + replaces the now deprecated **geometry** and `-g,--geometry` + options. +* **initial-window-size-chars** option to `foot.ini` and + `-W,--window-size-chars` command line option to `foot`. This option + configures the initial window size in **characters**, and is an + alternative to **initial-window-size-pixels**. ### Removed diff --git a/completions/zsh/_foot b/completions/zsh/_foot index ae8d34b1..b9019b93 100644 --- a/completions/zsh/_foot +++ b/completions/zsh/_foot @@ -11,7 +11,8 @@ _arguments \ '--maximized[start in maximized mode]' \ '--fullscreen[start in fullscreen mode]' \ '--login-shell[start shell as a login shell]' \ - '(-g --geometry)'{-g,--geometry}'[window WIDTHxHEIGHT, in pixels (700x500)]:geometry:()' \ + '(-w --window-size-pixels)'{-w,--window-size-pixels}'[window WIDTHxHEIGHT, in pixels (700x500)]:size_pixels:()' \ + '(-W --window-size-chars)'{-W,--window-size-chars}'[window WIDTHxHEIGHT, in characters (not set)]:size_chars:()' \ '(-s --server)'{-s,--server}'[run as server; open terminals by running footclient]:server:_files' \ '--hold[remain open after child process exits]' \ '(-p --print-pid)'{-p,--print-pid}'[print PID to this file or FD when up and running (server mode only)]:pidfile:_files' \ diff --git a/config.c b/config.c index f15be1c2..b52286c8 100644 --- a/config.c +++ b/config.c @@ -452,18 +452,49 @@ parse_section_main(const char *key, const char *value, struct config *conf, conf->app_id = xstrdup(value); } - else if (strcmp(key, "geometry") == 0) { + else if (strcmp(key, "initial-window-size-pixels") == 0 || + strcmp(key, "geometry") == 0 /* deprecated */) + { + if (strcmp(key, "geometry") == 0) { + LOG_WARN("deprecated: [default]: geometry: use 'initial-window-size-pixels' instead'"); + + const char *fmt = "%s:%d: \033[1mgeometry\033[21m, use \033[1minitial-window-size-pixels\033[21m instead"; + char *text = xasprintf(fmt, path, lineno); + + struct user_notification deprecation = { + .kind = USER_NOTIFICATION_DEPRECATED, + .text = text, + }; + tll_push_back(conf->notifications, deprecation); + } + unsigned width, height; if (sscanf(value, "%ux%u", &width, &height) != 2 || width == 0 || height == 0) { LOG_AND_NOTIFY_ERR( - "%s: %d: [default]: geometry: expected WIDTHxHEIGHT, " - "where both are positive integers, got '%s'", - path, lineno, value); + "%s: %d: [default]: initial-window-size-pixels: " + "expected WIDTHxHEIGHT, where both are positive integers, " + "got '%s'", path, lineno, value); return false; } - conf->width = width; - conf->height = height; + conf->size.type = CONF_SIZE_PX; + conf->size.px.width = width; + conf->size.px.height = height; + } + + else if (strcmp(key, "initial-window-size-chars") == 0) { + unsigned width, height; + if (sscanf(value, "%ux%u", &width, &height) != 2 || width == 0 || height == 0) { + LOG_AND_NOTIFY_ERR( + "%s: %d: [default]: initial-window-size-chars: " + "expected WIDTHxHEIGHT, where both are positive integers, " + "got '%s'", path, lineno, value); + return false; + } + + conf->size.type = CONF_SIZE_CELLS; + conf->size.cells.width = width; + conf->size.cells.height = height; } else if (strcmp(key, "pad") == 0) { @@ -1721,7 +1752,8 @@ add_default_mouse_bindings(struct config *conf) } bool -config_load(struct config *conf, const char *conf_path, bool errors_are_fatal) +config_load(struct config *conf, const char *conf_path, + user_notifications_t *initial_user_notifications, bool errors_are_fatal) { bool ret = false; @@ -1730,8 +1762,13 @@ config_load(struct config *conf, const char *conf_path, bool errors_are_fatal) .shell = get_shell(), .title = xstrdup("foot"), .app_id = xstrdup("foot"), - .width = 700, - .height = 500, + .size = { + .type = CONF_SIZE_PX, + .px = { + .width = 700, + .height = 500, + }, + }, .pad_x = 2, .pad_y = 2, .startup_mode = STARTUP_WINDOWED, @@ -1810,6 +1847,10 @@ config_load(struct config *conf, const char *conf_path, bool errors_are_fatal) .notifications = tll_init(), }; + tll_foreach(*initial_user_notifications, it) + tll_push_back(conf->notifications, it->item); + tll_free(*initial_user_notifications); + add_default_key_bindings(conf); add_default_search_bindings(conf); add_default_mouse_bindings(conf); @@ -1887,9 +1928,7 @@ config_free(struct config conf) tll_free(conf.bindings.mouse); tll_free(conf.bindings.search); - tll_foreach(conf.notifications, it) - free(it->item.text); - tll_free(conf.notifications); + user_notifications_free(&conf.notifications); } struct config_font diff --git a/config.h b/config.h index bffb4776..782314e6 100644 --- a/config.h +++ b/config.h @@ -9,6 +9,8 @@ #include "user-notification.h" #include "wayland.h" +enum conf_size_type {CONF_SIZE_PX, CONF_SIZE_CELLS}; + struct config_font { char *pattern; double pt_size; @@ -52,10 +54,24 @@ struct config { char *title; char *app_id; bool login_shell; - unsigned width; - unsigned height; + + struct { + enum conf_size_type type; + union { + struct { + unsigned width; + unsigned height; + } px; + struct { + unsigned width; + unsigned height; + } cells; + }; + } size; + unsigned pad_x; unsigned pad_y; + enum { STARTUP_WINDOWED, STARTUP_MAXIMIZED, STARTUP_FULLSCREEN } startup_mode; tll(struct config_font) fonts; @@ -156,7 +172,9 @@ struct config { user_notifications_t notifications; }; -bool config_load(struct config *conf, const char *path, bool errors_are_fatal); +bool config_load( + struct config *conf, const char *path, + user_notifications_t *initial_user_notifications, bool errors_are_fatal); void config_free(struct config conf); struct config_font config_font_parse(const char *pattern); diff --git a/doc/foot.1.scd b/doc/foot.1.scd index 19e1b0ee..c8fbddc7 100644 --- a/doc/foot.1.scd +++ b/doc/foot.1.scd @@ -45,8 +45,14 @@ the foot command line Default: _monospace_. +*-w*,*--window-size-pixels*=_WIDTHxHEIGHT_ + Set initial window width and height, in pixels. Default: _700x500_. + +*-W*,*--window-size-chars*=_WIDTHxHEIGHT_ + Set initial window width and height, in characters. Default: _not set_. + *-g*,*--geometry*=_WIDTHxHEIGHT_ - Set initial window width and height. Default: *700x500*. + Deprecated. Alias for *-w*,*--window-size-pixels*. *-t*,*--term*=_TERM_ Value to set the environment variable *TERM* to. Default: _foot_. diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index 81e3f945..25a40e45 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -35,18 +35,28 @@ in this order: Default: _monospace_. -*geometry* - Initial window width and height in pixels (subject to output - scaling), on the form _WIDTHxHEIGHT_. Default: _700x500_. - *pad* Padding between border and glyphs, in pixels (subject to output scaling), on the form _XxY_. Default: _2x2_. +*initial-window-size-pixels* + Initial window width and height in _pixels_ (subject to output + scaling), on the form _WIDTHxHEIGHT_. The height _includes_ the + titlebar when using CSDs. Mutually exclusive to + *initial-window-size-chars*. Default: _700x500_. + +*initial-window-size-chars* + Initial window width and height in _characters_, on the form + _WIDTHxHEIGHT_. Mutually exclusive to + *initial-window-size-pixels*. Default: _not set_. + *initial-window-mode* Initial window mode for each newly spawned window: *windowed*, *maximized* or *fullscreen*. Default: _windowed_. +*geometry* + Deprecated. Alias for *initial-window-size-pixels*. + *shell* Executable to launch. Typically a shell. Default: _$SHELL_ if set, otherwise the user's default shell (as specified in diff --git a/foot.ini b/foot.ini index 207ee657..59806254 100644 --- a/foot.ini +++ b/foot.ini @@ -1,9 +1,10 @@ # -*- conf -*- # font=monospace -# geometry=700x500 -# pad=2x2 +# initial-window-size-pixels=700x500 # Or, +# initial-window-size-chars= # initial-window-mode=windowed +# pad=2x2 # shell=$SHELL (if set, otherwise user's default shell from /etc/passwd) # term=foot # login-shell=no diff --git a/main.c b/main.c index b53aaf17..8ce4c7b0 100644 --- a/main.c +++ b/main.c @@ -55,7 +55,8 @@ print_usage(const char *prog_name) " --maximized start in maximized mode\n" " --fullscreen start in fullscreen mode\n" " --login-shell start shell as a login shell\n" - " -g,--geometry=WIDTHxHEIGHT set initial width and height\n" + " -w,--window-size-pixels=WIDTHxHEIGHT initial width and height, in pixels (alternative to '--dimensions')\n" + " -W,--window-size-chars=WIDTHxHEIGHT initial width and height, in characters (alternative to '--geometry')\n" " -s,--server[=PATH] run as a server (use 'footclient' to start terminals).\n" " Without PATH, $XDG_RUNTIME_DIR/foot-$WAYLAND_DISPLAY.sock will be used.\n" " --hold remain open after child process exits\n" @@ -143,25 +144,27 @@ main(int argc, char *const *argv) const char *const prog_name = argv[0]; static const struct option longopts[] = { - {"config", required_argument, NULL, 'c'}, - {"check-config", no_argument, NULL, 'C'}, - {"term", required_argument, NULL, 't'}, - {"title", required_argument, NULL, 'T'}, - {"app-id", required_argument, NULL, 'a'}, - {"login-shell", no_argument, NULL, 'L'}, - {"font", required_argument, NULL, 'f'}, - {"geometry", required_argument, NULL, 'g'}, - {"server", optional_argument, NULL, 's'}, - {"hold", no_argument, NULL, 'H'}, - {"maximized", no_argument, NULL, 'm'}, - {"fullscreen", no_argument, NULL, 'F'}, - {"presentation-timings", no_argument, NULL, 'P'}, /* Undocumented */ - {"print-pid", required_argument, NULL, 'p'}, - {"log-colorize", optional_argument, NULL, 'l'}, - {"log-no-syslog", no_argument, NULL, 'S'}, - {"version", no_argument, NULL, 'v'}, - {"help", no_argument, NULL, 'h'}, - {NULL, no_argument, NULL, 0}, + {"config", required_argument, NULL, 'c'}, + {"check-config", no_argument, NULL, 'C'}, + {"term", required_argument, NULL, 't'}, + {"title", required_argument, NULL, 'T'}, + {"app-id", required_argument, NULL, 'a'}, + {"login-shell", no_argument, NULL, 'L'}, + {"font", required_argument, NULL, 'f'}, + {"geometry", required_argument, NULL, 'g'}, /* Deprecated */ + {"window-size-pixels", required_argument, NULL, 'w'}, + {"window-size-chars", required_argument, NULL, 'W'}, + {"server", optional_argument, NULL, 's'}, + {"hold", no_argument, NULL, 'H'}, + {"maximized", no_argument, NULL, 'm'}, + {"fullscreen", no_argument, NULL, 'F'}, + {"presentation-timings", no_argument, NULL, 'P'}, /* Undocumented */ + {"print-pid", required_argument, NULL, 'p'}, + {"log-colorize", optional_argument, NULL, 'l'}, + {"log-no-syslog", no_argument, NULL, 'S'}, + {"version", no_argument, NULL, 'v'}, + {"help", no_argument, NULL, 'h'}, + {NULL, no_argument, NULL, 0}, }; bool check_config = false; @@ -171,6 +174,7 @@ main(int argc, char *const *argv) const char *conf_app_id = NULL; bool login_shell = false; tll(char *) conf_fonts = tll_init(); + enum conf_size_type conf_size_type = CONF_SIZE_PX; int conf_width = -1; int conf_height = -1; bool as_server = false; @@ -183,9 +187,10 @@ main(int argc, char *const *argv) const char *pid_file = NULL; enum log_colorize log_colorize = LOG_COLORIZE_AUTO; bool log_syslog = true; + user_notifications_t user_notifications = tll_init(); while (true) { - int c = getopt_long(argc, argv, "+c:Ct:a:Lf:g:s::Pp:l::Svh", longopts, NULL); + int c = getopt_long(argc, argv, "+c:Ct:a:Lf:g:w:W:s::Pp:l::Svh", longopts, NULL); if (c == -1) break; @@ -237,12 +242,37 @@ main(int argc, char *const *argv) break; case 'g': { + LOG_WARN("deprecated: -g,--geometry command line option. Use -w,--window-size-pixels instead"); + struct user_notification deprecation = { + .kind = USER_NOTIFICATION_DEPRECATED, + .text = xstrdup( + "\033[1m-g,--geometry\033[21m command line option. " + "Use \033[1m-w,--window-size-pixels\033[21m instead"), + }; + tll_push_back(user_notifications, deprecation); + /* FALLTHROUGH */ + } + case 'w': { unsigned width, height; if (sscanf(optarg, "%ux%u", &width, &height) != 2 || width == 0 || height == 0) { - fprintf(stderr, "error: invalid geometry: %s\n", optarg); + fprintf(stderr, "error: invalid window-size-pixels: %s\n", optarg); return EXIT_FAILURE; } + conf_size_type = CONF_SIZE_PX; + conf_width = width; + conf_height = height; + break; + } + + case 'W': { + unsigned width, height; + if (sscanf(optarg, "%ux%u", &width, &height) != 2 || width == 0 || height == 0) { + fprintf(stderr, "error: invalid window-size-chars: %s\n", optarg); + return EXIT_FAILURE; + } + + conf_size_type = CONF_SIZE_CELLS; conf_width = width; conf_height = height; break; @@ -323,7 +353,7 @@ main(int argc, char *const *argv) } struct config conf = {NULL}; - if (!config_load(&conf, conf_path, check_config)) { + if (!config_load(&conf, conf_path, &user_notifications, check_config)) { config_free(conf); return ret; } @@ -362,10 +392,21 @@ main(int argc, char *const *argv) tll_push_back(conf.fonts, config_font_parse(it->item)); tll_free(conf_fonts); } - if (conf_width > 0) - conf.width = conf_width; - if (conf_height > 0) - conf.height = conf_height; + if (conf_width > 0 && conf_height > 0) { + conf.size.type = conf_size_type; + + switch (conf_size_type) { + case CONF_SIZE_PX: + conf.size.px.width = conf_width; + conf.size.px.height = conf_height; + break; + + case CONF_SIZE_CELLS: + conf.size.cells.width = conf_width; + conf.size.cells.height = conf_height; + break; + } + } if (conf_server_socket_path != NULL) { free(conf.server_socket_path); conf.server_socket_path = xstrdup(conf_server_socket_path); diff --git a/render.c b/render.c index 288ea8da..80f3bd90 100644 --- a/render.c +++ b/render.c @@ -2032,13 +2032,24 @@ maybe_resize(struct terminal *term, int width, int height, bool force) width = term->unmaximized_width; height = term->unmaximized_height; } else { - width = term->conf->width; - height = term->conf->height; + switch (term->conf->size.type) { + case CONF_SIZE_PX: + width = term->conf->size.px.width; + height = term->conf->size.px.height; - if (term->window->use_csd == CSD_YES) { - /* Take CSD title bar into account */ - assert(!term->window->is_fullscreen); - height -= term->conf->csd.title_height; + if (term->window->use_csd == CSD_YES) { + /* Take CSD title bar into account */ + assert(!term->window->is_fullscreen); + height -= term->conf->csd.title_height; + } + break; + + case CONF_SIZE_CELLS: + width = 2 * term->conf->pad_x; + height = 2 * term->conf->pad_y; + width += term->conf->size.cells.width * term->cell_width; + height += term->conf->size.cells.height * term->cell_height; + break; } width *= scale; diff --git a/user-notification.h b/user-notification.h index 1777d521..f184871e 100644 --- a/user-notification.h +++ b/user-notification.h @@ -14,3 +14,11 @@ struct user_notification { }; typedef tll(struct user_notification) user_notifications_t; + +static inline void +user_notifications_free(user_notifications_t *notifications) +{ + tll_foreach(*notifications, it) + free(it->item.text); + tll_free(*notifications); +}