Logo Search packages:      
Sourcecode: netbook-launcher version File versions

launcher-app.c

/*
 * 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 <http://www.gnu.org/licenses/>.
 *
 * Authored by Neil Jagdish Patel <neil.patel@canonical.com>
 *
 */

#if HAVE_CONFIG_H
#include <config.h>
#endif

#include "launcher-app.h"

#include <glib.h>
#include <glib/gi18n.h>
#include <gio/gio.h>
#include <string.h>
#include <stdlib.h>

#include <clutter-gtk/gtk-clutter-util.h>
#include <tidy/tidy.h>

#include <gconf/gconf.h>
#include <gconf/gconf-client.h>

#include "clutter-focus-manager.h"

#include "launcher-background.h"
#include "launcher-catbar.h"
#include "launcher-config.h"
#include "launcher-defines.h"
#include "launcher-iconview.h"
#include "launcher-link-editor.h"
#include "launcher-menu.h"
#include "launcher-sidebar.h"
#include "launcher-startup.h"
#include "launcher-util.h"
#include "launcher-wm.h"

#define LINK_WATCH_DIR "/tmp/webfav"

G_DEFINE_TYPE (LauncherApp, launcher_app, CLUTTER_TYPE_GROUP);

#define LAUNCHER_APP_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
  LAUNCHER_TYPE_APP, \
  LauncherAppPrivate))

struct _LauncherAppPrivate
{
  gboolean windowed;

  LauncherWm   *wm;
  LauncherMenu *menu;
  
  ClutterActor *focus_manager;
  
  ClutterActor *bg;
  ClutterActor *shadow;
  ClutterActor *window;
  ClutterActor *ubuntu;
  ClutterActor *catbar;
  ClutterActor *iconviewbg;
  ClutterActor *iconview;
  ClutterActor *sidebar;

  ClutterTimeline       *time;
  ClutterEffectTemplate *temp;

  GFile *watch_dir;
  GFileMonitor *dir_monitor;
};

/* Callbacks */
static void
on_new_category (LauncherCatbar       *catbar,
                 LauncherMenuCategory *category,
                 LauncherApp          *app)
{
  LauncherAppPrivate *priv;
  LauncherConfig *cfg = launcher_config_get_default ();

  g_return_if_fail (LAUNCHER_IS_APP (app));
  g_return_if_fail (category);
  priv = app->priv;

  if (CLUTTER_IS_ACTOR (priv->iconview))
  {
    clutter_effect_fade (priv->temp, priv->iconview, 0,
                         (ClutterEffectCompleteFunc)clutter_actor_destroy, 
                         NULL);
  }

  priv->iconview = launcher_iconview_new ();
  clutter_container_add_actor (CLUTTER_CONTAINER (app),
                               priv->iconview);
  clutter_actor_set_position (priv->iconview, 
                         clutter_actor_get_x (priv->window)+cfg->bar_width-3,
                              PANEL_HEIGHT*2.3+PADDING);

  clutter_actor_show (priv->iconview);
  clutter_focus_manager_insert_group(CLUTTER_FOCUS_MANAGER(priv->focus_manager),
                                     CLUTTER_FOCUS_GROUP (priv->iconview),
                                     1);


  launcher_iconview_set_category (LAUNCHER_ICONVIEW (priv->iconview), category);
}

static gboolean
on_scroll_event (ClutterActor       *actor,
                 ClutterScrollEvent *event,
                 LauncherApp        *app)
{
  g_return_val_if_fail (LAUNCHER_IS_APP (app), FALSE);
  
  if (!LAUNCHER_IS_ICONVIEW (app->priv->iconview))
    return FALSE;

  return launcher_iconview_scroll_event (actor, event, 
                                         LAUNCHER_ICONVIEW (app->priv->iconview)
                                         );
}

