Cannot reduce size of gtk window programatically - c

I seem to be facing a problem when resizing a gtk window programatically. The problem is that once I have increased the width and height of the window to 800x600, I cannot seem to reduce it back to its original size of 400x200.
Below is the sample code. Has anyone faced such a problem?
#include <gtk/gtk.h>
static gboolean is_clicked = FALSE;
static void Child_window_resize( GtkWidget *widget,
GtkWidget *window)
{
if(!is_clicked)
{
g_print("Inside If block increase bool value %d\n",is_clicked);
gtk_widget_set_size_request(window,800,600);
is_clicked = TRUE;
}
else
{
g_print("Inside Else block decrease bool value %d\n",is_clicked);
gtk_widget_set_size_request(window,400,200);
is_clicked = FALSE;
}
}
int main(int argc, char* argv[])
{
GtkWidget *window;
GtkWidget *fixed;
GtkWidget *resizebutton;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_set_size_request(window,400,200);
gtk_window_set_resizable(GTK_WINDOW(window),TRUE);
gtk_window_set_title(GTK_WINDOW(window), "Demo Resize");
gtk_window_set_decorated(GTK_WINDOW(window),FALSE);
gtk_signal_connect(GTK_OBJECT(window), "destroy",
GTK_SIGNAL_FUNC(gtk_exit), NULL);
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
// creating a fixed GTK_CONTAINER
fixed = gtk_fixed_new();
gtk_container_add(GTK_CONTAINER(window),fixed);
gtk_widget_show(fixed);
resizebutton = gtk_button_new_with_label("Resize");
gtk_widget_set_size_request(resizebutton, 80, 60);
gtk_fixed_put(GTK_FIXED(fixed), resizebutton, 0, 0);
gtk_signal_connect(GTK_OBJECT(resizebutton), "clicked",
GTK_SIGNAL_FUNC(Child_window_resize), window);
gtk_widget_show(resizebutton);
gtk_widget_show(window);
gtk_main();
return 0;
}
Complied using ...
gcc -Wall -Werror -g resize.c -o resize -export-dynamic `pkg-config --cflags --libs gtk+-2.0 gthread-2.0`
Any help is much appreciated.

Instead of gtk_widget_set_size_request(), you need gtk_window_resize().
From the linked manual:
void
gtk_window_resize (GtkWindow *window,
gint width,
gint height);
Resizes the window as if the user had done so, obeying geometry
constraints. The default geometry constraint is that windows may not
be smaller than their size request; to override this constraint, call
gtk_widget_set_size_request() to set the window's request to a smaller
value.
If gtk_window_resize() is called before showing a window for the first
time, it overrides any default size set with
gtk_window_set_default_size().
Windows may not be resized smaller than 1 by 1 pixels.

Related

Changing background color of GtkEntry

