home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / common / screenshot.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-10  |  13.3 KB  |  489 lines

  1. /*  
  2.  *  ScreenShot plug-in
  3.  *  Copyright 1998-2000 Sven Neumann <sven@gimp.org>
  4.  *
  5.  *  Any suggestions, bug-reports or patches are very welcome.
  6.  * 
  7.  *  This plug-in uses the X-utility xwd to grab an image from the screen
  8.  *  and the xwd-plug-in created by Peter Kirchgessner (pkirchg@aol.com)
  9.  *  to load this image into the gimp.
  10.  *  Hence its nothing but a simple frontend to those utilities.
  11.  */
  12.  
  13. /* The GIMP -- an image manipulation program
  14.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  15.  *
  16.  * This program is free software; you can redistribute it and/or modify
  17.  * it under the terms of the GNU General Public License as published by
  18.  * the Free Software Foundation; either version 2 of the License, or
  19.  * (at your option) any later version.
  20.  *
  21.  * This program is distributed in the hope that it will be useful,
  22.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24.  * GNU General Public License for more details.
  25.  *
  26.  * You should have received a copy of the GNU General Public License
  27.  * along with this program; if not, write to the Free Software
  28.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  29.  */
  30.  
  31. #include "config.h"
  32.  
  33. #include <stdio.h>
  34. #include <errno.h>
  35. #include <sys/wait.h>
  36. #include <unistd.h>
  37. #ifdef __EMX__
  38. #include <process.h>
  39. #endif
  40.  
  41. #include <gtk/gtk.h>
  42.  
  43. #include <libgimp/gimp.h>
  44. #include <libgimp/gimpui.h>
  45.  
  46. #include "libgimp/stdplugins-intl.h"
  47.  
  48.  
  49. /* Defines */
  50. #define PLUG_IN_NAME        "extension_screenshot"
  51.  
  52. #ifndef XWD
  53. #define XWD "xwd"
  54. #endif
  55.  
  56. typedef struct
  57. {
  58.   gboolean   root;
  59.   gchar     *window_id;
  60.   guint      delay;
  61.   gboolean   decor;
  62. } ScreenShotValues;
  63.  
  64. static ScreenShotValues shootvals = 
  65.   FALSE,     /* root window */
  66.   NULL,      /* window ID */
  67.   0,         /* delay */
  68.   TRUE,      /* decorations */
  69. };
  70.  
  71.  
  72. static void      query (void);
  73. static void      run   (gchar      *name,
  74.             gint        nparams,
  75.             GimpParam  *param, 
  76.             gint       *nreturn_vals,
  77.             GimpParam **return_vals);
  78.  
  79. static void      shoot                (void);
  80. static gboolean  shoot_dialog         (void);
  81. static void      shoot_ok_callback    (GtkWidget *widget, 
  82.                        gpointer   data);
  83. static void      shoot_delay          (gint32     delay);
  84. static gint      shoot_delay_callback (gpointer   data);
  85.  
  86.  
  87. /* Global Variables */
  88. GimpPlugInInfo PLUG_IN_INFO =
  89. {
  90.   NULL,  /* init_proc  */
  91.   NULL,     /* quit_proc  */
  92.   query, /* query_proc */
  93.   run    /* run_proc   */
  94. };
  95.  
  96. /* the image that will be returned */
  97. gint32    image_ID = -1;
  98.  
  99. gboolean  run_flag = FALSE;
  100.  
  101.  
  102. /* Functions */
  103.  
  104. MAIN ()
  105.  
  106. static void
  107. query (void)
  108. {
  109.   static GimpParamDef args[] =
  110.   {
  111.     { GIMP_PDB_INT32,  "run_mode",  "Interactive, non-interactive" },
  112.     { GIMP_PDB_INT32,  "root",      "Root window { TRUE, FALSE }" },
  113.     { GIMP_PDB_STRING, "window_id", "Window id" }
  114.   };
  115.   static gint nargs = sizeof (args) / sizeof (args[0]);
  116.  
  117.   static GimpParamDef return_vals[] =
  118.   {
  119.     { GIMP_PDB_IMAGE, "image", "Output image" }
  120.   };
  121.   static gint nreturn_vals = sizeof (return_vals) / sizeof (return_vals[0]);
  122.  
  123.   gimp_install_procedure (PLUG_IN_NAME,
  124.               "Creates a screenshot of a single window or the whole screen",
  125.               "This extension serves as a simple frontend to the "
  126.               "X-window utility xwd and the xwd-file-plug-in. "
  127.               "After specifying some options, xwd is called, the "
  128.               "user selects a window, and the resulting image is "
  129.               "loaded into the gimp. Alternatively the whole "
  130.               "screen can be grabbed. When called non-interactively "
  131.               "it may grab the root window or use the window-id "
  132.               "passed as a parameter.",
  133.               "Sven Neumann <sven@gimp.org>",
  134.               "1998 - 2000",
  135.               "v0.9.5 (2000/10/29)",
  136.               N_("<Toolbox>/File/Acquire/Screen Shot..."),
  137.               NULL,
  138.               GIMP_EXTENSION,        
  139.               nargs, nreturn_vals,
  140.               args, return_vals);
  141. }
  142.  
  143. static void 
  144. run (gchar      *name,
  145.      gint        nparams,
  146.      GimpParam  *param,
  147.      gint       *nreturn_vals,
  148.      GimpParam **return_vals)
  149. {
  150.   /* Get the runmode from the in-parameters */
  151.   GimpRunModeType run_mode = param[0].data.d_int32;    
  152.  
  153.   /* status variable, use it to check for errors in invocation usualy only 
  154.    * during non-interactive calling
  155.    */
  156.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;     
  157.  
  158.   /* always return at least the status to the caller. */
  159.   static GimpParam values[1];
  160.  
  161.   /* initialize the return of the status */     
  162.   values[0].type          = GIMP_PDB_STATUS;
  163.   values[0].data.d_status = status;
  164.   *nreturn_vals = 1;
  165.   *return_vals  = values;
  166.  
  167.   /* how are we running today? */
  168.   switch (run_mode)
  169.     {
  170.     case GIMP_RUN_INTERACTIVE:
  171.       /* Possibly retrieve data from a previous run */
  172.       gimp_get_data (PLUG_IN_NAME, &shootvals);
  173.       shootvals.window_id = NULL;
  174.  
  175.       INIT_I18N_UI ();
  176.  
  177.      /* Get information from the dialog */
  178.       if (!shoot_dialog ())
  179.     status = GIMP_PDB_EXECUTION_ERROR;
  180.       break;
  181.  
  182.     case GIMP_RUN_NONINTERACTIVE:
  183.       if (nparams == 3) 
  184.     {
  185.       shootvals.root      = param[1].data.d_int32;
  186.       shootvals.window_id = (gchar*) param[2].data.d_string;
  187.       shootvals.delay     = 0;
  188.       shootvals.decor     = FALSE;
  189.     }
  190.       else
  191.     status = GIMP_PDB_CALLING_ERROR;
  192.       break;
  193.  
  194.     case GIMP_RUN_WITH_LAST_VALS:
  195.       /* Possibly retrieve data from a previous run */
  196.       gimp_get_data (PLUG_IN_NAME, &shootvals);
  197.       break;
  198.  
  199.     default:
  200.       break;
  201.     }
  202.  
  203.   if (status == GIMP_PDB_SUCCESS)
  204.     {
  205.       if (shootvals.delay > 0)
  206.     shoot_delay (shootvals.delay);
  207.       /* Run the main function */
  208.       shoot ();
  209.  
  210.       status = (image_ID != -1) ? GIMP_PDB_SUCCESS : GIMP_PDB_EXECUTION_ERROR;
  211.     }
  212.  
  213.   if (status == GIMP_PDB_SUCCESS)
  214.     {
  215.       if (run_mode == GIMP_RUN_INTERACTIVE)
  216.     {
  217.       /* Store variable states for next run */
  218.       gimp_set_data (PLUG_IN_NAME, &shootvals, sizeof (ScreenShotValues));
  219.       /* display the image */
  220.       gimp_display_new (image_ID);
  221.     }
  222.       /* set return values */
  223.       *nreturn_vals = 2;
  224.       values[1].type = GIMP_PDB_IMAGE;
  225.       values[1].data.d_image = image_ID;
  226.     }
  227.  
  228.   values[0].data.d_status = status; 
  229. }
  230.  
  231.  
  232. /* The main ScreenShot function */
  233. static void 
  234. shoot (void)
  235. {
  236.   GimpParam *params;
  237.   gint       retvals;
  238.   gchar     *tmpname;
  239.   gchar     *xwdargv[7];    /*  need a maximum of 7 arguments to xwd  */
  240.   gdouble    xres, yres;
  241.   gint       pid;
  242.   gint       wpid;
  243.   gint       status;
  244.   gint       i = 0;
  245.  
  246.   /*  get a temp name with the right extension  */
  247.   tmpname = gimp_temp_name ("xwd");
  248.  
  249.   /*  construct the xwd arguments  */
  250.   xwdargv[i++] = XWD;
  251.   xwdargv[i++] = "-out";
  252.   xwdargv[i++] = tmpname;
  253.   if ( shootvals.root == TRUE )
  254.     xwdargv[i++] = "-root";
  255.   else 
  256.     {
  257.       if (shootvals.decor == TRUE )
  258.     xwdargv[i++] = "-frame";
  259.       if (shootvals.window_id != NULL)
  260.     {
  261.       xwdargv[i++] = "-id";
  262.       xwdargv[i++] = shootvals.window_id;
  263.     }
  264.     }
  265.   xwdargv[i] = NULL;
  266.   
  267. #ifndef __EMX__
  268.   /*  fork off a xwd process  */
  269.   if ((pid = fork ()) < 0)
  270.     {
  271.       g_message ("screenshot: fork failed: %s\n", g_strerror (errno));
  272.       return;
  273.     }
  274.   else if (pid == 0)
  275.     {
  276.       execvp (XWD, xwdargv);
  277.       /*  What are we doing here? exec must have failed  */
  278.       g_message ("screenshot: exec failed: xwd: %s\n", g_strerror (errno));
  279.       return;
  280.     }
  281.   else
  282. #else /* __EMX__ */
  283.   pid = spawnvp (P_NOWAIT, XWD, xwdargv);
  284.   if (pid == -1)
  285.     {
  286.       g_message ("screenshot: spawn failed: %s\n", g_strerror (errno));
  287.       return;
  288.     }
  289. #endif
  290.     {
  291.       status = -1;
  292.       wpid = waitpid (pid, &status, 0);
  293.  
  294.       if ((wpid < 0) || !WIFEXITED (status))
  295.     {
  296.       /*  the tmpfile may have been created even if xwd failed  */
  297.       unlink (tmpname);
  298.       g_free (tmpname);
  299.       g_message ("screenshot: xwd didn't work\n");
  300.       return;
  301.     }
  302.     }
  303.  
  304.   /*  now load the tmpfile using the xwd-plug-in  */
  305.   params = gimp_run_procedure ("file_xwd_load",
  306.                    &retvals,
  307.                    GIMP_PDB_INT32, 1,
  308.                    GIMP_PDB_STRING, tmpname,
  309.                    GIMP_PDB_STRING, tmpname,
  310.                    GIMP_PDB_END);
  311.   if (params[0].data.d_status == GIMP_PDB_SUCCESS)
  312.     {
  313.       image_ID = params[1].data.d_image;
  314.     }
  315.   gimp_destroy_params (params, retvals);
  316.  
  317.   /*  get rid of the tmpfile  */
  318.   unlink (tmpname);
  319.   g_free (tmpname);
  320.  
  321.   if (image_ID != -1)
  322.     {
  323.       /*  figure out the monitor resolution and set the image to it  */
  324.       gimp_get_monitor_resolution (&xres, &yres);      
  325.       gimp_image_set_resolution (image_ID, xres, yres);
  326.  
  327.       /*  unset the image filename  */
  328.       gimp_image_set_filename (image_ID, "");
  329.     }
  330.   
  331.   return;
  332. }
  333.  
  334.  
  335. /*  ScreenShot dialog  */
  336.  
  337. static void
  338. shoot_ok_callback (GtkWidget *widget, 
  339.            gpointer   data)
  340. {
  341.   run_flag = TRUE;
  342.   gtk_widget_destroy (GTK_WIDGET (data));
  343. }
  344.  
  345. static gboolean
  346. shoot_dialog (void)
  347. {
  348.   GtkWidget *dialog;
  349.   GtkWidget *main_vbox;
  350.   GtkWidget *frame;
  351.   GtkWidget *vbox;
  352.   GtkWidget *hbox;
  353.   GtkWidget *label;
  354.   GtkWidget *button;
  355.   GtkWidget *decor_button;
  356.   GtkWidget *spinner;
  357.   GtkWidget *sep;
  358.   GSList    *radio_group = NULL;
  359.   GtkObject *adj;
  360.  
  361.  
  362.   gimp_ui_init ("screenshot", FALSE);
  363.  
  364.   /*  main dialog  */
  365.   dialog = gimp_dialog_new (_("Screen Shot"), "screenshot",
  366.                 gimp_standard_help_func, "filters/screenshot.html",
  367.                 GTK_WIN_POS_MOUSE,
  368.                 FALSE, TRUE, FALSE,
  369.  
  370.                 _("OK"), shoot_ok_callback,
  371.                 NULL, NULL, NULL, TRUE, FALSE,
  372.                 _("Cancel"), gtk_widget_destroy,
  373.                 NULL, 1, NULL, FALSE, TRUE,
  374.  
  375.                 NULL);
  376.  
  377.   gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
  378.               GTK_SIGNAL_FUNC (gtk_main_quit),
  379.               NULL);
  380.  
  381.   main_vbox = gtk_vbox_new (FALSE, 4);
  382.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
  383.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), main_vbox,
  384.               TRUE, TRUE, 0);
  385.   gtk_widget_show (main_vbox);
  386.  
  387.   /*  single window  */
  388.   frame = gtk_frame_new (_("Grab"));
  389.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  390.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  391.  
  392.   vbox = gtk_vbox_new (FALSE, 2);
  393.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  394.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  395.  
  396.   button = gtk_radio_button_new_with_label (radio_group, _("Single Window"));
  397.   radio_group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));  
  398.   gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
  399.   gtk_signal_connect (GTK_OBJECT (button), "toggled",
  400.               (GtkSignalFunc) gimp_radio_button_update,
  401.               &shootvals.root);
  402.   gtk_object_set_user_data (GTK_OBJECT (button), (gpointer) FALSE);
  403.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), ! shootvals.root);
  404.   gtk_widget_show (button);
  405.  
  406.   /*  with decorations  */
  407.   hbox = gtk_hbox_new (FALSE, 2);
  408.   gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
  409.   decor_button =
  410.     gtk_check_button_new_with_label (_("With Decorations"));
  411.   gtk_signal_connect (GTK_OBJECT (decor_button), "toggled",
  412.                       (GtkSignalFunc) gimp_toggle_button_update,
  413.                       &shootvals.decor);
  414.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (decor_button), 
  415.                 shootvals.decor);
  416.   gtk_object_set_data (GTK_OBJECT (button), "set_sensitive", decor_button);
  417.   gtk_box_pack_end (GTK_BOX (hbox), decor_button, FALSE, FALSE, 0);
  418.   gtk_widget_show (decor_button);
  419.   gtk_widget_show (hbox);
  420.  
  421.   sep = gtk_hseparator_new ();
  422.   gtk_box_pack_start (GTK_BOX (vbox), sep, FALSE, FALSE, 0);
  423.   gtk_widget_show (sep);
  424.  
  425.   /*  root window  */
  426.   button = gtk_radio_button_new_with_label (radio_group, _("Whole Screen"));
  427.   radio_group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));  
  428.   gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
  429.   gtk_signal_connect (GTK_OBJECT (button), "toggled",
  430.               (GtkSignalFunc) gimp_radio_button_update,
  431.               &shootvals.root);
  432.   gtk_object_set_user_data (GTK_OBJECT (button), (gpointer) TRUE);
  433.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), shootvals.root);
  434.   gtk_widget_show (button);
  435.  
  436.   gtk_widget_show (vbox);
  437.   gtk_widget_show (frame);
  438.  
  439.   /*  with delay  */
  440.   hbox = gtk_hbox_new (FALSE, 4);
  441.   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
  442.   label = gtk_label_new (_("after"));
  443.   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  444.   gtk_widget_show (label);
  445.  
  446.   adj = gtk_adjustment_new (shootvals.delay, 0.0, 100.0, 1.0, 5.0, 0.0);
  447.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  448.               gimp_int_adjustment_update, 
  449.               &shootvals.delay);
  450.   spinner = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 0, 0);
  451.   gtk_box_pack_start (GTK_BOX (hbox), spinner, FALSE, FALSE, 0);
  452.   gtk_widget_show (spinner);
  453.  
  454.   label = gtk_label_new (_("Seconds Delay"));
  455.   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  456.   gtk_widget_show (label);
  457.  
  458.   gtk_widget_show (hbox);
  459.   gtk_widget_show (dialog);
  460.  
  461.   gtk_main ();
  462.  
  463.   return run_flag;
  464. }
  465.  
  466.  
  467. /*  delay functions  */
  468. void
  469. shoot_delay (gint delay)
  470. {
  471.   gint timeout;
  472.  
  473.   timeout = gtk_timeout_add (1000, shoot_delay_callback, &delay);  gtk_main ();
  474. }
  475.  
  476. gint 
  477. shoot_delay_callback (gpointer data)
  478. {
  479.   gint *seconds_left = (gint *)data;
  480.  
  481.   (*seconds_left)--;
  482.  
  483.   if (!*seconds_left) 
  484.     gtk_main_quit();
  485.  
  486.   return *seconds_left;
  487. }
  488.