summaryrefslogtreecommitdiff
path: root/src/astal.vala
diff options
context:
space:
mode:
authorAylur <[email protected]>2024-05-19 02:39:53 +0200
committerAylur <[email protected]>2024-05-19 02:39:53 +0200
commit1425b396b08f0e91d45bbd0f92b1309115c7c870 (patch)
tree8af1a899a14d8a01a9ef50e248c077b48aed25bc /src/astal.vala
init 0.1.0
Diffstat (limited to 'src/astal.vala')
-rw-r--r--src/astal.vala171
1 files changed, 171 insertions, 0 deletions
diff --git a/src/astal.vala b/src/astal.vala
new file mode 100644
index 0000000..e9d1484
--- /dev/null
+++ b/src/astal.vala
@@ -0,0 +1,171 @@
+namespace Astal {
+public class Application : Gtk.Application {
+ public signal void request (string request);
+ private List<Gtk.CssProvider> css_providers;
+ private SocketService service;
+ private string socket;
+
+ public string instance_name { get; construct set; }
+
+ public List<Gtk.Window> windows {
+ get { return get_windows(); }
+ }
+
+ public Gtk.Settings settings {
+ get { return Gtk.Settings.get_default(); }
+ }
+
+ public Gdk.Screen screen {
+ get { return Gdk.Screen.get_default(); }
+ }
+
+ public string gtk_theme {
+ owned get { return settings.gtk_theme_name; }
+ set { settings.gtk_theme_name = value; }
+ }
+
+ public string icon_theme {
+ owned get { return settings.gtk_icon_theme_name; }
+ set { settings.gtk_icon_theme_name = value; }
+ }
+
+ public string cursor_theme {
+ owned get { return settings.gtk_cursor_theme_name; }
+ set { settings.gtk_cursor_theme_name = value; }
+ }
+
+ public void reset_css() {
+ foreach(var provider in css_providers) {
+ Gtk.StyleContext.remove_provider_for_screen(screen, provider);
+ css_providers.remove_all(provider);
+ }
+ }
+
+ public void inspector() {
+ Gtk.Window.set_interactive_debugging(true);
+ }
+
+ public Gtk.Window get_window(string name) throws WindowError {
+ foreach(var win in windows) {
+ if (win.name == name)
+ return win;
+ }
+
+ throw new WindowError.NO_WINDOW_WITH_NAME(name);
+ }
+
+ public void apply_css(string style, bool reset = false) throws Error {
+ var provider = new Gtk.CssProvider();
+
+ if (reset)
+ reset_css();
+
+ if (FileUtils.test(style, FileTest.EXISTS))
+ provider.load_from_path(style);
+ else
+ provider.load_from_data(style);
+
+ Gtk.StyleContext.add_provider_for_screen(
+ screen, provider, Gtk.STYLE_PROVIDER_PRIORITY_USER);
+
+ css_providers.append(provider);
+ }
+
+ private async void _socket_request(SocketConnection conn) {
+ string message = yield read_sock(conn);
+ request(message.strip());
+ response(message.strip(), conn);
+ }
+
+ public virtual void response(string msg, SocketConnection conn) {
+ write_sock.begin(conn, "missing response implementation on ".concat(application_id));
+ }
+
+ /**
+ * should be called before `run()`
+ * the return value indicates if instance is already running
+ */
+ public bool acquire_socket() {
+ socket = GLib.Environment.get_user_runtime_dir().concat(
+ "/",
+ instance_name,
+ ".sock");
+
+ if (FileUtils.test(socket, GLib.FileTest.EXISTS)) {
+ info("socket %s exists", socket);
+ return false;
+ }
+
+ try {
+ SocketAddress _;
+ service = new SocketService();
+ service.add_address(
+ new UnixSocketAddress(socket),
+ SocketType.STREAM,
+ SocketProtocol.DEFAULT,
+ null,
+ out _);
+
+ service.incoming.connect((conn) => {
+ _socket_request.begin(conn);
+ return false;
+ });
+
+ info("socket acquired: %s\n", socket);
+ return true;
+ } catch (Error err) {
+ critical("could not acquire socket %s\n", application_id);
+ critical(err.message);
+ return false;
+ }
+ }
+
+ construct {
+ if (instance_name == null)
+ instance_name = "astal";
+
+ if (application_id == null)
+ application_id = "io.Astal.".concat(instance_name);
+
+ shutdown.connect(() => {
+ if (FileUtils.test(socket, GLib.FileTest.EXISTS)){
+ try {
+ File.new_for_path(socket).delete(null);
+ } catch (Error err) {
+ warning(err.message);
+ }
+ }
+ });
+
+ SourceFunc close = () => { quit(); };
+ Unix.signal_add(1, close, Priority.HIGH);
+ Unix.signal_add(2, close, Priority.HIGH);
+ Unix.signal_add(15, close, Priority.HIGH);
+ }
+}
+
+public errordomain WindowError {
+ NO_WINDOW_WITH_NAME
+}
+
+public async string read_sock(SocketConnection conn) {
+ try {
+ var stream = new DataInputStream(conn.input_stream);
+ size_t size;
+ return yield stream.read_upto_async("\x04", -1, Priority.DEFAULT, null, out size);
+ } catch (Error err) {
+ critical(err.message);
+ return err.message;
+ }
+}
+
+public async void write_sock(SocketConnection conn, string response) {
+ try {
+ yield conn.output_stream.write_async(
+ response.concat("\x04").data,
+ Priority.DEFAULT);
+ } catch (Error err) {
+ critical(err.message);
+ }
+}
+}