All pastes #835862 Raw Edit

Anonymous

public text v1 · immutable
#835862 ·published 2007-12-29 02:14 UTC
rendered paste body
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <Imlib2.h>
#include <Evas.h>
#include <Ecore.h>
#include <Ecore_File.h>
#include <Ecore_X.h>
#include <Ecore_X_Cursor.h>
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
#  include <sys/time.h>
# else
#  include <time.h>
# endif
#endif
#include "config.h"
#include "egrab.h"

/* Function Prototypes */
static void _eg_print_help(void);
static void _eg_print_version(void);
static void _eg_free_options(void);
static void _eg_get_filename(void);
static void _eg_do_shot(void);
static void _eg_do_screen(void);
static void _eg_do_window(void);
static void _eg_do_thumb(void *data);
static int _eg_cb_mouse_up(void *data, int type, void *event);

/* Global Variables */
static Options *opts = NULL;
static Ecore_X_Window input_window = 0;
static Ecore_Event_Handler *mouse_hdl = 0;
static Ecore_Timer *timer = NULL;

/* Main Program Function */
int 
main(int argc, char **argv) 
{
   int i, qual, delay;
   int tw, th, ts;
   char *app, *file;

   /* allocate a structure to hold our options */
   opts = calloc(1, sizeof(Options));

   /* parse the options provided by user */
   for (i = 1; i < argc; i++) 
     {
	if (!strcmp(argv[i], "--beep")) 
	  opts->beep = 1;
	else if ((!strcmp(argv[i], "--delay")) && (i < (argc - 1)))
	  {
	     i++;
	     if (sscanf(argv[i], "%i", &delay) == 1) 
	       opts->delay = delay;
	  }
	else if (!strcmp(argv[i], "--prompt")) 
	  opts->prompt = 1;
	else if ((!strcmp(argv[i], "--app")) && (i < (argc - 1)))
	  {
	     i++;
	     if (sscanf(argv[i], "%s", &app) == 1) 
	       opts->app = evas_stringshare_add(app);
	  }
	else if ((!strcmp(argv[i], "--thumb")) && (i < (argc - 1)))
	  {
	     i++;
	     if (sscanf(argv[i], "%s", &file) == 1) 
	       {
		  opts->use_thumb = 1;
		  opts->thumb.filename = evas_stringshare_add(file);
	       }
	  }
	else if ((!strcmp(argv[i], "--thumb-geom")) && (i < (argc - 1)))
	  {
	     i++;
	     if (sscanf(argv[i], "%ix%i", &tw, &th) == 2) 
	       {
		  opts->use_thumb = 1;
		  opts->thumb.width = tw;
		  opts->thumb.height = th;
	       }
	     else if (sscanf(argv[i], "%i", &ts) == 1) 
	       {
		  if (ts < 1) ts = 1;
		  else if (ts > 100) ts = 100;
		  opts->use_thumb = 1;
		  opts->thumb.size = ts;
	       }
	  }
	else if ((!strcmp(argv[i], "--quality")) && (i < (argc - 1)))
	  {
	     i++;
	     if (sscanf(argv[i], "%i", &qual) == 1) 
	       opts->quality = qual;
	  }
	else if (!strcmp(argv[i], "--region")) 
	  opts->region = 1;
	else if (!strcmp(argv[i], "--window")) 
	  opts->window = 1;
	else if (!strcmp(argv[i], "--help")) 
	  {
	     _eg_print_help();
	     _eg_free_options();
	     exit(0);
	  }
	else if (!strcmp(argv[i], "--version")) 
	  {
	     _eg_print_version();
	     _eg_free_options();
	     exit(0);
	  }
	else if (i < argc) 
	  {
	     while (i < argc) 
	       {
		  if (!opts->filename) 
		    opts->filename = evas_stringshare_add(argv[i]);
		  else
		    {
		       printf("Unknown Option: %s\n", argv[i]);
		       _eg_print_help();
		       _eg_free_options();
		       exit(0);
		    }
		  i++;
	       }
	  }
     }

   /* initialize ecore */
   if (!ecore_init()) return -1;

   /* make sure Ecore_X is initialized */
   ecore_x_init(NULL);

   /* set app arguments */
   ecore_app_args_set(argc, (const char **)argv);

   /* parse the filename for '%', or create one if no filename is given */
   _eg_get_filename();

   /* start screenshot process */
   _eg_do_shot();

   /* begin the ecore main loop which will keep our app running */
   ecore_main_loop_begin();

   /* free our option structure */
   _eg_free_options();

   /* shutdown ecore_x */
   ecore_x_shutdown();

   /* shutdown ecore */
   ecore_shutdown();

   return 0;
}

