Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Dmitri Kourennyi 2019-04-01 15:47:56 -04:00
commit 273d4be3c6
37 changed files with 550 additions and 135 deletions

View file

@ -6,14 +6,8 @@ avec i3, **en cours de développement**. Lisez la
IRC](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway sur IRC](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway sur
irc.freenode.net). irc.freenode.net).
[![](https://sr.ht/ICd5.png)](https://sr.ht/ICd5.png) Si vous souhaitez soutenir le développement de Sway, vous pouvez contribuer à [la page
Patreon de SirCmpwn](https://patreon.com/sircmpwn).
Si vous souhaitez soutenir le développement de Sway, vous pouvez contribuer à [ma page
Patreon](https://patreon.com/sircmpwn) ou aux [primes](https://github.com/swaywm/sway/issues/986)
pour des fonctionnalités spécifiques.
Tout le monde est invité à réclamer une prime et vous pouvez donner une prime pour n'importe quelle
fonctionnalité souhaitée. Patreon est plus utile pour supporter l'état général et la
maintenance de Sway.
## Aide en français ## Aide en français
@ -39,21 +33,21 @@ IRC ou envoyez un e-mail à sir@cmpwn.com (en anglais seulement) pour des consei
Installez les dépendances : Installez les dépendances :
* meson * meson \*
* [wlc](https://github.com/Cloudef/wlc) * [wlroots](https://github.com/swaywm/wlroots)
* wayland * wayland
* xwayland * wayland-protocols \*
* libinput >= 1.6.0
* libcap
* pcre * pcre
* json-c >= 0.13 * json-c
* pango * pango
* cairo * cairo
* gdk-pixbuf2 * * gdk-pixbuf2 \*\*
* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (requis pour les pages man) * [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (optionnel: requis pour les pages man) \*
* git * git \*
_\*Uniquement requis pour swaybar, swaybg_ _\*Requis uniquement pour la compilation_
_\*\*Optionnel: requis uniquement pour swaybg_
Exécutez ces commandes : Exécutez ces commandes :
@ -65,6 +59,8 @@ Sur les systèmes sans logind, vous devez suid le binaire de sway :
sudo chmod a+s /usr/local/bin/sway sudo chmod a+s /usr/local/bin/sway
Sway se débarassera des permissions *root* peu de temps après le démarrage.
## Configuration ## Configuration
Si vous utilisez déjà i3, copiez votre configuration i3 à `~/.config/sway/config` et Si vous utilisez déjà i3, copiez votre configuration i3 à `~/.config/sway/config` et
@ -72,10 +68,6 @@ cela va fonctionner. Sinon, copiez l'exemple de fichier de configuration à
`~/.config/sway/config`. Il se trouve généralement dans `/etc/sway/config`. `~/.config/sway/config`. Il se trouve généralement dans `/etc/sway/config`.
Exécutez `man 5 sway` pour l'information sur la configuration. Exécutez `man 5 sway` pour l'information sur la configuration.
Mes propres dotfiles sont disponibles [ici](https://git.sr.ht/~sircmpwn/dotfiles) si
vous voulez un peu d'inspiration. Je vous recommande aussi de consulter le
[wiki](https://github.com/swaywm/sway/wiki).
## Exécution ## Exécution
Exécutez `sway` à partir d'un TTY. Certains gestionnaires d'affichage peuvent fonctionner, Exécutez `sway` à partir d'un TTY. Certains gestionnaires d'affichage peuvent fonctionner,

View file

@ -2,7 +2,7 @@
[**English**](https://github.com/swaywm/sway/blob/master/README.md#sway--) - [日本語](https://github.com/swaywm/sway/blob/master/README.ja.md#sway--) - [Deutsch](https://github.com/swaywm/sway/blob/master/README.de.md#sway--) - [Ελληνικά](https://github.com/swaywm/sway/blob/master/README.el.md#sway--) - [Français](https://github.com/swaywm/sway/blob/master/README.fr.md#sway--) - [Українська](https://github.com/swaywm/sway/blob/master/README.uk.md#sway--) - [Italiano](https://github.com/swaywm/sway/blob/master/README.it.md#sway--) - [Português](https://github.com/swaywm/sway/blob/master/README.pt.md#sway--) - [**English**](https://github.com/swaywm/sway/blob/master/README.md#sway--) - [日本語](https://github.com/swaywm/sway/blob/master/README.ja.md#sway--) - [Deutsch](https://github.com/swaywm/sway/blob/master/README.de.md#sway--) - [Ελληνικά](https://github.com/swaywm/sway/blob/master/README.el.md#sway--) - [Français](https://github.com/swaywm/sway/blob/master/README.fr.md#sway--) - [Українська](https://github.com/swaywm/sway/blob/master/README.uk.md#sway--) - [Italiano](https://github.com/swaywm/sway/blob/master/README.it.md#sway--) - [Português](https://github.com/swaywm/sway/blob/master/README.pt.md#sway--) -
[Русский](https://github.com/swaywm/sway/blob/master/README.ru.md#sway--) - [Български](https://github.com/swaywm/sway/blob/master/README.bg.md#sway--) - [Español](https://github.com/swaywm/sway/blob/master/README.es.md#sway--) - [Русский](https://github.com/swaywm/sway/blob/master/README.ru.md#sway--) - [Български](https://github.com/swaywm/sway/blob/master/README.bg.md#sway--) - [Español](https://github.com/swaywm/sway/blob/master/README.es.md#sway--) -
[Polski](https://github.com/swaywm/sway/blob/master/README.pl.md#sway--) [Polski](https://github.com/swaywm/sway/blob/master/README.pl.md#sway--) - [中文-简体](https://github.com/swaywm/sway/blob/master/README-zh-CN.md#sway--)
sway is an i3-compatible [Wayland](http://wayland.freedesktop.org/) compositor. sway is an i3-compatible [Wayland](http://wayland.freedesktop.org/) compositor.
Read the [FAQ](https://github.com/swaywm/sway/wiki). Join the [IRC Read the [FAQ](https://github.com/swaywm/sway/wiki). Join the [IRC

View file

@ -1,20 +1,12 @@
# sway # sway
**Sway** це сумісний з i3 композитор [Wayland](http://wayland.freedesktop.org/) Sway це сумісний з i3 композитор [Wayland](http://wayland.freedesktop.org/).
(**у стані розробки**). Ознайомтесь з Ознайомтесь з [ЧаПами](https://github.com/swaywm/sway/wiki). Приєднуйтесь до [спільноти в
[ЧаПами](https://github.com/swaywm/sway/wiki). Приєднуйтесь до [спільноти в
IRC](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway на IRC](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway на
irc.freenode.net). irc.freenode.net).
[![](https://sr.ht/ICd5.png)](https://sr.ht/ICd5.png) Якщо ви маєте бажання підтримати розробку sway, ви можете зробити свій внесок на сторінці
[SirCmpwn у Patreon](https://patreon.com/sircmpwn).
Якщо ви хочете підтримати розробку Sway, ви можете зробити свій внесок у
[SirCmpwn'ову сторінку Patreon](https://patreon.com/sircmpwn) або до
[фонду винагород](https://github.com/swaywm/sway/issues/986) за реалізацію
певного функціоналу.
Кожен може виставити винагороду за реалізацію довільної функції
(і, відповідно, забрати її собі, виконавши це завдання);
кошти від сторінки Patreon підтримують загальну розробку та підтримку Sway.
## Підтримка українською мовою ## Підтримка українською мовою
@ -39,28 +31,28 @@ Sway доступний у багатьох дистрибутивах Linux (а
для інформації щодо встановлення на вашому дистрибутиві. для інформації щодо встановлення на вашому дистрибутиві.
Якщо ви готові та зацікавлені запакувати і підтримувати Sway у вашому Якщо ви готові та зацікавлені запакувати і підтримувати Sway у вашому
дистрибутиві, будемо раді вас бачити у нашому каналі IRC. Ви також можете дистрибутиві, звертайтесь за порадами до нашого каналу в IRC або
спитати порад за адресою sir@cmpwn.com. пишіть на електронну пошту [sir@cmpwn.com](mailto:sir@cmpwn.com).
### З вихідного коду ### З вихідного коду
Встановіть залежності: Встановіть залежності:
* meson * meson \*
* [wlc](https://github.com/Cloudef/wlc) * [wlroots](https://github.com/swaywm/wlroots)
* wayland * wayland
* xwayland * wayland-protocols \*
* libinput >= 1.6.0
* libcap
* pcre * pcre
* json-c >= 0.13 * json-c
* pango * pango
* cairo * cairo
* gdk-pixbuf2 * * gdk-pixbuf2 \*\*
* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (required for man pages) * [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (необов'язково, необхідно для сторінок man) \*
* git * git \*
_\*Лише для swaybar, swaybg_ _\*Лише для компіляції_
_\*\*Необов'язково, необхідно для swaybg_
Виконайте ці команди: Виконайте ці команди:
@ -68,15 +60,12 @@ _\*Лише для swaybar, swaybg_
ninja -C build ninja -C build
sudo ninja -C build install sudo ninja -C build install
На системах **з** logind, варто встановити декілька можливостей (caps) На системах без logind, необхідно встановити біт SUID на виконуваний файл sway:
на виконуваний файл sway:
sudo setcap "cap_sys_ptrace,cap_sys_tty_config=eip" /usr/local/bin/sway
На системах **без** logind, необхідно встановити біт SUID на виконуваний файл sway:
sudo chmod a+s /usr/local/bin/sway sudo chmod a+s /usr/local/bin/sway
Sway втратить права доступу root незабаром після запуску.
## Налаштування ## Налаштування
Якщо ви вже використовуєте i3, скопіюйте свій файл налаштувань Якщо ви вже використовуєте i3, скопіюйте свій файл налаштувань

68
README.zh-CN.md Normal file
View file

@ -0,0 +1,68 @@
# sway
sway 是和 i3 兼容的 [Wayland](http://wayland.freedesktop.org/) compositor.
阅读 [FAQ](https://github.com/swaywm/sway/wiki). 加入 [IRC
频道](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on
irc.freenode.net).
如果你想要支持 sway 的发展, 请到 [SirCmpwn's
Patreon page](https://patreon.com/sircmpwn)贡献.
## 发布签名
发布是以 [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) 签名
并发布在 [GitHub](https://github.com/swaywm/sway/releases).
## 安装
### 从软件包中
Sway 在很多发行版中可用. 尝试在你的发行版中安装 "sway" 包.
如何这不可用, 请到 [此 wiki 页](https://github.com/swaywm/sway/wiki/Unsupported-packages)
检查针对你的发行版关于安装的信息.
如果你有兴趣给你的发行版打包 sway, 停下来到 IRC 频道或者发邮件至 sir@cmpwn.com 获取建议.
### 从源代码编译
安装依赖:
* meson \*
* [wlroots](https://github.com/swaywm/wlroots)
* wayland
* wayland-protocols \*
* pcre
* json-c
* pango
* cairo
* gdk-pixbuf2 \*\*
* [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (可选的: man pages) \*
* git \*
_\*编译时依赖_
_\*\*可选的: swaybg 依赖_
运行这些命令:
meson build
ninja -C build
sudo ninja -C build install
在没有 logind 的系统上, 你需要给 sway 二进制设置 suid:
sudo chmod a+s /usr/local/bin/sway
Sway 将会在启动后尽快丢掉 root 权限.
## 配置
如果你已经在使用 i3, 接下来复制你的 i3 配置到 `~/.config/sway/config`
它可以直接工作. 或者, 复制样本配置文件到
`~/.config/sway/config`. 它通常位于 `/etc/sway/config`.
运行 `man 5 sway` 获取关于配置的信息.
## 运行
从 TTY 中运行 `sway` . 某些显示管理器可能会工作但并不被 sway 支持
(已知的 gdm 工作得非常好).

View file

@ -4,6 +4,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
#include <wayland-server-protocol.h>
#include "log.h" #include "log.h"
#include "util.h" #include "util.h"
@ -54,3 +55,23 @@ float parse_float(const char *value) {
} }
return flt; return flt;
} }
const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel) {
switch (subpixel) {
case WL_OUTPUT_SUBPIXEL_UNKNOWN:
return "unknown";
case WL_OUTPUT_SUBPIXEL_NONE:
return "none";
case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB:
return "rgb";
case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR:
return "bgr";
case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB:
return "vrgb";
case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR:
return "vbgr";
}
sway_assert(false, "Unknown value for wl_output_subpixel.");
return NULL;
}

View file

@ -136,6 +136,7 @@ sway_cmd cmd_fullscreen;
sway_cmd cmd_gaps; sway_cmd cmd_gaps;
sway_cmd cmd_hide_edge_borders; sway_cmd cmd_hide_edge_borders;
sway_cmd cmd_include; sway_cmd cmd_include;
sway_cmd cmd_inhibit_idle;
sway_cmd cmd_input; sway_cmd cmd_input;
sway_cmd cmd_seat; sway_cmd cmd_seat;
sway_cmd cmd_ipc; sway_cmd cmd_ipc;
@ -261,6 +262,7 @@ sway_cmd output_cmd_enable;
sway_cmd output_cmd_mode; sway_cmd output_cmd_mode;
sway_cmd output_cmd_position; sway_cmd output_cmd_position;
sway_cmd output_cmd_scale; sway_cmd output_cmd_scale;
sway_cmd output_cmd_subpixel;
sway_cmd output_cmd_transform; sway_cmd output_cmd_transform;
sway_cmd seat_cmd_attach; sway_cmd seat_cmd_attach;

View file

@ -184,6 +184,7 @@ struct output_config {
int x, y; int x, y;
float scale; float scale;
int32_t transform; int32_t transform;
enum wl_output_subpixel subpixel;
char *background; char *background;
char *background_option; char *background_option;

View file

@ -20,6 +20,7 @@ struct criteria {
char *cmdlist; char *cmdlist;
char *target; // workspace or output name for `assign` criteria char *target; // workspace or output name for `assign` criteria
bool autofail; // __focused__ while no focus or n/a for focused view
pcre *title; pcre *title;
pcre *shell; pcre *shell;
pcre *app_id; pcre *app_id;

View file

@ -4,6 +4,14 @@
#include <wlr/types/wlr_idle.h> #include <wlr/types/wlr_idle.h>
#include "sway/server.h" #include "sway/server.h"
enum sway_idle_inhibit_mode {
INHIBIT_IDLE_APPLICATION, // Application set inhibitor (when visible)
INHIBIT_IDLE_FOCUS, // User set inhibitor when focused
INHIBIT_IDLE_FULLSCREEN, // User set inhibitor when fullscreen + visible
INHIBIT_IDLE_OPEN, // User set inhibitor while open
INHIBIT_IDLE_VISIBLE // User set inhibitor when visible
};
struct sway_idle_inhibit_manager_v1 { struct sway_idle_inhibit_manager_v1 {
struct wlr_idle_inhibit_manager_v1 *wlr_manager; struct wlr_idle_inhibit_manager_v1 *wlr_manager;
struct wl_listener new_idle_inhibitor_v1; struct wl_listener new_idle_inhibitor_v1;
@ -15,14 +23,24 @@ struct sway_idle_inhibit_manager_v1 {
struct sway_idle_inhibitor_v1 { struct sway_idle_inhibitor_v1 {
struct sway_idle_inhibit_manager_v1 *manager; struct sway_idle_inhibit_manager_v1 *manager;
struct sway_view *view; struct sway_view *view;
enum sway_idle_inhibit_mode mode;
struct wl_list link; struct wl_list link;
struct wl_listener destroy; struct wl_listener destroy;
}; };
void idle_inhibit_v1_check_active( void sway_idle_inhibit_v1_check_active(
struct sway_idle_inhibit_manager_v1 *manager); struct sway_idle_inhibit_manager_v1 *manager);
void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view,
enum sway_idle_inhibit_mode mode);
struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_inhibitor_for_view(
struct sway_view *view);
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 sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create(
struct wl_display *wl_display, struct wlr_idle *idle); struct wl_display *wl_display, struct wlr_idle *idle);
#endif #endif

View file

@ -31,6 +31,7 @@ struct sway_output {
int lx, ly; // layout coords int lx, ly; // layout coords
int width, height; // transformed buffer size int width, height; // transformed buffer size
enum wl_output_subpixel detected_subpixel;
bool enabled, configured; bool enabled, configured;
list_t *workspaces; list_t *workspaces;

View file

@ -215,10 +215,9 @@ size_t container_titlebar_height(void);
void floating_calculate_constraints(int *min_width, int *max_width, void floating_calculate_constraints(int *min_width, int *max_width,
int *min_height, int *max_height); int *min_height, int *max_height);
/** void container_floating_resize_and_center(struct sway_container *con);
* Resize and center the container in its workspace.
*/ void container_floating_set_default_size(struct sway_container *con);
void container_init_floating(struct sway_container *container);
void container_set_floating(struct sway_container *container, bool enable); void container_set_floating(struct sway_container *container, bool enable);

View file

@ -85,4 +85,6 @@ struct sway_container *root_find_container(
void root_get_box(struct sway_root *root, struct wlr_box *box); void root_get_box(struct sway_root *root, struct wlr_box *box);
void root_rename_pid_workspaces(const char *old_name, const char *new_name);
#endif #endif

View file

@ -3,6 +3,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <wayland-server-protocol.h>
/** /**
* Wrap i into the range [0, max[ * Wrap i into the range [0, max[
@ -29,4 +30,6 @@ bool parse_boolean(const char *boolean, bool current);
*/ */
float parse_float(const char *value); float parse_float(const char *value);
const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel);
#endif #endif

View file

@ -112,6 +112,7 @@ static struct cmd_handler command_handlers[] = {
{ "exit", cmd_exit }, { "exit", cmd_exit },
{ "floating", cmd_floating }, { "floating", cmd_floating },
{ "fullscreen", cmd_fullscreen }, { "fullscreen", cmd_fullscreen },
{ "inhibit_idle", cmd_inhibit_idle },
{ "kill", cmd_kill }, { "kill", cmd_kill },
{ "layout", cmd_layout }, { "layout", cmd_layout },
{ "mark", cmd_mark }, { "mark", cmd_mark },
@ -276,7 +277,6 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
// Var replacement, for all but first argument of set // Var replacement, for all but first argument of set
for (int i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) { for (int i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) {
argv[i] = do_var_replacement(argv[i]); argv[i] = do_var_replacement(argv[i]);
unescape_string(argv[i]);
} }
if (!config->handler_context.using_criteria) { if (!config->handler_context.using_criteria) {

View file

@ -316,7 +316,7 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
struct sway_binding *config_binding = mode_bindings->items[i]; struct sway_binding *config_binding = mode_bindings->items[i];
if (binding_key_compare(binding, config_binding)) { if (binding_key_compare(binding, config_binding)) {
sway_log(SWAY_INFO, "Overwriting binding '%s' for device '%s' " sway_log(SWAY_INFO, "Overwriting binding '%s' for device '%s' "
"from `%s` to `%s`", argv[0], binding->input, "to `%s` from `%s`", argv[0], binding->input,
binding->command, config_binding->command); binding->command, config_binding->command);
if (warn) { if (warn) {
config_add_swaynag_warning("Overwriting binding" config_add_swaynag_warning("Overwriting binding"
@ -420,7 +420,7 @@ struct cmd_results *cmd_bindswitch(int argc, char **argv) {
for (int i = 0; i < mode_bindings->length; ++i) { for (int i = 0; i < mode_bindings->length; ++i) {
struct sway_switch_binding *config_binding = mode_bindings->items[i]; struct sway_switch_binding *config_binding = mode_bindings->items[i];
if (binding_switch_compare(binding, config_binding)) { if (binding_switch_compare(binding, config_binding)) {
sway_log(SWAY_INFO, "Overwriting binding '%s' from `%s` to `%s`", sway_log(SWAY_INFO, "Overwriting binding '%s' to `%s` from `%s`",
argv[0], binding->command, config_binding->command); argv[0], binding->command, config_binding->command);
if (warn) { if (warn) {
config_add_swaynag_warning("Overwriting binding" config_add_swaynag_warning("Overwriting binding"

View file

@ -45,7 +45,10 @@ struct cmd_results *cmd_floating(int argc, char **argv) {
container_set_floating(container, wants_floating); container_set_floating(container, wants_floating);
// Floating containers in the scratchpad should be ignored
if (container->workspace) {
arrange_workspace(container->workspace); arrange_workspace(container->workspace);
}
return cmd_results_new(CMD_SUCCESS, NULL); return cmd_results_new(CMD_SUCCESS, NULL);
} }

View file

@ -0,0 +1,51 @@
#include <string.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/desktop/idle_inhibit_v1.h"
#include "sway/tree/container.h"
#include "sway/tree/view.h"
struct cmd_results *cmd_inhibit_idle(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "inhibit_idle", EXPECTED_EQUAL_TO, 1))) {
return error;
}
struct sway_container *con = config->handler_context.container;
if (!con || !con->view) {
return cmd_results_new(CMD_INVALID,
"Only views can have idle inhibitors");
}
bool clear = false;
enum sway_idle_inhibit_mode mode;
if (strcmp(argv[0], "focus") == 0) {
mode = INHIBIT_IDLE_FOCUS;
} else if (strcmp(argv[0], "fullscreen") == 0) {
mode = INHIBIT_IDLE_FULLSCREEN;
} else if (strcmp(argv[0], "open") == 0) {
mode = INHIBIT_IDLE_OPEN;
} else if (strcmp(argv[0], "none") == 0) {
clear = true;
} else if (strcmp(argv[0], "visible") == 0) {
mode = INHIBIT_IDLE_VISIBLE;
} else {
return cmd_results_new(CMD_INVALID,
"Expected `inhibit_idle focus|fullscreen|open|none|visible`");
}
struct sway_idle_inhibitor_v1 *inhibitor =
sway_idle_inhibit_v1_user_inhibitor_for_view(con->view);
if (inhibitor) {
if (clear) {
sway_idle_inhibit_v1_user_inhibitor_destroy(inhibitor);
} else {
inhibitor->mode = mode;
sway_idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
}
} else if (!clear) {
sway_idle_inhibit_v1_user_inhibitor_register(con->view, mode);
}
return cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -13,7 +13,8 @@
static struct cmd_handler mode_handlers[] = { static struct cmd_handler mode_handlers[] = {
{ "bindcode", cmd_bindcode }, { "bindcode", cmd_bindcode },
{ "bindswitch", cmd_bindswitch }, { "bindswitch", cmd_bindswitch },
{ "bindsym", cmd_bindsym } { "bindsym", cmd_bindsym },
{ "set", cmd_set },
}; };
struct cmd_results *cmd_mode(int argc, char **argv) { struct cmd_results *cmd_mode(int argc, char **argv) {

View file

@ -18,6 +18,7 @@ static struct cmd_handler output_handlers[] = {
{ "res", output_cmd_mode }, { "res", output_cmd_mode },
{ "resolution", output_cmd_mode }, { "resolution", output_cmd_mode },
{ "scale", output_cmd_scale }, { "scale", output_cmd_scale },
{ "subpixel", output_cmd_subpixel },
{ "transform", output_cmd_transform }, { "transform", output_cmd_transform },
}; };

View file

@ -0,0 +1,36 @@
#include <string.h>
#include "log.h"
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/output.h"
struct cmd_results *output_cmd_subpixel(int argc, char **argv) {
if (!config->handler_context.output_config) {
return cmd_results_new(CMD_FAILURE, "Missing output config");
}
if (!argc) {
return cmd_results_new(CMD_INVALID, "Missing subpixel argument.");
}
enum wl_output_subpixel subpixel;
if (strcmp(*argv, "rgb") == 0) {
subpixel = WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
} else if (strcmp(*argv, "bgr") == 0) {
subpixel = WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
} else if (strcmp(*argv, "vrgb") == 0) {
subpixel = WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
} else if (strcmp(*argv, "vbgr") == 0) {
subpixel = WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
} else if (strcmp(*argv, "none") == 0) {
subpixel = WL_OUTPUT_SUBPIXEL_NONE;
} else {
return cmd_results_new(CMD_INVALID, "Invalid output subpixel.");
}
struct output_config *oc = config->handler_context.output_config;
config->handler_context.leftovers.argc = argc - 1;
config->handler_context.leftovers.argv = argv + 1;
oc->subpixel = subpixel;
return NULL;
}

View file

@ -9,6 +9,7 @@
#include "sway/output.h" #include "sway/output.h"
#include "sway/tree/container.h" #include "sway/tree/container.h"
#include "sway/tree/workspace.h" #include "sway/tree/workspace.h"
#include "sway/tree/root.h"
static const char expected_syntax[] = static const char expected_syntax[] =
"Expected 'rename workspace <old_name> to <new_name>' or " "Expected 'rename workspace <old_name> to <new_name>' or "
@ -89,6 +90,9 @@ struct cmd_results *cmd_rename(int argc, char **argv) {
} }
sway_log(SWAY_DEBUG, "renaming workspace '%s' to '%s'", workspace->name, new_name); sway_log(SWAY_DEBUG, "renaming workspace '%s' to '%s'", workspace->name, new_name);
root_rename_pid_workspaces(workspace->name, new_name);
free(workspace->name); free(workspace->name);
workspace->name = new_name; workspace->name = new_name;

View file

@ -8,10 +8,11 @@
#include <unistd.h> #include <unistd.h>
#include <wlr/types/wlr_output_layout.h> #include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output.h> #include <wlr/types/wlr_output.h>
#include "log.h"
#include "sway/config.h" #include "sway/config.h"
#include "sway/output.h" #include "sway/output.h"
#include "sway/tree/root.h" #include "sway/tree/root.h"
#include "log.h"
#include "util.h"
int output_name_cmp(const void *item, const void *data) { int output_name_cmp(const void *item, const void *data) {
const struct output_config *output = item; const struct output_config *output = item;
@ -43,6 +44,7 @@ struct output_config *new_output_config(const char *name) {
oc->x = oc->y = -1; oc->x = oc->y = -1;
oc->scale = -1; oc->scale = -1;
oc->transform = -1; oc->transform = -1;
oc->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
return oc; return oc;
} }
@ -65,6 +67,9 @@ void merge_output_config(struct output_config *dst, struct output_config *src) {
if (src->scale != -1) { if (src->scale != -1) {
dst->scale = src->scale; dst->scale = src->scale;
} }
if (src->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN) {
dst->subpixel = src->subpixel;
}
if (src->refresh_rate != -1) { if (src->refresh_rate != -1) {
dst->refresh_rate = src->refresh_rate; dst->refresh_rate = src->refresh_rate;
} }
@ -187,10 +192,10 @@ struct output_config *store_output_config(struct output_config *oc) {
} }
sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz " sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
"position %d,%d scale %f transform %d) (bg %s %s) (dpms %d)", "position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (dpms %d)",
oc->name, oc->enabled, oc->width, oc->height, oc->refresh_rate, oc->name, oc->enabled, oc->width, oc->height, oc->refresh_rate,
oc->x, oc->y, oc->scale, oc->transform, oc->background, oc->x, oc->y, oc->scale, sway_wl_output_subpixel_to_string(oc->subpixel),
oc->background_option, oc->dpms_state); oc->transform, oc->background, oc->background_option, oc->dpms_state);
return oc; return oc;
} }
@ -363,6 +368,14 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
sway_log(SWAY_DEBUG, "Set %s scale to %f", oc->name, oc->scale); sway_log(SWAY_DEBUG, "Set %s scale to %f", oc->name, oc->scale);
wlr_output_set_scale(wlr_output, oc->scale); wlr_output_set_scale(wlr_output, oc->scale);
} }
if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) {
sway_log(SWAY_DEBUG, "Set %s subpixel to %s", oc->name,
sway_wl_output_subpixel_to_string(oc->subpixel));
wlr_output_set_subpixel(wlr_output, oc->subpixel);
output_damage_whole(output);
}
if (oc && oc->transform >= 0) { if (oc && oc->transform >= 0) {
sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, oc->transform); sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, oc->transform);
wlr_output_set_transform(wlr_output, oc->transform); wlr_output_set_transform(wlr_output, oc->transform);
@ -424,6 +437,8 @@ static void default_output_config(struct output_config *oc,
} }
oc->x = oc->y = -1; oc->x = oc->y = -1;
oc->scale = 1; oc->scale = 1;
struct sway_output *output = wlr_output->data;
oc->subpixel = output->detected_subpixel;
oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
oc->dpms_state = DPMS_ON; oc->dpms_state = DPMS_ON;
} }

View file

@ -16,7 +16,8 @@
#include "config.h" #include "config.h"
bool criteria_is_empty(struct criteria *criteria) { bool criteria_is_empty(struct criteria *criteria) {
return !criteria->title return !criteria->autofail
&& !criteria->title
&& !criteria->shell && !criteria->shell
&& !criteria->app_id && !criteria->app_id
&& !criteria->con_mark && !criteria->con_mark
@ -98,6 +99,10 @@ static void find_urgent_iterator(struct sway_container *con, void *data) {
static bool criteria_matches_view(struct criteria *criteria, static bool criteria_matches_view(struct criteria *criteria,
struct sway_view *view) { struct sway_view *view) {
if (criteria->autofail) {
return false;
}
if (criteria->title) { if (criteria->title) {
const char *title = view_get_title(view); const char *title = view_get_title(view);
if (!title || regex_cmp(title, criteria->title) != 0) { if (!title || regex_cmp(title, criteria->title) != 0) {
@ -366,50 +371,66 @@ static enum criteria_token token_from_name(char *name) {
* using criteria via IPC. Using __focused__ in config is not useful because * using criteria via IPC. Using __focused__ in config is not useful because
* criteria is only executed once per view. * criteria is only executed once per view.
*/ */
static char *get_focused_prop(enum criteria_token token) { static char *get_focused_prop(enum criteria_token token, bool *autofail) {
struct sway_seat *seat = input_manager_current_seat(); struct sway_seat *seat = input_manager_current_seat();
struct sway_container *focus = seat_get_focused_container(seat); struct sway_container *focus = seat_get_focused_container(seat);
if (!focus || !focus->view) { struct sway_view *view = focus ? focus->view : NULL;
return NULL;
}
struct sway_view *view = focus->view;
const char *value = NULL; const char *value = NULL;
switch (token) { switch (token) {
case T_APP_ID: case T_APP_ID:
*autofail = true;
if (view) {
value = view_get_app_id(view); value = view_get_app_id(view);
}
break; break;
case T_SHELL: case T_SHELL:
*autofail = true;
if (view) {
value = view_get_shell(view); value = view_get_shell(view);
}
break; break;
case T_TITLE: case T_TITLE:
*autofail = true;
if (view) {
value = view_get_title(view); value = view_get_title(view);
}
break; break;
case T_WORKSPACE: case T_WORKSPACE:
if (focus->workspace) { *autofail = true;
if (focus && focus->workspace) {
value = focus->workspace->name; value = focus->workspace->name;
} }
break; break;
case T_CON_ID: case T_CON_ID:
if (view->container == NULL) { *autofail = true;
return NULL; if (view && view->container) {
}
size_t id = view->container->node.id; size_t id = view->container->node.id;
size_t id_size = snprintf(NULL, 0, "%zu", id) + 1; size_t id_size = snprintf(NULL, 0, "%zu", id) + 1;
char *id_str = malloc(id_size); char *id_str = malloc(id_size);
snprintf(id_str, id_size, "%zu", id); snprintf(id_str, id_size, "%zu", id);
value = id_str; value = id_str;
}
break; break;
#if HAVE_XWAYLAND #if HAVE_XWAYLAND
case T_CLASS: case T_CLASS:
*autofail = true;
if (view) {
value = view_get_class(view); value = view_get_class(view);
}
break; break;
case T_INSTANCE: case T_INSTANCE:
*autofail = true;
if (view) {
value = view_get_instance(view); value = view_get_instance(view);
}
break; break;
case T_WINDOW_ROLE: case T_WINDOW_ROLE:
*autofail = true;
if (view) {
value = view_get_window_role(view); value = view_get_window_role(view);
}
break; break;
case T_WINDOW_TYPE: // These do not support __focused__ case T_WINDOW_TYPE: // These do not support __focused__
case T_ID: case T_ID:
@ -419,6 +440,7 @@ static char *get_focused_prop(enum criteria_token token) {
case T_TILING: case T_TILING:
case T_URGENT: case T_URGENT:
case T_INVALID: case T_INVALID:
*autofail = false;
break; break;
} }
if (value) { if (value) {
@ -439,7 +461,12 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
char *effective_value = NULL; char *effective_value = NULL;
if (value && strcmp(value, "__focused__") == 0) { if (value && strcmp(value, "__focused__") == 0) {
effective_value = get_focused_prop(token); bool autofail = false;
effective_value = get_focused_prop(token, &autofail);
if (!effective_value && autofail) {
criteria->autofail = true;
return true;
}
} else if (value) { } else if (value) {
effective_value = strdup(value); effective_value = strdup(value);
} }

View file

@ -2,18 +2,24 @@
#include <wlr/types/wlr_idle.h> #include <wlr/types/wlr_idle.h>
#include "log.h" #include "log.h"
#include "sway/desktop/idle_inhibit_v1.h" #include "sway/desktop/idle_inhibit_v1.h"
#include "sway/input/seat.h"
#include "sway/tree/container.h"
#include "sway/tree/view.h" #include "sway/tree/view.h"
#include "sway/server.h" #include "sway/server.h"
static void destroy_inhibitor(struct sway_idle_inhibitor_v1 *inhibitor) {
wl_list_remove(&inhibitor->link);
wl_list_remove(&inhibitor->destroy.link);
sway_idle_inhibit_v1_check_active(inhibitor->manager);
free(inhibitor);
}
static void handle_destroy(struct wl_listener *listener, void *data) { static void handle_destroy(struct wl_listener *listener, void *data) {
struct sway_idle_inhibitor_v1 *inhibitor = struct sway_idle_inhibitor_v1 *inhibitor =
wl_container_of(listener, inhibitor, destroy); wl_container_of(listener, inhibitor, destroy);
sway_log(SWAY_DEBUG, "Sway idle inhibitor destroyed"); sway_log(SWAY_DEBUG, "Sway idle inhibitor destroyed");
wl_list_remove(&inhibitor->link); destroy_inhibitor(inhibitor);
wl_list_remove(&inhibitor->destroy.link);
idle_inhibit_v1_check_active(inhibitor->manager);
free(inhibitor);
} }
void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) { void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) {
@ -29,28 +35,93 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) {
} }
inhibitor->manager = manager; inhibitor->manager = manager;
inhibitor->mode = INHIBIT_IDLE_APPLICATION;
inhibitor->view = view_from_wlr_surface(wlr_inhibitor->surface); inhibitor->view = view_from_wlr_surface(wlr_inhibitor->surface);
wl_list_insert(&manager->inhibitors, &inhibitor->link); wl_list_insert(&manager->inhibitors, &inhibitor->link);
inhibitor->destroy.notify = handle_destroy; inhibitor->destroy.notify = handle_destroy;
wl_signal_add(&wlr_inhibitor->events.destroy, &inhibitor->destroy); wl_signal_add(&wlr_inhibitor->events.destroy, &inhibitor->destroy);
idle_inhibit_v1_check_active(manager); sway_idle_inhibit_v1_check_active(manager);
} }
void idle_inhibit_v1_check_active( void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view,
enum sway_idle_inhibit_mode mode) {
struct sway_idle_inhibitor_v1 *inhibitor =
calloc(1, sizeof(struct sway_idle_inhibitor_v1));
if (!inhibitor) {
return;
}
inhibitor->manager = server.idle_inhibit_manager_v1;
inhibitor->mode = mode;
inhibitor->view = view;
wl_list_insert(&inhibitor->manager->inhibitors, &inhibitor->link);
inhibitor->destroy.notify = handle_destroy;
wl_signal_add(&view->events.unmap, &inhibitor->destroy);
sway_idle_inhibit_v1_check_active(inhibitor->manager);
}
struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_inhibitor_for_view(
struct sway_view *view) {
struct sway_idle_inhibitor_v1 *inhibitor;
wl_list_for_each(inhibitor, &server.idle_inhibit_manager_v1->inhibitors,
link) {
if (inhibitor->view == view &&
inhibitor->mode != INHIBIT_IDLE_APPLICATION) {
return inhibitor;
}
}
return NULL;
}
void sway_idle_inhibit_v1_user_inhibitor_destroy(
struct sway_idle_inhibitor_v1 *inhibitor) {
if (!inhibitor) {
return;
}
if (!sway_assert(inhibitor->mode != INHIBIT_IDLE_APPLICATION,
"User should not be able to destroy application inhibitor")) {
return;
}
destroy_inhibitor(inhibitor);
}
static bool check_active(struct sway_idle_inhibitor_v1 *inhibitor) {
switch (inhibitor->mode) {
case INHIBIT_IDLE_APPLICATION:
// If there is no view associated with the inhibitor, assume visible
return !inhibitor->view || view_is_visible(inhibitor->view);
case INHIBIT_IDLE_FOCUS:;
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &server.input->seats, link) {
struct sway_container *con = seat_get_focused_container(seat);
if (con && con->view && con->view == inhibitor->view) {
return true;
}
}
return false;
case INHIBIT_IDLE_FULLSCREEN:
return inhibitor->view->container &&
container_is_fullscreen_or_child(inhibitor->view->container) &&
view_is_visible(inhibitor->view);
case INHIBIT_IDLE_OPEN:
// Inhibitor is destroyed on unmap so it must be open/mapped
return true;
case INHIBIT_IDLE_VISIBLE:
return view_is_visible(inhibitor->view);
}
return false;
}
void sway_idle_inhibit_v1_check_active(
struct sway_idle_inhibit_manager_v1 *manager) { struct sway_idle_inhibit_manager_v1 *manager) {
struct sway_idle_inhibitor_v1 *inhibitor; struct sway_idle_inhibitor_v1 *inhibitor;
bool inhibited = false; bool inhibited = false;
wl_list_for_each(inhibitor, &manager->inhibitors, link) { wl_list_for_each(inhibitor, &manager->inhibitors, link) {
if (!inhibitor->view || !inhibitor->view->container) { if ((inhibited = check_active(inhibitor))) {
/* Cannot guess if view is visible so assume it is */
inhibited = true;
break;
}
if (view_is_visible(inhibitor->view)) {
inhibited = true;
break; break;
} }
} }

View file

@ -349,7 +349,7 @@ static void transaction_progress_queue(void) {
list_del(server.transactions, 0); list_del(server.transactions, 0);
if (!server.transactions->length) { if (!server.transactions->length) {
idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); sway_idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
return; return;
} }

View file

@ -435,7 +435,7 @@ static void handle_request_configure(struct wl_listener *listener, void *data) {
// Respect minimum and maximum sizes // Respect minimum and maximum sizes
view->natural_width = ev->width; view->natural_width = ev->width;
view->natural_height = ev->height; view->natural_height = ev->height;
container_init_floating(view->container); container_floating_resize_and_center(view->container);
configure(view, view->container->content_x, configure(view, view->container->content_x,
view->container->content_y, view->container->content_y,

View file

@ -108,7 +108,7 @@ static void handle_motion_postthreshold(struct sway_seat *seat) {
} }
if (node->type == N_WORKSPACE) { if (node->type == N_WORKSPACE) {
// Emtpy workspace // Empty workspace
e->target_node = node; e->target_node = node;
e->target_edge = WLR_EDGE_NONE; e->target_edge = WLR_EDGE_NONE;
workspace_get_box(node->sway_workspace, &e->drop_box); workspace_get_box(node->sway_workspace, &e->drop_box);
@ -164,7 +164,7 @@ static void handle_motion_postthreshold(struct sway_seat *seat) {
// Use the hovered view - but we must be over the actual surface // Use the hovered view - but we must be over the actual surface
con = node->sway_container; con = node->sway_container;
if (!con->view->surface || node == &e->con->node if (!con->view || !con->view->surface || node == &e->con->node
|| node_has_ancestor(node, &e->con->node)) { || node_has_ancestor(node, &e->con->node)) {
e->target_node = NULL; e->target_node = NULL;
e->target_edge = WLR_EDGE_NONE; e->target_edge = WLR_EDGE_NONE;

View file

@ -644,6 +644,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
json_object_object_add(output_json, "focused", json_object_object_add(output_json, "focused",
json_object_new_boolean(focused)); json_object_new_boolean(focused));
const char *subpixel = sway_wl_output_subpixel_to_string(output->wlr_output->subpixel);
json_object_object_add(output_json, "subpixel_hinting", json_object_new_string(subpixel));
json_object_array_add(outputs, output_json); json_object_array_add(outputs, output_json);
} }
struct sway_output *output; struct sway_output *output;

View file

@ -63,6 +63,7 @@ sway_sources = files(
'commands/fullscreen.c', 'commands/fullscreen.c',
'commands/gaps.c', 'commands/gaps.c',
'commands/hide_edge_borders.c', 'commands/hide_edge_borders.c',
'commands/inhibit_idle.c',
'commands/kill.c', 'commands/kill.c',
'commands/mark.c', 'commands/mark.c',
'commands/opacity.c', 'commands/opacity.c',
@ -169,6 +170,7 @@ sway_sources = files(
'commands/output/mode.c', 'commands/output/mode.c',
'commands/output/position.c', 'commands/output/position.c',
'commands/output/scale.c', 'commands/output/scale.c',
'commands/output/subpixel.c',
'commands/output/transform.c', 'commands/output/transform.c',
'tree/arrange.c', 'tree/arrange.c',

View file

@ -211,6 +211,9 @@ following properties:
|- scale |- scale
: float : float
: The scale currently in use on the output or _-1_ for disabled outputs : The scale currently in use on the output or _-1_ for disabled outputs
|- subpixel_hinting
: string
: The subpixel hinting current in use on the output. This can be _rgb_, _bgr_, _vrgb_, _vbgr_, or _none_
|- transform |- transform
: string : string
: The transform currently in use for the output. This can be _normal_, _90_, : The transform currently in use for the output. This can be _normal_, _90_,
@ -242,6 +245,7 @@ following properties:
"active": true, "active": true,
"primary": false, "primary": false,
"scale": 1.0, "scale": 1.0,
"subpixel_hinting": "rgb",
"transform": "normal", "transform": "normal",
"current_workspace": "1", "current_workspace": "1",
"modes": [ "modes": [

View file

@ -64,6 +64,13 @@ must be separated by one space. For example:
applications to taste. HiDPI isn't supported with Xwayland clients (windows applications to taste. HiDPI isn't supported with Xwayland clients (windows
will blur). will blur).
*output* <name> subpixel rgb|bgr|vrgb|vbgr|none
Manually sets the subpixel hinting for the specified output. This value is
usually auto-detected, but some displays may misreport their subpixel
geometry. Using the correct subpixel hinting allows for sharper text.
Incorrect values will result in blurrier text. When changing this via
*swaymsg*, some applications may need to be restarted to use the new value.
*output* <name> background|bg <file> <mode> [<fallback_color>] *output* <name> background|bg <file> <mode> [<fallback_color>]
Sets the wallpaper for the given output to the specified file, using the Sets the wallpaper for the given output to the specified file, using the
given scaling mode (one of "stretch", "fill", "fit", "center", "tile"). If given scaling mode (one of "stretch", "fill", "fit", "center", "tile"). If

View file

@ -146,6 +146,18 @@ set|plus|minus <amount>
_right_, _bottom_, and _left_ or per direction with _horizontal_ and _right_, _bottom_, and _left_ or per direction with _horizontal_ and
_vertical_. _vertical_.
*inhibit_idle* focus|fullscreen|open|none|visible
Set/unset an idle inhibitor for the view. _focus_ will inhibit idle when
the view is focused by any seat. _fullscreen_ will inhibit idle when the
view is fullscreen (or a descendant of a fullscreen container) and is
visible. _open_ will inhibit idle until the view is closed (or the
inhibitor is unset/changed). _visible_ will inhibit idle when the view is
visible on any output. _none_ will remove any existing idle inhibitor for
the view.
This can also be used with criteria to set an idle inhibitor for any
existing view or with _for_window_ to set idle inhibitors for future views.
*layout* default|splith|splitv|stacking|tabbed *layout* default|splith|splitv|stacking|tabbed
Sets the layout mode of the focused container. Sets the layout mode of the focused container.
@ -573,9 +585,9 @@ The default colors are:
Switches to the specified mode. The default mode _default_. Switches to the specified mode. The default mode _default_.
*mode* [--pango_markup] <mode> <mode-subcommands...> *mode* [--pango_markup] <mode> <mode-subcommands...>
The only valid _mode-subcommands..._ are *bindsym*, *bindcode* and The only valid _mode-subcommands..._ are *bindsym*, *bindcode*,
*bindswitch*. If _--pango_markup_ is given, then _mode_ will be interpreted *bindswitch*, and *set*. If _--pango_markup_ is given, then _mode_ will be
as pango markup. interpreted as pango markup.
*mouse_warping* output|container|none *mouse_warping* output|container|none
If _output_ is specified, the mouse will be moved to new outputs as you If _output_ is specified, the mouse will be moved to new outputs as you

View file

@ -649,18 +649,45 @@ void floating_calculate_constraints(int *min_width, int *max_width,
} }
void container_init_floating(struct sway_container *con) { static void floating_natural_resize(struct sway_container *con) {
struct sway_workspace *ws = con->workspace;
int min_width, max_width, min_height, max_height; int min_width, max_width, min_height, max_height;
floating_calculate_constraints(&min_width, &max_width, floating_calculate_constraints(&min_width, &max_width,
&min_height, &max_height); &min_height, &max_height);
if (!con->view) { if (!con->view) {
con->width = max_width; con->width = fmax(min_width, fmin(con->width, max_width));
con->height = max_height; con->height = fmax(min_height, fmin(con->height, max_height));
if (con->width > ws->width || con->height > ws->height) { } else {
struct sway_view *view = con->view;
con->content_width =
fmax(min_width, fmin(view->natural_width, max_width));
con->content_height =
fmax(min_height, fmin(view->natural_height, max_height));
container_set_geometry_from_content(con);
}
}
void container_floating_resize_and_center(struct sway_container *con) {
struct sway_workspace *ws = con->workspace;
if (!ws) {
// On scratchpad, just resize
floating_natural_resize(con);
return;
}
struct wlr_box *ob = wlr_output_layout_get_box(root->output_layout, struct wlr_box *ob = wlr_output_layout_get_box(root->output_layout,
ws->output->wlr_output); ws->output->wlr_output);
if (!ob) {
// On NOOP output. Will be called again when moved to an output
con->x = 0;
con->y = 0;
con->width = 0;
con->height = 0;
return;
}
floating_natural_resize(con);
if (!con->view) {
if (con->width > ws->width || con->height > ws->height) {
con->x = ob->x + (ob->width - con->width) / 2; con->x = ob->x + (ob->width - con->width) / 2;
con->y = ob->y + (ob->height - con->height) / 2; con->y = ob->y + (ob->height - con->height) / 2;
} else { } else {
@ -668,15 +695,8 @@ void container_init_floating(struct sway_container *con) {
con->y = ws->y + (ws->height - con->height) / 2; con->y = ws->y + (ws->height - con->height) / 2;
} }
} else { } else {
struct sway_view *view = con->view;
con->content_width =
fmax(min_width, fmin(view->natural_width, max_width));
con->content_height =
fmax(min_height, fmin(view->natural_height, max_height));
if (con->content_width > ws->width if (con->content_width > ws->width
|| con->content_height > ws->height) { || con->content_height > ws->height) {
struct wlr_box *ob = wlr_output_layout_get_box(root->output_layout,
ws->output->wlr_output);
con->content_x = ob->x + (ob->width - con->content_width) / 2; con->content_x = ob->x + (ob->width - con->content_width) / 2;
con->content_y = ob->y + (ob->height - con->content_height) / 2; con->content_y = ob->y + (ob->height - con->content_height) / 2;
} else { } else {
@ -692,6 +712,31 @@ void container_init_floating(struct sway_container *con) {
} }
} }
void container_floating_set_default_size(struct sway_container *con) {
if (!sway_assert(con->workspace, "Expected a container on a workspace")) {
return;
}
int min_width, max_width, min_height, max_height;
floating_calculate_constraints(&min_width, &max_width,
&min_height, &max_height);
struct wlr_box *box = calloc(1, sizeof(struct wlr_box));
workspace_get_box(con->workspace, box);
double width = fmax(min_width, fmin(box->width * 0.5, max_width));
double height = fmax(min_height, fmin(box->height * 0.75, max_height));
if (!con->view) {
con->width = width;
con->height = height;
} else {
con->content_width = width;
con->content_height = height;
container_set_geometry_from_content(con);
}
free(box);
}
void container_set_floating(struct sway_container *container, bool enable) { void container_set_floating(struct sway_container *container, bool enable) {
if (container_is_floating(container) == enable) { if (container_is_floating(container) == enable) {
return; return;
@ -704,7 +749,8 @@ void container_set_floating(struct sway_container *container, bool enable) {
struct sway_container *old_parent = container->parent; struct sway_container *old_parent = container->parent;
container_detach(container); container_detach(container);
workspace_add_floating(workspace, container); workspace_add_floating(workspace, container);
container_init_floating(container); container_floating_set_default_size(container);
container_floating_resize_and_center(container);
if (container->view) { if (container->view) {
view_set_tiled(container->view, false); view_set_tiled(container->view, false);
if (container->view->using_csd) { if (container->view->using_csd) {
@ -988,7 +1034,7 @@ void container_fullscreen_disable(struct sway_container *con) {
// criteria, it needs to be reinitialized as floating to get the proper // criteria, it needs to be reinitialized as floating to get the proper
// size and location // size and location
if (container_is_floating(con) && (con->width == 0 || con->height == 0)) { if (container_is_floating(con) && (con->width == 0 || con->height == 0)) {
container_init_floating(con); container_floating_resize_and_center(con);
} }
con->fullscreen_mode = FULLSCREEN_NONE; con->fullscreen_mode = FULLSCREEN_NONE;

View file

@ -60,6 +60,27 @@ static void restore_workspaces(struct sway_output *output) {
struct sway_workspace *ws = root->noop_output->workspaces->items[0]; struct sway_workspace *ws = root->noop_output->workspaces->items[0];
workspace_detach(ws); workspace_detach(ws);
output_add_workspace(output, ws); output_add_workspace(output, ws);
// If the floater was made floating while on the NOOP output, its width
// and height will be zero and it should be reinitialized as a floating
// container to get the appropriate size and location. Additionally, if
// the floater is wider or taller than the output or is completely
// outside of the output's bounds, do the same as the output layout has
// likely changed and the maximum size needs to be checked and the
// floater re-centered
for (int i = 0; i < ws->floating->length; i++) {
struct sway_container *floater = ws->floating->items[i];
if (floater->width == 0 || floater->height == 0 ||
floater->width > output->width ||
floater->height > output->height ||
floater->x > output->lx + output->width ||
floater->y > output->ly + output->height ||
floater->x + floater->width < output->lx ||
floater->y + floater->height < output->ly) {
container_floating_resize_and_center(floater);
}
}
ipc_event_workspace(NULL, ws, "move"); ipc_event_workspace(NULL, ws, "move");
} }
@ -71,6 +92,7 @@ struct sway_output *output_create(struct wlr_output *wlr_output) {
node_init(&output->node, N_OUTPUT, output); node_init(&output->node, N_OUTPUT, output);
output->wlr_output = wlr_output; output->wlr_output = wlr_output;
wlr_output->data = output; wlr_output->data = output;
output->detected_subpixel = wlr_output->subpixel;
wl_signal_init(&output->events.destroy); wl_signal_init(&output->events.destroy);

View file

@ -62,6 +62,8 @@ void root_scratchpad_add_container(struct sway_container *con) {
struct sway_container *parent = con->parent; struct sway_container *parent = con->parent;
struct sway_workspace *workspace = con->workspace; struct sway_workspace *workspace = con->workspace;
container_set_floating(con, true); container_set_floating(con, true);
container_floating_set_default_size(con);
container_floating_move_to_center(con);
container_detach(con); container_detach(con);
con->scratchpad = true; con->scratchpad = true;
list_add(root->scratchpad, con); list_add(root->scratchpad, con);
@ -124,15 +126,7 @@ void root_scratchpad_show(struct sway_container *con) {
struct wlr_box workspace_box; struct wlr_box workspace_box;
workspace_get_box(new_ws, &workspace_box); workspace_get_box(new_ws, &workspace_box);
if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) { if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) {
// Maybe resize it container_floating_resize_and_center(con);
if (con->width > new_ws->width || con->height > new_ws->height) {
container_init_floating(con);
}
// Center it
double new_lx = new_ws->x + (new_ws->width - con->width) / 2;
double new_ly = new_ws->y + (new_ws->height - con->height) / 2;
container_floating_move_to(con, new_lx, new_ly);
} }
arrange_workspace(new_ws); arrange_workspace(new_ws);
@ -390,3 +384,17 @@ void root_get_box(struct sway_root *root, struct wlr_box *box) {
box->width = root->width; box->width = root->width;
box->height = root->height; box->height = root->height;
} }
void root_rename_pid_workspaces(const char *old_name, const char *new_name) {
if (!pid_workspaces.prev && !pid_workspaces.next) {
wl_list_init(&pid_workspaces);
}
struct pid_workspace *pw = NULL;
wl_list_for_each(pw, &pid_workspaces, link) {
if (strcmp(pw->workspace, old_name) == 0) {
free(pw->workspace);
pw->workspace = strdup(new_name);
}
}
}

View file

@ -348,6 +348,9 @@ void init_themes(list_t **themes, list_t **basedirs) {
*themes = create_list(); *themes = create_list();
for (int i = 0; i < (*basedirs)->length; ++i) { for (int i = 0; i < (*basedirs)->length; ++i) {
list_t *dir_themes = load_themes_in_dir((*basedirs)->items[i]); list_t *dir_themes = load_themes_in_dir((*basedirs)->items[i]);
if (dir_themes == NULL) {
continue;
}
list_cat(*themes, dir_themes); list_cat(*themes, dir_themes);
list_free(dir_themes); list_free(dir_themes);
} }

View file

@ -186,11 +186,12 @@ static void pretty_print_output(json_object *o) {
json_object_object_get_ex(o, "focused", &focused); json_object_object_get_ex(o, "focused", &focused);
json_object_object_get_ex(o, "active", &active); json_object_object_get_ex(o, "active", &active);
json_object_object_get_ex(o, "current_workspace", &ws); json_object_object_get_ex(o, "current_workspace", &ws);
json_object *make, *model, *serial, *scale, *transform; json_object *make, *model, *serial, *scale, *subpixel, *transform;
json_object_object_get_ex(o, "make", &make); json_object_object_get_ex(o, "make", &make);
json_object_object_get_ex(o, "model", &model); json_object_object_get_ex(o, "model", &model);
json_object_object_get_ex(o, "serial", &serial); json_object_object_get_ex(o, "serial", &serial);
json_object_object_get_ex(o, "scale", &scale); json_object_object_get_ex(o, "scale", &scale);
json_object_object_get_ex(o, "subpixel_hinting", &subpixel);
json_object_object_get_ex(o, "transform", &transform); json_object_object_get_ex(o, "transform", &transform);
json_object *x, *y; json_object *x, *y;
json_object_object_get_ex(rect, "x", &x); json_object_object_get_ex(rect, "x", &x);
@ -209,6 +210,7 @@ static void pretty_print_output(json_object *o) {
" Current mode: %dx%d @ %f Hz\n" " Current mode: %dx%d @ %f Hz\n"
" Position: %d,%d\n" " Position: %d,%d\n"
" Scale factor: %f\n" " Scale factor: %f\n"
" Subpixel hinting: %s\n"
" Transform: %s\n" " Transform: %s\n"
" Workspace: %s\n", " Workspace: %s\n",
json_object_get_string(name), json_object_get_string(name),
@ -221,6 +223,7 @@ static void pretty_print_output(json_object *o) {
(float)json_object_get_int(refresh) / 1000, (float)json_object_get_int(refresh) / 1000,
json_object_get_int(x), json_object_get_int(y), json_object_get_int(x), json_object_get_int(y),
json_object_get_double(scale), json_object_get_double(scale),
json_object_get_string(subpixel),
json_object_get_string(transform), json_object_get_string(transform),
json_object_get_string(ws) json_object_get_string(ws)
); );