~ubuntu-branches/ubuntu/jaunty/gimp/jaunty-security

« back to all changes in this revision

Viewing changes to tools/gimp-remote.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2007-05-02 16:33:03 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070502163303-bvzhjzbpw8qglc4y
Tags: 2.3.16-1ubuntu1
* Resynchronized with Debian, remaining Ubuntu changes:
  - debian/rules: i18n magic.
* debian/control.in:
  - Maintainer: Ubuntu Core Developers <ubuntu-devel@lists.ubuntu.com>
* debian/patches/02_help-message.patch,
  debian/patches/03_gimp.desktop.in.in.patch,
  debian/patches/10_dont_show_wizard.patch: updated.
* debian/patches/04_composite-signedness.patch,
  debian/patches/05_add-letter-spacing.patch: dropped, used upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* The GIMP -- an image manipulation program
 
1
/* GIMP - The GNU Image Manipulation Program
2
2
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3
3
 *
4
4
 * gimp-remote.c
27
27
 * It is a really bad idea to use Drag'n'Drop for inter-client
28
28
 * communication. Dont even think about doing this in your own newly
29
29
 * created application. We do this *only*, because we are in a
30
 
 * feature freeze for Gimp 1.2 and adding a completely new communication
31
 
 * infrastructure for remote controlling Gimp is definitely a new
 
30
 * feature freeze for GIMP 1.2 and adding a completely new communication
 
31
 * infrastructure for remote controlling GIMP is definitely a new
32
32
 * feature...
33
 
 * Think about sockets or Corba when you want to do something similiar.
34
 
 * We definitely consider this for Gimp 2.0.
35
33
 *                                                Simon
36
34
 */
37
35
 
45
43
#include <unistd.h>
46
44
#endif
47
45
 
 
46
#include <locale.h>
 
47
 
48
48
#include <gdk/gdkx.h>
49
49
#include <gtk/gtk.h>
50
50
 
52
52
 
53
53
#include "libgimpbase/gimpversion.h"
54
54
 
 
55
#include <glib/gi18n.h>
 
56
 
55
57
 
56
58
#define GIMP_BINARY "gimp-" GIMP_APP_VERSION
57
59
 
58
60
 
59
 
static void start_new_gimp (GdkScreen   *screen,
60
 
                            const gchar *argv0,
61
 
                            const gchar *startup_id,
62
 
                            GString     *file_list) G_GNUC_NORETURN;
63
 
 
64
 
 
65
 
static gboolean  existing  = FALSE;
66
 
static gboolean  query     = FALSE;
67
 
static gboolean  no_splash = FALSE;
 
61
static void  start_new_gimp (GdkScreen   *screen,
 
62
                             const gchar *argv0,
 
63
                             const gchar *startup_id,
 
64
                             GString     *file_list) G_GNUC_NORETURN;
 
65
 
 
66
static void  show_version   (void) G_GNUC_NORETURN;
 
67
 
 
68
 
 
69
static gboolean      existing  = FALSE;
 
70
static gboolean      query     = FALSE;
 
71
static gboolean      no_splash = FALSE;
 
72
static gboolean      print_xid = FALSE;
 
73
static const gchar **filenames = NULL;
 
74
 
 
75
static const GOptionEntry main_entries[] =
 
76
{
 
77
  { "version", 'v', G_OPTION_FLAG_NO_ARG,
 
78
    G_OPTION_ARG_CALLBACK, (GOptionArgFunc) show_version,
 
79
    N_("Show version information and exit"), NULL
 
80
  },
 
81
  {
 
82
    "existing", 'e', 0,
 
83
    G_OPTION_ARG_NONE, &existing,
 
84
    N_("Use a running GIMP only, never start a new one"), NULL
 
85
  },
 
86
  {
 
87
    "query", 'q', 0,
 
88
    G_OPTION_ARG_NONE, &query,
 
89
    N_("Only check if GIMP is running, then quit"), NULL
 
90
  },
 
91
  {
 
92
    "print-xid", 'p', 0,
 
93
    G_OPTION_ARG_NONE, &print_xid,
 
94
    N_("Print X window ID of GIMP toolbox window, then quit"), NULL
 
95
  },
 
96
  {
 
97
    "no-splash", 's', 0,
 
98
    G_OPTION_ARG_NONE, &no_splash,
 
99
    N_("Start GIMP without showing the startup window"), NULL
 
100
  },
 
101
  {
 
102
    G_OPTION_REMAINING, 0, 0,
 
103
    G_OPTION_ARG_FILENAME_ARRAY, &filenames,
 
104
    NULL, NULL
 
105
  },
 
106
  { NULL }
 
107
};
68
108
 
