GFileMonitor - g_signal_handler_block "changed" signal doesn't block handler?

2017-03-30 Thread David C. Rankin
All

  I have implemented a GFileMonitor/g_file_monitor_file watch for respond to
changes to the current file by an external process within an editor[1], but
now issuing g_signal_handler_block to prevent the "changed" signal from being
handled on normal saves, does not prevent the callback from firing.

  The basic flow is this, I set the watch with:

GFile *gfile = g_file_new_for_path (app->filename);
...

/* create monitor for app->filename */
app->filemon = g_file_monitor_file (gfile,
G_FILE_MONITOR_NONE,
cancellable, );
...

/* connect changed signal to monitored file saving ID */
app->mfp_handler = g_signal_connect (G_OBJECT(app->filemon), "changed",
G_CALLBACK (file_monitor_on_changed), data);

  Both the instance (app->filemon) and handler_id (app->mfp_handler) are
saved. In order to prevent handling of changes during normal save/save as
operations, I created block and unblock functions to prevent the changes to
the file from firing the callback, e.g. show below with debug g_print calls:

void file_monitor_block_changed (gpointer data)
{
kwinst *app = (kwinst *)data;

if (!app->filemon || !app->mfp_handler) return;

g_print ("blocking changed (%lu)\n", app->mfp_handler);

g_signal_handler_block (app->filemon, app->mfp_handler);
}

void file_monitor_unblock_changed (gpointer data)
{
kwinst *app = (kwinst *)data;

if (!app->filemon || !app->mfp_handler) return;

g_print ("unblocking changed (%lu)\n", app->mfp_handler);

g_signal_handler_unblock (app->filemon, app->mfp_handler);
}

  To implement the block/unblock, I wrap the file 'save/save as' function in
the block, then save, then unblock, but the callback is still firing on normal
saves. e.g. in the save function I have:

if (app->mfp_handler)   /* current file monitor on file */
file_monitor_block_changed (app);   /* block "changed" signal */

g_print ("  buffer_write_file (app, filename)\n");
buffer_write_file (app, filename);  /* write to file app->filename */

if (filename)
file_monitor_add (app); /* setup monitoring on new name */
else if (app->mfp_handler)
file_monitor_unblock_changed (app); /* unblock "changed" signal */

  To my disbelief, the callback continues to fire as if I had not called block
at all. For instance when saving the file, the debug output is:

$ ./bin/gtkwrite
blocking changed (669)
  buffer_write_file (app, filename)
unblocking changed (669)
Monitor Event: File = /home/david/tmp/foo.txt.UY9IXY
G_FILE_MONITOR_EVENT_DELETED
Monitor Event: File = /home/david/tmp/foo.txt
G_FILE_MONITOR_EVENT_CREATED
Monitor Event: File = /home/david/tmp/foo.txt
G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT
Monitor Event: File = /home/david/tmp/foo.txt
G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED

from which I can see the block called, the call to save the file to disk, the
unblock call, and then the callback firing to delete the temp file
'foo.txt.UY9IXY', and create the new 'foo.txt' and then setting the
attributes. Why is this occurring? I get the exact same firing of the callback
if I completely remove the block/unblock calls, so it is not due to gio using
a temp file with the g_file_set_contents call during save.

  When I created my custom signal for using inotify directly, I could
block/unblock that signal without any problem, but when using GFileMonitor,
the block/unblock seems like it is completely ignored. All types are correct,
e.g. from the basic struct app:

GFileMonitor*filemon;
gulong  mfp_handler;

So what is the trick? How to I prevent the file_monitor_on_changed() callback
from firing in response to the "changed" signal on normal file saves. I
shouldn't have to completely disconnect/reconnect the callback should I? The
block/unblock should be sufficient for temporary use, right?

Let me know what the experts think. There is something funny about the way
block/unblock works with GFileMonitor that I'm missing. For normal signals in
the app, I have no problems with block/unblock.

