Merge lp:~woodrow-shen/gnome-screenshot/fix-hidpi.trusty into lp:ubuntu/trusty/gnome-screenshot
- fix-hidpi.trusty
- Merge into trusty
Proposed by
Woodrow Shen
on 2015-02-04
| Status: | Merged |
|---|---|
| Merge reported by: | Iain Lane |
| Merged at revision: | not available |
| Proposed branch: | lp:~woodrow-shen/gnome-screenshot/fix-hidpi.trusty |
| Merge into: | lp:ubuntu/trusty/gnome-screenshot |
| Diff against target: |
916 lines (+830/-6) 6 files modified
.pc/applied-patches (+1/-0) .pc/ubuntu_fix_hidpi.patch/src/screenshot-utils.c (+732/-0) debian/changelog (+7/-0) debian/patches/series (+1/-0) debian/patches/ubuntu_fix_hidpi.patch (+75/-0) src/screenshot-utils.c (+14/-6) |
| To merge this branch: | bzr merge lp:~woodrow-shen/gnome-screenshot/fix-hidpi.trusty |
| Related bugs: |
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| Iain Lane | 2015-02-04 | Approve on 2015-06-08 | |
| Sebastien Bacher | 2015-02-04 | Needs Fixing on 2015-02-04 | |
|
Review via email:
|
|||
Commit Message
Description of the Change
To post a comment you must log in.
| Woodrow Shen (woodrow-shen) wrote : | # |
Hi Sebastien,
This work isn't from upstream, however I file a bug to bugzilla (see https:/
So do you mean that basically we always would merge the updates into our package from upstream ?
| Sebastien Bacher (seb128) wrote : | # |
It's better to have the change reviewed and commited upstream if we can, but it's not a blocker. Thanks for sending it to GNOME
lp:~woodrow-shen/gnome-screenshot/fix-hidpi.trusty
updated
on 2015-02-04
- 25. By Woodrow Shen on 2015-02-04
-
* debian/
patches/ ubuntu_ fix_hidpi:
- add the header for patch - 26. By Woodrow Shen on 2015-02-04
-
* debian/
patches/ ubuntu_ fix_hidpi:
- fix the header for patch
| Woodrow Shen (woodrow-shen) wrote : | # |
Got it, so let the upstream review this patch, thanks your help.
| Iain Lane (laney) wrote : | # |
Upstream seems to be mostly inactive, uploaded to Ubuntu now. Thanks!
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
| 1 | === modified file '.pc/applied-patches' |
| 2 | --- .pc/applied-patches 2013-12-19 11:25:38 +0000 |
| 3 | +++ .pc/applied-patches 2015-02-04 10:34:12 +0000 |
| 4 | @@ -3,3 +3,4 @@ |
| 5 | ubuntu_unity_no_gnomeshell.patch |
| 6 | update_unity_list.patch |
| 7 | uri.patch |
| 8 | +ubuntu_fix_hidpi.patch |
| 9 | |
| 10 | === added directory '.pc/ubuntu_fix_hidpi.patch' |
| 11 | === added directory '.pc/ubuntu_fix_hidpi.patch/src' |
| 12 | === added file '.pc/ubuntu_fix_hidpi.patch/src/screenshot-utils.c' |
| 13 | --- .pc/ubuntu_fix_hidpi.patch/src/screenshot-utils.c 1970-01-01 00:00:00 +0000 |
| 14 | +++ .pc/ubuntu_fix_hidpi.patch/src/screenshot-utils.c 2015-02-04 10:34:12 +0000 |
| 15 | @@ -0,0 +1,732 @@ |
| 16 | +/* screenshot-utils.c - common functions for GNOME Screenshot |
| 17 | + * |
| 18 | + * Copyright (C) 2001-2006 Jonathan Blandford <jrb@alum.mit.edu> |
| 19 | + * Copyright (C) 2008 Cosimo Cecchi <cosimoc@gnome.org> |
| 20 | + * |
| 21 | + * This program is free software; you can redistribute it and/or |
| 22 | + * modify it under the terms of the GNU General Public |
| 23 | + * License as published by the Free Software Foundation; either |
| 24 | + * version 2 of the License, or (at your option) any later version. |
| 25 | + * |
| 26 | + * This program is distributed in the hope that it will be useful, |
| 27 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 28 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 29 | + * General Public License for more details. |
| 30 | + * |
| 31 | + * You should have received a copy of the GNU General Public |
| 32 | + * License along with this program; if not, write to the |
| 33 | + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| 34 | + */ |
| 35 | + |
| 36 | +#include <config.h> |
| 37 | +#include <gdk/gdkkeysyms.h> |
| 38 | +#include <gtk/gtk.h> |
| 39 | +#include <glib.h> |
| 40 | +#include <glib/gi18n.h> |
| 41 | +#include <glib/gstdio.h> |
| 42 | +#include <canberra-gtk.h> |
| 43 | +#include <stdlib.h> |
| 44 | + |
| 45 | +#ifdef HAVE_X11_EXTENSIONS_SHAPE_H |
| 46 | +#include <X11/extensions/shape.h> |
| 47 | +#endif |
| 48 | + |
| 49 | +#include "cheese-flash.h" |
| 50 | +#include "screenshot-application.h" |
| 51 | +#include "screenshot-config.h" |
| 52 | +#include "screenshot-utils.h" |
| 53 | + |
| 54 | +static GdkWindow * |
| 55 | +screenshot_find_active_window (void) |
| 56 | +{ |
| 57 | + GdkWindow *window; |
| 58 | + GdkScreen *default_screen; |
| 59 | + |
| 60 | + default_screen = gdk_screen_get_default (); |
| 61 | + window = gdk_screen_get_active_window (default_screen); |
| 62 | + |
| 63 | + return window; |
| 64 | +} |
| 65 | + |
| 66 | +static gboolean |
| 67 | +screenshot_window_is_desktop (GdkWindow *window) |
| 68 | +{ |
| 69 | + GdkWindow *root_window = gdk_get_default_root_window (); |
| 70 | + GdkWindowTypeHint window_type_hint; |
| 71 | + |
| 72 | + if (window == root_window) |
| 73 | + return TRUE; |
| 74 | + |
| 75 | + window_type_hint = gdk_window_get_type_hint (window); |
| 76 | + if (window_type_hint == GDK_WINDOW_TYPE_HINT_DESKTOP) |
| 77 | + return TRUE; |
| 78 | + |
| 79 | + return FALSE; |
| 80 | + |
| 81 | +} |
| 82 | + |
| 83 | +static Window |
| 84 | +find_wm_window (GdkWindow *window) |
| 85 | +{ |
| 86 | + Window xid, root, parent, *children; |
| 87 | + unsigned int nchildren; |
| 88 | + |
| 89 | + if (window == gdk_get_default_root_window ()) |
| 90 | + return None; |
| 91 | + |
| 92 | + xid = GDK_WINDOW_XID (window); |
| 93 | + |
| 94 | + do |
| 95 | + { |
| 96 | + if (XQueryTree (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), |
| 97 | + xid, &root, &parent, &children, &nchildren) == 0) |
| 98 | + { |
| 99 | + g_warning ("Couldn't find window manager window"); |
| 100 | + return None; |
| 101 | + } |
| 102 | + |
| 103 | + if (root == parent) |
| 104 | + return xid; |
| 105 | + |
| 106 | + xid = parent; |
| 107 | + } |
| 108 | + while (TRUE); |
| 109 | +} |
| 110 | + |
| 111 | +static cairo_region_t * |
| 112 | +make_region_with_monitors (GdkScreen *screen) |
| 113 | +{ |
| 114 | + cairo_region_t *region; |
| 115 | + int num_monitors; |
| 116 | + int i; |
| 117 | + |
| 118 | + num_monitors = gdk_screen_get_n_monitors (screen); |
| 119 | + |
| 120 | + region = cairo_region_create (); |
| 121 | + |
| 122 | + for (i = 0; i < num_monitors; i++) |
| 123 | + { |
| 124 | + GdkRectangle rect; |
| 125 | + |
| 126 | + gdk_screen_get_monitor_geometry (screen, i, &rect); |
| 127 | + cairo_region_union_rectangle (region, &rect); |
| 128 | + } |
| 129 | + |
| 130 | + return region; |
| 131 | +} |
| 132 | + |
| 133 | +static void |
| 134 | +blank_rectangle_in_pixbuf (GdkPixbuf *pixbuf, GdkRectangle *rect) |
| 135 | +{ |
| 136 | + int x, y; |
| 137 | + int x2, y2; |
| 138 | + guchar *pixels; |
| 139 | + int rowstride; |
| 140 | + int n_channels; |
| 141 | + guchar *row; |
| 142 | + gboolean has_alpha; |
| 143 | + |
| 144 | + g_assert (gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB); |
| 145 | + |
| 146 | + x2 = rect->x + rect->width; |
| 147 | + y2 = rect->y + rect->height; |
| 148 | + |
| 149 | + pixels = gdk_pixbuf_get_pixels (pixbuf); |
| 150 | + rowstride = gdk_pixbuf_get_rowstride (pixbuf); |
| 151 | + has_alpha = gdk_pixbuf_get_has_alpha (pixbuf); |
| 152 | + n_channels = gdk_pixbuf_get_n_channels (pixbuf); |
| 153 | + |
| 154 | + for (y = rect->y; y < y2; y++) |
| 155 | + { |
| 156 | + guchar *p; |
| 157 | + |
| 158 | + row = pixels + y * rowstride; |
| 159 | + p = row + rect->x * n_channels; |
| 160 | + |
| 161 | + for (x = rect->x; x < x2; x++) |
| 162 | + { |
| 163 | + *p++ = 0; |
| 164 | + *p++ = 0; |
| 165 | + *p++ = 0; |
| 166 | + |
| 167 | + if (has_alpha) |
| 168 | + *p++ = 255; /* opaque black */ |
| 169 | + } |
| 170 | + } |
| 171 | +} |
| 172 | + |
| 173 | +static void |
| 174 | +blank_region_in_pixbuf (GdkPixbuf *pixbuf, cairo_region_t *region) |
| 175 | +{ |
| 176 | + int n_rects; |
| 177 | + int i; |
| 178 | + int width, height; |
| 179 | + cairo_rectangle_int_t pixbuf_rect; |
| 180 | + |
| 181 | + n_rects = cairo_region_num_rectangles (region); |
| 182 | + |
| 183 | + width = gdk_pixbuf_get_width (pixbuf); |
| 184 | + height = gdk_pixbuf_get_height (pixbuf); |
| 185 | + |
| 186 | + pixbuf_rect.x = 0; |
| 187 | + pixbuf_rect.y = 0; |
| 188 | + pixbuf_rect.width = width; |
| 189 | + pixbuf_rect.height = height; |
| 190 | + |
| 191 | + for (i = 0; i < n_rects; i++) |
| 192 | + { |
| 193 | + cairo_rectangle_int_t rect, dest; |
| 194 | + |
| 195 | + cairo_region_get_rectangle (region, i, &rect); |
| 196 | + if (gdk_rectangle_intersect (&rect, &pixbuf_rect, &dest)) |
| 197 | + blank_rectangle_in_pixbuf (pixbuf, &dest); |
| 198 | + } |
| 199 | +} |
| 200 | + |
| 201 | +/* When there are multiple monitors with different resolutions, the visible area |
| 202 | + * within the root window may not be rectangular (it may have an L-shape, for |
| 203 | + * example). In that case, mask out the areas of the root window which would |
| 204 | + * not be visible in the monitors, so that screenshot do not end up with content |
| 205 | + * that the user won't ever see. |
| 206 | + */ |
| 207 | +static void |
| 208 | +mask_monitors (GdkPixbuf *pixbuf, GdkWindow *root_window) |
| 209 | +{ |
| 210 | + GdkScreen *screen; |
| 211 | + cairo_region_t *region_with_monitors; |
| 212 | + cairo_region_t *invisible_region; |
| 213 | + cairo_rectangle_int_t rect; |
| 214 | + |
| 215 | + screen = gdk_window_get_screen (root_window); |
| 216 | + |
| 217 | + region_with_monitors = make_region_with_monitors (screen); |
| 218 | + |
| 219 | + rect.x = 0; |
| 220 | + rect.y = 0; |
| 221 | + rect.width = gdk_screen_get_width (screen); |
| 222 | + rect.height = gdk_screen_get_height (screen); |
| 223 | + |
| 224 | + invisible_region = cairo_region_create_rectangle (&rect); |
| 225 | + cairo_region_subtract (invisible_region, region_with_monitors); |
| 226 | + |
| 227 | + blank_region_in_pixbuf (pixbuf, invisible_region); |
| 228 | + |
| 229 | + cairo_region_destroy (region_with_monitors); |
| 230 | + cairo_region_destroy (invisible_region); |
| 231 | +} |
| 232 | + |
| 233 | +static void |
| 234 | +screenshot_fallback_get_window_rect_coords (GdkWindow *window, |
| 235 | + gboolean include_border, |
| 236 | + GdkRectangle *real_coordinates_out, |
| 237 | + GdkRectangle *screenshot_coordinates_out) |
| 238 | +{ |
| 239 | + gint x_orig, y_orig; |
| 240 | + gint width, height; |
| 241 | + GdkRectangle real_coordinates; |
| 242 | + |
| 243 | + if (include_border) |
| 244 | + { |
| 245 | + gdk_window_get_frame_extents (window, &real_coordinates); |
| 246 | + } |
| 247 | + else |
| 248 | + { |
| 249 | + real_coordinates.width = gdk_window_get_width (window); |
| 250 | + real_coordinates.height = gdk_window_get_height (window); |
| 251 | + |
| 252 | + gdk_window_get_origin (window, &real_coordinates.x, &real_coordinates.y); |
| 253 | + } |
| 254 | + |
| 255 | + x_orig = real_coordinates.x; |
| 256 | + y_orig = real_coordinates.y; |
| 257 | + width = real_coordinates.width; |
| 258 | + height = real_coordinates.height; |
| 259 | + |
| 260 | + if (real_coordinates_out != NULL) |
| 261 | + *real_coordinates_out = real_coordinates; |
| 262 | + |
| 263 | + if (x_orig < 0) |
| 264 | + { |
| 265 | + width = width + x_orig; |
| 266 | + x_orig = 0; |
| 267 | + } |
| 268 | + |
| 269 | + if (y_orig < 0) |
| 270 | + { |
| 271 | + height = height + y_orig; |
| 272 | + y_orig = 0; |
| 273 | + } |
| 274 | + |
| 275 | + if (x_orig + width > gdk_screen_width ()) |
| 276 | + width = gdk_screen_width () - x_orig; |
| 277 | + |
| 278 | + if (y_orig + height > gdk_screen_height ()) |
| 279 | + height = gdk_screen_height () - y_orig; |
| 280 | + |
| 281 | + if (screenshot_coordinates_out != NULL) |
| 282 | + { |
| 283 | + screenshot_coordinates_out->x = x_orig; |
| 284 | + screenshot_coordinates_out->y = y_orig; |
| 285 | + screenshot_coordinates_out->width = width; |
| 286 | + screenshot_coordinates_out->height = height; |
| 287 | + } |
| 288 | +} |
| 289 | + |
| 290 | +void |
| 291 | +screenshot_play_sound_effect (const gchar *event_id, |
| 292 | + const gchar *event_desc) |
| 293 | +{ |
| 294 | + ca_context *c; |
| 295 | + ca_proplist *p = NULL; |
| 296 | + int res; |
| 297 | + |
| 298 | + c = ca_gtk_context_get (); |
| 299 | + |
| 300 | + res = ca_proplist_create (&p); |
| 301 | + if (res < 0) |
| 302 | + goto done; |
| 303 | + |
| 304 | + res = ca_proplist_sets (p, CA_PROP_EVENT_ID, event_id); |
| 305 | + if (res < 0) |
| 306 | + goto done; |
| 307 | + |
| 308 | + res = ca_proplist_sets (p, CA_PROP_EVENT_DESCRIPTION, event_desc); |
| 309 | + if (res < 0) |
| 310 | + goto done; |
| 311 | + |
| 312 | + res = ca_proplist_sets (p, CA_PROP_CANBERRA_CACHE_CONTROL, "permanent"); |
| 313 | + if (res < 0) |
| 314 | + goto done; |
| 315 | + |
| 316 | + ca_context_play_full (c, 0, p, NULL, NULL); |
| 317 | + |
| 318 | + done: |
| 319 | + if (p != NULL) |
| 320 | + ca_proplist_destroy (p); |
| 321 | + |
| 322 | +} |
| 323 | + |
| 324 | +static void |
| 325 | +screenshot_fallback_fire_flash (GdkWindow *window, |
| 326 | + GdkRectangle *rectangle) |
| 327 | +{ |
| 328 | + GdkRectangle rect; |
| 329 | + CheeseFlash *flash = NULL; |
| 330 | + |
| 331 | + if (rectangle != NULL) |
| 332 | + rect = *rectangle; |
| 333 | + else |
| 334 | + screenshot_fallback_get_window_rect_coords (window, |
| 335 | + screenshot_config->include_border, |
| 336 | + NULL, |
| 337 | + &rect); |
| 338 | + |
| 339 | + flash = cheese_flash_new (); |
| 340 | + cheese_flash_fire (flash, &rect); |
| 341 | + |
| 342 | + g_object_unref (flash); |
| 343 | +} |
| 344 | + |
| 345 | +GdkWindow * |
| 346 | +do_find_current_window (void) |
| 347 | +{ |
| 348 | + GdkWindow *current_window; |
| 349 | + GdkDeviceManager *manager; |
| 350 | + GdkDevice *device; |
| 351 | + |
| 352 | + current_window = screenshot_find_active_window (); |
| 353 | + manager = gdk_display_get_device_manager (gdk_display_get_default ()); |
| 354 | + device = gdk_device_manager_get_client_pointer (manager); |
| 355 | + |
| 356 | + /* If there's no active window, we fall back to returning the |
| 357 | + * window that the cursor is in. |
| 358 | + */ |
| 359 | + if (!current_window) |
| 360 | + current_window = gdk_device_get_window_at_position (device, NULL, NULL); |
| 361 | + |
| 362 | + if (current_window) |
| 363 | + { |
| 364 | + if (screenshot_window_is_desktop (current_window)) |
| 365 | + /* if the current window is the desktop (e.g. nautilus), we |
| 366 | + * return NULL, as getting the whole screen makes more sense. |
| 367 | + */ |
| 368 | + return NULL; |
| 369 | + |
| 370 | + /* Once we have a window, we take the toplevel ancestor. */ |
| 371 | + current_window = gdk_window_get_toplevel (current_window); |
| 372 | + } |
| 373 | + |
| 374 | + return current_window; |
| 375 | +} |
| 376 | + |
| 377 | +static GdkWindow * |
| 378 | +screenshot_fallback_find_current_window (void) |
| 379 | +{ |
| 380 | + GdkWindow *window = NULL; |
| 381 | + |
| 382 | + if (screenshot_config->take_window_shot) |
| 383 | + { |
| 384 | + window = do_find_current_window (); |
| 385 | + |
| 386 | + if (window == NULL) |
| 387 | + screenshot_config->take_window_shot = FALSE; |
| 388 | + } |
| 389 | + |
| 390 | + if (window == NULL) |
| 391 | + window = gdk_get_default_root_window (); |
| 392 | + |
| 393 | + return window; |
| 394 | +} |
| 395 | + |
| 396 | +static GdkPixbuf * |
| 397 | +screenshot_fallback_get_pixbuf (GdkRectangle *rectangle) |
| 398 | +{ |
| 399 | + GdkWindow *root, *wm_window = NULL; |
| 400 | + GdkPixbuf *screenshot; |
| 401 | + GdkRectangle real_coords, screenshot_coords; |
| 402 | + Window wm; |
| 403 | + GtkBorder frame_offset = { 0, 0, 0, 0 }; |
| 404 | + GdkWindow *window; |
| 405 | + |
| 406 | + window = screenshot_fallback_find_current_window (); |
| 407 | + |
| 408 | + screenshot_fallback_get_window_rect_coords (window, |
| 409 | + screenshot_config->include_border, |
| 410 | + &real_coords, |
| 411 | + &screenshot_coords); |
| 412 | + |
| 413 | + wm = find_wm_window (window); |
| 414 | + if (wm != None) |
| 415 | + { |
| 416 | + GdkRectangle wm_real_coords; |
| 417 | + |
| 418 | + wm_window = gdk_x11_window_foreign_new_for_display |
| 419 | + (gdk_window_get_display (window), wm); |
| 420 | + |
| 421 | + screenshot_fallback_get_window_rect_coords (wm_window, |
| 422 | + FALSE, |
| 423 | + &wm_real_coords, |
| 424 | + NULL); |
| 425 | + |
| 426 | + frame_offset.left = (gdouble) (real_coords.x - wm_real_coords.x); |
| 427 | + frame_offset.top = (gdouble) (real_coords.y - wm_real_coords.y); |
| 428 | + frame_offset.right = (gdouble) (wm_real_coords.width - real_coords.width - frame_offset.left); |
| 429 | + frame_offset.bottom = (gdouble) (wm_real_coords.height - real_coords.height - frame_offset.top); |
| 430 | + } |
| 431 | + |
| 432 | + if (rectangle) |
| 433 | + { |
| 434 | + screenshot_coords.x = rectangle->x - screenshot_coords.x; |
| 435 | + screenshot_coords.y = rectangle->y - screenshot_coords.y; |
| 436 | + screenshot_coords.width = rectangle->width; |
| 437 | + screenshot_coords.height = rectangle->height; |
| 438 | + } |
| 439 | + |
| 440 | + root = gdk_get_default_root_window (); |
| 441 | + screenshot = gdk_pixbuf_get_from_window (root, |
| 442 | + screenshot_coords.x, screenshot_coords.y, |
| 443 | + screenshot_coords.width, screenshot_coords.height); |
| 444 | + |
| 445 | + if (!screenshot_config->take_window_shot && |
| 446 | + !screenshot_config->take_area_shot) |
| 447 | + mask_monitors (screenshot, root); |
| 448 | + |
| 449 | +#ifdef HAVE_X11_EXTENSIONS_SHAPE_H |
| 450 | + if (screenshot_config->include_border && (wm != None)) |
| 451 | + { |
| 452 | + XRectangle *rectangles; |
| 453 | + GdkPixbuf *tmp; |
| 454 | + int rectangle_count, rectangle_order, i; |
| 455 | + |
| 456 | + /* we must use XShape to avoid showing what's under the rounder corners |
| 457 | + * of the WM decoration. |
| 458 | + */ |
| 459 | + rectangles = XShapeGetRectangles (GDK_DISPLAY_XDISPLAY (gdk_display_get_default()), |
| 460 | + wm, |
| 461 | + ShapeBounding, |
| 462 | + &rectangle_count, |
| 463 | + &rectangle_order); |
| 464 | + if (rectangles && rectangle_count > 0) |
| 465 | + { |
| 466 | + gboolean has_alpha = gdk_pixbuf_get_has_alpha (screenshot); |
| 467 | + |
| 468 | + tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, |
| 469 | + screenshot_coords.width, screenshot_coords.height); |
| 470 | + gdk_pixbuf_fill (tmp, 0); |
| 471 | + |
| 472 | + for (i = 0; i < rectangle_count; i++) |
| 473 | + { |
| 474 | + gint rec_x, rec_y; |
| 475 | + gint rec_width, rec_height; |
| 476 | + gint y; |
| 477 | + |
| 478 | + /* If we're using invisible borders, the ShapeBounding might not |
| 479 | + * have the same size as the frame extents, as it would include the |
| 480 | + * areas for the invisible borders themselves. |
| 481 | + * In that case, trim every rectangle we get by the offset between the |
| 482 | + * WM window size and the frame extents. |
| 483 | + */ |
| 484 | + rec_x = rectangles[i].x; |
| 485 | + rec_y = rectangles[i].y; |
| 486 | + rec_width = rectangles[i].width - (frame_offset.left + frame_offset.right); |
| 487 | + rec_height = rectangles[i].height - (frame_offset.top + frame_offset.bottom); |
| 488 | + |
| 489 | + if (real_coords.x < 0) |
| 490 | + { |
| 491 | + rec_x += real_coords.x; |
| 492 | + rec_x = MAX(rec_x, 0); |
| 493 | + rec_width += real_coords.x; |
| 494 | + } |
| 495 | + |
| 496 | + if (real_coords.y < 0) |
| 497 | + { |
| 498 | + rec_y += real_coords.y; |
| 499 | + rec_y = MAX(rec_y, 0); |
| 500 | + rec_height += real_coords.y; |
| 501 | + } |
| 502 | + |
| 503 | + if (screenshot_coords.x + rec_x + rec_width > gdk_screen_width ()) |
| 504 | + rec_width = gdk_screen_width () - screenshot_coords.x - rec_x; |
| 505 | + |
| 506 | + if (screenshot_coords.y + rec_y + rec_height > gdk_screen_height ()) |
| 507 | + rec_height = gdk_screen_height () - screenshot_coords.y - rec_y; |
| 508 | + |
| 509 | + for (y = rec_y; y < rec_y + rec_height; y++) |
| 510 | + { |
| 511 | + guchar *src_pixels, *dest_pixels; |
| 512 | + gint x; |
| 513 | + |
| 514 | + src_pixels = gdk_pixbuf_get_pixels (screenshot) |
| 515 | + + y * gdk_pixbuf_get_rowstride(screenshot) |
| 516 | + + rec_x * (has_alpha ? 4 : 3); |
| 517 | + dest_pixels = gdk_pixbuf_get_pixels (tmp) |
| 518 | + + y * gdk_pixbuf_get_rowstride (tmp) |
| 519 | + + rec_x * 4; |
| 520 | + |
| 521 | + for (x = 0; x < rec_width; x++) |
| 522 | + { |
| 523 | + *dest_pixels++ = *src_pixels++; |
| 524 | + *dest_pixels++ = *src_pixels++; |
| 525 | + *dest_pixels++ = *src_pixels++; |
| 526 | + |
| 527 | + if (has_alpha) |
| 528 | + *dest_pixels++ = *src_pixels++; |
| 529 | + else |
| 530 | + *dest_pixels++ = 255; |
| 531 | + } |
| 532 | + } |
| 533 | + } |
| 534 | + |
| 535 | + g_object_unref (screenshot); |
| 536 | + screenshot = tmp; |
| 537 | + |
| 538 | + XFree (rectangles); |
| 539 | + } |
| 540 | + } |
| 541 | +#endif /* HAVE_X11_EXTENSIONS_SHAPE_H */ |
| 542 | + |
| 543 | + /* if we have a selected area, there were by definition no cursor in the |
| 544 | + * screenshot */ |
| 545 | + if (screenshot_config->include_pointer && !rectangle) |
| 546 | + { |
| 547 | + GdkCursor *cursor; |
| 548 | + GdkPixbuf *cursor_pixbuf; |
| 549 | + |
| 550 | + cursor = gdk_cursor_new_for_display (gdk_display_get_default (), GDK_LEFT_PTR); |
| 551 | + cursor_pixbuf = gdk_cursor_get_image (cursor); |
| 552 | + |
| 553 | + if (cursor_pixbuf != NULL) |
| 554 | + { |
| 555 | + GdkDeviceManager *manager; |
| 556 | + GdkDevice *device; |
| 557 | + GdkRectangle rect; |
| 558 | + gint cx, cy, xhot, yhot; |
| 559 | + |
| 560 | + manager = gdk_display_get_device_manager (gdk_display_get_default ()); |
| 561 | + device = gdk_device_manager_get_client_pointer (manager); |
| 562 | + |
| 563 | + if (wm_window != NULL) |
| 564 | + gdk_window_get_device_position (wm_window, device, |
| 565 | + &cx, &cy, NULL); |
| 566 | + else |
| 567 | + gdk_window_get_device_position (window, device, |
| 568 | + &cx, &cy, NULL); |
| 569 | + |
| 570 | + sscanf (gdk_pixbuf_get_option (cursor_pixbuf, "x_hot"), "%d", &xhot); |
| 571 | + sscanf (gdk_pixbuf_get_option (cursor_pixbuf, "y_hot"), "%d", &yhot); |
| 572 | + |
| 573 | + /* in rect we have the cursor window coordinates */ |
| 574 | + rect.x = cx + real_coords.x; |
| 575 | + rect.y = cy + real_coords.y; |
| 576 | + rect.width = gdk_pixbuf_get_width (cursor_pixbuf); |
| 577 | + rect.height = gdk_pixbuf_get_height (cursor_pixbuf); |
| 578 | + |
| 579 | + /* see if the pointer is inside the window */ |
| 580 | + if (gdk_rectangle_intersect (&real_coords, &rect, &rect)) |
| 581 | + { |
| 582 | + gint cursor_x, cursor_y; |
| 583 | + |
| 584 | + cursor_x = cx - xhot - frame_offset.left; |
| 585 | + cursor_y = cy - yhot - frame_offset.top; |
| 586 | + gdk_pixbuf_composite (cursor_pixbuf, screenshot, |
| 587 | + cursor_x, cursor_y, |
| 588 | + rect.width, rect.height, |
| 589 | + cursor_x, cursor_y, |
| 590 | + 1.0, 1.0, |
| 591 | + GDK_INTERP_BILINEAR, |
| 592 | + 255); |
| 593 | + } |
| 594 | + |
| 595 | + g_object_unref (cursor_pixbuf); |
| 596 | + g_object_unref (cursor); |
| 597 | + } |
| 598 | + } |
| 599 | + |
| 600 | + screenshot_fallback_fire_flash (window, rectangle); |
| 601 | + |
| 602 | + return screenshot; |
| 603 | +} |
| 604 | + |
| 605 | +GdkPixbuf * |
| 606 | +screenshot_get_pixbuf (GdkRectangle *rectangle) |
| 607 | +{ |
| 608 | + GdkPixbuf *screenshot = NULL; |
| 609 | + gchar *path, *filename, *tmpname; |
| 610 | + const gchar *method_name; |
| 611 | + GVariant *method_params; |
| 612 | + GError *error = NULL; |
| 613 | + GDBusConnection *connection; |
| 614 | + |
| 615 | + path = g_build_filename (g_get_user_cache_dir (), "gnome-screenshot", NULL); |
| 616 | + g_mkdir_with_parents (path, 0700); |
| 617 | + |
| 618 | + tmpname = g_strdup_printf ("scr-%d.png", g_random_int ()); |
| 619 | + filename = g_build_filename (path, tmpname, NULL); |
| 620 | + |
| 621 | + if (screenshot_config->take_window_shot) |
| 622 | + { |
| 623 | + method_name = "ScreenshotWindow"; |
| 624 | + method_params = g_variant_new ("(bbbs)", |
| 625 | + screenshot_config->include_border, |
| 626 | + screenshot_config->include_pointer, |
| 627 | + TRUE, /* flash */ |
| 628 | + filename); |
| 629 | + } |
| 630 | + else if (rectangle != NULL) |
| 631 | + { |
| 632 | + method_name = "ScreenshotArea"; |
| 633 | + method_params = g_variant_new ("(iiiibs)", |
| 634 | + rectangle->x, rectangle->y, |
| 635 | + rectangle->width, rectangle->height, |
| 636 | + TRUE, /* flash */ |
| 637 | + filename); |
| 638 | + } |
| 639 | + else |
| 640 | + { |
| 641 | + method_name = "Screenshot"; |
| 642 | + method_params = g_variant_new ("(bbs)", |
| 643 | + screenshot_config->include_pointer, |
| 644 | + TRUE, /* flash */ |
| 645 | + filename); |
| 646 | + } |
| 647 | + |
| 648 | + if (!g_strcmp0 (g_getenv ("XDG_CURRENT_DESKTOP"), "Unity")) |
| 649 | + screenshot = screenshot_fallback_get_pixbuf(rectangle); |
| 650 | + else { |
| 651 | + connection = g_application_get_dbus_connection (g_application_get_default ()); |
| 652 | + g_dbus_connection_call_sync (connection, |
| 653 | + "org.gnome.Shell.Screenshot", |
| 654 | + "/org/gnome/Shell/Screenshot", |
| 655 | + "org.gnome.Shell.Screenshot", |
| 656 | + method_name, |
| 657 | + method_params, |
| 658 | + NULL, |
| 659 | + G_DBUS_CALL_FLAGS_NONE, |
| 660 | + -1, |
| 661 | + NULL, |
| 662 | + &error); |
| 663 | + |
| 664 | + if (error == NULL) |
| 665 | + { |
| 666 | + screenshot = gdk_pixbuf_new_from_file (filename, &error); |
| 667 | + |
| 668 | + /* remove the temporary file created by the shell */ |
| 669 | + g_unlink (filename); |
| 670 | + } |
| 671 | + |
| 672 | + if (error != NULL) |
| 673 | + { |
| 674 | + g_message ("Unable to use GNOME Shell's builtin screenshot interface, " |
| 675 | + "resorting to fallback X11."); |
| 676 | + g_error_free (error); |
| 677 | + |
| 678 | + screenshot = screenshot_fallback_get_pixbuf (rectangle); |
| 679 | + } |
| 680 | + } |
| 681 | + |
| 682 | + g_free (path); |
| 683 | + g_free (tmpname); |
| 684 | + g_free (filename); |
| 685 | + |
| 686 | + return screenshot; |
| 687 | +} |
| 688 | + |
| 689 | +gint |
| 690 | +screenshot_show_dialog (GtkWindow *parent, |
| 691 | + GtkMessageType message_type, |
| 692 | + GtkButtonsType buttons_type, |
| 693 | + const gchar *message, |
| 694 | + const gchar *detail) |
| 695 | +{ |
| 696 | + GtkWidget *dialog; |
| 697 | + GtkWindowGroup *group; |
| 698 | + gint response; |
| 699 | + |
| 700 | + g_return_val_if_fail ((parent == NULL) || (GTK_IS_WINDOW (parent)), |
| 701 | + GTK_RESPONSE_NONE); |
| 702 | + g_return_val_if_fail (message != NULL, GTK_RESPONSE_NONE); |
| 703 | + |
| 704 | + dialog = gtk_message_dialog_new (parent, |
| 705 | + GTK_DIALOG_DESTROY_WITH_PARENT, |
| 706 | + message_type, |
| 707 | + buttons_type, |
| 708 | + "%s", message); |
| 709 | + gtk_window_set_title (GTK_WINDOW (dialog), ""); |
| 710 | + |
| 711 | + if (detail) |
| 712 | + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), |
| 713 | + "%s", detail); |
| 714 | + |
| 715 | + if (parent) |
| 716 | + { |
| 717 | + group = gtk_window_get_group (parent); |
| 718 | + if (group != NULL) |
| 719 | + gtk_window_group_add_window (group, GTK_WINDOW (dialog)); |
| 720 | + } |
| 721 | + |
| 722 | + response = gtk_dialog_run (GTK_DIALOG (dialog)); |
| 723 | + |
| 724 | + gtk_widget_destroy (dialog); |
| 725 | + |
| 726 | + return response; |
| 727 | +} |
| 728 | + |
| 729 | +void |
| 730 | +screenshot_display_help (GtkWindow *parent) |
| 731 | +{ |
| 732 | + GError *error = NULL; |
| 733 | + |
| 734 | + gtk_show_uri (gtk_window_get_screen (parent), |
| 735 | + "help:ubuntu-help/screen-shot-record", |
| 736 | + gtk_get_current_event_time (), &error); |
| 737 | + |
| 738 | + if (error) |
| 739 | + { |
| 740 | + screenshot_show_dialog (parent, |
| 741 | + GTK_MESSAGE_ERROR, |
| 742 | + GTK_BUTTONS_OK, |
| 743 | + _("Error loading the help page"), |
| 744 | + error->message); |
| 745 | + g_error_free (error); |
| 746 | + } |
| 747 | +} |
| 748 | |
| 749 | === modified file 'debian/changelog' |
| 750 | --- debian/changelog 2014-01-16 11:16:23 +0000 |
| 751 | +++ debian/changelog 2015-02-04 10:34:12 +0000 |
| 752 | @@ -1,3 +1,10 @@ |
| 753 | +gnome-screenshot (3.10.1-0ubuntu2) trusty; urgency=medium |
| 754 | + |
| 755 | + * debian/patches/ubuntu_fix_hidpi: |
| 756 | + - support hidpi scale factor when rendering preview. |
| 757 | + |
| 758 | + -- Woodrow Shen (Shye-Tzeng Shen) <woodrow.shen@canonical.com> Wed, 04 Feb 2015 15:03:32 +0800 |
| 759 | + |
| 760 | gnome-screenshot (3.10.1-0ubuntu1) trusty; urgency=medium |
| 761 | |
| 762 | * New upstream version |
| 763 | |
| 764 | === modified file 'debian/patches/series' |
| 765 | --- debian/patches/series 2013-03-15 17:08:12 +0000 |
| 766 | +++ debian/patches/series 2015-02-04 10:34:12 +0000 |
| 767 | @@ -3,3 +3,4 @@ |
| 768 | ubuntu_unity_no_gnomeshell.patch |
| 769 | update_unity_list.patch |
| 770 | uri.patch |
| 771 | +ubuntu_fix_hidpi.patch |
| 772 | |
| 773 | === added file 'debian/patches/ubuntu_fix_hidpi.patch' |
| 774 | --- debian/patches/ubuntu_fix_hidpi.patch 1970-01-01 00:00:00 +0000 |
| 775 | +++ debian/patches/ubuntu_fix_hidpi.patch 2015-02-04 10:34:12 +0000 |
| 776 | @@ -0,0 +1,75 @@ |
| 777 | +Description: |
| 778 | + For Hi-DPI display case, such as the resolution 3840x2160, the scale factor is 2 |
| 779 | + and gnome-screenshot generates screenshot image wihtout considering the scale factor. |
| 780 | + So this patch will use this factor to correct the screenshot for Hi-DPI case. |
| 781 | + |
| 782 | +Origin: upstream |
| 783 | +Bug: https://bugzilla.gnome.org/show_bug.cgi?id=743957 |
| 784 | +Last-Update: 2015-02-04 |
| 785 | +--- |
| 786 | +This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ |
| 787 | +Index: b/src/screenshot-utils.c |
| 788 | +=================================================================== |
| 789 | +--- a/src/screenshot-utils.c 2015-02-04 14:57:06.590766000 +0800 |
| 790 | ++++ b/src/screenshot-utils.c 2015-02-04 15:53:09.856279594 +0800 |
| 791 | +@@ -383,10 +383,12 @@ |
| 792 | + { |
| 793 | + GdkWindow *root, *wm_window = NULL; |
| 794 | + GdkPixbuf *screenshot; |
| 795 | ++ GdkPixbuf *screenshot_scale; |
| 796 | + GdkRectangle real_coords, screenshot_coords; |
| 797 | + Window wm; |
| 798 | + GtkBorder frame_offset = { 0, 0, 0, 0 }; |
| 799 | + GdkWindow *window; |
| 800 | ++ gint scale_factor; |
| 801 | + |
| 802 | + window = screenshot_fallback_find_current_window (); |
| 803 | + |
| 804 | +@@ -427,9 +429,15 @@ |
| 805 | + screenshot_coords.x, screenshot_coords.y, |
| 806 | + screenshot_coords.width, screenshot_coords.height); |
| 807 | + |
| 808 | ++ scale_factor = gdk_window_get_scale_factor (root); |
| 809 | ++ screenshot_scale = gdk_pixbuf_scale_simple(screenshot, |
| 810 | ++ screenshot_coords.width * scale_factor, |
| 811 | ++ screenshot_coords.height * scale_factor, |
| 812 | ++ GDK_INTERP_BILINEAR); |
| 813 | ++ |
| 814 | + if (!screenshot_config->take_window_shot && |
| 815 | + !screenshot_config->take_area_shot) |
| 816 | +- mask_monitors (screenshot, root); |
| 817 | ++ mask_monitors (screenshot_scale, root); |
| 818 | + |
| 819 | + #ifdef HAVE_X11_EXTENSIONS_SHAPE_H |
| 820 | + if (screenshot_config->include_border && (wm != None)) |
| 821 | +@@ -448,7 +456,7 @@ |
| 822 | + &rectangle_order); |
| 823 | + if (rectangles && rectangle_count > 0) |
| 824 | + { |
| 825 | +- gboolean has_alpha = gdk_pixbuf_get_has_alpha (screenshot); |
| 826 | ++ gboolean has_alpha = gdk_pixbuf_get_has_alpha (screenshot_scale); |
| 827 | + |
| 828 | + tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, |
| 829 | + screenshot_coords.width, screenshot_coords.height); |
| 830 | +@@ -496,8 +504,8 @@ |
| 831 | + guchar *src_pixels, *dest_pixels; |
| 832 | + gint x; |
| 833 | + |
| 834 | +- src_pixels = gdk_pixbuf_get_pixels (screenshot) |
| 835 | +- + y * gdk_pixbuf_get_rowstride(screenshot) |
| 836 | ++ src_pixels = gdk_pixbuf_get_pixels (screenshot_scale) |
| 837 | ++ + y * gdk_pixbuf_get_rowstride(screenshot_scale) |
| 838 | + + rec_x * (has_alpha ? 4 : 3); |
| 839 | + dest_pixels = gdk_pixbuf_get_pixels (tmp) |
| 840 | + + y * gdk_pixbuf_get_rowstride (tmp) |
| 841 | +@@ -517,8 +525,8 @@ |
| 842 | + } |
| 843 | + } |
| 844 | + |
| 845 | +- g_object_unref (screenshot); |
| 846 | +- screenshot = tmp; |
| 847 | ++ g_object_unref (screenshot_scale); |
| 848 | ++ screenshot_scale = tmp; |
| 849 | + |
| 850 | + XFree (rectangles); |
| 851 | + } |
| 852 | |
| 853 | === modified file 'src/screenshot-utils.c' |
| 854 | --- src/screenshot-utils.c 2013-05-15 12:01:25 +0000 |
| 855 | +++ src/screenshot-utils.c 2015-02-04 10:34:12 +0000 |
| 856 | @@ -383,10 +383,12 @@ |
| 857 | { |
| 858 | GdkWindow *root, *wm_window = NULL; |
| 859 | GdkPixbuf *screenshot; |
| 860 | + GdkPixbuf *screenshot_scale; |
| 861 | GdkRectangle real_coords, screenshot_coords; |
| 862 | Window wm; |
| 863 | GtkBorder frame_offset = { 0, 0, 0, 0 }; |
| 864 | GdkWindow *window; |
| 865 | + gint scale_factor; |
| 866 | |
| 867 | window = screenshot_fallback_find_current_window (); |
| 868 | |
| 869 | @@ -427,9 +429,15 @@ |
| 870 | screenshot_coords.x, screenshot_coords.y, |
| 871 | screenshot_coords.width, screenshot_coords.height); |
| 872 | |
| 873 | + scale_factor = gdk_window_get_scale_factor (root); |
| 874 | + screenshot_scale = gdk_pixbuf_scale_simple(screenshot, |
| 875 | + screenshot_coords.width * scale_factor, |
| 876 | + screenshot_coords.height * scale_factor, |
| 877 | + GDK_INTERP_BILINEAR); |
| 878 | + |
| 879 | if (!screenshot_config->take_window_shot && |
| 880 | !screenshot_config->take_area_shot) |
| 881 | - mask_monitors (screenshot, root); |
| 882 | + mask_monitors (screenshot_scale, root); |
| 883 | |
| 884 | #ifdef HAVE_X11_EXTENSIONS_SHAPE_H |
| 885 | if (screenshot_config->include_border && (wm != None)) |
| 886 | @@ -448,7 +456,7 @@ |
| 887 | &rectangle_order); |
| 888 | if (rectangles && rectangle_count > 0) |
| 889 | { |
| 890 | - gboolean has_alpha = gdk_pixbuf_get_has_alpha (screenshot); |
| 891 | + gboolean has_alpha = gdk_pixbuf_get_has_alpha (screenshot_scale); |
| 892 | |
| 893 | tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, |
| 894 | screenshot_coords.width, screenshot_coords.height); |
| 895 | @@ -496,8 +504,8 @@ |
| 896 | guchar *src_pixels, *dest_pixels; |
| 897 | gint x; |
| 898 | |
| 899 | - src_pixels = gdk_pixbuf_get_pixels (screenshot) |
| 900 | - + y * gdk_pixbuf_get_rowstride(screenshot) |
| 901 | + src_pixels = gdk_pixbuf_get_pixels (screenshot_scale) |
| 902 | + + y * gdk_pixbuf_get_rowstride(screenshot_scale) |
| 903 | + rec_x * (has_alpha ? 4 : 3); |
| 904 | dest_pixels = gdk_pixbuf_get_pixels (tmp) |
| 905 | + y * gdk_pixbuf_get_rowstride (tmp) |
| 906 | @@ -517,8 +525,8 @@ |
| 907 | } |
| 908 | } |
| 909 | |
| 910 | - g_object_unref (screenshot); |
| 911 | - screenshot = tmp; |
| 912 | + g_object_unref (screenshot_scale); |
| 913 | + screenshot_scale = tmp; |
| 914 | |
| 915 | XFree (rectangles); |
| 916 | } |

Hey Woodrow, thanks for your work on that, some comments:
- is that work coming from upstream? if not could we forward them the change, it's not Ubuntu specific and we would benefit to see it reviewed/commited to the official vcs
- could you describe the change and add urls to the bugs in the patch for reference
- the bug should be fixed in vivid before being SRUed