Re: Emitting signals from threads
- From: ente <ente ck76 de>
- To: Mitko Haralanov <voidtrance gmail com>, ML-gtk <gtk-list gnome org>
- Subject: Re: Emitting signals from threads
- Date: Mon, 07 Jan 2019 17:54:24 -0600
Hi,
I am not sure with my answer. Treat it as unreliable.
There seems to be a difference between g_idle_add
and g_main_context_invoke_full. While the documentation of idle_add
says:
"Adds a function to be called [...] to the default main loop." (i.e.
main thread / the only gtk-thread) g_main_context_invoke_full does not
mention the main loop - although it mentions a "context" which I have
no experience with and which may be related to the main loop. So maybe
you must retrieve the correct context using g_main_context_default or
g_main_context_acquire. Keep in mind: glib is thread safe, gtk is not.
g_main_context_invoke_full may support glib multi threading while
g_idle_add clearly sends your function call to the gtk thread.
The effect you are describing makes sense to me. The effects you
observe sound very much like race conditions in the treeview event
handler.
Why aren't you using g_idle_add in the first place? In my experience
this works like a charm. Be careful with one thing tho: The main loop
has a "todo-list". Each time you call "g_idle_add" it adds an item to
that todo-list and schedules a call to your function. If your function
doesn't return false, it won't even be taken down from the todo-list.
Each click event ends on that todo-list. Each column resize adds
multiple items to that todo-list (depending on your column resize
policy and the number of rows). As soon as you add more items to that
list, your UI becomes unresponsive. It seems advisable to build your
own shadow todo-list for the update process, i.e.:
* setup a function "update_progress"
* on the first threaded update event, call idle_add for the function
and put the new progress and the row number in your own data structure
* while the function is still "planned in for idle_add", just add new
events to your own data structure
* process 1 to 10 (maybe some more) events on each of the calls
* the function returns true as long as there is still some events in
your own list; it returns false otherwise
* apply mutex checks on your data structure (not sure if i should
mention, I am sure you had this in your mind already)
Each time you update a progress bar in your treeview, several (at least
one) events are added to the gtk-todo list (repaint!, re-order? and
maybe some more). Doing multiple progress events at once may lower the
amount of events, gtk has to process (a re-order affects all rows -
doing an update on multiple rows does not change anything here).
That's my 5 cents. I hope it helped a bit.
regards,
ente
On Mon, 2019-01-07 at 08:28 -0800, Mitko Haralanov via gtk-list wrote:
Anyone have any ideas? I still can't figure out why the column sizes
go to
0.
Thank you.
On Tue, Dec 18, 2018, 13:40 Mitko Haralanov <
voidtrance gmail com
wrote:
This is Gtk3:
gtk3-3.22.26-2.fc27.x86_64
On Tue, Dec 18, 2018 at 1:14 PM Luca Bacci via gtk-list <
gtk-list gnome org
wrote:
Is it Gtk2 or Gtk3, which version exactly?
Il giorno mar 18 dic 2018 alle ore 18:47 Mitko Haralanov via gtk-
list <
gtk-list gnome org
ha scritto:
I mistakenly replied only to Luca!! Forwarding to the list.
(Sorry, Luca, my bad)
- Mitko
---------- Forwarded message ---------
From: Mitko Haralanov <
voidtrance gmail com
Date: Tue, Dec 18, 2018 at 9:37 AM
Subject: Re: Emitting signals from threads
To: Luca Bacci <
luca bacci982 gmail com
I found something that is different between the two cases -
button click
with signals and without.
Using the code from the link that Luca posted, I decided to
print the
size of each column when a button press is received. As it
turns out, the
width of the columns is different in the two cases:
Without thread signals:
column[0](193) = 0 -> 193
cell[0] = min->109, natural->109
column[1](66) = 193 -> 259
cell[0] = min->20, natural->20
cell[1] = min->16, natural->16
cell[2] = min->35, natural->35
column[2](36) = 259 -> 295
cell[0] = min->16, natural->16
x = 105.872116, y = 259.547516
(x and y are the coordinates of the button press event)
With thread signals:
column[0](0) = 0 -> 0
cell[0] = min->135, natural->135
column[1](66) = 0 -> 66
cell[0] = min->20, natural->20
cell[1] = min->16, natural->16
cell[2] = min->35, natural->35
column[2](36) = 66 -> 102
cell[0] = min->16, natural->16
x = 113.528488, y = 158.563782
As you can see, the width of the first column is 0 when the
signals are
being emitted. As expected, if I were to click very close to
the left
border of the widget, the edit dialog does not get triggered as
the x
coordinate falls within column 1:
column[0](0) = 0 -> 0
cell[0] = min->135, natural->135
column[1](66) = 0 -> 66
cell[0] = min->20, natural->20
cell[1] = min->16, natural->16
cell[2] = min->35, natural->35
column[2](36) = 66 -> 102
cell[0] = min->16, natural->16
x = 21.247330, y = 181.310333
I could use the cell renderer width if the column width is 0
but that
seems unreliable since the cell renderer width is not the same
as the
column and it's also not static.
On Tue, Dec 18, 2018 at 8:23 AM Mitko Haralanov <
voidtrance gmail com
wrote:
I am not posting the complete function because there is a lot
of
irrelevant code. I am also not interested in the specific
cell renderer but
rather the row on which the click occurred.
tatic gboolean on_button_press_event(GtkWidget *widget,
GdkEvent *event,
gpointer data)
{
GtkTreeView *treeview = GTK_TREE_VIEW(widget);
GdkEventButton *button = (GdkEventButton *)event;
GtkTreeModel *model;
GtkTreePath *path;
GtkTreeIter iter;
GtkTreeViewColumn *column;
GtkScopeProjectEditDialog *dialog;
GtkScopeProjectEditData *pdata, fill;
GtkScopeProject *project;
guint response, index;
gboolean ret = FALSE;
if (button->type != GDK_BUTTON_PRESS ||
!gtk_tree_view_get_path_at_pos(treeview, button->x,
button->y,
&path, &column, NULL, NULL))
return FALSE;
index = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(column),
"index"));
if (index != TREEVIEW_COLUMN_EDIT)
goto done;
model = gtk_tree_view_get_model(treeview);
if (!gtk_tree_model_get_iter(model, &iter, path))
goto done;
gtk_tree_model_get(model, &iter, PROJECT_COLUMN_OBJ,
&project, -1);
...
The issue is that the column which is returned by
gtk_tree_view_get_path_at_pos() is different depending on
whether thread
signals are being emitted vs not. I have verified that the
button press
coordinates are the same (button->x and button->y have the
same values in
both cases).
On Tue, Dec 18, 2018 at 5:24 AM Luca Bacci <
luca bacci982 gmail com
wrote:
Hi Mitko! Can you post here the code for the button-press
event
handler?
It should more or less follow the code here:
http://scentric.net/tutorial/sec-misc-get-renderer-from-click.html
Luca
Il giorno lun 17 dic 2018 alle ore 20:28 Mitko Haralanov
via gtk-list <
gtk-list gnome org
ha scritto:
Hi,
In my application, I want to be able to update a treeview
from a
separate thread. Each treeview row was a column that is a
progress bar. The
progress to be displayed is generated by a separate
thread as to not block
the UI.
Since GTK is not thread-safe, the way the application is
written is
that the thread, when it needs to emit a signal, will
prepare the signal
data and then call g_main_context_invoke_full(NULL, cb,
data, ...) in order
to be able to call g_singal_emit() in the global default
context thread.
The signal handler updates the tree model, which in turn
updates the tree
view.
For the most part this works with one big, ugly exception
- the same
treeview has a column, which is supposed to open the
item's Edit dialog
when clicked. So, naturally, I have a button-press
handler connected to the
treeview, which launches the Edit dialog when the button
press occurs in
the correct column.
However, when an update is running and the thread is
continuously
emitting signals, clicking on *any* column of *any* of
the other items
opens the Edit dialog. The treeview behaves as if the
items in it have only
one column.
Every example or document that I have seen in relation to
signals
from threads says to emit the signal from a g_idle_add()
handler. However,
g_main_context_invoke_full(NULL, ...) should be the same
as calling
g_idle_add().
Can someone shed some light into what might be happening?
Thank you.
_______________________________________________
gtk-list mailing list
gtk-list gnome org
https://mail.gnome.org/mailman/listinfo/gtk-list
_______________________________________________
gtk-list mailing list
gtk-list gnome org
https://mail.gnome.org/mailman/listinfo/gtk-list
_______________________________________________
gtk-list mailing list
gtk-list gnome org
https://mail.gnome.org/mailman/listinfo/gtk-list
_______________________________________________
gtk-list mailing list
gtk-list gnome org
https://mail.gnome.org/mailman/listinfo/gtk-list
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]