Dereferencing a String Vector in C++ when passing to GTK callback - c++

I have this code which is trying to pass a vector to a callback function:
static void displayvecchoices( GtkWidget *widget, gpointer data ) {
std::vector<std::string> vecp = *(std::vector<std::string> *)(data);
std::cout<<"vec: "<<vecp[0]<<std::endl;
}
int main(int argc, char *argv[] ) {
GtkWidget *window;
GtkWidget *display;
gtk_init(&argc, &argv);
window = gtk_dialog_new ();
g_signal_connect (window, "destroy", G_CALLBACK (destroy), NULL);
gtk_window_fullscreen (GTK_WINDOW(window));
std::vector<std::string> vec;
vec.push_back("1");
display = gtk_button_new_with_label ("Display");
g_signal_connect_swapped (display, "clicked", G_CALLBACK (displayvecchoices), &vec);
gtk_widget_set_can_default (display, TRUE);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), display, TRUE, TRUE, 0);
gtk_widget_grab_default (display);
gtk_widget_show (display);
gtk_main();
return 0;
}
When the button display is clicked, I get an error of 'bad alloc' and the program crashes.
When I try this:
std::vector<std::string>* vecp = (std::vector<std::string> *)(data);
std::cout<<"vec: "<<(*vecp)[0]<<std::endl;
It prints out vec: but no element and the size is said to be 18446744073706420840 of the vector.

It looks, your callback arguments are swapped:
you should either use g_signal_connect_object instead of g_signal_connect_swapped or
change displayvecchoices declaration to
static void displayvecchoices(gpointer data, GtkWidget *widget)

Related

Proper way of building Gtk system tray in c++

