screenshot.c 16.4 KB
Newer Older
1
/*
2
 *  ScreenShot plug-in
3
 *  Copyright 1998-2000 Sven Neumann <sven@gimp.org>
4
 *  Copyright 2003      Henrik Brix Andersen <brix@gimp.org>
Manish Singh's avatar
Manish Singh committed
5 6
 *
 *  Any suggestions, bug-reports or patches are very welcome.
7
 *
Manish Singh's avatar
Manish Singh committed
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 */

/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * 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
Manish Singh's avatar
Manish Singh committed
25
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Manish Singh's avatar
Manish Singh committed
26 27
 */

28 29 30 31 32 33 34
#include "config.h"

#include <gtk/gtk.h>

#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>

35
#if defined(GDK_WINDOWING_X11)
36
#include <gdk/gdkx.h>
37 38 39
#elif defined(GDK_WINDOWING_WIN32)
#include <windows.h>
#endif
40

Sven Neumann's avatar
Sven Neumann committed
41
#include "libgimp/stdplugins-intl.h"
Manish Singh's avatar
Manish Singh committed
42

43

Manish Singh's avatar
Manish Singh committed
44
/* Defines */
45
#define PLUG_IN_NAME "plug_in_screenshot"
Manish Singh's avatar
Manish Singh committed
46

47 48
#ifdef __GNUC__
#ifdef GDK_NATIVE_WINDOW_POINTER
49
#if GLIB_SIZEOF_VOID_P != 4
50 51 52
#warning window_id does not fit in PDB_INT32
#endif
#endif
Manish Singh's avatar
Manish Singh committed
53 54
#endif

55 56
typedef struct
{
57 58 59
  gboolean         root;
  guint            window_id;
  guint            delay;
Manish Singh's avatar
Manish Singh committed
60 61
} ScreenShotValues;

62 63
static ScreenShotValues shootvals =
{
64
  FALSE,     /* root window */
65 66
  0,         /* window ID   */
  0,         /* delay       */
Manish Singh's avatar
Manish Singh committed
67 68 69
};


70
static void      query (void);
71 72
static void      run   (const gchar      *name,
			gint              nparams,
73
			const GimpParam  *param,
74 75
			gint             *nreturn_vals,
			GimpParam       **return_vals);
Manish Singh's avatar
Manish Singh committed
76

77 78 79
static GdkNativeWindow select_window  (const GdkScreen *screen);
static gint32          create_image   (const GdkPixbuf *pixbuf);

80 81
static void      shoot                (void);
static gboolean  shoot_dialog         (void);
82
static void      shoot_ok_callback    (GtkWidget *widget,
83 84
				       gpointer   data);
static void      shoot_delay          (gint32     delay);
85
static gboolean  shoot_delay_callback (gpointer   data);
86

Manish Singh's avatar
Manish Singh committed
87 88

/* Global Variables */
Sven Neumann's avatar
Sven Neumann committed
89
GimpPlugInInfo PLUG_IN_INFO =
Manish Singh's avatar
Manish Singh committed
90
{
91 92 93 94
  NULL,  /* init_proc  */
  NULL,	 /* quit_proc  */
  query, /* query_proc */
  run    /* run_proc   */
Manish Singh's avatar
Manish Singh committed
95 96 97
};

/* the image that will be returned */
98
gint32     image_ID = -1;
Manish Singh's avatar
Manish Singh committed
99

100
gboolean   run_flag = FALSE;
101

102 103 104 105 106
/* the screen on which we are running */
GdkScreen *cur_screen = NULL;

/* the window the user selected */
GdkNativeWindow selected_native;
107

Manish Singh's avatar
Manish Singh committed
108 109 110 111
/* Functions */

MAIN ()

