"Fossies" - the Fresh Open Source Software Archive

Member "darktable-3.6.1/src/libs/backgroundjobs.c" (10 Sep 2021, 11425 Bytes) of package /linux/misc/darktable-3.6.1.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "backgroundjobs.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3.4.1.1_vs_3.6.0.

    1 /*
    2     This file is part of darktable,
    3     Copyright (C) 2011-2021 darktable developers.
    4 
    5     darktable is free software: you can redistribute it and/or modify
    6     it under the terms of the GNU General Public License as published by
    7     the Free Software Foundation, either version 3 of the License, or
    8     (at your option) any later version.
    9 
   10     darktable is distributed in the hope that it will be useful,
   11     but WITHOUT ANY WARRANTY; without even the implied warranty of
   12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13     GNU General Public License for more details.
   14 
   15     You should have received a copy of the GNU General Public License
   16     along with darktable.  If not, see <http://www.gnu.org/licenses/>.
   17 */
   18 
   19 #include "common/darktable.h"
   20 #include "common/debug.h"
   21 #include "common/image_cache.h"
   22 #include "control/conf.h"
   23 #include "control/control.h"
   24 #include "control/progress.h"
   25 #include "develop/develop.h"
   26 #include "dtgtk/button.h"
   27 #include "gui/draw.h"
   28 #include "gui/gtk.h"
   29 #include "libs/lib.h"
   30 #include "libs/lib_api.h"
   31 
   32 DT_MODULE(1)
   33 
   34 typedef struct dt_lib_backgroundjob_element_t
   35 {
   36   GtkWidget *widget, *label, *progressbar, *hbox;
   37 } dt_lib_backgroundjob_element_t;
   38 
   39 /* proxy functions */
   40 static void *_lib_backgroundjobs_added(dt_lib_module_t *self, gboolean has_progress_bar, const gchar *message);
   41 static void _lib_backgroundjobs_destroyed(dt_lib_module_t *self, dt_lib_backgroundjob_element_t *instance);
   42 static void _lib_backgroundjobs_cancellable(dt_lib_module_t *self, dt_lib_backgroundjob_element_t *instance,
   43                                             dt_progress_t *progress);
   44 static void _lib_backgroundjobs_updated(dt_lib_module_t *self, dt_lib_backgroundjob_element_t *instance,
   45                                         double value);
   46 static void _lib_backgroundjobs_message_updated(dt_lib_module_t *self, dt_lib_backgroundjob_element_t *instance,
   47                                                 const gchar *message);
   48 
   49 
   50 const char *name(dt_lib_module_t *self)
   51 {
   52   return _("background jobs");
   53 }
   54 
   55 const char **views(dt_lib_module_t *self)
   56 {
   57   static const char *v[] = {"*", NULL};
   58   return v;
   59 }
   60 
   61 uint32_t container(dt_lib_module_t *self)
   62 {
   63   return DT_UI_CONTAINER_PANEL_LEFT_BOTTOM;
   64 }
   65 
   66 int position()
   67 {
   68   return 1;
   69 }
   70 
   71 int expandable(dt_lib_module_t *self)
   72 {
   73   return 0;
   74 }
   75 
   76 void gui_init(dt_lib_module_t *self)
   77 {
   78   /* initialize base */
   79   self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
   80   gtk_widget_set_no_show_all(self->widget, TRUE);
   81 
   82   /* setup proxy */
   83   dt_pthread_mutex_lock(&darktable.control->progress_system.mutex);
   84 
   85   darktable.control->progress_system.proxy.module = self;
   86   darktable.control->progress_system.proxy.added = _lib_backgroundjobs_added;
   87   darktable.control->progress_system.proxy.destroyed = _lib_backgroundjobs_destroyed;
   88   darktable.control->progress_system.proxy.cancellable = _lib_backgroundjobs_cancellable;
   89   darktable.control->progress_system.proxy.updated = _lib_backgroundjobs_updated;
   90   darktable.control->progress_system.proxy.message_updated = _lib_backgroundjobs_message_updated;
   91 
   92   // iterate over darktable.control->progress_system.list and add everything that is already there and update
   93   // its gui_data!
   94   for(const GList *iter = darktable.control->progress_system.list; iter; iter = g_list_next(iter))
   95   {
   96     dt_progress_t *progress = (dt_progress_t *)iter->data;
   97     void *gui_data = dt_control_progress_get_gui_data(progress);
   98     free(gui_data);
   99     gui_data = _lib_backgroundjobs_added(self, dt_control_progress_has_progress_bar(progress),
  100                                          dt_control_progress_get_message(progress));
  101     dt_control_progress_set_gui_data(progress, gui_data);
  102     if(dt_control_progress_cancellable(progress)) _lib_backgroundjobs_cancellable(self, gui_data, progress);
  103     _lib_backgroundjobs_updated(self, gui_data, dt_control_progress_get_progress(progress));
  104   }
  105 
  106   dt_pthread_mutex_unlock(&darktable.control->progress_system.mutex);
  107 }
  108 
  109 void gui_cleanup(dt_lib_module_t *self)
  110 {
  111   /* lets kill proxy */
  112   dt_pthread_mutex_lock(&darktable.control->progress_system.mutex);
  113   darktable.control->progress_system.proxy.module = NULL;
  114   darktable.control->progress_system.proxy.added = NULL;
  115   darktable.control->progress_system.proxy.destroyed = NULL;
  116   darktable.control->progress_system.proxy.cancellable = NULL;
  117   darktable.control->progress_system.proxy.updated = NULL;
  118   dt_pthread_mutex_unlock(&darktable.control->progress_system.mutex);
  119 }
  120 
  121 /** the proxy functions */
  122 
  123 typedef struct _added_gui_thread_t
  124 {
  125   GtkWidget *self_widget, *instance_widget;
  126 } _added_gui_thread_t;
  127 
  128 static gboolean _added_gui_thread(gpointer user_data)
  129 {
  130   _added_gui_thread_t *params = (_added_gui_thread_t *)user_data;
  131 
  132   /* lets show jobbox if its hidden */
  133   gtk_box_pack_start(GTK_BOX(params->self_widget), params->instance_widget, TRUE, FALSE, 0);
  134   gtk_box_reorder_child(GTK_BOX(params->self_widget), params->instance_widget, 1);
  135   gtk_widget_show_all(params->instance_widget);
  136   gtk_widget_show(params->self_widget);
  137 
  138   free(params);
  139   return FALSE;
  140 }
  141 
  142 static void *_lib_backgroundjobs_added(dt_lib_module_t *self, gboolean has_progress_bar, const gchar *message)
  143 {
  144   // add a new gui thingy
  145   dt_lib_backgroundjob_element_t *instance
  146       = (dt_lib_backgroundjob_element_t *)calloc(1, sizeof(dt_lib_backgroundjob_element_t));
  147   if(!instance) return NULL;
  148   _added_gui_thread_t *params = (_added_gui_thread_t *)malloc(sizeof(_added_gui_thread_t));
  149   if(!params)
  150   {
  151     free(instance);
  152     return NULL;
  153   }
  154 
  155   instance->widget = gtk_event_box_new();
  156 
  157   /* initialize the ui elements for job */
  158   gtk_widget_set_name(GTK_WIDGET(instance->widget), "background_job_eventbox");
  159   GtkBox *vbox = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0));
  160   instance->hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
  161   gtk_container_add(GTK_CONTAINER(instance->widget), GTK_WIDGET(vbox));
  162 
  163   /* add job label */
  164   instance->label = gtk_label_new(message);
  165   gtk_widget_set_halign(instance->label, GTK_ALIGN_START);
  166   gtk_label_set_ellipsize(GTK_LABEL(instance->label), PANGO_ELLIPSIZE_END);
  167   gtk_box_pack_start(GTK_BOX(instance->hbox), GTK_WIDGET(instance->label), TRUE, TRUE, 0);
  168   gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(instance->hbox), TRUE, TRUE, 0);
  169 
  170   /* use progressbar ? */
  171   if(has_progress_bar)
  172   {
  173     instance->progressbar = gtk_progress_bar_new();
  174     gtk_box_pack_start(GTK_BOX(vbox), instance->progressbar, TRUE, FALSE, 0);
  175   }
  176 
  177   /* lets show jobbox if its hidden */
  178   params->self_widget = self->widget;
  179   params->instance_widget = instance->widget;
  180   g_main_context_invoke(NULL, _added_gui_thread, params);
  181 
  182   // return the gui thingy container
  183   return instance;
  184 }
  185 
  186 typedef struct _destroyed_gui_thread_t
  187 {
  188   dt_lib_module_t *self;
  189   dt_lib_backgroundjob_element_t *instance;
  190 } _destroyed_gui_thread_t;
  191 
  192 static gboolean _destroyed_gui_thread(gpointer user_data)
  193 {
  194   _destroyed_gui_thread_t *params = (_destroyed_gui_thread_t *)user_data;
  195 
  196   /* remove job widget from jobbox */
  197   if(params->instance->widget && GTK_IS_WIDGET(params->instance->widget))
  198     gtk_container_remove(GTK_CONTAINER(params->self->widget), params->instance->widget);
  199   params->instance->widget = NULL;
  200 
  201   /* if jobbox is empty let's hide */
  202   if(!dt_gui_container_has_children(GTK_CONTAINER(params->self->widget)))
  203     gtk_widget_hide(params->self->widget);
  204 
  205   // free data
  206   free(params->instance);
  207   free(params);
  208   return FALSE;
  209 }
  210 
  211 // remove the gui that is pointed to in instance
  212 static void _lib_backgroundjobs_destroyed(dt_lib_module_t *self, dt_lib_backgroundjob_element_t *instance)
  213 {
  214   _destroyed_gui_thread_t *params = (_destroyed_gui_thread_t *)malloc(sizeof(_destroyed_gui_thread_t));
  215   if(!params) return;
  216   params->self = self;
  217   params->instance = instance;
  218   g_main_context_invoke(NULL, _destroyed_gui_thread, params);
  219 }
  220 
  221 static void _lib_backgroundjobs_cancel_callback_new(GtkWidget *w, gpointer user_data)
  222 {
  223   dt_progress_t *progress = (dt_progress_t *)user_data;
  224   dt_control_progress_cancel(darktable.control, progress);
  225 }
  226 
  227 typedef struct _cancellable_gui_thread_t
  228 {
  229   dt_lib_backgroundjob_element_t *instance;
  230   dt_progress_t *progress;
  231 } _cancellable_gui_thread_t;
  232 
  233 static gboolean _cancellable_gui_thread(gpointer user_data)
  234 {
  235   _cancellable_gui_thread_t *params = (_cancellable_gui_thread_t *)user_data;
  236 
  237   GtkBox *hbox = GTK_BOX(params->instance->hbox);
  238   GtkWidget *button = dtgtk_button_new(dtgtk_cairo_paint_cancel, CPF_STYLE_FLAT, NULL);
  239   g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(_lib_backgroundjobs_cancel_callback_new), params->progress);
  240   gtk_box_pack_start(hbox, GTK_WIDGET(button), FALSE, FALSE, 0);
  241   gtk_widget_show_all(button);
  242 
  243   free(params);
  244   return FALSE;
  245 }
  246 
  247 static void _lib_backgroundjobs_cancellable(dt_lib_module_t *self, dt_lib_backgroundjob_element_t *instance,
  248                                             dt_progress_t *progress)
  249 {
  250   // add a cancel button to the gui. when clicked we want dt_control_progress_cancel(darktable.control,
  251   // progress); to be called
  252   if(!darktable.control->running) return;
  253 
  254   _cancellable_gui_thread_t *params = (_cancellable_gui_thread_t *)malloc(sizeof(_cancellable_gui_thread_t));
  255   if(!params) return;
  256   params->instance = instance;
  257   params->progress = progress;
  258   g_main_context_invoke(NULL, _cancellable_gui_thread, params);
  259 }
  260 
  261 typedef struct _update_gui_thread_t
  262 {
  263   dt_lib_backgroundjob_element_t *instance;
  264   double value;
  265 } _update_gui_thread_t;
  266 
  267 static gboolean _update_gui_thread(gpointer user_data)
  268 {
  269   _update_gui_thread_t *params = (_update_gui_thread_t *)user_data;
  270 
  271   gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(params->instance->progressbar), CLAMP(params->value, 0, 1.0));
  272 
  273   free(params);
  274   return FALSE;
  275 }
  276 
  277 static void _lib_backgroundjobs_updated(dt_lib_module_t *self, dt_lib_backgroundjob_element_t *instance,
  278                                         double value)
  279 {
  280   // update the progress bar
  281   if(!darktable.control->running) return;
  282 
  283   _update_gui_thread_t *params = (_update_gui_thread_t *)malloc(sizeof(_update_gui_thread_t));
  284   if(!params) return;
  285   params->instance = instance;
  286   params->value = value;
  287   g_main_context_invoke(NULL, _update_gui_thread, params);
  288 }
  289 
  290 typedef struct _update_label_gui_thread_t
  291 {
  292   dt_lib_backgroundjob_element_t *instance;
  293   char *message;
  294 } _update_label_gui_thread_t;
  295 
  296 static gboolean _update_message_gui_thread(gpointer user_data)
  297 {
  298   _update_label_gui_thread_t *params = (_update_label_gui_thread_t *)user_data;
  299 
  300   gtk_label_set_text(GTK_LABEL(params->instance->label), params->message);
  301 
  302   g_free(params->message);
  303   free(params);
  304   return FALSE;
  305 }
  306 
  307 static void _lib_backgroundjobs_message_updated(dt_lib_module_t *self, dt_lib_backgroundjob_element_t *instance,
  308                                                 const char *message)
  309 {
  310   // update the progress bar
  311   if(!darktable.control->running) return;
  312 
  313   _update_label_gui_thread_t *params = (_update_label_gui_thread_t *)malloc(sizeof(_update_label_gui_thread_t));
  314   if(!params) return;
  315   params->instance = instance;
  316   params->message = g_strdup(message);
  317   g_main_context_invoke(NULL, _update_message_gui_thread, params);
  318 }
  319 
  320 // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
  321 // vim: shiftwidth=2 expandtab tabstop=2 cindent
  322 // kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;