69
109
 
70
110
static GdkWindow *
84
124
 
85
125
  xdisplay = gdk_x11_display_get_xdisplay (display);
86
126
 
 
127
  role_atom   = XInternAtom (xdisplay, "WM_WINDOW_ROLE", TRUE);
 
128
  string_atom = XInternAtom (xdisplay, "STRING",         TRUE);
 
129
 
 
130
  if (role_atom == None || string_atom == None)
 
131
    return NULL;
 
132
 
87
133
  if (XQueryTree (xdisplay, GDK_WINDOW_XID (root_window),
88
134
                  &root, &parent, &children, &nchildren) == 0)
89
135
    return NULL;
91
137
  if (! (children && nchildren))
92
138
    return NULL;
93
139
 
94
 
  role_atom   = XInternAtom (xdisplay, "WM_WINDOW_ROLE", TRUE);
95
 
  string_atom = XInternAtom (xdisplay, "STRING",         TRUE);
96
 
 
97
140
  for (i = nchildren - 1; i >= 0; i--)
98
141
    {
99
142
      Window  window;
111
154
 
112
155
      window = XmuClientWindow (xdisplay, children[i]);
113
156
 
114
 
      /*  We are searching for the Gimp toolbox: Its WM_WINDOW_ROLE Property
 
157
      /*  We are searching for the GIMP toolbox: Its WM_WINDOW_ROLE Property
115
158
       *  (as set by gtk_window_set_role ()) has the value "gimp-toolbox".
116
 
       *  This is pretty reliable, since ask for a special property,
117
 
       *  explicitly set by the gimp. See below... :-)
 
159
       *  This is pretty reliable, since it ask for a special property,
 
160
       *  explicitly set by GIMP. See below... :-)
118
161
       */
119
162
 
120
163
      if (XGetWindowProperty (xdisplay, window,
123
166
                              FALSE,
124
167
                              string_atom,
125
168
                              &ret_type, &ret_format, &nitems, &bytes_after,
126
 
                              &data) == Success &&
127
 
          ret_type)
 
169
                              &data) == Success && ret_type)
128
170
        {
129
 
          if (nitems > 11 && strcmp (data, "gimp-toolbox") == 0)
 
171
          if (nitems > 11 &&
 
172
              strcmp ((const gchar *) data, "gimp-toolbox") == 0)
130
173
            {
131
174
              XFree (data);
132
175
              result = gdk_window_foreign_new_for_display (display, window);
144
187
 
145
188
static void
146
189
source_selection_get (GtkWidget        *widget,
147
 
                      GtkSelectionData *selection_data,
148
 
                      guint             info,
149
 
                      guint             time,
150
 
                      const gchar      *uri)
 
190
                      GtkSelectionData *selection_data,
 
191
                      guint             info,
 
192
                      guint             time,
 
193
                      const gchar      *uri)
151
194
{
152
195
  gtk_selection_data_set (selection_data,
153
196
                          selection_data->target,
154
 
                          8, uri, strlen (uri));
 
197
                          8, (const guchar *) uri, strlen (uri));
155
198
  gtk_main_quit ();
156
199
}
157
200
 
158
201
static gboolean
159
202
toolbox_hidden (gpointer data)
160
203
{
161
 
  g_printerr ("Could not connect to the Gimp.\n"
162
 
              "Make sure that the Toolbox is visible!\n");
 
204
  g_printerr ("%s\n%s\n",
 
205
              _("Could not connect to GIMP."),
 
206
              _("Make sure that the Toolbox is visible!"));
163
207
  gtk_main_quit ();
164
208
 
165
209
  return FALSE;
166
210
}
167
211
 
168
212
static void
169
 
usage (const gchar *name)
170
 
