mirror of
https://github.com/labwc/labwc.git
synced 2026-04-12 08:21:13 -04:00
Merge branch 'master' into headerbar_touch
This commit is contained in:
commit
861c0de99f
43 changed files with 1128 additions and 181 deletions
|
|
@ -98,7 +98,7 @@ Some distributions carry labwc in their repositories or user repositories.
|
|||
- @adcdam (Slackware)
|
||||
- @bdantas (Tiny Core Linux)
|
||||
- @Visone-Selektah (Venom Linux)
|
||||
- @tranzystorek-io (Void Linux)
|
||||
- @tranzystorekk (Void Linux)
|
||||
|
||||
kindly maintain the packages in their respective distro.
|
||||
|
||||
|
|
@ -350,19 +350,32 @@ Base both bugfixes and new features on `master`.
|
|||
|
||||
# Native Language Support
|
||||
|
||||
## Translators
|
||||
|
||||
### Weblate Instance
|
||||
|
||||
Translators can create an account at [LXQt Weblate](https://translate.lxqt-project.org/projects/labwc/labwc/)
|
||||
and use the web interface. Adding new languages should work, otherwise the
|
||||
administrators can be contacted. Suggestions for improving existing translations
|
||||
can be added without account.
|
||||
|
||||
### Github Pull Request
|
||||
|
||||
Translators can add their `MY_LOCALE.po` files to the `po` directory
|
||||
based on `po/labwc.pot` and issue a pull request. To do this they can
|
||||
generate their `MY_LOCALE.po` file in a few steps:
|
||||
|
||||
1. Edit the `po/LINGUAS` file to add their locale name by adding a space
|
||||
to the end of the field and typing the locale code.
|
||||
2. Copy the po/labwc.pot to po/MY_LOCALE.po
|
||||
3. Edit the newly generated MY_LOCALE.po file with some of their
|
||||
1. Edit the `po/LINGUAS` file to add their locale code in English
|
||||
alphabetical order to the field of locale codes.
|
||||
2. Copy the `po/labwc.pot` to `po/MY_LOCALE.po`
|
||||
3. Edit the newly generated `MY_LOCALE.po` file with some of their
|
||||
contact and locale details in the header of the file then add the
|
||||
translation strings under each English string.
|
||||
|
||||
[See this tutorial for further guidance](https://www.labri.fr/perso/fleury/posts/programming/a-quick-gettext-tutorial.html)
|
||||
|
||||
## Coders
|
||||
|
||||
Code contributors may need to update relevant files if their additions
|
||||
affect UI elements (at the moment only `src/menu/menu.c`). In this case
|
||||
the `po/labwc.pot` file needs to be updated so that translators can
|
||||
|
|
|
|||
40
NEWS.md
40
NEWS.md
|
|
@ -9,7 +9,7 @@ The format is based on [Keep a Changelog]
|
|||
|
||||
| Date | All Changes | wlroots version | lines-of-code |
|
||||
|------------|---------------|-----------------|---------------|
|
||||
| 2024-01-23 | [unreleased] | 0.17.1 | |
|
||||
| 2024-03-01 | [0.7.1] | 0.17.1 | 18624 |
|
||||
| 2023-12-22 | [0.7.0] | 0.17.1 | 16576 |
|
||||
| 2023-11-25 | [0.6.6] | 0.16.2 | 15796 |
|
||||
| 2023-09-23 | [0.6.5] | 0.16.2 | 14809 |
|
||||
|
|
@ -28,10 +28,33 @@ The format is based on [Keep a Changelog]
|
|||
| 2021-03-05 | [0.1.0] | 0.12.0 | 4627 |
|
||||
|
||||
|
||||
## [unreleased]
|
||||
## [0.7.1]
|
||||
|
||||
### Added
|
||||
|
||||
- Support libinput option sendEventsMode to allow enabling/disabling devices.
|
||||
Co-Authored-By: @Sachin-Bhat
|
||||
|
||||
```xml
|
||||
<libinput>
|
||||
<device>
|
||||
<sendEventsMode>yes|no|disabledOnExternalMouse</sendEventsMode>
|
||||
</device>
|
||||
</libinput>
|
||||
```
|
||||
|
||||
- Add click method libinput option. Written-by: @datMaffin
|
||||
|
||||
```xml
|
||||
<libinput>
|
||||
<device>
|
||||
<clickMethod>none|buttonAreas|clickfinger</clickMethod>
|
||||
</device>
|
||||
</libinput>
|
||||
```
|
||||
|
||||
- Add `data/labwc.svg` & `data/labwc-symbolic.svg`, and specify icon name
|
||||
in labwc.desktop to enable Display Managers to show an icons for labwc.
|
||||
- Expose output configuration test to clients. For example, this enables
|
||||
`wlr-randr --dryrun`
|
||||
- Add window-edge resistance for interactive moves/resizes and support negative
|
||||
|
|
@ -90,6 +113,7 @@ The format is based on [Keep a Changelog]
|
|||
- Add config option `<placement><policy>` with supported values `center`,
|
||||
`cursor` and `automatic`. The latter minimizes overlap with other windows
|
||||
already on screen and is similar to Openbox's smart window placement.
|
||||
The placement policies honour `<core><gap>`.
|
||||
Written-by: @ahesford #1312
|
||||
|
||||
```xml
|
||||
|
|
@ -100,6 +124,13 @@ The format is based on [Keep a Changelog]
|
|||
|
||||
### Fixed
|
||||
|
||||
- Delay popup-unconstrain until after first commit in response to a changed
|
||||
wlroots 0.17 interface and to get rid of the error message below. Issue #1372
|
||||
|
||||
[types/xdg_shell/wlr_xdg_surface.c:169] A configure is scheduled for an uninitialized xdg_surface
|
||||
|
||||
- Notify clients about configuration errors when changing output settings.
|
||||
Issue #1528.
|
||||
- Fix output configuration bug causing compositor crash when refresh rate is
|
||||
zero. Issue #1458
|
||||
- Fix disappearing cursor bug on view destruction. Issue #1393
|
||||
|
|
@ -124,6 +155,8 @@ The format is based on [Keep a Changelog]
|
|||
|
||||
### Changed
|
||||
|
||||
- Make `MoveToCursor` honour `<core><gap>`. Issue #1494
|
||||
- Add `Roll Up/Down` client-menu entry for `ToggleShade`
|
||||
- When a Wayland-native window is snapped to a screen edges or user-defined
|
||||
region, labwc will notify the application that it is "tiled", allowing the
|
||||
application to better adapt its rendering to constrained layouts. Windows
|
||||
|
|
@ -1043,7 +1076,8 @@ Compile with wlroots 0.12.0 and wayland-server >=1.16
|
|||
ShowMenu
|
||||
|
||||
[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/
|
||||
[unreleased]: https://github.com/labwc/labwc/compare/0.7.0...HEAD
|
||||
[unreleased]: https://github.com/labwc/labwc/compare/0.7.1...HEAD
|
||||
[0.7.1]: https://github.com/labwc/labwc/compare/0.7.0...0.7.1
|
||||
[0.7.0]: https://github.com/labwc/labwc/compare/0.6.6...0.7.0
|
||||
[0.6.6]: https://github.com/labwc/labwc/compare/0.6.5...0.6.6
|
||||
[0.6.5]: https://github.com/labwc/labwc/compare/0.6.4...0.6.5
|
||||
|
|
|
|||
|
|
@ -127,8 +127,11 @@ High-level summary of items that Labwc supports:
|
|||
|
||||
The obligatory screenshot:
|
||||
|
||||
<a href="https://i.imgur.com/vOelinT.png">
|
||||
<img src="https://i.imgur.com/vOelinTl.png">
|
||||
<a href="https://labwc.github.io/img/scrot1.png">
|
||||
<img src="https://labwc.github.io/img/scrot1-small.png">
|
||||
</a><br />
|
||||
<a href="https://labwc.github.io/obligatory-screenshot.html">
|
||||
<small>Screenshot description</small>
|
||||
</a>
|
||||
|
||||
## 2. Build and Installation
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ Actions are used in menus and keyboard/mouse bindings.
|
|||
to the center of the window. If the given output does not contain
|
||||
any windows, the cursor is centered on the given output.
|
||||
|
||||
*<action name="MoveToOutput" name="HDMI-A-1" direction="value" />*
|
||||
*<action name="MoveToOutput" name="HDMI-A-1" direction="value" wrap="no" />*
|
||||
Moves active window to other output, unless the window state is
|
||||
fullscreen.
|
||||
|
||||
|
|
@ -172,6 +172,9 @@ Actions are used in menus and keyboard/mouse bindings.
|
|||
be one of "left", "right", "up" or "down" to indicate that the window
|
||||
should be moved to the next output in that direction (if one exists).
|
||||
|
||||
*wrap* [yes|no] When using the direction attribute, wrap around from
|
||||
right-to-left or top-to-bottom, and vice versa. Default no.
|
||||
|
||||
*<action name="FitToOutput" />*
|
||||
Resizes active window size to width and height of the output when the
|
||||
window size exceeds the output size.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ labwc - configuration files
|
|||
|
||||
Labwc uses openbox-3.6 specification for configuration and theming, but does not
|
||||
support all options. The following files form the basis of the labwc
|
||||
configuration: rc.xml, menu.xml, autostart and environment.
|
||||
configuration: rc.xml, menu.xml, autostart, shutdown and environment.
|
||||
|
||||
No configuration files are needed to start and run labwc.
|
||||
|
||||
|
|
@ -34,11 +34,8 @@ alternative.
|
|||
The configuration directory location can be override with the -C command line
|
||||
option.
|
||||
|
||||
All configuration and theme files except autostart are re-loaded on receiving
|
||||
signal SIGHUP.
|
||||
|
||||
The *autostart* file is executed as a shell script. This is the place for
|
||||
executing clients for handling background images, panels and similar.
|
||||
All configuration and theme files except autostart and shutdown are re-loaded on
|
||||
receiving signal SIGHUP.
|
||||
|
||||
The *environment* file is parsed as *variable=value* and sets environment
|
||||
variables accordingly. It is recommended to specify keyboard layout settings and
|
||||
|
|
@ -48,6 +45,20 @@ sourced prior to running openbox.
|
|||
Note: Tilde (~) and environment variables in the value are expanded, but
|
||||
subshell syntax and apostrophes are ignored.
|
||||
|
||||
The *autostart* file is executed as a shell script after labwc has read its
|
||||
configuration and set variables defined in the environment file. Additionally,
|
||||
the environment variables WAYLAND_DISPLAY and (when labwc is built with Xwayland
|
||||
support) DISPLAY will be defined. This is the place for executing clients for
|
||||
handling background images, panels and other tasks that should run automatically
|
||||
when labwc launches.
|
||||
|
||||
The *shutdown* file is executed as a shell script when labwc is preparing to
|
||||
terminate itself. All environment variables, including WAYLAND_DISPLAY and
|
||||
DISPLAY, will be available to the script. However, because the script runs
|
||||
asynchronously with other termination tasks, the shutdown file should not assume
|
||||
that the display will be usable. This file is useful to perform any custom
|
||||
operations necessary to finalize a labwc session.
|
||||
|
||||
The *menu.xml* file defines the context/root-menus and is described in
|
||||
labwc-menu(5).
|
||||
|
||||
|
|
@ -511,7 +522,7 @@ extending outward from the snapped edge.
|
|||
```
|
||||
|
||||
*<touch deviceName="" />*
|
||||
A touch configuration can be bound to a specifc device. If device
|
||||
A touch configuration can be bound to a specific device. If device
|
||||
name is left empty, the touch configuration applies to all touch
|
||||
devices or functions as a fallback. Multiple touch configurations
|
||||
can exist.
|
||||
|
|
@ -592,6 +603,8 @@ extending outward from the snapped edge.
|
|||
<dragLock></dragLock>
|
||||
<middleEmulation></middleEmulation>
|
||||
<disableWhileTyping></disableWhileTyping>
|
||||
<clickMethod></clickMethod>
|
||||
<sendEventsMode></sendEventsMode>
|
||||
</device>
|
||||
</libinput>
|
||||
```
|
||||
|
|
@ -667,6 +680,36 @@ extending outward from the snapped edge.
|
|||
any motion events while a keyboard is typing, and for a short while
|
||||
after as well.
|
||||
|
||||
*<libinput><device><clickMethod>* [none|buttonAreas|clickfinger]
|
||||
Configure the method by which physical clicks on a touchpad are mapped to
|
||||
mouse-button events.
|
||||
|
||||
The click methods available are:
|
||||
- *buttonAreas* - The bottom of the touchpad is divided into distinct
|
||||
regions corresponding to left, middle and right buttons; clicking within
|
||||
the region will trigger the corresponding event. Clicking the main area
|
||||
further up produces a left button event.
|
||||
- *clickfinger* - Clicking with one, two or three finger(s) will produce
|
||||
left, right or middle button event without regard to the location of a
|
||||
click.
|
||||
- *none* - Physical clicks will not produce button events.
|
||||
|
||||
The default method depends on the touchpad hardware.
|
||||
|
||||
*<libinput><device><sendEventsMode>* [yes|no|disabledOnExternalMouse]
|
||||
Optionally enable or disable sending any device events.
|
||||
|
||||
The options available are:
|
||||
- *yes* - Events are sent as usual
|
||||
- *no* - No events are sent from this device
|
||||
- *disabledOnExternalMouse* - This device does not send events if an
|
||||
external mouse has been detected.
|
||||
|
||||
It is possible to prevent events from a device in the config and then do
|
||||
a Reconfigure to temporarily enable / disable specific devices.
|
||||
|
||||
By default, this setting is not configured.
|
||||
|
||||
## WINDOW RULES
|
||||
|
||||
Two types of window rules are supported, actions and properties. They are
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ labwc(1)
|
|||
|
||||
# NAME
|
||||
|
||||
labwc - a wayland stacking compositor
|
||||
labwc - a Wayland stacking compositor
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
|
|
@ -16,8 +16,10 @@ It is light-weight and independent with a focus on simply stacking windows
|
|||
well and rendering some window decorations. Where practicable it uses clients
|
||||
for wall-paper, panels, screenshots and so on.
|
||||
|
||||
# SIGNALS
|
||||
|
||||
The compositor will exit or reload its configuration upon receiving SIGTERM
|
||||
and SIGHUP respectively. For example:
|
||||
and SIGHUP respectively. For example:
|
||||
|
||||
```
|
||||
kill -s <signal> $LABWC_PID
|
||||
|
|
@ -40,7 +42,7 @@ the `--exit` and `--reconfigure` options use.
|
|||
Enable full logging, including debug information
|
||||
|
||||
*-e, --exit*
|
||||
Exit the compositor
|
||||
Exit the compositor by sending SIGTERM to `$LABWC_PID`
|
||||
|
||||
*-h, --help*
|
||||
Show help message and quit
|
||||
|
|
@ -49,7 +51,7 @@ the `--exit` and `--reconfigure` options use.
|
|||
Merge user config/theme files in all XDG Base Directories
|
||||
|
||||
*-r, --reconfigure*
|
||||
Reload the compositor configuration
|
||||
Reload the compositor configuration by sending SIGHUP to `$LABWC_PID`
|
||||
|
||||
*-s, --startup* <command>
|
||||
Run command on startup
|
||||
|
|
@ -60,6 +62,48 @@ the `--exit` and `--reconfigure` options use.
|
|||
*-V, --verbose*
|
||||
Enable more verbose logging
|
||||
|
||||
# SESSION MANAGEMENT
|
||||
|
||||
To enable the use of graphical clients launched via D-Bus or systemd servie
|
||||
activation, labwc can update both activation environments on launch. Provided
|
||||
that labwc is aware of an active D-Bus user session (*i.e.*, the environment
|
||||
variable `DBUS_SESSION_BUS_ADDRESS` is defined), the compositor will invoke the
|
||||
commands
|
||||
|
||||
```
|
||||
dbus-update-activation-environment
|
||||
systemctl --user import-environment
|
||||
```
|
||||
|
||||
(when available) to notify D-Bus and systemd with the values of the following
|
||||
environment variables:
|
||||
|
||||
```
|
||||
WAYLAND_DISPLAY
|
||||
DISPLAY
|
||||
XDG_CURRENT_DESKTOP
|
||||
XDG_SESSION_TYPE
|
||||
XCURSOR_SIZE
|
||||
XCURSOR_THEME
|
||||
LABWC_PWD
|
||||
```
|
||||
|
||||
This behavior is enabled by default whenever labwc uses the "DRM" wlroots
|
||||
backend (which implies that labwc is the primary compositor on the console).
|
||||
When other backends are employed (for example, when labwc runs nested in another
|
||||
Wayland compositor or an X11 server), updates to the activation environment are
|
||||
disabled by default. Updates to the activation environment can be forced by
|
||||
setting the environment variable `LABWC_UPDATE_ACTIVATION_ENV` to one of the
|
||||
truthy values `1`, `true`, `yes` or `on`; or suppressed by setting the variable
|
||||
to one of the falsy values `0`, `false`, `no` or `off`.
|
||||
|
||||
Whenever labwc updates the activation environment on launch, it will also
|
||||
attempt to clear the activation environment on exit. For D-Bus, which does not
|
||||
provide a means for properly un-setting variables in the activation environment,
|
||||
this is accomplished by setting the session variables to empty strings. For
|
||||
systemd, the command `systemctl --user unset-environment` will be invoked to
|
||||
actually remove the variables from the activation environment.
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
labwc-config(5), labwc-theme(5), labwc-actions(5)
|
||||
labwc-actions(5), labwc-config(5), labwc-menu(5), labwc-theme(5)
|
||||
|
|
|
|||
|
|
@ -7,10 +7,6 @@
|
|||
|
||||
<labwc_config>
|
||||
|
||||
<core>
|
||||
<gap>10</gap>
|
||||
</core>
|
||||
|
||||
<theme>
|
||||
<name></name>
|
||||
<cornerRadius>8</cornerRadius>
|
||||
|
|
|
|||
|
|
@ -465,13 +465,15 @@
|
|||
non-touch, default or the name of a device. You can obtain device names by
|
||||
running *libinput list-devices* as root or member of the input group.
|
||||
|
||||
Tap is set to *yes* be default. All others are left blank in order to use
|
||||
Tap is set to *yes* by default. All others are left blank in order to use
|
||||
device defaults.
|
||||
|
||||
All values are [yes|no] except for:
|
||||
- pointerSpeed [-1.0 to 1.0]
|
||||
- accelProfile [flat|adaptive]
|
||||
- tapButtonMap [lrm|lmr]
|
||||
- clickMethod [none|buttonAreas|clickfinger]
|
||||
- sendEventsMode [yes|no|disabledOnExternalMouse]
|
||||
-->
|
||||
<libinput>
|
||||
<device category="default">
|
||||
|
|
@ -485,6 +487,8 @@
|
|||
<dragLock></dragLock>
|
||||
<middleEmulation></middleEmulation>
|
||||
<disableWhileTyping></disableWhileTyping>
|
||||
<clickMethod></clickMethod>
|
||||
<sendEventsMode></sendEventsMode>
|
||||
</device>
|
||||
</libinput>
|
||||
|
||||
|
|
|
|||
|
|
@ -43,4 +43,23 @@ void string_truncate_at_pattern(char *buf, const char *pattern);
|
|||
*/
|
||||
char *strdup_printf(const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* str_join - format and join an array of strings with a separator
|
||||
* @parts: NULL-terminated array of string parts to be joined
|
||||
* @fmt: printf-style format string applied to each part
|
||||
* @sep: separator inserted between parts when joining
|
||||
*
|
||||
* A new string is allocated to hold the joined result. The user must free the
|
||||
* returned string. Returns NULL on error.
|
||||
*
|
||||
* Each part of the array is converted via the equivalent of sprintf(output,
|
||||
* fmt, part), so fmt should include a single "%s" format specification. If fmt
|
||||
* is NULL, a default "%s" will be used to copy each part verbatim.
|
||||
*
|
||||
* The separator is arbitrary. When the separator is NULL, a single space will
|
||||
* be used.
|
||||
*/
|
||||
char *str_join(const char * const parts[],
|
||||
const char *restrict fmt, const char *restrict sep);
|
||||
|
||||
#endif /* LABWC_STRING_HELPERS_H */
|
||||
|
|
|
|||
|
|
@ -23,11 +23,13 @@ struct libinput_category {
|
|||
int left_handed;
|
||||
enum libinput_config_tap_state tap;
|
||||
enum libinput_config_tap_button_map tap_button_map;
|
||||
int tap_and_drag; /* -1 or libinput_config_drag_state */
|
||||
int drag_lock; /* -1 or libinput_config_drag_lock_state */
|
||||
int accel_profile; /* -1 or libinput_config_accel_profile */
|
||||
int middle_emu; /* -1 or libinput_config_middle_emulation_state */
|
||||
int dwt; /* -1 or libinput_config_dwt_state */
|
||||
int tap_and_drag; /* -1 or libinput_config_drag_state */
|
||||
int drag_lock; /* -1 or libinput_config_drag_lock_state */
|
||||
int accel_profile; /* -1 or libinput_config_accel_profile */
|
||||
int middle_emu; /* -1 or libinput_config_middle_emulation_state */
|
||||
int dwt; /* -1 or libinput_config_dwt_state */
|
||||
int click_method; /* -1 or libinput_config_click_method */
|
||||
int send_events_mode; /* -1 or libinput_config_send_events_mode */
|
||||
};
|
||||
|
||||
enum lab_libinput_device_type get_device_type(const char *s);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
#ifndef LABWC_SESSION_H
|
||||
#define LABWC_SESSION_H
|
||||
|
||||
struct server;
|
||||
|
||||
/**
|
||||
* session_environment_init - set enrivonment variables based on <key>=<value>
|
||||
* pairs in `${XDG_CONFIG_DIRS:-/etc/xdg}/lawbc/environment` with user override
|
||||
|
|
@ -13,6 +15,12 @@ void session_environment_init(void);
|
|||
* session_autostart_init - run autostart file as shell script
|
||||
* Note: Same as `sh ~/.config/labwc/autostart` (or equivalent XDG config dir)
|
||||
*/
|
||||
void session_autostart_init(void);
|
||||
void session_autostart_init(struct server *server);
|
||||
|
||||
/**
|
||||
* session_shutdown - run session shutdown file as shell script
|
||||
* Note: Same as `sh ~/.config/labwc/shutdown` (or equivalent XDG config dir)
|
||||
*/
|
||||
void session_shutdown(struct server *server);
|
||||
|
||||
#endif /* LABWC_SESSION_H */
|
||||
|
|
|
|||
|
|
@ -3,11 +3,15 @@
|
|||
#define LABWC_EDGES_H
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "common/macros.h"
|
||||
|
||||
struct border;
|
||||
struct output;
|
||||
struct server;
|
||||
struct view;
|
||||
struct wlr_box;
|
||||
|
||||
static inline int
|
||||
clipped_add(int a, int b)
|
||||
|
|
@ -102,7 +106,7 @@ void edges_adjust_geom(struct view *view, struct border edges,
|
|||
|
||||
void edges_find_neighbors(struct border *nearest_edges, struct view *view,
|
||||
struct wlr_box target, struct output *output,
|
||||
edge_validator_t validator, bool use_pending);
|
||||
edge_validator_t validator, bool use_pending, bool ignore_hidden);
|
||||
|
||||
void edges_find_outputs(struct border *nearest_edges, struct view *view,
|
||||
struct wlr_box target, struct output *output,
|
||||
|
|
@ -116,4 +120,5 @@ void edges_adjust_resize_geom(struct view *view, struct border edges,
|
|||
|
||||
bool edges_traverse_edge(struct edge current, struct edge target, struct edge edge);
|
||||
|
||||
void edges_calculate_visibility(struct server *server, struct view *ignored_view);
|
||||
#endif /* LABWC_EDGES_H */
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ struct lab_layer_popup {
|
|||
/* To simplify moving popup nodes from the bottom to the top layer */
|
||||
struct wlr_box output_toplevel_sx_box;
|
||||
|
||||
struct wl_listener commit;
|
||||
struct wl_listener destroy;
|
||||
struct wl_listener new_popup;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ struct view {
|
|||
bool tearing_hint;
|
||||
bool visible_on_all_workspaces;
|
||||
enum view_edge tiled;
|
||||
uint32_t edges_visible; /* enum wlr_edges bitset */
|
||||
bool inhibits_keybinds;
|
||||
xkb_layout_index_t keyboard_layout;
|
||||
|
||||
|
|
@ -502,7 +503,8 @@ void view_on_output_destroy(struct view *view);
|
|||
void view_connect_map(struct view *view, struct wlr_surface *surface);
|
||||
void view_destroy(struct view *view);
|
||||
|
||||
struct output *view_get_adjacent_output(struct view *view, enum view_edge edge);
|
||||
struct output *view_get_adjacent_output(struct view *view, enum view_edge edge,
|
||||
bool wrap);
|
||||
enum view_axis view_axis_parse(const char *direction);
|
||||
enum view_edge view_edge_parse(const char *direction);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
project(
|
||||
'labwc',
|
||||
'c',
|
||||
version: '0.7.0',
|
||||
version: '0.7.1',
|
||||
license: 'GPL-2.0-only',
|
||||
meson_version: '>=0.59.0',
|
||||
default_options: [
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
de es et eu fi gl id it ja ka lt nl pa pl pt ru sv tr uk zh_CN
|
||||
cs de es et eu fi gl hu id it ja ka lt nl pa pl pt ru sv tr uk zh_CN
|
||||
|
|
|
|||
69
po/cs.po
Normal file
69
po/cs.po
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
# Labwc pot file
|
||||
# Copyright (C) 2024
|
||||
# This file is distributed under the same license as the labwc package.
|
||||
# zenobit <zenobit@disroot.org>, 2024.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: labwc\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/labwc/labwc/issues\n"
|
||||
"POT-Creation-Date: 2024-01-15 16:00-0500\n"
|
||||
"PO-Revision-Date: 2024-03-02 02:00+0100\n"
|
||||
"Last-Translator: zenobit <zenobit@disroot.org>\n"
|
||||
"Language-Team: Czech <zenobit@disroot.org>\n"
|
||||
"Language: cs\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: src/menu/menu.c:697
|
||||
msgid "Reconfigure"
|
||||
msgstr "Překonfigurovat"
|
||||
|
||||
#: src/menu/menu.c:699
|
||||
msgid "Exit"
|
||||
msgstr "Odejít"
|
||||
|
||||
#: src/menu/menu.c:715
|
||||
msgid "Minimize"
|
||||
msgstr "Minimalizovat"
|
||||
|
||||
#: src/menu/menu.c:717
|
||||
msgid "Maximize"
|
||||
msgstr "Maximalizovat"
|
||||
|
||||
#: src/menu/menu.c:719
|
||||
msgid "Fullscreen"
|
||||
msgstr "Na celou obrazovku"
|
||||
|
||||
#: src/menu/menu.c:721
|
||||
msgid "Roll up/down"
|
||||
msgstr "Rolovat nahoru/dolů"
|
||||
|
||||
#: src/menu/menu.c:723
|
||||
msgid "Decorations"
|
||||
msgstr "Dekorace"
|
||||
|
||||
#: src/menu/menu.c:725
|
||||
msgid "Always on Top"
|
||||
msgstr "Vždy nahoře"
|
||||
|
||||
#: src/menu/menu.c:730
|
||||
msgid "Move left"
|
||||
msgstr "Posunout doleva"
|
||||
|
||||
#: src/menu/menu.c:737
|
||||
msgid "Move right"
|
||||
msgstr "Posunout doprava"
|
||||
|
||||
#: src/menu/menu.c:742
|
||||
msgid "Always on Visible Workspace"
|
||||
msgstr "Vždy na viditelné Pracovní Ploše"
|
||||
|
||||
#: src/menu/menu.c:745
|
||||
msgid "Workspace"
|
||||
msgstr "Pracovní Plocha"
|
||||
|
||||
#: src/menu/menu.c:748
|
||||
msgid "Close"
|
||||
msgstr "Zavřít"
|
||||
11
po/fi.po
11
po/fi.po
|
|
@ -8,13 +8,16 @@ msgstr ""
|
|||
"Project-Id-Version: labwc\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/labwc/labwc/issues\n"
|
||||
"POT-Creation-Date: 2024-01-15 16:00-0500\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Automatically generated\n"
|
||||
"Language-Team: none\n"
|
||||
"PO-Revision-Date: 2024-02-29 14:23+0000\n"
|
||||
"Last-Translator: Jouni Järvinen <jounijarvis@gmail.com>\n"
|
||||
"Language-Team: Finnish <https://translate.lxqt-project.org/projects/labwc/"
|
||||
"labwc/fi/>\n"
|
||||
"Language: fi\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 4.2.1\n"
|
||||
|
||||
#: src/menu/menu.c:697
|
||||
msgid "Reconfigure"
|
||||
|
|
@ -22,7 +25,7 @@ msgstr ""
|
|||
|
||||
#: src/menu/menu.c:699
|
||||
msgid "Exit"
|
||||
msgstr ""
|
||||
msgstr "Poistu"
|
||||
|
||||
#: src/menu/menu.c:715
|
||||
msgid "Minimize"
|
||||
|
|
|
|||
72
po/hu.po
Normal file
72
po/hu.po
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
# Labwc pot file
|
||||
# Copyright (C) 2024
|
||||
# This file is distributed under the same license as the labwc package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: labwc\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/labwc/labwc/issues\n"
|
||||
"POT-Creation-Date: 2024-01-15 16:00-0500\n"
|
||||
"PO-Revision-Date: 2024-02-19 21:23+0000\n"
|
||||
"Last-Translator: winerysearch <david.fitala@gmail.com>\n"
|
||||
"Language-Team: Hungarian <https://translate.lxqt-project.org/projects/labwc/"
|
||||
"labwc/hu/>\n"
|
||||
"Language: hu\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 4.2.1\n"
|
||||
|
||||
#: src/menu/menu.c:697
|
||||
msgid "Reconfigure"
|
||||
msgstr "Rekonfigurál"
|
||||
|
||||
#: src/menu/menu.c:699
|
||||
msgid "Exit"
|
||||
msgstr "Kilépés"
|
||||
|
||||
#: src/menu/menu.c:715
|
||||
msgid "Minimize"
|
||||
msgstr "Kis méret"
|
||||
|
||||
#: src/menu/menu.c:717
|
||||
msgid "Maximize"
|
||||
msgstr "Teljes méret"
|
||||
|
||||
#: src/menu/menu.c:719
|
||||
msgid "Fullscreen"
|
||||
msgstr "Teljes képernyő"
|
||||
|
||||
#: src/menu/menu.c:721
|
||||
msgid "Roll up/down"
|
||||
msgstr "Felhúz / Legördül"
|
||||
|
||||
#: src/menu/menu.c:723
|
||||
msgid "Decorations"
|
||||
msgstr "Dekorációk"
|
||||
|
||||
#: src/menu/menu.c:725
|
||||
msgid "Always on Top"
|
||||
msgstr "Mindig felül"
|
||||
|
||||
#: src/menu/menu.c:730
|
||||
msgid "Move left"
|
||||
msgstr "Balra dokkol"
|
||||
|
||||
#: src/menu/menu.c:737
|
||||
msgid "Move right"
|
||||
msgstr "Jobbra dokkol"
|
||||
|
||||
#: src/menu/menu.c:742
|
||||
msgid "Always on Visible Workspace"
|
||||
msgstr "Kitűz"
|
||||
|
||||
#: src/menu/menu.c:745
|
||||
msgid "Workspace"
|
||||
msgstr "Munkaasztal"
|
||||
|
||||
#: src/menu/menu.c:748
|
||||
msgid "Close"
|
||||
msgstr "Bezárás"
|
||||
11
po/lt.po
11
po/lt.po
|
|
@ -8,14 +8,17 @@ msgstr ""
|
|||
"Project-Id-Version: labwc\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/labwc/labwc/issues\n"
|
||||
"POT-Creation-Date: 2024-01-15 16:00-0500\n"
|
||||
"PO-Revision-Date: 2024-01-04 15:23+0000\n"
|
||||
"PO-Revision-Date: 2024-02-29 14:23+0000\n"
|
||||
"Last-Translator: Moo <hazap@hotmail.com>\n"
|
||||
"Language-Team: Lithuanian <https://translate.lxqt-project.org/projects/labwc/labwc/lt/>\n"
|
||||
"Language-Team: Lithuanian <https://translate.lxqt-project.org/projects/labwc/"
|
||||
"labwc/lt/>\n"
|
||||
"Language: lt\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n % 10 == 1 && (n % 100 < 11 || n % 100 > 19)) ? 0 : ((n % 10 >= 2 && n % 10 <= 9 && (n % 100 < 11 || n % 100 > 19)) ? 1 : 2);\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n % 10 == 1 && (n % 100 < 11 || n % 100 > "
|
||||
"19)) ? 0 : ((n % 10 >= 2 && n % 10 <= 9 && (n % 100 < 11 || n % 100 > 19)) ? "
|
||||
"1 : 2);\n"
|
||||
"X-Generator: Weblate 4.2.1\n"
|
||||
|
||||
#: src/menu/menu.c:697
|
||||
|
|
@ -40,7 +43,7 @@ msgstr "Visas ekranas"
|
|||
|
||||
#: src/menu/menu.c:721
|
||||
msgid "Roll up/down"
|
||||
msgstr ""
|
||||
msgstr "Užraityti/atraityti"
|
||||
|
||||
#: src/menu/menu.c:723
|
||||
msgid "Decorations"
|
||||
|
|
|
|||
7
po/pa.po
7
po/pa.po
|
|
@ -8,9 +8,10 @@ msgstr ""
|
|||
"Project-Id-Version: labwc\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/labwc/labwc/issues\n"
|
||||
"POT-Creation-Date: 2024-01-15 16:00-0500\n"
|
||||
"PO-Revision-Date: 2023-12-26 07:23+0000\n"
|
||||
"PO-Revision-Date: 2024-02-21 14:23+0000\n"
|
||||
"Last-Translator: A S Alam <amanpreet.alam@gmail.com>\n"
|
||||
"Language-Team: Punjabi <https://translate.lxqt-project.org/projects/labwc/labwc/pa/>\n"
|
||||
"Language-Team: Punjabi <https://translate.lxqt-project.org/projects/labwc/"
|
||||
"labwc/pa/>\n"
|
||||
"Language: pa\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
|
@ -40,7 +41,7 @@ msgstr "ਪੂਰੀ ਸਕਰੀਨ"
|
|||
|
||||
#: src/menu/menu.c:721
|
||||
msgid "Roll up/down"
|
||||
msgstr ""
|
||||
msgstr "ਉੱਤੇ/ਹੇਠਾਂ ਸਕਰਾਓ"
|
||||
|
||||
#: src/menu/menu.c:723
|
||||
msgid "Decorations"
|
||||
|
|
|
|||
5
po/ru.po
5
po/ru.po
|
|
@ -8,8 +8,8 @@ msgstr ""
|
|||
"Project-Id-Version: labwc\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/labwc/labwc/issues\n"
|
||||
"POT-Creation-Date: 2024-01-15 16:00-0500\n"
|
||||
"PO-Revision-Date: 2024-01-30 08:23+0000\n"
|
||||
"Last-Translator: pixis1 <vaninpixel89@gmail.com>\n"
|
||||
"PO-Revision-Date: 2024-02-26 12:23+0000\n"
|
||||
"Last-Translator: Alice Ventus <zolkin.ag@phystech.edu>\n"
|
||||
"Language-Team: Russian <https://translate.lxqt-project.org/projects/labwc/"
|
||||
"labwc/ru/>\n"
|
||||
"Language: ru\n"
|
||||
|
|
@ -41,7 +41,6 @@ msgid "Fullscreen"
|
|||
msgstr "На весь экран"
|
||||
|
||||
#: src/menu/menu.c:721
|
||||
#, fuzzy
|
||||
msgid "Roll up/down"
|
||||
msgstr "Свернуть/развернуть в заголовок"
|
||||
|
||||
|
|
|
|||
7
po/tr.po
7
po/tr.po
|
|
@ -8,9 +8,10 @@ msgstr ""
|
|||
"Project-Id-Version: labwc\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/labwc/labwc/issues\n"
|
||||
"POT-Creation-Date: 2024-01-15 16:00-0500\n"
|
||||
"PO-Revision-Date: 2023-12-26 09:00+0000\n"
|
||||
"PO-Revision-Date: 2024-02-24 22:23+0000\n"
|
||||
"Last-Translator: Sabri Ünal <libreajans@gmail.com>\n"
|
||||
"Language-Team: Turkish <https://translate.lxqt-project.org/projects/labwc/labwc/tr/>\n"
|
||||
"Language-Team: Turkish <https://translate.lxqt-project.org/projects/labwc/"
|
||||
"labwc/tr/>\n"
|
||||
"Language: tr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
|
@ -40,7 +41,7 @@ msgstr "Tam Ekran"
|
|||
|
||||
#: src/menu/menu.c:721
|
||||
msgid "Roll up/down"
|
||||
msgstr ""
|
||||
msgstr "Yukarı/aşağı katla"
|
||||
|
||||
#: src/menu/menu.c:723
|
||||
msgid "Decorations"
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ server_protocols = [
|
|||
wl_protocol_dir / 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml',
|
||||
wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml',
|
||||
wl_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml',
|
||||
wl_protocol_dir / 'staging/xwayland-shell/xwayland-shell-v1.xml',
|
||||
wl_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml',
|
||||
'wlr-layer-shell-unstable-v1.xml',
|
||||
'wlr-input-inhibitor-unstable-v1.xml',
|
||||
|
|
|
|||
13
src/action.c
13
src/action.c
|
|
@ -397,6 +397,10 @@ action_arg_from_xml_node(struct action *action, const char *nodename, const char
|
|||
}
|
||||
goto cleanup;
|
||||
}
|
||||
if (!strcmp(argument, "wrap")) {
|
||||
action_arg_add_bool(action, argument, parse_bool(content, false));
|
||||
goto cleanup;
|
||||
}
|
||||
break;
|
||||
case ACTION_TYPE_VIRTUAL_OUTPUT_ADD:
|
||||
case ACTION_TYPE_VIRTUAL_OUTPUT_REMOVE:
|
||||
|
|
@ -924,10 +928,15 @@ actions_run(struct view *activator, struct server *server,
|
|||
} else {
|
||||
/* Config parsing makes sure that direction is a valid direction */
|
||||
enum view_edge edge = action_get_int(action, "direction", 0);
|
||||
target = view_get_adjacent_output(view, edge);
|
||||
bool wrap = action_get_bool(action, "wrap", false);
|
||||
target = view_get_adjacent_output(view, edge, wrap);
|
||||
}
|
||||
if (!target) {
|
||||
wlr_log(WLR_ERROR, "Invalid output.");
|
||||
/*
|
||||
* Most likely because we're already on the
|
||||
* output furthest in the requested direction.
|
||||
*/
|
||||
wlr_log(WLR_DEBUG, "Invalid output");
|
||||
break;
|
||||
}
|
||||
view_move_to_output(view, target);
|
||||
|
|
|
|||
|
|
@ -14,12 +14,16 @@ parse_bool(const char *str, int default_value)
|
|||
return true;
|
||||
} else if (!strcasecmp(str, "on")) {
|
||||
return true;
|
||||
} else if (!strcmp(str, "1")) {
|
||||
return true;
|
||||
} else if (!strcasecmp(str, "no")) {
|
||||
return false;
|
||||
} else if (!strcasecmp(str, "false")) {
|
||||
return false;
|
||||
} else if (!strcasecmp(str, "off")) {
|
||||
return false;
|
||||
} else if (!strcmp(str, "0")) {
|
||||
return false;
|
||||
}
|
||||
error_not_a_boolean:
|
||||
wlr_log(WLR_ERROR, "(%s) is not a boolean value", str);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
|
@ -83,3 +84,73 @@ strdup_printf(const char *fmt, ...)
|
|||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
char *
|
||||
str_join(const char * const parts[],
|
||||
const char *restrict fmt, const char *restrict sep)
|
||||
{
|
||||
assert(parts);
|
||||
|
||||
if (!fmt) {
|
||||
fmt = "%s";
|
||||
}
|
||||
|
||||
if (!sep) {
|
||||
sep = " ";
|
||||
}
|
||||
|
||||
size_t size = 0;
|
||||
size_t n_parts = 0;
|
||||
|
||||
size_t sep_len = strlen(sep);
|
||||
|
||||
/* Count the length of each formatted string */
|
||||
for (const char *const *s = parts; *s; ++s) {
|
||||
int n = snprintf(NULL, 0, fmt, *s);
|
||||
if (n < 0) {
|
||||
return NULL;
|
||||
}
|
||||
size += (size_t)n;
|
||||
++n_parts;
|
||||
}
|
||||
|
||||
if (n_parts < 1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Need (n_parts - 1) separators, plus one NULL terminator */
|
||||
size += (n_parts - 1) * sep_len + 1;
|
||||
|
||||
/* Concatenate the strings and separators */
|
||||
char *buf = xzalloc(size);
|
||||
char *p = buf;
|
||||
for (const char *const *s = parts; *s; ++s) {
|
||||
int n = 0;
|
||||
|
||||
if (p != buf) {
|
||||
n = snprintf(p, size, "%s", sep);
|
||||
if (n < 0 || (size_t)n >= size) {
|
||||
p = NULL;
|
||||
break;
|
||||
}
|
||||
size -= (size_t)n;
|
||||
p += (size_t)n;
|
||||
}
|
||||
|
||||
n = snprintf(p, size, fmt, *s);
|
||||
if (n < 0 || (size_t)n >= size) {
|
||||
p = NULL;
|
||||
break;
|
||||
}
|
||||
size -= (size_t)n;
|
||||
p += (size_t)n;
|
||||
}
|
||||
|
||||
if (!p) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ libinput_category_init(struct libinput_category *l)
|
|||
l->accel_profile = -1;
|
||||
l->middle_emu = -1;
|
||||
l->dwt = -1;
|
||||
l->click_method = -1;
|
||||
l->send_events_mode = -1;
|
||||
}
|
||||
|
||||
enum lab_libinput_device_type
|
||||
|
|
|
|||
|
|
@ -461,6 +461,29 @@ get_accel_profile(const char *s)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
get_send_events_mode(const char *s)
|
||||
{
|
||||
if (!s) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
int ret = parse_bool(s, -1);
|
||||
if (ret >= 0) {
|
||||
return ret
|
||||
? LIBINPUT_CONFIG_SEND_EVENTS_ENABLED
|
||||
: LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
|
||||
}
|
||||
|
||||
if (!strcasecmp(s, "disabledOnExternalMouse")) {
|
||||
return LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
|
||||
}
|
||||
|
||||
err:
|
||||
wlr_log(WLR_INFO, "Not a recognised send events mode");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
fill_libinput_category(char *nodename, char *content)
|
||||
{
|
||||
|
|
@ -563,6 +586,22 @@ fill_libinput_category(char *nodename, char *content)
|
|||
current_libinput_category->dwt = ret
|
||||
? LIBINPUT_CONFIG_DWT_ENABLED
|
||||
: LIBINPUT_CONFIG_DWT_DISABLED;
|
||||
} else if (!strcasecmp(nodename, "clickMethod")) {
|
||||
if (!strcasecmp(content, "none")) {
|
||||
current_libinput_category->click_method =
|
||||
LIBINPUT_CONFIG_CLICK_METHOD_NONE;
|
||||
} else if (!strcasecmp(content, "clickfinger")) {
|
||||
current_libinput_category->click_method =
|
||||
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER;
|
||||
} else if (!strcasecmp(content, "buttonAreas")) {
|
||||
current_libinput_category->click_method =
|
||||
LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "invalid clickMethod");
|
||||
}
|
||||
} else if (!strcasecmp(nodename, "sendEventsMode")) {
|
||||
current_libinput_category->send_events_mode =
|
||||
get_send_events_mode(content);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,19 +1,35 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <wlr/backend/drm.h>
|
||||
#include <wlr/backend/multi.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "common/buf.h"
|
||||
#include "common/dir.h"
|
||||
#include "common/file-helpers.h"
|
||||
#include "common/mem.h"
|
||||
#include "common/parse-bool.h"
|
||||
#include "common/spawn.h"
|
||||
#include "common/string-helpers.h"
|
||||
#include "config/session.h"
|
||||
#include "labwc.h"
|
||||
|
||||
static const char *const env_vars[] = {
|
||||
"DISPLAY",
|
||||
"WAYLAND_DISPLAY",
|
||||
"XDG_CURRENT_DESKTOP",
|
||||
"XCURSOR_SIZE",
|
||||
"XCURSOR_THEME",
|
||||
"XDG_SESSION_TYPE",
|
||||
"LABWC_PID",
|
||||
NULL
|
||||
};
|
||||
|
||||
static void
|
||||
process_line(char *line)
|
||||
{
|
||||
|
|
@ -65,23 +81,71 @@ read_environment_file(const char *filename)
|
|||
}
|
||||
|
||||
static void
|
||||
update_activation_env(const char *env_keys)
|
||||
backend_check_drm(struct wlr_backend *backend, void *is_drm)
|
||||
{
|
||||
if (wlr_backend_is_drm(backend)) {
|
||||
*(bool *)is_drm = true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
should_update_activation(struct server *server)
|
||||
{
|
||||
assert(server);
|
||||
|
||||
static const char *act_env = "LABWC_UPDATE_ACTIVATION_ENV";
|
||||
char *env = getenv(act_env);
|
||||
if (env) {
|
||||
/* Respect any valid preference from the environment */
|
||||
int enabled = parse_bool(env, -1);
|
||||
|
||||
if (enabled == -1) {
|
||||
wlr_log(WLR_ERROR, "ignoring non-Boolean variable %s", act_env);
|
||||
} else {
|
||||
wlr_log(WLR_DEBUG, "%s is %s",
|
||||
act_env, enabled ? "true" : "false");
|
||||
return enabled;
|
||||
}
|
||||
}
|
||||
|
||||
/* With no valid preference, update when a DRM backend is in use */
|
||||
bool have_drm = false;
|
||||
wlr_multi_for_each_backend(server->backend, backend_check_drm, &have_drm);
|
||||
return have_drm;
|
||||
}
|
||||
|
||||
static void
|
||||
update_activation_env(struct server *server, bool initialize)
|
||||
{
|
||||
if (!should_update_activation(server)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!getenv("DBUS_SESSION_BUS_ADDRESS")) {
|
||||
/* Prevent accidentally auto-launching a dbus session */
|
||||
wlr_log(WLR_INFO, "Not updating dbus execution environment: "
|
||||
"DBUS_SESSION_BUS_ADDRESS not set");
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_log(WLR_INFO, "Updating dbus execution environment");
|
||||
|
||||
char *cmd = strdup_printf("dbus-update-activation-environment %s", env_keys);
|
||||
char *env_keys = str_join(env_vars, "%s", " ");
|
||||
char *env_unset_keys = initialize ? NULL : str_join(env_vars, "%s=", " ");
|
||||
|
||||
char *cmd =
|
||||
strdup_printf("dbus-update-activation-environment %s",
|
||||
initialize ? env_keys : env_unset_keys);
|
||||
spawn_async_no_shell(cmd);
|
||||
free(cmd);
|
||||
|
||||
cmd = strdup_printf("systemctl --user import-environment %s", env_keys);
|
||||
cmd = strdup_printf("systemctl --user %s %s",
|
||||
initialize ? "import-environment" : "unset-environment", env_keys);
|
||||
spawn_async_no_shell(cmd);
|
||||
free(cmd);
|
||||
|
||||
free(env_keys);
|
||||
free(env_unset_keys);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -120,14 +184,11 @@ session_environment_init(void)
|
|||
paths_destroy(&paths);
|
||||
}
|
||||
|
||||
void
|
||||
session_autostart_init(void)
|
||||
static void
|
||||
run_session_script(const char *script)
|
||||
{
|
||||
/* Update dbus and systemd user environment, each may fail gracefully */
|
||||
update_activation_env("DISPLAY WAYLAND_DISPLAY XDG_CURRENT_DESKTOP");
|
||||
|
||||
struct wl_list paths;
|
||||
paths_config_create(&paths, "autostart");
|
||||
paths_config_create(&paths, script);
|
||||
|
||||
bool should_merge_config = rc.merge_config;
|
||||
struct wl_list *(*iter)(struct wl_list *list);
|
||||
|
|
@ -138,7 +199,7 @@ session_autostart_init(void)
|
|||
if (!file_exists(path->string)) {
|
||||
continue;
|
||||
}
|
||||
wlr_log(WLR_INFO, "run autostart file %s", path->string);
|
||||
wlr_log(WLR_INFO, "run session script %s", path->string);
|
||||
char *cmd = strdup_printf("sh %s", path->string);
|
||||
spawn_async_no_shell(cmd);
|
||||
free(cmd);
|
||||
|
|
@ -149,3 +210,20 @@ session_autostart_init(void)
|
|||
}
|
||||
paths_destroy(&paths);
|
||||
}
|
||||
|
||||
void
|
||||
session_autostart_init(struct server *server)
|
||||
{
|
||||
/* Update dbus and systemd user environment, each may fail gracefully */
|
||||
update_activation_env(server, /* initialize */ true);
|
||||
run_session_script("autostart");
|
||||
}
|
||||
|
||||
void
|
||||
session_shutdown(struct server *server)
|
||||
{
|
||||
run_session_script("shutdown");
|
||||
|
||||
/* Clear the dbus and systemd user environment, each may fail gracefully */
|
||||
update_activation_env(server, /* initialize */ false);
|
||||
}
|
||||
|
|
|
|||
84
src/debug.c
84
src/debug.c
|
|
@ -1,19 +1,23 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include "common/graphic-helpers.h"
|
||||
#include "common/scene-helpers.h"
|
||||
#include "debug.h"
|
||||
#include "labwc.h"
|
||||
#include "node.h"
|
||||
#include "ssd.h"
|
||||
#include "view.h"
|
||||
#include "workspaces.h"
|
||||
|
||||
#define HEADER_CHARS "------------------------------"
|
||||
|
||||
#define INDENT_SIZE 3
|
||||
#define LEFT_COL_SPACE 35
|
||||
|
||||
#define IGNORE_SSD true
|
||||
#define IGNORE_MENU true
|
||||
#define LEFT_COL_SPACE 35
|
||||
#define IGNORE_OSD_PREVIEW_OUTLINE true
|
||||
|
||||
static struct view *last_view;
|
||||
|
||||
|
|
@ -42,13 +46,13 @@ get_layer_name(uint32_t layer)
|
|||
{
|
||||
switch (layer) {
|
||||
case ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND:
|
||||
return "layer-background";
|
||||
return "output->layer-background";
|
||||
case ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM:
|
||||
return "layer-bottom";
|
||||
return "output->layer-bottom";
|
||||
case ZWLR_LAYER_SHELL_V1_LAYER_TOP:
|
||||
return "layer-top";
|
||||
return "output->layer-top";
|
||||
case ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY:
|
||||
return "layer-overlay";
|
||||
return "output->layer-overlay";
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
|
@ -57,16 +61,27 @@ get_layer_name(uint32_t layer)
|
|||
static const char *
|
||||
get_view_part(struct view *view, struct wlr_scene_node *node)
|
||||
{
|
||||
if (view && node == &view->scene_tree->node) {
|
||||
return "view";
|
||||
static char view_name[LEFT_COL_SPACE];
|
||||
if (!view) {
|
||||
return NULL;
|
||||
}
|
||||
if (view && node == view->scene_node) {
|
||||
if (node == &view->scene_tree->node) {
|
||||
const char *app_id = view_get_string_prop(view, "app_id");
|
||||
if (!app_id) {
|
||||
return "view";
|
||||
}
|
||||
snprintf(view_name, sizeof(view_name), "view (%s)", app_id);
|
||||
return view_name;
|
||||
}
|
||||
if (node == view->scene_node) {
|
||||
return "view->scene_node";
|
||||
}
|
||||
if (view) {
|
||||
return ssd_debug_get_node_name(view->ssd, node);
|
||||
if (view->resize_indicator.tree
|
||||
&& node == &view->resize_indicator.tree->node) {
|
||||
/* Created on-demand */
|
||||
return "view->resize_indicator";
|
||||
}
|
||||
return NULL;
|
||||
return ssd_debug_get_node_name(view->ssd, node);
|
||||
}
|
||||
|
||||
static const char *
|
||||
|
|
@ -81,12 +96,20 @@ get_special(struct server *server, struct wlr_scene_node *node)
|
|||
if (node == &server->view_tree->node) {
|
||||
return "server->view_tree";
|
||||
}
|
||||
if (node == &server->view_tree_always_on_bottom->node) {
|
||||
return "server->always_on_bottom";
|
||||
}
|
||||
if (node == &server->view_tree_always_on_top->node) {
|
||||
return "server->view_tree_always_on_top";
|
||||
return "server->always_on_top";
|
||||
}
|
||||
if (node->parent == server->view_tree) {
|
||||
/* Add node_descriptor just to get the name here? */
|
||||
return "workspace";
|
||||
struct workspace *workspace;
|
||||
wl_list_for_each(workspace, &server->workspaces, link) {
|
||||
if (&workspace->tree->node == node) {
|
||||
return workspace->name;
|
||||
}
|
||||
}
|
||||
return "unknown workspace";
|
||||
}
|
||||
if (node->parent == &server->scene->tree) {
|
||||
struct output *output;
|
||||
|
|
@ -95,15 +118,34 @@ get_special(struct server *server, struct wlr_scene_node *node)
|
|||
return "output->osd_tree";
|
||||
}
|
||||
if (node == &output->layer_popup_tree->node) {
|
||||
return "output->popup_tree";
|
||||
return "output->layer_popup_tree";
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (node == &output->layer_tree[i]->node) {
|
||||
return get_layer_name(i);
|
||||
}
|
||||
}
|
||||
if (node == &output->session_lock_tree->node) {
|
||||
return "output->session_lock_tree";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node == &server->xdg_popup_tree->node) {
|
||||
return "server->xdg_popup_tree";
|
||||
}
|
||||
if (node == &server->seat.drag.icons->node) {
|
||||
return "seat->drag.icons";
|
||||
}
|
||||
if (server->seat.region_overlay.tree
|
||||
&& node == &server->seat.region_overlay.tree->node) {
|
||||
/* Created on-demand */
|
||||
return "seat->region_overlay";
|
||||
}
|
||||
if (server->osd_state.preview_outline
|
||||
&& node == &server->osd_state.preview_outline->tree->node) {
|
||||
/* Created on-demand */
|
||||
return "osd_state->preview_outline";
|
||||
}
|
||||
#if HAVE_XWAYLAND
|
||||
if (node == &server->unmanaged_tree->node) {
|
||||
return "server->unmanaged_tree";
|
||||
|
|
@ -155,15 +197,21 @@ dump_tree(struct server *server, struct wlr_scene_node *node,
|
|||
HEADER_CHARS, HEADER_CHARS, HEADER_CHARS);
|
||||
printf(" ");
|
||||
}
|
||||
int padding = LEFT_COL_SPACE - pos - strlen(type);
|
||||
int max_width = LEFT_COL_SPACE - pos;
|
||||
int padding = max_width - strlen(type);
|
||||
if (padding < 0) {
|
||||
padding = 0;
|
||||
}
|
||||
if (!pos) {
|
||||
padding += 3;
|
||||
}
|
||||
printf("%s %*c %4d %4d [%p]\n", type, padding, ' ', x, y, node);
|
||||
printf("%.*s %*c %4d %4d [%p]\n", max_width - 1, type, padding, ' ', x, y, node);
|
||||
|
||||
if ((IGNORE_MENU && node == &server->menu_tree->node)
|
||||
|| (IGNORE_SSD && last_view
|
||||
&& ssd_debug_is_root_node(last_view->ssd, node))) {
|
||||
&& ssd_debug_is_root_node(last_view->ssd, node))
|
||||
|| (IGNORE_OSD_PREVIEW_OUTLINE && server->osd_state.preview_outline
|
||||
&& node == &server->osd_state.preview_outline->tree->node)) {
|
||||
printf("%*c%s\n", pos + 4 + INDENT_SIZE, ' ', "<skipping children>");
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
261
src/edges.c
261
src/edges.c
|
|
@ -1,6 +1,8 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <pixman.h>
|
||||
#include <wlr/util/edges.h>
|
||||
#include <wlr/util/box.h>
|
||||
#include "common/border.h"
|
||||
#include "common/macros.h"
|
||||
|
|
@ -8,6 +10,7 @@
|
|||
#include "edges.h"
|
||||
#include "labwc.h"
|
||||
#include "view.h"
|
||||
#include "node.h"
|
||||
|
||||
static void
|
||||
edges_for_target_geometry(struct border *edges, struct view *view,
|
||||
|
|
@ -35,34 +38,54 @@ edges_initialize(struct border *edges)
|
|||
}
|
||||
|
||||
static inline struct edge
|
||||
build_edge(struct border region, enum view_edge direction, int pad)
|
||||
build_edge(struct border region, enum wlr_edges direction, int pad)
|
||||
{
|
||||
struct edge edge = { 0 };
|
||||
|
||||
switch (direction) {
|
||||
case VIEW_EDGE_LEFT:
|
||||
case WLR_EDGE_LEFT:
|
||||
edge.offset = clipped_sub(region.left, pad);
|
||||
edge.min = region.top;
|
||||
edge.max = region.bottom;
|
||||
break;
|
||||
case VIEW_EDGE_RIGHT:
|
||||
case WLR_EDGE_RIGHT:
|
||||
edge.offset = clipped_add(region.right, pad);
|
||||
edge.min = region.top;
|
||||
edge.max = region.bottom;
|
||||
break;
|
||||
case VIEW_EDGE_UP:
|
||||
case WLR_EDGE_TOP:
|
||||
edge.offset = clipped_sub(region.top, pad);
|
||||
edge.min = region.left;
|
||||
edge.max = region.right;
|
||||
break;
|
||||
case VIEW_EDGE_DOWN:
|
||||
case WLR_EDGE_BOTTOM:
|
||||
edge.offset = clipped_add(region.bottom, pad);
|
||||
edge.min = region.left;
|
||||
edge.max = region.right;
|
||||
break;
|
||||
default:
|
||||
case WLR_EDGE_NONE:
|
||||
/* Should never be reached */
|
||||
assert(false);
|
||||
wlr_log(WLR_ERROR, "invalid direction");
|
||||
abort();
|
||||
}
|
||||
|
||||
return edge;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
is_lesser(enum wlr_edges direction)
|
||||
{
|
||||
return direction == WLR_EDGE_LEFT || direction == WLR_EDGE_TOP;
|
||||
}
|
||||
|
||||
static inline struct edge
|
||||
build_visible_edge(struct border region, enum wlr_edges direction,
|
||||
int pad, uint32_t edges_visible)
|
||||
{
|
||||
struct edge edge = build_edge(region, direction, pad);
|
||||
|
||||
if (!(edges_visible & direction)) {
|
||||
edge.offset = is_lesser(direction) ? INT_MIN : INT_MAX;
|
||||
}
|
||||
|
||||
return edge;
|
||||
|
|
@ -72,7 +95,7 @@ static void
|
|||
validate_single_region_edge(int *valid_edge,
|
||||
struct border view, struct border target,
|
||||
struct border region, edge_validator_t validator,
|
||||
enum view_edge direction)
|
||||
enum wlr_edges direction, uint32_t edges_visible)
|
||||
{
|
||||
/*
|
||||
* When a view snaps to another while moving to its target, it can do
|
||||
|
|
@ -90,42 +113,63 @@ validate_single_region_edge(int *valid_edge,
|
|||
* the region borders for aligned edges only.
|
||||
*/
|
||||
|
||||
bool lesser = direction == VIEW_EDGE_LEFT || direction == VIEW_EDGE_UP;
|
||||
enum wlr_edges opposing = WLR_EDGE_NONE;
|
||||
|
||||
switch (direction) {
|
||||
case WLR_EDGE_TOP:
|
||||
opposing = WLR_EDGE_BOTTOM;
|
||||
break;
|
||||
case WLR_EDGE_BOTTOM:
|
||||
opposing = WLR_EDGE_TOP;
|
||||
break;
|
||||
case WLR_EDGE_LEFT:
|
||||
opposing = WLR_EDGE_RIGHT;
|
||||
break;
|
||||
case WLR_EDGE_RIGHT:
|
||||
opposing = WLR_EDGE_LEFT;
|
||||
break;
|
||||
case WLR_EDGE_NONE:
|
||||
/* Should never be reached */
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
validator(valid_edge,
|
||||
build_edge(view, direction, 0),
|
||||
build_edge(target, direction, 0),
|
||||
build_edge(region, view_edge_invert(direction), 0),
|
||||
build_edge(region, direction, rc.gap), lesser);
|
||||
build_visible_edge(region, opposing, 0, edges_visible),
|
||||
build_visible_edge(region, direction, rc.gap, edges_visible),
|
||||
is_lesser(direction));
|
||||
}
|
||||
|
||||
static void
|
||||
validate_edges(struct border *valid_edges,
|
||||
struct border view, struct border target,
|
||||
struct border region, edge_validator_t validator)
|
||||
struct border region, uint32_t edges_visible,
|
||||
edge_validator_t validator)
|
||||
{
|
||||
/* Check for edges encountered during movement of left edge */
|
||||
validate_single_region_edge(&valid_edges->left,
|
||||
view, target, region, validator, VIEW_EDGE_LEFT);
|
||||
view, target, region, validator, WLR_EDGE_LEFT, edges_visible);
|
||||
|
||||
/* Check for edges encountered during movement of right edge */
|
||||
validate_single_region_edge(&valid_edges->right,
|
||||
view, target, region, validator, VIEW_EDGE_RIGHT);
|
||||
view, target, region, validator, WLR_EDGE_RIGHT, edges_visible);
|
||||
|
||||
/* Check for edges encountered during movement of top edge */
|
||||
validate_single_region_edge(&valid_edges->top,
|
||||
view, target, region, validator, VIEW_EDGE_UP);
|
||||
view, target, region, validator, WLR_EDGE_TOP, edges_visible);
|
||||
|
||||
/* Check for edges encountered during movement of bottom edge */
|
||||
validate_single_region_edge(&valid_edges->bottom,
|
||||
view, target, region, validator, VIEW_EDGE_DOWN);
|
||||
view, target, region, validator, WLR_EDGE_BOTTOM, edges_visible);
|
||||
}
|
||||
|
||||
static void
|
||||
validate_single_output_edge(int *valid_edge,
|
||||
struct border view, struct border target,
|
||||
struct border region, edge_validator_t validator,
|
||||
enum view_edge direction)
|
||||
enum wlr_edges direction)
|
||||
{
|
||||
static struct border unbounded = {
|
||||
.top = INT_MIN,
|
||||
|
|
@ -134,13 +178,11 @@ validate_single_output_edge(int *valid_edge,
|
|||
.left = INT_MIN,
|
||||
};
|
||||
|
||||
bool lesser = direction == VIEW_EDGE_LEFT || direction == VIEW_EDGE_UP;
|
||||
|
||||
validator(valid_edge,
|
||||
build_edge(view, direction, 0),
|
||||
build_edge(target, direction, 0),
|
||||
build_edge(region, direction, 0),
|
||||
build_edge(unbounded, direction, 0), lesser);
|
||||
build_edge(unbounded, direction, 0), is_lesser(direction));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -182,32 +224,170 @@ validate_output_edges(struct border *valid_edges,
|
|||
/* Left edge encounters a half-infinite region to the left of the output */
|
||||
|
||||
validate_single_output_edge(&valid_edges->left,
|
||||
view, target, output, validator, VIEW_EDGE_LEFT);
|
||||
view, target, output, validator, WLR_EDGE_LEFT);
|
||||
|
||||
/* Right edge encounters a half-infinite region to the right of the output */
|
||||
|
||||
validate_single_output_edge(&valid_edges->right,
|
||||
view, target, output, validator, VIEW_EDGE_RIGHT);
|
||||
view, target, output, validator, WLR_EDGE_RIGHT);
|
||||
|
||||
/* Top edge encounters a half-infinite region above the output */
|
||||
|
||||
validate_single_output_edge(&valid_edges->top,
|
||||
view, target, output, validator, VIEW_EDGE_UP);
|
||||
view, target, output, validator, WLR_EDGE_TOP);
|
||||
|
||||
/* Bottom edge encounters a half-infinite region below the output */
|
||||
validate_single_output_edge(&valid_edges->bottom,
|
||||
view, target, output, validator, VIEW_EDGE_DOWN);
|
||||
view, target, output, validator, WLR_EDGE_BOTTOM);
|
||||
}
|
||||
|
||||
/* Test if parts of the current view is covered by the remaining space in the region */
|
||||
static void
|
||||
subtract_view_from_space(struct view *view, pixman_region32_t *available)
|
||||
{
|
||||
struct wlr_box view_size = ssd_max_extents(view);
|
||||
pixman_box32_t view_rect = {
|
||||
.x1 = view_size.x,
|
||||
.x2 = view_size.x + view_size.width,
|
||||
.y1 = view_size.y,
|
||||
.y2 = view_size.y + view_size.height
|
||||
};
|
||||
|
||||
pixman_region_overlap_t overlap =
|
||||
pixman_region32_contains_rectangle(available, &view_rect);
|
||||
|
||||
switch (overlap) {
|
||||
case PIXMAN_REGION_IN:
|
||||
view->edges_visible = WLR_EDGE_TOP | WLR_EDGE_RIGHT
|
||||
| WLR_EDGE_BOTTOM | WLR_EDGE_LEFT;
|
||||
break;
|
||||
case PIXMAN_REGION_OUT:
|
||||
view->edges_visible = 0;
|
||||
return;
|
||||
case PIXMAN_REGION_PART:
|
||||
; /* works around "a label can only be part of a statement" */
|
||||
pixman_region32_t intersection;
|
||||
pixman_region32_init(&intersection);
|
||||
pixman_region32_intersect_rect(&intersection, available,
|
||||
view_size.x, view_size.y,
|
||||
view_size.width, view_size.height);
|
||||
|
||||
int nrects;
|
||||
const pixman_box32_t *rects =
|
||||
pixman_region32_rectangles(&intersection, &nrects);
|
||||
|
||||
view->edges_visible = 0;
|
||||
for (int i = 0; i < nrects; i++) {
|
||||
if (rects[i].x1 == view_rect.x1) {
|
||||
view->edges_visible |= WLR_EDGE_LEFT;
|
||||
}
|
||||
if (rects[i].y1 == view_rect.y1) {
|
||||
view->edges_visible |= WLR_EDGE_TOP;
|
||||
}
|
||||
if (rects[i].x2 == view_rect.x2) {
|
||||
view->edges_visible |= WLR_EDGE_RIGHT;
|
||||
}
|
||||
if (rects[i].y2 == view_rect.y2) {
|
||||
view->edges_visible |= WLR_EDGE_BOTTOM;
|
||||
}
|
||||
}
|
||||
pixman_region32_fini(&intersection);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Subtract the view geometry from the available region for the next check */
|
||||
pixman_region32_t view_region;
|
||||
pixman_region32_init_rects(&view_region, &view_rect, 1);
|
||||
pixman_region32_subtract(available, available, &view_region);
|
||||
pixman_region32_fini(&view_region);
|
||||
}
|
||||
|
||||
static void
|
||||
subtract_node_tree(struct wlr_scene_tree *tree, pixman_region32_t *available,
|
||||
struct view *ignored_view)
|
||||
{
|
||||
struct view *view;
|
||||
struct wlr_scene_node *node;
|
||||
struct node_descriptor *node_desc;
|
||||
wl_list_for_each_reverse(node, &tree->children, link) {
|
||||
if (!node->enabled) {
|
||||
/*
|
||||
* This skips everything that is not being
|
||||
* rendered, including minimized / unmapped
|
||||
* windows and workspaces other than the
|
||||
* current one.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
node_desc = node->data;
|
||||
if (node_desc && node_desc->type == LAB_NODE_DESC_VIEW) {
|
||||
view = node_view_from_node(node);
|
||||
if (view != ignored_view) {
|
||||
subtract_view_from_space(view, available);
|
||||
}
|
||||
} else if (node->type == WLR_SCENE_NODE_TREE) {
|
||||
subtract_node_tree(wlr_scene_tree_from_node(node),
|
||||
available, ignored_view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
edges_calculate_visibility(struct server *server, struct view *ignored_view)
|
||||
{
|
||||
/*
|
||||
* The region stores the available output layout space
|
||||
* and subtracts the window geometries in reverse rendering
|
||||
* order, e.g. a window rendered on top is subtracted first.
|
||||
*
|
||||
* This allows to detect if a window is actually visible.
|
||||
* If there is no overlap of its geometry and the remaining
|
||||
* region it must be completely covered by other windows.
|
||||
*
|
||||
*/
|
||||
pixman_region32_t region;
|
||||
pixman_region32_init(®ion);
|
||||
|
||||
/*
|
||||
* Initialize the region with each individual output.
|
||||
*
|
||||
* If we were to use NULL for the reference output we
|
||||
* would get a single combined wlr_box of the whole
|
||||
* layout which could cover actual invisible areas
|
||||
* in case the output resolutions differ.
|
||||
*/
|
||||
struct output *output;
|
||||
struct wlr_box layout_box;
|
||||
wl_list_for_each(output, &server->outputs, link) {
|
||||
if (!output_is_usable(output)) {
|
||||
continue;
|
||||
}
|
||||
wlr_output_layout_get_box(server->output_layout,
|
||||
output->wlr_output, &layout_box);
|
||||
pixman_region32_union_rect(®ion, ®ion,
|
||||
layout_box.x, layout_box.y, layout_box.width, layout_box.height);
|
||||
}
|
||||
|
||||
subtract_node_tree(&server->scene->tree, ®ion, ignored_view);
|
||||
|
||||
pixman_region32_fini(®ion);
|
||||
}
|
||||
|
||||
void
|
||||
edges_find_neighbors(struct border *nearest_edges, struct view *view,
|
||||
struct wlr_box target, struct output *output,
|
||||
edge_validator_t validator, bool use_pending)
|
||||
edge_validator_t validator, bool use_pending, bool ignore_hidden)
|
||||
{
|
||||
assert(view);
|
||||
assert(validator);
|
||||
assert(nearest_edges);
|
||||
|
||||
if (!output_is_usable(view->output)) {
|
||||
wlr_log(WLR_DEBUG, "ignoring edge search for view on unsable output");
|
||||
return;
|
||||
}
|
||||
|
||||
struct border view_edges = { 0 };
|
||||
struct border target_edges = { 0 };
|
||||
|
||||
|
|
@ -223,22 +403,21 @@ edges_find_neighbors(struct border *nearest_edges, struct view *view,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (output && v->output != output) {
|
||||
uint32_t edges_visible = ignore_hidden ? v->edges_visible :
|
||||
WLR_EDGE_TOP | WLR_EDGE_LEFT
|
||||
| WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT;
|
||||
|
||||
if (edges_visible == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* If view and v are on different outputs, make sure part of
|
||||
* view is actually in the usable area of the output of v.
|
||||
*/
|
||||
if (view->output != v->output) {
|
||||
struct wlr_box usable =
|
||||
output_usable_area_in_layout_coords(v->output);
|
||||
if (output && output != v->output && !view_on_output(v, output)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct wlr_box ol;
|
||||
if (!wlr_box_intersection(&ol, view_geom, &usable)) {
|
||||
continue;
|
||||
}
|
||||
/* Both view and v must share a common output */
|
||||
if (view->output != v->output && !(view->outputs & v->outputs)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct border border = ssd_get_margin(v->ssd);
|
||||
|
|
@ -252,7 +431,7 @@ edges_find_neighbors(struct border *nearest_edges, struct view *view,
|
|||
};
|
||||
|
||||
validate_edges(nearest_edges, view_edges,
|
||||
target_edges, win_edges, validator);
|
||||
target_edges, win_edges, edges_visible, validator);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -265,6 +444,12 @@ edges_find_outputs(struct border *nearest_edges, struct view *view,
|
|||
assert(validator);
|
||||
assert(nearest_edges);
|
||||
|
||||
if (!output_is_usable(view->output)) {
|
||||
wlr_log(WLR_DEBUG,
|
||||
"ignoring edge search for view on unsable output");
|
||||
return;
|
||||
}
|
||||
|
||||
struct border view_edges = { 0 };
|
||||
struct border target_edges = { 0 };
|
||||
|
||||
|
|
|
|||
|
|
@ -79,9 +79,7 @@ key_state_pressed_sent_keycodes(void)
|
|||
report(&bound, "before - bound:");
|
||||
|
||||
/* pressed_sent = pressed - bound */
|
||||
memcpy(pressed_sent.keys, pressed.keys,
|
||||
MAX_PRESSED_KEYS * sizeof(uint32_t));
|
||||
pressed_sent.nr_keys = pressed.nr_keys;
|
||||
pressed_sent = pressed;
|
||||
for (int i = 0; i < bound.nr_keys; ++i) {
|
||||
remove_key(&pressed_sent, bound.keys[i]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#include "edges.h"
|
||||
#include "input/keyboard.h"
|
||||
#include "labwc.h"
|
||||
#include "regions.h"
|
||||
|
|
@ -123,6 +124,9 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges)
|
|||
if (rc.resize_indicator) {
|
||||
resize_indicator_show(view);
|
||||
}
|
||||
if (rc.window_edge_strength) {
|
||||
edges_calculate_visibility(server, view);
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns true if view was snapped to any edge */
|
||||
|
|
|
|||
36
src/layers.c
36
src/layers.c
|
|
@ -260,14 +260,35 @@ popup_handle_destroy(struct wl_listener *listener, void *data)
|
|||
wl_container_of(listener, popup, destroy);
|
||||
wl_list_remove(&popup->destroy.link);
|
||||
wl_list_remove(&popup->new_popup.link);
|
||||
|
||||
/* Usually already removed unless there was no commit at all */
|
||||
if (popup->commit.notify) {
|
||||
wl_list_remove(&popup->commit.link);
|
||||
}
|
||||
|
||||
free(popup);
|
||||
}
|
||||
|
||||
static void
|
||||
popup_handle_commit(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct lab_layer_popup *popup =
|
||||
wl_container_of(listener, popup, commit);
|
||||
|
||||
if (popup->wlr_popup->base->initial_commit) {
|
||||
wlr_xdg_popup_unconstrain_from_box(popup->wlr_popup,
|
||||
&popup->output_toplevel_sx_box);
|
||||
|
||||
/* Prevent getting called over and over again */
|
||||
wl_list_remove(&popup->commit.link);
|
||||
popup->commit.notify = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void popup_handle_new_popup(struct wl_listener *listener, void *data);
|
||||
|
||||
static struct lab_layer_popup *
|
||||
create_popup(struct wlr_xdg_popup *wlr_popup, struct wlr_scene_tree *parent,
|
||||
struct wlr_box *output_toplevel_sx_box)
|
||||
create_popup(struct wlr_xdg_popup *wlr_popup, struct wlr_scene_tree *parent)
|
||||
{
|
||||
struct lab_layer_popup *popup = znew(*popup);
|
||||
popup->wlr_popup = wlr_popup;
|
||||
|
|
@ -282,10 +303,13 @@ create_popup(struct wlr_xdg_popup *wlr_popup, struct wlr_scene_tree *parent,
|
|||
|
||||
popup->destroy.notify = popup_handle_destroy;
|
||||
wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy);
|
||||
|
||||
popup->new_popup.notify = popup_handle_new_popup;
|
||||
wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup);
|
||||
|
||||
wlr_xdg_popup_unconstrain_from_box(wlr_popup, output_toplevel_sx_box);
|
||||
popup->commit.notify = popup_handle_commit;
|
||||
wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit);
|
||||
|
||||
return popup;
|
||||
}
|
||||
|
||||
|
|
@ -297,8 +321,7 @@ popup_handle_new_popup(struct wl_listener *listener, void *data)
|
|||
wl_container_of(listener, lab_layer_popup, new_popup);
|
||||
struct wlr_xdg_popup *wlr_popup = data;
|
||||
struct lab_layer_popup *new_popup = create_popup(wlr_popup,
|
||||
lab_layer_popup->scene_tree,
|
||||
&lab_layer_popup->output_toplevel_sx_box);
|
||||
lab_layer_popup->scene_tree);
|
||||
new_popup->output_toplevel_sx_box =
|
||||
lab_layer_popup->output_toplevel_sx_box;
|
||||
}
|
||||
|
|
@ -357,8 +380,7 @@ handle_new_popup(struct wl_listener *listener, void *data)
|
|||
.width = output_box.width,
|
||||
.height = output_box.height,
|
||||
};
|
||||
struct lab_layer_popup *popup = create_popup(wlr_popup,
|
||||
surface->tree, &output_toplevel_sx_box);
|
||||
struct lab_layer_popup *popup = create_popup(wlr_popup, surface->tree);
|
||||
popup->output_toplevel_sx_box = output_toplevel_sx_box;
|
||||
|
||||
if (surface->layer_surface->current.layer
|
||||
|
|
|
|||
|
|
@ -171,13 +171,15 @@ main(int argc, char *argv[])
|
|||
|
||||
menu_init(&server);
|
||||
|
||||
session_autostart_init();
|
||||
session_autostart_init(&server);
|
||||
if (startup_cmd) {
|
||||
spawn_async_no_shell(startup_cmd);
|
||||
}
|
||||
|
||||
wl_display_run(server.wl_display);
|
||||
|
||||
session_shutdown(&server);
|
||||
|
||||
server_finish(&server);
|
||||
|
||||
menu_finish(&server);
|
||||
|
|
|
|||
52
src/output.c
52
src/output.c
|
|
@ -150,6 +150,32 @@ output_request_state_notify(struct wl_listener *listener, void *data)
|
|||
struct output *output = wl_container_of(listener, output, request_state);
|
||||
const struct wlr_output_event_request_state *event = data;
|
||||
|
||||
/*
|
||||
* If wlroots ever requests other state changes here we could
|
||||
* restore more of ddc9047a67cd53b2948f71fde1bbe9118000dd3f.
|
||||
*/
|
||||
if (event->state->committed == WLR_OUTPUT_STATE_MODE) {
|
||||
/* Only the mode has changed */
|
||||
switch (event->state->mode_type) {
|
||||
case WLR_OUTPUT_STATE_MODE_FIXED:
|
||||
wlr_output_set_mode(output->wlr_output, event->state->mode);
|
||||
break;
|
||||
case WLR_OUTPUT_STATE_MODE_CUSTOM:
|
||||
wlr_output_set_custom_mode(output->wlr_output,
|
||||
event->state->custom_mode.width,
|
||||
event->state->custom_mode.height,
|
||||
event->state->custom_mode.refresh);
|
||||
break;
|
||||
}
|
||||
wlr_output_schedule_frame(output->wlr_output);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fallback path for everything that we didn't handle above.
|
||||
* The commit will cause a black frame injection so this
|
||||
* path causes flickering during resize of nested outputs.
|
||||
*/
|
||||
if (!wlr_output_commit_state(output->wlr_output, event->state)) {
|
||||
wlr_log(WLR_ERROR, "Backend requested a new state that could not be applied");
|
||||
}
|
||||
|
|
@ -405,10 +431,11 @@ output_update_for_layout_change(struct server *server)
|
|||
cursor_update_image(&server->seat);
|
||||
}
|
||||
|
||||
static void
|
||||
static bool
|
||||
output_config_apply(struct server *server,
|
||||
struct wlr_output_configuration_v1 *config)
|
||||
{
|
||||
bool success = true;
|
||||
server->pending_output_layout_change++;
|
||||
|
||||
struct wlr_output_configuration_head_v1 *head;
|
||||
|
|
@ -436,8 +463,15 @@ output_config_apply(struct server *server,
|
|||
output_enable_adaptive_sync(o, head->state.adaptive_sync_enabled);
|
||||
}
|
||||
if (!wlr_output_commit(o)) {
|
||||
wlr_log(WLR_ERROR, "Output config commit failed");
|
||||
continue;
|
||||
/*
|
||||
* FIXME: This is only part of the story, we should revert
|
||||
* all previously commited outputs as well here.
|
||||
*
|
||||
* See https://github.com/labwc/labwc/pull/1528
|
||||
*/
|
||||
wlr_log(WLR_INFO, "Output config commit failed: %s", o->name);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Only do Layout specific actions if the commit went trough */
|
||||
|
|
@ -477,6 +511,7 @@ output_config_apply(struct server *server,
|
|||
|
||||
server->pending_output_layout_change--;
|
||||
do_output_layout_change(server);
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
@ -509,11 +544,17 @@ verify_output_config_v1(const struct wlr_output_configuration_v1 *config)
|
|||
|
||||
if (wlr_output_is_wl(head->state.output) && refresh != 0) {
|
||||
/* Wayland backend does not support refresh rates */
|
||||
err_msg = "Wayland backend refresh rate unsupported";
|
||||
err_msg = "Wayland backend refresh rates unsupported";
|
||||
goto custom_mode_failed;
|
||||
}
|
||||
}
|
||||
|
||||
if (wlr_output_is_wl(head->state.output)
|
||||
&& !head->state.adaptive_sync_enabled) {
|
||||
err_msg = "Wayland backend requires adaptive sync";
|
||||
goto custom_mode_failed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure the new output state can be applied on
|
||||
* its own and inform the client when it can not.
|
||||
|
|
@ -569,8 +610,7 @@ handle_output_manager_apply(struct wl_listener *listener, void *data)
|
|||
|
||||
bool config_is_good = verify_output_config_v1(config);
|
||||
|
||||
if (config_is_good) {
|
||||
output_config_apply(server, config);
|
||||
if (config_is_good && output_config_apply(server, config)) {
|
||||
wlr_output_configuration_v1_send_succeeded(config);
|
||||
} else {
|
||||
wlr_output_configuration_v1_send_failed(config);
|
||||
|
|
|
|||
|
|
@ -114,8 +114,9 @@ resistance_move_apply(struct view *view, double *x, double *y)
|
|||
|
||||
if (rc.window_edge_strength != 0) {
|
||||
/* Find any relevant window edges encountered by this move */
|
||||
edges_find_neighbors(&next_edges, view, target, NULL,
|
||||
check_edge_window, /* use_pending */ false);
|
||||
edges_find_neighbors(&next_edges,
|
||||
view, target, NULL, check_edge_window,
|
||||
/* use_pending */ false, /* ignore_hidden */ true);
|
||||
}
|
||||
|
||||
/* If any "best" edges were encountered during this move, snap motion */
|
||||
|
|
@ -143,8 +144,9 @@ resistance_resize_apply(struct view *view, struct wlr_box *new_geom)
|
|||
|
||||
if (rc.window_edge_strength != 0) {
|
||||
/* Find any relevant window edges encountered by this move */
|
||||
edges_find_neighbors(&next_edges, view, *new_geom, NULL,
|
||||
check_edge_window, /* use_pending */ false);
|
||||
edges_find_neighbors(&next_edges,
|
||||
view, *new_geom, NULL, check_edge_window,
|
||||
/* use_pending */ false, /* ignore_hidden */ true);
|
||||
}
|
||||
|
||||
/* If any "best" edges were encountered during this move, snap motion */
|
||||
|
|
|
|||
48
src/seat.c
48
src/seat.c
|
|
@ -91,6 +91,24 @@ get_category(struct wlr_input_device *device)
|
|||
static void
|
||||
configure_libinput(struct wlr_input_device *wlr_input_device)
|
||||
{
|
||||
/*
|
||||
* TODO: We do not check any return values for the various
|
||||
* libinput_device_config_*_set_*() calls. It would
|
||||
* be nice if we could inform the users via log file
|
||||
* that some libinput setting could not be applied.
|
||||
*
|
||||
* TODO: We are currently using int32_t with -1 as default
|
||||
* to desribe the not-configured state. This is not
|
||||
* really optimal as we can't properly deal with
|
||||
* enum values that are 0. After some discussion via
|
||||
* IRC the best way forward seem to be to use a
|
||||
* uint32_t instead and UINT32_MAX as indicator for
|
||||
* a not-configured state. This allows to properly
|
||||
* test the enum being a member of a bitset via
|
||||
* mask & value == value. All libinput enums are
|
||||
* way below UINT32_MAX.
|
||||
*/
|
||||
|
||||
if (!wlr_input_device) {
|
||||
wlr_log(WLR_ERROR, "no wlr_input_device");
|
||||
return;
|
||||
|
|
@ -189,6 +207,36 @@ configure_libinput(struct wlr_input_device *wlr_input_device)
|
|||
wlr_log(WLR_INFO, "dwt configured");
|
||||
libinput_device_config_dwt_set_enabled(libinput_dev, dc->dwt);
|
||||
}
|
||||
|
||||
if ((dc->click_method != LIBINPUT_CONFIG_CLICK_METHOD_NONE
|
||||
&& (libinput_device_config_click_get_methods(libinput_dev)
|
||||
& dc->click_method) == 0)
|
||||
|| dc->click_method < 0) {
|
||||
wlr_log(WLR_INFO, "click method not configured");
|
||||
} else {
|
||||
wlr_log(WLR_INFO, "click method configured");
|
||||
|
||||
/*
|
||||
* Note, the documentation claims that:
|
||||
* > [...] The device may require changing to a neutral state
|
||||
* > first before activating the new method.
|
||||
*
|
||||
* However, just setting the method seems to work without
|
||||
* issues.
|
||||
*/
|
||||
|
||||
libinput_device_config_click_set_method(libinput_dev, dc->click_method);
|
||||
}
|
||||
|
||||
if ((dc->send_events_mode != LIBINPUT_CONFIG_SEND_EVENTS_ENABLED
|
||||
&& (libinput_device_config_send_events_get_modes(libinput_dev)
|
||||
& dc->send_events_mode) == 0)
|
||||
|| dc->send_events_mode < 0) {
|
||||
wlr_log(WLR_INFO, "send events mode not configured");
|
||||
} else {
|
||||
wlr_log(WLR_INFO, "send events mode configured");
|
||||
libinput_device_config_send_events_set_mode(libinput_dev, dc->send_events_mode);
|
||||
}
|
||||
}
|
||||
|
||||
static struct wlr_output *
|
||||
|
|
|
|||
12
src/server.c
12
src/server.c
|
|
@ -17,6 +17,7 @@
|
|||
#include <wlr/types/wlr_viewporter.h>
|
||||
#if HAVE_XWAYLAND
|
||||
#include <wlr/xwayland.h>
|
||||
#include "xwayland-shell-v1-protocol.h"
|
||||
#endif
|
||||
#include "drm-lease-v1-protocol.h"
|
||||
#include "config/rcxml.h"
|
||||
|
|
@ -172,9 +173,11 @@ server_global_filter(const struct wl_client *client, const struct wl_global *glo
|
|||
(void)iface; (void)server;
|
||||
|
||||
#if HAVE_XWAYLAND
|
||||
struct wl_client *xwayland_client =
|
||||
server->xwayland ? server->xwayland->server->client : NULL;
|
||||
if (xwayland_client && client == xwayland_client) {
|
||||
struct wl_client *xwayland_client = (server->xwayland && server->xwayland->server)
|
||||
? server->xwayland->server->client
|
||||
: NULL;
|
||||
|
||||
if (client == xwayland_client) {
|
||||
/*
|
||||
* Filter out wp_drm_lease_device_v1 for now as it is resulting in
|
||||
* issues with Xwayland applications lagging over time.
|
||||
|
|
@ -184,6 +187,9 @@ server_global_filter(const struct wl_client *client, const struct wl_global *glo
|
|||
if (!strcmp(iface->name, wp_drm_lease_device_v1_interface.name)) {
|
||||
return false;
|
||||
}
|
||||
} else if (!strcmp(iface->name, xwayland_shell_v1_interface.name)) {
|
||||
/* Filter out the xwayland shell for usual clients */
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
15
src/snap.c
15
src/snap.c
|
|
@ -121,8 +121,9 @@ snap_move_to_edge(struct view *view, enum view_edge direction,
|
|||
struct border next_edges;
|
||||
edges_initialize(&next_edges);
|
||||
|
||||
edges_find_neighbors(&next_edges, view, target,
|
||||
output, check_edge, /* use_pending */ true);
|
||||
edges_find_neighbors(&next_edges,
|
||||
view, target, output, check_edge,
|
||||
/* use_pending */ true, /* ignore_hidden */ false);
|
||||
|
||||
/* If any "best" edges were encountered, limit motion */
|
||||
edges_adjust_move_coords(view, next_edges,
|
||||
|
|
@ -196,8 +197,9 @@ snap_grow_to_next_edge(struct view *view, enum view_edge direction,
|
|||
edges_initialize(&next_edges);
|
||||
|
||||
/* Limit motion to any intervening edge of other views on this output */
|
||||
edges_find_neighbors(&next_edges, view, *geo,
|
||||
output, check_edge, /* use_pending */ true);
|
||||
edges_find_neighbors(&next_edges,
|
||||
view, *geo, output, check_edge,
|
||||
/* use_pending */ true, /* ignore_hidden */ false);
|
||||
edges_adjust_resize_geom(view, next_edges,
|
||||
resize_edges, geo, /* use_pending */ true);
|
||||
}
|
||||
|
|
@ -255,8 +257,9 @@ snap_shrink_to_next_edge(struct view *view, enum view_edge direction,
|
|||
view->output, check_edge, /* use_pending */ true);
|
||||
|
||||
/* Limit motion to any intervening edge of ther views on this output */
|
||||
edges_find_neighbors(&next_edges, view, *geo,
|
||||
view->output, check_edge, /* use_pending */ true);
|
||||
edges_find_neighbors(&next_edges,
|
||||
view, *geo, view->output, check_edge,
|
||||
/* use_pending */ true, /* ignore_hidden */ false);
|
||||
|
||||
edges_adjust_resize_geom(view, next_edges,
|
||||
resize_edges, geo, /* use_pending */ true);
|
||||
|
|
|
|||
83
src/view.c
83
src/view.c
|
|
@ -2,6 +2,7 @@
|
|||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <strings.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include "common/macros.h"
|
||||
#include "common/match.h"
|
||||
#include "common/mem.h"
|
||||
|
|
@ -1519,8 +1520,44 @@ view_on_output_destroy(struct view *view)
|
|||
view->output = NULL;
|
||||
}
|
||||
|
||||
static enum wlr_direction
|
||||
opposite_direction(enum wlr_direction direction)
|
||||
{
|
||||
switch (direction) {
|
||||
case WLR_DIRECTION_RIGHT:
|
||||
return WLR_DIRECTION_LEFT;
|
||||
case WLR_DIRECTION_LEFT:
|
||||
return WLR_DIRECTION_RIGHT;
|
||||
case WLR_DIRECTION_DOWN:
|
||||
return WLR_DIRECTION_UP;
|
||||
case WLR_DIRECTION_UP:
|
||||
return WLR_DIRECTION_DOWN;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static enum wlr_direction
|
||||
get_wlr_direction(enum view_edge edge)
|
||||
{
|
||||
switch (edge) {
|
||||
case VIEW_EDGE_LEFT:
|
||||
return WLR_DIRECTION_LEFT;
|
||||
case VIEW_EDGE_RIGHT:
|
||||
return WLR_DIRECTION_RIGHT;
|
||||
case VIEW_EDGE_UP:
|
||||
return WLR_DIRECTION_UP;
|
||||
case VIEW_EDGE_DOWN:
|
||||
return WLR_DIRECTION_DOWN;
|
||||
case VIEW_EDGE_CENTER:
|
||||
case VIEW_EDGE_INVALID:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct output *
|
||||
view_get_adjacent_output(struct view *view, enum view_edge edge)
|
||||
view_get_adjacent_output(struct view *view, enum view_edge edge, bool wrap)
|
||||
{
|
||||
assert(view);
|
||||
struct output *output = view->output;
|
||||
|
|
@ -1530,32 +1567,31 @@ view_get_adjacent_output(struct view *view, enum view_edge edge)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_box box = output_usable_area_in_layout_coords(output);
|
||||
int lx = box.x + box.width / 2;
|
||||
int ly = box.y + box.height / 2;
|
||||
|
||||
/* Determine any adjacent output in the appropriate direction */
|
||||
struct wlr_output *new_output = NULL;
|
||||
struct wlr_output *current_output = output->wlr_output;
|
||||
struct wlr_output_layout *layout = view->server->output_layout;
|
||||
switch (edge) {
|
||||
case VIEW_EDGE_LEFT:
|
||||
new_output = wlr_output_layout_adjacent_output(
|
||||
layout, WLR_DIRECTION_LEFT, current_output, 1, 0);
|
||||
break;
|
||||
case VIEW_EDGE_RIGHT:
|
||||
new_output = wlr_output_layout_adjacent_output(
|
||||
layout, WLR_DIRECTION_RIGHT, current_output, 1, 0);
|
||||
break;
|
||||
case VIEW_EDGE_UP:
|
||||
new_output = wlr_output_layout_adjacent_output(
|
||||
layout, WLR_DIRECTION_UP, current_output, 0, 1);
|
||||
break;
|
||||
case VIEW_EDGE_DOWN:
|
||||
new_output = wlr_output_layout_adjacent_output(
|
||||
layout, WLR_DIRECTION_DOWN, current_output, 0, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
enum wlr_direction direction = get_wlr_direction(edge);
|
||||
new_output = wlr_output_layout_adjacent_output(layout, direction,
|
||||
current_output, lx, ly);
|
||||
|
||||
/*
|
||||
* Optionally wrap around from top-to-bottom or left-to-right, and vice
|
||||
* versa.
|
||||
*/
|
||||
if (wrap && !new_output) {
|
||||
new_output = wlr_output_layout_farthest_output(layout,
|
||||
opposite_direction(direction), current_output, lx, ly);
|
||||
}
|
||||
|
||||
/* When "adjacent" output is the same as the original, there is no adjacent */
|
||||
/*
|
||||
* When "adjacent" output is the same as the original, there is no
|
||||
* adjacent
|
||||
*/
|
||||
if (!new_output || new_output == current_output) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -1629,7 +1665,8 @@ view_move_to_edge(struct view *view, enum view_edge direction, bool snap_to_wind
|
|||
}
|
||||
|
||||
/* Otherwise, move to edge of next adjacent display, if possible */
|
||||
struct output *output = view_get_adjacent_output(view, direction);
|
||||
struct output *output =
|
||||
view_get_adjacent_output(view, direction, /* wrap */ false);
|
||||
if (!output) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1788,7 +1825,7 @@ view_snap_to_edge(struct view *view, enum view_edge edge,
|
|||
|
||||
if (across_outputs && view->tiled == edge && view->maximized == VIEW_AXIS_NONE) {
|
||||
/* We are already tiled for this edge; try to switch outputs */
|
||||
output = view_get_adjacent_output(view, edge);
|
||||
output = view_get_adjacent_output(view, edge, /* wrap */ false);
|
||||
|
||||
if (!output) {
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -16,15 +16,17 @@ struct xdg_popup {
|
|||
struct view *parent_view;
|
||||
struct wlr_xdg_popup *wlr_popup;
|
||||
|
||||
struct wl_listener commit;
|
||||
struct wl_listener destroy;
|
||||
struct wl_listener new_popup;
|
||||
};
|
||||
|
||||
static void
|
||||
popup_unconstrain(struct view *view, struct wlr_xdg_popup *popup)
|
||||
popup_unconstrain(struct xdg_popup *popup)
|
||||
{
|
||||
struct view *view = popup->parent_view;
|
||||
struct server *server = view->server;
|
||||
struct wlr_box *popup_box = &popup->current.geometry;
|
||||
struct wlr_box *popup_box = &popup->wlr_popup->current.geometry;
|
||||
struct wlr_output_layout *output_layout = server->output_layout;
|
||||
struct wlr_output *wlr_output = wlr_output_layout_output_at(
|
||||
output_layout, view->current.x + popup_box->x,
|
||||
|
|
@ -39,7 +41,7 @@ popup_unconstrain(struct view *view, struct wlr_xdg_popup *popup)
|
|||
.width = output_box.width,
|
||||
.height = output_box.height,
|
||||
};
|
||||
wlr_xdg_popup_unconstrain_from_box(popup, &output_toplevel_box);
|
||||
wlr_xdg_popup_unconstrain_from_box(popup->wlr_popup, &output_toplevel_box);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -48,9 +50,28 @@ handle_xdg_popup_destroy(struct wl_listener *listener, void *data)
|
|||
struct xdg_popup *popup = wl_container_of(listener, popup, destroy);
|
||||
wl_list_remove(&popup->destroy.link);
|
||||
wl_list_remove(&popup->new_popup.link);
|
||||
|
||||
/* Usually already removed unless there was no commit at all */
|
||||
if (popup->commit.notify) {
|
||||
wl_list_remove(&popup->commit.link);
|
||||
}
|
||||
free(popup);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_xdg_popup_commit(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct xdg_popup *popup = wl_container_of(listener, popup, commit);
|
||||
|
||||
if (popup->wlr_popup->base->initial_commit) {
|
||||
popup_unconstrain(popup);
|
||||
|
||||
/* Prevent getting called over and over again */
|
||||
wl_list_remove(&popup->commit.link);
|
||||
popup->commit.notify = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
popup_handle_new_xdg_popup(struct wl_listener *listener, void *data)
|
||||
{
|
||||
|
|
@ -75,9 +96,13 @@ xdg_popup_create(struct view *view, struct wlr_xdg_popup *wlr_popup)
|
|||
|
||||
popup->destroy.notify = handle_xdg_popup_destroy;
|
||||
wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy);
|
||||
|
||||
popup->new_popup.notify = popup_handle_new_xdg_popup;
|
||||
wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup);
|
||||
|
||||
popup->commit.notify = handle_xdg_popup_commit;
|
||||
wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit);
|
||||
|
||||
/*
|
||||
* We must add xdg popups to the scene graph so they get rendered. The
|
||||
* wlroots scene graph provides a helper for this, but to use it we must
|
||||
|
|
@ -100,6 +125,4 @@ xdg_popup_create(struct view *view, struct wlr_xdg_popup *wlr_popup)
|
|||
wlr_scene_xdg_surface_create(parent_tree, wlr_popup->base);
|
||||
node_descriptor_create(wlr_popup->base->surface->data,
|
||||
LAB_NODE_DESC_XDG_POPUP, view);
|
||||
|
||||
popup_unconstrain(view, wlr_popup);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue