How to create a GtkImage from a Cairo context? - gtk

I got a paint function that works using a Cairo context and the end result should be a GtkImage (without intermediate image creation). I tried to use the gdk_cairo_create function but this code:
...
GdkPixbuf *pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, 22, 22);
GtkWidget *image = gtk_image_new_from_pixbuf (pixbuf);
GdkDrawable *drawable = image->window;
cairo_t *ctx = gdk_cairo_create (drawable);
my_cairo_paint_function (ctx);
...
fails with:
Gdk-CRITICAL **: IA__gdk_cairo_create: assertion `GDK_IS_DRAWABLE (drawable)' failed
Same with a simple:
#include <gtk/gtk.h>
#include <cairo.h>
int
main (int argc, char *argv[])
{
gtk_init(&argc, &argv);
cairo_t *ctx = gdk_cairo_create (gtk_widget_get_window (gtk_image_new_from_file ("foobar.png")));
gtk_main();
return 0;
}
I don't understand why this fails. Any help is appreciated!

GtkImage doesn't have a GdkWindow, so the call to gtk_widget_get_window() or the access of widget->window returns NULL. You can put the GtkImage in a GtkEventBox and draw on the event box's GdkWindow.
Although, it looks like you're trying (with gdk_pixbuf_new) to create an empty space to draw on. In that case, GtkImage is not the widget you want -- use GtkDrawingArea. And don't forget to call your paint function in the handler for the event-expose signal!

Related

GTK+3 in C lang: how to set MAXIMUM length of ProgressBar?

I'm totally in trouble. Wanna set maximum width of progressbar, but the only thing I found is min- properties, that can be set through CSS. What else can I do?
As you probably have found out through research, the CSS "max-width" property is not a property currently handled via the GTK CSS provider. In testing out various scenarios with a progress bar, it seems that the constricting factor is the width allowances of the various GTK containers. And, the only container that appeared to allow for adjusting the width of a progress bar was within a "GtkBox" container. Following is a minimal program I composed to test out various widths for a progress bar (FYI, this is GTK3).
#include <gtk/gtk.h>
int main (int argc, char *argv[])
{
GtkWidget *prog = NULL;
GtkWidget *win = NULL;
GtkWidget *box = NULL;
gtk_init (&argc, &argv);
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
prog = gtk_progress_bar_new();
gtk_window_set_title (GTK_WINDOW (win), "Progress Max");
gtk_container_set_border_width (GTK_CONTAINER (win), 20);
gtk_window_set_default_size(GTK_WINDOW(win), 400, 120);
g_signal_connect (win, "destroy", gtk_main_quit, NULL);
gtk_container_add (GTK_CONTAINER (win), box);
gtk_widget_set_size_request(prog, 200, 20); /* Vary the length to test the effect */
gtk_box_pack_start(GTK_BOX(box), prog, FALSE, TRUE, 40);
gtk_widget_show_all (win);
gtk_main ();
return 0;
}
Make note of the size values in the "gtk_widget_set_size_request" function to determine your progress bar width, and note the boolean values for the "fill" and "padding" parameters in the "gtk_box_pack_start" function. I believe that if you experiment with those statements that you should be able to control the desired width of your progress bar.
Regards.

Segfault when calling gtk_drawing_area_new

I have just a simple program
#include <gtk/gtk.h>
int main() {
GtkWidget * drawingarea = gtk_drawing_area_new(); // <-- Segfault
return 0;
}
which just creates a drawing area. But it segfaults. Why? I'm using ubuntu 18.04.
Using gtk_init before the call to gtk_drawing_area_new solves this problem.

What could be wrong: GLib-GObject-WARNING **: cannot register existing type 'PangoCairoFont'

I spent many weeks trying to get gtk+ 3.22 to build on Visual Studio 2015. Finally I got it built but the small GUI program failed to initialize gtk. The error is shown as below:
gtk+_gtk_test.exe:15980): Gtk-WARNING **: Could not find the icon 'window-minimize-symbolic-ltr'. The 'hicolor' theme
was not found either, perhaps you need to install it.
You can get a copy from:
http://icon-theme.freedesktop.org/releases
(gtk+_gtk_test.exe:15980): GLib-GObject-WARNING **: cannot register existing type 'PangoCairoFont'
(gtk+_gtk_test.exe:15980): GLib-GObject-CRITICAL **: g_type_interface_add_prerequisite: assertion 'G_TYPE_IS_INTERFACE (interface_type)' failed
(gtk+_gtk_test.exe:15980): Glib-CRITICAL **: g_once_init_leave: assertion 'result != 0' failed
The first warning exists because the executable cannot locate the icon files. I have already figured out how to fix this. However, I am unable to get the second Warning fixed. This is my first gtk+ project. When I debug the code, it seems that PangoCairoFont type failed because of the existence of PangoCairoWin32Font type.
What could be wrong here? Appreciate your advice.
Source code of the program:
#include <gtk/gtk.h>
void hello(GtkWidget *widget, gpointer data)
{
g_print("Hello, World\n");
}
gint delete_event(GtkWidget *widget, GdkEvent event, gpointer data)
{
/* when this fucntion returns FALSE, the delete-event
signal becomes a destroy signal*/
return FALSE;
}
void end_program(GtkWidget *widget, gpointer data)
{
/* End the main loop */
gtk_main_quit();
}
int main(int argc, char **argv)
{
GtkWindow *window;
GtkButton *button;
/* initialize Gtk+ */
gtk_init(&argc, &argv);
/* create window, set default height and width to 200px */
window = g_object_new(GTK_TYPE_WINDOW,
"default-height", 200,
"default-width", 200,
"border-width", 12,
"title", "GtkHello",
NULL);
/* add signal handlers for window */
g_signal_connect(window, "delete-event", G_CALLBACK(delete_event),
NULL);
g_signal_connect(window,
"destroy", G_CALLBACK(end_program),
NULL);
/* create button */
button = g_object_new(GTK_TYPE_BUTTON,
"label", "_Hello, World!\nClick here.",
"use-underline", TRUE,
NULL);
g_signal_connect(button,
"clicked", G_CALLBACK(hello),
NULL);
g_signal_connect_swapped(button,
"clicked", G_CALLBACK(gtk_widget_destroy),
window);
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(button));
gtk_widget_show_all(GTK_WIDGET(window));
/* start main loop */
gtk_main();
return 0;
}
I figured out. I mistakenly built pangocairo module into a static lib instead of DLL. This lib is further linked into different DLLs so the global variable has several copies, which caused the problem.

GTK+ and GdkPixbuf

I think I've got an understanding problem of GTK. My simple application has a stream of images and I'd like to display them within my GTK Window. Up to now, it looks like this:
GdkPixbuf *pb = gdk_pixbuf_new_from_data(img2, GDK_COLORSPACE_RGB,
FALSE, 24/3, 320, 240, 320*3,
NULL, NULL);
if(pb == NULL)
fprintf(stderr, "Pixbuf is null!\n");
if(image != NULL)
gtk_container_remove(GTK_CONTAINER(window), image);
image = gtk_image_new_from_pixbuf(pb);
gtk_container_add(GTK_CONTAINER(window), image);
printf("Updated!\n");
img2 is my (rgb) buffer that gets updated from a stream each time. I guess gtk_container_remove and gtk_container_add might be stupid to use for this?
Here's what I've got in addition:
GtkWidget *window;
GtkWidget *image;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_signal_connect(GTK_OBJECT(window), "destroy",
GTK_SIGNAL_FUNC(destroy), NULL);
/* ... */
start_routine_for_stream_that_calls_the_above(...)
/* ... */
gtk_widget_show_all(window);
gtk_main();
My problem is that it's not working this way... either I see only the last GdkPixbuf image or I see none, which is the correct behaviour ...
But how do I manage it to show an (stream of) updated GdkPixbuf?
Thanks for help
You need to be running the main loop while you change the images. For instance, you can do gtk_main() and use g_timeout_add() to schedule your callback to run say every second and replace images within that callback.

How do I change the colors of an arbitrary widget in GTK+?

If I'm writing an application that wants to communicate some information through the use of color, how can I change the background and foreground colors of a given widget? I would like to know how to do this in glade if it's possible, as well as programmatically (to a computed color).
I want to know how to do this to a complex widget as well, for example, an HBox that contains a VBox that contains some Labels.
Ideally this would also include a solution solution that allows me to tint the widget's existing colors, and identify the average colors of any images in use by the theme, so that I can programmatically compensate for any color choices which might make text unreadable or otherwise clashing - but I would be happy if I could just turn a button red.
Example program:
#include <gtk/gtk.h>
static void on_destroy(GtkWidget* widget, gpointer data)
{
gtk_main_quit ();
}
int main (int argc, char* argv[])
{
GtkWidget* window;
GtkWidget* button;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT (window), "destroy",
G_CALLBACK (on_destroy), NULL);
button = gtk_button_new_with_label("Hello world!");
GdkColor red = {0, 0xffff, 0x0000, 0x0000};
GdkColor green = {0, 0x0000, 0xffff, 0x0000};
GdkColor blue = {0, 0x0000, 0x0000, 0xffff};
gtk_widget_modify_bg(button, GTK_STATE_NORMAL, &red);
gtk_widget_modify_bg(button, GTK_STATE_PRELIGHT, &green);
gtk_widget_modify_bg(button, GTK_STATE_ACTIVE, &blue);
gtk_container_add(GTK_CONTAINER(window), button);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
The best documentation that I know of is the one available here: http://ometer.com/gtk-colors.html
You can always use gtk_widget_override_color () and gtk_widget_override_background_color (). These two functions allow you to change the color of a widget. But it is better to use CSS classes and regions in your widget/container implementation through gtk_style_context_add_class() and gtk_style_context_add_region().
To modify the color of a widget you can initialize a color and use it to modify the color of the widget:
GdkColor color;
gdk_color_parse("#00FF7F", &color);
gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &color);
To use an image instead of color:
GdkPixbuf *image = NULL;
GdkPixmap *background = NULL;
GtkStyle *style = NULL;
image = gdk_pixbuf_new_from_file ("background.jpg", NULL);
gdk_pixbuf_render_pixmap_and_mask (image, &background, NULL, 0);
style = gtk_style_new ();
style->bg_pixmap [0] = background;
gtk_widget_set_style (GTK_WIDGET(widget), GTK_STYLE (style));