static gboolean
eat_event (ClutterActor *stage, ClutterEvent *event, LauncherApp *app)
{
  gint opacity = clutter_actor_get_opacity (CLUTTER_ACTOR (app));

  if (opacity == 255)
  {
    g_signal_handlers_disconnect_by_func (stage, eat_event, app);
    clutter_ungrab_pointer ();
    return FALSE;
  }
  

  return TRUE;
}

static void
ungrab (ClutterActor *actor, LauncherApp *app)
{
  clutter_ungrab_pointer ();
  g_signal_handlers_disconnect_by_func (clutter_stage_get_default (), 
                                        eat_event, app);
}

static void
show_launcher (LauncherWm *wm, LauncherApp *app)
{ 
  LauncherAppPrivate *priv;

  g_return_if_fail (LAUNCHER_IS_APP (app));
  priv = app->priv;

  clutter_effect_fade (priv->temp, CLUTTER_ACTOR (app), 255, 
                       (ClutterEffectCompleteFunc)ungrab,
                       app);
}


static void
hide_launcher (LauncherWm *wm, WnckWindow *window, LauncherApp *app)
{
  LauncherAppPrivate *priv;

  g_return_if_fail (LAUNCHER_IS_APP (app));
  priv = app->priv;

  if (priv->windowed)
    return;

  clutter_effect_fade (priv->temp, CLUTTER_ACTOR (app), 50, NULL, NULL);

  clutter_grab_pointer (clutter_stage_get_default ());
  g_signal_connect (clutter_stage_get_default (),
                                    "captured-event", G_CALLBACK (eat_event), 
                                    app);
}

/*
 * External link watching 
 */
static gchar *
save_favion (const gchar *path)
{
#define ICON_DIR ".config/netbook-remix--launcher/icons"
  GFile *from;
  GFile *to;
  gchar *new_path, *temp, *leaf;

  from = g_file_new_for_path (path);

  temp = g_filename_display_basename (path);
  leaf = g_strdup_printf ("%ld-%s", time (NULL), temp);
  new_path = g_build_filename (g_get_home_dir (),  ICON_DIR, leaf, NULL);
  to = g_file_new_for_path (new_path);

  g_file_move (from, to, 0, NULL, NULL, NULL, NULL);

  g_free (temp);
  g_free (leaf);
  g_object_unref (from);
  g_object_unref (to);

  return new_path;
}

static void
on_link_reponse (GtkWidget *dialog, gint res, LauncherApp *app)
{
  if (!LAUNCHER_IS_APP (app))
  {
    gtk_widget_destroy (dialog);
    return;
  }

  if (res == GTK_RESPONSE_YES)
  {

     gchar *name = NULL, *exec = NULL, *icon_name = NULL, *real_icon;
     g_object_get (dialog, 
                   "link-name", &name,
                   "link-exec", &exec,
                   "link-icon", &icon_name,
                   NULL);
     real_icon = save_favion (icon_name);
     launcher_util_add_favorite (name, "Favorites", exec, real_icon);

     g_free (name);
     g_free (exec);
     g_free (icon_name);
     g_free (real_icon);
  }

  gtk_widget_destroy (dialog);
}


