diff options
Diffstat (limited to 'devel-docs/tools/shooter.c')
-rw-r--r-- | devel-docs/tools/shooter.c | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/devel-docs/tools/shooter.c b/devel-docs/tools/shooter.c new file mode 100644 index 0000000..ecfa18f --- /dev/null +++ b/devel-docs/tools/shooter.c @@ -0,0 +1,298 @@ + +#include "config.h" + +#include <stdlib.h> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <gegl.h> +#include <gdk/gdkx.h> +#include <gtk/gtk.h> + +#include <X11/extensions/shape.h> + +#include "libgimpbase/gimpbase.h" +#include "libgimpconfig/gimpconfig.h" +#include "libgimpmodule/gimpmodule.h" +#include "libgimpwidgets/gimpwidgets.h" +#include "libgimpwidgets/gimpwidgets-private.h" + +#include "shadow.h" +#include "units.h" +#include "widgets.h" + + +static Window +find_toplevel_window (Display *display, + Window xid) +{ + Window root, parent, *children; + guint nchildren; + + do + { + if (XQueryTree (display, xid, + &root, &parent, &children, &nchildren) == 0) + { + g_warning ("Couldn't find window manager window"); + return 0; + } + + if (root == parent) + return xid; + + xid = parent; + } + while (TRUE); +} + +static GdkPixbuf * +add_border_to_shot (GdkPixbuf *pixbuf) +{ + GdkPixbuf *retval; + + retval = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, + gdk_pixbuf_get_width (pixbuf) + 2, + gdk_pixbuf_get_height (pixbuf) + 2); + + /* Fill with solid black */ + gdk_pixbuf_fill (retval, 0x000000FF); + + gdk_pixbuf_copy_area (pixbuf, + 0, 0, + gdk_pixbuf_get_width (pixbuf), + gdk_pixbuf_get_height (pixbuf), + retval, 1, 1); + + return retval; +} + +static GdkPixbuf * +remove_shaped_area (GdkPixbuf *pixbuf, + Window window) +{ + Display *display; + GdkPixbuf *retval; + XRectangle *rectangles; + gint rectangle_count, rectangle_order; + gint i; + + retval = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, + gdk_pixbuf_get_width (pixbuf), + gdk_pixbuf_get_height (pixbuf)); + + gdk_pixbuf_fill (retval, 0); + + display = gdk_x11_display_get_xdisplay (gdk_display_get_default ()); + + rectangles = XShapeGetRectangles (display, window, ShapeBounding, + &rectangle_count, &rectangle_order); + + for (i = 0; i < rectangle_count; i++) + { + int y, x; + + for (y = rectangles[i].y; + y < rectangles[i].y + rectangles[i].height; + y++) + { + const guchar *src_pixels; + guchar *dest_pixels; + + src_pixels = gdk_pixbuf_get_pixels (pixbuf) + + y * gdk_pixbuf_get_rowstride (pixbuf) + + rectangles[i].x * (gdk_pixbuf_get_has_alpha (pixbuf) ? 4 : 3); + + dest_pixels = gdk_pixbuf_get_pixels (retval) + + y * gdk_pixbuf_get_rowstride (retval) + + rectangles[i].x * 4; + + for (x = rectangles[i].x; + x < rectangles[i].x + rectangles[i].width; + x++) + { + *dest_pixels++ = *src_pixels ++; + *dest_pixels++ = *src_pixels ++; + *dest_pixels++ = *src_pixels ++; + *dest_pixels++ = 255; + + if (gdk_pixbuf_get_has_alpha (pixbuf)) + src_pixels++; + } + } + } + + return retval; +} + +static GdkPixbuf * +take_window_shot (Window child, + gboolean include_decoration) +{ + GdkDisplay *display; + GdkScreen *screen; + GdkWindow *window; + Window xid; + gint x_orig, y_orig; + gint x = 0, y = 0; + gint width, height; + GdkPixbuf *tmp, *tmp2; + GdkPixbuf *retval; + + display = gdk_display_get_default (); + screen = gdk_screen_get_default (); + + if (include_decoration) + xid = find_toplevel_window (gdk_x11_display_get_xdisplay (display), child); + else + xid = child; + + window = gdk_x11_window_foreign_new_for_display (display, xid); + + width = gdk_window_get_width (window); + height = gdk_window_get_height (window); + gdk_window_get_origin (window, &x_orig, &y_orig); + + if (x_orig < 0) + { + x = - x_orig; + width = width + x_orig; + x_orig = 0; + } + + if (y_orig < 0) + { + y = - y_orig; + height = height + y_orig; + y_orig = 0; + } + + if (x_orig + width > gdk_screen_get_width (screen)) + width = gdk_screen_get_width (screen) - x_orig; + + if (y_orig + height > gdk_screen_get_height (screen)) + height = gdk_screen_get_height (screen) - y_orig; + + tmp = gdk_pixbuf_get_from_drawable (NULL, window, NULL, + x, y, 0, 0, width, height); + + if (include_decoration) + tmp2 = remove_shaped_area (tmp, xid); + else + tmp2 = add_border_to_shot (tmp); + + retval = create_shadowed_pixbuf (tmp2); + + g_object_unref (tmp); + g_object_unref (tmp2); + + return retval; +} + +static gboolean +shooter_get_foreground (GimpRGB *color) +{ + color->r = color->g = color->b = 0.0; + color->a = 1.0; + return TRUE; +} + +static gboolean +shooter_get_background (GimpRGB *color) +{ + color->r = color->g = color->b = 1.0; + color->a = 1.0; + return TRUE; +} + +static void +shooter_standard_help (const gchar *help_id, + gpointer help_data) +{ +} + +static void +shooter_ensure_modules (void) +{ + static GimpModuleDB *module_db = NULL; + + if (! module_db) + { + gchar *config = gimp_config_build_plug_in_path ("modules"); + gchar *path = gimp_config_path_expand (config, TRUE, NULL); + + module_db = gimp_module_db_new (FALSE); + gimp_module_db_load (module_db, path); + + g_free (path); + g_free (config); + } +} + +int +main (int argc, char **argv) +{ + GdkPixbuf *screenshot = NULL; + GList *toplevels; + GList *node; + + g_set_application_name ("GIMP documentation shooter"); + + /* If there's no DISPLAY, we silently error out. + * We don't want to break headless builds. + */ + if (! gtk_init_check (&argc, &argv)) + return EXIT_SUCCESS; + + gtk_rc_add_default_file (gimp_gtkrc ()); + + units_init (); + + gimp_widgets_init (shooter_standard_help, + shooter_get_foreground, + shooter_get_background, + shooter_ensure_modules); + + toplevels = get_all_widgets (); + + for (node = toplevels; node; node = g_list_next (node)) + { + GdkWindow *window; + WidgetInfo *info; + XID xid; + gchar *filename; + + info = node->data; + + gtk_widget_show (info->window); + + window = gtk_widget_get_window (info->window); + + gtk_widget_show_now (info->window); + gtk_widget_queue_draw (info->window); + + while (gtk_events_pending ()) + { + gtk_main_iteration (); + } + sleep (1); + + while (gtk_events_pending ()) + { + gtk_main_iteration (); + } + + xid = gdk_x11_drawable_get_xid (GDK_DRAWABLE (window)); + screenshot = take_window_shot (xid, info->include_decorations); + + filename = g_strdup_printf ("%s.png", info->name); + gdk_pixbuf_save (screenshot, filename, "png", NULL, NULL); + g_free(filename); + + gtk_widget_hide (info->window); + } + + return EXIT_SUCCESS; +} |