static void 
_eg_print_help(void) 
{
   printf("Usage: egrab [OPTIONS]... FILE\n"
	  "Where FILE is the target for the screenshot.\n"
	  "If no FILE is specified, a date-stamped file will be saved in "
	  "the current directory.\n"
	  "\t--help\t\t\tDisplay this help\n"
	  "\t--beep\t\t\tBeep before taking screenshot\n"
	  "\t--delay NUM\t\tWait NUM seconds before taking screenshot\n"
	  "\t--prompt\t\tPrompt for FILE\n"
	  "\t--app APP\t\tLaunch APP after taking screenshot\n"
	  "\t--thumb THUMB\t\tGenerate a thumbnail as THUMB\n"
	  "\t--thumb-geom NUM\tGeometry to use for thumbnail\n"
	  "\t\t\t\tNUM can be a percentage of the original size OR\n"
	  "\t\t\t\tthe actual geometry to use for the thumbnail,\n"
	  "\t\t\t\tie: 100x100\n"
	  "\t--quality NUM\t\tImage quality of screenshot\n"
	  "\t--region\t\tSelect a specific screen region\n"
	  "\t--window\t\tSelect a specifc window to grab\n"
	  );
}

static void 
_eg_print_version(void) 
{
   printf("egrab version "VERSION"\n");
}

static void 
_eg_free_options(void) 
{
   /* cleanup our options structure */
   if (!opts) return;
   if (opts->app) evas_stringshare_del(opts->app);
   if (opts->filename) evas_stringshare_del(opts->filename);
   if (opts->thumb.filename) evas_stringshare_del(opts->thumb.filename);
   free(opts);
   opts = NULL;
}

static void 
_eg_get_filename(void) 
{
   Ecore_List *fl = NULL;
   char *dir = NULL, *ext = NULL, *file = NULL;
   const char *f;
   char buf[256];
   struct tm *loctime;
   time_t t;
   int c = 0;

   /* get the current time in local format */
   t = time(NULL);
   loctime = localtime(&t);

   /* if no filename given, create one based on time */
   if ((!opts->filename) || (opts->filename == NULL))
     strftime(buf, sizeof(buf), "%Y-%m-%d-%H%M%S.png", loctime);
   else 
     {
	/* filename was given, check for '%' signs to 
	 * format based on strftime */
	if (strstr(opts->filename, "%")) 
	  strftime(buf, sizeof(buf), opts->filename, loctime);
	else 
	  {
	     /* no '%' signs, check for files existing in the directory */
	     if (ecore_file_exists(opts->filename)) 
	       {
		  /* get the directory */
		  dir = ecore_file_dir_get(opts->filename);

		  /* get the filename */
		  f = ecore_file_file_get(opts->filename);

		  /* if these two match, then no dir was passed in,
		   * use current dir */
		  if (!strcmp(dir, f)) dir = getenv("PWD");

		  /* strip the extension for searches */
		  ext = ecore_file_strip_ext(opts->filename);

		  /* list files in this directory & count them */
		  fl = ecore_file_ls(dir);
		  ecore_list_first_goto(fl);
		  while ((file = ecore_list_next(fl)) != NULL) 
		    {
		       /* skip "thumb" files in the count */
		       if (strstr(file, "thumb")) continue;
		       if (strstr(file, ext)) c++;
		    }

		  /* destroy the file list */
		  if (fl) ecore_list_destroy(fl);

		  /* assemble new filename based on count */
		  if (c > 0) 
		    {
		       c++;

		       /* strip the extension from filename */
		       file = ecore_file_strip_ext(opts->filename);

		       /* get the actual extension */
		       ext = strrchr(opts->filename, '.');
		       if (!ext) ext = strdup(".png");

		       /* assemble new filename */
		       snprintf(buf, sizeof(buf), "%s%i%s", file, c, ext);
		    }
		  else return;
	       }
	     else return;
	  }
     }
   /* set the new filename */
   if (opts->filename) evas_stringshare_del(opts->filename);
   opts->filename = evas_stringshare_add(buf);
}