int main(int argc, char *argv[])
{
gtk_init (&argc, &argv);
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "GtkStatusIcon Example");
gtk_widget_set_size_request (window, 200, -1);
set try icon file
GtkStatusIcon *trayIcon = gtk_status_icon_new_from_file ("/root/Desktop/icon.png");
set popup menu for tray icon
GtkWidget *menu, *menuItemView, *menuItemExit;
menu = gtk_menu_new();
menuItemView = gtk_menu_item_new_with_label ("View");
menuItemExit = gtk_menu_item_new_with_label ("Exit");
g_signal_connect (G_OBJECT (menuItemView), "activate", G_CALLBACK (trayView), window);
g_signal_connect (G_OBJECT (menuItemExit), "activate", G_CALLBACK (trayExit), NULL);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuItemView);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuItemExit);
gtk_widget_show_all (menu);
}
//gcc trayicon.c -o trayicon pkg-config --cflags --libs gtk+-2.0.
#include <gtk/gtk.h>
static void trayView(GtkMenuItem *item, gpointer user_data);
static void trayExit(GtkMenuItem *item, gpointer user_data);
static void trayIconActivated(GObject *trayIcon, gpointer data);
static void trayIconPopup(GtkStatusIcon *status_icon, guint button, guint32 activate_time, gpointer popUpMenu);
static void destroy (GtkWidget*, gpointer);
static gboolean delete_event (GtkWidget*, GdkEvent*, gpointer);
static gboolean window_state_event (GtkWidget *widget, gdkEventWindowState *event, gpointer user_data);
int main(int argc, char *argv[])
{
gtk_init (&argc, &argv);
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "GtkStatusIcon Example");
gtk_widget_set_size_request (window, 200, -1);
//set try icon file
GtkStatusIcon *trayIcon = gtk_status_icon_new_from_file ("/root/Desktop/icon.png");
//set popup menu for tray icon
GtkWidget *menu, *menuItemView, *menuItemExit;
menu = gtk_menu_new();
menuItemView = gtk_menu_item_new_with_label ("View");
menuItemExit = gtk_menu_item_new_with_label ("Exit");
g_signal_connect (G_OBJECT (menuItemView), "activate", G_CALLBACK (trayView), window);
g_signal_connect (G_OBJECT (menuItemExit), "activate", G_CALLBACK (trayExit), NULL);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuItemView);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuItemExit);
gtk_widget_show_all (menu);
//set tooltip
gtk_status_icon_set_tooltip (trayIcon, "MsgWatcherGTK");
//connect handlers for mouse events
g_signal_connect(GTK_STATUS_ICON (trayIcon), "activate", GTK_SIGNAL_FUNC (trayIconActivated), window);
g_signal_connect(GTK_STATUS_ICON (trayIcon), "popup-menu", GTK_SIGNAL_FUNC (trayIconPopup), menu);
gtk_status_icon_set_visible(trayIcon, FALSE); //set icon initially invisible
GtkWidget *menuBar, *menuItemTopLvl, *mainMenu, *mainMenuItemExit;
menuBar = gtk_menu_bar_new ();
menuItemTopLvl = gtk_menu_item_new_with_label ("Menu");
gtk_menu_shell_append (GTK_MENU_SHELL (menuBar), menuItemTopLvl);
mainMenu = gtk_menu_new ();
gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuItemTopLvl), mainMenu);
mainMenuItemExit = gtk_menu_item_new_with_label ("Quit");
g_signal_connect (G_OBJECT (mainMenuItemExit), "activate", G_CALLBACK (trayExit), NULL);
gtk_menu_shell_append (GTK_MENU_SHELL (mainMenu), mainMenuItemExit);
g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL);
g_signal_connect (G_OBJECT (window), "delete_event", G_CALLBACK (delete_event), trayIcon);
g_signal_connect (G_OBJECT (window), "window-state-event", G_CALLBACK (window_state_event), trayIcon);
gtk_container_add (GTK_CONTAINER (window), menuBar);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
static void trayView(GtkMenuItem *item, gpointer window)
{
gtk_widget_show(GTK_WIDGET(window));
gtk_window_deiconify(GTK_WINDOW(window));
}
static void trayExit(GtkMenuItem *item, gpointer user_data)
{
printf("exit");
gtk_main_quit();
}
static void trayIconActivated(GObject *trayIcon, gpointer window)
{
gtk_widget_show(GTK_WIDGET(window));
gtk_window_deiconify(GTK_WINDOW(window));
}
static void trayIconPopup(GtkStatusIcon *status_icon, guint button, guint32 activate_time, gpointer popUpMenu)
{
gtk_menu_popup(GTK_MENU(popUpMenu), NULL, NULL, gtk_status_icon_position_menu, status_icon, button, activate_time);
}
static void destroy (GtkWidget *window, gpointer data)
{
gtk_main_quit ();
}
static gboolean delete_event (GtkWidget *window, GdkEvent *event, gpointer data)
{
return FALSE;
}
static gboolean window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer trayIcon)
{
if(event->changed_mask == GDK_WINDOW_STATE_ICONIFIED && (event->new_window_state == GDK_WINDOW_STATE_ICONIFIED || event->new_window_state == (GDK_WINDOW_STATE_ICONIFIED | GDK_WINDOW_STATE_MAXIMIZED)))
{
gtk_widget_hide (GTK_WIDGET(widget));
gtk_status_icon_set_visible(GTK_STATUS_ICON(trayIcon), TRUE);
}
else if(event->changed_mask == GDK_WINDOW_STATE_WITHDRAWN && (event->new_window_state == GDK_WINDOW_STATE_ICONIFIED || event->new_window_state == (GDK_WINDOW_STATE_ICONIFIED | GDK_WINDOW_STATE_MAXIMIZED)))
{
gtk_status_icon_set_visible(GTK_STATUS_ICON(trayIcon), FALSE);
}
return TRUE;
}

GTK Blinks when drawing

