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

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.

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

How to get 2 textentry in gtk3

I'v been seaching google for 2 weeks now.
2 textentry in a gride.
(ex: userid, password)
Glade let me design that no problem...
For one textentry widget, it working.
I'm compiling/linking with mysql
so I would like to call functions, stored procedures
with entry1 and entry2.
Please help
thanks
:EDIT:
15:18 4 may 2019
I found a conclusive solution.
(But it's throwing seg fault)
bit of code following :
this is some kind of a transcription of the video into text (C code).
https://www.youtube.com/watch?v=_yTmW1QG3uk
obviously according to my goal really...
it's kind of working but let say you want to use the same
instance a second time, "seg fault"
I'm sure I will find the problem (gtk_main_quit) or something,
but the textentry multiples lines is solved :P
here's the code :
#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include <mysql/mysql.h>
GtkEntry *userid, *password;
static void Button_Pressed(GtkWidget *w, gpointer *data){
/* char *userid, *password;*/ //seg fault
/* userid[0]='\0';
password[0]='\0';*/
userid=gtk_entry_get_text(userid);
password=gtk_entry_get_text(password);
g_print("%s\n\r%s\n\r",userid, password);
}
static void CreateWindow(GtkApplication *myapp, gpointer *user_data){
GtkWidget *window;
window=gtk_application_window_new(myapp);
gtk_window_set_title(GTK_WIDGET(window), "Double Entry Solution");
gtk_window_set_default_size(GTK_WINDOW(window),400,400);
GtkWidget *vbox=gtk_vbox_new(FALSE,0);
gtk_container_add(GTK_CONTAINER(window), vbox);
gtk_widget_show(vbox);
// userid pack
userid=gtk_entry_new();
gtk_box_pack_start(GTK_CONTAINER(vbox), userid, TRUE, TRUE,0);
gtk_widget_show(userid);
GtkWidget *hbox=gtk_hbox_new(TRUE,0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
// password pack
password=gtk_entry_new();
gtk_box_pack_start(GTK_BOX(hbox), password, TRUE, TRUE,0);
gtk_widget_show(password);
GtkWidget *submit=gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
gtk_box_pack_start(GTK_BOX(vbox), submit, TRUE, TRUE,0);
GtkWidget *button=gtk_button_new_with_label("Login");
g_signal_connect(button, "clicked", G_CALLBACK(Button_Pressed), NULL);
gtk_container_add(GTK_CONTAINER(submit), button);
gtk_widget_show(button);
gtk_widget_show_all(window);
}
int main(int argc, char** argv){
GtkApplication *doubleentry;
doubleentry=gtk_application_new("smdelectro.business.site.doubleentry", G_APPLICATION_FLAGS_NONE);
g_signal_connect(doubleentry, "activate", G_CALLBACK(CreateWindow), NULL);
g_application_run(G_APPLICATION(doubleentry), argc, argv);
g_object_unref(doubleentry);
return (EXIT_SUCCESS);
}
The code below work :
#include <gtk/gtk.h>
int main(int argc, char **argv)
{
// Init
gtk_init(&argc,&argv);
// Create widgets
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
GtkGrid *grid = GTK_GRID(gtk_grid_new());
// Attach entries
gtk_grid_attach(grid,gtk_entry_new(),0,0,1,1);
gtk_grid_attach(grid,gtk_entry_new(),0,1,1,1);
// Add the grid in the window
gtk_container_add(GTK_CONTAINER(window),GTK_WIDGET(grid));
// Dirty way to force clean termination when window is closed
g_signal_connect(window,"delete-event",G_CALLBACK(gtk_main_quit),NULL);
// Show **everythings** (not only the window)
gtk_widget_show_all(window);
// Main loop
gtk_main();
return 0;
}
Without any source code I can't provide more help, could you post it please.
A common trap in GTK+3 is creating widget without showing them. If you replace gtk_widget_show_all with gtk_widget_show you will see a window without widgets, they are here but not displayed, because by default the visible property is set to FALSE.
finally,
creating c file with reference to xml is ONE way, it's cool, thanks Glade.
Creating pure C Gtk3 is pain... omg
xml parser to generate c code...
aw..
BRB

Cannot reduce size of gtk window programatically

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.

clutter stage in gtk can't not handle stage mouse press event

I have tried to use the clutter-gtk. I wrote a small piece of code that create a gtk window with a clutter stage in it. I try to get mouse button press event on the stage but there is nothing.
Here is the code:
#include <clutter/clutter.h>
#include <clutter-gtk/clutter-gtk.h>
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
/*gcc 3_clutter_app_clickable_text_in_gtk.c -o 3_clutter_app_clickable_text_in_gtk `pkg-config clutter-1.0 clutter-gtk-1.0 glib --cflags --libs`*/
/*mouse clic handler*/
void on_stage_button_press( ClutterStage *stage, ClutterEvent *event, gpointer data)
{
printf("ok\n");
}
int main(int argc, char *argv[])
{
if (gtk_clutter_init(&argc, &argv) != CLUTTER_INIT_SUCCESS)
return EXIT_FAILURE;
/*create the window*/
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (window), 640, 480);
/*destroy from window close all*/
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
/*vertical box, 0 spacing*/
GtkWidget * box = gtk_box_new(GTK_ORIENTATION_VERTICAL,0);
/*add box in the window*/
gtk_container_add(GTK_CONTAINER(window), box);
/*create the cutter widget*/
GtkWidget *clutter_widget = gtk_clutter_embed_new ();
gtk_widget_set_size_request (clutter_widget, 200, 200);
ClutterActor *stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED(clutter_widget));
clutter_stage_set_use_alpha(CLUTTER_STAGE(stage), TRUE);
ClutterColor stage_color ;
GString * bg_color = g_string_new("#555753ff");
clutter_color_from_string(&stage_color,bg_color->str);
clutter_actor_set_background_color(stage, &stage_color);
/*add the cutter widget in the box expand and fill are TRUE and spacing is 0*/
gtk_box_pack_start (GTK_BOX (box), clutter_widget, TRUE, TRUE, 0);
/*create line text*/
ClutterColor text_color;
GString * fg_color = g_string_new("#00000055");
clutter_color_from_string(&text_color, fg_color->str);
ClutterActor *some_text = clutter_text_new_full("Sans 24", "Hello, world", &text_color);
clutter_actor_set_size(some_text, 256, 128);
clutter_actor_set_position(some_text, 128, 128);
clutter_actor_add_child(CLUTTER_ACTOR(stage), some_text);
clutter_text_set_editable(CLUTTER_TEXT(some_text), TRUE);
/*define clic event*/
g_signal_connect(stage, "button-press-event", G_CALLBACK(on_stage_button_press), NULL);
/* Show the window and all its widgets: */
gtk_widget_show_all (GTK_WIDGET (window));
/* Start the main loop, so we can respond to events: */
gtk_main ();
return EXIT_SUCCESS;
}
Nothing happens when I click on the stage. I have made some tests and I can handle click event on the main windows, on the clutter_widget but not directly on the clutter stage.
This code is modified one from http://www.openismus.com/documents/clutter_tutorial/0.9/docs/tutorial/html/sec-stage-widget.html. In this one the author connect the signal directly on the stage but this example is for clutter 0.9 and don't compile anymore with clutter v > 1.0.
Any ideas on what I am doing wrong?
Edit
I have made some test with "key-press-event" which are handled. So the problem seems to come from the events mask of the stage.
Does anyone know how to change the event mask of the stage in order to force the stage to react on mouse events?
I close this question because :
clutter-gtk is just a proof of concept
clutter-gtk will not be used in the future
see https://mail.gnome.org/archives/clutter-list/2013-February/msg00059.html
so I don't want to loose more time with this.
For information,the same example using juste clutter works as expected.
CLUTTER_BACKEND=gdk ./yourexecutable

