After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 788101 - gtk_text_view_scroll_to_iter() does nothing
gtk_text_view_scroll_to_iter() does nothing
Status: RESOLVED OBSOLETE
Product: gtk+
Classification: Platform
Component: Widget: GtkTextView
3.22.x
Other Linux
: Normal normal
: ---
Assigned To: gtk-bugs
gtk-bugs
Depends on:
Blocks:
 
 
Reported: 2017-09-24 16:27 UTC by Mike Cornelison
Modified: 2018-05-02 19:08 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Mike Cornelison 2017-09-24 16:27:52 UTC
code fragment:
   gtk_text_buffer_select_range(textBuff,&iter1,&iter2);
   gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(widget),&iter2,0,0,1,1);
  
The select range works correctly but the selected text is below the bottom edge of a scrolling text widget. The scroll request does nothing. I have played with the four numerical args to no avail. I also tried making a GtkTextMark and scrolling to that, but that also does nothing. No errors are produced. The text widget scrolls OK using the mouse wheel or scroll bars. 
  
What can be behind this?
  
I looked for a forum but there seems to be nothing. If there is, please tell me.
Comment 1 André Klapper 2017-09-24 19:39:47 UTC
Could you provide a minimal self-contained testcase?
Comment 2 Mike Cornelison 2017-09-25 19:08:46 UTC
I wrote the test program which is copied below. 

Here is what I found out: 
1. If the container hierarchy is scroll-window, frame, text-view, then
   scrolling with the mouse wheel or scroll bars works, but programmatic
   scrolling (scroll to iter or mark) does not work.
2. If the container hierarchy is scroll-window, text-view (no frame),
   then everything works OK.

Test program and make file follow:


ztest.cc --------------------------------------------------------------------------------

//  test gtk_text_view for program-controlled scrolling


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <gtk/gtk.h>


int eventfunc(GtkWidget *widget, GdkEvent *event);
void textview_append(GtkWidget *widget, const char *text);
char * textview_get_line(GtkWidget *widget, int line);

int   currline = 0;
int   Nlines = 100;


int main(int argc, char *argv[])
{
   GtkWidget   *reportwin, *scrollwin, *frame, *textview;
   char        buff[100];

   setenv("GDK_BACKEND","x11",1);
   setenv("GTK_THEME","default",0);

   gtk_init(&argc,&argv);

   reportwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
   gtk_window_set_title(GTK_WINDOW(reportwin),"report window");
   gtk_window_set_default_size(GTK_WINDOW(reportwin),500,300);
   gtk_window_set_position(GTK_WINDOW(reportwin),GTK_WIN_POS_CENTER_ON_PARENT);
   scrollwin = gtk_scrolled_window_new(0,0);
   gtk_container_add(GTK_CONTAINER(reportwin),scrollwin);
//-------------------------------------------------------------------------------
//   frame = gtk_frame_new(0);
//   gtk_container_add(GTK_CONTAINER(scrollwin),frame);          //  option A FAILS
//   textview = gtk_text_view_new();
//   gtk_container_add(GTK_CONTAINER(frame),textview);
//-------------------------------------------------------------------------------
   textview = gtk_text_view_new();                             //  option B OK
   gtk_container_add(GTK_CONTAINER(scrollwin),textview);
//-------------------------------------------------------------------------------

   gtk_text_view_set_editable(GTK_TEXT_VIEW(textview),0);

   gtk_widget_show_all(reportwin);
   
   g_signal_connect(G_OBJECT(reportwin),"destroy",gtk_main_quit,0);
   g_signal_connect(G_OBJECT(reportwin),"delete-event",gtk_main_quit,0);
   
   gtk_widget_add_events(textview,GDK_BUTTON_PRESS_MASK);
   gtk_widget_add_events(textview,GDK_KEY_PRESS_MASK);
   gtk_widget_add_events(textview,GDK_ENTER_NOTIFY_MASK);
   g_signal_connect(G_OBJECT(textview),"key-press-event",G_CALLBACK(eventfunc),0);
   g_signal_connect(G_OBJECT(textview),"button-press-event",G_CALLBACK(eventfunc),0);
   g_signal_connect(G_OBJECT(textview),"enter-notify-event",G_CALLBACK(eventfunc),0);

   for (int line = 0; line < Nlines; line++) 
   {
      snprintf(buff,100,"%03d The quick brown fox jumps over the lazy dog.\n",line);
      textview_append(textview,buff);
   }

   gtk_main();
   return 0;
}


