diff options
| author | Hannes Schulze <contact@haschu.me> | 2026-04-26 01:22:34 +0200 |
|---|---|---|
| committer | Hannes Schulze <contact@haschu.me> | 2026-04-26 01:22:34 +0200 |
| commit | 00be66dad9d27fb9f271e7a645ef90a343753819 (patch) | |
| tree | 2d23b0598c3aa580b31bbf19b953a6e3c4d8aa83 /src/services/workspaces/sway-workspace-service.c | |
| parent | e80a97f5603658af3a444a3a8213024c0c9d36d6 (diff) | |
sway workspace service skeleton
Diffstat (limited to 'src/services/workspaces/sway-workspace-service.c')
| -rw-r--r-- | src/services/workspaces/sway-workspace-service.c | 450 |
1 files changed, 450 insertions, 0 deletions
diff --git a/src/services/workspaces/sway-workspace-service.c b/src/services/workspaces/sway-workspace-service.c new file mode 100644 index 0000000..5ab9cc4 --- /dev/null +++ b/src/services/workspaces/sway-workspace-service.c @@ -0,0 +1,450 @@ +#include "services/workspaces/sway-workspace-service.h" +#include <json-glib/json-glib.h> +#include <gtk/gtk.h> + +// +// FoobarSwayWorkspace: +// +// Representation of a workspace in Sway. +// + +#define FOOBAR_TYPE_SWAY_WORKSPACE foobar_sway_workspace_get_type( ) + +G_DECLARE_FINAL_TYPE( FoobarSwayWorkspace, foobar_sway_workspace, FOOBAR, SWAY_WORKSPACE, GObject ) + +struct _FoobarSwayWorkspace +{ + GObject parent_instance; + FoobarSwayWorkspaceService* service; + gint64 id; + gchar* name; + gchar* monitor; + FoobarWorkspaceFlags flags; +}; + +enum +{ + WORKSPACE_PROP_ID = 1, + WORKSPACE_PROP_NAME, + WORKSPACE_PROP_MONITOR, + WORKSPACE_PROP_FLAGS, + N_WORKSPACE_PROPS, +}; + +static void foobar_sway_workspace_class_init ( FoobarSwayWorkspaceClass* klass ); +static void foobar_sway_workspace_interface_init( FoobarWorkspaceInterface* iface ); +static void foobar_sway_workspace_init ( FoobarSwayWorkspace* self ); +static void foobar_sway_workspace_get_property ( GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec ); +static void foobar_sway_workspace_finalize ( GObject* object ); +static FoobarSwayWorkspace* foobar_sway_workspace_new ( FoobarSwayWorkspaceService* service ); +static gint64 foobar_sway_workspace_get_id ( FoobarWorkspace* self ); +static gchar const* foobar_sway_workspace_get_name ( FoobarWorkspace* workspace ); +static gchar const* foobar_sway_workspace_get_monitor ( FoobarWorkspace* workspace ); +static FoobarWorkspaceFlags foobar_sway_workspace_get_flags ( FoobarWorkspace* workspace ); +static void foobar_sway_workspace_activate ( FoobarWorkspace* workspace ); +static void foobar_sway_workspace_set_id ( FoobarSwayWorkspace* self, + gint64 value ); +static void foobar_sway_workspace_set_name ( FoobarSwayWorkspace* self, + gchar const* value ); +static void foobar_sway_workspace_set_monitor ( FoobarSwayWorkspace* self, + gchar const* value ); +static void foobar_sway_workspace_set_flags ( FoobarSwayWorkspace* self, + FoobarWorkspaceFlags value ); + +G_DEFINE_TYPE_WITH_CODE( + FoobarSwayWorkspace, foobar_sway_workspace, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE( FOOBAR_TYPE_WORKSPACE, foobar_sway_workspace_interface_init ) ); + +// +// FoobarSwayWorkspaceService: +// +// Service monitoring the workspaces provided by the window manager. This is implemented by communicating directly with +// Sway through its IPC socket. +// + +struct _FoobarSwayWorkspaceService +{ + GObject parent_instance; + GListStore* workspaces; + GtkSortListModel* sorted_workspaces; + gchar* socket_path; +}; + +enum +{ + PROP_WORKSPACES = 1, + N_PROPS, +}; + +static void foobar_sway_workspace_service_class_init ( FoobarSwayWorkspaceServiceClass* klass ); +static void foobar_sway_workspace_service_interface_init ( FoobarWorkspaceServiceInterface* iface ); +static void foobar_sway_workspace_service_init ( FoobarSwayWorkspaceService* self ); +static void foobar_sway_workspace_service_get_property ( GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec ); +static void foobar_sway_workspace_service_dispose ( GObject* object ); +static void foobar_sway_workspace_service_finalize ( GObject* object ); +static GListModel* foobar_sway_workspace_service_get_workspaces ( FoobarWorkspaceService* service ); +static gboolean foobar_sway_workspace_service_is_available ( FoobarWorkspaceService* service ); +static gchar* foobar_sway_workspace_service_get_socket_path( void ); + +G_DEFINE_TYPE_WITH_CODE( + FoobarSwayWorkspaceService, foobar_sway_workspace_service, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE( FOOBAR_TYPE_WORKSPACE_SERVICE, foobar_sway_workspace_service_interface_init ) ); + +// --------------------------------------------------------------------------------------------------------------------- +// Workspace +// --------------------------------------------------------------------------------------------------------------------- + +// +// Static initialization for workspaces. +// +void foobar_sway_workspace_class_init( FoobarSwayWorkspaceClass* klass ) +{ + GObjectClass* object_klass = G_OBJECT_CLASS( klass ); + object_klass->get_property = foobar_sway_workspace_get_property; + object_klass->finalize = foobar_sway_workspace_finalize; + + g_object_class_override_property( object_klass, WORKSPACE_PROP_ID, "id" ); + g_object_class_override_property( object_klass, WORKSPACE_PROP_NAME, "name" ); + g_object_class_override_property( object_klass, WORKSPACE_PROP_MONITOR, "monitor" ); + g_object_class_override_property( object_klass, WORKSPACE_PROP_FLAGS, "flags" ); +} + +// +// Interface initialization for workspaces. +// +void foobar_sway_workspace_interface_init( FoobarWorkspaceInterface* iface ) +{ + iface->get_id = foobar_sway_workspace_get_id; + iface->get_name = foobar_sway_workspace_get_name; + iface->get_monitor = foobar_sway_workspace_get_monitor; + iface->get_flags = foobar_sway_workspace_get_flags; + iface->activate = foobar_sway_workspace_activate; +} + +// +// Instance initialization for workspaces. +// +void foobar_sway_workspace_init( FoobarSwayWorkspace* self ) +{ + (void)self; +} + +// +// Property getter implementation, mapping a property id to a method. +// +void foobar_sway_workspace_get_property( + GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec ) +{ + FoobarSwayWorkspace* self = (FoobarSwayWorkspace*)object; + + switch ( prop_id ) + { + case WORKSPACE_PROP_ID: + g_value_set_int64( value, foobar_workspace_get_id( FOOBAR_WORKSPACE( self ) ) ); + break; + case WORKSPACE_PROP_NAME: + g_value_set_string( value, foobar_workspace_get_name( FOOBAR_WORKSPACE( self ) ) ); + break; + case WORKSPACE_PROP_MONITOR: + g_value_set_string( value, foobar_workspace_get_monitor( FOOBAR_WORKSPACE( self ) ) ); + break; + case WORKSPACE_PROP_FLAGS: + g_value_set_flags( value, foobar_workspace_get_flags( FOOBAR_WORKSPACE( self ) ) ); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); + break; + } +} + +// +// Instance cleanup for workspaces. +// +void foobar_sway_workspace_finalize( GObject* object ) +{ + FoobarSwayWorkspace* self = (FoobarSwayWorkspace*)object; + + g_clear_pointer( &self->name, g_free ); + g_clear_pointer( &self->monitor, g_free ); + + G_OBJECT_CLASS( foobar_sway_workspace_parent_class )->finalize( object ); +} + +// +// Create a new workspace that is owned by the given service (captured as an unowned reference). +// +FoobarSwayWorkspace* foobar_sway_workspace_new( FoobarSwayWorkspaceService* service ) +{ + FoobarSwayWorkspace* self = g_object_new( FOOBAR_TYPE_SWAY_WORKSPACE, NULL ); + self->service = service; + return self; +} + +// +// Numeric ID of the workspace. +// +gint64 foobar_sway_workspace_get_id( FoobarWorkspace* workspace ) +{ + FoobarSwayWorkspace* self = (FoobarSwayWorkspace*)workspace; + return self->id; +} + +// +// Optional human-readable workspace name. +// +gchar const* foobar_sway_workspace_get_name( FoobarWorkspace* workspace ) +{ + FoobarSwayWorkspace* self = (FoobarSwayWorkspace*)workspace; + return self->name; +} + +// +// Connector ID of the workspace's monitor. +// +gchar const* foobar_sway_workspace_get_monitor( FoobarWorkspace* workspace ) +{ + FoobarSwayWorkspace* self = (FoobarSwayWorkspace*)workspace; + return self->monitor; +} + +// +// Flags indicating the current state of the workspace. +// +FoobarWorkspaceFlags foobar_sway_workspace_get_flags( FoobarWorkspace* workspace ) +{ + FoobarSwayWorkspace* self = (FoobarSwayWorkspace*)workspace; + return self->flags; +} + +// +// Let this workspace become the active one. +// +void foobar_sway_workspace_activate( FoobarWorkspace* workspace ) +{ + FoobarSwayWorkspace* self = (FoobarSwayWorkspace*)workspace; + + if ( !self->service ) { return; } +} + +// +// Numeric ID of the workspace. +// +void foobar_sway_workspace_set_id( + FoobarSwayWorkspace* self, + gint64 value ) +{ + g_return_if_fail( FOOBAR_IS_SWAY_WORKSPACE( self ) ); + + if ( self->id != value ) + { + self->id = value; + g_object_notify( G_OBJECT( self ), "id" ); + } +} + +// +// Optional human-readable workspace name. +// +void foobar_sway_workspace_set_name( + FoobarSwayWorkspace* self, + gchar const* value ) +{ + g_return_if_fail( FOOBAR_IS_SWAY_WORKSPACE( self ) ); + + if ( g_strcmp0( self->name, value ) ) + { + g_clear_pointer( &self->name, g_free ); + self->name = g_strdup( value ); + g_object_notify( G_OBJECT( self ), "name" ); + } +} + +// +// Connector ID of the workspace's monitor. +// +void foobar_sway_workspace_set_monitor( + FoobarSwayWorkspace* self, + gchar const* value ) +{ + g_return_if_fail( FOOBAR_IS_SWAY_WORKSPACE( self ) ); + + if ( g_strcmp0( self->monitor, value ) ) + { + g_clear_pointer( &self->monitor, g_free ); + self->monitor = g_strdup( value ); + g_object_notify( G_OBJECT( self ), "monitor" ); + } +} + +// +// Flags indicating the current state of the workspace. +// +void foobar_sway_workspace_set_flags( + FoobarSwayWorkspace* self, + FoobarWorkspaceFlags value ) +{ + g_return_if_fail( FOOBAR_IS_SWAY_WORKSPACE( self ) ); + + if ( self->flags != value ) + { + self->flags = value; + g_object_notify( G_OBJECT( self ), "flags" ); + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// Service Implementation +// --------------------------------------------------------------------------------------------------------------------- + +// +// Static initialization for the workspace service. +// +void foobar_sway_workspace_service_class_init( FoobarSwayWorkspaceServiceClass* klass ) +{ + GObjectClass* object_klass = G_OBJECT_CLASS( klass ); + object_klass->get_property = foobar_sway_workspace_service_get_property; + object_klass->dispose = foobar_sway_workspace_service_dispose; + object_klass->finalize = foobar_sway_workspace_service_finalize; + + g_object_class_override_property( object_klass, PROP_WORKSPACES, "workspaces" ); +} + +// +// Interface initialization for the workspace service. +// +void foobar_sway_workspace_service_interface_init( FoobarWorkspaceServiceInterface* iface ) +{ + iface->get_workspaces = foobar_sway_workspace_service_get_workspaces; + iface->is_available = foobar_sway_workspace_service_is_available; +} + +// +// Instance initialization for the workspace service. +// +void foobar_sway_workspace_service_init( FoobarSwayWorkspaceService* self ) +{ + self->workspaces = g_list_store_new( FOOBAR_TYPE_WORKSPACE ); + + GtkCustomSorter* sorter = gtk_custom_sorter_new( foobar_workspace_sort_func, NULL, NULL ); + self->sorted_workspaces = gtk_sort_list_model_new( + G_LIST_MODEL( g_object_ref( self->workspaces ) ), + GTK_SORTER( sorter ) ); + + self->socket_path = foobar_sway_workspace_service_get_socket_path( ); + if ( !self->socket_path ) + { + return; + } + + (void)foobar_sway_workspace_set_id; + (void)foobar_sway_workspace_set_name; + (void)foobar_sway_workspace_set_monitor; + (void)foobar_sway_workspace_set_flags; + (void)foobar_sway_workspace_new; +} + +// +// Property getter implementation, mapping a property id to a method. +// +void foobar_sway_workspace_service_get_property( GObject* object, guint prop_id, GValue* value, GParamSpec* pspec ) +{ + FoobarSwayWorkspaceService* self = (FoobarSwayWorkspaceService*)object; + + switch ( prop_id ) + { + case PROP_WORKSPACES: + g_value_set_object( value, foobar_workspace_service_get_workspaces( FOOBAR_WORKSPACE_SERVICE( self ) ) ); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); + break; + } +} + +// +// Instance de-initialization for the workspace service. +// +// This is where the event thread is joined because it might still create new object references which is a bad thing to +// do in finalize. +// +void foobar_sway_workspace_service_dispose( GObject* object ) +{ + FoobarSwayWorkspaceService* self = (FoobarSwayWorkspaceService*)object; + + (void)self; + + G_OBJECT_CLASS( foobar_sway_workspace_service_parent_class )->dispose( object ); +} + +// +// Instance cleanup for the workspace service. +// +void foobar_sway_workspace_service_finalize( GObject* object ) +{ + FoobarSwayWorkspaceService* self = (FoobarSwayWorkspaceService*)object; + + for ( guint i = 0; i < g_list_model_get_n_items( G_LIST_MODEL( self->workspaces ) ); ++i ) + { + FoobarSwayWorkspace* workspace = g_list_model_get_item( G_LIST_MODEL( self->workspaces ), i ); + workspace->service = NULL; + } + // g_clear_object( &self->event_cancellable ); + g_clear_object( &self->sorted_workspaces ); + g_clear_object( &self->workspaces ); + g_clear_pointer( &self->socket_path, g_free ); + + G_OBJECT_CLASS( foobar_sway_workspace_service_parent_class )->finalize( object ); +} + +// +// Get a sorted list of all workspaces. +// +GListModel* foobar_sway_workspace_service_get_workspaces( FoobarWorkspaceService* service ) +{ + FoobarSwayWorkspaceService* self = (FoobarSwayWorkspaceService*)service; + return G_LIST_MODEL( self->sorted_workspaces ); +} + +// +// Check whether this service is connected to Sway. +// +gboolean foobar_sway_workspace_service_is_available( FoobarWorkspaceService* service ) +{ + FoobarSwayWorkspaceService* self = (FoobarSwayWorkspaceService*)service; + return self->socket_path != NULL; +} + +// --------------------------------------------------------------------------------------------------------------------- +// Public API +// --------------------------------------------------------------------------------------------------------------------- + +// +// Create a new Sway workspace service instance. +// +FoobarWorkspaceService* foobar_sway_workspace_service_new( void ) +{ + return g_object_new( FOOBAR_TYPE_SWAY_WORKSPACE_SERVICE, NULL ); +} + +// +// Get the sway socket path. +// +gchar* foobar_sway_workspace_service_get_socket_path( void ) +{ + gchar const* sock = g_getenv( "SWAYSOCK" ); + if ( !sock ) + { + return NULL; + } + + return g_strdup( sock ); +} |
