/* $Id: xfce4-snapshot.c 183 2006-08-06 19:45:25Z benny $ */
/*-
 * Copyright (c) 2004 Benedikt Meurer <benny@xfce.org>
 *
 * 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; You may only use version 2 of the License,
 * you have no option to use any other 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/**
 * Compile with:
 *  cc -o xfce4-snapshot xfce4-snapshot.c `pkg-config --cflags --libs gtk+-2.0`
 *
 * TODO:
 *
 * Grab modus:
 *  - Full Desktop (only this screen)
 *  - Full Desktop (all screens)
 *  - Window with decorations
 *  - Window without decorations
 *  - Desktop Region
 **/

#include <X11/Xlib.h>

#include <stdlib.h>

#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <gtk/gtk.h>

static void
store (GdkDrawable *da, int x1, int y1, int x2, int y2)
{
  int x, y, w, h;
  GdkPixbuf *pb;

  x = MIN (x1, x2);
  y = MIN (y1, y2);
  w = abs (x1 - x2);
  h = abs (y1 - y2);

  pb = gdk_pixbuf_get_from_drawable (NULL,
                                     da,
                                     NULL,
                                     x,
                                     y,
                                     0,
                                     0,
                                     w,
                                     h);

  gdk_pixbuf_save (pb, "test.png", "png", NULL, NULL);
}


static gboolean button_down = FALSE;
static gint button_x, button_y;
static gint last_x, last_y;
static GdkGC *gc, *gc_border;
static GtkWidget *invisible;
static GdkPixmap *os;
static int osw, osh;

static void
draw_outline (void)
{
  GdkDrawable *root = gdk_get_default_root_window ();
  gint x, y, w, h;

  x = MIN (last_x, button_x);
  y = MIN (last_y, button_y);
  w = abs (last_x - button_x);
  h = abs (last_y - button_y);

  gdk_gc_set_function (gc, GDK_COPY);
  gdk_draw_drawable (root, gc, os, 0, 0, 0, 0, osw, osh);

  gdk_gc_set_function (gc, GDK_INVERT);
  
  gdk_draw_rectangle (root, gc, TRUE, 0, 0, osw, y);
  gdk_draw_rectangle (root, gc, TRUE, 0, y + h, osw, osh - (y + h));
  gdk_draw_rectangle (root, gc, TRUE, 0, y, x, h);
  gdk_draw_rectangle (root, gc, TRUE, x + w, y, osw - (x + w), h);

  gdk_gc_set_function (gc, GDK_COPY);
  gdk_draw_rectangle (root, gc, FALSE, x, y, w, h);
}


static GdkFilterReturn
filter (GdkXEvent *xevent, GdkEvent *event, gpointer data)
{
  GdkWindow *root = gdk_get_default_root_window ();
  XEvent *xev = (XEvent *) xevent;
  XButtonEvent *be = (XButtonEvent *) xev;
  XMotionEvent *me = (XMotionEvent *) xev;
  GdkRectangle old, new, clip;

  if (xev->type == ButtonRelease)
    {
      clip.x = 0;
      clip.y = 0;
      clip.width = osw;
      clip.height = osh;
      gdk_gc_set_clip_rectangle (gc, &clip);

      gdk_draw_drawable (root, gc, os, 0, 0, 0, 0, osw, osh);
      
      g_print ("Rect: %d/%d - %d/%d\n", button_x, button_y,
               be->x_root, be->y_root);
      gdk_pointer_ungrab (GDK_CURRENT_TIME);
      gdk_x11_ungrab_server ();
      gdk_flush ();

      store (os, button_x, button_y, be->x_root, be->y_root);
      
      exit (0);      
    }
  else if (xev->type == ButtonPress)
    {
      button_down = TRUE;
      button_x = be->x_root;
      button_y = be->y_root;
      last_x = be->x_root;
      last_y = be->y_root;

      gdk_x11_grab_server ();
      gdk_drawable_get_size (root, &osw, &osh);
      os = gdk_pixmap_new (root, osw, osh, -1);
      gdk_draw_drawable (os, gc, root, 0, 0, 0, 0, osw, osh);
      gdk_gc_set_function (gc, GDK_INVERT);
      gdk_draw_rectangle (root, gc, TRUE, 0, 0, osw, osh);
    }
  else if (button_down && xev->type == MotionNotify)
    {
      old.x = MIN (last_x, button_x);
      old.y = MIN (last_y, button_y);
      old.width = abs (last_x - button_x);
      old.height = abs (last_y - button_y);
      
      new.x = MIN (me->x_root, button_x);
      new.y = MIN (me->y_root, button_y);
      new.width = abs (me->x_root - button_x);
      new.height = abs (me->y_root - button_y);
      
      gdk_rectangle_union (&old, &new, &clip);

      clip.width++;
      clip.height++;
      
      last_x = me->x_root;
      last_y = me->y_root;

      gdk_gc_set_clip_rectangle (gc, &clip);

      draw_outline ();
      /*      gdk_flush (); */
      /*  XSync (GDK_DISPLAY (), TRUE); */
    }
  else
    return GDK_FILTER_CONTINUE;

  return GDK_FILTER_REMOVE;
}


int
main (int argc, char **argv)
{
  GdkScreen *screen;
  GdkWindow *root;
  static gint8 dash_list[] = {1, 1, 1, 1};
  GdkGCValues values;
  GdkColor fg, bg;
  
  gtk_init (&argc, &argv);

  screen = gdk_screen_get_default ();
  
  root = gdk_screen_get_root_window (screen);

  invisible = gtk_invisible_new_for_screen (screen);
  gtk_widget_show_now (invisible);
  gtk_widget_add_events (invisible,
                         GDK_POINTER_MOTION_MASK |
                         GDK_BUTTON_MOTION_MASK |
                         GDK_BUTTON_PRESS_MASK |
                         GDK_BUTTON_RELEASE_MASK);
  gdk_window_add_filter (GDK_WINDOW (invisible->window),
                         filter, NULL);

  gdk_color_parse ("Grey", &fg);
  gdk_color_parse ("DarkRed", &bg);

  values.function = GDK_COPY;
  values.line_style = GDK_LINE_SOLID;
  values.fill = GDK_SOLID;
  values.subwindow_mode = GDK_INCLUDE_INFERIORS;
  gc = gdk_gc_new_with_values(gdk_get_default_root_window(),
                              &values,
                              GDK_GC_FUNCTION |
                              GDK_GC_LINE_STYLE |
                              GDK_GC_SUBWINDOW |
                              GDK_GC_FILL);

  gdk_gc_set_rgb_fg_color (gc, &fg);
  gdk_gc_set_rgb_bg_color (gc, &bg);

  //  gdk_x11_grab_server ();

  gdk_pointer_grab (GDK_WINDOW (invisible->window), TRUE,
                    GDK_POINTER_MOTION_MASK |
                    GDK_BUTTON_MOTION_MASK |
                    GDK_BUTTON_PRESS_MASK |
                    GDK_BUTTON_RELEASE_MASK,
                    NULL, gdk_cursor_new (GDK_CROSSHAIR),
                    GDK_CURRENT_TIME);

  gdk_flush ();
  
  gtk_main ();

  return 0;
}

