~ubuntu-branches/debian/sid/gnome-flashback/sid

« back to all changes in this revision

Viewing changes to gnome-flashback/libscreenshot/gf-screenshot.c

  • Committer: Package Import Robot
  • Author(s): Dmitry Shachnev
  • Date: 2015-09-25 18:45:14 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20150925184514-knl3kqg29qpvwxf9
Tags: 3.18.0-1
* New upstream release.
  - Added new module for switching keyboard layouts (closes: #731245).
  - Multiple fixes for display-config module (closes: #735279).
* Drop build-dependency on gnome-common, no longer needed.
* Add new build-dependencies:
  - libgnome-bluetooth-dev for bluetooth applet;
  - libibus-1.0-dev, libxkbcommon-x11-dev, libxkbfile-dev, xkb-data
    for input-sources module;
  - libpolkit-agent-1-dev, libpolkit-gobject-1-dev for polkit module.
* Install /usr/share/desktop-directories in gnome-flashback-common.
* Update debian/copyright.
* Drop no longer needed policykit-1-gnome dependency from
  gnome-session-flashback.
* Tighten some dependencies.
* Update gnome-flashback package description.
* Make gnome-flashback suggest gnome-power-manager (the power applet
  tries to call gnome-power-statistics application).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2015 Alberts Muktupāvels
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation, either version 3 of the License, or
 
7
 * (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 
16
 *
 
17
 * Based on code in gnome-screenshot:
 
18
 * https://git.gnome.org/browse/gnome-screenshot/tree/src/screenshot-utils.c
 
19
 * Copyright (C) 2001 - 2006 Jonathan Blandford, 2008 Cosimo Cecchi
 
20
 */
 
21
 
 
22
#include "config.h"
 
23
 
 
24
#include <gtk/gtk.h>
 
25
#include <gdk/gdkx.h>
 
26
#include <X11/extensions/shape.h>
 
27
 
 
28
#include "gf-dbus-screenshot.h"
 
29
#include "gf-flashspot.h"
 
30
#include "gf-screenshot.h"
 
31
#include "gf-select-area.h"
 
32
 
 
33
#define SCREENSHOT_DBUS_NAME "org.gnome.Shell.Screenshot"
 
34
#define SCREENSHOT_DBUS_PATH "/org/gnome/Shell/Screenshot"
 
35
 
 
36
typedef void (*GfInvocationCallback) (GfDBusScreenshot      *dbus_screenshot,
 
37
                                      GDBusMethodInvocation *invocation,
 
38
                                      gboolean               result,
 
39
                                      const gchar           *filename);
 
40
 
 
41
struct _GfScreenshot
 
42
{
 
43
  GObject           parent;
 
44
 
 
45
  GfDBusScreenshot *dbus_screenshot;
 
46
  gint              bus_name;
 
47
 
 
48
  GHashTable       *senders;
 
49
 
 
50
  GSettings        *lockdown;
 
51
};
 
52
 
 
53
typedef struct
 
54
{
 
55
  GfScreenshot *screenshot;
 
56
  gchar        *sender;
 
57
} FlashspotData;
 
58
 
 
59
typedef enum
 
60
{
 
61
  SCREENSHOT_SCREEN,
 
62
  SCREENSHOT_WINDOW,
 
63
  SCREENSHOT_AREA
 
64
} ScreenshotType;
 
65
 
 
66
G_DEFINE_TYPE (GfScreenshot, gf_screenshot, G_TYPE_OBJECT)
 
67
 
 
68
static gchar *
 
69
get_unique_path (const gchar *path,
 
70
                 const gchar *filename)
 
71
{
 
72
  gchar *ptr;
 
73
  gchar *real_filename;
 
74
  gchar *real_path;
 
75
  gint idx;
 
76
 
 
77
  ptr = g_strrstr (filename, ".png");
 
78
 
 
79
  if (ptr != NULL)
 
80
    real_filename = g_strndup (filename, ptr - filename);
 
81
  else
 
82
    real_filename = g_strdup (filename);
 
83
 
 
84
  real_path = NULL;
 
85
  idx = 0;
 
86
 
 
87
  do
 
88
    {
 
89
      gchar *name;
 
90
 
 
91
      if (idx == 0)
 
92
        name = g_strdup_printf ("%s.png", real_filename);
 
93
      else
 
94
        name = g_strdup_printf ("%s - %d.png", real_filename, idx);
 
95
 
 
96
      g_free (real_path);
 
97
      real_path = g_build_filename (path, name, NULL);
 
98
      g_free (name);
 
99
 
 
100
      idx++;
 
101
    }
 
102
  while (g_file_test (real_path, G_FILE_TEST_EXISTS));
 
103
 
 
104
  g_free (real_filename);
 
105
 
 
106
  return real_path;
 
107
}
 
108
 
 
109
static gchar *
 
110
get_filename (const gchar *filename)
 
111
{
 
112
  const gchar *path;
 
113
 
 
114
  if (g_path_is_absolute (filename))
 
115
    return g_strdup (filename);
 
116
 
 
117
  path = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
 
118
 
 
119
  if (!g_file_test (path, G_FILE_TEST_EXISTS))
 
120
    {
 
121
      path = g_get_home_dir ();
 
122
 
 
123
      if (!g_file_test (path, G_FILE_TEST_EXISTS))
 
124
        return NULL;
 
125
    }
 
126
 
 
127
  return get_unique_path (path, filename);
 
128
}
 
129
 
 
130
static gboolean
 
131
save_screenshot (GdkPixbuf    *pixbuf,
 
132
                 const gchar  *filename_in,
 
133
                 gchar       **filename_out)
 
134
{
 
135
  gboolean result;
 
136
  gchar *filename;
 
137
  GError *error;
 
138
 
 
139
  if (pixbuf == NULL)
 
140
    return FALSE;
 
141
 
 
142
  filename = get_filename (filename_in);
 
143
 
 
144
  error = NULL;
 
145
  result = gdk_pixbuf_save (pixbuf, filename, "png", &error, NULL);
 
146
 
 
147
  if (result)
 
148
    *filename_out = filename;
 
149
  else
 
150
    g_free (filename);
 
151
 
 
152
  if (error != NULL)
 
153
    {
 
154
      g_warning ("Failed to save screenshot: %s", error->message);
 
155
      g_error_free (error);
 
156
    }
 
157
 
 
158
  g_object_unref (pixbuf);
 
159
 
 
160
  return result;
 
161
}
 
162
 
 
163
static void
 
164
blank_rectangle_in_pixbuf (GdkPixbuf *pixbuf,
 
165
                           GdkRectangle *rect)
 
166
{
 
167
  gint x;
 
168
  gint y;
 
169
  gint x2;
 
170
  gint y2;
 
171
  guchar *pixels;
 
172
  gint rowstride;
 
173
  gint n_channels;
 
174
  guchar *row;
 
175
  gboolean has_alpha;
 
176
 
 
177
  g_assert (gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB);
 
178
 
 
179
  x2 = rect->x + rect->width;
 
180
  y2 = rect->y + rect->height;
 
181
 
 
182
  pixels = gdk_pixbuf_get_pixels (pixbuf);
 
183
  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
 
184
  has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
 
185
  n_channels = gdk_pixbuf_get_n_channels (pixbuf);
 
186
 
 
187
  for (y = rect->y; y < y2; y++)
 
188
    {
 
189
      guchar *p;
 
190
 
 
191
      row = pixels + y * rowstride;
 
192
      p = row + rect->x * n_channels;
 
193
 
 
194
      for (x = rect->x; x < x2; x++)
 
195
        {
 
196
          *p++ = 0;
 
197
          *p++ = 0;
 
198
          *p++ = 0;
 
199
 
 
200
          if (has_alpha)
 
201
            *p++ = 255;
 
202
        }
 
203
    }
 
204
}
 
205
 
 
206
static void
 
207
blank_region_in_pixbuf (GdkPixbuf      *pixbuf,
 
208
                        cairo_region_t *region)
 
209
{
 
210
  gint n_rects;
 
211
  gint i;
 
212
  gint width;
 
213
  gint height;
 
214
  cairo_rectangle_int_t pixbuf_rect;
 
215
 
 
216
  n_rects = cairo_region_num_rectangles (region);
 
217
 
 
218
  width = gdk_pixbuf_get_width (pixbuf);
 
219
  height = gdk_pixbuf_get_height (pixbuf);
 
220
 
 
221
  pixbuf_rect.x = 0;
 
222
  pixbuf_rect.y = 0;
 
223
  pixbuf_rect.width = width;
 
224
  pixbuf_rect.height = height;
 
225
 
 
226
  for (i = 0; i < n_rects; i++)
 
227
    {
 
228
      cairo_rectangle_int_t rect;
 
229
      cairo_rectangle_int_t dest;
 
230
 
 
231
      cairo_region_get_rectangle (region, i, &rect);
 
232
 
 
233
      if (gdk_rectangle_intersect (&rect, &pixbuf_rect, &dest))
 
234
        blank_rectangle_in_pixbuf (pixbuf, &dest);
 
235
    }
 
236
}
 
237
 
 
238
static cairo_region_t *
 
239
make_region_with_monitors (GdkScreen *screen)
 
240
{
 
241
  cairo_region_t *region;
 
242
  gint num_monitors;
 
243
  gint i;
 
244
 
 
245
  num_monitors = gdk_screen_get_n_monitors (screen);
 
246
  region = cairo_region_create ();
 
247
 
 
248
  for (i = 0; i < num_monitors; i++)
 
249
    {
 
250
      GdkRectangle rect;
 
251
 
 
252
      gdk_screen_get_monitor_geometry (screen, i, &rect);
 
253
      cairo_region_union_rectangle (region, &rect);
 
254
    }
 
255
 
 
256
  return region;
 
257
}
 
258
 
 
259
static void
 
260
mask_monitors (GdkPixbuf *pixbuf,
 
261
               GdkWindow *root_window)
 
262
{
 
263
  GdkScreen *screen;
 
264
  cairo_region_t *region_with_monitors;
 
265
  cairo_region_t *invisible_region;
 
266
  cairo_rectangle_int_t rect;
 
267
 
 
268
  screen = gdk_window_get_screen (root_window);
 
269
  region_with_monitors = make_region_with_monitors (screen);
 
270
 
 
271
  rect.x = 0;
 
272
  rect.y = 0;
 
273
  rect.width = gdk_screen_get_width (screen);
 
274
  rect.height = gdk_screen_get_height (screen);
 
275
 
 
276
  invisible_region = cairo_region_create_rectangle (&rect);
 
277
  cairo_region_subtract (invisible_region, region_with_monitors);
 
278
 
 
279
  blank_region_in_pixbuf (pixbuf, invisible_region);
 
280
 
 
281
  cairo_region_destroy (region_with_monitors);
 
282
  cairo_region_destroy (invisible_region);
 
283
}
 
284
 
 
285
static Window
 
286
find_wm_window (GdkDisplay *display,
 
287
                GdkWindow  *window)
 
288
{
 
289
  Display *xdisplay;
 
290
  Window xid;
 
291
  Window root;
 
292
  Window parent;
 
293
  Window *children;
 
294
  unsigned int nchildren;
 
295
 
 
296
  if (window == gdk_get_default_root_window ())
 
297
    return None;
 
298
 
 
299
  xdisplay = GDK_DISPLAY_XDISPLAY (display);
 
300
  xid = GDK_WINDOW_XID (window);
 
301
 
 
302
  while (TRUE)
 
303
    {
 
304
      if (XQueryTree (xdisplay, xid, &root, &parent, &children, &nchildren) == 0)
 
305
        {
 
306
          g_warning ("Couldn't find window manager window");
 
307
          return None;
 
308
        }
 
309
 
 
310
      if (root == parent)
 
311
        {
 
312
          if (children != NULL)
 
313
            XFree (children);
 
314
 
 
315
          return xid;
 
316
        }
 
317
 
 
318
      xid = parent;
 
319
 
 
320
      if (children != NULL)
 
321
        XFree (children);
 
322
    }
 
323
}
 
324
 
 
325
static void
 
326
get_window_rect_coords (GdkWindow    *window,
 
327
                        gboolean      include_frame,
 
328
                        GdkRectangle *real_out,
 
329
                        GdkRectangle *screenshot_out)
 
330
{
 
331
  GdkRectangle real;
 
332
  gint x;
 
333
  gint y;
 
334
  gint width;
 
335
  gint height;
 
336
  gint screen_width;
 
337
  gint screen_height;
 
338
 
 
339
  if (include_frame)
 
340
    {
 
341
      gdk_window_get_frame_extents (window, &real);
 
342
    }
 
343
  else
 
344
    {
 
345
      real.width = gdk_window_get_width (window);
 
346
      real.height = gdk_window_get_height (window);
 
347
 
 
348
      gdk_window_get_origin (window, &real.x, &real.y);
 
349
    }
 
350
 
 
351
  if (real_out != NULL)
 
352
    *real_out = real;
 
353
 
 
354
  x = real.x;
 
355
  y = real.y;
 
356
  width = real.width;
 
357
  height = real.height;
 
358
 
 
359
  if (x < 0)
 
360
    {
 
361
      width = width + x;
 
362
      x = 0;
 
363
    }
 
364
 
 
365
  if (y < 0)
 
366
    {
 
367
      height = height + y;
 
368
      y = 0;
 
369
    }
 
370
 
 
371
  screen_width = gdk_screen_width ();
 
372
  if (x + width > screen_width)
 
373
    width = screen_width - x;
 
374
 
 
375
  screen_height = gdk_screen_height ();
 
376
  if (y + height > screen_height)
 
377
    height = screen_height - y;
 
378
 
 
379
  if (screenshot_out != NULL)
 
380
    {
 
381
      screenshot_out->x = x;
 
382
      screenshot_out->y = y;
 
383
      screenshot_out->width = width;
 
384
      screenshot_out->height = height;
 
385
    }
 
386
}
 
387
 
 
388
static gboolean
 
389
window_is_desktop (GdkWindow *window)
 
390
{
 
391
  GdkWindow *root_window;
 
392
  GdkWindowTypeHint type_hint;
 
393
 
 
394
  root_window = gdk_get_default_root_window ();
 
395
 
 
396
  if (window == root_window)
 
397
    return TRUE;
 
398
 
 
399
  type_hint = gdk_window_get_type_hint (window);
 
400
 
 
401
  if (type_hint == GDK_WINDOW_TYPE_HINT_DESKTOP)
 
402
    return TRUE;
 
403
 
 
404
  return FALSE;
 
405
}
 
406
 
 
407
static GdkWindow *
 
408
find_active_window (void)
 
409
{
 
410
  GdkScreen *screen;
 
411
 
 
412
  screen = gdk_screen_get_default ();
 
413
 
 
414
  return gdk_screen_get_active_window (screen);
 
415
}
 
416
 
 
417
static GdkWindow *
 
418
find_current_window (GdkDisplay *display)
 
419
{
 
420
  GdkWindow *window;
 
421
  GdkWindow *toplevel;
 
422
 
 
423
  window = find_active_window ();
 
424
 
 
425
  if (window == NULL)
 
426
    {
 
427
      GdkDeviceManager *manager;
 
428
      GdkDevice *device;
 
429
 
 
430
      manager = gdk_display_get_device_manager (display);
 
431
      device = gdk_device_manager_get_client_pointer (manager);
 
432
 
 
433
      window = gdk_device_get_window_at_position (device, NULL, NULL);
 
434
 
 
435
      if (window)
 
436
        g_object_ref (window);
 
437
    }
 
438
 
 
439
  if (window)
 
440
    {
 
441
      if (window_is_desktop (window))
 
442
        {
 
443
          g_object_unref (window);
 
444
          return NULL;
 
445
        }
 
446
 
 
447
      toplevel = gdk_window_get_toplevel (window);
 
448
 
 
449
      g_object_unref (window);
 
450
      return toplevel;
 
451
    }
 
452
 
 
453
  return NULL;
 
454
}
 
455
 
 
456
static GdkWindow *
 
457
get_current_window (GdkDisplay     *display,
 
458
                    ScreenshotType  type)
 
459
{
 
460
  if (type == SCREENSHOT_WINDOW)
 
461
    return find_current_window (display);
 
462
 
 
463
  return gdk_get_default_root_window ();
 
464
}
 
465
 
 
466
static gboolean
 
467
take_screenshot_real (GfScreenshot    *screenshot,
 
468
                      ScreenshotType   type,
 
469
                      gboolean         include_frame,
 
470
                      gboolean         include_cursor,
 
471
                      gint            *x,
 
472
                      gint            *y,
 
473
                      gint            *width,
 
474
                      gint            *height,
 
475
                      const gchar     *filename_in,
 
476
                      gchar          **filename_out)
 
477
{
 
478
  GdkDisplay *display;
 
479
  GdkWindow *window;
 
480
  GdkRectangle real;
 
481
  GdkRectangle s;
 
482
  Window wm;
 
483
  GdkWindow *wm_window;
 
484
  GtkBorder frame_offset;
 
485
  GdkWindow *root;
 
486
  GdkPixbuf *pixbuf;
 
487
 
 
488
  display = gdk_display_get_default ();
 
489
  window = get_current_window (display, type);
 
490
 
 
491
  if (window == NULL)
 
492
    return FALSE;
 
493
 
 
494
  get_window_rect_coords (window, include_frame, &real, &s);
 
495
 
 
496
  wm = find_wm_window (display, window);
 
497
 
 
498
  if (wm != None)
 
499
    {
 
500
      GdkRectangle wm_real;
 
501
 
 
502
      wm_window = gdk_x11_window_foreign_new_for_display (display, wm);
 
503
      get_window_rect_coords (wm_window, FALSE, &wm_real, NULL);
 
504
 
 
505
      frame_offset.left = (gdouble) (real.x - wm_real.x);
 
506
      frame_offset.top = (gdouble) (real.y - wm_real.y);
 
507
      frame_offset.right = (gdouble) (wm_real.width - real.width - frame_offset.left);
 
508
      frame_offset.bottom = (gdouble) (wm_real.height - real.height - frame_offset.top);
 
509
    }
 
510
  else
 
511
    {
 
512
      frame_offset.left = 0;
 
513
      frame_offset.top = 0;
 
514
      frame_offset.right = 0;
 
515
      frame_offset.bottom = 0;
 
516
    }
 
517
 
 
518
  if (type != SCREENSHOT_WINDOW)
 
519
    {
 
520
      s.x = *x - s.x;
 
521
      s.y = *y - s.y;
 
522
      s.width  = *width;
 
523
      s.height = *height;
 
524
    }
 
525
 
 
526
  root = gdk_get_default_root_window ();
 
527
  pixbuf = gdk_pixbuf_get_from_window (root, s.x, s.y, s.width, s.height);
 
528
 
 
529
  if (type != SCREENSHOT_WINDOW && type != SCREENSHOT_AREA)
 
530
    mask_monitors (pixbuf, root);
 
531
 
 
532
  if (include_frame && wm != None)
 
533
    {
 
534
      XRectangle *rectangles;
 
535
      GdkPixbuf *tmp;
 
536
      gint rectangle_count;
 
537
      gint rectangle_order;
 
538
      gint i;
 
539
 
 
540
      rectangles = XShapeGetRectangles (GDK_DISPLAY_XDISPLAY (display),
 
541
                                        wm, ShapeBounding,
 
542
                                        &rectangle_count, &rectangle_order);
 
543
 
 
544
      if (rectangles && rectangle_count > 0)
 
545
        {
 
546
          gboolean has_alpha;
 
547
 
 
548
          has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
 
549
 
 
550
          tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, s.width, s.height);
 
551
          gdk_pixbuf_fill (tmp, 0);
 
552
 
 
553
          for (i = 0; i < rectangle_count; i++)
 
554
            {
 
555
              gint rec_x;
 
556
              gint rec_y;
 
557
              gint rec_width;
 
558
              gint rec_height;
 
559
              gint y2;
 
560
 
 
561
              /* If we're using invisible borders, the ShapeBounding might not
 
562
               * have the same size as the frame extents, as it would include
 
563
               * the areas for the invisible borders themselves.
 
564
               * In that case, trim every rectangle we get by the offset between
 
565
               * the WM window size and the frame extents. */
 
566
              rec_x = rectangles[i].x;
 
567
              rec_y = rectangles[i].y;
 
568
              rec_width = rectangles[i].width - (frame_offset.left + frame_offset.right);
 
569
              rec_height = rectangles[i].height - (frame_offset.top + frame_offset.bottom);
 
570
 
 
571
              if (real.x < 0)
 
572
                {
 
573
                  rec_x += real.x;
 
574
                  rec_x = MAX(rec_x, 0);
 
575
                  rec_width += real.x;
 
576
                }
 
577
 
 
578
              if (real.y < 0)
 
579
                {
 
580
                  rec_y += real.y;
 
581
                  rec_y = MAX(rec_y, 0);
 
582
                  rec_height += real.y;
 
583
                }
 
584
 
 
585
              if (s.x + rec_x + rec_width > gdk_screen_width ())
 
586
                rec_width = gdk_screen_width () - s.x - rec_x;
 
587
 
 
588
              if (s.y + rec_y + rec_height > gdk_screen_height ())
 
589
                rec_height = gdk_screen_height () - s.y - rec_y;
 
590
 
 
591
              for (y2 = rec_y; y2 < rec_y + rec_height; y2++)
 
592
                {
 
593
                  guchar *src_pixels;
 
594
                  guchar *dest_pixels;
 
595
                  gint x2;
 
596
 
 
597
                  src_pixels = gdk_pixbuf_get_pixels (pixbuf)
 
598
                             + y2 * gdk_pixbuf_get_rowstride(pixbuf)
 
599
                             + rec_x * (has_alpha ? 4 : 3);
 
600
                  dest_pixels = gdk_pixbuf_get_pixels (tmp)
 
601
                              + y2 * gdk_pixbuf_get_rowstride (tmp)
 
602
                              + rec_x * 4;
 
603
 
 
604
                  for (x2 = 0; x2 < rec_width; x2++)
 
605
                    {
 
606
                      *dest_pixels++ = *src_pixels++;
 
607
                      *dest_pixels++ = *src_pixels++;
 
608
                      *dest_pixels++ = *src_pixels++;
 
609
 
 
610
                      if (has_alpha)
 
611
                        *dest_pixels++ = *src_pixels++;
 
612
                      else
 
613
                        *dest_pixels++ = 255;
 
614
                    }
 
615
                }
 
616
            }
 
617
 
 
618
          g_object_unref (pixbuf);
 
619
          pixbuf = tmp;
 
620
 
 
621
          XFree (rectangles);
 
622
        }
 
623
    }
 
624
 
 
625
  /* If we have a selected area, there were by definition no cursor in the
 
626
   * screenshot. */
 
627
  if (include_cursor && type == SCREENSHOT_AREA)
 
628
    {
 
629
      GdkCursor *cursor;
 
630
      GdkPixbuf *cursor_pixbuf;
 
631
 
 
632
      cursor = gdk_cursor_new_for_display (display, GDK_LEFT_PTR);
 
633
      cursor_pixbuf = gdk_cursor_get_image (cursor);
 
634
 
 
635
      if (cursor_pixbuf != NULL)
 
636
        {
 
637
          GdkDeviceManager *manager;
 
638
          GdkDevice *device;
 
639
          GdkRectangle rect;
 
640
          gint cx;
 
641
          gint cy;
 
642
          gint xhot;
 
643
          gint yhot;
 
644
 
 
645
          manager = gdk_display_get_device_manager (display);
 
646
          device = gdk_device_manager_get_client_pointer (manager);
 
647
 
 
648
          if (wm_window != NULL)
 
649
            gdk_window_get_device_position (wm_window, device, &cx, &cy, NULL);
 
650
          else
 
651
            gdk_window_get_device_position (window, device, &cx, &cy, NULL);
 
652
 
 
653
          sscanf (gdk_pixbuf_get_option (cursor_pixbuf, "x_hot"), "%d", &xhot);
 
654
          sscanf (gdk_pixbuf_get_option (cursor_pixbuf, "y_hot"), "%d", &yhot);
 
655
 
 
656
          /* in rect we have the cursor window coordinates */
 
657
          rect.x = cx + real.x;
 
658
          rect.y = cy + real.y;
 
659
          rect.width = gdk_pixbuf_get_width (cursor_pixbuf);
 
660
          rect.height = gdk_pixbuf_get_height (cursor_pixbuf);
 
661
 
 
662
          /* see if the pointer is inside the window */
 
663
          if (gdk_rectangle_intersect (&real, &rect, &rect))
 
664
            {
 
665
              gint cursor_x;
 
666
              gint cursor_y;
 
667
 
 
668
              cursor_x = cx - xhot - frame_offset.left;
 
669
              cursor_y = cy - yhot - frame_offset.top;
 
670
 
 
671
              gdk_pixbuf_composite (cursor_pixbuf, pixbuf,
 
672
                                    cursor_x, cursor_y,
 
673
                                    rect.width, rect.height,
 
674
                                    cursor_x, cursor_y,
 
675
                                    1.0, 1.0,
 
676
                                    GDK_INTERP_BILINEAR,
 
677
                                    255);
 
678
            }
 
679
        }
 
680
 
 
681
      g_clear_object (&cursor_pixbuf);
 
682
      g_clear_object (&cursor);
 
683
    }
 
684
 
 
685
  if (type == SCREENSHOT_WINDOW)
 
686
    {
 
687
      GdkRectangle rect;
 
688
 
 
689
      get_window_rect_coords (window, include_frame, NULL, &rect);
 
690
 
 
691
      *x = rect.x;
 
692
      *y = rect.y;
 
693
      *width = rect.width;
 
694
      *height = rect.height;
 
695
    }
 
696
 
 
697
  return save_screenshot (pixbuf, filename_in, filename_out);
 
698
}
 
699
 
 
700
static void
 
701
remove_sender (GfScreenshot *screenshot,
 
702
               const gchar  *sender)
 
703
{
 
704
  gpointer name_id;
 
705
 
 
706
  name_id = g_hash_table_lookup (screenshot->senders, sender);
 
707
 
 
708
  if (name_id == NULL)
 
709
    return;
 
710
 
 
711
  g_bus_unwatch_name (GPOINTER_TO_UINT (name_id));
 
712
  g_hash_table_remove (screenshot->senders, sender);
 
713
}
 
714
 
 
715
static FlashspotData *
 
716
flashspot_data_new (GfScreenshot *screenshot,
 
717
                    const gchar  *sender)
 
718
{
 
719
  FlashspotData *data;
 
720
 
 
721
  data = (FlashspotData *) g_new0 (FlashspotData *, 1);
 
722
 
 
723
  data->screenshot = g_object_ref (screenshot);
 
724
  data->sender = g_strdup (sender);
 
725
 
 
726
  return data;
 
727
}
 
728
 
 
729
static void
 
730
flashspot_data_free (gpointer data)
 
731
{
 
732
  FlashspotData *real_data;
 
733
 
 
734
  real_data = (FlashspotData *) data;
 
735
 
 
736
  g_object_unref (real_data->screenshot);
 
737
  g_free (real_data->sender);
 
738
 
 
739
  g_free (real_data);
 
740
}
 
741
 
 
742
static void
 
743
flashspot_finished (GfFlashspot *flashspot,
 
744
                    gpointer     user_data)
 
745
{
 
746
  FlashspotData *data;
 
747
 
 
748
  data = (FlashspotData *) g_object_get_data (G_OBJECT (flashspot), "data");
 
749
 
 
750
  remove_sender (data->screenshot, data->sender);
 
751
}
 
752
 
 
753
static void
 
754
name_vanished_handler (GDBusConnection *connection,
 
755
                       const gchar     *name,
 
756
                       gpointer         user_data)
 
757
{
 
758
  GfScreenshot *screenshot;
 
759
 
 
760
  screenshot = GF_SCREENSHOT (user_data);
 
761
 
 
762
  remove_sender (screenshot, name);
 
763
}
 
764
 
 
765
static void
 
766
take_screenshot (GfScreenshot          *screenshot,
 
767
                 GDBusMethodInvocation *invocation,
 
768
                 ScreenshotType         type,
 
769
                 gboolean               include_frame,
 
770
                 gboolean               include_cursor,
 
771
                 gint                   x,
 
772
                 gint                   y,
 
773
                 gint                   width,
 
774
                 gint                   height,
 
775
                 GfInvocationCallback   callback,
 
776
                 gboolean               flash,
 
777
                 const gchar           *filename_in)
 
778
{
 
779
  const gchar *sender;
 
780
  gboolean disabled;
 
781
  guint name_id;
 
782
  gboolean result;
 
783
  gchar *filename_out;
 
784
 
 
785
  sender = g_dbus_method_invocation_get_sender (invocation);
 
786
  disabled = g_settings_get_boolean (screenshot->lockdown, "disable-save-to-disk");
 
787
 
 
788
  if (g_hash_table_lookup (screenshot->senders, sender) != NULL || disabled)
 
789
    {
 
790
      callback (screenshot->dbus_screenshot, invocation, FALSE, "");
 
791
      return;
 
792
    }
 
793
 
 
794
  name_id = g_bus_watch_name (G_BUS_TYPE_SESSION, sender,
 
795
                              G_BUS_NAME_WATCHER_FLAGS_NONE,
 
796
                              NULL, name_vanished_handler,
 
797
                              screenshot, NULL);
 
798
 
 
799
  g_hash_table_insert (screenshot->senders, g_strdup (sender),
 
800
                       GUINT_TO_POINTER (name_id));
 
801
 
 
802
  filename_out = NULL;
 
803
  result = take_screenshot_real (screenshot, type,
 
804
                                 include_frame, include_cursor,
 
805
                                 &x, &y, &width, &height,
 
806
                                 filename_in, &filename_out);
 
807
 
 
808
  if (result && flash)
 
809
    {
 
810
      GfFlashspot *flashspot;
 
811
      FlashspotData *data;
 
812
 
 
813
      flashspot = gf_flashspot_new ();
 
814
      data = flashspot_data_new (screenshot, sender);
 
815
 
 
816
      g_object_set_data_full (G_OBJECT (flashspot), "data", data,
 
817
                              flashspot_data_free);
 
818
 
 
819
      g_signal_connect (flashspot, "finished",
 
820
                        G_CALLBACK (flashspot_finished), NULL);
 
821
 
 
822
      gf_flashspot_fire (flashspot, x, y, width, height);
 
823
      g_object_unref (flashspot);
 
824
    }
 
825
  else
 
826
    {
 
827
      remove_sender (screenshot, sender);
 
828
    }
 
829
 
 
830
  callback (screenshot->dbus_screenshot, invocation,
 
831
            result, filename_out ? filename_out : "");
 
832
 
 
833
  g_free (filename_out);
 
834
}
 
835
 
 
836
static void
 
837
scale_area (gint *x,
 
838
            gint *y,
 
839
            gint *width,
 
840
            gint *height)
 
841
{
 
842
}
 
843
 
 
844
static void
 
845
unscale_area (gint *x,
 
846
              gint *y,
 
847
              gint *width,
 
848
              gint *height)
 
849
{
 
850
}
 
851
 
 
852
static gboolean
 
853
check_area (gint x,
 
854
            gint y,
 
855
            gint width,
 
856
            gint height)
 
857
{
 
858
  GdkScreen *screen;
 
859
  gint screen_width;
 
860
  gint screen_height;
 
861
 
 
862
  screen = gdk_screen_get_default ();
 
863
  screen_width = gdk_screen_get_width (screen);
 
864
  screen_height = gdk_screen_get_height (screen);
 
865
 
 
866
  return x >= 0 && y >= 0 && width > 0 && height > 0 &&
 
867
         x + width <= screen_width && y + height <= screen_height;
 
868
}
 
869
 
 
870
static gboolean
 
871
handle_screenshot (GfDBusScreenshot      *dbus_screenshot,
 
872
                   GDBusMethodInvocation *invocation,
 
873
                   gboolean               include_cursor,
 
874
                   gboolean               flash,
 
875
                   const gchar           *filename,
 
876
                   gpointer               user_data)
 
877
{
 
878
  GfScreenshot *screenshot;
 
879
  GdkScreen *screen;
 
880
  gint width;
 
881
  gint height;
 
882
 
 
883
  screenshot = GF_SCREENSHOT (user_data);
 
884
  screen = gdk_screen_get_default ();
 
885
  width = gdk_screen_get_width (screen);
 
886
  height = gdk_screen_get_height (screen);
 
887
 
 
888
  take_screenshot (screenshot, invocation, SCREENSHOT_SCREEN,
 
889
                   FALSE, include_cursor, 0, 0, width, height,
 
890
                   gf_dbus_screenshot_complete_screenshot,
 
891
                   flash, filename);
 
892
 
 
893
  return TRUE;
 
894
}
 
895
 
 
896
static gboolean
 
897
handle_screenshot_window (GfDBusScreenshot      *dbus_screenshot,
 
898
                          GDBusMethodInvocation *invocation,
 
899
                          gboolean               include_frame,
 
900
                          gboolean               include_cursor,
 
901
                          gboolean               flash,
 
902
                          const gchar           *filename,
 
903
                          gpointer               user_data)
 
904
{
 
905
  GfScreenshot *screenshot;
 
906
 
 
907
  screenshot = GF_SCREENSHOT (user_data);
 
908
 
 
909
  take_screenshot (screenshot, invocation, SCREENSHOT_WINDOW,
 
910
                   include_frame, include_cursor, 0, 0, 0, 0,
 
911
                   gf_dbus_screenshot_complete_screenshot_window,
 
912
                   flash, filename);
 
913
 
 
914
  return TRUE;
 
915
}
 
916
 
 
917
static gboolean
 
918
handle_screenshot_area (GfDBusScreenshot      *dbus_screenshot,
 
919
                        GDBusMethodInvocation *invocation,
 
920
                        gint                   x,
 
921
                        gint                   y,
 
922
                        gint                   width,
 
923
                        gint                   height,
 
924
                        gboolean               flash,
 
925
                        const gchar           *filename,
 
926
                        gpointer               user_data)
 
927
{
 
928
  GfScreenshot *screenshot;
 
929
 
 
930
  screenshot = GF_SCREENSHOT (user_data);
 
931
 
 
932
  if (!check_area (x, y, width, height))
 
933
    {
 
934
      g_dbus_method_invocation_return_error (invocation, G_IO_ERROR,
 
935
                                             G_IO_ERROR_CANCELLED,
 
936
                                             "Invalid params");
 
937
 
 
938
      return TRUE;
 
939
    }
 
940
 
 
941
  scale_area (&x, &y, &width, &height);
 
942
  take_screenshot (screenshot, invocation, SCREENSHOT_AREA,
 
943
                   FALSE, FALSE, x, y, width, height,
 
944
                   gf_dbus_screenshot_complete_screenshot_area,
 
945
                   flash, filename);
 
946
 
 
947
  return TRUE;
 
948
}
 
949
 
 
950
static gboolean
 
951
handle_flash_area (GfDBusScreenshot      *dbus_screenshot,
 
952
                   GDBusMethodInvocation *invocation,
 
953
                   gint                   x,
 
954
                   gint                   y,
 
955
                   gint                   width,
 
956
                   gint                   height,
 
957
                   gpointer               user_data)
 
958
{
 
959
  GfFlashspot *flashspot;
 
960
 
 
961
  if (!check_area (x, y, width, height))
 
962
    {
 
963
      g_dbus_method_invocation_return_error (invocation, G_IO_ERROR,
 
964
                                             G_IO_ERROR_CANCELLED,
 
965
                                             "Invalid params");
 
966
 
 
967
      return TRUE;
 
968
    }
 
969
 
 
970
  scale_area (&x, &y, &width, &height);
 
971
 
 
972
  flashspot = gf_flashspot_new ();
 
973
  gf_flashspot_fire (flashspot, x, y, width, height);
 
974
  g_object_unref (flashspot);
 
975
 
 
976
  gf_dbus_screenshot_complete_flash_area (dbus_screenshot, invocation);
 
977
 
 
978
  return TRUE;
 
979
}
 
980
 
 
981
static gboolean
 
982
handle_select_area (GfDBusScreenshot      *dbus_screenshot,
 
983
                    GDBusMethodInvocation *invocation,
 
984
                    gpointer               user_data)
 
985
{
 
986
  GfSelectArea *select_area;
 
987
  gint x;
 
988
  gint y;
 
989
  gint width;
 
990
  gint height;
 
991
 
 
992
  select_area = gf_select_area_new ();
 
993
  x = y = width = height = 0;
 
994
 
 
995
  if (gf_select_area_select (select_area, &x, &y, &width, &height))
 
996
    {
 
997
      unscale_area (&x, &y, &width, &height);
 
998
      gf_dbus_screenshot_complete_select_area (dbus_screenshot, invocation,
 
999
                                               x, y, width, height);
 
1000
    }
 
1001
  else
 
1002
    {
 
1003
      g_dbus_method_invocation_return_error (invocation, G_IO_ERROR,
 
1004
                                             G_IO_ERROR_CANCELLED,
 
1005
                                             "Operation was cancelled");
 
1006
    }
 
1007
 
 
1008
  g_object_unref (select_area);
 
1009
 
 
1010
  return TRUE;
 
1011
}
 
1012
 
 
1013
static void
 
1014
bus_acquired_handler (GDBusConnection *connection,
 
1015
                      const gchar     *name,
 
1016
                      gpointer         user_data)
 
1017
{
 
1018
  GfScreenshot *screenshot;
 
1019
  GfDBusScreenshot *dbus_screenshot;
 
1020
  GDBusInterfaceSkeleton *skeleton;
 
1021
  GError *error;
 
1022
  gboolean exported;
 
1023
 
 
1024
  screenshot = GF_SCREENSHOT (user_data);
 
1025
 
 
1026
  dbus_screenshot = screenshot->dbus_screenshot;
 
1027
  skeleton = G_DBUS_INTERFACE_SKELETON (dbus_screenshot);
 
1028
 
 
1029
  g_signal_connect (dbus_screenshot, "handle-screenshot",
 
1030
                    G_CALLBACK (handle_screenshot), screenshot);
 
1031
  g_signal_connect (dbus_screenshot, "handle-screenshot-window",
 
1032
                    G_CALLBACK (handle_screenshot_window), screenshot);
 
1033
  g_signal_connect (dbus_screenshot, "handle-screenshot-area",
 
1034
                    G_CALLBACK (handle_screenshot_area), screenshot);
 
1035
  g_signal_connect (dbus_screenshot, "handle-flash-area",
 
1036
                    G_CALLBACK (handle_flash_area), screenshot);
 
1037
  g_signal_connect (dbus_screenshot, "handle-select-area",
 
1038
                    G_CALLBACK (handle_select_area), screenshot);
 
1039
 
 
1040
  error = NULL;
 
1041
  exported = g_dbus_interface_skeleton_export (skeleton, connection,
 
1042
                                               SCREENSHOT_DBUS_PATH,
 
1043
                                               &error);
 
1044
 
 
1045
  if (!exported)
 
1046
    {
 
1047
      g_warning ("Failed to export interface: %s", error->message);
 
1048
      g_error_free (error);
 
1049
      return;
 
1050
    }
 
1051
}
 
1052
 
 
1053
static void
 
1054
gf_screenshot_dispose (GObject *object)
 
1055
{
 
1056
  GfScreenshot *screenshot;
 
1057
  GDBusInterfaceSkeleton *skeleton;
 
1058
 
 
1059
  screenshot = GF_SCREENSHOT (object);
 
1060
 
 
1061
  if (screenshot->bus_name)
 
1062
    {
 
1063
      g_bus_unown_name (screenshot->bus_name);
 
1064
      screenshot->bus_name = 0;
 
1065
    }
 
1066
 
 
1067
  if (screenshot->dbus_screenshot)
 
1068
    {
 
1069
      skeleton = G_DBUS_INTERFACE_SKELETON (screenshot->dbus_screenshot);
 
1070
 
 
1071
      g_dbus_interface_skeleton_unexport (skeleton);
 
1072
      g_clear_object (&screenshot->dbus_screenshot);
 
1073
    }
 
1074
 
 
1075
  if (screenshot->senders)
 
1076
    {
 
1077
      g_hash_table_destroy (screenshot->senders);
 
1078
      screenshot->senders = NULL;
 
1079
    }
 
1080
 
 
1081
  g_clear_object (&screenshot->lockdown);
 
1082
 
 
1083
  G_OBJECT_CLASS (gf_screenshot_parent_class)->dispose (object);
 
1084
}
 
1085
 
 
1086
static void
 
1087
gf_screenshot_class_init (GfScreenshotClass *screenshot_class)
 
1088
{
 
1089
  GObjectClass *object_class;
 
1090
 
 
1091
  object_class = G_OBJECT_CLASS (screenshot_class);
 
1092
 
 
1093
  object_class->dispose = gf_screenshot_dispose;
 
1094
}
 
1095
 
 
1096
static void
 
1097
gf_screenshot_init (GfScreenshot *screenshot)
 
1098
{
 
1099
  screenshot->dbus_screenshot = gf_dbus_screenshot_skeleton_new ();
 
1100
 
 
1101
  screenshot->bus_name = g_bus_own_name (G_BUS_TYPE_SESSION,
 
1102
                                         SCREENSHOT_DBUS_NAME,
 
1103
                                         G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
 
1104
                                         G_BUS_NAME_OWNER_FLAGS_REPLACE,
 
1105
                                         (GBusAcquiredCallback) bus_acquired_handler,
 
1106
                                         NULL, NULL, screenshot, NULL);
 
1107
 
 
1108
  screenshot->senders = g_hash_table_new_full (g_str_hash, g_str_equal,
 
1109
                                               g_free, NULL);
 
1110
 
 
1111
  screenshot->lockdown = g_settings_new ("org.gnome.desktop.lockdown");
 
1112
}
 
1113
 
 
1114
GfScreenshot *
 
1115
gf_screenshot_new (void)
 
1116
{
 
1117
  return g_object_new (GF_TYPE_SCREENSHOT, NULL);
 
1118
}