I have written a C language program with many GtkEntry's for data input. I have created the UI using Glade and the GtkEntrys emit an on_entry#_changed() signal when modified. My program checks the validity of the input, which has certain requirements. e.g., must be valid hexadecimal.
I would like the background of a GtkEntry to go red while it is invalid, and turn back to the original color when acceptable. The original color is dependent upon the desktop style set by the user. For example, on Ubuntu, I'm using a "Dark" style, so the box is dark gray.
What is the best way to implement this background color switching so that it applies to an individual GtkEntry and renders the user's chosen style color when the data is ok? I see a lot of discussion out there but it is often using deprecated functions.
You can use the error style class to mark the entry as having error. The following is a minimal example that checks if an entry has a valid hex digit and updates the entry style:
/* main.c
*
* Compile: cc -ggdb main.c -o main $(pkg-config --cflags --libs gtk+-3.0) -o main
* Run: ./main
*
* Author: Mohammed Sadiq <www.sadiqpk.org>
*
* SPDX-License-Identifier: LGPL-2.1-or-later OR CC0-1.0
*/
#include <gtk/gtk.h>
static void
entry_changed_cb (GtkEntry *entry)
{
GtkStyleContext *style;
const char *text;
gboolean empty;
g_assert (GTK_IS_ENTRY (entry));
style = gtk_widget_get_style_context (GTK_WIDGET (entry));
text = gtk_entry_get_text (entry);
empty = !*text;
/* Loop until we reach an invalid hex digit or the end of the string */
while (g_ascii_isxdigit (*text))
text++;
if (empty || *text)
gtk_style_context_add_class (style, "error");
else
gtk_style_context_remove_class (style, "error");
}
static void
app_activated_cb (GtkApplication *app)
{
GtkWindow *window;
GtkWidget *entry;
window = GTK_WINDOW (gtk_application_window_new (app));
entry = gtk_entry_new ();
gtk_widget_set_halign (entry, GTK_ALIGN_CENTER);
gtk_widget_set_valign (entry, GTK_ALIGN_CENTER);
gtk_widget_show (entry);
gtk_container_add (GTK_CONTAINER (window), entry);
g_signal_connect_object (entry, "changed",
G_CALLBACK (entry_changed_cb),
app, G_CONNECT_AFTER);
entry_changed_cb (GTK_ENTRY (entry));
gtk_window_present (window);
}
int
main (int argc,
char *argv[])
{
g_autoptr(GtkApplication) app = gtk_application_new (NULL, 0);
g_signal_connect (app, "activate", G_CALLBACK (app_activated_cb), NULL);
return g_application_run (G_APPLICATION (app), argc, argv);
}

C, gtk: ‘window’ undeclared (first use in this function)

I'm very new in C, i've started learning this language about 1 week ago, coming from Python. So,I have difficult understanding the C syntax, and the solution online. I'm trying building a simple graphic interface. In this example project created for this post, if the user types "create_window", the program creates a window, and if after it the user types "create_button" the program should create a button.. but it doesn't work. Below there is the error, but first the code:
#include <stdio.h>
#include <string.h>
#include <gtk/gtk.h>
void main(int argc, char* argv[]){
char row[50];
for(int i=0;i<=1;i++){
scanf("%s",row);
if(strstr(row,"create_window")!=NULL){
GtkWidget* window;
GtkWidget* button;
gtk_init(&argc,&argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "New window");
g_signal_connect(window,"destroy",G_CALLBACK(gtk_main_quit),NULL);
gtk_window_set_default_size(GTK_WINDOW(window),200,200);
gtk_widget_show_all(window);
gtk_main();
}
if(strstr(row,"create_button")!=NULL){
button = gtk_button_new_with_label("Button text");
gtk_container_add(GTK_CONTAINER(window), button);
gtk_widget_show_all(window);
gtk_main();
}
}
}
this code create successfully the window, but not the button. After creating the window, i type "create_button" and i receive this error:
error: ‘window’ undeclared (first use in this function)
80 | gtk_container_add(GTK_CONTAINER(window), button);
the complete error refers to my """complete""" project, if you need it write in a comment.
Your window variable is scoped exclusively to that first if.
Variables only exist within the scope in which they've been declared.
#include <stdio.h>
#include <string.h>
#include <gtk/gtk.h>
void main(int argc, char* argv[]) {
char row[50];
for(int i = 0; i <= 1; i++) {
scanf("%s", row);
GtkWidget* window;
GtkWidget* button;
if (strstr(row, "create_window") != NULL) {
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "New window");
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_window_set_default_size(GTK_WINDOW(window), 200, 200);
gtk_widget_show_all(window);
gtk_main();
}
if (strstr(row, "create_button") != NULL) {
button = gtk_button_new_with_label("Button text");
gtk_container_add(GTK_CONTAINER(window), button);
gtk_widget_show_all(window);
gtk_main();
}
}
}
Also, I suggest using a width specifier with scanf to avoid overflows.
scanf("%49s", row);
Your program doesn't make sense. You cannot create a button till you have a window to place it on (even if you fix the syntax error of making the variable available in the 2nd if statement). Also, gtk_main() runs an event loop and doesn't return. Perhaps you want to optionally create a button?
#include <gtk/gtk.h>
#include <stdio.h>
#include <string.h>
void main(int argc, char* argv[]){
gtk_init(&argc, &argv);
GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "New window");
g_signal_connect(window,"destroy", G_CALLBACK(gtk_main_quit),NULL);
gtk_window_set_default_size(GTK_WINDOW(window),200,200);
char row[50];
fgets(row, 50, stdin);
if(!strcmp(row, "create_button\n")) {
GtkWidget *button = gtk_button_new_with_label("Button text");
gtk_container_add(GTK_CONTAINER(window), button);
}
gtk_widget_show_all(window);
gtk_main();
}
I build the program and executed it like this:
gcc 1.c $(pkg-config --cflags atk) $(pkg-config --cflags gdk-3.0) $(pkg-config gtk-3.0) $(pkg-config --libs gtk+-3.0) $(pkg-config --libs gdk-3.0) && ./a.out
If you enter create_button\n it will create a window with a button, and if you enter any other line it will just create the window.
Otherwise, you need to tell us what should happen for "create_button"? Do we automatically create a window and then the button? Do we just remember that we need to create the button when user asks to "create_window"? If you want to show the window, then regain control, you need to use gtk_main_iteration_do(FALSE) instead of gtk_main(), and then you can add the button.