112 113
static void
query (void)
Manish Singh's avatar
Manish Singh committed
114
{
Sven Neumann's avatar
Sven Neumann committed
115
  static GimpParamDef args[] =
116
  {
117 118 119
    { GIMP_PDB_INT32, "run_mode",  "Interactive, non-interactive" },
    { GIMP_PDB_INT32, "root",      "Root window { TRUE, FALSE }" },
    { GIMP_PDB_INT32, "window_id", "Window id" }
120 121
  };

Sven Neumann's avatar
Sven Neumann committed
122
  static GimpParamDef return_vals[] =
123
  {
Sven Neumann's avatar
Sven Neumann committed
124
    { GIMP_PDB_IMAGE, "image", "Output image" }
125
  };
Manish Singh's avatar
Manish Singh committed
126 127

  gimp_install_procedure (PLUG_IN_NAME,
128
			  "Creates a screenshot of a single window or the whole screen",
129 130 131 132 133 134 135 136
                          "After specifying some options the user selects a window and "
                          "a time out is started. At the end of the time out the window "
                          "is grabbed and the image is loaded into The GIMP. Alternatively "
                          "the whole screen can be grabbed. When called non-interactively "
                          "it may grab the root window or use the window-id passed as a parameter.",
			  "Sven Neumann <sven@gimp.org>, Henrik Brix Andersen <brix@gimp.org>",
			  "1998 - 2003",
			  "v0.9.6 (2003/08/28)",
Jakub Steiner's avatar
Jakub Steiner committed
137
			  N_("<Toolbox>/File/Acquire/_Screen Shot..."),
Manish Singh's avatar
Manish Singh committed
138
			  NULL,
139
			  GIMP_PLUGIN,
140 141
			  G_N_ELEMENTS (args),
                          G_N_ELEMENTS (return_vals),
142
			  args, return_vals);
Manish Singh's avatar
Manish Singh committed
143 144
}

