#include #include #include #include #include #include #include #include #include #include #include #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # 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; }