/*
Copyright (C) 2008 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authored by Neil Jagdish Patel
*
*/
#if HAVE_CONFIG_H
#include
#endif
#include
#include
#include "launcher-sidebar.h"
#include
#include
#include
#include
#include "clutter-focus-group.h"
#include "launcher-config.h"
#include "launcher-defines.h"
#include "clutter-drag-dest.h"
#include "clutter-drag-server.h"
#include "launcher-icon.h"
#include "launcher-shortcut.h"
#include "launcher-notify.h"
#include "launcher-util.h"
#include "launcher-quit.h"
static void clutter_focus_group_iface_init (ClutterFocusGroupIface *iface);
static void on_link_clicked (ClutterActor *shortcut, gpointer null);
G_DEFINE_TYPE_WITH_CODE (LauncherSidebar,
launcher_sidebar,
CLUTTER_TYPE_GROUP,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_FOCUS_GROUP,
clutter_focus_group_iface_init));
#define LAUNCHER_SIDEBAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
LAUNCHER_TYPE_SIDEBAR, \
LauncherSidebarPrivate))
#define NAUTILUS "xdg-open \"%s\""
struct _LauncherSidebarPrivate
{
GVolumeMonitor *monitor;
GFile *bookfile;
GFileMonitor *bookfile_mon;
ClutterActor *bg;
ClutterActor *clip;
ClutterActor *grid;
ClutterActor *scroll;
TidyAdjustment *adjust;
GList *shortcuts;
GList *links;
GList *places;
GSList *excluded_volumes;
ClutterActor *trash;
ClutterActor *focused;
ClutterTimeline *timeline;
ClutterEffectTemplate *temp;
};
enum
{
SHORTCUTS_CHANGED,
LAST_SIGNAL
};
static guint32 _sidebar_signals[LAST_SIGNAL] = { 0 };
GList *
launcher_sidebar_get_places (LauncherSidebar *sidebar)
{
LauncherSidebarPrivate *priv;
GList *places = NULL;
g_return_val_if_fail (LAUNCHER_IS_SIDEBAR (sidebar), NULL);
priv = sidebar->priv;
places = g_list_concat (places, g_list_copy (priv->shortcuts));
places = g_list_concat (places, g_list_copy (priv->places));
return places;
}
gboolean
launcher_sidebar_scroll_event (ClutterActor *actor,
ClutterScrollEvent *event,
LauncherSidebar *bar)
{
TidyAdjustment *adjust;
LauncherConfig *cfg = launcher_config_get_default ();
gdouble diff = cfg->shortcut_height;
gdouble lower, upper;
if (!LAUNCHER_IS_SIDEBAR (bar)) return FALSE;
adjust = bar->priv->adjust;
if (!TIDY_IS_ADJUSTMENT (adjust))
return TRUE;
if (event->direction == CLUTTER_SCROLL_UP)
diff = -cfg->icon_height;
diff += tidy_adjustment_get_value (adjust);
tidy_adjustment_get_values (adjust, NULL, &lower, &upper, NULL, NULL, NULL);
diff = CLAMP (diff, lower, upper);
tidy_adjustment_set_value (adjust, diff);
return TRUE;
}
static void
ensure_layout (LauncherSidebar *bar)
{
LauncherSidebarPrivate *priv;
LauncherConfig *cfg = launcher_config_get_default ();
TidyAdjustment *adjustment;
ClutterActor *scroll, *tex, *frame;
GList *s;
gint bar_width = cfg->bar_width;
gint bar_height = cfg->shortcut_height;
gint offset = 0;
gint i = 0;
g_return_if_fail (LAUNCHER_IS_SIDEBAR (bar));
priv = bar->priv;
for (s = priv->shortcuts; s; s = s->next)
{
ClutterActor *actor = s->data;
if (!CLUTTER_IS_ACTOR (actor))
continue;
clutter_actor_set_position (actor, 0, offset);
offset += bar_height;
i++;
}
for (s = priv->places; s; s = s->next)
{
ClutterActor *actor = s->data;
if (!CLUTTER_IS_ACTOR (actor))
continue;
clutter_actor_set_position (actor, 0, offset);
offset += bar_height;
i++;
}
clutter_actor_set_size (priv->grid, bar_width, i * bar_height);
if (i > N_CATS-2)
{
tidy_scrollable_get_adjustments (TIDY_SCROLLABLE (priv->grid),
NULL, &adjustment);
priv->adjust = adjustment;
tidy_adjustment_set_values (adjustment,
0,
0, i * bar_height,
bar_height,
1 * bar_width,
(N_CATS-2) * bar_height);
if (priv->scroll)
{
tidy_scroll_bar_set_adjustment (TIDY_SCROLL_BAR (priv->scroll),
adjustment);
return;
}
tex = launcher_util_texture_new_from_file (PKGDATADIR"/scrollbar.svg");
clutter_actor_set_opacity (tex, 0);
clutter_container_add_actor (CLUTTER_CONTAINER (priv->grid), tex);
frame = tidy_texture_frame_new (CLUTTER_TEXTURE (tex), 5, 5, 5, 5);
clutter_actor_set_reactive (CLUTTER_ACTOR (frame), TRUE);
g_signal_connect (frame, "scroll-event",
G_CALLBACK (launcher_sidebar_scroll_event), adjustment);
scroll = priv->scroll = tidy_scroll_bar_new_with_handle (priv->adjust,
frame);
frame = tidy_texture_frame_new (CLUTTER_TEXTURE (tex), 5, 5, 5, 5);
clutter_actor_set_reactive (CLUTTER_ACTOR (frame), TRUE);
g_signal_connect (frame, "scroll-event",
G_CALLBACK (launcher_sidebar_scroll_event), adjustment);
clutter_actor_set_reactive (CLUTTER_ACTOR (scroll), TRUE);
g_signal_connect (scroll, "scroll-event",
G_CALLBACK (launcher_sidebar_scroll_event), adjustment);
clutter_actor_set_opacity (frame, 100);
tidy_scroll_bar_set_texture (TIDY_SCROLL_BAR (scroll), frame);
clutter_container_add_actor (CLUTTER_CONTAINER (priv->clip), scroll);
clutter_actor_set_size (scroll, bar_height * (N_CATS-2) -2, 5);
clutter_actor_set_anchor_point_from_gravity (scroll,
CLUTTER_GRAVITY_CENTER);
clutter_actor_set_position (scroll,
bar_width- 10/2,
((bar_height*(N_CATS-2))/2) + 2);
clutter_actor_set_opacity (scroll, 100);
clutter_actor_set_rotation (scroll, CLUTTER_Z_AXIS, 90, 0, 0, 0);
clutter_actor_show (scroll);
}
else if (CLUTTER_IS_ACTOR (priv->scroll))
{
clutter_actor_set_opacity (priv->scroll, 0);
}
g_signal_emit (bar, _sidebar_signals[SHORTCUTS_CHANGED], 0);
}
static void
on_drag_started (ClutterDragServer *server, LauncherSidebar *bar)
{
LauncherSidebarPrivate *priv;
GList *a;
g_return_if_fail (LAUNCHER_IS_SIDEBAR (bar));
priv = bar->priv;
for (a = priv->links; a; a = a->next)
{
ClutterActor *actor = a->data;
if (actor != priv->trash)
clutter_effect_fade (priv->temp, actor, 50, NULL, NULL);
}
clutter_effect_fade (priv->temp, priv->grid, 50, NULL, NULL);
}
static void
on_drag_finished (ClutterDragServer *server, LauncherSidebar *bar)
{
LauncherSidebarPrivate *priv;
GList *a;
g_return_if_fail (LAUNCHER_IS_SIDEBAR (bar));
priv = bar->priv;
for (a = priv->links; a; a = a->next)
{
ClutterActor *actor = a->data;
clutter_effect_fade (priv->temp, actor, 255, NULL, NULL);
}
clutter_effect_fade (priv->temp, priv->grid, 255, NULL, NULL);
}
/*
* PLACES
*/
static void
on_places_mount (GFile *file, GAsyncResult *res, LauncherShortcut *shortcut)
{
ClutterTexture *temp;
GError *error = NULL;
gboolean success;
success = g_file_mount_enclosing_volume_finish (file, res, &error);
if (success)
{
g_app_info_launch_default_for_uri (g_file_get_uri (file), NULL, &error);
}
temp = launcher_shortcut_get_texture (LAUNCHER_SHORTCUT (shortcut));
launcher_notify_popup (launcher_notify_get_default (),
launcher_shortcut_get_label (LAUNCHER_SHORTCUT (shortcut)),
temp,
-1);
g_object_unref (file);
}
static void
on_place_clicked (ClutterActor *shortcut, gpointer null)
{
GVfs *vfs;
GFile *file;
const gchar *uri;
ClutterTexture *temp;
GError *error = NULL;
launcher_shortcut_set_active (LAUNCHER_SHORTCUT (shortcut), FALSE);
uri = clutter_actor_get_name (shortcut);
if (!uri)
return;
g_app_info_launch_default_for_uri (uri, NULL, &error);
if (error)
{
g_warning ("%s\n", error->message);
g_error_free (error);
vfs = g_vfs_get_default ();
file = g_vfs_get_file_for_uri (vfs, uri);
g_file_mount_enclosing_volume (file, 0, NULL, NULL,
(GAsyncReadyCallback)on_places_mount,
shortcut);
return;
}
temp = launcher_shortcut_get_texture (LAUNCHER_SHORTCUT (shortcut));
launcher_notify_popup (launcher_notify_get_default (),
launcher_shortcut_get_label (LAUNCHER_SHORTCUT (shortcut)),
temp,
-1);
}
static ClutterActor *
add_place (LauncherSidebar *sidebar,
const gchar *icon_name,
const gchar *name,
const gchar *command)
{
LauncherSidebarPrivate *priv = sidebar->priv;
ClutterActor *shortcut;
//g_print ("%s: %s\n", command, icon_name);
shortcut = launcher_shortcut_new (icon_name, name, FALSE);
clutter_container_add_actor (CLUTTER_CONTAINER (priv->grid), shortcut);
clutter_actor_set_name (shortcut, command);
clutter_actor_show_all(shortcut);
priv->places = g_list_append (priv->places, shortcut);
g_signal_connect (shortcut, "clicked", G_CALLBACK (on_place_clicked), NULL);
return shortcut;
}
static gchar *
get_icon_name_for_place (const gchar *uri)
{
GFile *file;
GFileInfo *info;
GIcon *icon = NULL;
const gchar * const *names;
GtkIconTheme *icon_theme;
int i;
file = g_file_new_for_uri (uri);
info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_ICON,
0, NULL, NULL);
if (info)
icon = (GIcon*)g_file_info_get_attribute_object (info,
G_FILE_ATTRIBUTE_STANDARD_ICON);
if (!G_IS_THEMED_ICON (icon))
{
g_object_unref (file);
if (info)
g_object_unref (info);
g_print ("Not themed icon: %s\n", uri);
return g_strdup ("folder");
}
names = g_themed_icon_get_names (G_THEMED_ICON (icon));
icon_theme = gtk_icon_theme_get_default ();
for (i = 0; names[i] != NULL; i++)
{
if (gtk_icon_theme_has_icon (icon_theme, names[i]))
{
gchar *ret = g_strdup (names[i]);
g_object_unref (file);
g_object_unref (info);
return ret;
}
}
g_object_unref (file);
g_object_unref (info);
return NULL;
}
static void
load_places (LauncherSidebar *bar)
{
LauncherSidebarPrivate *priv = bar->priv;
gchar *path, *contents;
path = g_build_filename (g_get_home_dir (), ".gtk-bookmarks", NULL);
/* Remove the old places */
g_list_foreach (priv->places, (GFunc)clutter_actor_destroy, NULL);
g_list_free (priv->places);
priv->places = NULL;
if (!g_file_test (path, G_FILE_TEST_EXISTS))
{
g_debug ("No gtk-bookmarks file. Cannot load places");
g_free (path);
return;
}
if (!g_file_get_contents (path, &contents, NULL, NULL))
{
g_debug ("Unable to read gtk-bookmarks file");
g_free (path);
return;
}
if (contents)
{
gchar **bookmarks;
gint i;
bookmarks = g_strsplit (contents, "\n", -1);
for (i = 0; bookmarks[i]; i++)
{
gchar *icon_name;
gchar *label;
label = strchr (bookmarks[i], ' ');
if (label)
{
*label = '\0';
label++;
}
else
{
label = strrchr (bookmarks[i], '/');
if (label)
label++;
}
if ((!label || !label[0])
&& !g_ascii_strcasecmp (bookmarks[i], "network:///"))
{
label = _("Network");
}
if (label)
{
icon_name = get_icon_name_for_place (bookmarks[i]);
add_place (bar, icon_name, label, bookmarks[i]);
g_free (icon_name);
}
}
g_strfreev (bookmarks);
g_free (contents);
}
ensure_layout (bar);
}
static void
on_places_changed (GFileMonitor *monitor,
GFile *file,
GFile *old_file,
GFileMonitorEvent event,
LauncherSidebar *bar)
{
g_return_if_fail (LAUNCHER_IS_SIDEBAR (bar));
load_places (bar);
}
/*
* VOLUMES
*/
static gboolean
volume_is_excluded (LauncherSidebar *bar, GVolume *volume)
{
LauncherSidebarPrivate *priv = bar->priv;
GSList *v;
gchar *uid;
uid = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_HAL_UDI);
if (!uid)
return FALSE;
for (v = priv->excluded_volumes; v; v = v->next)
{
if (v->data && strstr (uid, v->data))
{
g_free (uid);
return TRUE;
}
}
g_free (uid);
return FALSE;
}
static gboolean
can_eject (GVolume *volume)
{
if (!G_IS_VOLUME (volume))
{
return FALSE;
}
else if (g_volume_can_eject (volume))
{
return TRUE;
}
else if (g_volume_get_mount (volume))
{
return TRUE;
}
return FALSE;
}
static void
on_volume_mounted (GVolume *volume,
GAsyncResult *res,
LauncherShortcut *shortcut)
{
gboolean success;
GMount *mount;
GFile *root;
gchar *path, *command;
g_return_if_fail (G_IS_VOLUME (volume));
success = g_volume_mount_finish (volume, res, NULL);
if (!success)
return;
if (shortcut)
launcher_shortcut_set_active (LAUNCHER_SHORTCUT (shortcut), FALSE);
mount = g_volume_get_mount (volume);
if (!G_IS_MOUNT (mount))
{
return;
}
root = g_mount_get_root (mount);
path = g_file_get_uri (root);
command = g_strdup_printf (NAUTILUS, path);
gdk_spawn_command_line_on_screen (gdk_screen_get_default (),
command, NULL);
g_free (command);
g_free (path);
}
static void
on_volume_clicked (ClutterActor *shortcut, GVolume *volume)
{
GMount *mount;
GFile *root;
gchar *path, *command;
ClutterTexture *temp;
g_return_if_fail (G_IS_VOLUME (volume));
mount = g_volume_get_mount (volume);
if (!G_IS_MOUNT (mount))
{
if (!g_volume_can_mount (volume))
return;
g_volume_mount (volume, 0, NULL, NULL,
(GAsyncReadyCallback)on_volume_mounted, shortcut);
return;
}
root = g_mount_get_root (mount);
path = g_file_get_uri (root);
command = g_strdup_printf (NAUTILUS, path);
gdk_spawn_command_line_on_screen (gdk_screen_get_default (),
command, NULL);
/* Notify the user */
temp = launcher_shortcut_get_texture (LAUNCHER_SHORTCUT (shortcut));
launcher_notify_popup (launcher_notify_get_default (),
launcher_shortcut_get_label (LAUNCHER_SHORTCUT (shortcut)),
CLUTTER_TEXTURE (temp),
-1);
g_free (command);
g_free (path);
}
void
launcher_sidebar_launch_volume (LauncherSidebar *sidebar,
GVolume *volume)
{
GMount *mount;
GFile *root;
gchar *path, *command;
g_return_if_fail (G_IS_VOLUME (volume));
mount = g_volume_get_mount (volume);
if (!G_IS_MOUNT (mount))
{
if (!g_volume_can_mount (volume))
return;
g_volume_mount (volume, 0, NULL, NULL,
(GAsyncReadyCallback)on_volume_mounted, NULL);
return;
}
root = g_mount_get_root (mount);
path = g_file_get_uri (root);
command = g_strdup_printf (NAUTILUS, path);
gdk_spawn_command_line_on_screen (gdk_screen_get_default (),
command, NULL);
g_free (command);
g_free (path);
}
static void
on_volume_ejected (GVolume *volume,
GAsyncResult *res,
LauncherShortcut *shortcut)
{
g_volume_eject_finish (volume, res, NULL);
clutter_actor_set_opacity (CLUTTER_ACTOR (shortcut), 175);
}
static void
on_mount_unmounted (GMount *mount,
GAsyncResult *res,
LauncherShortcut *shortcut)
{
g_mount_unmount_finish (mount, res, NULL);
clutter_actor_set_opacity (CLUTTER_ACTOR (shortcut), 175);
}
static void
on_eject_clicked (ClutterActor *shortcut, GVolume *volume)
{
g_return_if_fail (G_IS_VOLUME (volume));
if (g_volume_can_eject (volume))
{
g_volume_eject (volume, 0, NULL,
(GAsyncReadyCallback)on_volume_ejected, shortcut);
}
else
{
GMount *mount = g_volume_get_mount (volume);
if (!mount)
return;
g_mount_unmount (mount, 0, NULL,
(GAsyncReadyCallback)on_mount_unmounted, shortcut);
}
}
static void
on_link_clicked (ClutterActor *shortcut, gpointer null)
{
const gchar *command;
ClutterTexture *temp;
launcher_shortcut_set_active (LAUNCHER_SHORTCUT (shortcut), FALSE);
command = clutter_actor_get_name (shortcut);
if (command)
gdk_spawn_command_line_on_screen (gdk_screen_get_default (),
command, NULL);
/* Notify the user */
temp = launcher_shortcut_get_texture (LAUNCHER_SHORTCUT (shortcut));
launcher_notify_popup (launcher_notify_get_default (),
launcher_shortcut_get_label (LAUNCHER_SHORTCUT (shortcut)),
temp,
-1);
}
static void
on_trash_clicked (ClutterActor *shortcut, gpointer null)
{
launcher_shortcut_set_active (LAUNCHER_SHORTCUT (shortcut), FALSE);
}
/* Taken from nautilus::panel-util.c, with some modifications */
static gchar *
get_icon_name (GVolume *volume)
{
GIcon *icon;
const gchar * const *names;
GtkIconTheme *icon_theme;
int i;
icon = g_volume_get_icon (volume);
if (!G_IS_THEMED_ICON (icon))
return g_strdup ("gnome-fs-folder");
names = g_themed_icon_get_names (G_THEMED_ICON (icon));
icon_theme = gtk_icon_theme_get_default ();
for (i = 0; names[i] != NULL; i++)
{
if (gtk_icon_theme_has_icon (icon_theme, names[i]))
return g_strdup (names[i]);
}
return NULL;
}
static void
on_volume_removed (GVolume *volume, LauncherShortcut *shortcut)
{
LauncherSidebar *bar = g_object_get_data (G_OBJECT (shortcut), "bar");
g_return_if_fail (LAUNCHER_IS_SIDEBAR (bar));
g_debug ("Volume removed: %s", g_volume_get_name (volume));
bar->priv->shortcuts = g_list_remove (bar->priv->shortcuts, shortcut);
clutter_actor_destroy (CLUTTER_ACTOR (shortcut));
ensure_layout (bar);
}
static void
on_volume_changed (GVolume *volume, LauncherShortcut *shortcut)
{
GMount *mount;
g_return_if_fail (LAUNCHER_IS_SHORTCUT (shortcut));
launcher_shortcut_set_can_eject (shortcut, can_eject (volume));
mount = g_volume_get_mount (volume);
if (G_IS_MOUNT (mount))
clutter_actor_set_opacity (CLUTTER_ACTOR (shortcut), 255);
else
clutter_actor_set_opacity (CLUTTER_ACTOR (shortcut), 175);
}
static void
on_volume_added (GVolumeMonitor *monitor,
GVolume *volume,
LauncherSidebar *sidebar)
{
LauncherSidebarPrivate *priv;
GMount *mount;
ClutterActor *shortcut;
gchar *icon_name = NULL;
g_return_if_fail (LAUNCHER_IS_SIDEBAR (sidebar));
priv = sidebar->priv;
g_debug ("Volume Added: %s %s",
g_volume_get_name (volume),
g_volume_get_identifier (volume,
G_VOLUME_IDENTIFIER_KIND_HAL_UDI));
icon_name = get_icon_name (volume);
shortcut = launcher_shortcut_new (icon_name,
g_volume_get_name (volume),
can_eject (volume));
clutter_container_add_actor (CLUTTER_CONTAINER (priv->grid), shortcut);
g_object_set_data (G_OBJECT (shortcut), "volume", volume);
g_object_set_data (G_OBJECT (shortcut), "bar", sidebar);
clutter_actor_show_all (shortcut);
mount = g_volume_get_mount (volume);
if (!G_IS_MOUNT (mount))
clutter_actor_set_opacity (shortcut, 175);
g_signal_connect (shortcut, "clicked",
G_CALLBACK (on_volume_clicked), volume);
g_signal_connect (shortcut, "eject",
G_CALLBACK (on_eject_clicked), volume);
g_signal_connect (volume, "changed",
G_CALLBACK (on_volume_changed), shortcut);
g_signal_connect (volume, "removed",
G_CALLBACK (on_volume_removed), shortcut);
priv->shortcuts = g_list_append (priv->shortcuts, shortcut);
ensure_layout (sidebar);
g_free (icon_name);
}
/*
* /VOLUMES
*/
/*
* Remove favourite stuff
*/
static gboolean
on_trashed (ClutterDragDest *dest, gpointer data)
{
LauncherMenuApplication *app = data;
if (!app)
return FALSE;
launcher_util_remove_favorite (app);
clutter_drag_dest_finish (dest, TRUE);
return TRUE;
}
void
launcher_sidebar_show_trash (LauncherSidebar *sidebar,
gboolean show)
{
LauncherConfig *cfg = launcher_config_get_default ();
LauncherSidebarPrivate *priv;
ClutterActor *shortcut;
g_return_if_fail (LAUNCHER_IS_SIDEBAR (sidebar));
priv = sidebar->priv;
if (launcher_config_get_default ()->is_portrait)
show = FALSE;
if (show)
{
if (CLUTTER_IS_ACTOR (priv->trash))
{
priv->links = g_list_remove (priv->links, priv->trash);
clutter_actor_destroy (priv->trash);
}
shortcut = priv->trash = launcher_shortcut_new ("gnome-fs-trash-empty",
_("Remove favorite"),
FALSE);
clutter_actor_set_position (shortcut, 0,
cfg->win_height -
(cfg->shortcut_height*2)-(PANEL_HEIGHT*2));
clutter_container_add_actor (CLUTTER_CONTAINER (sidebar), shortcut);
clutter_actor_show_all (shortcut);
clutter_drag_dest_enable (CLUTTER_DRAG_DEST (priv->trash));
g_signal_connect (priv->trash, "drop",
G_CALLBACK (on_trashed), NULL);
g_signal_connect (shortcut, "clicked",
G_CALLBACK (on_trash_clicked), NULL);
priv->links = g_list_prepend (priv->links, shortcut);
}
else
{
priv->links = g_list_remove (priv->links, priv->trash);
if (CLUTTER_IS_ACTOR (priv->trash))
clutter_actor_destroy (priv->trash);
priv->trash = NULL;
}
ensure_layout (sidebar);
}
/*
* FOCUS STUFF
*/
static void
launcher_sidebar_set_focus (ClutterFocusGroup *group, gboolean has_focus)
{
LauncherSidebarPrivate *priv = LAUNCHER_SIDEBAR (group)->priv;
if (has_focus)
{
priv->focused = priv->shortcuts->data;
launcher_shortcut_set_active (LAUNCHER_SHORTCUT (priv->focused), TRUE);
}
else
launcher_shortcut_set_active (LAUNCHER_SHORTCUT (priv->focused), FALSE);
}
static gboolean
launcher_sidebar_direction_event (ClutterFocusGroup *group,
ClutterFocusDirection dir)
{
LauncherSidebarPrivate *priv = LAUNCHER_SIDEBAR (group)->priv;
LauncherConfig *cfg = launcher_config_get_default ();
LauncherShortcut *new;
GList *children, *c;
gint bar_height = cfg->shortcut_height;
gint current;
gint next;
switch (dir)
{
case CLUTTER_DIRECTION_RIGHT:
case CLUTTER_DIRECTION_LEFT:
return TRUE;
default:
;
}
/* Move to the next or previous category,
* if category is first or last, return FALSE
* page up and page down takes you to top and bottom
*/
children = g_list_copy (priv->shortcuts);
children = g_list_concat (children, g_list_copy (priv->places));
children = g_list_concat (children, g_list_copy (priv->links));
current = next = g_list_index (children, priv->focused);
switch (dir)
{
case CLUTTER_DIRECTION_UP:
next -= 1;
break;
case CLUTTER_DIRECTION_DOWN:
next += 1;
break;
case CLUTTER_DIRECTION_PAGE_UP:
next = 0;
break;
case CLUTTER_DIRECTION_PAGE_DOWN:
next = g_list_length (children) -1;
break;
default:
break;
}
if (next < 0) next = 0;
next = CLAMP (next, 0, g_list_length (children)-1);
new = g_list_nth_data (children, next);
priv->focused = CLUTTER_ACTOR (new);
launcher_shortcut_set_active (new, TRUE);
for (c = children; c; c= c->next)
{
LauncherShortcut *shortcut = c->data;
if (!LAUNCHER_IS_SHORTCUT (shortcut))
continue;
if (shortcut != new)
launcher_shortcut_set_active (shortcut, FALSE);
}
if (TIDY_IS_ADJUSTMENT (priv->adjust))
{
gint y, pos, page;
y = tidy_adjustment_get_value (priv->adjust);
pos = bar_height * (next);
page = (N_CATS-2) * bar_height;
if (pos >= (y + page))
{
tidy_adjustment_set_value (priv->adjust, pos);
}
else if (pos < y)
{
tidy_adjustment_set_value (priv->adjust, pos);
}
}
g_list_free (children);
return TRUE;
}
static gboolean
launcher_sidebar_action_event (ClutterFocusGroup *group)
{
LauncherSidebarPrivate *priv = LAUNCHER_SIDEBAR (group)->priv;
launcher_shortcut_clicked (LAUNCHER_SHORTCUT (priv->focused));
return TRUE;
}
static gboolean
launcher_sidebar_key_event (ClutterFocusGroup *group, const gchar *string)
{
g_debug ("String event: %s", string);
return TRUE;
}
static void
clutter_focus_group_iface_init (ClutterFocusGroupIface *iface)
{
iface->set_focus = launcher_sidebar_set_focus;
iface->direction_event = launcher_sidebar_direction_event;
iface->key_event = launcher_sidebar_key_event;
iface->action_event = launcher_sidebar_action_event;
}
/*
* /FOCUS STUFF
*/
/* GObject stuff */
static void
launcher_sidebar_finalize (GObject *object)
{
LauncherSidebarPrivate *priv;
g_return_if_fail (LAUNCHER_IS_SIDEBAR (object));
priv = LAUNCHER_SIDEBAR (object)->priv;
g_object_unref (priv->monitor);
g_object_unref (priv->bookfile_mon);
g_object_unref (priv->bookfile);
g_list_free (priv->shortcuts);
g_list_free (priv->links);
g_list_free (priv->places);
g_slist_free (priv->excluded_volumes);
G_OBJECT_CLASS (launcher_sidebar_parent_class)->finalize (object);
}
static void
launcher_sidebar_class_init (LauncherSidebarClass *klass)
{
GObjectClass *obj_class = G_OBJECT_CLASS (klass);
obj_class->finalize = launcher_sidebar_finalize;
_sidebar_signals[SHORTCUTS_CHANGED] =
g_signal_new ("shortcuts-changed",
G_OBJECT_CLASS_TYPE (obj_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (LauncherSidebarClass, shortcuts_changed),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
g_type_class_add_private (obj_class, sizeof (LauncherSidebarPrivate));
}
static ClutterActor *
add_shortcut (LauncherSidebar *sidebar,
const gchar *icon_name,
const gchar *name,
const gchar *command)
{
LauncherSidebarPrivate *priv = sidebar->priv;
ClutterActor *shortcut;
shortcut = launcher_shortcut_new (icon_name, name, FALSE);
clutter_container_add_actor (CLUTTER_CONTAINER (priv->grid), shortcut);
clutter_actor_set_name (shortcut, command);
clutter_actor_show_all (shortcut);
priv->shortcuts = g_list_append (priv->shortcuts, shortcut);
g_signal_connect (shortcut, "clicked", G_CALLBACK (on_link_clicked), NULL);
return shortcut;
}
static void
on_quit_clicked (ClutterActor *shortcut, gpointer null)
{
GtkWidget *quit;
quit = launcher_quit_new ();
gtk_dialog_run (GTK_DIALOG (quit));
gtk_widget_destroy (quit);
}
static void
load_volumes (LauncherSidebar *sidebar)
{
LauncherSidebarPrivate *priv;
LauncherConfig *cfg = launcher_config_get_default ();
ClutterActor *shortcut;
GList *volumes, *vol;
gint bar_height = cfg->shortcut_height;
gchar *home, *network;
g_return_if_fail (LAUNCHER_IS_SIDEBAR (sidebar));
priv = sidebar->priv;
home = g_strdup_printf (NAUTILUS, g_get_home_dir ());
shortcut = add_shortcut (sidebar, "gnome-fs-home", _("Home"), home);
g_free (home);
network = g_strdup_printf (NAUTILUS, "network:///");
shortcut = add_shortcut (sidebar, "gnome-fs-network", _("Network"), network);
g_free (network);
volumes = g_volume_monitor_get_volumes (priv->monitor);
for (vol = volumes; vol; vol = vol->next)
{
GVolume *volume;
volume = vol->data;
if (volume_is_excluded (sidebar, volume))
{
g_object_unref (volume);
continue;
}
on_volume_added (priv->monitor, volume, sidebar);
g_object_unref (volume);
}
g_list_free (volumes);
ensure_layout (sidebar);
shortcut = launcher_shortcut_new ("gtk-quit",
_("Quit..."),
FALSE);
clutter_container_add_actor (CLUTTER_CONTAINER (sidebar), shortcut);
clutter_actor_set_position (shortcut, 0,
cfg->win_height - (bar_height)-(PANEL_HEIGHT*2));
clutter_actor_set_name (shortcut, "gnome-session-save --gui --kill");
clutter_actor_show_all (shortcut);
priv->links = g_list_append (priv->links, shortcut);
g_signal_connect (shortcut, "clicked", G_CALLBACK (on_quit_clicked), NULL);
}
static void
launcher_sidebar_init (LauncherSidebar *sidebar)
{
LauncherSidebarPrivate *priv;
LauncherConfig *cfg = launcher_config_get_default ();
GConfClient *client = gconf_client_get_default ();
ClutterDragServer *server = clutter_drag_server_get_default ();
gchar *path;
priv = sidebar->priv = LAUNCHER_SIDEBAR_GET_PRIVATE (sidebar);
priv->monitor = g_volume_monitor_get ();
priv->shortcuts = NULL;
priv->clip = clutter_group_new ();
clutter_container_add_actor (CLUTTER_CONTAINER (sidebar), priv->clip);
clutter_actor_set_position (priv->clip, 0, 0);
clutter_actor_set_clip (priv->clip, 0, 2, cfg->bar_width,
cfg->shortcut_height * (N_CATS-2) +2);
clutter_actor_show (priv->clip);
priv->grid = tidy_viewport_new ();
clutter_container_add_actor (CLUTTER_CONTAINER (priv->clip), priv->grid);
clutter_actor_set_position (priv->grid, 0, 0);
clutter_actor_show (priv->grid);
priv->timeline = clutter_timeline_new_for_duration (SLOW_TIME);
priv->temp = clutter_effect_template_new (priv->timeline,
clutter_sine_inc_func);
priv->excluded_volumes = gconf_client_get_list (client,
"/apps/netbook-launcher/volume_exclude_list",
GCONF_VALUE_STRING,
NULL);
load_volumes (sidebar);
load_places (sidebar);
/* Places monitor */
path = g_build_filename (g_get_home_dir (), ".gtk-bookmarks", NULL);
priv->bookfile = g_file_new_for_path (path);
priv->bookfile_mon = g_file_monitor_file (priv->bookfile, 0, NULL, NULL);
g_signal_connect (priv->bookfile_mon, "changed",
G_CALLBACK (on_places_changed), sidebar);
g_free (path);
g_signal_connect (priv->monitor, "volume-added",
G_CALLBACK (on_volume_added), sidebar);
clutter_actor_set_reactive (CLUTTER_ACTOR (sidebar), TRUE);
g_signal_connect (sidebar, "scroll-event",
G_CALLBACK (launcher_sidebar_scroll_event), sidebar);
g_signal_connect (priv->grid, "scroll-event",
G_CALLBACK (launcher_sidebar_scroll_event), sidebar);
/* Hook up drag server signals */
g_signal_connect (server, "drag-started",
G_CALLBACK (on_drag_started), sidebar);
g_signal_connect (server, "drag-finished",
G_CALLBACK (on_drag_finished), sidebar);
g_object_unref (client);
}
ClutterActor *
launcher_sidebar_get_default (void)
{
static ClutterActor *sidebar = NULL;
if (!sidebar)
sidebar = g_object_new (LAUNCHER_TYPE_SIDEBAR,
NULL);
return sidebar;
}