145
static void
146 147 148 149 150
run (const gchar      *name,
     gint             nparams,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
Manish Singh's avatar
Manish Singh committed
151 152
{
  /* Get the runmode from the in-parameters */
153
  GimpRunMode run_mode = param[0].data.d_int32;
154

155
  /* status variable, use it to check for errors in invocation usually only
156 157
   * during non-interactive calling
   */
158
  GimpPDBStatusType status = GIMP_PDB_SUCCESS;
159 160

  /* always return at least the status to the caller. */
161
  static GimpParam values[2];
162

163
  /* initialize the return of the status */
164
  values[0].type          = GIMP_PDB_STATUS;
Manish Singh's avatar
Manish Singh committed
165 166
  values[0].data.d_status = status;
  *nreturn_vals = 1;
167
  *return_vals  = values;
168

169 170
  INIT_I18N ();

171
  /* how are we running today? */
Manish Singh's avatar
Manish Singh committed
172
  switch (run_mode)
173
    {
Sven Neumann's avatar
Sven Neumann committed
174
    case GIMP_RUN_INTERACTIVE:
Manish Singh's avatar
Manish Singh committed
175 176
      /* Possibly retrieve data from a previous run */
      gimp_get_data (PLUG_IN_NAME, &shootvals);
177
      shootvals.window_id = 0;
Manish Singh's avatar
Manish Singh committed
178

Sven Neumann's avatar
Sven Neumann committed
179 180
     /* Get information from the dialog */
      if (!shoot_dialog ())
181
	status = GIMP_PDB_EXECUTION_ERROR;
Manish Singh's avatar
Manish Singh committed
182 183
      break;

Sven Neumann's avatar
Sven Neumann committed
184
    case GIMP_RUN_NONINTERACTIVE:
185
      if (nparams == 3)
Manish Singh's avatar
Manish Singh committed
186
	{
187
	  shootvals.root      = param[1].data.d_int32;
188
	  shootvals.window_id = param[2].data.d_int32;
189
	  shootvals.delay     = 0;
Manish Singh's avatar
Manish Singh committed
190 191
	}
      else
Sven Neumann's avatar
Sven Neumann committed
192
	status = GIMP_PDB_CALLING_ERROR;
193 194 195

      if (!gdk_init_check (0, NULL))
	status = GIMP_PDB_CALLING_ERROR;
Manish Singh's avatar
Manish Singh committed
196
      break;
197

Sven Neumann's avatar
Sven Neumann committed
198
    case GIMP_RUN_WITH_LAST_VALS:
Manish Singh's avatar
Manish Singh committed
199 200 201
      /* Possibly retrieve data from a previous run */
      gimp_get_data (PLUG_IN_NAME, &shootvals);
      break;
202

Manish Singh's avatar
Manish Singh committed
203 204
    default:
      break;
205
    }
Manish Singh's avatar
Manish Singh committed
206

Sven Neumann's avatar
Sven Neumann committed
207
  if (status == GIMP_PDB_SUCCESS)
208 209 210 211 212
    {
      if (shootvals.delay > 0)
	shoot_delay (shootvals.delay);
      /* Run the main function */
      shoot ();
Manish Singh's avatar
Manish Singh committed
213

214 215
      status = (image_ID != -1) ? GIMP_PDB_SUCCESS : GIMP_PDB_EXECUTION_ERROR;
    }
Manish Singh's avatar
Manish Singh committed
216

Sven Neumann's avatar
Sven Neumann committed
217
  if (status == GIMP_PDB_SUCCESS)
218
    {
Sven Neumann's avatar
Sven Neumann committed
219
      if (run_mode == GIMP_RUN_INTERACTIVE)
220 221 222 223
	{
	  /* Store variable states for next run */
	  gimp_set_data (PLUG_IN_NAME, &shootvals, sizeof (ScreenShotValues));
	  /* display the image */
224
	  gimp_display_new (image_ID);
225 226 227
	}
      /* set return values */
      *nreturn_vals = 2;
Sven Neumann's avatar
Sven Neumann committed
228
      values[1].type = GIMP_PDB_IMAGE;
229 230
      values[1].data.d_image = image_ID;
    }
231

232
  values[0].data.d_status = status;
Manish Singh's avatar
Manish Singh committed
233 234
}

235
/* Allow the user to select a window with the mouse */
Manish Singh's avatar
Manish Singh committed
236

237 238
static GdkNativeWindow
select_window (const GdkScreen *screen)
Manish Singh's avatar
Manish Singh committed
239
{
240 241
#if defined(GDK_WINDOWING_X11)
  /* X11 specific code */
242

243
#define MASK (ButtonPressMask | ButtonReleaseMask)
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258

  Display    *x_dpy;
  Cursor      x_cursor;
  XEvent      x_event;
  Window      x_win;
  Window      x_root;
  gint        x_scr;
  gint        status;
  gint        buttons;

  x_dpy = GDK_SCREEN_XDISPLAY (GDK_SCREEN (screen));
  x_scr = GDK_SCREEN_XNUMBER (GDK_SCREEN (screen));

  x_win    = None;
  x_root   = RootWindow (x_dpy, x_scr);
259
  x_cursor = XCreateFontCursor (x_dpy, GDK_CROSSHAIR);
260 261 262
  buttons  = 0;

  status = XGrabPointer (x_dpy, x_root, False,
263
                         MASK, GrabModeSync, GrabModeAsync,
264 265 266
                         x_root, x_cursor, CurrentTime);

  if (status != GrabSuccess)
Manish Singh's avatar
Manish Singh committed
267
    {
268 269
      g_message (_("Screen Shot: Error grabbing the pointer"));
      return 0;
Manish Singh's avatar
Manish Singh committed
270
    }
271 272

  while ((x_win == None) || (buttons != 0))
Manish Singh's avatar
Manish Singh committed
273
    {
274
      XAllowEvents (x_dpy, SyncPointer, CurrentTime);
275
      XWindowEvent (x_dpy, x_root, MASK, &x_event);
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296

      switch (x_event.type)
        {
        case ButtonPress:
          if (x_win == None)
            {
              x_win = x_event.xbutton.subwindow;
              if (x_win == None)
                x_win = x_root;
            }
          buttons++;
          break;

        case ButtonRelease:
          if (buttons > 0)
            buttons--;
          break;

        default:
          g_assert_not_reached ();
        }
Manish Singh's avatar
Manish Singh committed
297
    }
298 299

  XUngrabPointer (x_dpy, CurrentTime);
300
  XFreeCursor (x_dpy, x_cursor);
301 302

  return x_win;
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
#elif defined(GDK_WINDOWING_WIN32)
  /* MS Windows specific code goes here (yet to be written) */

  /* basically the code should grab the pointer using a crosshair
     cursor, allow the user to click on a window and return the
     obtained HWND (as a GdkNativeWindow) - for more details consult
     the X11 specific code below */

  /* note to self: take a look at the winsnap plug-in for example
     code */

#warning Win32 screenshot window chooser not implemented yet
  return 0;
#else
#warning screenshot window chooser not implemented yet for this GDB backend
  return 0;
319
#endif /* GDK_WINDOWING_WIN32 */
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
}

/* Create a GimpImage from a GdkPixbuf */

static gint32
create_image (const GdkPixbuf *pixbuf)
{
  GimpPixelRgn	pr;
  GimpDrawable *drawable;
  GimpParasite *parasite;
  gint32        image;
  gint32        layer;
  gdouble       xres, yres;
  gchar        *comment;
  gint          width, height;
  gint          rowstride;
  gboolean      status;
  gchar        *buf;
  gint          i;

  width  = gdk_pixbuf_get_width (GDK_PIXBUF (pixbuf));
  height = gdk_pixbuf_get_height (GDK_PIXBUF (pixbuf));

  image = gimp_image_new (width, height, GIMP_RGB);
  layer = gimp_layer_new (image, _("Background"),
                          width, height,
                          GIMP_RGB_IMAGE, 100, GIMP_NORMAL_MODE);

  gimp_image_add_layer (image, layer, 0);

  drawable = gimp_drawable_get (layer);

  gimp_pixel_rgn_init (&pr, drawable,
                       0, 0, width, height,
                       TRUE, FALSE);

  /* copy the contents of the GdkPixbuf to the GimpDrawable */
  rowstride = gdk_pixbuf_get_rowstride (GDK_PIXBUF (pixbuf));
  buf       = gdk_pixbuf_get_pixels (GDK_PIXBUF (pixbuf));
  status    = gimp_progress_init (_("Loading Screen Shot..."));

  for (i = 0; i < height; i++)
Manish Singh's avatar
Manish Singh committed
362
    {
363 364 365 366 367
      gimp_pixel_rgn_set_row (&pr, buf, 0, i, width);
      buf += rowstride;
      /* update progress every 10 percent */
      if (status && ((i + 1) * 100 / height) % 10 == 0)
        status = gimp_progress_update ((i + 1.0) / height);
Manish Singh's avatar
Manish Singh committed
368
    }
369 370 371 372 373 374 375 376 377 378 379

  gimp_progress_update (1.0);

  /*  figure out the monitor resolution and set the image to it  */
  gimp_get_monitor_resolution (&xres, &yres);
  gimp_image_set_resolution (image, xres, yres);

  /* Set the default comment parasite */
  comment = gimp_get_default_comment ();

  if (comment)
380
    {
381 382 383 384 385 386 387 388
      parasite = gimp_parasite_new ("gimp-comment",
                                    GIMP_PARASITE_PERSISTENT,
                                    g_utf8_strlen (comment, -1) + 1,
                                    comment);

      gimp_image_parasite_attach (image_ID, parasite);
      gimp_parasite_free (parasite);
      g_free (comment);
389
    }
390

391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
  return image;
}

/* The main ScreenShot function */

static void
shoot (void)
{
  GdkWindow    *window;
  GdkPixbuf    *screenshot;
  GdkRectangle  clip;
  GdkPoint      origin;
  gint          screen_w, screen_h;

  /* use default screen if we are running non-interactively */
  if (cur_screen == NULL)
    cur_screen = gdk_screen_get_default ();

  screen_w = gdk_screen_get_width (GDK_SCREEN (cur_screen));
  screen_h = gdk_screen_get_height (GDK_SCREEN (cur_screen));
  clip.x   = 0;
  clip.y   = 0;

  if (shootvals.root)
    {
      /* entire screen */
      window = gdk_screen_get_root_window (GDK_SCREEN (cur_screen));
    }
  else
    {
      /* single window */
      if (shootvals.window_id)
        {
          window = gdk_window_foreign_new (shootvals.window_id);
        }
      else
        {
          window = gdk_window_foreign_new (selected_native);
        }
Manish Singh's avatar
Manish Singh committed
430 431
    }

432
  if (!window)
433
    {
434 435
      g_message (_("Screen Shot: Specified window not found"));
      return;
436 437
    }

438 439
  gdk_drawable_get_size (GDK_WINDOW (window), &clip.width, &clip.height);
  gdk_window_get_origin (GDK_WINDOW (window), &origin.x, &origin.y);
440

441 442
  /* do clipping */
  if (origin.x < 0)
443
    {
444 445 446 447 448 449 450 451 452 453 454 455
      clip.x = -origin.x;
      clip.width += origin.x;
    }
  if (origin.y < 0)
    {
      clip.y = -origin.y;
      clip.height += origin.y;
    }
  if (origin.x + clip.width > screen_w)
    clip.width -= origin.x + clip.width - screen_w;
  if (origin.y + clip.height > screen_h)
    clip.height -= origin.y + clip.height - screen_h;
456

457 458 459 460 461 462 463 464 465 466 467
  screenshot = gdk_pixbuf_get_from_drawable (NULL, GDK_WINDOW (window),
                                             NULL, clip.x, clip.y, 0, 0,
                                             clip.width, clip.height);

  gdk_display_beep (gdk_screen_get_display (GDK_SCREEN (cur_screen)));
  gdk_flush ();

  if (!screenshot)
    {
      g_message (_("Screen Shot: Error obtaining screenshot"));
      return;
468
    }
Manish Singh's avatar
Manish Singh committed
469

470 471
  image_ID = create_image (GDK_PIXBUF (screenshot));
}
Manish Singh's avatar
Manish Singh committed
472

473
/*  ScreenShot dialog  */
Manish Singh's avatar
Manish Singh committed
474

475
static void
476
shoot_ok_callback (GtkWidget *widget,
477 478 479
		   gpointer   data)
{
  run_flag = TRUE;
480 481 482 483

  /* get the screen on which we are running */
  cur_screen = gtk_widget_get_screen (GTK_WIDGET (widget));

484
  gtk_widget_destroy (GTK_WIDGET (data));
485 486 487

  if (!shootvals.root && !shootvals.window_id)
    selected_native = select_window (GDK_SCREEN (cur_screen));
488 489 490
}

static gboolean
Manish Singh's avatar
Manish Singh committed
491 492 493
shoot_dialog (void)
{
  GtkWidget *dialog;
494
  GtkWidget *main_vbox;
Manish Singh's avatar
Manish Singh committed
495 496 497
  GtkWidget *frame;
  GtkWidget *vbox;
  GtkWidget *hbox;
498
  GtkWidget *label;
499 500
  GtkWidget *button;
  GtkWidget *spinner;
Manish Singh's avatar
Manish Singh committed
501
  GSList    *radio_group = NULL;
502
  GtkObject *adj;
503

Manish Singh's avatar
Manish Singh committed
504

505
  gimp_ui_init ("screenshot", FALSE);
Manish Singh's avatar
Manish Singh committed
506

507
  /*  main dialog  */
508
  dialog = gimp_dialog_new (_("Screen Shot"), "screenshot",
509
			    gimp_standard_help_func, "filters/screenshot.html",
510 511 512
			    GTK_WIN_POS_MOUSE,
			    FALSE, TRUE, FALSE,

513
			    GTK_STOCK_CANCEL, gtk_widget_destroy,
514
			    NULL, 1, NULL, FALSE, TRUE,
Sven Neumann's avatar
Sven Neumann committed
515 516
			    GTK_STOCK_OK, shoot_ok_callback,
			    NULL, NULL, NULL, TRUE, FALSE,
517 518 519

			    NULL);

520
  g_signal_connect (dialog, "destroy",
521 522
                    G_CALLBACK (gtk_main_quit),
                    NULL);
523 524 525 526 527 528

  main_vbox = gtk_vbox_new (FALSE, 4);
  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), main_vbox,
		      TRUE, TRUE, 0);
  gtk_widget_show (main_vbox);
