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:
parent
a5e79676c4
commit
fb86ed6b05
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -2,11 +2,11 @@ install_manifest.txt
|
|||
*.swp
|
||||
*.o
|
||||
*.a
|
||||
.cache/
|
||||
bin/
|
||||
test/
|
||||
build/
|
||||
build-*/
|
||||
.cache/
|
||||
!build-scripts
|
||||
!build-scripts/*
|
||||
.lvimrc
|
||||
|
|
|
@ -99,7 +99,8 @@ Install dependencies:
|
|||
* json-c
|
||||
* pango
|
||||
* cairo
|
||||
* gdk-pixbuf2 (optional: system tray)
|
||||
* gdk-pixbuf2 (optional: additional image formats for system tray)
|
||||
* [swaybg] (optional: wallpaper)
|
||||
* [scdoc] (optional: man pages) \*
|
||||
* git (optional: version info) \*
|
||||
|
||||
|
|
|
@ -12,23 +12,6 @@
|
|||
|
||||
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) {
|
||||
// Clear output in case of failure
|
||||
output->type = GESTURE_TYPE_NONE;
|
||||
|
@ -38,7 +21,7 @@ char *gesture_parse(const char *input, struct gesture *output) {
|
|||
// Split input type, fingers and directions
|
||||
list_t *split = split_string(input, ":");
|
||||
if (split->length < 1 || split->length > 3) {
|
||||
return strformat(
|
||||
return format_str(
|
||||
"expected <gesture>[:<fingers>][:direction], got %s",
|
||||
input);
|
||||
}
|
||||
|
@ -51,8 +34,8 @@ char *gesture_parse(const char *input, struct gesture *output) {
|
|||
} else if (strcmp(split->items[0], "swipe") == 0) {
|
||||
output->type = GESTURE_TYPE_SWIPE;
|
||||
} else {
|
||||
return strformat("expected hold|pinch|swipe, got %s",
|
||||
split->items[0]);
|
||||
return format_str("expected hold|pinch|swipe, got %s",
|
||||
(const char *)split->items[0]);
|
||||
}
|
||||
|
||||
// Parse optional arguments
|
||||
|
@ -67,7 +50,7 @@ char *gesture_parse(const char *input, struct gesture *output) {
|
|||
next = split->length == 3 ? split->items[2] : NULL;
|
||||
} else if (split->length == 3) {
|
||||
// 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
|
||||
|
@ -95,7 +78,7 @@ char *gesture_parse(const char *input, struct gesture *output) {
|
|||
} else if (strcmp(item, "counterclockwise") == 0) {
|
||||
output->directions |= GESTURE_DIRECTION_COUNTERCLOCKWISE;
|
||||
} else {
|
||||
return strformat("expected direction, got %s", item);
|
||||
return format_str("expected direction, got %s", item);
|
||||
}
|
||||
}
|
||||
list_free_items_and_destroy(directions);
|
||||
|
@ -163,7 +146,7 @@ static char *gesture_directions_to_string(uint32_t directions) {
|
|||
if (!result) {
|
||||
result = strdup(name);
|
||||
} else {
|
||||
char *new = strformat("%s+%s", result, name);
|
||||
char *new = format_str("%s+%s", result, name);
|
||||
free(result);
|
||||
result = new;
|
||||
}
|
||||
|
@ -179,7 +162,7 @@ static char *gesture_directions_to_string(uint32_t directions) {
|
|||
|
||||
char *gesture_to_string(struct gesture *gesture) {
|
||||
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->fingers, directions);
|
||||
free(directions);
|
||||
|
|
|
@ -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, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
// Add one since vsnprintf excludes null terminator.
|
||||
int length = vsnprintf(NULL, 0, fmt, args) + 1;
|
||||
char *buf = vformat_str(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
char *buf = malloc(length);
|
||||
if (buf == NULL) {
|
||||
sway_log(SWAY_ERROR, "Failed to allocate memory");
|
||||
return;
|
||||
}
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, length, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
PangoLayout *layout = get_pango_layout(cairo, desc, buf, scale, markup);
|
||||
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;
|
||||
}
|
||||
g_object_unref(layout);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
|
@ -125,18 +119,11 @@ void render_text(cairo_t *cairo, const PangoFontDescription *desc,
|
|||
double scale, bool markup, const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
// Add one since vsnprintf excludes null terminator.
|
||||
int length = vsnprintf(NULL, 0, fmt, args) + 1;
|
||||
char *buf = vformat_str(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
char *buf = malloc(length);
|
||||
if (buf == NULL) {
|
||||
sway_log(SWAY_ERROR, "Failed to allocate memory");
|
||||
return;
|
||||
}
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, length, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
PangoLayout *layout = get_pango_layout(cairo, desc, buf, scale, markup);
|
||||
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_show_layout(cairo, layout);
|
||||
g_object_unref(layout);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -328,3 +329,35 @@ bool expand_path(char **path) {
|
|||
wordfree(&p);
|
||||
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
57
completions/meson.build
Normal 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
|
|
@ -18,7 +18,7 @@ set $term foot
|
|||
# Your preferred application launcher
|
||||
# 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.
|
||||
set $menu dmenu_path | dmenu | xargs swaymsg exec --
|
||||
set $menu dmenu_path | wmenu | xargs swaymsg exec --
|
||||
|
||||
### Appearance
|
||||
# window corner radius in px
|
||||
|
@ -228,7 +228,7 @@ bar {
|
|||
|
||||
# When the status_command prints a new line to stdout, swaybar updates.
|
||||
# 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 {
|
||||
statusline #ffffff
|
||||
|
|
|
@ -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()
|
||||
|
168
contrib/grimshot
168
contrib/grimshot
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
|
@ -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()
|
|
@ -44,7 +44,7 @@
|
|||
name = "swayfx-shell";
|
||||
inputsFrom = [
|
||||
self.packages.${system}.swayfx-unwrapped
|
||||
pkgs.wlroots_0_16
|
||||
pkgs.wlroots_0_17
|
||||
];
|
||||
nativeBuildInputs = with pkgs; [
|
||||
cmake
|
||||
|
@ -55,7 +55,7 @@
|
|||
shellHook = with pkgs; ''
|
||||
(
|
||||
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
|
||||
)'';
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <stdint.h>
|
||||
#include <cairo.h>
|
||||
#include <pango/pangocairo.h>
|
||||
#include "stringop.h"
|
||||
|
||||
/**
|
||||
* 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,
|
||||
const char *text, double scale, bool markup);
|
||||
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 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
|
||||
|
|
|
@ -5,6 +5,12 @@
|
|||
#include <stddef.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_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 ~
|
||||
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
|
||||
|
|
|
@ -3,13 +3,14 @@
|
|||
|
||||
#include <wlr/util/edges.h>
|
||||
#include "config.h"
|
||||
#include "stringop.h"
|
||||
|
||||
struct sway_container;
|
||||
|
||||
typedef struct cmd_results *sway_cmd(int argc, char **argv);
|
||||
|
||||
struct cmd_handler {
|
||||
char *command;
|
||||
const char *command;
|
||||
sway_cmd *handle;
|
||||
};
|
||||
|
||||
|
@ -46,7 +47,7 @@ enum expected_args {
|
|||
struct cmd_results *checkarg(int argc, const char *name,
|
||||
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);
|
||||
|
||||
/**
|
||||
|
@ -76,7 +77,7 @@ struct cmd_results *config_commands_command(char *exec);
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
@ -174,8 +175,6 @@ sway_cmd cmd_max_render_time;
|
|||
sway_cmd cmd_mode;
|
||||
sway_cmd cmd_mouse_warping;
|
||||
sway_cmd cmd_move;
|
||||
sway_cmd cmd_new_float;
|
||||
sway_cmd cmd_new_window;
|
||||
sway_cmd cmd_nop;
|
||||
sway_cmd cmd_opacity;
|
||||
sway_cmd cmd_saturation;
|
||||
|
@ -185,6 +184,7 @@ sway_cmd cmd_no_focus;
|
|||
sway_cmd cmd_output;
|
||||
sway_cmd cmd_permit;
|
||||
sway_cmd cmd_popup_during_fullscreen;
|
||||
sway_cmd cmd_primary_selection;
|
||||
sway_cmd cmd_reject;
|
||||
sway_cmd cmd_reload;
|
||||
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_natural_scroll;
|
||||
sway_cmd input_cmd_pointer_accel;
|
||||
sway_cmd input_cmd_rotation_angle;
|
||||
sway_cmd input_cmd_scroll_factor;
|
||||
sway_cmd input_cmd_repeat_delay;
|
||||
sway_cmd input_cmd_repeat_rate;
|
||||
sway_cmd input_cmd_scroll_button;
|
||||
sway_cmd input_cmd_scroll_button_lock;
|
||||
sway_cmd input_cmd_scroll_method;
|
||||
sway_cmd input_cmd_tap;
|
||||
sway_cmd input_cmd_tap_button_map;
|
||||
|
|
|
@ -12,8 +12,10 @@
|
|||
#include "../include/config.h"
|
||||
#include "gesture.h"
|
||||
#include "list.h"
|
||||
#include "stringop.h"
|
||||
#include "swaynag.h"
|
||||
#include "tree/container.h"
|
||||
#include "scenefx/types/fx/blur_data.h"
|
||||
#include "sway/input/tablet.h"
|
||||
#include "sway/tree/root.h"
|
||||
#include "wlr-layer-shell-unstable-v1-protocol.h"
|
||||
|
@ -155,10 +157,12 @@ struct input_config {
|
|||
int middle_emulation;
|
||||
int natural_scroll;
|
||||
float pointer_accel;
|
||||
float rotation_angle;
|
||||
float scroll_factor;
|
||||
int repeat_delay;
|
||||
int repeat_rate;
|
||||
int scroll_button;
|
||||
int scroll_button_lock;
|
||||
int scroll_method;
|
||||
int send_events;
|
||||
int tap;
|
||||
|
@ -470,15 +474,6 @@ enum xwayland_mode {
|
|||
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.
|
||||
*/
|
||||
|
@ -501,7 +496,7 @@ struct sway_config {
|
|||
|
||||
bool blur_enabled;
|
||||
bool blur_xray;
|
||||
struct blur_parameters blur_params;
|
||||
struct blur_data blur_params;
|
||||
|
||||
bool titlebar_separator;
|
||||
bool scratchpad_minimize;
|
||||
|
@ -564,6 +559,7 @@ struct sway_config {
|
|||
bool auto_back_and_forth;
|
||||
bool show_marks;
|
||||
enum alignment title_align;
|
||||
bool primary_selection;
|
||||
|
||||
bool tiling_drag;
|
||||
int tiling_drag_threshold;
|
||||
|
@ -657,7 +653,7 @@ void run_deferred_bindings(void);
|
|||
/**
|
||||
* 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
|
||||
|
|
|
@ -43,6 +43,7 @@ struct criteria {
|
|||
struct pattern *window_role;
|
||||
enum atom_name window_type;
|
||||
#endif
|
||||
bool all;
|
||||
bool floating;
|
||||
bool tiling;
|
||||
char urgent; // 'l' for latest or 'o' for oldest
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1,8 +1,6 @@
|
|||
#ifndef _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.h>
|
||||
#include "sway/server.h"
|
||||
|
||||
enum sway_idle_inhibit_mode {
|
||||
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 wl_listener new_idle_inhibitor_v1;
|
||||
struct wl_list inhibitors;
|
||||
|
||||
struct wlr_idle *idle;
|
||||
};
|
||||
|
||||
struct sway_idle_inhibitor_v1 {
|
||||
struct sway_idle_inhibit_manager_v1 *manager;
|
||||
struct wlr_idle_inhibitor_v1 *wlr_inhibitor;
|
||||
struct sway_view *view;
|
||||
enum sway_idle_inhibit_mode mode;
|
||||
|
@ -33,8 +28,7 @@ struct sway_idle_inhibitor_v1 {
|
|||
bool sway_idle_inhibit_v1_is_active(
|
||||
struct sway_idle_inhibitor_v1 *inhibitor);
|
||||
|
||||
void sway_idle_inhibit_v1_check_active(
|
||||
struct sway_idle_inhibit_manager_v1 *manager);
|
||||
void sway_idle_inhibit_v1_check_active(void);
|
||||
|
||||
void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view,
|
||||
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(
|
||||
struct sway_idle_inhibitor_v1 *inhibitor);
|
||||
|
||||
struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create(
|
||||
struct wl_display *wl_display, struct wlr_idle *idle);
|
||||
bool sway_idle_inhibit_manager_v1_init(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,14 +2,19 @@
|
|||
#define _SWAY_LAUNCHER_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include "sway/input/seat.h"
|
||||
|
||||
struct launcher_ctx {
|
||||
pid_t pid;
|
||||
char *name;
|
||||
char *fallback_name;
|
||||
struct wlr_xdg_activation_token_v1 *token;
|
||||
struct wl_listener token_destroy;
|
||||
struct sway_seat *seat;
|
||||
struct wl_listener seat_destroy;
|
||||
|
||||
bool activated;
|
||||
bool had_focused_surface;
|
||||
|
||||
struct sway_node *node;
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@ struct sway_cursor {
|
|||
pixman_region32_t confine; // invalid if active_constraint == NULL
|
||||
bool active_confine_requires_warp;
|
||||
|
||||
struct wlr_pointer_gestures_v1 *pointer_gestures;
|
||||
struct wl_listener hold_begin;
|
||||
struct wl_listener hold_end;
|
||||
struct wl_listener pinch_begin;
|
||||
|
@ -53,6 +52,7 @@ struct sway_cursor {
|
|||
|
||||
struct wl_listener touch_down;
|
||||
struct wl_listener touch_up;
|
||||
struct wl_listener touch_cancel;
|
||||
struct wl_listener touch_motion;
|
||||
struct wl_listener touch_frame;
|
||||
bool simulating_pointer_from_touch;
|
||||
|
@ -64,6 +64,7 @@ struct sway_cursor {
|
|||
struct wl_listener tool_proximity;
|
||||
struct wl_listener tool_button;
|
||||
bool simulating_pointer_from_tool_tip;
|
||||
bool simulating_pointer_from_tool_button;
|
||||
uint32_t tool_buttons;
|
||||
|
||||
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);
|
||||
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,
|
||||
struct wlr_input_device *device, uint32_t time_msec, uint32_t button,
|
||||
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);
|
||||
|
||||
void handle_request_set_cursor_shape(struct wl_listener *listener, void *data);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,6 +25,7 @@ struct sway_input_manager {
|
|||
struct wlr_keyboard_shortcuts_inhibit_manager_v1 *keyboard_shortcuts_inhibit;
|
||||
struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard;
|
||||
struct wlr_virtual_pointer_manager_v1 *virtual_pointer;
|
||||
struct wlr_pointer_gestures_v1 *pointer_gestures;
|
||||
|
||||
struct wl_listener new_input;
|
||||
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_configure_all_inputs(void);
|
||||
void input_manager_configure_all_input_mappings(void);
|
||||
|
||||
void input_manager_reset_input(struct sway_input_device *input_device);
|
||||
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
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);
|
||||
|
||||
bool sway_libinput_device_is_builtin(struct sway_input_device *device);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h>
|
||||
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
#include <wlr/types/wlr_touch.h>
|
||||
#include <wlr/util/edges.h>
|
||||
#include "sway/config.h"
|
||||
#include "sway/input/input-manager.h"
|
||||
|
@ -11,6 +12,7 @@
|
|||
#include "sway/input/text_input.h"
|
||||
|
||||
struct sway_seat;
|
||||
struct fx_render_context;
|
||||
|
||||
struct sway_seatop_impl {
|
||||
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,
|
||||
struct wlr_pointer_swipe_end_event *event);
|
||||
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,
|
||||
struct sway_tablet_tool *tool, uint32_t time_msec);
|
||||
void (*tablet_tool_tip)(struct sway_seat *seat, struct sway_tablet_tool *tool,
|
||||
uint32_t time_msec, enum wlr_tablet_tool_tip_state state);
|
||||
void (*end)(struct sway_seat *seat);
|
||||
void (*unref)(struct sway_seat *seat, struct sway_container *con);
|
||||
void (*render)(struct sway_seat *seat, struct sway_output *output,
|
||||
pixman_region32_t *damage);
|
||||
void (*render)(struct sway_seat *seat, struct fx_render_context *ctx);
|
||||
bool allow_set_cursor;
|
||||
};
|
||||
|
||||
|
@ -72,6 +81,7 @@ struct sway_drag_icon {
|
|||
struct wl_list link; // sway_root::drag_icons
|
||||
|
||||
double x, y; // in layout-local coordinates
|
||||
int dx, dy; // offset in surface-local coordinates
|
||||
|
||||
struct wl_listener surface_commit;
|
||||
struct wl_listener map;
|
||||
|
@ -94,8 +104,9 @@ struct sway_seat {
|
|||
struct sway_workspace *workspace;
|
||||
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;
|
||||
// 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
|
||||
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,
|
||||
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,
|
||||
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_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,
|
||||
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,
|
||||
struct sway_container *con);
|
||||
|
@ -318,6 +335,18 @@ void seatop_swipe_update(struct sway_seat *seat,
|
|||
void seatop_swipe_end(struct sway_seat *seat,
|
||||
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);
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
* (eg. dropzone for move-tiling)
|
||||
*/
|
||||
void seatop_render(struct sway_seat *seat, struct sway_output *output,
|
||||
pixman_region32_t *damage);
|
||||
void seatop_render(struct sway_seat *seat, struct fx_render_context *ctx);
|
||||
|
||||
bool seatop_allows_set_cursor(struct sway_seat *seat);
|
||||
|
||||
|
|
|
@ -4,12 +4,11 @@
|
|||
#include <wlr/types/wlr_text_input_v3.h>
|
||||
#include <wlr/types/wlr_input_method_v2.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include "sway/input/seat.h"
|
||||
|
||||
/**
|
||||
* The relay structure manages the relationship between text-input and
|
||||
* 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
|
||||
* relay manages life cycle of both sides. When both sides are present and
|
||||
* focused, the relay passes messages between them.
|
||||
|
|
|
@ -21,5 +21,6 @@ void ipc_event_mode(const char *mode, bool pango);
|
|||
void ipc_event_shutdown(const char *reason);
|
||||
void ipc_event_binding(struct sway_binding *binding);
|
||||
void ipc_event_input(const char *change, struct sway_input_device *device);
|
||||
void ipc_event_output(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -60,6 +60,10 @@ struct sway_layer_subsurface {
|
|||
};
|
||||
|
||||
struct sway_output;
|
||||
|
||||
struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
|
||||
struct wlr_surface *surface);
|
||||
|
||||
void arrange_layers(struct sway_output *output);
|
||||
|
||||
struct sway_layer_surface *layer_from_wlr_layer_surface_v1(
|
||||
|
|
|
@ -6,23 +6,33 @@
|
|||
#include <wlr/types/wlr_damage_ring.h>
|
||||
#include <wlr/types/wlr_output.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/view.h"
|
||||
|
||||
struct decoration_data get_undecorated_decoration_data();
|
||||
|
||||
struct sway_server;
|
||||
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 fx_render_context *ctx;
|
||||
pixman_region32_t *damage;
|
||||
struct wlr_box *clip_box;
|
||||
struct decoration_data deco_data;
|
||||
};
|
||||
|
||||
struct blur_stencil_data {
|
||||
struct fx_texture *stencil_texture;
|
||||
const struct wlr_fbox *stencil_src_box;
|
||||
float *stencil_matrix;
|
||||
struct sway_view *view;
|
||||
};
|
||||
|
||||
struct sway_output_state {
|
||||
|
@ -36,8 +46,6 @@ struct sway_output {
|
|||
struct sway_server *server;
|
||||
struct wl_list link;
|
||||
|
||||
struct fx_renderer *renderer;
|
||||
|
||||
struct wl_list layers[4]; // sway_layer_surface::link
|
||||
struct wlr_box usable_area;
|
||||
|
||||
|
@ -48,21 +56,20 @@ struct sway_output {
|
|||
int width, height; // transformed buffer size
|
||||
enum wl_output_subpixel detected_subpixel;
|
||||
enum scale_filter_mode scale_filter;
|
||||
// last applied mode when the output is powered off
|
||||
struct wlr_output_mode *current_mode;
|
||||
|
||||
bool enabling, enabled;
|
||||
list_t *workspaces;
|
||||
|
||||
struct sway_output_state current;
|
||||
|
||||
struct wl_listener layout_destroy;
|
||||
struct wl_listener destroy;
|
||||
struct wl_listener commit;
|
||||
struct wl_listener mode;
|
||||
struct wl_listener present;
|
||||
struct wl_listener damage;
|
||||
struct wl_listener frame;
|
||||
struct wl_listener needs_frame;
|
||||
struct wl_listener request_state;
|
||||
|
||||
struct {
|
||||
struct wl_signal disable;
|
||||
|
@ -72,6 +79,7 @@ struct sway_output {
|
|||
uint32_t refresh_nsec;
|
||||
int max_render_time; // In milliseconds
|
||||
struct wl_event_source *repaint_timer;
|
||||
bool gamma_lut_changed;
|
||||
};
|
||||
|
||||
struct sway_output_non_desktop {
|
||||
|
@ -80,6 +88,14 @@ struct sway_output_non_desktop {
|
|||
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);
|
||||
|
||||
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,
|
||||
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
|
||||
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);
|
||||
|
||||
void output_render(struct sway_output *output, struct timespec *when,
|
||||
pixman_region32_t *damage);
|
||||
void output_render(struct fx_render_context *ctx);
|
||||
|
||||
void output_surface_for_each_surface(struct sway_output *output,
|
||||
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(
|
||||
struct sway_output *output);
|
||||
|
||||
void render_rect(struct sway_output *output,
|
||||
pixman_region32_t *output_damage, const struct wlr_box *_box,
|
||||
void render_rect(struct fx_render_context *ctx, const struct wlr_box *_box,
|
||||
float color[static 4]);
|
||||
|
||||
void render_rounded_rect(struct sway_output *output,
|
||||
pixman_region32_t *output_damage, const struct wlr_box *_box,
|
||||
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_rounded_rect(struct fx_render_context *ctx, const struct wlr_box *_box,
|
||||
float color[static 4], int corner_radius, enum corner_location corner_location);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -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_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_test(struct wl_listener *listener, void *data);
|
||||
|
|
|
@ -3,14 +3,12 @@
|
|||
#include <stdbool.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/backend/session.h>
|
||||
#include <wlr/render/allocator.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_data_device.h>
|
||||
#include <wlr/types/wlr_input_method_v2.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_output_management_v1.h>
|
||||
#include <wlr/types/wlr_output_power_management_v1.h>
|
||||
|
@ -22,6 +20,7 @@
|
|||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include "config.h"
|
||||
#include "list.h"
|
||||
#include "sway/desktop/idle_inhibit_v1.h"
|
||||
#if HAVE_XWAYLAND
|
||||
#include "sway/xwayland.h"
|
||||
#endif
|
||||
|
@ -34,9 +33,10 @@ struct sway_server {
|
|||
const char *socket;
|
||||
|
||||
struct wlr_backend *backend;
|
||||
struct wlr_session *session;
|
||||
// secondary headless backend used for creating virtual outputs on-the-fly
|
||||
struct wlr_backend *headless_backend;
|
||||
struct wlr_renderer *wlr_renderer;
|
||||
struct wlr_renderer *renderer;
|
||||
struct wlr_allocator *allocator;
|
||||
|
||||
struct wlr_compositor *compositor;
|
||||
|
@ -51,9 +51,8 @@ struct sway_server {
|
|||
struct wl_listener new_output;
|
||||
struct wl_listener output_layout_change;
|
||||
|
||||
struct wlr_idle *idle;
|
||||
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 wl_listener layer_shell_surface;
|
||||
|
@ -91,6 +90,9 @@ struct sway_server {
|
|||
struct wl_listener output_manager_apply;
|
||||
struct wl_listener output_manager_test;
|
||||
|
||||
struct wlr_gamma_control_manager_v1 *gamma_control_manager_v1;
|
||||
struct wl_listener gamma_control_set_gamma;
|
||||
|
||||
struct {
|
||||
bool locked;
|
||||
struct wlr_session_lock_manager_v1 *manager;
|
||||
|
@ -110,9 +112,17 @@ struct sway_server {
|
|||
struct wlr_input_method_manager_v2 *input_method;
|
||||
struct wlr_text_input_manager_v3 *text_input;
|
||||
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 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
|
||||
|
||||
|
@ -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 xdg_activation_v1_handle_request_activate(struct wl_listener *listener,
|
||||
void *data);
|
||||
void xdg_activation_v1_handle_new_token(struct wl_listener *listener,
|
||||
void *data);
|
||||
|
||||
void set_rr_scheduling(void);
|
||||
|
||||
|
|
|
@ -15,4 +15,10 @@ struct sway_surface {
|
|||
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
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef _SWAY_SWAYNAG_H
|
||||
#define _SWAY_SWAYNAG_H
|
||||
#include <wayland-server-core.h>
|
||||
#include "stringop.h"
|
||||
|
||||
struct swaynag_instance {
|
||||
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
|
||||
// is false.
|
||||
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
|
||||
void swaynag_show(struct swaynag_instance *swaynag);
|
||||
|
|
|
@ -119,6 +119,11 @@ struct sway_container {
|
|||
|
||||
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;
|
||||
|
||||
int corner_radius;
|
||||
|
@ -206,6 +211,9 @@ size_t container_titlebar_height(void);
|
|||
void floating_calculate_constraints(int *min_width, int *max_width,
|
||||
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_set_default_size(struct sway_container *con);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef _SWAY_NODE_H
|
||||
#define _SWAY_NODE_H
|
||||
#include <wayland-server-core.h>
|
||||
#include <stdbool.h>
|
||||
#include "list.h"
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define _SWAY_VIEW_H
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include "config.h"
|
||||
#include "sway/config.h"
|
||||
#if HAVE_XWAYLAND
|
||||
#include <wlr/xwayland.h>
|
||||
#endif
|
||||
|
@ -162,6 +162,8 @@ struct sway_xwayland_view {
|
|||
struct wl_listener set_window_type;
|
||||
struct wl_listener set_hints;
|
||||
struct wl_listener set_decorations;
|
||||
struct wl_listener associate;
|
||||
struct wl_listener dissociate;
|
||||
struct wl_listener map;
|
||||
struct wl_listener unmap;
|
||||
struct wl_listener destroy;
|
||||
|
@ -179,6 +181,8 @@ struct sway_xwayland_unmanaged {
|
|||
struct wl_listener request_fullscreen;
|
||||
struct wl_listener commit;
|
||||
struct wl_listener set_geometry;
|
||||
struct wl_listener associate;
|
||||
struct wl_listener dissociate;
|
||||
struct wl_listener map;
|
||||
struct wl_listener unmap;
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define _SWAY_WORKSPACE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "sway/config.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/node.h"
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "config.h"
|
||||
#include "input.h"
|
||||
#include "pool-buffer.h"
|
||||
#include "cursor-shape-v1-client-protocol.h"
|
||||
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
|
||||
#include "xdg-output-unstable-v1-client-protocol.h"
|
||||
|
||||
|
@ -30,6 +31,7 @@ struct swaybar {
|
|||
struct wl_compositor *compositor;
|
||||
struct zwlr_layer_shell_v1 *layer_shell;
|
||||
struct zxdg_output_manager_v1 *xdg_output_manager;
|
||||
struct wp_cursor_shape_manager_v1 *cursor_shape_manager;
|
||||
struct wl_shm *shm;
|
||||
|
||||
struct swaybar_config *config;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <cairo.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <wayland-util.h>
|
||||
#include "swaybar/tray/tray.h"
|
||||
#include "list.h"
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include <strings.h>
|
||||
#include "list.h"
|
||||
#include "pool-buffer.h"
|
||||
#include "cursor-shape-v1-client-protocol.h"
|
||||
|
||||
#include "swaynag/types.h"
|
||||
|
||||
#define SWAYNAG_MAX_HEIGHT 500
|
||||
|
@ -58,6 +60,7 @@ struct swaynag_button {
|
|||
struct swaynag_details {
|
||||
bool visible;
|
||||
char *message;
|
||||
char *details_text;
|
||||
|
||||
int x;
|
||||
int y;
|
||||
|
@ -67,7 +70,7 @@ struct swaynag_details {
|
|||
int offset;
|
||||
int visible_lines;
|
||||
int total_lines;
|
||||
struct swaynag_button button_details;
|
||||
struct swaynag_button *button_details;
|
||||
struct swaynag_button button_up;
|
||||
struct swaynag_button button_down;
|
||||
};
|
||||
|
@ -84,6 +87,7 @@ struct swaynag {
|
|||
struct swaynag_output *output;
|
||||
struct zwlr_layer_shell_v1 *layer_shell;
|
||||
struct zwlr_layer_surface_v1 *layer_surface;
|
||||
struct wp_cursor_shape_manager_v1 *cursor_shape_manager;
|
||||
struct wl_surface *surface;
|
||||
|
||||
uint32_t width;
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
#ifndef _SWAYNAG_TYPES_H
|
||||
#define _SWAYNAG_TYPES_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <pango/pangocairo.h>
|
||||
#include "list.h"
|
||||
|
||||
struct swaynag_type {
|
||||
char *name;
|
||||
|
||||
char *font; // Used for debugging.
|
||||
PangoFontDescription *font_description;
|
||||
char *output;
|
||||
uint32_t anchors;
|
||||
|
|
126
meson.build
126
meson.build
|
@ -1,7 +1,7 @@
|
|||
project(
|
||||
'sway',
|
||||
'c',
|
||||
version: '0.3.2',
|
||||
version: '0.3.3',
|
||||
license: 'MIT',
|
||||
meson_version: '>=0.60.0',
|
||||
default_options: [
|
||||
|
@ -18,6 +18,7 @@ add_project_arguments(
|
|||
'-Wno-unused-parameter',
|
||||
'-Wno-unused-result',
|
||||
'-Wno-missing-braces',
|
||||
'-Wno-format-zero-length',
|
||||
'-Wundef',
|
||||
'-Wvla',
|
||||
],
|
||||
|
@ -35,46 +36,26 @@ if is_freebsd
|
|||
add_project_arguments('-D_C11_SOURCE', language: 'c')
|
||||
endif
|
||||
|
||||
# Execute the scenefx subproject, if any
|
||||
subproject(
|
||||
'scenefx',
|
||||
required: false,
|
||||
)
|
||||
scenefx = dependency('scenefx')
|
||||
|
||||
# Execute the wlroots subproject, if any
|
||||
wlroots_version = ['>=0.16.0', '<0.17.0']
|
||||
wlroots_version = ['>=0.17.0', '<0.18.0']
|
||||
subproject(
|
||||
'wlroots',
|
||||
default_options: ['examples=false'],
|
||||
required: false,
|
||||
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)
|
||||
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 = {
|
||||
'xwayland': false,
|
||||
'libinput_backend': false,
|
||||
'session': false,
|
||||
}
|
||||
foreach name, _ : wlroots_features
|
||||
var_name = 'have_' + name.underscorify()
|
||||
|
@ -85,6 +66,34 @@ endforeach
|
|||
if get_option('xwayland').enabled() and not wlroots_features['xwayland']
|
||||
error('Cannot enable Xwayland in sway: wlroots has been built without Xwayland support')
|
||||
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']
|
||||
|
||||
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)
|
||||
endif
|
||||
|
||||
if get_option('zsh-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
|
||||
subdir('completions')
|
||||
|
||||
summary({
|
||||
'xwayland': have_xwayland,
|
||||
|
@ -329,4 +286,3 @@ summary({
|
|||
'tray': have_tray,
|
||||
'man-pages': scdoc.found(),
|
||||
}, bool_yn: true)
|
||||
|
||||
|
|
|
@ -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('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications')
|
||||
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('sd-bus-provider', type: 'combo', choices: ['auto', 'libsystemd', 'libelogind', 'basu'], value: 'auto', description: 'Provider of the sd-bus library')
|
||||
|
|
|
@ -2,7 +2,7 @@ wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
|
|||
|
||||
wayland_scanner_dep = dependency('wayland-scanner', native: true)
|
||||
wayland_scanner = find_program(
|
||||
wayland_scanner_dep.get_variable(pkgconfig: 'wayland_scanner'),
|
||||
wayland_scanner_dep.get_variable('wayland_scanner'),
|
||||
native: true,
|
||||
)
|
||||
|
||||
|
@ -12,6 +12,8 @@ protocols = [
|
|||
wl_protocol_dir / 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml',
|
||||
wl_protocol_dir / 'unstable/tablet/tablet-unstable-v2.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',
|
||||
'idle.xml',
|
||||
'wlr-input-inhibitor-unstable-v1.xml',
|
||||
|
|
|
@ -127,6 +127,7 @@ static const struct cmd_handler config_handlers[] = {
|
|||
{ "default_orientation", cmd_default_orientation },
|
||||
{ "include", cmd_include },
|
||||
{ "scratchpad_minimize", cmd_scratchpad_minimize },
|
||||
{ "primary_selection", cmd_primary_selection },
|
||||
{ "swaybg_command", cmd_swaybg_command },
|
||||
{ "swaynag_command", cmd_swaynag_command },
|
||||
{ "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);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!handlers || !handlers_size) {
|
||||
return NULL;
|
||||
|
@ -404,10 +405,13 @@ struct cmd_results *config_command(char *exec, char **new_block) {
|
|||
sway_log(SWAY_INFO, "Config command: %s", exec);
|
||||
const struct cmd_handler *handler = find_core_handler(argv[0]);
|
||||
if (!handler || !handler->handle) {
|
||||
const char *error = handler
|
||||
? "Command '%s' is shimmed, but unimplemented"
|
||||
: "Unknown/invalid command '%s'";
|
||||
results = cmd_results_new(CMD_INVALID, error, argv[0]);
|
||||
if (handler) {
|
||||
results = cmd_results_new(CMD_INVALID,
|
||||
"Command '%s' is shimmed, but unimplemented", argv[0]);
|
||||
} else {
|
||||
results = cmd_results_new(CMD_INVALID,
|
||||
"Unknown/invalid command '%s'", argv[0]);
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
@ -509,20 +513,10 @@ struct cmd_results *cmd_results_new(enum cmd_status status,
|
|||
}
|
||||
results->status = status;
|
||||
if (format) {
|
||||
char *error = NULL;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int slen = vsnprintf(NULL, 0, format, args);
|
||||
results->error = vformat_str(format, 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 {
|
||||
results->error = NULL;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ struct cmd_results *cmd_assign(int argc, char **argv) {
|
|||
char *err_str = NULL;
|
||||
struct criteria *criteria = criteria_parse(argv[0], &err_str);
|
||||
if (!criteria) {
|
||||
error = cmd_results_new(CMD_INVALID, err_str);
|
||||
error = cmd_results_new(CMD_INVALID, "%s", err_str);
|
||||
free(err_str);
|
||||
return error;
|
||||
}
|
||||
|
|
|
@ -73,12 +73,10 @@ struct cmd_results *cmd_bar(int argc, char **argv) {
|
|||
}
|
||||
++argv; --argc;
|
||||
} else if (config->reading && !config->current_bar) {
|
||||
int len = snprintf(NULL, 0, "bar-%d", config->bars->length) + 1;
|
||||
id = malloc(len * sizeof(char));
|
||||
id = format_str("bar-%d", config->bars->length);
|
||||
if (!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 &&
|
||||
strcmp(argv[0], "hidden_state") != 0) {
|
||||
if (is_subcommand(argv[0])) {
|
||||
|
|
|
@ -96,7 +96,7 @@ static struct cmd_results *bar_cmd_bind(int argc, char **argv, bool code,
|
|||
}
|
||||
if (message) {
|
||||
free_bar_binding(binding);
|
||||
error = cmd_results_new(CMD_INVALID, message);
|
||||
error = cmd_results_new(CMD_INVALID, "%s", message);
|
||||
free(message);
|
||||
return error;
|
||||
} else if (!binding->button) {
|
||||
|
|
|
@ -26,7 +26,7 @@ static struct cmd_results *tray_bind(int argc, char **argv, bool code) {
|
|||
}
|
||||
if (message) {
|
||||
free(binding);
|
||||
error = cmd_results_new(CMD_INVALID, message);
|
||||
error = cmd_results_new(CMD_INVALID, "%s", message);
|
||||
free(message);
|
||||
return error;
|
||||
} else if (!binding->button) {
|
||||
|
|
|
@ -127,7 +127,7 @@ static struct cmd_results *identify_key(const char* name, bool first_key,
|
|||
if (!button) {
|
||||
if (message) {
|
||||
struct cmd_results *error =
|
||||
cmd_results_new(CMD_INVALID, message);
|
||||
cmd_results_new(CMD_INVALID, "%s", message);
|
||||
free(message);
|
||||
return error;
|
||||
} else {
|
||||
|
@ -143,7 +143,7 @@ static struct cmd_results *identify_key(const char* name, bool first_key,
|
|||
if (!button) {
|
||||
if (message) {
|
||||
struct cmd_results *error =
|
||||
cmd_results_new(CMD_INVALID, message);
|
||||
cmd_results_new(CMD_INVALID, "%s", message);
|
||||
free(message);
|
||||
return error;
|
||||
} 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);
|
||||
if (message) {
|
||||
struct cmd_results *error =
|
||||
cmd_results_new(CMD_INVALID, message);
|
||||
cmd_results_new(CMD_INVALID, "%s", message);
|
||||
free(message);
|
||||
return error;
|
||||
} else if (button) {
|
||||
|
@ -539,7 +539,7 @@ struct cmd_results *cmd_bind_or_unbind_switch(int argc, char **argv,
|
|||
free_switch_binding(binding);
|
||||
return cmd_results_new(CMD_FAILURE,
|
||||
"Invalid %s command (expected binding with the form "
|
||||
"<switch>:<state>)", bindtype, argc);
|
||||
"<switch>:<state>)", bindtype);
|
||||
}
|
||||
if (strcmp(split->items[0], "tablet") == 0) {
|
||||
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);
|
||||
return cmd_results_new(CMD_FAILURE,
|
||||
"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) {
|
||||
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,
|
||||
"Invalid %s command "
|
||||
"(expected switch state: unknown state %s)",
|
||||
bindtype, split->items[1]);
|
||||
bindtype, (const char *)split->items[1]);
|
||||
}
|
||||
list_free_items_and_destroy(split);
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h"
|
||||
#include "sway/commands.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/output.h"
|
||||
|
@ -21,10 +22,10 @@ struct cmd_results *cmd_blur(int argc, char **argv) {
|
|||
|
||||
struct sway_output *output;
|
||||
wl_list_for_each(output, &root->all_outputs, link) {
|
||||
if (output->renderer) {
|
||||
output->renderer->blur_buffer_dirty = true;
|
||||
output_damage_whole(output);
|
||||
}
|
||||
struct fx_effect_framebuffers *effect_fbos =
|
||||
fx_effect_framebuffers_try_get(output->wlr_output);
|
||||
effect_fbos->blur_buffer_dirty = true;
|
||||
output_damage_whole(output);
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h"
|
||||
#include "sway/commands.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/output.h"
|
||||
|
@ -18,10 +19,10 @@ struct cmd_results *cmd_blur_brightness(int argc, char **argv) {
|
|||
|
||||
struct sway_output *output;
|
||||
wl_list_for_each(output, &root->all_outputs, link) {
|
||||
if (output->renderer) {
|
||||
output->renderer->blur_buffer_dirty = true;
|
||||
output_damage_whole(output);
|
||||
}
|
||||
struct fx_effect_framebuffers *effect_fbos =
|
||||
fx_effect_framebuffers_try_get(output->wlr_output);
|
||||
effect_fbos->blur_buffer_dirty = true;
|
||||
output_damage_whole(output);
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h"
|
||||
#include "sway/commands.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/output.h"
|
||||
|
@ -18,10 +19,10 @@ struct cmd_results *cmd_blur_contrast(int argc, char **argv) {
|
|||
|
||||
struct sway_output *output;
|
||||
wl_list_for_each(output, &root->all_outputs, link) {
|
||||
if (output->renderer) {
|
||||
output->renderer->blur_buffer_dirty = true;
|
||||
output_damage_whole(output);
|
||||
}
|
||||
struct fx_effect_framebuffers *effect_fbos =
|
||||
fx_effect_framebuffers_try_get(output->wlr_output);
|
||||
effect_fbos->blur_buffer_dirty = true;
|
||||
output_damage_whole(output);
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h"
|
||||
#include "sway/commands.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/output.h"
|
||||
|
@ -16,13 +17,13 @@ struct cmd_results *cmd_blur_noise(int argc, char **argv) {
|
|||
|
||||
config->blur_params.noise = value;
|
||||
|
||||
struct sway_output *output;
|
||||
wl_list_for_each(output, &root->all_outputs, link) {
|
||||
if (output->renderer) {
|
||||
output->renderer->blur_buffer_dirty = true;
|
||||
output_damage_whole(output);
|
||||
}
|
||||
}
|
||||
struct sway_output *output;
|
||||
wl_list_for_each(output, &root->all_outputs, link) {
|
||||
struct fx_effect_framebuffers *effect_fbos =
|
||||
fx_effect_framebuffers_try_get(output->wlr_output);
|
||||
effect_fbos->blur_buffer_dirty = true;
|
||||
output_damage_whole(output);
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h"
|
||||
#include "sway/commands.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/output.h"
|
||||
|
@ -18,10 +19,10 @@ struct cmd_results *cmd_blur_passes(int argc, char **argv) {
|
|||
|
||||
struct sway_output *output;
|
||||
wl_list_for_each(output, &root->all_outputs, link) {
|
||||
if (output->renderer) {
|
||||
output->renderer->blur_buffer_dirty = true;
|
||||
output_damage_whole(output);
|
||||
}
|
||||
struct fx_effect_framebuffers *effect_fbos =
|
||||
fx_effect_framebuffers_try_get(output->wlr_output);
|
||||
effect_fbos->blur_buffer_dirty = true;
|
||||
output_damage_whole(output);
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h"
|
||||
#include "sway/commands.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/output.h"
|
||||
|
@ -18,10 +19,10 @@ struct cmd_results *cmd_blur_radius(int argc, char **argv) {
|
|||
|
||||
struct sway_output *output;
|
||||
wl_list_for_each(output, &root->all_outputs, link) {
|
||||
if (output->renderer) {
|
||||
output->renderer->blur_buffer_dirty = true;
|
||||
output_damage_whole(output);
|
||||
}
|
||||
struct fx_effect_framebuffers *effect_fbos =
|
||||
fx_effect_framebuffers_try_get(output->wlr_output);
|
||||
effect_fbos->blur_buffer_dirty = true;
|
||||
output_damage_whole(output);
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h"
|
||||
#include "sway/commands.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/output.h"
|
||||
|
@ -18,10 +19,10 @@ struct cmd_results *cmd_blur_saturation(int argc, char **argv) {
|
|||
|
||||
struct sway_output *output;
|
||||
wl_list_for_each(output, &root->all_outputs, link) {
|
||||
if (output->renderer) {
|
||||
output->renderer->blur_buffer_dirty = true;
|
||||
output_damage_whole(output);
|
||||
}
|
||||
struct fx_effect_framebuffers *effect_fbos =
|
||||
fx_effect_framebuffers_try_get(output->wlr_output);
|
||||
effect_fbos->blur_buffer_dirty = true;
|
||||
output_damage_whole(output);
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "scenefx/render/fx_renderer/fx_effect_framebuffers.h"
|
||||
#include "sway/commands.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/output.h"
|
||||
|
@ -15,10 +16,10 @@ struct cmd_results *cmd_blur_xray(int argc, char **argv) {
|
|||
|
||||
struct sway_output *output;
|
||||
wl_list_for_each(output, &root->all_outputs, link) {
|
||||
if (output->renderer) {
|
||||
output->renderer->blur_buffer_dirty = true;
|
||||
output_damage_whole(output);
|
||||
}
|
||||
struct fx_effect_framebuffers *effect_fbos =
|
||||
fx_effect_framebuffers_try_get(output->wlr_output);
|
||||
effect_fbos->blur_buffer_dirty = true;
|
||||
output_damage_whole(output);
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include "sway/config.h"
|
||||
#include "sway/server.h"
|
||||
#include "sway/desktop/launcher.h"
|
||||
#include "sway/server.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/root.h"
|
||||
#include "sway/tree/workspace.h"
|
||||
|
@ -64,7 +63,7 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) {
|
|||
}
|
||||
|
||||
pid_t pid, child;
|
||||
struct launcher_ctx *ctx = launcher_ctx_create();
|
||||
struct launcher_ctx *ctx = launcher_ctx_create_internal();
|
||||
// Fork process
|
||||
if ((pid = fork()) == 0) {
|
||||
// Fork child process again
|
||||
|
|
|
@ -23,16 +23,16 @@ static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name,
|
|||
char *err;
|
||||
int width = (int)strtol(argv[0], &err, 10);
|
||||
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) {
|
||||
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);
|
||||
if (*err) {
|
||||
return cmd_results_new(CMD_INVALID, cmd_name, usage);
|
||||
return cmd_results_new(CMD_INVALID, "%s", usage);
|
||||
}
|
||||
|
||||
*config_width = width;
|
||||
|
|
|
@ -33,10 +33,10 @@ struct cmd_results *cmd_font(int argc, char **argv) {
|
|||
return cmd_results_new(CMD_FAILURE, "Invalid font family.");
|
||||
}
|
||||
|
||||
const PangoFontMask flags = pango_font_description_get_set_fields(font_description);
|
||||
if ((flags & PANGO_FONT_MASK_SIZE) == 0) {
|
||||
const gint size = pango_font_description_get_size(font_description);
|
||||
if (size == 0) {
|
||||
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) {
|
||||
|
|
|
@ -14,7 +14,7 @@ struct cmd_results *cmd_for_window(int argc, char **argv) {
|
|||
char *err_str = NULL;
|
||||
struct criteria *criteria = criteria_parse(argv[0], &err_str);
|
||||
if (!criteria) {
|
||||
error = cmd_results_new(CMD_INVALID, err_str);
|
||||
error = cmd_results_new(CMD_INVALID, "%s", err_str);
|
||||
free(err_str);
|
||||
return error;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ struct cmd_results *cmd_hide_edge_borders(int argc, char **argv) {
|
|||
}
|
||||
|
||||
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) {
|
||||
|
@ -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_smart = ESMART_NO_GAPS;
|
||||
} 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;
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ struct cmd_results *cmd_inhibit_idle(int argc, char **argv) {
|
|||
sway_idle_inhibit_v1_user_inhibitor_destroy(inhibitor);
|
||||
} else {
|
||||
inhibitor->mode = mode;
|
||||
sway_idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
|
||||
sway_idle_inhibit_v1_check_active();
|
||||
}
|
||||
} else if (!clear) {
|
||||
sway_idle_inhibit_v1_user_inhibitor_register(con->view, mode);
|
||||
|
|
|
@ -25,7 +25,9 @@ static const struct cmd_handler input_handlers[] = {
|
|||
{ "pointer_accel", input_cmd_pointer_accel },
|
||||
{ "repeat_delay", input_cmd_repeat_delay },
|
||||
{ "repeat_rate", input_cmd_repeat_rate },
|
||||
{ "rotation_angle", input_cmd_rotation_angle },
|
||||
{ "scroll_button", input_cmd_scroll_button },
|
||||
{ "scroll_button_lock", input_cmd_scroll_button_lock },
|
||||
{ "scroll_factor", input_cmd_scroll_factor },
|
||||
{ "scroll_method", input_cmd_scroll_method },
|
||||
{ "tap", input_cmd_tap },
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <wlr/backend/libinput.h>
|
||||
#include <wlr/config.h>
|
||||
#include "sway/config.h"
|
||||
#include "sway/commands.h"
|
||||
#include "sway/input/input-manager.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,
|
||||
struct sway_input_device *input_device) {
|
||||
#if WLR_HAS_LIBINPUT_BACKEND
|
||||
struct wlr_input_device *wlr_device = input_device->wlr_device;
|
||||
if (!wlr_input_device_is_libinput(wlr_device)) {
|
||||
return;
|
||||
|
@ -41,6 +46,7 @@ static void toggle_supported_send_events_for_device(struct input_config *ic,
|
|||
}
|
||||
|
||||
ic->send_events = mode;
|
||||
#endif
|
||||
}
|
||||
|
||||
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,
|
||||
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)) {
|
||||
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]);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void toggle_send_events(int argc, char **argv) {
|
||||
|
|
|
@ -11,11 +11,21 @@ static bool parse_coords(const char *str, double *x, double *y, bool *mm) {
|
|||
*mm = false;
|
||||
|
||||
char *end;
|
||||
*x = strtod(str, &end);
|
||||
if (end[0] != 'x') {
|
||||
return false;
|
||||
|
||||
// Check for "0x" prefix to avoid strtod treating the string as hex
|
||||
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);
|
||||
if (end[0] == 'm') {
|
||||
|
|
|
@ -49,5 +49,5 @@ struct cmd_results *input_cmd_map_to_region(int argc, char **argv) {
|
|||
error:
|
||||
free(ic->mapped_to_region);
|
||||
ic->mapped_to_region = NULL;
|
||||
return cmd_results_new(CMD_FAILURE, errstr);
|
||||
return cmd_results_new(CMD_FAILURE, "%s", errstr);
|
||||
}
|
||||
|
|
29
sway/commands/input/rotation_angle.c
Normal file
29
sway/commands/input/rotation_angle.c
Normal 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);
|
||||
}
|
|
@ -21,7 +21,7 @@ struct cmd_results *input_cmd_scroll_button(int argc, char **argv) {
|
|||
char *message = NULL;
|
||||
uint32_t button = get_mouse_button(*argv, &message);
|
||||
if (message) {
|
||||
error = cmd_results_new(CMD_INVALID, message);
|
||||
error = cmd_results_new(CMD_INVALID, "%s", message);
|
||||
free(message);
|
||||
return error;
|
||||
} else if (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_DOWN
|
||||
|
|
26
sway/commands/input/scroll_button_lock.c
Normal file
26
sway/commands/input/scroll_button_lock.c
Normal 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);
|
||||
}
|
|
@ -153,7 +153,7 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
|
|||
workspace->output);
|
||||
}
|
||||
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 (container) {
|
||||
|
|
|
@ -206,9 +206,17 @@ static void container_move_to_workspace(struct sway_container *container,
|
|||
container_detach(container);
|
||||
workspace_add_floating(workspace, 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) {
|
||||
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 {
|
||||
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) {
|
||||
// move [window|container] [to] "workspace number x"
|
||||
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])) {
|
||||
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;
|
||||
} else {
|
||||
return cmd_results_new(CMD_INVALID, expected_syntax);
|
||||
return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
|
||||
}
|
||||
|
||||
if (destination->type == N_CONTAINER &&
|
||||
|
@ -821,7 +829,7 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) {
|
|||
}
|
||||
|
||||
if (!argc) {
|
||||
return cmd_results_new(CMD_INVALID, expected_position_syntax);
|
||||
return cmd_results_new(CMD_INVALID, "%s", expected_position_syntax);
|
||||
}
|
||||
|
||||
bool absolute = false;
|
||||
|
@ -831,19 +839,19 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) {
|
|||
++argv;
|
||||
}
|
||||
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) {
|
||||
--argc;
|
||||
++argv;
|
||||
}
|
||||
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 ||
|
||||
strcmp(argv[0], "pointer") == 0) {
|
||||
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);
|
||||
} 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) {
|
||||
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 };
|
||||
|
@ -878,7 +886,7 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) {
|
|||
}
|
||||
|
||||
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 };
|
||||
|
@ -887,7 +895,7 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) {
|
|||
argc -= num_consumed_args;
|
||||
argv += num_consumed_args;
|
||||
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) {
|
||||
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) {
|
||||
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
|
||||
// `--no-auto-back-and-forth` so treat others as invalid syntax
|
||||
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 ||
|
||||
|
@ -1053,5 +1061,5 @@ struct cmd_results *cmd_move(int argc, char **argv) {
|
|||
strcasecmp(argv[1], "position") == 0)) {
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ struct cmd_results *cmd_no_focus(int argc, char **argv) {
|
|||
char *err_str = NULL;
|
||||
struct criteria *criteria = criteria_parse(argv[0], &err_str);
|
||||
if (!criteria) {
|
||||
error = cmd_results_new(CMD_INVALID, err_str);
|
||||
error = cmd_results_new(CMD_INVALID, "%s", err_str);
|
||||
free(err_str);
|
||||
return error;
|
||||
}
|
||||
|
|
|
@ -111,7 +111,10 @@ struct cmd_results *cmd_output(int argc, char **argv) {
|
|||
if (!config->reloading && !config->validating) {
|
||||
apply_output_config_to_outputs(output);
|
||||
if (background) {
|
||||
spawn_swaybg();
|
||||
if (!spawn_swaybg()) {
|
||||
return cmd_results_new(CMD_FAILURE,
|
||||
"Failed to apply background configuration");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -123,7 +123,10 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
|
|||
src);
|
||||
config_add_swaynag_warning("Unable to access background file '%s'",
|
||||
src);
|
||||
struct cmd_results *result = cmd_results_new(CMD_FAILURE,
|
||||
"unable to access background file '%s'", src);
|
||||
free(src);
|
||||
return result;
|
||||
} else {
|
||||
output->background = src;
|
||||
output->background_option = strdup(mode);
|
||||
|
|
23
sway/commands/primary_selection.c
Normal file
23
sway/commands/primary_selection.c
Normal 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);
|
||||
}
|
|
@ -26,7 +26,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) {
|
|||
"Can't run this command while there's no outputs connected.");
|
||||
}
|
||||
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;
|
||||
|
@ -65,7 +65,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) {
|
|||
++argn; // move past "to"
|
||||
|
||||
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);
|
||||
|
|
|
@ -75,6 +75,10 @@ void container_resize_tiled(struct sway_container *con,
|
|||
return;
|
||||
}
|
||||
|
||||
if (container_is_scratchpad_hidden_or_child(con)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For HORIZONTAL or VERTICAL, we are growing in two directions so select
|
||||
// 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
|
||||
|
@ -249,16 +253,35 @@ static struct cmd_results *resize_adjust_tiled(uint32_t axis,
|
|||
struct movement_amount *amount) {
|
||||
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) {
|
||||
amount->unit = MOVEMENT_UNIT_PPT;
|
||||
}
|
||||
if (amount->unit == MOVEMENT_UNIT_PPT) {
|
||||
struct sway_container *parent = current->pending.parent;
|
||||
float pct = amount->amount / 100.0f;
|
||||
|
||||
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 {
|
||||
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,
|
||||
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->unit == MOVEMENT_UNIT_PPT ||
|
||||
width->unit == MOVEMENT_UNIT_DEFAULT) {
|
||||
|
@ -415,7 +443,7 @@ static struct cmd_results *cmd_resize_set(int argc, char **argv) {
|
|||
argc -= num_consumed_args;
|
||||
argv += num_consumed_args;
|
||||
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);
|
||||
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) {
|
||||
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]]'";
|
||||
uint32_t axis = parse_resize_axis(*argv);
|
||||
if (axis == WLR_EDGE_NONE) {
|
||||
return cmd_results_new(CMD_INVALID, usage);
|
||||
return cmd_results_new(CMD_INVALID, "%s", usage);
|
||||
}
|
||||
--argc; ++argv;
|
||||
|
||||
|
@ -473,7 +501,7 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv,
|
|||
argc -= num_consumed_args;
|
||||
argv += num_consumed_args;
|
||||
if (first_amount.unit == MOVEMENT_UNIT_INVALID) {
|
||||
return cmd_results_new(CMD_INVALID, usage);
|
||||
return cmd_results_new(CMD_INVALID, "%s", usage);
|
||||
}
|
||||
} else {
|
||||
first_amount.amount = 10;
|
||||
|
@ -483,7 +511,7 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv,
|
|||
// "or"
|
||||
if (argc) {
|
||||
if (strcmp(*argv, "or") != 0) {
|
||||
return cmd_results_new(CMD_INVALID, usage);
|
||||
return cmd_results_new(CMD_INVALID, "%s", usage);
|
||||
}
|
||||
--argc; ++argv;
|
||||
}
|
||||
|
@ -493,10 +521,10 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv,
|
|||
if (argc) {
|
||||
int num_consumed_args = parse_movement_amount(argc, argv, &second_amount);
|
||||
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) {
|
||||
return cmd_results_new(CMD_INVALID, usage);
|
||||
return cmd_results_new(CMD_INVALID, "%s", usage);
|
||||
}
|
||||
} else {
|
||||
second_amount.amount = 0;
|
||||
|
@ -566,5 +594,5 @@ struct cmd_results *cmd_resize(int argc, char **argv) {
|
|||
const char usage[] = "Expected 'resize <shrink|grow> "
|
||||
"<width|height|up|down|left|right> [<amount>] [px|ppt]'";
|
||||
|
||||
return cmd_results_new(CMD_INVALID, usage);
|
||||
return cmd_results_new(CMD_INVALID, "%s", usage);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ static struct cmd_results *handle_command(struct sway_cursor *cursor,
|
|||
int argc, char **argv) {
|
||||
if (strcasecmp(argv[0], "move") == 0) {
|
||||
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_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);
|
||||
} else if (strcasecmp(argv[0], "set") == 0) {
|
||||
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
|
||||
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);
|
||||
} else {
|
||||
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;
|
||||
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) {
|
||||
state = WLR_BUTTON_RELEASED;
|
||||
} else {
|
||||
return cmd_results_new(CMD_INVALID, expected_syntax);
|
||||
return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
|
||||
}
|
||||
|
||||
char *message = NULL;
|
||||
button = get_mouse_button(button_str, &message);
|
||||
if (message) {
|
||||
struct cmd_results *error =
|
||||
cmd_results_new(CMD_INVALID, message);
|
||||
cmd_results_new(CMD_INVALID, "%s", message);
|
||||
free(message);
|
||||
return error;
|
||||
} else if (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_DOWN
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdint.h>
|
||||
#include "log.h"
|
||||
#include "sway/commands.h"
|
||||
#include "sway/config.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");
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
#include "sway/tree/arrange.h"
|
||||
#include "sway/tree/view.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "log.h"
|
||||
#include "stringop.h"
|
||||
#include "util.h"
|
||||
|
||||
struct cmd_results *cmd_shadows(int argc, char **argv) {
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
#include "sway/commands.h"
|
||||
#include "sway/config.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"
|
||||
|
||||
struct cmd_results *cmd_shadows_on_csd(int argc, char **argv) {
|
||||
|
|
|
@ -32,7 +32,7 @@ static struct cmd_results *do_split(int layout) {
|
|||
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_workspace *ws = config->handler_context.workspace;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "sway/commands.h"
|
||||
#include "sway/output.h"
|
||||
#include "sway/tree/arrange.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/root.h"
|
||||
#include "sway/tree/view.h"
|
||||
#include "sway/tree/workspace.h"
|
||||
|
@ -13,180 +14,6 @@
|
|||
static const char expected_syntax[] =
|
||||
"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) {
|
||||
size_t *con_id = data;
|
||||
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")) {
|
||||
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;
|
||||
|
@ -238,7 +65,7 @@ struct cmd_results *cmd_swap(int argc, char **argv) {
|
|||
other = root_find_container(test_mark, value);
|
||||
} else {
|
||||
free(value);
|
||||
return cmd_results_new(CMD_INVALID, expected_syntax);
|
||||
return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
|
||||
}
|
||||
|
||||
if (!other) {
|
||||
|
|
|
@ -61,7 +61,7 @@ static struct cmd_results *cmd_workspace_gaps(int argc, char **argv,
|
|||
const char expected[] = "Expected 'workspace <name> gaps "
|
||||
"inner|outer|horizontal|vertical|top|right|bottom|left <px>'";
|
||||
if (gaps_location == 0) {
|
||||
return cmd_results_new(CMD_INVALID, expected);
|
||||
return cmd_results_new(CMD_INVALID, "%s", expected);
|
||||
}
|
||||
struct cmd_results *error = NULL;
|
||||
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;
|
||||
int amount = strtol(argv[gaps_location + 2], &end, 10);
|
||||
if (strlen(end)) {
|
||||
return cmd_results_new(CMD_FAILURE, expected);
|
||||
return cmd_results_new(CMD_FAILURE, "%s", expected);
|
||||
}
|
||||
|
||||
bool valid = false;
|
||||
|
@ -110,7 +110,7 @@ static struct cmd_results *cmd_workspace_gaps(int argc, char **argv,
|
|||
}
|
||||
}
|
||||
if (!valid) {
|
||||
return cmd_results_new(CMD_INVALID, expected);
|
||||
return cmd_results_new(CMD_INVALID, "%s", expected);
|
||||
}
|
||||
|
||||
// Prevent invalid gaps configurations.
|
||||
|
@ -174,7 +174,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
|
|||
}
|
||||
|
||||
if (root->fullscreen_global) {
|
||||
return cmd_results_new(CMD_FAILURE, "workspace",
|
||||
return cmd_results_new(CMD_FAILURE,
|
||||
"Can't switch workspaces while fullscreen global");
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ struct sway_config *config = NULL;
|
|||
|
||||
static struct xkb_state *keysym_translation_state_create(
|
||||
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(
|
||||
context,
|
||||
&rules,
|
||||
|
@ -280,6 +280,7 @@ static void config_defaults(struct sway_config *config) {
|
|||
config->title_align = ALIGN_LEFT;
|
||||
config->tiling_drag = true;
|
||||
config->tiling_drag_threshold = 9;
|
||||
config->primary_selection = true;
|
||||
|
||||
config->smart_gaps = SMART_GAPS_OFF;
|
||||
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");
|
||||
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 (old_config->swaybg_client != NULL) {
|
||||
wl_client_destroy(old_config->swaybg_client);
|
||||
|
@ -960,23 +966,18 @@ void config_add_swaynag_warning(char *fmt, ...) {
|
|||
if (config->reading && !config->validating) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
size_t length = vsnprintf(NULL, 0, fmt, args) + 1;
|
||||
char *str = vformat_str(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
char *temp = malloc(length + 1);
|
||||
if (!temp) {
|
||||
sway_log(SWAY_ERROR, "Failed to allocate buffer for warning.");
|
||||
if (str == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
va_start(args, fmt);
|
||||
vsnprintf(temp, length, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
swaynag_log(config->swaynag_command, &config->swaynag_config_errors,
|
||||
"Warning on line %i (%s) '%s': %s",
|
||||
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;
|
||||
strncpy(newptr, str, offset);
|
||||
newptr += offset;
|
||||
strncpy(newptr, var->value, vvlen);
|
||||
memcpy(newptr, var->value, vvlen);
|
||||
newptr += vvlen;
|
||||
strcpy(newptr, find + vnlen);
|
||||
free(str);
|
||||
|
|
|
@ -256,7 +256,6 @@ static void invoke_swaybar(struct bar_config *bar) {
|
|||
}
|
||||
|
||||
sway_log(SWAY_DEBUG, "Spawned swaybar %s", bar->id);
|
||||
return;
|
||||
}
|
||||
|
||||
void load_swaybar(struct bar_config *bar) {
|
||||
|
|
|
@ -31,9 +31,11 @@ struct input_config *new_input_config(const char* identifier) {
|
|||
input->middle_emulation = INT_MIN;
|
||||
input->natural_scroll = INT_MIN;
|
||||
input->accel_profile = INT_MIN;
|
||||
input->rotation_angle = FLT_MIN;
|
||||
input->pointer_accel = FLT_MIN;
|
||||
input->scroll_factor = FLT_MIN;
|
||||
input->scroll_button = INT_MIN;
|
||||
input->scroll_button_lock = INT_MIN;
|
||||
input->scroll_method = INT_MIN;
|
||||
input->left_handed = 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) {
|
||||
dst->natural_scroll = src->natural_scroll;
|
||||
}
|
||||
if (src->rotation_angle != FLT_MIN) {
|
||||
dst->rotation_angle = src->rotation_angle;
|
||||
}
|
||||
if (src->pointer_accel != FLT_MIN) {
|
||||
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) {
|
||||
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) {
|
||||
dst->send_events = src->send_events;
|
||||
}
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <wlr/config.h>
|
||||
#include <wlr/types/wlr_cursor.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/backend/drm.h>
|
||||
#include "sway/config.h"
|
||||
#include "sway/input/cursor.h"
|
||||
#include "sway/output.h"
|
||||
|
@ -17,6 +17,10 @@
|
|||
#include "log.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) {
|
||||
const struct output_config *output = item;
|
||||
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) {
|
||||
char *id_on_name = NULL;
|
||||
char id[128];
|
||||
char *name = NULL;
|
||||
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;
|
||||
}
|
||||
struct sway_output *output = all_output_by_name_or_id(oc->name);
|
||||
if (output == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
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
|
||||
// as (int)(1000 * mHz / 1000.f)
|
||||
// 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) {
|
||||
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;
|
||||
int best_diff_mhz = INT_MAX;
|
||||
wl_list_for_each(mode, &output->modes, link) {
|
||||
if (mode->width == width && mode->height == height) {
|
||||
if (mode->refresh == mhz) {
|
||||
best = mode;
|
||||
break;
|
||||
}
|
||||
if (best == NULL || mode->refresh > best->refresh) {
|
||||
int diff_mhz = abs(mode->refresh - mhz);
|
||||
if (diff_mhz < best_diff_mhz) {
|
||||
best_diff_mhz = diff_mhz;
|
||||
best = mode;
|
||||
if (best_diff_mhz == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!best) {
|
||||
sway_log(SWAY_ERROR, "Configured mode for %s not available", output->name);
|
||||
sway_log(SWAY_INFO, "Picking preferred mode instead");
|
||||
best = wlr_output_preferred_mode(output);
|
||||
if (best) {
|
||||
sway_log(SWAY_INFO, "Assigning configured mode (%dx%d@%.3fHz) to %s",
|
||||
best->width, best->height, best->refresh / 1000.f, output->name);
|
||||
} 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);
|
||||
}
|
||||
|
||||
static void set_modeline(struct wlr_output *output,
|
||||
struct wlr_output_state *pending, drmModeModeInfo *drm_mode) {
|
||||
#if WLR_HAS_DRM_BACKEND
|
||||
if (!wlr_output_is_drm(output)) {
|
||||
sway_log(SWAY_ERROR, "Modeline can only be set to DRM output");
|
||||
return;
|
||||
|
@ -295,6 +298,9 @@ static void set_modeline(struct wlr_output *output,
|
|||
if (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
|
||||
|
@ -436,9 +442,11 @@ static void queue_output_config(struct output_config *oc,
|
|||
enum wl_output_transform tr = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
if (oc && oc->transform >= 0) {
|
||||
tr = oc->transform;
|
||||
#if WLR_HAS_DRM_BACKEND
|
||||
} else if (wlr_output_is_drm(wlr_output)) {
|
||||
tr = wlr_drm_connector_get_panel_orientation(wlr_output);
|
||||
sway_log(SWAY_DEBUG, "Auto-detected output transform: %d", tr);
|
||||
#endif
|
||||
}
|
||||
if (wlr_output->transform != 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;
|
||||
if (oc && oc->scale > 0) {
|
||||
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 {
|
||||
scale = compute_default_scale(wlr_output, pending);
|
||||
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};
|
||||
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);
|
||||
if (!wlr_output_commit_state(wlr_output, &pending)) {
|
||||
// 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
|
||||
// this output came online, and some config items (like map_to_output) are
|
||||
// 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.
|
||||
input_manager_configure_xcursor();
|
||||
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_id = NULL;
|
||||
|
||||
size_t length = snprintf(NULL, 0, "%s on %s", identifier, name) + 1;
|
||||
char *id_on_name = malloc(length);
|
||||
snprintf(id_on_name, length, "%s on %s", identifier, name);
|
||||
char *id_on_name = format_str("%s on %s", identifier, name);
|
||||
int i = list_seq_find(config->output_configs, output_name_cmp, id_on_name);
|
||||
if (i >= 0) {
|
||||
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
|
||||
// will be applied during normal "new output" event from wlroots.
|
||||
bool wildcard = strcmp(oc->name, "*") == 0;
|
||||
char id[128];
|
||||
struct sway_output *sway_output, *tmp;
|
||||
wl_list_for_each_safe(sway_output, tmp, &root->all_outputs, link) {
|
||||
char *name = sway_output->wlr_output->name;
|
||||
output_get_identifier(id, sizeof(id), sway_output);
|
||||
if (wildcard || !strcmp(name, oc->name) || !strcmp(id, oc->name)) {
|
||||
if (output_match_name_or_id(sway_output, oc->name)) {
|
||||
char id[128];
|
||||
output_get_identifier(id, sizeof(id), sway_output);
|
||||
struct output_config *current = get_output_config(id, sway_output);
|
||||
if (!current) {
|
||||
// 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);
|
||||
|
||||
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_SUCCESS);
|
||||
|
@ -824,12 +837,13 @@ static bool _spawn_swaybg(char **command) {
|
|||
sway_log_errno(SWAY_ERROR, "close failed");
|
||||
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");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return WIFEXITED(fork_status) && WEXITSTATUS(fork_status) == EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
bool spawn_swaybg(void) {
|
||||
|
|
|
@ -99,7 +99,6 @@ static void seat_attachment_config_free(
|
|||
struct seat_attachment_config *attachment) {
|
||||
free(attachment->identifier);
|
||||
free(attachment);
|
||||
return;
|
||||
}
|
||||
|
||||
static struct seat_attachment_config *seat_attachment_config_copy(
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
bool criteria_is_empty(struct criteria *criteria) {
|
||||
return !criteria->title
|
||||
&& !criteria->shell
|
||||
&& !criteria->all
|
||||
&& !criteria->app_id
|
||||
&& !criteria->con_mark
|
||||
&& !criteria->con_id
|
||||
|
@ -456,6 +457,7 @@ static enum atom_name parse_window_type(const char *type) {
|
|||
#endif
|
||||
|
||||
enum criteria_token {
|
||||
T_ALL,
|
||||
T_APP_ID,
|
||||
T_CON_ID,
|
||||
T_CON_MARK,
|
||||
|
@ -478,7 +480,9 @@ enum criteria_token {
|
|||
};
|
||||
|
||||
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;
|
||||
} else if (strcmp(name, "con_id") == 0) {
|
||||
return T_CON_ID;
|
||||
|
@ -524,8 +528,8 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Require value, unless token is floating or tiled
|
||||
if (!value && token != T_FLOATING && token != T_TILING) {
|
||||
// Require value, unless token is all, floating or tiled
|
||||
if (!value && token != T_ALL && token != T_FLOATING && token != T_TILING) {
|
||||
const char *fmt = "Token '%s' requires a value";
|
||||
int len = strlen(fmt) + strlen(name) - 1;
|
||||
error = malloc(len);
|
||||
|
@ -535,6 +539,9 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
|
|||
|
||||
char *endptr = NULL;
|
||||
switch (token) {
|
||||
case T_ALL:
|
||||
criteria->all = true;
|
||||
break;
|
||||
case T_TITLE:
|
||||
pattern_create(&criteria->title, value);
|
||||
break;
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
Loading…
Reference in a new issue