How to determine which model is connected to a treeview given a callback? - gtk

In Gtk 2.0 the cell toggled event, for example, passes the cell rendered and the path to the callback. But in order to change the underlying model data I need to know which treeview or which model this event is for. What is the proper way to determine that?
EDIT:
To clarify, the GtkCellRenderer toggled signal calls a callback with 3 parameters: *cell_renderer, *path, user_data. In this callback, how do I retrieve the model that is connected to the treeview that received this signal?

When you connect the "toggled" signal, you can pass the GtkTreeView or the model as the user_data. I'm not an expert on Gtk+ with C programming language :), but I guess the following code will help you:
void cb_toggled (GtkCellRendererToggle *cell_renderer,gchar *path, gpointer user_data)
{
GtkListStore *store = (GtkListStore *) user_data;
...
}
int main(int argc, char **argv)
{
...
g_signal_connect(G_OBJECT(cell_renderer), "toggled", G_CALLBACK(cb_toggled), (gpointer)gtk_tree_view_get_model(treeview));
...
}

Related

How to get the end of continuous value update for Gtk Spinbox?

I'm using Gtk2 to make a small tool, it works like this:
Several Scales and Spinboxes control parameters of an algorithm.
When parameter changes, the algorithm will execute, and the updated result is rendered as a picture, shown in UI.
As the algorithm's workload is heavy, I don't want it run frequently during frequent parameter change. Specifically, during Scales are dragged or Spinbox's arrows buttons are pressed. Instead, I want the algorithm to be run "after" users have determined the parameters.
Currently, I listened the button-release event of the Scales, so the algorithm will run only on Scale dragging is done. However, this not fit for the Spinboxes, as they have separate entry and button sub-area. If I listen to Spinbox's button-release, it would behave weirdly.
So what event (or events) should I listen to obtain the occation that a continuous value update is finished for a Spinbox?
Could I see the code you have? The button-release works great for me. However, depending on your algorithm, you may be getting 'feedback'. Are you sure the rest of the code is not updating your spinbutton in some way?
I'd use a deferred computation, independent from the device you use to modify the data. In this way you can also input the numbers with the keyboard or copy and paste their content and the program will still work as expected.
A way to do this in GTK+ is by leveraging the main loop and using a timeout GSource, e.g.:
#include <gtk/gtk.h>
typedef struct {
guint event;
GSourceFunc callback;
GtkWidget *spin_button;
} Algorithm;
static gboolean your_callback(Algorithm *algorithm)
{
g_print("Your heavy computations go here...\n");
/* ... */
algorithm->event = 0;
return FALSE;
}
static void postpone(Algorithm *algorithm)
{
if (algorithm->event > 0) {
g_source_remove(algorithm->event);
}
/* Default delay is 1 second (1000 milliseconds) */
algorithm->event = g_timeout_add(1000, algorithm->callback, algorithm);
}
int main(int argc, char **argv)
{
GtkWidget *window, *spin_button;
Algorithm algorithm;
gtk_init(&argc, &argv);
spin_button = gtk_spin_button_new_with_range(0, 100, 0.1);
g_signal_connect_swapped(spin_button, "value-changed",
G_CALLBACK(postpone), &algorithm);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_container_add(GTK_CONTAINER(window), spin_button);
algorithm.event = 0;
algorithm.callback = (GSourceFunc) your_callback;
algorithm.spin_button = spin_button;
gtk_widget_show_all(window);
gtk_main();
return 0;
}

goocanvas signal handling corrupted after using a dialog

