Make the grid actually show real launchers

parent 33a812a3
......@@ -21,7 +21,7 @@ LT_INIT([disable-static])
PKG_PROG_PKG_CONFIG()
PKG_CHECK_MODULES([GTK], [wayland-client >= 1.0.2 gtk+-3.0 >= 3.7])
PKG_CHECK_MODULES([GTK], [wayland-client >= 1.0.2 gtk+-3.0 >= 3.7 libgnome-menu-3.0])
WAYLAND_SCANNER_RULES(['$(top_srcdir)/protocol'])
......
......@@ -3,10 +3,23 @@ libexec_PROGRAMS = weston-desktop-shell
AM_CFLAGS = $(GCC_CFLAGS)
AM_CPPFLAGS = $(CLIENT_CFLAGS) $(GTK_CFLAGS)
external_sources = \
egg-flow-box-accessible.c \
egg-flow-box-accessible.h \
egg-flow-box.c \
egg-flow-box.h
weston_desktop_shell_SOURCES = \
gtk-shell.c \
app-launcher.c \
app-launcher.h \
launcher-grid.c \
launcher-grid.h \
shell-app-system.c \
shell-app-system.h \
desktop-shell-client-protocol.h \
desktop-shell-protocol.c
desktop-shell-protocol.c \
$(external_sources)
weston_desktop_shell_LDADD = $(GTK_LIBS)
BUILT_SOURCES = \
......
/*
* Copyright (C) 2013 Collabora Ltd.
*
* Author: Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>
*/
#include "config.h"
#include "app-launcher.h"
#include <gio/gio.h>
#include <gio/gdesktopappinfo.h>
#include <gtk/gtk.h>
enum {
PROP_0,
PROP_INFO,
};
struct AppLauncherPrivate {
GDesktopAppInfo *info;
};
G_DEFINE_TYPE(AppLauncher, app_launcher, GTK_TYPE_BOX)
static void
get_property (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec)
{
AppLauncher *self = APP_LAUNCHER (object);
switch (param_id)
{
case PROP_INFO:
g_value_set_object (value, self->priv->info);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
static void
set_property (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec)
{
AppLauncher *self = APP_LAUNCHER (object);
switch (param_id)
{
case PROP_INFO:
self->priv->info = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
static void
app_launcher_dispose (GObject *object)
{
AppLauncher *self = APP_LAUNCHER (object);
g_clear_object (&self->priv->info);
G_OBJECT_CLASS (app_launcher_parent_class)->dispose (object);
}
static void
app_launcher_init (AppLauncher *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
APP_TYPE_LAUNCHER,
AppLauncherPrivate);
gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_VERTICAL);
}
static void
app_launcher_constructed (GObject *object)
{
AppLauncher *self = APP_LAUNCHER (object);
GtkWidget *label;
GtkWidget *image;
GIcon *icon;
icon = g_app_info_get_icon (G_APP_INFO (self->priv->info));
image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_LARGE_TOOLBAR);
gtk_box_pack_start (GTK_BOX (self), image, FALSE, FALSE, 6);
label = gtk_label_new (g_app_info_get_display_name (G_APP_INFO (self->priv->info)));
gtk_box_pack_start (GTK_BOX (self), label, FALSE, FALSE, 6);
}
static void
app_launcher_class_init (AppLauncherClass *klass)
{
GObjectClass *object_class = (GObjectClass *)klass;
object_class->constructed = app_launcher_constructed;
object_class->dispose = app_launcher_dispose;
object_class->get_property = get_property;
object_class->set_property = set_property;
g_object_class_install_property (object_class, PROP_INFO,
g_param_spec_object ("info",
"Info",
"The #GDesktopAppInfo that is being displayed",
G_TYPE_DESKTOP_APP_INFO,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_type_class_add_private (object_class, sizeof (AppLauncherPrivate));
}
GtkWidget *
app_launcher_new_from_desktop_info (GDesktopAppInfo *info)
{
return g_object_new (APP_TYPE_LAUNCHER,
"info", info,
NULL);
}
void
app_launcher_activate (AppLauncher *self)
{
GError *error = NULL;
g_app_info_launch (G_APP_INFO (self->priv->info), NULL, NULL, &error);
if (error)
{
g_warning ("Could not launch app %s: %s",
g_app_info_get_name (G_APP_INFO (self->priv->info)),
error->message);
g_clear_error (&error);
}
}
/*
* Copyright (C) 2013 Collabora Ltd.
*
* Author: Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>
*/
#ifndef __APP_LAUNCHER_H__
#define __APP_LAUNCHER_H__
#include <gio/gio.h>
#include <gio/gdesktopappinfo.h>
#include <gtk/gtk.h>
#define APP_TYPE_LAUNCHER (app_launcher_get_type ())
#define APP_LAUNCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), APP_TYPE_LAUNCHER, AppLauncher))
#define APP_LAUNCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), APP_TYPE_LAUNCHER, AppLauncherClass))
#define APP_IS_LAUNCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), APP_TYPE_LAUNCHER))
#define APP_IS_LAUNCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), APP_TYPE_LAUNCHER))
#define APP_LAUNCHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), APP_TYPE_LAUNCHER, AppLauncherClass))
typedef struct AppLauncher AppLauncher;
typedef struct AppLauncherClass AppLauncherClass;
typedef struct AppLauncherPrivate AppLauncherPrivate;
struct AppLauncher
{
GtkBox parent;
AppLauncherPrivate *priv;
};
struct AppLauncherClass
{
GtkBoxClass parent_class;
};
GType app_launcher_get_type (void) G_GNUC_CONST;
GtkWidget *app_launcher_new_from_desktop_info (GDesktopAppInfo *info);
void app_launcher_activate (AppLauncher *self);
#endif /* __APP_LAUNCHER_H__ */
/*
* Copyright (C) 2013 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "egg-flow-box.h"
#include "egg-flow-box-accessible.h"
static void atk_selection_interface_init (AtkSelectionIface *iface);
G_DEFINE_TYPE_WITH_CODE (EggFlowBoxAccessible, egg_flow_box_accessible, GTK_TYPE_CONTAINER_ACCESSIBLE,
G_IMPLEMENT_INTERFACE (ATK_TYPE_SELECTION, atk_selection_interface_init))
static void
egg_flow_box_accessible_init (EggFlowBoxAccessible *accessible)
{
}
static void
egg_flow_box_accessible_initialize (AtkObject *obj,
gpointer data)
{
ATK_OBJECT_CLASS (egg_flow_box_accessible_parent_class)->initialize (obj, data);
obj->role = ATK_ROLE_LIST_BOX;
}
static AtkStateSet*
egg_flow_box_accessible_ref_state_set (AtkObject *obj)
{
AtkStateSet *state_set;
GtkWidget *widget;
state_set = ATK_OBJECT_CLASS (egg_flow_box_accessible_parent_class)->ref_state_set (obj);
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
if (widget != NULL)
atk_state_set_add_state (state_set, ATK_STATE_MANAGES_DESCENDANTS);
return state_set;
}
static void
egg_flow_box_accessible_class_init (EggFlowBoxAccessibleClass *klass)
{
AtkObjectClass *object_class = ATK_OBJECT_CLASS (klass);
object_class->initialize = egg_flow_box_accessible_initialize;
object_class->ref_state_set = egg_flow_box_accessible_ref_state_set;
}
static gboolean
egg_flow_box_accessible_add_selection (AtkSelection *selection,
gint idx)
{
GtkWidget *box;
GList *children;
GtkWidget *child;
box = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
if (box == NULL)
return FALSE;
children = gtk_container_get_children (GTK_CONTAINER (box));
child = g_list_nth_data (children, idx);
g_list_free (children);
if (child)
{
egg_flow_box_select_child (EGG_FLOW_BOX (box), child);
return TRUE;
}
return FALSE;
}
static gboolean
egg_flow_box_accessible_remove_selection (AtkSelection *selection,
gint idx)
{
GtkWidget *box;
GList *children;
GtkWidget *child;
box = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
if (box == NULL)
return FALSE;
children = gtk_container_get_children (GTK_CONTAINER (box));
child = g_list_nth_data (children, idx);
g_list_free (children);
if (child)
{
egg_flow_box_unselect_child (EGG_FLOW_BOX (box), child);
return TRUE;
}
return FALSE;
}
static gboolean
egg_flow_box_accessible_clear_selection (AtkSelection *selection)
{
GtkWidget *box;
box = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
if (box == NULL)
return FALSE;
egg_flow_box_unselect_all (EGG_FLOW_BOX (box));
return TRUE;
}
static gboolean
egg_flow_box_accessible_select_all (AtkSelection *selection)
{
GtkWidget *box;
box = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
if (box == NULL)
return FALSE;
egg_flow_box_select_all (EGG_FLOW_BOX (box));
return TRUE;
}
typedef struct
{
gint idx;
GtkWidget *child;
} FindSelectedData;
static void
find_selected_child (EggFlowBox *box,
GtkWidget *child,
gpointer data)
{
FindSelectedData *d = data;
if (d->idx == 0)
{
if (d->child == NULL)
d->child = child;
}
else
d->idx -= 1;
}
static AtkObject *
egg_flow_box_accessible_ref_selection (AtkSelection *selection,
gint idx)
{
GtkWidget *box;
GtkWidget *widget;
AtkObject *accessible;
FindSelectedData data;
box = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
if (box == NULL)
return NULL;
data.idx = idx;
data.child = NULL;
egg_flow_box_selected_foreach (EGG_FLOW_BOX (box), find_selected_child, &data);
if (data.child == NULL)
return NULL;
accessible = gtk_widget_get_accessible (data.child);
g_object_ref (accessible);
return accessible;
}
static void
count_selected (EggFlowBox *box,
GtkWidget *child,
gpointer data)
{
gint *count = data;
*count += 1;
}
static gint
egg_flow_box_accessible_get_selection_count (AtkSelection *selection)
{
GtkWidget *box;
gint count;
box = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
if (box == NULL)
return 0;
count = 0;
egg_flow_box_selected_foreach (EGG_FLOW_BOX (box), count_selected, &count);
return count;
}
static gboolean
egg_flow_box_accessible_is_child_selected (AtkSelection *selection,
gint idx)
{
GtkWidget *box;
GtkWidget *widget;
GList *children;
GtkWidget *child;
box = gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
if (box == NULL)
return FALSE;
children = gtk_container_get_children (GTK_CONTAINER (box));
child = g_list_nth_data (children, idx);
g_list_free (children);
return egg_flow_box_is_child_selected (EGG_FLOW_BOX (box), child);
}
static void atk_selection_interface_init (AtkSelectionIface *iface)
{
iface->add_selection = egg_flow_box_accessible_add_selection;
iface->clear_selection = egg_flow_box_accessible_clear_selection;
iface->ref_selection = egg_flow_box_accessible_ref_selection;
iface->get_selection_count = egg_flow_box_accessible_get_selection_count;
iface->is_child_selected = egg_flow_box_accessible_is_child_selected;
}
void
_egg_flow_box_accessible_selection_changed (GtkWidget *box)
{
AtkObject *accessible;
accessible = gtk_widget_get_accessible (box);
g_signal_emit_by_name (accessible, "selection-changed");
}
void
_egg_flow_box_accessible_update_cursor (GtkWidget *box,
GtkWidget *child)
{
AtkObject *accessible;
AtkObject *descendant;
accessible = gtk_widget_get_accessible (box);
descendant = child ? gtk_widget_get_accessible (child) : NULL;
g_signal_emit_by_name (accessible, "active-descendant-changed", descendant);
}
/*
* Copyright (C) 2013 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __EGG_FLOW_BOX_ACCESSIBLE_H__
#define __EGG_FLOW_BOX_ACCESSIBLE_H__
#include <gtk/gtk-a11y.h>
G_BEGIN_DECLS
#define EGG_TYPE_FLOW_BOX_ACCESSIBLE (egg_flow_box_accessible_get_type ())
#define EGG_FLOW_BOX_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_FLOW_BOX_ACCESSIBLE, EggFlowBoxAccessible))
#define EGG_FLOW_BOX_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_FLOW_BOX_ACCESSIBLE, EggFlowBoxAccessibleClass))
#define EGG_IS_FLOW_BOX_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_FLOW_BOX_ACCESSIBLE))
#define EGG_IS_FLOW_BOX_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_FLOW_BOX_ACCESSIBLE))
#define EGG_FLOW_BOX_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_FLOW_BOX_ACCESSIBLE, EggFlowBoxAccessibleClass))
typedef struct _EggFlowBoxAccessible EggFlowBoxAccessible;
typedef struct _EggFlowBoxAccessibleClass EggFlowBoxAccessibleClass;
typedef struct _EggFlowBoxAccessiblePrivate EggFlowBoxAccessiblePrivate;
struct _EggFlowBoxAccessible
{
GtkContainerAccessible parent;
EggFlowBoxAccessiblePrivate *priv;
};
struct _EggFlowBoxAccessibleClass
{
GtkContainerAccessibleClass parent_class;
};
GType egg_flow_box_accessible_get_type (void);
void _egg_flow_box_accessible_selection_changed (GtkWidget *box);
void _egg_flow_box_accessible_update_cursor (GtkWidget *box, GtkWidget *child);
G_END_DECLS
#endif /* __EGG_FLOW_BOX_ACCESSIBLE_H__ */
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* Copyright (C) 2010 Openismus GmbH
* Copyright (C) 2013 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Authors:
* Tristan Van Berkom <tristanvb@openismus.com>
* Matthias Clasen <mclasen@redhat.com>
* William Jon McCann <jmccann@redhat.com>
*/
#ifndef __EGG_FLOW_BOX_H__
#define __EGG_FLOW_BOX_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define EGG_TYPE_FLOW_BOX (egg_flow_box_get_type ())
#define EGG_FLOW_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_FLOW_BOX, EggFlowBox))
#define EGG_FLOW_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_FLOW_BOX, EggFlowBoxClass))
#define EGG_IS_FLOW_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_FLOW_BOX))
#define EGG_IS_FLOW_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_FLOW_BOX))
#define EGG_FLOW_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_FLOW_BOX, EggFlowBoxClass))
typedef struct _EggFlowBox EggFlowBox;
typedef struct _EggFlowBoxPrivate EggFlowBoxPrivate;
typedef struct _EggFlowBoxClass EggFlowBoxClass;
/**
* EggFlowBoxForeachFunc:
* @flow_box: an #EggFlowBox
* @child: The child #GtkWidget
* @data: user data
*
* A function used by egg_flow_box_selected_foreach() to map all
* selected children. It will be called on every selected child in the box.
*/
typedef void (* EggFlowBoxForeachFunc) (EggFlowBox *flow_box,
GtkWidget *child,
gpointer data);
struct _EggFlowBox
{
GtkContainer container;
/*< private >*/
EggFlowBoxPrivate *priv;
};
struct _EggFlowBoxClass
{
GtkContainerClass parent_class;
void (* child_activated) (EggFlowBox *self, GtkWidget *child);
void (* selected_children_changed) (EggFlowBox *self);
void (*activate_cursor_child) (EggFlowBox *self);
void (*toggle_cursor_child) (EggFlowBox *self);
void (*move_cursor) (EggFlowBox *self, GtkMovementStep step, gint count);
void (*select_all) (EggFlowBox *self);
void (*unselect_all) (EggFlowBox *self);
};
GType egg_flow_box_get_type (void) G_GNUC_CONST;
GtkWidget *egg_flow_box_new (void);
void egg_flow_box_set_homogeneous (EggFlowBox *box,
gboolean homogeneous);
gboolean egg_flow_box_get_homogeneous (EggFlowBox *box);
void egg_flow_box_set_halign_policy (EggFlowBox *box,
GtkAlign align);
GtkAlign egg_flow_box_get_halign_policy (EggFlowBox *box);
void egg_flow_box_set_valign_policy (EggFlowBox *box,
GtkAlign align);
GtkAlign egg_flow_box_get_valign_policy (EggFlowBox *box);
void egg_flow_box_set_row_spacing (EggFlowBox *box,
guint spacing);
guint egg_flow_box_get_row_spacing (EggFlowBox *box);
void egg_flow_box_set_column_spacing (EggFlowBox *box,
guint spacing);
guint egg_flow_box_get_column_spacing (EggFlowBox *box);
void egg_flow_box_set_min_children_per_line (EggFlowBox *box,
guint n_children);
guint egg_flow_box_get_min_children_per_line (EggFlowBox *box);
void egg_flow_box_set_max_children_per_line (EggFlowBox *box,
guint n_children);
guint egg_flow_box_get_max_children_per_line (EggFlowBox *box);
gboolean egg_flow_box_get_activate_on_single_click (EggFlowBox *box);
void egg_flow_box_set_activate_on_single_click (EggFlowBox *box,
gboolean single);
GList *egg_flow_box_get_selected_children (EggFlowBox *box);
void egg_flow_box_selected_foreach (EggFlowBox *box,
EggFlowBoxForeachFunc func,
gpointer data);
void egg_flow_box_select_child (EggFlowBox *box,
GtkWidget *child);
void egg_flow_box_unselect_child (EggFlowBox *box,
GtkWidget *child);
void egg_flow_box_select_all (EggFlowBox *box);
void egg_flow_box_unselect_all (EggFlowBox *box);
gboolean egg_flow_box_is_child_selected (EggFlowBox *box,
GtkWidget *child);
GtkSelectionMode egg_flow_box_get_selection_mode (EggFlowBox *box);
void egg_flow_box_set_selection_mode (EggFlowBox *box,
GtkSelectionMode mode);
void egg_flow_box_set_adjustment (EggFlowBox *box,
GtkAdjustment *adjustment);
G_END_DECLS
#endif /* __EGG_FLOW_BOX_H__ */
......@@ -5,6 +5,7 @@
#include <gdk/gdkwayland.h>
#include "desktop-shell-client-protocol.h"
#include "launcher-grid.h"
extern char **environ; /* defined by libc */
......@@ -68,10 +69,8 @@ static const struct desktop_shell_listener listener = {
static void
launcher_grid_create (struct desktop *desktop)
{
GdkWindow *gdk_window;
struct element *launcher_grid;
GtkWidget *grid;
GtkWidget *launcher;
launcher_grid = malloc (sizeof *launcher_grid);
memset (launcher_grid, 0, sizeof *launcher_grid);
......@@ -82,11 +81,7 @@ launcher_grid_create (struct desktop *desktop)
gtk_window_set_decorated(GTK_WINDOW(launcher_grid->window), FALSE);
gtk_widget_realize(launcher_grid->window);
grid = gtk_grid_new ();
launcher = gtk_image_new_from_icon_name ("gnome-terminal", GTK_ICON_SIZE_LARGE_TOOLBAR);
gtk_container_add (GTK_CONTAINER (grid), launcher);
grid = launcher_grid_new ();
gtk_container_add (GTK_CONTAINER (launcher_grid->window), grid);
......
/*
* Copyright (C) 2013 Collabora Ltd.
*
* Author: Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>
*/
#include "launcher-grid.h"
#include <gtk/gtk.h>
#include "app-launcher.h"
#include "shell-app-system.h"
#include "egg-flow-box.h"
static void
child_activated_cb (GtkWidget *grid,
GtkWidget *widget,
GtkWidget *scrolled_window)
{
AppLauncher *app = APP_LAUNCHER (widget);
app_launcher_activate (app);
/* A menu item has been activated so let's hide the menu */
gtk_widget_hide (gtk_widget_get_parent (scrolled_window));
}
static void
installed_changed_cb (ShellAppSystem *app_system, GtkWidget *grid)
{
GHashTable *entries = shell_app_system_get_entries (app_system);
GHashTableIter iter;
gpointer key, value;
/* FIXME: if the tree changes while we're running, we'll readd entries
* that haven't been removed from the tree, so we'll get lots of dups */
g_hash_table_iter_init (&iter, entries);
while (g_hash_table_iter_next (&iter, &key, &value))
{
GDesktopAppInfo *info = value;
GtkWidget *app = app_launcher_new_from_desktop_info (info);
gtk_container_add (GTK_CONTAINER (grid), app);
}
gtk_widget_show_all (grid);
}
GtkWidget *
launcher_grid_new (void)
{
GtkWidget *scrolled_window;
GtkWidget *grid;