int eventfunc(GtkWidget *widget, GdkEvent *event)
{
   GdkDisplay        *display;
   GdkWindow         *gdkwin;
   static GdkCursor  *arrowcursor = 0;
   GtkTextIter       iter1;
   int               mpx, mpy, tbx, tby, line, pos, kbkey;
   char              *textline;

   #define TEXT GTK_TEXT_WINDOW_TEXT
   #define VIEW GTK_TEXT_VIEW
   #define ARROW GDK_TOP_LEFT_ARROW
   #define appfontsize 12

   if (! arrowcursor) {
      gdkwin = gtk_widget_get_window(widget);
      display = gdk_window_get_display(gdkwin);
      arrowcursor = gdk_cursor_new_for_display(display,ARROW);
   }

   gdkwin = gtk_text_view_get_window(VIEW(widget),TEXT);
   if (gdkwin) gdk_window_set_cursor(gdkwin,arrowcursor);

   if (event->type == GDK_KEY_PRESS) {
      kbkey = ((GdkEventKey *) event)->keyval;
      printf("keyboard key %d \n",kbkey);
      if (kbkey == GDK_KEY_Up) currline--;
      if (kbkey == GDK_KEY_Down) currline++;
      if (currline < 0) currline = 0;
      if (currline > Nlines-1) currline = Nlines - 1;
      textline = textview_get_line(widget,currline);
      return 1;
   }

   if (event->type == GDK_BUTTON_PRESS) {
      mpx = int(((GdkEventButton *) event)->x);
      mpy = int(((GdkEventButton *) event)->y);
      mpx -= appfontsize / 2;
      if (mpx < 0) mpx = 0;
      gtk_text_view_window_to_buffer_coords(VIEW(widget),TEXT,mpx,mpy,&tbx,&tby);
      gtk_text_view_get_iter_at_location(VIEW(widget),&iter1,tbx,tby);
      line = gtk_text_iter_get_line(&iter1);
      pos = gtk_text_iter_get_line_offset(&iter1);
      printf("click on line %d  position %d \n",line,pos);
      currline = line;
      textline = textview_get_line(widget,currline);
      if (textline) free(textline);
      return 1;
   }
   
   return 0;
}


void textview_append(GtkWidget *widget, const char *text)
{
   GtkTextBuffer  *textBuff;
   GtkTextIter    enditer;
   GtkTextMark    *endmark;
   GtkTextTag     *fontag;

   textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));

   gtk_text_buffer_get_end_iter(textBuff,&enditer);
   endmark = gtk_text_buffer_create_mark(textBuff,"endmark",&enditer,0);

   fontag = gtk_text_buffer_create_tag(textBuff,0,"font","mono 12",0);
   gtk_text_buffer_insert_with_tags(textBuff,&enditer,text,-1,fontag,NULL);

   gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(widget),endmark,0,0,1,1);

   while (gtk_events_pending()) gtk_main_iteration_do(0);
   return;
}


char * textview_get_line(GtkWidget *widget, int line)
{
   GtkTextBuffer  *textBuff;
   GtkTextIter    iter1, iter2;
   int            nlines;
   char           *textline;

   textBuff = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
   
   nlines = gtk_text_buffer_get_line_count(textBuff);
   if (line < 0 || line >= nlines) return 0;
   
   gtk_text_buffer_get_iter_at_line(textBuff,&iter1,line);
   iter2 = iter1;
   gtk_text_iter_forward_line(&iter2);
   textline = gtk_text_buffer_get_text(textBuff,&iter1,&iter2,0);
   if (! textline) return 0;
   gtk_text_buffer_select_range(textBuff,&iter1,&iter2);
   gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(widget),&iter1,0,0,1,1);
   gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(widget),&iter2,0,0,1,1);
   return textline;
}



Makefile: --------------------------------------------------------------------------

CFLAGS = $(CXXFLAGS) -Wall -O0 -c `pkg-config --cflags gtk+-3.0`

ztest: ztest.o
	$(CXX) $(LDFLAGS) -o ztest ztest.o `pkg-config --libs gtk+-3.0`

ztest.o: ztest.cc
	$(CXX) $(CFLAGS) -o ztest.o ztest.cc
Comment 3 Daniel Boles 2018-03-15 12:55:44 UTC
I'm pretty sure this is just because ScrolledWindow won't traverse >1 child to get scroll adjustments to sync to.

When adding the TextView, ScrolledWindow.add() finds that it's a GtkScrollable, so the SW syncs its h/v adjustments with the TextView.

Otherwise, when adding the Frame, or any other non-Scrollable, that gets wrapped in the autogenerated ViewPort, then the ScrolledWindow syncs its adjustments with those of the ViewPort, not the nested TextView.

In this case, I can't see why you wouldn't just use Frame > ScrolledWindow > TextView anyway.
Comment 4 GNOME Infrastructure Team 2018-05-02 19:08:39 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to GNOME's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/gtk/issues/918.