Compare commits

...

23 Commits
1.0 ... master

Author SHA1 Message Date
Arti Zirk 6233901a88
Merge pull request #8 from alex-courtis/add-way-displays
add way-displays to readme
2023-07-26 15:42:56 +03:00
Arti Zirk 2c5e4d72b5
Merge pull request #7 from bhepple/patch-3
Update README.md - update fedora package location
2023-07-26 15:41:20 +03:00
Alexander Courtis 4cc1d2300d add way-displays to readme 2023-07-03 14:06:16 +10:00
Bob Hepple 7afc947f62
Update README.md - update fedora package location 2023-07-03 12:53:51 +10:00
redtide 1a32d8bbe2
Minor changes to changelog 2023-07-01 14:07:26 +02:00
redtide 64aa4a551d
Added CHANGELOG.md (keepachangelog.com format) 2023-07-01 14:01:16 +02:00
redtide 052c492040
Fixed license SPDX ID in main meson.build 2023-07-01 13:37:40 +02:00
redtide 0683283fa5
Updated desktop file
- Removed Version key: it's the version of the Desktop Entry Specification, not the application version and it's not required (see Table 2. Standard Keys in the specification)
- Set a real Name to display in menu for the application, with GenericName and Comment (same page as above)
- Italian translation strings
2023-07-01 12:45:24 +02:00
redtide 919726a2e5
Bump to current development version, use semver 2023-07-01 12:37:16 +02:00
redtide aefde05389
Added .editorconfig and .clang-format 2023-07-01 12:35:38 +02:00
redtide c15e5870d9
Ignore QtCreator files 2023-07-01 12:34:46 +02:00
redtide 73f3cc2dd2
Merge pull request #2 from WhyNotHugo/output-name-bottom-left
Move the output name overlay to the bottom left
2023-07-01 09:52:32 +02:00
redtide 9f8508b31e
Merge pull request #1 from somini/patch-1
Move icon to the app_id name
2023-07-01 09:52:11 +02:00
somini f4cf935e49
Install icon to the app_id location
This is so that the desktop files picks it up correctly.

Thanks, @WhyNotHugo and @jbeich.
2023-04-02 11:57:39 +01:00
Hugo Osvaldo Barrera 59edbbd155 Move the output name overlay to the bottom left
The output name overlay renders on the top left by default. At the same
time, wdisplays renders the output previews on its top left corner too.

The results is that the overlay covered the output previews, making
seeing it and interacting with it tricky.

Moving the output name to the bottom left makes sure there's never any
overlap between it and the draggable previews shows for each output.
2022-02-25 17:37:46 +01:00
Arti Zirk a9aa7472e3 Merge remote-tracking branch 'IntinteDAO/patch-1' 2021-03-29 11:33:43 +03:00
Arti Zirk 5c6568a5b0 Merge remote-tracking branch 'emersion/fix-global-version' 2021-03-29 11:30:31 +03:00
Simon Ser 5198a9c94b
Use correct versions when binding globals
Changes to protocols aren't forward-compatible. It's not possible to use
version n+1 when a client has been designed to work with version n. For
instance in wlr-screencopy v5 a new event has been added. Binding to
version 5 without upgrading the client leads to libwayland errors
because libwayland doesn't know how to handle the event.

The client needs to maintain its own version requirements.

Closes: https://github.com/cyclopsian/wdisplays/issues/18
2020-07-27 11:08:50 +02:00
IntinteDAO cfc833984e
Added categories to the program shortcut 2020-06-17 00:32:45 +02:00
Jason Francis dd7e1e22ee Update README 2020-05-09 15:42:15 -04:00
Jason Francis 0ed52013dd Create WdHeadForm class 2020-05-09 13:37:18 -04:00
Jason Francis f3f2b9e9e2 Backport GTK4 changes
Includes refactoring to use GMenuModel and GtkEventController
2020-05-08 20:26:33 -04:00
Jason Francis 71ce9741d1 Add package links 2020-05-08 20:21:59 -04:00
20 changed files with 946 additions and 827 deletions

4
.clang-format Normal file
View File

@ -0,0 +1,4 @@
---
IndentWidth: '2'
...

14
.editorconfig Normal file
View File

@ -0,0 +1,14 @@
# EditorConfig configuration
# http://editorconfig.org
# Top-most EditorConfig file
root = true
# UTF-8 charset, set indent to spaces with width of four,
# with no trailing whitespaces and a newline ending every file.
[*]
charset = utf-8
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

1
.gitignore vendored
View File

@ -1 +1,2 @@
/build/
*.user

View File

