~ubuntu-branches/ubuntu/vivid/gimp/vivid

« back to all changes in this revision

Viewing changes to tools/gimp-remote-x11.c

  • Committer: Package Import Robot
  • Author(s): Jordi Mallach
  • Date: 2012-05-08 18:50:03 UTC
  • mto: (1.1.26) (0.5.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 71.
  • Revision ID: package-import@ubuntu.com-20120508185003-tltkvbaysf8d2426
ImportĀ upstreamĀ versionĀ 2.8.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* GIMP - The GNU Image Manipulation Program
2
 
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3
 
 *
4
 
 * gimp-remote-x11.c
5
 
 * Copyright (C) 2000-2007  Sven Neumann <sven@gimp.org>
6
 
 *                          Simon Budig <simon@gimp.org>
7
 
 *
8
 
 * X11 specific routines for gimp-remote.
9
 
 *
10
 
 * This program is free software; you can redistribute it and/or modify
11
 
 * it under the terms of the GNU General Public License as published by
12
 
 * the Free Software Foundation; either version 2 of the License, or
13
 
 * (at your option) any later version.
14
 
 *
15
 
 * This program is distributed in the hope that it will be useful,
16
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 
 * GNU General Public License for more details.
19
 
 *
20
 
 * You should have received a copy of the GNU General Public License
21
 
 * along with this program; if not, write to the Free Software
22
 
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
 
 */
24
 
 
25
 
#include "config.h"
26
 
 
27
 
#include <stdlib.h>
28
 
#include <string.h>
29
 
#include <errno.h>
30
 
 
31
 
#ifdef HAVE_UNISTD_H
32
 
#include <unistd.h>
33
 
#endif
34
 
 
35
 
#include <gdk/gdkx.h>
36
 
#include <gtk/gtk.h>
37
 
 
38
 
#include <X11/Xmu/WinUtil.h>
39
 
 
40
 
#include "libgimpbase/gimpversion.h"
41
 
 
42
 
#include <glib/gi18n.h>
43
 
 
44
 
#include "gimp-remote.h"
45
 
 
46
 
 
47
 
#define GIMP_BINARY "gimp-" GIMP_APP_VERSION
48
 
 
49
 
 
50
 
static void
51
 
source_selection_get (GtkWidget        *widget,
52
 
                      GtkSelectionData *selection_data,
53
 
                      guint             info,
54
 
                      guint             time,
55
 
                      const gchar      *uri)
56
 
{
57
 
  gtk_selection_data_set (selection_data,
58
 
                          selection_data->target,
59
 
                          8, (const guchar *) uri, strlen (uri));
60
 
  gtk_main_quit ();
61
 
}
62
 
 
63
 
static gboolean
64
 
toolbox_hidden (gpointer data)
65
 
{
66
 
  g_printerr ("%s\n%s\n",
67
 
              _("Could not connect to GIMP."),
68
 
              _("Make sure that the Toolbox is visible!"));
69
 
  gtk_main_quit ();
70
 
 
71
 
  return FALSE;
72
 
}
73
 
 
74
 
GdkWindow *
75
 
gimp_remote_find_toolbox (GdkDisplay *display,
76
 
                          GdkScreen  *screen)
77
 
{
78
 
  GdkWindow  *result = NULL;
79
 
  Display    *xdisplay;
80
 
  Window      root, parent;
81
 
  Window     *children;
82
 
  Atom        role_atom;
83
 
  Atom        string_atom;
84
 
  guint       nchildren;
85
 
  gint        i;
86
 
 
87
 
  GdkWindow  *root_window = gdk_screen_get_root_window (screen);
88
 
 
89
 
  xdisplay = gdk_x11_display_get_xdisplay (display);
90
 
 
91
 
  role_atom   = XInternAtom (xdisplay, "WM_WINDOW_ROLE", TRUE);
92
 
  string_atom = XInternAtom (xdisplay, "STRING",         TRUE);
93
 
 
94
 
  if (role_atom == None || string_atom == None)
95
 
    return NULL;
96
 
 
97
 
  if (XQueryTree (xdisplay, GDK_WINDOW_XID (root_window),
98
 
                  &root, &parent, &children, &nchildren) == 0)
99
 
    return NULL;
100
 
 
101
 
  if (! (children && nchildren))
102
 
    return NULL;
103
 
 
104
 
  for (i = nchildren - 1; i >= 0; i--)
105
 
    {
106
 
      Window  window;
107
 
      Atom    ret_type;
108
 
      gint    ret_format;
109
 
      gulong  bytes_after;
110
 
      gulong  nitems;
111
 
      guchar *data;
112
 
 
113
 
      /*  The XmuClientWindow() function finds a window at or below the
114
 
       *  specified window, that has a WM_STATE property. If such a
115
 
       *  window is found, it is returned; otherwise the argument window
116
 
       *  is returned.
117
 
       */
118
 
 
119
 
      window = XmuClientWindow (xdisplay, children[i]);
120
 
 
121
 
      /*  We are searching for the GIMP toolbox: Its WM_WINDOW_ROLE Property
122
 
       *  (as set by gtk_window_set_role ()) has the value "gimp-toolbox".
123
 
       *  This is pretty reliable, since it ask for a special property,
124
 
       *  explicitly set by GIMP. See below... :-)
125
 
       */
126
 
 
127
 
      if (XGetWindowProperty (xdisplay, window,
128
 
                              role_atom,
129
 
                              0, 32,
130
 
                              FALSE,
131
 
                              string_atom,
132
 
                              &ret_type, &ret_format, &nitems, &bytes_after,
133
 
                              &data) == Success && ret_type)
134
 
        {
135
 
          if (nitems > 11 &&
136
 
              strcmp ((const gchar *) data, "gimp-toolbox") == 0)
137
 
            {
138
 
              XFree (data);
139
 
              result = gdk_window_foreign_new_for_display (display, window);
140
 
              break;
141
 
            }
142
 
 
143
 
          XFree (data);
144
 
        }
145
 
    }
146
 
 
147
 
  XFree (children);
148
 
 
149
 
  return result;
150
 
}
151
 
 
152
 
void
153
 
gimp_remote_launch (GdkScreen   *screen,
154
 
                    const gchar *argv0,
155
 
                    const gchar *startup_id,
156
 
                    gboolean     no_splash,
157
 
                    GString     *file_list)
158
 
{
159
 
  gchar        *display_name;
160
 
  gchar       **argv;
161
 
  gchar        *gimp, *path, *name, *pwd;
162
 
  const gchar  *spath;
163
 
  gint          i;
164
 
 
165
 
  if (startup_id)
166
 
    g_setenv ("DESKTOP_STARTUP_ID", startup_id, TRUE);
167
 
 
168
 
  if (file_list->len > 0)
169
 
    file_list = g_string_prepend (file_list, "\n");
170
 
 
171
 
  display_name = gdk_screen_make_display_name (screen);
172
 
  file_list = g_string_prepend (file_list, display_name);
173
 
  file_list = g_string_prepend (file_list, "--display\n");
174
 
  g_free (display_name);
175
 
 
176
 
  if (no_splash)
177
 
    file_list = g_string_prepend (file_list, "--no-splash\n");
178
 
 
179
 
  file_list = g_string_prepend (file_list, "gimp\n");
180
 
 
181
 
  argv = g_strsplit (file_list->str, "\n", 0);
182
 
 
183
 
  /* We are searching for the path the gimp-remote executable lives in */
184
 
 
185
 
  /*
186
 
   * the "_" environment variable usually gets set by the sh-family of
187
 
   * shells. We have to sanity-check it. If we do not find anything
188
 
   * usable in it try argv[0], then fall back to search the path.
189
 
   */
190
 
 
191
 
  gimp  = NULL;
192
 
  spath = NULL;
193
 
 
194
 
  for (i = 0; i < 2; i++)
195
 
    {
196
 
      if (i == 0)
197
 
        {
198
 
          spath = g_getenv ("_");
199
 
        }
200
 
      else if (i == 1)
201
 
        {
202
 
          spath = argv0;
203
 
        }
204
 
 
205
 
      if (spath)
206
 
        {
207
 
          name = g_path_get_basename (spath);
208
 
 
209
 
          if (! strncmp (name, "gimp-remote", 11))
210
 
            {
211
 
              path = g_path_get_dirname (spath);
212
 
 
213
 
              if (g_path_is_absolute (spath))
214
 
                {
215
 
                  gimp = g_build_filename (path, GIMP_BINARY, NULL);
216
 
                }
217
 
              else
218
 
                {
219
 
                  pwd = g_get_current_dir ();
220
 
                  gimp = g_build_filename (pwd, path, GIMP_BINARY, NULL);
221
 
                  g_free (pwd);
222
 
                }
223
 
 
224
 
              g_free (path);
225
 
            }
226
 
 
227
 
          g_free (name);
228
 
        }
229
 
 
230
 
      if (gimp)
231
 
        break;
232
 
    }
233
 
 
234
 
  /* We must ensure that gimp is started with a different PID.
235
 
     Otherwise it could happen that (when it opens it's display) it sends
236
 
     the same auth token again (because that one is uniquified with PID
237
 
     and time()), which the server would deny.  */
238
 
  switch (fork ())
239
 
    {
240
 
    case -1:
241
 
      exit (EXIT_FAILURE);
242
 
 
243
 
    case 0: /* child */
244
 
      execv (gimp, argv);
245
 
      execvp (GIMP_BINARY, argv);
246
 
 
247
 
      /*  if execv and execvp return, there was an error  */
248
 
      g_printerr (_("Couldn't start '%s': %s"),
249
 
                  GIMP_BINARY, g_strerror (errno));
250
 
      g_printerr ("\n");
251
 
 
252
 
      exit (EXIT_FAILURE);
253
 
 
254
 
    default: /* parent */
255
 
      break;
256
 
    }
257
 
 
258
 
  exit (EXIT_SUCCESS);
259
 
}
260
 
 
261
 
gboolean
262
 
gimp_remote_drop_files (GdkDisplay *display,
263
 
                        GdkWindow  *window,
264
 
                        GString    *file_list)
265
 
{
266
 
  GdkDragContext  *context;
267
 
  GdkDragProtocol  protocol;
268
 
  GtkWidget       *source;
269
 
  GdkAtom          sel_type;
270
 
  GdkAtom          sel_id;
271
 
  GList           *targetlist;
272
 
  guint            timeout;
273
 
 
274
 
  gdk_drag_get_protocol_for_display (display,
275
 
                                     GDK_WINDOW_XID (window),
276
 
                                     &protocol);
277
 
  if (protocol != GDK_DRAG_PROTO_XDND)
278
 
    {
279
 
      g_printerr ("GIMP Window doesnt use Xdnd-Protocol - huh?\n");
280
 
      return FALSE;
281
 
    }
282
 
 
283
 
  /*  Problem: If the Toolbox is hidden via Tab (gtk_widget_hide)
284
 
   *  it does not accept DnD-Operations and gtk_main() will not be
285
 
   *  terminated. If the Toolbox is simply unmapped (by the WM)
286
 
   *  DnD works. But in both cases gdk_window_is_visible() returns
287
 
   *  FALSE. To work around this we add a timeout and abort after
288
 
   *  5 seconds.
289
 
   */
290
 
 
291
 
  timeout = g_timeout_add (5000, toolbox_hidden, NULL);
292
 
 
293
 
  /*  set up an DND-source  */
294
 
  source = gtk_window_new (GTK_WINDOW_TOPLEVEL);
295
 
  g_signal_connect (source, "selection-get",
296
 
                    G_CALLBACK (source_selection_get),
297
 
                    file_list->str);
298
 
  gtk_widget_realize (source);
299
 
 
300
 
 
301
 
  /*  specify the id and the content-type of the selection used to
302
 
   *  pass the URIs to GIMP.
303
 
   */
304
 
  sel_id   = gdk_atom_intern ("XdndSelection", FALSE);
305
 
  sel_type = gdk_atom_intern ("text/uri-list", FALSE);
306
 
  targetlist = g_list_prepend (NULL, GUINT_TO_POINTER (sel_type));
307
 
 
308
 
  /*  assign the selection to our DnD-source  */
309
 
  gtk_selection_owner_set (source, sel_id, GDK_CURRENT_TIME);
310
 
  gtk_selection_add_target (source, sel_id, sel_type, 0);
311
 
 
312
 
  /*  drag_begin/motion/drop  */
313
 
  context = gdk_drag_begin (source->window, targetlist);
314
 
 
315
 
  gdk_drag_motion (context, window, protocol, 0, 0,
316
 
                   GDK_ACTION_COPY, GDK_ACTION_COPY, GDK_CURRENT_TIME);
317
 
 
318
 
  gdk_drag_drop (context, GDK_CURRENT_TIME);
319
 
 
320
 
  /*  finally enter the mainloop to handle the events  */
321
 
  gtk_main ();
322
 
 
323
 
  g_source_remove (timeout);
324
 
 
325
 
  return TRUE;
326
 
}
327
 
 
328
 
void
329
 
gimp_remote_print_id (GdkWindow *window)
330
 
{
331
 
  g_print ("0x%lx\n", GDK_WINDOW_XID (window));
332
 
}