/* launcher.c
 * Copyright (C) 2002-2004 Pascal Eberhard <pascal.ebo@netcourrier.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * 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, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */


#include <sys/types.h>  /* execlp */
#include <unistd.h>     /* fork, execlp */

#include "launcher.h"
#include "common.h"

// ----------------------------------------------------------------------------
launcher_t* launcher_new(void)
{
  launcher_t  *l;
  app_list_t *apps;

  l = (launcher_t *)malloc(sizeof(launcher_t));
  g_assert(l != NULL);

  l->window = gtk_window_new(GTK_WINDOW_POPUP);
  g_signal_connect(G_OBJECT(l->window), "delete_event", gtk_main_quit, NULL);

  l->event_box = gtk_event_box_new();
  gtk_container_add(GTK_CONTAINER(l->window), l->event_box);
  /* And bind an action to it */
  gtk_widget_set_events(l->event_box, GDK_BUTTON_PRESS_MASK);
  g_signal_connect(G_OBJECT(l->event_box), "button_press_event",
                    G_CALLBACK(launcher_button_press_event), l);
  g_signal_connect(G_OBJECT(l->event_box), "button_release_event",
                    G_CALLBACK(launcher_button_release_event), l);
  g_signal_connect(G_OBJECT(l->event_box), "enter_notify_event",
                    G_CALLBACK(launcher_enter_notify_event), l);
  g_signal_connect(G_OBJECT(l->event_box), "leave_notify_event",
                    G_CALLBACK(launcher_leave_notify_event), l);

  l->image = NULL;
  l->pixbuf = NULL;
  l->bitmap_mask = NULL;

  l->x = 0;
  l->y = 0;
  l->width = 0;
  l->height = 0;

  l->editor_started = FALSE;

  l->xwidth = gdk_screen_width();
  l->xheight = gdk_screen_height();

  l->timeout_activated = 0;
  l->apps = NULL;

  xmlrc_load_from_file(&apps, NULL, &l->apwal_pref);
  launcher_load_apps(l, apps);
  
  return l;
}
// ----------------------------------------------------------------------------
void launcher_load_apps(launcher_t *l, app_list_t *apps)
{
  app_t *app;
  GdkPixbuf *pixbuf;
  GdkModifierType state;                // mouse state
  gint x_min, y_min;
  gint width, height;
  
  g_assert(l != NULL);

  if (l->apps)
    app_list_free(&(l->apps));

  if (l->image)
  {
    gtk_container_remove(GTK_CONTAINER(l->event_box), l->image);
    g_object_unref(l->pixbuf);
  }

  l->pixbuf = NULL;
  l->image = NULL;
  l->bitmap_mask = NULL;

  l->apps = apps;
  if (!apps)
    return;

  l->width = ICON_WIDTH * (app_list_delta_x(l->apps) + 1);
  l->height = ICON_HEIGHT * (app_list_delta_y(l->apps) + 1);
  x_min = app_list_min_x(l->apps);
  y_min = app_list_min_y(l->apps);
  TRACE("Dx:%d, Dy:%d, x_min:%d, y_min:%d",
         app_list_delta_x(l->apps), app_list_delta_y(l->apps),
         x_min, y_min); 
  // get the current position of the mouse cursor
  gdk_window_get_pointer (l->window->window, &l->x, &l->y, &state);
  // check if the position is correct
  l->x = l->x + (x_min * ICON_WIDTH);
  if (l->x < 0)
    l->x = 0;
  else if (l->x + l->width > l->xwidth)
    l->x = l->xwidth - l->width;
  l->y = l->y + (y_min * ICON_HEIGHT);
  if (l->y < 0)
    l->y = 0;
  else if (l->y + l->height > l->xheight)
    l->y = l->xheight - l->height;
  // change position of the window to the mouse cursor position
  //deprecated gtk_widget_set_uposition(l->window, l->x, l->y);
  gtk_window_move(GTK_WINDOW(l->window), l->x, l->y);

  l->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB/*colorspace*/,
                             TRUE/*has_alpha*/,
                             8/*bits_per_sample*/,
                             l->width, l->height);
  app = app_list_first(l->apps);
  while (app)
  {
    pixbuf = gdk_pixbuf_new_from_apwal(app->icon, NULL, NULL);

    if (!app_is_executable(app))
      gdk_pixbuf_saturate_and_pixelate(pixbuf, pixbuf, 0.1/*saturation*/,
                                       TRUE/*pixelate*/);

    width = gdk_pixbuf_get_width(pixbuf); 
    height = gdk_pixbuf_get_height(pixbuf);
    width = width < ICON_WIDTH  ? width : ICON_WIDTH;
    height= height< ICON_HEIGHT ? height: ICON_HEIGHT;
    gdk_pixbuf_copy_area(pixbuf/*src_pixbuf*/,
                         0 /*src_x*/, 0/*src_y*/, width, height,
                         l->pixbuf/*dest_pixbuf*/,
                         (app->x - x_min)*ICON_WIDTH/*dest_x*/,
                         (app->y - y_min)*ICON_HEIGHT/*dest_y*/);
    g_object_unref(pixbuf);
    app = app_list_next(l->apps);
  }

  gdk_pixbuf_render_pixmap_and_mask(l->pixbuf,
                                    NULL/*pixmap_return*/,
                                    &l->bitmap_mask/*mask_return*/,
                                    128/*alpha_threshold*/);

  l->image = gtk_image_new_from_pixbuf(l->pixbuf);
  gtk_container_add(GTK_CONTAINER(l->event_box), l->image);
  gtk_widget_shape_combine_mask(l->window, l->bitmap_mask,
                                0/*offset_x*/, 0/*offset_y*/);
  
  gtk_widget_show(l->image);
  gtk_widget_show(l->event_box);
  gtk_widget_show(l->window);

  launcher_timeout_start(l);
}
// ----------------------------------------------------------------------------
void launcher_timeout_start(launcher_t *l)
{
  g_assert(l != NULL);

  if (!l->timeout_activated)
  {
      l->timeout_handler_id = g_timeout_add(l->apwal_pref->timeout,
                                              launcher_timeout_function, l);
      l->timeout_activated = 1 ;
  }
}
// ----------------------------------------------------------------------------
void launcher_timeout_stop(launcher_t *l)
{
  g_assert(l != NULL);

  if (l->timeout_activated)
  { g_source_remove(l->timeout_handler_id) ;
    l->timeout_activated = 0 ;
  }
}              
// ----------------------------------------------------------------------------
gint launcher_timeout_function(gpointer data)
{ 
  launcher_t *l = (launcher_t*) data;
  g_assert(l != NULL);

  if (l->editor_started == TRUE)
  {
    TRACE("%s", "editor started, timeout disactivated");
    return 0;
  }
  gtk_main_quit();
  return 0;
}
// ----------------------------------------------------------------------------
gboolean launcher_button_press_event(GtkWidget *widget,
                                     GdkEventButton *event, launcher_t *l)
{
  g_assert(l != NULL);

  TRACE("type:%x, x:%f, y:%f, button:%d",
          event->type, event->x, event->y, event->button);
  return TRUE;
}
// ----------------------------------------------------------------------------
gboolean launcher_button_release_event(GtkWidget *widget,
                                       GdkEventButton *event, launcher_t *l)
{
  guint  pos_x;
  guint  pos_y;
  gboolean launched;
  app_t *app;
  GtkWidget *dialog;
  apwalapp_t *apwal;

  g_assert(l != NULL);

  TRACE("type:%x, x:%f, y:%f, button:%d",
          event->type, event->x, event->y, event->button);

  if (event->button == 3/*clic avec le bouton droit*/)
  {
    if (!l->editor_started)
    {
      l->editor_started = TRUE;
      g_signal_handlers_disconnect_by_func(l->window, launcher_leave_notify_event, l);
      gtk_widget_hide(l->window);
      launcher_timeout_stop(l);
      while (gtk_events_pending())
      { gtk_main_iteration();
      }
      apwal = apwalapp_new();
    }
  }
  else
  {
    pos_x = (((int)event->x) / ICON_WIDTH) + app_list_min_x(l->apps);
    pos_y = (((int)event->y) / ICON_WIDTH) + app_list_min_y(l->apps);
    TRACE("EXEC x:%d, y:%d, pos_x:%d, pos_y:%d ",
            (int)event->x, (int)event->y, pos_x, pos_y);
    app = app_list_at_xy(l->apps, pos_x, pos_y);
    app_dumpln(app);
    launched = app_exec(app, l->apwal_pref->exit_at_app_launch);
    if (!launched)
    {
      dialog = gtk_message_dialog_new(GTK_WINDOW(l->window),
                 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
                 GTK_BUTTONS_CLOSE, "An error occured while trying to launch "
                 "the application '%s'.\n(path:'%s')",
                 app->cmdline, app->path);
      gtk_dialog_run(GTK_DIALOG(dialog));
      gtk_widget_destroy(dialog);
    }
  }
  return TRUE;
}
// ----------------------------------------------------------------------------
gboolean launcher_enter_notify_event(GtkWidget *widget,
                                     GdkEventCrossing *event,
                                     launcher_t *l)
{
  g_assert(l != NULL);

//  TRACE("type:%x, x:%f, y:%f", event->type, event->x, event->y);
  launcher_timeout_stop(l);
  return TRUE;
}
// ----------------------------------------------------------------------------
gboolean launcher_leave_notify_event(GtkWidget *widget,
                                     GdkEventCrossing *event,
                                     launcher_t *l)
{
  g_assert(l != NULL);

//  TRACE("type:%x, x:%f, y:%f", event->type, event->x, event->y);
  launcher_timeout_start(l);
  return TRUE;
}
// ----------------------------------------------------------------------------