@ -8,7 +8,7 @@ Copyright: 2020 Jason Francis <jason@cycles.network>
License: CC0-1.0
Files: resources/style.css resources/wdisplays.desktop.in resources/*.ui
resources/resources.xml
resources/resources.xml.in
Copyright: 2020 Jason Francis <jason@cycles.network>
License: GPL-3.0-or-later

58
CHANGELOG.md Normal file
View File

@ -0,0 +1,58 @@
# Changelog
The format is based on [Keep a Changelog][1].
This project tries to adhere to [Semantic Versioning][2].
## [Unreleased]
## [1.1.1] - 2023-07-01
### Added
Added QtCreator files to .gitignore (redtide)
.editorconfig and .clang-format (redtide)
this file (redtide)
### Changed
Install icon to the app_id location (somini)
Move the output name overlay to the bottom left (WhyNotHugo)
Bump to current development version, use semver (redtide)
Updated desktop file (redtide)
### Fixed
Fixed license SPDX ID in main meson.build
## [1.1] - 2023-04-18
### Added
Added categories to the program shortcut (IntinteDAO)
### Changed
Add package links (Jason Francis)
Backport GTK4 changes (Jason Francis)
Create WdHeadForm class (Jason Francis)
Update README (Jason Francis)
Use correct versions when binding globals (Simon Ser)
## [v1.0] - 2020-05-09
First release after <https://github.com/MichaelAquilina/wdisplays> fork
(backup of the original, deleted repository at <https://github.com/cyclopsian/wdisplays>)
### Changed
Update application ID and readme (Jason Francis)
[1]: https://keepachangelog.com/en/1.0.0/
[2]: https://semver.org/spec/v2.0.0.html
[Unreleased]: https://github.com/artizirk/wdisplays/compare/1.1.1...HEAD
[1.1.1]: https://github.com/artizirk/wdisplays/compare/1.1...1.1.1
[1.1]: https://github.com/artizirk/wdisplays/compare/1.0...1.1
[1.0]: https://github.com/artizirk/wdisplays/releases/tag/1.0

View File

@ -4,13 +4,27 @@
wdisplays is a graphical application for configuring displays in Wayland
compositors. It borrows some code from [kanshi]. It should work in any
compositor that implements the wlr-output-management-unstable-v1 protocol,
including [sway]. The goal of this project is to allow precise adjustment of
display settings in kiosks, digital signage, and other elaborate multi-monitor
setups.
compositor that implements the wlr-output-management-unstable-v1 protocol.
Compositors that are known to support the protocol are [Sway] and [Wayfire].
The goal of this project is to allow precise adjustment of display settings in
kiosks, digital signage, and other elaborate multi-monitor setups.
![Screenshot](wdisplays.png)
# Installation
[![Repology][repology-img]][repology-pkg]
Check your distro for a `wdisplays` package. Known distro packages:
- [Alpine](https://pkgs.alpinelinux.org/package/edge/testing/x86_64/wdisplays)
- [Arch](https://aur.archlinux.org/packages/wdisplays-git/)
- [Debian](https://packages.debian.org/sid/wdisplays)
- [Fedora](https://packages.fedoraproject.org/pkgs/wdisplays/wdisplays)
- [FreeBSD](https://svnweb.freebsd.org/ports/head/x11/wdisplays/)
- [Nix](https://github.com/NixOS/nixpkgs/tree/master/pkgs/tools/graphics/wdisplays)
- [OpenSUSE](https://build.opensuse.org/package/show/home%3AMWh3/wdisplays)
# Building
Build requirements are:
@ -26,8 +40,6 @@ ninja -C build
sudo ninja -C build install
```
Binaries are not available. Only building from source is supported.
# Usage
Displays can be moved around the virtual screen space by clicking and dragging
@ -58,12 +70,23 @@ It's intended to be the Wayland equivalent of an xrandr GUI, like [ARandR].
Sway, like i3, doesn't save any settings unless you put them in the config
file. See man `sway-output`. If you want to have multiple configurations
depending on the monitors connected, you'll need to use an external program
like [kanshi]. Integration with that and other external daemons is planned.
like [kanshi] or [way-displays]. Integration with that and other external
daemons is planned.
### How do I add support to my compositor?
A minimal amount of code (approximately 150-200 LOC) is currently required to
get support for this in wlroots compositors. See the diff here for a sample
implementation on top of tinywl: [tinywl-output-management].
[kanshi]: https://github.com/emersion/kanshi
[sway]: https://github.com/swaywm/sway
[way-displays]: https://github.com/alex-courtis/way-displays
[Sway]: https://swaywm.org
[Wayfire]: https://wayfire.org
[ARandR]: https://christian.amsuess.com/tools/arandr/
[tinywl-output-management]: https://git.sr.ht/~jf/tinywl-output-management/commit/87a45d89ae0e7975e2a59f84e960380dd2f5ac08
[license-img]: https://img.shields.io/badge/License-GPL%203.0%20or%20later-blue.svg?logo=gnu
[license-spdx]: https://spdx.org/licenses/GPL-3.0-or-later.html
[repology-img]: https://repology.org/badge/tiny-repos/wdisplays.svg
[repology-pkg]: https://repology.org/project/wdisplays/versions

View File

@ -1,11 +1,16 @@
# SPDX-FileCopyrightText: 2020 Jason Francis <jason@cycles.network>
# SPDX-License-Identifier: CC0-1.0
project('network.cycles.wdisplays', 'c', license: 'MIT', version: '1.0')
project('network.cycles.wdisplays', 'c',
license: 'GPL-3.0-or-later',
version: '1.1.1'
)
conf = configuration_data()
conf.set('app_id', meson.project_name())
conf.set('version', meson.project_version())
conf = configuration_data({
'app_id': meson.project_name(),
'version': meson.project_version(),
'resource_prefix': '/' / '/'.join(meson.project_name().split('.')),
})
subdir('protocol')
subdir('resources')

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.0 -->
<!-- Generated with glade 3.22.2 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<object class="GtkAdjustment" id="height_adjustment">
@ -7,23 +7,6 @@
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkPopover" id="modes">
<property name="can_focus">False</property>
<child>
<object class="GtkBox" id="mode_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_start">10</property>
<property name="margin_end">10</property>
<property name="margin_top">10</property>
<property name="margin_bottom">10</property>
<property name="orientation">vertical</property>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
<object class="GtkAdjustment" id="pos_x_adjustment">
<property name="upper">16383</property>
<property name="step_increment">1</property>
@ -50,7 +33,7 @@
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkGrid" id="form">
<template class="WdHeadForm" parent="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_start">8</property>
@ -69,7 +52,7 @@
<property name="halign">start</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="enabled" swapped="no"/>
<signal name="toggled" handler="enabled_toggled" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
@ -99,7 +82,7 @@
<property name="adjustment">scale_adjustment</property>
<property name="digits">2</property>
<property name="value">1</property>
<signal name="change-value" handler="scale" swapped="no"/>
<signal name="value-changed" handler="position_spin_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
@ -194,6 +177,7 @@
<property name="spacing">8</property>
<child>
<object class="GtkSpinButton" id="refresh">
<property name="name">refresh</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="width_chars">9</property>
@ -202,6 +186,7 @@
<property name="digits">3</property>
<property name="numeric">True</property>
<property name="update_policy">if-valid</property>
<signal name="value-changed" handler="mode_spin_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
@ -245,7 +230,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="popover">transforms</property>
<child>
<placeholder/>
</child>
@ -277,7 +261,7 @@
<property name="halign">start</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="flipped" swapped="no"/>
<signal name="toggled" handler="flipped_toggled" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
@ -299,6 +283,7 @@
<property name="adjustment">pos_x_adjustment</property>
<property name="numeric">True</property>
<property name="update_policy">if-valid</property>
<signal name="value-changed" handler="position_spin_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">0</property>
@ -315,6 +300,7 @@
<property name="adjustment">pos_y_adjustment</property>
<property name="numeric">True</property>
<property name="update_policy">if-valid</property>
<signal name="value-changed" handler="position_spin_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">2</property>
@ -323,6 +309,7 @@
</child>
<child>
<object class="GtkSpinButton" id="width">
<property name="name">width</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="width_chars">4</property>
@ -331,6 +318,7 @@
<property name="adjustment">width_adjustment</property>
<property name="numeric">True</property>
<property name="update_policy">if-valid</property>
<signal name="value-changed" handler="mode_spin_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">0</property>
@ -351,6 +339,7 @@
</child>
<child>
<object class="GtkSpinButton" id="height">
<property name="name">height</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="width_chars">4</property>
@ -359,6 +348,7 @@
<property name="adjustment">height_adjustment</property>
<property name="numeric">True</property>
<property name="update_policy">if-valid</property>
<signal name="value-changed" handler="mode_spin_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">2</property>
@ -371,9 +361,7 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Select Mode Preset</property>
<property name="margin_left">8</property>
<property name="margin_start">8</property>
<property name="popover">modes</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
@ -406,76 +394,5 @@
<child>
<placeholder/>
</child>
</object>
<object class="GtkPopover" id="transforms">
<property name="can_focus">False</property>
<property name="relative_to">rotate_button</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_start">10</property>
<property name="margin_end">10</property>
<property name="margin_top">10</property>
<property name="margin_bottom">10</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkModelButton" id="rotate_0">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">transform.rotate_0</property>
<property name="text" translatable="yes">Don't Rotate</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkModelButton" id="rotate_90">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">transform.rotate_90</property>
<property name="text" translatable="yes">Rotate 90°</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkModelButton" id="rotate_180">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">transform.rotate_180</property>
<property name="text" translatable="yes">Rotate 180°</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkModelButton" id="rotate_270">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">transform.rotate_270</property>
<property name="text" translatable="yes">Rotate 270°</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
</object>
</template>
</interface>

View File

@ -1,11 +1,17 @@
# SPDX-FileCopyrightText: 2020 Jason Francis <jason@cycles.network>
# SPDX-License-Identifier: CC0-1.0
resources_xml = configure_file(
input: 'resources.xml.in',
output: 'resources.xml',
configuration: conf
)
gnome = import('gnome')
resources = gnome.compile_resources(
'waydisplay-resources', 'resources.xml',
'wdisplays-resources', resources_xml,
source_dir : '.',
c_name : 'waydisplay_resources')
c_name : 'wdisplays_resources')
scour = find_program('scour', required: false)
@ -30,9 +36,12 @@ if scour.found()
'@INPUT@', '@OUTPUT@'],
install: true,
install_dir: icondir)
else
install_data(icon, install_dir: icondir)
endif
else
install_data(icon,
rename: '@0@.svg'.format(meson.project_name()),
install_dir: icondir
)
endif
install_data(
configure_file(input: 'wdisplays.desktop.in',

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/">
<gresource prefix="@resource_prefix@">
<file compressed="true" preprocess="xml-stripblanks">wdisplays.ui</file>
<file compressed="true" preprocess="xml-stripblanks">head.ui</file>
<file compressed="true">style.css</file>

View File

@ -1,7 +1,12 @@
[Desktop Entry]
Version=@version@
Type=Application
Name=wdisplays
Comment=Wlroots display configuration
Categories=GTK;Settings;DesktopSettings;
Exec=wdisplays
Icon=@app_id@
Name=Displays
GenericName=Displays configuration
Comment=wlroots displays configuration
Name[it]=Schermi
GenericName[it]=Impostazioni degli schermi
Comment[it]=Impostazioni degli schermi per wlroots

View File

@ -11,62 +11,6 @@
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkPopover" id="main_menu">
<property name="can_focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_start">10</property>
<property name="margin_end">10</property>
<property name="margin_top">10</property>
<property name="margin_bottom">10</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkModelButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">app.auto-apply</property>
<property name="text" translatable="yes">_Automatically Apply Changes</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkModelButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">app.capture-screens</property>
<property name="text" translatable="yes">Show Screen Contents</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkModelButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">app.show-overlay</property>
<property name="text" translatable="yes">Overlay Screen Names</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkWindow" id="heads_window">
<property name="can_focus">False</property>
<property name="title" translatable="yes">wdisplays</property>
@ -171,8 +115,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="margin_left">8</property>
<property name="margin_right">8</property>
<property name="margin_start">8</property>
<property name="margin_end">8</property>
<property name="margin_top">8</property>
@ -248,14 +190,14 @@
<object class="GtkButtonBox" id="zoom_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">expand</property>
<child>
<object class="GtkButton" id="zoom_out">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Zoom Out</property>
<signal name="clicked" handler="zoom_out" swapped="yes"/>
<property name="action_name">app.zoom-out</property>
<accelerator key="minus" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
@ -263,7 +205,6 @@
<property name="icon_name">zoom-out-symbolic</property>
</object>
</child>
<accelerator key="minus" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="expand">True</property>
@ -278,7 +219,7 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Zoom Reset</property>
<signal name="clicked" handler="zoom_reset" swapped="yes"/>
<property name="action_name">app.zoom-reset</property>
<accelerator key="0" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
</object>
<packing>
@ -294,7 +235,8 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Zoom In</property>
<signal name="clicked" handler="zoom_in" swapped="yes"/>
<property name="action_name">app.zoom-in</property>
<accelerator key="equal" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
@ -302,7 +244,6 @@
<property name="icon_name">zoom-in-symbolic</property>
</object>
</child>
<accelerator key="equal" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="expand">True</property>
@ -311,6 +252,9 @@
<property name="non_homogeneous">True</property>
</packing>
</child>
<style>
<class name="linked"/>
</style>
</object>
</child>
<child>
@ -318,7 +262,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="popover">main_menu</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
@ -355,7 +298,7 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
<signal name="clicked" handler="apply_changes" swapped="no"/>
<property name="action_name">app.apply-changes</property>
<style>
<class name="suggested-action"/>
</style>
@ -371,7 +314,7 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
<signal name="clicked" handler="cancel_changes" swapped="no"/>
<property name="action_name">app.cancel-changes</property>
</object>
<packing>
<property name="position">1</property>

View File

@ -6,5 +6,6 @@
#define WDISPLAYS_APP_ID "@app_id@"
#define WDISPLAYS_VERSION "@version@"
#define WDISPLAYS_RESOURCE_PREFIX "@resource_prefix@"
#endif

393
src/headform.c Normal file
View File

@ -0,0 +1,393 @@
/* SPDX-FileCopyrightText: 2020 Jason Francis <jason@cycles.network>
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "headform.h"
#include "wdisplays.h"
typedef struct _WdHeadFormPrivate {
GtkWidget *enabled;
GtkWidget *description;
GtkWidget *physical_size;
GtkWidget *scale;
GtkWidget *pos_x;
GtkWidget *pos_y;
GtkWidget *width;
GtkWidget *height;
GtkWidget *refresh;
GtkWidget *mode_button;
GtkWidget *rotate_button;
GtkWidget *flipped;
GAction *mode_action;
GAction *rotate_action;
} WdHeadFormPrivate;
enum {
CHANGED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
G_DEFINE_TYPE_WITH_CODE(WdHeadForm, wd_head_form, GTK_TYPE_GRID,
G_ADD_PRIVATE(WdHeadForm))
static const char *HEAD_PREFIX = "head";
static const char *MODE_PREFIX = "mode";
static const char *ROTATE_PREFIX = "rotate";
static void head_form_update_sensitivity(WdHeadForm *form) {
WdHeadFormPrivate *priv = wd_head_form_get_instance_private(form);
bool enabled_toggled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->enabled));
g_autoptr(GList) children = gtk_container_get_children(GTK_CONTAINER(form));
for (GList *child = children; child != NULL; child = child->next) {
GtkWidget *widget = GTK_WIDGET(child->data);
if (widget != priv->enabled) {
gtk_widget_set_sensitive(widget, enabled_toggled);
}
}
}
static GVariant *create_mode_variant(int32_t w, int32_t h, int32_t r) {
GVariant * const children[] = {
g_variant_new_int32(w),
g_variant_new_int32(h),
g_variant_new_int32(r),
};
return g_variant_new_tuple(children, G_N_ELEMENTS(children));
}
struct vid_mode {
int32_t width;
int32_t height;
int32_t refresh;
};
static void unpack_mode_variant(GVariant *value, struct vid_mode *mode) {
g_autoptr(GVariant) width = g_variant_get_child_value(value, 0);
mode->width = g_variant_get_int32(width);
g_autoptr(GVariant) height = g_variant_get_child_value(value, 1);
mode->height = g_variant_get_int32(height);
g_autoptr(GVariant) refresh = g_variant_get_child_value(value, 2);
mode->refresh = g_variant_get_int32(refresh);
}
static void enabled_toggled(GtkToggleButton *toggle, gpointer data) {
WdHeadForm *form = WD_HEAD_FORM(data);
head_form_update_sensitivity(form);
g_signal_emit(form, signals[CHANGED], 0, WD_FIELD_ENABLED);
}
static void mode_spin_changed(GtkSpinButton *spin_button, gpointer data) {
WdHeadForm *form = WD_HEAD_FORM(data);
WdHeadFormPrivate *priv = wd_head_form_get_instance_private(form);
struct vid_mode mode;
GVariant *value = g_action_get_state(priv->mode_action);
unpack_mode_variant(value, &mode);
if (strcmp(gtk_widget_get_name(GTK_WIDGET(spin_button)), "width") == 0) {
mode.width = gtk_spin_button_get_value(spin_button);
} else if (strcmp(gtk_widget_get_name(GTK_WIDGET(spin_button)), "height") == 0) {
mode.height = gtk_spin_button_get_value(spin_button);
} else if (strcmp(gtk_widget_get_name(GTK_WIDGET(spin_button)), "refresh") == 0) {
mode.refresh = gtk_spin_button_get_value(spin_button) * 1000.;
}
g_action_activate(priv->mode_action, create_mode_variant(mode.width, mode.height, mode.refresh));
g_signal_emit(form, signals[CHANGED], 0, WD_FIELD_MODE);
}
static void position_spin_changed(GtkSpinButton *spin_button, gpointer data) {
WdHeadForm *form = WD_HEAD_FORM(data);
g_signal_emit(form, signals[CHANGED], 0, WD_FIELD_POSITION);
}
static void flipped_toggled(GtkToggleButton *toggle, gpointer data) {
WdHeadForm *form = WD_HEAD_FORM(data);
g_signal_emit(form, signals[CHANGED], 0, WD_FIELD_TRANSFORM);
}
static void wd_head_form_class_init(WdHeadFormClass *class) {
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(class);
signals[CHANGED] = g_signal_new("changed",
G_OBJECT_CLASS_TYPE(class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET(WdHeadFormClass, changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_INT);
gtk_widget_class_set_template_from_resource(widget_class,
WDISPLAYS_RESOURCE_PREFIX "/head.ui");
gtk_widget_class_bind_template_callback(widget_class, enabled_toggled);
gtk_widget_class_bind_template_callback(widget_class, mode_spin_changed);
gtk_widget_class_bind_template_callback(widget_class, position_spin_changed);
gtk_widget_class_bind_template_callback(widget_class, flipped_toggled);
gtk_widget_class_bind_template_child_private(widget_class, WdHeadForm, enabled);
gtk_widget_class_bind_template_child_private(widget_class, WdHeadForm, description);
gtk_widget_class_bind_template_child_private(widget_class, WdHeadForm, physical_size);
gtk_widget_class_bind_template_child_private(widget_class, WdHeadForm, scale);
gtk_widget_class_bind_template_child_private(widget_class, WdHeadForm, pos_x);
gtk_widget_class_bind_template_child_private(widget_class, WdHeadForm, pos_y);
gtk_widget_class_bind_template_child_private(widget_class, WdHeadForm, width);
gtk_widget_class_bind_template_child_private(widget_class, WdHeadForm, height);
gtk_widget_class_bind_template_child_private(widget_class, WdHeadForm, refresh);
gtk_widget_class_bind_template_child_private(widget_class, WdHeadForm, mode_button);
gtk_widget_class_bind_template_child_private(widget_class, WdHeadForm, rotate_button);
gtk_widget_class_bind_template_child_private(widget_class, WdHeadForm, flipped);
gtk_widget_class_set_css_name(widget_class, "wd-head-form");
}
static int32_t get_rotate_value(enum wl_output_transform transform) {
if (transform == WL_OUTPUT_TRANSFORM_90 || transform == WL_OUTPUT_TRANSFORM_FLIPPED_90) {
return 90;
} else if (transform == WL_OUTPUT_TRANSFORM_180 || transform == WL_OUTPUT_TRANSFORM_FLIPPED_180) {
return 180;
} else if (transform == WL_OUTPUT_TRANSFORM_270 || transform == WL_OUTPUT_TRANSFORM_FLIPPED_270) {
return 270;
}
return 0;
}
static void rotate_selected(GSimpleAction *action, GVariant *param, gpointer data) {
WdHeadForm *form = data;
WdHeadFormPrivate *priv = wd_head_form_get_instance_private(form);
GMenuModel *menu = gtk_menu_button_get_menu_model(GTK_MENU_BUTTON(priv->rotate_button));
int items = g_menu_model_get_n_items(menu);
for (int i = 0; i < items; i++) {
g_autoptr(GVariant) target = g_menu_model_get_item_attribute_value(menu, i, G_MENU_ATTRIBUTE_TARGET, NULL);
g_autoptr(GVariant) label = g_menu_model_get_item_attribute_value(menu, i, G_MENU_ATTRIBUTE_LABEL, NULL);
if (g_variant_get_int32(target) == g_variant_get_int32(param)) {
gtk_button_set_label(GTK_BUTTON(priv->rotate_button), g_variant_get_string(label, NULL));
break;
}
}
g_simple_action_set_state(action, param);
g_signal_emit(form, signals[CHANGED], 0, WD_FIELD_TRANSFORM);
}
static void mode_selected(GSimpleAction *action, GVariant *param, gpointer data) {
WdHeadForm *form = data;
WdHeadFormPrivate *priv = wd_head_form_get_instance_private(form);
struct vid_mode mode;
unpack_mode_variant(param, &mode);
g_simple_action_set_state(action, param);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(priv->width), mode.width);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(priv->height), mode.height);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(priv->refresh), mode.refresh / 1000.);
g_signal_emit(form, signals[CHANGED], 0, WD_FIELD_MODE);
}
static void wd_head_form_init(WdHeadForm *form) {
gtk_widget_init_template(GTK_WIDGET(form));
WdHeadFormPrivate *priv = wd_head_form_get_instance_private(form);
GSimpleActionGroup *head_actions = g_simple_action_group_new();
gtk_widget_insert_action_group(priv->mode_button, HEAD_PREFIX, G_ACTION_GROUP(head_actions));
gtk_widget_insert_action_group(priv->rotate_button, HEAD_PREFIX, G_ACTION_GROUP(head_actions));
GMenu *rotate_menu = g_menu_new();
g_menu_append(rotate_menu, "Don't Rotate", "head.rotate(0)");
g_menu_append(rotate_menu, "Rotate 90°", "head.rotate(90)");
g_menu_append(rotate_menu, "Rotate 180°", "head.rotate(180)");
g_menu_append(rotate_menu, "Rotate 270°", "head.rotate(270)");
gtk_menu_button_set_menu_model(GTK_MENU_BUTTON(priv->rotate_button), G_MENU_MODEL(rotate_menu));
static const GVariantType * const mode_types[] = {
G_VARIANT_TYPE_INT32,
G_VARIANT_TYPE_INT32,
G_VARIANT_TYPE_INT32
};
GSimpleAction *action = g_simple_action_new_stateful("mode",
g_variant_type_new_tuple(mode_types, G_N_ELEMENTS(mode_types)),
create_mode_variant(0, 0, 0));
g_action_map_add_action(G_ACTION_MAP(head_actions), G_ACTION(action));
g_signal_connect(action, "change-state", G_CALLBACK(mode_selected), form);
g_object_unref(action);
priv->mode_action = G_ACTION(action);
action = g_simple_action_new_stateful(ROTATE_PREFIX, G_VARIANT_TYPE_INT32,
g_variant_new_int32(0));
g_action_map_add_action(G_ACTION_MAP(head_actions), G_ACTION(action));
g_signal_connect(action, "change-state", G_CALLBACK(rotate_selected), form);
g_object_unref(action);
priv->rotate_action = G_ACTION(action);
g_object_unref(head_actions);
}
void wd_head_form_update(WdHeadForm *form, const struct wd_head *head,
enum wd_head_fields fields) {
g_return_if_fail(form);
g_return_if_fail(head);
WdHeadFormPrivate *priv = wd_head_form_get_instance_private(form);
if (!fields)
return;
if (fields & WD_FIELD_DESCRIPTION)
gtk_label_set_text(GTK_LABEL(priv->description), head->description);
if (fields & WD_FIELD_PHYSICAL_SIZE) {
g_autofree gchar *physical_str = g_strdup_printf("%dmm × %dmm", head->phys_width, head->phys_height);
gtk_label_set_text(GTK_LABEL(priv->physical_size), physical_str);
}
if (fields & WD_FIELD_ENABLED)
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->enabled), head->enabled);
if (fields & WD_FIELD_SCALE)
gtk_spin_button_set_value(GTK_SPIN_BUTTON(priv->scale), head->scale);
if (fields & WD_FIELD_POSITION) {
gtk_spin_button_set_value(GTK_SPIN_BUTTON(priv->pos_x), head->x);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(priv->pos_y), head->y);
}
if (fields & WD_FIELD_MODE) {
GMenu *mode_menu = g_menu_new();
struct wd_mode *mode;
g_autofree gchar *action = g_strdup_printf("%s.%s", HEAD_PREFIX, MODE_PREFIX);
wl_list_for_each(mode, &head->modes, link) {
g_autofree gchar *name = g_strdup_printf("%d×%d@%0.3fHz", mode->width, mode->height, mode->refresh / 1000.);
GMenuItem *item = g_menu_item_new(name, action);
g_menu_item_set_attribute_value(item, G_MENU_ATTRIBUTE_TARGET,
create_mode_variant(mode->width, mode->height, mode->refresh));
g_menu_append_item(mode_menu, item);
}
gtk_menu_button_set_menu_model(GTK_MENU_BUTTON(priv->mode_button), G_MENU_MODEL(mode_menu));
// Mode entries
int w = head->custom_mode.width;
int h = head->custom_mode.height;
int r = head->custom_mode.refresh;
if (head->enabled && head->mode != NULL) {
w = head->mode->width;
h = head->mode->height;
r = head->mode->refresh;
} else if (!head->enabled && w == 0 && h == 0) {
struct wd_mode *mode;
wl_list_for_each(mode, &head->modes, link) {
if (mode->preferred) {
w = mode->width;
h = mode->height;
r = mode->refresh;
break;
}
}
}
g_action_change_state(priv->mode_action, create_mode_variant(w, h, r));
}
if (fields & WD_FIELD_TRANSFORM) {
int active_rotate = get_rotate_value(head->transform);
g_action_change_state(priv->rotate_action, g_variant_new_int32(active_rotate));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->flipped),
head->transform == WL_OUTPUT_TRANSFORM_FLIPPED
|| head->transform == WL_OUTPUT_TRANSFORM_FLIPPED_90
|| head->transform == WL_OUTPUT_TRANSFORM_FLIPPED_180
|| head->transform == WL_OUTPUT_TRANSFORM_FLIPPED_270);
}
// Sync state
if (fields & WD_FIELD_ENABLED) {
head_form_update_sensitivity(form);
}
g_signal_emit(form, signals[CHANGED], 0);
}
GtkWidget *wd_head_form_new(void) {
return gtk_widget_new(WD_TYPE_HEAD_FORM, NULL);
}
gboolean wd_head_form_get_enabled(WdHeadForm *form) {
WdHeadFormPrivate *priv = wd_head_form_get_instance_private(form);
return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->enabled));
}
gboolean wd_head_form_has_changes(WdHeadForm *form, const struct wd_head *head) {
g_return_val_if_fail(form, FALSE);
WdHeadFormPrivate *priv = wd_head_form_get_instance_private(form);
if (head->enabled != gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->enabled))) {
return TRUE;
}
double old_scale = round(head->scale * 100.) / 100.;
double new_scale = round(gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->scale)) * 100.) / 100.;
if (old_scale != new_scale) {
return TRUE;
}
if (head->x != gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->pos_x))) {
return TRUE;
}
if (head->y != gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->pos_y))) {
return TRUE;
}
int w = head->mode != NULL ? head->mode->width : head->custom_mode.width;
if (w != gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->width))) {
return TRUE;
}
int h = head->mode != NULL ? head->mode->height : head->custom_mode.height;
if (h != gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->height))) {
return TRUE;
}
int r = head->mode != NULL ? head->mode->refresh : head->custom_mode.refresh;
if (r / 1000. != gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->refresh))) {
return TRUE;
}
if (g_variant_get_int32(g_action_get_state(priv->rotate_action)) != get_rotate_value(head->transform)) {
return TRUE;
}
bool flipped = head->transform == WL_OUTPUT_TRANSFORM_FLIPPED
|| head->transform == WL_OUTPUT_TRANSFORM_FLIPPED_90
|| head->transform == WL_OUTPUT_TRANSFORM_FLIPPED_180
|| head->transform == WL_OUTPUT_TRANSFORM_FLIPPED_270;
if (flipped != gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->flipped))) {
return TRUE;
}
return FALSE;
}
void wd_head_form_fill_config(WdHeadForm *form, struct wd_head_config *output) {
g_return_if_fail(form);
g_return_if_fail(output);
WdHeadFormPrivate *priv = wd_head_form_get_instance_private(form);
output->enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->enabled));
output->scale = gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->scale));
output->x = gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->pos_x));
output->y = gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->pos_y));
output->width = gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->width));
output->height = gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->height));
output->refresh = gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->refresh)) * 1000.;
int32_t rotate = g_variant_get_int32(g_action_get_state(priv->rotate_action));
gboolean flipped = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->flipped));
switch (rotate) {
case 0: output->transform = flipped ? WL_OUTPUT_TRANSFORM_FLIPPED : WL_OUTPUT_TRANSFORM_NORMAL; break;
case 90: output->transform = flipped ? WL_OUTPUT_TRANSFORM_FLIPPED_90 : WL_OUTPUT_TRANSFORM_90; break;
case 180: output->transform = flipped ? WL_OUTPUT_TRANSFORM_FLIPPED_180 : WL_OUTPUT_TRANSFORM_180; break;
case 270: output->transform = flipped ? WL_OUTPUT_TRANSFORM_FLIPPED_270 : WL_OUTPUT_TRANSFORM_270; break;
}
}
void wd_head_form_get_dimensions(WdHeadForm *form, WdHeadDimensions *dimensions) {
g_return_if_fail(form);
g_return_if_fail(dimensions);
WdHeadFormPrivate *priv = wd_head_form_get_instance_private(form);
dimensions->x = gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->pos_x));
dimensions->y = gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->pos_y));
dimensions->w = gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->width));
dimensions->h = gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->height));
dimensions->scale = gtk_spin_button_get_value(GTK_SPIN_BUTTON(priv->scale));
dimensions->rotation_id = g_variant_get_int32(g_action_get_state(priv->rotate_action)) / 90;
dimensions->flipped = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->flipped));
}
void wd_head_form_set_position(WdHeadForm *form, double x, double y) {
g_return_if_fail(form);
WdHeadFormPrivate *priv = wd_head_form_get_instance_private(form);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(priv->pos_x), x);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(priv->pos_y), y);
}

59
src/headform.h Normal file
View File

@ -0,0 +1,59 @@
/* SPDX-FileCopyrightText: 2020 Jason Francis <jason@cycles.network>
* SPDX-License-Identifier: GPL-3.0-or-later */
#ifndef WDISPLAY_HEADFORM_H
#define WDISPLAY_HEADFORM_H
#include <gtk/gtk.h>
G_BEGIN_DECLS
enum wd_head_fields {
WD_FIELD_NAME = 1 << 0,
WD_FIELD_ENABLED = 1 << 1,
WD_FIELD_DESCRIPTION = 1 << 2,
WD_FIELD_PHYSICAL_SIZE = 1 << 3,
WD_FIELD_SCALE = 1 << 4,
WD_FIELD_POSITION = 1 << 5,
WD_FIELD_MODE = 1 << 6,
WD_FIELD_TRANSFORM = 1 << 7,
WD_FIELDS_ALL = (1 << 8) - 1
};
#define WD_TYPE_HEAD_FORM (wd_head_form_get_type())
G_DECLARE_DERIVABLE_TYPE(
WdHeadForm, wd_head_form, WD, HEAD_FORM, GtkGrid)
struct _WdHeadFormClass {
GtkGridClass parent_class;
void (*changed)(WdHeadForm *form, enum wd_head_fields fields);
};
struct wd_head;
struct wd_head_config;
typedef struct _WdHeadDimensions {
gdouble x;
gdouble y;
gdouble w;
gdouble h;
gdouble scale;
int rotation_id;
gboolean flipped;
} WdHeadDimensions;
GtkWidget *wd_head_form_new(void);
gboolean wd_head_form_get_enabled(WdHeadForm *form);
gboolean wd_head_form_has_changes(WdHeadForm *form, const struct wd_head *head);
void wd_head_form_update(WdHeadForm *form, const struct wd_head *head,
enum wd_head_fields fields);
void wd_head_form_fill_config(WdHeadForm *form, struct wd_head_config *output);
void wd_head_form_get_dimensions(WdHeadForm *form, WdHeadDimensions *dimensions);
void wd_head_form_set_position(WdHeadForm *form, double x, double y);
G_END_DECLS
#endif