I'm really new with GTK, and im trying to learn how to handle it for a project i have in mind.
The thing is, i could manage to make an app for placing "Generators" on a window ... Each time i click on the screen, the app place a gen in the window, and prepare another one ready to be placed ...
The problem is that the program blinks when is drawing all the generators ...
Each gen has to redraw itself all the time, and this is i think the problem... Here is the code ... how can i make it faster? ... Thanks in advance!!
// gcc main.c -o main `pkg-config gtk+-3.0 --cflags --libs`
#include <gtk/gtk.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
using namespace std;
class Gen{
public:
int x;
int y;
GdkPixbuf *pix;
GtkWidget *canvas;
bool placed;
Gen(GtkWidget *canvas){
this->canvas=canvas;
GError *err = NULL;
pix = gdk_pixbuf_new_from_file("./Img/gen.png", &err);
pix= gdk_pixbuf_scale_simple(pix,50,50, GDK_INTERP_BILINEAR);
x=10;y=10;
placed=0;
}
void draw(cairo_t *cr){
gdk_cairo_set_source_pixbuf(cr, pix, x, y);
cairo_paint(cr);
}
void updatePosition(int a, int b){
if(placed==0){
x=a-25;
y=b-25;
}
}
void place(){
placed=1;
}
};
class Map{
public:
vector<Gen *> Gens;
GtkWidget *window;
GtkWidget *canvas;
int xPointer,yPointer;
Map(GtkWidget *_window, GtkWidget *_canvas){
window=_window;
canvas=_canvas;
}
void draw(){
cairo_t *cr;
cr = gdk_cairo_create (gtk_widget_get_window(canvas));
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_rectangle(cr, xPointer-35, yPointer-35, 70, 70);
cairo_paint(cr);
for(vector<Gen *>::const_iterator i=Gens.begin();i!=Gens.end();i++){
(*i)->draw(cr);
}
cairo_destroy (cr);
}
void place(){
Gen *aux=Gens.back();
aux->place();
//Gens.push_back(new Gen(canvas));
}
void moving(int x,int y){
xPointer=x;yPointer=y;
if(Gens.size()==0){
Gens.push_back(new Gen(canvas));
}
else if (Gens.back()->placed==1){
Gens.push_back(new Gen(canvas));
}
Gen *aux=Gens.back();
aux->updatePosition(x,y);
this->draw();
cout<<"Elementos -> "<<Gens.size()<<"\n";
}
};
static gboolean
moving(GtkWidget *da, GdkEvent *event, gpointer data)
{
int x, y;
GdkModifierType state;
gdk_window_get_device_position (gdk_event_get_window ((GdkEvent *) event),
gdk_event_get_device ((GdkEvent *) event),
&x, &y, &state);
/*
(void)event; (void)data;
((Gen *)da)->draw();*/
Map *g=(Map *)data;
g->moving(x,y);
}
static gboolean
placing (GtkWidget *da, GdkEvent *event, gpointer data)
{
Map *g=(Map *)data;
g->place();
}
int main ( int argc, char **argv) {
GtkWidget *window;
GtkWidget *canvas;
gtk_init (&argc , &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_set_size_request (window,
500, 500);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_main_quit) , NULL);
canvas = gtk_drawing_area_new ();
Map *g=new Map(window,canvas);
gtk_container_add (GTK_CONTAINER (window), canvas);
gtk_widget_set_events(window, GDK_POINTER_MOTION_MASK);
//g_signal_connect (canvas, "draw", G_CALLBACK (drawing), (gpointer *)g);
g_signal_connect (window, "motion-notify-event", G_CALLBACK (moving), (gpointer *)g);
g_signal_connect (window, "button-press-event", G_CALLBACK (placing), (gpointer *)g);
//g_signal_connect (canvas, "motion-notify-event", (GCallback) on_window_draw, NULL);
gtk_widget_set_app_paintable(canvas, TRUE);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
Several remarks here:
Gen::pix is allocated each time a Gen object is created. It's the same pixbuf, but you create one, then another one when using the scaling function (meaning you're leaking memory of the original pixbuf), and this for each Gen object. This is really unefficient, so using a static pix member, loading then scaling the pixbuf and fixing the memory leak would allow you to do this only once.
Then: you're calling gdk_cairo_create in the draw handler, but since GTK 3, you're supposed to get the cairo context as an input parameter in the draw signal callback. I see you're calling a custom draw method through the motion events, that's not how the GTK+ drawing stack works!
To do it right:
in the main, connect to the draw signal of the GtkDrawingArea
in your motion callbacks, just change positions of the Gen objects, and call gtk_widget_queue_draw for the drawing area. This will fire the draw signal for you.
in the callback connected to the draw signal, you then redraw your Gen objects in the cairo context you're given.
to improve performance, you can use the cairo clipping functions, or call gtk_widget_queue_draw_area or gtk_widget_queue_draw_region instead of gtk_widget_queue_draw. You'll get then a pre-computed clipping region in the cairo context you'll receive in your draw callback. With those hints, you can determine exactly what part of the image needs to be redrawn, and avoid unnecessary work.
Please read The GTK+ Drawing Model in the official documentation.

