forked from AuroraMiddleware/gtk
386b63b85d
In 99.9% of all cases, these are just NULL, NULL. So just do away with these arguments, people can use the setters for the rare cases where they want the scrolled window to use a different adjustment.
203 lines
7.3 KiB
C
203 lines
7.3 KiB
C
/* Lists/Application launcher
|
|
*
|
|
* This demo uses the GtkListView widget as a fancy application launcher.
|
|
*
|
|
* It is also a very small introduction to listviews.
|
|
*/
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
/* This is the function that creates the #GListModel that we need.
|
|
* GTK list widgets need a #GListModel to display, as models support change
|
|
* notifications.
|
|
* Unfortunately various older APIs do not provide list models, so we create
|
|
* our own.
|
|
*/
|
|
static GListModel *
|
|
create_application_list (void)
|
|
{
|
|
GListStore *store;
|
|
GList *apps, *l;
|
|
|
|
/* We use a #GListStore here, which is a simple array-like list implementation
|
|
* for manual management.
|
|
* List models need to know what type of data they provide, so we need to
|
|
* provide the type here. As we want to do a list of applications, #GAppInfo
|
|
* is the object we provide.
|
|
*/
|
|
store = g_list_store_new (G_TYPE_APP_INFO);
|
|
|
|
apps = g_app_info_get_all ();
|
|
|
|
for (l = apps; l; l = l->next)
|
|
g_list_store_append (store, l->data);
|
|
|
|
g_list_free_full (apps, g_object_unref);
|
|
|
|
return G_LIST_MODEL (store);
|
|
}
|
|
|
|
/* This is the function we use for setting up new listitems to display.
|
|
* We add just an #GtkImage and a #GtkKabel here to display the application's
|
|
* icon and name, as this is just a simple demo.
|
|
*/
|
|
static void
|
|
setup_listitem_cb (GtkListItemFactory *factory,
|
|
GtkListItem *list_item)
|
|
{
|
|
GtkWidget *box;
|
|
GtkWidget *image;
|
|
GtkWidget *label;
|
|
|
|
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
|
|
image = gtk_image_new ();
|
|
gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
|
|
gtk_box_append (GTK_BOX (box), image);
|
|
label = gtk_label_new ("");
|
|
gtk_box_append (GTK_BOX (box), label);
|
|
gtk_list_item_set_child (list_item, box);
|
|
}
|
|
|
|
/* Here we need to prepare the listitem for displaying its item. We get the
|
|
* listitem already set up from the previous function, so we can reuse the
|
|
* #GtkImage widget we set up above.
|
|
* We get the item - which we know is a #GAppInfo because it comes out of
|
|
* the model we set up above, grab its icon and display it.
|
|
*/
|
|
static void
|
|
bind_listitem_cb (GtkListItemFactory *factory,
|
|
GtkListItem *list_item)
|
|
{
|
|
GtkWidget *image;
|
|
GtkWidget *label;
|
|
GAppInfo *app_info;
|
|
|
|
image = gtk_widget_get_first_child (gtk_list_item_get_child (list_item));
|
|
label = gtk_widget_get_next_sibling (image);
|
|
app_info = gtk_list_item_get_item (list_item);
|
|
|
|
gtk_image_set_from_gicon (GTK_IMAGE (image), g_app_info_get_icon (app_info));
|
|
gtk_label_set_label (GTK_LABEL (label), g_app_info_get_display_name (app_info));
|
|
}
|
|
|
|
/* In more complex code, we would also need functions to unbind and teardown
|
|
* the listitem, but this is simple code, so the default implementations are
|
|
* enough. If we had connected signals, this step would have been necessary.
|
|
*
|
|
* The #GtkSignalListItemFactory documentation contains more information about
|
|
* this step.
|
|
*/
|
|
|
|
/* This function is called whenever an item in the list is activated. This is
|
|
* the simple way to allow reacting to the Enter key or double-clicking on a
|
|
* listitem.
|
|
* Of course, it is possible to use far more complex interactions by turning
|
|
* off activation and adding buttons or other widgets in the setup function
|
|
* above, but this is a simple demo, so we'll use the simple way.
|
|
*/
|
|
static void
|
|
activate_cb (GtkListView *list,
|
|
guint position,
|
|
gpointer unused)
|
|
{
|
|
GAppInfo *app_info;
|
|
GdkAppLaunchContext *context;
|
|
GError *error = NULL;
|
|
|
|
app_info = g_list_model_get_item (gtk_list_view_get_model (list), position);
|
|
|
|
/* Prepare the context for launching the application and launch it. This
|
|
* code is explained in detail in the documentation for #GdkAppLaunchContext
|
|
* and #GAppInfo.
|
|
*/
|
|
context = gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (list)));
|
|
if (!g_app_info_launch (app_info,
|
|
NULL,
|
|
G_APP_LAUNCH_CONTEXT (context),
|
|
&error))
|
|
{
|
|
GtkWidget *dialog;
|
|
|
|
/* And because error handling is important, even a simple demo has it:
|
|
* We display an error dialog that something went wrong.
|
|
*/
|
|
dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (list))),
|
|
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
|
|
GTK_MESSAGE_ERROR,
|
|
GTK_BUTTONS_CLOSE,
|
|
"Could not launch %s", g_app_info_get_display_name (app_info));
|
|
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error->message);
|
|
g_clear_error (&error);
|
|
gtk_widget_show (dialog);
|
|
}
|
|
|
|
g_object_unref (context);
|
|
g_object_unref (app_info);
|
|
}
|
|
|
|
static GtkWidget *window = NULL;
|
|
|
|
GtkWidget *
|
|
do_listview_applauncher (GtkWidget *do_widget)
|
|
{
|
|
if (window == NULL)
|
|
{
|
|
GtkWidget *list, *sw;
|
|
GListModel *model;
|
|
GtkListItemFactory *factory;
|
|
|
|
/* Create a window and set a few defaults */
|
|
window = gtk_window_new ();
|
|
gtk_window_set_default_size (GTK_WINDOW (window), 640, 320);
|
|
gtk_window_set_display (GTK_WINDOW (window),
|
|
gtk_widget_get_display (do_widget));
|
|
gtk_window_set_title (GTK_WINDOW (window), "Application Launcher");
|
|
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
|
|
|
|
/* The #GtkListitemFactory is what is used to create #GtkListItems
|
|
* to display the data from the model. So it is absolutely necessary
|
|
* to create one.
|
|
* We will use a #GtkSignalListItemFactory because it is the simplest
|
|
* one to use. Different ones are available for different use cases.
|
|
* The most powerful one is #GtkBuilderListItemFactory which uses
|
|
* #GtkBuilder .ui files, so it requires little code.
|
|
*/
|
|
factory = gtk_signal_list_item_factory_new ();
|
|
g_signal_connect (factory, "setup", G_CALLBACK (setup_listitem_cb), NULL);
|
|
g_signal_connect (factory, "bind", G_CALLBACK (bind_listitem_cb), NULL);
|
|
|
|
/* Create the list widget here.
|
|
*/
|
|
list = gtk_list_view_new_with_factory (factory);
|
|
/* We connect the activate signal here. It's the function we defined
|
|
* above for launching the selected application.
|
|
*/
|
|
g_signal_connect (list, "activate", G_CALLBACK (activate_cb), NULL);
|
|
|
|
/* And of course we need to set the data model. Here we call the function
|
|
* we wrote above that gives us the list of applications. Then we set
|
|
* it on the list widget.
|
|
* The list will now take items from the model and use the factory
|
|
* to create as many listitems as it needs to show itself to the user.
|
|
*/
|
|
model = create_application_list ();
|
|
gtk_list_view_set_model (GTK_LIST_VIEW (list), model);
|
|
g_object_unref (model);
|
|
|
|
/* List widgets should always be contained in a #GtkScrolledWindow,
|
|
* because otherwise they might get too large or they might not
|
|
* be scrollable.
|
|
*/
|
|
sw = gtk_scrolled_window_new ();
|
|
gtk_window_set_child (GTK_WINDOW (window), sw);
|
|
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), list);
|
|
}
|
|
|
|
if (!gtk_widget_get_visible (window))
|
|
gtk_widget_show (window);
|
|
else
|
|
gtk_window_destroy (GTK_WINDOW (window));
|
|
|
|
return window;
|
|
}
|