├── .clang-format
├── .github
├── gif.gif
├── tile
└── tile.png
├── .gitignore
├── LICENCE
├── README.md
├── include
├── astro.h
├── config.h
├── gui.h
├── map.h
└── version.h
├── meson.build
├── release
└── src
├── astro.c
├── gui.c
├── main.c
└── map.c
/.clang-format:
--------------------------------------------------------------------------------
1 | AllowShortCaseLabelsOnASingleLine: true
2 | PointerAlignment: Left
3 | IndentWidth: 4
4 | ReflowComments: true
5 |
--------------------------------------------------------------------------------
/.github/gif.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sentriz/wlr-sunclock/acd130a4d2655435d960b9c19b52a3fb20e292af/.github/gif.gif
--------------------------------------------------------------------------------
/.github/tile:
--------------------------------------------------------------------------------
1 | ocean #F5F3FF earth #6D28D9
2 | ocean #EDE9FE earth #4C1D95
3 | ocean #ECFDF5 earth #831843
4 | ocean #FFFBEB earth #064E3B
5 |
--------------------------------------------------------------------------------
/.github/tile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sentriz/wlr-sunclock/acd130a4d2655435d960b9c19b52a3fb20e292af/.github/tile.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | compile_commands.json
2 | build
3 | .clangd/
4 | .cache/
5 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | (demo gif, in reality it updates in real time)
3 |
4 | # wlr-sunclock
5 |
6 | wayland desktop widget to show to the sun's shadows on earth.
7 | uses [gtk-layer-shell](https://github.com/wmww/gtk-layer-shell) and the [layer shell protocol](https://github.com/swaywm/wlr-protocols/blob/master/unstable/wlr-layer-shell-unstable-v1.xml) to render on your desktop, behind your windows
8 |
9 | now with colour support 😎
10 | 
11 |
12 | ## Installation
13 |
14 | [](https://repology.org/project/wlr-sunclock/versions)
15 |
16 | ### from source
17 |
18 | pacman -S gtk-layer-shell gtk3 wayland librsvg
19 |
20 | meson build
21 | sudo ninja -C build install
22 |
23 | ### from AUR
24 |
25 | please see [wlr-sunclock-git](https://aur.archlinux.org/packages/wlr-sunclock-git/)
26 |
27 | ### from OBS
28 |
29 | please see [X11:Wayland/wlr-sunclock](https://build.opensuse.org/package/show/X11:Wayland/wlr-sunclock) for the openSUSE package
30 |
31 | ### from Fedora Copr
32 |
33 | please see [wef/wlr-sunclock](https://copr.fedorainfracloud.org/coprs/wef/wlr-sunclock/) for a Fedora package
34 |
35 | ## CLI args
36 |
37 | -a, --anchors=ANCHORS string of window anchors (see below)
38 | -i, --monitor-index=MONITOR_INDEX monitor to show window on (starts at 0)
39 | -l, --layer= desktop layer to show the widget on
40 | -m, --margins=MARGINS comma separated margins for window
41 | -w, --width=WIDTH width of the window
42 | -d, --border-width=BORDER_WIDTH width of the window's border
43 | -o, --colour-ocean=COLOUR_OCEAN colour of the ocean
44 | -n, --colour-land=COLOUR_LAND colour of the land
45 | -v, --version print version
46 |
47 | ## Anchors
48 |
49 | -a tl -a tr -a br -a bl -a '' -a tblr
50 | ┌─┬───┐ ┌───┬─┐ ┌─────┐ ┌─────┐ ┌─────┐ ╔═════╗
51 | ├─┘ │ │ └─┤ │ │ │ │ │ ┌─┐ │ ║ ║
52 | │ │ │ │ │ ┌─┤ ├─┐ │ │ └─┘ │ ║ ║
53 | └─────┘ └─────┘ └───┴─┘ └─┴───┘ └─────┘ ╚═════╝
54 |
55 | ## Start on boot with sway example
56 |
57 | # ~/.config/sway/config
58 |
59 | exec wlr-sunclock \
60 | --margins "0,16,0,16" \
61 | --width 800 \
62 | --layer bottom \
63 | --anchors br \
64 | --border-width 2 \
65 | --colour-ocean "#C4B5FD" \
66 | --colour-land "#6D28D9"
67 |
--------------------------------------------------------------------------------
/include/astro.h:
--------------------------------------------------------------------------------
1 | #ifndef SUNCLOCK_ASTRO_H
2 | #define SUNCLOCK_ASTRO_H
3 |
4 | #include
5 |
6 | double astro_gm_time_to_julian(struct tm* t);
7 | long astro_gm_time_to_julian_astro(struct tm* t);
8 | double astro_kepler(double m, double ecc);
9 | void astro_sun_position(double jd, int apparent, double* ra, double* dec,
10 | double* rv, double* slong);
11 | void astro_project_illum(short* wtab, int xdots, int ydots, double dec);
12 |
13 | #endif
14 |
--------------------------------------------------------------------------------
/include/config.h:
--------------------------------------------------------------------------------
1 | #ifndef SUNCLOCK_CONFIG_H
2 | #define SUNCLOCK_CONFIG_H
3 |
4 | enum sunclock_layer {
5 | SUNCLOCK_LAYER_BACKGROUND,
6 | SUNCLOCK_LAYER_BOTTOM,
7 | SUNCLOCK_LAYER_TOP,
8 | SUNCLOCK_LAYER_OVERLAY,
9 | };
10 |
11 | struct sunclock_gui_settings {
12 | int margins[4];
13 | int border_width;
14 |
15 | char* title;
16 | enum sunclock_layer layer;
17 | char* anchors;
18 | int monitor_index;
19 | int width;
20 |
21 | char* colour_ocean;
22 | char* colour_land;
23 | };
24 |
25 | #endif
26 |
--------------------------------------------------------------------------------
/include/gui.h:
--------------------------------------------------------------------------------
1 | #ifndef SUNCLOCK_GUI_H
2 | #define SUNCLOCK_GUI_H
3 |
4 | #include "config.h"
5 | #include "gtk-layer-shell.h"
6 | #include
7 |
8 | void sunclock_gui_activate(GtkApplication* app, gpointer psettings);
9 | int sunclock_gui_start(struct sunclock_gui_settings* settings);
10 |
11 | #endif
12 |
--------------------------------------------------------------------------------
/include/map.h:
--------------------------------------------------------------------------------
1 | #ifndef SUNCLOCK_MAP__H
2 | #define SUNCLOCK_MAP__H
3 |
4 | #include
5 |
6 | gchar* sunclock_map_svg(char* colour_ocean, char* colour_land);
7 |
8 | #endif
9 |
--------------------------------------------------------------------------------
/include/version.h:
--------------------------------------------------------------------------------
1 | #ifndef SUNCLOCK_VERSION_H
2 | #define SUNCLOCK_VERSION_H
3 |
4 | #define SUNCLOCK_VERSION "v1.0.0"
5 |
6 | #endif
7 |
--------------------------------------------------------------------------------
/meson.build:
--------------------------------------------------------------------------------
1 | project(
2 | 'wlr-sunclock',
3 | 'c',
4 | meson_version : '>=0.46.0',
5 | default_options : ['warning_level=3', 'werror=true'],
6 | version : 'v1.0.0'
7 | )
8 |
9 | cc = meson.get_compiler('c')
10 | gtk = dependency('gtk+-wayland-3.0', version: '>=3.22.0')
11 | gtk_layer_shell = dependency('gtk-layer-shell-0')
12 | librsvg = dependency('librsvg-2.0')
13 |
14 | add_project_arguments(cc.get_supported_arguments([
15 | '-Wno-deprecated-declarations',
16 | '-Wno-overlength-strings',
17 | ]), language: 'c')
18 |
19 | executable(
20 | meson.project_name(),
21 | files(
22 | 'src/main.c',
23 | 'src/gui.c',
24 | 'src/astro.c',
25 | 'src/map.c',
26 | ),
27 | include_directories: ['include'],
28 | dependencies: [
29 | cc.find_library('m'),
30 | gtk,
31 | gtk_layer_shell,
32 | librsvg,
33 | ],
34 | install: true,
35 | link_args: ['-lm'],
36 | )
37 |
--------------------------------------------------------------------------------
/release:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # safety checks
4 | if [[ $# -ne 1 ]]; then
5 | echo "usage: $0 " >&2
6 | exit 1
7 | fi
8 |
9 | if [[ "$(git rev-parse --abbrev-ref HEAD)" != 'master' ]]; then
10 | echo "not on the master branch" >&2
11 | exit 1
12 | fi
13 |
14 | # get latest and check if clean
15 | if [[ -n "$(git status --porcelain)" ]]; then
16 | echo "working directory is dirty" >&2
17 | exit 1
18 | fi
19 |
20 | # get the current verison from last git tag into array and
21 | # inc the provided part
22 | semver_expression='s/^v([0-9]+)\.([0-9]+)\.([0-9]+).*$/\1 \2 \3/'
23 | version=( $(git describe --tags | sed -E -e "$semver_expression" ) )
24 | case "$1" in
25 | major) ((version[0]++))
26 | version[1]=0
27 | version[2]=0
28 | ;;
29 | minor) ((version[1]++))
30 | version[2]=0
31 | ;;
32 | patch) ((version[2]++))
33 | ;;
34 | *) echo 'please provide a valid version in increment' >&2
35 | exit 1
36 | ;;
37 | esac
38 | new_version="v${version[0]}.${version[1]}.${version[2]}"
39 |
40 | # update meson.build
41 | meson rewrite kwargs set project / version "$new_version"
42 |
43 | # write version header
44 | cat > include/version.h <
45 | #include
46 | #include
47 | #include
48 |
49 | #define PI 3.14159265358979323846
50 | #define E 2.7182818284590452354
51 | #define EPSILON 1E-6
52 |
53 | #define abs(x) ((x) < 0 ? (-(x)) : x) /* absolute value */
54 | #define sgn(x) (((x) < 0) ? -1 : ((x) > 0 ? 1 : 0)) /* extract sign */
55 | #define dtr(x) ((x) * (PI / 180.0)) /* degree -> radian */
56 | #define rtd(x) ((x) / (PI / 180.0)) /* radian -> degree */
57 | #define fixangle(a) ((a)-360.0 * (floor((a) / 360.0))) /* fix angle */
58 |
59 | #define TERMINC 100 /* circle segments for terminator */
60 | #define PROJINT (60 * 10) /* frequency of seasonal recalculation */
61 |
62 | /* convert internal GMT date and time to Julian day and fraction */
63 | double astro_gm_time_to_julian(struct tm* t) {
64 | double y = t->tm_year + 1900;
65 | double m = t->tm_mon + 1;
66 | if (m > 2)
67 | m = m - 3;
68 | else {
69 | m = m + 9;
70 | y--;
71 | }
72 | /* compute century */
73 | double c = y / 100L;
74 | y -= 100L * c;
75 | return t->tm_mday + (c * 146097L) / 4 + (y * 1461L) / 4 +
76 | (m * 153L + 2) / 5 + 1721119L;
77 | }
78 |
79 | /* convert internal GMT date and time to astronomical Julian time (i.e. Julian
80 | * date plus day fraction, expressed as a double) */
81 | long astro_gm_time_to_julian_astro(struct tm* t) {
82 | return (astro_gm_time_to_julian(t) - 0.5) +
83 | (((long)t->tm_sec) + 60L * (t->tm_min + 60L * t->tm_hour)) / 86400.0;
84 | }
85 |
86 | double astro_kepler(double m, double ecc) {
87 | double delta;
88 | double e = m = dtr(m);
89 | do {
90 | delta = e - ecc * sin(e) - m;
91 | e -= delta / (1 - ecc * cos(e));
92 | } while (abs(delta) > EPSILON);
93 | return e;
94 | }
95 |
96 | /* calculate position of the Sun. JD is the Julian date of the instant for which
97 | the position is desired and APPARENT should be nonzero if the apparent position
98 | (corrected for nutation and aberration) is desired. The Sun's co-ordinates are
99 | returned in RA and DEC, both specified in degrees (divide RA by 15 to obtain
100 | hours). The radius vector to the Sun in astronomical units is returned in RV
101 | and the Sun's longitude (true or apparent, as desired) is returned as degrees
102 | in SLONG */
103 | void astro_sun_position(double jd, int apparent, double* ra, double* dec,
104 | double* rv, double* slong) {
105 | /* time in Julian centuries of 36525 ephemeris days, measured from the epoch
106 | * 1900 January 0.5 ET */
107 | double t = (jd - 2415020.0) / 36525.0;
108 | double t2 = t * t;
109 | double t3 = t2 * t;
110 |
111 | /* geometric mean longitude of the Sun, referred to the mean equinox of the
112 | * date */
113 | double l = fixangle(279.69668 + 36000.76892 * t + 0.0003025 * t2);
114 |
115 | /* sun's mean anomaly */
116 | double m =
117 | fixangle(358.47583 + 35999.04975 * t - 0.000150 * t2 - 0.0000033 * t3);
118 |
119 | /* eccentricity of the Earth's orbit */
120 | double e = 0.01675104 - 0.0000418 * t - 0.000000126 * t2;
121 |
122 | /* eccentric anomaly */
123 | double ea = astro_kepler(m, e);
124 |
125 | /* true anomaly */
126 | double v = fixangle(2 * rtd(atan(sqrt((1 + e) / (1 - e)) * tan(ea / 2))));
127 |
128 | /* sun's true longitude */
129 | double theta = l + v - m;
130 |
131 | /* obliquity of the ecliptic */
132 | double eps = 23.452294 - 0.0130125 * t - 0.00000164 * t2 + 0.000000503 * t3;
133 |
134 | /* corrections for Sun's apparent longitude, if desired */
135 | if (apparent) {
136 | double omega = fixangle(259.18 - 1934.142 * t);
137 | theta = theta - 0.00569 - 0.00479 * sin(dtr(omega));
138 | eps += 0.00256 * cos(dtr(omega));
139 | }
140 |
141 | /* return Sun's longitude and radius vector */
142 | *slong = theta;
143 | *rv = (1.0000002 * (1 - e * e)) / (1 + e * cos(dtr(v)));
144 |
145 | /* determine solar co-ordinates */
146 | *ra =
147 | fixangle(rtd(atan2(cos(dtr(eps)) * sin(dtr(theta)), cos(dtr(theta)))));
148 | *dec = rtd(asin(sin(dtr(eps)) * sin(dtr(theta))));
149 | }
150 |
151 | /* greenwich Mean Siderial Time for a given instant expressed as a Julian date
152 | * and fraction */
153 | double astro_gm_siderial_time(double jd) {
154 | /* time, in Julian centuries of 36525 ephemeris days, measured from the
155 | * epoch 1900 January 0.5 ET */
156 | double t = ((floor(jd + 0.5) - 0.5) - 2415020.0) / 36525.0;
157 | double theta0 = 6.6460656 + 2400.051262 * t + 0.00002581 * t * t;
158 |
159 | t = (jd + 0.5) - (floor(jd + 0.5));
160 | theta0 += (t * 24.0) * 1.002737908;
161 | theta0 = (theta0 - 24.0 * (floor(theta0 / 24.0)));
162 | return theta0;
163 | }
164 |
165 | /* project illuminated area on the map */
166 | void astro_project_illum(short* wtab, int xdots, int ydots, double dec) {
167 | int i, ftf = 1, ilon, ilat, lilon = 0, lilat = 0, xt;
168 | double m, x, y, z, th, lon, lat;
169 |
170 | /* clear unoccupied cells in width table */
171 | for (i = 0; i < ydots; i++)
172 | wtab[i] = -1;
173 |
174 | /* build transformation for declination */
175 | double s = sin(-dtr(dec));
176 | double c = cos(-dtr(dec));
177 |
178 | /* increment over a semicircle of illumination */
179 | for (th = -(PI / 2); th <= PI / 2 + 0.001; th += PI / TERMINC) {
180 | /* transform the point through the declination rotation */
181 | x = -s * sin(th);
182 | y = cos(th);
183 | z = c * sin(th);
184 |
185 | /* transform the resulting co-ordinate through the map projection to
186 | * obtain screen co-ordinates */
187 | lon = (y == 0 && x == 0) ? 0.0 : rtd(atan2(y, x));
188 | lat = rtd(asin(z));
189 |
190 | ilat = ydots - (lat + 90) * (ydots / 180.0);
191 | ilon = lon * (xdots / 360.0);
192 |
193 | if (ftf) {
194 | /* first time. just save start co-ordinate */
195 | lilon = ilon;
196 | lilat = ilat;
197 | ftf = 0;
198 | continue;
199 | }
200 |
201 | /* trace out the line and set the width table */
202 | if (lilat == ilat) {
203 | wtab[(ydots - 1) - ilat] = ilon == 0 ? 1 : ilon;
204 | } else {
205 | m = ((double)(ilon - lilon)) / (ilat - lilat);
206 | for (i = lilat; i != ilat; i += sgn(ilat - lilat)) {
207 | xt = lilon + floor((m * (i - lilat)) + 0.5);
208 | wtab[(ydots - 1) - i] = xt == 0 ? 1 : xt;
209 | }
210 | }
211 | lilon = ilon;
212 | lilat = ilat;
213 | }
214 |
215 | /* tweak the widths to generate full illumination for the correct pole */
216 | if (dec < 0.0) {
217 | ilat = ydots - 1;
218 | lilat = -1;
219 | } else {
220 | ilat = 0;
221 | lilat = 1;
222 | }
223 |
224 | for (i = ilat; i != ydots / 2; i += lilat) {
225 | if (wtab[i] != -1) {
226 | while (1) {
227 | wtab[i] = xdots / 2;
228 | if (i == ilat)
229 | break;
230 | i -= lilat;
231 | }
232 | break;
233 | }
234 | }
235 | }
236 |
--------------------------------------------------------------------------------
/src/gui.c:
--------------------------------------------------------------------------------
1 | #include "astro.h"
2 | #include "config.h"
3 | #include "gtk-layer-shell.h"
4 | #include "map.h"
5 | #include
6 | #include
7 | #include
8 |
9 | static void sunclock_gui_fill_wtab(short* wtab, int width, int height,
10 | int* gmt_position) {
11 | time_t raw_time;
12 | time(&raw_time);
13 | struct tm* gm_time = gmtime(&raw_time);
14 |
15 | double jt, sunra, sundec, sunrv, sunlong;
16 | jt = astro_gm_time_to_julian_astro(gm_time);
17 | astro_sun_position(jt, FALSE, &sunra, &sundec, &sunrv, &sunlong);
18 | astro_project_illum(wtab, width, height, sundec);
19 |
20 | // note: greenwich is in the middle
21 | int sec =
22 | gm_time->tm_hour * 60 * 60 + gm_time->tm_min * 60 + gm_time->tm_sec;
23 | *gmt_position = width * sec / 86400;
24 | }
25 |
26 | static void sunclock_gui_draw_line(cairo_t* cr, short x1, short y1, short x2,
27 | short y2) {
28 | cairo_move_to(cr, x1, y1);
29 | cairo_line_to(cr, x2, y2);
30 | cairo_stroke(cr);
31 | }
32 |
33 | static gboolean sunclock_gui_draw_shade_timeout(GtkWidget* widget) {
34 | gtk_widget_queue_draw(widget);
35 | return TRUE;
36 | }
37 |
38 | static gboolean sunclock_gui_draw_shade(GtkWidget* widget, cairo_t* cr,
39 | gpointer image) {
40 | int height = gtk_widget_get_allocated_height(widget);
41 | int width = gtk_widget_get_allocated_width(widget);
42 |
43 | GdkPixbuf* image_scaled = gdk_pixbuf_scale_simple(
44 | (GdkPixbuf*)image, width, height, GDK_INTERP_BILINEAR);
45 | gdk_cairo_set_source_pixbuf(cr, image_scaled, 0, 0);
46 | cairo_paint(cr);
47 | g_object_unref(image_scaled);
48 |
49 | GdkRGBA colour;
50 | colour.red = 0.933333;
51 | colour.green = 0.933333;
52 | colour.blue = 0.925490;
53 | colour.alpha = 1.0;
54 |
55 | gdk_cairo_set_source_rgba(cr, &colour);
56 |
57 | // calculate the illuminated area
58 | int gmt_position;
59 | short wtab[height];
60 | sunclock_gui_fill_wtab(wtab, width, height, &gmt_position);
61 |
62 | // draw illuminated area
63 | cairo_set_line_width(cr, 0.3);
64 | int start, stop;
65 | int middle = width - gmt_position;
66 | for (int y = 0; y < height; y++) {
67 | if (wtab[y] <= 0)
68 | continue;
69 | start = middle - wtab[y];
70 | stop = middle + wtab[y];
71 | if (start < 0) {
72 | sunclock_gui_draw_line(cr, 0, y, stop, y);
73 | sunclock_gui_draw_line(cr, width + start, y, width, y);
74 | } else if (stop > width) {
75 | sunclock_gui_draw_line(cr, start, y, width, y);
76 | sunclock_gui_draw_line(cr, 0, y, stop - width, y);
77 | } else
78 | sunclock_gui_draw_line(cr, start, y, stop, y);
79 | }
80 |
81 | return FALSE;
82 | }
83 |
84 | void sunclock_gui_activate(GtkApplication* app, gpointer psettings) {
85 | GtkWindow* gtk_window = GTK_WINDOW(gtk_application_window_new(app));
86 | gtk_layer_init_for_window(gtk_window);
87 |
88 | struct sunclock_gui_settings* settings = psettings;
89 |
90 | // user setting border, layer
91 | gtk_container_set_border_width(GTK_CONTAINER(gtk_window),
92 | settings->border_width);
93 | gtk_layer_set_layer(gtk_window, (int)settings->layer);
94 |
95 | // user setting margin
96 | for (int i = 0; i < 4; i++)
97 | gtk_layer_set_margin(gtk_window, i, settings->margins[i]);
98 |
99 | // user setting anchor
100 | for (const char* c = settings->anchors; *c; c++)
101 | switch (*c) {
102 | case 'l': gtk_layer_set_anchor(gtk_window, 0, TRUE); break;
103 | case 'r': gtk_layer_set_anchor(gtk_window, 1, TRUE); break;
104 | case 't': gtk_layer_set_anchor(gtk_window, 2, TRUE); break;
105 | case 'b': gtk_layer_set_anchor(gtk_window, 3, TRUE); break;
106 | }
107 |
108 | // user setting monitor index
109 | GdkDisplay* display = gdk_display_get_default();
110 | GdkMonitor* monitor =
111 | gdk_display_get_monitor(display, settings->monitor_index);
112 | gtk_layer_set_monitor(gtk_window, monitor);
113 |
114 | GtkWidget* canvas = gtk_drawing_area_new();
115 | gtk_widget_set_hexpand(canvas, TRUE);
116 | gtk_widget_set_vexpand(canvas, TRUE);
117 |
118 | int image_width = settings->width;
119 | int image_height = settings->width / 2;
120 | gtk_widget_set_size_request(canvas, image_width, image_height);
121 |
122 | const gchar* map_svg =
123 | sunclock_map_svg(settings->colour_ocean, settings->colour_land);
124 | glong map_len = g_utf8_strlen(map_svg, -1);
125 | RsvgHandle* map_handle =
126 | rsvg_handle_new_from_data((guint8*)map_svg, map_len, NULL);
127 | GdkPixbuf* map_image = rsvg_handle_get_pixbuf(map_handle);
128 |
129 | // draw canvas now and every 30s
130 | g_signal_connect(canvas, "draw", G_CALLBACK(sunclock_gui_draw_shade),
131 | map_image);
132 | g_timeout_add_seconds(30, G_SOURCE_FUNC(sunclock_gui_draw_shade_timeout),
133 | canvas);
134 |
135 | gtk_container_add(GTK_CONTAINER(gtk_window), canvas);
136 | gtk_widget_show_all(GTK_WIDGET(gtk_window));
137 | }
138 |
139 | int sunclock_gui_start(struct sunclock_gui_settings* settings) {
140 | GtkApplication* app = gtk_application_new(settings->title, 0);
141 | g_signal_connect(app, "activate", G_CALLBACK(sunclock_gui_activate),
142 | settings);
143 |
144 | int status = g_application_run(G_APPLICATION(app), 0, 0);
145 | g_object_unref(app);
146 | return status;
147 | }
148 |
--------------------------------------------------------------------------------
/src/main.c:
--------------------------------------------------------------------------------
1 | #include "config.h"
2 | #include "gui.h"
3 | #include "version.h"
4 | #include
5 | #include
6 | #include
7 |
8 | static enum sunclock_layer layer_from_str(char* in) {
9 | if (strcmp(in, "background") == 0)
10 | return SUNCLOCK_LAYER_BACKGROUND;
11 | if (strcmp(in, "bottom") == 0)
12 | return SUNCLOCK_LAYER_BOTTOM;
13 | if (strcmp(in, "top") == 0)
14 | return SUNCLOCK_LAYER_TOP;
15 | if (strcmp(in, "overlay") == 0)
16 | return SUNCLOCK_LAYER_OVERLAY;
17 | return -1;
18 | }
19 |
20 | // clang-format off
21 | static char doc[] = "Displays a sunclock desktop widget using the layer shell protocol";
22 | static struct argp_option options[] = {
23 | {"layer", 'l', "", 0, "desktop layer to show the widget on", 1},
24 | {"width", 'w', "WIDTH", 0, "width of the window", 1},
25 | {"anchors", 'a', "ANCHORS", 0, "string of window anchors (see readme)", 1},
26 | {"margins", 'm', "MARGINS", 0, "comma separated margins for window", 1},
27 | {"monitor-index", 'i', "MONITOR_INDEX", 0, "monitor to show window on (starts at 0)", 1},
28 | {"border-width", 'd', "BORDER_WIDTH", 0, "width of the window's border", 2},
29 | {"colour-ocean", 'o', "COLOUR_OCEAN", 0, "colour of the ocean", 3},
30 | {"colour-land", 'n', "COLOUR_LAND", 0, "colour of the land", 3},
31 | {"version", 'v', NULL, 0, "print version", 4},
32 | {0},
33 | };
34 | // clang-format on
35 |
36 | static error_t parse_option(int key, char* arg, struct argp_state* state) {
37 | struct sunclock_gui_settings* settings = state->input;
38 | switch (key) {
39 | case 'l':
40 | settings->layer = layer_from_str(arg);
41 | if ((int)settings->layer == -1) {
42 | fprintf(stderr, "invalid layer %s provided\n", arg);
43 | argp_usage(state);
44 | };
45 | break;
46 | case 'w': settings->width = atoi(arg); break;
47 | case 'a': settings->anchors = arg; break;
48 | case 'm':
49 | for (int i = 0; i < 4; i++)
50 | settings->margins[i] = atoi(strsep(&arg, ","));
51 | break;
52 | case 'i': settings->monitor_index = atoi(arg); break;
53 | case 'd': settings->border_width = atoi(arg); break;
54 | case 'o': settings->colour_ocean = arg; break;
55 | case 'n': settings->colour_land = arg; break;
56 | case 'v':
57 | fprintf(stderr, "sunclock version %s\n", SUNCLOCK_VERSION);
58 | exit(0);
59 | break;
60 | case ARGP_KEY_ARG: break;
61 | default: return ARGP_ERR_UNKNOWN;
62 | }
63 | return 0;
64 | }
65 |
66 | int main(int argc, char* argv[]) {
67 | struct argp argp = {options, parse_option, NULL, doc, NULL, NULL, NULL};
68 | struct sunclock_gui_settings settings = {
69 | .title = "xyz.senan.wlr-sunclock",
70 | .layer = SUNCLOCK_LAYER_BOTTOM,
71 | .width = 300,
72 | .anchors = "",
73 | .monitor_index = 0,
74 | .colour_ocean = "#4c446d",
75 | .colour_land = "#726f9e",
76 | };
77 | argp_parse(&argp, argc, argv, 0, 0, &settings);
78 | return sunclock_gui_start(&settings);
79 | }
80 |
--------------------------------------------------------------------------------
/src/map.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | // clang-format off
4 | const char* svg =
5 | ""
6 | "";
10 | // clang-format on
11 |
12 | gchar* sunclock_map_svg(char* colour_ocean, char* colour_land) {
13 | return g_strdup_printf(svg, colour_ocean, colour_land);
14 | }
15 |
--------------------------------------------------------------------------------