/* 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; }