Set frame position of decorated GtkWindow on screen

I have a task to restore window frame position on screen on program startup - so to define initial window position.
Consider the following decorated GtkWindow instance on Linux:
The window has two principal boxes: frame box and client box.
And there are two GTK functions that allow to set size and position of the window on screen:
gtk_window_move() - sets window's frame box position on screen and
gtk_window_resize - sets window's client box size.
Question:
Is there any way in GTK to define initial frame placement of the window?
On Windows I can do that by calling MoveWindow() and on MacOS NSWindow setFrame method. But on GTK... Am I asking too much?
Connect to the "realize" signal for the window (important: before calling gtk_widget_show). Then call gtk_window_move from the handler:
#include <gtk/gtk.h>
void on_window_realize(GtkWidget *widget,
gpointer user_data)
{
GtkWindow *window = GTK_WINDOW(user_data);
gtk_window_move(window, 100, 40);
}
int main(int argc, char **argv) {
GtkWidget *window = NULL;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(window,
"realize",
G_CALLBACK(on_window_realize),
(gpointer)window);
g_signal_connect(window, "destroy", gtk_main_quit, NULL);
gtk_widget_show(window);
gtk_main();
return 0;
}

GTK in C: Segmentation Fault when using key-release or key-press

For context, I'm trying to make a program that changes stylized label text in response to some physical inputs on a beaglebone black (eg. get a signal, if high/low, show this text). In lieu of those inputs, which I don't have access to right now, I decided to use key-release as a substitute.
I've been basing my code off of this combo-box tutorial, which changes label text based on the text of a combo-box selection. I've modified that code to use stylized text as in the code below.
#include <gtk/gtk.h>
void combo_selected(GtkWidget *widget, gpointer window) {
gchar *text = g_strjoin(NULL,"<span font='48' weight='bold' color='#DDDDDD'>",gtk_combo_box_get_active_text(GTK_COMBO_BOX(widget)),"</span>",NULL); //label text, uses pango markup
gtk_label_set_markup(GTK_LABEL(window), text);
g_free(text);
}
int main(int argc, char *argv[]) {
GtkWidget *window;
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *combo;
GtkWidget *label;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "GtkComboBox");
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_container_set_border_width(GTK_CONTAINER(window), 15);
gtk_window_set_default_size(GTK_WINDOW(window), 300, 200);
hbox = gtk_hbox_new(FALSE, 0);
vbox = gtk_vbox_new(FALSE, 15);
combo = gtk_combo_box_new_text();
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Ubuntu");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Arch");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Fedora");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Mint");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Gentoo");
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Debian");
gtk_box_pack_start(GTK_BOX(vbox), combo, FALSE, FALSE, 0);
gchar *str = "<span font='48' weight='bold' color='#DDDDDD'>Not Initialized</span>"; //label text, uses pango markup
label = gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(label), str); //add pango str to label
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), hbox);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(G_OBJECT(combo), "changed",
G_CALLBACK(combo_selected), (gpointer) label);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
That works, however when attempting to use a key-release or key-press instead of the combo box options, I get a segmentation fault. Below is the further-modified code (with some things commented out).
#include <gtk/gtk.h>
#include <unistd.h>
#include <stdio.h>
void fpcheck(GtkWidget *window, gpointer lbl) {
gchar *text = "<span font='48' weight='bold' color='#DDDDDD'>Press index finger firmly on sensor.</span>";
gtk_label_set_markup(GTK_LABEL(lbl), text);
//sleep(2); //placeholder -> fp detection
//text = "<span font='48' weight='bold' color='#DDDDDD'>Fingerprint recognized!</span>";
//gtk_label_set_markup(GTK_LABEL(lbl), text);
g_free(text);
}
int main(int argc, char *argv[]) {
GtkWidget *window; //main window
GtkWidget *align; //alignment settings
GtkWidget *lbl; //text
GdkColor color = {0, 0x0, 0x0, 0x0}; //window color
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL); //init window
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); //window pos on screen
gtk_window_set_default_size(GTK_WINDOW(window), 800, 480); //window size
//gtk_window_set_resizable(GTK_WINDOW(window), FALSE); //user cant resize
gtk_window_set_title(GTK_WINDOW(window),"User Display"); //window title
gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &color); //set color to window
align = gtk_alignment_new(.5,.5,0,0); //x,y alignment
lbl = gtk_label_new(NULL); //label init
gchar *str = "<span font='48' weight='bold' color='#DDDDDD'>Not Initialized</span>"; //label text, uses pango markup
gtk_container_add(GTK_CONTAINER(align), lbl); //add label to alignment
gtk_container_add(GTK_CONTAINER(window), align); //add label to window
gtk_label_set_markup(GTK_LABEL(lbl), str); //add pango str to label
g_signal_connect(G_OBJECT(window), "key-release-event", G_CALLBACK(fpcheck), (gpointer) lbl); //calls fpcheck to change label
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window); //build the window all at once
gtk_main();
return 0;
}
If I comment out the gtk_label_set_markup line and g_free(text) line in fpcheck, there's no error but it doesn't do anything, of course. From looking at other online resources, I think this error is being cause by trying to access the GTK_LABEL(lbl) because of the first argument in fpcheck being incorrect, but thats just a guess and I don't know what I'd put there instead. In the example, it's just "Widget," referring to the combo-box, I think, since it gets the text from the selected option.
On that note, I tried removing that argument, and now instead of a segmentation error, I get the following error without even pressing/releasing.
(test:6698): GLib-GObject-WARNING **: invalid cast from 'GtkWindow' to 'GtkLabel'
(test:6698): Gtk-CRITICAL **: IA__gtk_label_set_markup: assertion 'GTK_IS_LABEL (label)' failed
I did a few gdb backtraces, but none of them seem to be particularly helpful. If anyone wants 'em, I can post them.
Any ideas on the problems I'm having?
Thanks.
key-release-event handler has this signature
gboolean
user_function (GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
Your fpcheck() needs to look like that.
It's easier to find problems like this early if you learn the habit of doing e.g. g_assert (GTK_IS_LABEL (user_data)) as the first thing in every handler where the userdata definitely always has to be a label.

Auto scrolling GtkScrolledWindow with GtkTextView wrapped in GtkBox

When I have GtkTextView in GtkScrolledWindow, it scrolls automatically when user appends new line at the bottom of the widget. When I put GtkTextView in GtkBox and then in GtkScrolledWindow I doesn't work. I need to put box between GtkTextView and scrollbar and I can't do that without placing whole thing in another box. Is there any way to preserve autoscrolling behaviour when using GtkBox inside GtkScrolledWindow?
There is code that ilustrates my problem:
#include <gtk/gtk.h>
int main(int argc, char *argv[]) {
GtkWidget *window;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window),
gdk_screen_width()*0.5, gdk_screen_height()*0.5);
GtkWidget *main = gtk_box_new(0, 0);
gtk_container_add(GTK_CONTAINER(window), main);
/*/////////////////////////////////////////////////*/
/* IMPORTANT PART */
/* FIRST CASE (this one works correctly) */
GtkWidget *scrolled_window_first = gtk_scrolled_window_new(NULL, NULL);
GtkWidget *text_view_first = gtk_text_view_new();
gtk_container_add(GTK_CONTAINER(scrolled_window_first), text_view_first);
gtk_box_pack_start(GTK_BOX(main), scrolled_window_first, 1, 1, 0);
/* SECOND CASE (there is no auto scroll which I need) */
GtkWidget *scrolled_window_second = gtk_scrolled_window_new(NULL, NULL);
GtkWidget *text_view_second = gtk_text_view_new();
GtkWidget *box_from_second_example = gtk_box_new(0, 0);
GtkWidget *example_box_before_scroller = gtk_box_new(0,0);
GtkWidget *example_label = gtk_label_new("I need this box badly!");
gtk_box_pack_start(GTK_BOX(box_from_second_example), text_view_second, 1, 1, 0);
gtk_container_add(GTK_CONTAINER(scrolled_window_second), box_from_second_example);
gtk_container_add(GTK_CONTAINER(box_from_second_example), example_box_before_scroller);
gtk_box_pack_start(GTK_BOX(main), scrolled_window_second, 1, 1, 0);
/* END IMPORTANT PART */
/*/////////////////////////////////////////////////*/
gtk_container_add(GTK_CONTAINER(example_box_before_scroller), example_label);
g_signal_connect(GTK_WINDOW(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main ();
return 0;
}
The problem is GtkTextView implements GtkScrollable but GtkBox does not. This is not a minor issue: if you want to go the GtkBox way you should put it inside a GtkViewport and add the scrollability stuff... quite some code that involves deep understanding of how the whole thing scrolls.
Anyway if you are lazy enough you could also note GtkTextview is a GtkContainer. In other words you could add widgets around the GtkTextview without the need to incomodate GtkBox. Not exactly what you were looking for but maybe good enough for your purposes:
#include <gtk/gtk.h>
gint main(gint argc, gchar **argv)
{
GtkWidget *window, *scrolled_window, *text_view, *label;
gtk_init(&argc, &argv);
text_view = gtk_text_view_new();
gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view)),
"1\n\n\n2\n\n\n3\n\n\n4\n\n\n5\n\n\n6\n\n\n7\n\n\n8", -1);
/* Use this to set the size you want to reserve on the right */
gtk_text_view_set_border_window_size(GTK_TEXT_VIEW(text_view),
GTK_TEXT_WINDOW_RIGHT,
130);
/* Add whatever you want instead of a GtkLabel */
gtk_text_view_add_child_in_window(GTK_TEXT_VIEW(text_view),
gtk_label_new("You badly need this"),
GTK_TEXT_WINDOW_RIGHT,
0, 0);
scrolled_window = gtk_scrolled_window_new(NULL, NULL);
gtk_container_add(GTK_CONTAINER(scrolled_window), text_view);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window), 320, 240);
gtk_container_add(GTK_CONTAINER(window), scrolled_window);
gtk_widget_show_all(window);
gtk_main ();
return 0;
}
Did you try to modify the GtkAdjustments the textview creates by default (GtkScrolledWindow implements the GtkScrollable afaik).
GtkAdjustment * gtk_scrollable_get_hadjustment (GtkScrollable *scrollable);
I think the best approach would be to detect insertions to the GtkTextBuffer (get the views buffer via
GtkTextBuffer * gtk_text_view_get_buffer (GtkTextView *text_view);
and hook a callback (which tests for \n) to its insert-text g_signal and use
void gtk_adjustment_set_value (GtkAdjustment *adjustment,
gdouble value);
to modify the scrolling height.
Note that this is untested and a simpler method might be around the corner.

Resources