static void 
_eg_do_shot(void) 
{
   if (opts->delay > 0) 
     {

     }
   else 
     {
	/* are we taking a region, window or whole screen shot? */
	if (opts->region)
	  printf("Take Region\n");
	else if (opts->window)
	  _eg_do_window();
	else
	  _eg_do_screen();
     }
}

static void 
_eg_do_screen(void) 
{
   Imlib_Image *im = NULL;
   Imlib_Load_Error err;
   Ecore_X_Display *disp;
   Ecore_X_Window root;
   int w, h;

   /* get the display */
   disp = ecore_x_display_get();

   /* get the root window */
   root = RootWindow(disp, 0);

   /* get the size of the root window */
   ecore_x_window_size_get(root, &w, &h);

   /* setup imlib in preparation for shot */
   imlib_context_set_display(disp);
   imlib_context_set_drawable(root);
   imlib_context_set_visual(DefaultVisual(disp, DefaultScreen(disp)));

   /* if user wanted a beep, then beep there shall be */
   if (opts->beep) XBell(disp, 0);

   /* actually create the shot */
   im = imlib_create_image_from_drawable(0, 0, 0, w, h, 1);
   if (!im) return;

   /* set imlib context to our current shot: 
    * this tells imlib what image we are working with */
   imlib_context_set_image(im);

   /* if user passed in any quality settings, attach them to the image */
   if (opts->quality)
     imlib_image_attach_data_value("quality", NULL, opts->quality, NULL);

   /* save the image to disk */
   imlib_save_image_with_error_return(opts->filename, &err);
   if (err) 
     {
	printf("Error taking screenshot: %s\n", opts->filename);
	imlib_free_image_and_decache();
	return;
     }

   /* if user wanted a thumbnail, do it */
   if (opts->use_thumb) _eg_do_thumb(im);

   /* cleanup imlib */
   imlib_context_set_image(im); 
   imlib_free_image_and_decache();

   /* quit the main ecore loop */
   ecore_main_loop_quit();
}

static void 
_eg_do_window(void) 
{
   Ecore_X_Display *disp;
   Ecore_X_Window root;
   int x, y, w, h;

   /* get the display */
   disp = ecore_x_display_get();

   /* get the root window */
   root = RootWindow(disp, 0);

   /* get the size of the current root window */
   ecore_x_window_geometry_get(root, &x, &y, &w, &h);

   /* check if our input window already exists & delete it */
   if (input_window) ecore_x_window_del(input_window);

   /* create a new input window to recieve click event */
   input_window = ecore_x_window_input_new(root, x, y, w, h);

   /* move and resize the input window */
   ecore_x_window_move(input_window, 0, 0);
   ecore_x_window_resize(input_window, w, h);

   /* show the input window */
   ecore_x_window_show(input_window);
   ecore_x_window_raise(input_window);

   /* set the mouse pointer */
   ecore_x_window_cursor_set(input_window, ECORE_X_CURSOR_PLUS);
   ecore_x_window_cursor_show(input_window, 1);

   /* grab the mouse
   if (!ecore_x_pointer_confine_grab(input_window))
     printf("Cannot grab mouse\n");
    */

   /* setup handler to recieve click event */
   mouse_hdl = ecore_event_handler_add(ECORE_X_EVENT_MOUSE_BUTTON_UP, 
				       _eg_cb_mouse_up, NULL);
}

