I have an App which as some point Opens a new Window and works fine.
Then After I'm done with it, I need to switch back to the main window.
I understood that I need the function:
gtk_widget_hide();
but I cant figure out how to hide the main Window, to print only the second one and again after I click the button in the second window to go back to the first one.
This is what I have so far:
#include <stdio.h>
#include <gtk/gtk.h>
static void crete_new_wind (GtkWidget *widget);
gboolean destroy (GtkWidget *window);
int main (int argc, char *argv[]){
GtkWidget *window, *button, *box;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "First Window");
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
gtk_widget_set_size_request (window, 300, 300);
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
button = gtk_button_new_with_label ("Go to Window B");
g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (crete_new_wind), (gpointer) window);
box = gtk_box_new (TRUE, 1);
gtk_box_pack_end (GTK_BOX (box), button, TRUE, TRUE, 1);
gtk_container_add (GTK_CONTAINER (window), box);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
void crete_new_wind (GtkWidget *widget){
GtkWidget *window, *button, *box;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Second Window");
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
gtk_widget_set_size_request (window, 300, 300);
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);;
g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), widget);
button = gtk_button_new_with_label ("Go back to Window A");
g_signal_connect (G_OBJECT (button), "destroy", G_CALLBACK (destroy), NULL);
gtk_widget_hide(widget);
box = gtk_box_new (TRUE, 1);
gtk_box_pack_end (GTK_BOX (box), button, TRUE, TRUE, 1);
gtk_container_add (GTK_CONTAINER (window), box);
gtk_widget_show_all (window);
}
gboolean destroy (GtkWidget *widget){
gtk_widget_destroy (widget);
return TRUE;
}
If I click on the button(Go to Window B) I have this:
But the main window is still there, avaible to the user which is not what I need.
Thats because the clicked callback wants two parameters
Change the prototype and the function to
static void crete_new_wind(GtkButton *dummy, gpointer widget);
static void crete_new_wind(GtkButton *dummy, gpointer widget) {
in order to use the second parameter in your function.
Related
I have for example this code:
#include <gtk/gtk.h>
static void
print_hello (GtkWidget *widget,
gpointer data)
{
g_print ("Hello World\n");
}
static void
activate (GtkApplication *app,
gpointer user_data)
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *button_box;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
gtk_container_add (GTK_CONTAINER (window), button_box);
button = gtk_button_new_with_label ("Hello World");
g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
gtk_container_add (GTK_CONTAINER (button_box), button);
gtk_widget_show_all (window);
}
int
main (int argc,
char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new ("foo.bar", 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;
}
It looks like this:
How can I automatically resize the window, so it has the perfect size for the one button.
With Java Swing, you could simply call pack(), but I wasn't able to find a similar method for GTK.
For GtkWindow there would be gtk_window_resize, but it requires giving an height and width, so I would have to calculate it manually.
This would work with just one button, but anything more complex would be error-prone and prone to failure.
Is there any equivalent to pack?
I need to pick the user's choice and store the value in a global variable then after the user has chosen the vbox with the buttons should disappear and control be returned to create_window(). I don't know if it is the best method for such a task.
#include "test.h"
int number_players;
void create_window() {
GtkWidget *window;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "test");
gtk_window_maximize (GTK_WINDOW (window));
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
get_number_players(window);
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (destroy), NULL);
gtk_widget_show_all (window);
g_print("%d\n", number_players);
gtk_main();
}
void get_number_players (GtkWidget *window) {
GtkWidget *vbox, *button_choice1, *button_choice2, *button_choice3;
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
button_choice1 = gtk_button_new_with_label("six Players");
button_choice2 = gtk_button_new_with_label("Seven Players");
button_choice3 = gtk_button_new_with_label("nine Players");
gtk_container_add (GTK_CONTAINER (window), vbox);
gtk_container_add (GTK_CONTAINER (vbox), button_choice1);
gtk_container_add (GTK_CONTAINER (vbox), button_choice2);
gtk_container_add (GTK_CONTAINER (vbox), button_choice3);
g_signal_connect(G_OBJECT(button_choice1), "clicked", G_CALLBACK(read_choice), GINT_TO_POINTER(6));
g_signal_connect(G_OBJECT(button_choice2), "clicked", G_CALLBACK(read_choice), GINT_TO_POINTER(7));
g_signal_connect(G_OBJECT(button_choice3), "clicked", G_CALLBACK(read_choice), GINT_TO_POINTER(9));
}
void read_choice (GtkWidget *window, gpointer data) {
number_players = GPOINTER_TO_INT(data);
}
void destroy (GtkWidget *window, gpointer data)
{
gtk_main_quit ();
}
From some reason the global variable number_players is not printed correclty if I print in read_choice though I can see the right value.
Using GTK3 in C, I have an interface with buttons. I want a user with a mouse to be able to press a button OR use press a single button on the keyboard to do the same thing.
MWE (modified from GTK3 Hello World example):
/*
* Ignore keyboard cursor in GTK3 C
*/
#include <gtk/gtk.h>
void thing() {
printf("did a thing\n");
}
void otherthing() {
printf("did something different\n");
}
static gboolean key_event(GtkWidget *widget, GdkEventKey *event) {
gchar* val = gdk_keyval_name (event->keyval);
if (strcmp(val, "Left") == 0) {
thing();
}
return 0;
}
static void activate (GtkApplication *app, gpointer user_data) {
GtkWidget *window;
GtkWidget *button;
GtkWidget *button2;
GtkWidget *button_box;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
gtk_container_add (GTK_CONTAINER (window), button_box);
button = gtk_button_new_with_label ("Do the thing");
button2 = gtk_button_new_with_label ("xxx");
g_signal_connect(window, "key-release-event", G_CALLBACK(key_event), NULL);
g_signal_connect (button, "clicked", G_CALLBACK (thing), window);
g_signal_connect (button2, "clicked", G_CALLBACK (otherthing), window);
gtk_container_add (GTK_CONTAINER (button_box), button2);
gtk_container_add (GTK_CONTAINER (button_box), button);
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;
}
In this program, the user can press the left arrow key to execute thing. The user can also click on the gui button to execute thing. However, hitting certain keyboard keys such as space or enter will "click" on the gui button to execute thing.
How do I prevent the keyboard from "clicking" on a button which the keyboard cursor is on in this case?
Fake Button Hack
I have hacked a workaround into my code for now using a useless button. I will not be marking this answer as solved since it is very sloppy, but it does the job until something better becomes available.
Description
This hack adds another button with no functions assigned. Using gtk_widget_grab_focus, we force this useless "fakebutton" to hold keyboard focus. We reissue this command every time a button is pressed.
Problems
Grabbing focus back to the fakebutton is slow. The user can issue a quick succession of commands (in the case of the MWE by pressing Left and Space to erroneously issue the otherthing function).
MWE
/*
* Ignore keyboard cursor in GTK3 C
*/
#include <gtk/gtk.h>
GtkWidget *fakebutton;
void thing() {
printf("did a thing\n");
}
void otherthing() {
printf("did something different\n");
}
static gboolean key_event(GtkWidget *widget, GdkEventKey *event) {
gchar* val = gdk_keyval_name (event->keyval);
if (strcmp(val, "Left") == 0) {
thing();
gtk_widget_grab_focus(fakebutton);
} else {
gtk_widget_grab_focus(fakebutton);
}
return 0;
}
static void activate (GtkApplication *app, gpointer user_data) {
GtkWidget *window;
GtkWidget *button;
GtkWidget *button2;
GtkWidget *button_box;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
gtk_container_add (GTK_CONTAINER (window), button_box);
button = gtk_button_new_with_label ("Do the thing");
button2 = gtk_button_new_with_label ("xxx");
fakebutton = gtk_button_new();
g_signal_connect(window, "key-release-event", G_CALLBACK(key_event), NULL);
g_signal_connect (button, "clicked", G_CALLBACK (thing), window);
g_signal_connect (button2, "clicked", G_CALLBACK (otherthing), window);
gtk_container_add (GTK_CONTAINER (button_box), button2);
gtk_container_add (GTK_CONTAINER (button_box), fakebutton);
gtk_container_add (GTK_CONTAINER (button_box), button);
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;
}
I want to set the position of the window using gtk_window_set_position
but it seems that after the window is created, the gtk_window_set_position will not take effect.
I'm wondering how to call gtk_window_set_position after the window shows up, i.e. a button event?
I just wrote a minimal working example that implements two approaches. One approach uses gtk_window_move and the other gtk_window_set_position.
If you have the gtk+ reference at hand the code should be self explanatory.
#include <gtk/gtk.h>
#include <glib.h>
void
button1_clicked_cb (GtkWidget * widget, GtkWindow * window)
{
GdkWindow *root;
gint width, height, rwidth, rheight;
gtk_window_get_size (window, &width, &height);
root = gtk_widget_get_root_window (GTK_WIDGET (window));
gdk_window_get_geometry (root, NULL, NULL, &rwidth,
&rheight);
gtk_window_move (window, (rwidth - width) / 2,
(rheight - height) / 2);
}
void
button2_clicked_cb (GtkWidget * widget, GtkWindow * window)
{
gtk_widget_hide (GTK_WIDGET (window));
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_widget_show_all (GTK_WIDGET (window));
}
int
main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *box;
GtkWidget *button1;
GtkWidget *button2;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
button1 = gtk_button_new_with_label ("approach 1");
button2 = gtk_button_new_with_label ("approach 2");
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
gtk_box_pack_start (GTK_BOX (box), button1, TRUE, TRUE,
10);
gtk_box_pack_start (GTK_BOX (box), button2, TRUE, TRUE,
10);
gtk_container_add (GTK_CONTAINER (window), box);
gtk_widget_show_all (window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect (button1, "clicked",
G_CALLBACK (button1_clicked_cb),
window);
g_signal_connect (button2, "clicked",
G_CALLBACK (button2_clicked_cb),
window);
gtk_main ();
return 0;
}
I have developed one popup window (Non decorated) using GTK+ and glade tool in C.
It popup on its parent window when a button clicked. I want to destroy or hide this popup window when user clicks out side this window. User can click on parent window or any other window.
I have tried to capture GDK_FOCUS_CHANGE event but I am not able to capture this event. Is there any way to achieve this? How do I know that click is on other window then pop up window? How is it clear that pop up window has lost it's focus?
So that I can hide it.
The relevant code is as follow:
/*
* Compile me with:
gcc -o popup popup.c $(pkg-config --cflags --libs gtk+-2.0 gmodule-2.0)
*/
#include <gtk/gtk.h>
static void on_popup_clicked (GtkButton*, GtkWidget*);
static gboolean on_popup_window_event(GtkWidget*, GdkEventExpose*);
int main (int argc, char *argv[])
{
GtkWidget *window, *button, *vbox;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Parent window");
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
gtk_widget_set_size_request (window, 300, 300);
gtk_window_set_position (GTK_WINDOW (window),GTK_WIN_POS_CENTER);
button = gtk_button_new_with_label("Pop Up");
g_signal_connect (G_OBJECT (button), "clicked",G_CALLBACK (on_popup_clicked),(gpointer) window);
vbox = gtk_vbox_new (FALSE, 3);
gtk_box_pack_end(GTK_BOX (vbox), button, FALSE, FALSE, 5);
gtk_container_add (GTK_CONTAINER (window), vbox);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
void on_popup_clicked (GtkButton* button, GtkWidget* pWindow)
{
GtkWidget *popup_window;
popup_window = gtk_window_new (GTK_WINDOW_POPUP);
gtk_window_set_title (GTK_WINDOW (popup_window), "Pop Up window");
gtk_container_set_border_width (GTK_CONTAINER (popup_window), 10);
gtk_window_set_resizable(GTK_WINDOW (popup_window), FALSE);
gtk_window_set_decorated(GTK_WINDOW (popup_window), FALSE);
gtk_widget_set_size_request (popup_window, 150, 150);
gtk_window_set_transient_for(GTK_WINDOW (popup_window),GTK_WINDOW (pWindow));
gtk_window_set_position (GTK_WINDOW (popup_window),GTK_WIN_POS_CENTER);
g_signal_connect (G_OBJECT (button), "event",
G_CALLBACK (on_popup_window_event),NULL);
GdkColor color;
gdk_color_parse("#3b3131", &color);
gtk_widget_modify_bg(GTK_WIDGET(popup_window), GTK_STATE_NORMAL, &color);
gtk_widget_show_all (popup_window);
}
gboolean on_popup_window_event(GtkWidget *popup_window, GdkEventExpose *event)
{
if(event->type == GDK_FOCUS_CHANGE)
gtk_widget_hide (popup_window);
return FALSE;
}
Here I am not able to hide this pop up window when user clicks on parent window or on other window. How can I do this?
I have to stick with Gtk+2.14 version.
Changes:
switch from GTK_WINDOW_POPUP to GTK_WINDOW_TOPLEVEL, counter-intuitive, but I could not figure out how to get a popup to accept focus.
add gtk_window hints to prevent popup from showing in taskbar and pager
intentionally set the focus on the popup window
set the GDK_FOCUS_CHANGE_MASK on the GDK_WINDOW with gtk_widget_set_events (required for the next step)
connect to the focus-out-event of the popup window
change the signal handler to handle a different signal
I would also suggest reading the GTK+ source to see how it handles popup windows for tooltips and menus when they are shown... but those are usually destroyed based on the mouse moving out of range, not the popup losing focus, per se.
#include
static void on_popup_clicked (GtkButton*, GtkWidget*);
gboolean on_popup_focus_out (GtkWidget*, GdkEventFocus*, gpointer);
int
main (int argc, char *argv[])
{
GtkWidget *window, *button, *vbox;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Parent window");
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
gtk_widget_set_size_request (window, 300, 300);
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
button = gtk_button_new_with_label ("Pop Up");
g_signal_connect (G_OBJECT (button),
"clicked",
G_CALLBACK (on_popup_clicked),
(gpointer) window);
vbox = gtk_vbox_new (FALSE, 3);
gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 5);
gtk_container_add (GTK_CONTAINER (window), vbox);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
void
on_popup_clicked (GtkButton* button, GtkWidget* pWindow)
{
GtkWidget *popup_window;
popup_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (popup_window), "Pop Up window");
gtk_container_set_border_width (GTK_CONTAINER (popup_window), 10);
gtk_window_set_resizable (GTK_WINDOW (popup_window), FALSE);
gtk_window_set_decorated (GTK_WINDOW (popup_window), FALSE);
gtk_window_set_skip_taskbar_hint (GTK_WINDOW (popup_window), TRUE);
gtk_window_set_skip_pager_hint (GTK_WINDOW (popup_window), TRUE);
gtk_widget_set_size_request (popup_window, 150, 150);
gtk_window_set_transient_for (GTK_WINDOW (popup_window), GTK_WINDOW (pWindow));
gtk_window_set_position (GTK_WINDOW (popup_window), GTK_WIN_POS_CENTER);
gtk_widget_set_events (popup_window, GDK_FOCUS_CHANGE_MASK);
g_signal_connect (G_OBJECT (popup_window),
"focus-out-event",
G_CALLBACK (on_popup_focus_out),
NULL);
GdkColor color;
gdk_color_parse ("#3b3131", &color);
gtk_widget_modify_bg (GTK_WIDGET (popup_window), GTK_STATE_NORMAL, &color);
gtk_widget_show_all (popup_window);
gtk_widget_grab_focus (popup_window);
}
gboolean
on_popup_focus_out (GtkWidget *widget,
GdkEventFocus *event,
gpointer data)
{
gtk_widget_destroy (widget);
return TRUE;
}
You don't need to set keyboard focus to your popup window.
You just need to capture mouse to your popup_window->window using gdk_pointer_grab(...) with True owner_events and GDK_BUTTON_PRESS_MASK GdkEventMask arguments.
Then connect your popup_window to "button-press-event". Inside it's handler hide/destroy your popup_window and release capture using gdk_pointer_ungrab(...) if *event coordinates are negative or higher than your popup_window size.
Another alternative is to simply add a button press listener to the parent window. This has the advantage that the popup window still looks like a popup (both the parent and itself can be active at once)
#include <stdio.h>
#include <gtk/gtk.h>
static void on_popup_clicked (GtkButton*, GtkWidget*);
gulong handler_id;
gboolean
on_click (GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
{
g_signal_handler_disconnect (widget, handler_id);
gtk_widget_destroy (user_data);
return TRUE;
}
gboolean
on_popup_focus_out (GtkWidget *widget,
GdkEventFocus *event,
gpointer data)
{
gtk_widget_destroy (widget);
return TRUE;
}
int
main (int argc, char *argv[])
{
GtkWidget *window, *button, *vbox;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Parent window");
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
gtk_widget_set_size_request (window, 300, 300);
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
button = gtk_button_new_with_label ("Pop Up");
g_signal_connect (G_OBJECT (button),
"clicked",
G_CALLBACK (on_popup_clicked),
(gpointer) window);
vbox = gtk_vbox_new (FALSE, 3);
gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 5);
gtk_container_add (GTK_CONTAINER (window), vbox);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
void
on_popup_clicked (GtkButton* button, GtkWidget* pWindow)
{
GtkWidget *popup_window;
popup_window = gtk_window_new (GTK_WINDOW_POPUP);
gtk_window_set_title (GTK_WINDOW (popup_window), "Pop Up window");
gtk_container_set_border_width (GTK_CONTAINER (popup_window), 10);
gtk_window_set_resizable (GTK_WINDOW (popup_window), FALSE);
gtk_window_set_decorated (GTK_WINDOW (popup_window), FALSE);
gtk_window_set_skip_taskbar_hint (GTK_WINDOW (popup_window), TRUE);
gtk_window_set_skip_pager_hint (GTK_WINDOW (popup_window), TRUE);
gtk_widget_set_size_request (popup_window, 150, 150);
gtk_window_set_transient_for (GTK_WINDOW (popup_window), GTK_WINDOW (pWindow));
gtk_window_set_position (GTK_WINDOW (popup_window), GTK_WIN_POS_CENTER);
gtk_widget_add_events (popup_window, GDK_FOCUS_CHANGE_MASK);
gtk_widget_add_events (pWindow, GDK_BUTTON_PRESS_MASK);
g_signal_connect (G_OBJECT (popup_window),
"focus-out-event",
G_CALLBACK (on_popup_focus_out),
NULL);
handler_id = g_signal_connect (G_OBJECT (pWindow),
"button-press-event",
G_CALLBACK (on_click),
popup_window);
GdkColor color;
gdk_color_parse ("#3b3131", &color);
gtk_widget_modify_bg (GTK_WIDGET (popup_window), GTK_STATE_NORMAL, &color);
gtk_widget_show_all (popup_window);
gtk_widget_grab_focus (popup_window);
}