static void
on_watch_dir_changed (GFileMonitor      *monitor,
                      GFile             *file,
                      GFile             *other_file,
                      GFileMonitorEvent  event,
                      LauncherApp       *app)
{
  LauncherAppPrivate *priv;
  gchar *link_path;

  g_return_if_fail (LAUNCHER_IS_APP (app));
  priv = app->priv;

  if (event != G_FILE_MONITOR_EVENT_CREATED)
    return;

  link_path = g_file_get_path (file);
  if (link_path && strstr (link_path, ".desktop"))
  {
    GKeyFile *file;
    
    file = g_key_file_new ();
    if (g_key_file_load_from_file (file, link_path, 0, NULL))
    {
      GtkWidget *dialog;
      gchar *icon_path;
      
      icon_path = g_build_filename (LINK_WATCH_DIR, 
                                    g_key_file_get_string (file, 
                                                      G_KEY_FILE_DESKTOP_GROUP,
                                           G_KEY_FILE_DESKTOP_KEY_ICON, NULL),
                                    NULL);
      dialog = launcher_link_editor_new ();
      g_object_set (dialog, 
                "title", _("Add Shortcut"),
                "link-name", 
                  g_key_file_get_string (file, G_KEY_FILE_DESKTOP_GROUP,
                                         G_KEY_FILE_DESKTOP_KEY_NAME, NULL),
                "link-exec",
                  g_key_file_get_string (file, G_KEY_FILE_DESKTOP_GROUP,
                                         G_KEY_FILE_DESKTOP_KEY_URL, NULL),
                "link-icon", icon_path,
                NULL);
      gtk_dialog_add_buttons (GTK_DIALOG (dialog), 
                              "gtk-cancel", GTK_RESPONSE_CANCEL,
                              GTK_STOCK_APPLY, GTK_RESPONSE_YES,
                              NULL);
      g_signal_connect (dialog, "response",
                        G_CALLBACK (on_link_reponse), app);
                                   
      launcher_util_present_window (GTK_WINDOW (dialog));
      g_free (icon_path);
    }
    g_key_file_free (file);
  }
 

  g_free (link_path);
}

static void
watch_links (LauncherApp *app)
{
  LauncherAppPrivate *priv = app->priv;
  GFile *dir;

  g_mkdir_with_parents (LINK_WATCH_DIR, 0700);

  dir = priv->watch_dir = g_file_new_for_path (LINK_WATCH_DIR);

  priv->dir_monitor = g_file_monitor_directory (dir, 0, NULL, NULL);

  g_signal_connect (priv->dir_monitor, "changed",
                    G_CALLBACK (on_watch_dir_changed), app);
}

static gboolean
launch_dist_page (ClutterActor *actor, ClutterButtonEvent *event)
{
  const gchar *url;
  gchar *exec;

  if (event->button != 1)
    return FALSE;

  url = clutter_actor_get_name (actor);
  exec = g_strdup_printf ("%s %s", XDG_OPEN, url);

  gdk_spawn_command_line_on_screen (gdk_screen_get_default (),
                                      exec, 
                                      NULL);
  g_free (exec);

  return FALSE;
}

static void
load_dist_logo (LauncherApp *app)
{
#define DIST_DIR "/apps/netbook-launcher"
#define DIST_IMG DIST_DIR"/dist_image"
#define DIST_URL DIST_DIR"/dist_url"
  LauncherAppPrivate *priv = app->priv;
  LauncherConfig *cfg = launcher_config_get_default ();
  GConfClient *client = gconf_client_get_default ();
  ClutterActor *tex;
  GdkPixbuf *logo;
  gint width, height;
  const gchar *imageurl;
  const gchar *url;

  width = cfg->bar_width;
  height = cfg->shortcut_height * 1.1;
  height *= 1;

  gconf_client_add_dir (client, DIST_DIR, GCONF_CLIENT_PRELOAD_NONE, NULL);
  imageurl = gconf_client_get_string (client, DIST_IMG, NULL);
  url = gconf_client_get_string (client, DIST_URL, NULL);

  if (!imageurl)
    return;

  logo = gdk_pixbuf_new_from_file_at_scale (imageurl,
                                            width, height, TRUE, NULL);

  if (logo)
  {
    tex = launcher_util_texture_new_from_pixbuf (logo);
    clutter_container_add_actor (CLUTTER_CONTAINER (app), tex);
    clutter_actor_set_anchor_point_from_gravity (tex, CLUTTER_GRAVITY_CENTER);
    clutter_actor_set_position (tex, 
                                clutter_actor_get_x (priv->window) + (width/2),
                                CSH() - PADDING*2 - (height/2));
    clutter_actor_set_name (tex, url);
    clutter_actor_set_reactive (tex, TRUE);
    clutter_actor_show (tex);

    if (url)
    {
      g_signal_connect (tex, "button-release-event",
                      G_CALLBACK (launch_dist_page), NULL);
    }
    g_object_unref (logo);
  }

  g_object_unref (client);
}

