feat: add base layout for dashboard applcation list
This commit is contained in:
parent
be7a573bef
commit
363d0d1678
@ -7,7 +7,7 @@ diya-taskbar
|
||||
|
||||
diya-dashboard
|
||||
{
|
||||
background-color: blue;
|
||||
background-color: lightgray;
|
||||
}
|
||||
|
||||
#diya_shell_background
|
||||
@ -15,3 +15,7 @@ diya-dashboard
|
||||
background-image:url("file:///etc/xdg/labwc/wpp.jpg");
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
flowbox flowboxchild {
|
||||
border: 5px solid black;
|
||||
}
|
@ -20,7 +20,7 @@
|
||||
<child>
|
||||
<object class="GtkSearchEntry" id="search_entry">
|
||||
<property name="hexpand">1</property>
|
||||
<!--signal name="search-changed" handler="search_text_changed"/-->
|
||||
<signal name="search-changed" handler="diya_dashboard_search_text_changed"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
@ -31,17 +31,52 @@
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="tmp">
|
||||
<property name="visible">1</property>
|
||||
<object class="GtkStack" id="stack">
|
||||
<property name="vexpand">1</property>
|
||||
<property name="label" translatable="yes">content</property>
|
||||
<property name="hexpand">1</property>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">app_list</property>
|
||||
<property name="title">Application list</property>
|
||||
<property name="child">
|
||||
<object class="GtkScrolledWindow" id="sidebar-sw">
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<child>
|
||||
<object class="GtkFlowBox" id="app_list_box">
|
||||
<property name="activate-on-single-click">1</property>
|
||||
<signal name="child-activated" handler="diya_dashboard_app_launch"/>
|
||||
</object>
|
||||
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">search_list</property>
|
||||
<property name="title">Search</property>
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<property name="label">second stack child</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child type="title">
|
||||
<object class="GtkStackSwitcher" id="tabs">
|
||||
<property name="stack">stack</property>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<!--child>
|
||||
<object class="GtkBox" id="taskbar">
|
||||
<property name="orientation">horizontal</property>
|
||||
<child>
|
||||
@ -52,7 +87,7 @@
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</child-->
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
|
@ -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,16 +111,93 @@ enum
|
||||
|
||||
static GParamSpec *g_prop[N_PROPERTIES] = {0};
|
||||
|
||||
|
||||
G_DEFINE_TYPE(DiyaDashboardWidget, diya_dashboard_widget, DIYA_TYPE_SHELL_WINDOW)
|
||||
|
||||
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_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");
|
||||
@ -57,6 +228,44 @@ static void diya_dashboard_widget_init(DiyaDashboardWidget * 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)
|
||||
@ -75,16 +284,11 @@ static void diya_dashboard_set_property(GObject *object, guint property_id, cons
|
||||
self->active = 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;
|
||||
}
|
||||
@ -108,23 +312,6 @@ static void diya_dashboard_get_property(GObject *object, guint property_id, GVal
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
|
||||
@ -138,8 +325,10 @@ static void diya_dashboard_widget_class_init(DiyaDashboardWidgetClass* class)
|
||||
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);
|
||||
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user