From 62f3e56dee9471403addc6e8741aaf19e561dce3 Mon Sep 17 00:00:00 2001 From: icedman Date: Mon, 30 Dec 2024 00:03:36 +0800 Subject: [PATCH 1/4] add dbus service --- Makefile | 2 +- dwl.c | 281 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 282 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 578194f..5df8984 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ DWLDEVCFLAGS = -g -Wpedantic -Wall -Wextra -Wdeclaration-after-statement \ -Wfloat-conversion # CFLAGS / LDFLAGS -PKGS = wayland-server xkbcommon libinput $(XLIBS) +PKGS = wayland-server xkbcommon libinput gio-2.0 glib-2.0 $(XLIBS) DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(WLR_INCS) $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS) LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(WLR_LIBS) -lm $(LIBS) diff --git a/dwl.c b/dwl.c index 0eba3e9..46d25cb 100644 --- a/dwl.c +++ b/dwl.c @@ -68,6 +68,9 @@ #include #endif +#include +#include + #include "util.h" /* macros */ @@ -243,6 +246,50 @@ typedef struct { struct wl_listener destroy; } SessionLock; +typedef struct { + GMainContext *context; + GMainLoop *loop; + guint owner_id; + void* timer; + int interval; + + GDBusConnection *connection; + gchar *property_message; + gint property_count; +} DBusService; + +static DBusService *dbus; + +static GDBusNodeInfo *introspection_data = NULL; + +const gchar *introspection_xml = + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + +#define SERVICE_NAME "com.dwl.DBus" +#define OBJECT_PATH "/com/dwl/DBus" +#define INTERFACE_NAME "com.dwl.DBus.Interface" + /* function declarations */ static void applybounds(Client *c, struct wlr_box *bbox); static void applyrules(Client *c); @@ -356,6 +403,39 @@ static void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, LayerSurface **pl, double *nx, double *ny); static void zoom(const Arg *arg); + +static void dbus_on_name_acquired(GDBusConnection *connection, const gchar *name, + gpointer user_data); +static void dbus_on_name_lost(GDBusConnection *connection, const gchar *name, + gpointer user_data); +static void dbus_on_bus_acquired(GDBusConnection *connection, const gchar *name, + gpointer user_data); +static int dbus_service_update(void *data); +static int dbus_service_init(void); +static void dbus_service_cleanup(void); + +// Method handler +static void dbus_handle_method_call(GDBusConnection *connection, const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data); +// Property handlers +static GVariant *dbus_get_property(GDBusConnection *connection, const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *property_name, GError **error, + gpointer user_data); +static gboolean dbus_set_property(GDBusConnection *connection, const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *property_name, GVariant *value, + GError **error, gpointer user_data); + +// Emit the MessageChanged signal +static void dbus_emit_client_signal(GDBusConnection *connection, const char* signal, Client *c); + /* variables */ static pid_t child_pid = -1; static int locked; @@ -424,6 +504,13 @@ static struct wlr_xwayland *xwayland; static xcb_atom_t netatom[NetLast]; #endif +// VTable +static const GDBusInterfaceVTable interface_vtable = { + .method_call = dbus_handle_method_call, + .get_property = dbus_get_property, + .set_property = dbus_set_property, +}; + /* configuration, allows nested code to access above variables */ #include "config.h" @@ -670,6 +757,8 @@ checkidleinhibitor(struct wlr_surface *exclude) void cleanup(void) { + dbus_service_cleanup(); + #ifdef XWAYLAND wlr_xwayland_destroy(xwayland); xwayland = NULL; @@ -1404,6 +1493,8 @@ focusclient(Client *c, int lift) /* Activate the new client */ client_activate_surface(client_surface(c), 1); + + dbus_emit_client_signal(dbus->connection, "WindowFocused", c); } void @@ -1737,6 +1828,8 @@ mapnotify(struct wl_listener *listener, void *data) } printstatus(); + dbus_emit_client_signal(dbus->connection, "WindowOpened", c); + unset_fullscreen: m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y); wl_list_for_each(w, &clients, link) { @@ -2604,6 +2697,8 @@ setup(void) fprintf(stderr, "failed to setup XWayland X server, continuing without it\n"); } #endif + + dbus_service_init(); } void @@ -2755,6 +2850,7 @@ unmapnotify(struct wl_listener *listener, void *data) { /* Called when the surface is unmapped, and should no longer be shown. */ Client *c = wl_container_of(listener, c, unmap); + dbus_emit_client_signal(dbus->connection, "WindowClosed", c); if (c == grabc) { cursor_mode = CurNormal; grabc = NULL; @@ -3151,6 +3247,191 @@ xwaylandready(struct wl_listener *listener, void *data) } #endif +GString* gstring_append_client_json(GString *gstring, Client *c) { + const char *appid, *title; + const char *fmt = "{ \"id\": \"0x%x\", \"title\": \"%s\", \"app_id\": \"%s\" }"; + + GString *gstringTemp = g_string_new(""); + appid = client_get_appid(c); + title = client_get_title(c); + g_string_assign(gstringTemp, title); + g_string_replace(gstringTemp, "\"", "'", 0); + g_string_append_printf(gstring, fmt, c, gstringTemp->str, appid); + + g_string_free(gstringTemp, TRUE); + return gstring; +} + +static void dbus_handle_method_call(GDBusConnection *connection, const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) { + if (g_strcmp0(method_name, "GetWindows") == 0) { + const char *response = "Hello from D-Bus!"; + g_print("HelloWorld method called by %s\n", sender); + + Client *c = NULL; + GString *gstring = g_string_new("["); + wl_list_for_each(c, &clients, link) { + gstring_append_client_json(gstring, c); + if (c->link.next != &clients) { + g_string_append_printf(gstring, ","); + } + } + g_string_append_printf(gstring, "]"); + g_dbus_method_invocation_return_value(invocation, + g_variant_new("(s)", gstring->str)); + g_string_free(gstring, TRUE); + } else if (g_strcmp0(method_name, "FocusWindow") == 0) { + const gchar *window; + g_variant_get(parameters, "(s)", &window); + + uintptr_t address = strtol(window, NULL, 16); // Base 16 for hexadecimal + Client *c = NULL; + wl_list_for_each(c, &clients, link) { + if ((uintptr_t)c == address) { + focusclient(c, true); + } + } + + // g_print("focus %s\n", window); + g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", window)); + g_free(window); + + } else { + g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, + G_DBUS_ERROR_UNKNOWN_METHOD, + "Unknown method: %s", method_name); + } +} + +static GVariant *dbus_get_property(GDBusConnection *connection, const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *property_name, GError **error, + gpointer user_data) { + if (g_strcmp0(property_name, "Message") == 0) { + return g_variant_new_string(dbus->property_message ? dbus->property_message + : "Default Message"); + } else if (g_strcmp0(property_name, "Count") == 0) { + dbus->property_count = 0; + // Monitor *m = NULL; + // wl_list_for_each(m, &mons, link) { + // dbus->property_count++; + // } + + Client *c = NULL; + wl_list_for_each(c, &clients, link) { + dbus->property_count++; + } + + return g_variant_new_int32(dbus->property_count); + } + return NULL; // Property not found +} + +static gboolean dbus_set_property(GDBusConnection *connection, const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *property_name, GVariant *value, + GError **error, gpointer user_data) { + if (g_strcmp0(property_name, "Message") == 0) { + g_free(dbus->property_message); + dbus->property_message = g_strdup(g_variant_get_string(value, NULL)); + return TRUE; + } + g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_PROPERTY_READ_ONLY, + "The 'Count' property is read-only."); + return FALSE; +} + +static void dbus_emit_client_signal(GDBusConnection *connection, const char* signal, Client *c) { + g_print("emit %s\n", signal); + GString *gstring = g_string_new(""); + gstring_append_client_json(gstring, c); + + g_dbus_connection_emit_signal(connection, + NULL, // No sender (broadcast to all clients) + OBJECT_PATH, // Object path + INTERFACE_NAME, // Interface name + signal, // Signal name + g_variant_new("(s)", gstring->str), // Arguments + NULL); // No error + g_string_free(gstring, TRUE); +} + +static void dbus_on_name_acquired(GDBusConnection *connection, const gchar *name, + gpointer user_data) { + g_print("Service name '%s' acquired.\n", SERVICE_NAME); +} + +static void dbus_on_name_lost(GDBusConnection *connection, const gchar *name, + gpointer user_data) { + g_print("Service name '%s' lost.\n", SERVICE_NAME); +} + +static void dbus_on_bus_acquired(GDBusConnection *connection, const gchar *name, + gpointer user_data) { + GError *error = NULL; + + // Register the object + guint registration_id = g_dbus_connection_register_object( + connection, OBJECT_PATH, introspection_data->interfaces[0], + &interface_vtable, + NULL, // user data + NULL, // user data free function + &error); + + if (registration_id == 0) { + g_printerr("Failed to register object: %s\n", error->message); + g_error_free(error); + } + + dbus->connection = connection; + +} + +static int dbus_service_update(void *data) +{ + g_main_context_iteration(dbus->context, FALSE); + wl_event_source_timer_update(dbus->timer, dbus->interval); + return 0; +} + +static int dbus_service_init(void) { + dbus = ecalloc(1, sizeof(DBusService)); + DBusService *d = dbus; + d->interval = 150; + d->property_message = NULL; + d->property_count = 0; + + d->loop = g_main_loop_new(NULL, FALSE); + d->context = g_main_loop_get_context(d->loop); + + dbus->timer = wl_event_loop_add_timer(event_loop, dbus_service_update, dbus); + + // Create introspection data + introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL); + + // Acquire the bus name + d->owner_id = g_bus_own_name(G_BUS_TYPE_SESSION, SERVICE_NAME, + G_BUS_NAME_OWNER_FLAGS_NONE, dbus_on_bus_acquired, + dbus_on_name_acquired, dbus_on_name_lost, NULL, NULL); + + wl_event_source_timer_update(dbus->timer, dbus->interval); + return 0; +} + +static void dbus_service_cleanup(void) { + g_bus_unown_name(dbus->owner_id); + g_main_loop_unref(dbus->loop); + g_dbus_node_info_unref(introspection_data); + free(dbus); + dbus = NULL; +} + int main(int argc, char *argv[]) { -- 2.47.1 From 735481c04d7caed712990e7b005badbeb8a622b0 Mon Sep 17 00:00:00 2001 From: icedman Date: Mon, 30 Dec 2024 00:33:15 +0800 Subject: [PATCH 2/4] add patch --- patches/dbus/README.md | 8 + patches/dbus/dbus.patch | 381 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 389 insertions(+) create mode 100644 patches/dbus/README.md create mode 100644 patches/dbus/dbus.patch diff --git a/patches/dbus/README.md b/patches/dbus/README.md new file mode 100644 index 0000000..234223b --- /dev/null +++ b/patches/dbus/README.md @@ -0,0 +1,8 @@ +### Description +Implements a dbus service provider for Gnome-based enviroment. + +### Download +- [main 2024-12-30](/icedman/dwl/raw/branch/dbus-patch/patches/dbus/dbus.patch) + +### Author +- [icedman](https://codeberg.org/icedman) diff --git a/patches/dbus/dbus.patch b/patches/dbus/dbus.patch new file mode 100644 index 0000000..3f8e984 --- /dev/null +++ b/patches/dbus/dbus.patch @@ -0,0 +1,381 @@ +From 62f3e56dee9471403addc6e8741aaf19e561dce3 Mon Sep 17 00:00:00 2001 +From: icedman +Date: Mon, 30 Dec 2024 00:03:36 +0800 +Subject: [PATCH] add dbus service + +--- + Makefile | 2 +- + dwl.c | 281 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 282 insertions(+), 1 deletion(-) + +diff --git a/Makefile b/Makefile +index 578194f..5df8984 100644 +--- a/Makefile ++++ b/Makefile +@@ -12,7 +12,7 @@ DWLDEVCFLAGS = -g -Wpedantic -Wall -Wextra -Wdeclaration-after-statement \ + -Wfloat-conversion + + # CFLAGS / LDFLAGS +-PKGS = wayland-server xkbcommon libinput $(XLIBS) ++PKGS = wayland-server xkbcommon libinput gio-2.0 glib-2.0 $(XLIBS) + DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(WLR_INCS) $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS) + LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(WLR_LIBS) -lm $(LIBS) + +diff --git a/dwl.c b/dwl.c +index 0eba3e9..46d25cb 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -68,6 +68,9 @@ + #include + #endif + ++#include ++#include ++ + #include "util.h" + + /* macros */ +@@ -243,6 +246,50 @@ typedef struct { + struct wl_listener destroy; + } SessionLock; + ++typedef struct { ++ GMainContext *context; ++ GMainLoop *loop; ++ guint owner_id; ++ void* timer; ++ int interval; ++ ++ GDBusConnection *connection; ++ gchar *property_message; ++ gint property_count; ++} DBusService; ++ ++static DBusService *dbus; ++ ++static GDBusNodeInfo *introspection_data = NULL; ++ ++const gchar *introspection_xml = ++ "" ++ " " ++ " " ++ " " ++ " " ++ " " ++ " " ++ " " ++ " " ++ " " ++ " " ++ " " ++ " " ++ " " ++ " " ++ " " ++ " " ++ " " ++ " " ++ " " ++ " " ++ ""; ++ ++#define SERVICE_NAME "com.dwl.DBus" ++#define OBJECT_PATH "/com/dwl/DBus" ++#define INTERFACE_NAME "com.dwl.DBus.Interface" ++ + /* function declarations */ + static void applybounds(Client *c, struct wlr_box *bbox); + static void applyrules(Client *c); +@@ -356,6 +403,39 @@ static void xytonode(double x, double y, struct wlr_surface **psurface, + Client **pc, LayerSurface **pl, double *nx, double *ny); + static void zoom(const Arg *arg); + ++ ++static void dbus_on_name_acquired(GDBusConnection *connection, const gchar *name, ++ gpointer user_data); ++static void dbus_on_name_lost(GDBusConnection *connection, const gchar *name, ++ gpointer user_data); ++static void dbus_on_bus_acquired(GDBusConnection *connection, const gchar *name, ++ gpointer user_data); ++static int dbus_service_update(void *data); ++static int dbus_service_init(void); ++static void dbus_service_cleanup(void); ++ ++// Method handler ++static void dbus_handle_method_call(GDBusConnection *connection, const gchar *sender, ++ const gchar *object_path, ++ const gchar *interface_name, ++ const gchar *method_name, GVariant *parameters, ++ GDBusMethodInvocation *invocation, ++ gpointer user_data); ++// Property handlers ++static GVariant *dbus_get_property(GDBusConnection *connection, const gchar *sender, ++ const gchar *object_path, ++ const gchar *interface_name, ++ const gchar *property_name, GError **error, ++ gpointer user_data); ++static gboolean dbus_set_property(GDBusConnection *connection, const gchar *sender, ++ const gchar *object_path, ++ const gchar *interface_name, ++ const gchar *property_name, GVariant *value, ++ GError **error, gpointer user_data); ++ ++// Emit the MessageChanged signal ++static void dbus_emit_client_signal(GDBusConnection *connection, const char* signal, Client *c); ++ + /* variables */ + static pid_t child_pid = -1; + static int locked; +@@ -424,6 +504,13 @@ static struct wlr_xwayland *xwayland; + static xcb_atom_t netatom[NetLast]; + #endif + ++// VTable ++static const GDBusInterfaceVTable interface_vtable = { ++ .method_call = dbus_handle_method_call, ++ .get_property = dbus_get_property, ++ .set_property = dbus_set_property, ++}; ++ + /* configuration, allows nested code to access above variables */ + #include "config.h" + +@@ -670,6 +757,8 @@ checkidleinhibitor(struct wlr_surface *exclude) + void + cleanup(void) + { ++ dbus_service_cleanup(); ++ + #ifdef XWAYLAND + wlr_xwayland_destroy(xwayland); + xwayland = NULL; +@@ -1404,6 +1493,8 @@ focusclient(Client *c, int lift) + + /* Activate the new client */ + client_activate_surface(client_surface(c), 1); ++ ++ dbus_emit_client_signal(dbus->connection, "WindowFocused", c); + } + + void +@@ -1737,6 +1828,8 @@ mapnotify(struct wl_listener *listener, void *data) + } + printstatus(); + ++ dbus_emit_client_signal(dbus->connection, "WindowOpened", c); ++ + unset_fullscreen: + m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y); + wl_list_for_each(w, &clients, link) { +@@ -2604,6 +2697,8 @@ setup(void) + fprintf(stderr, "failed to setup XWayland X server, continuing without it\n"); + } + #endif ++ ++ dbus_service_init(); + } + + void +@@ -2755,6 +2850,7 @@ unmapnotify(struct wl_listener *listener, void *data) + { + /* Called when the surface is unmapped, and should no longer be shown. */ + Client *c = wl_container_of(listener, c, unmap); ++ dbus_emit_client_signal(dbus->connection, "WindowClosed", c); + if (c == grabc) { + cursor_mode = CurNormal; + grabc = NULL; +@@ -3151,6 +3247,191 @@ xwaylandready(struct wl_listener *listener, void *data) + } + #endif + ++GString* gstring_append_client_json(GString *gstring, Client *c) { ++ const char *appid, *title; ++ const char *fmt = "{ \"id\": \"0x%x\", \"title\": \"%s\", \"app_id\": \"%s\" }"; ++ ++ GString *gstringTemp = g_string_new(""); ++ appid = client_get_appid(c); ++ title = client_get_title(c); ++ g_string_assign(gstringTemp, title); ++ g_string_replace(gstringTemp, "\"", "'", 0); ++ g_string_append_printf(gstring, fmt, c, gstringTemp->str, appid); ++ ++ g_string_free(gstringTemp, TRUE); ++ return gstring; ++} ++ ++static void dbus_handle_method_call(GDBusConnection *connection, const gchar *sender, ++ const gchar *object_path, ++ const gchar *interface_name, ++ const gchar *method_name, GVariant *parameters, ++ GDBusMethodInvocation *invocation, ++ gpointer user_data) { ++ if (g_strcmp0(method_name, "GetWindows") == 0) { ++ const char *response = "Hello from D-Bus!"; ++ g_print("HelloWorld method called by %s\n", sender); ++ ++ Client *c = NULL; ++ GString *gstring = g_string_new("["); ++ wl_list_for_each(c, &clients, link) { ++ gstring_append_client_json(gstring, c); ++ if (c->link.next != &clients) { ++ g_string_append_printf(gstring, ","); ++ } ++ } ++ g_string_append_printf(gstring, "]"); ++ g_dbus_method_invocation_return_value(invocation, ++ g_variant_new("(s)", gstring->str)); ++ g_string_free(gstring, TRUE); ++ } else if (g_strcmp0(method_name, "FocusWindow") == 0) { ++ const gchar *window; ++ g_variant_get(parameters, "(s)", &window); ++ ++ uintptr_t address = strtol(window, NULL, 16); // Base 16 for hexadecimal ++ Client *c = NULL; ++ wl_list_for_each(c, &clients, link) { ++ if ((uintptr_t)c == address) { ++ focusclient(c, true); ++ } ++ } ++ ++ // g_print("focus %s\n", window); ++ g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", window)); ++ g_free(window); ++ ++ } else { ++ g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, ++ G_DBUS_ERROR_UNKNOWN_METHOD, ++ "Unknown method: %s", method_name); ++ } ++} ++ ++static GVariant *dbus_get_property(GDBusConnection *connection, const gchar *sender, ++ const gchar *object_path, ++ const gchar *interface_name, ++ const gchar *property_name, GError **error, ++ gpointer user_data) { ++ if (g_strcmp0(property_name, "Message") == 0) { ++ return g_variant_new_string(dbus->property_message ? dbus->property_message ++ : "Default Message"); ++ } else if (g_strcmp0(property_name, "Count") == 0) { ++ dbus->property_count = 0; ++ // Monitor *m = NULL; ++ // wl_list_for_each(m, &mons, link) { ++ // dbus->property_count++; ++ // } ++ ++ Client *c = NULL; ++ wl_list_for_each(c, &clients, link) { ++ dbus->property_count++; ++ } ++ ++ return g_variant_new_int32(dbus->property_count); ++ } ++ return NULL; // Property not found ++} ++ ++static gboolean dbus_set_property(GDBusConnection *connection, const gchar *sender, ++ const gchar *object_path, ++ const gchar *interface_name, ++ const gchar *property_name, GVariant *value, ++ GError **error, gpointer user_data) { ++ if (g_strcmp0(property_name, "Message") == 0) { ++ g_free(dbus->property_message); ++ dbus->property_message = g_strdup(g_variant_get_string(value, NULL)); ++ return TRUE; ++ } ++ g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_PROPERTY_READ_ONLY, ++ "The 'Count' property is read-only."); ++ return FALSE; ++} ++ ++static void dbus_emit_client_signal(GDBusConnection *connection, const char* signal, Client *c) { ++ g_print("emit %s\n", signal); ++ GString *gstring = g_string_new(""); ++ gstring_append_client_json(gstring, c); ++ ++ g_dbus_connection_emit_signal(connection, ++ NULL, // No sender (broadcast to all clients) ++ OBJECT_PATH, // Object path ++ INTERFACE_NAME, // Interface name ++ signal, // Signal name ++ g_variant_new("(s)", gstring->str), // Arguments ++ NULL); // No error ++ g_string_free(gstring, TRUE); ++} ++ ++static void dbus_on_name_acquired(GDBusConnection *connection, const gchar *name, ++ gpointer user_data) { ++ g_print("Service name '%s' acquired.\n", SERVICE_NAME); ++} ++ ++static void dbus_on_name_lost(GDBusConnection *connection, const gchar *name, ++ gpointer user_data) { ++ g_print("Service name '%s' lost.\n", SERVICE_NAME); ++} ++ ++static void dbus_on_bus_acquired(GDBusConnection *connection, const gchar *name, ++ gpointer user_data) { ++ GError *error = NULL; ++ ++ // Register the object ++ guint registration_id = g_dbus_connection_register_object( ++ connection, OBJECT_PATH, introspection_data->interfaces[0], ++ &interface_vtable, ++ NULL, // user data ++ NULL, // user data free function ++ &error); ++ ++ if (registration_id == 0) { ++ g_printerr("Failed to register object: %s\n", error->message); ++ g_error_free(error); ++ } ++ ++ dbus->connection = connection; ++ ++} ++ ++static int dbus_service_update(void *data) ++{ ++ g_main_context_iteration(dbus->context, FALSE); ++ wl_event_source_timer_update(dbus->timer, dbus->interval); ++ return 0; ++} ++ ++static int dbus_service_init(void) { ++ dbus = ecalloc(1, sizeof(DBusService)); ++ DBusService *d = dbus; ++ d->interval = 150; ++ d->property_message = NULL; ++ d->property_count = 0; ++ ++ d->loop = g_main_loop_new(NULL, FALSE); ++ d->context = g_main_loop_get_context(d->loop); ++ ++ dbus->timer = wl_event_loop_add_timer(event_loop, dbus_service_update, dbus); ++ ++ // Create introspection data ++ introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL); ++ ++ // Acquire the bus name ++ d->owner_id = g_bus_own_name(G_BUS_TYPE_SESSION, SERVICE_NAME, ++ G_BUS_NAME_OWNER_FLAGS_NONE, dbus_on_bus_acquired, ++ dbus_on_name_acquired, dbus_on_name_lost, NULL, NULL); ++ ++ wl_event_source_timer_update(dbus->timer, dbus->interval); ++ return 0; ++} ++ ++static void dbus_service_cleanup(void) { ++ g_bus_unown_name(dbus->owner_id); ++ g_main_loop_unref(dbus->loop); ++ g_dbus_node_info_unref(introspection_data); ++ free(dbus); ++ dbus = NULL; ++} ++ + int + main(int argc, char *argv[]) + { +-- +2.47.1 + -- 2.47.1 From 958933eeb575fb59c5555cb2c37a296c42bdcd52 Mon Sep 17 00:00:00 2001 From: icedman Date: Mon, 30 Dec 2024 00:38:13 +0800 Subject: [PATCH 3/4] update README with some dbus info --- patches/dbus/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/patches/dbus/README.md b/patches/dbus/README.md index 234223b..2cbab54 100644 --- a/patches/dbus/README.md +++ b/patches/dbus/README.md @@ -6,3 +6,16 @@ Implements a dbus service provider for Gnome-based enviroment. ### Author - [icedman](https://codeberg.org/icedman) + +### DBus Methods +- GetWindows() -> windows +- FocusWindow(window) + +### Signals +- WindowOpen -> window +- WindowFocused -> window +- WindowClosed -> window + +### Properties +- Count (number of active windows) + -- 2.47.1 From 421fef1f0d1c583e92bb73b41b75397d9ae89e93 Mon Sep 17 00:00:00 2001 From: icedman Date: Tue, 31 Dec 2024 10:35:30 +0800 Subject: [PATCH 4/4] add closeWindow and quitApp --- dwl.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/dwl.c b/dwl.c index 46d25cb..c4a07d0 100644 --- a/dwl.c +++ b/dwl.c @@ -269,6 +269,14 @@ const gchar *introspection_xml = " " " " " " + " " + " " + " " + " " + " " + " " + " " + " " " " " " " " @@ -3300,6 +3308,38 @@ static void dbus_handle_method_call(GDBusConnection *connection, const gchar *se g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", window)); g_free(window); + } else if (g_strcmp0(method_name, "CloseWindow") == 0) { + const gchar *window; + g_variant_get(parameters, "(s)", &window); + + uintptr_t address = strtol(window, NULL, 16); // Base 16 for hexadecimal + Client *c = NULL; + wl_list_for_each(c, &clients, link) { + if ((uintptr_t)c == address) { + client_send_close(c); + } + } + + // g_print("focus %s\n", window); + g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", window)); + g_free(window); + + } else if (g_strcmp0(method_name, "QuitApp") == 0) { + const gchar *appid; + g_variant_get(parameters, "(s)", &appid); + + Client *c = NULL; + wl_list_for_each(c, &clients, link) { + const char *c_appid = client_get_appid(c); + g_print("[%s] [%s]", appid, c_appid); + if (g_strcmp0(appid, c_appid) == 0) { + client_send_close(c); + } + } + + g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", appid)); + g_free(appid); + } else { g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, -- 2.47.1