Footnote [1]: (see earlier post "Howto integrate an inotify watch on editor
file in GTK+2 event loop?")

-- 
David C. Rankin, J.D.,P.E.
___
gtk-app-devel-list mailing list
gtk-app-devel-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list


No releases for March

2017-03-30 Thread Brian Manning
Hi all,

There was no new code in the Gtk-Perl repos, so there's no releases for March.

The next release announcement for April will be sent out shortly.

Thanks,

Brian
___
gtk-perl-list mailing list
gtk-perl-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-perl-list


GTK+ with Broadway.

2017-03-30 Thread Igor D
Hi,

I'm trying to change the cursor when it is over certain widget and do not
succeed to do that
when I'm working with GTK+ via Broadway. Without Broadway it works
perfectly.
Somebody knows about limitation for this case ?

Thanks,
Igor
___
gtk-list mailing list
gtk-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-list


Re: Input event reduction

2017-03-30 Thread Emmanuele Bassi
On 30 March 2017 at 11:21, Gabriele Greco  wrote:
>>
>> Thanks. While I can remember have read your explanations somewhere
>> already, I really missed that g_main_context_invoke() function.
>
>
> There is some difference/advantage on calling:
>
> g_main_context_invoke(NULL, func, data)?
>
> instead of
>
> g_idle_add(func, data);

Calling g_main_context_invoke() will ensure that the main context is
owned and acquired during the invocation. As I said, it will do the
right thing depending on the type of context you are using.

> As far as I can see from the function documentations g_main_context_invoke
> seems useful when having multiple contexts on different threads, I'm wrong?

Correct, but remember that different libraries may have different
contexts in different threads already by the time you call your code.

It's also a good rule of thumb to start using this function, as it
will be more efficient once you start using API like GTask, with its
own main context.

Ciao,
 Emmanuele.

-- 
https://www.bassi.io
[@] ebassi [@gmail.com]
___
gtk-app-devel-list mailing list
gtk-app-devel-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list


Re: Input event reduction

2017-03-30 Thread Gabriele Greco
>
>
> Thanks. While I can remember have read your explanations somewhere
> already, I really missed that g_main_context_invoke() function.


There is some difference/advantage on calling:

g_main_context_invoke(NULL, func, data)?

instead of

g_idle_add(func, data);

As far as I can see from the function documentations g_main_context_invoke
seems useful when having multiple contexts on different threads, I'm wrong?

-- 
*Bye,*
* Gabry*
___
gtk-app-devel-list mailing list
gtk-app-devel-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list


Re: Input event reduction

2017-03-30 Thread Stefan Salewski
On Thu, 2017-03-30 at 10:21 +0100, Emmanuele Bassi wrote:
> g_idle_add() or, better yet, g_main_context_invoke().

Thanks. While I can remember have read your explanations somewhere
already, I really missed that g_main_context_invoke() function.
___
gtk-app-devel-list mailing list
gtk-app-devel-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list

Re: Input event reduction

2017-03-30 Thread Stefan Salewski
On Thu, 2017-03-30 at 11:10 +0200, Nicola Fontana wrote:
> 
> 
> As said you can leverage the main loop and unroll yours, e.g.:
> 
> gboolean my_idle_callback()
> {
> gint n;
> for (n = 0; n < 100; ++n) {
> ...
> }
> return FALSE;
> }
> 
> should become:
> 
> gboolean my_unrolled_idle_callback()
> {
> static gint n = 0;
> ...
> ++n;
> return n < 100;
> }
> 
> Depending on your use case, the above could or could not be
> possible.
> 

Ah yes, that is an interesting idea.

> > 
> > So I have to go back to my initial idea -- create a thread which
> > gets a
> > message for each "changed" signal, and then calls an idle function
> > only
> > for the last message in the queue each. I have to use
> > gdk_threads_add_idle() then.
> 
> This is probably the cleanest solution, although I don't
> understand why you would have to use gdk_threads_add_idle().

I think gdk_threads_add_idle() is the recommended way to update the GTK
GUI from inside a second thread. I am doing it in the current version
of the editor already for querying and displaying extended symbol
information, see https://github.com/ngtk3/NEd

Here is where gdk_threads_add_idle() was suggested:
https://developer.gnome.org/gdk3/stable/gdk3-Threads.html
"You can schedule work in the main thread safely from other threads by
using gdk_threads_add_idle() and gdk_threads_add_timeout()"

> 
> > 
> > The task of that idle function in my current use case would be to
> > get
> > highlight syntax information from the IDE process called nimsuggest
> > and
> > then to apply the corresponding tags to gtksource textbuffer.
> 
> IMO it is essential to split your code in two parts: (1) gathering
> the highlight information and (2) applying it to the textbuffer.

Yes, that was my thoughts too. It would imply some additional code, but
may be the best solution.

> 
> (1) can be run entirely in the working thread (hence non-blocking)
> while (2) must be implemented as a callback to be run in the GTK+
> thread. I cannot believe (2) takes tenths of second.
> 
> When you are ready from (1) you can spawn the idle callback with
> g_source_attach()... no needs for gdk_threads_add_idle(). In the
> following StackOverflow answer I provided an example in C:
> 
> http://stackoverflow.com/questions/27950493/safety-of-using-pthreads-
> in-gtk2-0-application#27990662
> 

Thanks for that suggestion, I will look at the stackoverflow example.
And indeed, applying the text tags to the gtksource buffer is finally
the only critical part. I dont know how fast that really is, I would
assume that it takes less than 50 ms, what would be fine. If it really
is slow, I may split it in multiple parts/calls.


___
gtk-app-devel-list mailing list
gtk-app-devel-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list

Re: Input event reduction

2017-03-30 Thread Emmanuele Bassi
On 30 March 2017 at 10:10, Nicola Fontana  wrote:

> When you are ready from (1) you can spawn the idle callback with
> g_source_attach()... no needs for gdk_threads_add_idle(). In the
> following StackOverflow answer I provided an example in C:

A small correction: use g_main_context_invoke() instead, as it will
always do the right thing.

The only reason to prefer gdk_threads_add_idle() to g_idle_add() (or
g_main_context_invoke()) is that your own code may depend on
additional libraries that still attempt at acquiring the GDK thread
lock — i.e. they use gdk_threads_enter()/gdk_threads_leave() inside a
separate thread to mark a critical section. No newly written,
maintained, or portable code should do that, so you can safely use
g_idle_add() or, better yet, g_main_context_invoke().

Ciao,
 Emmanuele.

-- 
https://www.bassi.io
[@] ebassi [@gmail.com]
___
gtk-app-devel-list mailing list
gtk-app-devel-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list

Re: Input event reduction

2017-03-30 Thread Nicola Fontana
Il Thu, 30 Mar 2017 09:38:41 +0200 Stefan Salewski  scrisse:

> On Wed, 2017-03-29 at 23:26 +0200, Nicola Fontana wrote:
> > 
> > 
> > idle functions do *not* run in the background so if you don't
> > release the CPU you will experience what you described.
> > 
> > AFAIK all the GMainLoop code is single-threaded hence, as a
> > consequence, you will block the UI whenever the CPU is busy
> > running your code, being it inside a signal handler, a timeout
> > function or (as in your case) an idle function.
> > 
> > Just avoid loops when you know they are expensive. Instead
> > leverage the cyclic nature of GMainLoop for iterating over your
> > code, i.e. by respawning your idle function as much as needed.
> >   
> 
> In that case it is really a bad idea to have a outer loop in that idle
> function :-(

As said you can leverage the main loop and unroll yours, e.g.:

gboolean my_idle_callback()
{
gint n;
for (n = 0; n < 100; ++n) {
...
}
return FALSE;
}

should become:

gboolean my_unrolled_idle_callback()
{
static gint n = 0;
...
++n;
return n < 100;
}

Depending on your use case, the above could or could not be
possible.

> So I have to go back to my initial idea -- create a thread which gets a
> message for each "changed" signal, and then calls an idle function only
> for the last message in the queue each. I have to use
> gdk_threads_add_idle() then.

This is probably the cleanest solution, although I don't
understand why you would have to use gdk_threads_add_idle().

> The task of that idle function in my current use case would be to get
> highlight syntax information from the IDE process called nimsuggest and
> then to apply the corresponding tags to gtksource textbuffer.

IMO it is essential to split your code in two parts: (1) gathering
the highlight information and (2) applying it to the textbuffer.

(1) can be run entirely in the working thread (hence non-blocking)
while (2) must be implemented as a callback to be run in the GTK+
thread. I cannot believe (2) takes tenths of second.

When you are ready from (1) you can spawn the idle callback with
g_source_attach()... no needs for gdk_threads_add_idle(). In the
following StackOverflow answer I provided an example in C:

http://stackoverflow.com/questions/27950493/safety-of-using-pthreads-in-gtk2-0-application#27990662

Ciao.
-- 
Nicola
___
gtk-app-devel-list mailing list
gtk-app-devel-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list

Re: Input event reduction

2017-03-30 Thread Stefan Salewski
On Thu, 2017-03-30 at 09:38 +0200, Stefan Salewski wrote:
> Currently I wonder if the call of gtk3.mainIteration() inside the
> idle
> function is possible and if it would help updating the display. In my
> first draft of the Nim toy chess I used something like this
> 
> while gtk3.eventsPending(): discard gtk3.mainIteration()

Yes, that has an effect, it seems to allow GUI redraw, but keyboard
input remains sluggish. If I add additional a sleep() function call
keyboard seems to react better. But of course that is no real solution,
so I have to test the thread idea next.
___
gtk-app-devel-list mailing list
gtk-app-devel-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list


Re: Input event reduction

2017-03-30 Thread Stefan Salewski
On Wed, 2017-03-29 at 23:26 +0200, Nicola Fontana wrote:
> 
> 
> idle functions do *not* run in the background so if you don't
> release the CPU you will experience what you described.
> 
> AFAIK all the GMainLoop code is single-threaded hence, as a
> consequence, you will block the UI whenever the CPU is busy
> running your code, being it inside a signal handler, a timeout
> function or (as in your case) an idle function.
> 
> Just avoid loops when you know they are expensive. Instead
> leverage the cyclic nature of GMainLoop for iterating over your
> code, i.e. by respawning your idle function as much as needed.
> 

In that case it is really a bad idea to have a outer loop in that idle
function :-(

So I have to go back to my initial idea -- create a thread which gets a
message for each "changed" signal, and then calls an idle function only
for the last message in the queue each. I have to use
gdk_threads_add_idle() then.

The task of that idle function in my current use case would be to get
highlight syntax information from the IDE process called nimsuggest and
then to apply the corresponding tags to gtksource textbuffer.
Unfortunately that may take a few hundred milliseconds for each full
update.

Currently I wonder if the call of gtk3.mainIteration() inside the idle
function is possible and if it would help updating the display. In my
first draft of the Nim toy chess I used something like this

while gtk3.eventsPending(): discard gtk3.mainIteration()

to avoid display freeze.
___
gtk-app-devel-list mailing list
gtk-app-devel-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list