How to draw / render to a widget using the widgets Xid in GTK/Cairo in 'C'

I have a need to write a GTK application in C that does some animation using Cairo that will render into a GTK widget that exists in another running application. The idea is to do the very same thing you can do with VLC and Mplayer. For example Mplayer has the -wid option:
-wid (also see -guiwid) (X11, OpenGL and DirectX only)
This tells MPlayer to attach to an existing window. Useful to embed MPlayer in a browser (e.g. the plugger extension). This option
fills the given window completely, thus aspect scaling, panscan, etc
are no longer handled by MPlayer but must be managed by the
application that created the window.
With this Mplayer option you can create a GTK application with a GTKImage widget, get it's Xid and then play a movie in the GTK application using Mplayer with the Xid specified.
I'm trying to do the same thing except render/draw into the external window using Cairo. Anybody have suggestions or better yet a small code sample?
Take a look to the GtkSocket and GtkPlug classes.
The main program will create a GtkSocket and the XID you can pass to the other program will be returned by the function gtk_socket_get_id(). Then the other program will use it as argument to the gtk_plug_new() function. All the render will be done in children of this new GtkPlug object.
UPDATE: Well, if you want... here it is a minimal example of GtkSocket/GtkPlug. You don't say if you are using GTK+2 or GTK+3, so I'm assuming version 2.
server.c:
#include <gtk/gtk.h>
int main(int argc, char **argv)
{
gtk_init(&argc, &argv);
GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
GtkWidget *sck = gtk_socket_new();
gtk_container_add(GTK_CONTAINER(wnd), sck);
gtk_window_set_default_size(GTK_WINDOW(wnd), 400, 300);
gtk_widget_show_all(wnd);
GdkNativeWindow nwnd = gtk_socket_get_id(GTK_SOCKET(sck));
g_print("%lu\n", nwnd);
gtk_main();
return 0;
}
client.c:
#include <stdlib.h>
#include <gtk/gtk.h>
#include <cairo/cairo.h>
#include <math.h>
gboolean OnDraw(GtkWidget *w, GdkEvent *ev, gpointer data)
{
GtkAllocation size;
gtk_widget_get_allocation(w, &size);
cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(w));
cairo_set_source_rgb(cr, 1, 0, 0);
cairo_arc(cr, size.width/2, size.height/2, size.height/2, 0, 2*M_PI);
cairo_fill(cr);
cairo_destroy(cr);
return TRUE;
}
int main(int argc, char **argv)
{
gtk_init(&argc, &argv);
GdkNativeWindow nwnd = strtoul(argv[1], NULL, 10);
GtkWidget *plug = gtk_plug_new(nwnd);
GtkWidget *canvas = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER(plug), canvas);
g_signal_connect(canvas, "expose-event", (GCallback)OnDraw, NULL);
gtk_widget_show_all(plug);
gtk_main();
return 0;
}
The XID to be used is printed by the server and has to be copied/pasted as argument to the client:
$ ./server
60817441
^Z
[1]+ Stopped ./server
$ bg
$ ./client 60817441

Resources