{
171
 
  g_print ("gimp-remote version %s\n\n", GIMP_VERSION);
172
 
  g_print ("Tells a running Gimp to open a (local or remote) image file.\n\n"
173
 
           "Usage: %s [options] [FILE|URI]...\n\n", name);
174
 
  g_print ("Valid options are:\n"
175
 
           "  -h, --help            Output this help.\n"
176
 
           "  -v, --version         Output version info.\n"
177
 
           "  --display <display>   Use the designated X display.\n"
178
 
           "  -e, --existing        Use a running GIMP only, never start a new one.\n"
179
 
           "  -q, --query           Query if a GIMP is running, then quit.\n"
180
 
           "  -s, --no-splash       Start GIMP w/o showing the startup window.\n"
181
 
           "\n");
182
 
  g_print ("Example:  %s http://www.gimp.org/icons/frontpage-small.gif\n"
183
 
           "     or:  %s localfile.png\n\n", name, name);
184
 
}
185
 
 
186
 
static void
187
213
start_new_gimp (GdkScreen   *screen,
188
214
                const gchar *argv0,
189
215
                const gchar *startup_id,
278
304
      execvp (GIMP_BINARY, argv);
279
305
 
280
306
      /*  if execv and execvp return, there was an error  */
281
 
      g_printerr ("Couldn't start %s for the following reason: %s\n",
282
 
                      GIMP_BINARY, g_strerror (errno));
 
307
      g_printerr (_("Couldn't start '%s': %s"),
 
308
                  GIMP_BINARY, g_strerror (errno));
 
309
      g_printerr ("\n");
283
310
 
284
311
      exit (EXIT_FAILURE);
285
312
 
291
318
}
292
319
 
293
320
static void
294
 
parse_option (const gchar *progname,
295
 
              const gchar *arg)
296
 
