Make GtkScrolledWindow display all children by default - c

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.

Related

When is GtkTextView's preferred size updated?

I have noticed that GtkTextView's preferred size doesn't change immediately after its contents are changed, but only sometime later in event processing.
In following example, when you click the button, the text in GtkTextView is updated via gtk_text_buffer_set_text(). The new text is long enough to cause a line wrap, and so the preferred height of the control should change. But the gtk_widget_get_preferred_size() still reports old preferred height. Later, in 'size-allocate' event handler, the gtk_widget_get_preferred_size() is already reporting correct size for new contents.
I am trying to understand what happens between the return from button's 'clicked' event handler and 'size-allocate' event handler, that causes GtkTextView's preferred size to update to reflect its changed contents.
#include <gtk/gtk.h>
static bool button_clicked(GtkWidget* obj, GtkWidget* view)
{
// set text in GtkTextView to
const char* long_text="aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa";
printf("----------------------------\n");
printf("in button_clicked(): setting text\n");
GtkTextBuffer* buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
gtk_text_buffer_set_text(buffer, long_text, -1);
GtkRequisition req;
gtk_widget_get_preferred_size(view, &req, NULL);
printf("in button_clicked(): preferred height = %u\n", req.height);
return false;
}
static bool on_size_allocate(GtkWidget* obj, GdkRectangle *allocation, GtkWidget* view)
{
GtkRequisition req;
gtk_widget_get_preferred_size(view, &req, NULL);
printf("in on_size_allocate(): preferred height = %u\n", req.height);
return false;
}
static void activate(GtkApplication* app, gpointer user_data)
{
GtkWidget *window;
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW (window), "Wrapped text");
gtk_window_set_default_size(GTK_WINDOW (window), 200, 200);
gtk_widget_show_all(window);
GtkTextBuffer* buffer = gtk_text_buffer_new(NULL);
GtkWidget* view = GTK_WIDGET(gtk_text_view_new_with_buffer(buffer));
g_object_unref(buffer);
gtk_widget_set_size_request(view, 180, -1);
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view), GTK_WRAP_WORD_CHAR);
g_signal_connect(view, "size-allocate", G_CALLBACK(on_size_allocate), view);
GtkWidget *button = gtk_button_new_with_label("Set Text");
g_signal_connect(button, "clicked", G_CALLBACK(button_clicked), view);
GtkWidget* grid = gtk_grid_new();
gtk_container_add(GTK_CONTAINER(window), grid);
gtk_grid_attach(GTK_GRID(grid), button, 0, 0, 1, 1);
gtk_grid_attach(GTK_GRID(grid), view, 0, 1, 1, 1);
gtk_widget_show_all(window);
}
int main (int argc, char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new("org.gtk.example", 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;
}
This displays:
in on_size_allocate(): preferred height = 17
----------------------------
in button_clicked(): setting text
in button_clicked(): preferred height = 17
in on_size_allocate(): preferred height = 34

(Stack:7229): Gdk-CRITICAL **: 11:09:22.221: gdk_window_get_origin: assertion 'GDK_IS_WINDOW (window)' failed

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();
}

C: How to replace GtkAlignment function with newer GtkWidget align property

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.

GTK3 "gtk_entry_new" does not work in "POPUP" modus

i´m just working arround in GTK3 with an input field and found a problem what i do not understand. I can write in the field gtk_entry_new on TOPLEVEL modus but i can not in POPUP modus. Here is my shortened code (I kow this does noting but i is more easy to read):
#include <gtk/gtk.h>
int main(int argc, char **argv) {
gtk_init(&argc, &argv);
GtkWidget *window;
GtkWidget *inputfield;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
inputfield = gtk_entry_new();
gtk_container_add(GTK_CONTAINER(window), inputfield);
//this two lines are make TOPLEVEL look like POPUP
gtk_window_set_decorated (GTK_WINDOW(window), FALSE);
gtk_window_set_resizable (GTK_WINDOW(window), FALSE);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
When I change the line window = gtk_window_new(GTK_WINDOW_TOPLEVEL); to window = gtk_window_new(GTK_WINDOW_POPUP); I can not insert any characters into the field. Someone has a hint for me?

Gtk: Forbid vertical resize of GtkWindow

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;
}

Resources