Compare commits

...

55 commits

Author SHA1 Message Date
Consolatis
d6dcda73d6 [wip] chase wlroots: track master branch 2025-10-03 01:11:59 +02:00
Consolatis
19b8ad35f9 chase wlroots: ime: rename to new_input_method (MR 5107)
Ref: 06aacb2a6fd237a5e1062d611909432bbcf5b566
(input-method: rename input_method event to new_input_method)
2025-10-03 01:11:59 +02:00
Christopher Snowhill
b7f46ac9ba [wip] chase wlroots: Add wl_fixes interface (MR + subproject commit missing)
Ref: 812675ba34ce612e9294e8a9814b1baf4b4775d4
(fixes: add implementation)
2025-10-03 01:11:59 +02:00
Consolatis
13e838cd34 chase wlroots: ime: rename to new_text_input (MR 5032)
Ref: 536100488fc4c64528786801860f96cfa1a55765
(text-input-v3: Name new text input event correctly)
2025-10-03 01:11:59 +02:00
Consolatis
a0dacbf85d chase wlroots: increase wlroots meson dep 2025-10-03 01:11:59 +02:00
Consolatis
4cc00058e3 [revert later] CI: allow compiling wlroots as subproject 2025-10-03 01:11:57 +02:00
Johan Malm
bed0be8a88 src/common/graphic-helpers.c: fix declaration/definition arg name difference
Some checks failed
labwc.github.io / notify (push) Has been cancelled
2025-10-01 21:18:44 +01:00
Johan Malm
0d0d1075cc include/common/scene-helpers: fix declaration/definition arg name difference 2025-10-01 21:18:44 +01:00
Johan Malm
4c1e66f6c8 include/common/buf.h: fix declaration/definition arg name difference 2025-10-01 21:18:44 +01:00
Johan Malm
389cef9c3b include/common/box.h: fix declaration/definition arg name difference 2025-10-01 21:18:44 +01:00
tokyo4j
e558d0d619 labnag: rename options for color 2025-10-01 20:10:33 +01:00
Johan Malm
c8581b3fed include/common/xml.h: fix declaration/definition arg name difference 2025-09-30 02:38:13 +02:00
Johan Malm
60d536304b Privatize view_append_children() 2025-09-29 20:22:46 +01:00
Johan Malm
9ec49144ac Privatize desktop_topmost_focusable_view() 2025-09-29 20:22:46 +01:00
Johan Malm
eb41c6a3b0 Privatize view_contains_window_type() 2025-09-29 20:22:46 +01:00
Johan Malm
2ea0f6fff4 Privatize output_manager_init() 2025-09-29 20:22:46 +01:00
Johan Malm
950c634cea Privatize xwayland_surface_from_view() 2025-09-29 20:22:46 +01:00
Johan Malm
286005e121 Privatize rcxml_parse_xml() 2025-09-29 20:22:46 +01:00
Johan Malm
040e25f38e Privatize private view_get_root() 2025-09-29 20:22:46 +01:00
Johan Malm
27f3097f8f build: add 'sections' option to show unused functions 2025-09-29 20:22:46 +01:00
tokyo4j
c5cd1f691d CI: use libwlroots-0.19-dev build-dep for Debian 2025-09-29 19:41:32 +01:00
tokyo4j
46bd1fef95 CI: add unit tests 2025-09-29 19:41:32 +01:00
tokyo4j
7e27f78662 test/xml: use xmlBufferContent()
xmlBuffer->content has been deprecated.
2025-09-29 19:41:32 +01:00
tokyo4j
1043a9becc test: fix build error in t/xml.c
38a1a9b broke `t/xml.c` due to `macros.h` requiring `wlr/version.h`.
This commit fixes it by adding `wlroots` as a direct dependency of the
test executables.
2025-09-29 19:41:32 +01:00
Johan Malm
94c980c6be action: fix UAF when using prompt during reconfigure
Reported-by: @jlindgren90

Fixes #3106
2025-09-26 21:25:34 +01:00
Johan Malm
c9030dcc5b CI: fix broken FreeBSD CI by setting -Dlibsfdo:b_ndebug=false
...because with with

    meson setup build -Dbuildtype=release -Db_ndebug=true \
        --werror --force-fallback-for=libsfdo

