diff --git a/README.md b/README.md index 8e70aef5d..cd87985a0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # sway -**[English][en]** - [Deutsch][de] - [Dansk][dk] - [Español][es] - [Français][fr] - [Ελληνικά][gr] - [Magyar][hu] - [ﻑﺍﺮﺳی][ir] - [Italiano][it] - [日本語][ja] - [한국어][ko] - [Nederlands][nl] - [Polski][pl] - [Português][pt] - [Română][ro] - [Русский][ru] - [Türkçe][tr] - [Українська][uk] - [中文-简体][zh-CN] - [中文-繁體][zh-TW] +**[English][en]** - [Deutsch][de] - [Dansk][dk] - [Español][es] - [Français][fr] - [Svenska][sv] - [Ελληνικά][gr] - [Magyar][hu] - [فارسی][ir] - [Italiano][it] - [日本語][ja] - [한국어][ko] - [Nederlands][nl] - [Polski][pl] - [Português][pt] - [Română][ro] - [Русский][ru] - [Türkçe][tr] - [Українська][uk] - [中文-简体][zh-CN] - [中文-繁體][zh-TW] sway is an [i3]-compatible [Wayland] compositor. Read the [FAQ]. Join the [IRC channel] \(#sway on irc.libera.chat). @@ -66,6 +66,7 @@ sway (gdm is known to work fairly well). [dk]: README.dk.md [es]: README.es.md [fr]: README.fr.md +[sv]: README.sv.md [gr]: README.gr.md [hu]: README.hu.md [ir]: README.ir.md diff --git a/README.sv.md b/README.sv.md new file mode 100644 index 000000000..287242705 --- /dev/null +++ b/README.sv.md @@ -0,0 +1,89 @@ +# sway + +[English][en] - [Deutsch][de] - [Dansk][dk] - [Español][es] - [Français][fr] - **[Svenska][sv]** - [Ελληνικά][gr] - [Magyar][hu] - [فارسی][ir] - [Italiano][it] - [日本語][ja] - [한국어][ko] - [Nederlands][nl] - [Polski][pl] - [Português][pt] - [Română][ro] - [Русский][ru] - [Türkçe][tr] - [Українська][uk] - [中文-简体][zh-CN] - [中文-繁體][zh-TW] + +sway är en [i3]-kompatibel [Wayland] compositor. Läs våran [FAQ]-sida. Gå med i vår +[IRC-kanal] \(#sway på irc.libera.chat). + +## Utgåvosignaturer + +Utgåvor är signerade med [E88F5E48] och publicerade på [GitHub][GitHub releases]. + +## Installering + +### Med pakethanterare + +Sway är tillgänglig i många distributioner. Prova att installera "sway" med din distributions pakethanterare. + +### Genom att kompilera från källkod + +Kolla in [denna wiki-sida][Development setup] om du vill bygga sway och wlroots HEAD för testning eller utveckling. + +Installera paket som sway behöver: + +* meson \* +* [wlroots] +* wayland +* wayland-protocols \* +* pcre2 +* json-c +* pango +* cairo +* gdk-pixbuf2 (valbar: systembricka) +* [scdoc] (valbar: manualer) \* +* git (valbar: versioninfo) \* + +_\* Krav för kompilering_ + +Kör dessa kommandon: + + meson build/ + ninja -C build/ + sudo ninja -C build/ install + +På system utan logind eller seatd måste du ge sways exekverbara fil root-privilegier: + + sudo chmod a+s /usr/local/bin/sway + +Sway kommer att överge sina root-privilegier kort efter uppstart. + +## Konfiguration + +Ifall du redan använder i3 så kan du kopiera din konfigurationsfil till `~/.config/sway/config` och det kommer då att fungera som det ska. +Kopiera annars exemplarkonfigurationsfilen till `~/.config/sway/config`. Den ligger oftast i `/etc/sway/config`. +Kör `man 5 sway` för mer information kring konfigurationen. + +## Att köra sway + +Kör `sway` från en TTY. Vissa inloggningahanterare kan fungera men inte vara stödda av sway (gdm ska fungera hyfsat bra). + +[en]: https://github.com/swaywm/sway#readme +[de]: README.de.md +[dk]: README.dk.md +[es]: README.es.md +[fr]: README.fr.md +[sv]: README.sv.md +[gr]: README.gr.md +[hu]: README.hu.md +[ir]: README.ir.md +[it]: README.it.md +[ja]: README.ja.md +[ko]: README.ko.md +[nl]: README.nl.md +[pl]: README.pl.md +[pt]: README.pt.md +[ro]: README.ro.md +[ru]: README.ru.md +[tr]: README.tr.md +[uk]: README.uk.md +[zh-CN]: README.zh-CN.md +[zh-TW]: README.zh-TW.md +[i3]: https://i3wm.org/ +[Wayland]: http://wayland.freedesktop.org/ +[FAQ]: https://github.com/swaywm/sway/wiki +[IRC-kanal]: https://web.libera.chat/gamja/?channels=#sway +[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 +[GitHub releases]: https://github.com/swaywm/sway/releases +[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup +[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots +[scdoc]: https://git.sr.ht/~sircmpwn/scdoc diff --git a/contrib/grimshot b/contrib/grimshot index 4ce31f29f..d42fe9d84 100755 --- a/contrib/grimshot +++ b/contrib/grimshot @@ -13,18 +13,32 @@ ## See `man 1 grimshot` or `grimshot usage` for further details. getTargetDirectory() { - test -f ${XDG_CONFIG_HOME:-~/.config}/user-dirs.dirs && \ - . ${XDG_CONFIG_HOME:-~/.config}/user-dirs.dirs + test -f "${XDG_CONFIG_HOME:-~/.config}/user-dirs.dirs" && \ + . "${XDG_CONFIG_HOME:-~/.config}/user-dirs.dirs" - echo ${XDG_SCREENSHOTS_DIR:-${XDG_PICTURES_DIR:-$HOME}} + echo "${XDG_SCREENSHOTS_DIR:-${XDG_PICTURES_DIR:-$HOME}}" } -if [ "$1" = "--notify" ]; then - NOTIFY=yes - shift 1 -else - NOTIFY=no -fi +NOTIFY=no +CURSOR= + +while [ $# -gt 0 ]; do + key="$1" + + case $key in + -n|--notify) + NOTIFY=yes + shift # past argument + ;; + -c|--cursor) + CURSOR=yes + shift # past argument + ;; + *) # unknown option + break # done with parsing --flags + ;; + esac +done ACTION=${1:-usage} SUBJECT=${2:-screen} @@ -32,7 +46,7 @@ FILE=${3:-$(getTargetDirectory)/$(date -Ins).png} if [ "$ACTION" != "save" ] && [ "$ACTION" != "copy" ] && [ "$ACTION" != "check" ]; then echo "Usage:" - echo " grimshot [--notify] (copy|save) [active|screen|output|area|window] [FILE|-]" + echo " grimshot [--notify] [--cursor] (copy|save) [active|screen|output|area|window] [FILE|-]" echo " grimshot check" echo " grimshot usage" echo "" @@ -67,7 +81,7 @@ notifyError() { MESSAGE=${1:-"Error taking screenshot with grim"} notify -u critical "$TITLE" "$MESSAGE" else - echo $1 + echo "$1" fi } @@ -91,12 +105,12 @@ takeScreenshot() { FILE=$1 GEOM=$2 OUTPUT=$3 - if [ ! -z "$OUTPUT" ]; then - grim -o "$OUTPUT" "$FILE" || die "Unable to invoke grim" + if [ -n "$OUTPUT" ]; then + grim ${CURSOR:+-c} -o "$OUTPUT" "$FILE" || die "Unable to invoke grim" elif [ -z "$GEOM" ]; then - grim "$FILE" || die "Unable to invoke grim" + grim ${CURSOR:+-c} "$FILE" || die "Unable to invoke grim" else - grim -g "$GEOM" "$FILE" || die "Unable to invoke grim" + grim ${CURSOR:+-c} -g "$GEOM" "$FILE" || die "Unable to invoke grim" fi } @@ -147,7 +161,7 @@ else TITLE="Screenshot of $SUBJECT" MESSAGE=$(basename "$FILE") notifyOk "$MESSAGE" "$TITLE" - echo $FILE + echo "$FILE" else notifyError "Error taking screenshot with grim" fi diff --git a/contrib/grimshot.1 b/contrib/grimshot.1 index e4baccfdd..2c4c6a958 100644 --- a/contrib/grimshot.1 +++ b/contrib/grimshot.1 @@ -1,11 +1,11 @@ -.\" Generated by scdoc 1.11.1 +.\" Generated by scdoc 1.11.2 .\" Complete documentation for this program is not available as a GNU info page .ie \n(.g .ds Aq \(aq .el .ds Aq ' .nh .ad l .\" Begin generated content: -.TH "grimshot" "1" "2021-02-23" +.TH "grimshot" "1" "2022-03-31" .P .SH NAME .P @@ -13,7 +13,7 @@ grimshot - a helper for screenshots within sway .P .SH SYNOPSIS .P -\fBgrimshot\fR [--notify] (copy|save) [TARGET] [FILE] +\fBgrimshot\fR [--notify] [--cursor] (copy|save) [TARGET] [FILE] .br \fBgrimshot\fR check .br @@ -26,12 +26,17 @@ grimshot - a helper for screenshots within sway Show notifications to the user that a screenshot has been taken.\& .P .RE +\fB--cursor\fR +.RS 4 +Include cursors in the screenshot.\& +.P +.RE \fBsave\fR .RS 4 Save the screenshot into a regular file.\& Grimshot will write images files to \fBXDG_SCREENSHOTS_DIR\fR if this is set (or defined in \fBuser-dirs.\&dir\fR), or otherwise fall back to \fBXDG_PICTURES_DIR\fR.\& -Set FILE to '-' to pipe the output to STDOUT.\& +Set FILE to '\&-'\& to pipe the output to STDOUT.\& .P .RE \fBcopy\fR diff --git a/contrib/grimshot.1.scd b/contrib/grimshot.1.scd index d2a577599..e356f99d9 100644 --- a/contrib/grimshot.1.scd +++ b/contrib/grimshot.1.scd @@ -6,7 +6,7 @@ grimshot - a helper for screenshots within sway # SYNOPSIS -*grimshot* [--notify] (copy|save) [TARGET] [FILE]++ +*grimshot* [--notify] [--cursor] (copy|save) [TARGET] [FILE]++ *grimshot* check++ *grimshot* usage @@ -15,8 +15,11 @@ grimshot - a helper for screenshots within sway *--notify* Show notifications to the user that a screenshot has been taken. +*--cursor* + Include cursors in the screenshot. + *save* - Save the screenshot into a regular file. Grimshot will write images + Save the screenshot into a regular file. Grimshot will write image files to *XDG_SCREENSHOTS_DIR* if this is set (or defined in *user-dirs.dir*), or otherwise fall back to *XDG_PICTURES_DIR*. Set FILE to '-' to pipe the output to STDOUT. diff --git a/meson.build b/meson.build index 5bedeb2e4..46352da54 100644 --- a/meson.build +++ b/meson.build @@ -69,6 +69,7 @@ bash_comp = dependency('bash-completion', required: false) fish_comp = dependency('fish', required: false) math = cc.find_library('m') rt = cc.find_library('rt') +xcb_icccm = dependency('xcb-icccm', required: get_option('xwayland')) wlroots_features = { 'xwayland': false, diff --git a/sway/commands/output/background.c b/sway/commands/output/background.c index 1a3939d43..67f212ff3 100644 --- a/sway/commands/output/background.c +++ b/sway/commands/output/background.c @@ -102,19 +102,19 @@ struct cmd_results *output_cmd_background(int argc, char **argv) { } char *conf_path = dirname(conf); - char *rel_path = src; - src = malloc(strlen(conf_path) + strlen(src) + 2); - if (!src) { - free(rel_path); + char *real_src = malloc(strlen(conf_path) + strlen(src) + 2); + if (!real_src) { + free(src); free(conf); sway_log(SWAY_ERROR, "Unable to allocate memory"); return cmd_results_new(CMD_FAILURE, "Unable to allocate resources"); } - snprintf(src, strlen(conf_path) + strlen(src) + 2, "%s/%s", conf_path, rel_path); - free(rel_path); + snprintf(real_src, strlen(conf_path) + strlen(src) + 2, "%s/%s", conf_path, src); + free(src); free(conf); + src = real_src; } bool can_access = access(src, F_OK) != -1; diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 1250415e5..159f33360 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -271,10 +271,6 @@ static void handle_output_destroy(struct wl_listener *listener, void *data) { wl_resource_get_client(sway_layer->layer_surface->resource); bool set_focus = seat->exclusive_client == client; - wl_list_remove(&sway_layer->output_destroy.link); - wl_list_remove(&sway_layer->link); - wl_list_init(&sway_layer->link); - if (set_focus) { struct sway_layer_surface *layer = find_mapped_layer_by_client(client, sway_layer->layer_surface->output); @@ -283,7 +279,6 @@ static void handle_output_destroy(struct wl_listener *listener, void *data) { } } - sway_layer->layer_surface->output = NULL; wlr_layer_surface_v1_destroy(sway_layer->layer_surface); } @@ -292,10 +287,7 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { wl_container_of(listener, layer, surface_commit); struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface; struct wlr_output *wlr_output = layer_surface->output; - if (wlr_output == NULL) { - return; - } - + sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); struct sway_output *output = wlr_output->data; struct wlr_box old_extent = layer->extent; @@ -342,13 +334,8 @@ static void unmap(struct sway_layer_surface *sway_layer) { cursor_rebase_all(); struct wlr_output *wlr_output = sway_layer->layer_surface->output; - if (wlr_output == NULL) { - return; - } + sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); struct sway_output *output = wlr_output->data; - if (output == NULL) { - return; - } output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y, sway_layer->layer_surface->surface, true); } @@ -376,22 +363,24 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&sway_layer->surface_commit.link); wl_list_remove(&sway_layer->new_popup.link); wl_list_remove(&sway_layer->new_subsurface.link); - if (sway_layer->layer_surface->output != NULL) { - struct sway_output *output = sway_layer->layer_surface->output->data; - if (output != NULL) { - arrange_layers(output); - transaction_commit_dirty(); - } - wl_list_remove(&sway_layer->output_destroy.link); - sway_layer->layer_surface->output = NULL; - } + + struct wlr_output *wlr_output = sway_layer->layer_surface->output; + sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); + struct sway_output *output = wlr_output->data; + arrange_layers(output); + transaction_commit_dirty(); + wl_list_remove(&sway_layer->output_destroy.link); + sway_layer->layer_surface->output = NULL; + free(sway_layer); } static void handle_map(struct wl_listener *listener, void *data) { struct sway_layer_surface *sway_layer = wl_container_of(listener, sway_layer, map); - struct sway_output *output = sway_layer->layer_surface->output->data; + struct wlr_output *wlr_output = sway_layer->layer_surface->output; + sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); + struct sway_output *output = wlr_output->data; output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y, sway_layer->layer_surface->surface, true); wlr_surface_send_enter(sway_layer->layer_surface->surface, @@ -409,9 +398,7 @@ static void subsurface_damage(struct sway_layer_subsurface *subsurface, bool whole) { struct sway_layer_surface *layer = subsurface->layer_surface; struct wlr_output *wlr_output = layer->layer_surface->output; - if (!wlr_output) { - return; - } + sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); struct sway_output *output = wlr_output->data; int ox = subsurface->wlr_subsurface->current.x + layer->geo.x; int oy = subsurface->wlr_subsurface->current.y + layer->geo.y; @@ -514,6 +501,7 @@ static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) { } } struct wlr_output *wlr_output = layer->layer_surface->output; + sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); struct sway_output *output = wlr_output->data; output_damage_surface(output, ox, oy, surface, whole); } @@ -522,6 +510,7 @@ static void popup_handle_map(struct wl_listener *listener, void *data) { struct sway_layer_popup *popup = wl_container_of(listener, popup, map); struct sway_layer_surface *layer = popup_get_layer(popup); struct wlr_output *wlr_output = layer->layer_surface->output; + sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); wlr_surface_send_enter(popup->wlr_popup->base->surface, wlr_output); popup_damage(popup, true); } @@ -551,7 +540,9 @@ static void popup_unconstrain(struct sway_layer_popup *popup) { struct sway_layer_surface *layer = popup_get_layer(popup); struct wlr_xdg_popup *wlr_popup = popup->wlr_popup; - struct sway_output *output = layer->layer_surface->output->data; + struct wlr_output *wlr_output = layer->layer_surface->output; + sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); + struct sway_output *output = wlr_output->data; // the output box expressed in the coordinate system of the toplevel parent // of the popup @@ -643,6 +634,10 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { sway_log(SWAY_ERROR, "no output to auto-assign layer surface '%s' to", layer_surface->namespace); + // Note that layer_surface->output can be NULL + // here, but none of our destroy callbacks are + // registered yet so we don't have to make them + // handle that case. wlr_layer_surface_v1_destroy(layer_surface); return; } diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 483398e9d..7c5dde530 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "log.h" #include "sway/desktop.h" #include "sway/desktop/transaction.h" @@ -311,7 +312,7 @@ static bool wants_floating(struct sway_view *view) { } } - struct wlr_xwayland_surface_size_hints *size_hints = surface->size_hints; + xcb_size_hints_t *size_hints = surface->size_hints; if (size_hints != NULL && size_hints->min_width > 0 && size_hints->min_height > 0 && (size_hints->max_width == size_hints->min_width || @@ -365,7 +366,7 @@ static void destroy(struct sway_view *view) { static void get_constraints(struct sway_view *view, double *min_width, double *max_width, double *min_height, double *max_height) { struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; - struct wlr_xwayland_surface_size_hints *size_hints = surface->size_hints; + xcb_size_hints_t *size_hints = surface->size_hints; if (size_hints == NULL) { *min_width = DBL_MIN; @@ -684,14 +685,15 @@ static void handle_set_hints(struct wl_listener *listener, void *data) { if (!xsurface->mapped) { return; } - if (!xsurface->hints_urgency && view->urgent_timer) { + const bool hints_urgency = xcb_icccm_wm_hints_get_urgency(xsurface->hints); + if (!hints_urgency && view->urgent_timer) { // The view is in the timeout period. We'll ignore the request to // unset urgency so that the view remains urgent until the timer clears // it. return; } if (view->allow_request_urgent) { - view_set_urgent(view, (bool)xsurface->hints_urgency); + view_set_urgent(view, hints_urgency); } } diff --git a/sway/meson.build b/sway/meson.build index 5f34ce6b0..4ccb2ba10 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -220,6 +220,7 @@ sway_deps = [ wayland_server, wlroots, xkbcommon, + xcb_icccm, ] if have_xwayland diff --git a/sway/server.c b/sway/server.c index 8de9f6294..9bfcffaf5 100644 --- a/sway/server.c +++ b/sway/server.c @@ -213,8 +213,8 @@ bool server_init(struct sway_server *server) { // Avoid using "wayland-0" as display socket char name_candidate[16]; - for (int i = 1; i <= 32; ++i) { - snprintf(name_candidate, sizeof(name_candidate), "wayland-%d", i); + for (unsigned int i = 1; i <= 32; ++i) { + snprintf(name_candidate, sizeof(name_candidate), "wayland-%u", i); if (wl_display_add_socket(server->wl_display, name_candidate) >= 0) { server->socket = strdup(name_candidate); break;