I use a goocanvas and use signals for mouse events connected to some graphical items. If I use a dialog from a signal handler, all signals are broken after closing the dialog. Is this a bug of gtkmm/goocanvas or is this some kind of misuse in my program?
The wrong behavior is:
You can click somewhere in the canvas area, nothing is happen which is correct. If you click on the circle the signal handler starts the dialog which is also expected. After closing the dialog ( OK button ) you can click somewhere on the canvas and the signal handler is called which is wrong.
In my real program the signal handlers are sometimes never called and sometimes called on wrong areas and so on. A bit strange behavior. I hope someone can find the problem.
#include <gtkmm.h>
#include <goocanvasmm.h>
#include <sigc++/sigc++.h>
bool ShowDialog( const Glib::RefPtr<Goocanvas::Item>& item, GdkEventButton* ev)
{
enum { OK };
Gtk::Dialog dialog;
dialog.add_button( Gtk::Stock::OK, OK);
dialog.show_all_children();
dialog.run();
return false;
}
int main(int argc, char* argv[])
{
Gtk::Main app(&argc, &argv);
Goocanvas::init("example", "0.1", argc, argv);
Gtk::Window win;
Goocanvas::Canvas m_canvas;
m_canvas.set_size_request(640, 480);
m_canvas.set_bounds(0, 0, 800, 800);
Glib::RefPtr<Goocanvas::Item> root = m_canvas.get_root_item();
Glib::RefPtr<Goocanvas::Ellipse> outer = Goocanvas::Ellipse::create( 100,100,20,20);
outer->property_line_width() = 5;
outer->property_stroke_color() = "red";
outer->property_fill_color()="blue";
root->add_child( outer );
sigc::connection conn2= outer->signal_button_press_event().connect( sigc::ptr_fun(&ShowDialog));
win.add(m_canvas);
win.show_all_children();
Gtk::Main::run(win);
return 0;
}

Updating a gtk_tree_view from pthreads

I've been trying to figure out some method to cause a GtkTreeView to redraw after I update the bound GtkListStore from a background thread created with pthreads.
Generally, the widget does not update until something obscures an existing row (even a mouse cursor ).
Most of my searches for this problem has "your tree model doesn't/isn't generating the correct signals" ....
I'm running an old Red Hat 9 with gtk+ 2.0.0, for industrial embedded applications. Most of the data comes from ipc/socket/pipes and gets displayed by a GTK app. Unfortunately so does CRITICAL alarms, which has a habit of not showing when they should. We will (one day) move to a current kernel, but I need to get something working with the existing software.
I've tried emiting the "row-changed" signals, tried calling the gtk_widget_queue_draw and also tried connecting to the "expose-event", where I've tried various things that don't work or seg fault.
server.c
bool Server::Start()
{
// ....
// pthread_t _id;
//
pthread_create( & _id, NULL, &StaticServerThread, this );
// ....
}
viewer.c
bool Viewer::ReadFinished( SocketArgs * args )
{
gdk_threads_enter();
// Populate the buffer and message
//
// GtkListStore *_outputStore;
// gchar *buffer;
// gchar *message;
GtkTreeIter iter;
gtk_list_store_insert_with_values( _outputStore, &iter, 0,
0, buffer, 1, message, -1 );
// ....
gdk_threads_leave();
}
You can perform the updates to the list store in the main thread. For example, you can use g_idle_add() in the worker thread.

Why is the signal callback data pointer pointing to a junk value when the callback is fired?