/* GObject stuff */
static void
launcher_app_finalize (GObject *object)
{
  LauncherAppPrivate *priv;

  priv = LAUNCHER_APP_GET_PRIVATE (object);

  g_object_unref (priv->wm);
  g_object_unref (priv->menu);

  G_OBJECT_CLASS (launcher_app_parent_class)->finalize (object);
}

static void
launcher_app_class_init (LauncherAppClass *klass)
{
  GObjectClass        *obj_class = G_OBJECT_CLASS (klass);

  obj_class->finalize = launcher_app_finalize;

  g_type_class_add_private (obj_class, sizeof (LauncherAppPrivate));
}

static void
launcher_app_init (LauncherApp *app)
{
  LauncherAppPrivate *priv;
  ClutterActor *stage = clutter_stage_get_default ();
  LauncherConfig *cfg = launcher_config_get_default ();
  GdkPixbuf *pixbuf;
  const gchar *winmode;
      
  priv = app->priv = LAUNCHER_APP_GET_PRIVATE (app);

  winmode = g_getenv ("LAUNCHER_WINDOWED");
  priv->windowed = winmode ? atoi (winmode) : FALSE; 
  
  /* The desktop background */
  priv->bg = launcher_background_new ();
  clutter_container_add_actor (CLUTTER_CONTAINER (stage), priv->bg);
  clutter_actor_set_size (priv->bg, CSW(), CSH());
  clutter_actor_set_position (priv->bg, 0, 0);
  clutter_actor_show (priv->bg);

  /* Main container group */
  clutter_container_add_actor (CLUTTER_CONTAINER (stage), CLUTTER_ACTOR (app));
  clutter_actor_set_position (CLUTTER_ACTOR (app), 0, 0);
  clutter_actor_set_size (CLUTTER_ACTOR (app), CSW(), CSH());
  clutter_actor_show (CLUTTER_ACTOR (app));

  /* Focus server */
  priv->focus_manager = clutter_focus_manager_get_default ();
  clutter_container_add_actor (CLUTTER_CONTAINER (stage), priv->focus_manager);

  stage = CLUTTER_ACTOR (app);

  /* Shadow 
  priv->shadow = launcher_util_texture_new_from_file (PKGDATADIR"/shadow.png");
  clutter_container_add_actor (CLUTTER_CONTAINER (stage), priv->shadow);
  clutter_actor_set_position (priv->shadow, 0, PANEL_HEIGHT);
  if (!priv->windowed) clutter_actor_show (priv->shadow);
  */

  /* Window */
  pixbuf = gdk_pixbuf_new_from_file (PKGDATADIR"/window.svg", NULL);
  priv->window = g_object_new (CLUTTER_TYPE_TEXTURE, NULL);
  launcher_util_texture_set_from_pixbuf (CLUTTER_TEXTURE (priv->window), 
                                         pixbuf);
  g_object_unref (pixbuf);
  clutter_container_add_actor (CLUTTER_CONTAINER (stage), priv->window);
  clutter_actor_set_size (priv->window, cfg->win_width, cfg->win_height);
  clutter_actor_set_position (priv->window, 
                              (CSW()-cfg->win_width)/2, 
                              PANEL_HEIGHT + 5);
  clutter_actor_show (priv->window);

  /* Ubuntu logo */
  priv->ubuntu = launcher_util_texture_new_from_file (PKGDATADIR"/ubuntu.png");
  clutter_container_add_actor (CLUTTER_CONTAINER (stage), priv->ubuntu);
  clutter_actor_set_anchor_point_from_gravity (priv->ubuntu, 
                                               CLUTTER_GRAVITY_NORTH);
  clutter_actor_set_position (priv->ubuntu, CSW()/2, 
                              PANEL_HEIGHT + PADDING + PANEL_HEIGHT/4);
  clutter_actor_show (priv->ubuntu);

  /* Init the WM interface */
  priv->wm = launcher_wm_get_default ();
  g_signal_connect (priv->wm, "show-windec", G_CALLBACK (hide_launcher), app);
  g_signal_connect (priv->wm, "hide-windec", G_CALLBACK (show_launcher), app);

  /* Application menu */
  priv->menu = launcher_menu_get_default ();

  /* Iconviewbg */
  priv->iconviewbg = launcher_util_texture_new_from_file 
                                                  (PKGDATADIR"/iconviewbg.png");
  clutter_actor_set_opacity (priv->iconviewbg, 0);
  clutter_container_add_actor (CLUTTER_CONTAINER (stage), priv->iconviewbg);
  priv->iconviewbg = tidy_texture_frame_new (CLUTTER_TEXTURE (priv->iconviewbg),
                                             30, 30, 30, 30);
  clutter_container_add_actor (CLUTTER_CONTAINER (stage), priv->iconviewbg);
  clutter_actor_set_size (priv->iconviewbg, cfg->iconview_width,
                          cfg->win_height-(PANEL_HEIGHT*1.3+PADDING));
  clutter_actor_set_position (priv->iconviewbg, 
                           clutter_actor_get_x (priv->window)+cfg->bar_width-3, 
                           PANEL_HEIGHT*2.3+PADDING+2);
  clutter_actor_show (priv->iconviewbg);
  clutter_actor_set_reactive (CLUTTER_ACTOR (priv->iconviewbg), TRUE);
  g_signal_connect (priv->iconviewbg, "scroll-event",
                    G_CALLBACK (on_scroll_event), app);
    
  /* Sidebar */
  priv->sidebar = launcher_sidebar_get_default ();
  clutter_container_add_actor (CLUTTER_CONTAINER (stage), priv->sidebar);
  clutter_actor_set_position (priv->sidebar, 
                              clutter_actor_get_x (priv->window)
                                +CAW(priv->window)-cfg->bar_width,
                              PANEL_HEIGHT*2.3+PADDING);
  clutter_actor_show (priv->sidebar);
  clutter_focus_manager_insert_group(CLUTTER_FOCUS_MANAGER(priv->focus_manager),
                                     CLUTTER_FOCUS_GROUP (priv->sidebar),
                                     1);
  /* Category bar */
  priv->catbar = launcher_catbar_get_default ();
  clutter_container_add_actor (CLUTTER_CONTAINER (stage), priv->catbar);
  clutter_actor_set_position (priv->catbar, 
                              clutter_actor_get_x (priv->window),
                              PANEL_HEIGHT*2.3+PADDING);
  clutter_actor_show (priv->catbar);
  g_signal_connect (priv->catbar, "category-selected",
                    G_CALLBACK (on_new_category), app);
  clutter_focus_manager_insert_group(CLUTTER_FOCUS_MANAGER(priv->focus_manager),
                                     CLUTTER_FOCUS_GROUP (priv->catbar),
                                     0);
  /* dist logo */
  load_dist_logo (app);

  on_new_category (NULL, 
                   launcher_menu_get_categories (priv->menu)->data,
                   app);

  priv->time = clutter_timeline_new_for_duration (MID_TIME);
  priv->temp = clutter_effect_template_new (priv->time, 
                                            clutter_sine_inc_func);

  watch_links (app);
}

ClutterActor *
launcher_app_get_default (void)

{
  static ClutterActor *app = NULL;

  if (!app)
    app = g_object_new (LAUNCHER_TYPE_APP, 
                       NULL);

  return app;
}

Generated by  Doxygen 1.6.0   Back to index