GFileMonitor - g_signal_handler_block "changed" 信号不阻止处理程序?
GFileMonitor - g_signal_handler_block "changed" signal doesn't block handler?
全部,
这可能需要一些时间来设置。在过去的几个月里,我有一个小型编辑器项目[1]。我最初想在当前编辑器文件上实现一个 inotify
监视,以防止被外部进程修改。我创建了一个自定义信号和 add
、remove
和 monitor
(使用 pselect
)的例程和 block
和 [=30= 的监视和例程] 发射自定义信号以允许正常 save/save as
而不会触发回调。我遇到的问题是如何将 monitor
添加到 gtk_event_loop
以便对循环的每次迭代执行检查。我决定使用 g_idle_add
并转到 gtk-app-devel 列表以确定该方法是否合理或者是否有更好的方法。共识是使用 GIO/GFileMonitor
而不是直接使用 inotify
。
快进到当前问题。我重写了使用 GFileMonitor/g_file_monitor_file
的实现并重写了 block
和 unblock
例程以阻止处理 "changed"
信号以允许正常的 save/save as
而不触发回调.问题是当我在保存文件之前 block
实例和 handler_id 回调时,回调仍然会触发。当使用带有自定义信号的 inotify
实现时,阻止信号的发射效果很好。我已将其发回 gtk-app-devel 列表,但在 return 中没有收到任何信息——这就是我在这里提问的原因。为什么 g_signal_handler_block
和 GIO/GFileMonitor
不阻止对 "changed"
信号回调的处理? (更重要的是,我该如何修复它)
注意:(MCVE - 完整的测试代码在 https://github.com/drankinatty/gtktest)。要使用 GtkSourceView2 构建,只需键入 make with=-DWGTKSOURCEVIEW2
,它将构建为 bin/gtkwrite
,否则不构建,只需键入 make
,它将构建为 bin/gtkedit
.
相关代码逻辑如下(app
是struct
持有相关编辑器variables/info和设置的实例)GIO/GFileMonitor实现在gtk_filemon.[ch]
保存函数的包装在 gtk_filebuf.c
:
typedef struct {
...
gchar *filename;
GFileMonitor *filemon;
gulong mfp_handler;
...
} kwinst;
kwinst *app = g_slice_new (kwinst);
我将手表设置为:
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, &err);
...
/* 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);
实例 (app->filemon
) 和 handler_id (app->mfp_handler
) 都已保存。 (mfp
只是 modified by foreign process 的缩写)为了防止在正常 save/save as 操作期间处理更改,我创建了 block 和 unblock 函数以防止触发回调对文件的更改,例如下面显示调试 g_print 调用:
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);
}
为了实现block/unblock
,我用block
包装文件'save/save as'函数,然后保存[2],然后unblock
,但回调仍然是在正常保存时开火。例如我拥有的保存功能的相关部分是:
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 */
使用上面的调试 g_print
语句,发出 save
结果如下:
$ ./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
我是否包含 block/unblock
没有区别,回调的触发没有改变。我怀疑问题在于 "changed"
信号及其处理是通过 GIO
而不是 GTK
实现的(因为 inotify
实现的自定义信号是)使用 g_signal_handler_block
阻止处理 "changed"
信号的能力存在一些差异——尽管我在文档中找不到区别。文档指出:
To get informed about changes to the file or directory you are monitoring,
connect to the “changed” signal. The signal will be emitted in the thread-default
main context of the thread that the monitor was created in (though if the global
default main context is blocked, this may cause notifications to be blocked
even if the thread-default context is still running).
https://developer.gnome.org/gio/stable/GFile.html#g-file-monitor-file
应用程序本身不使用任何显式线程,也不 fork
保存的任何部分。所以我不知道为什么 block/unblock
不阻止处理 "changed"
信号。保存完全包含在 block/unblock
中,除非 g_file_set_contents
调用是异步的,否则我看不到任何时间问题。
为什么调用 g_signal_handler_block/g_signal_handler_unblock
无法阻止对当前文件更改时发出的 "changed"
信号的处理?我可以 g_signal_handler_disconnect
并且什么都不触发,但我不应该 disconnect
来暂时阻止处理。我错过了什么?
为了完整起见,file_monitor_on_changed
函数连同脚注包含在下面:
void file_monitor_on_changed (GFileMonitor *mon,
GFile *file, GFile *other,
GFileMonitorEvent evtype,
gpointer data)
{
kwinst *app = (kwinst *)data;
g_print ("Monitor Event: File = %s\n", g_file_get_parse_name (file));
switch (evtype)
{
case G_FILE_MONITOR_EVENT_CHANGED:
/* prompt or emit custom signal modified by foreign process */
g_print ("G_FILE_MONITOR_EVENT_CHANGED\n");
break;
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
g_print ("G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT\n");
break;
case G_FILE_MONITOR_EVENT_DELETED:
/* avoid firing on normal '.tmp' file delete */
if (g_strcmp0 (g_file_get_parse_name (file), app->filename)) {
g_print (" ignoring 'tmp' file delete.\n");
break;
}
/* prompt or emit custom signal modified by foreign process */
g_print ("G_FILE_MONITOR_EVENT_DELETED\n");
/* prompt save file */
break;
case G_FILE_MONITOR_EVENT_CREATED:
g_print ("G_FILE_MONITOR_EVENT_CREATED\n");
break;
case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
g_print ("G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED\n");
break;
case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
g_print ("G_FILE_MONITOR_EVENT_PRE_UNMOUNT\n");
break;
case G_FILE_MONITOR_EVENT_UNMOUNTED:
g_print ("G_FILE_MONITOR_EVENT_UNMOUNTED\n");
break;
case G_FILE_MONITOR_EVENT_MOVED:
g_print ("G_FILE_MONITOR_EVENT_MOVED\n");
/* prompt save file */
break;
case G_FILE_MONITOR_EVENT_RENAMED:
/* prompt save file */
g_print ("G_FILE_MONITOR_EVENT_RENAMED\n");
break;
case G_FILE_MONITOR_EVENT_MOVED_IN:
g_print ("G_FILE_MONITOR_EVENT_MOVED_IN\n");
break;
case G_FILE_MONITOR_EVENT_MOVED_OUT:
g_print ("G_FILE_MONITOR_EVENT_MOVED_OUT\n");
break;
default:
g_print ("unknown EVENT on changed signal.\n");
}
if (mon || other) {}
}
使用g_signal_handler_block在其他情况下工作正常
作为评论中提到的一点,我可以确认我可以轻松 block
、unblock
其他信号处理程序而不会出现问题。具体来说,在使用 inotify
实现时,我创建了以下自定义信号:
/* create signal to monitor file modified by foreign process */
app->SIG_MODFP = g_signal_new ("modified-foreign",
GTK_TYPE_TEXT_BUFFER,
GTK_RUN_ACTION,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
1,
G_TYPE_POINTER);
然后将信号连接到处理程序并保存 handler_id 如下:
/* custom signals */
app->mfp_handler2 = g_signal_connect (GTK_TEXT_BUFFER(app->buffer),
"modified-foreign",
G_CALLBACK (on_modified_foreign), app);
on_modified_foreign
回调是一个简单的测试回调,用于测试 block/unblock:
void on_modified_foreign (GtkTextBuffer *buffer,
kwinst *app)
{
dlg_info ("File has changed on disk, reload?", "Modified by Foreign Process");
if (buffer || app) {}
}
以上 dlg_info
只是 gtk_message_dialog_new
的包装器,用于在发出 "modified-foreign"
信号时弹出对话框。
然后执行一个简单的测试,其中一个菜单项会导致发出信号,例如:
void menu_status_bigredbtn_activate (GtkMenuItem *menuitem, kwinst *app)
{
g_signal_emit_by_name (G_OBJECT(app->buffer), "modified-foreign::", app);
}
最后 blocking/unblocking 工作正常:
void menu_status_block_activate (GtkMenuItem *menuitem, kwinst *app)
{
if (!app->mfp_handler2) return;
GtkTextBuffer *buffer = GTK_TEXT_BUFFER(app->buffer);
g_signal_handler_block (buffer, app->mfp_handler2);
}
void menu_status_unblock_activate (GtkMenuItem *menuitem, kwinst *app)
{
if (!app->mfp_handler2) return;
GtkTextBuffer *buffer = GTK_TEXT_BUFFER(app->buffer);
g_signal_handler_unblock (buffer, app->mfp_handler2);
}
一切正常。 Select bigredbtn
菜单项,发出信号向上弹出对话框。然后选择 block
菜单项,然后再次尝试 bigredbtn
-- 没有任何反应,没有对话框,什么也没有。然后选择 unblock
菜单项并再次选择 bigredbtn
,每次选择都会再次弹出对话框。 (并且在处理程序被阻塞时发出的信号没有排队,并且一旦解除阻塞就不会调用处理程序)
这就是我卡住的地方。很大一部分问题是没有逐行挑选GIO源代码,在很大程度上,它是一个大黑盒子。在 GTK 方面一切正常,但是当使用 GIO 功能做同样的事情时,结果似乎没有按预期工作。
感谢您对此问题的任何其他见解。
脚注 1: https://github.com/drankinatty/gtkwrite
脚注 2: buffer_write_file
调用 g_file_set_contents
写入磁盘。
好的,我已经玩够了,我找到了解决办法。无论出于何种原因,在 GIO 的宏伟计划中,关键似乎是从信号最初连接的同一源中调用 block
和 unblock
。例如,添加 block/unblock gtk_filemon.c
源中的函数,然后从任何地方调用(如上面的测试菜单项所做的那样)工作正常,例如:
void file_monitor_block_changed (gpointer data)
{
kwinst *app = (kwinst *)data;
if (!app->filemon || !app->mfp_handler) return;
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_signal_handler_unblock (app->filemon, app->mfp_handler);
}
这允许来自 menu_status_block_activate
和 menu_status_unblock_activate
中的上述两个函数的调用按预期工作,并在阻塞时成功阻止处理 "changed"
信号,并在解除阻塞时恢复。为什么不能通过使用 实例 和 handler_id 直接调用 g_signal_handler_block
和 g_signal_handler_unblock
来完成只是暂时必须保持文档之谜。
注意: 如果有人想玩的话,我会将 github.com gtktest 代码保留到 4 月中旬,此后工作代码将存在于 https://github.com/drankinatty/gtkwrite.
全部,
这可能需要一些时间来设置。在过去的几个月里,我有一个小型编辑器项目[1]。我最初想在当前编辑器文件上实现一个 inotify
监视,以防止被外部进程修改。我创建了一个自定义信号和 add
、remove
和 monitor
(使用 pselect
)的例程和 block
和 [=30= 的监视和例程] 发射自定义信号以允许正常 save/save as
而不会触发回调。我遇到的问题是如何将 monitor
添加到 gtk_event_loop
以便对循环的每次迭代执行检查。我决定使用 g_idle_add
并转到 gtk-app-devel 列表以确定该方法是否合理或者是否有更好的方法。共识是使用 GIO/GFileMonitor
而不是直接使用 inotify
。
快进到当前问题。我重写了使用 GFileMonitor/g_file_monitor_file
的实现并重写了 block
和 unblock
例程以阻止处理 "changed"
信号以允许正常的 save/save as
而不触发回调.问题是当我在保存文件之前 block
实例和 handler_id 回调时,回调仍然会触发。当使用带有自定义信号的 inotify
实现时,阻止信号的发射效果很好。我已将其发回 gtk-app-devel 列表,但在 return 中没有收到任何信息——这就是我在这里提问的原因。为什么 g_signal_handler_block
和 GIO/GFileMonitor
不阻止对 "changed"
信号回调的处理? (更重要的是,我该如何修复它)
注意:(MCVE - 完整的测试代码在 https://github.com/drankinatty/gtktest)。要使用 GtkSourceView2 构建,只需键入 make with=-DWGTKSOURCEVIEW2
,它将构建为 bin/gtkwrite
,否则不构建,只需键入 make
,它将构建为 bin/gtkedit
.
相关代码逻辑如下(app
是struct
持有相关编辑器variables/info和设置的实例)GIO/GFileMonitor实现在gtk_filemon.[ch]
保存函数的包装在 gtk_filebuf.c
:
typedef struct {
...
gchar *filename;
GFileMonitor *filemon;
gulong mfp_handler;
...
} kwinst;
kwinst *app = g_slice_new (kwinst);
我将手表设置为:
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, &err);
...
/* 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);
实例 (app->filemon
) 和 handler_id (app->mfp_handler
) 都已保存。 (mfp
只是 modified by foreign process 的缩写)为了防止在正常 save/save as 操作期间处理更改,我创建了 block 和 unblock 函数以防止触发回调对文件的更改,例如下面显示调试 g_print 调用:
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);
}
为了实现block/unblock
,我用block
包装文件'save/save as'函数,然后保存[2],然后unblock
,但回调仍然是在正常保存时开火。例如我拥有的保存功能的相关部分是:
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 */
使用上面的调试 g_print
语句,发出 save
结果如下:
$ ./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
我是否包含 block/unblock
没有区别,回调的触发没有改变。我怀疑问题在于 "changed"
信号及其处理是通过 GIO
而不是 GTK
实现的(因为 inotify
实现的自定义信号是)使用 g_signal_handler_block
阻止处理 "changed"
信号的能力存在一些差异——尽管我在文档中找不到区别。文档指出:
To get informed about changes to the file or directory you are monitoring, connect to the “changed” signal. The signal will be emitted in the thread-default main context of the thread that the monitor was created in (though if the global default main context is blocked, this may cause notifications to be blocked even if the thread-default context is still running).
https://developer.gnome.org/gio/stable/GFile.html#g-file-monitor-file
应用程序本身不使用任何显式线程,也不 fork
保存的任何部分。所以我不知道为什么 block/unblock
不阻止处理 "changed"
信号。保存完全包含在 block/unblock
中,除非 g_file_set_contents
调用是异步的,否则我看不到任何时间问题。
为什么调用 g_signal_handler_block/g_signal_handler_unblock
无法阻止对当前文件更改时发出的 "changed"
信号的处理?我可以 g_signal_handler_disconnect
并且什么都不触发,但我不应该 disconnect
来暂时阻止处理。我错过了什么?
为了完整起见,file_monitor_on_changed
函数连同脚注包含在下面:
void file_monitor_on_changed (GFileMonitor *mon,
GFile *file, GFile *other,
GFileMonitorEvent evtype,
gpointer data)
{
kwinst *app = (kwinst *)data;
g_print ("Monitor Event: File = %s\n", g_file_get_parse_name (file));
switch (evtype)
{
case G_FILE_MONITOR_EVENT_CHANGED:
/* prompt or emit custom signal modified by foreign process */
g_print ("G_FILE_MONITOR_EVENT_CHANGED\n");
break;
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
g_print ("G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT\n");
break;
case G_FILE_MONITOR_EVENT_DELETED:
/* avoid firing on normal '.tmp' file delete */
if (g_strcmp0 (g_file_get_parse_name (file), app->filename)) {
g_print (" ignoring 'tmp' file delete.\n");
break;
}
/* prompt or emit custom signal modified by foreign process */
g_print ("G_FILE_MONITOR_EVENT_DELETED\n");
/* prompt save file */
break;
case G_FILE_MONITOR_EVENT_CREATED:
g_print ("G_FILE_MONITOR_EVENT_CREATED\n");
break;
case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
g_print ("G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED\n");
break;
case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
g_print ("G_FILE_MONITOR_EVENT_PRE_UNMOUNT\n");
break;
case G_FILE_MONITOR_EVENT_UNMOUNTED:
g_print ("G_FILE_MONITOR_EVENT_UNMOUNTED\n");
break;
case G_FILE_MONITOR_EVENT_MOVED:
g_print ("G_FILE_MONITOR_EVENT_MOVED\n");
/* prompt save file */
break;
case G_FILE_MONITOR_EVENT_RENAMED:
/* prompt save file */
g_print ("G_FILE_MONITOR_EVENT_RENAMED\n");
break;
case G_FILE_MONITOR_EVENT_MOVED_IN:
g_print ("G_FILE_MONITOR_EVENT_MOVED_IN\n");
break;
case G_FILE_MONITOR_EVENT_MOVED_OUT:
g_print ("G_FILE_MONITOR_EVENT_MOVED_OUT\n");
break;
default:
g_print ("unknown EVENT on changed signal.\n");
}
if (mon || other) {}
}
使用g_signal_handler_block在其他情况下工作正常
作为评论中提到的一点,我可以确认我可以轻松 block
、unblock
其他信号处理程序而不会出现问题。具体来说,在使用 inotify
实现时,我创建了以下自定义信号:
/* create signal to monitor file modified by foreign process */
app->SIG_MODFP = g_signal_new ("modified-foreign",
GTK_TYPE_TEXT_BUFFER,
GTK_RUN_ACTION,
0,
NULL,
NULL,
NULL,
G_TYPE_NONE,
1,
G_TYPE_POINTER);
然后将信号连接到处理程序并保存 handler_id 如下:
/* custom signals */
app->mfp_handler2 = g_signal_connect (GTK_TEXT_BUFFER(app->buffer),
"modified-foreign",
G_CALLBACK (on_modified_foreign), app);
on_modified_foreign
回调是一个简单的测试回调,用于测试 block/unblock:
void on_modified_foreign (GtkTextBuffer *buffer,
kwinst *app)
{
dlg_info ("File has changed on disk, reload?", "Modified by Foreign Process");
if (buffer || app) {}
}
以上 dlg_info
只是 gtk_message_dialog_new
的包装器,用于在发出 "modified-foreign"
信号时弹出对话框。
然后执行一个简单的测试,其中一个菜单项会导致发出信号,例如:
void menu_status_bigredbtn_activate (GtkMenuItem *menuitem, kwinst *app)
{
g_signal_emit_by_name (G_OBJECT(app->buffer), "modified-foreign::", app);
}
最后 blocking/unblocking 工作正常:
void menu_status_block_activate (GtkMenuItem *menuitem, kwinst *app)
{
if (!app->mfp_handler2) return;
GtkTextBuffer *buffer = GTK_TEXT_BUFFER(app->buffer);
g_signal_handler_block (buffer, app->mfp_handler2);
}
void menu_status_unblock_activate (GtkMenuItem *menuitem, kwinst *app)
{
if (!app->mfp_handler2) return;
GtkTextBuffer *buffer = GTK_TEXT_BUFFER(app->buffer);
g_signal_handler_unblock (buffer, app->mfp_handler2);
}
一切正常。 Select bigredbtn
菜单项,发出信号向上弹出对话框。然后选择 block
菜单项,然后再次尝试 bigredbtn
-- 没有任何反应,没有对话框,什么也没有。然后选择 unblock
菜单项并再次选择 bigredbtn
,每次选择都会再次弹出对话框。 (并且在处理程序被阻塞时发出的信号没有排队,并且一旦解除阻塞就不会调用处理程序)
这就是我卡住的地方。很大一部分问题是没有逐行挑选GIO源代码,在很大程度上,它是一个大黑盒子。在 GTK 方面一切正常,但是当使用 GIO 功能做同样的事情时,结果似乎没有按预期工作。
感谢您对此问题的任何其他见解。
脚注 1: https://github.com/drankinatty/gtkwrite
脚注 2: buffer_write_file
调用 g_file_set_contents
写入磁盘。
好的,我已经玩够了,我找到了解决办法。无论出于何种原因,在 GIO 的宏伟计划中,关键似乎是从信号最初连接的同一源中调用 block
和 unblock
。例如,添加 block/unblock gtk_filemon.c
源中的函数,然后从任何地方调用(如上面的测试菜单项所做的那样)工作正常,例如:
void file_monitor_block_changed (gpointer data)
{
kwinst *app = (kwinst *)data;
if (!app->filemon || !app->mfp_handler) return;
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_signal_handler_unblock (app->filemon, app->mfp_handler);
}
这允许来自 menu_status_block_activate
和 menu_status_unblock_activate
中的上述两个函数的调用按预期工作,并在阻塞时成功阻止处理 "changed"
信号,并在解除阻塞时恢复。为什么不能通过使用 实例 和 handler_id 直接调用 g_signal_handler_block
和 g_signal_handler_unblock
来完成只是暂时必须保持文档之谜。
注意: 如果有人想玩的话,我会将 github.com gtktest 代码保留到 4 月中旬,此后工作代码将存在于 https://github.com/drankinatty/gtkwrite.