[SOLVED]How to auto scroll the scrollbar to bottom when window get minimized

I am working on a project which has to be in GTK-2.0 and the problem I am facing is that If the window gets Minimized after being Maximized the scrollbar does not goes back the bottom anymore.

Here is a part of the code which could be seen and tested:

#include <gtk/gtk.h>

typedef struct
{
    GtkWidget *entry;
    GtkWidget *textview;
} Widgets;

void chatMSG ( GtkButton *, Widgets * );

int main ( void )
{
    GtkWidget *window, *scrolled_win, *hbox, *vbox, *button;
    Widgets *widg = g_slice_new ( Widgets );
    /// ***
    gtk_init ( NULL, NULL );
    /// ***
    window = gtk_window_new ( GTK_WINDOW_TOPLEVEL );
    g_signal_connect ( G_OBJECT ( window ), "delete_event", gtk_main_quit, NULL );
    gtk_window_set_title ( GTK_WINDOW ( window ), "WhatsChat" );
    gtk_container_set_border_width ( GTK_CONTAINER ( window ), 10 );
    gtk_widget_set_size_request ( window, 250, 200 );
    /// ***
    widg->textview = gtk_text_view_new();
    gtk_text_view_set_editable ( GTK_TEXT_VIEW ( widg->textview ), FALSE );
    gtk_text_view_set_cursor_visible ( GTK_TEXT_VIEW ( widg->textview ), FALSE );
    /// ***
    widg->entry = gtk_entry_new();
    button = gtk_button_new_with_label ( "Send" );
    /// ***
    g_signal_connect ( G_OBJECT ( button      ), "clicked",  G_CALLBACK ( chatMSG ), ( gpointer ) widg );
    g_signal_connect ( G_OBJECT ( widg->entry ), "activate", G_CALLBACK ( chatMSG ), ( gpointer ) widg );
    /// ***
    scrolled_win = gtk_scrolled_window_new ( NULL, NULL );
    gtk_widget_set_size_request ( scrolled_win, -1, 200 );
    gtk_scrolled_window_set_policy ( GTK_SCROLLED_WINDOW ( scrolled_win ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
    gtk_container_add ( GTK_CONTAINER ( scrolled_win ), widg->textview );
    /// ***
    hbox = gtk_hbox_new ( FALSE, 5 );
    gtk_box_pack_start_defaults ( GTK_BOX ( hbox ), widg->entry );
    gtk_box_pack_start_defaults ( GTK_BOX ( hbox ), button );
    /// ***
    vbox = gtk_vbox_new ( FALSE, 5 );
    gtk_box_pack_start ( GTK_BOX ( vbox ), scrolled_win, TRUE, TRUE, 0 );
    gtk_box_pack_start ( GTK_BOX ( vbox ), hbox, FALSE, TRUE, 0 );
    /// ***
    gtk_container_add ( GTK_CONTAINER ( window ), vbox );
    gtk_widget_show_all ( window );
    gtk_main();
}

void chatMSG ( GtkButton *button, Widgets *widg )
{
    ( void ) button;
    GtkTextBuffer *buffer;
    GtkTextMark *mark;
    GtkTextIter iter, start, end;
    const gchar *text;
    /// ***
    buffer = gtk_text_view_get_buffer ( GTK_TEXT_VIEW ( widg->textview ) );
    text   = gtk_entry_get_text ( GTK_ENTRY ( widg->entry ) );
    /// ***
    mark = gtk_text_buffer_get_insert ( buffer );
    gtk_text_buffer_get_iter_at_mark ( buffer, &iter, mark );
    gtk_text_buffer_get_bounds ( buffer, &start, &end );

    if (  gtk_text_buffer_get_char_count ( buffer ) && strlen( text ) > 0 )
    {
        gtk_text_buffer_insert ( buffer, &iter, "\n", -1 );
    }

    gtk_text_buffer_insert ( buffer, &iter, text, -1 );
    gtk_entry_set_text ( GTK_ENTRY ( widg->entry ), "" );
    /// ***
    mark = gtk_text_buffer_create_mark ( buffer, NULL, &iter, FALSE );
    gtk_text_view_scroll_mark_onscreen ( GTK_TEXT_VIEW ( widg->textview ), mark );
    gtk_text_buffer_delete_mark ( buffer, mark );
}

My guess is that somehow I mixed up things in the chatMSG() Funcion. How do I keep the scrollbar at a bottom after user minimize the Window?

There’s probably a better way, but here’s an option that seems to work pretty well:

void
scroll_value_changed (GtkAdjustment *adjustment,
                      gpointer       user_data)
{
    double *from_bottom = user_data;

    double value = gtk_adjustment_get_value (adjustment);
    double upper = gtk_adjustment_get_upper (adjustment);
    double page_size = gtk_adjustment_get_page_size (adjustment);

    *from_bottom = upper - page_size - value;
}

void
scroll_bottom_gravity (GtkWidget    *scrolled_window,
                       GdkRectangle *allocation,
                       gpointer      user_data)
{
    GtkAdjustment *adjustment = gtk_scrolled_window_get_vadjustment (
        GTK_SCROLLED_WINDOW (scrolled_window));

    double *from_bottom = user_data;

    double upper = gtk_adjustment_get_upper (adjustment);
    double page_size = gtk_adjustment_get_page_size (adjustment);

    gtk_adjustment_set_value (adjustment, upper - page_size - *from_bottom);
}

and in main:

{
    double from_bottom = 0.0;
    GtkAdjustment *adjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (scrolled_win));
    g_signal_connect (scrolled_win, "size-allocate", (GCallback) scroll_bottom_gravity, &from_bottom);
    g_signal_connect (adjustment, "value-changed", (GCallback) scroll_value_changed, &from_bottom);
}

It mostly preserves the position of the scrolled window relative to the bottom of the visible page. The only glitch is if the scrollbar is close to the bottom in an unmaximized window and you toggle maximize, the scrollbar will stay at the bottom instead of returning to the previous position.

Also, you’re inserting text at the (invisible) cursor, not necessarily at the end of the buffer. You can use gtk_text_buffer_get_end_iter for that.

1 Like

There was something similar which I was approaching and did not work.
Now I know why.
This solution you provided is more that I need.
Thank you

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.