Manish Singh's avatar
Manish Singh committed
529

530 531
  /*  single window  */
  frame = gtk_frame_new (_("Grab"));
Manish Singh's avatar
Manish Singh committed
532
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
533
  gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
Manish Singh's avatar
Manish Singh committed
534

535
  vbox = gtk_vbox_new (FALSE, 2);
536
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
Manish Singh's avatar
Manish Singh committed
537 538
  gtk_container_add (GTK_CONTAINER (frame), vbox);

539
  button = gtk_radio_button_new_with_mnemonic (radio_group,
540
					       _("_Single Window"));
541
  radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
542
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), ! shootvals.root);
543
  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
544 545 546 547 548
  gtk_widget_show (button);

  g_object_set_data (G_OBJECT (button), "gimp-item-data",
                     GINT_TO_POINTER (FALSE));

549
  g_signal_connect (button, "toggled",
550 551
                    G_CALLBACK (gimp_radio_button_update),
                    &shootvals.root);
552 553

  /*  root window  */
554 555
  button = gtk_radio_button_new_with_mnemonic (radio_group,
					       _("_Whole Screen"));
556
  radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
557
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), shootvals.root);
558
  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
559 560 561 562

  g_object_set_data (G_OBJECT (button), "gimp-item-data",
                     GINT_TO_POINTER (TRUE));