static void 
_eg_do_thumb(void *data) 
{
   Imlib_Image *im = NULL, *thumb = NULL;
   Imlib_Load_Error err;
   char *ext = NULL;
   char buf[4096];
   int w, h, tw, th;

   if (!(im = data)) return;

   /* set imlib context to our current shot */
   imlib_context_set_image(im);

   /* get the image width & height */
   w = imlib_image_get_width();
   h = imlib_image_get_height();

   /* calculate thumbnail size */
   if ((opts->thumb.width > 0) && (opts->thumb.height > 0)) 
     {
	tw = w * opts->thumb.width / 100;
	th = h * opts->thumb.height / 100;
     }
   else if (opts->thumb.size > 0) 
     {
	tw = w * opts->thumb.size / 100;
	th = h * opts->thumb.size / 100;
     }
   else 
     {
	/* by default, create a 50% thumbnail */
	tw = w * 50 / 100;
	th = h * 50 / 100;
     }

   /* actually create the thumbnail of our image */
   thumb = imlib_create_cropped_scaled_image(0, 0, w, h, tw, th);
   if (!thumb) 
     printf("Error creating thumbnail: %s\n", opts->filename);
   else 
     {
	/* set imlib context to the thumbnail */
	imlib_context_set_image(thumb);

	/* check for user-supplied thumbnail filename */
	if (!opts->thumb.filename) 
	  {
	     /* no thumbname filename supplied, create one */
	     ext = ecore_file_strip_ext(opts->filename);
	     snprintf(buf, sizeof(buf), "%s-thumb", ext);
	     
	     /* check for extension */
	     ext = strrchr(opts->filename, '.');
	     if (ext) 
	       snprintf(buf, sizeof(buf), "%s%s", strdup(buf), ext);
	     else
	       snprintf(buf, sizeof(buf), "%s.png", strdup(buf));
	     opts->thumb.filename = evas_stringshare_add(buf);
	  }

	/* actually save the thumbnail */
	imlib_save_image_with_error_return(opts->thumb.filename, &err);
	if (err) 
	  printf("Error saving thumbnail: %s\n", opts->thumb.filename);

	/* cleanup imlib */
	imlib_free_image_and_decache();
     }
}

static int 
_eg_cb_mouse_up(void *data, int type, void *event) 
{
   Ecore_X_Event_Mouse_Button_Up *ev;
   Ecore_X_Display *disp;
   Ecore_X_Window win, root;
   Imlib_Image *im = NULL;
   Imlib_Load_Error err;
   int x, y, w, h;

   ev = event;

   /* check for correct mouse button */
   if (ev->button != 1) return 1;

   /* check for correct window */
   if (ev->win != input_window) return 1;

   /* get last known pointer position */
   ecore_x_pointer_last_xy_get(&x, &y);

   /* delete the event handler */
   ecore_event_handler_del(mouse_hdl);
   mouse_hdl = 0;

   /* delete the input window */
   ecore_x_window_del(input_window);
   input_window = 0;

   /* release the pointer
   ecore_x_pointer_ungrab();
    */

   /* get the window which was clicked */
   win = ecore_x_window_at_xy_get(x, y);

   /* get the display */
   disp = ecore_x_display_get();

   /* E uses many parent windows...grab the correct one */
   root = RootWindow(disp, 0);
   while (win != root) 
     {
	if (ecore_x_window_parent_get(win) == root) break;
	win = ecore_x_window_parent_get(win);
     }
   
   /* get this window's dimensions */
   ecore_x_window_geometry_get(win, &x, &y, &w, &h);

   /* setup imlib in preparation for shot */
   imlib_context_set_display(disp);
   imlib_context_set_drawable(root);
   imlib_context_set_visual(DefaultVisual(disp, DefaultScreen(disp)));

   /* if user wanted a beep, then beep there shall be */
   if (opts->beep) XBell(disp, 0);

   /* actually create the shot */
   im = imlib_create_image_from_drawable(0, x, y, w, h, 1);
   if (!im) return -1;

   /* set imlib context to our current shot: 
    * this tells imlib what image we are working with */
   imlib_context_set_image(im);

   /* if user passed in any quality settings, attach them to the image */
   if (opts->quality)
     imlib_image_attach_data_value("quality", NULL, opts->quality, NULL);

   /* save the image to disk */
   imlib_save_image_with_error_return(opts->filename, &err);
   if (err) 
     {
	printf("Error taking screenshot: %s\n", opts->filename);
	imlib_free_image_and_decache();
	return -1;
     }

   /* if user wanted a thumbnail, do it */
   if (opts->use_thumb) _eg_do_thumb(im);

   /* cleanup imlib */
   imlib_context_set_image(im); 
   imlib_free_image_and_decache();

   /* quit the main ecore loop */
   ecore_main_loop_quit();
   return 0;
}