diff options
| author | Hannes Schulze <haschu0103@outlook.de> | 2024-07-01 17:00:08 +0200 |
|---|---|---|
| committer | Hannes Schulze <haschu0103@outlook.de> | 2024-07-01 17:00:08 +0200 |
| commit | 16483d65744488146e96d149b41f5869a2597a4c (patch) | |
| tree | 4e1c5a9d00deababc675a94064010d3d23bc5996 | |
| parent | f82081215e1f29140ab9c70e897ac62e9b456919 (diff) | |
add quick answers
| -rw-r--r-- | flake.lock | 6 | ||||
| -rw-r--r-- | flake.nix | 1 | ||||
| -rw-r--r-- | res/icons/fluent-calculator-symbolic.svg | 3 | ||||
| -rw-r--r-- | res/icons/icons.gresource.xml | 1 | ||||
| -rw-r--r-- | src/application.c | 5 | ||||
| -rw-r--r-- | src/launcher-item.c | 73 | ||||
| -rw-r--r-- | src/launcher-item.h | 28 | ||||
| -rw-r--r-- | src/launcher.c | 83 | ||||
| -rw-r--r-- | src/launcher.h | 2 | ||||
| -rw-r--r-- | src/meson.build | 1 | ||||
| -rw-r--r-- | src/services/application-service.c | 211 | ||||
| -rw-r--r-- | src/services/application-service.h | 4 | ||||
| -rw-r--r-- | src/services/meson.build | 1 | ||||
| -rw-r--r-- | src/services/quick-answer-service.c | 317 | ||||
| -rw-r--r-- | src/services/quick-answer-service.h | 21 |
15 files changed, 624 insertions, 133 deletions
@@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1714906307, - "narHash": "sha256-UlRZtrCnhPFSJlDQE7M0eyhgvuuHBTe1eJ9N9AQlJQ0=", + "lastModified": 1719506693, + "narHash": "sha256-C8e9S7RzshSdHB7L+v9I51af1gDM5unhJ2xO1ywxNH8=", "owner": "nixos", "repo": "nixpkgs", - "rev": "25865a40d14b3f9cf19f19b924e2ab4069b09588", + "rev": "b2852eb9365c6de48ffb0dc2c9562591f652242a", "type": "github" }, "original": { @@ -30,6 +30,7 @@ pkgs.clang-tools ]; inputsFrom = [ foobar ]; + hardeningDisable = [ "fortify" ]; }; }; }); diff --git a/res/icons/fluent-calculator-symbolic.svg b/res/icons/fluent-calculator-symbolic.svg new file mode 100644 index 0000000..21b9799 --- /dev/null +++ b/res/icons/fluent-calculator-symbolic.svg @@ -0,0 +1,3 @@ +<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M7 7C7 5.89543 7.89543 5 9 5H15C16.1046 5 17 5.89543 17 7V8C17 9.10457 16.1046 10 15 10H9C7.89543 10 7 9.10457 7 8V7ZM9 6.5C8.72386 6.5 8.5 6.72386 8.5 7V8C8.5 8.27614 8.72386 8.5 9 8.5H15C15.2761 8.5 15.5 8.27614 15.5 8V7C15.5 6.72386 15.2761 6.5 15 6.5H9ZM8.25 14.5C8.94036 14.5 9.5 13.9404 9.5 13.25C9.5 12.5596 8.94036 12 8.25 12C7.55964 12 7 12.5596 7 13.25C7 13.9404 7.55964 14.5 8.25 14.5ZM9.5 17.25C9.5 17.9404 8.94036 18.5 8.25 18.5C7.55964 18.5 7 17.9404 7 17.25C7 16.5596 7.55964 16 8.25 16C8.94036 16 9.5 16.5596 9.5 17.25ZM15.75 14.5C16.4404 14.5 17 13.9404 17 13.25C17 12.5596 16.4404 12 15.75 12C15.0596 12 14.5 12.5596 14.5 13.25C14.5 13.9404 15.0596 14.5 15.75 14.5ZM17 17.25C17 17.9404 16.4404 18.5 15.75 18.5C15.0596 18.5 14.5 17.9404 14.5 17.25C14.5 16.5596 15.0596 16 15.75 16C16.4404 16 17 16.5596 17 17.25ZM12 14.5C12.6904 14.5 13.25 13.9404 13.25 13.25C13.25 12.5596 12.6904 12 12 12C11.3096 12 10.75 12.5596 10.75 13.25C10.75 13.9404 11.3096 14.5 12 14.5ZM13.25 17.25C13.25 17.9404 12.6904 18.5 12 18.5C11.3096 18.5 10.75 17.9404 10.75 17.25C10.75 16.5596 11.3096 16 12 16C12.6904 16 13.25 16.5596 13.25 17.25ZM7.25 2C5.45507 2 4 3.45507 4 5.25V18.75C4 20.5449 5.45507 22 7.25 22H16.75C18.5449 22 20 20.5449 20 18.75V5.25C20 3.45507 18.5449 2 16.75 2H7.25ZM5.5 5.25C5.5 4.2835 6.2835 3.5 7.25 3.5H16.75C17.7165 3.5 18.5 4.2835 18.5 5.25V18.75C18.5 19.7165 17.7165 20.5 16.75 20.5H7.25C6.2835 20.5 5.5 19.7165 5.5 18.75V5.25Z" fill="#212121"/> +</svg> diff --git a/res/icons/icons.gresource.xml b/res/icons/icons.gresource.xml index 29cab10..a5061ca 100644 --- a/res/icons/icons.gresource.xml +++ b/res/icons/icons.gresource.xml @@ -48,5 +48,6 @@ <file compressed="true">fluent-chevron-right-symbolic.svg</file> <file compressed="true">fluent-checkmark-symbolic.svg</file> <file compressed="true">fluent-microphone-symbolic.svg</file> + <file compressed="true">fluent-calculator-symbolic.svg</file> </gresource> </gresources> diff --git a/src/application.c b/src/application.c index a32e1ce..bad62b1 100644 --- a/src/application.c +++ b/src/application.c @@ -7,6 +7,7 @@ #include "services/battery-service.h" #include "services/clock-service.h" #include "services/brightness-service.h" +#include "services/quick-answer-service.h" #include "services/workspace-service.h" #include "services/notification-service.h" #include "services/audio-service.h" @@ -38,6 +39,7 @@ struct _FoobarApplication FoobarNetworkService* network_service; FoobarBluetoothService* bluetooth_service; FoobarApplicationService* application_service; + FoobarQuickAnswerService* quick_answer_service; FoobarConfigurationService* configuration_service; gulong config_handler_id; FoobarServer* server_skeleton; @@ -180,6 +182,7 @@ void foobar_application_activate( GApplication* app ) self->network_service = foobar_network_service_new( ); self->bluetooth_service = foobar_bluetooth_service_new( ); self->application_service = foobar_application_service_new( ); + self->quick_answer_service = foobar_quick_answer_service_new( ); self->configuration_service = foobar_configuration_service_new( ); // Enforce a uniform style by forcing Adwaita and shipping our own icons. @@ -231,6 +234,7 @@ void foobar_application_activate( GApplication* app ) self->launcher = foobar_launcher_new( self->application_service, + self->quick_answer_service, self->configuration_service ); g_object_ref( self->launcher ); @@ -358,6 +362,7 @@ void foobar_application_finalize( GObject* object ) g_clear_object( &self->network_service ); g_clear_object( &self->bluetooth_service ); g_clear_object( &self->application_service ); + g_clear_object( &self->quick_answer_service ); g_clear_object( &self->configuration_service ); g_clear_object( &self->style_provider ); g_clear_object( &self->server_skeleton ); diff --git a/src/launcher-item.c b/src/launcher-item.c new file mode 100644 index 0000000..c4de70b --- /dev/null +++ b/src/launcher-item.c @@ -0,0 +1,73 @@ +#include "launcher-item.h" + +static void foobar_launcher_item_default_init( FoobarLauncherItemInterface* iface ); + +G_DEFINE_INTERFACE( FoobarLauncherItem, foobar_launcher_item, G_TYPE_OBJECT ) + +// +// Static initialization for the launcher item interface. +// +void foobar_launcher_item_default_init( FoobarLauncherItemInterface* iface ) +{ + g_object_interface_install_property( iface, g_param_spec_string( + "title", + "Title", + "The title text displayed in the launcher.", + NULL, + G_PARAM_READABLE ) ); + g_object_interface_install_property( iface, g_param_spec_string( + "description", + "Description", + "Text displayed below the title.", + NULL, + G_PARAM_READABLE ) ); + g_object_interface_install_property( iface, g_param_spec_object( + "icon", + "Icon", + "Icon to show for the item.", + G_TYPE_ICON, + G_PARAM_READABLE ) ); +} + +// +// Get the title text displayed in the launcher. +// +gchar const* foobar_launcher_item_get_title( FoobarLauncherItem* self ) +{ + g_return_val_if_fail( FOOBAR_IS_LAUNCHER_ITEM( self ), NULL ); + FoobarLauncherItemInterface* iface = FOOBAR_LAUNCHER_ITEM_GET_IFACE( self ); + g_return_val_if_fail( iface->get_title != NULL, NULL ); + return iface->get_title( self ); +} + +// +// Get the text displayed below the title. +// +gchar const* foobar_launcher_item_get_description( FoobarLauncherItem* self ) +{ + g_return_val_if_fail( FOOBAR_IS_LAUNCHER_ITEM( self ), NULL ); + FoobarLauncherItemInterface* iface = FOOBAR_LAUNCHER_ITEM_GET_IFACE( self ); + g_return_val_if_fail( iface->get_description != NULL, NULL ); + return iface->get_description( self ); +} + +// +// Get the icon to show for the item. +// +GIcon* foobar_launcher_item_get_icon( FoobarLauncherItem* self ) +{ + g_return_val_if_fail( FOOBAR_IS_LAUNCHER_ITEM( self ), NULL ); + FoobarLauncherItemInterface* iface = FOOBAR_LAUNCHER_ITEM_GET_IFACE( self ); + g_return_val_if_fail( iface->get_icon != NULL, NULL ); + return iface->get_icon( self ); +} + +// +// Activate the item, e.g. by launching the application. +// +void foobar_launcher_item_activate( FoobarLauncherItem* self ) +{ + g_return_if_fail( FOOBAR_IS_LAUNCHER_ITEM( self ) ); + FoobarLauncherItemInterface* iface = FOOBAR_LAUNCHER_ITEM_GET_IFACE( self ); + if ( iface->activate ) { iface->activate( self ); } +} diff --git a/src/launcher-item.h b/src/launcher-item.h new file mode 100644 index 0000000..b2d274a --- /dev/null +++ b/src/launcher-item.h @@ -0,0 +1,28 @@ +#pragma once + +#include <glib-object.h> +#include <gio/gio.h> + +G_BEGIN_DECLS + +#define FOOBAR_TYPE_LAUNCHER_ITEM foobar_launcher_item_get_type( ) + +G_DECLARE_INTERFACE( FoobarLauncherItem, foobar_launcher_item, FOOBAR, LAUNCHER_ITEM, GObject ) + +struct _FoobarLauncherItemInterface +{ + GTypeInterface parent_interface; + + gchar const* ( *get_title ) ( FoobarLauncherItem* self ); + gchar const* ( *get_description )( FoobarLauncherItem* self ); + GIcon* ( *get_icon ) ( FoobarLauncherItem* self ); + void ( *activate ) ( FoobarLauncherItem* self ); +}; + +gchar const* foobar_launcher_item_get_title ( FoobarLauncherItem* self ); +gchar const* foobar_launcher_item_get_description( FoobarLauncherItem* self ); +GIcon* foobar_launcher_item_get_icon ( FoobarLauncherItem* self ); +void foobar_launcher_item_activate ( FoobarLauncherItem* self ); + +G_END_DECLS + diff --git a/src/launcher.c b/src/launcher.c index da37715..f4b34d8 100644 --- a/src/launcher.c +++ b/src/launcher.c @@ -1,4 +1,5 @@ #include "launcher.h" +#include "launcher-item.h" #include "widgets/limit-container.h" #include <gtk4-layer-shell.h> #include <gdk/gdkkeysyms.h> @@ -21,8 +22,11 @@ struct _FoobarLauncher GtkWidget* list_view; GtkWidget* limit_container; GtkFilterListModel* filter_model; + GListStore* quick_answer_model; + GtkFlattenListModel* flatten_model; GtkSingleSelection* selection_model; FoobarApplicationService* application_service; + FoobarQuickAnswerService* quick_answer_service; FoobarConfigurationService* configuration_service; gulong config_handler_id; }; @@ -119,9 +123,28 @@ void foobar_launcher_init( FoobarLauncher* self ) GtkWidget *separator = gtk_separator_new( GTK_ORIENTATION_HORIZONTAL ); + // Set up the results list view and an event controller for auto-switching focus to the input. + + GtkListItemFactory* item_factory = gtk_signal_list_item_factory_new( ); + g_signal_connect( item_factory, "setup", G_CALLBACK( foobar_launcher_handle_item_setup ), NULL ); + + GtkCustomFilter* filter = gtk_custom_filter_new( foobar_launcher_filter_func, self, NULL ); + + self->filter_model = gtk_filter_list_model_new( NULL, GTK_FILTER( filter ) ); + + self->quick_answer_model = g_list_store_new( FOOBAR_TYPE_LAUNCHER_ITEM ); + + GListStore* flattened_models = g_list_store_new( G_TYPE_LIST_MODEL ); + g_list_store_append( flattened_models, self->quick_answer_model ); + g_list_store_append( flattened_models, self->filter_model ); + + self->flatten_model = gtk_flatten_list_model_new( G_LIST_MODEL( flattened_models ) ); + + self->selection_model = gtk_single_selection_new( G_LIST_MODEL( g_object_ref( self->flatten_model ) ) ); + { - GtkExpression* list_expr = gtk_constant_expression_new( GTK_TYPE_FILTER_LIST_MODEL, self->filter_model ); - GtkExpression* count_expr = gtk_property_expression_new( GTK_TYPE_FILTER_LIST_MODEL, list_expr, "n-items" ); + GtkExpression* list_expr = gtk_constant_expression_new( GTK_TYPE_FLATTEN_LIST_MODEL, self->flatten_model ); + GtkExpression* count_expr = gtk_property_expression_new( GTK_TYPE_FLATTEN_LIST_MODEL, list_expr, "n-items" ); GtkExpression* visible_params[] = { count_expr }; GtkExpression* visible_expr = gtk_cclosure_expression_new( G_TYPE_BOOLEAN, @@ -134,17 +157,6 @@ void foobar_launcher_init( FoobarLauncher* self ) gtk_expression_bind( visible_expr, separator, "visible", NULL ); } - // Set up the results list view and an event controller for auto-switching focus to the input. - - GtkListItemFactory* item_factory = gtk_signal_list_item_factory_new( ); - g_signal_connect( item_factory, "setup", G_CALLBACK( foobar_launcher_handle_item_setup ), NULL ); - - GtkCustomFilter* filter = gtk_custom_filter_new( foobar_launcher_filter_func, self, NULL ); - - self->filter_model = gtk_filter_list_model_new( NULL, GTK_FILTER( filter ) ); - - self->selection_model = gtk_single_selection_new( G_LIST_MODEL( g_object_ref( self->filter_model ) ) ); - GtkEventController* list_controller = gtk_event_controller_key_new( ); g_signal_connect( list_controller, "key-pressed", G_CALLBACK( foobar_launcher_handle_list_key ), self ); g_signal_connect( list_controller, "key-released", G_CALLBACK( foobar_launcher_handle_list_key ), self ); @@ -201,8 +213,11 @@ void foobar_launcher_finalize( GObject* object ) g_clear_signal_handler( &self->config_handler_id, self->configuration_service ); g_clear_object( &self->filter_model ); + g_clear_object( &self->quick_answer_model ); + g_clear_object( &self->flatten_model ); g_clear_object( &self->selection_model ); g_clear_object( &self->application_service ); + g_clear_object( &self->quick_answer_service ); g_clear_object( &self->configuration_service ); g_clear_pointer( &self->search_terms, g_strfreev ); @@ -218,13 +233,16 @@ void foobar_launcher_finalize( GObject* object ) // FoobarLauncher* foobar_launcher_new( FoobarApplicationService* application_service, + FoobarQuickAnswerService* quick_answer_service, FoobarConfigurationService* configuration_service ) { g_return_val_if_fail( FOOBAR_IS_APPLICATION_SERVICE( application_service ), NULL ); + g_return_val_if_fail( FOOBAR_IS_QUICK_ANSWER_SERVICE( quick_answer_service ), NULL ); g_return_val_if_fail( FOOBAR_IS_CONFIGURATION_SERVICE( configuration_service ), NULL ); FoobarLauncher* self = g_object_new( FOOBAR_TYPE_LAUNCHER, NULL ); self->application_service = g_object_ref( application_service ); + self->quick_answer_service = g_object_ref( quick_answer_service ); self->configuration_service = g_object_ref( configuration_service ); // Set up the result list view's source model. @@ -299,6 +317,17 @@ void foobar_launcher_handle_search_changed( { FoobarLauncher* self = (FoobarLauncher*)userdata; + // Update quick answer. + + g_autoptr(FoobarQuickAnswer) answer = foobar_quick_answer_service_query( self->quick_answer_service, gtk_editable_get_text( editable ) ); + g_list_store_remove_all( self->quick_answer_model ); + if (answer) + { + g_list_store_append(self->quick_answer_model, answer); + } + + // Update filter. + GStrvBuilder* terms_builder = g_strv_builder_new( ); g_autofree gchar* query = g_strdup( gtk_editable_get_text( editable ) ); gchar* query_start = query; @@ -416,24 +445,24 @@ void foobar_launcher_handle_item_setup( gtk_widget_set_valign( icon, GTK_ALIGN_CENTER ); gtk_widget_add_css_class( icon, "icon" ); - GtkWidget* name = gtk_label_new( NULL ); - gtk_label_set_justify( GTK_LABEL( name ), GTK_JUSTIFY_LEFT ); - gtk_label_set_xalign( GTK_LABEL( name ), 0 ); - gtk_label_set_wrap( GTK_LABEL( name ), FALSE ); - gtk_label_set_ellipsize( GTK_LABEL( name ), PANGO_ELLIPSIZE_END ); - gtk_widget_add_css_class( name, "name" ); + GtkWidget* title = gtk_label_new( NULL ); + gtk_label_set_justify( GTK_LABEL( title ), GTK_JUSTIFY_LEFT ); + gtk_label_set_xalign( GTK_LABEL( title ), 0 ); + gtk_label_set_wrap( GTK_LABEL( title ), FALSE ); + gtk_label_set_ellipsize( GTK_LABEL( title ), PANGO_ELLIPSIZE_END ); + gtk_widget_add_css_class( title, "name" ); GtkWidget* description = gtk_label_new( NULL ); gtk_label_set_justify( GTK_LABEL( description ), GTK_JUSTIFY_LEFT ); gtk_label_set_xalign( GTK_LABEL( description ), 0 ); - gtk_label_set_wrap( GTK_LABEL( name ), FALSE ); + gtk_label_set_wrap( GTK_LABEL( description ), FALSE ); gtk_label_set_ellipsize( GTK_LABEL( description ), PANGO_ELLIPSIZE_END ); gtk_widget_add_css_class( description, "description" ); GtkWidget* column = gtk_box_new( GTK_ORIENTATION_VERTICAL, 0 ); gtk_widget_set_hexpand( column, TRUE ); gtk_widget_set_valign( column, GTK_ALIGN_CENTER ); - gtk_box_append( GTK_BOX( column ), name ); + gtk_box_append( GTK_BOX( column ), title ); gtk_box_append( GTK_BOX( column ), description ); GtkWidget* row = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 0 ); @@ -447,7 +476,7 @@ void foobar_launcher_handle_item_setup( { GtkExpression* item_expr = gtk_property_expression_new( GTK_TYPE_LIST_ITEM, NULL, "item" ); - GtkExpression* icon_expr = gtk_property_expression_new( FOOBAR_TYPE_APPLICATION_ITEM, item_expr, "icon" ); + GtkExpression* icon_expr = gtk_property_expression_new( FOOBAR_TYPE_LAUNCHER_ITEM, item_expr, "icon" ); gtk_expression_bind( gtk_expression_ref( icon_expr ), icon, "gicon", list_item ); GtkExpression* visible_params[] = { icon_expr }; GtkExpression* visible_expr = gtk_cclosure_expression_new( @@ -463,13 +492,13 @@ void foobar_launcher_handle_item_setup( { GtkExpression* item_expr = gtk_property_expression_new( GTK_TYPE_LIST_ITEM, NULL, "item" ); - GtkExpression* name_expr = gtk_property_expression_new( FOOBAR_TYPE_APPLICATION_ITEM, item_expr, "name" ); - gtk_expression_bind( name_expr, name, "label", list_item ); + GtkExpression* title_expr = gtk_property_expression_new( FOOBAR_TYPE_LAUNCHER_ITEM, item_expr, "title" ); + gtk_expression_bind( title_expr, title, "label", list_item ); } { GtkExpression* item_expr = gtk_property_expression_new( GTK_TYPE_LIST_ITEM, NULL, "item" ); - GtkExpression* description_expr = gtk_property_expression_new( FOOBAR_TYPE_APPLICATION_ITEM, item_expr, "description" ); + GtkExpression* description_expr = gtk_property_expression_new( FOOBAR_TYPE_LAUNCHER_ITEM, item_expr, "description" ); gtk_expression_bind( gtk_expression_ref( description_expr ), description, "label", list_item ); GtkExpression* visible_params[] = { description_expr }; GtkExpression* visible_expr = gtk_cclosure_expression_new( @@ -496,8 +525,8 @@ void foobar_launcher_handle_item_activate( FoobarLauncher* self = (FoobarLauncher*)userdata; GListModel* list = G_LIST_MODEL( gtk_list_view_get_model( view ) ); - FoobarApplicationItem* item = g_list_model_get_item( list, position ); - foobar_application_item_launch( item ); + FoobarLauncherItem* item = g_list_model_get_item( list, position ); + foobar_launcher_item_activate( item ); gtk_widget_set_visible( GTK_WIDGET( self ), FALSE ); } diff --git a/src/launcher.h b/src/launcher.h index 4c3e495..5d92607 100644 --- a/src/launcher.h +++ b/src/launcher.h @@ -3,6 +3,7 @@ #include <gtk/gtk.h> #include "services/application-service.h" #include "services/configuration-service.h" +#include "services/quick-answer-service.h" G_BEGIN_DECLS @@ -11,6 +12,7 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE( FoobarLauncher, foobar_launcher, FOOBAR, LAUNCHER, GtkWindow ) FoobarLauncher* foobar_launcher_new ( FoobarApplicationService* application_service, + FoobarQuickAnswerService* quick_answer_service, FoobarConfigurationService* configuration_service ); void foobar_launcher_apply_configuration( FoobarLauncher* self, FoobarLauncherConfiguration const* config ); diff --git a/src/meson.build b/src/meson.build index b089bce..78e0575 100644 --- a/src/meson.build +++ b/src/meson.build @@ -4,6 +4,7 @@ foobar_sources = files( 'utils.c', 'panel.c', 'launcher.c', + 'launcher-item.c', 'control-center.c', 'notification-area.c', ) diff --git a/src/services/application-service.c b/src/services/application-service.c index 3885719..42835ac 100644 --- a/src/services/application-service.c +++ b/src/services/application-service.c @@ -1,4 +1,5 @@ #include "services/application-service.h" +#include "launcher-item.h" #include "utils.h" #include <gtk/gtk.h> #include <gio/gdesktopappinfo.h> @@ -21,29 +22,38 @@ struct _FoobarApplicationItem enum { APP_PROP_ID = 1, - APP_PROP_NAME, - APP_PROP_DESCRIPTION, APP_PROP_EXECUTABLE, APP_PROP_CATEGORIES, - APP_PROP_ICON, APP_PROP_FREQUENCY, + APP_PROP_TITLE, + APP_PROP_DESCRIPTION, + APP_PROP_ICON, N_APP_PROPS, }; static GParamSpec* app_props[N_APP_PROPS] = { 0 }; -static void foobar_application_item_class_init ( FoobarApplicationItemClass* klass ); -static void foobar_application_item_init ( FoobarApplicationItem* self ); -static void foobar_application_item_get_property( GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec ); -static void foobar_application_item_finalize ( GObject* object ); -static FoobarApplicationItem* foobar_application_item_new ( FoobarApplicationService* service ); -static void foobar_application_item_set_info ( FoobarApplicationItem* self, - GAppInfo* value ); +static void foobar_application_item_class_init ( FoobarApplicationItemClass* klass ); +static void foobar_application_item_launcher_item_interface_init( FoobarLauncherItemInterface* iface ); +static void foobar_application_item_init ( FoobarApplicationItem* self ); +static void foobar_application_item_get_property ( GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec ); +static void foobar_application_item_finalize ( GObject* object ); +static FoobarApplicationItem* foobar_application_item_new ( FoobarApplicationService* service ); +static gchar const* foobar_application_item_get_title ( FoobarLauncherItem* self ); +static gchar const* foobar_application_item_get_description ( FoobarLauncherItem* self ); +static GIcon* foobar_application_item_get_icon ( FoobarLauncherItem* self ); +static void foobar_application_item_activate ( FoobarLauncherItem* self ); +static void foobar_application_item_set_info ( FoobarApplicationItem* self, + GAppInfo* value ); -G_DEFINE_FINAL_TYPE( FoobarApplicationItem, foobar_application_item, G_TYPE_OBJECT ) +G_DEFINE_FINAL_TYPE_WITH_CODE( + FoobarApplicationItem, + foobar_application_item, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE( FOOBAR_TYPE_LAUNCHER_ITEM, foobar_application_item_launcher_item_interface_init ) ) // // FoobarApplicationService: @@ -124,24 +134,13 @@ void foobar_application_item_class_init( FoobarApplicationItemClass* klass ) object_klass->get_property = foobar_application_item_get_property; object_klass->finalize = foobar_application_item_finalize; + gpointer launcher_item_iface = g_type_default_interface_peek( FOOBAR_TYPE_LAUNCHER_ITEM ); app_props[APP_PROP_ID] = g_param_spec_string( "id", "ID", "Application identifier string.", NULL, G_PARAM_READABLE ); - app_props[APP_PROP_NAME] = g_param_spec_string( - "name", - "Name", - "Displayed name for the application.", - NULL, - G_PARAM_READABLE ); - app_props[APP_PROP_DESCRIPTION] = g_param_spec_string( - "description", - "Description", - "Brief description of the application.", - NULL, - G_PARAM_READABLE ); app_props[APP_PROP_EXECUTABLE] = g_param_spec_string( "executable", "Executable", @@ -154,12 +153,6 @@ void foobar_application_item_class_init( FoobarApplicationItemClass* klass ) "Semicolon-separated list of application categories.", NULL, G_PARAM_READABLE ); - app_props[APP_PROP_ICON] = g_param_spec_object( - "icon", - "Icon", - "Icon to show for the application.", - G_TYPE_ICON, - G_PARAM_READABLE ); app_props[APP_PROP_FREQUENCY] = g_param_spec_int64( "frequency", "Frequency", @@ -168,10 +161,30 @@ void foobar_application_item_class_init( FoobarApplicationItemClass* klass ) INT64_MAX, 0, G_PARAM_READABLE ); + app_props[APP_PROP_TITLE] = g_param_spec_override( + "title", + g_object_interface_find_property( launcher_item_iface, "title" ) ); + app_props[APP_PROP_DESCRIPTION] = g_param_spec_override( + "description", + g_object_interface_find_property( launcher_item_iface, "description" ) ); + app_props[APP_PROP_ICON] = g_param_spec_override( + "icon", + g_object_interface_find_property( launcher_item_iface, "icon" ) ); g_object_class_install_properties( object_klass, N_APP_PROPS, app_props ); } // +// Static initialization of the FoobarLauncherItem interface. +// +void foobar_application_item_launcher_item_interface_init( FoobarLauncherItemInterface* iface ) +{ + iface->get_title = foobar_application_item_get_title; + iface->get_description = foobar_application_item_get_description; + iface->get_icon = foobar_application_item_get_icon; + iface->activate = foobar_application_item_activate; +} + +// // Instance initialization for application items. // void foobar_application_item_init( FoobarApplicationItem* self ) @@ -195,24 +208,24 @@ void foobar_application_item_get_property( case APP_PROP_ID: g_value_set_string( value, foobar_application_item_get_id( self ) ); break; - case APP_PROP_NAME: - g_value_set_string( value, foobar_application_item_get_name( self ) ); - break; - case APP_PROP_DESCRIPTION: - g_value_set_string( value, foobar_application_item_get_description( self ) ); - break; case APP_PROP_EXECUTABLE: g_value_set_string( value, foobar_application_item_get_executable( self ) ); break; case APP_PROP_CATEGORIES: g_value_set_string( value, foobar_application_item_get_categories( self ) ); break; - case APP_PROP_ICON: - g_value_set_object( value, foobar_application_item_get_icon( self ) ); - break; case APP_PROP_FREQUENCY: g_value_set_int64( value, foobar_application_item_get_frequency( self ) ); break; + case APP_PROP_TITLE: + g_value_set_string( value, foobar_launcher_item_get_title( FOOBAR_LAUNCHER_ITEM ( self ) ) ); + break; + case APP_PROP_DESCRIPTION: + g_value_set_string( value, foobar_launcher_item_get_description( FOOBAR_LAUNCHER_ITEM( self ) ) ); + break; + case APP_PROP_ICON: + g_value_set_object( value, foobar_launcher_item_get_icon( FOOBAR_LAUNCHER_ITEM( self ) ) ); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); break; @@ -251,62 +264,91 @@ gchar const* foobar_application_item_get_id( FoobarApplicationItem* self ) } // -// Get the application's human-readable name. +// Get the application's executable name. // -gchar const* foobar_application_item_get_name( FoobarApplicationItem* self ) +gchar const* foobar_application_item_get_executable( FoobarApplicationItem* self ) { g_return_val_if_fail( FOOBAR_IS_APPLICATION_ITEM( self ), NULL ); - return self->info ? g_app_info_get_display_name( self->info ) : NULL; + return self->info ? g_app_info_get_executable( self->info ) : NULL; } // -// Get an optional short description for the application. +// Get the semicolon-separated list of categories for this application. // -gchar const* foobar_application_item_get_description( FoobarApplicationItem* self ) +gchar const* foobar_application_item_get_categories( FoobarApplicationItem* self ) { g_return_val_if_fail( FOOBAR_IS_APPLICATION_ITEM( self ), NULL ); - return self->info ? g_app_info_get_description( self->info ) : NULL; + return G_IS_DESKTOP_APP_INFO( self->info ) + ? g_desktop_app_info_get_categories( G_DESKTOP_APP_INFO( self->info ) ) + : NULL; } // -// Get the application's executable name. +// Get the number of times this application was opened using the launcher. // -gchar const* foobar_application_item_get_executable( FoobarApplicationItem* self ) +gint64 foobar_application_item_get_frequency( FoobarApplicationItem* self ) { - g_return_val_if_fail( FOOBAR_IS_APPLICATION_ITEM( self ), NULL ); - return self->info ? g_app_info_get_executable( self->info ) : NULL; + g_return_val_if_fail( FOOBAR_IS_APPLICATION_ITEM( self ), 0 ); + + if ( !self->service ) { return 0; } + gpointer value = g_hash_table_lookup( self->service->frequencies, foobar_application_item_get_id( self ) ); + return GPOINTER_TO_SIZE( value ); } // -// Get the semicolon-separated list of categories for this application. +// Get the application's human-readable name. // -gchar const* foobar_application_item_get_categories( FoobarApplicationItem* self ) +gchar const* foobar_application_item_get_title( FoobarLauncherItem* item ) { - g_return_val_if_fail( FOOBAR_IS_APPLICATION_ITEM( self ), NULL ); - return G_IS_DESKTOP_APP_INFO( self->info ) - ? g_desktop_app_info_get_categories( G_DESKTOP_APP_INFO( self->info ) ) - : NULL; + FoobarApplicationItem* self = ( FoobarApplicationItem* )item; + return self->info ? g_app_info_get_display_name( self->info ) : NULL; +} + +// +// Get an optional short description for the application. +// +gchar const* foobar_application_item_get_description( FoobarLauncherItem* item ) +{ + FoobarApplicationItem* self = ( FoobarApplicationItem* )item; + return self->info ? g_app_info_get_description( self->info ) : NULL; } // // Get an icon representing the application. // -GIcon* foobar_application_item_get_icon( FoobarApplicationItem* self ) +GIcon* foobar_application_item_get_icon( FoobarLauncherItem* item ) { - g_return_val_if_fail( FOOBAR_IS_APPLICATION_ITEM( self ), NULL ); + FoobarApplicationItem* self = ( FoobarApplicationItem* )item; return self->info ? g_app_info_get_icon( self->info ) : NULL; } // -// Get the number of times this application was opened using the launcher. +// Launch the application, increasing its frequency by one. // -gint64 foobar_application_item_get_frequency( FoobarApplicationItem* self ) +void foobar_application_item_activate( FoobarLauncherItem* item ) { - g_return_val_if_fail( FOOBAR_IS_APPLICATION_ITEM( self ), 0 ); + FoobarApplicationItem* self = ( FoobarApplicationItem* )item; - if ( !self->service ) { return 0; } - gpointer value = g_hash_table_lookup( self->service->frequencies, foobar_application_item_get_id( self ) ); - return GPOINTER_TO_SIZE( value ); + if ( !self->info ) { return; } + + g_autoptr( GError ) error = NULL; + if ( !g_app_info_launch( self->info, NULL, NULL, &error ) ) + { + g_warning( "Unable to launch application: %s", error->message ); + } + + gchar const* id = foobar_application_item_get_id( self ); + if ( !self->service || !id ) { return; } + + gpointer value = g_hash_table_lookup( self->service->frequencies, id ); + value = GSIZE_TO_POINTER( GPOINTER_TO_SIZE( value ) + 1 ); + g_mutex_lock( &self->service->frequencies_mutex ); + g_hash_table_insert( self->service->frequencies, g_strdup( id ), value ); + g_mutex_unlock( &self->service->frequencies_mutex ); + + g_object_notify_by_pspec( G_OBJECT( self ), app_props[APP_PROP_FREQUENCY] ); + gtk_sorter_changed( gtk_sort_list_model_get_sorter( self->service->sorted_items ), GTK_SORTER_CHANGE_DIFFERENT ); + foobar_application_service_write_cache( self->service ); } // @@ -325,7 +367,7 @@ void foobar_application_item_set_info( if ( value ) { self->info = g_object_ref( value ); } g_object_notify_by_pspec( G_OBJECT( self ), app_props[APP_PROP_ID] ); - g_object_notify_by_pspec( G_OBJECT( self ), app_props[APP_PROP_NAME] ); + g_object_notify_by_pspec( G_OBJECT( self ), app_props[APP_PROP_TITLE] ); g_object_notify_by_pspec( G_OBJECT( self ), app_props[APP_PROP_DESCRIPTION] ); g_object_notify_by_pspec( G_OBJECT( self ), app_props[APP_PROP_EXECUTABLE] ); g_object_notify_by_pspec( G_OBJECT( self ), app_props[APP_PROP_ICON] ); @@ -346,8 +388,8 @@ gboolean foobar_application_item_match( for ( gchar const* const* it = terms; *it; ++it ) { gchar const* term = *it; - gchar const* name = foobar_application_item_get_name( self ); - gchar const* description = foobar_application_item_get_description( self ); + gchar const* name = foobar_launcher_item_get_title( FOOBAR_LAUNCHER_ITEM( self ) ); + gchar const* description = foobar_launcher_item_get_description( FOOBAR_LAUNCHER_ITEM( self ) ); gchar const* executable = foobar_application_item_get_executable( self ); gchar const* categories = foobar_application_item_get_categories( self ); gchar const* id = foobar_application_item_get_id( self ); @@ -363,35 +405,6 @@ gboolean foobar_application_item_match( return TRUE; } -// -// Launch the application, increasing its frequency by one. -// -void foobar_application_item_launch( FoobarApplicationItem* self ) -{ - g_return_if_fail( FOOBAR_IS_APPLICATION_ITEM( self ) ); - - if ( !self->info ) { return; } - - g_autoptr( GError ) error = NULL; - if ( !g_app_info_launch( self->info, NULL, NULL, &error ) ) - { - g_warning( "Unable to launch application: %s", error->message ); - } - - gchar const* id = foobar_application_item_get_id( self ); - if ( !self->service || !id ) { return; } - - gpointer value = g_hash_table_lookup( self->service->frequencies, id ); - value = GSIZE_TO_POINTER( GPOINTER_TO_SIZE( value ) + 1 ); - g_mutex_lock( &self->service->frequencies_mutex ); - g_hash_table_insert( self->service->frequencies, g_strdup( id ), value ); - g_mutex_unlock( &self->service->frequencies_mutex ); - - g_object_notify_by_pspec( G_OBJECT( self ), app_props[APP_PROP_FREQUENCY] ); - gtk_sorter_changed( gtk_sort_list_model_get_sorter( self->service->sorted_items ), GTK_SORTER_CHANGE_DIFFERENT ); - foobar_application_service_write_cache( self->service ); -} - // --------------------------------------------------------------------------------------------------------------------- // Service Implementation // --------------------------------------------------------------------------------------------------------------------- @@ -722,8 +735,8 @@ gint foobar_application_service_sort_func( if ( freq_a > freq_b ) { return -1; } if ( freq_a < freq_b ) { return 1; } - gchar const* name_a = foobar_application_item_get_name( app_a ); - gchar const* name_b = foobar_application_item_get_name( app_b ); + gchar const* name_a = foobar_launcher_item_get_title( FOOBAR_LAUNCHER_ITEM( app_a ) ); + gchar const* name_b = foobar_launcher_item_get_title( FOOBAR_LAUNCHER_ITEM( app_b ) ); gint name_res = g_strcmp0( name_a, name_b ); if ( name_res ) { return name_res; } diff --git a/src/services/application-service.h b/src/services/application-service.h index 3c2622a..dd043fc 100644 --- a/src/services/application-service.h +++ b/src/services/application-service.h @@ -11,15 +11,11 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE( FoobarApplicationItem, foobar_application_item, FOOBAR, APPLICATION_ITEM, GObject ) gchar const* foobar_application_item_get_id ( FoobarApplicationItem* self ); -gchar const* foobar_application_item_get_name ( FoobarApplicationItem* self ); -gchar const* foobar_application_item_get_description( FoobarApplicationItem* self ); gchar const* foobar_application_item_get_executable ( FoobarApplicationItem* self ); gchar const* foobar_application_item_get_categories ( FoobarApplicationItem* self ); -GIcon* foobar_application_item_get_icon ( FoobarApplicationItem* self ); gint64 foobar_application_item_get_frequency ( FoobarApplicationItem* self ); gboolean foobar_application_item_match ( FoobarApplicationItem* self, gchar const* const* terms ); -void foobar_application_item_launch ( FoobarApplicationItem* self ); G_DECLARE_FINAL_TYPE( FoobarApplicationService, foobar_application_service, FOOBAR, APPLICATION_SERVICE, GObject ) diff --git a/src/services/meson.build b/src/services/meson.build index 990102b..e4f151d 100644 --- a/src/services/meson.build +++ b/src/services/meson.build @@ -8,5 +8,6 @@ foobar_sources += files( 'network-service.c', 'bluetooth-service.c', 'application-service.c', + 'quick-answer-service.c', 'configuration-service.c', ) diff --git a/src/services/quick-answer-service.c b/src/services/quick-answer-service.c new file mode 100644 index 0000000..b564a16 --- /dev/null +++ b/src/services/quick-answer-service.c @@ -0,0 +1,317 @@ +#include "services/quick-answer-service.h" +#include "launcher-item.h" +#include <gdk/gdk.h> + +struct _FoobarQuickAnswer +{ + GObject parent_instance; + gchar* title; + gchar* value; + GIcon* icon; +}; + +enum +{ + ANSWER_PROP_VALUE = 1, + ANSWER_PROP_TITLE, + ANSWER_PROP_DESCRIPTION, + ANSWER_PROP_ICON, + N_ANSWER_PROPS, +}; + +static GParamSpec* answer_props[N_ANSWER_PROPS] = { 0 }; + +static void foobar_quick_answer_class_init ( FoobarQuickAnswerClass* klass ); +static void foobar_quick_answer_launcher_item_interface_init( FoobarLauncherItemInterface* iface ); +static void foobar_quick_answer_init ( FoobarQuickAnswer* self ); +static void foobar_quick_answer_get_property ( GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec ); +static void foobar_quick_answer_finalize ( GObject* object ); +static FoobarQuickAnswer* foobar_quick_answer_new ( void ); +static gchar const* foobar_quick_answer_get_title ( FoobarLauncherItem* self ); +static gchar const* foobar_quick_answer_get_description ( FoobarLauncherItem* self ); +static GIcon* foobar_quick_answer_get_icon ( FoobarLauncherItem* self ); +static void foobar_quick_answer_activate ( FoobarLauncherItem* self ); +static void foobar_quick_answer_set_title ( FoobarQuickAnswer* self, + gchar const* value ); +static void foobar_quick_answer_set_value ( FoobarQuickAnswer* self, + gchar const* value ); +static void foobar_quick_answer_set_icon ( FoobarQuickAnswer* self, + GIcon* value ); + +G_DEFINE_FINAL_TYPE_WITH_CODE( + FoobarQuickAnswer, + foobar_quick_answer, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE( FOOBAR_TYPE_LAUNCHER_ITEM, foobar_quick_answer_launcher_item_interface_init ) ) + +struct _FoobarQuickAnswerService +{ + GObject parent_instance; +}; + +static void foobar_quick_answer_service_class_init( FoobarQuickAnswerServiceClass* klass ); +static void foobar_quick_answer_service_init ( FoobarQuickAnswerService* self ); + +G_DEFINE_FINAL_TYPE( FoobarQuickAnswerService, foobar_quick_answer_service, G_TYPE_OBJECT ) + +// --------------------------------------------------------------------------------------------------------------------- +// Quick Answers +// --------------------------------------------------------------------------------------------------------------------- + +// +// Static initialization for quick answers. +// +void foobar_quick_answer_class_init( FoobarQuickAnswerClass* klass ) +{ + GObjectClass* object_klass = G_OBJECT_CLASS( klass ); + object_klass->get_property = foobar_quick_answer_get_property; + object_klass->finalize = foobar_quick_answer_finalize; + + gpointer launcher_item_iface = g_type_default_interface_peek( FOOBAR_TYPE_LAUNCHER_ITEM ); + answer_props[ANSWER_PROP_VALUE] = g_param_spec_string( + "value", + "Value", + "The raw value of the quick answer.", + NULL, + G_PARAM_READABLE ); + answer_props[ANSWER_PROP_TITLE] = g_param_spec_override( + "title", + g_object_interface_find_property( launcher_item_iface, "title" ) ); + answer_props[ANSWER_PROP_DESCRIPTION] = g_param_spec_override( + "description", + g_object_interface_find_property( launcher_item_iface, "description" ) ); + answer_props[ANSWER_PROP_ICON] = g_param_spec_override( + "icon", + g_object_interface_find_property( launcher_item_iface, "icon" ) ); + g_object_class_install_properties( object_klass, N_ANSWER_PROPS, answer_props ); +} + +// +// Static initialization of the FoobarLauncherItem interface. +// +void foobar_quick_answer_launcher_item_interface_init( FoobarLauncherItemInterface* iface ) +{ + iface->get_title = foobar_quick_answer_get_title; + iface->get_description = foobar_quick_answer_get_description; + iface->get_icon = foobar_quick_answer_get_icon; + iface->activate = foobar_quick_answer_activate; +} + +// +// Instance initialization for quick answers. +// +void foobar_quick_answer_init( FoobarQuickAnswer* self ) +{ + (void)self; +} + +// +// Property getter implementation, mapping a property id to a method. +// +void foobar_quick_answer_get_property( + GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec ) +{ + FoobarQuickAnswer* self = (FoobarQuickAnswer*)object; + + switch ( prop_id ) + { + case ANSWER_PROP_VALUE: + g_value_set_string( value, foobar_quick_answer_get_value( self ) ); + break; + case ANSWER_PROP_TITLE: + g_value_set_string( value, foobar_launcher_item_get_title( FOOBAR_LAUNCHER_ITEM ( self ) ) ); + break; + case ANSWER_PROP_DESCRIPTION: + g_value_set_string( value, foobar_launcher_item_get_description( FOOBAR_LAUNCHER_ITEM( self ) ) ); + break; + case ANSWER_PROP_ICON: + g_value_set_object( value, foobar_launcher_item_get_icon( FOOBAR_LAUNCHER_ITEM( self ) ) ); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); + break; + } +} + +// +// Instance cleanup for quick answers. +// +void foobar_quick_answer_finalize( GObject* object ) +{ + FoobarQuickAnswer* self = (FoobarQuickAnswer*)object; + + g_clear_pointer( &self->title, g_free ); + g_clear_pointer( &self->value, g_free ); + g_clear_object( &self->icon ); + + G_OBJECT_CLASS( foobar_quick_answer_parent_class )->finalize( object ); +} + +// +// Create a new, default-initialized quick answer. +// +FoobarQuickAnswer* foobar_quick_answer_new( void ) +{ + return g_object_new( FOOBAR_TYPE_QUICK_ANSWER, NULL ); +} + +// +// Get the raw value of the quick answer. +// +gchar const* foobar_quick_answer_get_value( FoobarQuickAnswer* self ) +{ + g_return_val_if_fail( FOOBAR_IS_QUICK_ANSWER( self ), NULL ); + return self->value; +} + +// +// Get the title for the quick answer. +// +gchar const* foobar_quick_answer_get_title( FoobarLauncherItem* item ) +{ + FoobarQuickAnswer* self = ( FoobarQuickAnswer* )item; + return self->title; +} + +// +// Get the description shown below the title, always NULL for quick answers. +// +gchar const* foobar_quick_answer_get_description( FoobarLauncherItem* item ) +{ + (void)item; + return NULL; +} + +// +// Get an icon representing the quick answer. +// +GIcon* foobar_quick_answer_get_icon( FoobarLauncherItem* item ) +{ + FoobarQuickAnswer* self = ( FoobarQuickAnswer* )item; + return self->icon; +} + +// +// Copy the quick answer's value into the clipboard. +// +void foobar_quick_answer_activate( FoobarLauncherItem* item ) +{ + FoobarQuickAnswer* self = ( FoobarQuickAnswer* )item; + if ( self->value ) + { + GdkClipboard* clipboard = gdk_display_get_clipboard( gdk_display_get_default( ) ); + gdk_clipboard_set_text( clipboard, self->value ); + } +} + +// +// Update the raw value of the quick answer. +// +void foobar_quick_answer_set_value( + FoobarQuickAnswer* self, + gchar const* value ) +{ + g_return_if_fail( FOOBAR_IS_QUICK_ANSWER( self ) ); + + if ( g_strcmp0( self->value, value ) ) + { + g_clear_pointer( &self->value, g_free ); + self->value = g_strdup( value ); + g_object_notify_by_pspec( G_OBJECT( self ), answer_props[ANSWER_PROP_VALUE] ); + } +} + +// +// Update the title for the quick answer. +// +void foobar_quick_answer_set_title( + FoobarQuickAnswer* self, + gchar const* value ) +{ + g_return_if_fail( FOOBAR_IS_QUICK_ANSWER( self ) ); + + if ( g_strcmp0( self->title, value ) ) + { + g_clear_pointer( &self->title, g_free ); + self->title = g_strdup( value ); + g_object_notify_by_pspec( G_OBJECT( self ), answer_props[ANSWER_PROP_TITLE] ); + } +} + +// +// Update the icon representing the quick answer. +// +void foobar_quick_answer_set_icon( + FoobarQuickAnswer* self, + GIcon* value ) +{ + g_return_if_fail( FOOBAR_IS_QUICK_ANSWER( self ) ); + + if ( self->icon != value ) + { + g_clear_object( &self->icon ); + self->icon = value ? g_object_ref( value ) : NULL; + g_object_notify_by_pspec( G_OBJECT( self ), answer_props[ANSWER_PROP_ICON] ); + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// Service Implementation +// --------------------------------------------------------------------------------------------------------------------- + +// +// Static initialization for the quick answer service. +// +void foobar_quick_answer_service_class_init( FoobarQuickAnswerServiceClass* klass ) +{ + (void)klass; +} + +// +// Instance initialization for the quick answer service. +// +void foobar_quick_answer_service_init( FoobarQuickAnswerService* self ) +{ + (void)self; +} + +// --------------------------------------------------------------------------------------------------------------------- +// Public API +// --------------------------------------------------------------------------------------------------------------------- + +// +// Create a new quick answer service instance. +// +FoobarQuickAnswerService* foobar_quick_answer_service_new( void ) +{ + return g_object_new( FOOBAR_TYPE_QUICK_ANSWER_SERVICE, NULL ); +} + +// +// Query the service for a quick answer. +// +FoobarQuickAnswer* foobar_quick_answer_service_query( + FoobarQuickAnswerService* self, + gchar const* query ) +{ + (void)self; + + if ( !g_strcmp0(query, "2+2") ) + { + g_autoptr(GIcon) icon = g_themed_icon_new("fluent-calculator-symbolic"); + + FoobarQuickAnswer* answer = foobar_quick_answer_new(); + foobar_quick_answer_set_value(answer, "4"); + foobar_quick_answer_set_title(answer, "= 4"); + foobar_quick_answer_set_icon(answer, icon); + return answer; + } + + return NULL; +} diff --git a/src/services/quick-answer-service.h b/src/services/quick-answer-service.h new file mode 100644 index 0000000..02a8e10 --- /dev/null +++ b/src/services/quick-answer-service.h @@ -0,0 +1,21 @@ +#pragma once + +#include <glib-object.h> +#include <gio/gio.h> + +G_BEGIN_DECLS + +#define FOOBAR_TYPE_QUICK_ANSWER foobar_quick_answer_get_type( ) +#define FOOBAR_TYPE_QUICK_ANSWER_SERVICE foobar_quick_answer_service_get_type( ) + +G_DECLARE_FINAL_TYPE( FoobarQuickAnswer, foobar_quick_answer, FOOBAR, QUICK_ANSWER, GObject ) + +gchar const* foobar_quick_answer_get_value( FoobarQuickAnswer* self ); + +G_DECLARE_FINAL_TYPE( FoobarQuickAnswerService, foobar_quick_answer_service, FOOBAR, QUICK_ANSWER_SERVICE, GObject ) + +FoobarQuickAnswerService* foobar_quick_answer_service_new ( void ); +FoobarQuickAnswer* foobar_quick_answer_service_query ( FoobarQuickAnswerService* self, + gchar const* query ); + +G_END_DECLS |
