On 12/22/2015 05:13 PM, David C. Rankin wrote:
How can I limit the the execution of the 'on_mark_set' callback to a single
call regardless of whether there is data being entered or if cursor is being
moved with the arrow-keys or mouse? Any help will be greatly appreciated.
OK, I have a solution that is probably not as elegant as desired. Delving into
the "mark_set" signal and multiple firing of the callback opened a small can of
worms regarding a number of considerations associated with GtkTextMark and
GtkTextIter relationships.
The problem can be summarized as follows:
(1) the proper callback prototype to handle the "mark_set" signal is:
void on_mark_set (GtkTextBuffer *buffer, GtkTextIter *iter,
GtkTextMark *mark, context *app)
(2) there are multiple text marks at each iter location.
(3) when responding to the "mark_set" signal, the 'mark' passed to the callback
can be any of the marks at the "iter" location which are passed in "no
particular order" and are passed differently depending on whether normal text is
being entered, arrow-keys are pressed, or whether the mouse is clicked to
reposition to "insert" cursor mark.
(4) This prevents a simple comparison between the "mark" parameter and
gtk_text_buffer_get_insert (buffer) alone from being used to determine whether
to respond to a "mark_set" signal or not.
The short version of a solution to prevent responding to multiple "mark_set"
signals is as follows. (the callback is still fired, but you can test between
'current' and 'new' line:col locations responding only when the values differ)
void on_mark_set (GtkTextBuffer *buffer, GtkTextIter *iter,
GtkTextMark *mark, context *app)
{
gint line, col;
line = gtk_text_iter_get_line (iter);
col = gtk_text_iter_get_line_offset (iter);
if (line == app->line && col == app->col) return;
app->line = line;
app->col = col;
g_print (" line: %3d col: %d\n", app->line + 1, app->col + 1);
if (buffer) {}
if (mark) {}
}
Now for the rest of the story... I am normally reasonably adept at finding this
type of information myself in the documentation or via the web without having to
ask, but in this case there simply isn't much in the way of details on how, what
or in what order "mark_set" callback parameters are passed each time the
callback is fired. I'll leave what I found here to save the next person a bit of
time.
Each time the "mark_set" signal is generated, there can be multiple marks at any
given iter *location*. In the case of normal input (e.g. 'a', 'b', etc...) the
mark passed to the on_mark_set() callback is not necessarily the "insert" mark,
but is apparently simply the last of the marks present at that iter *location*.
(In each case below an anonymous mark is passed as a result of normal text
input) The list of marks at any given iter position can be found by the GSList
of marks returned by gtk_text_iter_get_marks (iter). (*note:* the marks in the
list returned are in *no particular* order -- which is probably the basis for
this whole issue to begin with. See:
https://developer.gnome.org/gtk2/stable/GtkTextIter.html#gtk-text-iter-get-marks) For
example, you can examine the marks with the following debug code:
void on_mark_set (GtkTextBuffer *buffer, GtkTextIter *iter,
GtkTextMark *mark, context *app)
{
gint line, col;
#ifdef DEBUG
g_print (" mark: %p - gtbgi (buffer): %p mark->name: %s\n", mark,
gtk_text_buffer_get_insert (buffer),
gtk_text_mark_get_name (mark));
GSList *marks = gtk_text_iter_get_marks (iter);
GSList *p = marks;
gint i = 0;
while (p) {
const gchar *name = gtk_text_mark_get_name (GTK_TEXT_MARK(p->data));
g_print ("mark[%d] : %p : %s\n", i++, GTK_TEXT_MARK(p->data),
name);
p = p->next;
}
g_slist_free (marks);
#endif
line = gtk_text_iter_get_line (iter);
col = gtk_text_iter_get_line_offset (iter);
if (line == app->line && col == app->col) return;
app->line = line;
app->col = col;
#ifdef DEBUG
g_print (" line: %3d col: %d\n\n", app->line + 1, app->col + 1);
#endif
if (mark) {}
}
Compiling and then using the same (enter 'abc', then Left-Arrow, then
*mouse-click* at the end) fires the on_mark_set() callback for each 'abc' entered:
$ ./bin/text_mcve_dbg
mark: 0x2458880 - gtbgi (buffer): 0x237d600 mark->name: (null)
mark[0] : 0x237d600 : insert
mark[1] : 0x237d620 : selection_bound
mark[2] : 0x237d7a0 : gtk_drag_target
mark[3] : 0x2458880 : (null)
line: 1 col: 2
mark: 0x24792c0 - gtbgi (buffer): 0x237d600 mark->name: (null)
mark[0] : 0x237d600 : insert
mark[1] : 0x237d620 : selection_bound
mark[2] : 0x237d7a0 : gtk_drag_target