563
  g_signal_connect (button, "toggled",
564 565
                    G_CALLBACK (gimp_radio_button_update),
                    &shootvals.root);
Manish Singh's avatar
Manish Singh committed
566

567
  gtk_widget_show (button);
568 569 570
  gtk_widget_show (vbox);
  gtk_widget_show (frame);

571
  /*  with delay  */
572 573
  hbox = gtk_hbox_new (FALSE, 4);
  gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
574
  label = gtk_label_new_with_mnemonic (_("_after"));
575
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
576
  gtk_widget_show (label);
577

578 579 580 581
  adj = gtk_adjustment_new (shootvals.delay, 0.0, 100.0, 1.0, 5.0, 0.0);
  spinner = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 0, 0);
  gtk_box_pack_start (GTK_BOX (hbox), spinner, FALSE, FALSE, 0);
  gtk_widget_show (spinner);
582

583
  g_signal_connect (adj, "value_changed",
584
                    G_CALLBACK (gimp_int_adjustment_update),
585 586
                    &shootvals.delay);

587 588
  label = gtk_label_new (_("Seconds Delay"));
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
589 590
  gtk_widget_show (label);

591
  gtk_widget_show (hbox);
Manish Singh's avatar
Manish Singh committed
592 593 594 595
  gtk_widget_show (dialog);

  gtk_main ();

596
  return run_flag;
597 598 599
}


600
/*  delay functions  */
601 602 603
void
shoot_delay (gint delay)
{
604 605
  g_timeout_add (1000, shoot_delay_callback, &delay);
  gtk_main ();
606 607
}

608
gboolean
609 610
shoot_delay_callback (gpointer data)
{
611
  gint *seconds_left = data;
612

613
  (*seconds_left)--;
614

615
  if (!*seconds_left)
616
    gtk_main_quit ();
Manish Singh's avatar
Manish Singh committed
617

618 619
  return *seconds_left;
}