Ok, I'm writing a method that creates an entire panel and it's containing contents and adds it to the form. The panels are stored in an array.
Here's the basic idea.
void vscale1Event(GtkWidget *widget, int *vscale_id)
{
int value = gtk_range_get_value(GTK_RANGE(vscale_struct[*vscale_id]->vscale1));
do stuff with this value;
}
void add_vscale_panel(int vscale_id)
{
vscale_struct[vscale_id]->vscale1 = ..... ;
vscale_struct[vscale_id]->vscale2 = ..... ;
add buttons to form;
gtk_signal_connect(GTK_OBJECT(vscale_struct[button_id]), "value_changed", (GtkSignalFunc)vscale1Event, &vscale_id);
gtk_signal_connect(GTK_OBJECT(vscale_struct[button_id]), "value_changed", (GtkSignalFunc)vscale2Event, &vscale_id);
}
int main()
{
for (i = 0; i<n; i++)
{
add_vscale_panel(i);
}
}
The problem I'm having, is that &vscale_id that I'm passing in, later becomes junk (it's value is a junk number around 32000) when I move the scale.
But - the gtk_signal_connect is only being called that once.
Ok, I get that it's probably something to do with the call stack, that bit of memory no longer being reserved.
But I did this same thing earlier for another panel, and it's working fine.
what I've changed - is trying to make things a bit tidier.
The previous version I had all the panels and widgets each in seperate arrays.
eg
GtkWidget **outerPanel;
GtkWidget **innerPanel1;
GtkWidget **vscale1;
whereas this one I'm doing it:
typedef struct
{
GtkWidget **vscale1;
Gtkwidget **vscale2;
} V_Panel;
V_Panel **vscale_struct;
Not bothering putting the panels into arrays or structs - because I figure I don't need to access them later? ( I found that you can 'recycle' labels so I figure panels (h and vboxes), are the same.
Also - an interesting clue - when I run valgrind - it works fine. Some how valgrind changes the way the program uses it's memory.
Any help here?
If you can perhaps explain what's happening when you call gtk_signal_connect. -
Here's my actual code: http://pastebin.com/MGfUihjM
relevant lines are
45, 145, 274, 308, 391
The problem is that your taking the address of a variable on the stack - in this case the parameter to the function. That address in memory is definitely not guaranteed to continue to hold the value you expect it to since it is just part of the stack frame
The correct way to pack your integer value_id into the callback userdata pointer is to use GINT_TO_POINTER and to reverse it using GPOINTER_TO_INT.
So your signal connection would be:
gtk_signal_connect(GTK_OBJECT(vscale_struct[button_id]),
"value_changed",
(GtkSignalFunc)vscale1Event,
GINT_TO_POINTER(value_id));
And in your signal handler would look like:
void vscale1Event(GtkWidget *widget, gpointer userdata)
{
int vscale_id = GPOINTER_TO_INT (userdata);
int value = gtk_range_get_value(GTK_RANGE(vscale_struct[vscale_id]->vscale1));
do stuff with this value;
}

Do I have to manually attach a gtk signal handler when I specified the function name in glade?

I'm writing my first gtk program, using gtkmm, and glade.
I made a filechooserbutton and it has a signal called file-set
So I set that to what I assume is the function name I want it to call when the file is chosen.
But then I see here:
http://library.gnome.org/devel/gtkmm-tutorial/unstable/sec-builder-accessing-widgets.html.en
That they're manually getting the dialog widget and setting a button signal handler in the code.
Which is the right way to do it?
And while I'm here any links to good examples would be handy, they seem to be few and far between. Thanks.
This is how I did it:
// create the UI
refUI = Gtk::Builder::create();
refUI->add_from_file(grq::GLADE_FILE);
// grab your widget
refUI->get_widget("but_new", but_new); // Gtk::ToolButton *but_new;
but_new->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_new_game));
// your signal handler looks something like this :)
void MainWindow::on_new_game() {}
edit:
Basically the *this is the object on which you will be calling the function your signal handler.
This is what my main looks like:
int main(int argc, char **argv) {
Gtk::Main kit(argc, argv);
MainWindow main_window;
kit.run(*main_window.window);
return 0;
}
MainWindow is basically a class that wraps GtkWindow and defines the widgets, a. la.:
class MainWindow
{
private:
Glib::RefPtr<Gtk::Builder> refUI;
//
// Widgets
//
Gtk::ToolButton *but_about;
public:
// The window. This is public so we can hook into events and
// call kit.run(window) against it, if needed.
Gtk::Window *window;
MainWindow()
{
// Load the data for this window and it's widgets.
refUI = Gtk::Builder::create();
refUI->add_from_file(grq::GLADE_FILE);
// The window
refUI->get_widget("main_window", window);
// Widgets
refUI->get_widget("but_about", but_about);
but_about->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_about));
...
}
virtual ~MainWindow()
{
if (window != NULL)
{
delete window; // Frees all the children for the window, too.
}
}
virtual void on_about()
{
// stuff
}
};
Hope this helps!
I found the answer to my question as an afterthought in another stackoverflow question.
But I don't remember which one it was.
The answer seems to be that you have to programmatically add the signal handler to the widget in your code, the gtkbuilder won't do it for you.