Taking a screenshot with C\GTK - c

I'm trying to take a screenshot of the entire screen with C and GTK. I don't want to make a call to an external application for speed reasons. I've found Python code for this (Take a screenshot via a python script. [Linux]); I just need to figure out how to do that in C.

After looking at the GNOME-Screenshot code and a Python example, I came up with this:
GdkPixbuf * get_screenshot(){
GdkPixbuf *screenshot;
GdkWindow *root_window;
gint x_orig, y_orig;
gint width, height;
root_window = gdk_get_default_root_window ();
gdk_drawable_get_size (root_window, &width, &height);
gdk_window_get_origin (root_window, &x_orig, &y_orig);
screenshot = gdk_pixbuf_get_from_drawable (NULL, root_window, NULL,
x_orig, y_orig, 0, 0, width, height);
return screenshot;
}
Which seems to work perfectly. Thanks!

9 years passed and as mentioned above API is removed.
As far as I understand, currently the bare minimum to do this at Linux is:
GdkWindow * root;
GdkPixbuf * screenshot;
gint x, y, width, height;
root = gdk_get_default_root_window ();
gdk_window_get_geometry (root, &x, &y, &width, &height);
screenshot = gdk_pixbuf_get_from_window (root, x, y, width, height);
// gdk_pixbuf_save...
This is very slightly tested and may fail. Further reading is in gnome-screenshooter repo

Related

Possible to export GtkWidget cairo_t drawing to vector image format (svg)?

