I can't find how to do that :( there's gtk_window_set_resizable, but it disables resizing at all and i still want my window to resize horizontally.
Any ideas?
I believe you can try using gtk_window_set_geometry_hints function and specify max and min height for your window. In this case you would still allow width change whereas height will stay constant. Pls, check if an example below would work for you:
int main(int argc, char * argv[])
{
gtk_init(&argc, &argv);
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
GdkGeometry hints;
hints.min_width = 0;
hints.max_width = gdk_screen_get_width(gtk_widget_get_screen(window));;
hints.min_height = 300;
hints.max_height = 300;
gtk_window_set_geometry_hints(
GTK_WINDOW(window),
window,
&hints,
(GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE));
gtk_widget_show_all(window);
gtk_main();
return 0;
}
hope this helps, regards
Here's my implementation in GTK#
public static void SetFixedDimensions (
Window window, bool vertical, bool horizontal)
{
int width, height;
window.GetSize(out width, out height);
var hintGeometry = new Gdk.Geometry();
hintGeometry.MaxHeight = vertical ? height : Int32.MaxValue;
hintGeometry.MinHeight = vertical ? height : 0;
hintGeometry.MaxWidth = horizontal ? width : Int32.MaxValue;
hintGeometry.MinWidth = horizontal ? width : 0;
window.SetGeometryHints(window, hintGeometry, Gdk.WindowHints.MaxSize);
}
Building upon #serge_gubenko's answer, if you want to forbid vertical resize only after the initial layout, you will need to setup a callback for signal size-allocate.
Example:
static gint signal_connect_id_cb_dialog_size_allocate;
static void
cb_dialog_size_allocate (GtkWidget *window,
GdkRectangle *allocation,
gpointer user_data)
{
GdkGeometry hints;
g_signal_handler_disconnect (G_OBJECT (dialog),
signal_connect_id_cb_dialog_size_allocate);
/* dummy values for min/max_width to not restrict horizontal resizing */
hints.min_width = 0;
hints.max_width = G_MAXINT;
/* do not allow vertial resizing */
hints.min_height = allocation->height;
hints.max_height = allocation->height;
gtk_window_set_geometry_hints (GTK_WINDOW (window), (GtkWidget *) NULL,
&hints,
(GdkWindowHints) (GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE));
}
int main(int argc, char * argv[])
{
gtk_init(&argc, &argv);
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
signal_connect_id_cb_dialog_size_allocate =
g_signal_connect (G_OBJECT (state->dialog),
"size-allocate",
G_CALLBACK (cb_dialog_size_allocate),
(gpointer) NULL /* user_data */);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
Related
I'm trying to use cairo to draw some arcs but gcc warns me that gdk_cairo_create() is deprecated. Use gdk_window_begin_draw_frame() and gdk_drawing_context_get_cairo_context() instead.
To get around this I did some research and found out that for gdk_window_begin_draw_frame() I need "GdkWindow".I've always been using GtkWidget for my windows so I need to convert "GtkWidget" to "GdkWindow", but gtk_widget_get_window() returns NULL and causes segfault.
#include <gtk/gtk.h>
#include <cairo.h>
void main(int argc , char **argv){
gtk_init(&argc , &argv);
GtkWidget *win;
GdkWindow *gdkwin;
GdkDrawingContext *dc;
cairo_region_t *region;
cairo_t *cr;
win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
region = cairo_region_create();
gdkwin = gtk_widget_get_window(GTK_WIDGET(win));
//Here gdkwin should contain a GdkWindow but it's NULL.
gc = gdk_window_begin_draw_frame(gdkwin , (const cairo_region_t*)®ion);
...
...
Here's the runtime errors:
(a.out:6852): Gdk-CRITICAL **: 23:53:06.042: gdk_window_begin_draw_frame: assertion 'GDK_IS_WINDOW (window)' failed
(a.out:6852): Gdk-CRITICAL **: 23:53:06.042: gdk_drawing_context_get_cairo_context: assertion 'GDK_IS_DRAWING_CONTEXT (context)' failed
Segmentation fault
I want to get a cairo object and use it for cairo_arc().
Thanks.Best regards.
The below is the complete source code to get Cairo working under GTK 3. It should be compilable as is.
As the others already pointed out, you have to use the draw signal to make things work.
#include <gtk/gtk.h>
#include <cairo.h>
// ------------------------------------------------------------
gboolean on_draw (GtkWidget *widget,
GdkEventExpose *event,
gpointer data)
{
// "convert" the G*t*kWidget to G*d*kWindow (no, it's not a GtkWindow!)
GdkWindow* window = gtk_widget_get_window(widget);
cairo_region_t * cairoRegion = cairo_region_create();
GdkDrawingContext * drawingContext;
drawingContext = gdk_window_begin_draw_frame (window,cairoRegion);
{
// say: "I want to start drawing"
cairo_t * cr = gdk_drawing_context_get_cairo_context (drawingContext);
{ // do your drawing
cairo_move_to(cr, 30, 30);
cairo_set_font_size(cr,15);
cairo_show_text(cr, "hello world");
}
// say: "I'm finished drawing
gdk_window_end_draw_frame(window,drawingContext);
}
// cleanup
cairo_region_destroy(cairoRegion);
return FALSE;
}
// ------------------------------------------------------------
int main (int argc, char * argv[]) {
gtk_init(&argc, &argv);
GtkWindow * window;
{ // window setup
window = (GtkWindow*)gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (window, 200, 200);
gtk_window_set_position (window, GTK_WIN_POS_CENTER);
gtk_window_set_title (window, "Drawing");
g_signal_connect(window, "destroy", gtk_main_quit, NULL);
}
// create the are we can draw in
GtkDrawingArea* drawingArea;
{
drawingArea = (GtkDrawingArea*) gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER(window), (GtkWidget*)drawingArea);
g_signal_connect((GtkWidget*)drawingArea, "draw", G_CALLBACK(on_draw), NULL);
}
gtk_widget_show_all ((GtkWidget*)window);
gtk_main();
return 0;
}
// ------------------------------------------------------------
In GTK+ 3, you're supposed to do your drawing in response to the draw signal. Doing it in the main makes no sense (the widgets have just been created, but initializing them further in done when running the main event loop).
Please read: https://developer.gnome.org/gtk3/stable/chap-drawing-model.html
The Dark Trick's program is complete.
He uses the functions as follows,
GdkWindow* window = gtk_widget_get_window (widget);
cairo_region_t *cairoRegion = cairo_region_create();
GdkDrawingContext *drawingContext;
drawingContext = gdk_window_begin_draw_frame (window, cairoRegion);
cairo_t *cr = gdk_drawing_context_get_cairo_context (drawingContext);
But I am using the the functions as follows,
GdkWindow *window = gtk_widget_get_window(widget);
cairo_rectangle_int_t cairoRectangle = {0, 0, 200, 200};
cairo_region_t *cairoRegion = cairo_region_create_rectangle (&cairoRectangle);
GdkDrawingContext *drawingContext;
drawingContext = gdk_window_begin_draw_frame (window,cairoRegion);
cairo_t *cr = gdk_drawing_context_get_cairo_context (drawingContext);
This worked, but I can not understand the differencies, for I am an OldUrologist.
I'm not positive, but I think you're trying to get the GdkWindow before it is ready. I think you need to connect to the window's "realize" signal, and only when that signal has been emitted should you try to access the underlying GdkWindow.
#include <gtk/gtk.h>
#include <cairo.h>
void OnWindowRealize(GtkWidget *pWidget, gpointer data)
{
GdkWindow *pUnderlyingWindow = gtk_widget_get_window(pWidget);
cairo_region_t *region = cairo_region_create();
GdkDrawingContext *gc = gdk_window_begin_draw_frame(pUnderlyingWindow, (const cairo_region_t*)®ion);
//etc...
}
void main(int argc , char **argv)
{
gtk_init(&argc , &argv);
GtkWidget *win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(win), "realize", OnWindowRealize, NULL);
//etc...
}
I am trying to modify the cairo graphics rendering I found in http://zetcode.com/gfx/cairo/basicdrawing/ so that it updates the graphics when I click the drawing area with the left mouse button. Currently the code in the website uses the right mouse button click to update the graphics.
I have tried adding gtk_widget_queue_draw(widget); to gboolean clicked(), when event->button == 1:
#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;
gtk_widget_queue_draw(widget);
}
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;
}
However, this does not work since now the graphics aren't updated at all.
Is there a way of updating the graphics by pressing the left mouse button (button 1) and simultaneously carry out inserting the coordinates to struct glob as before?
Thanks!
You are setting glob.count = 0 after drawing the lines, however glob.count is only updated by one in the clicked() callback, so it will never draw more than a single line. Also the first line is from point (glob.coordx[0], glob.coordy[0]) to (glob.coordx[0], glob.coordy[0]) (that is: it starts and ends at the same point) so it has no length, and will not be visible.
Solution: remove the line glob.count = 0; from do_drawing().
g_signal_connect(window, "button-press-event", G_CALLBACK(clicked), NULL);
When your callback is called, the window (which emits "button-press-event") is passed as first parameter. The queue_draw call queues redraw of window. However, redraw of DrawingArea is not requested and will not happen.
You can:
Queue redraw of DrawingArea
Connect to "button-press-event" of DrawingArea
Without any changes of code: press a mouse button and resize the window. Gtk will see, that DrawingArea has changed (it's resized too) and queue redraw of this widget.
I am trying to build an App in linux Ubuntu with C and GTK3 and I get an Error about gdk_window_get_origin and I can not figure out what I am doing wrong.
The app runs and the Window is indeed the size of my Screen, but there is this warning which I cannot fix it:
(Stack:7229): Gdk-CRITICAL **: 11:09:22.221: gdk_window_get_origin: assertion 'GDK_IS_WINDOW (window)' failed
Screen max: 1600W X 900H
Here is a sample code:
#include <gtk/gtk.h>
int main(int argc, char *argv[])
{
GtkWidget *window;
gint width, height;
gtk_init(&argc, &argv);
/// Creating the Window
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
/// Get window Size
GdkDisplay *dpy = gtk_widget_get_display( window );
GdkWindow *win = gtk_widget_get_window(window);
GdkMonitor *monitor = gdk_display_get_monitor_at_window(dpy, win);
/// Get window Geometry
GdkRectangle geometry;
gdk_monitor_get_geometry(monitor, &geometry);
width = geometry.width;
height = geometry.height;
g_print("Screen max: %dW X %dH\n", width, height);
// Setting the default size of the Window
gtk_window_set_default_size(GTK_WINDOW(window), width, height );
// Destroy the Window
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main();
}
TL;DR: You are trying to access GdkWindow before GtkWindow is realized.
From gtk_widget_get_window documentation:
Returns the widget’s window if it is realized, NULL otherwise
And gtk_widget_realize:
Creates the GDK (windowing system) resources associated with a widget.
For example, widget->window will be created when a widget is realized.
Normally realization happens implicitly; if you show a widget and all
its parent containers, then the widget will be realized and mapped
automatically.
You need to either call gtk_widget_realize before trying to access GdkWindow with gtk_widget_get_display or postpone the access until the window is realized (after the start of the Gtk main loop) using callback to realize signal:
#include <gtk/gtk.h>
void print_geometry(GtkWidget* widget, GdkRectangle* geometry)
{
GdkDisplay *dpy = gtk_widget_get_display(widget);
GdkWindow *win = gtk_widget_get_window(widget);
GdkMonitor *monitor = gdk_display_get_monitor_at_window(dpy, win);
gdk_monitor_get_geometry(monitor, geometry);
gint width = geometry->width;
gint height = geometry->height;
g_print("Screen max: %dW X %dH\n", width, height);
gtk_window_set_default_size(GTK_WINDOW(widget), width, height );
}
int main(int argc, char *argv[])
{
GtkWidget *window;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
GdkRectangle geometry;
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(window, "realize", G_CALLBACK(print_geometry), &geometry);
gtk_widget_show_all(window);
gtk_main();
}
I am a new C programmer coming from Java. After reading some old books and articles, I've written the following code:
#include <gtk/gtk.h>
static void activate(GtkApplication* app, gpointer user_data) {
GtkWidget *window;
GtkWidget *button1;
GtkWidget *box;
box = gtk_alignment_new(0, 0, 0, 0);
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "Calculator");
gtk_window_set_default_size(GTK_WINDOW(window), 300, 400);
gtk_container_add(GTK_CONTAINER(window), box);
button1 = gtk_button_new();
gtk_button_set_label(GTK_BUTTON(button1), "1");
gtk_widget_set_size_request(button1, 40, 30);
gtk_container_add(GTK_CONTAINER(box), button1);
gtk_widget_show_all(window);
}
int main(int argc, char **argv) {
GtkApplication *app;
int status;
app = gtk_application_new("me.test.calculator", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
The code compiles and runs correctly. The problem is that gtk_alignment_new is deprecated and I want to get rid of it.
I've tried replacing gtk_alignment_new with:
gtk_widget_set_halign(box, GTK_ALIGN_START);
gtk_widget_set_valign(box, GTK_ALIGN_START);
but the window does not show up when using this method. Thanks.
You want to set the halign/valign properties of the button (and then add the button straight into the window) to achieve the same functional results as your original code. 'box' is no longer needed at all.
Note that a GtkWindow is a GtkBin so only takes a single child: you will need to add additional containers in between to actually make a calculator. Maybe start by adding a GtkGrid as the sole window child and then attach all your buttons into the grid.
Using jku's advice I've written the following code which compiles and runs correctly without using gtk_alignment_new:
#include <gtk/gtk.h>
static void activate(GtkApplication* app, gpointer user_data) {
GtkWidget *window;
GtkWidget *button1;
GtkWidget *fixed;
fixed = gtk_fixed_new();
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "Calculator");
gtk_window_set_default_size(GTK_WINDOW(window), 300, 400);
gtk_container_add(GTK_CONTAINER(window), fixed);
button1 = gtk_button_new();
gtk_button_set_label(GTK_BUTTON(button1), "1");
gtk_widget_set_size_request(button1, 45, 35);
gtk_fixed_put(GTK_FIXED(fixed), button1, 5, 200);
gtk_widget_show_all(window);
}
int main(int argc, char **argv) {
GtkApplication *app;
int status;
app = gtk_application_new("me.test.calculator", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
NOTE: I ended up using GtxFixed because the size of the window will be fixed as well.
How do I initialize a GtkScrolledWindow to avoid scrollbars by growing as much as possible?
By default it seems to be as small as possible.
Demo code (Quit with SIGINT):
#include <gtk/gtk.h>
int main(int argc, char *argv[]) {
GtkWidget* window;
GtkWidget* content;
GtkWidget* sw;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
sw = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_container_add(GTK_CONTAINER(window), sw);
gtk_widget_show(sw);
content = gtk_button_new_with_label("This is a very, very"
"very very very very very very very very long text");
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw), content);
gtk_widget_show(content);
gtk_widget_show(window);
gtk_main();
return 0;
}
I think this both works and is not an ugly hack (much):
int main(int argc, char *argv[]) {
GtkWidget* window;
GtkWidget* content;
GtkWidget* sw;
GtkRequisition size;
GtkWidget* viewport;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
sw = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_container_add(GTK_CONTAINER(window), sw);
gtk_widget_show(sw);
content = gtk_button_new_with_label("This is a very, very"
"very very very very very very very very long text");
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw), content);
gtk_widget_show(content);
gtk_widget_show(window);
viewport = gtk_widget_get_ancestor(content, GTK_TYPE_VIEWPORT);
gtk_widget_size_request(viewport, &size);
gtk_widget_set_size_request(sw, size.width, size.height);
gtk_main();
return 0;
}
I'm not sure what the proper way to do this is, but I've found that what works best for me is to set the size of the window, and the widgets contained within it usually size themselves correctly:
gtk_window_set_default_size(GTK_WINDOW(window), 1000, 500);
Alternatively, you can set the size of the GtkScrolledWindow:
gtk_widget_set_size_request(window, 500, 250);
Note that in especially this last case, localisation, font sizes, and other such details probably have to be considered when calculationg the size in pixels.