File diff suppressed because it is too large Load Diff

View File

@ -4,8 +4,8 @@
cc = meson.get_compiler('c')
m_dep = cc.find_library('m', required : false)
rt_dep = cc.find_library('rt', required : false)
gdk = dependency('gdk-3.0')
gtk = dependency('gtk+-3.0')
gdk = dependency('gdk-3.0', version: '>= 3.24')
gtk = dependency('gtk+-3.0', version: '>= 3.24')
assert(gdk.get_pkgconfig_variable('targets').split().contains('wayland'), 'Wayland GDK backend not present')
epoxy = dependency('epoxy')
@ -15,10 +15,11 @@ executable(
'wdisplays',
[
'main.c',
'outputs.c',
'render.c',
'glviewport.c',
'headform.c',
'outputs.c',
'overlay.c',
'render.c',
resources,
],
dependencies : [

View File

@ -534,20 +534,20 @@ static void registry_handle_global(void *data, struct wl_registry *registry,
if (strcmp(interface, zwlr_output_manager_v1_interface.name) == 0) {
state->output_manager = wl_registry_bind(registry, name,
&zwlr_output_manager_v1_interface, version);
&zwlr_output_manager_v1_interface, 1);
zwlr_output_manager_v1_add_listener(state->output_manager,
&output_manager_listener, state);
} else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) {
state->xdg_output_manager = wl_registry_bind(registry, name,
&zxdg_output_manager_v1_interface, version);
&zxdg_output_manager_v1_interface, 2);
} else if(strcmp(interface, zwlr_screencopy_manager_v1_interface.name) == 0) {
state->copy_manager = wl_registry_bind(registry, name,
&zwlr_screencopy_manager_v1_interface, version);
&zwlr_screencopy_manager_v1_interface, 1);
} else if(strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
state->layer_shell = wl_registry_bind(registry, name,
&zwlr_layer_shell_v1_interface, version);
&zwlr_layer_shell_v1_interface, 1);
} else if(strcmp(interface, wl_shm_interface.name) == 0) {
state->shm = wl_registry_bind(registry, name, &wl_shm_interface, version);
state->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
}
}

