Cannot get g_signal_connect to pass parameters correctly. Its probably because I do not understand the "c_handler" or "data" parameters. The code is here:
#include <gtk/gtk.h>
// Function prototypes
void my_file_saveas();
// Function
void my_file_saveas(GtkTextBuffer *buf)
{
// Get the start and end bounds of the buffer
GtkTextIter start, end;
gtk_text_buffer_get_bounds (buf, &start, &end);
}
int main(int argc, char *argv[])
{
GtkWidget *menubar;
GtkWidget *fileMenu;
GtkWidget *fileMh;
GtkWidget *saveasMi;
GtkWidget *view;
GtkTextBuffer *buffer;
GtkWidget *scroll_window;
GtkWidget *vbox;
GtkWidget *window;
// Call this function first
gtk_init(&argc, &argv);
// Create widgets
menubar = gtk_menu_bar_new();
fileMenu = gtk_menu_new();
fileMh = gtk_menu_item_new_with_label("File");
saveasMi = gtk_menu_item_new_with_label("Save As");
view = gtk_text_view_new();
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
// Set out the menubar
gtk_menu_shell_append(GTK_MENU_SHELL(fileMenu), saveasMi);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(fileMh), fileMenu);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), fileMh);
// Create a scroll window and add the view to it
scroll_window = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add(GTK_CONTAINER(scroll_window), view);
// Create a vertical box and add the menubar and scroll_window
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), scroll_window, TRUE, TRUE, 0);
// Setup top level window
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 640, 480);
// Put the box in the top level window
gtk_container_add(GTK_CONTAINER(window), vbox);
// Events
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(G_OBJECT(saveasMi), "activate", G_CALLBACK(my_file_saveas), buffer);
// Display the window
gtk_widget_show_all(window);
// Runs main
gtk_main();
return 0;
}
It compiles OK. But the output when I run it is here:
graeme#graeme-HP-xw4300-Workstation ~/c/test $ ./ed10
(ed10:2974): Gtk-CRITICAL **: gtk_text_buffer_get_bounds: assertion 'GTK_IS_TEXT_BUFFER (buffer)' failed
Your error is self-explanatory (kind of):
(debugsig:26923): Gtk-CRITICAL **: gtk_text_buffer_get_bounds:
assertion 'GTK_IS_TEXT_BUFFER (buffer)' failed
Looking at your code -- you do not declare an independent GTK_TEXT_BUFFER (e.g. GtkTextBuffer *). gtk_text_view_new will provide a default buffer, but you can alternatively use gtk_text_view_new_with_buffer (buffer) if you independently declare a buffer with, e.g. gtk_text_buffer_new (NULL); (you will get a default buffer with either gtk_text_view_new or gtk_text_view_new_with_buffer (NULL);). Your choice..., what you have will work.
Your real problem is your callback function prototype is wrong, it should contain your menuitem (that is the real issue, it is taking your buffer as a GtkMenuItem causing the error 'GTK_IS_TEXT_BUFFER (buffer)' failed), e.g.
void my_file_saveas (GtkMenuItem *menuitem, gpointer data)
{
// Get the start and end bounds of the buffer
GtkTextBuffer *buf = GTK_TEXT_BUFFER (data);
GtkTextIter start, end;
gtk_text_buffer_get_bounds (buf, &start, &end);
/* print the number of lines to stdout */
g_print ("Buffer has %d lines.\n", gtk_text_iter_get_line (&end) -
gtk_text_iter_get_line (&start) + 1);
if (menuitem) {} /* stub to suppress warning of unused menuitem */
}
Candidly, I cannot believe it let you compile without error (or warning), but it did, I compiled with:
gcc -Wall -Wextra -pedantic -finline-functions -std=gnu11 ...
and it let me compile with the incorrect prototype too -- wrapped me around the axle for a bit :)
Here is a working example of your code:
#include <gtk/gtk.h>
// Function
void my_file_saveas (GtkMenuItem *menuitem, gpointer data)
{
// Get the start and end bounds of the buffer
GtkTextBuffer *buf = GTK_TEXT_BUFFER (data);
GtkTextIter start, end;
gtk_text_buffer_get_bounds (buf, &start, &end);
g_print ("Buffer has %d lines.\n", gtk_text_iter_get_line (&end) -
gtk_text_iter_get_line (&start) + 1);
if (menuitem) {} /* stub to suppress warning of unused menuitem */
}
int main(int argc, char *argv[])
{
GtkWidget *menubar;
GtkWidget *fileMenu;
GtkWidget *fileMh;
GtkWidget *saveasMi;
GtkWidget *view;
GtkTextBuffer *buffer = NULL;
GtkWidget *scroll_window;
GtkWidget *vbox;
GtkWidget *window;
// Call this function first
gtk_init(&argc, &argv);
// Create widgets
menubar = gtk_menu_bar_new();
fileMenu = gtk_menu_new();
fileMh = gtk_menu_item_new_with_label("File");
saveasMi = gtk_menu_item_new_with_label("Save As");
/** example declaring independent buffer
*
* buffer = gtk_text_buffer_new (NULL);
* view = gtk_text_view_new_with_buffer(buffer);
*/
view = gtk_text_view_new();
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
if (!view || !buffer) {
g_print ("error - no view or buf.\n");
return 1;
}
// Set out the menubar
gtk_menu_shell_append(GTK_MENU_SHELL(fileMenu), saveasMi);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(fileMh), fileMenu);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), fileMh);
// Create a scroll window and add the view to it
scroll_window = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add(GTK_CONTAINER(scroll_window), view);
// Create a vertical box and add the menubar and scroll_window
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), scroll_window, TRUE, TRUE, 0);
// Setup top level window
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 640, 480);
// Put the box in the top level window
gtk_container_add(GTK_CONTAINER(window), vbox);
// Events
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(G_OBJECT(saveasMi), "activate", G_CALLBACK(my_file_saveas),
buffer);
// Display the window
gtk_widget_show_all(window);
// Runs main
gtk_main();
return 0;
}
If you want to look at a bit of a larger example (GTK+2, but 100% applicable here), take a look at https://github.com/drankinatty/gtkwrite. (The textview and buffer declarations are in gtk_windef.c)
Related
I am programming on linux program and I am trying to prepare program with GTK+3, but I don't know how close program automatically after execute the function without kill that execute.
the step that i want in my program is:
open gtk window and this window there is button (open Xreader).
press button, it tells system to execute xreader program.
close gtk window automatically without needing to close xreader .
here is my code
#include<stdio.h>
#include<gtk/gtk.h>
static void
open_app(GtkWidget *Widget, gpointer data){
system("xreader");
gtk_main_quit();
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *button1;
gtk_init(&argc, &argv);
/*make window */
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
/*give name to the window*/
gtk_window_set_title(GTK_WINDOW(window), "launcher");
/*make size of window*/
gtk_window_set_default_size(GTK_WINDOW(window), 700, 700);
/*open the window in the meddal*/
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
button1 = gtk_button_new_with_label("Open Xreader");
gtk_container_add(GTK_CONTAINER(window), button1);
gtk_widget_show_all(window);
g_signal_connect(button1,"clicked",G_CALLBACK(open_app), NULL);
g_signal_connect(window, "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_main();
return 0;
}
everytime trying to execute my program and press the button (open Xreader) gtk not close till close xreader .
You cannot use system here, because according to its documentation, https://man7.org/linux/man-pages/man3/system.3.html
system() returns after the command has been completed.
Since you are using gtk, don't forget library functions provided by glib. It has a bunch of functions related to process and thread handling. For example, you can use GSubprocess class from glib, g_subprocess_new.
#include <gtk/gtk.h>
#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
static void open_app(GtkWidget *Widget, gpointer data) {
g_subprocess_new(G_SUBPROCESS_FLAGS_NONE, NULL, "xreader", NULL);
gtk_main_quit();
}
int main(int argc, char *argv[]) {
GtkWidget *window;
GtkWidget *button1;
gtk_init(&argc, &argv);
/*make window */
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
/*give name to the window*/
gtk_window_set_title(GTK_WINDOW(window), "launcher");
/*make size of window*/
gtk_window_set_default_size(GTK_WINDOW(window), 700, 700);
/*open the window in the meddal*/
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
button1 = gtk_button_new_with_label("Open Xreader");
gtk_container_add(GTK_CONTAINER(window), button1);
gtk_widget_show_all(window);
g_signal_connect(button1, "clicked", G_CALLBACK(open_app), NULL);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_main();
return 0;
}
I am trying to make UI using GTK in c for raspberry pi 4. I want to change the visibility of different widgets based on button click just to simulate a new page. I have tried everything available on the internet but as I am not that good at coding I cant figure out what is wrong.
can someone please help ?
This program compiles but when I press the button it gives error " assertion failed on gtk_widget_show " and also on widget hide. Also a segmentation fault occurs and the program crashes.
I am using cmake to compile my code. I have attached the error screen shot.
#include <gtk/gtk.h>
typedef struct AppData
{
GtkWidget *label1;
GtkWidget *label2;
} AppData;
static void button1 (gpointer data)
{
AppData *data2 = (AppData*)data;
gtk_widget_hide(data2->label1);
gtk_widget_show(data2->label2);
}
static void button2 ( gpointer data)
{
AppData *data2 = (AppData*)data;
gtk_widget_show(data2->label1);
gtk_widget_hide(data2->label2);
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *fixed;
GtkWidget *btn1;
GtkWidget *btn2;
GtkWidget *box1;
GtkWidget *box2;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "ethercat test 1");
gtk_window_set_default_size(GTK_WINDOW(window), 1000,500);
fixed = gtk_fixed_new();
gtk_container_add(GTK_CONTAINER(window), fixed);
box1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 1);
gtk_fixed_put(GTK_FIXED(fixed), box1, 0,0);
box2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 1);
gtk_fixed_put(GTK_FIXED(fixed), box2, 100,100);
AppData *app_data = g_new0 (AppData, 2);
app_data->label1 = gtk_label_new("label1");
gtk_box_pack_start(GTK_BOX(box1),app_data->label1, TRUE,TRUE,0);
app_data->label2 = gtk_label_new("label2");
gtk_box_pack_start(GTK_BOX(box2),app_data->label2, TRUE,TRUE,0);
btn1 = gtk_button_new_with_label("ethercat 1");
gtk_fixed_put(GTK_FIXED(fixed), btn1, 10, 450);
gtk_widget_set_size_request(btn1, 80,30);
btn2 = gtk_button_new_with_label("ethercat 2");
gtk_fixed_put(GTK_FIXED(fixed), btn2, 110, 450);
gtk_widget_set_size_request(btn2, 80,30);
gtk_widget_show_all(window);
g_signal_connect(G_OBJECT(btn1), "clicked", G_CALLBACK(button1), app_data);
g_signal_connect(G_OBJECT(btn2), "clicked", G_CALLBACK(button2), app_data);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_main();
printf("program end\n");
return (0);
}
enter image description here
The function signature of your "clicked" callbacks is wrong. It should be of the form as described in the documentation:
void on_clicked(
GtkButton* self,
gpointer user_data
)
So for example, your button2() function becomes
static void button2 (GtkButton *btn2, gpointer data)
{
AppData *data2 = (AppData*)data;
gtk_widget_show(data2->label1);
gtk_widget_hide(data2->label2);
}
I have a C GTK3 program that has a notebook with two images. I want to be able to grab the corner of the window and adjust the size of the image currently displayed. What I currently have is a program that once started, the window keeps growing until I kill it from the terminal using ctrl-c. I put a sleep call in the callback to slow it down, but it still grows. How do I stop the window from growing unless I "grab" a corner of the window and adjust it myself?
#include <stdio.h>
#include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
GtkWidget *notebook;
gboolean resize_image(GtkWidget *widget, GdkRectangle *allocation,
gpointer user_data)
{
int w,h, pagenum;
GdkPixbuf *pxbscaled;
GtkWidget *image;
GdkPixbuf *pixbuf;
pagenum = gtk_notebook_get_current_page (GTK_NOTEBOOK(notebook));
image = gtk_notebook_get_nth_page (GTK_NOTEBOOK(notebook), pagenum);
// GtkImageType image_type = gtk_image_get_storage_type
// (GTK_IMAGE(image));
pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(image));
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);
printf("Allocation height %d width %d.\n", h, w);
gtk_image_set_from_pixbuf(GTK_IMAGE(image), pxbscaled);
g_object_unref (pxbscaled);
sleep(2);
return FALSE;
}
static gboolean delete( GtkWidget *widget,
GtkWidget *event,
gpointer data )
{
gtk_main_quit ();
return FALSE;
}
int main( int argc,
char *argv[] )
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *table;
GtkWidget *label;
GtkWidget *image;
int i;
char bufferl[32];
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
// gtk_widget_set_size_request (GTK_WIDGET(window), 800, 480);
g_signal_connect (window, "delete-event",
G_CALLBACK (delete), NULL);
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
table = gtk_grid_new ();
gtk_container_add (GTK_CONTAINER (window), table);
/* Create notebook, place position of tabs */
notebook = gtk_notebook_new ();
gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
gtk_grid_attach (GTK_GRID (table), notebook, 0, 6, 3, 3);
gtk_widget_show (notebook);
/* Append pages to the notebook */
for (i = 0; i < 2; i++) {
sprintf(bufferl, "Page %d", i + 1);
if (i == 0) {
image = gtk_image_new_from_file("image1.jpg");
} else {
image = gtk_image_new_from_file("image2.jpg");
}
gtk_widget_set_halign(image, GTK_ALIGN_START);
gtk_widget_set_valign(image, GTK_ALIGN_START);
g_signal_connect(window, "size-allocate",
G_CALLBACK(resize_image), NULL);
label = gtk_label_new (bufferl);
gtk_notebook_append_page (GTK_NOTEBOOK(notebook),
image, label);
}
/* Create a close button */
button = gtk_button_new_with_label ("close");
g_signal_connect (button, "clicked",
G_CALLBACK (delete), NULL);
gtk_grid_attach (GTK_GRID (table), button, 0, 10, 1, 1);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
A user will need to provide image1.jpg and image2.jpg. Edit out the sleep call will result in the program filling the screen extremely quickly.
EDIT: I have also asked this question on the gtk mailing list.
The window with the image was growing because I was applying the size of the window to the image. Hence the image got larger and thus made the window get larger. Which continued in an endless progression, the "size-allocate" signal was constantly being called.
I fixed it by limiting the allocation height in the call back, by multiplying it by 0.75.
Now I can expand and contract the window with ease and it does not grow out of control.
The image does get ugly quite quickly, but that is another problem.
I am receiving this error and not sure why...Please take a look at my buttons array, maybe I messed smth there, I am not sure...
The error i get is: Xlib: extension "RANDR" missing on display ":24.0".
and nothing happens after that, meaning my program doesnt run at all....
#include <gtk/gtk.h>
/* Our new improved callback. The data passed to this function
* is printed to stdout. */
static void callback (GtkWidget *widget, gpointer data)
{
system ((gchar *) data);
}
/* another callback */
static gboolean delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
{
gtk_main_quit ();
return FALSE;
}
int main (int argc, char *argv[])
{
/* GtkWidget is the storage type for widgets */
GtkWidget *window;
GtkWidget *box1;
/* This is called in all GTK applications. Arguments are parsed
* from the command line and are returned to the application. */
gtk_init (&argc, &argv);
/* Create a new window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
/* This is a new call, which just sets the title of our
* new window to "My Assignments" */
gtk_window_set_title (GTK_WINDOW (window), "My Assignments");
/* Here we just set a handler for delete_event that immediately
* exits GTK. */
g_signal_connect (window, "delete-event",
G_CALLBACK (delete_event), NULL);
/* Sets the border width of the window. */
gtk_container_set_border_width (GTK_CONTAINER (window), 50);
/* We create a box to pack widgets into. This is described in detail
* in the "packing" section. The box is not really visible, it
* is just used as a tool to arrange widgets. */
box1 = gtk_vbox_new (FALSE,0);
/* Put the box into the main window. */
gtk_container_add (GTK_CONTAINER (window), box1);
/*array is here*/
GtkWidget *button[2];
int i;
for (i=0; i<2; i++)
{
button[i]=gtk_button_new();
}
button[0] = gtk_button_new_with_label ("Run shellscript");
g_signal_connect (button[0], "clicked",
G_CALLBACK (callback), "shellscript");
gtk_box_pack_start (GTK_BOX (box1), button[0], TRUE, TRUE, 0);
gtk_widget_show(button[0]);
button[1] = gtk_button_new_with_label ("Run program2 ");
g_signal_connect (button[1], "clicked",
G_CALLBACK (callback), "program");
gtk_box_pack_start (GTK_BOX (box1), button[1], TRUE, TRUE, 0);
gtk_widget_show(button[1]);
gtk_widget_show (box1);
/* Rest in gtk_main and wait for the fun to begin! */
gtk_main ();
return 0;
}
I have a gtk_window which contain 4 buttons.
One of these buttons will open a file selection dialog (another function) which - when the file has been choosed - will show up a dialog with 3 gtk_entry (this function).
static void function_with_3_gtk_entry (gchar *message, gpointer mainwin){
GtkWidget *dialog, *label, *content_area, *entry1, *entry2, *entry3;
/* Create the widgets */
dialog = gtk_dialog_new_with_buttons ("Nome File", mainwin, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_NONE, NULL);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
entry1 = gtk_entry_new();
entry2 = gtk_entry_new();
entry3 = gtk_entry_new();
gtk_widget_set_size_request(dialog, 250, 200);
/* Ensure that the dialog box is destroyed when the user responds */
g_signal_connect_swapped (dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog);
/* Add the label, and show everything we've added to the dialog */
gtk_container_add (GTK_CONTAINER (content_area), entry1);
gtk_container_add (GTK_CONTAINER (content_area), entry2);
gtk_container_add (GTK_CONTAINER (content_area), entry3);
gtk_widget_show_all (dialog);
}
My questions are:
can i use another gtk_window into this function instead of a gtk_dialog?
how can i set the dialog not resizable?
The code snippet below has two functions:
create_dialog() creates a dialog which cannot be resized, as requested.
create_window() creates a window, within a function, as requested.
Hope this helps.
#include <gtk/gtk.h>
/* Create a dialog, which cannot be resized by the user. */
void create_dialog(GtkWidget *button, gpointer window) {
GtkWidget *dialog, *label, *content_area;
/* New label for dialog content */
label = gtk_label_new("This is a dialog!");
/* Make a new dialog with an 'OK' button */
dialog = gtk_dialog_new_with_buttons("This is a dialog, which (shouldn't | can't) be resized!", window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_NONE, NULL);
/* Add label to dialog */
content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
gtk_container_add(GTK_CONTAINER(content_area), label);
/* Destroy dialog properly */
g_signal_connect(dialog, "response", G_CALLBACK(gtk_widget_destroy), dialog);
/* Set dialog to not resize. */
gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
gtk_widget_show_all(dialog);
}
/* Create a window, while in a function! */
void create_window(GtkWidget *button, gpointer window) {
GtkWidget *new_window, *label;
/*New label for dialog content */
label = gtk_label_new("This is a window, created in a function!");
/* Create new window */
new_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
/* Add label to window */
gtk_container_add(GTK_CONTAINER(new_window), label);
gtk_widget_show_all(new_window);
}
/* Boring implementation bits */
gint main(gint argc, char **argv) {
/* Initialise GTK+ */
gtk_init(&argc, &argv);
GtkWidget *main_win, *dialog_button, *window_button, *button_container;
/* Create a button, one for each function. */
dialog_button = gtk_button_new_with_label("Create dialog!");
window_button = gtk_button_new_with_label("Create window!");
/* Pack buttons into a box. */
button_container = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
gtk_box_pack_start(GTK_BOX(button_container), dialog_button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(button_container), window_button, FALSE, FALSE, 0);
/* Connect signals to button callback functions */
g_signal_connect(dialog_button, "clicked", G_CALLBACK(create_dialog), main_win);
g_signal_connect(window_button, "clicked", G_CALLBACK(create_window), main_win);
/* Create a new window, show it, and run GTK+ */
main_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(main_win, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_container_add(GTK_CONTAINER(main_win), button_container);
gtk_widget_show_all(main_win);
gtk_main();
return 0;
}