diff --git a/doc/configuration/options.rst b/doc/configuration/options.rst index a0d297b..be769d9 100644 --- a/doc/configuration/options.rst +++ b/doc/configuration/options.rst @@ -142,6 +142,14 @@ General settings :type: Boolean :default: false +.. describe:: smooth-reload + + Defines if flickering will be removed when a file is reloaded on change. + This option might increase memory usage. + + :type: Boolean + :default: true + .. describe:: zoom-max Defines the maximum percentage that the zoom level can be diff --git a/doc/man/zathurarc.5.rst b/doc/man/zathurarc.5.rst index 7b83808..e6a5480 100644 --- a/doc/man/zathurarc.5.rst +++ b/doc/man/zathurarc.5.rst @@ -749,6 +749,13 @@ zathura * Value type: Boolean * Default value: false +*smooth-reload* + Defines if flickering will be removed when a file is reloaded on change. This + option might increase memory usage. + + * Value type: Boolean + * Default value: true + *render-loading* Defines if the "Loading..." text should be displayed if a page is rendered. diff --git a/zathura/callbacks.c b/zathura/callbacks.c index 738834a..5c1c039 100644 --- a/zathura/callbacks.c +++ b/zathura/callbacks.c @@ -204,6 +204,15 @@ cb_refresh_view(GtkWidget* GIRARA_UNUSED(view), gpointer data) return; } + if (zathura->pages != NULL && zathura->pages[page_id] != NULL) { + ZathuraPage* page_widget = ZATHURA_PAGE(zathura->pages[page_id]); + if (page_widget != NULL) { + if (zathura_page_widget_have_surface(page_widget)) { + document_predecessor_free(zathura); + } + } + } + GtkAdjustment* vadj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view)); GtkAdjustment* hadj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view)); diff --git a/zathura/config.c b/zathura/config.c index 7b51400..c082a5a 100644 --- a/zathura/config.c +++ b/zathura/config.c @@ -267,6 +267,8 @@ config_load_default(zathura_t* zathura) girara_setting_add(gsession, "highlight-transparency", &float_value, FLOAT, false, _("Transparency for highlighting"), NULL, NULL); bool_value = true; girara_setting_add(gsession, "render-loading", &bool_value, BOOLEAN, false, _("Render 'Loading ...'"), NULL, NULL); + bool_value = true; + girara_setting_add(gsession, "smooth-reload", &bool_value, BOOLEAN, false, _("Smooth over flicker when reloading file"), NULL, NULL); girara_setting_add(gsession, "adjust-open", "best-fit", STRING, false, _("Adjust to when opening file"), NULL, NULL); bool_value = false; girara_setting_add(gsession, "show-hidden", &bool_value, BOOLEAN, false, _("Show hidden files and directories"), NULL, NULL); diff --git a/zathura/page-widget.c b/zathura/page-widget.c index 733f224..ef9577c 100644 --- a/zathura/page-widget.c +++ b/zathura/page-widget.c @@ -522,7 +522,28 @@ zathura_page_widget_draw(GtkWidget* widget, cairo_t* cairo) const unsigned int page_height = gtk_widget_get_allocated_height(widget); const unsigned int page_width = gtk_widget_get_allocated_width(widget); - if (priv->surface != NULL || priv->thumbnail != NULL) { + bool smooth_reload = true; + girara_setting_get(priv->zathura->ui.session, "smooth-reload", &smooth_reload); + + bool surface_exists = priv->surface != NULL || priv->thumbnail != NULL; + + if (priv->zathura->predecessor_document != NULL && priv->zathura->predecessor_pages != NULL + && smooth_reload && !surface_exists) { + unsigned int page_index = zathura_page_get_index(priv->page); + + if (page_index < zathura_document_get_number_of_pages(priv->zathura->predecessor_document)) { + /* render real page */ + zathura_render_request(priv->render_request, g_get_real_time()); + + girara_debug("using predecessor page for idx %d", page_index); + document = priv->zathura->predecessor_document; + page = ZATHURA_PAGE(priv->zathura->predecessor_pages[page_index]); + priv = zathura_page_widget_get_instance_private(page); + } + surface_exists = priv->surface != NULL || priv->thumbnail != NULL; + } + + if (surface_exists) { cairo_save(cairo); const unsigned int rotation = zathura_document_get_rotation(document); @@ -634,6 +655,10 @@ zathura_page_widget_draw(GtkWidget* widget, cairo_t* cairo) ); } } else { + if (smooth_reload) { + girara_debug("rendering loading screen, flicker might be happening"); + } + /* set background color */ if (zathura_renderer_recolor_enabled(priv->zathura->sync.render_thread) == true) { GdkRGBA color; diff --git a/zathura/zathura.c b/zathura/zathura.c index 6a6cae3..c5e00c8 100644 --- a/zathura/zathura.c +++ b/zathura/zathura.c @@ -1493,6 +1493,32 @@ save_fileinfo_to_db(zathura_t* zathura) g_free(file_info.first_page_column_list); } +bool +document_predecessor_free(zathura_t* zathura) { + if (zathura == NULL + || (zathura->predecessor_document == NULL + && zathura->predecessor_pages == NULL)) { + return false; + } + + if (zathura->predecessor_pages != NULL) { + for (unsigned int i = 0; i < zathura_document_get_number_of_pages(zathura->predecessor_document); i++) { + g_object_unref(zathura->predecessor_pages[i]); + } + free(zathura->predecessor_pages); + zathura->predecessor_pages = NULL; + girara_debug("freed predecessor pages"); + } + if (zathura->predecessor_document != NULL) { + /* remove document */ + zathura_document_free(zathura->predecessor_document); + zathura->predecessor_document = NULL; + girara_debug("freed predecessor document"); + } + + return true; +} + bool document_close(zathura_t* zathura, bool keep_monitor) { @@ -1508,6 +1534,9 @@ document_close(zathura_t* zathura, bool keep_monitor) g_free(window_icon); } + bool smooth_reload = true; + girara_setting_get(zathura->ui.session, "smooth-reload", &smooth_reload); + /* stop rendering */ zathura_renderer_stop(zathura->sync.render_thread); g_clear_object(&zathura->window_icon_render_request); @@ -1543,17 +1572,43 @@ document_close(zathura_t* zathura, bool keep_monitor) /* release render thread */ g_clear_object(&zathura->sync.render_thread); + /* keep the current state to prevent flicker? */ + bool override_predecessor = keep_monitor && smooth_reload; + + if (override_predecessor) { + /* do not override predecessor buffer with empty pages */ + unsigned int cur_page_num = zathura_document_get_current_page_number(zathura->document); + ZathuraPage* cur_page = ZATHURA_PAGE(zathura->pages[cur_page_num]); + if (!zathura_page_widget_have_surface(cur_page)) { + override_predecessor = false; + } + } + + /* free predecessor buffer if we want to overwrite it or if we destroy the document for good */ + if (override_predecessor || !keep_monitor || !smooth_reload) { + document_predecessor_free(zathura); + } + /* remove widgets */ gtk_container_foreach(GTK_CONTAINER(zathura->ui.page_widget), remove_page_from_table, NULL); - for (unsigned int i = 0; i < zathura_document_get_number_of_pages(zathura->document); i++) { - g_object_unref(zathura->pages[i]); - } - free(zathura->pages); - zathura->pages = NULL; - /* remove document */ - zathura_document_free(zathura->document); - zathura->document = NULL; + if (!override_predecessor) { + for (unsigned int i = 0; i < zathura_document_get_number_of_pages(zathura->document); i++) { + g_object_unref(zathura->pages[i]); + } + free(zathura->pages); + zathura->pages = NULL; + + /* remove document */ + zathura_document_free(zathura->document); + zathura->document = NULL; + } else { + girara_debug("preserving pages and document as predecessor"); + zathura->predecessor_pages = zathura->pages; + zathura->pages = NULL; + zathura->predecessor_document = zathura->document; + zathura->document = NULL; + } /* remove index */ if (zathura->ui.index != NULL) { diff --git a/zathura/zathura.h b/zathura/zathura.h index 7a31717..a9cf41e 100644 --- a/zathura/zathura.h +++ b/zathura/zathura.h @@ -184,7 +184,9 @@ struct zathura_s } stdin_support; zathura_document_t* document; /**< The current document */ + zathura_document_t* predecessor_document; /**< The document from before a reload */ GtkWidget** pages; /**< The page widgets */ + GtkWidget** predecessor_pages; /**< The page widgets from before a reload */ zathura_database_t* database; /**< The database */ ZathuraDbus* dbus; /**< D-Bus service */ ZathuraRenderRequest* window_icon_render_request; /**< Render request for window icon */ @@ -360,6 +362,14 @@ void document_open_idle(zathura_t* zathura, const char* path, */ bool document_save(zathura_t* zathura, const char* path, bool overwrite); +/** + * Frees the "predecessor" buffers used for smooth-reload + * + * @param zathura The zathura session + * @return If no error occurred true, otherwise false, is returned. + */ +bool document_predecessor_free(zathura_t* zathura); + /** * Closes the current opened document *