Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
dd7e1e22ee | |||
0ed52013dd | |||
f3f2b9e9e2 | |||
71ce9741d1 | |||
1a58f8e15c | |||
69564522bc |
@ -1,14 +1,14 @@
|
|||||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||||
Upstream-Name: wdisplays
|
Upstream-Name: wdisplays
|
||||||
Upstream-Contact: Jason Francis <jason@cycles.network>
|
Upstream-Contact: Jason Francis <jason@cycles.network>
|
||||||
Source: https://wdisplays.cycles.network
|
Source: <https://cyclopsian.github.io/wdisplays>
|
||||||
|
|
||||||
Files: README.md .gitignore
|
Files: README.md .gitignore
|
||||||
Copyright: 2020 Jason Francis <jason@cycles.network>
|
Copyright: 2020 Jason Francis <jason@cycles.network>
|
||||||
License: CC0-1.0
|
License: CC0-1.0
|
||||||
|
|
||||||
Files: resources/style.css resources/wdisplays.desktop.in resources/*.ui
|
Files: resources/style.css resources/wdisplays.desktop.in resources/*.ui
|
||||||
resources/resources.xml
|
resources/resources.xml.in
|
||||||
Copyright: 2020 Jason Francis <jason@cycles.network>
|
Copyright: 2020 Jason Francis <jason@cycles.network>
|
||||||
License: GPL-3.0-or-later
|
License: GPL-3.0-or-later
|
||||||
|
|
||||||
|
37
README.md
37
README.md
@ -4,13 +4,27 @@
|
|||||||
|
|
||||||
wdisplays is a graphical application for configuring displays in Wayland
|
wdisplays is a graphical application for configuring displays in Wayland
|
||||||
compositors. It borrows some code from [kanshi]. It should work in any
|
compositors. It borrows some code from [kanshi]. It should work in any
|
||||||
compositor that implements the wlr-output-management-unstable-v1 protocol,
|
compositor that implements the wlr-output-management-unstable-v1 protocol.
|
||||||
including [sway]. The goal of this project is to allow precise adjustment of
|
Compositors that are known to support the protocol are [Sway] and [Wayfire].
|
||||||
display settings in kiosks, digital signage, and other elaborate multi-monitor
|
The goal of this project is to allow precise adjustment of display settings in
|
||||||
setups.
|
kiosks, digital signage, and other elaborate multi-monitor setups.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
# 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://copr.fedorainfracloud.org/coprs/wef/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
|
# Building
|
||||||
|
|
||||||
Build requirements are:
|
Build requirements are:
|
||||||
@ -26,8 +40,6 @@ ninja -C build
|
|||||||
sudo ninja -C build install
|
sudo ninja -C build install
|
||||||
```
|
```
|
||||||
|
|
||||||
Binaries are not available. Only building from source is supported.
|
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
|
|
||||||
Displays can be moved around the virtual screen space by clicking and dragging
|
Displays can be moved around the virtual screen space by clicking and dragging
|
||||||
@ -60,10 +72,19 @@ 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
|
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]. 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
|
[kanshi]: https://github.com/emersion/kanshi
|
||||||
[sway]: https://github.com/swaywm/sway
|
[Sway]: https://swaywm.org
|
||||||
|
[Wayfire]: https://wayfire.org
|
||||||
[ARandR]: https://christian.amsuess.com/tools/arandr/
|
[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-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
|
[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
|
||||||
|
5
debian/changelog
vendored
5
debian/changelog
vendored
@ -1,5 +0,0 @@
|
|||||||
wdisplays (1.0-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
* Initial release
|
|
||||||
|
|
||||||
-- Jason Francis <cycl0ps@tuta.io> Fri, 8 May 2020 20:08:08 -0500
|
|
23
debian/control
vendored
23
debian/control
vendored
@ -1,23 +0,0 @@
|
|||||||
Source: wdisplays
|
|
||||||
Section: x11
|
|
||||||
Priority: optional
|
|
||||||
Maintainer: Jason Francis <cycl0ps@tuta.io>
|
|
||||||
Build-Depends: debhelper-compat (= 12),
|
|
||||||
meson,
|
|
||||||
libwayland-dev,
|
|
||||||
libgtk-3-dev,
|
|
||||||
libepoxy-dev
|
|
||||||
Standards-Version: 4.5.0
|
|
||||||
Homepage: https://cyclopsian.github.io/wdisplays
|
|
||||||
Vcs-Browser: https://github.com/cyclopsian/wdisplays
|
|
||||||
Vcs-Git: https://github.com/cyclopsian/wdisplays.git
|
|
||||||
|
|
||||||
Package: wdisplays
|
|
||||||
Architecture: any
|
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
|
||||||
Description: GUI display configurator for wlroots compositors
|
|
||||||
wdisplays is a graphical application for configuring displays in Wayland
|
|
||||||
compositors. It works with 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.
|
|
432
debian/copyright
vendored
432
debian/copyright
vendored
@ -1,432 +0,0 @@
|
|||||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
|
||||||
Upstream-Name: wdisplays
|
|
||||||
Upstream-Contact: Jason Francis <cycl0ps@tuta.io>
|
|
||||||
Source: <https://cyclopsian.github.io/wdisplays>
|
|
||||||
|
|
||||||
Files: *
|
|
||||||
Copyright: Jason Francis <cycl0ps@tuta.io>
|
|
||||||
License: GPL-3.0-or-later
|
|
||||||
|
|
||||||
Files: src/wdisplays.h src/outputs.c
|
|
||||||
Copyright: Jason Francis <cycl0ps@tuta.io>
|
|
||||||
License: GPL-3.0-or-later and MIT
|
|
||||||
Files: debian/*
|
|
||||||
Copyright: 2020 Jason Francis <cycl0ps@tuta.io>
|
|
||||||
License: GPL-3.0-or-later
|
|
||||||
|
|
||||||
Files: README.md .gitignore
|
|
||||||
Copyright: 2020 Jason Francis <jason@cycles.network>
|
|
||||||
License: CC0-1.0
|
|
||||||
|
|
||||||
Files: meson.build */meson.build
|
|
||||||
Copyright: Jason Francis <cycl0ps@tuta.io>
|
|
||||||
License: CC0-1.0
|
|
||||||
|
|
||||||
Files: resources/style.css resources/wdisplays.desktop.in resources/*.ui
|
|
||||||
resources/resources.xml
|
|
||||||
Copyright: 2020 Jason Francis <jason@cycles.network>
|
|
||||||
License: GPL-3.0-or-later
|
|
||||||
|
|
||||||
Files: wdisplays.png resources/wdisplays.svg
|
|
||||||
Copyright: 2020 Jason Francis <jason@cycles.network>
|
|
||||||
License: CC-BY-SA-4.0
|
|
||||||
|
|
||||||
Files: protocol/wlr-layer-shell-unstable-v1.xml
|
|
||||||
Copyright: 2017 Drew DeVault
|
|
||||||
License: MIT
|
|
||||||
|
|
||||||
Files: protocol/wlr-output-management-unstable-v1.xml
|
|
||||||
Copyright: 2019 Purism SPC
|
|
||||||
License: MIT
|
|
||||||
|
|
||||||
Files: protocol/wlr-screencopy-unstable-v1.xml
|
|
||||||
Copyright: 2018 Simon Ser
|
|
||||||
License: MIT
|
|
||||||
|
|
||||||
License: GPL-3.0-or-later
|
|
||||||
On Debian systems, the complete text of the GNU General
|
|
||||||
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
|
|
||||||
|
|
||||||
License: CC0-1.0
|
|
||||||
On Debian systems the full text of the CC0-1.0 license can be found in
|
|
||||||
/usr/share/common-licenses/CC0-1.0
|
|
||||||
|
|
||||||
License: MIT
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
copy of this software and associated documentation files (the "Software"),
|
|
||||||
to deal in the Software without restriction, including without limitation
|
|
||||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
Software is furnished to do so, subject to the following conditions:
|
|
||||||
.
|
|
||||||
The above copyright notice and this permission notice shall be included
|
|
||||||
in all copies or substantial portions of the Software.
|
|
||||||
.
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
||||||
OR IMPLIED, INCLUDING BUT NOT LIGPL-3.0-or-laterED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
||||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
License: CC-BY-SA-4.0
|
|
||||||
Creative Commons Attribution-ShareAlike 4.0 International Creative Commons
|
|
||||||
Corporation ("Creative Commons") is not a law firm and does not provide legal
|
|
||||||
services or legal advice. Distribution of Creative Commons public licenses
|
|
||||||
does not create a lawyer-client or other relationship. Creative Commons makes
|
|
||||||
its licenses and related information available on an "as-is" basis. Creative
|
|
||||||
Commons gives no warranties regarding its licenses, any material licensed
|
|
||||||
under their terms and conditions, or any related information. Creative Commons
|
|
||||||
disclaims all liability for damages resulting from their use to the fullest
|
|
||||||
extent possible.
|
|
||||||
.
|
|
||||||
Using Creative Commons Public Licenses
|
|
||||||
.
|
|
||||||
Creative Commons public licenses provide a standard set of terms and
|
|
||||||
conditions that creators and other rights holders may use to share original
|
|
||||||
works of authorship and other material subject to copyright and certain other
|
|
||||||
rights specified in the public license below. The following considerations are
|
|
||||||
for informational purposes only, are not exhaustive, and do not form part of
|
|
||||||
our licenses.
|
|
||||||
.
|
|
||||||
Considerations for licensors: Our public licenses are intended for use by
|
|
||||||
those authorized to give the public permission to use material in ways
|
|
||||||
otherwise restricted by copyright and certain other rights. Our licenses are
|
|
||||||
irrevocable. Licensors should read and understand the terms and conditions of
|
|
||||||
the license they choose before applying it. Licensors should also secure all
|
|
||||||
rights necessary before applying our licenses so that the public can reuse the
|
|
||||||
material as expected. Licensors should clearly mark any material not subject
|
|
||||||
to the license. This includes other CC-licensed material, or material used
|
|
||||||
under an exception or limitation to copyright. More considerations for
|
|
||||||
licensors : wiki.creativecommons.org/Considerations_for_licensors
|
|
||||||
.
|
|
||||||
Considerations for the public: By using one of our public licenses, a licensor
|
|
||||||
grants the public permission to use the licensed material under specified
|
|
||||||
terms and conditions. If the licensor's permission is not necessary for any
|
|
||||||
reason–for example, because of any applicable exception or limitation to
|
|
||||||
copyright–then that use is not regulated by the license. Our licenses grant
|
|
||||||
only permissions under copyright and certain other rights that a licensor has
|
|
||||||
authority to grant. Use of the licensed material may still be restricted for
|
|
||||||
other reasons, including because others have copyright or other rights in the
|
|
||||||
material. A licensor may make special requests, such as asking that all
|
|
||||||
changes be marked or described.
|
|
||||||
.
|
|
||||||
Although not required by our licenses, you are encouraged to respect those
|
|
||||||
requests where reasonable. More considerations for the public :
|
|
||||||
wiki.creativecommons.org/Considerations_for_licensees
|
|
||||||
.
|
|
||||||
Creative Commons Attribution-ShareAlike 4.0 International Public License
|
|
||||||
.
|
|
||||||
By exercising the Licensed Rights (defined below), You accept and agree to be
|
|
||||||
bound by the terms and conditions of this Creative Commons
|
|
||||||
Attribution-ShareAlike 4.0 International Public License ("Public License"). To
|
|
||||||
the extent this Public License may be interpreted as a contract, You are
|
|
||||||
granted the Licensed Rights in consideration of Your acceptance of these terms
|
|
||||||
and conditions, and the Licensor grants You such rights in consideration of
|
|
||||||
benefits the Licensor receives from making the Licensed Material available
|
|
||||||
under these terms and conditions.
|
|
||||||
.
|
|
||||||
Section 1 – Definitions.
|
|
||||||
.
|
|
||||||
a. Adapted Material means material subject to Copyright and Similar Rights
|
|
||||||
that is derived from or based upon the Licensed Material and in which the
|
|
||||||
Licensed Material is translated, altered, arranged, transformed, or otherwise
|
|
||||||
modified in a manner requiring permission under the Copyright and Similar
|
|
||||||
Rights held by the Licensor. For purposes of this Public License, where the
|
|
||||||
Licensed Material is a musical work, performance, or sound recording, Adapted
|
|
||||||
Material is always produced where the Licensed Material is synched in timed
|
|
||||||
relation with a moving image.
|
|
||||||
.
|
|
||||||
b. Adapter's License means the license You apply to Your Copyright and Similar
|
|
||||||
Rights in Your contributions to Adapted Material in accordance with the terms
|
|
||||||
and conditions of this Public License.
|
|
||||||
.
|
|
||||||
c. BY-SA Compatible License means a license listed at
|
|
||||||
creativecommons.org/compatiblelicenses, approved by Creative Commons as
|
|
||||||
essentially the equivalent of this Public License.
|
|
||||||
.
|
|
||||||
d. Copyright and Similar Rights means copyright and/or similar rights closely
|
|
||||||
related to copyright including, without limitation, performance, broadcast,
|
|
||||||
sound recording, and Sui Generis Database Rights, without regard to how the
|
|
||||||
rights are labeled or categorized. For purposes of this Public License, the
|
|
||||||
rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.
|
|
||||||
.
|
|
||||||
e. Effective Technological Measures means those measures that, in the absence
|
|
||||||
of proper authority, may not be circumvented under laws fulfilling obligations
|
|
||||||
under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996,
|
|
||||||
and/or similar international agreements.
|
|
||||||
.
|
|
||||||
f. Exceptions and Limitations means fair use, fair dealing, and/or any other
|
|
||||||
exception or limitation to Copyright and Similar Rights that applies to Your
|
|
||||||
use of the Licensed Material.
|
|
||||||
.
|
|
||||||
g. License Elements means the license attributes listed in the name of a
|
|
||||||
Creative Commons Public License. The License Elements of this Public License
|
|
||||||
are Attribution and ShareAlike.
|
|
||||||
.
|
|
||||||
h. Licensed Material means the artistic or literary work, database, or other
|
|
||||||
material to which the Licensor applied this Public License.
|
|
||||||
.
|
|
||||||
i. Licensed Rights means the rights granted to You subject to the terms and
|
|
||||||
conditions of this Public License, which are limited to all Copyright and
|
|
||||||
Similar Rights that apply to Your use of the Licensed Material and that the
|
|
||||||
Licensor has authority to license.
|
|
||||||
.
|
|
||||||
j. Licensor means the individual(s) or entity(ies) granting rights under this
|
|
||||||
Public License.
|
|
||||||
.
|
|
||||||
k. Share means to provide material to the public by any means or process that
|
|
||||||
requires permission under the Licensed Rights, such as reproduction, public
|
|
||||||
display, public performance, distribution, dissemination, communication, or
|
|
||||||
importation, and to make material available to the public including in ways
|
|
||||||
that members of the public may access the material from a place and at a time
|
|
||||||
individually chosen by them.
|
|
||||||
.
|
|
||||||
l. Sui Generis Database Rights means rights other than copyright resulting
|
|
||||||
from Directive 96/9/EC of the European Parliament and of the Council of 11
|
|
||||||
March 1996 on the legal protection of databases, as amended and/or succeeded,
|
|
||||||
as well as other essentially equivalent rights anywhere in the world.
|
|
||||||
.
|
|
||||||
m. You means the individual or entity exercising the Licensed Rights under
|
|
||||||
this Public License. Your has a corresponding meaning.
|
|
||||||
.
|
|
||||||
Section 2 – Scope.
|
|
||||||
.
|
|
||||||
a. License grant.
|
|
||||||
.
|
|
||||||
1. Subject to the terms and conditions of this Public License, the Licensor
|
|
||||||
hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive,
|
|
||||||
irrevocable license to exercise the Licensed Rights in the Licensed Material
|
|
||||||
to:
|
|
||||||
.
|
|
||||||
A. reproduce and Share the Licensed Material, in whole or in part;
|
|
||||||
and
|
|
||||||
.
|
|
||||||
B. produce, reproduce, and Share Adapted Material.
|
|
||||||
.
|
|
||||||
2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions
|
|
||||||
and Limitations apply to Your use, this Public License does not apply, and You
|
|
||||||
do not need to comply with its terms and conditions.
|
|
||||||
.
|
|
||||||
3. Term. The term of this Public License is specified in Section 6(a).
|
|
||||||
.
|
|
||||||
4. Media and formats; technical modifications allowed. The Licensor authorizes
|
|
||||||
You to exercise the Licensed Rights in all media and formats whether now known
|
|
||||||
or hereafter created, and to make technical modifications necessary to do so.
|
|
||||||
The Licensor waives and/or agrees not to assert any right or authority to
|
|
||||||
forbid You from making technical modifications necessary to exercise the
|
|
||||||
Licensed Rights, including technical modifications necessary to circumvent
|
|
||||||
Effective Technological Measures. For purposes of this Public License, simply
|
|
||||||
making modifications authorized by this Section 2(a)(4) never produces Adapted
|
|
||||||
Material.
|
|
||||||
.
|
|
||||||
5. Downstream recipients.
|
|
||||||
.
|
|
||||||
A. Offer from the Licensor – Licensed Material. Every recipient of the
|
|
||||||
Licensed Material automatically receives an offer from the Licensor to
|
|
||||||
exercise the Licensed Rights under the terms and conditions of this Public
|
|
||||||
License.
|
|
||||||
.
|
|
||||||
B. Additional offer from the Licensor – Adapted Material. Every recipient of
|
|
||||||
Adapted Material from You automatically receives an offer from the Licensor to
|
|
||||||
exercise the Licensed Rights in the Adapted Material under the conditions of
|
|
||||||
the Adapter's License You apply.
|
|
||||||
.
|
|
||||||
C. No downstream restrictions. You may not offer or impose any additional or
|
|
||||||
different terms or conditions on, or apply any Effective Technological
|
|
||||||
Measures to, the Licensed Material if doing so restricts exercise of the
|
|
||||||
Licensed Rights by any recipient of the Licensed Material.
|
|
||||||
.
|
|
||||||
6. No endorsement. Nothing in this Public License constitutes or may be
|
|
||||||
construed as permission to assert or imply that You are, or that Your use of
|
|
||||||
the Licensed Material is, connected with, or sponsored, endorsed, or granted
|
|
||||||
official status by, the Licensor or others designated to receive attribution
|
|
||||||
as provided in Section 3(a)(1)(A)(i).
|
|
||||||
.
|
|
||||||
b. Other rights.
|
|
||||||
.
|
|
||||||
1. Moral rights, such as the right of integrity, are not licensed under this
|
|
||||||
Public License, nor are publicity, privacy, and/or other similar personality
|
|
||||||
rights; however, to the extent possible, the Licensor waives and/or agrees not
|
|
||||||
to assert any such rights held by the Licensor to the limited extent necessary
|
|
||||||
to allow You to exercise the Licensed Rights, but not otherwise.
|
|
||||||
.
|
|
||||||
2. Patent and trademark rights are not licensed under this Public License.
|
|
||||||
.
|
|
||||||
3. To the extent possible, the Licensor waives any right to collect royalties
|
|
||||||
from You for the exercise of the Licensed Rights, whether directly or through
|
|
||||||
a collecting society under any voluntary or waivable statutory or compulsory
|
|
||||||
licensing scheme. In all other cases the Licensor expressly reserves any right
|
|
||||||
to collect such royalties.
|
|
||||||
.
|
|
||||||
Section 3 – License Conditions.
|
|
||||||
.
|
|
||||||
Your exercise of the Licensed Rights is expressly made subject to the
|
|
||||||
following conditions.
|
|
||||||
.
|
|
||||||
a. Attribution.
|
|
||||||
.
|
|
||||||
1. If You Share the Licensed Material (including in modified form), You must:
|
|
||||||
.
|
|
||||||
A. retain the following if it is supplied by the Licensor with the Licensed
|
|
||||||
Material:
|
|
||||||
.
|
|
||||||
i. identification of the creator(s) of the Licensed Material and any others
|
|
||||||
designated to receive attribution, in any reasonable manner requested by the
|
|
||||||
Licensor (including by pseudonym if designated);
|
|
||||||
.
|
|
||||||
ii. a copyright notice;
|
|
||||||
.
|
|
||||||
iii. a notice that refers to this Public License;
|
|
||||||
.
|
|
||||||
iv. a notice that refers to the disclaimer of warranties;
|
|
||||||
.
|
|
||||||
v. a URI or hyperlink to the Licensed Material to the extent reasonably
|
|
||||||
practicable;
|
|
||||||
.
|
|
||||||
B. indicate if You modified the Licensed Material and retain an indication of
|
|
||||||
any previous modifications; and
|
|
||||||
.
|
|
||||||
C. indicate the Licensed Material is licensed under this Public License, and
|
|
||||||
include the text of, or the URI or hyperlink to, this Public License.
|
|
||||||
.
|
|
||||||
2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner
|
|
||||||
based on the medium, means, and context in which You Share the Licensed
|
|
||||||
Material. For example, it may be reasonable to satisfy the conditions by
|
|
||||||
providing a URI or hyperlink to a resource that includes the required
|
|
||||||
information.
|
|
||||||
.
|
|
||||||
3. If requested by the Licensor, You must remove any of the information
|
|
||||||
required by Section 3(a)(1)(A) to the extent reasonably practicable.
|
|
||||||
.
|
|
||||||
b. ShareAlike.In addition to the conditions in Section 3(a), if You Share
|
|
||||||
Adapted Material You produce, the following conditions also apply.
|
|
||||||
.
|
|
||||||
1. The Adapter's License You apply must be a Creative Commons license with the
|
|
||||||
same License Elements, this version or later, or a BY-SA Compatible License.
|
|
||||||
.
|
|
||||||
2. You must include the text of, or the URI or hyperlink to, the Adapter's
|
|
||||||
License You apply. You may satisfy this condition in any reasonable manner
|
|
||||||
based on the medium, means, and context in which You Share Adapted Material.
|
|
||||||
.
|
|
||||||
3. You may not offer or impose any additional or different terms or conditions
|
|
||||||
on, or apply any Effective Technological Measures to, Adapted Material that
|
|
||||||
restrict exercise of the rights granted under the Adapter's License You apply.
|
|
||||||
.
|
|
||||||
Section 4 – Sui Generis Database Rights.
|
|
||||||
.
|
|
||||||
Where the Licensed Rights include Sui Generis Database Rights that apply to
|
|
||||||
Your use of the Licensed Material:
|
|
||||||
.
|
|
||||||
a. for the avoidance of doubt, Section 2(a)(1) grants You the right to
|
|
||||||
extract, reuse, reproduce, and Share all or a substantial portion of the
|
|
||||||
contents of the database;
|
|
||||||
.
|
|
||||||
b. if You include all or a substantial portion of the database contents in a
|
|
||||||
database in which You have Sui Generis Database Rights, then the database in
|
|
||||||
which You have Sui Generis Database Rights (but not its individual contents)
|
|
||||||
is Adapted Material, including for purposes of Section 3(b); and
|
|
||||||
.
|
|
||||||
c. You must comply with the conditions in Section 3(a) if You Share all or a
|
|
||||||
substantial portion of the contents of the database.
|
|
||||||
.
|
|
||||||
For the avoidance of doubt, this Section 4 supplements and does not replace
|
|
||||||
Your obligations under this Public License where the Licensed Rights include
|
|
||||||
other Copyright and Similar Rights.
|
|
||||||
.
|
|
||||||
Section 5 – Disclaimer of Warranties and Limitation of Liability.
|
|
||||||
.
|
|
||||||
a. Unless otherwise separately undertaken by the Licensor, to the extent
|
|
||||||
possible, the Licensor offers the Licensed Material as-is and as-available,
|
|
||||||
and makes no representations or warranties of any kind concerning the Licensed
|
|
||||||
Material, whether express, implied, statutory, or other. This includes,
|
|
||||||
without limitation, warranties of title, merchantability, fitness for a
|
|
||||||
particular purpose, non-infringement, absence of latent or other defects,
|
|
||||||
accuracy, or the presence or absence of errors, whether or not known or
|
|
||||||
discoverable. Where disclaimers of warranties are not allowed in full or in
|
|
||||||
part, this disclaimer may not apply to You.
|
|
||||||
.
|
|
||||||
b. To the extent possible, in no event will the Licensor be liable to You on
|
|
||||||
any legal theory (including, without limitation, negligence) or otherwise for
|
|
||||||
any direct, special, indirect, incidental, consequential, punitive, exemplary,
|
|
||||||
or other losses, costs, expenses, or damages arising out of this Public
|
|
||||||
License or use of the Licensed Material, even if the Licensor has been advised
|
|
||||||
of the possibility of such losses, costs, expenses, or damages. Where a
|
|
||||||
limitation of liability is not allowed in full or in part, this limitation may
|
|
||||||
not apply to You.
|
|
||||||
.
|
|
||||||
c. The disclaimer of warranties and limitation of liability provided above
|
|
||||||
shall be interpreted in a manner that, to the extent possible, most closely
|
|
||||||
approximates an absolute disclaimer and waiver of all liability.
|
|
||||||
.
|
|
||||||
Section 6 – Term and Termination.
|
|
||||||
.
|
|
||||||
a. This Public License applies for the term of the Copyright and Similar
|
|
||||||
Rights licensed here. However, if You fail to comply with this Public License,
|
|
||||||
then Your rights under this Public License terminate automatically.
|
|
||||||
.
|
|
||||||
b. Where Your right to use the Licensed Material has terminated under Section
|
|
||||||
6(a), it reinstates:
|
|
||||||
.
|
|
||||||
1. automatically as of the date the violation is cured, provided it is cured
|
|
||||||
within 30 days of Your discovery of the violation; or
|
|
||||||
.
|
|
||||||
2. upon express reinstatement by the Licensor.
|
|
||||||
.
|
|
||||||
c. For the avoidance of doubt, this Section 6(b) does not affect any right the
|
|
||||||
Licensor may have to seek remedies for Your violations of this Public License.
|
|
||||||
.
|
|
||||||
d. For the avoidance of doubt, the Licensor may also offer the Licensed
|
|
||||||
Material under separate terms or conditions or stop distributing the Licensed
|
|
||||||
Material at any time; however, doing so will not terminate this Public
|
|
||||||
License.
|
|
||||||
.
|
|
||||||
e. Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
|
|
||||||
.
|
|
||||||
Section 7 – Other Terms and Conditions.
|
|
||||||
.
|
|
||||||
a. The Licensor shall not be bound by any additional or different terms or
|
|
||||||
conditions communicated by You unless expressly agreed.
|
|
||||||
.
|
|
||||||
b. Any arrangements, understandings, or agreements regarding the Licensed
|
|
||||||
Material not stated herein are separate from and independent of the terms and
|
|
||||||
conditions of this Public License.
|
|
||||||
.
|
|
||||||
Section 8 – Interpretation.
|
|
||||||
.
|
|
||||||
a. For the avoidance of doubt, this Public License does not, and shall not be
|
|
||||||
interpreted to, reduce, limit, restrict, or impose conditions on any use of
|
|
||||||
the Licensed Material that could lawfully be made without permission under
|
|
||||||
this Public License.
|
|
||||||
.
|
|
||||||
b. To the extent possible, if any provision of this Public License is deemed
|
|
||||||
unenforceable, it shall be automatically reformed to the minimum extent
|
|
||||||
necessary to make it enforceable. If the provision cannot be reformed, it
|
|
||||||
shall be severed from this Public License without affecting the enforceability
|
|
||||||
of the remaining terms and conditions.
|
|
||||||
.
|
|
||||||
c. No term or condition of this Public License will be waived and no failure
|
|
||||||
to comply consented to unless expressly agreed to by the Licensor.
|
|
||||||
.
|
|
||||||
d. Nothing in this Public License constitutes or may be interpreted as a
|
|
||||||
limitation upon, or waiver of, any privileges and immunities that apply to the
|
|
||||||
Licensor or You, including from the legal processes of any jurisdiction or
|
|
||||||
authority.
|
|
||||||
.
|
|
||||||
Creative Commons is not a party to its public licenses. Notwithstanding,
|
|
||||||
Creative Commons may elect to apply one of its public licenses to material it
|
|
||||||
publishes and in those instances will be considered the "Licensor." The text
|
|
||||||
of the Creative Commons public licenses is dedicated to the public domain
|
|
||||||
under the CC0 Public Domain Dedication. Except for the limited purpose of
|
|
||||||
indicating that material is shared under a Creative Commons public license or
|
|
||||||
as otherwise permitted by the Creative Commons policies published at
|
|
||||||
creativecommons.org/policies, Creative Commons does not authorize the use of
|
|
||||||
the trademark "Creative Commons" or any other trademark or logo of Creative
|
|
||||||
Commons without its prior written consent including, without limitation, in
|
|
||||||
connection with any unauthorized modifications to any of its public licenses
|
|
||||||
or any other arrangements, understandings, or agreements concerning use of
|
|
||||||
licensed material. For the avoidance of doubt, this paragraph does not form
|
|
||||||
part of the public licenses.
|
|
||||||
.
|
|
||||||
Creative Commons may be contacted at creativecommons.org.
|
|
7
debian/rules
vendored
7
debian/rules
vendored
@ -1,7 +0,0 @@
|
|||||||
#!/usr/bin/make -f
|
|
||||||
|
|
||||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
|
||||||
|
|
||||||
%:
|
|
||||||
dh $@
|
|
||||||
|
|
1
debian/source/format
vendored
1
debian/source/format
vendored
@ -1 +0,0 @@
|
|||||||
3.0 (quilt)
|
|
1
debian/wdisplays.docs
vendored
1
debian/wdisplays.docs
vendored
@ -1 +0,0 @@
|
|||||||
README.md
|
|
@ -3,9 +3,11 @@
|
|||||||
|
|
||||||
project('network.cycles.wdisplays', 'c', license: 'MIT', version: '1.0')
|
project('network.cycles.wdisplays', 'c', license: 'MIT', version: '1.0')
|
||||||
|
|
||||||
conf = configuration_data()
|
conf = configuration_data({
|
||||||
conf.set('app_id', meson.project_name())
|
'app_id': meson.project_name(),
|
||||||
conf.set('version', meson.project_version())
|
'version': meson.project_version(),
|
||||||
|
'resource_prefix': '/' / '/'.join(meson.project_name().split('.')),
|
||||||
|
})
|
||||||
|
|
||||||
subdir('protocol')
|
subdir('protocol')
|
||||||
subdir('resources')
|
subdir('resources')
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!-- Generated with glade 3.22.0 -->
|
<!-- Generated with glade 3.22.2 -->
|
||||||
<interface>
|
<interface>
|
||||||
<requires lib="gtk+" version="3.22"/>
|
<requires lib="gtk+" version="3.22"/>
|
||||||
<object class="GtkAdjustment" id="height_adjustment">
|
<object class="GtkAdjustment" id="height_adjustment">
|
||||||
@ -7,23 +7,6 @@
|
|||||||
<property name="step_increment">1</property>
|
<property name="step_increment">1</property>
|
||||||
<property name="page_increment">10</property>
|
<property name="page_increment">10</property>
|
||||||
</object>
|
</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">
|
<object class="GtkAdjustment" id="pos_x_adjustment">
|
||||||
<property name="upper">16383</property>
|
<property name="upper">16383</property>
|
||||||
<property name="step_increment">1</property>
|
<property name="step_increment">1</property>
|
||||||
@ -50,7 +33,7 @@
|
|||||||
<property name="step_increment">1</property>
|
<property name="step_increment">1</property>
|
||||||
<property name="page_increment">10</property>
|
<property name="page_increment">10</property>
|
||||||
</object>
|
</object>
|
||||||
<object class="GtkGrid" id="form">
|
<template class="WdHeadForm" parent="GtkGrid">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="margin_start">8</property>
|
<property name="margin_start">8</property>
|
||||||
@ -69,7 +52,7 @@
|
|||||||
<property name="halign">start</property>
|
<property name="halign">start</property>
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
<property name="draw_indicator">True</property>
|
<property name="draw_indicator">True</property>
|
||||||
<signal name="toggled" handler="enabled" swapped="no"/>
|
<signal name="toggled" handler="enabled_toggled" swapped="no"/>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="left_attach">1</property>
|
<property name="left_attach">1</property>
|
||||||
@ -99,7 +82,7 @@
|
|||||||
<property name="adjustment">scale_adjustment</property>
|
<property name="adjustment">scale_adjustment</property>
|
||||||
<property name="digits">2</property>
|
<property name="digits">2</property>
|
||||||
<property name="value">1</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>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="left_attach">1</property>
|
<property name="left_attach">1</property>
|
||||||
@ -194,6 +177,7 @@
|
|||||||
<property name="spacing">8</property>
|
<property name="spacing">8</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkSpinButton" id="refresh">
|
<object class="GtkSpinButton" id="refresh">
|
||||||
|
<property name="name">refresh</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="width_chars">9</property>
|
<property name="width_chars">9</property>
|
||||||
@ -202,6 +186,7 @@
|
|||||||
<property name="digits">3</property>
|
<property name="digits">3</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
<property name="update_policy">if-valid</property>
|
<property name="update_policy">if-valid</property>
|
||||||
|
<signal name="value-changed" handler="mode_spin_changed" swapped="no"/>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
@ -245,7 +230,6 @@
|
|||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">True</property>
|
<property name="receives_default">True</property>
|
||||||
<property name="popover">transforms</property>
|
|
||||||
<child>
|
<child>
|
||||||
<placeholder/>
|
<placeholder/>
|
||||||
</child>
|
</child>
|
||||||
@ -277,7 +261,7 @@
|
|||||||
<property name="halign">start</property>
|
<property name="halign">start</property>
|
||||||
<property name="use_underline">True</property>
|
<property name="use_underline">True</property>
|
||||||
<property name="draw_indicator">True</property>
|
<property name="draw_indicator">True</property>
|
||||||
<signal name="toggled" handler="flipped" swapped="no"/>
|
<signal name="toggled" handler="flipped_toggled" swapped="no"/>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="left_attach">1</property>
|
<property name="left_attach">1</property>
|
||||||
@ -299,6 +283,7 @@
|
|||||||
<property name="adjustment">pos_x_adjustment</property>
|
<property name="adjustment">pos_x_adjustment</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
<property name="update_policy">if-valid</property>
|
<property name="update_policy">if-valid</property>
|
||||||
|
<signal name="value-changed" handler="position_spin_changed" swapped="no"/>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="left_attach">0</property>
|
<property name="left_attach">0</property>
|
||||||
@ -315,6 +300,7 @@
|
|||||||
<property name="adjustment">pos_y_adjustment</property>
|
<property name="adjustment">pos_y_adjustment</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
<property name="update_policy">if-valid</property>
|
<property name="update_policy">if-valid</property>
|
||||||
|
<signal name="value-changed" handler="position_spin_changed" swapped="no"/>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="left_attach">2</property>
|
<property name="left_attach">2</property>
|
||||||
@ -323,6 +309,7 @@
|
|||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkSpinButton" id="width">
|
<object class="GtkSpinButton" id="width">
|
||||||
|
<property name="name">width</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="width_chars">4</property>
|
<property name="width_chars">4</property>
|
||||||
@ -331,6 +318,7 @@
|
|||||||
<property name="adjustment">width_adjustment</property>
|
<property name="adjustment">width_adjustment</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
<property name="update_policy">if-valid</property>
|
<property name="update_policy">if-valid</property>
|
||||||
|
<signal name="value-changed" handler="mode_spin_changed" swapped="no"/>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="left_attach">0</property>
|
<property name="left_attach">0</property>
|
||||||
@ -351,6 +339,7 @@
|
|||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkSpinButton" id="height">
|
<object class="GtkSpinButton" id="height">
|
||||||
|
<property name="name">height</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="width_chars">4</property>
|
<property name="width_chars">4</property>
|
||||||
@ -359,6 +348,7 @@
|
|||||||
<property name="adjustment">height_adjustment</property>
|
<property name="adjustment">height_adjustment</property>
|
||||||
<property name="numeric">True</property>
|
<property name="numeric">True</property>
|
||||||
<property name="update_policy">if-valid</property>
|
<property name="update_policy">if-valid</property>
|
||||||
|
<signal name="value-changed" handler="mode_spin_changed" swapped="no"/>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="left_attach">2</property>
|
<property name="left_attach">2</property>
|
||||||
@ -371,9 +361,7 @@
|
|||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">True</property>
|
<property name="receives_default">True</property>
|
||||||
<property name="tooltip_text" translatable="yes">Select Mode Preset</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="margin_start">8</property>
|
||||||
<property name="popover">modes</property>
|
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkImage">
|
<object class="GtkImage">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
@ -406,76 +394,5 @@
|
|||||||
<child>
|
<child>
|
||||||
<placeholder/>
|
<placeholder/>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</template>
|
||||||
<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>
|
|
||||||
</interface>
|
</interface>
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
# SPDX-FileCopyrightText: 2020 Jason Francis <jason@cycles.network>
|
# SPDX-FileCopyrightText: 2020 Jason Francis <jason@cycles.network>
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
resources_xml = configure_file(
|
||||||
|
input: 'resources.xml.in',
|
||||||
|
output: 'resources.xml',
|
||||||
|
configuration: conf
|
||||||
|
)
|
||||||
|
|
||||||
gnome = import('gnome')
|
gnome = import('gnome')
|
||||||
resources = gnome.compile_resources(
|
resources = gnome.compile_resources(
|
||||||
'waydisplay-resources', 'resources.xml',
|
'wdisplays-resources', resources_xml,
|
||||||
source_dir : '.',
|
source_dir : '.',
|
||||||
c_name : 'waydisplay_resources')
|
c_name : 'wdisplays_resources')
|
||||||
|
|
||||||
scour = find_program('scour', required: false)
|
scour = find_program('scour', required: false)
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<gresources>
|
<gresources>
|
||||||
<gresource prefix="/">
|
<gresource prefix="@resource_prefix@">
|
||||||
<file compressed="true" preprocess="xml-stripblanks">wdisplays.ui</file>
|
<file compressed="true" preprocess="xml-stripblanks">wdisplays.ui</file>
|
||||||
<file compressed="true" preprocess="xml-stripblanks">head.ui</file>
|
<file compressed="true" preprocess="xml-stripblanks">head.ui</file>
|
||||||
<file compressed="true">style.css</file>
|
<file compressed="true">style.css</file>
|
@ -11,62 +11,6 @@
|
|||||||
<property name="step_increment">1</property>
|
<property name="step_increment">1</property>
|
||||||
<property name="page_increment">10</property>
|
<property name="page_increment">10</property>
|
||||||
</object>
|
</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">
|
<object class="GtkWindow" id="heads_window">
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="title" translatable="yes">wdisplays</property>
|
<property name="title" translatable="yes">wdisplays</property>
|
||||||
@ -171,8 +115,6 @@
|
|||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="halign">center</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_start">8</property>
|
||||||
<property name="margin_end">8</property>
|
<property name="margin_end">8</property>
|
||||||
<property name="margin_top">8</property>
|
<property name="margin_top">8</property>
|
||||||
@ -248,14 +190,14 @@
|
|||||||
<object class="GtkButtonBox" id="zoom_box">
|
<object class="GtkButtonBox" id="zoom_box">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="layout_style">expand</property>
|
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkButton" id="zoom_out">
|
<object class="GtkButton" id="zoom_out">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">True</property>
|
<property name="receives_default">True</property>
|
||||||
<property name="tooltip_text" translatable="yes">Zoom Out</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>
|
<child>
|
||||||
<object class="GtkImage">
|
<object class="GtkImage">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
@ -263,7 +205,6 @@
|
|||||||
<property name="icon_name">zoom-out-symbolic</property>
|
<property name="icon_name">zoom-out-symbolic</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<accelerator key="minus" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
|
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">True</property>
|
<property name="expand">True</property>
|
||||||
@ -278,7 +219,7 @@
|
|||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">True</property>
|
<property name="receives_default">True</property>
|
||||||
<property name="tooltip_text" translatable="yes">Zoom Reset</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"/>
|
<accelerator key="0" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
@ -294,7 +235,8 @@
|
|||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">True</property>
|
<property name="receives_default">True</property>
|
||||||
<property name="tooltip_text" translatable="yes">Zoom In</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>
|
<child>
|
||||||
<object class="GtkImage">
|
<object class="GtkImage">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
@ -302,7 +244,6 @@
|
|||||||
<property name="icon_name">zoom-in-symbolic</property>
|
<property name="icon_name">zoom-in-symbolic</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<accelerator key="equal" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
|
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">True</property>
|
<property name="expand">True</property>
|
||||||
@ -311,6 +252,9 @@
|
|||||||
<property name="non_homogeneous">True</property>
|
<property name="non_homogeneous">True</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="linked"/>
|
||||||
|
</style>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
@ -318,7 +262,6 @@
|
|||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">True</property>
|
<property name="receives_default">True</property>
|
||||||
<property name="popover">main_menu</property>
|
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkImage">
|
<object class="GtkImage">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
@ -355,7 +298,7 @@
|
|||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">True</property>
|
<property name="receives_default">True</property>
|
||||||
<property name="use_underline">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>
|
<style>
|
||||||
<class name="suggested-action"/>
|
<class name="suggested-action"/>
|
||||||
</style>
|
</style>
|
||||||
@ -371,7 +314,7 @@
|
|||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">True</property>
|
<property name="receives_default">True</property>
|
||||||
<property name="use_underline">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>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
|
@ -6,5 +6,6 @@
|
|||||||
|
|
||||||
#define WDISPLAYS_APP_ID "@app_id@"
|
#define WDISPLAYS_APP_ID "@app_id@"
|
||||||
#define WDISPLAYS_VERSION "@version@"
|
#define WDISPLAYS_VERSION "@version@"
|
||||||
|
#define WDISPLAYS_RESOURCE_PREFIX "@resource_prefix@"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
393
src/headform.c
Normal file
393
src/headform.c
Normal 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
59
src/headform.h
Normal 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
|
||||||
|
|
924
src/main.c
924
src/main.c
File diff suppressed because it is too large
Load Diff
@ -4,8 +4,8 @@
|
|||||||
cc = meson.get_compiler('c')
|
cc = meson.get_compiler('c')
|
||||||
m_dep = cc.find_library('m', required : false)
|
m_dep = cc.find_library('m', required : false)
|
||||||
rt_dep = cc.find_library('rt', required : false)
|
rt_dep = cc.find_library('rt', required : false)
|
||||||
gdk = dependency('gdk-3.0')
|
gdk = dependency('gdk-3.0', version: '>= 3.24')
|
||||||
gtk = dependency('gtk+-3.0')
|
gtk = dependency('gtk+-3.0', version: '>= 3.24')
|
||||||
assert(gdk.get_pkgconfig_variable('targets').split().contains('wayland'), 'Wayland GDK backend not present')
|
assert(gdk.get_pkgconfig_variable('targets').split().contains('wayland'), 'Wayland GDK backend not present')
|
||||||
epoxy = dependency('epoxy')
|
epoxy = dependency('epoxy')
|
||||||
|
|
||||||
@ -15,10 +15,11 @@ executable(
|
|||||||
'wdisplays',
|
'wdisplays',
|
||||||
[
|
[
|
||||||
'main.c',
|
'main.c',
|
||||||
'outputs.c',
|
|
||||||
'render.c',
|
|
||||||
'glviewport.c',
|
'glviewport.c',
|
||||||
|
'headform.c',
|
||||||
|
'outputs.c',
|
||||||
'overlay.c',
|
'overlay.c',
|
||||||
|
'render.c',
|
||||||
resources,
|
resources,
|
||||||
],
|
],
|
||||||
dependencies : [
|
dependencies : [
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <wayland-client.h>
|
#include <wayland-client.h>
|
||||||
|
|
||||||
|
#include "headform.h"
|
||||||
|
|
||||||
struct zxdg_output_v1;
|
struct zxdg_output_v1;
|
||||||
struct zxdg_output_manager_v1;
|
struct zxdg_output_manager_v1;
|
||||||
struct zwlr_output_mode_v1;
|
struct zwlr_output_mode_v1;
|
||||||
@ -39,18 +41,6 @@ typedef struct _GdkCursor GdkCursor;
|
|||||||
struct _cairo_surface;
|
struct _cairo_surface;
|
||||||
typedef struct _cairo_surface cairo_surface_t;
|
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_output {
|
||||||
struct wd_state *state;
|
struct wd_state *state;
|
||||||
struct zxdg_output_v1 *xdg_output;
|
struct zxdg_output_v1 *xdg_output;
|
||||||
@ -205,10 +195,10 @@ struct wd_state {
|
|||||||
unsigned int reset_idle;
|
unsigned int reset_idle;
|
||||||
|
|
||||||
struct wd_render_head_data *clicked;
|
struct wd_render_head_data *clicked;
|
||||||
/* top left, bottom right */
|
struct wd_point drag_start;
|
||||||
struct wd_point click_offset;
|
struct wd_point head_drag_start; /* 0-1 range in head rect */
|
||||||
bool panning;
|
bool panning;
|
||||||
struct wd_point pan_last;
|
struct wd_point pan_start;
|
||||||
|
|
||||||
GtkWidget *main_box;
|
GtkWidget *main_box;
|
||||||
GtkWidget *header_stack;
|
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
|
* Updates the UI form for a single head. Useful for when the compositor
|
||||||
* notifies us of updated configuration caused by another program.
|
* 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.
|
* Updates the stack and all forms to the last known server state.
|
||||||
|
Reference in New Issue
Block a user