View File

@ -132,7 +132,7 @@ void window_map(GtkWidget *widget, gpointer data) {
&layer_surface_listener, output);
zwlr_layer_surface_v1_set_anchor(output->overlay_layer_surface,
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
resize(output);

View File

@ -20,6 +20,8 @@
#include <stdbool.h>
#include <wayland-client.h>
#include "headform.h"
struct zxdg_output_v1;
struct zxdg_output_manager_v1;
struct zwlr_output_mode_v1;
@ -39,18 +41,6 @@ typedef struct _GdkCursor GdkCursor;
struct _cairo_surface;
typedef struct _cairo_surface cairo_surface_t;
enum wd_head_fields {
WD_FIELD_NAME = 1 << 0,
WD_FIELD_ENABLED = 1 << 1,
WD_FIELD_DESCRIPTION = 1 << 2,
WD_FIELD_PHYSICAL_SIZE = 1 << 3,
WD_FIELD_SCALE = 1 << 4,
WD_FIELD_POSITION = 1 << 5,
WD_FIELD_MODE = 1 << 6,
WD_FIELD_TRANSFORM = 1 << 7,
WD_FIELDS_ALL = (1 << 8) - 1
};
struct wd_output {
struct wd_state *state;
struct zxdg_output_v1 *xdg_output;
@ -205,10 +195,10 @@ struct wd_state {
unsigned int reset_idle;
struct wd_render_head_data *clicked;
/* top left, bottom right */
struct wd_point click_offset;
struct wd_point drag_start;
struct wd_point head_drag_start; /* 0-1 range in head rect */
bool panning;
struct wd_point pan_last;
struct wd_point pan_start;
GtkWidget *main_box;
GtkWidget *header_stack;
@ -301,7 +291,7 @@ void wd_ui_reset_heads(struct wd_state *state);
* Updates the UI form for a single head. Useful for when the compositor
* notifies us of updated configuration caused by another program.
*/
void wd_ui_reset_head(const struct wd_head *head, unsigned int fields);
void wd_ui_reset_head(const struct wd_head *head, enum wd_head_fields fields);
/*
* Updates the stack and all forms to the last known server state.