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
33
* Think about sockets or Corba when you want to do something similiar.
34
* We definitely consider this for Gimp 2.0.
53
53
#include "libgimpbase/gimpversion.h"
55
#include <glib/gi18n.h>
56
58
#define GIMP_BINARY "gimp-" GIMP_APP_VERSION
59
static void start_new_gimp (GdkScreen *screen,
61
const gchar *startup_id,
62
GString *file_list) G_GNUC_NORETURN;
65
static gboolean existing = FALSE;
66
static gboolean query = FALSE;
67
static gboolean no_splash = FALSE;
61
static void start_new_gimp (GdkScreen *screen,
63
const gchar *startup_id,
64
GString *file_list) G_GNUC_NORETURN;
66
static void show_version (void) G_GNUC_NORETURN;
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;
75
static const GOptionEntry main_entries[] =
77
{ "version", 'v', G_OPTION_FLAG_NO_ARG,
78
G_OPTION_ARG_CALLBACK, (GOptionArgFunc) show_version,
79
N_("Show version information and exit"), NULL
83
G_OPTION_ARG_NONE, &existing,
84
N_("Use a running GIMP only, never start a new one"), NULL
88
G_OPTION_ARG_NONE, &query,
89
N_("Only check if GIMP is running, then quit"), NULL
93
G_OPTION_ARG_NONE, &print_xid,
94
N_("Print X window ID of GIMP toolbox window, then quit"), NULL
98
G_OPTION_ARG_NONE, &no_splash,
99
N_("Start GIMP without showing the startup window"), NULL
102
G_OPTION_REMAINING, 0, 0,
103
G_OPTION_ARG_FILENAME_ARRAY, &filenames,
70
110
static GdkWindow *
85
125
xdisplay = gdk_x11_display_get_xdisplay (display);
127
role_atom = XInternAtom (xdisplay, "WM_WINDOW_ROLE", TRUE);
128
string_atom = XInternAtom (xdisplay, "STRING", TRUE);
130
if (role_atom == None || string_atom == None)
87
133
if (XQueryTree (xdisplay, GDK_WINDOW_XID (root_window),
88
134
&root, &parent, &children, &nchildren) == 0)
112
155
window = XmuClientWindow (xdisplay, children[i]);
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... :-)
120
163
if (XGetWindowProperty (xdisplay, window,
146
189
source_selection_get (GtkWidget *widget,
147
GtkSelectionData *selection_data,
190
GtkSelectionData *selection_data,
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 ();
159
202
toolbox_hidden (gpointer data)
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 ();
169
usage (const gchar *name)
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"
182
g_print ("Example: %s http://www.gimp.org/icons/frontpage-small.gif\n"
183
" or: %s localfile.png\n\n", name, name);
187
213
start_new_gimp (GdkScreen *screen,
188
214
const gchar *argv0,
189
215
const gchar *startup_id,
294
parse_option (const gchar *progname,
297
if (strcmp (arg, "-v") == 0 ||
298
strcmp (arg, "--version") == 0)
300
g_print ("gimp-remote version %s\n", GIMP_VERSION);
303
else if (strcmp (arg, "-h") == 0 ||
304
strcmp (arg, "-?") == 0 ||
305
strcmp (arg, "--help") == 0 ||
306
strcmp (arg, "--usage") == 0)
311
else if (strcmp (arg, "-e") == 0 || strcmp (arg, "--existing") == 0)
315
else if (strcmp (arg, "-q") == 0 || strcmp (arg, "--query") == 0)
319
else if (strcmp (arg, "-s") == 0 || strcmp (arg, "--no-splash") == 0)
323
else if (strcmp (arg, "-n") == 0 || strcmp (arg, "--new") == 0)
325
/* accepted for backward compatibility; this is now the default */
329
g_printerr ("Unknown option %s\n", arg);
330
g_printerr ("Try %s --help to get detailed usage instructions.\n",
323
g_print (_("%s version %s"), "gimp-remote", GIMP_VERSION);
332
setlocale (LC_ALL, "");
334
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
335
#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
336
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
339
textdomain (GETTEXT_PACKAGE);
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
348
is_valid_uri (const gchar *name)
350
const gchar *c = name;
352
g_return_val_if_fail (name != NULL, FALSE);
354
/* first character must be alpha */
355
if (! g_ascii_isalpha (*c))
359
while (*c != '\0' && *c != ':')
361
if (! g_ascii_isalnum (*c) && *c != '+' && *c != '-' && *c != '.')
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 ();
380
GOptionContext *context;
381
GError *error = NULL;
384
GdkWindow *gimp_window;
385
const gchar *startup_id;
386
gchar *desktop_startup_id = NULL;
387
GString *file_list = g_string_new (NULL);
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);
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));
403
if (! g_option_context_parse (context, &argc, &argv, &error))
405
g_printerr ("%s\n", error->message);
406
g_error_free (error);
357
411
gtk_init (&argc, &argv);
359
for (i = 1; i < argc; i++)
361
gchar *file_uri = NULL;
362
gboolean options = TRUE;
364
if (strlen (argv[i]) == 0)
367
if (options && *argv[i] == '-')
369
if (strcmp (argv[i], "--"))
371
parse_option (argv[0], argv[i]);
376
/* everything following a -- is interpreted as arguments */
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))
388
if (g_path_is_absolute (argv[i]))
390
file_uri = g_filename_to_uri (argv[i], NULL, NULL);
394
gchar *abs = g_build_filename (cwd, argv[i], NULL);
396
file_uri = g_filename_to_uri (abs, NULL, NULL);
403
file_uri = g_strdup (argv[i]);
408
if (file_list->len > 0)
409
file_list = g_string_append_c (file_list, '\n');
411
file_list = g_string_append (file_list, file_uri);
415
gchar *cwd = g_get_current_dir ();
418
for (i = 0; filenames[i]; i++)
420
const gchar *name = filenames[i];
423
/* If not already a valid URI */
424
if (! is_valid_uri (name))
426
if (g_path_is_absolute (name))
428
uri = g_filename_to_uri (name, NULL, NULL);
432
gchar *abs = g_build_filename (cwd, name, NULL);
434
uri = g_filename_to_uri (abs, NULL, NULL);
440
uri = g_strdup (name);
445
if (file_list->len > 0)
446
file_list = g_string_append_c (file_list, '\n');
448
file_list = g_string_append (file_list, uri);
416
456
display = gdk_display_get_default ();
417
457
screen = gdk_screen_get_default ();
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)
422
462
start_new_gimp (screen, argv[0], desktop_startup_id, file_list);
425
465
gimp_window = gimp_remote_find_window (display, screen);
467
if (! query && ! print_xid)
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
456
timeout = g_timeout_add (1500, toolbox_hidden, NULL);
496
timeout = g_timeout_add (5000, toolbox_hidden, NULL);
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),
463
503
gtk_widget_realize (source);
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.
469
509
sel_id = gdk_atom_intern ("XdndSelection", FALSE);
470
510
sel_type = gdk_atom_intern ("text/uri-list", FALSE);