we get the following warning:

    In file included from ../subprojects/libsfdo/common/dirs.c:5:
    ../subprojects/libsfdo/include/common/membuild.h: In function ‘sfdo_membuild_validate’:
    ../subprojects/libsfdo/include/common/membuild.h:29:65: error: unused parameter ‘membuild’ [-Werror=unused-parameter]
       29 | static inline void sfdo_membuild_validate(struct sfdo_membuild *membuild) {

...because `sfdo_membuild_validate()` contains nothing but an `assert()`
and that therefore results in an `unused-parameter` warning with `NDEBUG`.

https://gitlab.freedesktop.org/vyivel/libsfdo/-/blob/main/include/common/membuild.h?ref_type=heads#L30
2025-09-26 19:06:21 +02:00
Johan Malm
26bd02d457 Add translate.h for HAVE_NLS includes/defines
...to shrink labwc.h footprint
2025-09-26 10:43:23 -04:00
Johan Malm
1692c47fa0 Remove unused function key_state_nr_pressed_keys() 2025-09-26 10:41:21 -04:00
Johan Malm
bdc8e1c546 Remove unused function lab_xml_get_node() 2025-09-26 10:41:21 -04:00
Johan Malm
ee87b4fc30 Remove unused function trim_last_field() 2025-09-26 10:41:21 -04:00
Johan Malm
34e52a40c7 Remove unused function node_layer_popup_from_node() 2025-09-26 10:41:21 -04:00
Johan Malm
139a5f0383 Remove unused function output_max_scale() 2025-09-26 10:41:21 -04:00
Johan Malm
0bf2678f9d Remove unused function scaled_font_buffer_set_max_width() 2025-09-26 10:41:21 -04:00
Johan Malm
6bbdc3c6dc Remove unused function menu_call_actions() 2025-09-26 10:41:21 -04:00
Johan Malm
7a5b7aa378 rcxml.h: minor tweaks to order of variables 2025-09-25 21:12:36 +01:00
Johan Malm
5fdebedcd9 labwc-config(5): document <promptCommand>
Some checks failed
labwc.github.io / notify (push) Has been cancelled
2025-09-24 20:13:51 +01:00
Johan Malm
5765586636 config: add <core><promptCommand>
...to enable configuration of the action prompt command.

Also set some better defaults for labnag.

The new default command is:

    labnag \
        --message '%m' \
        --button-dismiss '%n' \
        --button-dismiss '%y' \
        --background '%b' \
        --text '%t' \
        --border '%t' \
        --border-bottom '%t' \
        --button-background '%b' \
        --button-text '%t' \
        --border-bottom-size 1 \
        --button-border-size 3 \
        --timeout 0

...where the conversion specifiers are defined as follows:

    %m: the `<prompt>` message option
    %n: _("No")
    %y: _("Yes")
    %b: osd.bg.color
    %t: osd.label.text.color

This config options also enables the use of a different dialog client, for
example like this:

    <core>
      <promptCommand>zenity --question --text="%m"</promptCommand>
    </core>
2025-09-24 20:13:51 +01:00
Johan Malm
7028e65154 labnag: fix segfault caused by providing --timeout as long option 2025-09-24 20:13:51 +01:00
tokyo4j
ebce406b11 font: remove 4px padding on the right
Added `menu.items.padding.x` padding between item text and arrow instead.

Replaced `if (!string)` with `if (string_null_or_empty(string))` in
`font_extents()` just as a minor optimization.
2025-09-22 18:23:33 +01:00
Johan Malm
141f932efa README.md: remove high-level scope summary
...as it is very old and not relevant anymore.
2025-09-21 20:50:59 +09:00
tokyo4j
24f39e3a41 default-bindings.h: set combine="yes" for SnapToEdge keybinds
Some checks failed
labwc.github.io / notify (push) Has been cancelled
2025-09-19 16:23:23 +09:00
tokyo4j
2ac48116e1 action: allow SnapToEdge to combine two cardinal directions
This patch adds `combine` argument to (Toggle)SnapToEdge actions.
This allows to snap a window to e.g. up-left by running two actions:
- `<action name="SnapToEdge" direction="left" combine="yes" />`
- `<action name="SnapToEdge" direction="up" combine="yes" />`

Then running `<action name="SnapToEdge" direction="down" combine="yes" />`
snaps it to left again. This behavior is almost the same as KWin, except
that snapping a up-right-tiled window to right doesn't move it to the
right-adjacent output, but makes it right-tiled first.
2025-09-19 16:23:23 +09:00
tokyo4j
af6a0df231 view: remove an obsolete code in view_snap_to_edge()
We no longer need to call view_apply_tiled_geometry() there, since we now
clear view->tiled when dragging a tiled window since 9f51384.
2025-09-19 16:23:23 +09:00
Johan Malm
0db3b9309b libsfdo.wrap: update revision to v0.1.4 2025-09-18 23:42:53 +02:00
Johan Malm
387e62d87b README.md: remove yambar reference as discontinued 2025-09-17 22:38:35 +02:00
cunlem
c6503e299f Update labwc-actions.5.scd
Some checks failed
labwc.github.io / notify (push) Has been cancelled
2025-09-16 20:27:02 +01:00
Johan Malm
268ef857db NEWS.md: interim update 2025-09-16 20:21:10 +01:00
tokyo4j
f09ace51bf view: fix <query monitor="current|left|right" />
Before this commit, <else> branch was always executed with
monitor="current", monitor="left" or monitor="right" queries.

For example:

<action name="If">
  <query monitor="current" />
  <then>
    <action />
  </then>
  <else>
    <action />
  </else>
</action>
2025-09-15 03:45:05 +09:00
John Lindgren
d54051d9c1 clang-format: tweak to match existing code a little better
"clang-format -i src/view.c" before:
  1 file changed, 204 insertions(+), 169 deletions(-)

"clang-format -i src/view.c" after:
  1 file changed, 181 insertions(+), 146 deletions(-)
2025-09-13 12:06:52 +01:00
John Lindgren
5ce20b2b95 rcxml: use const char* for string literals 2025-09-13 12:06:52 +01:00
John Lindgren
072d45d4b2 osd-thumbnail: put designated initializers in order 2025-09-13 12:06:52 +01:00
John Lindgren
0ce10f6afa interactive: add braces around case containing declaration 2025-09-13 12:06:52 +01:00
John Lindgren
bca0ec07ac rcxml: use fixed arrays for rc.title_buttons_*
These are just lists of enum lab_node_type, with a bounded size and
no middle-insertions/removals, so linked lists are overkill.

Also, the use of wl_list_for_each[_reverse] just to access the first or
last entry in the list (corner button) was weird.
2025-09-13 12:06:52 +01:00
thatonecoder (formerly Coccocoa's Helper)
e17ec0203c CONTRIBUTING.md: fix some typos, lots of Oxford commas
The primary change is “Github”/“github” ⇾ “GitHub”, but there are plenty of others.
2025-09-11 21:15:44 +01:00
Johan Malm
f2639226c7 labwc-config(5): add example for autoEnableOutputs
Some checks failed
labwc.github.io / notify (push) Has been cancelled
...with inspiration from example in #3059 by @jlindgren90
2025-09-09 21:34:22 +01:00
60 changed files with 674 additions and 430 deletions

View file

@ -12,14 +12,21 @@ UseTab: Always
IndentWidth: 8
ContinuationIndentWidth: 8
AlignAfterOpenBracket: DontAlign
AlignOperands: false
AlwaysBreakAfterDefinitionReturnType: true
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Linux
IndentCaseLabels: false
PenaltyBreakOpenParenthesis: 100
PenaltyReturnTypeOnItsOwnLine: 500
SpaceBeforeParens: ControlStatementsExceptControlMacros
ForEachMacros: ['for_each_view',
'for_each_view_reverse',
'wl_array_for_each',
'wl_list_for_each',
'wl_list_for_each_reverse',
'wl_list_for_each_reverse_safe',
'wl_list_for_each_safe']
IncludeCategories:
- Regex: '<.*>'
- Regex: '.*'

View file

@ -82,7 +82,7 @@ jobs:
pacman -Syu --noconfirm
pacman -S --noconfirm git meson clang wlroots0.19 libdrm libinput \
wayland-protocols cairo pango libxml2 xorg-xwayland librsvg \
libdisplay-info gdb ttf-dejavu foot libsfdo
libdisplay-info gdb ttf-dejavu foot libsfdo cmocka
- name: Install Debian Testing dependencies
if: matrix.name == 'Debian'
@ -92,7 +92,8 @@ jobs:
apt-get upgrade -y
apt-get install -y git gcc clang gdb xwayland
apt-get build-dep -y labwc
apt-get build-dep -y libwlroots-0.18-dev
apt-get build-dep -y libwlroots-0.19-dev
apt-get build-dep -y libxkbcommon-dev
- name: Install FreeBSD dependencies
if: matrix.name == 'FreeBSD'
@ -119,7 +120,7 @@ jobs:
xbps-install -y git meson gcc clang pkg-config scdoc \
cairo-devel glib-devel libpng-devel librsvg-devel libxml2-devel \
pango-devel wlroots0.19-devel gdb bash xorg-server-xwayland \
dejavu-fonts-ttf libsfdo-devel foot
dejavu-fonts-ttf libsfdo-devel foot hwids
# These builds are executed on all runners
- name: Build with gcc
@ -168,6 +169,7 @@ jobs:
meson setup build-gcc-release -Dxwayland=enabled \
-Dbuildtype=release -Db_ndebug=true --werror
meson configure build-gcc-release -Dwlroots:b_ndebug=false || true
meson configure build-gcc-release -Dlibsfdo:b_ndebug=false || true
meson compile -C build-gcc-release
' | $TARGET
@ -190,6 +192,7 @@ jobs:
meson setup build-clang-release -Dxwayland=enabled \
-Dbuildtype=release -Db_ndebug=true --werror
meson configure build-clang-release -Dwlroots:b_ndebug=false || true
meson configure build-clang-release -Dlibsfdo:b_ndebug=false || true
meson compile -C build-clang-release
' | $TARGET
@ -205,6 +208,18 @@ jobs:
meson compile -C build-gcc-no-feature
' | $TARGET
# Unit tests, run on Arch only
- name: Build with gcc - unit test
if: matrix.name == 'Arch'
run: |
echo '
cd "$GITHUB_WORKSPACE"
export CC=gcc
meson setup build-gcc-unit-test -Dtest=enabled --werror
meson compile -C build-gcc-unit-test
meson test -C build-gcc-unit-test --print-errorlogs
' | $TARGET
# Runtime tests, these run on Arch and Void only (the later due to libmusl being used)
- name: Build with gcc - runtime test
if: matrix.name == 'Arch'

View file

@ -23,14 +23,14 @@
# How to Contribute
1. Report bugs as github issues. We use a template prompting you to provide
1. Report bugs as GitHub issues. We use a template prompting you to provide
some sensible information such as what happened, what you expected to happen
and steps to reproduce. If applicable try with default configuration. If
you are able to, try to do some debugging (guidelines below).
and steps to reproduce. If applicable try with default configuration. If
you are able to, try debugging (guidelines below).
2. Submit patches as github pull-requests. If you wish to introduces significant
2. Submit patches as GitHub pull requests. If you wish to introduce significant
changes or new features, consult the [scope document], discuss on IRC or via
a github issue first.
a GitHub issue first.
# Debugging
@ -251,14 +251,14 @@ We try to keep the use of GLib pretty minimal for the following reasons:
- The use of GLib has been known to make AddressSanitiser diagnose false
positives and negatives.
- Log messages coming from GLib functions look inconsistent.
- The use of GLib functions, naming-conventions and iterators in a code base
- The use of GLib functions, naming-conventions and iterators in a codebase
that is predominantly ANSI C creates a clash which makes readability and
maintainability harder.
- Mixing gmalloc()/malloc() and respective free()s can create problems with
memory pools [^1]
Having said that, with our use of cairo and pango we depend on glib-2.0 anyway
so linking with it and making use of some of its helper functions comes for free
Having said that, with our use of cairo and pango we depend on glib-2.0 anyway,
so linking with it and making use of some of its helper functions comes for free,
and can keep the code simpler.
For example, if we were going to carry out extensive string manipulation,
@ -291,7 +291,7 @@ match(const gchar *pattern, const gchar *string)
### The Use of GNU Extensions
We avoid [GNU C extensions] because we want to fit into the eco-system
We avoid [GNU C extensions] because we want to fit into the ecosystem
(wayland and wlroots) we live in.
We do use `__typeof__` which strictly speaking is a GNU C extension (`typeof`)
@ -300,18 +300,18 @@ but through the use of `__` is supported by gcc and clang without defining
in the [`wl_container_of()`] macro which is needed in `wl_list*` and it
does provide pretty big benefits in terms of type safety.
We compile with `-std=c11` because that's what 'wlroots' uses and we do not
We compile with `-std=c11` because that's what 'wlroots' uses, and we do not
want to increase the entry-level for OSs without good reason (and currently
we can't think of one).
### Naming Conventions
There are three types of coordinate systems: surface, output and layout - for
There are three types of coordinate systems: surface, output, and layout — for
which the variables (sx, sy), (ox, oy) and (lx, ly) are used respectively in
line with wlroots.
With the introduction of the scene-graph API, some wlroots functions also use
node coordinates (nx, ny) but we prefer (sx, sy) where possible.
node coordinates (nx, ny), but we prefer (sx, sy) where possible.
We do not worry about namespace issues too much and we try to not make the code
a pain to use just to uniquify names. If we were writing a library we would
@ -361,11 +361,11 @@ In new files, please order `#include` lines as follows:
compiles cleanly on its own, without implicit dependencies on other
headers being included first.
- Then list any "system" headers (those not part of labwc) in alphebetical
- Then list any "system" headers (those not part of labwc) in alphabetical
order, using angle brackets. This includes 3rd-party library headers
such as `<cairo.h>`, as well as wlroots headers.
- Then list any other labwc headers in alphetical order, using quotation
- Then list any other labwc headers in alphabetical order, using quotation
marks and relative to the `include/` folder. Subfolders below `include/`,
such as `common/`, should be specified even when including one header
from another in the same folder (for example, `#include "common/buf.h"`
@ -388,11 +388,11 @@ This first line should:
- In most cases be prefixed with "area: " where area refers to a filename
or identifier for the general area of the code being modified.
- Not capitalize the first word following the "area: " prefix, unless
it's a name, acronym or similar.
it's a name, acronym, or similar.
- Skip the full stop
And please wrap the commit message at max 74 characters, otherwise `git log`
and similar look so weird. URLs and other references are exempt.
and similar look very weird. URLs and other references are exempt.
# Unit Tests
@ -404,9 +404,9 @@ In the bigger scheme of validating that the compositor meets users' needs, unit
tests do not contribute a great deal. However, they have a role to play in
providing some verification that stand-alone functions behave as expected.
On this project, writing unit-tests is not compulsory nor do we measure
On this project, writing unit-tests is not compulsory, nor do we measure
coverage. The inclusion of the t/ directory does not signify a move towards
test-driven development. We intend to use unit tests sparingly and only when
test-driven development. We intend to use unit tests sparingly, and only when
devs find them useful.
## Usage
@ -432,17 +432,17 @@ 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
### 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
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 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
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)
@ -483,13 +483,13 @@ follow the steps to be taken:
2. Update `NEWS.md` with the release details and run
`git commit -m 'NEWS.md: update notes for X.Y.Z'`
Note: If new dependencies are needed, make this clear.
3. In `meson.build` update the version and (if required) the wlroots
3. In `meson.build`, update the version, and (if required) the wlroots
dependency version. Then run `git commit -m 'build: bump version to X.Y.Z'`
4. Run `git tag -a X.Y.Z`. The first line of the commit message should be
"labwc X.Y.Z" and the body should be the `NEWS.md` additions removing
hash characters (#) from the headings as these will otherwise be
ignored by git.
5. On github, create a 'Release' as some distros use this as a trigger. Set it
5. On GitHub, create a 'Release' as some distros use this as a trigger. Set it
as 'latest release'.
[scope document]: https://github.com/labwc/labwc-scope#readme
@ -510,4 +510,3 @@ follow the steps to be taken:
different memory pools (and new/delete call constructors and
destructors)."
See: https://docs.gtk.org/glib/memory.html

32
NEWS.md
View file

@ -9,7 +9,7 @@ The format is based on [Keep a Changelog]
| Date | All Changes | wlroots version | lines-of-code |
|------------|---------------|-----------------|---------------|
| 2025-08-25 | [unreleased] | 0.19.0 | |
| 2025-09-15 | [unreleased] | 0.19.0 | 28686 |
| 2025-08-02 | [0.9.1] | 0.19.0 | 28605 |
| 2025-07-11 | [0.9.0] | 0.19.0 | 28586 |
| 2025-05-02 | [0.8.4] | 0.18.2 | 27679 |
@ -110,6 +110,12 @@ There are some regression warnings worth noting for the switch to wlroots 0.19:
### Added
- Support `Border` context for mousebinds as an alias for `Top`...`BRCorner` to
make configuration easier. @tokyo4j [#3047]
- Add window-switcher mode with thumbnails. This can be enabled with:
`<windowSwitcher style="thumbnail">`. @tokyo4j [#2981]
- Add `toggle` option to `GoToDesktop` action. This has the effect of going back
to the last desktop if already on the target. @RainerKuemmerle [#3024]
- Add `<core maximizedDecoration="titlebar|none"/>` to allow hiding titlebar
when window is maximized. @CosmicFusion @tokyo4j [#3015]
- Use client-send-to-menu as 'Workspace' submenu in built-in client-menu
@ -141,6 +147,10 @@ There are some regression warnings worth noting for the switch to wlroots 0.19:
### Fixed
- Restore initially-maximized window position after unplug/plug @tokyo4j [#3042]
- Fix large client-side icon not being loaded when the rendered icon size is
larger than icon sizes from the client. @tokyo4j [#3033]
- Improve debug logging for configuring input devices @jlindgren90 [#3028]
- Fix false positives when matching desktop entries @datMaffin [#3004]
- Prevent accidental downcasting of scale in scaled-icon-buffer to avoid blurry
icons on non-integer scales and a cairo assert when using a output scale < 1.
@ -152,6 +162,16 @@ There are some regression warnings worth noting for the switch to wlroots 0.19:
### Changed
- `Focus` and `Raise` on window border press because it is probably what most
people expect and it makes the behavior consistent with that of Openbox.
@johanmalm [#3039] [#3049]
- On interactive resize, only un-maximize the axis/axes that are being resized.
@jlindgren90 [#3043]
- Change theme setting `osd.window-switcher.*` to
`osd.window-switcher.style-classic.*`. Backward compatibility is preserved.
@tokyo4j [#2981]
- In client-list menu, add brackets around the titles of any minimised windows
@davidphilipbarr [#3002]
- Respect client-initiated window resize of non-maximized axis, for example
remember the width of vertically-maximized window resizing itself
horizontally. @jlindgren90 [#3020]
@ -2763,10 +2783,20 @@ Compile with wlroots 0.12.0 and wayland-server >=1.16
[#2971]: https://github.com/labwc/labwc/pull/2971
[#2972]: https://github.com/labwc/labwc/pull/2972
[#2976]: https://github.com/labwc/labwc/pull/2976
[#2981]: https://github.com/labwc/labwc/pull/2981
[#2994]: https://github.com/labwc/labwc/pull/2994
[#2995]: https://github.com/labwc/labwc/pull/2995
[#2998]: https://github.com/labwc/labwc/pull/2998
[#3002]: https://github.com/labwc/labwc/pull/3002
[#3004]: https://github.com/labwc/labwc/pull/3004
[#3011]: https://github.com/labwc/labwc/pull/3011
[#3015]: https://github.com/labwc/labwc/pull/3015
[#3020]: https://github.com/labwc/labwc/pull/3020
[#3024]: https://github.com/labwc/labwc/pull/3024
[#3028]: https://github.com/labwc/labwc/pull/3028
[#3033]: https://github.com/labwc/labwc/pull/3033
[#3039]: https://github.com/labwc/labwc/pull/3039
[#3042]: https://github.com/labwc/labwc/pull/3042
[#3043]: https://github.com/labwc/labwc/pull/3043
[#3047]: https://github.com/labwc/labwc/pull/3047
[#3049]: https://github.com/labwc/labwc/pull/3049

View file

@ -101,21 +101,8 @@ spend our effort.
A lot of emphasis is put on code simplicity when considering features.
The main development effort is focused on producing a solid foundation for a
stacking compositor rather than adding configuration and theming options.
See [scope] for full details on implemented features.
High-level summary of items that Labwc supports:
- [x] Config files (rc.xml, autostart, shutdown, environment, menu.xml)
- [x] Theme files and xbm/png/svg icons
- [x] Basic desktop and client menus
- [x] HiDPI
- [x] wlroots protocols such as `output-management`, `layer-shell` and
`foreign-toplevel`
- [x] Optionally xwayland
### 1.5 Videos
| video link | date | duration
@ -249,7 +236,7 @@ Suggested apps to use with Labwc:
- Screen shooter: [grim]
- Screen recorder: [wf-recorder]
- Background image: [swaybg]
- Panel: [waybar], [yambar], [lavalauncher], [sfwbar], [xfce4-panel]
- Panel: [waybar], [lavalauncher], [sfwbar], [xfce4-panel]
- Launchers: [bemenu], [fuzzel], [wofi]
- Output managers: [wlopm], [kanshi], [wlr-randr]
- Screen locker: [swaylock]
@ -292,7 +279,6 @@ The default window bar menu can be translated on the [weblate platform](https://
[wf-recorder]: https://github.com/ammen99/wf-recorder
[swaybg]: https://github.com/swaywm/swaybg
[waybar]: https://github.com/Alexays/Waybar
[yambar]: https://codeberg.org/dnkl/yambar
[lavalauncher]: https://sr.ht/~leon_plickat/LavaLauncher
[sfwbar]: https://github.com/LBCrion/sfwbar
[xfce4-panel]: https://gitlab.xfce.org/xfce/xfce4-panel

View file

@ -45,7 +45,7 @@ struct conf {
uint32_t details_background;
uint32_t background;
uint32_t text;
uint32_t border;
uint32_t button_border;
uint32_t border_bottom;
/* Sizing */
@ -429,7 +429,7 @@ render_button(cairo_t *cairo, struct nag *nag, struct button *button, int *x)
button->width = text_width + padding * 2;
button->height = text_height + padding * 2;
cairo_set_source_u32(cairo, nag->conf->border);
cairo_set_source_u32(cairo, nag->conf->button_border);
cairo_rectangle(cairo, button->x - border, button->y - border,
button->width + border * 2, button->height + border * 2);
cairo_fill(cairo);
@ -1255,7 +1255,7 @@ conf_init(struct conf *conf)
conf->background = 0x323232FF;
conf->text = 0xFFFFFFFF;
conf->button_text = 0xFFFFFFFF;
conf->border = 0x222222FF;
conf->button_border = 0x222222FF;
conf->border_bottom = 0x444444FF;
conf->bar_border_thickness = 2;
conf->message_padding = 8;
@ -1270,7 +1270,7 @@ conf_init(struct conf *conf)
conf->background = 0x900000FF;
conf->text = 0xFFFFFFFF;
conf->button_text = 0xFFFFFFFF;
conf->border = 0xD92424FF;
conf->button_border = 0xD92424FF;
conf->border_bottom = 0x470909FF;
}
@ -1342,9 +1342,9 @@ nag_parse_options(int argc, char **argv, struct nag *nag,
{
enum type_options {
TO_COLOR_BACKGROUND = 256,
TO_COLOR_BORDER,
TO_COLOR_BUTTON_BORDER,
TO_COLOR_BORDER_BOTTOM,
TO_COLOR_BUTTON,
TO_COLOR_BUTTON_BG,
TO_COLOR_DETAILS,
TO_COLOR_TEXT,
TO_COLOR_BUTTON_TEXT,
@ -1370,19 +1370,19 @@ nag_parse_options(int argc, char **argv, struct nag *nag,
{"detailed-button", required_argument, NULL, 'L'},
{"message", required_argument, NULL, 'm'},
{"output", required_argument, NULL, 'o'},
{"timeout", no_argument, NULL, 't'},
{"timeout", required_argument, NULL, 't'},
{"version", no_argument, NULL, 'v'},
{"background", required_argument, NULL, TO_COLOR_BACKGROUND},
{"border", required_argument, NULL, TO_COLOR_BORDER},
{"border-bottom", required_argument, NULL, TO_COLOR_BORDER_BOTTOM},
{"button-background", required_argument, NULL, TO_COLOR_BUTTON},
{"text", required_argument, NULL, TO_COLOR_TEXT},
{"button-text", required_argument, NULL, TO_COLOR_BUTTON_TEXT},
{"background-color", required_argument, NULL, TO_COLOR_BACKGROUND},
{"button-border-color", required_argument, NULL, TO_COLOR_BUTTON_BORDER},
{"border-bottom-color", required_argument, NULL, TO_COLOR_BORDER_BOTTOM},
{"button-background-color", required_argument, NULL, TO_COLOR_BUTTON_BG},
{"text-color", required_argument, NULL, TO_COLOR_TEXT},
{"button-text-color", required_argument, NULL, TO_COLOR_BUTTON_TEXT},
{"border-bottom-size", required_argument, NULL, TO_THICK_BAR_BORDER},
{"message-padding", required_argument, NULL, TO_PADDING_MESSAGE},
{"details-border-size", required_argument, NULL, TO_THICK_DET_BORDER},
{"details-background", required_argument, NULL, TO_COLOR_DETAILS},
{"details-background-color", required_argument, NULL, TO_COLOR_DETAILS},
{"button-border-size", required_argument, NULL, TO_THICK_BTN_BORDER},
{"button-gap", required_argument, NULL, TO_GAP_BTN},
{"button-dismiss-gap", required_argument, NULL, TO_GAP_BTN_DISMISS},
@ -1413,21 +1413,23 @@ nag_parse_options(int argc, char **argv, struct nag *nag,
" -v, --version Show the version number and quit.\n"
"\n"
"The following appearance options can also be given:\n"
" --background RRGGBB[AA] Background color.\n"
" --border RRGGBB[AA] Border color.\n"
" --border-bottom RRGGBB[AA] Bottom border color.\n"
" --button-background RRGGBB[AA] Button background color.\n"
" --text RRGGBB[AA] Text color.\n"
" --button-text RRGGBB[AA] Button text color.\n"
" --border-bottom-size size Thickness of the bar border.\n"
" --message-padding padding Padding for the message.\n"
" --details-border-size size Thickness for the details border.\n"
" --details-background RRGGBB[AA] Details background color.\n"
" --button-border-size size Thickness for the button border.\n"
" --button-gap gap Size of the gap between buttons\n"
" --button-dismiss-gap gap Size of the gap for dismiss button.\n"
" --button-margin-right margin Margin from dismiss button to edge.\n"
" --button-padding padding Padding for the button text.\n";
" --background-color RRGGBB[AA] Background color.\n"
" --button-border-color RRGGBB[AA] Button border color.\n"
" --border-bottom-color RRGGBB[AA] Bottom border color.\n"
" --button-background-color RRGGBB[AA]\n"
" Button background color.\n"
" --text-color RRGGBB[AA] Text color.\n"
" --button-text-color RRGGBB[AA] Button text color.\n"
" --border-bottom-size size Thickness of the bar border.\n"
" --message-padding padding Padding for the message.\n"
" --details-border-size size Thickness for the details border.\n"
" --details-background-color RRGGBB[AA]\n"
" Details background color.\n"
" --button-border-size size Thickness for the button border.\n"
" --button-gap gap Size of the gap between buttons\n"
" --button-dismiss-gap gap Size of the gap for dismiss button.\n"
" --button-margin-right margin Margin from dismiss button to edge.\n"
" --button-padding padding Padding for the button text.\n";
optind = 1;
while (1) {
@ -1522,8 +1524,8 @@ nag_parse_options(int argc, char **argv, struct nag *nag,
fprintf(stderr, "Invalid background color: %s\n", optarg);
}
break;
case TO_COLOR_BORDER: /* Border color */
if (!parse_color(optarg, &conf->border)) {
case TO_COLOR_BUTTON_BORDER: /* Border color */
if (!parse_color(optarg, &conf->button_border)) {
fprintf(stderr, "Invalid border color: %s\n", optarg);
}
break;
@ -1532,7 +1534,7 @@ nag_parse_options(int argc, char **argv, struct nag *nag,
fprintf(stderr, "Invalid border bottom color: %s\n", optarg);
}
break;
case TO_COLOR_BUTTON: /* Button background color */
case TO_COLOR_BUTTON_BG: /* Button background color */
if (!parse_color(optarg, &conf->button_background)) {
fprintf(stderr, "Invalid button background color: %s\n", optarg);
}

View file

@ -62,22 +62,22 @@ _labnag_ [options...]
# APPEARANCE OPTIONS
*--background* <RRGGBB[AA]>
*--background-color* <RRGGBB[AA]>
Set the color of the background.
*--border* <RRGGBB[AA]>
Set the color of the border.
*--button-border-color* <RRGGBB[AA]>
Set the color of the button border.
*--border-bottom* <RRGGBB[AA]>
*--border-bottom-color* <RRGGBB[AA]>
Set the color of the bottom border.
*--button-background* <RRGGBB[AA]>
*--button-background-color* <RRGGBB[AA]>
Set the color for the background for buttons.
*--text* <RRGGBB[AA]>
*--text-color* <RRGGBB[AA]>
Set the text color.
*--button-text* <RRGGBB[AA]>
*--button-text-color* <RRGGBB[AA]>
Set the button text color.
*--border-bottom-size* <size>
@ -86,7 +86,7 @@ _labnag_ [options...]
*--message-padding* <padding>
Set the padding for the message.
*--details-background* <RRGGBB[AA]>
*--details-background-color* <RRGGBB[AA]>
Set the color for the background for details.
*--details-border-size* <size>
@ -126,11 +126,11 @@ labnag \\
-Z "Hibernate" "systemctl hibernate"\\
-Z " Suspend " "systemctl suspend"\\
-Z " Cancel "\\
--background 00ffff\\
--button-background 00ffff\\
--border 00ccccaa\\
--text 000000\\
--button-text 000000\\
--background-color 00ffff\\
--button-background-color 00ffff\\
--button-border-color 00ccccaa\\
--text-color 000000\\
--button-text-color 000000\\
--button-gap 8\\
--button-margin-right 0\\
--button-padding 5\\

View file

@ -92,11 +92,18 @@ Actions are used in menus and keyboard/mouse bindings.
Move window relative to its current position. Positive value of x moves
it right, negative left. Positive value of y moves it down, negative up.
*<action name="ToggleSnapToEdge" direction="value" />*++
*<action name="SnapToEdge" direction="value" />*
Resize window to fill half the output in the given direction. Supports
directions "left", "up", "right", "down", "up-left", "up-right", "down-left",
"down-right" and "center".
*<action name="ToggleSnapToEdge" direction="value" combine="value" />*++
*<action name="SnapToEdge" direction="value" combine="value" />*
Resize window to fill half or quarter the output in the given direction.
*direction* [up|down|left|right|up-left|up-right|down-left|down-right|center]
Direction in which to snap the window.
*combine* [yes|no]
Allows to snap a window to an output corner by combining two
directions. For example, snapping a window to *right* and then
to *up* places it in the *up-right* quarter of the output.
Default is no.
ToggleSnapToEdge additionally toggles the active window between
tiled to the given direction and its untiled position.
@ -479,7 +486,7 @@ Actions that execute other actions. Used in keyboard/mouse bindings.
The "left" , "right", "left-occupied" and
"right-occupied" directions will not wrap.
*tiled* [up|right|down|left|top-left|top-right|down-left|down-right|center|any]
*tiled* [up|right|down|left|up-left|up-right|down-left|down-right|center|any]
Whether the client is tiled (snapped) along the the
indicated screen edge.

View file

@ -179,6 +179,7 @@ this is for compatibility with Openbox.
<reuseOutputMode>no</reuseOutputMode>
<xwaylandPersistence>no</xwaylandPersistence>
<primarySelection>yes</primarySelection>
<promptCommand>[see details below]</promptCommand>
</core>
```
@ -228,6 +229,23 @@ this is for compatibility with Openbox.
unless an external tool such as `wlr-randr` or `kanshi` is used to
manage outputs.
The reason for the existance of this option is that after losing signal
from the PC (e.g. by `wlopm -off`), some monitors do an input detection
that makes it appear (from the PC side) to disconnect and reconnect a
few seconds later, causing the monitor to turn back on again (as labwc
auto-enables newly connected outputs by default).
An example usage pattern to avoid the above behavior looks as follows:
- Set *<core><autoEnableOutputs>* to *no*
- Run kanshi (e.g. from autostart) and rely on it to enable new outputs
- Have swayidle kill and restart kanshi when entering powersave as
follows:
```
swayidle -w timeout 600 \\
'pkill kanshi ; wlopm --off \*' resume 'kanshi & wlopm --on \*'
```
*<core><reuseOutputMode>* [yes|no]
Try to re-use the existing output mode (resolution / refresh rate).
This may prevent unnecessary screenblank delays when starting labwc
@ -248,6 +266,53 @@ this is for compatibility with Openbox.
up/down) in Chromium and electron based clients without inadvertantly
pasting the primary clipboard. Default is yes.
*<core><promptCommand>*
Set command to be invoked for an action prompt (*<action><prompt>*)
The following conversion specifiers are supported:
- *%m*: the *<prompt>* message option
- *%n*: "No" (in local language if translation is available)
- *%y*: "Yes" (in local language if translation is available)
- *%b*: osd.bg.color
- *%t*: osd.label.text.color
The default prompt command is:
```
labnag \\
--message '%m' \\
--button-dismiss '%n' \\
--button-dismiss '%y' \\
--background-color '%b' \\
--text-color '%t' \\
--button-border-color '%t' \\
--border-bottom-color '%t' \\
--button-background-color '%b' \\
--button-text-color '%t' \\
--border-bottom-size 1 \\
--button-border-size 3 \\
--timeout 0
```
Example 1: The prompt can be configured to use a different dialog client
```
<core>
<promptCommand>zenity --question --text="%m"</promptCommand>
</core>
```
Example 2: A more complex zenity command could be used:
```
zenity \\
--question \\
--title="" \\
--text="%m" \\
--ok-label="%y" \\
--cancel-label="%n"
```
## PLACEMENT
```
@ -710,7 +775,7 @@ extending outward from the snapped edge.
W-Return - lab-sensible-terminal
A-F4 - close window
W-a - toggle maximize
W-<arrow> - resize window to fill half the output
W-<arrow> - resize window to fill half or quarter of the output
A-Space - show window menu
```

View file

@ -19,6 +19,10 @@
<reuseOutputMode>no</reuseOutputMode>
<xwaylandPersistence>no</xwaylandPersistence>
<primarySelection>yes</primarySelection>
<!--
# See labwc-config(5) for details
<promptCommand></promptCommand>
-->
</core>
<placement>
@ -271,16 +275,16 @@
<action name="ToggleMaximize" />
</keybind>
<keybind key="W-Left">
<action name="SnapToEdge" direction="left" />
<action name="SnapToEdge" direction="left" combine="yes" />
</keybind>
<keybind key="W-Right">
<action name="SnapToEdge" direction="right" />
<action name="SnapToEdge" direction="right" combine="yes" />
</keybind>
<keybind key="W-Up">
<action name="SnapToEdge" direction="up" />
<action name="SnapToEdge" direction="up" combine="yes" />
</keybind>
<keybind key="W-Down">
<action name="SnapToEdge" direction="down" />
<action name="SnapToEdge" direction="down" combine="yes" />
</keybind>
<keybind key="A-Space">
<action name="ShowMenu" menu="client-menu" atCursor="no" />

View file

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef LABWC_ACTION_PROMPT_COMMAND_H
#define LABWC_ACTION_PROMPT_COMMAND_H
struct buf;
struct action;
struct theme;
void action_prompt_command(struct buf *buf, const char *format,
struct action *action, struct theme *theme);
#endif /* LABWC_ACTION_PROMPT_COMMAND_H */

View file

@ -23,6 +23,8 @@ struct action {
struct action *action_create(const char *action_name);
const char *action_get_str(struct action *action, const char *key,
const char *default_value);
bool action_is_valid(struct action *action);
bool action_is_show_menu(struct action *action);
@ -48,6 +50,7 @@ bool actions_contain_toggle_keybinds(struct wl_list *action_list);
void actions_run(struct view *activator, struct server *server,
struct wl_list *actions, struct cursor_context *ctx);
void action_prompts_destroy(void);
bool action_check_prompt_result(pid_t pid, int exit_code);
void action_free(struct action *action);

View file

@ -18,7 +18,7 @@ void box_union(struct wlr_box *box_dest, struct wlr_box *box_a,
* The returned x & y coordinates are the centered content position
* relative to the top-left corner of the bounding box.
*/
struct wlr_box box_fit_within(int width, int height, struct wlr_box *bounding_box);
struct wlr_box box_fit_within(int width, int height, struct wlr_box *bound);
struct wlr_fbox box_to_fbox(struct wlr_box *box);

View file

@ -50,6 +50,17 @@ void buf_expand_shell_variables(struct buf *s);
*/
void buf_add_fmt(struct buf *s, const char *fmt, ...);
/**
* buf_add_hex_color - add rgb color as hex string to C string buffer
* @s: buffer
* @color: rgb color to be added
*
* For example:
* - With the input 'red' (defined as red[4] = { 1.0f, 0.0f, 0.0f, 1.0f}) the
* string "#ff0000ff" will be written to the buffer.
*/
void buf_add_hex_color(struct buf *s, float color[4]);
/**
* buf_add - add data to C string buffer
* @s: buffer
@ -60,9 +71,9 @@ void buf_add(struct buf *s, const char *data);
/**
* buf_add_char - add single char to C string buffer
* @s: buffer
* @data: char to be added
* @ch: char to be added
*/
void buf_add_char(struct buf *s, char data);
void buf_add_char(struct buf *s, char ch);
/**
* buf_clear - clear the buffer, internal allocations are preserved

View file

@ -20,6 +20,6 @@ struct wlr_scene_node *lab_wlr_scene_get_prev_node(struct wlr_scene_node *node);
/* A variant of wlr_scene_output_commit() that respects wlr_output->pending */
bool lab_wlr_scene_output_commit(struct wlr_scene_output *scene_output,
struct wlr_output_state *output_state);
struct wlr_output_state *state);
#endif /* LABWC_SCENE_HELPERS_H */

View file

@ -15,15 +15,6 @@ bool string_null_or_empty(const char *s);
*/
bool str_space_only(const char *s);
/**
* trim_last_field() - Trim last field of string splitting on provided delim
* @buf: string to trim
* @delim: delimitator
*
* Example: With delim='_' and buf="foo_bar_baz" the return value is "foo_bar"
*/
void trim_last_field(char *buf, char delim);
/**
* string_strip - strip white space left and right
* Note: this function does a left skip, so the returning pointer cannot be

View file

@ -25,12 +25,11 @@
* </action>
* </keybind>
*/
void lab_xml_expand_dotted_attributes(xmlNode *root);
void lab_xml_expand_dotted_attributes(xmlNode *parent);
/* Returns true if the node only contains a string or is empty */
bool lab_xml_node_is_leaf(xmlNode *node);
bool lab_xml_get_node(xmlNode *node, const char *key, xmlNode **dst_node);
bool lab_xml_get_string(xmlNode *node, const char *key, char *s, size_t len);
bool lab_xml_get_int(xmlNode *node, const char *key, int *i);
bool lab_xml_get_bool(xmlNode *node, const char *key, bool *b);

View file

@ -35,6 +35,10 @@ static struct key_combos {
.name = "direction",
.value = "left",
},
.attributes[1] = {
.name = "combine",
.value = "yes",
},
}, {
.binding = "W-Right",
.action = "SnapToEdge",
@ -42,6 +46,10 @@ static struct key_combos {
.name = "direction",
.value = "right",
},
.attributes[1] = {
.name = "combine",
.value = "yes",
},
}, {
.binding = "W-Up",
.action = "SnapToEdge",
@ -49,6 +57,10 @@ static struct key_combos {
.name = "direction",
.value = "up",
},
.attributes[1] = {
.name = "combine",
.value = "yes",
},
}, {
.binding = "W-Down",
.action = "SnapToEdge",
@ -56,6 +68,10 @@ static struct key_combos {
.name = "direction",
.value = "down",
},
.attributes[1] = {
.name = "combine",
.value = "yes",
},
}, {
.binding = "A-Space",
.action = "ShowMenu",

View file

@ -14,6 +14,9 @@
#define BUTTON_MAP_MAX 16
/* max of one button of each type (no repeats) */
#define TITLE_BUTTONS_MAX ((LAB_NODE_BUTTON_LAST + 1) - LAB_NODE_BUTTON_FIRST)
enum adaptive_sync_mode {
LAB_ADAPTIVE_SYNC_DISABLED,
LAB_ADAPTIVE_SYNC_ENABLED,
@ -48,11 +51,6 @@ struct button_map_entry {
uint32_t to;
};
struct title_button {
enum lab_node_type type;
struct wl_list link;
};
struct usable_area_override {
struct border margin;
char *output;
@ -73,9 +71,12 @@ struct rcxml {
enum tearing_mode allow_tearing;
bool auto_enable_outputs;
bool reuse_output_mode;
enum lab_placement_policy placement_policy;
bool xwayland_persistence;
bool primary_selection;
char *prompt_command;
/* placement */
enum lab_placement_policy placement_policy;
int placement_cascade_offset_x;
int placement_cascade_offset_y;
@ -88,8 +89,12 @@ struct rcxml {
char *theme_name;
char *icon_theme_name;
char *fallback_app_icon_name;
struct wl_list title_buttons_left;
struct wl_list title_buttons_right;
enum lab_node_type title_buttons_left[TITLE_BUTTONS_MAX];
int nr_title_buttons_left;
enum lab_node_type title_buttons_right[TITLE_BUTTONS_MAX];
int nr_title_buttons_right;
int corner_radius;
bool show_title;
bool title_layout_loaded;
@ -195,7 +200,6 @@ struct rcxml {
extern struct rcxml rc;
void rcxml_parse_xml(struct buf *b);
void rcxml_read(const char *filename);
void rcxml_finish(void);

View file

@ -24,6 +24,5 @@ void key_state_store_pressed_key_as_bound(uint32_t keycode);
bool key_state_corresponding_press_event_was_bound(uint32_t keycode);
void key_state_bound_key_remove(uint32_t keycode);
int key_state_nr_bound_keys(void);
int key_state_nr_pressed_keys(void);
#endif /* LABWC_KEY_STATE_H */

View file

@ -7,13 +7,6 @@
#include "common/set.h"
#include "input/cursor.h"
#include "overlay.h"
#if HAVE_NLS
#include <libintl.h>
#include <locale.h>
#define _ gettext
#else
#define _(s) (s)
#endif
#define XCURSOR_DEFAULT "left_ptr"
#define XCURSOR_SIZE 24
@ -366,7 +359,6 @@ void desktop_focus_view_or_surface(struct seat *seat, struct view *view,
void desktop_arrange_all_views(struct server *server);
void desktop_focus_output(struct output *output);
struct view *desktop_topmost_focusable_view(struct server *server);
/**
* Toggles the (output local) visibility of the layershell top layer

View file

@ -100,18 +100,6 @@ void menu_open_root(struct menu *menu, int x, int y);
*/
void menu_process_cursor_motion(struct wlr_scene_node *node);
/**
* menu_call_actions - call actions associated with a menu node
*
* If menuitem connected to @node does not just open a submenu:
* - associated actions will be called
* - server->menu_current will be closed
* - server->menu_current will be set to NULL
*
* Returns true if actions have actually been executed
*/
bool menu_call_actions(struct wlr_scene_node *node);
/**
* menu_close_root- close root menu
*

View file

@ -45,13 +45,6 @@ struct view *node_view_from_node(struct wlr_scene_node *wlr_scene_node);
struct lab_layer_surface *node_layer_surface_from_node(
struct wlr_scene_node *wlr_scene_node);
/**
* node_layer_popup_from_node - return lab_layer_popup struct from node
* @wlr_scene_node: wlr_scene_node from which to return data
*/
struct lab_layer_popup *node_layer_popup_from_node(
struct wlr_scene_node *wlr_scene_node);
/**
* node_menuitem_from_node - return menuitem struct from node
* @wlr_scene_node: wlr_scene_node from which to return data

View file

@ -40,7 +40,6 @@ struct output {
void output_init(struct server *server);
void output_finish(struct server *server);
void output_manager_init(struct server *server);
struct output *output_from_wlr_output(struct server *server,
struct wlr_output *wlr_output);
struct output *output_from_name(struct server *server, const char *name);
@ -70,11 +69,4 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener,
void *data);
void output_enable_adaptive_sync(struct output *output, bool enabled);
/**
* output_max_scale() - get maximum scale factor of all usable outputs.
* Used when loading/rendering resources (e.g. icons) that may be
* displayed on any output.
*/
float output_max_scale(struct server *server);
#endif // LABWC_OUTPUT_H

View file

@ -73,12 +73,4 @@ void scaled_font_buffer_update(struct scaled_font_buffer *self, const char *text
int max_width, struct font *font, const float *color,
const float *bg_color);
/**
* Update the max width of an existing auto scaling font buffer
* and force a new render.
*
* No steps are taken to detect if its actually required to render a new buffer.
*/
void scaled_font_buffer_set_max_width(struct scaled_font_buffer *self, int max_width);
#endif /* LABWC_SCALED_FONT_BUFFER_H */

14
include/translate.h Normal file
View file

@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef LABWC_TRANSLATE_H
#define LABWC_TRANSLATE_H
#include "config.h"
#if HAVE_NLS
#include <libintl.h>
#include <locale.h>
#define _ gettext
#else
#define _(s) (s)
#endif
#endif /* LABWC_TRANSLATE_H */

View file

@ -425,7 +425,6 @@ void view_array_append(struct server *server, struct wl_array *views,
enum lab_view_criteria criteria);
enum view_wants_focus view_wants_focus(struct view *view);
bool view_contains_window_type(struct view *view, enum lab_window_type window_type);
/* If view is NULL, the size of SSD is not considered */
struct wlr_box view_get_edge_snap_box(struct view *view, struct output *output,
@ -548,14 +547,12 @@ void view_move_to_edge(struct view *view, enum lab_edge direction, bool snap_to_
void view_grow_to_edge(struct view *view, enum lab_edge direction);
void view_shrink_to_edge(struct view *view, enum lab_edge direction);
void view_snap_to_edge(struct view *view, enum lab_edge direction,
bool across_outputs, bool store_natural_geometry);
bool across_outputs, bool combine, bool store_natural_geometry);
void view_snap_to_region(struct view *view, struct region *region, bool store_natural_geometry);
void view_move_to_output(struct view *view, struct output *output);
void view_move_to_front(struct view *view);
void view_move_to_back(struct view *view);
struct view *view_get_root(struct view *view);
void view_append_children(struct view *view, struct wl_array *children);
/**
* view_get_modal_dialog() - returns any modal dialog found among this

View file

@ -65,8 +65,6 @@ void xwayland_unmanaged_create(struct server *server,
void xwayland_view_create(struct server *server,
struct wlr_xwayland_surface *xsurface, bool mapped);
struct wlr_xwayland_surface *xwayland_surface_from_view(struct view *view);
void xwayland_server_init(struct server *server,
struct wlr_compositor *compositor);
void xwayland_server_finish(struct server *server);

View file

@ -51,9 +51,9 @@ endif
add_project_arguments('-DLABWC_VERSION=@0@'.format(version), language: 'c')
wlroots = dependency(
'wlroots-0.19',
'wlroots-0.20',
default_options: ['default_library=static', 'examples=false'],
version: ['>=0.19.0', '<0.20.0'],
version: ['>=0.20.0', '<0.21.0'],
)
wlroots_has_xwayland = wlroots.get_variable('have_xwayland') == 'true'
@ -134,6 +134,15 @@ if get_option('static_analyzer').enabled()
add_project_arguments(['-fanalyzer'], language: 'c')
endif
link_args = []
if get_option('sections').enabled()
add_project_arguments(['-ffunction-sections'], language: 'c')
link_args += [
'-Wl,--gc-sections',
'-Wl,--print-gc-sections',
]
endif
msgfmt = find_program('msgfmt', required: get_option('nls'))
if msgfmt.found()
source_root = meson.current_source_dir()
@ -193,6 +202,7 @@ executable(
include_directories: [labwc_inc],
dependencies: labwc_deps,
install: true,
link_args: link_args,
)
install_data('data/labwc.desktop', install_dir: get_option('datadir') / 'wayland-sessions')

View file

@ -5,3 +5,4 @@ option('icon', type: 'feature', value: 'enabled', description: 'Enable window ic
option('nls', type: 'feature', value: 'auto', description: 'Enable native language support')
option('static_analyzer', type: 'feature', value: 'disabled', description: 'Run gcc static analyzer')
option('test', type: 'feature', value: 'disabled', description: 'Run tests')
option('sections', type: 'feature', value: 'disabled', description: 'Show unused functions')

108
src/action-prompt-command.c Normal file
View file

@ -0,0 +1,108 @@
// SPDX-License-Identifier: GPL-2.0-only
#define _POSIX_C_SOURCE 200809L
#include "action-prompt-command.h"
#include <stdio.h>
#include <wlr/util/log.h>
#include "action.h"
#include "common/buf.h"
#include "theme.h"
#include "translate.h"
enum {
LAB_PROMPT_NONE = 0,
LAB_PROMPT_MESSAGE,
LAB_PROMPT_NO,
LAB_PROMPT_YES,
LAB_PROMPT_BG_COL,
LAB_PROMPT_TEXT_COL,
LAB_PROMPT_COUNT
};
typedef void field_conversion_type(struct buf *buf, struct action *action,
struct theme *theme);
struct field_converter {
const char fmt_char;
field_conversion_type *fn;
};
/* %m */
static void
set_message(struct buf *buf, struct action *action, struct theme *theme)
{
buf_add(buf, action_get_str(action, "message.prompt", "Choose wisely"));
}
/* %n */
static void
set_no(struct buf *buf, struct action *action, struct theme *theme)
{
buf_add(buf, _("No"));
}
/* %y */
static void
set_yes(struct buf *buf, struct action *action, struct theme *theme)
{
buf_add(buf, _("Yes"));
}
/* %b */
static void
set_bg_col(struct buf *buf, struct action *action, struct theme *theme)
{
buf_add_hex_color(buf, theme->osd_bg_color);
}
/* %t */
static void
set_text_col(struct buf *buf, struct action *action, struct theme *theme)
{
buf_add_hex_color(buf, theme->osd_label_text_color);
}
static const struct field_converter field_converter[LAB_PROMPT_COUNT] = {
[LAB_PROMPT_MESSAGE] = { 'm', set_message },
[LAB_PROMPT_NO] = { 'n', set_no },
[LAB_PROMPT_YES] = { 'y', set_yes },
[LAB_PROMPT_BG_COL] = { 'b', set_bg_col },
[LAB_PROMPT_TEXT_COL] = { 't', set_text_col },
};
void
action_prompt_command(struct buf *buf, const char *format,
struct action *action, struct theme *theme)
{
if (!format) {
wlr_log(WLR_ERROR, "missing format");
return;
}
for (const char *p = format; *p; p++) {
/*
* If we're not on a conversion specifier (like %m) then just
* keep adding it to the buffer
*/
if (*p != '%') {
buf_add_char(buf, *p);
continue;
}
/* Process the %* conversion specifier */
++p;
bool found = false;
for (unsigned char i = 0; i < LAB_PROMPT_COUNT; i++) {
if (*p == field_converter[i].fmt_char) {
field_converter[i].fn(buf, action, theme);
found = true;
break;
}
}
if (!found) {
wlr_log(WLR_ERROR,
"invalid prompt command conversion specifier '%c'", *p);
}
}
}

View file

@ -10,6 +10,7 @@
#include <wlr/types/wlr_scene.h>
#include <wlr/util/log.h>
#include "action-prompt-codes.h"
#include "action-prompt-command.h"
#include "common/buf.h"
#include "common/macros.h"
#include "common/list.h"
@ -281,7 +282,7 @@ action_get_arg(struct action *action, const char *key, enum action_arg_type type
return NULL;
}
static const char *
const char *
action_get_str(struct action *action, const char *key, const char *default_value)
{
struct action_arg_str *arg = action_get_arg(action, key, LAB_ACTION_ARG_STR);
@ -337,11 +338,6 @@ action_arg_from_xml_node(struct action *action, const char *nodename, const char
}
break;
case ACTION_TYPE_MOVE_TO_EDGE:
if (!strcasecmp(argument, "snapWindows")) {
action_arg_add_bool(action, argument, parse_bool(content, true));
goto cleanup;
}
/* Falls through */
case ACTION_TYPE_TOGGLE_SNAP_TO_EDGE:
case ACTION_TYPE_SNAP_TO_EDGE:
case ACTION_TYPE_GROW_TO_EDGE:
@ -358,6 +354,17 @@ action_arg_from_xml_node(struct action *action, const char *nodename, const char
}
goto cleanup;
}
if (action->type == ACTION_TYPE_MOVE_TO_EDGE
&& !strcasecmp(argument, "snapWindows")) {
action_arg_add_bool(action, argument, parse_bool(content, true));
goto cleanup;
}
if ((action->type == ACTION_TYPE_SNAP_TO_EDGE
|| action->type == ACTION_TYPE_TOGGLE_SNAP_TO_EDGE)
&& !strcasecmp(argument, "combine")) {
action_arg_add_bool(action, argument, parse_bool(content, false));
goto cleanup;
}
break;
case ACTION_TYPE_SHOW_MENU:
if (!strcmp(argument, "menu")) {
@ -827,12 +834,13 @@ handle_view_destroy(struct wl_listener *listener, void *data)
static void
action_prompt_create(struct view *view, struct server *server, struct action *action)
{
char *command = strdup_printf("labnag -m \"%s\" -Z \"%s\" -Z \"%s\"",
action_get_str(action, "message.prompt", "Choose wisely"),
_("No"), _("Yes"));
struct buf command = BUF_INIT;
action_prompt_command(&command, rc.prompt_command, action, rc.theme);
wlr_log(WLR_INFO, "prompt command: '%s'", command.data);
int pipe_fd;
pid_t prompt_pid = spawn_piped(command, &pipe_fd);
pid_t prompt_pid = spawn_piped(command.data, &pipe_fd);
if (prompt_pid < 0) {
wlr_log(WLR_ERROR, "Failed to create action prompt");
goto cleanup;
@ -856,7 +864,16 @@ action_prompt_create(struct view *view, struct server *server, struct action *ac
wl_list_insert(&prompts, &prompt->link);
cleanup:
free(command);
buf_reset(&command);
}
void
action_prompts_destroy(void)
{
struct action_prompt *prompt, *tmp;
wl_list_for_each_safe(prompt, tmp, &prompts, link) {
action_prompt_destroy(prompt);
}
}
bool
@ -1031,9 +1048,9 @@ run_action(struct view *view, struct server *server, struct action *action,
view_apply_natural_geometry(view);
break;
}
view_snap_to_edge(view, edge,
/*across_outputs*/ true,
/*store_natural_geometry*/ true);
bool combine = action_get_bool(action, "combine", false);
view_snap_to_edge(view, edge, /*across_outputs*/ true,
combine, /*store_natural_geometry*/ true);
}
break;
case ACTION_TYPE_GROW_TO_EDGE:

View file

@ -128,6 +128,30 @@ buf_add_fmt(struct buf *s, const char *fmt, ...)
s->data[s->len] = 0;
}
void
buf_add_hex_color(struct buf *s, float color[4])
{
/*
* In theme.c parse_hexstr() colors are pre-multiplied (by alpha) as
* expected by wlr_scene(). We therefore need to reverse that here.
*
* For details, see https://github.com/labwc/labwc/pull/1685
*/
float alpha = color[3];
/* Avoid division by zero */
if (alpha == 0.0f) {
buf_add(s, "#00000000");
return;
}
buf_add_fmt(s, "#%02x%02x%02x%02x",
(int)(color[0] / alpha * 255),
(int)(color[1] / alpha * 255),
(int)(color[2] / alpha * 255),
(int)(alpha * 255));
}
void
buf_add(struct buf *s, const char *data)
{

View file

@ -22,7 +22,7 @@ static PangoRectangle
font_extents(struct font *font, const char *string)
{
PangoRectangle rect = { 0 };
if (!string) {
if (string_null_or_empty(string)) {
return rect;
}
cairo_surface_t *surface;
@ -43,10 +43,6 @@ font_extents(struct font *font, const char *string)
pango_layout_get_extents(layout, NULL, &rect);
pango_extents_to_pixels(&rect, NULL);
/* we put a 2 px edge on each side - because Openbox does it :) */
/* TODO: remove the 4 pixel addition and always do the padding by the caller */
rect.width += 4;
cairo_destroy(c);
cairo_surface_destroy(surface);
pango_font_description_free(desc);

View file

@ -27,34 +27,34 @@ draw_cairo_border(cairo_t *cairo, struct wlr_fbox fbox, double line_width)
/* Sets the cairo color. Splits the single color channels */
void
set_cairo_color(cairo_t *cairo, const float *c)
set_cairo_color(cairo_t *cairo, const float *color)
{
/*
* We are dealing with pre-multiplied colors
* but cairo expects unmultiplied colors here
*/
float alpha = c[3];
float alpha = color[3];
if (alpha == 0.0f) {
cairo_set_source_rgba(cairo, 0, 0, 0, 0);
return;
}
cairo_set_source_rgba(cairo, c[0] / alpha, c[1] / alpha,
c[2] / alpha, alpha);
cairo_set_source_rgba(cairo, color[0] / alpha, color[1] / alpha,
color[2] / alpha, alpha);
}
cairo_pattern_t *
color_to_pattern(const float *c)
color_to_pattern(const float *color)
{
float alpha = c[3];
float alpha = color[3];
if (alpha == 0.0f) {
return cairo_pattern_create_rgba(0, 0, 0, 0);
}
return cairo_pattern_create_rgba(
c[0] / alpha, c[1] / alpha, c[2] / alpha, alpha);
return cairo_pattern_create_rgba(color[0] / alpha, color[1] / alpha,
color[2] / alpha, alpha);
}
/*

View file

@ -20,15 +20,6 @@ string_null_or_empty(const char *s)
return !s || !*s;
}
void
trim_last_field(char *buf, char delim)
{
char *p = strrchr(buf, delim);
if (p) {
*p = '\0';
}
}
static void
rtrim(char *s)
{

View file

@ -164,12 +164,6 @@ get_node(xmlNode *node, const char *key, xmlNode **dst_node, bool leaf_only)
return false;
}
bool
lab_xml_get_node(xmlNode *node, const char *key, xmlNode **dst_node)
{
return get_node(node, key, dst_node, /* leaf_only */ false);
}
bool
lab_xml_get_string(xmlNode *node, const char *key, char *s, size_t len)
{

View file

@ -33,6 +33,7 @@
#include "osd.h"
#include "regions.h"
#include "ssd.h"
#include "translate.h"
#include "view.h"
#include "window-rules.h"
#include "workspaces.h"
@ -116,7 +117,8 @@ parse_window_type(const char *type)
* desk D All-desktops toggle (aka omnipresent)
*/
static void
fill_section(const char *content, struct wl_list *list, uint32_t *found_buttons)
fill_section(const char *content, enum lab_node_type *buttons, int *count,
uint32_t *found_buttons /* bitmask */)
{
gchar **identifiers = g_strsplit(content, ",", -1);
for (size_t i = 0; identifiers[i]; ++i) {
@ -162,9 +164,8 @@ fill_section(const char *content, struct wl_list *list, uint32_t *found_buttons)
*found_buttons |= (1 << type);
struct title_button *item = znew(*item);
item->type = type;
wl_list_append(list, &item->link);
assert(*count < TITLE_BUTTONS_MAX);
buttons[(*count)++] = type;
}
g_strfreev(identifiers);
}
@ -172,28 +173,16 @@ fill_section(const char *content, struct wl_list *list, uint32_t *found_buttons)
static void
clear_title_layout(void)
{
struct title_button *button, *button_tmp;
wl_list_for_each_safe(button, button_tmp, &rc.title_buttons_left, link) {
wl_list_remove(&button->link);
zfree(button);
}
wl_list_for_each_safe(button, button_tmp, &rc.title_buttons_right, link) {
wl_list_remove(&button->link);
zfree(button);
}
rc.nr_title_buttons_left = 0;
rc.nr_title_buttons_right = 0;
rc.title_layout_loaded = false;
}
static void
fill_title_layout(char *content)
fill_title_layout(const char *content)
{
clear_title_layout();
struct wl_list *sections[] = {
&rc.title_buttons_left,
&rc.title_buttons_right,
};
gchar **parts = g_strsplit(content, ":", -1);
if (g_strv_length(parts) != 2) {
@ -202,9 +191,10 @@ fill_title_layout(char *content)
}
uint32_t found_buttons = 0;
for (size_t i = 0; parts[i]; ++i) {
fill_section(parts[i], sections[i], &found_buttons);
}
fill_section(parts[0], rc.title_buttons_left,
&rc.nr_title_buttons_left, &found_buttons);
fill_section(parts[1], rc.title_buttons_right,
&rc.nr_title_buttons_right, &found_buttons);
rc.title_layout_loaded = true;
err:
@ -1113,6 +1103,10 @@ entry(xmlNode *node, char *nodename, char *content)
set_bool(content, &rc.xwayland_persistence);
} else if (!strcasecmp(nodename, "primarySelection.core")) {
set_bool(content, &rc.primary_selection);
} else if (!strcasecmp(nodename, "promptCommand.core")) {
xstrdup_replace(rc.prompt_command, content);
} else if (!strcmp(nodename, "policy.placement")) {
enum lab_placement_policy policy = view_placement_parse(content);
if (policy != LAB_PLACE_INVALID) {
@ -1329,8 +1323,7 @@ traverse(xmlNode *node)
}
}
/* Exposed in header file to allow unit tests to parse buffers */
void
static void
rcxml_parse_xml(struct buf *b)
{
int options = 0;
@ -1362,8 +1355,6 @@ rcxml_init(void)
static bool has_run;
if (!has_run) {
wl_list_init(&rc.title_buttons_left);
wl_list_init(&rc.title_buttons_right);
wl_list_init(&rc.usable_area_overrides);
wl_list_init(&rc.keybinds);
wl_list_init(&rc.mousebinds);
@ -1637,6 +1628,22 @@ post_processing(void)
load_default_mouse_bindings();
}
if (!rc.prompt_command) {
rc.prompt_command =
xstrdup("labnag "
"--message '%m' "
"--button-dismiss '%n' "
"--button-dismiss '%y' "
"--background-color '%b' "
"--text-color '%t' "
"--button-border-color '%t' "
"--border-bottom-color '%t' "
"--button-background-color '%b' "
"--button-text-color '%t' "
"--border-bottom-size 1 "
"--button-border-size 3 "
"--timeout 0");
}
if (!rc.fallback_app_icon_name) {
rc.fallback_app_icon_name = xstrdup("labwc");
}
@ -1899,6 +1906,7 @@ rcxml_finish(void)
zfree(rc.font_menuheader.name);
zfree(rc.font_menuitem.name);
zfree(rc.font_osd.name);
zfree(rc.prompt_command);
zfree(rc.theme_name);
zfree(rc.icon_theme_name);
zfree(rc.fallback_app_icon_name);

View file

@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
#include "desktop-entry.h"
#include <locale.h>
#include <sfdo-desktop.h>
#include <sfdo-icon.h>
#include <sfdo-basedir.h>

View file

@ -132,7 +132,7 @@ desktop_focus_view_or_surface(struct seat *seat, struct view *view,
}
}
struct view *
static struct view *
desktop_topmost_focusable_view(struct server *server)
{
struct view *view;

View file

@ -583,11 +583,11 @@ input_method_relay_create(struct seat *seat)
relay->popup_tree = wlr_scene_tree_create(&seat->server->scene->tree);
relay->new_text_input.notify = handle_new_text_input;
wl_signal_add(&seat->server->text_input_manager->events.text_input,
wl_signal_add(&seat->server->text_input_manager->events.new_text_input,
&relay->new_text_input);
relay->new_input_method.notify = handle_new_input_method;
wl_signal_add(&seat->server->input_method_manager->events.input_method,
wl_signal_add(&seat->server->input_method_manager->events.new_input_method,
&relay->new_input_method);
relay->focused_surface_destroy.notify = handle_focused_surface_destroy;

View file

@ -84,9 +84,3 @@ key_state_nr_bound_keys(void)
{
return bound.size;
}
int
key_state_nr_pressed_keys(void)
{
return pressed.size;
}

View file

@ -101,7 +101,7 @@ interactive_begin(struct view *view, enum input_mode mode, enum lab_edge edges)
cursor_shape = LAB_CURSOR_GRAB;
break;
case LAB_INPUT_STATE_RESIZE:
case LAB_INPUT_STATE_RESIZE: {
if (view->shaded || view->fullscreen ||
view->maximized == VIEW_AXIS_BOTH) {
/*
@ -133,6 +133,7 @@ interactive_begin(struct view *view, enum input_mode mode, enum lab_edge edges)
view_set_untiled(view);
cursor_shape = cursor_get_from_edge(edges);
break;
}
default:
/* Should not be reached */
return;
@ -259,9 +260,8 @@ snap_to_edge(struct view *view)
view_maximize(view, VIEW_AXIS_BOTH,
/*store_natural_geometry*/ false);
} else {
view_snap_to_edge(view, edge,
/*across_outputs*/ false,
/*store_natural_geometry*/ false);
view_snap_to_edge(view, edge, /*across_outputs*/ false,
/*combine*/ false, /*store_natural_geometry*/ false);
}
return true;

View file

@ -11,6 +11,7 @@
#include "config/session.h"
#include "labwc.h"
#include "theme.h"
#include "translate.h"
#include "menu/menu.h"
struct rcxml rc = { 0 };

View file

@ -29,6 +29,7 @@
#include "scaled-buffer/scaled-font-buffer.h"
#include "scaled-buffer/scaled-icon-buffer.h"
#include "theme.h"
#include "translate.h"
#include "view.h"
#include "workspaces.h"
@ -135,6 +136,7 @@ item_create(struct menu *menu, const char *text, const char *icon_name, bool sho
assert(menu);
assert(text);
struct theme *theme = menu->server->theme;
struct menuitem *menuitem = znew(*menuitem);
menuitem->parent = menu;
menuitem->selectable = true;
@ -151,7 +153,8 @@ item_create(struct menu *menu, const char *text, const char *icon_name, bool sho
menuitem->native_width = font_width(&rc.font_menuitem, text);
if (menuitem->arrow) {
menuitem->native_width += font_width(&rc.font_menuitem, menuitem->arrow);
menuitem->native_width += font_width(&rc.font_menuitem, menuitem->arrow)
+ theme->menu_items_padding_x;
}
wl_list_append(&menu->menuitems, &menuitem->link);
@ -177,7 +180,7 @@ item_create_scene_for_state(struct menuitem *item, float *text_color,
int bg_width = menu->size.width - 2 * theme->menu_border_width;
int arrow_width = item->arrow ?
font_width(&rc.font_menuitem, item->arrow) : 0;
font_width(&rc.font_menuitem, item->arrow) + theme->menu_items_padding_x : 0;
int label_max_width = bg_width - 2 * theme->menu_items_padding_x
- arrow_width - icon_width;
@ -227,7 +230,7 @@ item_create_scene_for_state(struct menuitem *item, float *text_color,
scaled_font_buffer_update(arrow_buffer, item->arrow, -1,
&rc.font_menuitem, text_color, bg_color);
/* Vertically center and right-align arrow */
x += label_max_width;
x += label_max_width + theme->menu_items_padding_x;
y = (theme->menu_item_height - label_buffer->height) / 2;
wlr_scene_node_set_position(&arrow_buffer->scene_buffer->node, x, y);
@ -1542,15 +1545,6 @@ menu_process_cursor_motion(struct wlr_scene_node *node)
menu_process_item_selection(item);
}
bool
menu_call_actions(struct wlr_scene_node *node)
{
assert(node && node->data);
struct menuitem *item = node_menuitem_from_node(node);
return menu_execute_item(item);
}
void
menu_close_root(struct server *server)
{

View file

@ -1,5 +1,6 @@
labwc_sources = files(
'action.c',
'action-prompt-command.c',
'buffer.c',
'debug.c',
'desktop.c',

View file

@ -50,15 +50,6 @@ node_layer_surface_from_node(struct wlr_scene_node *wlr_scene_node)
return (struct lab_layer_surface *)node_descriptor->data;
}
struct lab_layer_popup *
node_layer_popup_from_node(struct wlr_scene_node *wlr_scene_node)
{
assert(wlr_scene_node->data);
struct node_descriptor *node_descriptor = wlr_scene_node->data;
assert(node_descriptor->type == LAB_NODE_LAYER_POPUP);
return (struct lab_layer_popup *)node_descriptor->data;
}
struct menuitem *
node_menuitem_from_node(struct wlr_scene_node *wlr_scene_node)
{

View file

@ -130,12 +130,12 @@ create_item_scene(struct wlr_scene_tree *parent, struct view *view,
/* background for selected item */
struct lab_scene_rect_options opts = {
.border_colors = (float *[1]) { switcher_theme->item_active_border_color },
.nr_borders = 1,
.border_width = switcher_theme->item_active_border_width,
.bg_color = switcher_theme->item_active_bg_color,
.width = switcher_theme->item_width,
.height = switcher_theme->item_height,
.bg_color = switcher_theme->item_active_bg_color,
.nr_borders = 1,
.border_colors = (float *[1]) { switcher_theme->item_active_border_color },
.border_width = switcher_theme->item_active_border_width,
};
item->active_bg = lab_scene_rect_create(item->tree, &opts);
@ -241,12 +241,12 @@ osd_thumbnail_create(struct output *output, struct wl_array *views)
/* background */
struct lab_scene_rect_options bg_opts = {
.width = nr_cols * switcher_theme->item_width + 2 * padding,
.height = nr_rows * switcher_theme->item_height + 2 * padding,
.bg_color = theme->osd_bg_color,
.border_colors = (float *[1]) { theme->osd_border_color },
.nr_borders = 1,
.border_width = theme->osd_border_width,
.border_colors = (float *[1]) { theme->osd_border_color },
.bg_color = theme->osd_bg_color,
.width = nr_cols * switcher_theme->item_width + 2 * padding,
.height = nr_rows * switcher_theme->item_height + 2 * padding,
};
struct lab_scene_rect *bg =
lab_scene_rect_create(output->osd_scene.tree, &bg_opts);

View file

@ -551,6 +551,8 @@ handle_new_output(struct wl_listener *listener, void *data)
do_output_layout_change(server);
}
static void output_manager_init(struct server *server);
void
output_init(struct server *server)
{
@ -890,7 +892,7 @@ handle_gamma_control_set_gamma(struct wl_listener *listener, void *data)
wlr_output_schedule_frame(output->wlr_output);
}
void
static void
output_manager_init(struct server *server)
{
server->output_manager = wlr_output_manager_v1_create(server->wl_display);
@ -1142,17 +1144,3 @@ output_enable_adaptive_sync(struct output *output, bool enabled)
enabled ? "en" : "dis", output->wlr_output->name);
}
}
float
output_max_scale(struct server *server)
{
/* Never return less than 1, in case outputs are disabled */
float scale = 1;
struct output *output;
wl_list_for_each(output, &server->outputs, link) {
if (output_is_usable(output)) {
scale = MAX(scale, output->wlr_output->scale);
}
}
return scale;
}

View file

@ -139,17 +139,3 @@ scaled_font_buffer_update(struct scaled_font_buffer *self, const char *text,
scaled_buffer_request_update(self->scaled_buffer,
self->width, self->height);
}
void
scaled_font_buffer_set_max_width(struct scaled_font_buffer *self, int max_width)
{
self->max_width = max_width;
int computed_height;
font_get_buffer_size(self->max_width, self->text, &self->font,
&self->width, &computed_height);
self->height = (self->fixed_height > 0) ?
self->fixed_height : computed_height;
scaled_buffer_request_update(self->scaled_buffer,
self->width, self->height);
}

View file

@ -17,6 +17,7 @@
#include <wlr/types/wlr_ext_foreign_toplevel_list_v1.h>
#include <wlr/types/wlr_ext_image_capture_source_v1.h>
#include <wlr/types/wlr_ext_image_copy_capture_v1.h>
#include <wlr/types/wlr_fixes.h>
#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
#include <wlr/types/wlr_fractional_scale_v1.h>
#include <wlr/types/wlr_input_method_v2.h>
@ -78,6 +79,9 @@
static void
reload_config_and_theme(struct server *server)
{
/* Avoid UAF when dialog client is used during reconfigure */
action_prompts_destroy();
scaled_buffer_invalidate_sharing();
rcxml_finish();
rcxml_read(rc.config_file);
@ -252,6 +256,7 @@ allow_for_sandbox(const struct wlr_security_context_v1_state *security_state,
"wl_data_device_manager", /* would be great if we could drop this one */
"wl_seat",
"xdg_wm_base",
"wl_fixes",
/* enhanced */
"wl_output",
"wl_drm",
@ -431,6 +436,8 @@ server_init(struct server *server)
server->wl_event_loop = wl_display_get_event_loop(server->wl_display);
wlr_fixes_create(server->wl_display, 1);
/* Catch signals */
server->sighup_source = wl_event_loop_add_signal(
server->wl_event_loop, SIGHUP, handle_sighup, server);

View file

@ -193,9 +193,6 @@ resize_indicator_update(struct view *view)
/* Let the indicator change width as required by the content */
int width = font_width(&rc.font_osd, text);
/* font_extents() adds 4 pixels to the calculated width */
width -= 4;
resize_indicator_set_size(indicator, width);
/* Center the indicator in the window */

View file

@ -81,7 +81,6 @@ ssd_titlebar_create(struct ssd *ssd)
LAB_NODE_TITLE, view, /*data*/ NULL);
/* Buttons */
struct title_button *b;
int x = theme->window_titlebar_padding_width;
/* Center vertically within titlebar */
@ -90,20 +89,22 @@ ssd_titlebar_create(struct ssd *ssd)
wl_list_init(&subtree->buttons_left);
wl_list_init(&subtree->buttons_right);
wl_list_for_each(b, &rc.title_buttons_left, link) {
for (int b = 0; b < rc.nr_title_buttons_left; b++) {
enum lab_node_type type = rc.title_buttons_left[b];
struct lab_img **imgs =
theme->window[active].button_imgs[b->type];
attach_ssd_button(&subtree->buttons_left, b->type, parent,
theme->window[active].button_imgs[type];
attach_ssd_button(&subtree->buttons_left, type, parent,
imgs, x, y, view);
x += theme->window_button_width + theme->window_button_spacing;
}
x = width - theme->window_titlebar_padding_width + theme->window_button_spacing;
wl_list_for_each_reverse(b, &rc.title_buttons_right, link) {
for (int b = rc.nr_title_buttons_right - 1; b >= 0; b--) {
x -= theme->window_button_width + theme->window_button_spacing;
enum lab_node_type type = rc.title_buttons_right[b];
struct lab_img **imgs =
theme->window[active].button_imgs[b->type];
attach_ssd_button(&subtree->buttons_right, b->type, parent,
theme->window[active].button_imgs[type];
attach_ssd_button(&subtree->buttons_right, type, parent,
imgs, x, y, view);
}
}
@ -223,8 +224,8 @@ update_visible_buttons(struct ssd *ssd)
int width = MAX(view->current.width - 2 * theme->window_titlebar_padding_width, 0);
int button_width = theme->window_button_width;
int button_spacing = theme->window_button_spacing;
int button_count_left = wl_list_length(&rc.title_buttons_left);
int button_count_right = wl_list_length(&rc.title_buttons_right);
int button_count_left = rc.nr_title_buttons_left;
int button_count_right = rc.nr_title_buttons_right;
/* Make sure infinite loop never occurs */
assert(button_width > 0);

View file

@ -231,25 +231,16 @@ load_button(struct theme *theme, struct button *b, int active)
struct lab_img **rounded_img =
&button_imgs[b->type][b->state_set | LAB_BS_ROUNDED];
struct title_button *leftmost_button;
wl_list_for_each(leftmost_button,
&rc.title_buttons_left, link) {
if (leftmost_button->type == b->type) {
*rounded_img = lab_img_copy(*img);
lab_img_add_modifier(*rounded_img,
round_left_corner_button);
}
break;
if (rc.nr_title_buttons_left > 0
&& b->type == rc.title_buttons_left[0]) {
*rounded_img = lab_img_copy(*img);
lab_img_add_modifier(*rounded_img, round_left_corner_button);
}
struct title_button *rightmost_button;
wl_list_for_each_reverse(rightmost_button,
&rc.title_buttons_right, link) {
if (rightmost_button->type == b->type) {
*rounded_img = lab_img_copy(*img);
lab_img_add_modifier(*rounded_img,
round_right_corner_button);
}
break;
if (rc.nr_title_buttons_right > 0
&& b->type == rc.title_buttons_right
[rc.nr_title_buttons_right - 1]) {
*rounded_img = lab_img_copy(*img);
lab_img_add_modifier(*rounded_img, round_right_corner_button);
}
}

View file

@ -120,6 +120,16 @@ query_str_match(const char *condition, const char *value)
return value && match_glob(condition, value);
}
static bool
view_contains_window_type(struct view *view, enum lab_window_type window_type)
{
assert(view);
if (view->impl->contains_window_type) {
return view->impl->contains_window_type(view, window_type);
}
return false;
}
bool
view_matches_query(struct view *view, struct view_query *query)
{
@ -215,26 +225,41 @@ view_matches_query(struct view *view, struct view_query *query)
if (query->monitor) {
struct output *current = output_nearest_to_cursor(view->server);
if (!strcasecmp(query->monitor, "current") && current != view->output) {
return false;
}
if (!strcasecmp(query->monitor, "left") &&
output_get_adjacent(current, LAB_EDGE_LEFT, false) != view->output) {
return false;
}
if (!strcasecmp(query->monitor, "right") &&
output_get_adjacent(current, LAB_EDGE_RIGHT, false) != view->output) {
return false;
}
if (output_from_name(view->server, query->monitor) != view->output) {
return false;
if (!strcasecmp(query->monitor, "current")) {
if (current != view->output) {
return false;
}
} else if (!strcasecmp(query->monitor, "left")) {
if (output_get_adjacent(current, LAB_EDGE_LEFT, false)
!= view->output) {
return false;
}
} else if (!strcasecmp(query->monitor, "right")) {
if (output_get_adjacent(current, LAB_EDGE_RIGHT, false)
!= view->output) {
return false;
}
} else {
if (output_from_name(view->server, query->monitor)
!= view->output) {
return false;
}
}
}
return true;
}
static struct view *
view_get_root(struct view *view)
{
assert(view);
if (view->impl->get_root) {
return view->impl->get_root(view);
}
return view;
}
static bool
matches_criteria(struct view *view, enum lab_view_criteria criteria)
{
@ -388,16 +413,6 @@ view_wants_focus(struct view *view)
return VIEW_WANTS_FOCUS_ALWAYS;
}
bool
view_contains_window_type(struct view *view, enum lab_window_type window_type)
{
assert(view);
if (view->impl->contains_window_type) {
return view->impl->contains_window_type(view, window_type);
}
return false;
}
bool
view_is_focusable(struct view *view)
{
@ -793,6 +808,15 @@ _minimize(struct view *view, bool minimized)
}
}
static void
view_append_children(struct view *view, struct wl_array *children)
{
assert(view);
if (view->impl->append_children) {
view->impl->append_children(view, children);
}
}
static void
minimize_sub_views(struct view *view, bool minimized)
{
@ -2121,7 +2145,7 @@ view_placement_parse(const char *policy)
void
view_snap_to_edge(struct view *view, enum lab_edge edge,
bool across_outputs, bool store_natural_geometry)
bool across_outputs, bool combine, bool store_natural_geometry)
{
assert(view);
@ -2137,25 +2161,45 @@ view_snap_to_edge(struct view *view, enum lab_edge edge,
view_set_shade(view, false);
if (across_outputs && view->tiled == edge && view->maximized == VIEW_AXIS_NONE) {
/* We are already tiled for this edge; try to switch outputs */
output = output_get_adjacent(view->output, edge, /* wrap */ false);
if (lab_edge_is_cardinal(edge) && view->maximized == VIEW_AXIS_NONE) {
enum lab_edge invert_edge = lab_edge_invert(edge);
/* Represents axis of snapping direction */
enum lab_edge parallel_mask = edge | invert_edge;
/*
* The vector view->tiled is split to components
* parallel/orthogonal to snapping direction. For example,
* view->tiled=TOP_LEFT is split to parallel_tiled=TOP and
* orthogonal_tiled=LEFT when edge=TOP or edge=BOTTOM.
*/
enum lab_edge parallel_tiled = view->tiled & parallel_mask;
enum lab_edge orthogonal_tiled = view->tiled & ~parallel_mask;
if (!output) {
if (across_outputs && view->tiled == edge) {
/*
* No more output to move to
*
* We re-apply the tiled geometry without changing any
* state because the window might have been moved away
* (and thus got untiled) and then snapped back to the
* original edge.
* E.g. when window is tiled to up and being snapped
* to up again, move it to the output above and tile
* it to down.
*/
view_apply_tiled_geometry(view);
return;
output = output_get_adjacent(view->output, edge,
/* wrap */ false);
if (!output) {
return;
}
edge = invert_edge;
} else if (combine && parallel_tiled == invert_edge
&& orthogonal_tiled != LAB_EDGE_NONE) {
/*
* E.g. when window is tiled to downleft/downright and
* being snapped to up, tile it to left/right.
*/
edge = view->tiled & ~parallel_mask;
} else if (combine && parallel_tiled == LAB_EDGE_NONE) {
/*
* E.g. when window is tiled to left/right and being
* snapped to up, tile it to upleft/upright.
*/
edge = view->tiled | edge;
}
/* When switching outputs, jump to the opposite edge */
edge = lab_edge_invert(edge);
}
if (view->maximized != VIEW_AXIS_NONE) {
@ -2302,25 +2346,6 @@ view_move_to_back(struct view *view)
desktop_update_top_layer_visibility(view->server);
}
struct view *
view_get_root(struct view *view)
{
assert(view);
if (view->impl->get_root) {
return view->impl->get_root(view);
}
return view;
}
void
view_append_children(struct view *view, struct wl_array *children)
{
assert(view);
if (view->impl->append_children) {
view->impl->append_children(view, children);
}
}
struct view *
view_get_modal_dialog(struct view *view)
{

View file

@ -40,6 +40,21 @@ static xcb_atom_t atoms[ATOM_COUNT] = {0};
static void xwayland_view_unmap(struct view *view, bool client_request);
static struct xwayland_view *
xwayland_view_from_view(struct view *view)
{
assert(view->type == LAB_XWAYLAND_VIEW);
return (struct xwayland_view *)view;
}
static struct wlr_xwayland_surface *
xwayland_surface_from_view(struct view *view)
{
struct xwayland_view *xwayland_view = xwayland_view_from_view(view);
assert(xwayland_view->xwayland_surface);
return xwayland_view->xwayland_surface;
}
static bool
xwayland_view_contains_window_type(struct view *view,
enum lab_window_type window_type)
@ -186,21 +201,6 @@ top_parent_of(struct view *view)
return s;
}
static struct xwayland_view *
xwayland_view_from_view(struct view *view)
{
assert(view->type == LAB_XWAYLAND_VIEW);
return (struct xwayland_view *)view;
}
struct wlr_xwayland_surface *
xwayland_surface_from_view(struct view *view)
{
struct xwayland_view *xwayland_view = xwayland_view_from_view(view);
assert(xwayland_view->xwayland_surface);
return xwayland_view->xwayland_surface;
}
static void
ensure_initial_geometry_and_output(struct view *view)
{

View file

@ -1,6 +1,6 @@
[wrap-git]
url = https://gitlab.freedesktop.org/vyivel/libsfdo.git
revision = v0.1.3
revision = v0.1.4
[provide]
dependency_names = libsfdo-basedir, libsfdo-desktop, libsfdo-icon

View file

@ -1,7 +1,7 @@
[wrap-git]
url = https://gitlab.freedesktop.org/wlroots/wlroots.git
revision = 0.19
revision = master
[provide]
dependency_names = wlroots-0.19
wlroots-0.19=wlroots
dependency_names = wlroots-0.20
wlroots-0.20=wlroots

View file

@ -1,3 +1,10 @@
test_deps = [
dep_cmocka,
glib,
xml2,
wlroots,
]
test_lib = static_library(
'test_lib',
sources: files(
@ -8,12 +15,7 @@ test_lib = static_library(
'../src/common/parse-bool.c',
),
include_directories: [labwc_inc],
dependencies: [
dep_cmocka,
glib,
xml2,
wlroots,
],
dependencies: test_deps,
)
tests = [
@ -30,7 +32,7 @@ foreach t : tests
sources: '@0@.c'.format(t),
include_directories: [labwc_inc],
link_with: [test_lib],
dependencies: [xml2],
dependencies: test_deps,
),
is_parallel: false,
)

View file

@ -111,7 +111,7 @@ test_lab_xml_expand_dotted_attributes(void **state)
xmlBuffer *buf = xmlBufferCreate();
xmlNodeDump(buf, root->doc, root, 0, 0);
assert_string_equal(test_cases[i].after, (char *)buf->content);
assert_string_equal(test_cases[i].after, (char *)xmlBufferContent(buf));
xmlBufferFree(buf);
xmlFreeDoc(doc);