feat: 1.9 merge (#277)

Co-authored-by: William McKinnon <contact@willmckinnon.com>
Co-authored-by: Erik Reider <35975961+ErikReider@users.noreply.github.com>
This commit is contained in:
Reza Jelveh 2024-04-15 13:39:41 +08:00 committed by GitHub
parent a5e79676c4
commit fb86ed6b05
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
161 changed files with 3161 additions and 4682 deletions

2
.gitignore vendored
View file

@ -2,11 +2,11 @@ install_manifest.txt
*.swp *.swp
*.o *.o
*.a *.a
.cache/
bin/ bin/
test/ test/
build/ build/
build-*/ build-*/
.cache/
!build-scripts !build-scripts
!build-scripts/* !build-scripts/*
.lvimrc .lvimrc

View file

@ -99,7 +99,8 @@ Install dependencies:
* json-c * json-c
* pango * pango
* cairo * cairo
* gdk-pixbuf2 (optional: system tray) * gdk-pixbuf2 (optional: additional image formats for system tray)
* [swaybg] (optional: wallpaper)
* [scdoc] (optional: man pages) \* * [scdoc] (optional: man pages) \*
* git (optional: version info) \* * git (optional: version info) \*

View file

@ -12,23 +12,6 @@
const uint8_t GESTURE_FINGERS_ANY = 0; const uint8_t GESTURE_FINGERS_ANY = 0;
// Helper to easily allocate and format string
static char *strformat(const char *format, ...) {
va_list args;
va_start(args, format);
int length = vsnprintf(NULL, 0, format, args) + 1;
va_end(args);
char *result = malloc(length);
if (result) {
va_start(args, format);
vsnprintf(result, length, format, args);
va_end(args);
}
return result;
}
char *gesture_parse(const char *input, struct gesture *output) { char *gesture_parse(const char *input, struct gesture *output) {
// Clear output in case of failure // Clear output in case of failure
output->type = GESTURE_TYPE_NONE; output->type = GESTURE_TYPE_NONE;
@ -38,7 +21,7 @@ char *gesture_parse(const char *input, struct gesture *output) {
// Split input type, fingers and directions // Split input type, fingers and directions
list_t *split = split_string(input, ":"); list_t *split = split_string(input, ":");
if (split->length < 1 || split->length > 3) { if (split->length < 1 || split->length > 3) {
return strformat( return format_str(
"expected <gesture>[:<fingers>][:direction], got %s", "expected <gesture>[:<fingers>][:direction], got %s",
input); input);
} }
@ -51,8 +34,8 @@ char *gesture_parse(const char *input, struct gesture *output) {
} else if (strcmp(split->items[0], "swipe") == 0) { } else if (strcmp(split->items[0], "swipe") == 0) {
output->type = GESTURE_TYPE_SWIPE; output->type = GESTURE_TYPE_SWIPE;
} else { } else {
return strformat("expected hold|pinch|swipe, got %s", return format_str("expected hold|pinch|swipe, got %s",
split->items[0]); (const char *)split->items[0]);
} }
// Parse optional arguments // Parse optional arguments
@ -67,7 +50,7 @@ char *gesture_parse(const char *input, struct gesture *output) {
next = split->length == 3 ? split->items[2] : NULL; next = split->length == 3 ? split->items[2] : NULL;
} else if (split->length == 3) { } else if (split->length == 3) {
// Fail here if argument can only be finger count // Fail here if argument can only be finger count
return strformat("expected 1-9, got %s", next); return format_str("expected 1-9, got %s", next);
} }
// If there is an argument left, try to parse as direction // If there is an argument left, try to parse as direction
@ -95,7 +78,7 @@ char *gesture_parse(const char *input, struct gesture *output) {
} else if (strcmp(item, "counterclockwise") == 0) { } else if (strcmp(item, "counterclockwise") == 0) {
output->directions |= GESTURE_DIRECTION_COUNTERCLOCKWISE; output->directions |= GESTURE_DIRECTION_COUNTERCLOCKWISE;
} else { } else {
return strformat("expected direction, got %s", item); return format_str("expected direction, got %s", item);
} }
} }
list_free_items_and_destroy(directions); list_free_items_and_destroy(directions);
@ -163,7 +146,7 @@ static char *gesture_directions_to_string(uint32_t directions) {
if (!result) { if (!result) {
result = strdup(name); result = strdup(name);
} else { } else {
char *new = strformat("%s+%s", result, name); char *new = format_str("%s+%s", result, name);
free(result); free(result);
result = new; result = new;
} }
@ -179,7 +162,7 @@ static char *gesture_directions_to_string(uint32_t directions) {
char *gesture_to_string(struct gesture *gesture) { char *gesture_to_string(struct gesture *gesture) {
char *directions = gesture_directions_to_string(gesture->directions); char *directions = gesture_directions_to_string(gesture->directions);
char *result = strformat("%s:%u:%s", char *result = format_str("%s:%u:%s",
gesture_type_string(gesture->type), gesture_type_string(gesture->type),
gesture->fingers, directions); gesture->fingers, directions);
free(directions); free(directions);

View file

@ -84,18 +84,11 @@ void get_text_size(cairo_t *cairo, const PangoFontDescription *desc, int *width,
int *baseline, double scale, bool markup, const char *fmt, ...) { int *baseline, double scale, bool markup, const char *fmt, ...) {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
// Add one since vsnprintf excludes null terminator. char *buf = vformat_str(fmt, args);
int length = vsnprintf(NULL, 0, fmt, args) + 1;
va_end(args); va_end(args);
char *buf = malloc(length);
if (buf == NULL) { if (buf == NULL) {
sway_log(SWAY_ERROR, "Failed to allocate memory");
return; return;
} }
va_start(args, fmt);
vsnprintf(buf, length, fmt, args);
va_end(args);
PangoLayout *layout = get_pango_layout(cairo, desc, buf, scale, markup); PangoLayout *layout = get_pango_layout(cairo, desc, buf, scale, markup);
pango_cairo_update_layout(cairo, layout); pango_cairo_update_layout(cairo, layout);
@ -104,6 +97,7 @@ void get_text_size(cairo_t *cairo, const PangoFontDescription *desc, int *width,
*baseline = pango_layout_get_baseline(layout) / PANGO_SCALE; *baseline = pango_layout_get_baseline(layout) / PANGO_SCALE;
} }
g_object_unref(layout); g_object_unref(layout);
free(buf); free(buf);
} }
@ -125,18 +119,11 @@ void render_text(cairo_t *cairo, const PangoFontDescription *desc,
double scale, bool markup, const char *fmt, ...) { double scale, bool markup, const char *fmt, ...) {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
// Add one since vsnprintf excludes null terminator. char *buf = vformat_str(fmt, args);
int length = vsnprintf(NULL, 0, fmt, args) + 1;
va_end(args); va_end(args);
char *buf = malloc(length);
if (buf == NULL) { if (buf == NULL) {
sway_log(SWAY_ERROR, "Failed to allocate memory");
return; return;
} }
va_start(args, fmt);
vsnprintf(buf, length, fmt, args);
va_end(args);
PangoLayout *layout = get_pango_layout(cairo, desc, buf, scale, markup); PangoLayout *layout = get_pango_layout(cairo, desc, buf, scale, markup);
cairo_font_options_t *fo = cairo_font_options_create(); cairo_font_options_t *fo = cairo_font_options_create();
@ -146,5 +133,6 @@ void render_text(cairo_t *cairo, const PangoFontDescription *desc,
pango_cairo_update_layout(cairo, layout); pango_cairo_update_layout(cairo, layout);
pango_cairo_show_layout(cairo, layout); pango_cairo_show_layout(cairo, layout);
g_object_unref(layout); g_object_unref(layout);
free(buf); free(buf);
} }

View file

@ -1,5 +1,6 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include <ctype.h> #include <ctype.h>
#include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -328,3 +329,35 @@ bool expand_path(char **path) {
wordfree(&p); wordfree(&p);
return true; return true;
} }
char *vformat_str(const char *fmt, va_list args) {
char *str = NULL;
va_list args_copy;
va_copy(args_copy, args);
int len = vsnprintf(NULL, 0, fmt, args);
if (len < 0) {
sway_log_errno(SWAY_ERROR, "vsnprintf(\"%s\") failed", fmt);
goto out;
}
str = malloc(len + 1);
if (str == NULL) {
sway_log_errno(SWAY_ERROR, "malloc() failed");
goto out;
}
vsnprintf(str, len + 1, fmt, args_copy);
out:
va_end(args_copy);
return str;
}
char *format_str(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
char *str = vformat_str(fmt, args);
va_end(args);
return str;
}

57
completions/meson.build Normal file
View file

@ -0,0 +1,57 @@
if get_option('zsh-completions')
zsh_files = files(
'zsh/_sway',
'zsh/_swaymsg',
)
zsh_install_dir = join_paths(datadir, 'zsh', 'site-functions')
install_data(zsh_files, install_dir: zsh_install_dir)
endif
if get_option('bash-completions')
bash_comp = dependency('bash-completion', required: false)
bash_files = files(
'bash/sway',
'bash/swaymsg',
)
if get_option('swaybar')
bash_files += files('bash/swaybar')
endif
if bash_comp.found()
bash_install_dir = bash_comp.get_variable(
pkgconfig: 'completionsdir',
pkgconfig_define: ['datadir', datadir]
)
else
bash_install_dir = join_paths(datadir, 'bash-completion', 'completions')
endif
install_data(bash_files, install_dir: bash_install_dir)
endif
if get_option('fish-completions')
fish_comp = dependency('fish', required: false)
fish_files = files(
'fish/sway.fish',
'fish/swaymsg.fish',
)
if get_option('swaynag')
fish_files += files('fish/swaynag.fish')
endif
if fish_comp.found()
fish_install_dir = fish_comp.get_variable(
pkgconfig: 'completionsdir',
pkgconfig_define: ['datadir', datadir]
)
else
fish_install_dir = join_paths(datadir, 'fish', 'vendor_completions.d')
endif
install_data(fish_files, install_dir: fish_install_dir)
endif

View file

@ -18,7 +18,7 @@ set $term foot
# Your preferred application launcher # Your preferred application launcher
# Note: pass the final command to swaymsg so that the resulting window can be opened # Note: pass the final command to swaymsg so that the resulting window can be opened
# on the original workspace that the command was run on. # on the original workspace that the command was run on.
set $menu dmenu_path | dmenu | xargs swaymsg exec -- set $menu dmenu_path | wmenu | xargs swaymsg exec --
### Appearance ### Appearance
# window corner radius in px # window corner radius in px
@ -228,7 +228,7 @@ bar {
# When the status_command prints a new line to stdout, swaybar updates. # When the status_command prints a new line to stdout, swaybar updates.
# The default just shows the current date and time. # The default just shows the current date and time.
status_command while date +'%Y-%m-%d %I:%M:%S %p'; do sleep 1; done status_command while date +'%Y-%m-%d %X'; do sleep 1; done
colors { colors {
statusline #ffffff statusline #ffffff

View file

@ -1,124 +0,0 @@
#!/usr/bin/python
# This script requires i3ipc-python package (install it from a system package manager
# or pip).
# It adds icons to the workspace name for each open window.
# Set your keybindings like this: set $workspace1 workspace number 1
# Add your icons to WINDOW_ICONS.
# Based on https://github.com/maximbaz/dotfiles/blob/master/bin/i3-autoname-workspaces
import argparse
import i3ipc
import logging
import re
import signal
import sys
WINDOW_ICONS = {
"firefox": "",
}
DEFAULT_ICON = "󰀏"
def icon_for_window(window):
name = None
if window.app_id is not None and len(window.app_id) > 0:
name = window.app_id.lower()
elif window.window_class is not None and len(window.window_class) > 0:
name = window.window_class.lower()
if name in WINDOW_ICONS:
return WINDOW_ICONS[name]
logging.info("No icon available for window with name: %s" % str(name))
return DEFAULT_ICON
def rename_workspaces(ipc):
for workspace in ipc.get_tree().workspaces():
name_parts = parse_workspace_name(workspace.name)
icon_tuple = ()
for w in workspace:
if w.app_id is not None or w.window_class is not None:
icon = icon_for_window(w)
if not ARGUMENTS.duplicates and icon in icon_tuple:
continue
icon_tuple += (icon,)
name_parts["icons"] = " ".join(icon_tuple) + " "
new_name = construct_workspace_name(name_parts)
ipc.command('rename workspace "%s" to "%s"' % (workspace.name, new_name))
def undo_window_renaming(ipc):
for workspace in ipc.get_tree().workspaces():
name_parts = parse_workspace_name(workspace.name)
name_parts["icons"] = None
new_name = construct_workspace_name(name_parts)
ipc.command('rename workspace "%s" to "%s"' % (workspace.name, new_name))
ipc.main_quit()
sys.exit(0)
def parse_workspace_name(name):
return re.match(
"(?P<num>[0-9]+):?(?P<shortname>\w+)? ?(?P<icons>.+)?", name
).groupdict()
def construct_workspace_name(parts):
new_name = str(parts["num"])
if parts["shortname"] or parts["icons"]:
new_name += ":"
if parts["shortname"]:
new_name += parts["shortname"]
if parts["icons"]:
new_name += " " + parts["icons"]
return new_name
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="This script automatically changes the workspace name in sway depending on your open applications."
)
parser.add_argument(
"--duplicates",
"-d",
action="store_true",
help="Set it when you want an icon for each instance of the same application per workspace.",
)
parser.add_argument(
"--logfile",
"-l",
type=str,
default="/tmp/sway-autoname-workspaces.log",
help="Path for the logfile.",
)
args = parser.parse_args()
global ARGUMENTS
ARGUMENTS = args
logging.basicConfig(
level=logging.INFO,
filename=ARGUMENTS.logfile,
filemode="w",
format="%(message)s",
)
ipc = i3ipc.Connection()
for sig in [signal.SIGINT, signal.SIGTERM]:
signal.signal(sig, lambda signal, frame: undo_window_renaming(ipc))
def window_event_handler(ipc, e):
if e.change in ["new", "close", "move"]:
rename_workspaces(ipc)
ipc.on("window", window_event_handler)
rename_workspaces(ipc)
ipc.main()

View file

@ -1,168 +0,0 @@
#!/bin/sh
## Grimshot: a helper for screenshots within sway
## Requirements:
## - `grim`: screenshot utility for wayland
## - `slurp`: to select an area
## - `swaymsg`: to read properties of current window
## - `wl-copy`: clipboard utility
## - `jq`: json utility to parse swaymsg output
## - `notify-send`: to show notifications
## Those are needed to be installed, if unsure, run `grimshot check`
##
## See `man 1 grimshot` or `grimshot usage` for further details.
getTargetDirectory() {
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/user-dirs.dirs" && \
. "${XDG_CONFIG_HOME:-$HOME/.config}/user-dirs.dirs"
echo "${XDG_SCREENSHOTS_DIR:-${XDG_PICTURES_DIR:-$HOME}}"
}
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}
FILE=${3:-$(getTargetDirectory)/$(date -Ins).png}
if [ "$ACTION" != "save" ] && [ "$ACTION" != "copy" ] && [ "$ACTION" != "check" ]; then
echo "Usage:"
echo " grimshot [--notify] [--cursor] (copy|save) [active|screen|output|area|window] [FILE|-]"
echo " grimshot check"
echo " grimshot usage"
echo ""
echo "Commands:"
echo " copy: Copy the screenshot data into the clipboard."
echo " save: Save the screenshot to a regular file or '-' to pipe to STDOUT."
echo " check: Verify if required tools are installed and exit."
echo " usage: Show this message and exit."
echo ""
echo "Targets:"
echo " active: Currently active window."
echo " screen: All visible outputs."
echo " output: Currently active output."
echo " area: Manually select a region."
echo " window: Manually select a window."
exit
fi
notify() {
notify-send -t 3000 -a grimshot "$@"
}
notifyOk() {
[ "$NOTIFY" = "no" ] && return
TITLE=${2:-"Screenshot"}
MESSAGE=${1:-"OK"}
notify "$TITLE" "$MESSAGE"
}
notifyError() {
if [ $NOTIFY = "yes" ]; then
TITLE=${2:-"Screenshot"}
MESSAGE=${1:-"Error taking screenshot with grim"}
notify -u critical "$TITLE" "$MESSAGE"
else
echo "$1"
fi
}
die() {
MSG=${1:-Bye}
notifyError "Error: $MSG"
exit 2
}
check() {
COMMAND=$1
if command -v "$COMMAND" > /dev/null 2>&1; then
RESULT="OK"
else
RESULT="NOT FOUND"
fi
echo " $COMMAND: $RESULT"
}
takeScreenshot() {
FILE=$1
GEOM=$2
OUTPUT=$3
if [ -n "$OUTPUT" ]; then
grim ${CURSOR:+-c} -o "$OUTPUT" "$FILE" || die "Unable to invoke grim"
elif [ -z "$GEOM" ]; then
grim ${CURSOR:+-c} "$FILE" || die "Unable to invoke grim"
else
grim ${CURSOR:+-c} -g "$GEOM" "$FILE" || die "Unable to invoke grim"
fi
}
if [ "$ACTION" = "check" ] ; then
echo "Checking if required tools are installed. If something is missing, install it to your system and make it available in PATH..."
check grim
check slurp
check swaymsg
check wl-copy
check jq
check notify-send
exit
elif [ "$SUBJECT" = "area" ] ; then
GEOM=$(slurp -d)
# Check if user exited slurp without selecting the area
if [ -z "$GEOM" ]; then
exit 1
fi
WHAT="Area"
elif [ "$SUBJECT" = "active" ] ; then
FOCUSED=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]?, .floating_nodes[]?) | select(.focused)')
GEOM=$(echo "$FOCUSED" | jq -r '.rect | "\(.x),\(.y) \(.width)x\(.height)"')
APP_ID=$(echo "$FOCUSED" | jq -r '.app_id')
WHAT="$APP_ID window"
elif [ "$SUBJECT" = "screen" ] ; then
GEOM=""
WHAT="Screen"
elif [ "$SUBJECT" = "output" ] ; then
GEOM=""
OUTPUT=$(swaymsg -t get_outputs | jq -r '.[] | select(.focused)' | jq -r '.name')
WHAT="$OUTPUT"
elif [ "$SUBJECT" = "window" ] ; then
GEOM=$(swaymsg -t get_tree | jq -r '.. | select(.pid? and .visible?) | .rect | "\(.x),\(.y) \(.width)x\(.height)"' | slurp)
# Check if user exited slurp without selecting the area
if [ -z "$GEOM" ]; then
exit 1
fi
WHAT="Window"
else
die "Unknown subject to take a screen shot from" "$SUBJECT"
fi
if [ "$ACTION" = "copy" ] ; then
takeScreenshot - "$GEOM" "$OUTPUT" | wl-copy --type image/png || die "Clipboard error"
notifyOk "$WHAT copied to buffer"
else
if takeScreenshot "$FILE" "$GEOM" "$OUTPUT"; then
TITLE="Screenshot of $SUBJECT"
MESSAGE=$(basename "$FILE")
notifyOk "$MESSAGE" "$TITLE"
echo "$FILE"
else
notifyError "Error taking screenshot with grim"
fi
fi

View file

@ -1,109 +0,0 @@
.\" 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" "2022-03-31"
.P
.SH NAME
.P
grimshot - a helper for screenshots within sway
.P
.SH SYNOPSIS
.P
\fBgrimshot\fR [--notify] [--cursor] (copy|save) [TARGET] [FILE]
.br
\fBgrimshot\fR check
.br
\fBgrimshot\fR usage
.P
.SH OPTIONS
.P
\fB--notify\fR
.RS 4
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.\&
.P
.RE
\fBcopy\fR
.RS 4
Copy the screenshot data (as image/png) into the clipboard.\&
.P
.RE
.SH DESCRIPTION
.P
Grimshot is an easy-to-use screenshot utility for sway.\& It provides a
convenient interface over grim, slurp and jq, and supports storing the
screenshot either directly to the clipboard using wl-copy or to a file.\&
.P
.SH EXAMPLES
.P
An example usage pattern is to add these bindings to your sway config:
.P
.nf
.RS 4
# Screenshots:
# Super+P: Current window
# Super+Shift+p: Select area
# Super+Alt+p Current output
# Super+Ctrl+p Select a window
bindsym Mod4+p exec grimshot save active
bindsym Mod4+Shift+p exec grimshot save area
bindsym Mod4+Mod1+p exec grimshot save output
bindsym Mod4+Ctrl+p exec grimshot save window
.fi
.RE
.P
.SH TARGETS
.P
grimshot can capture the following named targets:
.P
\fIactive\fR
.RS 4
Captures the currently active window.\&
.P
.RE
\fIscreen\fR
.RS 4
Captures the entire screen.\& This includes all visible outputs.\&
.P
.RE
\fIarea\fR
.RS 4
Allows manually selecting a rectangular region, and captures that.\&
.P
.RE
\fIwindow\fR
.RS 4
Allows manually selecting a single window (by clicking on it), and
captures it.\&
.P
.RE
\fIoutput\fR
.RS 4
Captures the currently active output.\&
.P
.RE
.SH OUTPUT
.P
Grimshot will print the filename of the captured screenshot to stdout if called
with the \fIsave\fR subcommand.\&
.P
.SH SEE ALSO
.P
\fBgrim\fR(1)

View file

@ -1,80 +0,0 @@
grimshot(1)
# NAME
grimshot - a helper for screenshots within sway
# SYNOPSIS
*grimshot* [--notify] [--cursor] (copy|save) [TARGET] [FILE]++
*grimshot* check++
*grimshot* usage
# OPTIONS
*--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 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.
*copy*
Copy the screenshot data (as image/png) into the clipboard.
# DESCRIPTION
Grimshot is an easy-to-use screenshot utility for sway. It provides a
convenient interface over grim, slurp and jq, and supports storing the
screenshot either directly to the clipboard using wl-copy or to a file.
# EXAMPLES
An example usage pattern is to add these bindings to your sway config:
```
# Screenshots:
# Super+P: Current window
# Super+Shift+p: Select area
# Super+Alt+p Current output
# Super+Ctrl+p Select a window
bindsym Mod4+p exec grimshot save active
bindsym Mod4+Shift+p exec grimshot save area
bindsym Mod4+Mod1+p exec grimshot save output
bindsym Mod4+Ctrl+p exec grimshot save window
```
# TARGETS
grimshot can capture the following named targets:
_active_
Captures the currently active window.
_screen_
Captures the entire screen. This includes all visible outputs.
_area_
Allows manually selecting a rectangular region, and captures that.
_window_
Allows manually selecting a single window (by clicking on it), and
captures it.
_output_
Captures the currently active output.
# OUTPUT
Grimshot will print the filename of the captured screenshot to stdout if called
with the _save_ subcommand.
# SEE ALSO
*grim*(1)

View file

@ -1,69 +0,0 @@
#!/usr/bin/python
# This script requires i3ipc-python package (install it from a system package manager
# or pip).
# It makes inactive windows transparent. Use `transparency_val` variable to control
# transparency strength in range of 0…1 or use the command line argument -o.
import argparse
import i3ipc
import signal
import sys
from functools import partial
def on_window_focus(inactive_opacity, ipc, event):
global prev_focused
global prev_workspace
focused_workspace = ipc.get_tree().find_focused()
if focused_workspace == None:
return
focused = event.container
workspace = focused_workspace.workspace().num
if focused.id != prev_focused.id: # https://github.com/swaywm/sway/issues/2859
focused.command("opacity 1")
if workspace == prev_workspace:
prev_focused.command("opacity " + inactive_opacity)
prev_focused = focused
prev_workspace = workspace
def remove_opacity(ipc):
for workspace in ipc.get_tree().workspaces():
for w in workspace:
w.command("opacity 1")
ipc.main_quit()
sys.exit(0)
if __name__ == "__main__":
transparency_val = "0.80"
parser = argparse.ArgumentParser(
description="This script allows you to set the transparency of unfocused windows in sway."
)
parser.add_argument(
"--opacity",
"-o",
type=str,
default=transparency_val,
help="set opacity value in range 0...1",
)
args = parser.parse_args()
ipc = i3ipc.Connection()
prev_focused = None
prev_workspace = ipc.get_tree().find_focused().workspace().num
for window in ipc.get_tree():
if window.focused:
prev_focused = window
else:
window.command("opacity " + args.opacity)
for sig in [signal.SIGINT, signal.SIGTERM]:
signal.signal(sig, lambda signal, frame: remove_opacity(ipc))
ipc.on("window::focus", partial(on_window_focus, args.opacity))
ipc.main()

View file

@ -44,7 +44,7 @@
name = "swayfx-shell"; name = "swayfx-shell";
inputsFrom = [ inputsFrom = [
self.packages.${system}.swayfx-unwrapped self.packages.${system}.swayfx-unwrapped
pkgs.wlroots_0_16 pkgs.wlroots_0_17
]; ];
nativeBuildInputs = with pkgs; [ nativeBuildInputs = with pkgs; [
cmake cmake
@ -55,7 +55,7 @@
shellHook = with pkgs; '' shellHook = with pkgs; ''
( (
mkdir -p "$PWD/subprojects" && cd "$PWD/subprojects" mkdir -p "$PWD/subprojects" && cd "$PWD/subprojects"
cp -R --no-preserve=mode,ownership ${wlroots_0_16.src} wlroots cp -R --no-preserve=mode,ownership ${wlroots_0_17.src} wlroots
)''; )'';
}; };
} }

View file

@ -5,6 +5,7 @@
#include <stdint.h> #include <stdint.h>
#include <cairo.h> #include <cairo.h>
#include <pango/pangocairo.h> #include <pango/pangocairo.h>
#include "stringop.h"
/** /**
* Utility function which escape characters a & < > ' ". * Utility function which escape characters a & < > ' ".
@ -16,9 +17,9 @@ size_t escape_markup_text(const char *src, char *dest);
PangoLayout *get_pango_layout(cairo_t *cairo, const PangoFontDescription *desc, PangoLayout *get_pango_layout(cairo_t *cairo, const PangoFontDescription *desc,
const char *text, double scale, bool markup); const char *text, double scale, bool markup);
void get_text_size(cairo_t *cairo, const PangoFontDescription *desc, int *width, int *height, void get_text_size(cairo_t *cairo, const PangoFontDescription *desc, int *width, int *height,
int *baseline, double scale, bool markup, const char *fmt, ...); int *baseline, double scale, bool markup, const char *fmt, ...) _SWAY_ATTRIB_PRINTF(8, 9);
void get_text_metrics(const PangoFontDescription *desc, int *height, int *baseline); void get_text_metrics(const PangoFontDescription *desc, int *height, int *baseline);
void render_text(cairo_t *cairo, PangoFontDescription *desc, void render_text(cairo_t *cairo, PangoFontDescription *desc,
double scale, bool markup, const char *fmt, ...); double scale, bool markup, const char *fmt, ...) _SWAY_ATTRIB_PRINTF(5, 6);
#endif #endif

View file

@ -5,6 +5,12 @@
#include <stddef.h> #include <stddef.h>
#include "list.h" #include "list.h"
#ifdef __GNUC__
#define _SWAY_ATTRIB_PRINTF(start, end) __attribute__((format(printf, start, end)))
#else
#define _SWAY_ATTRIB_PRINTF(start, end)
#endif
void strip_whitespace(char *str); void strip_whitespace(char *str);
void strip_quotes(char *str); void strip_quotes(char *str);
@ -31,4 +37,7 @@ char *argsep(char **stringp, const char *delim, char *matched_delim);
// Expand a path using shell replacements such as $HOME and ~ // Expand a path using shell replacements such as $HOME and ~
bool expand_path(char **path); bool expand_path(char **path);
char *vformat_str(const char *fmt, va_list args) _SWAY_ATTRIB_PRINTF(1, 0);
char *format_str(const char *fmt, ...) _SWAY_ATTRIB_PRINTF(1, 2);
#endif #endif

View file

@ -3,13 +3,14 @@
#include <wlr/util/edges.h> #include <wlr/util/edges.h>
#include "config.h" #include "config.h"
#include "stringop.h"
struct sway_container; struct sway_container;
typedef struct cmd_results *sway_cmd(int argc, char **argv); typedef struct cmd_results *sway_cmd(int argc, char **argv);
struct cmd_handler { struct cmd_handler {
char *command; const char *command;
sway_cmd *handle; sway_cmd *handle;
}; };
@ -46,7 +47,7 @@ enum expected_args {
struct cmd_results *checkarg(int argc, const char *name, struct cmd_results *checkarg(int argc, const char *name,
enum expected_args type, int val); enum expected_args type, int val);
const struct cmd_handler *find_handler(char *line, const struct cmd_handler *find_handler(const char *line,
const struct cmd_handler *cmd_handlers, size_t handlers_size); const struct cmd_handler *cmd_handlers, size_t handlers_size);
/** /**
@ -76,7 +77,7 @@ struct cmd_results *config_commands_command(char *exec);
/** /**
* Allocates a cmd_results object. * Allocates a cmd_results object.
*/ */
struct cmd_results *cmd_results_new(enum cmd_status status, const char *error, ...); struct cmd_results *cmd_results_new(enum cmd_status status, const char *error, ...) _SWAY_ATTRIB_PRINTF(2, 3);
/** /**
* Frees a cmd_results object. * Frees a cmd_results object.
*/ */
@ -174,8 +175,6 @@ sway_cmd cmd_max_render_time;
sway_cmd cmd_mode; sway_cmd cmd_mode;
sway_cmd cmd_mouse_warping; sway_cmd cmd_mouse_warping;
sway_cmd cmd_move; sway_cmd cmd_move;
sway_cmd cmd_new_float;
sway_cmd cmd_new_window;
sway_cmd cmd_nop; sway_cmd cmd_nop;
sway_cmd cmd_opacity; sway_cmd cmd_opacity;
sway_cmd cmd_saturation; sway_cmd cmd_saturation;
@ -185,6 +184,7 @@ sway_cmd cmd_no_focus;
sway_cmd cmd_output; sway_cmd cmd_output;
sway_cmd cmd_permit; sway_cmd cmd_permit;
sway_cmd cmd_popup_during_fullscreen; sway_cmd cmd_popup_during_fullscreen;
sway_cmd cmd_primary_selection;
sway_cmd cmd_reject; sway_cmd cmd_reject;
sway_cmd cmd_reload; sway_cmd cmd_reload;
sway_cmd cmd_rename; sway_cmd cmd_rename;
@ -290,10 +290,12 @@ sway_cmd input_cmd_map_to_region;
sway_cmd input_cmd_middle_emulation; sway_cmd input_cmd_middle_emulation;
sway_cmd input_cmd_natural_scroll; sway_cmd input_cmd_natural_scroll;
sway_cmd input_cmd_pointer_accel; sway_cmd input_cmd_pointer_accel;
sway_cmd input_cmd_rotation_angle;
sway_cmd input_cmd_scroll_factor; sway_cmd input_cmd_scroll_factor;
sway_cmd input_cmd_repeat_delay; sway_cmd input_cmd_repeat_delay;
sway_cmd input_cmd_repeat_rate; sway_cmd input_cmd_repeat_rate;
sway_cmd input_cmd_scroll_button; sway_cmd input_cmd_scroll_button;
sway_cmd input_cmd_scroll_button_lock;
sway_cmd input_cmd_scroll_method; sway_cmd input_cmd_scroll_method;
sway_cmd input_cmd_tap; sway_cmd input_cmd_tap;
sway_cmd input_cmd_tap_button_map; sway_cmd input_cmd_tap_button_map;

View file

@ -12,8 +12,10 @@
#include "../include/config.h" #include "../include/config.h"
#include "gesture.h" #include "gesture.h"
#include "list.h" #include "list.h"
#include "stringop.h"
#include "swaynag.h" #include "swaynag.h"
#include "tree/container.h" #include "tree/container.h"
#include "scenefx/types/fx/blur_data.h"
#include "sway/input/tablet.h" #include "sway/input/tablet.h"
#include "sway/tree/root.h" #include "sway/tree/root.h"
#include "wlr-layer-shell-unstable-v1-protocol.h" #include "wlr-layer-shell-unstable-v1-protocol.h"
@ -155,10 +157,12 @@ struct input_config {
int middle_emulation; int middle_emulation;
int natural_scroll; int natural_scroll;
float pointer_accel; float pointer_accel;
float rotation_angle;
float scroll_factor; float scroll_factor;
int repeat_delay; int repeat_delay;
int repeat_rate; int repeat_rate;
int scroll_button; int scroll_button;
int scroll_button_lock;
int scroll_method; int scroll_method;
int send_events; int send_events;
int tap; int tap;
@ -470,15 +474,6 @@ enum xwayland_mode {
XWAYLAND_MODE_IMMEDIATE, XWAYLAND_MODE_IMMEDIATE,
}; };
struct blur_parameters {
int num_passes;
int radius;
float noise;
float brightness;
float contrast;
float saturation;
};
/** /**
* The configuration struct. The result of loading a config file. * The configuration struct. The result of loading a config file.
*/ */
@ -501,7 +496,7 @@ struct sway_config {
bool blur_enabled; bool blur_enabled;
bool blur_xray; bool blur_xray;
struct blur_parameters blur_params; struct blur_data blur_params;
bool titlebar_separator; bool titlebar_separator;
bool scratchpad_minimize; bool scratchpad_minimize;
@ -564,6 +559,7 @@ struct sway_config {
bool auto_back_and_forth; bool auto_back_and_forth;
bool show_marks; bool show_marks;
enum alignment title_align; enum alignment title_align;
bool primary_selection;
bool tiling_drag; bool tiling_drag;
int tiling_drag_threshold; int tiling_drag_threshold;
@ -657,7 +653,7 @@ void run_deferred_bindings(void);
/** /**
* Adds a warning entry to the swaynag instance used for errors. * Adds a warning entry to the swaynag instance used for errors.
*/ */
void config_add_swaynag_warning(char *fmt, ...); void config_add_swaynag_warning(char *fmt, ...) _SWAY_ATTRIB_PRINTF(1, 2);
/** /**
* Free config struct * Free config struct

View file

@ -43,6 +43,7 @@ struct criteria {
struct pattern *window_role; struct pattern *window_role;
enum atom_name window_type; enum atom_name window_type;
#endif #endif
bool all;
bool floating; bool floating;
bool tiling; bool tiling;
char urgent; // 'l' for latest or 'o' for oldest char urgent; // 'l' for latest or 'o' for oldest

View file

@ -1,27 +0,0 @@
#ifndef FX_FRAMEBUFFER_H
#define FX_FRAMEBUFFER_H
#include <GLES2/gl2.h>
#include <stdbool.h>
#include <wlr/types/wlr_output.h>
#include "sway/desktop/fx_renderer/fx_stencilbuffer.h"
#include "sway/desktop/fx_renderer/fx_texture.h"
struct fx_framebuffer {
GLuint fb;
struct fx_stencilbuffer stencil_buffer;
struct fx_texture texture;
};
struct fx_framebuffer fx_framebuffer_create();
void fx_framebuffer_bind(struct fx_framebuffer *buffer);
void fx_framebuffer_update(struct fx_framebuffer *buffer, int width, int height);
void fx_framebuffer_add_stencil_buffer(struct fx_framebuffer *buffer, int width, int height);
void fx_framebuffer_release(struct fx_framebuffer *buffer);
#endif

View file

@ -1,236 +0,0 @@
#ifndef _SWAY_OPENGL_H
#define _SWAY_OPENGL_H
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <stdbool.h>
#include <wlr/render/egl.h>
#include "sway/desktop/fx_renderer/fx_framebuffer.h"
#include "sway/desktop/fx_renderer/fx_texture.h"
enum corner_location { TOP_LEFT, TOP_RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT, ALL, NONE };
enum fx_tex_shader_source {
SHADER_SOURCE_TEXTURE_RGBA = 1,
SHADER_SOURCE_TEXTURE_RGBX = 2,
SHADER_SOURCE_TEXTURE_EXTERNAL = 3,
};
enum fx_rounded_quad_shader_source {
SHADER_SOURCE_QUAD_ROUND = 1,
SHADER_SOURCE_QUAD_ROUND_TOP_LEFT = 2,
SHADER_SOURCE_QUAD_ROUND_TOP_RIGHT = 3,
SHADER_SOURCE_QUAD_ROUND_BOTTOM_RIGHT = 4,
SHADER_SOURCE_QUAD_ROUND_BOTTOM_LEFT = 5,
};
struct decoration_data {
float alpha;
float saturation;
int corner_radius;
float dim;
float *dim_color;
bool has_titlebar;
bool discard_transparent;
bool blur;
bool shadow;
};
struct blur_shader {
GLuint program;
GLint proj;
GLint tex;
GLint pos_attrib;
GLint tex_attrib;
GLint radius;
GLint halfpixel;
};
struct effects_shader {
GLuint program;
GLint proj;
GLint tex;
GLint pos_attrib;
GLint tex_attrib;
GLfloat noise;
GLfloat brightness;
GLfloat contrast;
GLfloat saturation;
};
struct box_shadow_shader {
GLuint program;
GLint proj;
GLint color;
GLint pos_attrib;
GLint position;
GLint size;
GLint blur_sigma;
GLint corner_radius;
};
struct corner_shader {
GLuint program;
GLint proj;
GLint color;
GLint pos_attrib;
GLint is_top_left;
GLint is_top_right;
GLint is_bottom_left;
GLint is_bottom_right;
GLint position;
GLint radius;
GLint half_size;
GLint half_thickness;
};
struct quad_shader {
GLuint program;
GLint proj;
GLint color;
GLint pos_attrib;
};
struct rounded_quad_shader {
GLuint program;
GLint proj;
GLint color;
GLint pos_attrib;
GLint size;
GLint position;
GLint radius;
};
struct stencil_mask_shader {
GLuint program;
GLint proj;
GLint color;
GLint pos_attrib;
GLint half_size;
GLint position;
GLint radius;
};
struct tex_shader {
GLuint program;
GLint proj;
GLint tex;
GLint alpha;
GLint pos_attrib;
GLint tex_attrib;
GLint size;
GLint position;
GLint radius;
GLint saturation;
GLint dim;
GLint dim_color;
GLint has_titlebar;
GLint discard_transparent;
};
struct fx_renderer {
float projection[9];
int viewport_width, viewport_height;
struct wlr_output *wlr_output;
// The framebuffer used by wlroots
struct fx_framebuffer wlr_buffer;
// Contains the blurred background for tiled windows
struct fx_framebuffer blur_buffer;
// Contains the original pixels to draw over the areas where artifact are visible
struct fx_framebuffer blur_saved_pixels_buffer;
// Blur swaps between the two effects buffers everytime it scales the image
// Buffer used for effects
struct fx_framebuffer effects_buffer;
// Swap buffer used for effects
struct fx_framebuffer effects_buffer_swapped;
// The region where there's blur
pixman_region32_t blur_padding_region;
bool blur_buffer_dirty;
struct {
bool OES_egl_image_external;
} exts;
struct {
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
} procs;
struct {
struct box_shadow_shader box_shadow;
struct blur_shader blur1;
struct blur_shader blur2;
struct effects_shader blur_effects;
struct corner_shader corner;
struct quad_shader quad;
struct rounded_quad_shader rounded_quad;
struct rounded_quad_shader rounded_tl_quad;
struct rounded_quad_shader rounded_tr_quad;
struct rounded_quad_shader rounded_bl_quad;
struct rounded_quad_shader rounded_br_quad;
struct stencil_mask_shader stencil_mask;
struct tex_shader tex_rgba;
struct tex_shader tex_rgbx;
struct tex_shader tex_ext;
} shaders;
};
struct decoration_data get_undecorated_decoration_data();
struct fx_renderer *fx_renderer_create(struct wlr_egl *egl, struct wlr_output *output);
void fx_renderer_fini(struct fx_renderer *renderer);
void fx_renderer_begin(struct fx_renderer *renderer, int width, int height);
void fx_renderer_end(struct fx_renderer *renderer);
void fx_renderer_clear(const float color[static 4]);
void fx_renderer_scissor(struct wlr_box *box);
// Initialize the stenciling work
void fx_renderer_stencil_mask_init();
// Close the mask
void fx_renderer_stencil_mask_close(bool draw_inside_mask);
// Finish stenciling and clear the buffer
void fx_renderer_stencil_mask_fini();
bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, struct fx_texture *fx_texture,
const struct wlr_fbox *src_box, const struct wlr_box *dst_box, const float matrix[static 9],
struct decoration_data deco_data);
bool fx_render_texture_with_matrix(struct fx_renderer *renderer, struct fx_texture *fx_texture,
const struct wlr_box *dst_box, const float matrix[static 9], struct decoration_data deco_data);
void fx_render_rect(struct fx_renderer *renderer, const struct wlr_box *box,
const float color[static 4], const float projection[static 9]);
void fx_render_rounded_rect(struct fx_renderer *renderer, const struct wlr_box *box,
const float color[static 4], const float matrix[static 9], int radius,
enum corner_location corner_location);
void fx_render_border_corner(struct fx_renderer *renderer, const struct wlr_box *box,
const float color[static 4], const float matrix[static 9],
enum corner_location corner_location, int radius, int border_thickness);
void fx_render_box_shadow(struct fx_renderer *renderer, const struct wlr_box *box,
const struct wlr_box *inner_box, const float color[static 4],
const float matrix[static 9], int corner_radius, float blur_sigma);
void fx_render_blur(struct fx_renderer *renderer, const float matrix[static 9],
struct fx_framebuffer **buffer, struct blur_shader *shader,
const struct wlr_box *box, int blur_radius);
void fx_render_blur_effects(struct fx_renderer *renderer, const float matrix[static 9],
struct fx_framebuffer **buffer, float blur_noise, float blur_brightness,
float blur_contrast, float blur_saturation);
#endif

View file

@ -1,18 +0,0 @@
#ifndef FX_STENCILBUFFER_H
#define FX_STENCILBUFFER_H
#include <GLES2/gl2.h>
#include <stdbool.h>
#include <wlr/render/wlr_texture.h>
struct fx_stencilbuffer {
GLuint rb;
int width;
int height;
};
struct fx_stencilbuffer fx_stencilbuffer_create();
void fx_stencilbuffer_release(struct fx_stencilbuffer *stencil_buffer);
#endif

View file

@ -1,22 +0,0 @@
#ifndef FX_TEXTURE_H
#define FX_TEXTURE_H
#include <GLES2/gl2.h>
#include <stdbool.h>
#include <wlr/render/wlr_texture.h>
struct fx_texture {
GLuint target;
GLuint id;
bool has_alpha;
int width;
int height;
};
struct fx_texture fx_texture_create();
struct fx_texture fx_texture_from_wlr_texture(struct wlr_texture *tex);
void fx_texture_release(struct fx_texture *texture);
#endif

View file

@ -1,9 +0,0 @@
#ifndef _MATRIX_H
#define _MATRIX_H
#include <wlr/types/wlr_output.h>
void matrix_projection(float mat[static 9], int width, int height,
enum wl_output_transform transform);
#endif

View file

@ -1,8 +1,6 @@
#ifndef _SWAY_DESKTOP_IDLE_INHIBIT_V1_H #ifndef _SWAY_DESKTOP_IDLE_INHIBIT_V1_H
#define _SWAY_DESKTOP_IDLE_INHIBIT_V1_H #define _SWAY_DESKTOP_IDLE_INHIBIT_V1_H
#include <wlr/types/wlr_idle_inhibit_v1.h> #include <wlr/types/wlr_idle_inhibit_v1.h>
#include <wlr/types/wlr_idle.h>
#include "sway/server.h"
enum sway_idle_inhibit_mode { enum sway_idle_inhibit_mode {
INHIBIT_IDLE_APPLICATION, // Application set inhibitor (when visible) INHIBIT_IDLE_APPLICATION, // Application set inhibitor (when visible)
@ -16,12 +14,9 @@ struct sway_idle_inhibit_manager_v1 {
struct wlr_idle_inhibit_manager_v1 *wlr_manager; struct wlr_idle_inhibit_manager_v1 *wlr_manager;
struct wl_listener new_idle_inhibitor_v1; struct wl_listener new_idle_inhibitor_v1;
struct wl_list inhibitors; struct wl_list inhibitors;
struct wlr_idle *idle;
}; };
struct sway_idle_inhibitor_v1 { struct sway_idle_inhibitor_v1 {
struct sway_idle_inhibit_manager_v1 *manager;
struct wlr_idle_inhibitor_v1 *wlr_inhibitor; struct wlr_idle_inhibitor_v1 *wlr_inhibitor;
struct sway_view *view; struct sway_view *view;
enum sway_idle_inhibit_mode mode; enum sway_idle_inhibit_mode mode;
@ -33,8 +28,7 @@ struct sway_idle_inhibitor_v1 {
bool sway_idle_inhibit_v1_is_active( bool sway_idle_inhibit_v1_is_active(
struct sway_idle_inhibitor_v1 *inhibitor); struct sway_idle_inhibitor_v1 *inhibitor);
void sway_idle_inhibit_v1_check_active( void sway_idle_inhibit_v1_check_active(void);
struct sway_idle_inhibit_manager_v1 *manager);
void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view, void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view,
enum sway_idle_inhibit_mode mode); enum sway_idle_inhibit_mode mode);
@ -48,6 +42,6 @@ struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_application_inhibitor_for_vi
void sway_idle_inhibit_v1_user_inhibitor_destroy( void sway_idle_inhibit_v1_user_inhibitor_destroy(
struct sway_idle_inhibitor_v1 *inhibitor); struct sway_idle_inhibitor_v1 *inhibitor);
struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create( bool sway_idle_inhibit_manager_v1_init(void);
struct wl_display *wl_display, struct wlr_idle *idle);
#endif #endif

View file

@ -2,14 +2,19 @@
#define _SWAY_LAUNCHER_H #define _SWAY_LAUNCHER_H
#include <stdlib.h> #include <stdlib.h>
#include <wayland-server-core.h>
#include "sway/input/seat.h"
struct launcher_ctx { struct launcher_ctx {
pid_t pid; pid_t pid;
char *name; char *fallback_name;
struct wlr_xdg_activation_token_v1 *token; struct wlr_xdg_activation_token_v1 *token;
struct wl_listener token_destroy; struct wl_listener token_destroy;
struct sway_seat *seat;
struct wl_listener seat_destroy;
bool activated; bool activated;
bool had_focused_surface;
struct sway_node *node; struct sway_node *node;
struct wl_listener node_destroy; struct wl_listener node_destroy;
@ -25,7 +30,10 @@ void launcher_ctx_consume(struct launcher_ctx *ctx);
void launcher_ctx_destroy(struct launcher_ctx *ctx); void launcher_ctx_destroy(struct launcher_ctx *ctx);
struct launcher_ctx *launcher_ctx_create(void); struct launcher_ctx *launcher_ctx_create_internal(void);
struct launcher_ctx *launcher_ctx_create(
struct wlr_xdg_activation_token_v1 *token, struct sway_node *node);
const char *launcher_ctx_get_token_name(struct launcher_ctx *ctx); const char *launcher_ctx_get_token_name(struct launcher_ctx *ctx);

View file

@ -35,7 +35,6 @@ struct sway_cursor {
pixman_region32_t confine; // invalid if active_constraint == NULL pixman_region32_t confine; // invalid if active_constraint == NULL
bool active_confine_requires_warp; bool active_confine_requires_warp;
struct wlr_pointer_gestures_v1 *pointer_gestures;
struct wl_listener hold_begin; struct wl_listener hold_begin;
struct wl_listener hold_end; struct wl_listener hold_end;
struct wl_listener pinch_begin; struct wl_listener pinch_begin;
@ -53,6 +52,7 @@ struct sway_cursor {
struct wl_listener touch_down; struct wl_listener touch_down;
struct wl_listener touch_up; struct wl_listener touch_up;
struct wl_listener touch_cancel;
struct wl_listener touch_motion; struct wl_listener touch_motion;
struct wl_listener touch_frame; struct wl_listener touch_frame;
bool simulating_pointer_from_touch; bool simulating_pointer_from_touch;
@ -64,6 +64,7 @@ struct sway_cursor {
struct wl_listener tool_proximity; struct wl_listener tool_proximity;
struct wl_listener tool_button; struct wl_listener tool_button;
bool simulating_pointer_from_tool_tip; bool simulating_pointer_from_tool_tip;
bool simulating_pointer_from_tool_button;
uint32_t tool_buttons; uint32_t tool_buttons;
struct wl_listener request_set_cursor; struct wl_listener request_set_cursor;
@ -107,6 +108,10 @@ void cursor_unhide(struct sway_cursor *cursor);
int cursor_get_timeout(struct sway_cursor *cursor); int cursor_get_timeout(struct sway_cursor *cursor);
void cursor_notify_key_press(struct sway_cursor *cursor); void cursor_notify_key_press(struct sway_cursor *cursor);
void pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
struct wlr_input_device *device, double dx, double dy,
double dx_unaccel, double dy_unaccel);
void dispatch_cursor_button(struct sway_cursor *cursor, void dispatch_cursor_button(struct sway_cursor *cursor,
struct wlr_input_device *device, uint32_t time_msec, uint32_t button, struct wlr_input_device *device, uint32_t time_msec, uint32_t button,
enum wlr_button_state state); enum wlr_button_state state);
@ -140,4 +145,6 @@ uint32_t get_mouse_button(const char *name, char **error);
const char *get_mouse_button_name(uint32_t button); const char *get_mouse_button_name(uint32_t button);
void handle_request_set_cursor_shape(struct wl_listener *listener, void *data);
#endif #endif

View file

@ -25,6 +25,7 @@ struct sway_input_manager {
struct wlr_keyboard_shortcuts_inhibit_manager_v1 *keyboard_shortcuts_inhibit; struct wlr_keyboard_shortcuts_inhibit_manager_v1 *keyboard_shortcuts_inhibit;
struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard; struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard;
struct wlr_virtual_pointer_manager_v1 *virtual_pointer; struct wlr_virtual_pointer_manager_v1 *virtual_pointer;
struct wlr_pointer_gestures_v1 *pointer_gestures;
struct wl_listener new_input; struct wl_listener new_input;
struct wl_listener inhibit_activate; struct wl_listener inhibit_activate;
@ -44,7 +45,7 @@ void input_manager_configure_xcursor(void);
void input_manager_apply_input_config(struct input_config *input_config); void input_manager_apply_input_config(struct input_config *input_config);
void input_manager_configure_all_inputs(void); void input_manager_configure_all_input_mappings(void);
void input_manager_reset_input(struct sway_input_device *input_device); void input_manager_reset_input(struct sway_input_device *input_device);

View file

@ -4,6 +4,9 @@
bool sway_input_configure_libinput_device(struct sway_input_device *device); bool sway_input_configure_libinput_device(struct sway_input_device *device);
void sway_input_configure_libinput_device_send_events(
struct sway_input_device *device);
void sway_input_reset_libinput_device(struct sway_input_device *device); void sway_input_reset_libinput_device(struct sway_input_device *device);
bool sway_libinput_device_is_builtin(struct sway_input_device *device); bool sway_libinput_device_is_builtin(struct sway_input_device *device);

View file

@ -4,6 +4,7 @@
#include <wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h> #include <wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h>
#include <wlr/types/wlr_layer_shell_v1.h> #include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_seat.h> #include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_touch.h>
#include <wlr/util/edges.h> #include <wlr/util/edges.h>
#include "sway/config.h" #include "sway/config.h"
#include "sway/input/input-manager.h" #include "sway/input/input-manager.h"
@ -11,6 +12,7 @@
#include "sway/input/text_input.h" #include "sway/input/text_input.h"
struct sway_seat; struct sway_seat;
struct fx_render_context;
struct sway_seatop_impl { struct sway_seatop_impl {
void (*button)(struct sway_seat *seat, uint32_t time_msec, void (*button)(struct sway_seat *seat, uint32_t time_msec,
@ -36,14 +38,21 @@ struct sway_seatop_impl {
void (*swipe_end)(struct sway_seat *seat, void (*swipe_end)(struct sway_seat *seat,
struct wlr_pointer_swipe_end_event *event); struct wlr_pointer_swipe_end_event *event);
void (*rebase)(struct sway_seat *seat, uint32_t time_msec); void (*rebase)(struct sway_seat *seat, uint32_t time_msec);
void (*touch_motion)(struct sway_seat *seat,
struct wlr_touch_motion_event *event, double lx, double ly);
void (*touch_up)(struct sway_seat *seat,
struct wlr_touch_up_event *event);
void (*touch_down)(struct sway_seat *seat,
struct wlr_touch_down_event *event, double lx, double ly);
void (*touch_cancel)(struct sway_seat *seat,
struct wlr_touch_cancel_event *event);
void (*tablet_tool_motion)(struct sway_seat *seat, void (*tablet_tool_motion)(struct sway_seat *seat,
struct sway_tablet_tool *tool, uint32_t time_msec); struct sway_tablet_tool *tool, uint32_t time_msec);
void (*tablet_tool_tip)(struct sway_seat *seat, struct sway_tablet_tool *tool, void (*tablet_tool_tip)(struct sway_seat *seat, struct sway_tablet_tool *tool,
uint32_t time_msec, enum wlr_tablet_tool_tip_state state); uint32_t time_msec, enum wlr_tablet_tool_tip_state state);
void (*end)(struct sway_seat *seat); void (*end)(struct sway_seat *seat);
void (*unref)(struct sway_seat *seat, struct sway_container *con); void (*unref)(struct sway_seat *seat, struct sway_container *con);
void (*render)(struct sway_seat *seat, struct sway_output *output, void (*render)(struct sway_seat *seat, struct fx_render_context *ctx);
pixman_region32_t *damage);
bool allow_set_cursor; bool allow_set_cursor;
}; };
@ -72,6 +81,7 @@ struct sway_drag_icon {
struct wl_list link; // sway_root::drag_icons struct wl_list link; // sway_root::drag_icons
double x, y; // in layout-local coordinates double x, y; // in layout-local coordinates
int dx, dy; // offset in surface-local coordinates
struct wl_listener surface_commit; struct wl_listener surface_commit;
struct wl_listener map; struct wl_listener map;
@ -94,8 +104,9 @@ struct sway_seat {
struct sway_workspace *workspace; struct sway_workspace *workspace;
char *prev_workspace_name; // for workspace back_and_forth char *prev_workspace_name; // for workspace back_and_forth
// If the focused layer is set, views cannot receive keyboard focus
struct wlr_layer_surface_v1 *focused_layer; struct wlr_layer_surface_v1 *focused_layer;
// If the exclusive layer is set, views cannot receive keyboard focus
bool has_exclusive_layer;
// If exclusive_client is set, no other clients will receive input events // If exclusive_client is set, no other clients will receive input events
struct wl_client *exclusive_client; struct wl_client *exclusive_client;
@ -157,6 +168,9 @@ void seat_add_device(struct sway_seat *seat,
void seat_configure_device(struct sway_seat *seat, void seat_configure_device(struct sway_seat *seat,
struct sway_input_device *device); struct sway_input_device *device);
void seat_configure_device_mapping(struct sway_seat *seat,
struct sway_input_device *input_device);
void seat_reset_device(struct sway_seat *seat, void seat_reset_device(struct sway_seat *seat,
struct sway_input_device *input_device); struct sway_input_device *input_device);
@ -255,10 +269,13 @@ enum wlr_edges find_resize_edge(struct sway_container *cont,
void seatop_begin_default(struct sway_seat *seat); void seatop_begin_default(struct sway_seat *seat);
void seatop_begin_down(struct sway_seat *seat, struct sway_container *con, void seatop_begin_down(struct sway_seat *seat, struct sway_container *con,
uint32_t time_msec, double sx, double sy); double sx, double sy);
void seatop_begin_down_on_surface(struct sway_seat *seat, void seatop_begin_down_on_surface(struct sway_seat *seat,
struct wlr_surface *surface, uint32_t time_msec, double sx, double sy); struct wlr_surface *surface, double sx, double sy);
void seatop_begin_touch_down(struct sway_seat *seat, struct wlr_surface *surface,
struct wlr_touch_down_event *event, double sx, double sy, double lx, double ly);
void seatop_begin_move_floating(struct sway_seat *seat, void seatop_begin_move_floating(struct sway_seat *seat,
struct sway_container *con); struct sway_container *con);
@ -318,6 +335,18 @@ void seatop_swipe_update(struct sway_seat *seat,
void seatop_swipe_end(struct sway_seat *seat, void seatop_swipe_end(struct sway_seat *seat,
struct wlr_pointer_swipe_end_event *event); struct wlr_pointer_swipe_end_event *event);
void seatop_touch_motion(struct sway_seat *seat,
struct wlr_touch_motion_event *event, double lx, double ly);
void seatop_touch_up(struct sway_seat *seat,
struct wlr_touch_up_event *event);
void seatop_touch_down(struct sway_seat *seat,
struct wlr_touch_down_event *event, double lx, double ly);
void seatop_touch_cancel(struct sway_seat *seat,
struct wlr_touch_cancel_event *event);
void seatop_rebase(struct sway_seat *seat, uint32_t time_msec); void seatop_rebase(struct sway_seat *seat, uint32_t time_msec);
/** /**
@ -336,8 +365,7 @@ void seatop_unref(struct sway_seat *seat, struct sway_container *con);
* Instructs a seatop to render anything that it needs to render * Instructs a seatop to render anything that it needs to render
* (eg. dropzone for move-tiling) * (eg. dropzone for move-tiling)
*/ */
void seatop_render(struct sway_seat *seat, struct sway_output *output, void seatop_render(struct sway_seat *seat, struct fx_render_context *ctx);
pixman_region32_t *damage);
bool seatop_allows_set_cursor(struct sway_seat *seat); bool seatop_allows_set_cursor(struct sway_seat *seat);

View file

@ -4,12 +4,11 @@
#include <wlr/types/wlr_text_input_v3.h> #include <wlr/types/wlr_text_input_v3.h>
#include <wlr/types/wlr_input_method_v2.h> #include <wlr/types/wlr_input_method_v2.h>
#include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_compositor.h>
#include "sway/input/seat.h"
/** /**
* The relay structure manages the relationship between text-input and * The relay structure manages the relationship between text-input and
* input_method interfaces on a given seat. Multiple text-input interfaces may * input_method interfaces on a given seat. Multiple text-input interfaces may
* be bound to a relay, but at most one will be focused (reveiving events) at * be bound to a relay, but at most one will be focused (receiving events) at
* a time. At most one input-method interface may be bound to the seat. The * a time. At most one input-method interface may be bound to the seat. The
* relay manages life cycle of both sides. When both sides are present and * relay manages life cycle of both sides. When both sides are present and
* focused, the relay passes messages between them. * focused, the relay passes messages between them.

View file

@ -21,5 +21,6 @@ void ipc_event_mode(const char *mode, bool pango);
void ipc_event_shutdown(const char *reason); void ipc_event_shutdown(const char *reason);
void ipc_event_binding(struct sway_binding *binding); void ipc_event_binding(struct sway_binding *binding);
void ipc_event_input(const char *change, struct sway_input_device *device); void ipc_event_input(const char *change, struct sway_input_device *device);
void ipc_event_output(void);
#endif #endif

View file

@ -60,6 +60,10 @@ struct sway_layer_subsurface {
}; };
struct sway_output; struct sway_output;
struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
struct wlr_surface *surface);
void arrange_layers(struct sway_output *output); void arrange_layers(struct sway_output *output);
struct sway_layer_surface *layer_from_wlr_layer_surface_v1( struct sway_layer_surface *layer_from_wlr_layer_surface_v1(

View file

@ -6,23 +6,33 @@
#include <wlr/types/wlr_damage_ring.h> #include <wlr/types/wlr_damage_ring.h>
#include <wlr/types/wlr_output.h> #include <wlr/types/wlr_output.h>
#include "config.h" #include "config.h"
#include "sway/desktop/fx_renderer/fx_renderer.h" #include "scenefx/render/pass.h"
#include "sway/tree/node.h" #include "sway/tree/node.h"
#include "sway/tree/view.h" #include "sway/tree/view.h"
struct decoration_data get_undecorated_decoration_data();
struct sway_server; struct sway_server;
struct sway_container; struct sway_container;
struct decoration_data {
float alpha;
float saturation;
int corner_radius;
float dim;
float *dim_color;
bool has_titlebar;
bool discard_transparent;
bool blur;
bool shadow;
};
struct render_data { struct render_data {
struct fx_render_context *ctx;
pixman_region32_t *damage; pixman_region32_t *damage;
struct wlr_box *clip_box; struct wlr_box *clip_box;
struct decoration_data deco_data; struct decoration_data deco_data;
}; struct sway_view *view;
struct blur_stencil_data {
struct fx_texture *stencil_texture;
const struct wlr_fbox *stencil_src_box;
float *stencil_matrix;
}; };
struct sway_output_state { struct sway_output_state {
@ -36,8 +46,6 @@ struct sway_output {
struct sway_server *server; struct sway_server *server;
struct wl_list link; struct wl_list link;
struct fx_renderer *renderer;
struct wl_list layers[4]; // sway_layer_surface::link struct wl_list layers[4]; // sway_layer_surface::link
struct wlr_box usable_area; struct wlr_box usable_area;
@ -48,21 +56,20 @@ struct sway_output {
int width, height; // transformed buffer size int width, height; // transformed buffer size
enum wl_output_subpixel detected_subpixel; enum wl_output_subpixel detected_subpixel;
enum scale_filter_mode scale_filter; enum scale_filter_mode scale_filter;
// last applied mode when the output is powered off
struct wlr_output_mode *current_mode;
bool enabling, enabled; bool enabling, enabled;
list_t *workspaces; list_t *workspaces;
struct sway_output_state current; struct sway_output_state current;
struct wl_listener layout_destroy;
struct wl_listener destroy; struct wl_listener destroy;
struct wl_listener commit; struct wl_listener commit;
struct wl_listener mode;
struct wl_listener present; struct wl_listener present;
struct wl_listener damage; struct wl_listener damage;
struct wl_listener frame; struct wl_listener frame;
struct wl_listener needs_frame; struct wl_listener needs_frame;
struct wl_listener request_state;
struct { struct {
struct wl_signal disable; struct wl_signal disable;
@ -72,6 +79,7 @@ struct sway_output {
uint32_t refresh_nsec; uint32_t refresh_nsec;
int max_render_time; // In milliseconds int max_render_time; // In milliseconds
struct wl_event_source *repaint_timer; struct wl_event_source *repaint_timer;
bool gamma_lut_changed;
}; };
struct sway_output_non_desktop { struct sway_output_non_desktop {
@ -80,6 +88,14 @@ struct sway_output_non_desktop {
struct wl_listener destroy; struct wl_listener destroy;
}; };
struct fx_render_context {
struct sway_output *output;
struct wlr_renderer *renderer;
pixman_region32_t *output_damage;
struct fx_gles_render_pass *pass;
};
struct sway_output *output_create(struct wlr_output *wlr_output); struct sway_output *output_create(struct wlr_output *wlr_output);
void output_destroy(struct sway_output *output); void output_destroy(struct sway_output *output);
@ -111,6 +127,9 @@ void output_damage_box(struct sway_output *output, struct wlr_box *box);
void output_damage_whole_container(struct sway_output *output, void output_damage_whole_container(struct sway_output *output,
struct sway_container *con); struct sway_container *con);
bool output_match_name_or_id(struct sway_output *output,
const char *name_or_id);
// this ONLY includes the enabled outputs // this ONLY includes the enabled outputs
struct sway_output *output_by_name_or_id(const char *name_or_id); struct sway_output *output_by_name_or_id(const char *name_or_id);
@ -127,8 +146,7 @@ bool output_has_opaque_overlay_layer_surface(struct sway_output *output);
struct sway_workspace *output_get_active_workspace(struct sway_output *output); struct sway_workspace *output_get_active_workspace(struct sway_output *output);
void output_render(struct sway_output *output, struct timespec *when, void output_render(struct fx_render_context *ctx);
pixman_region32_t *damage);
void output_surface_for_each_surface(struct sway_output *output, void output_surface_for_each_surface(struct sway_output *output,
struct wlr_surface *surface, double ox, double oy, struct wlr_surface *surface, double ox, double oy,
@ -181,20 +199,16 @@ void output_get_box(struct sway_output *output, struct wlr_box *box);
enum sway_container_layout output_get_default_layout( enum sway_container_layout output_get_default_layout(
struct sway_output *output); struct sway_output *output);
void render_rect(struct sway_output *output, void render_rect(struct fx_render_context *ctx, const struct wlr_box *_box,
pixman_region32_t *output_damage, const struct wlr_box *_box,
float color[static 4]); float color[static 4]);
void render_rounded_rect(struct sway_output *output, void render_rounded_rect(struct fx_render_context *ctx, const struct wlr_box *_box,
pixman_region32_t *output_damage, const struct wlr_box *_box, float color[static 4], int corner_radius, enum corner_location corner_location);
float color[static 4], int corner_radius,
enum corner_location corner_location);
void render_blur(bool optimized, struct sway_output *output,
pixman_region32_t *output_damage, const struct wlr_box *dst_box,
pixman_region32_t *opaque_region, struct decoration_data *deco_data,
struct blur_stencil_data *stencil_data);
void render_blur(struct fx_render_context *ctx, struct wlr_texture *texture,
const struct wlr_fbox *src_box, const struct wlr_box *dst_box,
bool optimized_blur, pixman_region32_t *opaque_region,
struct decoration_data deco_data);
void premultiply_alpha(float color[4], float opacity); void premultiply_alpha(float color[4], float opacity);
@ -204,6 +218,8 @@ enum wlr_direction opposite_direction(enum wlr_direction d);
void handle_output_layout_change(struct wl_listener *listener, void *data); void handle_output_layout_change(struct wl_listener *listener, void *data);
void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data);
void handle_output_manager_apply(struct wl_listener *listener, void *data); void handle_output_manager_apply(struct wl_listener *listener, void *data);
void handle_output_manager_test(struct wl_listener *listener, void *data); void handle_output_manager_test(struct wl_listener *listener, void *data);

View file

@ -3,14 +3,12 @@
#include <stdbool.h> #include <stdbool.h>
#include <wayland-server-core.h> #include <wayland-server-core.h>
#include <wlr/backend.h> #include <wlr/backend.h>
#include <wlr/backend/session.h>
#include <wlr/render/allocator.h> #include <wlr/render/allocator.h>
#include <wlr/render/wlr_renderer.h> #include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_data_device.h> #include <wlr/types/wlr_data_device.h>
#include <wlr/types/wlr_input_method_v2.h> #include <wlr/types/wlr_input_method_v2.h>
#include <wlr/types/wlr_foreign_toplevel_management_v1.h> #include <wlr/types/wlr_foreign_toplevel_management_v1.h>
#include <wlr/types/wlr_drm_lease_v1.h>
#include <wlr/types/wlr_layer_shell_v1.h> #include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_output_management_v1.h> #include <wlr/types/wlr_output_management_v1.h>
#include <wlr/types/wlr_output_power_management_v1.h> #include <wlr/types/wlr_output_power_management_v1.h>
@ -22,6 +20,7 @@
#include <wlr/types/wlr_xdg_shell.h> #include <wlr/types/wlr_xdg_shell.h>
#include "config.h" #include "config.h"
#include "list.h" #include "list.h"
#include "sway/desktop/idle_inhibit_v1.h"
#if HAVE_XWAYLAND #if HAVE_XWAYLAND
#include "sway/xwayland.h" #include "sway/xwayland.h"
#endif #endif
@ -34,9 +33,10 @@ struct sway_server {
const char *socket; const char *socket;
struct wlr_backend *backend; struct wlr_backend *backend;
struct wlr_session *session;
// secondary headless backend used for creating virtual outputs on-the-fly // secondary headless backend used for creating virtual outputs on-the-fly
struct wlr_backend *headless_backend; struct wlr_backend *headless_backend;
struct wlr_renderer *wlr_renderer; struct wlr_renderer *renderer;
struct wlr_allocator *allocator; struct wlr_allocator *allocator;
struct wlr_compositor *compositor; struct wlr_compositor *compositor;
@ -51,9 +51,8 @@ struct sway_server {
struct wl_listener new_output; struct wl_listener new_output;
struct wl_listener output_layout_change; struct wl_listener output_layout_change;
struct wlr_idle *idle;
struct wlr_idle_notifier_v1 *idle_notifier_v1; struct wlr_idle_notifier_v1 *idle_notifier_v1;
struct sway_idle_inhibit_manager_v1 *idle_inhibit_manager_v1; struct sway_idle_inhibit_manager_v1 idle_inhibit_manager_v1;
struct wlr_layer_shell_v1 *layer_shell; struct wlr_layer_shell_v1 *layer_shell;
struct wl_listener layer_shell_surface; struct wl_listener layer_shell_surface;
@ -91,6 +90,9 @@ struct sway_server {
struct wl_listener output_manager_apply; struct wl_listener output_manager_apply;
struct wl_listener output_manager_test; struct wl_listener output_manager_test;
struct wlr_gamma_control_manager_v1 *gamma_control_manager_v1;
struct wl_listener gamma_control_set_gamma;
struct { struct {
bool locked; bool locked;
struct wlr_session_lock_manager_v1 *manager; struct wlr_session_lock_manager_v1 *manager;
@ -110,9 +112,17 @@ struct sway_server {
struct wlr_input_method_manager_v2 *input_method; struct wlr_input_method_manager_v2 *input_method;
struct wlr_text_input_manager_v3 *text_input; struct wlr_text_input_manager_v3 *text_input;
struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager; struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager;
struct wlr_content_type_manager_v1 *content_type_manager_v1;
struct wlr_data_control_manager_v1 *data_control_manager_v1;
struct wlr_screencopy_manager_v1 *screencopy_manager_v1;
struct wlr_export_dmabuf_manager_v1 *export_dmabuf_manager_v1;
struct wlr_security_context_manager_v1 *security_context_manager_v1;
struct wlr_xdg_activation_v1 *xdg_activation_v1; struct wlr_xdg_activation_v1 *xdg_activation_v1;
struct wl_listener xdg_activation_v1_request_activate; struct wl_listener xdg_activation_v1_request_activate;
struct wl_listener xdg_activation_v1_new_token;
struct wl_listener request_set_cursor_shape;
struct wl_list pending_launcher_ctxs; // launcher_ctx::link struct wl_list pending_launcher_ctxs; // launcher_ctx::link
@ -174,6 +184,8 @@ void handle_xdg_decoration(struct wl_listener *listener, void *data);
void handle_pointer_constraint(struct wl_listener *listener, void *data); void handle_pointer_constraint(struct wl_listener *listener, void *data);
void xdg_activation_v1_handle_request_activate(struct wl_listener *listener, void xdg_activation_v1_handle_request_activate(struct wl_listener *listener,
void *data); void *data);
void xdg_activation_v1_handle_new_token(struct wl_listener *listener,
void *data);
void set_rr_scheduling(void); void set_rr_scheduling(void);

View file

@ -15,4 +15,10 @@ struct sway_surface {
struct wl_event_source *frame_done_timer; struct wl_event_source *frame_done_timer;
}; };
void surface_update_outputs(struct wlr_surface *surface);
void surface_enter_output(struct wlr_surface *surface,
struct sway_output *output);
void surface_leave_output(struct wlr_surface *surface,
struct sway_output *output);
#endif #endif

View file

@ -1,6 +1,7 @@
#ifndef _SWAY_SWAYNAG_H #ifndef _SWAY_SWAYNAG_H
#define _SWAY_SWAYNAG_H #define _SWAY_SWAYNAG_H
#include <wayland-server-core.h> #include <wayland-server-core.h>
#include "stringop.h"
struct swaynag_instance { struct swaynag_instance {
struct wl_client *client; struct wl_client *client;
@ -21,7 +22,7 @@ bool swaynag_spawn(const char *swaynag_command,
// Write a log message to swaynag->fd[1]. This will fail when swaynag->detailed // Write a log message to swaynag->fd[1]. This will fail when swaynag->detailed
// is false. // is false.
void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag, void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag,
const char *fmt, ...); const char *fmt, ...) _SWAY_ATTRIB_PRINTF(3, 4);
// If swaynag->detailed, close swaynag->fd[1] so swaynag displays // If swaynag->detailed, close swaynag->fd[1] so swaynag displays
void swaynag_show(struct swaynag_instance *swaynag); void swaynag_show(struct swaynag_instance *swaynag);

View file

@ -119,6 +119,11 @@ struct sway_container {
float saturation; float saturation;
// Stores last output size and position for adjusting coordinates of
// scratchpad windows.
// Unused for non-scratchpad windows.
struct wlr_box transform;
float alpha; float alpha;
int corner_radius; int corner_radius;
@ -206,6 +211,9 @@ size_t container_titlebar_height(void);
void floating_calculate_constraints(int *min_width, int *max_width, void floating_calculate_constraints(int *min_width, int *max_width,
int *min_height, int *max_height); int *min_height, int *max_height);
void floating_fix_coordinates(struct sway_container *con,
struct wlr_box *old, struct wlr_box *new);
void container_floating_resize_and_center(struct sway_container *con); void container_floating_resize_and_center(struct sway_container *con);
void container_floating_set_default_size(struct sway_container *con); void container_floating_set_default_size(struct sway_container *con);

View file

@ -1,5 +1,6 @@
#ifndef _SWAY_NODE_H #ifndef _SWAY_NODE_H
#define _SWAY_NODE_H #define _SWAY_NODE_H
#include <wayland-server-core.h>
#include <stdbool.h> #include <stdbool.h>
#include "list.h" #include "list.h"

View file

@ -2,7 +2,7 @@
#define _SWAY_VIEW_H #define _SWAY_VIEW_H
#include <wayland-server-core.h> #include <wayland-server-core.h>
#include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_compositor.h>
#include "config.h" #include "sway/config.h"
#if HAVE_XWAYLAND #if HAVE_XWAYLAND
#include <wlr/xwayland.h> #include <wlr/xwayland.h>
#endif #endif
@ -162,6 +162,8 @@ struct sway_xwayland_view {
struct wl_listener set_window_type; struct wl_listener set_window_type;
struct wl_listener set_hints; struct wl_listener set_hints;
struct wl_listener set_decorations; struct wl_listener set_decorations;
struct wl_listener associate;
struct wl_listener dissociate;
struct wl_listener map; struct wl_listener map;
struct wl_listener unmap; struct wl_listener unmap;
struct wl_listener destroy; struct wl_listener destroy;
@ -179,6 +181,8 @@ struct sway_xwayland_unmanaged {
struct wl_listener request_fullscreen; struct wl_listener request_fullscreen;
struct wl_listener commit; struct wl_listener commit;
struct wl_listener set_geometry; struct wl_listener set_geometry;
struct wl_listener associate;
struct wl_listener dissociate;
struct wl_listener map; struct wl_listener map;
struct wl_listener unmap; struct wl_listener unmap;
struct wl_listener destroy; struct wl_listener destroy;
@ -273,7 +277,12 @@ void view_set_activated(struct sway_view *view, bool activated);
/** /**
* Called when the view requests to be focused. * Called when the view requests to be focused.
*/ */
void view_request_activate(struct sway_view *view); void view_request_activate(struct sway_view *view, struct sway_seat *seat);
/*
* Called when the view requests urgent state
*/
void view_request_urgent(struct sway_view *view);
/** /**
* If possible, instructs the client to change their decoration mode. * If possible, instructs the client to change their decoration mode.

View file

@ -2,6 +2,7 @@
#define _SWAY_WORKSPACE_H #define _SWAY_WORKSPACE_H
#include <stdbool.h> #include <stdbool.h>
#include "sway/config.h"
#include "sway/tree/container.h" #include "sway/tree/container.h"
#include "sway/tree/node.h" #include "sway/tree/node.h"

View file

@ -4,6 +4,7 @@
#include "config.h" #include "config.h"
#include "input.h" #include "input.h"
#include "pool-buffer.h" #include "pool-buffer.h"
#include "cursor-shape-v1-client-protocol.h"
#include "wlr-layer-shell-unstable-v1-client-protocol.h" #include "wlr-layer-shell-unstable-v1-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h" #include "xdg-output-unstable-v1-client-protocol.h"
@ -30,6 +31,7 @@ struct swaybar {
struct wl_compositor *compositor; struct wl_compositor *compositor;
struct zwlr_layer_shell_v1 *layer_shell; struct zwlr_layer_shell_v1 *layer_shell;
struct zxdg_output_manager_v1 *xdg_output_manager; struct zxdg_output_manager_v1 *xdg_output_manager;
struct wp_cursor_shape_manager_v1 *cursor_shape_manager;
struct wl_shm *shm; struct wl_shm *shm;
struct swaybar_config *config; struct swaybar_config *config;

View file

@ -4,6 +4,7 @@
#include <cairo.h> #include <cairo.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <wayland-util.h>
#include "swaybar/tray/tray.h" #include "swaybar/tray/tray.h"
#include "list.h" #include "list.h"

View file

@ -4,6 +4,8 @@
#include <strings.h> #include <strings.h>
#include "list.h" #include "list.h"
#include "pool-buffer.h" #include "pool-buffer.h"
#include "cursor-shape-v1-client-protocol.h"
#include "swaynag/types.h" #include "swaynag/types.h"
#define SWAYNAG_MAX_HEIGHT 500 #define SWAYNAG_MAX_HEIGHT 500
@ -58,6 +60,7 @@ struct swaynag_button {
struct swaynag_details { struct swaynag_details {
bool visible; bool visible;
char *message; char *message;
char *details_text;
int x; int x;
int y; int y;
@ -67,7 +70,7 @@ struct swaynag_details {
int offset; int offset;
int visible_lines; int visible_lines;
int total_lines; int total_lines;
struct swaynag_button button_details; struct swaynag_button *button_details;
struct swaynag_button button_up; struct swaynag_button button_up;
struct swaynag_button button_down; struct swaynag_button button_down;
}; };
@ -84,6 +87,7 @@ struct swaynag {
struct swaynag_output *output; struct swaynag_output *output;
struct zwlr_layer_shell_v1 *layer_shell; struct zwlr_layer_shell_v1 *layer_shell;
struct zwlr_layer_surface_v1 *layer_surface; struct zwlr_layer_surface_v1 *layer_surface;
struct wp_cursor_shape_manager_v1 *cursor_shape_manager;
struct wl_surface *surface; struct wl_surface *surface;
uint32_t width; uint32_t width;

View file

@ -1,10 +1,13 @@
#ifndef _SWAYNAG_TYPES_H #ifndef _SWAYNAG_TYPES_H
#define _SWAYNAG_TYPES_H #define _SWAYNAG_TYPES_H
#include <stdint.h>
#include <pango/pangocairo.h>
#include "list.h"
struct swaynag_type { struct swaynag_type {
char *name; char *name;
char *font; // Used for debugging.
PangoFontDescription *font_description; PangoFontDescription *font_description;
char *output; char *output;
uint32_t anchors; uint32_t anchors;

View file

@ -1,7 +1,7 @@
project( project(
'sway', 'sway',
'c', 'c',
version: '0.3.2', version: '0.3.3',
license: 'MIT', license: 'MIT',
meson_version: '>=0.60.0', meson_version: '>=0.60.0',
default_options: [ default_options: [
@ -18,6 +18,7 @@ add_project_arguments(
'-Wno-unused-parameter', '-Wno-unused-parameter',
'-Wno-unused-result', '-Wno-unused-result',
'-Wno-missing-braces', '-Wno-missing-braces',
'-Wno-format-zero-length',
'-Wundef', '-Wundef',
'-Wvla', '-Wvla',
], ],
@ -35,46 +36,26 @@ if is_freebsd
add_project_arguments('-D_C11_SOURCE', language: 'c') add_project_arguments('-D_C11_SOURCE', language: 'c')
endif endif
# Execute the scenefx subproject, if any
subproject(
'scenefx',
required: false,
)
scenefx = dependency('scenefx')
# Execute the wlroots subproject, if any # Execute the wlroots subproject, if any
wlroots_version = ['>=0.16.0', '<0.17.0'] wlroots_version = ['>=0.17.0', '<0.18.0']
subproject( subproject(
'wlroots', 'wlroots',
default_options: ['examples=false'], default_options: ['examples=false'],
required: false, required: false,
version: wlroots_version, version: wlroots_version,
) )
jsonc = dependency('json-c', version: '>=0.13')
pcre2 = dependency('libpcre2-8')
wayland_server = dependency('wayland-server', version: '>=1.21.0')
wayland_client = dependency('wayland-client')
wayland_cursor = dependency('wayland-cursor')
wayland_egl = dependency('wayland-egl')
egl = dependency('egl')
wayland_protos = dependency('wayland-protocols', version: '>=1.24')
wlroots = dependency('wlroots', version: wlroots_version) wlroots = dependency('wlroots', version: wlroots_version)
xkbcommon = dependency('xkbcommon')
cairo = dependency('cairo')
pango = dependency('pango')
pangocairo = dependency('pangocairo')
gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf'))
pixman = dependency('pixman-1')
glesv2 = dependency('glesv2')
libevdev = dependency('libevdev')
libinput = dependency('libinput', version: '>=1.21.0')
xcb = dependency('xcb', required: get_option('xwayland'))
drm_full = dependency('libdrm') # only needed for drm_fourcc.h
drm = drm_full.partial_dependency(compile_args: true, includes: true)
libudev = dependency('libudev')
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'))
threads = dependency('threads') # for pthread_setschedparam
wlroots_features = { wlroots_features = {
'xwayland': false, 'xwayland': false,
'libinput_backend': false,
'session': false,
} }
foreach name, _ : wlroots_features foreach name, _ : wlroots_features
var_name = 'have_' + name.underscorify() var_name = 'have_' + name.underscorify()
@ -85,6 +66,34 @@ endforeach
if get_option('xwayland').enabled() and not wlroots_features['xwayland'] if get_option('xwayland').enabled() and not wlroots_features['xwayland']
error('Cannot enable Xwayland in sway: wlroots has been built without Xwayland support') error('Cannot enable Xwayland in sway: wlroots has been built without Xwayland support')
endif endif
null_dep = dependency('', required: false)
jsonc = dependency('json-c', version: '>=0.13')
pcre2 = dependency('libpcre2-8')
wayland_server = dependency('wayland-server', version: '>=1.21.0')
wayland_client = dependency('wayland-client')
wayland_cursor = dependency('wayland-cursor')
wayland_egl = dependency('wayland-egl')
egl = dependency('egl')
wayland_protos = dependency('wayland-protocols', version: '>=1.24')
xkbcommon = dependency('xkbcommon', version: '>=1.5.0')
cairo = dependency('cairo')
pango = dependency('pango')
pangocairo = dependency('pangocairo')
gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf'))
pixman = dependency('pixman-1')
libevdev = dependency('libevdev')
libinput = wlroots_features['libinput_backend'] ? dependency('libinput', version: '>=1.21.0') : null_dep
xcb = dependency('xcb', required: get_option('xwayland'))
drm_full = dependency('libdrm') # only needed for drm_fourcc.h
drm = drm_full.partial_dependency(compile_args: true, includes: true)
libudev = wlroots_features['libinput_backend'] ? dependency('libudev') : null_dep
math = cc.find_library('m')
rt = cc.find_library('rt')
xcb_icccm = dependency('xcb-icccm', required: get_option('xwayland'))
threads = dependency('threads') # for pthread_setschedparam
have_xwayland = xcb.found() and xcb_icccm.found() and wlroots_features['xwayland'] have_xwayland = xcb.found() and xcb_icccm.found() and wlroots_features['xwayland']
if get_option('sd-bus-provider') == 'auto' if get_option('sd-bus-provider') == 'auto'
@ -269,59 +278,7 @@ if get_option('default-wallpaper')
install_data(wallpaper_files, install_dir: wallpaper_install_dir) install_data(wallpaper_files, install_dir: wallpaper_install_dir)
endif endif
if get_option('zsh-completions') subdir('completions')
zsh_files = files(
'completions/zsh/_sway',
'completions/zsh/_swaymsg',
)
zsh_install_dir = join_paths(datadir, 'zsh', 'site-functions')
install_data(zsh_files, install_dir: zsh_install_dir)
endif
if get_option('bash-completions')
bash_files = files(
'completions/bash/sway',
'completions/bash/swaymsg',
)
if get_option('swaybar')
bash_files += files('completions/bash/swaybar')
endif
if bash_comp.found()
bash_install_dir = bash_comp.get_variable(
pkgconfig: 'completionsdir',
pkgconfig_define: ['datadir', datadir]
)
else
bash_install_dir = join_paths(datadir, 'bash-completion', 'completions')
endif
install_data(bash_files, install_dir: bash_install_dir)
endif
if get_option('fish-completions')
fish_files = files(
'completions/fish/sway.fish',
'completions/fish/swaymsg.fish',
)
if get_option('swaynag')
fish_files += files('completions/fish/swaynag.fish')
endif
if fish_comp.found()
fish_install_dir = fish_comp.get_variable(
pkgconfig: 'completionsdir',
pkgconfig_define: ['datadir', datadir]
)
else
fish_install_dir = join_paths(datadir, 'fish', 'vendor_completions.d')
endif
install_data(fish_files, install_dir: fish_install_dir)
endif
summary({ summary({
'xwayland': have_xwayland, 'xwayland': have_xwayland,
@ -329,4 +286,3 @@ summary({
'tray': have_tray, 'tray': have_tray,
'man-pages': scdoc.found(), 'man-pages': scdoc.found(),
}, bool_yn: true) }, bool_yn: true)

View file

@ -6,6 +6,6 @@ option('swaybar', type: 'boolean', value: true, description: 'Enable support for
option('swaynag', type: 'boolean', value: true, description: 'Enable support for swaynag') option('swaynag', type: 'boolean', value: true, description: 'Enable support for swaynag')
option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications') option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications')
option('tray', type: 'feature', value: 'auto', description: 'Enable support for swaybar tray') option('tray', type: 'feature', value: 'auto', description: 'Enable support for swaybar tray')
option('gdk-pixbuf', type: 'feature', value: 'auto', description: 'Enable support for more image formats in swaybg') option('gdk-pixbuf', type: 'feature', value: 'auto', description: 'Enable support for more image formats in swaybar tray')
option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages')
option('sd-bus-provider', type: 'combo', choices: ['auto', 'libsystemd', 'libelogind', 'basu'], value: 'auto', description: 'Provider of the sd-bus library') option('sd-bus-provider', type: 'combo', choices: ['auto', 'libsystemd', 'libelogind', 'basu'], value: 'auto', description: 'Provider of the sd-bus library')

View file

@ -2,7 +2,7 @@ wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
wayland_scanner_dep = dependency('wayland-scanner', native: true) wayland_scanner_dep = dependency('wayland-scanner', native: true)
wayland_scanner = find_program( wayland_scanner = find_program(
wayland_scanner_dep.get_variable(pkgconfig: 'wayland_scanner'), wayland_scanner_dep.get_variable('wayland_scanner'),
native: true, native: true,
) )
@ -12,6 +12,8 @@ protocols = [
wl_protocol_dir / 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml', wl_protocol_dir / 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml',
wl_protocol_dir / 'unstable/tablet/tablet-unstable-v2.xml', wl_protocol_dir / 'unstable/tablet/tablet-unstable-v2.xml',
wl_protocol_dir / 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml', wl_protocol_dir / 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml',
wl_protocol_dir / 'staging/content-type/content-type-v1.xml',
wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml',
'wlr-layer-shell-unstable-v1.xml', 'wlr-layer-shell-unstable-v1.xml',
'idle.xml', 'idle.xml',
'wlr-input-inhibitor-unstable-v1.xml', 'wlr-input-inhibitor-unstable-v1.xml',

View file

@ -127,6 +127,7 @@ static const struct cmd_handler config_handlers[] = {
{ "default_orientation", cmd_default_orientation }, { "default_orientation", cmd_default_orientation },
{ "include", cmd_include }, { "include", cmd_include },
{ "scratchpad_minimize", cmd_scratchpad_minimize }, { "scratchpad_minimize", cmd_scratchpad_minimize },
{ "primary_selection", cmd_primary_selection },
{ "swaybg_command", cmd_swaybg_command }, { "swaybg_command", cmd_swaybg_command },
{ "swaynag_command", cmd_swaynag_command }, { "swaynag_command", cmd_swaynag_command },
{ "workspace_layout", cmd_workspace_layout }, { "workspace_layout", cmd_workspace_layout },
@ -171,7 +172,7 @@ static int handler_compare(const void *_a, const void *_b) {
return strcasecmp(a->command, b->command); return strcasecmp(a->command, b->command);
} }
const struct cmd_handler *find_handler(char *line, const struct cmd_handler *find_handler(const char *line,
const struct cmd_handler *handlers, size_t handlers_size) { const struct cmd_handler *handlers, size_t handlers_size) {
if (!handlers || !handlers_size) { if (!handlers || !handlers_size) {
return NULL; return NULL;
@ -404,10 +405,13 @@ struct cmd_results *config_command(char *exec, char **new_block) {
sway_log(SWAY_INFO, "Config command: %s", exec); sway_log(SWAY_INFO, "Config command: %s", exec);
const struct cmd_handler *handler = find_core_handler(argv[0]); const struct cmd_handler *handler = find_core_handler(argv[0]);
if (!handler || !handler->handle) { if (!handler || !handler->handle) {
const char *error = handler if (handler) {
? "Command '%s' is shimmed, but unimplemented" results = cmd_results_new(CMD_INVALID,
: "Unknown/invalid command '%s'"; "Command '%s' is shimmed, but unimplemented", argv[0]);
results = cmd_results_new(CMD_INVALID, error, argv[0]); } else {
results = cmd_results_new(CMD_INVALID,
"Unknown/invalid command '%s'", argv[0]);
}
goto cleanup; goto cleanup;
} }
@ -509,20 +513,10 @@ struct cmd_results *cmd_results_new(enum cmd_status status,
} }
results->status = status; results->status = status;
if (format) { if (format) {
char *error = NULL;
va_list args; va_list args;
va_start(args, format); va_start(args, format);
int slen = vsnprintf(NULL, 0, format, args); results->error = vformat_str(format, args);
va_end(args); va_end(args);
if (slen > 0) {
error = malloc(slen + 1);
if (error != NULL) {
va_start(args, format);
vsnprintf(error, slen + 1, format, args);
va_end(args);
}
}
results->error = error;
} else { } else {
results->error = NULL; results->error = NULL;
} }

View file

@ -17,7 +17,7 @@ struct cmd_results *cmd_assign(int argc, char **argv) {
char *err_str = NULL; char *err_str = NULL;
struct criteria *criteria = criteria_parse(argv[0], &err_str); struct criteria *criteria = criteria_parse(argv[0], &err_str);
if (!criteria) { if (!criteria) {
error = cmd_results_new(CMD_INVALID, err_str); error = cmd_results_new(CMD_INVALID, "%s", err_str);
free(err_str); free(err_str);
return error; return error;
} }

View file

@ -73,12 +73,10 @@ struct cmd_results *cmd_bar(int argc, char **argv) {
} }
++argv; --argc; ++argv; --argc;
} else if (config->reading && !config->current_bar) { } else if (config->reading && !config->current_bar) {
int len = snprintf(NULL, 0, "bar-%d", config->bars->length) + 1; id = format_str("bar-%d", config->bars->length);
id = malloc(len * sizeof(char));
if (!id) { if (!id) {
return cmd_results_new(CMD_FAILURE, "Unable to allocate bar id"); return cmd_results_new(CMD_FAILURE, "Unable to allocate bar id");
} }
snprintf(id, len, "bar-%d", config->bars->length);
} else if (!config->reading && strcmp(argv[0], "mode") != 0 && } else if (!config->reading && strcmp(argv[0], "mode") != 0 &&
strcmp(argv[0], "hidden_state") != 0) { strcmp(argv[0], "hidden_state") != 0) {
if (is_subcommand(argv[0])) { if (is_subcommand(argv[0])) {

View file

@ -96,7 +96,7 @@ static struct cmd_results *bar_cmd_bind(int argc, char **argv, bool code,
} }
if (message) { if (message) {
free_bar_binding(binding); free_bar_binding(binding);
error = cmd_results_new(CMD_INVALID, message); error = cmd_results_new(CMD_INVALID, "%s", message);
free(message); free(message);
return error; return error;
} else if (!binding->button) { } else if (!binding->button) {

View file

@ -26,7 +26,7 @@ static struct cmd_results *tray_bind(int argc, char **argv, bool code) {
} }
if (message) { if (message) {
free(binding); free(binding);
error = cmd_results_new(CMD_INVALID, message); error = cmd_results_new(CMD_INVALID, "%s", message);
free(message); free(message);
return error; return error;
} else if (!binding->button) { } else if (!binding->button) {

View file

@ -127,7 +127,7 @@ static struct cmd_results *identify_key(const char* name, bool first_key,
if (!button) { if (!button) {
if (message) { if (message) {
struct cmd_results *error = struct cmd_results *error =
cmd_results_new(CMD_INVALID, message); cmd_results_new(CMD_INVALID, "%s", message);
free(message); free(message);
return error; return error;
} else { } else {
@ -143,7 +143,7 @@ static struct cmd_results *identify_key(const char* name, bool first_key,
if (!button) { if (!button) {
if (message) { if (message) {
struct cmd_results *error = struct cmd_results *error =
cmd_results_new(CMD_INVALID, message); cmd_results_new(CMD_INVALID, "%s", message);
free(message); free(message);
return error; return error;
} else { } else {
@ -182,7 +182,7 @@ static struct cmd_results *identify_key(const char* name, bool first_key,
uint32_t button = get_mouse_bindsym(name, &message); uint32_t button = get_mouse_bindsym(name, &message);
if (message) { if (message) {
struct cmd_results *error = struct cmd_results *error =
cmd_results_new(CMD_INVALID, message); cmd_results_new(CMD_INVALID, "%s", message);
free(message); free(message);
return error; return error;
} else if (button) { } else if (button) {
@ -539,7 +539,7 @@ struct cmd_results *cmd_bind_or_unbind_switch(int argc, char **argv,
free_switch_binding(binding); free_switch_binding(binding);
return cmd_results_new(CMD_FAILURE, return cmd_results_new(CMD_FAILURE,
"Invalid %s command (expected binding with the form " "Invalid %s command (expected binding with the form "
"<switch>:<state>)", bindtype, argc); "<switch>:<state>)", bindtype);
} }
if (strcmp(split->items[0], "tablet") == 0) { if (strcmp(split->items[0], "tablet") == 0) {
binding->type = WLR_SWITCH_TYPE_TABLET_MODE; binding->type = WLR_SWITCH_TYPE_TABLET_MODE;
@ -549,7 +549,8 @@ struct cmd_results *cmd_bind_or_unbind_switch(int argc, char **argv,
free_switch_binding(binding); free_switch_binding(binding);
return cmd_results_new(CMD_FAILURE, return cmd_results_new(CMD_FAILURE,
"Invalid %s command (expected switch binding: " "Invalid %s command (expected switch binding: "
"unknown switch %s)", bindtype, split->items[0]); "unknown switch %s)", bindtype,
(const char *)split->items[0]);
} }
if (strcmp(split->items[1], "on") == 0) { if (strcmp(split->items[1], "on") == 0) {
binding->trigger = SWAY_SWITCH_TRIGGER_ON; binding->trigger = SWAY_SWITCH_TRIGGER_ON;
@ -562,7 +563,7 @@ struct cmd_results *cmd_bind_or_unbind_switch(int argc, char **argv,
return cmd_results_new(CMD_FAILURE, return cmd_results_new(CMD_FAILURE,
"Invalid %s command " "Invalid %s command "
"(expected switch state: unknown state %s)", "(expected switch state: unknown state %s)",
bindtype, split->items[1]); bindtype, (const char *)split->items[1]);
} }
list_free_items_and_destroy(split); list_free_items_and_destroy(split);

View file

@ -1,3 +1,4 @@
#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h"
#include "sway/commands.h" #include "sway/commands.h"
#include "sway/config.h" #include "sway/config.h"
#include "sway/output.h" #include "sway/output.h"
@ -21,10 +22,10 @@ struct cmd_results *cmd_blur(int argc, char **argv) {
struct sway_output *output; struct sway_output *output;
wl_list_for_each(output, &root->all_outputs, link) { wl_list_for_each(output, &root->all_outputs, link) {
if (output->renderer) { struct fx_effect_framebuffers *effect_fbos =
output->renderer->blur_buffer_dirty = true; fx_effect_framebuffers_try_get(output->wlr_output);
output_damage_whole(output); effect_fbos->blur_buffer_dirty = true;
} output_damage_whole(output);
} }
return cmd_results_new(CMD_SUCCESS, NULL); return cmd_results_new(CMD_SUCCESS, NULL);

View file

@ -1,3 +1,4 @@
#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h"
#include "sway/commands.h" #include "sway/commands.h"
#include "sway/config.h" #include "sway/config.h"
#include "sway/output.h" #include "sway/output.h"
@ -18,10 +19,10 @@ struct cmd_results *cmd_blur_brightness(int argc, char **argv) {
struct sway_output *output; struct sway_output *output;
wl_list_for_each(output, &root->all_outputs, link) { wl_list_for_each(output, &root->all_outputs, link) {
if (output->renderer) { struct fx_effect_framebuffers *effect_fbos =
output->renderer->blur_buffer_dirty = true; fx_effect_framebuffers_try_get(output->wlr_output);
output_damage_whole(output); effect_fbos->blur_buffer_dirty = true;
} output_damage_whole(output);
} }
return cmd_results_new(CMD_SUCCESS, NULL); return cmd_results_new(CMD_SUCCESS, NULL);

View file

@ -1,3 +1,4 @@
#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h"
#include "sway/commands.h" #include "sway/commands.h"
#include "sway/config.h" #include "sway/config.h"
#include "sway/output.h" #include "sway/output.h"
@ -18,10 +19,10 @@ struct cmd_results *cmd_blur_contrast(int argc, char **argv) {
struct sway_output *output; struct sway_output *output;
wl_list_for_each(output, &root->all_outputs, link) { wl_list_for_each(output, &root->all_outputs, link) {
if (output->renderer) { struct fx_effect_framebuffers *effect_fbos =
output->renderer->blur_buffer_dirty = true; fx_effect_framebuffers_try_get(output->wlr_output);
output_damage_whole(output); effect_fbos->blur_buffer_dirty = true;
} output_damage_whole(output);
} }
return cmd_results_new(CMD_SUCCESS, NULL); return cmd_results_new(CMD_SUCCESS, NULL);

View file

@ -1,3 +1,4 @@
#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h"
#include "sway/commands.h" #include "sway/commands.h"
#include "sway/config.h" #include "sway/config.h"
#include "sway/output.h" #include "sway/output.h"
@ -16,13 +17,13 @@ struct cmd_results *cmd_blur_noise(int argc, char **argv) {
config->blur_params.noise = value; config->blur_params.noise = value;
struct sway_output *output; struct sway_output *output;
wl_list_for_each(output, &root->all_outputs, link) { wl_list_for_each(output, &root->all_outputs, link) {
if (output->renderer) { struct fx_effect_framebuffers *effect_fbos =
output->renderer->blur_buffer_dirty = true; fx_effect_framebuffers_try_get(output->wlr_output);
output_damage_whole(output); effect_fbos->blur_buffer_dirty = true;
} output_damage_whole(output);
} }
return cmd_results_new(CMD_SUCCESS, NULL); return cmd_results_new(CMD_SUCCESS, NULL);
} }

View file

@ -1,3 +1,4 @@
#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h"
#include "sway/commands.h" #include "sway/commands.h"
#include "sway/config.h" #include "sway/config.h"
#include "sway/output.h" #include "sway/output.h"
@ -18,10 +19,10 @@ struct cmd_results *cmd_blur_passes(int argc, char **argv) {
struct sway_output *output; struct sway_output *output;
wl_list_for_each(output, &root->all_outputs, link) { wl_list_for_each(output, &root->all_outputs, link) {
if (output->renderer) { struct fx_effect_framebuffers *effect_fbos =
output->renderer->blur_buffer_dirty = true; fx_effect_framebuffers_try_get(output->wlr_output);
output_damage_whole(output); effect_fbos->blur_buffer_dirty = true;
} output_damage_whole(output);
} }
return cmd_results_new(CMD_SUCCESS, NULL); return cmd_results_new(CMD_SUCCESS, NULL);

View file

@ -1,3 +1,4 @@
#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h"
#include "sway/commands.h" #include "sway/commands.h"
#include "sway/config.h" #include "sway/config.h"
#include "sway/output.h" #include "sway/output.h"
@ -18,10 +19,10 @@ struct cmd_results *cmd_blur_radius(int argc, char **argv) {
struct sway_output *output; struct sway_output *output;
wl_list_for_each(output, &root->all_outputs, link) { wl_list_for_each(output, &root->all_outputs, link) {
if (output->renderer) { struct fx_effect_framebuffers *effect_fbos =
output->renderer->blur_buffer_dirty = true; fx_effect_framebuffers_try_get(output->wlr_output);
output_damage_whole(output); effect_fbos->blur_buffer_dirty = true;
} output_damage_whole(output);
} }
return cmd_results_new(CMD_SUCCESS, NULL); return cmd_results_new(CMD_SUCCESS, NULL);

View file

@ -1,3 +1,4 @@
#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h"
#include "sway/commands.h" #include "sway/commands.h"
#include "sway/config.h" #include "sway/config.h"
#include "sway/output.h" #include "sway/output.h"
@ -18,10 +19,10 @@ struct cmd_results *cmd_blur_saturation(int argc, char **argv) {
struct sway_output *output; struct sway_output *output;
wl_list_for_each(output, &root->all_outputs, link) { wl_list_for_each(output, &root->all_outputs, link) {
if (output->renderer) { struct fx_effect_framebuffers *effect_fbos =
output->renderer->blur_buffer_dirty = true; fx_effect_framebuffers_try_get(output->wlr_output);
output_damage_whole(output); effect_fbos->blur_buffer_dirty = true;
} output_damage_whole(output);
} }
return cmd_results_new(CMD_SUCCESS, NULL); return cmd_results_new(CMD_SUCCESS, NULL);

View file

@ -1,3 +1,4 @@
#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h"
#include "sway/commands.h" #include "sway/commands.h"
#include "sway/config.h" #include "sway/config.h"
#include "sway/output.h" #include "sway/output.h"
@ -15,10 +16,10 @@ struct cmd_results *cmd_blur_xray(int argc, char **argv) {
struct sway_output *output; struct sway_output *output;
wl_list_for_each(output, &root->all_outputs, link) { wl_list_for_each(output, &root->all_outputs, link) {
if (output->renderer) { struct fx_effect_framebuffers *effect_fbos =
output->renderer->blur_buffer_dirty = true; fx_effect_framebuffers_try_get(output->wlr_output);
output_damage_whole(output); effect_fbos->blur_buffer_dirty = true;
} output_damage_whole(output);
} }
return cmd_results_new(CMD_SUCCESS, NULL); return cmd_results_new(CMD_SUCCESS, NULL);

View file

@ -9,7 +9,6 @@
#include "sway/config.h" #include "sway/config.h"
#include "sway/server.h" #include "sway/server.h"
#include "sway/desktop/launcher.h" #include "sway/desktop/launcher.h"
#include "sway/server.h"
#include "sway/tree/container.h" #include "sway/tree/container.h"
#include "sway/tree/root.h" #include "sway/tree/root.h"
#include "sway/tree/workspace.h" #include "sway/tree/workspace.h"
@ -64,7 +63,7 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) {
} }
pid_t pid, child; pid_t pid, child;
struct launcher_ctx *ctx = launcher_ctx_create(); struct launcher_ctx *ctx = launcher_ctx_create_internal();
// Fork process // Fork process
if ((pid = fork()) == 0) { if ((pid = fork()) == 0) {
// Fork child process again // Fork child process again

View file

@ -23,16 +23,16 @@ static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name,
char *err; char *err;
int width = (int)strtol(argv[0], &err, 10); int width = (int)strtol(argv[0], &err, 10);
if (*err) { if (*err) {
return cmd_results_new(CMD_INVALID, cmd_name, usage); return cmd_results_new(CMD_INVALID, "%s", usage);
} }
if (strcmp(argv[1], "x") != 0) { if (strcmp(argv[1], "x") != 0) {
return cmd_results_new(CMD_INVALID, cmd_name, usage); return cmd_results_new(CMD_INVALID, "%s", usage);
} }
int height = (int)strtol(argv[2], &err, 10); int height = (int)strtol(argv[2], &err, 10);
if (*err) { if (*err) {
return cmd_results_new(CMD_INVALID, cmd_name, usage); return cmd_results_new(CMD_INVALID, "%s", usage);
} }
*config_width = width; *config_width = width;

View file

@ -33,10 +33,10 @@ struct cmd_results *cmd_font(int argc, char **argv) {
return cmd_results_new(CMD_FAILURE, "Invalid font family."); return cmd_results_new(CMD_FAILURE, "Invalid font family.");
} }
const PangoFontMask flags = pango_font_description_get_set_fields(font_description); const gint size = pango_font_description_get_size(font_description);
if ((flags & PANGO_FONT_MASK_SIZE) == 0) { if (size == 0) {
pango_font_description_free(font_description); pango_font_description_free(font_description);
return cmd_results_new(CMD_FAILURE, "Font size not given."); return cmd_results_new(CMD_FAILURE, "Invalid font size.");
} }
if (config->font_description != NULL) { if (config->font_description != NULL) {

View file

@ -14,7 +14,7 @@ struct cmd_results *cmd_for_window(int argc, char **argv) {
char *err_str = NULL; char *err_str = NULL;
struct criteria *criteria = criteria_parse(argv[0], &err_str); struct criteria *criteria = criteria_parse(argv[0], &err_str);
if (!criteria) { if (!criteria) {
error = cmd_results_new(CMD_INVALID, err_str); error = cmd_results_new(CMD_INVALID, "%s", err_str);
free(err_str); free(err_str);
return error; return error;
} }

View file

@ -20,7 +20,7 @@ struct cmd_results *cmd_hide_edge_borders(int argc, char **argv) {
} }
if (!argc) { if (!argc) {
return cmd_results_new(CMD_INVALID, expected_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
} }
if (strcmp(argv[0], "none") == 0) { if (strcmp(argv[0], "none") == 0) {
@ -38,7 +38,7 @@ struct cmd_results *cmd_hide_edge_borders(int argc, char **argv) {
config->hide_edge_borders = E_NONE; config->hide_edge_borders = E_NONE;
config->hide_edge_borders_smart = ESMART_NO_GAPS; config->hide_edge_borders_smart = ESMART_NO_GAPS;
} else { } else {
return cmd_results_new(CMD_INVALID, expected_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
} }
config->hide_lone_tab = hide_lone_tab; config->hide_lone_tab = hide_lone_tab;

View file

@ -41,7 +41,7 @@ struct cmd_results *cmd_inhibit_idle(int argc, char **argv) {
sway_idle_inhibit_v1_user_inhibitor_destroy(inhibitor); sway_idle_inhibit_v1_user_inhibitor_destroy(inhibitor);
} else { } else {
inhibitor->mode = mode; inhibitor->mode = mode;
sway_idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); sway_idle_inhibit_v1_check_active();
} }
} else if (!clear) { } else if (!clear) {
sway_idle_inhibit_v1_user_inhibitor_register(con->view, mode); sway_idle_inhibit_v1_user_inhibitor_register(con->view, mode);

View file

@ -25,7 +25,9 @@ static const struct cmd_handler input_handlers[] = {
{ "pointer_accel", input_cmd_pointer_accel }, { "pointer_accel", input_cmd_pointer_accel },
{ "repeat_delay", input_cmd_repeat_delay }, { "repeat_delay", input_cmd_repeat_delay },
{ "repeat_rate", input_cmd_repeat_rate }, { "repeat_rate", input_cmd_repeat_rate },
{ "rotation_angle", input_cmd_rotation_angle },
{ "scroll_button", input_cmd_scroll_button }, { "scroll_button", input_cmd_scroll_button },
{ "scroll_button_lock", input_cmd_scroll_button_lock },
{ "scroll_factor", input_cmd_scroll_factor }, { "scroll_factor", input_cmd_scroll_factor },
{ "scroll_method", input_cmd_scroll_method }, { "scroll_method", input_cmd_scroll_method },
{ "tap", input_cmd_tap }, { "tap", input_cmd_tap },

View file

@ -1,14 +1,19 @@
#include <limits.h> #include <limits.h>
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
#include <wlr/backend/libinput.h> #include <wlr/config.h>
#include "sway/config.h" #include "sway/config.h"
#include "sway/commands.h" #include "sway/commands.h"
#include "sway/input/input-manager.h" #include "sway/input/input-manager.h"
#include "log.h" #include "log.h"
#if WLR_HAS_LIBINPUT_BACKEND
#include <wlr/backend/libinput.h>
#endif
static void toggle_supported_send_events_for_device(struct input_config *ic, static void toggle_supported_send_events_for_device(struct input_config *ic,
struct sway_input_device *input_device) { struct sway_input_device *input_device) {
#if WLR_HAS_LIBINPUT_BACKEND
struct wlr_input_device *wlr_device = input_device->wlr_device; struct wlr_input_device *wlr_device = input_device->wlr_device;
if (!wlr_input_device_is_libinput(wlr_device)) { if (!wlr_input_device_is_libinput(wlr_device)) {
return; return;
@ -41,6 +46,7 @@ static void toggle_supported_send_events_for_device(struct input_config *ic,
} }
ic->send_events = mode; ic->send_events = mode;
#endif
} }
static int mode_for_name(const char *name) { static int mode_for_name(const char *name) {
@ -56,6 +62,7 @@ static int mode_for_name(const char *name) {
static void toggle_select_send_events_for_device(struct input_config *ic, static void toggle_select_send_events_for_device(struct input_config *ic,
struct sway_input_device *input_device, int argc, char **argv) { struct sway_input_device *input_device, int argc, char **argv) {
#if WLR_HAS_LIBINPUT_BACKEND
if (!wlr_input_device_is_libinput(input_device->wlr_device)) { if (!wlr_input_device_is_libinput(input_device->wlr_device)) {
return; return;
} }
@ -72,6 +79,7 @@ static void toggle_select_send_events_for_device(struct input_config *ic,
} }
} }
ic->send_events = mode_for_name(argv[index % argc]); ic->send_events = mode_for_name(argv[index % argc]);
#endif
} }
static void toggle_send_events(int argc, char **argv) { static void toggle_send_events(int argc, char **argv) {

View file

@ -11,11 +11,21 @@ static bool parse_coords(const char *str, double *x, double *y, bool *mm) {
*mm = false; *mm = false;
char *end; char *end;
*x = strtod(str, &end);
if (end[0] != 'x') { // Check for "0x" prefix to avoid strtod treating the string as hex
return false; if (str[0] == '0' && str[1] == 'x') {
if (strlen(str) < 3) {
return false;
}
*x = 0;
end = (char *)str + 2;
} else {
*x = strtod(str, &end);
if (end[0] != 'x') {
return false;
}
++end;
} }
++end;
*y = strtod(end, &end); *y = strtod(end, &end);
if (end[0] == 'm') { if (end[0] == 'm') {

View file

@ -49,5 +49,5 @@ struct cmd_results *input_cmd_map_to_region(int argc, char **argv) {
error: error:
free(ic->mapped_to_region); free(ic->mapped_to_region);
ic->mapped_to_region = NULL; ic->mapped_to_region = NULL;
return cmd_results_new(CMD_FAILURE, errstr); return cmd_results_new(CMD_FAILURE, "%s", errstr);
} }

View file

@ -0,0 +1,29 @@
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "sway/config.h"
#include "sway/commands.h"
#include "sway/input/input-manager.h"
#include "util.h"
struct cmd_results *input_cmd_rotation_angle(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "rotation_angle", EXPECTED_AT_LEAST, 1))) {
return error;
}
struct input_config *ic = config->handler_context.input_config;
if (!ic) {
return cmd_results_new(CMD_FAILURE, "No input device defined.");
}
float rotation_angle = parse_float(argv[0]);
if (isnan(rotation_angle)) {
return cmd_results_new(CMD_INVALID,
"Invalid rotation_angle; expected float.");
} if (rotation_angle < 0 || rotation_angle > 360) {
return cmd_results_new(CMD_INVALID, "Input out of range [0, 360)");
}
ic->rotation_angle = rotation_angle;
return cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -21,7 +21,7 @@ struct cmd_results *input_cmd_scroll_button(int argc, char **argv) {
char *message = NULL; char *message = NULL;
uint32_t button = get_mouse_button(*argv, &message); uint32_t button = get_mouse_button(*argv, &message);
if (message) { if (message) {
error = cmd_results_new(CMD_INVALID, message); error = cmd_results_new(CMD_INVALID, "%s", message);
free(message); free(message);
return error; return error;
} else if (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_DOWN } else if (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_DOWN

View file

@ -0,0 +1,26 @@
#include <libinput.h>
#include <string.h>
#include <strings.h>
#include "sway/config.h"
#include "sway/commands.h"
#include "sway/input/input-manager.h"
#include "util.h"
struct cmd_results *input_cmd_scroll_button_lock(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "scroll_button_lock", EXPECTED_AT_LEAST, 1))) {
return error;
}
struct input_config *ic = config->handler_context.input_config;
if (!ic) {
return cmd_results_new(CMD_FAILURE, "No input device defined.");
}
if (parse_boolean(argv[0], true)) {
ic->scroll_button_lock = LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED;
} else {
ic->scroll_button_lock = LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED;
}
return cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -153,7 +153,7 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
workspace->output); workspace->output);
} }
if (new_layout == L_NONE) { if (new_layout == L_NONE) {
return cmd_results_new(CMD_INVALID, expected_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
} }
if (new_layout != old_layout) { if (new_layout != old_layout) {
if (container) { if (container) {

View file

@ -206,9 +206,17 @@ static void container_move_to_workspace(struct sway_container *container,
container_detach(container); container_detach(container);
workspace_add_floating(workspace, container); workspace_add_floating(workspace, container);
container_handle_fullscreen_reparent(container); container_handle_fullscreen_reparent(container);
// If changing output, center it within the workspace // If changing output, adjust the coordinates of the window.
if (old_output != workspace->output && !container->pending.fullscreen_mode) { if (old_output != workspace->output && !container->pending.fullscreen_mode) {
container_floating_move_to_center(container); struct wlr_box workspace_box, old_workspace_box;
workspace_get_box(workspace, &workspace_box);
workspace_get_box(old_workspace, &old_workspace_box);
floating_fix_coordinates(container, &old_workspace_box, &workspace_box);
if (container->scratchpad && workspace->output) {
struct wlr_box output_box;
output_get_box(workspace->output, &output_box);
container->transform = workspace_box;
}
} }
} else { } else {
container_detach(container); container_detach(container);
@ -462,7 +470,7 @@ static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth,
if (strcasecmp(argv[1], "number") == 0) { if (strcasecmp(argv[1], "number") == 0) {
// move [window|container] [to] "workspace number x" // move [window|container] [to] "workspace number x"
if (argc < 3) { if (argc < 3) {
return cmd_results_new(CMD_INVALID, expected_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
} }
if (!isdigit(argv[2][0])) { if (!isdigit(argv[2][0])) {
return cmd_results_new(CMD_INVALID, return cmd_results_new(CMD_INVALID,
@ -522,7 +530,7 @@ static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth,
} }
destination = &dest_con->node; destination = &dest_con->node;
} else { } else {
return cmd_results_new(CMD_INVALID, expected_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
} }
if (destination->type == N_CONTAINER && if (destination->type == N_CONTAINER &&
@ -821,7 +829,7 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) {
} }
if (!argc) { if (!argc) {
return cmd_results_new(CMD_INVALID, expected_position_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_position_syntax);
} }
bool absolute = false; bool absolute = false;
@ -831,19 +839,19 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) {
++argv; ++argv;
} }
if (!argc) { if (!argc) {
return cmd_results_new(CMD_INVALID, expected_position_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_position_syntax);
} }
if (strcmp(argv[0], "position") == 0) { if (strcmp(argv[0], "position") == 0) {
--argc; --argc;
++argv; ++argv;
} }
if (!argc) { if (!argc) {
return cmd_results_new(CMD_INVALID, expected_position_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_position_syntax);
} }
if (strcmp(argv[0], "cursor") == 0 || strcmp(argv[0], "mouse") == 0 || if (strcmp(argv[0], "cursor") == 0 || strcmp(argv[0], "mouse") == 0 ||
strcmp(argv[0], "pointer") == 0) { strcmp(argv[0], "pointer") == 0) {
if (absolute) { if (absolute) {
return cmd_results_new(CMD_INVALID, expected_position_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_position_syntax);
} }
return cmd_move_to_position_pointer(container); return cmd_move_to_position_pointer(container);
} else if (strcmp(argv[0], "center") == 0) { } else if (strcmp(argv[0], "center") == 0) {
@ -865,7 +873,7 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) {
} }
if (argc < 2) { if (argc < 2) {
return cmd_results_new(CMD_FAILURE, expected_position_syntax); return cmd_results_new(CMD_FAILURE, "%s", expected_position_syntax);
} }
struct movement_amount lx = { .amount = 0, .unit = MOVEMENT_UNIT_INVALID }; struct movement_amount lx = { .amount = 0, .unit = MOVEMENT_UNIT_INVALID };
@ -878,7 +886,7 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) {
} }
if (argc < 1) { if (argc < 1) {
return cmd_results_new(CMD_FAILURE, expected_position_syntax); return cmd_results_new(CMD_FAILURE, "%s", expected_position_syntax);
} }
struct movement_amount ly = { .amount = 0, .unit = MOVEMENT_UNIT_INVALID }; struct movement_amount ly = { .amount = 0, .unit = MOVEMENT_UNIT_INVALID };
@ -887,7 +895,7 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) {
argc -= num_consumed_args; argc -= num_consumed_args;
argv += num_consumed_args; argv += num_consumed_args;
if (argc > 0) { if (argc > 0) {
return cmd_results_new(CMD_INVALID, expected_position_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_position_syntax);
} }
if (ly.unit == MOVEMENT_UNIT_INVALID) { if (ly.unit == MOVEMENT_UNIT_INVALID) {
return cmd_results_new(CMD_INVALID, "Invalid y position specified"); return cmd_results_new(CMD_INVALID, "Invalid y position specified");
@ -1033,13 +1041,13 @@ struct cmd_results *cmd_move(int argc, char **argv) {
} }
if (!argc) { if (!argc) {
return cmd_results_new(CMD_INVALID, expected_full_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_full_syntax);
} }
// Only `move [window|container] [to] workspace` supports // Only `move [window|container] [to] workspace` supports
// `--no-auto-back-and-forth` so treat others as invalid syntax // `--no-auto-back-and-forth` so treat others as invalid syntax
if (no_auto_back_and_forth && strcasecmp(argv[0], "workspace") != 0) { if (no_auto_back_and_forth && strcasecmp(argv[0], "workspace") != 0) {
return cmd_results_new(CMD_INVALID, expected_full_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_full_syntax);
} }
if (strcasecmp(argv[0], "workspace") == 0 || if (strcasecmp(argv[0], "workspace") == 0 ||
@ -1053,5 +1061,5 @@ struct cmd_results *cmd_move(int argc, char **argv) {
strcasecmp(argv[1], "position") == 0)) { strcasecmp(argv[1], "position") == 0)) {
return cmd_move_to_position(argc, argv); return cmd_move_to_position(argc, argv);
} }
return cmd_results_new(CMD_INVALID, expected_full_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_full_syntax);
} }

View file

@ -13,7 +13,7 @@ struct cmd_results *cmd_no_focus(int argc, char **argv) {
char *err_str = NULL; char *err_str = NULL;
struct criteria *criteria = criteria_parse(argv[0], &err_str); struct criteria *criteria = criteria_parse(argv[0], &err_str);
if (!criteria) { if (!criteria) {
error = cmd_results_new(CMD_INVALID, err_str); error = cmd_results_new(CMD_INVALID, "%s", err_str);
free(err_str); free(err_str);
return error; return error;
} }

View file

@ -111,7 +111,10 @@ struct cmd_results *cmd_output(int argc, char **argv) {
if (!config->reloading && !config->validating) { if (!config->reloading && !config->validating) {
apply_output_config_to_outputs(output); apply_output_config_to_outputs(output);
if (background) { if (background) {
spawn_swaybg(); if (!spawn_swaybg()) {
return cmd_results_new(CMD_FAILURE,
"Failed to apply background configuration");
}
} }
} }

View file

@ -123,7 +123,10 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
src); src);
config_add_swaynag_warning("Unable to access background file '%s'", config_add_swaynag_warning("Unable to access background file '%s'",
src); src);
struct cmd_results *result = cmd_results_new(CMD_FAILURE,
"unable to access background file '%s'", src);
free(src); free(src);
return result;
} else { } else {
output->background = src; output->background = src;
output->background_option = strdup(mode); output->background_option = strdup(mode);

View file

@ -0,0 +1,23 @@
#include <string.h>
#include <strings.h>
#include "sway/config.h"
#include "sway/commands.h"
#include "util.h"
struct cmd_results *cmd_primary_selection(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "primary_selection", EXPECTED_EQUAL_TO, 1))) {
return error;
}
bool primary_selection = parse_boolean(argv[0], true);
if (config->reloading && config->primary_selection != primary_selection) {
return cmd_results_new(CMD_FAILURE,
"primary_selection can only be enabled/disabled at launch");
}
config->primary_selection = parse_boolean(argv[0], true);
return cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -26,7 +26,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) {
"Can't run this command while there's no outputs connected."); "Can't run this command while there's no outputs connected.");
} }
if (strcasecmp(argv[0], "workspace") != 0) { if (strcasecmp(argv[0], "workspace") != 0) {
return cmd_results_new(CMD_INVALID, expected_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
} }
int argn = 1; int argn = 1;
@ -65,7 +65,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) {
++argn; // move past "to" ++argn; // move past "to"
if (argn >= argc) { if (argn >= argc) {
return cmd_results_new(CMD_INVALID, expected_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
} }
char *new_name = join_args(argv + argn, argc - argn); char *new_name = join_args(argv + argn, argc - argn);

View file

@ -75,6 +75,10 @@ void container_resize_tiled(struct sway_container *con,
return; return;
} }
if (container_is_scratchpad_hidden_or_child(con)) {
return;
}
// For HORIZONTAL or VERTICAL, we are growing in two directions so select // For HORIZONTAL or VERTICAL, we are growing in two directions so select
// both adjacent siblings. For RIGHT or DOWN, just select the next sibling. // both adjacent siblings. For RIGHT or DOWN, just select the next sibling.
// For LEFT or UP, convert it to a RIGHT or DOWN resize and reassign con to // For LEFT or UP, convert it to a RIGHT or DOWN resize and reassign con to
@ -249,16 +253,35 @@ static struct cmd_results *resize_adjust_tiled(uint32_t axis,
struct movement_amount *amount) { struct movement_amount *amount) {
struct sway_container *current = config->handler_context.container; struct sway_container *current = config->handler_context.container;
if (container_is_scratchpad_hidden_or_child(current)) {
return cmd_results_new(CMD_FAILURE, "Cannot resize a hidden scratchpad container");
}
if (amount->unit == MOVEMENT_UNIT_DEFAULT) { if (amount->unit == MOVEMENT_UNIT_DEFAULT) {
amount->unit = MOVEMENT_UNIT_PPT; amount->unit = MOVEMENT_UNIT_PPT;
} }
if (amount->unit == MOVEMENT_UNIT_PPT) { if (amount->unit == MOVEMENT_UNIT_PPT) {
struct sway_container *parent = current->pending.parent;
float pct = amount->amount / 100.0f; float pct = amount->amount / 100.0f;
if (is_horizontal(axis)) { if (is_horizontal(axis)) {
amount->amount = (float)current->pending.width * pct; while (parent && parent->pending.layout != L_HORIZ) {
parent = parent->pending.parent;
}
if (parent) {
amount->amount = (float)parent->pending.width * pct;
} else {
amount->amount = (float)current->pending.workspace->width * pct;
}
} else { } else {
amount->amount = (float)current->pending.height * pct; while (parent && parent->pending.layout != L_VERT) {
parent = parent->pending.parent;
}
if (parent) {
amount->amount = (float)parent->pending.height * pct;
} else {
amount->amount = (float)current->pending.workspace->height * pct;
}
} }
} }
@ -277,6 +300,11 @@ static struct cmd_results *resize_adjust_tiled(uint32_t axis,
*/ */
static struct cmd_results *resize_set_tiled(struct sway_container *con, static struct cmd_results *resize_set_tiled(struct sway_container *con,
struct movement_amount *width, struct movement_amount *height) { struct movement_amount *width, struct movement_amount *height) {
if (container_is_scratchpad_hidden_or_child(con)) {
return cmd_results_new(CMD_FAILURE, "Cannot resize a hidden scratchpad container");
}
if (width->amount) { if (width->amount) {
if (width->unit == MOVEMENT_UNIT_PPT || if (width->unit == MOVEMENT_UNIT_PPT ||
width->unit == MOVEMENT_UNIT_DEFAULT) { width->unit == MOVEMENT_UNIT_DEFAULT) {
@ -415,7 +443,7 @@ static struct cmd_results *cmd_resize_set(int argc, char **argv) {
argc -= num_consumed_args; argc -= num_consumed_args;
argv += num_consumed_args; argv += num_consumed_args;
if (width.unit == MOVEMENT_UNIT_INVALID) { if (width.unit == MOVEMENT_UNIT_INVALID) {
return cmd_results_new(CMD_INVALID, usage); return cmd_results_new(CMD_INVALID, "%s", usage);
} }
} }
@ -427,10 +455,10 @@ static struct cmd_results *cmd_resize_set(int argc, char **argv) {
} }
int num_consumed_args = parse_movement_amount(argc, argv, &height); int num_consumed_args = parse_movement_amount(argc, argv, &height);
if (argc > num_consumed_args) { if (argc > num_consumed_args) {
return cmd_results_new(CMD_INVALID, usage); return cmd_results_new(CMD_INVALID, "%s", usage);
} }
if (width.unit == MOVEMENT_UNIT_INVALID) { if (width.unit == MOVEMENT_UNIT_INVALID) {
return cmd_results_new(CMD_INVALID, usage); return cmd_results_new(CMD_INVALID, "%s", usage);
} }
} }
@ -462,7 +490,7 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv,
"[<amount> px|ppt [or <amount> px|ppt]]'"; "[<amount> px|ppt [or <amount> px|ppt]]'";
uint32_t axis = parse_resize_axis(*argv); uint32_t axis = parse_resize_axis(*argv);
if (axis == WLR_EDGE_NONE) { if (axis == WLR_EDGE_NONE) {
return cmd_results_new(CMD_INVALID, usage); return cmd_results_new(CMD_INVALID, "%s", usage);
} }
--argc; ++argv; --argc; ++argv;
@ -473,7 +501,7 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv,
argc -= num_consumed_args; argc -= num_consumed_args;
argv += num_consumed_args; argv += num_consumed_args;
if (first_amount.unit == MOVEMENT_UNIT_INVALID) { if (first_amount.unit == MOVEMENT_UNIT_INVALID) {
return cmd_results_new(CMD_INVALID, usage); return cmd_results_new(CMD_INVALID, "%s", usage);
} }
} else { } else {
first_amount.amount = 10; first_amount.amount = 10;
@ -483,7 +511,7 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv,
// "or" // "or"
if (argc) { if (argc) {
if (strcmp(*argv, "or") != 0) { if (strcmp(*argv, "or") != 0) {
return cmd_results_new(CMD_INVALID, usage); return cmd_results_new(CMD_INVALID, "%s", usage);
} }
--argc; ++argv; --argc; ++argv;
} }
@ -493,10 +521,10 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv,
if (argc) { if (argc) {
int num_consumed_args = parse_movement_amount(argc, argv, &second_amount); int num_consumed_args = parse_movement_amount(argc, argv, &second_amount);
if (argc > num_consumed_args) { if (argc > num_consumed_args) {
return cmd_results_new(CMD_INVALID, usage); return cmd_results_new(CMD_INVALID, "%s", usage);
} }
if (second_amount.unit == MOVEMENT_UNIT_INVALID) { if (second_amount.unit == MOVEMENT_UNIT_INVALID) {
return cmd_results_new(CMD_INVALID, usage); return cmd_results_new(CMD_INVALID, "%s", usage);
} }
} else { } else {
second_amount.amount = 0; second_amount.amount = 0;
@ -566,5 +594,5 @@ struct cmd_results *cmd_resize(int argc, char **argv) {
const char usage[] = "Expected 'resize <shrink|grow> " const char usage[] = "Expected 'resize <shrink|grow> "
"<width|height|up|down|left|right> [<amount>] [px|ppt]'"; "<width|height|up|down|left|right> [<amount>] [px|ppt]'";
return cmd_results_new(CMD_INVALID, usage); return cmd_results_new(CMD_INVALID, "%s", usage);
} }

View file

@ -18,7 +18,7 @@ static struct cmd_results *handle_command(struct sway_cursor *cursor,
int argc, char **argv) { int argc, char **argv) {
if (strcasecmp(argv[0], "move") == 0) { if (strcasecmp(argv[0], "move") == 0) {
if (argc < 3) { if (argc < 3) {
return cmd_results_new(CMD_INVALID, expected_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
} }
int delta_x = strtol(argv[1], NULL, 10); int delta_x = strtol(argv[1], NULL, 10);
int delta_y = strtol(argv[2], NULL, 10); int delta_y = strtol(argv[2], NULL, 10);
@ -27,7 +27,7 @@ static struct cmd_results *handle_command(struct sway_cursor *cursor,
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
} else if (strcasecmp(argv[0], "set") == 0) { } else if (strcasecmp(argv[0], "set") == 0) {
if (argc < 3) { if (argc < 3) {
return cmd_results_new(CMD_INVALID, expected_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
} }
// map absolute coords (0..1,0..1) to root container coords // map absolute coords (0..1,0..1) to root container coords
float x = strtof(argv[1], NULL) / root->width; float x = strtof(argv[1], NULL) / root->width;
@ -37,7 +37,7 @@ static struct cmd_results *handle_command(struct sway_cursor *cursor,
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
} else { } else {
if (argc < 2) { if (argc < 2) {
return cmd_results_new(CMD_INVALID, expected_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
} }
struct cmd_results *error = NULL; struct cmd_results *error = NULL;
if ((error = press_or_release(cursor, argv[0], argv[1]))) { if ((error = press_or_release(cursor, argv[0], argv[1]))) {
@ -92,14 +92,14 @@ static struct cmd_results *press_or_release(struct sway_cursor *cursor,
} else if (strcasecmp(action, "release") == 0) { } else if (strcasecmp(action, "release") == 0) {
state = WLR_BUTTON_RELEASED; state = WLR_BUTTON_RELEASED;
} else { } else {
return cmd_results_new(CMD_INVALID, expected_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
} }
char *message = NULL; char *message = NULL;
button = get_mouse_button(button_str, &message); button = get_mouse_button(button_str, &message);
if (message) { if (message) {
struct cmd_results *error = struct cmd_results *error =
cmd_results_new(CMD_INVALID, message); cmd_results_new(CMD_INVALID, "%s", message);
free(message); free(message);
return error; return error;
} else if (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_DOWN } else if (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_DOWN

View file

@ -3,6 +3,7 @@
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
#include <stdint.h> #include <stdint.h>
#include "log.h"
#include "sway/commands.h" #include "sway/commands.h"
#include "sway/config.h" #include "sway/config.h"
#include "sway/input/seat.h" #include "sway/input/seat.h"
@ -69,5 +70,10 @@ struct cmd_results *seat_cmd_idle_wake(int argc, char **argv) {
return cmd_results_new(CMD_FAILURE, "Invalid idle source"); return cmd_results_new(CMD_FAILURE, "Invalid idle source");
} }
config->handler_context.seat_config->idle_wake_sources = sources; config->handler_context.seat_config->idle_wake_sources = sources;
sway_log(SWAY_INFO, "Warning: seat idle_wake is deprecated");
if (config->reading) {
config_add_swaynag_warning("seat idle_wake is deprecated. "
"Only seat idle_inhibit is supported.");
}
return cmd_results_new(CMD_SUCCESS, NULL); return cmd_results_new(CMD_SUCCESS, NULL);
} }

View file

@ -4,8 +4,6 @@
#include "sway/tree/arrange.h" #include "sway/tree/arrange.h"
#include "sway/tree/view.h" #include "sway/tree/view.h"
#include "sway/tree/container.h" #include "sway/tree/container.h"
#include "log.h"
#include "stringop.h"
#include "util.h" #include "util.h"
struct cmd_results *cmd_shadows(int argc, char **argv) { struct cmd_results *cmd_shadows(int argc, char **argv) {

View file

@ -2,10 +2,6 @@
#include "sway/commands.h" #include "sway/commands.h"
#include "sway/config.h" #include "sway/config.h"
#include "sway/tree/arrange.h" #include "sway/tree/arrange.h"
#include "sway/tree/view.h"
#include "sway/tree/container.h"
#include "log.h"
#include "stringop.h"
#include "util.h" #include "util.h"
struct cmd_results *cmd_shadows_on_csd(int argc, char **argv) { struct cmd_results *cmd_shadows_on_csd(int argc, char **argv) {

View file

@ -32,7 +32,7 @@ static struct cmd_results *do_split(int layout) {
return cmd_results_new(CMD_SUCCESS, NULL); return cmd_results_new(CMD_SUCCESS, NULL);
} }
static struct cmd_results *do_unsplit() { static struct cmd_results *do_unsplit(void) {
struct sway_container *con = config->handler_context.container; struct sway_container *con = config->handler_context.container;
struct sway_workspace *ws = config->handler_context.workspace; struct sway_workspace *ws = config->handler_context.workspace;

View file

@ -5,6 +5,7 @@
#include "sway/commands.h" #include "sway/commands.h"
#include "sway/output.h" #include "sway/output.h"
#include "sway/tree/arrange.h" #include "sway/tree/arrange.h"
#include "sway/tree/container.h"
#include "sway/tree/root.h" #include "sway/tree/root.h"
#include "sway/tree/view.h" #include "sway/tree/view.h"
#include "sway/tree/workspace.h" #include "sway/tree/workspace.h"
@ -13,180 +14,6 @@
static const char expected_syntax[] = static const char expected_syntax[] =
"Expected 'swap container with id|con_id|mark <arg>'"; "Expected 'swap container with id|con_id|mark <arg>'";
static void swap_places(struct sway_container *con1,
struct sway_container *con2) {
struct sway_container *temp = malloc(sizeof(struct sway_container));
temp->pending.x = con1->pending.x;
temp->pending.y = con1->pending.y;
temp->pending.width = con1->pending.width;
temp->pending.height = con1->pending.height;
temp->width_fraction = con1->width_fraction;
temp->height_fraction = con1->height_fraction;
temp->pending.parent = con1->pending.parent;
temp->pending.workspace = con1->pending.workspace;
bool temp_floating = container_is_floating(con1);
con1->pending.x = con2->pending.x;
con1->pending.y = con2->pending.y;
con1->pending.width = con2->pending.width;
con1->pending.height = con2->pending.height;
con1->width_fraction = con2->width_fraction;
con1->height_fraction = con2->height_fraction;
con2->pending.x = temp->pending.x;
con2->pending.y = temp->pending.y;
con2->pending.width = temp->pending.width;
con2->pending.height = temp->pending.height;
con2->width_fraction = temp->width_fraction;
con2->height_fraction = temp->height_fraction;
int temp_index = container_sibling_index(con1);
if (con2->pending.parent) {
container_insert_child(con2->pending.parent, con1,
container_sibling_index(con2));
} else if (container_is_floating(con2)) {
workspace_add_floating(con2->pending.workspace, con1);
} else {
workspace_insert_tiling(con2->pending.workspace, con1,
container_sibling_index(con2));
}
if (temp->pending.parent) {
container_insert_child(temp->pending.parent, con2, temp_index);
} else if (temp_floating) {
workspace_add_floating(temp->pending.workspace, con2);
} else {
workspace_insert_tiling(temp->pending.workspace, con2, temp_index);
}
free(temp);
}
static void swap_focus(struct sway_container *con1,
struct sway_container *con2, struct sway_seat *seat,
struct sway_container *focus) {
if (focus == con1 || focus == con2) {
struct sway_workspace *ws1 = con1->pending.workspace;
struct sway_workspace *ws2 = con2->pending.workspace;
enum sway_container_layout layout1 = container_parent_layout(con1);
enum sway_container_layout layout2 = container_parent_layout(con2);
if (focus == con1 && (layout2 == L_TABBED || layout2 == L_STACKED)) {
if (workspace_is_visible(ws2)) {
seat_set_focus(seat, &con2->node);
}
seat_set_focus_container(seat, ws1 != ws2 ? con2 : con1);
} else if (focus == con2 && (layout1 == L_TABBED
|| layout1 == L_STACKED)) {
if (workspace_is_visible(ws1)) {
seat_set_focus(seat, &con1->node);
}
seat_set_focus_container(seat, ws1 != ws2 ? con1 : con2);
} else if (ws1 != ws2) {
seat_set_focus_container(seat, focus == con1 ? con2 : con1);
} else {
seat_set_focus_container(seat, focus);
}
} else {
seat_set_focus_container(seat, focus);
}
if (root->fullscreen_global) {
seat_set_focus(seat,
seat_get_focus_inactive(seat, &root->fullscreen_global->node));
}
}
void container_swap(struct sway_container *con1, struct sway_container *con2) {
if (!sway_assert(con1 && con2, "Cannot swap with nothing")) {
return;
}
if (!sway_assert(!container_has_ancestor(con1, con2)
&& !container_has_ancestor(con2, con1),
"Cannot swap ancestor and descendant")) {
return;
}
sway_log(SWAY_DEBUG, "Swapping containers %zu and %zu",
con1->node.id, con2->node.id);
bool scratch1 = con1->scratchpad;
bool hidden1 = container_is_scratchpad_hidden(con1);
bool scratch2 = con2->scratchpad;
bool hidden2 = container_is_scratchpad_hidden(con2);
if (scratch1) {
if (hidden1) {
root_scratchpad_show(con1);
}
root_scratchpad_remove_container(con1);
}
if (scratch2) {
if (hidden2) {
root_scratchpad_show(con2);
}
root_scratchpad_remove_container(con2);
}
enum sway_fullscreen_mode fs1 = con1->pending.fullscreen_mode;
if (fs1) {
container_fullscreen_disable(con1);
}
enum sway_fullscreen_mode fs2 = con2->pending.fullscreen_mode;
if (fs2) {
container_fullscreen_disable(con2);
}
struct sway_seat *seat = config->handler_context.seat;
struct sway_container *focus = seat_get_focused_container(seat);
struct sway_workspace *vis1 =
output_get_active_workspace(con1->pending.workspace->output);
struct sway_workspace *vis2 =
output_get_active_workspace(con2->pending.workspace->output);
if (!sway_assert(vis1 && vis2, "con1 or con2 are on an output without a"
"workspace. This should not happen")) {
return;
}
char *stored_prev_name = NULL;
if (seat->prev_workspace_name) {
stored_prev_name = strdup(seat->prev_workspace_name);
}
swap_places(con1, con2);
if (!workspace_is_visible(vis1)) {
seat_set_focus(seat, seat_get_focus_inactive(seat, &vis1->node));
}
if (!workspace_is_visible(vis2)) {
seat_set_focus(seat, seat_get_focus_inactive(seat, &vis2->node));
}
swap_focus(con1, con2, seat, focus);
if (stored_prev_name) {
free(seat->prev_workspace_name);
seat->prev_workspace_name = stored_prev_name;
}
if (scratch1) {
root_scratchpad_add_container(con2, NULL);
if (!hidden1) {
root_scratchpad_show(con2);
}
}
if (scratch2) {
root_scratchpad_add_container(con1, NULL);
if (!hidden2) {
root_scratchpad_show(con1);
}
}
if (fs1) {
container_set_fullscreen(con2, fs1);
}
if (fs2) {
container_set_fullscreen(con1, fs2);
}
}
static bool test_con_id(struct sway_container *container, void *data) { static bool test_con_id(struct sway_container *container, void *data) {
size_t *con_id = data; size_t *con_id = data;
return container->node.id == *con_id; return container->node.id == *con_id;
@ -219,7 +46,7 @@ struct cmd_results *cmd_swap(int argc, char **argv) {
} }
if (strcasecmp(argv[0], "container") || strcasecmp(argv[1], "with")) { if (strcasecmp(argv[0], "container") || strcasecmp(argv[1], "with")) {
return cmd_results_new(CMD_INVALID, expected_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
} }
struct sway_container *current = config->handler_context.container; struct sway_container *current = config->handler_context.container;
@ -238,7 +65,7 @@ struct cmd_results *cmd_swap(int argc, char **argv) {
other = root_find_container(test_mark, value); other = root_find_container(test_mark, value);
} else { } else {
free(value); free(value);
return cmd_results_new(CMD_INVALID, expected_syntax); return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
} }
if (!other) { if (!other) {

View file

@ -61,7 +61,7 @@ static struct cmd_results *cmd_workspace_gaps(int argc, char **argv,
const char expected[] = "Expected 'workspace <name> gaps " const char expected[] = "Expected 'workspace <name> gaps "
"inner|outer|horizontal|vertical|top|right|bottom|left <px>'"; "inner|outer|horizontal|vertical|top|right|bottom|left <px>'";
if (gaps_location == 0) { if (gaps_location == 0) {
return cmd_results_new(CMD_INVALID, expected); return cmd_results_new(CMD_INVALID, "%s", expected);
} }
struct cmd_results *error = NULL; struct cmd_results *error = NULL;
if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO, if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO,
@ -79,7 +79,7 @@ static struct cmd_results *cmd_workspace_gaps(int argc, char **argv,
char *end; char *end;
int amount = strtol(argv[gaps_location + 2], &end, 10); int amount = strtol(argv[gaps_location + 2], &end, 10);
if (strlen(end)) { if (strlen(end)) {
return cmd_results_new(CMD_FAILURE, expected); return cmd_results_new(CMD_FAILURE, "%s", expected);
} }
bool valid = false; bool valid = false;
@ -110,7 +110,7 @@ static struct cmd_results *cmd_workspace_gaps(int argc, char **argv,
} }
} }
if (!valid) { if (!valid) {
return cmd_results_new(CMD_INVALID, expected); return cmd_results_new(CMD_INVALID, "%s", expected);
} }
// Prevent invalid gaps configurations. // Prevent invalid gaps configurations.
@ -174,7 +174,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
} }
if (root->fullscreen_global) { if (root->fullscreen_global) {
return cmd_results_new(CMD_FAILURE, "workspace", return cmd_results_new(CMD_FAILURE,
"Can't switch workspaces while fullscreen global"); "Can't switch workspaces while fullscreen global");
} }

View file

@ -38,7 +38,7 @@ struct sway_config *config = NULL;
static struct xkb_state *keysym_translation_state_create( static struct xkb_state *keysym_translation_state_create(
struct xkb_rule_names rules) { struct xkb_rule_names rules) {
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_SECURE_GETENV);
struct xkb_keymap *xkb_keymap = xkb_keymap_new_from_names( struct xkb_keymap *xkb_keymap = xkb_keymap_new_from_names(
context, context,
&rules, &rules,
@ -280,6 +280,7 @@ static void config_defaults(struct sway_config *config) {
config->title_align = ALIGN_LEFT; config->title_align = ALIGN_LEFT;
config->tiling_drag = true; config->tiling_drag = true;
config->tiling_drag_threshold = 9; config->tiling_drag_threshold = 9;
config->primary_selection = true;
config->smart_gaps = SMART_GAPS_OFF; config->smart_gaps = SMART_GAPS_OFF;
config->gaps_inner = 0; config->gaps_inner = 0;
@ -511,6 +512,11 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
old_config->xwayland ? "enabled" : "disabled"); old_config->xwayland ? "enabled" : "disabled");
config->xwayland = old_config->xwayland; config->xwayland = old_config->xwayland;
// primary_selection can only be enabled/disabled at launch
sway_log(SWAY_DEBUG, "primary_selection will remain %s",
old_config->primary_selection ? "enabled" : "disabled");
config->primary_selection = old_config->primary_selection;
if (!config->validating) { if (!config->validating) {
if (old_config->swaybg_client != NULL) { if (old_config->swaybg_client != NULL) {
wl_client_destroy(old_config->swaybg_client); wl_client_destroy(old_config->swaybg_client);
@ -960,23 +966,18 @@ void config_add_swaynag_warning(char *fmt, ...) {
if (config->reading && !config->validating) { if (config->reading && !config->validating) {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
size_t length = vsnprintf(NULL, 0, fmt, args) + 1; char *str = vformat_str(fmt, args);
va_end(args); va_end(args);
if (str == NULL) {
char *temp = malloc(length + 1);
if (!temp) {
sway_log(SWAY_ERROR, "Failed to allocate buffer for warning.");
return; return;
} }
va_start(args, fmt);
vsnprintf(temp, length, fmt, args);
va_end(args);
swaynag_log(config->swaynag_command, &config->swaynag_config_errors, swaynag_log(config->swaynag_command, &config->swaynag_config_errors,
"Warning on line %i (%s) '%s': %s", "Warning on line %i (%s) '%s': %s",
config->current_config_line_number, config->current_config_path, config->current_config_line_number, config->current_config_path,
config->current_config_line, temp); config->current_config_line, str);
free(str);
} }
} }
@ -1016,7 +1017,7 @@ char *do_var_replacement(char *str) {
int offset = find - str; int offset = find - str;
strncpy(newptr, str, offset); strncpy(newptr, str, offset);
newptr += offset; newptr += offset;
strncpy(newptr, var->value, vvlen); memcpy(newptr, var->value, vvlen);
newptr += vvlen; newptr += vvlen;
strcpy(newptr, find + vnlen); strcpy(newptr, find + vnlen);
free(str); free(str);

View file

@ -256,7 +256,6 @@ static void invoke_swaybar(struct bar_config *bar) {
} }
sway_log(SWAY_DEBUG, "Spawned swaybar %s", bar->id); sway_log(SWAY_DEBUG, "Spawned swaybar %s", bar->id);
return;
} }
void load_swaybar(struct bar_config *bar) { void load_swaybar(struct bar_config *bar) {

View file

@ -31,9 +31,11 @@ struct input_config *new_input_config(const char* identifier) {
input->middle_emulation = INT_MIN; input->middle_emulation = INT_MIN;
input->natural_scroll = INT_MIN; input->natural_scroll = INT_MIN;
input->accel_profile = INT_MIN; input->accel_profile = INT_MIN;
input->rotation_angle = FLT_MIN;
input->pointer_accel = FLT_MIN; input->pointer_accel = FLT_MIN;
input->scroll_factor = FLT_MIN; input->scroll_factor = FLT_MIN;
input->scroll_button = INT_MIN; input->scroll_button = INT_MIN;
input->scroll_button_lock = INT_MIN;
input->scroll_method = INT_MIN; input->scroll_method = INT_MIN;
input->left_handed = INT_MIN; input->left_handed = INT_MIN;
input->repeat_delay = INT_MIN; input->repeat_delay = INT_MIN;
@ -74,6 +76,9 @@ void merge_input_config(struct input_config *dst, struct input_config *src) {
if (src->natural_scroll != INT_MIN) { if (src->natural_scroll != INT_MIN) {
dst->natural_scroll = src->natural_scroll; dst->natural_scroll = src->natural_scroll;
} }
if (src->rotation_angle != FLT_MIN) {
dst->rotation_angle = src->rotation_angle;
}
if (src->pointer_accel != FLT_MIN) { if (src->pointer_accel != FLT_MIN) {
dst->pointer_accel = src->pointer_accel; dst->pointer_accel = src->pointer_accel;
} }
@ -92,6 +97,9 @@ void merge_input_config(struct input_config *dst, struct input_config *src) {
if (src->scroll_button != INT_MIN) { if (src->scroll_button != INT_MIN) {
dst->scroll_button = src->scroll_button; dst->scroll_button = src->scroll_button;
} }
if (src->scroll_button_lock != INT_MIN) {
dst->scroll_button_lock = src->scroll_button_lock;
}
if (src->send_events != INT_MIN) { if (src->send_events != INT_MIN) {
dst->send_events = src->send_events; dst->send_events = src->send_events;
} }

View file

@ -6,10 +6,10 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#include <wlr/config.h>
#include <wlr/types/wlr_cursor.h> #include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_output_layout.h> #include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output.h> #include <wlr/types/wlr_output.h>
#include <wlr/backend/drm.h>
#include "sway/config.h" #include "sway/config.h"
#include "sway/input/cursor.h" #include "sway/input/cursor.h"
#include "sway/output.h" #include "sway/output.h"
@ -17,6 +17,10 @@
#include "log.h" #include "log.h"
#include "util.h" #include "util.h"
#if WLR_HAS_DRM_BACKEND
#include <wlr/backend/drm.h>
#endif
int output_name_cmp(const void *item, const void *data) { int output_name_cmp(const void *item, const void *data) {
const struct output_config *output = item; const struct output_config *output = item;
const char *name = data; const char *name = data;
@ -149,25 +153,16 @@ static void merge_wildcard_on_all(struct output_config *wildcard) {
} }
static void merge_id_on_name(struct output_config *oc) { static void merge_id_on_name(struct output_config *oc) {
char *id_on_name = NULL; struct sway_output *output = all_output_by_name_or_id(oc->name);
char id[128]; if (output == NULL) {
char *name = NULL; return;
struct sway_output *output;
wl_list_for_each(output, &root->all_outputs, link) {
name = output->wlr_output->name;
output_get_identifier(id, sizeof(id), output);
if (strcmp(name, oc->name) == 0 || strcmp(id, oc->name) == 0) {
size_t length = snprintf(NULL, 0, "%s on %s", id, name) + 1;
id_on_name = malloc(length);
if (!id_on_name) {
sway_log(SWAY_ERROR, "Failed to allocate id on name string");
return;
}
snprintf(id_on_name, length, "%s on %s", id, name);
break;
}
} }
const char *name = output->wlr_output->name;
char id[128];
output_get_identifier(id, sizeof(id), output);
char *id_on_name = format_str("%s on %s", id, name);
if (!id_on_name) { if (!id_on_name) {
return; return;
} }
@ -253,7 +248,9 @@ static void set_mode(struct wlr_output *output, struct wlr_output_state *pending
// Not all floating point integers can be represented exactly // Not all floating point integers can be represented exactly
// as (int)(1000 * mHz / 1000.f) // as (int)(1000 * mHz / 1000.f)
// round() the result to avoid any error // round() the result to avoid any error
int mhz = (int)round(refresh_rate * 1000); int mhz = (int)roundf(refresh_rate * 1000);
// If no target refresh rate is given, match highest available
mhz = mhz <= 0 ? INT_MAX : mhz;
if (wl_list_empty(&output->modes) || custom) { if (wl_list_empty(&output->modes) || custom) {
sway_log(SWAY_DEBUG, "Assigning custom mode to %s", output->name); sway_log(SWAY_DEBUG, "Assigning custom mode to %s", output->name);
@ -263,29 +260,35 @@ static void set_mode(struct wlr_output *output, struct wlr_output_state *pending
} }
struct wlr_output_mode *mode, *best = NULL; struct wlr_output_mode *mode, *best = NULL;
int best_diff_mhz = INT_MAX;
wl_list_for_each(mode, &output->modes, link) { wl_list_for_each(mode, &output->modes, link) {
if (mode->width == width && mode->height == height) { if (mode->width == width && mode->height == height) {
if (mode->refresh == mhz) { int diff_mhz = abs(mode->refresh - mhz);
best = mode; if (diff_mhz < best_diff_mhz) {
break; best_diff_mhz = diff_mhz;
}
if (best == NULL || mode->refresh > best->refresh) {
best = mode; best = mode;
if (best_diff_mhz == 0) {
break;
}
} }
} }
} }
if (!best) { if (best) {
sway_log(SWAY_ERROR, "Configured mode for %s not available", output->name); sway_log(SWAY_INFO, "Assigning configured mode (%dx%d@%.3fHz) to %s",
sway_log(SWAY_INFO, "Picking preferred mode instead"); best->width, best->height, best->refresh / 1000.f, output->name);
best = wlr_output_preferred_mode(output);
} else { } else {
sway_log(SWAY_DEBUG, "Assigning configured mode to %s", output->name); best = wlr_output_preferred_mode(output);
sway_log(SWAY_INFO, "Configured mode (%dx%d@%.3fHz) not available, "
"applying preferred mode (%dx%d@%.3fHz)",
width, height, refresh_rate,
best->width, best->height, best->refresh / 1000.f);
} }
wlr_output_state_set_mode(pending, best); wlr_output_state_set_mode(pending, best);
} }
static void set_modeline(struct wlr_output *output, static void set_modeline(struct wlr_output *output,
struct wlr_output_state *pending, drmModeModeInfo *drm_mode) { struct wlr_output_state *pending, drmModeModeInfo *drm_mode) {
#if WLR_HAS_DRM_BACKEND
if (!wlr_output_is_drm(output)) { if (!wlr_output_is_drm(output)) {
sway_log(SWAY_ERROR, "Modeline can only be set to DRM output"); sway_log(SWAY_ERROR, "Modeline can only be set to DRM output");
return; return;
@ -295,6 +298,9 @@ static void set_modeline(struct wlr_output *output,
if (mode) { if (mode) {
wlr_output_state_set_mode(pending, mode); wlr_output_state_set_mode(pending, mode);
} }
#else
sway_log(SWAY_ERROR, "Modeline can only be set to DRM output");
#endif
} }
/* Some manufacturers hardcode the aspect-ratio of the output in the physical /* Some manufacturers hardcode the aspect-ratio of the output in the physical
@ -436,9 +442,11 @@ static void queue_output_config(struct output_config *oc,
enum wl_output_transform tr = WL_OUTPUT_TRANSFORM_NORMAL; enum wl_output_transform tr = WL_OUTPUT_TRANSFORM_NORMAL;
if (oc && oc->transform >= 0) { if (oc && oc->transform >= 0) {
tr = oc->transform; tr = oc->transform;
#if WLR_HAS_DRM_BACKEND
} else if (wlr_output_is_drm(wlr_output)) { } else if (wlr_output_is_drm(wlr_output)) {
tr = wlr_drm_connector_get_panel_orientation(wlr_output); tr = wlr_drm_connector_get_panel_orientation(wlr_output);
sway_log(SWAY_DEBUG, "Auto-detected output transform: %d", tr); sway_log(SWAY_DEBUG, "Auto-detected output transform: %d", tr);
#endif
} }
if (wlr_output->transform != tr) { if (wlr_output->transform != tr) {
sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, tr); sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, tr);
@ -450,6 +458,16 @@ static void queue_output_config(struct output_config *oc,
float scale; float scale;
if (oc && oc->scale > 0) { if (oc && oc->scale > 0) {
scale = oc->scale; scale = oc->scale;
// The factional-scale-v1 protocol uses increments of 120ths to send
// the scale factor to the client. Adjust the scale so that we use the
// same value as the clients'.
float adjusted_scale = round(scale * 120) / 120;
if (scale != adjusted_scale) {
sway_log(SWAY_INFO, "Adjusting output scale from %f to %f",
scale, adjusted_scale);
scale = adjusted_scale;
}
} else { } else {
scale = compute_default_scale(wlr_output, pending); scale = compute_default_scale(wlr_output, pending);
sway_log(SWAY_DEBUG, "Auto-detected output scale: %f", scale); sway_log(SWAY_DEBUG, "Auto-detected output scale: %f", scale);
@ -499,10 +517,6 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
struct wlr_output_state pending = {0}; struct wlr_output_state pending = {0};
queue_output_config(oc, output, &pending); queue_output_config(oc, output, &pending);
if (!oc || oc->power != 0) {
output->current_mode = pending.mode;
}
sway_log(SWAY_DEBUG, "Committing output %s", wlr_output->name); sway_log(SWAY_DEBUG, "Committing output %s", wlr_output->name);
if (!wlr_output_commit_state(wlr_output, &pending)) { if (!wlr_output_commit_state(wlr_output, &pending)) {
// Failed to commit output changes, maybe the output is missing a CRTC. // Failed to commit output changes, maybe the output is missing a CRTC.
@ -576,7 +590,7 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
// Reconfigure all devices, since input config may have been applied before // Reconfigure all devices, since input config may have been applied before
// this output came online, and some config items (like map_to_output) are // this output came online, and some config items (like map_to_output) are
// dependent on an output being present. // dependent on an output being present.
input_manager_configure_all_inputs(); input_manager_configure_all_input_mappings();
// Reconfigure the cursor images, since the scale may have changed. // Reconfigure the cursor images, since the scale may have changed.
input_manager_configure_xcursor(); input_manager_configure_xcursor();
return true; return true;
@ -619,9 +633,7 @@ static struct output_config *get_output_config(char *identifier,
struct output_config *oc_name = NULL; struct output_config *oc_name = NULL;
struct output_config *oc_id = NULL; struct output_config *oc_id = NULL;
size_t length = snprintf(NULL, 0, "%s on %s", identifier, name) + 1; char *id_on_name = format_str("%s on %s", identifier, name);
char *id_on_name = malloc(length);
snprintf(id_on_name, length, "%s on %s", identifier, name);
int i = list_seq_find(config->output_configs, output_name_cmp, id_on_name); int i = list_seq_find(config->output_configs, output_name_cmp, id_on_name);
if (i >= 0) { if (i >= 0) {
oc_id_on_name = config->output_configs->items[i]; oc_id_on_name = config->output_configs->items[i];
@ -708,12 +720,11 @@ void apply_output_config_to_outputs(struct output_config *oc) {
// this is during startup then there will be no container and config // this is during startup then there will be no container and config
// will be applied during normal "new output" event from wlroots. // will be applied during normal "new output" event from wlroots.
bool wildcard = strcmp(oc->name, "*") == 0; bool wildcard = strcmp(oc->name, "*") == 0;
char id[128];
struct sway_output *sway_output, *tmp; struct sway_output *sway_output, *tmp;
wl_list_for_each_safe(sway_output, tmp, &root->all_outputs, link) { wl_list_for_each_safe(sway_output, tmp, &root->all_outputs, link) {
char *name = sway_output->wlr_output->name; if (output_match_name_or_id(sway_output, oc->name)) {
output_get_identifier(id, sizeof(id), sway_output); char id[128];
if (wildcard || !strcmp(name, oc->name) || !strcmp(id, oc->name)) { output_get_identifier(id, sizeof(id), sway_output);
struct output_config *current = get_output_config(id, sway_output); struct output_config *current = get_output_config(id, sway_output);
if (!current) { if (!current) {
// No stored output config matched, apply oc directly // No stored output config matched, apply oc directly
@ -814,7 +825,9 @@ static bool _spawn_swaybg(char **command) {
setenv("WAYLAND_SOCKET", wayland_socket_str, true); setenv("WAYLAND_SOCKET", wayland_socket_str, true);
execvp(command[0], command); execvp(command[0], command);
sway_log_errno(SWAY_ERROR, "execvp failed"); sway_log_errno(SWAY_ERROR, "failed to execute '%s' "
"(background configuration probably not applied)",
command[0]);
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
_exit(EXIT_SUCCESS); _exit(EXIT_SUCCESS);
@ -824,12 +837,13 @@ static bool _spawn_swaybg(char **command) {
sway_log_errno(SWAY_ERROR, "close failed"); sway_log_errno(SWAY_ERROR, "close failed");
return false; return false;
} }
if (waitpid(pid, NULL, 0) < 0) { int fork_status = 0;
if (waitpid(pid, &fork_status, 0) < 0) {
sway_log_errno(SWAY_ERROR, "waitpid failed"); sway_log_errno(SWAY_ERROR, "waitpid failed");
return false; return false;
} }
return true; return WIFEXITED(fork_status) && WEXITSTATUS(fork_status) == EXIT_SUCCESS;
} }
bool spawn_swaybg(void) { bool spawn_swaybg(void) {

View file

@ -99,7 +99,6 @@ static void seat_attachment_config_free(
struct seat_attachment_config *attachment) { struct seat_attachment_config *attachment) {
free(attachment->identifier); free(attachment->identifier);
free(attachment); free(attachment);
return;
} }
static struct seat_attachment_config *seat_attachment_config_copy( static struct seat_attachment_config *seat_attachment_config_copy(

View file

@ -19,6 +19,7 @@
bool criteria_is_empty(struct criteria *criteria) { bool criteria_is_empty(struct criteria *criteria) {
return !criteria->title return !criteria->title
&& !criteria->shell && !criteria->shell
&& !criteria->all
&& !criteria->app_id && !criteria->app_id
&& !criteria->con_mark && !criteria->con_mark
&& !criteria->con_id && !criteria->con_id
@ -456,6 +457,7 @@ static enum atom_name parse_window_type(const char *type) {
#endif #endif
enum criteria_token { enum criteria_token {
T_ALL,
T_APP_ID, T_APP_ID,
T_CON_ID, T_CON_ID,
T_CON_MARK, T_CON_MARK,
@ -478,7 +480,9 @@ enum criteria_token {
}; };
static enum criteria_token token_from_name(char *name) { static enum criteria_token token_from_name(char *name) {
if (strcmp(name, "app_id") == 0) { if (strcmp(name, "all") == 0) {
return T_ALL;
} else if (strcmp(name, "app_id") == 0) {
return T_APP_ID; return T_APP_ID;
} else if (strcmp(name, "con_id") == 0) { } else if (strcmp(name, "con_id") == 0) {
return T_CON_ID; return T_CON_ID;
@ -524,8 +528,8 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
return false; return false;
} }
// Require value, unless token is floating or tiled // Require value, unless token is all, floating or tiled
if (!value && token != T_FLOATING && token != T_TILING) { if (!value && token != T_ALL && token != T_FLOATING && token != T_TILING) {
const char *fmt = "Token '%s' requires a value"; const char *fmt = "Token '%s' requires a value";
int len = strlen(fmt) + strlen(name) - 1; int len = strlen(fmt) + strlen(name) - 1;
error = malloc(len); error = malloc(len);
@ -535,6 +539,9 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
char *endptr = NULL; char *endptr = NULL;
switch (token) { switch (token) {
case T_ALL:
criteria->all = true;
break;
case T_TITLE: case T_TITLE:
pattern_create(&criteria->title, value); pattern_create(&criteria->title, value);
break; break;

View file

@ -1,89 +0,0 @@
#include "log.h"
#include "sway/desktop/fx_renderer/fx_framebuffer.h"
#include "sway/desktop/fx_renderer/fx_stencilbuffer.h"
#include "sway/desktop/fx_renderer/fx_texture.h"
struct fx_framebuffer fx_framebuffer_create() {
return (struct fx_framebuffer) {
.fb = -1,
.stencil_buffer = fx_stencilbuffer_create(),
.texture = fx_texture_create(),
};
}
void fx_framebuffer_bind(struct fx_framebuffer *buffer) {
glBindFramebuffer(GL_FRAMEBUFFER, buffer->fb);
}
void fx_framebuffer_update(struct fx_framebuffer *buffer, int width, int height) {
bool first_alloc = false;
if (buffer->fb == (uint32_t) -1) {
glGenFramebuffers(1, &buffer->fb);
first_alloc = true;
}
if (buffer->texture.id == 0) {
first_alloc = true;
glGenTextures(1, &buffer->texture.id);
glBindTexture(GL_TEXTURE_2D, buffer->texture.id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
if (first_alloc || buffer->texture.width != width || buffer->texture.height != height) {
glBindTexture(GL_TEXTURE_2D, buffer->texture.id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindFramebuffer(GL_FRAMEBUFFER, buffer->fb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
buffer->texture.id, 0);
buffer->texture.target = GL_TEXTURE_2D;
buffer->texture.has_alpha = false;
buffer->texture.width = width;
buffer->texture.height = height;
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
sway_log(SWAY_ERROR, "Framebuffer incomplete, couldn't create! (FB status: %i)", status);
return;
}
sway_log(SWAY_DEBUG, "Framebuffer created, status %i", status);
}
glBindTexture(GL_TEXTURE_2D, 0);
}
void fx_framebuffer_add_stencil_buffer(struct fx_framebuffer *buffer, int width, int height) {
bool first_alloc = false;
if (buffer->stencil_buffer.rb == (uint32_t) -1) {
glGenRenderbuffers(1, &buffer->stencil_buffer.rb);
first_alloc = true;
}
if (first_alloc || buffer->stencil_buffer.width != width || buffer->stencil_buffer.height != height) {
glBindRenderbuffer(GL_RENDERBUFFER, buffer->stencil_buffer.rb);
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);
buffer->stencil_buffer.width = width;
buffer->stencil_buffer.height = height;
}
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, buffer->stencil_buffer.rb);
}
void fx_framebuffer_release(struct fx_framebuffer *buffer) {
// Release the framebuffer
if (buffer->fb != (uint32_t) -1 && buffer->fb) {
glDeleteFramebuffers(1, &buffer->fb);
}
buffer->fb = -1;
// Release the stencil buffer
fx_stencilbuffer_release(&buffer->stencil_buffer);
// Release the texture
fx_texture_release(&buffer->texture);
}

View file

@ -1,961 +0,0 @@
/*
The original wlr_renderer was heavily referenced in making this project
https://gitlab.freedesktop.org/wlroots/wlroots/-/tree/master/render/gles2
*/
#include <assert.h>
#include <GLES2/gl2.h>
#include <stdlib.h>
#include <wlr/backend.h>
#include <wlr/render/egl.h>
#include <wlr/render/gles2.h>
#include <wlr/types/wlr_matrix.h>
#include <wlr/util/box.h>
#include "log.h"
#include "sway/desktop/fx_renderer/fx_framebuffer.h"
#include "sway/desktop/fx_renderer/fx_renderer.h"
#include "sway/desktop/fx_renderer/fx_stencilbuffer.h"
#include "sway/desktop/fx_renderer/fx_texture.h"
#include "sway/desktop/fx_renderer/matrix.h"
#include "sway/server.h"
// shaders
#include "blur1_frag_src.h"
#include "blur2_frag_src.h"
#include "blur_effects_frag_src.h"
#include "box_shadow_frag_src.h"
#include "common_vert_src.h"
#include "corner_frag_src.h"
#include "quad_frag_src.h"
#include "quad_round_frag_src.h"
#include "stencil_mask_frag_src.h"
#include "tex_frag_src.h"
static const GLfloat verts[] = {
1, 0, // top right
0, 0, // top left
1, 1, // bottom right
0, 1, // bottom left
};
static GLuint compile_shader(GLuint type, const GLchar *src) {
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &src, NULL);
glCompileShader(shader);
GLint ok;
glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
if (ok == GL_FALSE) {
sway_log(SWAY_ERROR, "Failed to compile shader");
glDeleteShader(shader);
shader = 0;
}
return shader;
}
static GLuint link_program(const GLchar *frag_src) {
const GLchar *vert_src = common_vert_src;
GLuint vert = compile_shader(GL_VERTEX_SHADER, vert_src);
if (!vert) {
goto error;
}
GLuint frag = compile_shader(GL_FRAGMENT_SHADER, frag_src);
if (!frag) {
glDeleteShader(vert);
goto error;
}
GLuint prog = glCreateProgram();
glAttachShader(prog, vert);
glAttachShader(prog, frag);
glLinkProgram(prog);
glDetachShader(prog, vert);
glDetachShader(prog, frag);
glDeleteShader(vert);
glDeleteShader(frag);
GLint ok;
glGetProgramiv(prog, GL_LINK_STATUS, &ok);
if (ok == GL_FALSE) {
sway_log(SWAY_ERROR, "Failed to link shader");
glDeleteProgram(prog);
goto error;
}
return prog;
error:
return 0;
}
static bool link_blur_program(struct blur_shader *shader, const char *shader_program) {
GLuint prog;
shader->program = prog = link_program(shader_program);
if (!shader->program) {
return false;
}
shader->proj = glGetUniformLocation(prog, "proj");
shader->tex = glGetUniformLocation(prog, "tex");
shader->pos_attrib = glGetAttribLocation(prog, "pos");
shader->tex_attrib = glGetAttribLocation(prog, "texcoord");
shader->radius = glGetUniformLocation(prog, "radius");
shader->halfpixel = glGetUniformLocation(prog, "halfpixel");
return true;
}
static bool link_blur_effects_program(struct effects_shader *shader, const char *shader_program) {
GLuint prog;
shader->program = prog = link_program(shader_program);
if (!shader->program) {
return false;
}
shader->proj = glGetUniformLocation(prog, "proj");
shader->tex = glGetUniformLocation(prog, "tex");
shader->pos_attrib = glGetAttribLocation(prog, "pos");
shader->tex_attrib = glGetAttribLocation(prog, "texcoord");
shader->noise = glGetUniformLocation(prog, "noise");
shader->brightness = glGetUniformLocation(prog, "brightness");
shader->contrast = glGetUniformLocation(prog, "contrast");
shader->saturation = glGetUniformLocation(prog, "saturation");
return true;
}
static bool link_box_shadow_program(struct box_shadow_shader *shader) {
GLuint prog;
shader->program = prog = link_program(box_shadow_frag_src);
if (!shader->program) {
return false;
}
shader->proj = glGetUniformLocation(prog, "proj");
shader->color = glGetUniformLocation(prog, "color");
shader->pos_attrib = glGetAttribLocation(prog, "pos");
shader->position = glGetUniformLocation(prog, "position");
shader->size = glGetUniformLocation(prog, "size");
shader->blur_sigma = glGetUniformLocation(prog, "blur_sigma");
shader->corner_radius = glGetUniformLocation(prog, "corner_radius");
return true;
}
static bool link_corner_program(struct corner_shader *shader) {
GLuint prog;
shader->program = prog = link_program(corner_frag_src);
if (!shader->program) {
return false;
}
shader->proj = glGetUniformLocation(prog, "proj");
shader->color = glGetUniformLocation(prog, "color");
shader->pos_attrib = glGetAttribLocation(prog, "pos");
shader->position = glGetUniformLocation(prog, "position");
shader->half_size = glGetUniformLocation(prog, "half_size");
shader->half_thickness = glGetUniformLocation(prog, "half_thickness");
shader->radius = glGetUniformLocation(prog, "radius");
shader->is_top_left = glGetUniformLocation(prog, "is_top_left");
shader->is_top_right = glGetUniformLocation(prog, "is_top_right");
shader->is_bottom_left = glGetUniformLocation(prog, "is_bottom_left");
shader->is_bottom_right = glGetUniformLocation(prog, "is_bottom_right");
return true;
}
static bool link_quad_program(struct quad_shader *shader) {
GLuint prog;
shader->program = prog = link_program(quad_frag_src);
if (!shader->program) {
return false;
}
shader->proj = glGetUniformLocation(prog, "proj");
shader->color = glGetUniformLocation(prog, "color");
shader->pos_attrib = glGetAttribLocation(prog, "pos");
return true;
}
static bool link_rounded_quad_program(struct rounded_quad_shader *shader,
enum fx_rounded_quad_shader_source source) {
GLchar quad_src[2048];
snprintf(quad_src, sizeof(quad_src),
"#define SOURCE %d\n%s", source, quad_round_frag_src);
GLuint prog;
shader->program = prog = link_program(quad_src);
if (!shader->program) {
return false;
}
shader->proj = glGetUniformLocation(prog, "proj");
shader->color = glGetUniformLocation(prog, "color");
shader->pos_attrib = glGetAttribLocation(prog, "pos");
shader->size = glGetUniformLocation(prog, "size");
shader->position = glGetUniformLocation(prog, "position");
shader->radius = glGetUniformLocation(prog, "radius");
return true;
}
static bool link_stencil_mask_program(struct stencil_mask_shader *shader) {
GLuint prog;
shader->program = prog = link_program(stencil_mask_frag_src);
if (!shader->program) {
return false;
}
shader->proj = glGetUniformLocation(prog, "proj");
shader->color = glGetUniformLocation(prog, "color");
shader->pos_attrib = glGetAttribLocation(prog, "pos");
shader->position = glGetUniformLocation(prog, "position");
shader->half_size = glGetUniformLocation(prog, "half_size");
shader->radius = glGetUniformLocation(prog, "radius");
return true;
}
static bool link_tex_program(struct tex_shader *shader,
enum fx_tex_shader_source source) {
GLchar frag_src[2048];
snprintf(frag_src, sizeof(frag_src),
"#define SOURCE %d\n%s", source, tex_frag_src);
GLuint prog;
shader->program = prog = link_program(frag_src);
if (!shader->program) {
return false;
}
shader->proj = glGetUniformLocation(prog, "proj");
shader->tex = glGetUniformLocation(prog, "tex");
shader->alpha = glGetUniformLocation(prog, "alpha");
shader->dim = glGetUniformLocation(prog, "dim");
shader->dim_color = glGetUniformLocation(prog, "dim_color");
shader->pos_attrib = glGetAttribLocation(prog, "pos");
shader->tex_attrib = glGetAttribLocation(prog, "texcoord");
shader->size = glGetUniformLocation(prog, "size");
shader->position = glGetUniformLocation(prog, "position");
shader->radius = glGetUniformLocation(prog, "radius");
shader->saturation = glGetUniformLocation(prog, "saturation");
shader->has_titlebar = glGetUniformLocation(prog, "has_titlebar");
shader->discard_transparent = glGetUniformLocation(prog, "discard_transparent");
return true;
}
static bool check_gl_ext(const char *exts, const char *ext) {
size_t extlen = strlen(ext);
const char *end = exts + strlen(exts);
while (exts < end) {
if (exts[0] == ' ') {
exts++;
continue;
}
size_t n = strcspn(exts, " ");
if (n == extlen && strncmp(ext, exts, n) == 0) {
return true;
}
exts += n;
}
return false;
}
static void load_gl_proc(void *proc_ptr, const char *name) {
void *proc = (void *)eglGetProcAddress(name);
if (proc == NULL) {
sway_log(SWAY_ERROR, "GLES2 RENDERER: eglGetProcAddress(%s) failed", name);
abort();
}
*(void **)proc_ptr = proc;
}
struct fx_renderer *fx_renderer_create(struct wlr_egl *egl, struct wlr_output *wlr_output) {
struct fx_renderer *renderer = calloc(1, sizeof(struct fx_renderer));
if (renderer == NULL) {
return NULL;
}
renderer->wlr_output = wlr_output;
// TODO: wlr_egl_make_current or eglMakeCurrent?
// TODO: assert instead of conditional statement?
if (!eglMakeCurrent(wlr_egl_get_display(egl), EGL_NO_SURFACE, EGL_NO_SURFACE,
wlr_egl_get_context(egl))) {
sway_log(SWAY_ERROR, "GLES2 RENDERER: Could not make EGL current");
return NULL;
}
renderer->wlr_buffer = fx_framebuffer_create();
renderer->blur_buffer = fx_framebuffer_create();
renderer->blur_saved_pixels_buffer = fx_framebuffer_create();
renderer->effects_buffer = fx_framebuffer_create();
renderer->effects_buffer_swapped = fx_framebuffer_create();
renderer->blur_buffer_dirty = true;
// get extensions
const char *exts_str = (const char *)glGetString(GL_EXTENSIONS);
if (exts_str == NULL) {
sway_log(SWAY_ERROR, "GLES2 RENDERER: Failed to get GL_EXTENSIONS");
return NULL;
}
sway_log(SWAY_INFO, "Creating swayfx GLES2 renderer");
sway_log(SWAY_INFO, "Using %s", glGetString(GL_VERSION));
sway_log(SWAY_INFO, "GL vendor: %s", glGetString(GL_VENDOR));
sway_log(SWAY_INFO, "GL renderer: %s", glGetString(GL_RENDERER));
sway_log(SWAY_INFO, "Supported GLES2 extensions: %s", exts_str);
// TODO: the rest of the gl checks
if (check_gl_ext(exts_str, "GL_OES_EGL_image_external")) {
renderer->exts.OES_egl_image_external = true;
load_gl_proc(&renderer->procs.glEGLImageTargetTexture2DOES,
"glEGLImageTargetTexture2DOES");
}
// blur shaders
if (!link_blur_program(&renderer->shaders.blur1, blur1_frag_src)) {
goto error;
}
if (!link_blur_program(&renderer->shaders.blur2, blur2_frag_src)) {
goto error;
}
// effects shader
if (!link_blur_effects_program(&renderer->shaders.blur_effects, blur_effects_frag_src)) {
goto error;
}
// box shadow shader
if (!link_box_shadow_program(&renderer->shaders.box_shadow)) {
goto error;
}
// corner border shader
if (!link_corner_program(&renderer->shaders.corner)) {
goto error;
}
// quad fragment shader
if (!link_quad_program(&renderer->shaders.quad)) {
goto error;
}
// rounded quad fragment shaders
if (!link_rounded_quad_program(&renderer->shaders.rounded_quad,
SHADER_SOURCE_QUAD_ROUND)) {
goto error;
}
if (!link_rounded_quad_program(&renderer->shaders.rounded_tl_quad,
SHADER_SOURCE_QUAD_ROUND_TOP_LEFT)) {
goto error;
}
if (!link_rounded_quad_program(&renderer->shaders.rounded_tr_quad,
SHADER_SOURCE_QUAD_ROUND_TOP_RIGHT)) {
goto error;
}
if (!link_rounded_quad_program(&renderer->shaders.rounded_bl_quad,
SHADER_SOURCE_QUAD_ROUND_BOTTOM_LEFT)) {
goto error;
}
if (!link_rounded_quad_program(&renderer->shaders.rounded_br_quad,
SHADER_SOURCE_QUAD_ROUND_BOTTOM_RIGHT)) {
goto error;
}
// stencil mask shader
if (!link_stencil_mask_program(&renderer->shaders.stencil_mask)) {
goto error;
}
// fragment shaders
if (!link_tex_program(&renderer->shaders.tex_rgba, SHADER_SOURCE_TEXTURE_RGBA)) {
goto error;
}
if (!link_tex_program(&renderer->shaders.tex_rgbx, SHADER_SOURCE_TEXTURE_RGBX)) {
goto error;
}
if (!link_tex_program(&renderer->shaders.tex_ext, SHADER_SOURCE_TEXTURE_EXTERNAL)) {
goto error;
}
if (!eglMakeCurrent(wlr_egl_get_display(egl),
EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
sway_log(SWAY_ERROR, "GLES2 RENDERER: Could not unset current EGL");
goto error;
}
sway_log(SWAY_INFO, "GLES2 RENDERER: Shaders Initialized Successfully");
return renderer;
error:
glDeleteProgram(renderer->shaders.blur1.program);
glDeleteProgram(renderer->shaders.blur2.program);
glDeleteProgram(renderer->shaders.blur_effects.program);
glDeleteProgram(renderer->shaders.box_shadow.program);
glDeleteProgram(renderer->shaders.corner.program);
glDeleteProgram(renderer->shaders.quad.program);
glDeleteProgram(renderer->shaders.rounded_quad.program);
glDeleteProgram(renderer->shaders.rounded_bl_quad.program);
glDeleteProgram(renderer->shaders.rounded_br_quad.program);
glDeleteProgram(renderer->shaders.rounded_tl_quad.program);
glDeleteProgram(renderer->shaders.rounded_tr_quad.program);
glDeleteProgram(renderer->shaders.stencil_mask.program);
glDeleteProgram(renderer->shaders.tex_rgba.program);
glDeleteProgram(renderer->shaders.tex_rgbx.program);
glDeleteProgram(renderer->shaders.tex_ext.program);
if (!eglMakeCurrent(wlr_egl_get_display(egl),
EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
sway_log(SWAY_ERROR, "GLES2 RENDERER: Could not unset current EGL");
}
// TODO: more freeing?
free(renderer);
sway_log(SWAY_ERROR, "GLES2 RENDERER: Error Initializing Shaders");
return NULL;
}
void fx_renderer_fini(struct fx_renderer *renderer) {
fx_framebuffer_release(&renderer->blur_buffer);
fx_framebuffer_release(&renderer->blur_saved_pixels_buffer);
fx_framebuffer_release(&renderer->effects_buffer);
fx_framebuffer_release(&renderer->effects_buffer_swapped);
}
void fx_renderer_begin(struct fx_renderer *renderer, int width, int height) {
glViewport(0, 0, width, height);
renderer->viewport_width = width;
renderer->viewport_height = height;
// Store the wlr FBO
renderer->wlr_buffer.fb =
wlr_gles2_renderer_get_current_fbo(renderer->wlr_output->renderer);
// Get the fx_texture
struct wlr_texture *wlr_texture = wlr_texture_from_buffer(
renderer->wlr_output->renderer, renderer->wlr_output->back_buffer);
renderer->wlr_buffer.texture = fx_texture_from_wlr_texture(wlr_texture);
wlr_texture_destroy(wlr_texture);
// Add the stencil to the wlr fbo
fx_framebuffer_add_stencil_buffer(&renderer->wlr_buffer, width, height);
// Create the framebuffers
fx_framebuffer_update(&renderer->blur_saved_pixels_buffer, width, height);
fx_framebuffer_update(&renderer->effects_buffer, width, height);
fx_framebuffer_update(&renderer->effects_buffer_swapped, width, height);
// Add a stencil buffer to the main buffer & bind the main buffer
fx_framebuffer_bind(&renderer->wlr_buffer);
pixman_region32_init(&renderer->blur_padding_region);
// refresh projection matrix
matrix_projection(renderer->projection, width, height,
WL_OUTPUT_TRANSFORM_FLIPPED_180);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
void fx_renderer_end(struct fx_renderer *renderer) {
pixman_region32_fini(&renderer->blur_padding_region);
}
void fx_renderer_clear(const float color[static 4]) {
glClearColor(color[0], color[1], color[2], color[3]);
glClearStencil(0);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
void fx_renderer_scissor(struct wlr_box *box) {
if (box) {
glScissor(box->x, box->y, box->width, box->height);
glEnable(GL_SCISSOR_TEST);
} else {
glDisable(GL_SCISSOR_TEST);
}
}
void fx_renderer_stencil_mask_init() {
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
// Disable writing to color buffer
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
}
void fx_renderer_stencil_mask_close(bool draw_inside_mask) {
// Reenable writing to color buffer
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
if (draw_inside_mask) {
glStencilFunc(GL_EQUAL, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
return;
}
glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
}
void fx_renderer_stencil_mask_fini() {
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
glDisable(GL_STENCIL_TEST);
}
bool fx_render_subtexture_with_matrix(struct fx_renderer *renderer, struct fx_texture *fx_texture,
const struct wlr_fbox *src_box, const struct wlr_box *dst_box, const float matrix[static 9],
struct decoration_data deco_data) {
// Fixes corner radii not being "round" when the radii is larger than
// the height/width
int min_size = MIN(dst_box->height, dst_box->width) * 0.5;
if (deco_data.corner_radius > min_size) {
deco_data.corner_radius = min_size;
}
struct tex_shader *shader = NULL;
switch (fx_texture->target) {
case GL_TEXTURE_2D:
if (fx_texture->has_alpha) {
shader = &renderer->shaders.tex_rgba;
} else {
shader = &renderer->shaders.tex_rgbx;
}
break;
case GL_TEXTURE_EXTERNAL_OES:
shader = &renderer->shaders.tex_ext;
if (!renderer->exts.OES_egl_image_external) {
sway_log(SWAY_ERROR, "Failed to render texture: "
"GL_TEXTURE_EXTERNAL_OES not supported");
return false;
}
break;
default:
sway_log(SWAY_ERROR, "Aborting render");
abort();
}
float gl_matrix[9];
wlr_matrix_multiply(gl_matrix, renderer->projection, matrix);
// OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set
// to GL_FALSE
wlr_matrix_transpose(gl_matrix, gl_matrix);
// if there's no opacity or rounded corners we don't need to blend
if (!fx_texture->has_alpha && deco_data.alpha == 1.0 && !deco_data.corner_radius) {
glDisable(GL_BLEND);
} else {
glEnable(GL_BLEND);
}
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glActiveTexture(GL_TEXTURE0);
glBindTexture(fx_texture->target, fx_texture->id);
glTexParameteri(fx_texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glUseProgram(shader->program);
float* dim_color = deco_data.dim_color;
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, gl_matrix);
glUniform1i(shader->tex, 0);
glUniform2f(shader->size, dst_box->width, dst_box->height);
glUniform2f(shader->position, dst_box->x, dst_box->y);
glUniform1f(shader->alpha, deco_data.alpha);
glUniform1f(shader->dim, deco_data.dim);
glUniform4f(shader->dim_color, dim_color[0], dim_color[1], dim_color[2], dim_color[3]);
glUniform1f(shader->has_titlebar, deco_data.has_titlebar);
glUniform1f(shader->discard_transparent, deco_data.discard_transparent);
glUniform1f(shader->saturation, deco_data.saturation);
glUniform1f(shader->radius, deco_data.corner_radius);
const GLfloat x1 = src_box->x / fx_texture->width;
const GLfloat y1 = src_box->y / fx_texture->height;
const GLfloat x2 = (src_box->x + src_box->width) / fx_texture->width;
const GLfloat y2 = (src_box->y + src_box->height) / fx_texture->height;
const GLfloat texcoord[] = {
x2, y1, // top right
x1, y1, // top left
x2, y2, // bottom right
x1, y2, // bottom left
};
glVertexAttribPointer(shader->pos_attrib, 2, GL_FLOAT, GL_FALSE, 0, verts);
glVertexAttribPointer(shader->tex_attrib, 2, GL_FLOAT, GL_FALSE, 0, texcoord);
glEnableVertexAttribArray(shader->pos_attrib);
glEnableVertexAttribArray(shader->tex_attrib);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(shader->pos_attrib);
glDisableVertexAttribArray(shader->tex_attrib);
glBindTexture(fx_texture->target, 0);
return true;
}
bool fx_render_texture_with_matrix(struct fx_renderer *renderer, struct fx_texture *texture,
const struct wlr_box *dst_box, const float matrix[static 9],
struct decoration_data deco_data) {
struct wlr_fbox src_box = {
.x = 0,
.y = 0,
.width = texture->width,
.height = texture->height,
};
return fx_render_subtexture_with_matrix(renderer, texture, &src_box,
dst_box, matrix, deco_data);
}
void fx_render_rect(struct fx_renderer *renderer, const struct wlr_box *box,
const float color[static 4], const float projection[static 9]) {
if (box->width == 0 || box->height == 0) {
return;
}
assert(box->width > 0 && box->height > 0);
float matrix[9];
wlr_matrix_project_box(matrix, box, WL_OUTPUT_TRANSFORM_NORMAL, 0, projection);
float gl_matrix[9];
wlr_matrix_multiply(gl_matrix, renderer->projection, matrix);
// TODO: investigate why matrix is flipped prior to this cmd
// wlr_matrix_multiply(gl_matrix, flip_180, gl_matrix);
wlr_matrix_transpose(gl_matrix, gl_matrix);
if (color[3] == 1.0) {
glDisable(GL_BLEND);
} else {
glEnable(GL_BLEND);
}
struct quad_shader shader = renderer->shaders.quad;
glUseProgram(shader.program);
glUniformMatrix3fv(shader.proj, 1, GL_FALSE, gl_matrix);
glUniform4f(shader.color, color[0], color[1], color[2], color[3]);
glVertexAttribPointer(shader.pos_attrib, 2, GL_FLOAT, GL_FALSE,
0, verts);
glEnableVertexAttribArray(shader.pos_attrib);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(shader.pos_attrib);
}
void fx_render_rounded_rect(struct fx_renderer *renderer, const struct wlr_box *box,
const float color[static 4], const float matrix[static 9], int radius,
enum corner_location corner_location) {
if (box->width == 0 || box->height == 0) {
return;
}
assert(box->width > 0 && box->height > 0);
// Fixes corner radii not being "round" when the radii is larger than
// the height/width
int min_size = MIN(box->height, box->width) * 0.5;
if (radius > min_size) {
radius = min_size;
}
struct rounded_quad_shader *shader = NULL;
switch (corner_location) {
case ALL:
shader = &renderer->shaders.rounded_quad;
break;
case TOP_LEFT:
shader = &renderer->shaders.rounded_tl_quad;
break;
case TOP_RIGHT:
shader = &renderer->shaders.rounded_tr_quad;
break;
case BOTTOM_LEFT:
shader = &renderer->shaders.rounded_bl_quad;
break;
case BOTTOM_RIGHT:
shader = &renderer->shaders.rounded_br_quad;
break;
default:
sway_log(SWAY_ERROR, "Invalid Corner Location. Aborting render");
abort();
}
float gl_matrix[9];
wlr_matrix_multiply(gl_matrix, renderer->projection, matrix);
// TODO: investigate why matrix is flipped prior to this cmd
// wlr_matrix_multiply(gl_matrix, flip_180, gl_matrix);
wlr_matrix_transpose(gl_matrix, gl_matrix);
glEnable(GL_BLEND);
glUseProgram(shader->program);
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, gl_matrix);
glUniform4f(shader->color, color[0], color[1], color[2], color[3]);
// rounded corners
glUniform2f(shader->size, box->width, box->height);
glUniform2f(shader->position, box->x, box->y);
glUniform1f(shader->radius, radius);
glVertexAttribPointer(shader->pos_attrib, 2, GL_FLOAT, GL_FALSE,
0, verts);
glEnableVertexAttribArray(shader->pos_attrib);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(shader->pos_attrib);
}
void fx_render_border_corner(struct fx_renderer *renderer, const struct wlr_box *box,
const float color[static 4], const float matrix[static 9],
enum corner_location corner_location, int radius, int border_thickness) {
if (border_thickness == 0 || box->width == 0 || box->height == 0) {
return;
}
assert(box->width > 0 && box->height > 0);
// Fixes corner radii not being "round" when the radii is larger than
// the height/width
int min_size = MIN(box->height, box->width) * 0.5;
if (radius > min_size) {
radius = min_size;
}
float gl_matrix[9];
wlr_matrix_multiply(gl_matrix, renderer->projection, matrix);
// TODO: investigate why matrix is flipped prior to this cmd
// wlr_matrix_multiply(gl_matrix, flip_180, gl_matrix);
wlr_matrix_transpose(gl_matrix, gl_matrix);
if (color[3] == 1.0 && !radius) {
glDisable(GL_BLEND);
} else {
glEnable(GL_BLEND);
}
struct corner_shader shader = renderer->shaders.corner;
glUseProgram(shader.program);
glUniformMatrix3fv(shader.proj, 1, GL_FALSE, gl_matrix);
glUniform4f(shader.color, color[0], color[1], color[2], color[3]);
glUniform1f(shader.is_top_left, corner_location == TOP_LEFT);
glUniform1f(shader.is_top_right, corner_location == TOP_RIGHT);
glUniform1f(shader.is_bottom_left, corner_location == BOTTOM_LEFT);
glUniform1f(shader.is_bottom_right, corner_location == BOTTOM_RIGHT);
glUniform2f(shader.position, box->x, box->y);
glUniform1f(shader.radius, radius);
glUniform2f(shader.half_size, box->width / 2.0, box->height / 2.0);
glUniform1f(shader.half_thickness, border_thickness / 2.0);
glVertexAttribPointer(shader.pos_attrib, 2, GL_FLOAT, GL_FALSE,
0, verts);
glEnableVertexAttribArray(shader.pos_attrib);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(shader.pos_attrib);
}
void fx_render_stencil_mask(struct fx_renderer *renderer, const struct wlr_box *box,
const float matrix[static 9], int corner_radius) {
if (box->width == 0 || box->height == 0) {
return;
}
assert(box->width > 0 && box->height > 0);
// Fixes corner radii not being "round" when the radii is larger than
// the height/width
int min_size = MIN(box->height, box->width) * 0.5;
if (corner_radius > min_size) {
corner_radius = min_size;
}
// TODO: just pass gl_matrix?
float gl_matrix[9];
wlr_matrix_multiply(gl_matrix, renderer->projection, matrix);
// TODO: investigate why matrix is flipped prior to this cmd
// wlr_matrix_multiply(gl_matrix, flip_180, gl_matrix);
wlr_matrix_transpose(gl_matrix, gl_matrix);
glEnable(GL_BLEND);
struct stencil_mask_shader shader = renderer->shaders.stencil_mask;
glUseProgram(shader.program);
glUniformMatrix3fv(shader.proj, 1, GL_FALSE, gl_matrix);
glUniform2f(shader.half_size, box->width * 0.5, box->height * 0.5);
glUniform2f(shader.position, box->x, box->y);
glUniform1f(shader.radius, corner_radius);
glVertexAttribPointer(shader.pos_attrib, 2, GL_FLOAT, GL_FALSE,
0, verts);
glEnableVertexAttribArray(shader.pos_attrib);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(shader.pos_attrib);
}
// TODO: alpha input arg?
void fx_render_box_shadow(struct fx_renderer *renderer, const struct wlr_box *box,
const struct wlr_box *inner_box, const float color[static 4],
const float matrix[static 9], int corner_radius, float blur_sigma) {
if (box->width == 0 || box->height == 0) {
return;
}
assert(box->width > 0 && box->height > 0);
// Fixes corner radii not being "round" when the radii is larger than
// the height/width
int min_size = MIN(box->height, box->width) * 0.5;
if (corner_radius > min_size) {
corner_radius = min_size;
}
float gl_matrix[9];
wlr_matrix_multiply(gl_matrix, renderer->projection, matrix);
// TODO: investigate why matrix is flipped prior to this cmd
// wlr_matrix_multiply(gl_matrix, flip_180, gl_matrix);
wlr_matrix_transpose(gl_matrix, gl_matrix);
fx_renderer_stencil_mask_init();
// Draw the rounded rect as a mask
fx_render_stencil_mask(renderer, inner_box, matrix, corner_radius);
fx_renderer_stencil_mask_close(false);
// blending will practically always be needed (unless we have a madman
// who uses opaque shadows with zero sigma), so just enable it
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
struct box_shadow_shader shader = renderer->shaders.box_shadow;
glUseProgram(shader.program);
glUniformMatrix3fv(shader.proj, 1, GL_FALSE, gl_matrix);
glUniform4f(shader.color, color[0], color[1], color[2], color[3]);
glUniform1f(shader.blur_sigma, blur_sigma);
glUniform1f(shader.corner_radius, corner_radius);
glUniform2f(shader.size, box->width, box->height);
glUniform2f(shader.position, box->x, box->y);
glVertexAttribPointer(shader.pos_attrib, 2, GL_FLOAT, GL_FALSE,
0, verts);
glEnableVertexAttribArray(shader.pos_attrib);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(shader.pos_attrib);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
fx_renderer_stencil_mask_fini();
}
void fx_render_blur(struct fx_renderer *renderer, const float matrix[static 9],
struct fx_framebuffer **buffer, struct blur_shader *shader,
const struct wlr_box *box, int blur_radius) {
glDisable(GL_BLEND);
glDisable(GL_STENCIL_TEST);
glActiveTexture(GL_TEXTURE0);
glBindTexture((*buffer)->texture.target, (*buffer)->texture.id);
glTexParameteri((*buffer)->texture.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glUseProgram(shader->program);
// OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set
// to GL_FALSE
float gl_matrix[9];
wlr_matrix_transpose(gl_matrix, matrix);
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, gl_matrix);
glUniform1i(shader->tex, 0);
glUniform1f(shader->radius, blur_radius);
if (shader == &renderer->shaders.blur1) {
glUniform2f(shader->halfpixel, 0.5f / (renderer->viewport_width / 2.0f), 0.5f / (renderer->viewport_height / 2.0f));
} else {
glUniform2f(shader->halfpixel, 0.5f / (renderer->viewport_width * 2.0f), 0.5f / (renderer->viewport_height * 2.0f));
}
glVertexAttribPointer(shader->pos_attrib, 2, GL_FLOAT, GL_FALSE, 0, verts);
glVertexAttribPointer(shader->tex_attrib, 2, GL_FLOAT, GL_FALSE, 0, verts);
glEnableVertexAttribArray(shader->pos_attrib);
glEnableVertexAttribArray(shader->tex_attrib);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(shader->pos_attrib);
glDisableVertexAttribArray(shader->tex_attrib);
}
void fx_render_blur_effects(struct fx_renderer *renderer, const float matrix[static 9],
struct fx_framebuffer **buffer, float blur_noise, float blur_brightness,
float blur_contrast, float blur_saturation) {
struct effects_shader shader = renderer->shaders.blur_effects;
glActiveTexture(GL_TEXTURE0);
glBindTexture((*buffer)->texture.target, (*buffer)->texture.id);
glTexParameteri((*buffer)->texture.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glUseProgram(shader.program);
// OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set
// to GL_FALSE
float gl_matrix[9];
wlr_matrix_transpose(gl_matrix, matrix);
glUniformMatrix3fv(shader.proj, 1, GL_FALSE, gl_matrix);
glUniform1i(shader.tex, 0);
glUniform1f(shader.noise, blur_noise);
glUniform1f(shader.brightness, blur_brightness);
glUniform1f(shader.contrast, blur_contrast);
glUniform1f(shader.saturation, blur_saturation);
glVertexAttribPointer(shader.pos_attrib, 2, GL_FLOAT, GL_FALSE, 0, verts);
glVertexAttribPointer(shader.tex_attrib, 2, GL_FLOAT, GL_FALSE, 0, verts);
glEnableVertexAttribArray(shader.pos_attrib);
glEnableVertexAttribArray(shader.tex_attrib);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(shader.pos_attrib);
glDisableVertexAttribArray(shader.tex_attrib);
}

View file

@ -1,21 +0,0 @@
#include <assert.h>
#include <wlr/render/gles2.h>
#include "sway/desktop/fx_renderer/fx_stencilbuffer.h"
struct fx_stencilbuffer fx_stencilbuffer_create() {
return (struct fx_stencilbuffer) {
.rb = -1,
.width = -1,
.height = -1,
};
}
void fx_stencilbuffer_release(struct fx_stencilbuffer *stencil_buffer) {
if (stencil_buffer->rb != (uint32_t) -1 && stencil_buffer->rb) {
glDeleteRenderbuffers(1, &stencil_buffer->rb);
}
stencil_buffer->rb = -1;
stencil_buffer->width = -1;
stencil_buffer->height = -1;
}

View file

@ -1,37 +0,0 @@
#include <assert.h>
#include <wlr/render/gles2.h>
#include "sway/desktop/fx_renderer/fx_texture.h"
struct fx_texture fx_texture_create() {
return (struct fx_texture) {
.id = 0,
.target = 0,
.width = -1,
.height = -1,
};
}
struct fx_texture fx_texture_from_wlr_texture(struct wlr_texture *texture) {
assert(wlr_texture_is_gles2(texture));
struct wlr_gles2_texture_attribs texture_attrs;
wlr_gles2_texture_get_attribs(texture, &texture_attrs);
return (struct fx_texture) {
.target = texture_attrs.target,
.id = texture_attrs.tex,
.has_alpha = texture_attrs.has_alpha,
.width = texture->width,
.height = texture->height,
};
}
void fx_texture_release(struct fx_texture *texture) {
if (texture->id) {
glDeleteTextures(1, &texture->id);
}
texture->id = 0;
texture->width = -1;
texture->height = -1;
}

View file

@ -1,70 +0,0 @@
#include <math.h>
#include <string.h>
#include <wlr/types/wlr_output.h>
#include "sway/desktop/fx_renderer/matrix.h"
static const float transforms[][9] = {
[WL_OUTPUT_TRANSFORM_NORMAL] = {
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f,
},
[WL_OUTPUT_TRANSFORM_90] = {
0.0f, 1.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f,
},
[WL_OUTPUT_TRANSFORM_180] = {
-1.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, 0.0f, 1.0f,
},
[WL_OUTPUT_TRANSFORM_270] = {
0.0f, -1.0f, 0.0f,
1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f,
},
[WL_OUTPUT_TRANSFORM_FLIPPED] = {
-1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f,
},
[WL_OUTPUT_TRANSFORM_FLIPPED_90] = {
0.0f, 1.0f, 0.0f,
1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f,
},
[WL_OUTPUT_TRANSFORM_FLIPPED_180] = {
1.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, 0.0f, 1.0f,
},
[WL_OUTPUT_TRANSFORM_FLIPPED_270] = {
0.0f, -1.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f,
},
};
void matrix_projection(float mat[static 9], int width, int height,
enum wl_output_transform transform) {
memset(mat, 0, sizeof(*mat) * 9);
const float *t = transforms[transform];
float x = 2.0f / width;
float y = 2.0f / height;
// Rotation + reflection
mat[0] = x * t[0];
mat[1] = x * t[1];
mat[3] = y * -t[3];
mat[4] = y * -t[4];
// Translation
mat[2] = -copysign(1.0f, mat[0] + mat[1]);
mat[5] = -copysign(1.0f, mat[3] + mat[4]);
// Identity
mat[8] = 1.0f;
}

Some files were not shown because too many files have changed in this diff Show more