2013-09-30 01:59:22 +00:00
|
|
|
#include <gdk/gdk.h>
|
2004-08-23 21:22:55 +00:00
|
|
|
#include <gtk/gtk.h>
|
2013-09-30 01:59:22 +00:00
|
|
|
#include <gdkx.h>
|
2016-11-20 10:43:09 +00:00
|
|
|
#include <cairo-xlib.h>
|
2013-09-30 01:59:22 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <X11/extensions/shape.h>
|
|
|
|
|
|
|
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <locale.h>
|
2004-08-23 21:22:55 +00:00
|
|
|
#include "widgets.h"
|
2013-09-30 01:59:22 +00:00
|
|
|
#include "shadow.h"
|
|
|
|
|
|
|
|
static GdkPixbuf *
|
2020-08-04 01:09:54 +00:00
|
|
|
add_border (GdkPixbuf *pixbuf)
|
2004-08-23 21:22:55 +00:00
|
|
|
{
|
2013-09-30 01:59:22 +00:00
|
|
|
GdkPixbuf *retval;
|
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
retval = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
|
|
|
|
gdk_pixbuf_get_width (pixbuf) + 2,
|
|
|
|
gdk_pixbuf_get_height (pixbuf) + 2);
|
2013-09-30 01:59:22 +00:00
|
|
|
|
|
|
|
/* Fill with solid black */
|
|
|
|
gdk_pixbuf_fill (retval, 0xFF);
|
|
|
|
gdk_pixbuf_copy_area (pixbuf,
|
2020-08-04 01:09:54 +00:00
|
|
|
0, 0,
|
|
|
|
gdk_pixbuf_get_width (pixbuf),
|
|
|
|
gdk_pixbuf_get_height (pixbuf),
|
|
|
|
retval, 1, 1);
|
|
|
|
|
|
|
|
g_object_unref (pixbuf);
|
2004-08-23 21:22:55 +00:00
|
|
|
|
2013-09-30 01:59:22 +00:00
|
|
|
return retval;
|
2004-08-23 21:22:55 +00:00
|
|
|
}
|
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
static GMainLoop *loop;
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
quit_when_idle (gpointer loop)
|
2004-08-23 21:22:55 +00:00
|
|
|
{
|
2020-08-04 01:09:54 +00:00
|
|
|
g_main_loop_quit (loop);
|
2004-08-23 21:22:55 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
return G_SOURCE_REMOVE;
|
2004-08-23 21:22:55 +00:00
|
|
|
}
|
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
static void
|
|
|
|
draw_paintable (GdkPaintable *paintable,
|
|
|
|
gpointer out_surface)
|
2004-08-23 21:22:55 +00:00
|
|
|
{
|
2020-08-04 01:09:54 +00:00
|
|
|
GtkSnapshot *snapshot;
|
|
|
|
GskRenderNode *node;
|
2016-11-20 10:43:09 +00:00
|
|
|
cairo_surface_t *surface;
|
2020-08-04 01:09:54 +00:00
|
|
|
cairo_t *cr;
|
|
|
|
|
|
|
|
snapshot = gtk_snapshot_new ();
|
|
|
|
gdk_paintable_snapshot (paintable,
|
|
|
|
snapshot,
|
|
|
|
gdk_paintable_get_intrinsic_width (paintable),
|
|
|
|
gdk_paintable_get_intrinsic_height (paintable));
|
|
|
|
node = gtk_snapshot_free_to_node (snapshot);
|
|
|
|
|
|
|
|
/* If the window literally draws nothing, we assume it hasn't been mapped yet and as such
|
|
|
|
* the invalidations were only side effects of resizes.
|
|
|
|
*/
|
|
|
|
if (node == NULL)
|
|
|
|
return;
|
2013-09-30 01:59:22 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
|
|
|
gdk_paintable_get_intrinsic_width (paintable),
|
|
|
|
gdk_paintable_get_intrinsic_height (paintable));
|
2013-09-30 01:59:22 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
cr = cairo_create (surface);
|
|
|
|
gsk_render_node_draw (node, cr);
|
|
|
|
cairo_destroy (cr);
|
|
|
|
gsk_render_node_unref (node);
|
2013-09-30 01:59:22 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
g_signal_handlers_disconnect_by_func (paintable, draw_paintable, out_surface);
|
2013-09-30 01:59:22 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
*(cairo_surface_t **) out_surface = surface;
|
2013-09-30 01:59:22 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
g_idle_add (quit_when_idle, loop);
|
|
|
|
}
|
2004-08-23 21:22:55 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
static cairo_surface_t *
|
|
|
|
snapshot_widget (GtkWidget *widget)
|
|
|
|
{
|
|
|
|
GdkPaintable *paintable;
|
|
|
|
cairo_surface_t *surface;
|
2013-09-30 01:59:22 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
g_assert (gtk_widget_get_realized (widget));
|
2013-09-30 01:59:22 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
loop = g_main_loop_new (NULL, FALSE);
|
2013-09-30 01:59:22 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
/* We wait until the widget is drawn for the first time.
|
|
|
|
*
|
|
|
|
* We also use an inhibit mechanism, to give module functions a chance
|
|
|
|
* to delay the snapshot.
|
|
|
|
*/
|
|
|
|
paintable = gtk_widget_paintable_new (widget);
|
|
|
|
g_signal_connect (paintable, "invalidate-contents", G_CALLBACK (draw_paintable), &surface);
|
|
|
|
g_main_loop_run (loop);
|
2004-08-23 21:22:55 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
g_main_loop_unref (loop);
|
|
|
|
g_object_unref (paintable);
|
2020-10-26 03:18:51 +00:00
|
|
|
gtk_window_destroy (GTK_WINDOW (gtk_widget_get_root (widget)));
|
2013-09-30 01:59:22 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
return surface;
|
2004-08-23 21:22:55 +00:00
|
|
|
}
|
|
|
|
|
2020-10-26 02:17:15 +00:00
|
|
|
static gboolean
|
|
|
|
quit_cb (gpointer data)
|
|
|
|
{
|
|
|
|
*(gboolean *)data = TRUE;
|
2020-10-26 03:18:51 +00:00
|
|
|
g_main_context_wakeup (NULL);
|
2020-10-26 02:17:15 +00:00
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
int
|
|
|
|
main (int argc, char **argv)
|
2014-02-13 18:26:17 +00:00
|
|
|
{
|
2020-08-04 01:09:54 +00:00
|
|
|
GList *toplevels, *node;
|
2014-02-13 16:37:46 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
gtk_init ();
|
2004-08-23 21:22:55 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
toplevels = get_all_widgets ();
|
2004-08-23 21:22:55 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
for (node = toplevels; node; node = node->next)
|
2004-08-23 21:22:55 +00:00
|
|
|
{
|
2020-08-04 01:09:54 +00:00
|
|
|
WidgetInfo *info;
|
2004-08-23 21:22:55 +00:00
|
|
|
char *filename;
|
2020-08-04 01:09:54 +00:00
|
|
|
cairo_surface_t *surface;
|
|
|
|
GdkPixbuf *pixbuf;
|
2020-10-26 03:18:51 +00:00
|
|
|
GtkWidget *widget;
|
2013-09-30 01:59:22 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
info = node->data;
|
2013-09-30 01:59:22 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
gtk_widget_show (info->window);
|
2013-09-30 01:59:22 +00:00
|
|
|
|
2020-08-04 04:14:17 +00:00
|
|
|
if (info->no_focus)
|
|
|
|
{
|
|
|
|
gtk_root_set_focus (GTK_ROOT (info->window), NULL);
|
|
|
|
gdk_clipboard_set_content (gdk_display_get_primary_clipboard (gdk_display_get_default ()),
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
2020-10-26 03:18:51 +00:00
|
|
|
if (info->snapshot_popover)
|
|
|
|
{
|
|
|
|
GtkWidget *button = gtk_window_get_child (GTK_WINDOW (info->window));
|
|
|
|
|
|
|
|
gtk_menu_button_popup (GTK_MENU_BUTTON (button));
|
|
|
|
widget = GTK_WIDGET (gtk_menu_button_get_popover (GTK_MENU_BUTTON (button)));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
widget = info->window;
|
|
|
|
}
|
|
|
|
|
2020-10-26 02:17:15 +00:00
|
|
|
if (info->wait > 0)
|
|
|
|
{
|
|
|
|
gboolean quit = FALSE;
|
|
|
|
|
|
|
|
g_timeout_add (info->wait, quit_cb, &quit);
|
|
|
|
|
|
|
|
while (!quit)
|
|
|
|
g_main_context_iteration (NULL, TRUE);
|
|
|
|
}
|
2020-08-04 04:14:17 +00:00
|
|
|
|
2020-10-26 03:18:51 +00:00
|
|
|
surface = snapshot_widget (widget);
|
2014-02-13 16:37:46 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0,
|
|
|
|
cairo_image_surface_get_width (surface),
|
|
|
|
cairo_image_surface_get_height (surface));
|
2014-02-13 16:37:46 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
if (!info->include_decorations)
|
|
|
|
pixbuf = add_border (pixbuf);
|
2014-02-13 16:37:46 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
pixbuf = add_shadow (pixbuf);
|
2014-02-13 16:37:46 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
filename = g_strdup_printf ("./%s.png", info->name);
|
2014-02-13 16:37:46 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
gdk_pixbuf_save (pixbuf, filename, "png", NULL, NULL);
|
|
|
|
g_free (filename);
|
2014-02-13 16:37:46 +00:00
|
|
|
|
2020-08-04 01:09:54 +00:00
|
|
|
g_object_unref (pixbuf);
|
|
|
|
cairo_surface_destroy (surface);
|
|
|
|
}
|
2004-08-23 21:22:55 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|