ccairogtk4

How to take screenshot in gtk4?


I am trying to take a screenshot of the root window in gtk4. This is how I do it in gtk3--

      GdkWindow *root_win = gdk_get_default_root_window();
      gint width = gdk_window_get_width(root_win);
      gint height = gdk_window_get_height(root_win);

      cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
      width, height);
      /*.........................*/

      cairo_surface_write_to_png(surface, "image.png");

But gdk_get_default_root_window function has been removed in gtk4. How to take a screen shot in Gtk4? Please do not recommend x11.


For reference, with GTK 2 & 3 without Cairo:

    GdkPixbuf *image = NULL;
    int width = 0, height = 0;

    #if GTK_CHECK_VERSION (4,0,0)
        width = gtk_widget_get_width (window);
        height = gtk_widget_get_height (window);
        GtkSnapshot *snapshot = gtk_snapshot_new (); // ?
        // @todo
    #elif GTK_CHECK_VERSION (3,0,0)
        GdkWindow *root = gtk_widget_get_window (window);
        gtk_window_get_size (GTK_WINDOW (window), &width, &height);
        image = gdk_pixbuf_get_from_window (root, 0, 0, width, height);
    #else // GTK 2
        GdkWindow *root = gtk_widget_get_window (window);
        gtk_window_get_size (GTK_WINDOW (window), &width, &height);
        image = gdk_pixbuf_get_from_drawable (NULL, root, 
            gdk_colormap_get_system (), 0, 0, 0, 0, width, height);
    #endif

    gdk_pixbuf_save (image, "demo.png", "png", NULL, "compression", "9", NULL);
    g_object_unref (image);

