diff --git a/resources/session-shell.css b/resources/session-shell.css
index 48a694b..89795fd 100644
--- a/resources/session-shell.css
+++ b/resources/session-shell.css
@@ -7,11 +7,15 @@ diya-taskbar
diya-dashboard
{
- background-color: blue;
+ background-color: lightgray;
}
#diya_shell_background
{
background-image:url("file:///etc/xdg/labwc/wpp.jpg");
background-size: cover;
+}
+
+flowbox flowboxchild {
+ border: 5px solid black;
}
\ No newline at end of file
diff --git a/resources/ui/dashboard.ui b/resources/ui/dashboard.ui
index 399481c..64aa119 100644
--- a/resources/ui/dashboard.ui
+++ b/resources/ui/dashboard.ui
@@ -20,7 +20,7 @@
@@ -31,17 +31,52 @@
-
-
+
+
+
+ stack
+
+
+
+
diff --git a/src/widgets/dashboard-widget.c b/src/widgets/dashboard-widget.c
index 747ca60..c58b482 100644
--- a/src/widgets/dashboard-widget.c
+++ b/src/widgets/dashboard-widget.c
@@ -1,10 +1,104 @@
#include "dashboard-widget.h"
+/**
+ * Implementation of list model
+ *
+ */
+struct _DiyaDashboardListModel
+{
+ GObject parent_instance;
+ GList *appinfos;
+};
+
+static guint diya_dashboard_list_model_get_n_items(GListModel *list)
+{
+ DiyaDashboardListModel *self = DIYA_DASHBOARD_LIST_MODEL(list);
+ return g_list_length(self->appinfos);
+}
+
+static gpointer diya_dashboard_list_model_get_item(GListModel *list, guint position)
+{
+ DiyaDashboardListModel *self = DIYA_DASHBOARD_LIST_MODEL(list);
+ return g_object_ref(g_list_nth_data(self->appinfos, position));
+}
+
+static GType diya_dashboard_list_model_get_item_type(GListModel *list)
+{
+ (void)list; // Unused parameter
+ return G_TYPE_APP_INFO;
+}
+
+static void diya_dashboard_list_model_interface_init(GListModelInterface *iface)
+{
+ iface->get_n_items = diya_dashboard_list_model_get_n_items;
+ iface->get_item = diya_dashboard_list_model_get_item;
+ iface->get_item_type = diya_dashboard_list_model_get_item_type;
+}
+
+G_DEFINE_TYPE_WITH_CODE(DiyaDashboardListModel, diya_dashboard_list_model, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE(G_TYPE_LIST_MODEL, diya_dashboard_list_model_interface_init))
+
+static void diya_dashboard_list_model_finalize(GObject *object)
+{
+ g_debug("diya_dashboard_list_model_finalize");
+ DiyaDashboardListModel *self = DIYA_DASHBOARD_LIST_MODEL(object);
+ g_list_free_full(self->appinfos, g_object_unref);
+ G_OBJECT_CLASS(diya_dashboard_list_model_parent_class)->finalize(object);
+}
+
+static void diya_dashboard_list_model_dispose(GObject *object)
+{
+ (void)object;
+ g_debug("diya_dashboard_list_model_dispose");
+ G_OBJECT_CLASS(diya_dashboard_list_model_parent_class)->dispose(object);
+}
+
+static void diya_dashboard_list_model_init(DiyaDashboardListModel *self)
+{
+ self->appinfos = NULL;
+}
+
+static void diya_dashboard_list_model_class_init(DiyaDashboardListModelClass *class)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(class);
+ gobject_class->finalize = diya_dashboard_list_model_finalize;
+ gobject_class->dispose = diya_dashboard_list_model_dispose;
+}
+
+void diya_dashboard_list_model_append(DiyaDashboardListModel *self, GAppInfo *info)
+{
+ self->appinfos = g_list_append(self->appinfos, g_object_ref(info));
+ // self->appinfos = g_list_reverse(self->appinfos);
+ g_list_model_items_changed(G_LIST_MODEL(self), g_list_length(self->appinfos) - 1, 0, 1);
+}
+
+static gint diya_dashboard_app_info_cmd(GAppInfo *a, GAppInfo *b)
+{
+ return !g_app_info_equal(a, b);
+}
+
+gboolean diya_dashboard_list_model_contain(DiyaDashboardListModel *self, GAppInfo *info)
+{
+ GList *found = NULL;
+ found = g_list_find_custom(self->appinfos, info, (GCompareFunc)diya_dashboard_app_info_cmd);
+ return found != NULL;
+}
+
+/**
+ * Implement of Dashboard widget
+ *
+ */
+
struct _DiyaDashboardWidget
{
DiyaShellWindow parent;
GtkWidget *revealer;
GtkWidget *search_entry;
+ GtkWidget *app_list_box;
+ DiyaDashboardListModel *list_model;
+ GtkSortListModel *sort_model;
+ GtkFilterListModel *proxy_model;
+ GtkSorter *sorter;
+ GtkFilter *filter;
bool active;
};
@@ -17,140 +111,235 @@ enum
static GParamSpec *g_prop[N_PROPERTIES] = {0};
+G_DEFINE_TYPE(DiyaDashboardWidget, diya_dashboard_widget, DIYA_TYPE_SHELL_WINDOW)
-G_DEFINE_TYPE (DiyaDashboardWidget, diya_dashboard_widget, DIYA_TYPE_SHELL_WINDOW)
-
-static void diya_dashboard_widget_dispose(GObject* object)
+static void diya_dashboard_widget_dispose(GObject *object)
{
- (void) object;
+ DiyaDashboardWidget *self = DIYA_DASHBOARD_WIDGET(object);
g_debug("diya_dashboard_widget_dispose");
+ if (self->proxy_model)
+ {
+ g_object_unref(self->proxy_model);
+ }
+ // verify if the list model + sorter is also unref
G_OBJECT_CLASS(diya_dashboard_widget_parent_class)->dispose(object);
}
-static void diya_dashboard_widget_init(DiyaDashboardWidget * self)
+static void diya_dashboard_app_launch(GtkFlowBox *box, GtkFlowBoxChild *child, gpointer user_data)
+{
+ (void)box; // Unused parameter
+ DiyaDashboardWidget *self = DIYA_DASHBOARD_WIDGET(user_data);
+ int current_index = gtk_flow_box_child_get_index(child);
+ if (current_index < 0)
+ {
+ g_warning("Invalid child index: %d", current_index);
+ return;
+ }
+ GAppInfo *app = G_APP_INFO(g_list_model_get_item(G_LIST_MODEL(self->proxy_model), current_index));
+ assert(app);
+ diya_shell_launch(diya_shell_window_get_shell(DIYA_SHELL_WINDOW(self)), app);
+ g_object_set(self, DIYA_PROP_DASHBOARD_ACTIVE, false, NULL);
+ g_object_unref(app);
+}
+static void diya_dashboard_app_icon_clicked(GtkWidget *widget, gpointer user_data)
+{
+ // relay signal to the GTK_FLOW_BOX_CHILD parent
+ g_signal_emit_by_name(gtk_widget_get_parent(widget), "activate", user_data);
+}
+
+static GtkWidget *diya_dashboard_create_app_icon_widget(void *item, void *user_data)
+{
+ (void)user_data; // Unused parameter
+ GAppInfo *app_info = G_APP_INFO(item);
+ const gchar *name = g_app_info_get_display_name(app_info);
+ GIcon *icon = g_app_info_get_icon(app_info);
+ GtkWidget *widget = gtk_button_new_with_label(name);
+ if (icon)
+ {
+ g_debug("app_info %s has icon %s", name, g_icon_to_string(icon));
+ // gtk_button_set_icon_name(GTK_BUTTON(widget), g_icon_to_string(icon));
+ }
+ g_signal_connect(widget, "clicked", G_CALLBACK(diya_dashboard_app_icon_clicked), user_data);
+ return widget;
+}
+
+static int diya_dashboard_app_info_cmp(GAppInfo *a, GAppInfo *b, gpointer user_data)
+{
+ (void)user_data; // Unused parameter
+ const gchar *name_a = g_app_info_get_id(a);
+ const gchar *name_b = g_app_info_get_id(b);
+ return g_strcmp0(name_a, name_b);
+}
+
+static gboolean diya_app_info_filter_func(GAppInfo *app_info, gpointer user_data)
+{
+ DiyaDashboardWidget *self = DIYA_DASHBOARD_WIDGET(user_data);
+ gchar *text = g_utf8_strdown(gtk_editable_get_text(GTK_EDITABLE(self->search_entry)), -1);
+ if (strlen(text) == 0)
+ {
+ g_free(text);
+ return true;
+ }
+ gchar *name = g_utf8_strdown(g_app_info_get_display_name(app_info), -1);
+ if(!name)
+ {
+ g_free(text);
+ return false;
+ }
+ gboolean result = g_str_has_prefix(name, text);
+ g_free(text);
+ g_free(name);
+ return result;
+}
+
+static void diya_dashboard_search_text_changed(GtkEntry *entry, DiyaDashboardWidget *self)
+{
+ (void)entry; // Unused parameter
+ gtk_filter_changed(self->filter, GTK_FILTER_CHANGE_DIFFERENT);
+}
+
+static void diya_dashboard_widget_init(DiyaDashboardWidget *self)
{
g_debug("diya_dashboard_widget_init");
- gtk_widget_init_template (GTK_WIDGET(self));
+ gtk_widget_init_template(GTK_WIDGET(self));
self->active = false;
-
+
// int layer shell for window
- gtk_layer_init_for_window (GTK_WINDOW(self));
+ gtk_layer_init_for_window(GTK_WINDOW(self));
// anchor window to all edges
- gtk_layer_set_anchor (GTK_WINDOW(self), GTK_LAYER_SHELL_EDGE_LEFT, true);
- gtk_layer_set_anchor (GTK_WINDOW(self), GTK_LAYER_SHELL_EDGE_RIGHT, true);
- gtk_layer_set_anchor (GTK_WINDOW(self), GTK_LAYER_SHELL_EDGE_TOP, true);
- gtk_layer_set_anchor (GTK_WINDOW(self), GTK_LAYER_SHELL_EDGE_BOTTOM, true);
+ gtk_layer_set_anchor(GTK_WINDOW(self), GTK_LAYER_SHELL_EDGE_LEFT, true);
+ gtk_layer_set_anchor(GTK_WINDOW(self), GTK_LAYER_SHELL_EDGE_RIGHT, true);
+ gtk_layer_set_anchor(GTK_WINDOW(self), GTK_LAYER_SHELL_EDGE_TOP, true);
+ gtk_layer_set_anchor(GTK_WINDOW(self), GTK_LAYER_SHELL_EDGE_BOTTOM, true);
gtk_layer_set_namespace(GTK_WINDOW(self), "diya-dashboard");
// set margin on window
for (int i = 0; i < GTK_LAYER_SHELL_EDGE_ENTRY_NUMBER; i++)
- gtk_layer_set_margin (GTK_WINDOW(self), i, 0);
- gtk_layer_set_layer (GTK_WINDOW(self), GTK_LAYER_SHELL_LAYER_TOP);
- //gtk_layer_set_keyboard_mode (GTK_WINDOW(self), GTK_LAYER_SHELL_KEYBOARD_MODE_ON_DEMAND);
- // the top launcher shall be exclusive
- //gtk_layer_auto_exclusive_zone_enable (GTK_WINDOW(self));
+ gtk_layer_set_margin(GTK_WINDOW(self), i, 0);
+ gtk_layer_set_layer(GTK_WINDOW(self), GTK_LAYER_SHELL_LAYER_TOP);
+ // gtk_layer_set_keyboard_mode (GTK_WINDOW(self), GTK_LAYER_SHELL_KEYBOARD_MODE_ON_DEMAND);
+ // the top launcher shall be exclusive
+ // gtk_layer_auto_exclusive_zone_enable (GTK_WINDOW(self));
gtk_layer_set_keyboard_mode(GTK_WINDOW(self), GTK_LAYER_SHELL_KEYBOARD_MODE_ON_DEMAND);
// gtk_widget_set_can_focus(GTK_WIDGET(self), true);
- //gtk_widget_set_name(GTK_WIDGET(dashboard),NAMESPACE);
- //gtk_window_set_default_size(GTK_WINDOW(dashboard), 48, 48);
+ // gtk_widget_set_name(GTK_WIDGET(dashboard),NAMESPACE);
+ // gtk_window_set_default_size(GTK_WINDOW(dashboard), 48, 48);
// event controller
- //GtkEventController *event_controller = gtk_event_controller_key_new();
- //g_signal_connect(event_controller, "key-pressed", G_CALLBACK(on_diya_dashboard_key_press), self);
+ // GtkEventController *event_controller = gtk_event_controller_key_new();
+ // g_signal_connect(event_controller, "key-pressed", G_CALLBACK(on_diya_dashboard_key_press), self);
// gtk_widget_add_controller(GTK_WIDGET(self), event_controller);
+ self->list_model = g_object_new(DIYA_TYPE_DASHBOARD_LIST_MODEL, NULL);
+ self->sorter = GTK_SORTER(gtk_custom_sorter_new((GCompareDataFunc)diya_dashboard_app_info_cmp, NULL, NULL));
+ self->sort_model = gtk_sort_list_model_new(G_LIST_MODEL(self->list_model), self->sorter);
+ self->filter = GTK_FILTER(gtk_custom_filter_new((GtkCustomFilterFunc)diya_app_info_filter_func, self, NULL));
+ self->proxy_model = gtk_filter_list_model_new(G_LIST_MODEL(self->sort_model), self->filter);
+ gtk_flow_box_bind_model(GTK_FLOW_BOX(self->app_list_box), G_LIST_MODEL(self->proxy_model), diya_dashboard_create_app_icon_widget, self, NULL);
+
+ gtk_flow_box_set_selection_mode(GTK_FLOW_BOX(self->app_list_box), GTK_SELECTION_SINGLE);
+ gtk_flow_box_set_activate_on_single_click(GTK_FLOW_BOX(self->app_list_box), true);
+}
+
+static void diya_dashboard_show(DiyaDashboardWidget *self)
+{
+ gtk_window_present(GTK_WINDOW(self));
+ // gtk_widget_set_visible(GTK_WIDGET(self), true);
+ gtk_revealer_set_reveal_child(GTK_REVEALER(self->revealer), true);
+ gtk_window_set_focus(GTK_WINDOW(self), self->search_entry);
+ // gtk_widget_grab_focus( GTK_WIDGET(self->search_entry));
+ GList *apps = g_app_info_get_all();
+ GList *l;
+ for (l = apps; l != NULL; l = l->next)
+ {
+ GAppInfo *info = l->data;
+ if (diya_dashboard_list_model_contain(self->list_model, info))
+ {
+ continue;
+ }
+ g_debug("add AppInfo %s", g_app_info_get_id(info));
+ diya_dashboard_list_model_append(self->list_model, info);
+ }
+ g_list_free_full(apps, g_object_unref);
+ gtk_sorter_changed(self->sorter, GTK_SORTER_CHANGE_INVERTED);
+}
+
+static void diya_dashboard_hide(DiyaDashboardWidget *self)
+{
+ gtk_revealer_set_reveal_child(GTK_REVEALER(self->revealer), false);
+ gtk_widget_set_visible(GTK_WIDGET(self), false);
}
static void diya_dashboard_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
{
- DiyaDashboardWidget * self = DIYA_DASHBOARD_WIDGET(object);
+ DiyaDashboardWidget *self = DIYA_DASHBOARD_WIDGET(object);
switch (property_id)
{
case PROP_ACTIVE:
{
gboolean active = g_value_get_boolean(value);
- if(self->active == active)
+ if (self->active == active)
{
return;
}
self->active = active;
- if(self->active)
+ if (self->active)
{
- gtk_window_present(GTK_WINDOW(self));
- // gtk_widget_set_visible(GTK_WIDGET(self), true);
- gtk_revealer_set_reveal_child(GTK_REVEALER(self->revealer), true);
- gtk_window_set_focus(GTK_WINDOW(self), self->search_entry);
- // gtk_widget_grab_focus( GTK_WIDGET(self->search_entry));
+ diya_dashboard_show(self);
}
else
{
- gtk_revealer_set_reveal_child(GTK_REVEALER(self->revealer), false);
- gtk_widget_set_visible(GTK_WIDGET(self), false);
+ diya_dashboard_hide(self);
}
break;
}
default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
}
}
static void diya_dashboard_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
{
- DiyaDashboardWidget * self = DIYA_DASHBOARD_WIDGET(object);
+ DiyaDashboardWidget *self = DIYA_DASHBOARD_WIDGET(object);
switch (property_id)
{
case PROP_ACTIVE:
g_value_set_boolean(value, self->active);
break;
default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
}
}
-static void diya_dashboard_launch(GtkButton* btn, DiyaDashboardWidget* self)
-{
- g_debug("Clicked %d %d", DIYA_IS_DASHBOARD_WIDGET(self), GTK_IS_BUTTON(btn));
-
- GError* error = NULL;
- GAppInfo* app = g_app_info_create_from_commandline("gtk4example", "Gtk Example", G_APP_INFO_CREATE_NONE, &error);
- if(error)
- {
- g_critical("Unable to create app info: %s", error->message);
- g_error_free(error);
- return;
- }
- diya_shell_launch(diya_shell_window_get_shell(DIYA_SHELL_WINDOW(self)), app);
- g_object_set(self, DIYA_PROP_DASHBOARD_ACTIVE, false, NULL);
-
-}
-
-static void diya_dashboard_widget_class_init(DiyaDashboardWidgetClass* class)
+static void diya_dashboard_widget_class_init(DiyaDashboardWidgetClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
gobject_class->dispose = diya_dashboard_widget_dispose;
gobject_class->set_property = diya_dashboard_set_property;
gobject_class->get_property = diya_dashboard_get_property;
- //DiyaShellWindowClass* base_class = DIYA_SHELL_WINDOW_CLASS(class);
- //base_class->setup = diya_dashboard_widget_setup;
+ // DiyaShellWindowClass* base_class = DIYA_SHELL_WINDOW_CLASS(class);
+ // base_class->setup = diya_dashboard_widget_setup;
- gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),"/dev/iohub/diya/shell/dashboard.ui");
- gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), DiyaDashboardWidget, revealer);
- gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), DiyaDashboardWidget, search_entry);
+ gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS(class), "/dev/iohub/diya/shell/dashboard.ui");
+ gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), DiyaDashboardWidget, revealer);
+ gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), DiyaDashboardWidget, search_entry);
+ gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS(class), DiyaDashboardWidget, app_list_box);
- gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), diya_dashboard_launch);
+ gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), diya_dashboard_app_launch);
+ gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class), diya_dashboard_search_text_changed);
gtk_widget_class_set_css_name(GTK_WIDGET_CLASS(class), "diya-dashboard");
- //gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS (class), ExampleAppWindow, stack);
- //gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), search_text_changed);
+ // gtk_widget_class_bind_template_child(GTK_WIDGET_CLASS (class), ExampleAppWindow, stack);
+ // gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), search_text_changed);
- g_prop[PROP_ACTIVE] = g_param_spec_boolean(DIYA_PROP_DASHBOARD_ACTIVE, NULL, "Active the dashboard", false, G_PARAM_READWRITE); //
-
- g_object_class_install_properties (gobject_class, N_PROPERTIES, g_prop);
+ g_prop[PROP_ACTIVE] = g_param_spec_boolean(DIYA_PROP_DASHBOARD_ACTIVE, NULL, "Active the dashboard", false, G_PARAM_READWRITE); //
+
+ g_object_class_install_properties(gobject_class, N_PROPERTIES, g_prop);
}
-gboolean diya_dashboard_is_active(DiyaDashboardWidget* self)
+gboolean diya_dashboard_is_active(DiyaDashboardWidget *self)
{
return self->active;
}
\ No newline at end of file
diff --git a/src/widgets/dashboard-widget.h b/src/widgets/dashboard-widget.h
index cf09e3f..4410e97 100644
--- a/src/widgets/dashboard-widget.h
+++ b/src/widgets/dashboard-widget.h
@@ -9,6 +9,9 @@
#define DIYA_TYPE_DASHBOARD_WIDGET (diya_dashboard_widget_get_type())
G_DECLARE_FINAL_TYPE (DiyaDashboardWidget, diya_dashboard_widget, DIYA, DASHBOARD_WIDGET, DiyaShellWindow)
+#define DIYA_TYPE_DASHBOARD_LIST_MODEL (diya_dashboard_list_model_get_type())
+G_DECLARE_FINAL_TYPE (DiyaDashboardListModel, diya_dashboard_list_model, DIYA, DASHBOARD_LIST_MODEL, GObject)
+
gboolean diya_dashboard_is_active(DiyaDashboardWidget* self);
#endif
\ No newline at end of file