/* * Copyright 2015 Javier S. Pedro * * This file is part of MDock. * * MDock is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MDock is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MDock. If not, see . */ #include #include "thumbnailer.h" #define THUMBNAIL_MAX_WIDTH 196 #define THUMBNAIL_MAX_HEIGHT 196 typedef struct _ThumbnailData { GdkPixmap * pix; guint update_source; time_t timestamp; } ThumbnailData; G_DEFINE_QUARK(mdock-thumbnail-data, mdock_thumbnail_data) static inline ThumbnailData * thumbnail_data_new() { return g_slice_new0(ThumbnailData); } static void thumbnail_data_destroy(ThumbnailData *tdata) { g_clear_object(&tdata->pix); if (tdata->update_source) g_source_remove(tdata->update_source); g_slice_free(ThumbnailData, tdata); } void thumbnailer_enable_for_window(WnckWindow *window) { g_object_set_qdata_full(G_OBJECT(window), mdock_thumbnail_data_quark(), thumbnail_data_new(), (GDestroyNotify)thumbnail_data_destroy); } static gboolean thumbnailer_do_update(gpointer data) { ThumbnailData *tdata = g_object_get_qdata(G_OBJECT(data), mdock_thumbnail_data_quark()); g_return_val_if_fail(tdata, G_SOURCE_REMOVE); thumbnailer_update_thumbnail(WNCK_WINDOW(data)); tdata->update_source = 0; return G_SOURCE_REMOVE; } void thumbnailer_schedule_update(WnckWindow *window) { ThumbnailData *tdata = g_object_get_qdata(G_OBJECT(window), mdock_thumbnail_data_quark()); g_return_if_fail(tdata); if (!tdata->update_source) { tdata->update_source = g_timeout_add(500, thumbnailer_do_update, window); } } void thumbnailer_update_thumbnail(WnckWindow *window) { GdkDisplay *display = gdk_display_get_default(); GdkScreen *screen = gdk_display_get_default_screen(display); ThumbnailData *tdata = g_object_get_qdata(G_OBJECT(window), mdock_thumbnail_data_quark()); g_return_if_fail(tdata); g_return_if_fail(wnck_window_is_active(window)); GdkWindow *root = gdk_get_default_root_window(); gdouble scale = MAX(gdk_screen_get_resolution(screen), 96.0) / 96.0; const gint max_w = THUMBNAIL_MAX_WIDTH * scale, max_h = THUMBNAIL_MAX_HEIGHT * scale; int screen_x, screen_y, win_x, win_y, win_w, win_h, thumb_w, thumb_h, cur_w, cur_h; gdk_window_get_origin(root, &screen_x, &screen_y); wnck_window_get_client_window_geometry(window, &win_x, &win_y, &win_w, &win_h); if (win_w > max_w || win_h > max_h) { if (win_h > win_w) { thumb_w = (max_h * win_w) / win_h; thumb_h = max_h; } else { thumb_w = max_w; thumb_h = (max_w * win_h) / win_w; } } else { thumb_w = win_w; thumb_h = win_h; } if (tdata->pix) { gdk_pixmap_get_size(tdata->pix, &cur_w, &cur_h); } if (!tdata->pix || cur_w != thumb_w || cur_h != thumb_h) { g_clear_object(&tdata->pix); g_debug("Recreating pixmap for %s (%dx%d)", wnck_window_get_name(window), thumb_w, thumb_h); tdata->pix = gdk_pixmap_new(root, thumb_w, thumb_h, -1); } g_return_if_fail(tdata->pix); g_debug("Updating thumbnail for %s (%dx%d)", wnck_window_get_name(window), thumb_w, thumb_h); double scale_w = thumb_w / (double)win_w, scale_h = thumb_h / (double)win_h; cairo_t *cr = gdk_cairo_create(GDK_DRAWABLE(tdata->pix)); cairo_scale(cr, scale_w, scale_h); gdk_cairo_set_source_window(cr, root, -(win_x - screen_x), -(win_y - screen_y)); cairo_pattern_set_filter(cairo_get_source (cr), CAIRO_FILTER_FAST); cairo_paint(cr); cairo_destroy(cr); time(&tdata->timestamp); } GdkPixmap * thumbnailer_get_thumbnail(WnckWindow *window) { ThumbnailData *tdata = g_object_get_qdata(G_OBJECT(window), mdock_thumbnail_data_quark()); g_return_val_if_fail(tdata, NULL); return tdata->pix; }