Solution

  • Since this question existed, I have repeatedly occupied myself with it, because I am also very interested in it. I have gained support here. https://discourse.gnome.org/t/gtk4-screenshot-with-gtksnapshot/27981/3?u=holger The problem is to get a "own" GtkSnapshot, which can then be converted into a GskTexture and printed out accordingly. It is important that the GtkWidget is already drawn.

    In this example, I was guided by a contribution from April 2020. https://blog.gtk.org/

    
    #include<gtk/gtk.h>
    
    /* This is the important part */
    void demo_snapshot(GtkWidget *widget, GtkSnapshot *snapshot);
    
    void custom_snapshot(GtkWidget *widget) {
        GtkSnapshot *snapshot = gtk_snapshot_new();
        
            demo_snapshot(widget, snapshot);
    
        int w = gtk_widget_get_width(widget);
        int h = gtk_widget_get_height(widget);
    
            GskRenderNode *node = gtk_snapshot_free_to_node (snapshot);
        GskRenderer *renderer = gtk_native_get_renderer (gtk_widget_get_native (widget));
        GdkTexture *texture = gsk_renderer_render_texture (renderer,
                                           node,
                                           &GRAPHENE_RECT_INIT (0, 0, w,h ));
        gdk_texture_save_to_png (texture, "screenshot.png");
    
    };
    
    /* From here the GtkWidget to be printed begins*/
    
    #define MY_TYPE_WIDGET (my_widget_get_type())
    G_DECLARE_FINAL_TYPE (MyWidget, my_widget, MY, WIDGET, GtkWidget)
    
    GtkWidget *my_widget_new();
    
    /*********************************/
    
    struct _MyWidget
    {
        GtkWidget parent_instance;
    };
    
    struct _MyWidgetClass
    {
        GtkWidgetClass parent_class;
    };
    
    G_DEFINE_TYPE(MyWidget, my_widget, GTK_TYPE_WIDGET)
    
    
    void
    demo_snapshot (GtkWidget *widget, GtkSnapshot *snapshot)
    {
      GdkRGBA red, green, yellow, blue;
      float w, h;
    
      gdk_rgba_parse (&red, "red");
      gdk_rgba_parse (&green, "green");
      gdk_rgba_parse (&yellow, "yellow");
      gdk_rgba_parse (&blue, "blue");
    
      w = gtk_widget_get_width (widget) / 2.0;
      h = gtk_widget_get_height (widget) / 2.0;
    
      gtk_snapshot_append_color (snapshot, &red,
                                 &GRAPHENE_RECT_INIT(0, 0, w, h));
      gtk_snapshot_append_color (snapshot, &green,
                                 &GRAPHENE_RECT_INIT(w, 0, w, h));
      gtk_snapshot_append_color (snapshot, &yellow,
                                 &GRAPHENE_RECT_INIT(0, h, w, h));
      gtk_snapshot_append_color (snapshot, &blue,
                                 &GRAPHENE_RECT_INIT(w, h, w, h));
    }
    
    
    static void click_cb (GtkGestureClick *gesture,
                          int              n_press,
                          double           x,
                          double           y)
    {
      GtkEventController *controller = GTK_EVENT_CONTROLLER (gesture);
      GtkWidget *widget = gtk_event_controller_get_widget (controller);
    
      custom_snapshot(widget);
    
      if (x < gtk_widget_get_width (widget) / 2.0 &&
          y < gtk_widget_get_height (widget) / 2.0)
         g_print ("red!\n");
      else if  (x > gtk_widget_get_width (widget) / 2.0 &&
          y > gtk_widget_get_height (widget) / 2.0)
          g_print ("blue!\n");
      else if  (x > gtk_widget_get_width (widget) / 2.0 &&
          y < gtk_widget_get_height (widget) / 2.0)
          g_print ("green!\n");
      else if  (x < gtk_widget_get_width (widget) / 2.0 &&
          y > gtk_widget_get_height (widget) / 2.0)
          g_print ("yellow!\n");
    };
    
    void
    demo_measure (GtkWidget      *widget,
                  GtkOrientation  orientation,
                  int             for_size,
                  int            *minimum_size,
                  int            *natural_size,
                  int            *minimum_baseline,
                  int            *natural_baseline)
    {
      *minimum_size = 100;
      *natural_size = 200;
    };
    
    
    static void my_widget_dispose(GObject *gobject)
    {
        MyWidget *self = MY_WIDGET(gobject);
        G_OBJECT_CLASS (my_widget_parent_class)->dispose (gobject);
    };
    
    static void my_widget_class_init (MyWidgetClass *class)
    {
        G_OBJECT_CLASS(class)->dispose = my_widget_dispose;
        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
        // no layout manager necessary here
        widget_class->snapshot = demo_snapshot;
        widget_class->measure = demo_measure;   
    
    };
    
    static void my_widget_init (MyWidget *self)
    {
       
          GtkGesture *controller = gtk_gesture_click_new ();
              g_signal_connect_object (controller, "pressed",             
                                G_CALLBACK (click_cb), NULL,G_CONNECT_DEFAULT);
              gtk_widget_add_controller (GTK_WIDGET(self), GTK_EVENT_CONTROLLER(controller));
    };
    
    GtkWidget *my_widget_new()
    {
        MyWidget *self;
        self = g_object_new(MY_TYPE_WIDGET,NULL);
        return GTK_WIDGET (self);
    };
    
    /************************************************************/
    
    static void activate (GtkApplication *app, gpointer user_data)
    {
        GtkWidget *window;
        window = gtk_application_window_new(app);
        GtkWidget *widget = my_widget_new();
        gtk_window_set_child(GTK_WINDOW(window),GTK_WIDGET(widget));
        gtk_window_present(GTK_WINDOW (window));
    
    };
    
    int main (int argc, char **argv)
    {
        GtkApplication *app;
        int status;
    
        app = gtk_application_new("org.gtk.mywidget",
                G_APPLICATION_DEFAULT_FLAGS);
        g_signal_connect(app, "activate", G_CALLBACK(activate),NULL);
        status = g_application_run (G_APPLICATION(app), argc, argv);
        g_object_unref(app);
        return status;
    }
    

    enter image description here

    Have fun trying.