summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/application.c6
-rw-r--r--src/services/workspace-service.c51
-rw-r--r--src/services/workspace-service.h3
-rw-r--r--src/services/workspaces/hyprland-workspace-service.c58
-rw-r--r--src/services/workspaces/meson.build1
-rw-r--r--src/services/workspaces/sway-workspace-service.c450
-rw-r--r--src/services/workspaces/sway-workspace-service.h13
7 files changed, 524 insertions, 58 deletions
diff --git a/src/application.c b/src/application.c
index cb05f65..8a4d41c 100644
--- a/src/application.c
+++ b/src/application.c
@@ -1,5 +1,4 @@
#include "application.h"
-#include "glib-object.h"
#include "panel.h"
#include "launcher.h"
#include "control-center.h"
@@ -11,6 +10,7 @@
#include "services/quick-answer-service.h"
#include "services/workspace-service.h"
#include "services/workspaces/hyprland-workspace-service.h"
+#include "services/workspaces/sway-workspace-service.h"
#include "services/notification-service.h"
#include "services/audio-service.h"
#include "services/network-service.h"
@@ -702,5 +702,9 @@ void foobar_application_initialize_workspaces( FoobarApplication* self )
self->workspace_service = foobar_hyprland_workspace_service_new( );
if ( foobar_workspace_service_is_available( self->workspace_service ) ) { return; }
+ g_clear_object( &self->workspace_service );
+ self->workspace_service = foobar_sway_workspace_service_new( );
+ if ( foobar_workspace_service_is_available( self->workspace_service ) ) { return; }
+
g_warning( "No suitable workspace manager implementation found." );
}
diff --git a/src/services/workspace-service.c b/src/services/workspace-service.c
index f9a6ecd..26779c0 100644
--- a/src/services/workspace-service.c
+++ b/src/services/workspace-service.c
@@ -140,6 +140,57 @@ void foobar_workspace_activate( FoobarWorkspace* self )
FOOBAR_WORKSPACE_GET_IFACE( self )->activate( self );
}
+//
+// Sorting callback for workspaces. Items are sorted to be in the following order:
+// 1. normal
+// 2. named persistent
+// 3. named
+// 4. special
+// 5. named special
+//
+gint foobar_workspace_sort_func(
+ gconstpointer item_a,
+ gconstpointer item_b,
+ gpointer userdata )
+{
+ (void)userdata;
+
+ FoobarWorkspace* workspace_a = (FoobarWorkspace*)item_a;
+ FoobarWorkspace* workspace_b = (FoobarWorkspace*)item_b;
+ gint64 id_a = foobar_workspace_get_id( workspace_a );
+ gint64 id_b = foobar_workspace_get_id( workspace_b );
+ gboolean special_a = ( foobar_workspace_get_flags( workspace_a ) & FOOBAR_WORKSPACE_FLAGS_SPECIAL ) != 0;
+ gboolean special_b = ( foobar_workspace_get_flags( workspace_b ) & FOOBAR_WORKSPACE_FLAGS_SPECIAL ) != 0;
+ gboolean named_a = id_a < 0;
+ gboolean named_b = id_b < 0;
+
+ // both normal (includes numbered persistent) => sort by ID
+ if ( !named_a && !named_b )
+ {
+ if ( id_a < id_b ) { return -1; }
+ if ( id_a > id_b ) { return 1; }
+ return 0;
+ }
+
+ // one normal, one special => normal first
+ if ( special_a && !special_b ) { return 1; }
+ if ( !special_a && special_b ) { return -1; }
+
+ // only one normal, one named
+ if ( named_a && !named_b ) { return -1; }
+ if ( !named_a && named_b ) { return 1; }
+
+ // both special
+ if ( special_a && special_b )
+ {
+ // if one is -99 => put it last
+ if ( id_a == -99 && id_b != -99 ) { return 1; }
+ if ( id_a != -99 && id_b == -99 ) { return -1; }
+ }
+
+ return g_strcmp0( foobar_workspace_get_name( workspace_a ), foobar_workspace_get_name( workspace_b ) );
+}
+
// ---------------------------------------------------------------------------------------------------------------------
// Service Interface
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/services/workspace-service.h b/src/services/workspace-service.h
index 62259d7..e02bc22 100644
--- a/src/services/workspace-service.h
+++ b/src/services/workspace-service.h
@@ -44,6 +44,9 @@ gchar const* foobar_workspace_get_name ( FoobarWorkspace* self );
gchar const* foobar_workspace_get_monitor( FoobarWorkspace* self );
FoobarWorkspaceFlags foobar_workspace_get_flags ( FoobarWorkspace* self );
void foobar_workspace_activate ( FoobarWorkspace* self );
+gint foobar_workspace_sort_func ( gconstpointer item_a,
+ gconstpointer item_b,
+ gpointer userdata );
G_DECLARE_INTERFACE( FoobarWorkspaceService, foobar_workspace_service, FOOBAR, WORKSPACE_SERVICE, GObject )
diff --git a/src/services/workspaces/hyprland-workspace-service.c b/src/services/workspaces/hyprland-workspace-service.c
index 27a01b7..3abe152 100644
--- a/src/services/workspaces/hyprland-workspace-service.c
+++ b/src/services/workspaces/hyprland-workspace-service.c
@@ -1,6 +1,4 @@
#include "services/workspaces/hyprland-workspace-service.h"
-#include "glib-object.h"
-#include "services/workspace-service.h"
#include <json-glib/json-glib.h>
#include <gtk/gtk.h>
#include <string.h>
@@ -135,9 +133,6 @@ static gint64 foobar_hyprland_workspace_service_parse_id
static gchar* foobar_hyprland_workspace_service_get_hyprland_base_path ( void );
static gint foobar_hyprland_workspace_service_compare_ids ( gconstpointer a,
gconstpointer b );
-static gint foobar_hyprland_workspace_service_sort_func ( gconstpointer item_a,
- gconstpointer item_b,
- gpointer userdata );
G_DEFINE_TYPE_WITH_CODE(
@@ -457,7 +452,7 @@ void foobar_hyprland_workspace_service_init( FoobarHyprlandWorkspaceService* sel
{
self->workspaces = g_list_store_new( FOOBAR_TYPE_WORKSPACE );
- GtkCustomSorter* sorter = gtk_custom_sorter_new( foobar_hyprland_workspace_service_sort_func, NULL, NULL );
+ 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 ) );
@@ -1288,57 +1283,6 @@ gint foobar_hyprland_workspace_service_compare_ids(
}
//
-// Sorting callback for workspaces. Items are sorted to be in the following order:
-// 1. normal
-// 2. named persistent
-// 3. named
-// 4. special
-// 5. named special
-//
-gint foobar_hyprland_workspace_service_sort_func(
- gconstpointer item_a,
- gconstpointer item_b,
- gpointer userdata )
-{
- (void)userdata;
-
- FoobarWorkspace* workspace_a = (FoobarWorkspace*)item_a;
- FoobarWorkspace* workspace_b = (FoobarWorkspace*)item_b;
- gint64 id_a = foobar_workspace_get_id( workspace_a );
- gint64 id_b = foobar_workspace_get_id( workspace_b );
- gboolean special_a = ( foobar_workspace_get_flags( workspace_a ) & FOOBAR_WORKSPACE_FLAGS_SPECIAL ) != 0;
- gboolean special_b = ( foobar_workspace_get_flags( workspace_b ) & FOOBAR_WORKSPACE_FLAGS_SPECIAL ) != 0;
- gboolean named_a = id_a < 0;
- gboolean named_b = id_b < 0;
-
- // both normal (includes numbered persistent) => sort by ID
- if ( !named_a && !named_b )
- {
- if ( id_a < id_b ) { return -1; }
- if ( id_a > id_b ) { return 1; }
- return 0;
- }
-
- // one normal, one special => normal first
- if ( special_a && !special_b ) { return 1; }
- if ( !special_a && special_b ) { return -1; }
-
- // only one normal, one named
- if ( named_a && !named_b ) { return -1; }
- if ( !named_a && named_b ) { return 1; }
-
- // both special
- if ( special_a && special_b )
- {
- // if one is -99 => put it last
- if ( id_a == -99 && id_b != -99 ) { return 1; }
- if ( id_a != -99 && id_b == -99 ) { return -1; }
- }
-
- return g_strcmp0( foobar_workspace_get_name( workspace_a ), foobar_workspace_get_name( workspace_b ) );
-}
-
-//
// Create a new EventData structure.
//
static EventData* event_data_new(
diff --git a/src/services/workspaces/meson.build b/src/services/workspaces/meson.build
index 7de31dd..5c96af4 100644
--- a/src/services/workspaces/meson.build
+++ b/src/services/workspaces/meson.build
@@ -1,3 +1,4 @@
foobar_sources += files(
'hyprland-workspace-service.c',
+ 'sway-workspace-service.c',
)
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 );
+}
diff --git a/src/services/workspaces/sway-workspace-service.h b/src/services/workspaces/sway-workspace-service.h
new file mode 100644
index 0000000..8d078eb
--- /dev/null
+++ b/src/services/workspaces/sway-workspace-service.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "services/workspace-service.h"
+
+G_BEGIN_DECLS
+
+#define FOOBAR_TYPE_SWAY_WORKSPACE_SERVICE foobar_sway_workspace_service_get_type( )
+
+G_DECLARE_FINAL_TYPE( FoobarSwayWorkspaceService, foobar_sway_workspace_service, FOOBAR, SWAY_WORKSPACE_SERVICE, GObject )
+
+FoobarWorkspaceService* foobar_sway_workspace_service_new( void );
+
+G_END_DECLS