Reputation: 61
GTK uses cairo for drawing. So I'm trying to create a hello world app that writes to an image (svg, png, ...) instead of X11. I'm facing 2 problems: - The image is empty - When starting without X11 running (which is the actual goal) I get the error "** (a.out:9021): WARNING **: Could not open X display"
The code is draft!
#include <string>
#include <iostream>
#include <thread>
#include <chrono>
#include <cmath>
#include <cairo.h>
#include <cairommconfig.h>
#include <cairomm/context.h>
#include <cairomm/surface.h>
#include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
GtkWidget *window;
GtkWidget *button;
// GtkWidget *main_window = gtk_initialize();
window = gtk_offscreen_window_new();
button = gtk_button_new_with_label ("Hello World");
gtk_container_add (GTK_CONTAINER (window), button);
gtk_widget_show (window);
GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(window));
std::cout << "gdk window: " << gdk_window << std::endl;
cairo_surface_t * surfp = gdk_offscreen_window_get_surface(gdk_window);
std::cout << "Created Window will now draw to png" << std::endl;
std::string filename = "image.svg";
double width = 600;
double height = 400;
Cairo::SvgSurface srfobj(surfp);
Cairo::RefPtr<Cairo::SvgSurface> refptr(&srfobj);
Cairo::RefPtr<Cairo::Context> cr = Cairo::Context::create(refptr);
cr->save(); // save the state of the context
cr->show_page();
std::cout << "Wrote SVG file \"" << filename << "\"" << std::endl;
std::chrono::milliseconds dura( 200 );
std::this_thread::sleep_for(dura);
return 0;
}
Upvotes: 1
Views: 1585
Reputation: 53
Here is my solution based on your example code - keep in mind it is a dirty solution and may not work using newer versions of GTK3. It works to save the UI of a window (only tested with the one button), but still requires (somewhere) a running X-server. It also ignores / don't use your settings for the picture size - you'll have to resize it at your own. I don't know if (and how) it is possible to cut this string (X-Server // X-Framebuffer) too (DirectFB seems not to be really supported anymore), but...
Have fun!
// Default
#include <string>
#include <iostream>
#include <thread>
#include <chrono>
// cairo / cairomm / gtk
#include <cairo.h>
#include <cairomm/context.h> //libcairomm-1.0-dev
#include <gtk/gtk.h>
int main(int argc, char *argv[]) {
// Init
gtk_init(&argc, &argv);
// Create window with a button
GtkWidget *window;
GtkWidget *button;
window = gtk_offscreen_window_new();
button = gtk_button_new_with_label("Hello World");
gtk_container_add(GTK_CONTAINER(window), button);
gtk_widget_show_all(window);
// Make a gdk window out of it, prepare cairo and draw it to it
GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window));
cairo_surface_t* surfp = gdk_offscreen_window_get_surface(gdk_window);
cairo_t* context = cairo_create(surfp);
gtk_widget_draw(GTK_WIDGET(window), context);
// Yay - begin the dump!
Cairo::SvgSurface srfobj(surfp);
std::string filename = "image.png";
srfobj.write_to_png(filename);
std::cout << "Done." << std::endl;
// Aaand a little sleep...
std::chrono::milliseconds dura(1000);
std::this_thread::sleep_for(dura);
return 0;
}
Upvotes: 2
Reputation: 5683
The answer to both your questions is that you cannot run GTK+ applications without some sort of output. You're using gtk-x11 which requires an XServer. You might have some luck with the DirectFB backend, but I wouldn't hold your breath as I don't know if it's even maintained anymore.
Because Gtk doesn't run without an XServer the resulting image is empty.
Upvotes: 1
Reputation: 6886
Upvotes: 1