I have found an application (ufsm/ufsm-compose), which uses Cairo internally, to allow for vector drawing in the application GUI canvas.
I'd like to try to export the canvas drawing as a vector image - primarily SVG - with minimal changes to the program, however, I'm not sure whether it is possible.
This application uses gtk_drawing_area_new to instantiate a GtkWidget (ufsmm_canvas_new in ufsm-compose/controller.c), and then a draw_cb callback is made to run on draw event - similar to the approach here:
https://zetcode.com/gfx/cairo/basicdrawing/
Then, draw_cb "automagically" receives a reference to cairo_t, and uses that in calls to rendering functions, that use typical cairo_rectangle etc draw commands (see ufsmm_canvas_render in ufsm-compose/render.c).
However, I'm not really sure whether I can export these drawings somehow in a vector image (SVG). For instance, on this page:
https://www.cairographics.org/manual/cairo-SVG-Surfaces.html
... I can see that for SVG, one should call cairo_svg_surface_create - however, the ufsm-compose application does not use this command (in fact, there is no mention of the word "surface" anywhere in the ufsm-compose code -- which, otherwise, figures also in say cairo_image_surface_create (https://www.cairographics.org/tutorial/) which is used for bitmap images).
So, what are my options in exporting this drawing as an SVG (or other vector format)? Could I get away with instantiating a cairo_svg_surface_create upon export command, then somehow copying the application canvas' cairo_t to this SVG, and then finally save the SVG? If so - how exactly do I do this - can a full example be found on the Internet?
Could I get away with instantiating a cairo_svg_surface_create upon export command, then somehow copying the application canvas' cairo_t to this SVG, and then finally save the SVG? If so - how exactly do I do this - can a full example be found on the Internet?
Looking at the code of the draw_cb, one finds:
struct ufsmm_canvas *priv =
g_object_get_data(G_OBJECT(widget), "canvas private");
gint width, height;
GtkAllocation allocation;
gtk_widget_get_allocation(widget, &allocation);
width = allocation.width;
height = allocation.height;
priv->cr = cr;
//priv->menu->cr = cr;
priv->window_width = width;
priv->window_height = height;
ufsmm_canvas_render(priv, width, height);
ufsmm_nav_render(priv, width, height);
//menu_render(priv->menu, priv->theme, priv->selection, width, height);
uc_status_render(priv, width, height);
So, apparently, the state of the application is kept in a struct ufsmm_canvas. When you have such a canvas, you have to decide on a size of your drawing and then there are just three functions to call to do the drawing.
So, to export the drawing, one could do (completely untested):
void export_drawing(struct ufsmm_canvas *priv, int width, int height, const char* filename) {
cairo_surface_t *surface = cairo_svg_surface_create(filename, width, height);
cairo_t *cr = cairo_create(surface);
priv->cr = cr;
priv->window_width = width;
priv->window_height = height;
ufsmm_canvas_render(priv, width, height);
ufsmm_nav_render(priv, width, height);
//menu_render(priv->menu, priv->theme, priv->selection, width, height);
uc_status_render(priv, width, height);
cairo_destroy(cr);
cairo_destroy(surface);
}
EDIT: here is a tested version, along with a quick-n-dirty hack, so svg image always gets exported upon a save command:
#include <cairo-svg.h>
...
void export_drawing(struct ufsmm_canvas *priv, int width, int height) {
printf("export_drawing ufsm_out.svg ...\n");
cairo_surface_t *surface = cairo_svg_surface_create("ufsm_out.svg", width, height);
cairo_t *cr = cairo_create(surface);
cairo_t *old_cr = priv->cr;
priv->cr = cr;
ufsmm_canvas_render(priv, width, height);
cairo_destroy(cr);
cairo_surface_destroy(surface);
priv->cr = old_cr;
printf("export_drawing DONE\n");
}
void canvas_save(void *context)
{
struct ufsmm_canvas *priv = (struct ufsmm_canvas *) context;
if (priv->model->filename == NULL) {
canvas_save_as(context);
} else {
L_DEBUG("%s: writing to '%s'", __func__, priv->model->filename);
remove_dangling_guard_refs(priv);
ufsmm_model_write(priv->model->filename, priv->model);
uc_rstatus_set(false);
}
export_drawing(priv, priv->window_width, priv->window_height);
}

How can I use g_idle_add() to get window size?

I am trying to get window size after application the window is drawn and full screen I dont want a default 200x200 size. This article suggests using g_idle_add().
gpointer data;
int width, height;
void get_sizes()
{
gtk_window_get_size((GtkWindow*)window, &width, &height);
printf("Sizes:\t%i × %i\n", width, height);
}
I ran g_idle_add((GSourceFunc)get_sizes, data); after gtk_window_present(); The function get_sizes keeps looping endlessly what am i doing wrong?

saving gtk window position

I'm trying to save the gtk window position(absolute) to restore it wehn I open the applicaiton again
here's my code so far:
gint x,y;
gtk_window_get_position(main_window,&x,&y);
printf("current position is:\nx: %i\ny:%i\n",x,y);
this code runs when the application exits, I always get:
current position is:
x: 0
y:0
What am I doing wrong.
gtk_window_get_position usually does a best guess but you cannot rely on it because
the X Window System does not specify a way to obtain the geometry of
the decorations placed on a window by the window manager.
(from gtk_window_get_position reference)
To see the function in action, try something like below:
#include <gtk/gtk.h>
int main(int argv, char* argc[])
{
GtkWidget *window, *button;
gint x, y;
gtk_init(&argv, &argc);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Test Window");
button = gtk_button_new_with_label("Close");
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(gtk_main_quit), (gpointer)NULL);
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
gtk_container_add(GTK_CONTAINER(window), button);
gtk_window_get_position(GTK_WINDOW(window), &x, &y);
printf("current position is:\nx: %i\ny:%i\n", x, y);
gtk_window_set_position(GTK_WINDOW(window),
GTK_WIN_POS_CENTER_ALWAYS);
gtk_window_get_position(GTK_WINDOW(window), &x, &y);
printf("new position is:\nx: %i\ny:%i\n", x, y);
gtk_widget_show_all(window);
gtk_main();
}
Edit
If you wish the window to appear at a specific location, you could try something like:
gtk_window_move(GTK_WINDOW(window), 420, 180);
However the above function should be placed after
gtk_widget_show_all(window);
because
most window managers ignore requests for initial window positions
(instead using a user-defined placement algorithm) and honor requests
after the window has already been shown.
(from gtk_window_move reference)
I've just implemented this feature using pygobject; it's not C but it could still be useful to have a look at it.
You can find the code here.
I've used GNOME Builder's default template for a python GNOME application, so it should be super-easy to replicate if you set your project with it.

How to draw directly on the desktop?

I'm wondering how to draw directly on the root window in an X11 environment with Cairo (in C), in order to make widgets. I've copied some parts of the code of tint2, but it's quite enormous, and the only result I have is not satisfying.
I would be pleased to have a complete working sample code, or at least some tips or little programs to study.
Thank you guys !
The "bottom" window is the root window. The problem is that in some desktop environments we have windows on top of the root window, so if you change the root window, you won't see your changes: you need to change the window that's on the top.
This program does what you ask for: draw on the root window. To test it, I suggest you to:
ctrl+alt+f1
login as root
stop your desktop environment ("/etc/init.d/gdm stop", "/etc/init.d/kdm stop" or whatever is needed in your distro)
X -noreset -retro &
DISPLAY=:0.0 xterm &
DISPLAY=:0.0 metacity &
Then, go back to X (ctrl+alt+f7 or maybe f8) and run the program.
If you want to draw on Nautilus' top window, you will need to find out its window ID and then use it as the "w" variable. The "xwininfo" command might help you testing...
#include <assert.h>
#include <stdio.h>
#include <X11/Xlib.h>
#include <cairo.h>
#include <cairo-xlib.h>
int width, height;
void draw(cairo_t *cr) {
int quarter_w = width / 4;
int quarter_h = height / 4;
cairo_set_source_rgb(cr, 1.0, 0.0, 0.0);
cairo_rectangle(cr, quarter_w, quarter_h, quarter_w * 2, quarter_h * 2);
cairo_fill(cr);
}
int main() {
Display *d = XOpenDisplay(NULL);
assert(d);
int s = DefaultScreen(d);
Window w = RootWindow(d, s);
width = DisplayWidth(d, s);
height = DisplayHeight(d, s);
cairo_surface_t *surf = cairo_xlib_surface_create(d, w,
DefaultVisual(d, s),
width, height);
cairo_t *cr = cairo_create(surf);
XSelectInput(d, w, ExposureMask);
draw(cr);
XEvent ev;
while (1) {
XNextEvent(d, &ev);
printf("Event!\n");
if (ev.type == Expose) {
draw(cr);
}
}
cairo_destroy(cr);
cairo_surface_destroy(surf);
XCloseDisplay(d);
return 0;
}

How to stretch a bitmap in C and SDL?

I am making a game for my CS class and the sprites I have found online are too small. How do you 'stretch' a bitmap... make them bigger using SDL? (I need to increase there size 50%, there all the same size.) A snippet of example code would be appreciated.
This question does not specify SDL version, and even though SDL2 was not available when the question was written, an SDL2 answer would add completeness here i believe.
Unlike SDL1.2, scaling is possible in SDL2 using the API method SDL_RenderCopyEx. No additional libs besides the basic SDL2 lib are needed.
int SDL_RenderCopyEx(SDL_Renderer* renderer,
SDL_Texture* texture,
const SDL_Rect* srcrect,
const SDL_Rect* dstrect,
const double angle,
const SDL_Point* center,
const SDL_RendererFlip flip)
By setting the size of dstrect one can scale the texture to an integer number of pixels. It is also possible to rotate and flip the texture at the same time.
Reference: https://wiki.libsdl.org/SDL_RenderCopyEx
Create your textures as usual:
surface = IMG_Load(filePath);
texture = SDL_CreateTextureFromSurface(renderer, surface);
And when it's time to render it, call SDL_RenderCopyEx instead of SDL_RenderCopy
You're going to get a better looking result using software that is designed for this task. A good option is ImageMagick. It can be used from the command line or programatically.
For example, from the command line you just enter:
convert sprite.bmp -resize 150% bigsprite.bmp
If for some strange reason you want to write your own bilinear resize, this guy looks like he knows what he is doing.
have you tried?
SDL_Rect src, dest;
src.x = 0;
src.y = 0;
src.w = image->w;
src.h = image->h;
dest.x = 100;
dest.y = 100;
dest.w = image->w*1.5;
dest.h = image->h*1.5;
SDL_BlitSurface(image, &src, screen, &dest);
Use for stretch the undocumented function of SDL:
extern DECLSPEC int SDLCALL SDL_SoftStretch(SDL_Surface *src, SDL_Rect *srcrect,
SDL_Surface *dst, SDL_Rect *dstrect);
Like:
SDL_SoftStretch(image, &src, screen, &dest);

Resources