]> granicus.if.org Git - handbrake/commitdiff
LinGui: Make disk warning limit configurable
authorJohn Stebbins <jstebbins.hb@gmail.com>
Tue, 20 Jun 2017 21:52:19 +0000 (14:52 -0700)
committerJohn Stebbins <jstebbins.hb@gmail.com>
Tue, 20 Jun 2017 21:52:19 +0000 (14:52 -0700)
Allow disabling and setting disk warning limit in preferences.
When enabled checks disk fullness every 10 seconds during encoding.
If disk full condition is detected, pauses the encode and gives
a popup with options "Resume, I've fixed the problem", "Resume, Don't
tell me again", and "Cancel Current and Stop".

gtk/src/callbacks.c
gtk/src/ghb.m4
gtk/src/hb-backend.c
gtk/src/hb-backend.h
gtk/src/internal_defaults.json
gtk/src/queuehandler.c
gtk/src/queuehandler.h

index 469eb2b3bb729b3cf70a6493a27fa25d203f45db..2ee6431f518efb61d4dc4b428e9ec13a7b87df6b 100644 (file)
@@ -2955,39 +2955,6 @@ ghb_cancel_encode2(signal_user_data_t *ud, const gchar *extra_msg)
     return FALSE;
 }
 
-static gint
-find_queue_job(GhbValue *queue, gint unique_id, GhbValue **job)
-{
-    GhbValue *queueDict, *uiDict;
-    gint ii, count;
-    gint job_unique_id;
-
-    g_debug("find_queue_job");
-    if (job != NULL)
-    {
-        *job = NULL;
-    }
-    if (unique_id == 0)  // Invalid Id
-        return -1;
-
-    count = ghb_array_len(queue);
-    for (ii = 0; ii < count; ii++)
-    {
-        queueDict = ghb_array_get(queue, ii);
-        uiDict = ghb_dict_get(queueDict, "uiSettings");
-        job_unique_id = ghb_dict_get_int(uiDict, "job_unique_id");
-        if (job_unique_id == unique_id)
-        {
-            if (job != NULL)
-            {
-                *job = queueDict;
-            }
-            return ii;
-        }
-    }
-    return -1;
-}
-
 static void
 start_new_log(signal_user_data_t *ud, GhbValue *uiDict)
 {
@@ -3061,7 +3028,7 @@ submit_job(signal_user_data_t *ud, GhbValue *queueDict)
     ghb_start_queue();
 
     // Start queue activity spinner
-    int index = find_queue_job(ud->queue, unique_id, NULL);
+    int index = ghb_find_queue_job(ud->queue, unique_id, NULL);
     if (index >= 0)
     {
         GtkTreeView *treeview;
@@ -3207,6 +3174,7 @@ ghb_start_next_job(signal_user_data_t *ud)
     ghb_notify_done(ud);
     ghb_update_pending(ud);
     gtk_widget_hide(progress);
+    ghb_dict_set_bool(ud->globals, "SkipDiskFreeCheck", FALSE);
 }
 
 gchar*
@@ -3217,7 +3185,7 @@ working_status_string(signal_user_data_t *ud, ghb_instance_status_t *status)
     gint index;
 
     qcount = ghb_array_len(ud->queue);
-    index = find_queue_job(ud->queue, status->unique_id, NULL);
+    index = ghb_find_queue_job(ud->queue, status->unique_id, NULL);
     if (qcount > 1)
     {
         job_str = g_strdup_printf(_("job %d of %d, "), index+1, qcount);
@@ -3285,7 +3253,7 @@ searching_status_string(signal_user_data_t *ud, ghb_instance_status_t *status)
     gint index;
 
     qcount = ghb_array_len(ud->queue);
-    index = find_queue_job(ud->queue, status->unique_id, NULL);
+    index = ghb_find_queue_job(ud->queue, status->unique_id, NULL);
     if (qcount > 1)
     {
         job_str = g_strdup_printf(_("job %d of %d, "), index+1, qcount);
@@ -3330,7 +3298,9 @@ ghb_backend_events(signal_user_data_t *ud)
     GtkTreeIter iter;
     static gint prev_scan_state = -1;
     static gint prev_queue_state = -1;
+    static gint event_sequence = 0;
 
+    event_sequence++;
     ghb_track_status();
     ghb_get_status(&status);
     if (prev_scan_state != status.scan.state ||
@@ -3451,7 +3421,7 @@ ghb_backend_events(signal_user_data_t *ud)
 
     if (status.queue.unique_id != 0)
     {
-        index = find_queue_job(ud->queue, status.queue.unique_id, NULL);
+        index = ghb_find_queue_job(ud->queue, status.queue.unique_id, NULL);
         if (index >= 0)
         {
             treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
@@ -3476,6 +3446,11 @@ ghb_backend_events(signal_user_data_t *ud)
                 }
             }
             g_free(path);
+            if ((status.queue.state & GHB_STATE_WORKING) &&
+                (event_sequence % 50 == 0)) // check every 10 seconds
+            {
+                ghb_low_disk_check(ud);
+            }
         }
     }
 
@@ -3517,7 +3492,7 @@ ghb_backend_events(signal_user_data_t *ud)
         gint qstatus;
         const gchar *status_icon;
 
-        index = find_queue_job(ud->queue, status.queue.unique_id, &queueDict);
+        index = ghb_find_queue_job(ud->queue, status.queue.unique_id, &queueDict);
         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
         store = gtk_tree_view_get_model(treeview);
         switch( status.queue.error )
@@ -3572,6 +3547,7 @@ ghb_backend_events(signal_user_data_t *ud)
         {
             ghb_uninhibit_gsm();
             gtk_widget_hide(GTK_WIDGET(progress));
+            ghb_dict_set_bool(ud->globals, "SkipDiskFreeCheck", FALSE);
         }
         ghb_save_queue(ud->queue);
         ud->cancel_encode = GHB_CANCEL_NONE;
index 73577af350c0bcc9bdba310cef7c58a84b3543a9..ed0319cdc6f93bc53315f73db343b891213369f7 100644 (file)
@@ -346,6 +346,11 @@ conjunction with the "Forced" option.</property>
     <property name="step_increment">0.1</property>
     <property name="page_increment">1</property>
   </object>
+  <object class="GtkAdjustment" id="DiskFreeLimitAdjustment">
+    <property name="upper">1000000</property>
+    <property name="step_increment">500</property>
+    <property name="page_increment">1000</property>
+  </object>
   <object class="GtkAboutDialog" id="hb_about">
     <property name="transient_for">hb_window</property>
     <property name="can_focus">False</property>
@@ -7680,6 +7685,84 @@ This file may be reloaded at a later time to edit your jobs and re-encode.</prop
                             <property name="height">1</property>
                           </packing>
                         </child>
+                        <child>
+                          <object class="GtkBox" id="DiskFreeBox">
+                            <property name="orientation">vertical</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="spacing">2</property>
+                            <child>
+                              <object class="GtkCheckButton" id="DiskFreeCheck">
+                                <property name="label" translatable="yes">Monitor destination disk free space</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="tooltip_text" translatable="yes">Pause encoding if free disk space drops below limit</property>
+                                <property name="halign">start</property>
+                                <property name="draw_indicator">True</property>
+                                <signal name="toggled" handler="pref_changed_cb" swapped="no"/>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkBox" id="DiskFreeLimitBox">
+                                <property name="orientation">horizontal</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="spacing">4</property>
+                                <property name="margin-start">21</property>
+                                <child>
+                                  <object class="GtkSpinButton" id="DiskFreeLimit">
+                                    <property name="width-chars">7</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="tooltip_text" translatable="yes">Pause encoding if free disk space drops below limit</property>
+                                    <property name="primary_icon_activatable">False</property>
+                                    <property name="secondary_icon_activatable">False</property>
+                                    <property name="valign">GTK_ALIGN_CENTER</property>
+                                    <property name="adjustment">DiskFreeLimitAdjustment</property>
+                                    <property name="width_request">55</property>
+                                    <signal name="value-changed" handler="pref_changed_cb" swapped="no"/>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="DiskFreeLimitLabel">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="halign">start</property>
+                                    <property name="label" translatable="yes">MB Limit</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="top_attach">2</property>
+                            <property name="left_attach">0</property>
+                            <property name="width">1</property>
+                            <property name="height">1</property>
+                          </packing>
+                        </child>
                         <child>
                           <object class="GtkBox" id="vbox2">
                             <property name="orientation">vertical</property>
@@ -7785,7 +7868,7 @@ This file may be reloaded at a later time to edit your jobs and re-encode.</prop
                             </child>
                           </object>
                           <packing>
-                            <property name="top_attach">2</property>
+                            <property name="top_attach">3</property>
                             <property name="left_attach">0</property>
                             <property name="width">1</property>
                             <property name="height">1</property>
@@ -7802,7 +7885,7 @@ This file may be reloaded at a later time to edit your jobs and re-encode.</prop
                             <signal name="toggled" handler="pref_changed_cb" swapped="no"/>
                           </object>
                           <packing>
-                            <property name="top_attach">3</property>
+                            <property name="top_attach">4</property>
                             <property name="left_attach">0</property>
                             <property name="width">1</property>
                             <property name="height">1</property>
@@ -7820,7 +7903,7 @@ This file may be reloaded at a later time to edit your jobs and re-encode.</prop
                             <signal name="toggled" handler="pref_changed_cb" swapped="no"/>
                           </object>
                           <packing>
-                            <property name="top_attach">4</property>
+                            <property name="top_attach">5</property>
                             <property name="left_attach">0</property>
                             <property name="width">1</property>
                             <property name="height">1</property>
@@ -7840,7 +7923,7 @@ on the Video tab instead.</property>
                             <signal name="toggled" handler="advanced_video_changed_cb" swapped="no"/>
                           </object>
                           <packing>
-                            <property name="top_attach">5</property>
+                            <property name="top_attach">6</property>
                             <property name="left_attach">0</property>
                             <property name="width">1</property>
                             <property name="height">1</property>
@@ -7859,7 +7942,7 @@ Check this if you want the queue to clean itself up by deleting completed jobs.<
                             <signal name="toggled" handler="pref_changed_cb" swapped="no"/>
                           </object>
                           <packing>
-                            <property name="top_attach">6</property>
+                            <property name="top_attach">7</property>
                             <property name="left_attach">0</property>
                             <property name="width">1</property>
                             <property name="height">1</property>
index ab8b8ef89d576a7b50538c7cf50365c81c977ee8..07f3a7248baefe2cc2d43e1a6b70c41af87e914d 100644 (file)
@@ -4274,19 +4274,31 @@ ghb_stop_live_encode()
 
 void
 ghb_pause_queue()
+{
+    hb_status.queue.state |= GHB_STATE_PAUSED;
+    hb_pause( h_queue );
+}
+
+void
+ghb_resume_queue()
+{
+    hb_status.queue.state &= ~GHB_STATE_PAUSED;
+    hb_resume( h_queue );
+}
+
+void
+ghb_pause_resume_queue()
 {
     hb_state_t s;
     hb_get_state2( h_queue, &s );
 
     if( s.state == HB_STATE_PAUSED )
     {
-        hb_status.queue.state &= ~GHB_STATE_PAUSED;
-        hb_resume( h_queue );
+        ghb_resume_queue();
     }
     else
     {
-        hb_status.queue.state |= GHB_STATE_PAUSED;
-        hb_pause( h_queue );
+        ghb_pause_queue();
     }
 }
 
index 47627c71daf8d17a2ef64dafbd8662e6c7f76db6..450989a06143284be98e285f31df502602bf0cbf 100644 (file)
@@ -103,6 +103,8 @@ void ghb_remove_job(gint unique_id);
 void ghb_start_queue(void);
 void ghb_stop_queue(void);
 void ghb_pause_queue(void);
+void ghb_resume_queue(void);
+void ghb_pause_resume_queue(void);
 
 void ghb_start_live_encode();
 void ghb_stop_live_encode();
index f0ba22badc86731b38ecf1de18152b95583ea17c..7d70db5fac22b2de71f209a4b2d2996a714787a5 100644 (file)
@@ -1,5 +1,6 @@
 {
     "Globals": {
+        "SkipDiskFreeCheck": false,
         "show_preview": false,
         "scan_source": "",
         "volume_label": "New Video"
@@ -68,6 +69,8 @@
         "x264FastDecode": false
     },
     "Preferences": {
+        "DiskFreeCheck": true,
+        "DiskFreeLimit": 10000,
         "RemoveFinishedJobs": false,
         "HideAdvancedVideoSettings": true,
         "AutoScan": false,
index 6d8718c83a49f134c89ea74b68c3d90685bf3658..a708598fa6c1f7d4807fb0d5c9f1ddd39fe5d98f 100644 (file)
@@ -984,6 +984,154 @@ queue_reload_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
     }
 }
 
+gint64
+ghb_dest_free_space(GhbValue *settings)
+{
+    GFile       *gfile;
+    GFileInfo   *info;
+    guint64      size;
+    const gchar *dest     = ghb_dict_get_string(settings, "destination");
+    gchar       *destdir  = g_path_get_dirname(dest);
+    gchar       *resolved = ghb_resolve_symlink(destdir);
+
+    gfile = g_file_new_for_path(resolved);
+    info  = g_file_query_filesystem_info(gfile,
+                                G_FILE_ATTRIBUTE_FILESYSTEM_FREE, NULL, NULL);
+    if (info != NULL)
+    {
+        if (g_file_info_has_attribute(info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE))
+        {
+            size = g_file_info_get_attribute_uint64(info,
+                                    G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
+            return size;
+        }
+        g_object_unref(info);
+    }
+    g_object_unref(gfile);
+    g_free(resolved);
+    g_free(destdir);
+
+    return -1;
+}
+
+gint
+ghb_find_queue_job(GhbValue *queue, gint unique_id, GhbValue **job)
+{
+    GhbValue *queueDict, *uiDict;
+    gint ii, count;
+    gint job_unique_id;
+
+    if (job != NULL)
+    {
+        *job = NULL;
+    }
+    if (unique_id == 0)  // Invalid Id
+        return -1;
+
+    count = ghb_array_len(queue);
+    for (ii = 0; ii < count; ii++)
+    {
+        queueDict = ghb_array_get(queue, ii);
+        uiDict = ghb_dict_get(queueDict, "uiSettings");
+        job_unique_id = ghb_dict_get_int(uiDict, "job_unique_id");
+        if (job_unique_id == unique_id)
+        {
+            if (job != NULL)
+            {
+                *job = queueDict;
+            }
+            return ii;
+        }
+    }
+    return -1;
+}
+
+void
+ghb_low_disk_check(signal_user_data_t *ud)
+{
+    GtkWindow       *hb_window;
+    GtkWidget       *dialog;
+    GtkResponseType  response;
+    ghb_status_t     status;
+    const char      *paused_msg = "";
+    const char      *dest;
+    gint64           free_size;
+    gint64           free_limit;
+    GhbValue        *qDict;
+    GhbValue        *settings;
+
+    if (ghb_dict_get_bool(ud->globals, "SkipDiskFreeCheck") ||
+        !ghb_dict_get_bool(ud->prefs, "DiskFreeCheck"))
+    {
+        return;
+    }
+
+    ghb_get_status(&status);
+    if (status.queue.unique_id <= 0)
+    {
+        // No current job
+        return;
+    }
+    ghb_find_queue_job(ud->queue, status.queue.unique_id, &qDict);
+    if (qDict == NULL)
+    {
+        // Failed to find queue setting!
+        return;
+    }
+    settings = ghb_dict_get(qDict, "uiSettings");
+    free_size = ghb_dest_free_space(settings);
+    if (free_size < 0)
+    {
+        // Failed to read free space
+        return;
+    }
+    // limit is in MB
+    free_limit = ghb_dict_get_int(ud->prefs, "DiskFreeLimit") * 1024 * 1024;
+    if (free_size > free_limit)
+    {
+        return;
+    }
+
+    if ((status.queue.state & GHB_STATE_WORKING) &&
+        !(status.queue.state & GHB_STATE_PAUSED))
+    {
+        paused_msg = "Encoding has been paused.\n\n";
+        ghb_pause_queue();
+    }
+    dest      = ghb_dict_get_string(settings, "destination");
+    hb_window = GTK_WINDOW(GHB_WIDGET(ud->builder, "hb_window"));
+    dialog    = gtk_message_dialog_new(hb_window, GTK_DIALOG_MODAL,
+            GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE,
+            _("%sThe destination filesystem is almost full: %"PRIu64"MB free.\n"
+              "Destination: %s\n"
+              "Encode may be incomplete if you proceed.\n"),
+            paused_msg, free_size / (1024 * 1024), dest); 
+    gtk_dialog_add_buttons( GTK_DIALOG(dialog),
+                           _("Resume, I've fixed the problem"), 1,
+                           _("Resume, Don't tell me again"), 2,
+                           _("Cancel Current and Stop"), 3, 
+                           NULL);
+    response = gtk_dialog_run(GTK_DIALOG(dialog));
+    gtk_widget_destroy(dialog);
+    switch ((int)response)
+    {
+        case 1:
+            ghb_resume_queue();
+            break;
+        case 2:
+            ghb_dict_set_bool(ud->globals, "SkipDiskFreeCheck", TRUE);
+            ghb_resume_queue();
+            break;
+        case 3:
+            ghb_stop_queue();
+            ud->cancel_encode = GHB_CANCEL_ALL;
+            break;
+        default:
+            ghb_resume_queue();
+            break;
+    }
+}
+
 static gboolean
 validate_settings(signal_user_data_t *ud, GhbValue *settings, gint batch)
 {
@@ -1056,45 +1204,6 @@ validate_settings(signal_user_data_t *ud, GhbValue *settings, gint batch)
         return FALSE;
     }
 #endif
-    if (!batch)
-    {
-        GFile *gfile;
-        GFileInfo *info;
-        guint64 size;
-        gchar *resolved = ghb_resolve_symlink(destdir);
-
-        gfile = g_file_new_for_path(resolved);
-        info = g_file_query_filesystem_info(gfile,
-                            G_FILE_ATTRIBUTE_FILESYSTEM_FREE, NULL, NULL);
-        if (info != NULL)
-        {
-            if (g_file_info_has_attribute(info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE))
-            {
-                size = g_file_info_get_attribute_uint64(info,
-                                        G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
-
-                gint64 fsize = (guint64)10 * 1024 * 1024 * 1024;
-                if (size < fsize)
-                {
-                    message = g_strdup_printf(
-                                _("Destination filesystem is almost full: %uM free\n\n"
-                                "Encode may be incomplete if you proceed.\n"),
-                                (guint)(size / (1024L*1024L)));
-                    if (!ghb_message_dialog(hb_window, GTK_MESSAGE_QUESTION,
-                                            message, _("Cancel"), _("Proceed")))
-                    {
-                        g_free(message);
-                        g_free(destdir);
-                        return FALSE;
-                    }
-                    g_free(message);
-                }
-            }
-            g_object_unref(info);
-        }
-        g_object_unref(gfile);
-        g_free(resolved);
-    }
     g_free(destdir);
     if (g_file_test(dest, G_FILE_TEST_EXISTS))
     {
@@ -2277,7 +2386,7 @@ queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 G_MODULE_EXPORT void
 queue_pause_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
 {
-    ghb_pause_queue();
+    ghb_pause_resume_queue();
 }
 
 gboolean
index 50f6cc250e40ce7078c964b1016e285747625fd4..34b052d0fea7279e901f9744e44971af52ac087d 100644 (file)
@@ -32,5 +32,7 @@ void ghb_queue_buttons_grey(signal_user_data_t *ud);
 gboolean ghb_reload_queue(signal_user_data_t *ud);
 void ghb_queue_remove_row(signal_user_data_t *ud, int row);
 void ghb_finalize_job(GhbValue *settings);
+gint ghb_find_queue_job(GhbValue *queue, gint unique_id, GhbValue **job);
+void ghb_low_disk_check(signal_user_data_t *ud);
 
 #endif // _QUEUEHANDLER_H_