From 1124835f97212277f72e87e0b784f7dbce4a059e Mon Sep 17 00:00:00 2001 From: icedman Date: Tue, 31 Dec 2024 10:44:56 +0800 Subject: [PATCH] add dbus patch --- patches/dbus/README.md | 23 + patches/dbus/dbus.patch | 903 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 926 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..1ce175e --- /dev/null +++ b/patches/dbus/README.md @@ -0,0 +1,23 @@ +### 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) + +### DBus Methods +- GetWindows() -> windows +- FocusWindow(window) +- CloseWindow(window) +- QuitApp(appid) + +### Signals +- WindowOpen -> window +- WindowFocused -> window +- WindowClosed -> window + +### Properties +- Count (number of active windows) + diff --git a/patches/dbus/dbus.patch b/patches/dbus/dbus.patch new file mode 100644 index 0000000..23f041d --- /dev/null +++ b/patches/dbus/dbus.patch @@ -0,0 +1,903 @@ +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 +