Compilation for GTK+ using OpenGL

Context: I am learning development of GUI using GTK+. I also wanted to draw lines and circles on the GUI. So I started with the tutorials and I am stuck with the part of GtkGLArea. I am following the code given in the GTK+ documentation
The error:
glTrial.cpp:32:13: error: variable or field ‘on_realize’ declared void
on_realize (GtkGLarea *area)
^
glTrial.cpp:32:13: error: ‘GtkGLarea’ was not declared in this scope
glTrial.cpp:32:24: error: ‘area’ was not declared in this scope
on_realize (GtkGLarea *area)
I believe I am not compiling properly and the compiler is not able to find correct headers.
Compilation:
g++ -std=c++14 \`pkg-config --cflags gtk+-3.0\` -o glTrial glTrial.cpp \`pkg-config --libs gtk+-3.0\`
The code:
#include <gtk/gtk.h>
#include <gtkgl-2.0/gtkgl/gdkgl.h>
#include <gtkgl-2.0/gtkgl/gtkglarea.h>
static void
print_hello (GtkWidget *widget,
gpointer user_data)
{
g_print ("Hello World\n");
}
static gboolean
render (GtkGLArea *area, GdkGLContext *context)
{
// inside this function it's safe to use GL; the given
// #GdkGLContext has been made current to the drawable
// surface used by the #GtkGLArea and the viewport has
// already been set to be the size of the allocation
// we can start by clearing the buffer
//glClearColor (0, 0, 0, 0);
// glClear (GL_COLOR_BUFFER_BIT);
// draw your object
// draw_an_object ();
// we completed our drawing; the draw commands will be
// flushed at the end of the signal emission chain, and
// the buffers will be drawn on the window
return TRUE;
}
static void
on_realize (GtkGLarea *area)
{
// We need to make the context current if we want to
// call GL API
gtk_gl_area_make_current (area);
// If there were errors during the initialization or
// when trying to make the context current, this
// function will return a #GError for you to catch
if (gtk_gl_area_get_error (area) != NULL)
return;
// You can also use gtk_gl_area_set_error() in order
// to show eventual initialization errors on the
// GtkGLArea widget itself
GError *internal_error = NULL;
init_buffer_objects (&error);
if (error != NULL)
{
gtk_gl_area_set_error (area, error);
g_error_free (error);
return;
}
init_shaders (&error);
if (error != NULL)
{
gtk_gl_area_set_error (area, error);
g_error_free (error);
return;
}
}
static void
activate (GtkApplication* app,
gpointer user_data)
{
GtkWidget *window;
GtkWidget *grid;
GtkWidget *button;
GtkWidget *gl_area =gtk_gl_area_new();
/* Create a new window, and set its title */
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "Window");
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
// gtk_window_set_default_size(GTK_WINDOW(window), 200, 200);
/* Here we construct the container that is going to pack the buttons*/
grid = gtk_grid_new();
/* Pack the container in the window */
gtk_container_add (GTK_CONTAINER (window), grid);
button = gtk_button_new_with_label ("Quit");
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
gtk_grid_attach (GTK_GRID (grid), button, 0, 0, 2, 1);
button = gtk_button_new_with_label ("Hello");
g_signal_connect_swapped (button, "clicked", G_CALLBACK (print_hello), NULL);
gtk_grid_attach (GTK_GRID (grid), button, 0, 1, 2, 1);
/* Trial for GL area*/
g_signal_connect (gl_area, "render", G_CALLBACK(render), NULL);
gtk_grid_attach (GTK_GRID (grid), gl_area, 0, 2, 10, 10);
gtk_widget_show_all (window);
}
int
main (int argc,
char **argv)
{
GtkApplication *app;
int status;
g_application_run (G_APPLICATION (app), argc, argv);
// 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;
}
According to a fast google, you are looking for GtkGLArea, note the uppercase A.
– derhass
you need:
sudo apt install *epoxy*
and
c++ t.c --target=arm-linux-gnu `pkg-config --libs --cflags gtk+-3.0 epoxy ` -o op

passing argument/arguments signal to callback on GTK+ in C

Here is my code:
#include <gtk/gtk.h>
G_MODULE_EXPORT void waka(GtkWidget *button, GtkWidget* entry1)
{
printf("%s",gtk_entry_get_text(GTK_ENTRY(entry1)));
}
int main(int argc, char * argv[])
{
GtkWidget *window, *button, *entry;
gtk_init(&argc,&argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
button = gtk_button_new_with_label("hha");
g_signal_connect(G_OBJECT(button),"clicked",G_CALLBACK(waka),entry);
entry = gtk_entry_new();
GtkWidget *vbox;
vbox = gtk_vbox_new(FALSE,2);
gtk_box_pack_start_defaults(GTK_BOX(vbox),button);
gtk_box_pack_start_defaults(GTK_BOX(vbox),entry);
gtk_container_add(GTK_CONTAINER(window),vbox);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
When I launch it, and try to fill in some string in the entry box, and then click the button, it said 'segmentation fault'. What is going on?
Also, the callback only works with one user data argument. How about if I want two or more arguments, what must I do in the callback function, and in the call to g_signal_connect()?
the problem is that you're trying to use pointer to entry before initializing it. I've changed a bit your code to fix this, see if it will work for you:
#include <gtk/gtk.h>
void waka(GtkWidget *button, GtkWidget* entry1)
{
g_print("entry: %s\n", gtk_entry_get_text(GTK_ENTRY(entry1)));
}
int main(int argc, char * argv[])
{
GtkWidget *window, *button, *entry, *vbox;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
button = gtk_button_new_with_label("hha");
entry = gtk_entry_new();
vbox = gtk_vbox_new(FALSE, 2);
gtk_box_pack_start_defaults(GTK_BOX(vbox),button);
gtk_box_pack_start_defaults(GTK_BOX(vbox),entry);
gtk_container_add(GTK_CONTAINER(window),vbox);
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(waka), entry);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
hope this helps, regards

Get text from Textbox in GTK+

I'm trying to get the input text from a text box in a callback function when the user changes something it it (on "changed").
The code goes as follow:
#include <stdio.h>
#include <gtk/gtk.h>
void enter_callback( GtkWidget *widget, GtkEditable *buffer)
{
printf("%s",gtk_editable_get_chars(buffer, 0, -1));
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *text;
GtkWidget *table;
gtk_init (&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
table = gtk_table_new (2, 2, TRUE);
gtk_container_add (GTK_CONTAINER (window), table);
text=gtk_text_new(NULL, NULL);
gtk_text_set_editable(text, TRUE);
gtk_signal_connect(GTK_OBJECT(text), "changed", GTK_SIGNAL_FUNC(enter_callback), (GtkEditable*)text);
gtk_table_attach_defaults(GTK_TABLE(table), text, 0, 1, 0, 1);
gtk_container_border_width (GTK_CONTAINER (window), 40);
gtk_window_set_default_size (GTK_WINDOW(window), 640, 200);
gtk_widget_show(text);
gtk_widget_show(window);
gtk_widget_show(table);
gtk_main();
return 0;
}
The code compiles just right, I'm compiling it on Code::Blocks on debug, checking output on the console by printf. The problem is I get <NULL> as a callback everytime I change something on the textbox. How can I get the correct output?
SOLUTION:
As noted by Washu, gtk_text is deprecated and gtk_text_view should be used instead.
According to the GTK documentation, GtkText is deprecated, buggy, and should not be used. You should instead be using the GtkTextView widget via gtk_text_view_new.
You can use GtkEntry widget too. And use gtk_entry_get_text () (which return const gchar * value) that to get text from GtkEntry, for instance.