diff options
Diffstat (limited to 'src/services')
| -rw-r--r-- | src/services/workspace-service.c | 51 | ||||
| -rw-r--r-- | src/services/workspace-service.h | 3 | ||||
| -rw-r--r-- | src/services/workspaces/hyprland-workspace-service.c | 56 | ||||
| -rw-r--r-- | src/services/workspaces/sway-workspace-service.c | 402 |
4 files changed, 425 insertions, 87 deletions
diff --git a/src/services/workspace-service.c b/src/services/workspace-service.c index 26779c0..f9a6ecd 100644 --- a/src/services/workspace-service.c +++ b/src/services/workspace-service.c @@ -140,57 +140,6 @@ 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 e02bc22..62259d7 100644 --- a/src/services/workspace-service.h +++ b/src/services/workspace-service.h @@ -44,9 +44,6 @@ 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 3abe152..9a64c49 100644 --- a/src/services/workspaces/hyprland-workspace-service.c +++ b/src/services/workspaces/hyprland-workspace-service.c @@ -133,6 +133,9 @@ 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( @@ -452,7 +455,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_workspace_sort_func, NULL, NULL ); + GtkCustomSorter* sorter = gtk_custom_sorter_new( foobar_hyprland_workspace_service_sort_func, NULL, NULL ); self->sorted_workspaces = gtk_sort_list_model_new( G_LIST_MODEL( g_object_ref( self->workspaces ) ), GTK_SORTER( sorter ) ); @@ -1283,6 +1286,57 @@ 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/sway-workspace-service.c b/src/services/workspaces/sway-workspace-service.c index 5ab9cc4..ebb0167 100644 --- a/src/services/workspaces/sway-workspace-service.c +++ b/src/services/workspaces/sway-workspace-service.c @@ -1,6 +1,20 @@ #include "services/workspaces/sway-workspace-service.h" +#include "gio/gio.h" +#include "glib-object.h" +#include "glib.h" +#include "services/workspace-service.h" #include <json-glib/json-glib.h> #include <gtk/gtk.h> +#include <stdio.h> +#include <string.h> + +static const gchar MAGIC_STRING[] = "i3-ipc"; + +#define MESSAGE_TYPE_COMMAND 0 +#define MESSAGE_TYPE_WORKSPACES 1 + +typedef struct _MessageHeader MessageHeader; +typedef enum _FoobarSwayError FoobarSwayError; // // FoobarSwayWorkspace: @@ -17,6 +31,7 @@ struct _FoobarSwayWorkspace GObject parent_instance; FoobarSwayWorkspaceService* service; gint64 id; + gint64 num; gchar* name; gchar* monitor; FoobarWorkspaceFlags flags; @@ -32,27 +47,30 @@ enum }; static void foobar_sway_workspace_class_init ( FoobarSwayWorkspaceClass* klass ); -static void foobar_sway_workspace_interface_init( FoobarWorkspaceInterface* iface ); +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 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 gint64 foobar_sway_workspace_get_id ( FoobarWorkspace* self ); +static gint64 foobar_sway_workspace_get_num ( FoobarSwayWorkspace* 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 ); + gint64 value ); +static void foobar_sway_workspace_set_num ( FoobarSwayWorkspace* self, + gint64 value ); static void foobar_sway_workspace_set_name ( FoobarSwayWorkspace* self, - gchar const* value ); + gchar const* value ); static void foobar_sway_workspace_set_monitor ( FoobarSwayWorkspace* self, - gchar const* value ); + gchar const* value ); static void foobar_sway_workspace_set_flags ( FoobarSwayWorkspace* self, - FoobarWorkspaceFlags value ); + FoobarWorkspaceFlags value ); G_DEFINE_TYPE_WITH_CODE( FoobarSwayWorkspace, foobar_sway_workspace, G_TYPE_OBJECT, @@ -79,23 +97,68 @@ enum 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 ); +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 void foobar_sway_workspace_service_initialize ( FoobarSwayWorkspaceService* self ); +static JsonNode* foobar_sway_workspace_service_send_request ( FoobarSwayWorkspaceService* self, + guint type, + gchar const* payload, + GError** error ); +static gboolean foobar_sway_workspace_service_write ( GSocket* socket, + guint32 type, + gchar const* payload, + GCancellable* cancellable, + GError** out_error ); +static JsonNode* foobar_sway_workspace_service_read ( GSocket* socket, + guint32* out_type, + GCancellable* cancellable, + GError** out_error ); +static gchar* foobar_sway_workspace_service_get_socket_path ( void ); +static gint foobar_sway_workspace_service_sort_func ( gconstpointer item_a, + gconstpointer item_b, + gpointer userdata ); 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 ) ); +// +// MessageHeader: +// +// Header in an i3wm/sway protocol message. +// + +struct __attribute__((__packed__)) _MessageHeader +{ + gchar magic_string[sizeof(MAGIC_STRING) - 1]; + guint32 message_length; + guint32 message_type; +}; + +// +// FoobarSwayError: +// +// Custom error domain for sway-related errors. +// + +enum _FoobarSwayError +{ + FOOBAR_SWAY_ERROR_INVALID_MAGIC_STRING, + FOOBAR_SWAY_ERROR_MISMATCHING_TYPE, +}; + +G_DEFINE_QUARK( foobar-sway-error, foobar_sway_error ); +#define FOOBAR_SWAY_ERROR ( foobar_sway_error_quark( ) ) + // --------------------------------------------------------------------------------------------------------------------- // Workspace // --------------------------------------------------------------------------------------------------------------------- @@ -199,6 +262,15 @@ gint64 foobar_sway_workspace_get_id( FoobarWorkspace* workspace ) } // +// Logical number of the workspace. +// +gint64 foobar_sway_workspace_get_num( FoobarSwayWorkspace* self ) +{ + g_return_val_if_fail( FOOBAR_IS_SWAY_WORKSPACE( self ), -1 ); + return self->num; +} + +// // Optional human-readable workspace name. // gchar const* foobar_sway_workspace_get_name( FoobarWorkspace* workspace ) @@ -233,6 +305,34 @@ void foobar_sway_workspace_activate( FoobarWorkspace* workspace ) FoobarSwayWorkspace* self = (FoobarSwayWorkspace*)workspace; if ( !self->service ) { return; } + + gchar const* name = foobar_workspace_get_name( FOOBAR_WORKSPACE( self ) ); + g_autofree gchar* request = g_strdup_printf( "workspace --no-auto-back-and-forth \"%s\"", name ); + + g_autoptr( GError ) error = NULL; + g_autoptr( JsonNode ) response = foobar_sway_workspace_service_send_request( + self->service, + MESSAGE_TYPE_COMMAND, + request, + &error ); + + if ( !response ) + { + g_warning( "Unable to send workspace activation command: %s", error->message ); + return; + } + + JsonArray* array = json_node_get_array( response ); + for ( guint i = 0; i < json_array_get_length( array ); ++i ) + { + JsonObject* status_object = json_array_get_object_element( array, i ); + gboolean success = json_object_get_boolean_member( status_object, "success" ); + if ( !success ) + { + g_warning( "Could not activate workspace." ); + return; + } + } } // @@ -240,7 +340,7 @@ void foobar_sway_workspace_activate( FoobarWorkspace* workspace ) // void foobar_sway_workspace_set_id( FoobarSwayWorkspace* self, - gint64 value ) + gint64 value ) { g_return_if_fail( FOOBAR_IS_SWAY_WORKSPACE( self ) ); @@ -252,11 +352,22 @@ void foobar_sway_workspace_set_id( } // +// Logical number of the workspace. +// +void foobar_sway_workspace_set_num( + FoobarSwayWorkspace* self, + gint64 value ) +{ + g_return_if_fail( FOOBAR_IS_SWAY_WORKSPACE( self ) ); + self->num = value; +} + +// // Optional human-readable workspace name. // void foobar_sway_workspace_set_name( FoobarSwayWorkspace* self, - gchar const* value ) + gchar const* value ) { g_return_if_fail( FOOBAR_IS_SWAY_WORKSPACE( self ) ); @@ -273,7 +384,7 @@ void foobar_sway_workspace_set_name( // void foobar_sway_workspace_set_monitor( FoobarSwayWorkspace* self, - gchar const* value ) + gchar const* value ) { g_return_if_fail( FOOBAR_IS_SWAY_WORKSPACE( self ) ); @@ -290,7 +401,7 @@ void foobar_sway_workspace_set_monitor( // void foobar_sway_workspace_set_flags( FoobarSwayWorkspace* self, - FoobarWorkspaceFlags value ) + FoobarWorkspaceFlags value ) { g_return_if_fail( FOOBAR_IS_SWAY_WORKSPACE( self ) ); @@ -334,7 +445,7 @@ 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 ); + GtkCustomSorter* sorter = gtk_custom_sorter_new( foobar_sway_workspace_service_sort_func, NULL, NULL ); self->sorted_workspaces = gtk_sort_list_model_new( G_LIST_MODEL( g_object_ref( self->workspaces ) ), GTK_SORTER( sorter ) ); @@ -345,6 +456,8 @@ void foobar_sway_workspace_service_init( FoobarSwayWorkspaceService* self ) return; } + foobar_sway_workspace_service_initialize( self ); + (void)foobar_sway_workspace_set_id; (void)foobar_sway_workspace_set_name; (void)foobar_sway_workspace_set_monitor; @@ -435,6 +548,194 @@ FoobarWorkspaceService* foobar_sway_workspace_service_new( void ) return g_object_new( FOOBAR_TYPE_SWAY_WORKSPACE_SERVICE, NULL ); } +// --------------------------------------------------------------------------------------------------------------------- +// Helper Methods +// --------------------------------------------------------------------------------------------------------------------- + +// +// Refresh the list of workspaces by actively sending a request to Sway. +// +void foobar_sway_workspace_service_initialize( FoobarSwayWorkspaceService* self ) +{ + 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_list_store_remove_all( self->workspaces ); + g_autoptr( GListStore ) workspaces = g_list_store_new( FOOBAR_TYPE_WORKSPACE ); + + { + g_autoptr( GError ) error = NULL; + g_autoptr( JsonNode ) workspaces_node = foobar_sway_workspace_service_send_request( + self, + MESSAGE_TYPE_WORKSPACES, + "", + &error ); + if ( !workspaces_node ) + { + g_warning( "Unable to load workspaces: %s", error->message ); + return; + } + + JsonArray* workspaces_array = json_node_get_array( workspaces_node ); + for ( guint i = 0; i < json_array_get_length( workspaces_array ); ++i ) + { + JsonObject* workspace_object = json_array_get_object_element( workspaces_array, i ); + gchar const* name = json_object_get_string_member( workspace_object, "name" ); + gchar const* output = json_object_get_string_member( workspace_object, "output" ); + gint64 id = json_object_get_int_member( workspace_object, "id" ); + gint64 num = json_object_get_int_member( workspace_object, "num" ); + gboolean visible = json_object_get_boolean_member( workspace_object, "visible" ); + gboolean focused = json_object_get_boolean_member( workspace_object, "focused" ); + gboolean urgent = json_object_get_boolean_member( workspace_object, "urgent" ); + + FoobarWorkspaceFlags flags = FOOBAR_WORKSPACE_FLAGS_NONE; + flags = visible ? flags | FOOBAR_WORKSPACE_FLAGS_VISIBLE : flags; + flags = focused ? flags | FOOBAR_WORKSPACE_FLAGS_ACTIVE : flags; + flags = urgent ? flags | FOOBAR_WORKSPACE_FLAGS_URGENT : flags; + + g_autoptr(FoobarSwayWorkspace) workspace = foobar_sway_workspace_new( self ); + foobar_sway_workspace_set_id( workspace, id ); + foobar_sway_workspace_set_num( workspace, num ); + foobar_sway_workspace_set_name( workspace, name ); + foobar_sway_workspace_set_monitor( workspace, output ); + foobar_sway_workspace_set_flags( workspace, flags ); + + g_list_store_append( workspaces, workspace ); + } + } + + for ( guint i = 0; i < g_list_model_get_n_items( G_LIST_MODEL( workspaces ) ); ++i ) + { + FoobarWorkspace* workspace = g_list_model_get_item( G_LIST_MODEL( workspaces ), i ); + g_list_store_append( self->workspaces, workspace ); + } +} + +// +// Synchronously send a command to Sway, returning the entire response. +// +JsonNode* foobar_sway_workspace_service_send_request( + FoobarSwayWorkspaceService* self, + guint type, + gchar const* payload, + GError** error ) +{ + g_autoptr( GSocket ) sock = g_socket_new( + G_SOCKET_FAMILY_UNIX, + G_SOCKET_TYPE_STREAM, + G_SOCKET_PROTOCOL_DEFAULT, + error ); + if ( !sock ) { return NULL; } + + g_autoptr( GSocketAddress ) addr = g_unix_socket_address_new( self->socket_path ); + if ( !g_socket_connect( sock, addr, NULL, error ) ) { return NULL; } + + if ( !foobar_sway_workspace_service_write( sock, type, payload, NULL, error ) ) { return NULL; } + + guint reply_type; + JsonNode* reply = foobar_sway_workspace_service_read( sock, &reply_type, NULL, error ); + if ( !reply ) { return NULL; } + + if ( reply_type != type ) + { + g_set_error( + error, + FOOBAR_SWAY_ERROR, + FOOBAR_SWAY_ERROR_MISMATCHING_TYPE, + "Mismatching message type in reply: Sent %u, but received %u.", + type, + reply_type ); + json_node_unref( reply ); + return NULL; + } + + return reply; +} + +// +// Write a request onto a Sway socket. +// +gboolean foobar_sway_workspace_service_write( + GSocket* socket, + guint32 type, + gchar const* payload, + GCancellable* cancellable, + GError** out_error ) +{ + guint32 payload_length = strlen( payload ); + + MessageHeader header = { 0 }; + memcpy( header.magic_string, MAGIC_STRING, sizeof( header.magic_string ) ); + header.message_length = payload_length; + header.message_type = type; + + gsize buffer_length = sizeof( MessageHeader ) + payload_length; + g_autofree gchar* buffer = g_new0( gchar, buffer_length ); + memcpy( buffer + 0, &header, sizeof( MessageHeader ) ); + memcpy( buffer + sizeof( MessageHeader ), payload, payload_length ); + + return g_socket_send( socket, buffer, buffer_length, cancellable, out_error ) != -1; +} + +// +// Read a response or event from a Sway socket. +// +JsonNode* foobar_sway_workspace_service_read( + GSocket* socket, + guint32* out_type, + GCancellable* cancellable, + GError** out_error ) +{ + gchar header_buffer[ sizeof( MessageHeader ) ]; + gsize header_received = 0; + while ( header_received < sizeof( header_buffer ) ) + { + gssize received = g_socket_receive( + socket, + &header_buffer[ header_received ], + sizeof( header_buffer ) - header_received, + cancellable, + out_error ); + if ( received < 0 ) { return NULL; } + header_received += received; + } + + MessageHeader header = { 0 }; + memcpy( &header, header_buffer, sizeof( MessageHeader ) ); + + if ( memcmp( header.magic_string, MAGIC_STRING, sizeof( header.magic_string ) ) != 0 ) + { + g_set_error( + out_error, + FOOBAR_SWAY_ERROR, + FOOBAR_SWAY_ERROR_INVALID_MAGIC_STRING, + "Received invalid magic string from Sway." ); + return NULL; + } + + g_autofree gchar* buffer = g_new0( gchar, header.message_length + 1 ); + gsize buffer_received = 0; + while ( buffer_received < header.message_length ) + { + gssize received = g_socket_receive( + socket, + &buffer[ buffer_received ], + header.message_length - buffer_received, + cancellable, + out_error ); + if ( received < 0 ) { return NULL; } + buffer_received += received; + } + + g_autoptr( JsonParser ) parser = json_parser_new( ); + if ( !json_parser_load_from_data( parser, buffer, (gssize)header.message_length, out_error ) ) { return NULL; } + + if ( out_type ) { *out_type = header.message_type; } + return json_parser_steal_root( parser ); +} + // // Get the sway socket path. // @@ -448,3 +749,40 @@ gchar* foobar_sway_workspace_service_get_socket_path( void ) return g_strdup( sock ); } + +// +// Sorting callback for workspaces. Items are sorted to be in the following order: +// 1. named +// 2. numbered +// +gint foobar_sway_workspace_service_sort_func( + gconstpointer item_a, + gconstpointer item_b, + gpointer userdata ) +{ + (void)userdata; + + FoobarSwayWorkspace* workspace_a = (FoobarSwayWorkspace*)item_a; + FoobarSwayWorkspace* workspace_b = (FoobarSwayWorkspace*)item_b; + gint64 num_a = foobar_sway_workspace_get_num( workspace_a ); + gint64 num_b = foobar_sway_workspace_get_num( workspace_b ); + gboolean named_a = num_a < 0; + gboolean named_b = num_b < 0; + gchar const* name_a = foobar_workspace_get_name( FOOBAR_WORKSPACE( workspace_a ) ); + gchar const* name_b = foobar_workspace_get_name( FOOBAR_WORKSPACE( workspace_b ) ); + + // both numbered => sort by number + if ( !named_a && !named_b ) + { + if ( num_a < num_b ) { return -1; } + if ( num_a > num_b ) { return 1; } + return 0; + } + + // one numbered, one named + if ( named_a && !named_b ) { return -1; } + if ( !named_a && named_b ) { return 1; } + + // both named + return g_strcmp0( name_a, name_b ); +} |
