When I'm resizing the GtkWindow, i want the GtkImage to resize as well while keeping the same aspect ratio as before.
I can't find any good examples on how to set this up with GTK3
This is what i've tried so far:
#include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
GtkAllocation *allocation = g_new0 (GtkAllocation, 1);
gboolean resize_image(GtkWidget *widget, GdkEvent *event, GtkWidget *window) {
GdkPixbuf *pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(widget));
if (pixbuf == NULL) {
g_printerr("Failed to resize image\n");
return 1;
}
gtk_widget_get_allocation(GTK_WIDGET(widget), allocation);
pixbuf = gdk_pixbuf_scale_simple(pixbuf, widget->allocation.width, widget->allocation.height, GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf(GTK_IMAGE(widget), pixbuf);
return FALSE;
}
int main(int argc, char **argv) {
GtkWidget *window = NULL;
GtkWidget *image = NULL;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
image = gtk_image_new_from_file("image.jpg");
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(image, "draw", G_CALLBACK(resize_image), (gpointer)window);
gtk_container_add(GTK_CONTAINER(window), image);
gtk_widget_show_all(GTK_WIDGET(window));
gtk_main();
return 0;
}
This code should just resize the Pixbuf to the size of the parent, but it doesn't work, i get these errors:
GdkPixbuf-CRITICAL **: gdk_pixbuf_get_width: assertion 'GDK_IS_PIXBUF
(pixbuf)' failed
GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT
(object)' failed
Even if this code would work, i wouldn't be able to keep the same aspect ratio, how to achieve this?
Thanks in Advance
Well, a trick to do this is using a GtkLayout between the image and the window.
Also, instead of using the draw signal, use the size-allocate signal.
We will load a GdkPixbuf and use it as reference for scaling, otherwise the quality would deteriorate with cumulative 'resizing'.
A simple approach would be:
#include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
struct _resize_widgets {
GtkWidget *image;
GdkPixbuf *pixbuf;
};
typedef struct _resize_widgets ResizeWidgets;
gboolean resize_image(GtkWidget *widget, GdkRectangle *allocation, gpointer user_data) {
int x,y,w,h;
GdkPixbuf *pxbscaled;
GtkWidget *image = (GtkWidget *) ((ResizeWidgets *) user_data)->image;
GdkPixbuf *pixbuf= (GdkPixbuf *) ((ResizeWidgets *) user_data)->pixbuf;
x = 0;
y = 0;
h = allocation->height;
w = (gdk_pixbuf_get_width(pixbuf) * h) / gdk_pixbuf_get_height(pixbuf);
pxbscaled = gdk_pixbuf_scale_simple(pixbuf, w, h, GDK_INTERP_BILINEAR);
if (w < allocation->width) {
x = (allocation->width - w) / 2;
gtk_layout_move(GTK_LAYOUT(widget), image, x, y);
}
gtk_image_set_from_pixbuf(GTK_IMAGE(image), pxbscaled);
g_object_unref (pxbscaled);
return FALSE;
}
int main(int argc, char **argv) {
GtkWidget *window = NULL;
GtkWidget *image = NULL;
GtkWidget *container = NULL;
GdkPixbuf *pixbuf = NULL;
ResizeWidgets *widgets;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
container = gtk_layout_new(NULL, NULL);
image = gtk_image_new();
pixbuf = gdk_pixbuf_new_from_file ("image.png", NULL);
if (pixbuf == NULL) {
g_printerr("Failed to resize image\n");
return 1;
}
widgets = g_new0(ResizeWidgets, 1);
widgets->image = image;
widgets->pixbuf = pixbuf;
gtk_container_add(GTK_CONTAINER(window), container);
gtk_layout_put(GTK_LAYOUT(container), image, 0, 0);
gtk_widget_set_size_request (GTK_WIDGET(window), 20, 20);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(container, "size-allocate", G_CALLBACK(resize_image), widgets);
gtk_widget_show_all(GTK_WIDGET(window));
gtk_main();
g_object_unref (pixbuf);
g_free(widgets);
return 0;
}
Compile with gcc -o main main.cpkg-config --cflags --libs gtk+-3.0`
This will keep aspect ratio. If that is not desired, then the resize_image callback handler would be:
gboolean resize_image(GtkWidget *widget, GdkRectangle *allocation, gpointer user_data) {
int x,y,w,h;
GdkPixbuf *pxbscaled;
GtkWidget *image = (GtkWidget *) ((ResizeWidgets *) user_data)->image;
GdkPixbuf *pixbuf= (GdkPixbuf *) ((ResizeWidgets *) user_data)->pixbuf;
pxbscaled = gdk_pixbuf_scale_simple(pixbuf, allocation->width, allocation->height, GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf(GTK_IMAGE(image), pxbscaled);
g_object_unref (pxbscaled);
return FALSE;
}
This is a simple hack, there are other options obviously, like cairo for drawing or simply checking Eye of Gnome (eog) implementation which is much more complete.
Related
I was wondering how to produce double clicks?
Take the following code that draws lines using single clicks http://zetcode.com/gfx/cairo/basicdrawing/:
#include <cairo.h>
#include <gtk/gtk.h>
static void do_drawing(cairo_t *);
struct {
int count;
double coordx[100];
double coordy[100];
} glob;
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
gpointer user_data)
{
do_drawing(cr);
return FALSE;
}
static void do_drawing(cairo_t *cr)
{
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_set_line_width(cr, 0.5);
int i, j;
for (i = 0; i <= glob.count - 1; i++ ) {
for (j = 0; j <= glob.count - 1; j++ ) {
cairo_move_to(cr, glob.coordx[i], glob.coordy[i]);
cairo_line_to(cr, glob.coordx[j], glob.coordy[j]);
}
}
glob.count = 0;
cairo_stroke(cr);
}
static gboolean clicked(GtkWidget *widget, GdkEventButton *event,
gpointer user_data)
{
if (event->button == 1) {
glob.coordx[glob.count] = event->x;
glob.coordy[glob.count++] = event->y;
}
if (event->button == 3) {
gtk_widget_queue_draw(widget);
}
return TRUE;
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *darea;
glob.count = 0;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER(window), darea);
gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK);
g_signal_connect(G_OBJECT(darea), "draw",
G_CALLBACK(on_draw_event), NULL);
g_signal_connect(window, "destroy",
G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(window, "button-press-event",
G_CALLBACK(clicked), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 400, 300);
gtk_window_set_title(GTK_WINDOW(window), "Lines");
gtk_widget_show_all(window);
gtk_main();
return 0;
}
How do I get this program to respond to double clicks events instead of the single clicks?
I cannot find it in this list https://lazka.github.io/pgi-docs/Gtk-3.0/classes/Button.html#Gtk.Button.signals.clicked.
From GdkEventButton:
For double-clicks the order of events will be:
GDK_BUTTON_PRESS
GDK_BUTTON_RELEASE
GDK_BUTTON_PRESS
GDK_2BUTTON_PRESS
GDK_BUTTON_RELEASE
Note that the first click is received just like a normal button press,
while the second click results in a GDK_2BUTTON_PRESS being received
just after the GDK_BUTTON_PRESS.
(...)
For a double click to occur, the second button press must occur within 1/4 of a second of the first.
Each GdkEvent has a GdkEventType field that you can check for GDK_2BUTTON_PRESS or GDK_DOUBLE_BUTTON_PRESS (alias added in 3.6):
a mouse button has been double-clicked (clicked twice within a short
period of time). Note that each click also generates a
GDK_BUTTON_PRESS event.
in button-press-event callback.
#include <gtk/gtk.h>
gboolean clicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
{
if(event->type == GDK_DOUBLE_BUTTON_PRESS)
printf("double\n");
return TRUE;
}
int main (int argc, char *argv[])
{
gtk_init (&argc, &argv);
GtkWidget *window;
GtkWidget *label;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
label = gtk_label_new("label");
gtk_container_add(GTK_CONTAINER(window), label);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK);
g_signal_connect(window, "button-press-event", G_CALLBACK(clicked), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 400, 300);
gtk_widget_show_all(window);
gtk_main ();
return 0;
}
I found the following GTK+3 code in Zetcode. It creates an animation using the cairo library while displaying an image:
#include <cairo.h>
#include <gtk/gtk.h>
/* compile with
*
* gcc spectrum.c -o spectrum `pkg-config --cflags --libs gtk+-3.0`
*
* */
static void do_drawing(cairo_t *);
struct {
gboolean timer;
cairo_surface_t *image;
cairo_surface_t *surface;
gint img_width;
gint img_height;
} glob;
static void init_vars()
{
glob.image = cairo_image_surface_create_from_png("beckov.png");
glob.img_width = cairo_image_surface_get_width(glob.image);
glob.img_height = cairo_image_surface_get_height(glob.image);
glob.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
glob.img_width, glob.img_height);
glob.timer = TRUE;
}
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
gpointer user_data)
{
do_drawing(cr);
return FALSE;
}
static void do_drawing(cairo_t *cr)
{
cairo_t *ic;
static gint count = 0;
ic = cairo_create(glob.surface);
gint i, j;
for (i = 0; i <= glob.img_height; i+=7) {
for (j = 0 ; j < count; j++) {
cairo_move_to(ic, 0, i+j);
cairo_line_to(ic, glob.img_width, i+j);
}
}
count++;
if (count == 8) glob.timer = FALSE;
cairo_set_source_surface(cr, glob.image, 10, 10);
cairo_mask_surface(cr, glob.surface, 10, 10);
cairo_stroke(ic);
cairo_destroy(ic);
}
static gboolean time_handler(GtkWidget *widget)
{
if (!glob.timer) return FALSE;
gtk_widget_queue_draw(widget);
return TRUE;
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *darea;
init_vars();
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER (window), darea);
g_signal_connect(G_OBJECT(darea), "draw",
G_CALLBACK(on_draw_event), NULL);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 325, 250);
gtk_window_set_title(GTK_WINDOW(window), "Spectrum");
g_timeout_add(400, (GSourceFunc) time_handler, (gpointer) window);
gtk_widget_show_all(window);
gtk_main();
cairo_surface_destroy(glob.image);
cairo_surface_destroy(glob.surface);
return 0;
}
I achieve exatly the same result if I remove the do_drawing() function and move its code to the on_draw_event(), like:
#include <cairo.h>
#include <gtk/gtk.h>
/* compile with
*
* gcc spectrum.c -o spectrum `pkg-config --cflags --libs gtk+-3.0`
*
* */
struct {
gboolean timer;
cairo_surface_t *image;
cairo_surface_t *surface;
gint img_width;
gint img_height;
} glob;
static void init_vars()
{
glob.image = cairo_image_surface_create_from_png("beckov.png");
glob.img_width = cairo_image_surface_get_width(glob.image);
glob.img_height = cairo_image_surface_get_height(glob.image);
glob.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
glob.img_width, glob.img_height);
glob.timer = TRUE;
}
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
gpointer user_data)
{
cairo_t *ic;
static gint count = 0;
ic = cairo_create(glob.surface);
gint i, j;
for (i = 0; i <= glob.img_height; i+=7) {
for (j = 0 ; j < count; j++) {
cairo_move_to(ic, 0, i+j);
cairo_line_to(ic, glob.img_width, i+j);
}
}
count++;
if (count == 8) glob.timer = FALSE;
cairo_set_source_surface(cr, glob.image, 10, 10);
cairo_mask_surface(cr, glob.surface, 10, 10);
cairo_stroke(ic);
cairo_destroy(ic);
return FALSE;
}
static gboolean time_handler(GtkWidget *widget)
{
if (!glob.timer) return FALSE;
gtk_widget_queue_draw(widget);
return TRUE;
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *darea;
init_vars();
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER (window), darea);
g_signal_connect(G_OBJECT(darea), "draw",
G_CALLBACK(on_draw_event), NULL);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 325, 250);
gtk_window_set_title(GTK_WINDOW(window), "Spectrum");
g_timeout_add(400, (GSourceFunc) time_handler, (gpointer) window);
gtk_widget_show_all(window);
gtk_main();
cairo_surface_destroy(glob.image);
cairo_surface_destroy(glob.surface);
return 0;
}
So... I wonder... Am I missing something here (loss of generality)?
Or was the call to do_drawing() in function on_draw_event() of the original code redundant?
Thanks
Yes. It's correct on compiler's side.
But it's a good practice for functions to solve exactly one task. do_drawing is busy with drawing lines and pixels, on_draw_event is busy with processing events. Probably in this code snippet there is no real reason to make a separate function, but usually on_draw_event would be much more complicated.
I'm new at GTK, and I was wondering how can I create a new window after a click button. I've got this function
void cb_create_entry(GtkWidget *, gpointer);
int create_window(int argc, char *argv[]){
GtkWidget *p_window = NULL;
GtkWidget *p_main_box = NULL;
GtkWidget *p_button[5];
gtk_init (&argc, &argv);
//Create window
p_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(p_window), "Hello");
gtk_window_set_default_size(GTK_WINDOW(p_window), 320, 200);
p_main_box = gtk_vbox_new(TRUE, 0);
gtk_container_add(GTK_CONTAINER(p_window), p_main_box);
{
p_button[0] = gtk_button_new_with_label("Create entry");
g_signal_connect(G_OBJECT(p_button[0]), "clicked",
G_CALLBACK(cb_create_entry), NULL);
gtk_box_pack_start(GTK_BOX(p_main_box), p_button[0], FALSE, FALSE, 0);
}
gtk_widget_show_all(p_window);
gtk_main ();
return EXIT_SUCCESS;
and callback.h
#ifndef CALLBACK_H_INCLUDED
#define CALLBACK_H_INCLUDED
#include <gtk/gtk.h>
void cb_create_entry(GtkWidget *p_widget, gpointer user_data){
gtk_button_released(p_widget);
GtkWidget *p_window;
GtkWidget *p_v_box;
GtkWidget *p_entry;
p_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(p_window), "Create DB");
gtk_window_set_default_size(GTK_WINDOW(p_window), 320, 200);
p_v_box = gtk_vbox_new(TRUE, 0);
gtk_container_add(GTK_CONTAINER(p_window), p_v_box);
p_entry = gtk_entry_new();
gtk_box_pack_start(GTK_BOX(p_v_box), p_entry, TRUE, FALSE, 0);
}
and main
int main(int argc, char const *argv[]) {
create_window(argc, argv);
return 0;
}
But it doesn't work. I'd like to create a new window with an input. But when I click on button, nothing happens.
I'm a bit confused on how you laid out your file structure. Since there's no input on that I'll assume that the file with create_window function is the same where you have main. Then, callback.h should not have implementation code.
Nevertheless, i don't see any gtk_widget_show or gtk_widget_show_all calls and not sure you suppressed or just missed them. I'll assume the later because by your description it seems that you can see the initial window.
It's also missing a call to gtk_main.
Adding GtkWidget show functions and gtk_main to your code, it does work like expected:
Lets call the first file main.c :
#include <gtk/gtk.h>
#include "callback.h"
void cb_create_entry(GtkWidget *, gpointer);
int create_window(int argc, char *argv[]){
GtkWidget *p_window = NULL;
GtkWidget *p_main_box = NULL;
GtkWidget *p_button[5];
gtk_init (&argc, &argv);
//Create window
p_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(p_window), "Hello");
gtk_window_set_default_size(GTK_WINDOW(p_window), 320, 200);
p_main_box = gtk_vbox_new(TRUE, 0);
gtk_container_add(GTK_CONTAINER(p_window), p_main_box);
p_button[0] = gtk_button_new_with_label("Create entry");
g_signal_connect(G_OBJECT(p_button[0]), "clicked",
G_CALLBACK(cb_create_entry), NULL);
gtk_box_pack_start(GTK_BOX(p_main_box), p_button[0], FALSE, FALSE, 0);
gtk_widget_show_all(p_window);
}
int main (int argc, char *argv[]) {
create_window(argc, argv);
gtk_main ();
return 0;
}
And the other file callbacks.h :
#include <gtk/gtk.h>
void cb_create_entry(GtkWidget *p_widget, gpointer user_data){
gtk_button_released(p_widget);
GtkWidget *p_window;
GtkWidget *p_v_box;
GtkWidget *p_entry;
p_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(p_window), "Create DB");
gtk_window_set_default_size(GTK_WINDOW(p_window), 320, 200);
p_v_box = gtk_vbox_new(TRUE, 0);
gtk_container_add(GTK_CONTAINER(p_window), p_v_box);
p_entry = gtk_entry_new();
gtk_box_pack_start(GTK_BOX(p_v_box), p_entry, TRUE, FALSE, 0);
gtk_widget_show_all(p_window);
}
Then compiling with:
gcc -o test main.c callback.h `pkg-config --cflags --libs gtk+-3.0`
will result in a window with a button, which after being pressed will create and show a new window with a GtkEntry:
now callback.h looks like that :
int cb_create_entry(GtkWidget *p_widget, gpointer user_data){
GtkWidget *p_window = NULL;
GtkWidget *p_entry = NULL;
GtkWidget *p_button = NULL;
GtkWidget *p_main_box = NULL;
GtkWidget *p_label = NULL;
p_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(p_window), "Create entry");
gtk_window_set_default_size(GTK_WINDOW(p_window), 320, 200);
g_signal_connect (G_OBJECT (p_window), "destroy", G_CALLBACK (cb_quit), NULL);
p_main_box = gtk_vbox_new(TRUE, 0);
gtk_container_add(GTK_CONTAINER(p_window), p_main_box);
p_label = gtk_label_new("Please, name your DB");
gtk_container_add(GTK_CONTAINER(p_main_box), p_label);
p_entry = gtk_entry_new();
gtk_container_add(GTK_CONTAINER(p_main_box), p_entry);
p_button = gtk_button_new_with_label("Create !");
gtk_container_add(GTK_CONTAINER(p_main_box), p_button);
{
GtkWidget *p_quit = NULL;
p_quit = gtk_button_new_with_label("Quit");
g_signal_connect(G_OBJECT(p_quit), "clicked", G_CALLBACK(cb_quit), NULL);
gtk_box_pack_start(GTK_BOX(p_main_box), p_quit, FALSE, FALSE, 0);
}
//gtk_widget_show(p_entry);
gtk_widget_show_all(p_window);
return EXIT_SUCCESS;}
I have a simple GTK3 app that displays an image from a file in a window.
When you resize the window, the image is scaled in the expose callback to fit the window.
However, once the window has grown, you can't shrink it again; the resize handles only let you make the window ever bigger.
With GTK2 it was trivial to allow grow and shrink with gtk_window_set_policy(w,1,1,1).
How can the same effect be achieved in GTK3?
Here's the ever-growing code example:
#include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
gboolean resize_image(GtkWidget *widget, GdkEvent *event, void *data)
{
GdkPixbuf *pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(widget));
if (pixbuf == NULL)
{
g_printerr("Failed to get pixbuf\n");
return 1;
}
pixbuf = gdk_pixbuf_scale_simple(pixbuf,
widget->allocation.width, widget->allocation.height,
GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf(GTK_IMAGE(widget), pixbuf);
return FALSE;
}
int main(int argc, char **argv)
{
GtkWidget *window = NULL;
GtkWidget *image = NULL;
if (argc < 2 || argc > 3)
{
g_printerr("Usage: %s <image>\n", argv[0]);
return 1;
}
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
image = gtk_image_new_from_file(argv[1]);
if (image == NULL)
{
g_printerr("Could not open \"%s\"\n", argv[1]);
return 1;
}
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(image, "expose-event", G_CALLBACK(resize_image), NULL);
gtk_container_add(GTK_CONTAINER(window), image);
gtk_widget_show_all(GTK_WIDGET(window));
gtk_main();
return 0;
}
Eric Cecashon on the gtk-list mailing list suggests using a cairo drawing area inside a 1x1 grid container, which works fairly well:
/*
gcc -Wall da_resize.c -o da_resize `pkg-config gtk+-3.0 --cflags --libs`
Tested on Ubuntu16.04, GTK3.18.
*/
#include<gtk/gtk.h>
gboolean draw_picture(GtkWidget *da, cairo_t *cr, gpointer data)
{
gint width=gtk_widget_get_allocated_width(da);
gint height=gtk_widget_get_allocated_height(da);
GdkPixbuf *temp=gdk_pixbuf_scale_simple((GdkPixbuf*)data, width, height, GDK_INTERP_BILINEAR);
gdk_cairo_set_source_pixbuf(cr, temp, 0, 0);
cairo_paint(cr);
g_object_unref(temp);
return FALSE;
}
int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
GtkWidget *window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Resize Picture");
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 400, 400);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
//Needs a valid picture.
GdkPixbuf *pixbuf=gdk_pixbuf_new_from_file(argc>1 ? argv[1] : "image.jpg", NULL);
GtkWidget *da1=gtk_drawing_area_new();
gtk_widget_set_hexpand(da1, TRUE);
gtk_widget_set_vexpand(da1, TRUE);
g_signal_connect(da1, "draw", G_CALLBACK(draw_picture), pixbuf);
GtkWidget *grid=gtk_grid_new();
gtk_grid_attach(GTK_GRID(grid), da1, 0, 0, 1, 1);
gtk_container_add(GTK_CONTAINER(window), grid);
gtk_widget_show_all(window);
gtk_main();
g_object_unref(pixbuf);
return 0;
}
I'm programming my first bigger GTK+-Application and i have some troubles with exiting the application.
I want to have a Quit-Button in a dialog box, because normally you should run the program in full-screen-mode.
First I tried to call "gtk_main_quit" direktly from a signal but it also didn't work. Now i tried it through an event, the console output works but "gtk_main_quit" doesn't do anything!
Can somebody explain what I'm doing wrong? If you want to give me some tips for better coding, I will really welcome that, too!
Thanks for you help in advance!
#include <stdlib.h>
#include <gtk/gtk.h>
#include <time.h>
static gboolean gtk_delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
g_message("delete event occured\n");
gtk_main_quit();
return TRUE;
}
static void check_toggle_fullscreen (GtkToggleButton *checkButton_fullscreen, GtkWindow *window)
{
if (gtk_toggle_button_get_active(checkButton_fullscreen))
{
gtk_window_fullscreen(GTK_WINDOW(window));
}
else
{
gtk_window_unfullscreen(GTK_WINDOW(window));
}
}
static gboolean double_clicked (GtkWidget *eventbox, GdkEventButton *event, GtkWindow *window)
{
GtkWidget *dialog, *hbox, *checkButton_fullscreen, *image, *button_preferences, *button_closeApp;
dialog = gtk_dialog_new_with_buttons("Schnelleinstellung", window, GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
checkButton_fullscreen = gtk_check_button_new_with_label("Fullscreen");
image = gtk_image_new_from_stock(GTK_STOCK_FULLSCREEN, GTK_ICON_SIZE_BUTTON);
hbox = gtk_hbox_new(FALSE, 10);
gtk_box_pack_start_defaults (GTK_BOX(hbox), image);
gtk_box_pack_start_defaults (GTK_BOX(hbox), checkButton_fullscreen);
if (gdk_window_get_state(gtk_widget_get_window(GTK_WIDGET(window))) & GDK_WINDOW_STATE_FULLSCREEN)
{
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkButton_fullscreen), TRUE);
}
button_closeApp = gtk_button_new_from_stock(GTK_STOCK_QUIT);
button_preferences = gtk_button_new_from_stock(GTK_STOCK_PREFERENCES);
//Fill dialog with content
gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), button_preferences);
gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), button_closeApp);
g_signal_connect(G_OBJECT(checkButton_fullscreen), "toggled", G_CALLBACK(check_toggle_fullscreen), (gpointer)window);
g_signal_connect(G_OBJECT(button_closeApp), "clicked", G_CALLBACK(gtk_delete_event), NULL);
if (event-> type == GDK_2BUTTON_PRESS)
{
gtk_widget_show_all(dialog);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
return FALSE;
}
int main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *vbox2;
GtkWidget *label[5];
GtkWidget *frame1, *frame2;
GtkWidget *eventbox;
PangoFontDescription *font;
gtk_init(&argc, &argv);
//Window_TOPLEVEL
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),"Abnahme");
gtk_window_maximize(GTK_WINDOW(window));
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_NONE);
gtk_window_set_decorated(GTK_WINDOW(window), TRUE);
vbox = gtk_vbox_new(FALSE, 10);
vbox2 = gtk_vbox_new(FALSE, 10);
frame1 = gtk_frame_new("Naechster Skid");
frame2 = gtk_frame_new("Warteschlange");
eventbox = gtk_event_box_new();
gtk_frame_set_shadow_type(GTK_FRAME(frame1), GTK_SHADOW_IN);
gtk_frame_set_shadow_type(GTK_FRAME(frame2), GTK_SHADOW_IN);
label[0] = gtk_label_new("1");
font = pango_font_description_from_string("Arial 40");
gtk_widget_modify_font(label[0], font);
gtk_label_set_markup(GTK_LABEL(label[0]), "<b>Erster Skid</b>");
int j = 1;
while(j<5)
{
gchar buffer[10];
label[j] = gtk_label_new("0");
g_snprintf(buffer, sizeof(buffer), "%i",j+1);
gtk_label_set_markup(GTK_LABEL(label[j]), buffer);
gtk_widget_modify_font(label[j], font);
j++;
}
//Level 0
gtk_container_add(GTK_CONTAINER(window), eventbox);
gtk_event_box_set_above_child(GTK_EVENT_BOX(eventbox), TRUE);
gtk_container_add(GTK_CONTAINER(eventbox), vbox);
//Level 1
gtk_box_pack_start(GTK_BOX(vbox),frame1, TRUE, TRUE, 0);
//Level 2
gtk_container_add(GTK_CONTAINER(frame1), label[0]);
//Level 1
gtk_box_pack_start(GTK_BOX(vbox),frame2, TRUE, TRUE, 0);
//Level 2
gtk_container_add(GTK_CONTAINER(frame2), vbox2);
//Level 3
int i = 1;
while(i<5)
{
gtk_box_pack_start(GTK_BOX(vbox2), label[i], TRUE, TRUE, 0);
i++;
}
//Signals
g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(gtk_delete_event), NULL);
g_signal_connect(G_OBJECT(eventbox), "button_press_event", G_CALLBACK(double_clicked), (gpointer) window);
gtk_widget_set_events(eventbox, GDK_BUTTON_PRESS_MASK);
gtk_widget_realize(eventbox);
/* Enter the main loop */
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
gtk_dialog_run() enters a recursive main loop. gtk_main_quit() only exits the innermost recursion of the main loop.
I don't know if GTK+ provides a clean way to do what you want; you might have to do that yourself somehow.
To delete gtk_dialog_run() and gtk_widget_destroy() like under the code is available to quit dialog button.
if (event-> type == GDK_2BUTTON_PRESS)
{
gtk_widget_show_all(dialog);
/*
* gtk_dialog_run(GTK_DIALOG(dialog));
* gtk_widget_destroy(dialog);
*/
}
It seems that the reason is running dialog is blocking to quit app.