{
297
 
  if (strcmp (arg, "-v") == 0 ||
298
 
      strcmp (arg, "--version") == 0)
299
 
    {
300
 
      g_print ("gimp-remote version %s\n", GIMP_VERSION);
301
 
      exit (EXIT_SUCCESS);
302
 
    }
303
 
  else if (strcmp (arg, "-h") == 0 ||
304
 
           strcmp (arg, "-?") == 0 ||
305
 
           strcmp (arg, "--help") == 0 ||
306
 
           strcmp (arg, "--usage") == 0)
307
 
    {
308
 
      usage (progname);
309
 
      exit (EXIT_SUCCESS);
310
 
    }
311
 
  else if (strcmp (arg, "-e") == 0 || strcmp (arg, "--existing") == 0)
312
 
    {
313
 
      existing = TRUE;
314
 
    }
315
 
  else if (strcmp (arg, "-q") == 0 || strcmp (arg, "--query") == 0)
316
 
    {
317
 
      query = TRUE;
318
 
    }
319
 
  else if (strcmp (arg, "-s") == 0 || strcmp (arg, "--no-splash") == 0)
320
 
    {
321
 
      no_splash = TRUE;
322
 
    }
323
 
  else if (strcmp (arg, "-n") == 0 || strcmp (arg, "--new") == 0)
324
 
    {
325
 
      /*  accepted for backward compatibility; this is now the default  */
326
 
    }
327
 
  else
328
 
    {
329
 
      g_printerr ("Unknown option %s\n", arg);
330
 
      g_printerr ("Try %s --help to get detailed usage instructions.\n",
331
 
                  progname);
332
 
 
333
 
      exit (EXIT_FAILURE);
334
 
    }
 
321
show_version (void)
 
322
{
 
323
  g_print (_("%s version %s"), "gimp-remote", GIMP_VERSION);
 
324
  g_print ("\n");
 
325
 
 
326
  exit (EXIT_SUCCESS);
 
327
}
 
328
 
 
329
static void
 
330
init_i18n (void)
 
331
{
 
332
  setlocale (LC_ALL, "");
 
333
 
 
334
  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
 
335
#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
 
336
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
 
337
#endif
 
338
 
 
339
  textdomain (GETTEXT_PACKAGE);
 
340
}
 
341
 
 
342
/* Check name for a valid URI scheme as described in RFC 2396.
 
343
 * URI scheme:suffix with scheme = [alpha][alphanum|digit|+|-|.]*
 
344
 * Note that a null suffix will be considered as an invalid URI.
 
345
 * return 1 if valid scheme found, else 0
 
346
 */
 
347
static gboolean
 
348
is_valid_uri (const gchar *name)
 
349
{
 
350
  const gchar *c = name;
 
351
 
 
352
  g_return_val_if_fail (name != NULL, FALSE);
 
353
 
 
354
  /* first character must be alpha */
 
355
  if (! g_ascii_isalpha (*c))
 
356
    return FALSE;
 
357
 
 
358
  c++;
 
359
  while (*c != '\0' && *c != ':')
 
360
    {
 
361
      if (! g_ascii_isalnum (*c) && *c != '+' && *c != '-' && *c != '.')
 
362
        return FALSE;
 
363
      c++;
 
364
    }
 
365
 
 
366
  if (*c == ':')
 
367
    {
 
368
      c++;
 
369
      if (*c != '\0')
 
370
        return TRUE;
 
371
    }
 
372
 
 
373
  return FALSE;
335
374
}
336
375
 
337
376
gint
338
377
main (gint    argc,
339
378
      gchar **argv)
340
379
{
341
 
  GdkDisplay  *display;
342
 
  GdkScreen   *screen;
343
 
  GdkWindow   *gimp_window;
344
 
  const gchar *startup_id;
345
 
  gchar       *desktop_startup_id = NULL;
346
 
  GString     *file_list          = g_string_new (NULL);
347
 
  gchar       *cwd                = g_get_current_dir ();
348
 
  gint         i;
 
380
  GOptionContext *context;
 
381
  GError         *error = NULL;
 
382
  GdkDisplay     *display;
 
383
  GdkScreen      *screen;
 
384
  GdkWindow      *gimp_window;
 
385
  const gchar    *startup_id;
 
386
  gchar          *desktop_startup_id = NULL;
 
387
  GString        *file_list          = g_string_new (NULL);
 
388
 
 
389
  init_i18n ();
349
390
 
350
391
  /* we save the startup_id before calling gtk_init()
351
392
     because GTK+ will unset it  */
354
395
  if (startup_id && *startup_id)
355
396
    desktop_startup_id = g_strdup (startup_id);
356
397
 
 
398
  /* parse the command-line options */
 
399
  context = g_option_context_new ("[FILE|URI...]");
 
400
  g_option_context_add_main_entries (context, main_entries, NULL);
 
401
  g_option_context_add_group (context, gtk_get_option_group (TRUE));
 
402
 
 
403
  if (! g_option_context_parse (context, &argc, &argv, &error))
 
404
    {
 
405
      g_printerr ("%s\n", error->message);
 
406
      g_error_free (error);
 
407
 
 
408
      exit (EXIT_FAILURE);
 
409
    }
 
410
 
357
411
  gtk_init (&argc, &argv);
358
412
 
359
 
  for (i = 1; i < argc; i++)
 
413
  if (filenames)
360
414
    {
361
 
      gchar    *file_uri = NULL;
362
 
      gboolean  options  = TRUE;
363
 
 
364
 
      if (strlen (argv[i]) == 0)
365
 
        continue;
366
 
 
367
 
      if (options && *argv[i] == '-')
368
 
        {
369
 
          if (strcmp (argv[i], "--"))
370
 
            {
371
 
              parse_option (argv[0], argv[i]);
372
 
              continue;
373
 
            }
374
 
          else
375
 
            {
376
 
              /*  everything following a -- is interpreted as arguments  */
377
 
              options = FALSE;
378
 
              continue;
379
 
            }
380
 
        }
381
 
 
382
 
      /* If not already a valid URI */
383
 
      if (g_ascii_strncasecmp ("file:",  argv[i], 5) &&
384
 
          g_ascii_strncasecmp ("ftp:",   argv[i], 4) &&
385
 
          g_ascii_strncasecmp ("http:",  argv[i], 5) &&
386
 
          g_ascii_strncasecmp ("https:", argv[i], 6))
387
 
        {
388
 
          if (g_path_is_absolute (argv[i]))
389
 
            {
390
 
              file_uri = g_filename_to_uri (argv[i], NULL, NULL);
391
 
            }
392
 
          else
393
 
            {
394
 
              gchar *abs = g_build_filename (cwd, argv[i], NULL);
395
 
 
396
 
              file_uri = g_filename_to_uri (abs, NULL, NULL);
397
 
 
398
 
              g_free (abs);
399
 
            }
400
 
        }
401
 
      else
402
 
        {
403
 
          file_uri = g_strdup (argv[i]);
404
 
        }
405
 
 
406
 
      if (file_uri)
407
 
        {
408
 
          if (file_list->len > 0)
409
 
            file_list = g_string_append_c (file_list, '\n');
410
 
 
411
 
          file_list = g_string_append (file_list, file_uri);
412
 
          g_free (file_uri);
413
 
        }
 
415
      gchar *cwd = g_get_current_dir ();
 
416
      gint   i;
 
417
 
 
418
      for (i = 0; filenames[i]; i++)
 
419
        {
 
420
          const gchar *name = filenames[i];
 
421
          gchar       *uri;
 
422
 
 
423
          /* If not already a valid URI */
 
424
          if (! is_valid_uri (name))
 
425
            {
 
426
              if (g_path_is_absolute (name))
 
427
                {
 
428
                  uri = g_filename_to_uri (name, NULL, NULL);
 
429
                }
 
430
              else
 
431
                {
 
432
                  gchar *abs = g_build_filename (cwd, name, NULL);
 
433
 
 
434
                  uri = g_filename_to_uri (abs, NULL, NULL);
 
435
                  g_free (abs);
 
436
                }
 
437
            }
 
438
          else
 
439
            {
 
440
              uri = g_strdup (name);
 
441
            }
 
442
 
 
443
          if (uri)
 
444
            {
 
445
              if (file_list->len > 0)
 
446
                file_list = g_string_append_c (file_list, '\n');
 
447
 
 
448
              file_list = g_string_append (file_list, uri);
 
449
              g_free (uri);
 
450
            }
 
451
        }
 
452
 
 
453
      g_free (cwd);
414
454
    }
415
455
 
416
456
  display = gdk_display_get_default ();
417
457
  screen  = gdk_screen_get_default ();
418
458
 
419
459
  /*  if called without any filenames, always start a new GIMP  */
420
 
  if (file_list->len == 0 && !query && !existing)
 
460
  if (file_list->len == 0 && !query && !print_xid && !existing)
421
461
    {
422
462
      start_new_gimp (screen, argv[0], desktop_startup_id, file_list);
423
463
    }
424
464
 
425
465
  gimp_window = gimp_remote_find_window (display, screen);
426
466
 
427
 
  if (! query)
 
467
  if (! query && ! print_xid)
428
468
    {
429
469
      if (gimp_window)
430
470
        {
441
481
                                             &protocol);
442
482
          if (protocol != GDK_DRAG_PROTO_XDND)
443
483
            {
444
 
              g_printerr ("Gimp Window doesnt use Xdnd-Protocol - huh?\n");
 
484
              g_printerr ("GIMP Window doesnt use Xdnd-Protocol - huh?\n");
445
485
              return EXIT_FAILURE;
446
486
            }
447
487
 
450
490
           *  terminated. If the Toolbox is simply unmapped (by the WM)
451
491
           *  DnD works. But in both cases gdk_window_is_visible() returns
452
492
           *  FALSE. To work around this we add a timeout and abort after
453
 
           *  1.5 seconds.
 
493
           *  5 seconds.
454
494
           */
455
495
 
456
 
          timeout = g_timeout_add (1500, toolbox_hidden, NULL);
 
496
          timeout = g_timeout_add (5000, toolbox_hidden, NULL);
457
497
 
458
498
          /*  set up an DND-source  */
459
499
          source = gtk_window_new (GTK_WINDOW_TOPLEVEL);
460
 
          g_signal_connect (source, "selection_get",
 
500
          g_signal_connect (source, "selection-get",
461
501
                            G_CALLBACK (source_selection_get),
462
502
                            file_list->str);
463
503
          gtk_widget_realize (source);
464
504
 
465
505
 
466
506
          /*  specify the id and the content-type of the selection used to
467
 
           *  pass the URIs to Gimp.
 
507
           *  pass the URIs to GIMP.
468
508
           */
469
509
          sel_id   = gdk_atom_intern ("XdndSelection", FALSE);
470
510
          sel_type = gdk_atom_intern ("text/uri-list", FALSE);
492
532
          start_new_gimp (screen, argv[0], desktop_startup_id, file_list);
493
533
        }
494
534
    }
 
535
  else if (print_xid)
 
536
    {
 
537
      if (gimp_window)
 
538
        {
 
539
          g_print ("0x%lx\n", GDK_WINDOW_XID (gimp_window));
 
540
        }
 
541
    }
495
542
 
496
543
  gdk_notify_startup_complete ();
497
544
 
 
545
  g_option_context_free (context);
 
546
 
498
547
  g_string_free (file_list, TRUE);
499
548
  g_free (desktop_startup_id);
500
549