summaryrefslogtreecommitdiffstats
path: root/gtk
diff options
context:
space:
mode:
authorjstebbins <[email protected]>2008-09-06 16:48:54 +0000
committerjstebbins <[email protected]>2008-09-06 16:48:54 +0000
commit88b4851b757a6276f4b717127a5463005b6a868f (patch)
treec52e671d57ec6b3a40e5f7b2ede8e800ca33e795 /gtk
parent6d9a7854ec8143ac4b45b66eb2a32e357ba6cacb (diff)
LinGui: Add queue save/restore
- 2 instances of libhb are used. One for queue activities and one for scanning new sources prior to adding to the queue. - Improve chapter entry usability. In addition to "return" advancing to the next chapter for editing, up and down arrows will advance to prev/next and put the cell in edit mode. - Add an accelerator key to jump to the destination entry box. - Fix a queue window resize problem. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@1668 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'gtk')
-rw-r--r--gtk/src/Makefile.am18
-rw-r--r--gtk/src/callbacks.c421
-rw-r--r--gtk/src/callbacks.h1
-rw-r--r--gtk/src/ghb.ui7
-rw-r--r--gtk/src/ghbcellrenderertext.c1972
-rw-r--r--gtk/src/ghbcellrenderertext.h105
-rw-r--r--gtk/src/hb-backend.c387
-rw-r--r--gtk/src/hb-backend.h5
-rw-r--r--gtk/src/main.c13
-rw-r--r--gtk/src/marshalers.c125
-rw-r--r--gtk/src/marshalers.h28
-rw-r--r--gtk/src/plist.c8
-rw-r--r--gtk/src/plist.h2
-rw-r--r--gtk/src/presets.c90
-rw-r--r--gtk/src/presets.h3
-rw-r--r--gtk/src/settings.c13
-rw-r--r--gtk/src/settings.h3
17 files changed, 2946 insertions, 255 deletions
diff --git a/gtk/src/Makefile.am b/gtk/src/Makefile.am
index 02eca572d..2de9f748d 100644
--- a/gtk/src/Makefile.am
+++ b/gtk/src/Makefile.am
@@ -98,8 +98,12 @@ ghb_SOURCES = \
hb-backend.h \
renderer_button.h \
renderer_button.c \
+ ghbcellrenderertext.c \
+ ghbcellrenderertext.h \
ghb-dvd.c \
- ghb-dvd.h
+ ghb-dvd.h \
+ marshalers.c \
+ marshalers.h
ghb_LDFLAGS = \
-Wl,--export-dynamic
@@ -119,6 +123,8 @@ makewidgetdeps_LDADD = $(GHBTOOLS_LIBS)
quotestring_SOURCES = preset_to_string.c
+callbacks.c: widget_deps.h widget_reverse_deps.h
+
widget_deps.h: makewidgetdeps quotestring
./makewidgetdeps
./quotestring widget_deps widget_deps.h
@@ -127,12 +133,22 @@ widget_reverse_deps.h: makewidgetdeps quotestring
./makewidgetdeps
./quotestring widget_reverse_deps widget_reverse_deps.h
+presets.c: internal_defaults.h standard_presets.h
+
internal_defaults.h: quotestring internal_defaults.xml
./quotestring internal_defaults.xml internal_defaults.h
standard_presets.h: quotestring standard_presets.xml
./quotestring standard_presets.xml standard_presets.h
+ghbcellrenderertext.c: marshalers.h
+
+marshalers.h: marshalers.list
+ glib-genmarshal --prefix=ghb_marshal marshalers.list --header > marshalers.h
+
+marshalers.c: marshalers.list
+ glib-genmarshal --prefix=ghb_marshal marshalers.list --body > marshalers.c
+
EXTRA_DIST = $(builder_DATA) $(icons) HandBrakeCLI
uninstall-local:
diff --git a/gtk/src/callbacks.c b/gtk/src/callbacks.c
index a0517616b..bd07e34b2 100644
--- a/gtk/src/callbacks.c
+++ b/gtk/src/callbacks.c
@@ -21,6 +21,7 @@
#include <sys/stat.h>
#include <libhal-storage.h>
#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
#include <glib/gstdio.h>
#include <gio/gio.h>
@@ -31,6 +32,7 @@
#include "plist.h"
#include "hb-backend.h"
#include "ghb-dvd.h"
+#include "ghbcellrenderertext.h"
static void update_chapter_list(signal_user_data_t *ud);
static void clear_audio_list(signal_user_data_t *ud);
@@ -261,7 +263,7 @@ expand_tilde(const gchar *path)
void
on_quit1_activate(GtkMenuItem *quit, signal_user_data_t *ud)
{
- gint state = ghb_get_state();
+ gint state = ghb_get_queue_state();
g_debug("on_quit1_activate ()");
if (state & GHB_STATE_WORKING)
{
@@ -685,6 +687,43 @@ update_destination_extension(signal_user_data_t *ud)
g_free(filename);
}
+static void
+destination_select_title(GtkEntry *entry)
+{
+ const gchar *dest;
+ gint start, end;
+
+ dest = gtk_entry_get_text(entry);
+ for (end = strlen(dest)-1; end > 0; end--)
+ {
+ if (dest[end] == '.')
+ {
+ break;
+ }
+ }
+ for (start = end; start >= 0; start--)
+ {
+ if (dest[start] == '/')
+ {
+ start++;
+ break;
+ }
+ }
+ if (start < end)
+ {
+ gtk_editable_select_region(GTK_EDITABLE(entry), start, end);
+ }
+}
+
+gboolean
+destination_grab_cb(
+ GtkEntry *entry,
+ signal_user_data_t *ud)
+{
+ destination_select_title(entry);
+ return FALSE;
+}
+
static gboolean update_default_destination = FALSE;
void
@@ -757,7 +796,7 @@ window_destroy_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *
gboolean
window_delete_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *ud)
{
- gint state = ghb_get_state();
+ gint state = ghb_get_queue_state();
g_debug("window_delete_event_cb ()");
if (state & GHB_STATE_WORKING)
{
@@ -2674,7 +2713,6 @@ static gboolean
queue_add(signal_user_data_t *ud)
{
// Add settings to the queue
- static gint unique_id = 0;
GValue *settings;
g_debug("queue_add ()");
@@ -2686,14 +2724,12 @@ queue_add(signal_user_data_t *ud)
ud->queue = ghb_array_value_new(32);
// Make a copy of current settings to be used for the new job
settings = ghb_value_dup(ud->settings);
- ghb_settings_set_int(settings, "job_unique_id", unique_id);
ghb_settings_set_int(settings, "job_status", GHB_QUEUE_PENDING);
-
+ ghb_settings_set_int(settings, "job_unique_id", 0);
ghb_array_append(ud->queue, settings);
add_to_queue_list(ud, settings);
- ghb_add_job (settings, unique_id);
+ ghb_save_queue(ud->queue);
- unique_id++;
return TRUE;
}
@@ -2763,13 +2799,13 @@ queue_remove_clicked_cb(GtkWidget *widget, gchar *path, signal_user_data_t *ud)
{
return;
}
+ unique_id = ghb_settings_get_int(settings, "job_unique_id");
+ ghb_remove_job(unique_id);
}
// Remove the selected item
gtk_tree_store_remove(GTK_TREE_STORE(store), &iter);
// Remove the corresponding item from the queue list
- unique_id = ghb_settings_get_int(settings, "job_unique_id");
ghb_array_remove(ud->queue, row);
- ghb_remove_job(unique_id);
}
else
{
@@ -2785,6 +2821,7 @@ find_queue_job(GValue *queue, gint unique_id, GValue **job)
gint job_unique_id;
*job = NULL;
+ g_debug("find_queue_job");
count = ghb_array_len(queue);
for (ii = 0; ii < count; ii++)
{
@@ -2804,14 +2841,20 @@ queue_buttons_grey(signal_user_data_t *ud, gboolean working)
{
GtkWidget *widget;
GtkAction *action;
- gint titleindex = ghb_settings_get_int(ud->settings, "title");
- gboolean title_ok = (titleindex >= 0);
+ gint queue_count;
+ gint titleindex;
+ gboolean title_ok;
+
+ queue_count = ghb_array_len(ud->queue);
+ titleindex = ghb_settings_get_int(ud->settings, "title");
+ title_ok = (titleindex >= 0);
+
widget = GHB_WIDGET (ud->builder, "queue_start1");
- gtk_widget_set_sensitive (widget, !working && title_ok);
+ gtk_widget_set_sensitive (widget, !working && (title_ok || queue_count));
widget = GHB_WIDGET (ud->builder, "queue_start2");
- gtk_widget_set_sensitive (widget, !working && title_ok);
+ gtk_widget_set_sensitive (widget, !working && (title_ok || queue_count));
action = GHB_ACTION (ud->builder, "queue_start_menu");
- gtk_action_set_sensitive (action, !working && title_ok);
+ gtk_action_set_sensitive (action, !working && (title_ok || queue_count));
widget = GHB_WIDGET (ud->builder, "queue_pause1");
gtk_widget_set_sensitive (widget, working);
widget = GHB_WIDGET (ud->builder, "queue_pause2");
@@ -2827,6 +2870,97 @@ queue_buttons_grey(signal_user_data_t *ud, gboolean working)
void queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud);
static void
+submit_job(GValue *settings)
+{
+ static gint unique_id = 1;
+
+ g_debug("submit_job");
+ if (settings == NULL) return;
+ ghb_settings_set_int(settings, "job_unique_id", unique_id);
+ ghb_settings_set_int(settings, "job_status", GHB_QUEUE_RUNNING);
+ ghb_add_job (settings, unique_id);
+ ghb_start_queue();
+ unique_id++;
+}
+
+static void
+queue_scan(GValue *js)
+{
+ gchar *path;
+ gint titleindex;
+
+ path = ghb_settings_get_string( js, "source");
+ titleindex = ghb_settings_get_int(js, "title");
+ ghb_backend_queue_scan(path, titleindex+1);
+ g_free(path);
+}
+
+static GValue*
+start_next_job(signal_user_data_t *ud, gboolean find_first)
+{
+ static gint current = 0;
+ gint count, ii, jj;
+ GValue *js;
+ gint status;
+
+ g_debug("start_next_job");
+ count = ghb_array_len(ud->queue);
+ if (find_first)
+ { // Start the first pending item in the queue
+ current = 0;
+ for (ii = 0; ii < count; ii++)
+ {
+
+ js = ghb_array_get_nth(ud->queue, ii);
+ status = ghb_settings_get_int(js, "job_status");
+ if (status == GHB_QUEUE_PENDING)
+ {
+ current = ii;
+ queue_scan(js);
+ return js;
+ }
+ }
+ // Nothing pending
+ return NULL;
+ }
+ // Find the next pending item after the current running item
+ for (ii = 0; ii < count-1; ii++)
+ {
+ js = ghb_array_get_nth(ud->queue, ii);
+ status = ghb_settings_get_int(js, "job_status");
+ if (status == GHB_QUEUE_RUNNING)
+ {
+ for (jj = ii+1; jj < count; jj++)
+ {
+ js = ghb_array_get_nth(ud->queue, jj);
+ status = ghb_settings_get_int(js, "job_status");
+ if (status == GHB_QUEUE_PENDING)
+ {
+ current = jj;
+ queue_scan(js);
+ return js;
+ }
+ }
+ }
+ }
+ // No running item found? Maybe it was deleted
+ // Look for a pending item starting from the last index we started
+ for (ii = current; ii < count; ii++)
+ {
+ js = ghb_array_get_nth(ud->queue, ii);
+ status = ghb_settings_get_int(js, "job_status");
+ if (status == GHB_QUEUE_PENDING)
+ {
+ current = ii;
+ queue_scan(js);
+ return js;
+ }
+ }
+ // Nothing found
+ return NULL;
+}
+
+static void
ghb_backend_events(signal_user_data_t *ud)
{
ghb_status_t status;
@@ -2834,7 +2968,6 @@ ghb_backend_events(signal_user_data_t *ud)
GtkProgressBar *progress;
gint titleindex;
GValue *js;
- static gint current_id = -1;
gint index;
GtkTreeView *treeview;
GtkTreeStore *store;
@@ -2845,6 +2978,8 @@ ghb_backend_events(signal_user_data_t *ud)
ghb_track_status();
ghb_get_status(&status);
progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
+ // First handle the status of title scans
+ // Then handle the status of the queue
if (status.state & GHB_STATE_SCANNING)
{
status_str = g_strdup_printf ("Scanning title %d of %d...",
@@ -2879,22 +3014,56 @@ ghb_backend_events(signal_user_data_t *ud)
gtk_progress_bar_set_text (progress, "No Source");
}
ghb_clear_state(GHB_STATE_SCANDONE);
- queue_buttons_grey(ud, (0 != (status.state & GHB_STATE_WORKING)));
+ queue_buttons_grey(ud, (0 != (status.queue_state & GHB_STATE_WORKING)));
+ }
+ else if (status.queue_state & GHB_STATE_SCANNING)
+ {
+ status_str = g_strdup_printf ("Scanning ...");
+ gtk_progress_bar_set_text (progress, status_str);
+ g_free(status_str);
+ gtk_progress_bar_set_fraction (progress, 0);
}
- else if (status.state & GHB_STATE_PAUSED)
+ else if (status.queue_state & GHB_STATE_SCANDONE)
+ {
+ ghb_clear_queue_state(GHB_STATE_SCANDONE);
+ submit_job(ud->current_job);
+ }
+ else if (status.queue_state & GHB_STATE_PAUSED)
{
status_str = g_strdup_printf ("Paused");
gtk_progress_bar_set_text (progress, status_str);
g_free(status_str);
}
- else if (status.state & GHB_STATE_WORKING)
+ else if (status.queue_state & GHB_STATE_WORKING)
{
+ gchar *task_str, *job_str;
+ gint qcount;
+
+ if (status.job_count > 1)
+ {
+ task_str = g_strdup_printf("pass %d of %d, ",
+ status.job_cur, status.job_count);
+ }
+ else
+ {
+ task_str = g_strdup("");
+ }
+ qcount = ghb_array_len(ud->queue);
+ if (qcount > 1)
+ {
+ index = find_queue_job(ud->queue, status.unique_id, &js);
+ job_str = g_strdup_printf("job %d of %d, ", index+1, qcount);
+ }
+ else
+ {
+ job_str = g_strdup("");
+ }
if(status.seconds > -1)
{
status_str= g_strdup_printf(
- "Encoding: task %d of %d, %.2f %%"
+ "Encoding: %s%s%.2f %%"
" (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)",
- status.job_cur, status.job_count,
+ job_str, task_str,
100.0 * status.progress,
status.rate_cur, status.rate_avg, status.hours,
status.minutes, status.seconds );
@@ -2902,28 +3071,34 @@ ghb_backend_events(signal_user_data_t *ud)
else
{
status_str= g_strdup_printf(
- "Encoding: task %d of %d, %.2f %%",
- status.job_cur, status.job_count,
+ "Encoding: %s%s%.2f %%",
+ job_str, task_str,
100.0 * status.progress );
}
+ g_free(job_str);
+ g_free(task_str);
gtk_progress_bar_set_text (progress, status_str);
gtk_progress_bar_set_fraction (progress, status.progress);
g_free(status_str);
}
- else if (status.state & GHB_STATE_WORKDONE)
+ else if (status.queue_state & GHB_STATE_WORKDONE)
{
+ gint qstatus;
+
work_started = FALSE;
queue_buttons_grey(ud, FALSE);
- index = find_queue_job(ud->queue, current_id, &js);
+ index = find_queue_job(ud->queue, status.unique_id, &js);
treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
+ if (ud->cancel_encode)
+ status.error = GHB_ERROR_CANCELED;
switch( status.error )
{
case GHB_ERROR_NONE:
gtk_progress_bar_set_text( progress, "Rip done!" );
+ qstatus = GHB_QUEUE_DONE;
if (js != NULL)
{
- ghb_settings_set_int(js, "job_status", GHB_QUEUE_DONE);
gchar *path = g_strdup_printf ("%d", index);
if (gtk_tree_model_get_iter_from_string(
GTK_TREE_MODEL(store), &iter, path))
@@ -2935,9 +3110,9 @@ ghb_backend_events(signal_user_data_t *ud)
break;
case GHB_ERROR_CANCELED:
gtk_progress_bar_set_text( progress, "Rip canceled." );
+ qstatus = GHB_QUEUE_CANCELED;
if (js != NULL)
{
- ghb_settings_set_int(js, "job_status", GHB_QUEUE_CANCELED);
gchar *path = g_strdup_printf ("%d", index);
if (gtk_tree_model_get_iter_from_string(
GTK_TREE_MODEL(store), &iter, path))
@@ -2949,9 +3124,9 @@ ghb_backend_events(signal_user_data_t *ud)
break;
default:
gtk_progress_bar_set_text( progress, "Rip failed.");
+ qstatus = GHB_QUEUE_CANCELED;
if (js != NULL)
{
- ghb_settings_set_int(js, "job_status", GHB_QUEUE_CANCELED);
gchar *path = g_strdup_printf ("%d", index);
if (gtk_tree_model_get_iter_from_string(
GTK_TREE_MODEL(store), &iter, path))
@@ -2961,49 +3136,29 @@ ghb_backend_events(signal_user_data_t *ud)
g_free(path);
}
}
- current_id = -1;
gtk_progress_bar_set_fraction (progress, 1.0);
- ghb_clear_state(GHB_STATE_WORKDONE);
+ ghb_clear_queue_state(GHB_STATE_WORKDONE);
+ if (!ud->cancel_encode)
+ ud->current_job = start_next_job(ud, FALSE);
+ else
+ ud->current_job = NULL;
+ if (js)
+ ghb_settings_set_int(js, "job_status", qstatus);
+ ghb_save_queue(ud->queue);
+ ud->cancel_encode = FALSE;
}
- else if (status.state & GHB_STATE_MUXING)
+ else if (status.queue_state & GHB_STATE_MUXING)
{
gtk_progress_bar_set_text(progress, "Muxing: this may take awhile...");
}
- if (status.state & GHB_STATE_WORKING)
+ if (status.queue_state & GHB_STATE_WORKING)
{
if (!work_started)
{
work_started = TRUE;
queue_buttons_grey(ud, TRUE);
}
- if (status.unique_id != current_id)
- {
- index = find_queue_job(ud->queue, current_id, &js);
- if (js != NULL)
- {
- ghb_settings_set_int(js, "job_status", GHB_QUEUE_DONE);
- treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "queue_list"));
- store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
- gchar *path = g_strdup_printf ("%d", index);
- if (gtk_tree_model_get_iter_from_string(
- GTK_TREE_MODEL(store), &iter, path))
- {
- gtk_tree_store_set(store, &iter, 0, "hb-complete", -1);
- }
- g_free(path);
- }
-
- index = find_queue_job(ud->queue, status.unique_id, &js);
- if (js != NULL)
- {
- ghb_settings_set_int(js, "job_status", GHB_QUEUE_RUNNING);
- current_id = status.unique_id;
- }
- }
- else
- {
- index = find_queue_job(ud->queue, status.unique_id, &js);
- }
+ index = find_queue_job(ud->queue, status.unique_id, &js);
if (index >= 0)
{
gchar working_icon[] = "hb-working0";
@@ -3293,38 +3448,32 @@ update_chapter_list(signal_user_data_t *ud)
}
}
-static GtkTreePath *nextPath = NULL;
-static gboolean chapter_selection_changed = FALSE;
+static gint chapter_edit_key = 0;
-static gboolean
-next_cell(signal_user_data_t *ud)
+gboolean
+chapter_keypress_cb(
+ GhbCellRendererText *cell,
+ GdkEventKey *event,
+ signal_user_data_t *ud)
{
- GtkTreeView *treeview;
- GtkTreeViewColumn *column;
-
- if (nextPath)
- {
- if (!chapter_selection_changed)
- {
- treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
- column = gtk_tree_view_get_column(treeview, 1);
- gtk_tree_view_set_cursor(treeview, nextPath, column, TRUE);
- }
- gtk_tree_path_free(nextPath);
- nextPath = NULL;
- }
- chapter_selection_changed = FALSE;
+ chapter_edit_key = event->keyval;
return FALSE;
}
void
-chapter_edited_cb(GtkCellRendererText *cell, gchar *path, gchar *text, signal_user_data_t *ud)
+chapter_edited_cb(
+ GhbCellRendererText *cell,
+ gchar *path,
+ gchar *text,
+ signal_user_data_t *ud)
{
GtkTreePath *treepath;
GtkListStore *store;
GtkTreeView *treeview;
GtkTreeIter iter;
gint index;
+ gint *pi;
+ gint row;
g_debug("chapter_edited_cb ()");
g_debug("path (%s)", path);
@@ -3332,8 +3481,9 @@ chapter_edited_cb(GtkCellRendererText *cell, gchar *path, gchar *text, signal_us
treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list"));
store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview));
treepath = gtk_tree_path_new_from_string (path);
+ pi = gtk_tree_path_get_indices(treepath);
+ row = pi[0];
gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, treepath);
- gtk_tree_path_free (treepath);
gtk_list_store_set(store, &iter,
1, text,
2, TRUE,
@@ -3346,29 +3496,54 @@ chapter_edited_cb(GtkCellRendererText *cell, gchar *path, gchar *text, signal_us
chapters = ghb_settings_get_value(ud->settings, "chapter_list");
chapter = ghb_array_get_nth(chapters, index-1);
g_value_set_string(chapter, text);
- if (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter))
+ if ((chapter_edit_key == GDK_Return || chapter_edit_key == GDK_Down) &&
+ gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter))
{
- nextPath = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
- chapter_selection_changed = FALSE;
+ GtkTreeViewColumn *column;
+
+ gtk_tree_path_next(treepath);
// When a cell has been edited, I want to advance to the
// next cell and start editing it automaitcally.
// Unfortunately, we may not be in a state here where
// editing is allowed. This happens when the user selects
// a new cell with the mouse instead of just hitting enter.
// Some kind of Gtk quirk. widget_editable==NULL assertion.
- // Editing is enabled again once the current event has been
+ // Editing is enabled again once the selection event has been
// processed. So I'm queueing up a callback to be called
// when things go idle. There, I will advance to the next
// cell and initiate editing.
- g_idle_add((GSourceFunc)next_cell, ud);
+ //
+ // Now, you might be asking why I don't catch the keypress
+ // event and determine what action to take based on that.
+ // The Gtk developers in their infinite wisdom have made the
+ // actual GtkEdit widget being used a private member of
+ // GtkCellRendererText, so it can not be accessed to hang a
+ // signal handler off of. And they also do not propagate the
+ // keypress signals in any other way. So that information is lost.
+ //g_idle_add((GSourceFunc)next_cell, ud);
+ //
+ // Keeping the above comment for posterity.
+ // I got industrious and made my own CellTextRendererText that
+ // passes on the key-press-event. So now I have much better
+ // control of this.
+ column = gtk_tree_view_get_column(treeview, 1);
+ gtk_tree_view_set_cursor(treeview, treepath, column, TRUE);
+ }
+ else if (chapter_edit_key == GDK_Up && row > 0)
+ {
+ GtkTreeViewColumn *column;
+ gtk_tree_path_prev(treepath);
+ column = gtk_tree_view_get_column(treeview, 1);
+ gtk_tree_view_set_cursor(treeview, treepath, column, TRUE);
}
+ gtk_tree_path_free (treepath);
}
void
chapter_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
{
g_debug("chapter_list_selection_changed_cb ()");
- chapter_selection_changed = TRUE;
+ //chapter_selection_changed = TRUE;
}
void
@@ -3427,6 +3602,7 @@ queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
gboolean running = FALSE;
gint count, ii;
gint status;
+ gint state;
count = ghb_array_len(ud->queue);
for (ii = 0; ii < count; ii++)
@@ -3447,12 +3623,18 @@ queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
if (!queue_add(ud))
return;
}
- ghb_start_queue();
+ state = ghb_get_queue_state();
+ if (state == GHB_STATE_IDLE)
+ {
+ // Add the first pending queue item and start
+ ud->current_job = start_next_job(ud, TRUE);
+ }
}
void
queue_stop_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
{
+ ud->cancel_encode = TRUE;
cancel_encode(NULL);
}
@@ -3880,3 +4062,68 @@ easter_egg_cb(
return FALSE;
}
+gboolean
+ghb_reload_queue(signal_user_data_t *ud)
+{
+ GValue *queue;
+ gint unfinished = 0;
+ gint count, ii;
+ gint status;
+ GValue *settings;
+ gchar *message;
+
+ g_debug("ghb_reload_queue");
+ queue = ghb_load_queue();
+ // Look for unfinished entries
+ count = ghb_array_len(queue);
+ for (ii = 0; ii < count; ii++)
+ {
+ settings = ghb_array_get_nth(queue, ii);
+ status = ghb_settings_get_int(settings, "job_status");
+ if (status != GHB_QUEUE_DONE && status != GHB_QUEUE_CANCELED)
+ {
+ unfinished++;
+ }
+ }
+ if (unfinished)
+ {
+ message = g_strdup_printf(
+ "You have %d unfinished jobs in a saved queue.\n\n"
+ "Would you like to reload them?",
+ unfinished);
+ if (ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "No", "Yes"))
+ {
+ GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_window");
+ gtk_widget_show (widget);
+
+ ud->queue = queue;
+ // First get rid of any old items we don't want
+ for (ii = count-1; ii >= 0; ii--)
+ {
+ settings = ghb_array_get_nth(queue, ii);
+ status = ghb_settings_get_int(settings, "job_status");
+ if (status == GHB_QUEUE_DONE || status == GHB_QUEUE_CANCELED)
+ {
+ ghb_array_remove(queue, ii);
+ }
+ }
+ count = ghb_array_len(queue);
+ for (ii = 0; ii < count; ii++)
+ {
+ settings = ghb_array_get_nth(queue, ii);
+ ghb_settings_set_int(settings, "job_unique_id", 0);
+ ghb_settings_set_int(settings, "job_status", GHB_QUEUE_PENDING);
+ add_to_queue_list(ud, settings);
+ }
+ queue_buttons_grey(ud, FALSE);
+ }
+ else
+ {
+ ghb_value_free(queue);
+ ghb_remove_queue_file();
+ }
+ g_free(message);
+ }
+ return FALSE;
+}
+
diff --git a/gtk/src/callbacks.h b/gtk/src/callbacks.h
index 652c6ae53..6bb8d3aea 100644
--- a/gtk/src/callbacks.h
+++ b/gtk/src/callbacks.h
@@ -42,6 +42,7 @@ gboolean ghb_message_dialog(
GtkMessageType type, const gchar *message,
const gchar *no, const gchar *yes);
void ghb_init_dep_map();
+gboolean ghb_reload_queue(signal_user_data_t *ud);
#endif // _CALLBACKS_H_
diff --git a/gtk/src/ghb.ui b/gtk/src/ghb.ui
index 9377dc085..8f24a88a0 100644
--- a/gtk/src/ghb.ui
+++ b/gtk/src/ghb.ui
@@ -715,6 +715,8 @@
<property name="tooltip-text" translatable="yes">Destination path with file name for output.</property>
<property name="width_chars">41</property>
<signal handler="destination_entry_changed_cb" name="changed"/>
+ <signal handler="destination_grab_cb" name="grab-focus" after="yes"/>
+ <accelerator key="d" signal="grab-focus" modifiers="GDK_MOD1_MASK"/>
</object>
<packing>
<property name="position">1</property>
@@ -858,7 +860,7 @@
<child type="label">
<object class="GtkLabel" id="label11">
<property name="visible">True</property>
- <property name="label" translatable="yes">&lt;b&gt;Destination&lt;/b&gt;</property>
+ <property name="label" translatable="yes">&lt;b&gt;&lt;u&gt;D&lt;/u&gt;estination&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
@@ -3130,6 +3132,7 @@ no-fast-pskip=0:no-dct-decimate=0:cabac=1</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="headers_clickable">True</property>
<property name="rules_hint">True</property>
+ <property name="enable-search">False</property>
</object>
</child>
</object>
@@ -3891,6 +3894,7 @@ this setting.</property>
</object>
<packing>
<property name="position">1</property>
+ <property name="expand">False</property>
</packing>
</child>
<child>
@@ -3914,6 +3918,7 @@ this setting.</property>
</object>
<packing>
<property name="position">2</property>
+ <property name="expand">True</property>
</packing>
</child>
<child>
diff --git a/gtk/src/ghbcellrenderertext.c b/gtk/src/ghbcellrenderertext.c
new file mode 100644
index 000000000..849cdd242
--- /dev/null
+++ b/gtk/src/ghbcellrenderertext.c
@@ -0,0 +1,1972 @@
+/* gtkcellrenderertext.c
+ * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n-lib.h>
+#include <gtk/gtkmarshal.h>
+//#include <gtk/gtkeditable.h>
+//#include <gtk/gtkentry.h>
+//#include <gtk/gtkintl.h>
+//#include <gtk/gtkprivate.h>
+//#include <gtk/gtktreeprivate.h>
+//#include <gtk/gtkalias.h>
+
+#include "marshalers.h"
+#include "ghbcellrenderertext.h"
+
+#ifdef ENABLE_NLS
+#define P_(String) dgettext(GETTEXT_PACKAGE "-properties",String)
+#else
+#define P_(String) (String)
+#endif
+
+#define I_(string) g_intern_static_string (string)
+
+#define GTK_PARAM_READABLE G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
+#define GTK_PARAM_WRITABLE G_PARAM_WRITABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
+#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
+
+
+
+static void ghb_cell_renderer_text_finalize (GObject *object);
+
+static void ghb_cell_renderer_text_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void ghb_cell_renderer_text_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void ghb_cell_renderer_text_get_size (GtkCellRenderer *cell,
+ GtkWidget *widget,
+ GdkRectangle *cell_area,
+ gint *x_offset,
+ gint *y_offset,
+ gint *width,
+ gint *height);
+static void ghb_cell_renderer_text_render (GtkCellRenderer *cell,
+ GdkWindow *window,
+ GtkWidget *widget,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GdkRectangle *expose_area,
+ GtkCellRendererState flags);
+
+static GtkCellEditable *ghb_cell_renderer_text_start_editing (GtkCellRenderer *cell,
+ GdkEvent *event,
+ GtkWidget *widget,
+ const gchar *path,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GtkCellRendererState flags);
+
+enum {
+ EDITED,
+ KEYPRESS,
+ LAST_SIGNAL
+};
+
+enum {
+ PROP_0,
+
+ PROP_TEXT,
+ PROP_MARKUP,
+ PROP_ATTRIBUTES,
+ PROP_SINGLE_PARAGRAPH_MODE,
+ PROP_WIDTH_CHARS,
+ PROP_WRAP_WIDTH,
+ PROP_ALIGN,
+
+ /* Style args */
+ PROP_BACKGROUND,
+ PROP_FOREGROUND,
+ PROP_BACKGROUND_GDK,
+ PROP_FOREGROUND_GDK,
+ PROP_FONT,
+ PROP_FONT_DESC,
+ PROP_FAMILY,
+ PROP_STYLE,
+ PROP_VARIANT,
+ PROP_WEIGHT,
+ PROP_STRETCH,
+ PROP_SIZE,
+ PROP_SIZE_POINTS,
+ PROP_SCALE,
+ PROP_EDITABLE,
+ PROP_STRIKETHROUGH,
+ PROP_UNDERLINE,
+ PROP_RISE,
+ PROP_LANGUAGE,
+ PROP_ELLIPSIZE,
+ PROP_WRAP_MODE,
+
+ /* Whether-a-style-arg-is-set args */
+ PROP_BACKGROUND_SET,
+ PROP_FOREGROUND_SET,
+ PROP_FAMILY_SET,
+ PROP_STYLE_SET,
+ PROP_VARIANT_SET,
+ PROP_WEIGHT_SET,
+ PROP_STRETCH_SET,
+ PROP_SIZE_SET,
+ PROP_SCALE_SET,
+ PROP_EDITABLE_SET,
+ PROP_STRIKETHROUGH_SET,
+ PROP_UNDERLINE_SET,
+ PROP_RISE_SET,
+ PROP_LANGUAGE_SET,
+ PROP_ELLIPSIZE_SET,
+ PROP_ALIGN_SET
+};
+
+static guint text_cell_renderer_signals [LAST_SIGNAL];
+
+#define GHB_CELL_RENDERER_TEXT_PATH "gtk-cell-renderer-text-path"
+
+#define GHB_CELL_RENDERER_TEXT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GHB_TYPE_CELL_RENDERER_TEXT, GhbCellRendererTextPrivate))
+
+typedef struct _GhbCellRendererTextPrivate GhbCellRendererTextPrivate;
+struct _GhbCellRendererTextPrivate
+{
+ guint single_paragraph : 1;
+ guint language_set : 1;
+ guint markup_set : 1;
+ guint ellipsize_set : 1;
+ guint align_set : 1;
+
+ gulong focus_out_id;
+ PangoLanguage *language;
+ PangoEllipsizeMode ellipsize;
+ PangoWrapMode wrap_mode;
+ PangoAlignment align;
+
+ gulong populate_popup_id;
+ gulong entry_menu_popdown_timeout;
+ gboolean in_entry_menu;
+
+ gint width_chars;
+ gint wrap_width;
+
+ GtkWidget *entry;
+};
+
+G_DEFINE_TYPE (GhbCellRendererText, ghb_cell_renderer_text, GTK_TYPE_CELL_RENDERER)
+
+static void
+ghb_cell_renderer_text_init (GhbCellRendererText *celltext)
+{
+ GhbCellRendererTextPrivate *priv;
+
+ priv = GHB_CELL_RENDERER_TEXT_GET_PRIVATE (celltext);
+
+ GTK_CELL_RENDERER (celltext)->xalign = 0.0;
+ GTK_CELL_RENDERER (celltext)->yalign = 0.5;
+ GTK_CELL_RENDERER (celltext)->xpad = 2;
+ GTK_CELL_RENDERER (celltext)->ypad = 2;
+ celltext->font_scale = 1.0;
+ celltext->fixed_height_rows = -1;
+ celltext->font = pango_font_description_new ();
+
+ priv->width_chars = -1;
+ priv->wrap_width = -1;
+ priv->wrap_mode = PANGO_WRAP_CHAR;
+ priv->align = PANGO_ALIGN_LEFT;
+ priv->align_set = FALSE;
+}
+
+static void
+ghb_cell_renderer_text_class_init (GhbCellRendererTextClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+ GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class);
+
+ object_class->finalize = ghb_cell_renderer_text_finalize;
+
+ object_class->get_property = ghb_cell_renderer_text_get_property;
+ object_class->set_property = ghb_cell_renderer_text_set_property;
+
+ cell_class->get_size = ghb_cell_renderer_text_get_size;
+ cell_class->render = ghb_cell_renderer_text_render;
+ cell_class->start_editing = ghb_cell_renderer_text_start_editing;
+
+ g_object_class_install_property (object_class,
+ PROP_TEXT,
+ g_param_spec_string ("text",
+ P_("Text"),
+ P_("Text to render"),
+ NULL,
+ GTK_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_MARKUP,
+ g_param_spec_string ("markup",
+ P_("Markup"),
+ P_("Marked up text to render"),
+ NULL,
+ GTK_PARAM_WRITABLE));
+
+ g_object_class_install_property (object_class,
+ PROP_ATTRIBUTES,
+ g_param_spec_boxed ("attributes",
+ P_("Attributes"),
+ P_("A list of style attributes to apply to the text of the renderer"),
+ PANGO_TYPE_ATTR_LIST,
+ GTK_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_SINGLE_PARAGRAPH_MODE,
+ g_param_spec_boolean ("single-paragraph-mode",
+ P_("Single Paragraph Mode"),
+ P_("Whether or not to keep all text in a single paragraph"),
+ FALSE,
+ GTK_PARAM_READWRITE));
+
+
+ g_object_class_install_property (object_class,
+ PROP_BACKGROUND,
+ g_param_spec_string ("background",
+ P_("Background color name"),
+ P_("Background color as a string"),
+ NULL,
+ GTK_PARAM_WRITABLE));
+
+ g_object_class_install_property (object_class,
+ PROP_BACKGROUND_GDK,
+ g_param_spec_boxed ("background-gdk",
+ P_("Background color"),
+ P_("Background color as a GdkColor"),
+ GDK_TYPE_COLOR,
+ GTK_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_FOREGROUND,
+ g_param_spec_string ("foreground",
+ P_("Foreground color name"),
+ P_("Foreground color as a string"),
+ NULL,
+ GTK_PARAM_WRITABLE));
+
+ g_object_class_install_property (object_class,
+ PROP_FOREGROUND_GDK,
+ g_param_spec_boxed ("foreground-gdk",
+ P_("Foreground color"),
+ P_("Foreground color as a GdkColor"),
+ GDK_TYPE_COLOR,
+ GTK_PARAM_READWRITE));
+
+
+ g_object_class_install_property (object_class,
+ PROP_EDITABLE,
+ g_param_spec_boolean ("editable",
+ P_("Editable"),
+ P_("Whether the text can be modified by the user"),
+ FALSE,
+ GTK_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_FONT,
+ g_param_spec_string ("font",
+ P_("Font"),
+ P_("Font description as a string, e.g. \"Sans Italic 12\""),
+ NULL,
+ GTK_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_FONT_DESC,
+ g_param_spec_boxed ("font-desc",
+ P_("Font"),
+ P_("Font description as a PangoFontDescription struct"),
+ PANGO_TYPE_FONT_DESCRIPTION,
+ GTK_PARAM_READWRITE));
+
+
+ g_object_class_install_property (object_class,
+ PROP_FAMILY,
+ g_param_spec_string ("family",
+ P_("Font family"),
+ P_("Name of the font family, e.g. Sans, Helvetica, Times, Monospace"),
+ NULL,
+ GTK_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_STYLE,
+ g_param_spec_enum ("style",
+ P_("Font style"),
+ P_("Font style"),
+ PANGO_TYPE_STYLE,
+ PANGO_STYLE_NORMAL,
+ GTK_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_VARIANT,
+ g_param_spec_enum ("variant",
+ P_("Font variant"),
+ P_("Font variant"),
+ PANGO_TYPE_VARIANT,
+ PANGO_VARIANT_NORMAL,
+ GTK_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_WEIGHT,
+ g_param_spec_int ("weight",
+ P_("Font weight"),
+ P_("Font weight"),
+ 0,
+ G_MAXINT,
+ PANGO_WEIGHT_NORMAL,
+ GTK_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_STRETCH,
+ g_param_spec_enum ("stretch",
+ P_("Font stretch"),
+ P_("Font stretch"),
+ PANGO_TYPE_STRETCH,
+ PANGO_STRETCH_NORMAL,
+ GTK_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_SIZE,
+ g_param_spec_int ("size",
+ P_("Font size"),
+ P_("Font size"),
+ 0,
+ G_MAXINT,
+ 0,
+ GTK_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_SIZE_POINTS,
+ g_param_spec_double ("size-points",
+ P_("Font points"),
+ P_("Font size in points"),
+ 0.0,
+ G_MAXDOUBLE,
+ 0.0,
+ GTK_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_SCALE,
+ g_param_spec_double ("scale",
+ P_("Font scale"),
+ P_("Font scaling factor"),
+ 0.0,
+ G_MAXDOUBLE,
+ 1.0,
+ GTK_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_RISE,
+ g_param_spec_int ("rise",
+ P_("Rise"),
+ P_("Offset of text above the baseline "
+ "(below the baseline if rise is negative)"),
+ -G_MAXINT,
+ G_MAXINT,
+ 0,
+ GTK_PARAM_READWRITE));
+
+
+ g_object_class_install_property (object_class,
+ PROP_STRIKETHROUGH,
+ g_param_spec_boolean ("strikethrough",
+ P_("Strikethrough"),
+ P_("Whether to strike through the text"),
+ FALSE,
+ GTK_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_UNDERLINE,
+ g_param_spec_enum ("underline",
+ P_("Underline"),
+ P_("Style of underline for this text"),
+ PANGO_TYPE_UNDERLINE,
+ PANGO_UNDERLINE_NONE,
+ GTK_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_LANGUAGE,
+ g_param_spec_string ("language",
+ P_("Language"),
+ P_("The language this text is in, as an ISO code. "
+ "Pango can use this as a hint when rendering the text. "
+ "If you don't understand this parameter, you probably don't need it"),
+ NULL,
+ GTK_PARAM_READWRITE));
+
+
+ /**
+ * GhbCellRendererText:ellipsize:
+ *
+ * Specifies the preferred place to ellipsize the string, if the cell renderer
+ * does not have enough room to display the entire string. Setting it to
+ * %PANGO_ELLIPSIZE_NONE turns off ellipsizing. See the wrap-width property
+ * for another way of making the text fit into a given width.
+ *
+ * Since: 2.6
+ */
+ g_object_class_install_property (object_class,
+ PROP_ELLIPSIZE,
+ g_param_spec_enum ("ellipsize",
+ P_("Ellipsize"),
+ P_("The preferred place to ellipsize the string, "
+ "if the cell renderer does not have enough room "
+ "to display the entire string"),
+ PANGO_TYPE_ELLIPSIZE_MODE,
+ PANGO_ELLIPSIZE_NONE,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GhbCellRendererText:width-chars:
+ *
+ * The desired width of the cell, in characters. If this property is set to
+ * -1, the width will be calculated automatically, otherwise the cell will
+ * request either 3 characters or the property value, whichever is greater.
+ *
+ * Since: 2.6
+ **/
+ g_object_class_install_property (object_class,
+ PROP_WIDTH_CHARS,
+ g_param_spec_int ("width-chars",
+ P_("Width In Characters"),
+ P_("The desired width of the label, in characters"),
+ -1,
+ G_MAXINT,
+ -1,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GhbCellRendererText:wrap-mode:
+ *
+ * Specifies how to break the string into multiple lines, if the cell
+ * renderer does not have enough room to display the entire string.
+ * This property has no effect unless the wrap-width property is set.
+ *
+ * Since: 2.8
+ */
+ g_object_class_install_property (object_class,
+ PROP_WRAP_MODE,
+ g_param_spec_enum ("wrap-mode",
+ P_("Wrap mode"),
+ P_("How to break the string into multiple lines, "
+ "if the cell renderer does not have enough room "
+ "to display the entire string"),
+ PANGO_TYPE_WRAP_MODE,
+ PANGO_WRAP_CHAR,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GhbCellRendererText:wrap-width:
+ *
+ * Specifies the width at which the text is wrapped. The wrap-mode property can
+ * be used to influence at what character positions the line breaks can be placed.
+ * Setting wrap-width to -1 turns wrapping off.
+ *
+ * Since: 2.8
+ */
+ g_object_class_install_property (object_class,
+ PROP_WRAP_WIDTH,
+ g_param_spec_int ("wrap-width",
+ P_("Wrap width"),
+ P_("The width at which the text is wrapped"),
+ -1,
+ G_MAXINT,
+ -1,
+ GTK_PARAM_READWRITE));
+
+ /**
+ * GhbCellRendererText:alignment:
+ *
+ * Specifies how to align the lines of text with respect to each other.
+ *
+ * Note that this property describes how to align the lines of text in
+ * case there are several of them. The "xalign" property of #GtkCellRenderer,
+ * on the other hand, sets the horizontal alignment of the whole text.
+ *
+ * Since: 2.10
+ */
+ g_object_class_install_property (object_class,
+ PROP_ALIGN,
+ g_param_spec_enum ("alignment",
+ P_("Alignment"),
+ P_("How to align the lines"),
+ PANGO_TYPE_ALIGNMENT,
+ PANGO_ALIGN_LEFT,
+ GTK_PARAM_READWRITE));
+
+ /* Style props are set or not */
+
+#define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (object_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, GTK_PARAM_READWRITE))
+
+ ADD_SET_PROP ("background-set", PROP_BACKGROUND_SET,
+ P_("Background set"),
+ P_("Whether this tag affects the background color"));
+
+ ADD_SET_PROP ("foreground-set", PROP_FOREGROUND_SET,
+ P_("Foreground set"),
+ P_("Whether this tag affects the foreground color"));
+
+ ADD_SET_PROP ("editable-set", PROP_EDITABLE_SET,
+ P_("Editability set"),
+ P_("Whether this tag affects text editability"));
+
+ ADD_SET_PROP ("family-set", PROP_FAMILY_SET,
+ P_("Font family set"),
+ P_("Whether this tag affects the font family"));
+
+ ADD_SET_PROP ("style-set", PROP_STYLE_SET,
+ P_("Font style set"),
+ P_("Whether this tag affects the font style"));
+
+ ADD_SET_PROP ("variant-set", PROP_VARIANT_SET,
+ P_("Font variant set"),
+ P_("Whether this tag affects the font variant"));
+
+ ADD_SET_PROP ("weight-set", PROP_WEIGHT_SET,
+ P_("Font weight set"),
+ P_("Whether this tag affects the font weight"));
+
+ ADD_SET_PROP ("stretch-set", PROP_STRETCH_SET,
+ P_("Font stretch set"),
+ P_("Whether this tag affects the font stretch"));
+
+ ADD_SET_PROP ("size-set", PROP_SIZE_SET,
+ P_("Font size set"),
+ P_("Whether this tag affects the font size"));
+
+ ADD_SET_PROP ("scale-set", PROP_SCALE_SET,
+ P_("Font scale set"),
+ P_("Whether this tag scales the font size by a factor"));
+
+ ADD_SET_PROP ("rise-set", PROP_RISE_SET,
+ P_("Rise set"),
+ P_("Whether this tag affects the rise"));
+
+ ADD_SET_PROP ("strikethrough-set", PROP_STRIKETHROUGH_SET,
+ P_("Strikethrough set"),
+ P_("Whether this tag affects strikethrough"));
+
+ ADD_SET_PROP ("underline-set", PROP_UNDERLINE_SET,
+ P_("Underline set"),
+ P_("Whether this tag affects underlining"));
+
+ ADD_SET_PROP ("language-set", PROP_LANGUAGE_SET,
+ P_("Language set"),
+ P_("Whether this tag affects the language the text is rendered as"));
+
+ ADD_SET_PROP ("ellipsize-set", PROP_ELLIPSIZE_SET,
+ P_("Ellipsize set"),
+ P_("Whether this tag affects the ellipsize mode"));
+
+ ADD_SET_PROP ("align-set", PROP_ALIGN_SET,
+ P_("Align set"),
+ P_("Whether this tag affects the alignment mode"));
+
+ /**
+ * GhbCellRendererText::edited
+ * @renderer: the object which received the signal
+ * @path: the path identifying the edited cell
+ * @new_text: the new text
+ *
+ * This signal is emitted after @renderer has been edited.
+ *
+ * It is the responsibility of the application to update the model
+ * and store @new_text at the position indicated by @path.
+ */
+ text_cell_renderer_signals [EDITED] =
+ g_signal_new (I_("edited"),
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GhbCellRendererTextClass, edited),
+ NULL, NULL,
+ ghb_marshal_VOID__STRING_STRING,
+ G_TYPE_NONE, 2,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+
+ text_cell_renderer_signals [KEYPRESS] =
+ g_signal_new (I_("key-press-event"),
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GhbCellRendererTextClass, keypress),
+ NULL, NULL,
+ ghb_marshal_BOOLEAN__BOXED,
+ G_TYPE_BOOLEAN, 1,
+ GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+ g_type_class_add_private (object_class, sizeof (GhbCellRendererTextPrivate));
+}
+
+static void
+ghb_cell_renderer_text_finalize (GObject *object)
+{
+ GhbCellRendererText *celltext = GHB_CELL_RENDERER_TEXT (object);
+ GhbCellRendererTextPrivate *priv;
+
+ priv = GHB_CELL_RENDERER_TEXT_GET_PRIVATE (object);
+
+ pango_font_description_free (celltext->font);
+
+ g_free (celltext->text);
+
+ if (celltext->extra_attrs)
+ pango_attr_list_unref (celltext->extra_attrs);
+
+ if (priv->language)
+ g_object_unref (priv->language);
+
+ (* G_OBJECT_CLASS (ghb_cell_renderer_text_parent_class)->finalize) (object);
+}
+
+static PangoFontMask
+get_property_font_set_mask (guint prop_id)
+{
+ switch (prop_id)
+ {
+ case PROP_FAMILY_SET:
+ return PANGO_FONT_MASK_FAMILY;
+ case PROP_STYLE_SET:
+ return PANGO_FONT_MASK_STYLE;
+ case PROP_VARIANT_SET:
+ return PANGO_FONT_MASK_VARIANT;
+ case PROP_WEIGHT_SET:
+ return PANGO_FONT_MASK_WEIGHT;
+ case PROP_STRETCH_SET:
+ return PANGO_FONT_MASK_STRETCH;
+ case PROP_SIZE_SET:
+ return PANGO_FONT_MASK_SIZE;
+ }
+
+ return 0;
+}
+
+static void
+ghb_cell_renderer_text_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GhbCellRendererText *celltext = GHB_CELL_RENDERER_TEXT (object);
+ GhbCellRendererTextPrivate *priv;
+
+ priv = GHB_CELL_RENDERER_TEXT_GET_PRIVATE (object);
+
+ switch (param_id)
+ {
+ case PROP_TEXT:
+ g_value_set_string (value, celltext->text);
+ break;
+
+ case PROP_ATTRIBUTES:
+ g_value_set_boxed (value, celltext->extra_attrs);
+ break;
+
+ case PROP_SINGLE_PARAGRAPH_MODE:
+ g_value_set_boolean (value, priv->single_paragraph);
+ break;
+
+ case PROP_BACKGROUND_GDK:
+ {
+ GdkColor color;
+
+ color.red = celltext->background.red;
+ color.green = celltext->background.green;
+ color.blue = celltext->background.blue;
+
+ g_value_set_boxed (value, &color);
+ }
+ break;
+
+ case PROP_FOREGROUND_GDK:
+ {
+ GdkColor color;
+
+ color.red = celltext->foreground.red;
+ color.green = celltext->foreground.green;
+ color.blue = celltext->foreground.blue;
+
+ g_value_set_boxed (value, &color);
+ }
+ break;
+
+ case PROP_FONT:
+ g_value_take_string (value, pango_font_description_to_string (celltext->font));
+ break;
+
+ case PROP_FONT_DESC:
+ g_value_set_boxed (value, celltext->font);
+ break;
+
+ case PROP_FAMILY:
+ g_value_set_string (value, pango_font_description_get_family (celltext->font));
+ break;
+
+ case PROP_STYLE:
+ g_value_set_enum (value, pango_font_description_get_style (celltext->font));
+ break;
+
+ case PROP_VARIANT:
+ g_value_set_enum (value, pango_font_description_get_variant (celltext->font));
+ break;
+
+ case PROP_WEIGHT:
+ g_value_set_int (value, pango_font_description_get_weight (celltext->font));
+ break;
+
+ case PROP_STRETCH:
+ g_value_set_enum (value, pango_font_description_get_stretch (celltext->font));
+ break;
+
+ case PROP_SIZE:
+ g_value_set_int (value, pango_font_description_get_size (celltext->font));
+ break;
+
+ case PROP_SIZE_POINTS:
+ g_value_set_double (value, ((double)pango_font_description_get_size (celltext->font)) / (double)PANGO_SCALE);
+ break;
+
+ case PROP_SCALE:
+ g_value_set_double (value, celltext->font_scale);
+ break;
+
+ case PROP_EDITABLE:
+ g_value_set_boolean (value, celltext->editable);
+ break;
+
+ case PROP_STRIKETHROUGH:
+ g_value_set_boolean (value, celltext->strikethrough);
+ break;
+
+ case PROP_UNDERLINE:
+ g_value_set_enum (value, celltext->underline_style);
+ break;
+
+ case PROP_RISE:
+ g_value_set_int (value, celltext->rise);
+ break;
+
+ case PROP_LANGUAGE:
+ g_value_set_static_string (value, pango_language_to_string (priv->language));
+ break;
+
+ case PROP_ELLIPSIZE:
+ g_value_set_enum (value, priv->ellipsize);
+ break;
+
+ case PROP_WRAP_MODE:
+ g_value_set_enum (value, priv->wrap_mode);
+ break;
+
+ case PROP_WRAP_WIDTH:
+ g_value_set_int (value, priv->wrap_width);
+ break;
+
+ case PROP_ALIGN:
+ g_value_set_enum (value, priv->align);
+ break;
+
+ case PROP_BACKGROUND_SET:
+ g_value_set_boolean (value, celltext->background_set);
+ break;
+
+ case PROP_FOREGROUND_SET:
+ g_value_set_boolean (value, celltext->foreground_set);
+ break;
+
+ case PROP_FAMILY_SET:
+ case PROP_STYLE_SET:
+ case PROP_VARIANT_SET:
+ case PROP_WEIGHT_SET:
+ case PROP_STRETCH_SET:
+ case PROP_SIZE_SET:
+ {
+ PangoFontMask mask = get_property_font_set_mask (param_id);
+ g_value_set_boolean (value, (pango_font_description_get_set_fields (celltext->font) & mask) != 0);
+
+ break;
+ }
+
+ case PROP_SCALE_SET:
+ g_value_set_boolean (value, celltext->scale_set);
+ break;
+
+ case PROP_EDITABLE_SET:
+ g_value_set_boolean (value, celltext->editable_set);
+ break;
+
+ case PROP_STRIKETHROUGH_SET:
+ g_value_set_boolean (value, celltext->strikethrough_set);
+ break;
+
+ case PROP_UNDERLINE_SET:
+ g_value_set_boolean (value, celltext->underline_set);
+ break;
+
+ case PROP_RISE_SET:
+ g_value_set_boolean (value, celltext->rise_set);
+ break;
+
+ case PROP_LANGUAGE_SET:
+ g_value_set_boolean (value, priv->language_set);
+ break;
+
+ case PROP_ELLIPSIZE_SET:
+ g_value_set_boolean (value, priv->ellipsize_set);
+ break;
+
+ case PROP_ALIGN_SET:
+ g_value_set_boolean (value, priv->align_set);
+ break;
+
+ case PROP_WIDTH_CHARS:
+ g_value_set_int (value, priv->width_chars);
+ break;
+
+ case PROP_BACKGROUND:
+ case PROP_FOREGROUND:
+ case PROP_MARKUP:
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+
+static void
+set_bg_color (GhbCellRendererText *celltext,
+ GdkColor *color)
+{
+ if (color)
+ {
+ if (!celltext->background_set)
+ {
+ celltext->background_set = TRUE;
+ g_object_notify (G_OBJECT (celltext), "background-set");
+ }
+
+ celltext->background.red = color->red;
+ celltext->background.green = color->green;
+ celltext->background.blue = color->blue;
+ }
+ else
+ {
+ if (celltext->background_set)
+ {
+ celltext->background_set = FALSE;
+ g_object_notify (G_OBJECT (celltext), "background-set");
+ }
+ }
+}
+
+
+static void
+set_fg_color (GhbCellRendererText *celltext,
+ GdkColor *color)
+{
+ if (color)
+ {
+ if (!celltext->foreground_set)
+ {
+ celltext->foreground_set = TRUE;
+ g_object_notify (G_OBJECT (celltext), "foreground-set");
+ }
+
+ celltext->foreground.red = color->red;
+ celltext->foreground.green = color->green;
+ celltext->foreground.blue = color->blue;
+ }
+ else
+ {
+ if (celltext->foreground_set)
+ {
+ celltext->foreground_set = FALSE;
+ g_object_notify (G_OBJECT (celltext), "foreground-set");
+ }
+ }
+}
+
+static PangoFontMask
+set_font_desc_fields (PangoFontDescription *desc,
+ PangoFontMask to_set)
+{
+ PangoFontMask changed_mask = 0;
+
+ if (to_set & PANGO_FONT_MASK_FAMILY)
+ {
+ const char *family = pango_font_description_get_family (desc);
+ if (!family)
+ {
+ family = "sans";
+ changed_mask |= PANGO_FONT_MASK_FAMILY;
+ }
+
+ pango_font_description_set_family (desc, family);
+ }
+ if (to_set & PANGO_FONT_MASK_STYLE)
+ pango_font_description_set_style (desc, pango_font_description_get_style (desc));
+ if (to_set & PANGO_FONT_MASK_VARIANT)
+ pango_font_description_set_variant (desc, pango_font_description_get_variant (desc));
+ if (to_set & PANGO_FONT_MASK_WEIGHT)
+ pango_font_description_set_weight (desc, pango_font_description_get_weight (desc));
+ if (to_set & PANGO_FONT_MASK_STRETCH)
+ pango_font_description_set_stretch (desc, pango_font_description_get_stretch (desc));
+ if (to_set & PANGO_FONT_MASK_SIZE)
+ {
+ gint size = pango_font_description_get_size (desc);
+ if (size <= 0)
+ {
+ size = 10 * PANGO_SCALE;
+ changed_mask |= PANGO_FONT_MASK_SIZE;
+ }
+
+ pango_font_description_set_size (desc, size);
+ }
+
+ return changed_mask;
+}
+
+static void
+notify_set_changed (GObject *object,
+ PangoFontMask changed_mask)
+{
+ if (changed_mask & PANGO_FONT_MASK_FAMILY)
+ g_object_notify (object, "family-set");
+ if (changed_mask & PANGO_FONT_MASK_STYLE)
+ g_object_notify (object, "style-set");
+ if (changed_mask & PANGO_FONT_MASK_VARIANT)
+ g_object_notify (object, "variant-set");
+ if (changed_mask & PANGO_FONT_MASK_WEIGHT)
+ g_object_notify (object, "weight-set");
+ if (changed_mask & PANGO_FONT_MASK_STRETCH)
+ g_object_notify (object, "stretch-set");
+ if (changed_mask & PANGO_FONT_MASK_SIZE)
+ g_object_notify (object, "size-set");
+}
+
+static void
+notify_fields_changed (GObject *object,
+ PangoFontMask changed_mask)
+{
+ if (changed_mask & PANGO_FONT_MASK_FAMILY)
+ g_object_notify (object, "family");
+ if (changed_mask & PANGO_FONT_MASK_STYLE)
+ g_object_notify (object, "style");
+ if (changed_mask & PANGO_FONT_MASK_VARIANT)
+ g_object_notify (object, "variant");
+ if (changed_mask & PANGO_FONT_MASK_WEIGHT)
+ g_object_notify (object, "weight");
+ if (changed_mask & PANGO_FONT_MASK_STRETCH)
+ g_object_notify (object, "stretch");
+ if (changed_mask & PANGO_FONT_MASK_SIZE)
+ g_object_notify (object, "size");
+}
+
+static void
+set_font_description (GhbCellRendererText *celltext,
+ PangoFontDescription *font_desc)
+{
+ GObject *object = G_OBJECT (celltext);
+ PangoFontDescription *new_font_desc;
+ PangoFontMask old_mask, new_mask, changed_mask, set_changed_mask;
+
+ if (font_desc)
+ new_font_desc = pango_font_description_copy (font_desc);
+ else
+ new_font_desc = pango_font_description_new ();
+
+ old_mask = pango_font_description_get_set_fields (celltext->font);
+ new_mask = pango_font_description_get_set_fields (new_font_desc);
+
+ changed_mask = old_mask | new_mask;
+ set_changed_mask = old_mask ^ new_mask;
+
+ pango_font_description_free (celltext->font);
+ celltext->font = new_font_desc;
+
+ g_object_freeze_notify (object);
+
+ g_object_notify (object, "font-desc");
+ g_object_notify (object, "font");
+
+ if (changed_mask & PANGO_FONT_MASK_FAMILY)
+ g_object_notify (object, "family");
+ if (changed_mask & PANGO_FONT_MASK_STYLE)
+ g_object_notify (object, "style");
+ if (changed_mask & PANGO_FONT_MASK_VARIANT)
+ g_object_notify (object, "variant");
+ if (changed_mask & PANGO_FONT_MASK_WEIGHT)
+ g_object_notify (object, "weight");
+ if (changed_mask & PANGO_FONT_MASK_STRETCH)
+ g_object_notify (object, "stretch");
+ if (changed_mask & PANGO_FONT_MASK_SIZE)
+ {
+ g_object_notify (object, "size");
+ g_object_notify (object, "size-points");
+ }
+
+ notify_set_changed (object, set_changed_mask);
+
+ g_object_thaw_notify (object);
+}
+
+static void
+ghb_cell_renderer_text_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GhbCellRendererText *celltext = GHB_CELL_RENDERER_TEXT (object);
+ GhbCellRendererTextPrivate *priv;
+
+ priv = GHB_CELL_RENDERER_TEXT_GET_PRIVATE (object);
+
+ switch (param_id)
+ {
+ case PROP_TEXT:
+ g_free (celltext->text);
+
+ if (priv->markup_set)
+ {
+ if (celltext->extra_attrs)
+ pango_attr_list_unref (celltext->extra_attrs);
+ celltext->extra_attrs = NULL;
+ priv->markup_set = FALSE;
+ }
+
+ celltext->text = g_strdup (g_value_get_string (value));
+ g_object_notify (object, "text");
+ break;
+
+ case PROP_ATTRIBUTES:
+ if (celltext->extra_attrs)
+ pango_attr_list_unref (celltext->extra_attrs);
+
+ celltext->extra_attrs = g_value_get_boxed (value);
+ if (celltext->extra_attrs)
+ pango_attr_list_ref (celltext->extra_attrs);
+ break;
+ case PROP_MARKUP:
+ {
+ const gchar *str;
+ gchar *text = NULL;
+ GError *error = NULL;
+ PangoAttrList *attrs = NULL;
+
+ str = g_value_get_string (value);
+ if (str && !pango_parse_markup (str,
+ -1,
+ 0,
+ &attrs,
+ &text,
+ NULL,
+ &error))
+ {
+ g_warning ("Failed to set text from markup due to error parsing markup: %s",
+ error->message);
+ g_error_free (error);
+ return;
+ }
+
+ g_free (celltext->text);
+
+ if (celltext->extra_attrs)
+ pango_attr_list_unref (celltext->extra_attrs);
+
+ celltext->text = text;
+ celltext->extra_attrs = attrs;
+ priv->markup_set = TRUE;
+ }
+ break;
+
+ case PROP_SINGLE_PARAGRAPH_MODE:
+ priv->single_paragraph = g_value_get_boolean (value);
+ break;
+
+ case PROP_BACKGROUND:
+ {
+ GdkColor color;
+
+ if (!g_value_get_string (value))
+ set_bg_color (celltext, NULL); /* reset to background_set to FALSE */
+ else if (gdk_color_parse (g_value_get_string (value), &color))
+ set_bg_color (celltext, &color);
+ else
+ g_warning ("Don't know color `%s'", g_value_get_string (value));
+
+ g_object_notify (object, "background-gdk");
+ }
+ break;
+
+ case PROP_FOREGROUND:
+ {
+ GdkColor color;
+
+ if (!g_value_get_string (value))
+ set_fg_color (celltext, NULL); /* reset to foreground_set to FALSE */
+ else if (gdk_color_parse (g_value_get_string (value), &color))
+ set_fg_color (celltext, &color);
+ else
+ g_warning ("Don't know color `%s'", g_value_get_string (value));
+
+ g_object_notify (object, "foreground-gdk");
+ }
+ break;
+
+ case PROP_BACKGROUND_GDK:
+ /* This notifies the GObject itself. */
+ set_bg_color (celltext, g_value_get_boxed (value));
+ break;
+
+ case PROP_FOREGROUND_GDK:
+ /* This notifies the GObject itself. */
+ set_fg_color (celltext, g_value_get_boxed (value));
+ break;
+
+ case PROP_FONT:
+ {
+ PangoFontDescription *font_desc = NULL;
+ const gchar *name;
+
+ name = g_value_get_string (value);
+
+ if (name)
+ font_desc = pango_font_description_from_string (name);
+
+ set_font_description (celltext, font_desc);
+
+ pango_font_description_free (font_desc);
+
+ if (celltext->fixed_height_rows != -1)
+ celltext->calc_fixed_height = TRUE;
+ }
+ break;
+
+ case PROP_FONT_DESC:
+ set_font_description (celltext, g_value_get_boxed (value));
+
+ if (celltext->fixed_height_rows != -1)
+ celltext->calc_fixed_height = TRUE;
+ break;
+
+ case PROP_FAMILY:
+ case PROP_STYLE:
+ case PROP_VARIANT:
+ case PROP_WEIGHT:
+ case PROP_STRETCH:
+ case PROP_SIZE:
+ case PROP_SIZE_POINTS:
+ {
+ PangoFontMask old_set_mask = pango_font_description_get_set_fields (celltext->font);
+
+ switch (param_id)
+ {
+ case PROP_FAMILY:
+ pango_font_description_set_family (celltext->font,
+ g_value_get_string (value));
+ break;
+ case PROP_STYLE:
+ pango_font_description_set_style (celltext->font,
+ g_value_get_enum (value));
+ break;
+ case PROP_VARIANT:
+ pango_font_description_set_variant (celltext->font,
+ g_value_get_enum (value));
+ break;
+ case PROP_WEIGHT:
+ pango_font_description_set_weight (celltext->font,
+ g_value_get_int (value));
+ break;
+ case PROP_STRETCH:
+ pango_font_description_set_stretch (celltext->font,
+ g_value_get_enum (value));
+ break;
+ case PROP_SIZE:
+ pango_font_description_set_size (celltext->font,
+ g_value_get_int (value));
+ g_object_notify (object, "size-points");
+ break;
+ case PROP_SIZE_POINTS:
+ pango_font_description_set_size (celltext->font,
+ g_value_get_double (value) * PANGO_SCALE);
+ g_object_notify (object, "size");
+ break;
+ }
+
+ if (celltext->fixed_height_rows != -1)
+ celltext->calc_fixed_height = TRUE;
+
+ notify_set_changed (object, old_set_mask & pango_font_description_get_set_fields (celltext->font));
+ g_object_notify (object, "font-desc");
+ g_object_notify (object, "font");
+
+ break;
+ }
+
+ case PROP_SCALE:
+ celltext->font_scale = g_value_get_double (value);
+ celltext->scale_set = TRUE;
+ if (celltext->fixed_height_rows != -1)
+ celltext->calc_fixed_height = TRUE;
+ g_object_notify (object, "scale-set");
+ break;
+
+ case PROP_EDITABLE:
+ celltext->editable = g_value_get_boolean (value);
+ celltext->editable_set = TRUE;
+ if (celltext->editable)
+ GTK_CELL_RENDERER (celltext)->mode = GTK_CELL_RENDERER_MODE_EDITABLE;
+ else
+ GTK_CELL_RENDERER (celltext)->mode = GTK_CELL_RENDERER_MODE_INERT;
+ g_object_notify (object, "editable-set");
+ break;
+
+ case PROP_STRIKETHROUGH:
+ celltext->strikethrough = g_value_get_boolean (value);
+ celltext->strikethrough_set = TRUE;
+ g_object_notify (object, "strikethrough-set");
+ break;
+
+ case PROP_UNDERLINE:
+ celltext->underline_style = g_value_get_enum (value);
+ celltext->underline_set = TRUE;
+ g_object_notify (object, "underline-set");
+
+ break;
+
+ case PROP_RISE:
+ celltext->rise = g_value_get_int (value);
+ celltext->rise_set = TRUE;
+ g_object_notify (object, "rise-set");
+ if (celltext->fixed_height_rows != -1)
+ celltext->calc_fixed_height = TRUE;
+ break;
+
+ case PROP_LANGUAGE:
+ priv->language_set = TRUE;
+ if (priv->language)
+ g_object_unref (priv->language);
+ priv->language = pango_language_from_string (g_value_get_string (value));
+ g_object_notify (object, "language-set");
+ break;
+
+ case PROP_ELLIPSIZE:
+ priv->ellipsize = g_value_get_enum (value);
+ priv->ellipsize_set = TRUE;
+ g_object_notify (object, "ellipsize-set");
+ break;
+
+ case PROP_WRAP_MODE:
+ priv->wrap_mode = g_value_get_enum (value);
+ break;
+
+ case PROP_WRAP_WIDTH:
+ priv->wrap_width = g_value_get_int (value);
+ break;
+
+ case PROP_WIDTH_CHARS:
+ priv->width_chars = g_value_get_int (value);
+ break;
+
+ case PROP_ALIGN:
+ priv->align = g_value_get_enum (value);
+ priv->align_set = TRUE;
+ g_object_notify (object, "align-set");
+ break;
+
+ case PROP_BACKGROUND_SET:
+ celltext->background_set = g_value_get_boolean (value);
+ break;
+
+ case PROP_FOREGROUND_SET:
+ celltext->foreground_set = g_value_get_boolean (value);
+ break;
+
+ case PROP_FAMILY_SET:
+ case PROP_STYLE_SET:
+ case PROP_VARIANT_SET:
+ case PROP_WEIGHT_SET:
+ case PROP_STRETCH_SET:
+ case PROP_SIZE_SET:
+ if (!g_value_get_boolean (value))
+ {
+ pango_font_description_unset_fields (celltext->font,
+ get_property_font_set_mask (param_id));
+ }
+ else
+ {
+ PangoFontMask changed_mask;
+
+ changed_mask = set_font_desc_fields (celltext->font,
+ get_property_font_set_mask (param_id));
+ notify_fields_changed (G_OBJECT (celltext), changed_mask);
+ }
+ break;
+
+ case PROP_SCALE_SET:
+ celltext->scale_set = g_value_get_boolean (value);
+ break;
+
+ case PROP_EDITABLE_SET:
+ celltext->editable_set = g_value_get_boolean (value);
+ break;
+
+ case PROP_STRIKETHROUGH_SET:
+ celltext->strikethrough_set = g_value_get_boolean (value);
+ break;
+
+ case PROP_UNDERLINE_SET:
+ celltext->underline_set = g_value_get_boolean (value);
+ break;
+
+ case PROP_RISE_SET:
+ celltext->rise_set = g_value_get_boolean (value);
+ break;
+
+ case PROP_LANGUAGE_SET:
+ priv->language_set = g_value_get_boolean (value);
+ break;
+
+ case PROP_ELLIPSIZE_SET:
+ priv->ellipsize_set = g_value_get_boolean (value);
+ break;
+
+ case PROP_ALIGN_SET:
+ priv->align_set = g_value_get_boolean (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+/**
+ * ghb_cell_renderer_text_new:
+ *
+ * Creates a new #GhbCellRendererText. Adjust how text is drawn using
+ * object properties. Object properties can be
+ * set globally (with g_object_set()). Also, with #GtkTreeViewColumn,
+ * you can bind a property to a value in a #GtkTreeModel. For example,
+ * you can bind the "text" property on the cell renderer to a string
+ * value in the model, thus rendering a different string in each row
+ * of the #GtkTreeView
+ *
+ * Return value: the new cell renderer
+ **/
+GtkCellRenderer *
+ghb_cell_renderer_text_new (void)
+{
+ return g_object_new (GHB_TYPE_CELL_RENDERER_TEXT, NULL);
+}
+
+static void
+add_attr (PangoAttrList *attr_list,
+ PangoAttribute *attr)
+{
+ attr->start_index = 0;
+ attr->end_index = G_MAXINT;
+
+ pango_attr_list_insert (attr_list, attr);
+}
+
+static PangoLayout*
+get_layout (GhbCellRendererText *celltext,
+ GtkWidget *widget,
+ gboolean will_render,
+ GtkCellRendererState flags)
+{
+ PangoAttrList *attr_list;
+ PangoLayout *layout;
+ PangoUnderline uline;
+ GhbCellRendererTextPrivate *priv;
+
+ priv = GHB_CELL_RENDERER_TEXT_GET_PRIVATE (celltext);
+
+ layout = gtk_widget_create_pango_layout (widget, celltext->text);
+
+ if (celltext->extra_attrs)
+ attr_list = pango_attr_list_copy (celltext->extra_attrs);
+ else
+ attr_list = pango_attr_list_new ();
+
+ pango_layout_set_single_paragraph_mode (layout, priv->single_paragraph);
+
+ if (will_render)
+ {
+ /* Add options that affect appearance but not size */
+
+ /* note that background doesn't go here, since it affects
+ * background_area not the PangoLayout area
+ */
+
+ if (celltext->foreground_set
+ && (flags & GTK_CELL_RENDERER_SELECTED) == 0)
+ {
+ PangoColor color;
+
+ color = celltext->foreground;
+
+ add_attr (attr_list,
+ pango_attr_foreground_new (color.red, color.green, color.blue));
+ }
+
+ if (celltext->strikethrough_set)
+ add_attr (attr_list,
+ pango_attr_strikethrough_new (celltext->strikethrough));
+ }
+
+ add_attr (attr_list, pango_attr_font_desc_new (celltext->font));
+
+ if (celltext->scale_set &&
+ celltext->font_scale != 1.0)
+ add_attr (attr_list, pango_attr_scale_new (celltext->font_scale));
+
+ if (celltext->underline_set)
+ uline = celltext->underline_style;
+ else
+ uline = PANGO_UNDERLINE_NONE;
+
+ if (priv->language_set)
+ add_attr (attr_list, pango_attr_language_new (priv->language));
+
+ if ((flags & GTK_CELL_RENDERER_PRELIT) == GTK_CELL_RENDERER_PRELIT)
+ {
+ switch (uline)
+ {
+ case PANGO_UNDERLINE_NONE:
+ uline = PANGO_UNDERLINE_SINGLE;
+ break;
+
+ case PANGO_UNDERLINE_SINGLE:
+ uline = PANGO_UNDERLINE_DOUBLE;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (uline != PANGO_UNDERLINE_NONE)
+ add_attr (attr_list, pango_attr_underline_new (celltext->underline_style));
+
+ if (celltext->rise_set)
+ add_attr (attr_list, pango_attr_rise_new (celltext->rise));
+
+ if (priv->ellipsize_set)
+ pango_layout_set_ellipsize (layout, priv->ellipsize);
+ else
+ pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE);
+
+ if (priv->wrap_width != -1)
+ {
+ pango_layout_set_width (layout, priv->wrap_width * PANGO_SCALE);
+ pango_layout_set_wrap (layout, priv->wrap_mode);
+ }
+ else
+ {
+ pango_layout_set_width (layout, -1);
+ pango_layout_set_wrap (layout, PANGO_WRAP_CHAR);
+ }
+
+ if (priv->align_set)
+ pango_layout_set_alignment (layout, priv->align);
+ else
+ {
+ PangoAlignment align;
+
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+ align = PANGO_ALIGN_RIGHT;
+ else
+ align = PANGO_ALIGN_LEFT;
+
+ pango_layout_set_alignment (layout, align);
+ }
+
+ pango_layout_set_attributes (layout, attr_list);
+
+ pango_attr_list_unref (attr_list);
+
+ return layout;
+}
+
+static void
+get_size (GtkCellRenderer *cell,
+ GtkWidget *widget,
+ GdkRectangle *cell_area,
+ PangoLayout *layout,
+ gint *x_offset,
+ gint *y_offset,
+ gint *width,
+ gint *height)
+{
+ GhbCellRendererText *celltext = (GhbCellRendererText *) cell;
+ PangoRectangle rect;
+ GhbCellRendererTextPrivate *priv;
+
+ priv = GHB_CELL_RENDERER_TEXT_GET_PRIVATE (cell);
+
+ if (celltext->calc_fixed_height)
+ {
+ PangoContext *context;
+ PangoFontMetrics *metrics;
+ PangoFontDescription *font_desc;
+ gint row_height;
+
+ font_desc = pango_font_description_copy_static (widget->style->font_desc);
+ pango_font_description_merge_static (font_desc, celltext->font, TRUE);
+
+ if (celltext->scale_set)
+ pango_font_description_set_size (font_desc,
+ celltext->font_scale * pango_font_description_get_size (font_desc));
+
+ context = gtk_widget_get_pango_context (widget);
+
+ metrics = pango_context_get_metrics (context,
+ font_desc,
+ pango_context_get_language (context));
+ row_height = (pango_font_metrics_get_ascent (metrics) +
+ pango_font_metrics_get_descent (metrics));
+ pango_font_metrics_unref (metrics);
+
+ pango_font_description_free (font_desc);
+
+ gtk_cell_renderer_set_fixed_size (cell,
+ cell->width, 2*cell->ypad +
+ celltext->fixed_height_rows * PANGO_PIXELS (row_height));
+
+ if (height)
+ {
+ *height = cell->height;
+ height = NULL;
+ }
+ celltext->calc_fixed_height = FALSE;
+ if (width == NULL)
+ return;
+ }
+
+ if (layout)
+ g_object_ref (layout);
+ else
+ layout = get_layout (celltext, widget, FALSE, 0);
+
+ pango_layout_get_extents (layout, NULL, &rect);
+ pango_extents_to_pixels (&rect, NULL);
+
+ if (height)
+ *height = cell->ypad * 2 + rect.height;
+
+ /* The minimum size for ellipsized labels is ~ 3 chars */
+ if (width)
+ {
+ if (priv->ellipsize || priv->width_chars > 0)
+ {
+ PangoContext *context;
+ PangoFontMetrics *metrics;
+ gint char_width;
+
+ context = pango_layout_get_context (layout);
+ metrics = pango_context_get_metrics (context, widget->style->font_desc, pango_context_get_language (context));
+
+ char_width = pango_font_metrics_get_approximate_char_width (metrics);
+ pango_font_metrics_unref (metrics);
+
+ *width = cell->xpad * 2 + (PANGO_PIXELS (char_width) * MAX (priv->width_chars, 3));
+ }
+ else
+ {
+ *width = cell->xpad * 2 + rect.x + rect.width;
+ }
+ }
+
+ if (cell_area)
+ {
+ if (x_offset)
+ {
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+ *x_offset = (1.0 - cell->xalign) * (cell_area->width - (rect.x + rect.width + (2 * cell->xpad)));
+ else
+ *x_offset = cell->xalign * (cell_area->width - (rect.x + rect.width + (2 * cell->xpad)));
+
+ if ((priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE) || priv->wrap_width != -1)
+ *x_offset = MAX(*x_offset, 0);
+ }
+ if (y_offset)
+ {
+ *y_offset = cell->yalign * (cell_area->height - (rect.height + (2 * cell->ypad)));
+ *y_offset = MAX (*y_offset, 0);
+ }
+ }
+ else
+ {
+ if (x_offset) *x_offset = 0;
+ if (y_offset) *y_offset = 0;
+ }
+
+ g_object_unref (layout);
+}
+
+
+static void
+ghb_cell_renderer_text_get_size (GtkCellRenderer *cell,
+ GtkWidget *widget,
+ GdkRectangle *cell_area,
+ gint *x_offset,
+ gint *y_offset,
+ gint *width,
+ gint *height)
+{
+ get_size (cell, widget, cell_area, NULL,
+ x_offset, y_offset, width, height);
+}
+
+static void
+ghb_cell_renderer_text_render (GtkCellRenderer *cell,
+ GdkDrawable *window,
+ GtkWidget *widget,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GdkRectangle *expose_area,
+ GtkCellRendererState flags)
+
+{
+ GhbCellRendererText *celltext = (GhbCellRendererText *) cell;
+ PangoLayout *layout;
+ GtkStateType state;
+ gint x_offset;
+ gint y_offset;
+ GhbCellRendererTextPrivate *priv;
+
+ priv = GHB_CELL_RENDERER_TEXT_GET_PRIVATE (cell);
+
+ layout = get_layout (celltext, widget, TRUE, flags);
+ get_size (cell, widget, cell_area, layout, &x_offset, &y_offset, NULL, NULL);
+
+ if (!cell->sensitive)
+ {
+ state = GTK_STATE_INSENSITIVE;
+ }
+ else if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED)
+ {
+ if (GTK_WIDGET_HAS_FOCUS (widget))
+ state = GTK_STATE_SELECTED;
+ else
+ state = GTK_STATE_ACTIVE;
+ }
+ else if ((flags & GTK_CELL_RENDERER_PRELIT) == GTK_CELL_RENDERER_PRELIT &&
+ GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT)
+ {
+ state = GTK_STATE_PRELIGHT;
+ }
+ else
+ {
+ if (GTK_WIDGET_STATE (widget) == GTK_STATE_INSENSITIVE)
+ state = GTK_STATE_INSENSITIVE;
+ else
+ state = GTK_STATE_NORMAL;
+ }
+
+ if (celltext->background_set &&
+ (flags & GTK_CELL_RENDERER_SELECTED) == 0)
+ {
+ cairo_t *cr = gdk_cairo_create (window);
+
+ if (expose_area)
+ {
+ gdk_cairo_rectangle (cr, expose_area);
+ cairo_clip (cr);
+ }
+
+ gdk_cairo_rectangle (cr, background_area);
+ cairo_set_source_rgb (cr,
+ celltext->background.red / 65535.,
+ celltext->background.green / 65535.,
+ celltext->background.blue / 65535.);
+ cairo_fill (cr);
+
+ cairo_destroy (cr);
+ }
+
+ if (priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE)
+ pango_layout_set_width (layout,
+ (cell_area->width - x_offset - 2 * cell->xpad) * PANGO_SCALE);
+ else if (priv->wrap_width == -1)
+ pango_layout_set_width (layout, -1);
+
+ gtk_paint_layout (widget->style,
+ window,
+ state,
+ TRUE,
+ expose_area,
+ widget,
+ "cellrenderertext",
+ cell_area->x + x_offset + cell->xpad,
+ cell_area->y + y_offset + cell->ypad,
+ layout);
+
+ g_object_unref (layout);
+}
+
+static gboolean
+ghb_cell_renderer_text_keypress(
+ GtkCellEditable *entry,
+ GdkEventKey *event,
+ gpointer data)
+{
+ gboolean result;
+ g_signal_emit(
+ data, text_cell_renderer_signals[KEYPRESS], 0, event, &result);
+ return result;
+}
+
+static void
+ghb_cell_renderer_text_editing_done (GtkCellEditable *entry,
+ gpointer data)
+{
+ const gchar *path;
+ const gchar *new_text;
+ GhbCellRendererTextPrivate *priv;
+
+ priv = GHB_CELL_RENDERER_TEXT_GET_PRIVATE (data);
+
+ priv->entry = NULL;
+
+ if (priv->focus_out_id > 0)
+ {
+ g_signal_handler_disconnect (entry, priv->focus_out_id);
+ priv->focus_out_id = 0;
+ }
+
+ if (priv->populate_popup_id > 0)
+ {
+ g_signal_handler_disconnect (entry, priv->populate_popup_id);
+ priv->populate_popup_id = 0;
+ }
+
+ if (priv->entry_menu_popdown_timeout)
+ {
+ g_source_remove (priv->entry_menu_popdown_timeout);
+ priv->entry_menu_popdown_timeout = 0;
+ }
+
+ gtk_cell_renderer_stop_editing (GTK_CELL_RENDERER (data),
+ GTK_ENTRY (entry)->editing_canceled);
+ if (GTK_ENTRY (entry)->editing_canceled)
+ return;
+
+ path = g_object_get_data (G_OBJECT (entry), GHB_CELL_RENDERER_TEXT_PATH);
+ new_text = gtk_entry_get_text (GTK_ENTRY (entry));
+
+ g_signal_emit (data, text_cell_renderer_signals[EDITED], 0, path, new_text);
+}
+
+static gboolean
+popdown_timeout (gpointer data)
+{
+ GhbCellRendererTextPrivate *priv;
+
+ priv = GHB_CELL_RENDERER_TEXT_GET_PRIVATE (data);
+
+ priv->entry_menu_popdown_timeout = 0;
+
+ if (!GTK_WIDGET_HAS_FOCUS (priv->entry))
+ ghb_cell_renderer_text_editing_done (GTK_CELL_EDITABLE (priv->entry), data);
+
+ return FALSE;
+}
+
+static void
+ghb_cell_renderer_text_popup_unmap (GtkMenu *menu,
+ gpointer data)
+{
+ GhbCellRendererTextPrivate *priv;
+
+ priv = GHB_CELL_RENDERER_TEXT_GET_PRIVATE (data);
+
+ priv->in_entry_menu = FALSE;
+
+ if (priv->entry_menu_popdown_timeout)
+ return;
+
+ priv->entry_menu_popdown_timeout = gdk_threads_add_timeout (500, popdown_timeout,
+ data);
+}
+
+static void
+ghb_cell_renderer_text_populate_popup (GtkEntry *entry,
+ GtkMenu *menu,
+ gpointer data)
+{
+ GhbCellRendererTextPrivate *priv;
+
+ priv = GHB_CELL_RENDERER_TEXT_GET_PRIVATE (data);
+
+ if (priv->entry_menu_popdown_timeout)
+ {
+ g_source_remove (priv->entry_menu_popdown_timeout);
+ priv->entry_menu_popdown_timeout = 0;
+ }
+
+ priv->in_entry_menu = TRUE;
+
+ g_signal_connect (menu, "unmap",
+ G_CALLBACK (ghb_cell_renderer_text_popup_unmap), data);
+}
+
+static gboolean
+ghb_cell_renderer_text_focus_out_event (GtkWidget *entry,
+ GdkEvent *event,
+ gpointer data)
+{
+ GhbCellRendererTextPrivate *priv;
+
+ priv = GHB_CELL_RENDERER_TEXT_GET_PRIVATE (data);
+
+ if (priv->in_entry_menu)
+ return FALSE;
+
+ GTK_ENTRY (entry)->editing_canceled = TRUE;
+ gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry));
+ gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry));
+
+ /* entry needs focus-out-event */
+ return FALSE;
+}
+
+static GtkCellEditable *
+ghb_cell_renderer_text_start_editing (GtkCellRenderer *cell,
+ GdkEvent *event,
+ GtkWidget *widget,
+ const gchar *path,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GtkCellRendererState flags)
+{
+ GtkRequisition requisition;
+ GhbCellRendererText *celltext;
+ GhbCellRendererTextPrivate *priv;
+
+ celltext = GHB_CELL_RENDERER_TEXT (cell);
+ priv = GHB_CELL_RENDERER_TEXT_GET_PRIVATE (cell);
+
+ /* If the cell isn't editable we return NULL. */
+ if (celltext->editable == FALSE)
+ return NULL;
+
+ priv->entry = g_object_new (GTK_TYPE_ENTRY,
+ "has-frame", FALSE,
+ "xalign", cell->xalign,
+ NULL);
+
+ if (celltext->text)
+ gtk_entry_set_text (GTK_ENTRY (priv->entry), celltext->text);
+ g_object_set_data_full (G_OBJECT (priv->entry), I_(GHB_CELL_RENDERER_TEXT_PATH), g_strdup (path), g_free);
+
+ gtk_editable_select_region (GTK_EDITABLE (priv->entry), 0, -1);
+
+ gtk_widget_size_request (priv->entry, &requisition);
+ if (requisition.height < cell_area->height)
+ {
+ GtkBorder *style_border;
+ GtkBorder border;
+
+ gtk_widget_style_get (priv->entry,
+ "inner-border", &style_border,
+ NULL);
+
+ if (style_border)
+ {
+ border = *style_border;
+ g_boxed_free (GTK_TYPE_BORDER, style_border);
+ }
+ else
+ {
+ /* Since boxed style properties can't have default values ... */
+ border.left = 2;
+ border.right = 2;
+ }
+
+ border.top = (cell_area->height - requisition.height) / 2;
+ border.bottom = (cell_area->height - requisition.height) / 2;
+ gtk_entry_set_inner_border (GTK_ENTRY (priv->entry), &border);
+ }
+
+ priv->in_entry_menu = FALSE;
+ if (priv->entry_menu_popdown_timeout)
+ {
+ g_source_remove (priv->entry_menu_popdown_timeout);
+ priv->entry_menu_popdown_timeout = 0;
+ }
+
+ g_signal_connect (priv->entry,
+ "key-press-event",
+ G_CALLBACK (ghb_cell_renderer_text_keypress),
+ celltext);
+ g_signal_connect (priv->entry,
+ "editing_done",
+ G_CALLBACK (ghb_cell_renderer_text_editing_done),
+ celltext);
+ priv->focus_out_id = g_signal_connect_after (priv->entry, "focus_out_event",
+ G_CALLBACK (ghb_cell_renderer_text_focus_out_event),
+ celltext);
+ priv->populate_popup_id =
+ g_signal_connect (priv->entry, "populate_popup",
+ G_CALLBACK (ghb_cell_renderer_text_populate_popup),
+ celltext);
+
+ gtk_widget_show (priv->entry);
+
+ return GTK_CELL_EDITABLE (priv->entry);
+}
+
+/**
+ * ghb_cell_renderer_text_set_fixed_height_from_font:
+ * @renderer: A #GhbCellRendererText
+ * @number_of_rows: Number of rows of text each cell renderer is allocated, or -1
+ *
+ * Sets the height of a renderer to explicitly be determined by the "font" and
+ * "y_pad" property set on it. Further changes in these properties do not
+ * affect the height, so they must be accompanied by a subsequent call to this
+ * function. Using this function is unflexible, and should really only be used
+ * if calculating the size of a cell is too slow (ie, a massive number of cells
+ * displayed). If @number_of_rows is -1, then the fixed height is unset, and
+ * the height is determined by the properties again.
+ **/
+void
+ghb_cell_renderer_text_set_fixed_height_from_font (GhbCellRendererText *renderer,
+ gint number_of_rows)
+{
+ g_return_if_fail (GHB_IS_CELL_RENDERER_TEXT (renderer));
+ g_return_if_fail (number_of_rows == -1 || number_of_rows > 0);
+
+ if (number_of_rows == -1)
+ {
+ gtk_cell_renderer_set_fixed_size (GTK_CELL_RENDERER (renderer),
+ GTK_CELL_RENDERER (renderer)->width,
+ -1);
+ }
+ else
+ {
+ renderer->fixed_height_rows = number_of_rows;
+ renderer->calc_fixed_height = TRUE;
+ }
+}
+
diff --git a/gtk/src/ghbcellrenderertext.h b/gtk/src/ghbcellrenderertext.h
new file mode 100644
index 000000000..0e12ba17a
--- /dev/null
+++ b/gtk/src/ghbcellrenderertext.h
@@ -0,0 +1,105 @@
+/* gtkcellrenderertext.h
+ * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GHB_CELL_RENDERER_TEXT_H__
+#define __GHB_CELL_RENDERER_TEXT_H__
+
+#include <pango/pango.h>
+#include <gtk/gtkcellrenderer.h>
+
+
+G_BEGIN_DECLS
+
+
+#define GHB_TYPE_CELL_RENDERER_TEXT (ghb_cell_renderer_text_get_type ())
+#define GHB_CELL_RENDERER_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GHB_TYPE_CELL_RENDERER_TEXT, GhbCellRendererText))
+#define GHB_CELL_RENDERER_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GHB_TYPE_CELL_RENDERER_TEXT, GhbCellRendererTextClass))
+#define GHB_IS_CELL_RENDERER_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GHB_TYPE_CELL_RENDERER_TEXT))
+#define GHB_IS_CELL_RENDERER_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GHB_TYPE_CELL_RENDERER_TEXT))
+#define GHB_CELL_RENDERER_TEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GHB_TYPE_CELL_RENDERER_TEXT, GhbCellRendererTextClass))
+
+typedef struct _GhbCellRendererText GhbCellRendererText;
+typedef struct _GhbCellRendererTextClass GhbCellRendererTextClass;
+
+struct _GhbCellRendererText
+{
+ GtkCellRenderer parent;
+
+ /*< private >*/
+ gchar *text;
+ PangoFontDescription *font;
+ gdouble font_scale;
+ PangoColor foreground;
+ PangoColor background;
+
+ PangoAttrList *extra_attrs;
+
+ PangoUnderline underline_style;
+
+ gint rise;
+ gint fixed_height_rows;
+
+ guint strikethrough : 1;
+
+ guint editable : 1;
+
+ guint scale_set : 1;
+
+ guint foreground_set : 1;
+ guint background_set : 1;
+
+ guint underline_set : 1;
+
+ guint rise_set : 1;
+
+ guint strikethrough_set : 1;
+
+ guint editable_set : 1;
+ guint calc_fixed_height : 1;
+};
+
+struct _GhbCellRendererTextClass
+{
+ GtkCellRendererClass parent_class;
+
+ void (* edited) (GhbCellRendererText *cell_renderer_text,
+ const gchar *path,
+ const gchar *new_text);
+
+ gboolean (* keypress) (GhbCellRendererText *cell_renderer_text,
+ GdkEventKey *event);
+
+ /* Padding for future expansion */
+ void (*_gtk_reserved1) (void);
+ void (*_gtk_reserved2) (void);
+ void (*_gtk_reserved3) (void);
+ void (*_gtk_reserved4) (void);
+};
+
+GType ghb_cell_renderer_text_get_type (void) G_GNUC_CONST;
+GtkCellRenderer *ghb_cell_renderer_text_new (void);
+
+void ghb_cell_renderer_text_set_fixed_height_from_font (GhbCellRendererText *renderer,
+ gint number_of_rows);
+
+
+G_END_DECLS
+
+
+#endif /* __GHB_CELL_RENDERER_TEXT_H__ */
diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c
index 7edeb4ca5..eb60ad95a 100644
--- a/gtk/src/hb-backend.c
+++ b/gtk/src/hb-backend.c
@@ -46,7 +46,6 @@ typedef struct
{
gint count;
options_map_t *map;
- gint *grey_options;
} combo_opts_t;
static options_map_t d_container_opts[] =
@@ -445,21 +444,120 @@ ghb_vquality_range(signal_user_data_t *ud, gint *min, gint *max)
}
gint
+ghb_lookup_vrate(const GValue *vrate)
+{
+ gint ii;
+ gchar *str;
+ gint result = 0;
+
+ str = ghb_value_string(vrate);
+ for (ii = 0; ii < hb_video_rates_count; ii++)
+ {
+ if (strcmp(hb_video_rates[ii].string, str) == 0)
+ {
+ result = hb_video_rates[ii].rate;
+ }
+ }
+ g_free(str);
+ // Default to "same as source"
+ return result;
+}
+
+gint
+ghb_lookup_vcodec(const GValue *vcodec)
+{
+ gint ii;
+ gchar *str;
+ gint result = HB_VCODEC_FFMPEG;
+
+ str = ghb_value_string(vcodec);
+ for (ii = 0; ii < vcodec_opts.count; ii++)
+ {
+ if (strcmp(vcodec_opts.map[ii].shortOpt, str) == 0)
+ {
+ result = vcodec_opts.map[ii].ivalue;
+ }
+ }
+ g_free(str);
+ return result;
+}
+
+gint
+ghb_lookup_denoise(const GValue *denoise)
+{
+ gint ii;
+ gchar *str;
+ gint result = -1;
+
+ str = ghb_value_string(denoise);
+ for (ii = 0; ii < denoise_opts.count; ii++)
+ {
+ if (strcmp(denoise_opts.map[ii].shortOpt, str) == 0)
+ {
+ result = denoise_opts.map[ii].ivalue;
+ }
+ }
+ g_free(str);
+ // Custom
+ return result;
+}
+
+gint
+ghb_lookup_deint(const GValue *deint)
+{
+ gint ii;
+ gchar *str;
+ gint result = -1;
+
+ str = ghb_value_string(deint);
+ for (ii = 0; ii < deint_opts.count; ii++)
+ {
+ if (strcmp(deint_opts.map[ii].shortOpt, str) == 0)
+ {
+ result = deint_opts.map[ii].ivalue;
+ }
+ }
+ g_free(str);
+ // Custom
+ return result;
+}
+
+gint
+ghb_lookup_mux(const GValue *mux)
+{
+ gint ii;
+ gchar *str;
+ gint result = HB_MUX_MKV;
+
+ str = ghb_value_string(mux);
+ for (ii = 0; ii < container_opts.count; ii++)
+ {
+ if (strcmp(container_opts.map[ii].shortOpt, str) == 0)
+ {
+ result = container_opts.map[ii].ivalue;
+ }
+ }
+ g_free(str);
+ return result;
+}
+
+gint
ghb_lookup_acodec(const GValue *acodec)
{
gint ii;
gchar *str;
+ gint result = HB_ACODEC_FAAC;
str = ghb_value_string(acodec);
for (ii = 0; ii < acodec_opts.count; ii++)
{
if (strcmp(acodec_opts.map[ii].shortOpt, str) == 0)
{
- return acodec_opts.map[ii].ivalue;
+ result = acodec_opts.map[ii].ivalue;
}
}
g_free(str);
- return HB_ACODEC_FAAC;
+ return result;
}
gint
@@ -467,17 +565,19 @@ ghb_lookup_mix(const GValue *mix)
{
gint ii;
gchar *str;
+ gint result = HB_AMIXDOWN_DOLBYPLII;
+
str = ghb_value_string(mix);
for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
{
if (strcmp(hb_audio_mixdowns[ii].short_name, str) == 0)
{
- return hb_audio_mixdowns[ii].amixdown;
+ result = hb_audio_mixdowns[ii].amixdown;
}
}
g_free(str);
- return HB_AMIXDOWN_DOLBYPLII;
+ return result;
}
#if 0
@@ -569,7 +669,8 @@ get_amix_value(gint val)
}
// Handle for libhb. Gets set by ghb_backend_init()
-static hb_handle_t * h = NULL;
+static hb_handle_t * h_scan = NULL;
+static hb_handle_t * h_queue = NULL;
extern void hb_get_tempory_directory(hb_handle_t *h, char path[512]);
@@ -578,7 +679,7 @@ ghb_hb_cleanup(gboolean partial)
{
char dir[512];
- hb_get_tempory_directory(h, dir);
+ hb_get_tempory_directory(h_scan, dir);
del_tree(dir, !partial);
}
@@ -589,8 +690,8 @@ get_hb_audio(gint titleindex, gint track)
hb_title_t * title;
hb_audio_config_t *audio = NULL;
- if (h == NULL) return NULL;
- list = hb_get_titles( h );
+ if (h_scan == NULL) return NULL;
+ list = hb_get_titles( h_scan );
if( !hb_list_count( list ) )
{
/* No valid title, stop right there */
@@ -1066,9 +1167,9 @@ title_opts_set(GtkBuilder *builder, const gchar *name)
g_debug("title_opts_set ()\n");
store = get_combo_box_store(builder, name);
gtk_list_store_clear(store);
- if (h != NULL)
+ if (h_scan != NULL)
{
- list = hb_get_titles( h );
+ list = hb_get_titles( h_scan );
count = hb_list_count( list );
if (count > 100) count = 100;
}
@@ -1170,9 +1271,9 @@ audio_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex)
g_debug("audio_track_opts_set ()\n");
store = get_combo_box_store(builder, name);
gtk_list_store_clear(store);
- if (h != NULL)
+ if (h_scan != NULL)
{
- list = hb_get_titles( h );
+ list = hb_get_titles( h_scan );
title = (hb_title_t*)hb_list_item( list, titleindex );
if (title != NULL)
{
@@ -1221,9 +1322,9 @@ subtitle_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex)
g_debug("subtitle_opts_set ()\n");
store = get_combo_box_store(builder, name);
gtk_list_store_clear(store);
- if (h != NULL)
+ if (h_scan != NULL)
{
- list = hb_get_titles( h );
+ list = hb_get_titles( h_scan );
title = (hb_title_t*)hb_list_item( list, titleindex );
if (title != NULL)
{
@@ -1287,8 +1388,8 @@ ghb_longest_title()
gint titleindex = 0;
g_debug("ghb_longest_title ()\n");
- if (h == NULL) return 0;
- list = hb_get_titles( h );
+ if (h_scan == NULL) return 0;
+ list = hb_get_titles( h_scan );
count = hb_list_count( list );
if (count > 100) count = 100;
for (ii = 0; ii < count; ii++)
@@ -1315,9 +1416,9 @@ ghb_find_audio_track(gint titleindex, const gchar *lang, gint index)
gint match = 0;
g_debug("find_audio_track ()\n");
- if (h != NULL)
+ if (h_scan != NULL)
{
- list = hb_get_titles( h );
+ list = hb_get_titles( h_scan );
title = (hb_title_t*)hb_list_item( list, titleindex );
if (title != NULL)
{
@@ -1495,8 +1596,8 @@ ghb_get_chapters(gint titleindex)
GValue *chapters = NULL;
g_debug("ghb_get_chapters (title = %d)\n", titleindex);
- if (h == NULL) return NULL;
- list = hb_get_titles( h );
+ if (h_scan == NULL) return NULL;
+ list = hb_get_titles( h_scan );
title = (hb_title_t*)hb_list_item( list, titleindex );
if (title == NULL) return NULL;
count = hb_list_count( title->list_chapter );
@@ -1561,7 +1662,8 @@ void
ghb_backend_init(GtkBuilder *builder, gint debug, gint update)
{
/* Init libhb */
- h = hb_init( debug, update );
+ h_scan = hb_init( debug, update );
+ h_queue = hb_init( debug, 0 );
// Set up the list model for the combos
init_ui_combo_boxes(builder);
// Populate all the combos
@@ -1571,7 +1673,7 @@ ghb_backend_init(GtkBuilder *builder, gint debug, gint update)
void
ghb_backend_scan(const gchar *path, gint titleindex)
{
- hb_scan( h, path, titleindex );
+ hb_scan( h_scan, path, titleindex );
hb_status.state |= GHB_STATE_SCANNING;
// initialize count and cur to something that won't cause FPE
// when computing progress
@@ -1579,12 +1681,26 @@ ghb_backend_scan(const gchar *path, gint titleindex)
hb_status.title_cur = 0;
}
+void
+ghb_backend_queue_scan(const gchar *path, gint titleindex)
+{
+ g_debug("ghb_backend_queue_scan()");
+ hb_scan( h_queue, path, titleindex );
+ hb_status.queue_state |= GHB_STATE_SCANNING;
+}
+
gint
ghb_get_state()
{
return hb_status.state;
}
+gint
+ghb_get_queue_state()
+{
+ return hb_status.queue_state;
+}
+
void
ghb_clear_state(gint state)
{
@@ -1592,12 +1708,24 @@ ghb_clear_state(gint state)
}
void
+ghb_clear_queue_state(gint state)
+{
+ hb_status.queue_state &= ~state;
+}
+
+void
ghb_set_state(gint state)
{
hb_status.state |= state;
}
void
+ghb_set_queue_state(gint state)
+{
+ hb_status.queue_state |= state;
+}
+
+void
ghb_get_status(ghb_status_t *status)
{
memcpy(status, &hb_status, sizeof(ghb_status_t));
@@ -1607,24 +1735,12 @@ void
ghb_track_status()
{
hb_state_t s;
- static gint scan_complete_count = 0;
- gint scans;
+ hb_state_t s_queue;
- if (h == NULL) return;
- hb_get_state( h, &s );
- scans = hb_get_scancount(h);
- if (scans > scan_complete_count)
- {
- hb_status.state &= ~GHB_STATE_SCANNING;
- hb_status.state |= GHB_STATE_SCANDONE;
- scan_complete_count = hb_get_scancount(h);
- }
+ if (h_scan == NULL) return;
+ hb_get_state( h_scan, &s );
switch( s.state )
{
- case HB_STATE_IDLE:
- /* Nothing to do */
- break;
-
#define p s.param.scanning
case HB_STATE_SCANNING:
{
@@ -1640,10 +1756,25 @@ ghb_track_status()
hb_status.state |= GHB_STATE_SCANDONE;
} break;
-#define p s.param.working
+ }
+ hb_get_state( h_queue, &s_queue );
+ switch( s_queue.state )
+ {
+ case HB_STATE_SCANNING:
+ {
+ hb_status.queue_state |= GHB_STATE_SCANNING;
+ } break;
+
+ case HB_STATE_SCANDONE:
+ {
+ hb_status.queue_state &= ~GHB_STATE_SCANNING;
+ hb_status.queue_state |= GHB_STATE_SCANDONE;
+ } break;
+
+#define p s_queue.param.working
case HB_STATE_WORKING:
- hb_status.state |= GHB_STATE_WORKING;
- hb_status.state &= ~GHB_STATE_PAUSED;
+ hb_status.queue_state |= GHB_STATE_WORKING;
+ hb_status.queue_state &= ~GHB_STATE_PAUSED;
hb_status.job_cur = p.job_cur;
hb_status.job_count = p.job_count;
hb_status.progress = p.progress;
@@ -1657,25 +1788,23 @@ ghb_track_status()
#undef p
case HB_STATE_PAUSED:
- hb_status.state |= GHB_STATE_PAUSED;
+ hb_status.queue_state |= GHB_STATE_PAUSED;
break;
-#define p s.param.muxing
case HB_STATE_MUXING:
{
- hb_status.state |= GHB_STATE_MUXING;
+ hb_status.queue_state |= GHB_STATE_MUXING;
} break;
-#undef p
-#define p s.param.workdone
+#define p s_queue.param.workdone
case HB_STATE_WORKDONE:
{
hb_job_t *job;
- hb_status.state |= GHB_STATE_WORKDONE;
- hb_status.state &= ~GHB_STATE_MUXING;
- hb_status.state &= ~GHB_STATE_PAUSED;
- hb_status.state &= ~GHB_STATE_WORKING;
+ hb_status.queue_state |= GHB_STATE_WORKDONE;
+ hb_status.queue_state &= ~GHB_STATE_MUXING;
+ hb_status.queue_state &= ~GHB_STATE_PAUSED;
+ hb_status.queue_state &= ~GHB_STATE_WORKING;
switch (p.error)
{
case HB_ERROR_NONE:
@@ -1691,8 +1820,8 @@ ghb_track_status()
// When a job is stopped, libhb removes it from the job list,
// but does not remove other jobs that may be associated with it.
// Associated jobs are taged in the sequence id.
- while (((job = hb_job(h, 0)) != NULL) && ((job->sequence_id >> 24) != 0) )
- hb_rem( h, job );
+ while ((job = hb_job(h_queue, 0)) != NULL)
+ hb_rem( h_queue, job );
} break;
#undef p
}
@@ -1704,8 +1833,8 @@ ghb_get_title_info(ghb_title_info_t *tinfo, gint titleindex)
hb_list_t * list;
hb_title_t * title;
- if (h == NULL) return FALSE;
- list = hb_get_titles( h );
+ if (h_scan == NULL) return FALSE;
+ list = hb_get_titles( h_scan );
if( !hb_list_count( list ) )
{
/* No valid title, stop right there */
@@ -1784,8 +1913,8 @@ ghb_set_scale(signal_user_data_t *ud, gint mode)
g_debug("ghb_set_scale ()\n");
- if (h == NULL) return;
- list = hb_get_titles( h );
+ if (h_scan == NULL) return;
+ list = hb_get_titles( h_scan );
if( !hb_list_count( list ) )
{
/* No valid title, stop right there */
@@ -2015,8 +2144,8 @@ ghb_calculate_target_bitrate(GValue *settings, gint titleindex)
hb_job_t * job;
gint size;
- if (h == NULL) return 2000;
- list = hb_get_titles( h );
+ if (h_scan == NULL) return 2000;
+ list = hb_get_titles( h_scan );
title = hb_list_item( list, titleindex );
if (title == NULL) return 2000;
job = title->job;
@@ -2070,26 +2199,28 @@ gboolean
ghb_validate_filter_string(const gchar *str, gint max_fields)
{
gint fields = 0;
- gboolean in_field = FALSE;
+ gchar *end;
+ gdouble val;
+
if (str == NULL || *str == 0) return TRUE;
while (*str)
{
- if (*str >= '0' && *str <= '9')
- {
- if (!in_field)
- {
- fields++;
- // negative max_fields means infinate
- if (max_fields >= 0 && fields > max_fields) return FALSE;
- in_field = TRUE;
- }
+ val = g_strtod(str, &end);
+ if (str != end)
+ { // Found a numeric value
+ fields++;
+ // negative max_fields means infinate
+ if (max_fields >= 0 && fields > max_fields) return FALSE;
+ if (*end == 0)
+ return TRUE;
+ if (*end != ':')
+ return FALSE;
+ str = end + 1;
}
- else if (!in_field) return FALSE;
- else if (*str != ':') return FALSE;
- else in_field = FALSE;
- str++;
+ else
+ return FALSE;
}
- return TRUE;
+ return FALSE;
}
gboolean
@@ -2136,7 +2267,7 @@ ghb_validate_filters(signal_user_data_t *ud)
index = ghb_settings_get_combo_index(ud->settings, "tweak_deinterlace");
if (index < 0)
{
- str = ghb_settings_get_combo_string(ud->settings, "tweak_deinterlace");
+ str = ghb_settings_get_string(ud->settings, "tweak_deinterlace");
if (!ghb_validate_filter_string(str, 4))
{
message = g_strdup_printf(
@@ -2167,7 +2298,7 @@ ghb_validate_filters(signal_user_data_t *ud)
index = ghb_settings_get_combo_index(ud->settings, "tweak_denoise");
if (index < 0)
{
- str = ghb_settings_get_combo_string(ud->settings, "tweak_denoise");
+ str = ghb_settings_get_string(ud->settings, "tweak_denoise");
if (!ghb_validate_filter_string(str, 4))
{
message = g_strdup_printf(
@@ -2284,8 +2415,8 @@ ghb_validate_audio(signal_user_data_t *ud)
gchar *message;
GValue *value;
- if (h == NULL) return FALSE;
- list = hb_get_titles( h );
+ if (h_scan == NULL) return FALSE;
+ list = hb_get_titles( h_scan );
if( !hb_list_count( list ) )
{
/* No valid title, stop right there */
@@ -2542,8 +2673,8 @@ ghb_add_job(GValue *js, gint unique_id)
gchar *dest_str = NULL;
g_debug("ghb_add_job()\n");
- if (h == NULL) return;
- list = hb_get_titles( h );
+ if (h_queue == NULL) return;
+ list = hb_get_titles( h_queue );
if( !hb_list_count( list ) )
{
/* No valid title, stop right there */
@@ -2551,7 +2682,10 @@ ghb_add_job(GValue *js, gint unique_id)
return;
}
- gint titleindex = ghb_settings_get_int(js, "title");
+ // Since I'm doing a scan of the single title I want just prior
+ // to adding the job, there is only the one title to choose from.
+ //gint titleindex = ghb_settings_get_int(js, "title");
+ gint titleindex = 0;
title = hb_list_item( list, titleindex );
if (title == NULL) return;
@@ -2560,7 +2694,7 @@ ghb_add_job(GValue *js, gint unique_id)
if (job == NULL) return;
tweaks = ghb_settings_get_int(js, "allow_tweaks");
- job->mux = ghb_settings_get_int(js, "container");
+ job->mux = ghb_lookup_mux(ghb_settings_get_value(js, "container"));
if (job->mux == HB_MUX_MP4)
{
job->largeFileSize = ghb_settings_get_boolean(js, "large_mp4");
@@ -2616,10 +2750,10 @@ ghb_add_job(GValue *js, gint unique_id)
gboolean decomb = ghb_settings_get_boolean(js, "decomb");
- gint deint = ghb_settings_get_int(
- js, tweaks ? "tweak_deinterlace":"deinterlace");
+ gint deint = ghb_lookup_deint(
+ ghb_settings_get_value(js, tweaks ? "tweak_deinterlace":"deinterlace"));
if (!decomb)
- job->deinterlace = (deint == 0) ? 0 : 1;
+ job->deinterlace = (deint != 0) ? 1 : 0;
else
job->deinterlace = 0;
job->grayscale = ghb_settings_get_boolean(js, "grayscale");
@@ -2677,7 +2811,10 @@ ghb_add_job(GValue *js, gint unique_id)
}
if( job->deinterlace )
{
- deint_str = ghb_settings_get_combo_string(js,
+ if (deint > 0)
+ deint_str = g_strdup(deint_opts.map[deint].svalue);
+ else
+ deint_str = ghb_settings_get_string(js,
tweaks ? "tweak_deinterlace" : "deinterlace");
hb_filter_deinterlace.settings = deint_str;
hb_list_add( job->filters, &hb_filter_deinterlace );
@@ -2695,19 +2832,22 @@ ghb_add_job(GValue *js, gint unique_id)
}
hb_list_add( job->filters, &hb_filter_deblock );
}
- gint denoise = ghb_settings_get_int(
- js, tweaks ? "tweak_denoise" : "denoise");
+ gint denoise = ghb_lookup_denoise(
+ ghb_settings_get_value(js, tweaks ? "tweak_denoise" : "denoise"));
if( denoise != 0 )
{
- denoise_str = (gchar*)ghb_settings_get_combo_string(
- js, tweaks ? "tweak_denoise" : "denoise");
+ if (denoise > 0)
+ denoise_str = g_strdup(denoise_opts.map[denoise].svalue);
+ else
+ denoise_str = (gchar*)ghb_settings_get_string(
+ js, tweaks ? "tweak_denoise" : "denoise");
hb_filter_denoise.settings = denoise_str;
- hb_list_add( job->filters, &hb_filter_deblock );
+ hb_list_add( job->filters, &hb_filter_denoise );
}
job->width = ghb_settings_get_int(js, "scale_width");
job->height = ghb_settings_get_int(js, "scale_height");
- job->vcodec = ghb_settings_get_int(js, "video_codec");
+ job->vcodec = ghb_lookup_vcodec(ghb_settings_get_value(js, "video_codec"));
if ((job->mux == HB_MUX_MP4 || job->mux == HB_MUX_AVI) &&
(job->vcodec == HB_VCODEC_THEORA))
{
@@ -2762,7 +2902,7 @@ ghb_add_job(GValue *js, gint unique_id)
job->vfr = FALSE;
}
- gint vrate = ghb_settings_get_int(js, "framerate");
+ gint vrate = ghb_lookup_vrate(ghb_settings_get_value(js, "framerate"));
if( vrate == 0 || job->vfr )
{
job->vrate = title->rate;
@@ -2801,7 +2941,8 @@ ghb_add_job(GValue *js, gint unique_id)
asettings = ghb_array_get_nth(audio_list, ii);
audio.in.track = ghb_settings_get_int(asettings, "audio_track");
audio.out.track = tcount;
- audio.out.codec = ghb_settings_get_int(asettings, "audio_codec");
+ audio.out.codec = ghb_lookup_acodec(
+ ghb_settings_get_value(asettings, "audio_codec"));
taudio = (hb_audio_config_t *) hb_list_audio_config_item( title->list_audio, audio.in.track );
if ((taudio->in.codec != HB_ACODEC_AC3) && (audio.out.codec == HB_ACODEC_AC3))
{
@@ -2845,11 +2986,13 @@ ghb_add_job(GValue *js, gint unique_id)
}
else
{
- audio.out.mixdown = ghb_settings_get_int (asettings, "audio_mix");
+ audio.out.mixdown = ghb_lookup_mix(
+ ghb_settings_get_value (asettings, "audio_mix"));
// Make sure the mixdown is valid and pick a new one if not.
- audio.out.mixdown = ghb_get_best_mix(titleindex, audio.in.track, audio.out.codec,
- audio.out.mixdown);
- audio.out.bitrate = ghb_settings_get_int(asettings, "audio_bitrate") / 1000;
+ audio.out.mixdown = ghb_get_best_mix(titleindex,
+ audio.in.track, audio.out.codec, audio.out.mixdown);
+ audio.out.bitrate =
+ ghb_settings_get_int(asettings, "audio_bitrate") / 1000;
gint srate = ghb_settings_get_int(asettings, "audio_rate");
if (srate == 0) // 0 is same as source
audio.out.samplerate = taudio->in.samplerate;
@@ -2892,6 +3035,28 @@ ghb_add_job(GValue *js, gint unique_id)
job->x264opts = NULL;
}
gint subtitle = ghb_settings_get_int(js, "subtitle_lang");
+ gchar *slang = ghb_settings_get_string(js, "subtitle_lang");
+ subtitle = -2; // default to none
+ if (strcmp(slang, "auto") == 0)
+ {
+ subtitle = -1;
+ }
+ else
+ {
+ gint scount;
+ hb_subtitle_t * subt;
+
+ scount = hb_list_count(title->list_subtitle);
+ for (ii = 0; ii < scount; ii++)
+ {
+ subt = (hb_subtitle_t *)hb_list_item(title->list_subtitle, ii);
+ if (strcmp(slang, subt->iso639_2) == 0)
+ {
+ subtitle = ii;
+ break;
+ }
+ }
+ }
gboolean forced_subtitles = ghb_settings_get_boolean(js, "forced_subtitles");
job->subtitle_force = forced_subtitles;
if (subtitle >= 0)
@@ -2920,7 +3085,7 @@ ghb_add_job(GValue *js, gint unique_id)
* Add the pre-scan job
*/
job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
- hb_add( h, job );
+ hb_add( h_queue, job );
//if (job->x264opts != NULL)
// g_free(job->x264opts);
@@ -2973,7 +3138,7 @@ ghb_add_job(GValue *js, gint unique_id)
job->x264opts = x264opts;
}
job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
- hb_add( h, job );
+ hb_add( h_queue, job );
//if (job->x264opts != NULL)
// g_free(job->x264opts);
@@ -2988,7 +3153,7 @@ ghb_add_job(GValue *js, gint unique_id)
job->indepth_scan = 0;
job->x264opts = x264opts2;
job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
- hb_add( h, job );
+ hb_add( h_queue, job );
//if (job->x264opts != NULL)
// g_free(job->x264opts);
}
@@ -2997,7 +3162,7 @@ ghb_add_job(GValue *js, gint unique_id)
job->indepth_scan = 0;
job->pass = 0;
job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
- hb_add( h, job );
+ hb_add( h_queue, job );
//if (job->x264opts != NULL)
// g_free(job->x264opts);
}
@@ -3018,39 +3183,39 @@ ghb_remove_job(gint unique_id)
// Multiples passes all get the same id
// remove them all.
// Go backwards through list, so reordering doesn't screw me.
- ii = hb_count(h) - 1;
- while ((job = hb_job(h, ii--)) != NULL)
+ ii = hb_count(h_queue) - 1;
+ while ((job = hb_job(h_queue, ii--)) != NULL)
{
if ((job->sequence_id & 0xFFFFFF) == unique_id)
- hb_rem(h, job);
+ hb_rem(h_queue, job);
}
}
void
ghb_start_queue()
{
- hb_start( h );
+ hb_start( h_queue );
}
void
ghb_stop_queue()
{
- hb_stop( h );
+ hb_stop( h_queue );
}
void
ghb_pause_queue()
{
hb_state_t s;
- hb_get_state2( h, &s );
+ hb_get_state2( h_queue, &s );
if( s.state == HB_STATE_PAUSED )
{
- hb_resume( h );
+ hb_resume( h_queue );
}
else
{
- hb_pause( h );
+ hb_pause( h_queue );
}
}
@@ -3064,7 +3229,7 @@ ghb_get_preview_image(
hb_title_t *title;
hb_list_t *list;
- list = hb_get_titles( h );
+ list = hb_get_titles( h_scan );
if( !hb_list_count( list ) )
{
/* No valid title, stop right there */
@@ -3144,7 +3309,7 @@ ghb_get_preview_image(
bufferSize = newSize;
buffer = (guint8*) g_realloc( buffer, bufferSize );
}
- hb_get_preview( h, title, index, buffer );
+ hb_get_preview( h_scan, title, index, buffer );
// Create an GdkPixbuf and copy the libhb image into it, converting it from
// libhb's format something suitable. Along the way, we'll strip off the
diff --git a/gtk/src/hb-backend.h b/gtk/src/hb-backend.h
index 3e171f1cf..19ba4205b 100644
--- a/gtk/src/hb-backend.h
+++ b/gtk/src/hb-backend.h
@@ -29,6 +29,7 @@ enum
typedef struct ghb_status_s
{
gint state;
+ gint queue_state;
// SCANNING
gint title_count;
@@ -90,10 +91,14 @@ void ghb_pause_queue(void);
gint ghb_get_state(void);
void ghb_clear_state(gint state);
+void ghb_clear_queue_state(gint state);
+
void ghb_set_state(gint state);
+gint ghb_get_queue_state();
void ghb_get_status(ghb_status_t *status);
void ghb_track_status(void);
void ghb_backend_scan(const gchar *path, gint titleindex);
+void ghb_backend_queue_scan(const gchar *path, gint titleindex);
gboolean ghb_get_title_info(ghb_title_info_t *tinfo, gint titleindex);
void ghb_set_scale(signal_user_data_t *ud, gint mode);
GValue* ghb_get_chapters(gint titleindex);
diff --git a/gtk/src/main.c b/gtk/src/main.c
index cc5c20a2e..6cf76ae1c 100644
--- a/gtk/src/main.c
+++ b/gtk/src/main.c
@@ -38,6 +38,7 @@
#include "renderer_button.h"
#include "hb-backend.h"
#include "ghb-dvd.h"
+#include "ghbcellrenderertext.h"
/*
@@ -219,6 +220,7 @@ change_font(GtkWidget *widget, gpointer data)
extern void chapter_list_selection_changed_cb(void);
extern void chapter_edited_cb(void);
+extern void chapter_keypress_cb(void);
// Create and bind the tree model to the tree view for the chapter list
// Also, connect up the signal that lets us know the selection has changed
@@ -237,17 +239,18 @@ bind_chapter_tree_model (signal_user_data_t *ud)
treestore = gtk_list_store_new(3, G_TYPE_INT, G_TYPE_STRING, G_TYPE_BOOLEAN);
gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(treestore));
- cell = gtk_cell_renderer_text_new();
+ cell = ghb_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes(
_("Chapter No."), cell, "text", 0, NULL);
gtk_tree_view_append_column(treeview, GTK_TREE_VIEW_COLUMN(column));
- cell = gtk_cell_renderer_text_new();
+ cell = ghb_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes(
_("Chapter Title"), cell, "text", 1, "editable", 2, NULL);
gtk_tree_view_append_column(treeview, GTK_TREE_VIEW_COLUMN(column));
- g_signal_connect(cell, "edited", chapter_edited_cb, ud);
+ g_signal_connect(cell, "key-press-event", chapter_keypress_cb, ud);
+ g_signal_connect(cell, "edited", chapter_edited_cb, ud);
g_signal_connect(selection, "changed", chapter_list_selection_changed_cb, ud);
g_debug("Done\n");
}
@@ -504,9 +507,11 @@ main (int argc, char *argv[])
ud = g_malloc(sizeof(signal_user_data_t));
ud->debug = FALSE;
+ ud->cancel_encode = FALSE;
g_log_set_handler (NULL, G_LOG_LEVEL_DEBUG, debug_log_handler, ud);
ud->settings = ghb_settings_new();
ud->queue = NULL;
+ ud->current_job = NULL;
ud->current_dvd_device = NULL;
// Redirect stderr to the activity window
IoRedirect(ud);
@@ -600,6 +605,8 @@ main (int argc, char *argv[])
// Source overridden from command line option
ghb_settings_set_string(ud->settings, "source", dvd_device);
}
+ // Reload and check status of the last saved queue
+ g_idle_add((GSourceFunc)ghb_reload_queue, ud);
// Start timer for monitoring libhb status, 500ms
g_timeout_add (500, ghb_timer_cb, (gpointer)ud);
// Everything should be go-to-go. Lets rock!
diff --git a/gtk/src/marshalers.c b/gtk/src/marshalers.c
new file mode 100644
index 000000000..0f234ec3d
--- /dev/null
+++ b/gtk/src/marshalers.c
@@ -0,0 +1,125 @@
+
+#include <glib-object.h>
+
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v) g_value_get_char (v)
+#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v) g_value_get_int (v)
+#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
+#define g_marshal_value_peek_long(v) g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
+#define g_marshal_value_peek_float(v) g_value_get_float (v)
+#define g_marshal_value_peek_double(v) g_value_get_double (v)
+#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v) g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v) g_value_get_object (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ * Do not access GValues directly in your code. Instead, use the
+ * g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
+#define g_marshal_value_peek_char(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v) (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v) (v)->data[0].v_long
+#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_float(v) (v)->data[0].v_float
+#define g_marshal_value_peek_double(v) (v)->data[0].v_double
+#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+/* VOID:STRING,STRING (marshalers.list:1) */
+void
+ghb_marshal_VOID__STRING_STRING (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__STRING_STRING) (gpointer data1,
+ gpointer arg_1,
+ gpointer arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__STRING_STRING callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__STRING_STRING) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_string (param_values + 1),
+ g_marshal_value_peek_string (param_values + 2),
+ data2);
+}
+
+/* BOOLEAN:BOXED (marshalers.list:2) */
+void
+ghb_marshal_BOOLEAN__BOXED (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef gboolean (*GMarshalFunc_BOOLEAN__BOXED) (gpointer data1,
+ gpointer arg_1,
+ gpointer data2);
+ register GMarshalFunc_BOOLEAN__BOXED callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+ gboolean v_return;
+
+ g_return_if_fail (return_value != NULL);
+ g_return_if_fail (n_param_values == 2);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_BOOLEAN__BOXED) (marshal_data ? marshal_data : cc->callback);
+
+ v_return = callback (data1,
+ g_marshal_value_peek_boxed (param_values + 1),
+ data2);
+
+ g_value_set_boolean (return_value, v_return);
+}
+
diff --git a/gtk/src/marshalers.h b/gtk/src/marshalers.h
new file mode 100644
index 000000000..1034f926d
--- /dev/null
+++ b/gtk/src/marshalers.h
@@ -0,0 +1,28 @@
+
+#ifndef __ghb_marshal_MARSHAL_H__
+#define __ghb_marshal_MARSHAL_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/* VOID:STRING,STRING (marshalers.list:1) */
+extern void ghb_marshal_VOID__STRING_STRING (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* BOOLEAN:BOXED (marshalers.list:2) */
+extern void ghb_marshal_BOOLEAN__BOXED (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+G_END_DECLS
+
+#endif /* __ghb_marshal_MARSHAL_H__ */
+
diff --git a/gtk/src/plist.c b/gtk/src/plist.c
index da7bc55e7..93178b370 100644
--- a/gtk/src/plist.c
+++ b/gtk/src/plist.c
@@ -382,14 +382,12 @@ ghb_plist_parse(const gchar *buf, gssize len)
}
GValue*
-ghb_plist_parse_file(const gchar *filename)
+ghb_plist_parse_file(FILE *fd)
{
- FILE *fd;
gchar *buffer;
size_t size;
GValue *gval;
- fd = fopen(filename, "r");
if (fd == NULL)
return NULL;
fseek(fd, 0, SEEK_END);
@@ -577,11 +575,13 @@ main(gint argc, gchar *argv[])
g_type_init();
- gval = ghb_plist_parse_file(argv[1]);
+ file = g_fopen(argv[1], "r");
+ gval = ghb_plist_parse_file(file);
if (argc > 2)
ghb_plist_write_file(argv[2], gval);
else
ghb_plist_write(stdout, gval);
+ if (file) fclose (file);
return 0;
}
#endif
diff --git a/gtk/src/plist.h b/gtk/src/plist.h
index 8b2498826..4ea06780a 100644
--- a/gtk/src/plist.h
+++ b/gtk/src/plist.h
@@ -6,7 +6,7 @@
#include <glib-object.h>
GValue* ghb_plist_parse(const gchar *buf, gssize len);
-GValue* ghb_plist_parse_file(const gchar *filename);
+GValue* ghb_plist_parse_file(FILE *fd);
void ghb_plist_write(FILE *file, GValue *gval);
void ghb_plist_write_file(const gchar *filename, GValue *gval);
diff --git a/gtk/src/presets.c b/gtk/src/presets.c
index 75ef74538..8f032d819 100644
--- a/gtk/src/presets.c
+++ b/gtk/src/presets.c
@@ -372,6 +372,40 @@ store_plist(GValue *plist, const gchar *name)
fclose(file);
}
+static GValue*
+load_plist(const gchar *name)
+{
+ const gchar *dir;
+ gchar *config;
+ FILE *file;
+ GValue *plist = NULL;
+
+ dir = g_get_user_config_dir();
+ config = g_strdup_printf ("%s/ghb/%s", dir, name);
+ if (g_file_test(config, G_FILE_TEST_IS_REGULAR))
+ {
+ file = g_fopen(config, "r");
+ plist = ghb_plist_parse_file(file);
+ }
+ g_free(config);
+ return plist;
+}
+
+static void
+remove_plist(const gchar *name)
+{
+ const gchar *dir;
+ gchar *config;
+
+ dir = g_get_user_config_dir();
+ config = g_strdup_printf ("%s/ghb/%s", dir, name);
+ if (g_file_test(config, G_FILE_TEST_IS_REGULAR))
+ {
+ g_unlink(config);
+ }
+ g_free(config);
+}
+
static gboolean prefs_initializing = FALSE;
void
@@ -535,28 +569,15 @@ ghb_settings_init(signal_user_data_t *ud)
void
ghb_prefs_load(signal_user_data_t *ud)
{
- const gchar *dir;
- gchar *config;
GValue *dict, *internal;
GHashTableIter iter;
gchar *key;
GValue *gval;
g_debug("ghb_prefs_load");
- dir = g_get_user_config_dir();
- config = g_strdup_printf ("%s/ghb/preferences", dir);
- if (g_file_test(config, G_FILE_TEST_IS_REGULAR))
- {
- prefsPlist = ghb_plist_parse_file(config);
- if (prefsPlist == NULL)
- prefsPlist = ghb_dict_value_new();
- }
- else
- {
- // Make an empty plist
+ prefsPlist = load_plist("preferences");
+ if (prefsPlist == NULL)
prefsPlist = ghb_dict_value_new();
- }
- g_free(config);
dict = plist_get_dict(prefsPlist, "Preferences");
internal = plist_get_dict(internalPlist, "Preferences");
if (dict == NULL && internal)
@@ -575,7 +596,6 @@ ghb_prefs_load(signal_user_data_t *ud)
g_strdup("destination_dir"), ghb_value_dup(ghb_string_value(dir)));
store_plist(prefsPlist, "preferences");
}
-
}
void
@@ -619,29 +639,33 @@ presets_store()
}
void
-ghb_presets_load()
+ghb_save_queue(GValue *queue)
{
- const gchar *dir;
- gchar *config;
+ store_plist(queue, "queue");
+}
- dir = g_get_user_config_dir();
- config = g_strdup_printf ("%s/ghb/presets", dir);
- if (g_file_test(config, G_FILE_TEST_IS_REGULAR))
- {
- presetsPlist = ghb_plist_parse_file(config);
- if (presetsPlist == NULL)
- {
- presetsPlist = ghb_plist_parse(
- standardPresets, sizeof(standardPresets)-1);
- presets_store();
- }
- }
- else
+GValue*
+ghb_load_queue()
+{
+ return load_plist("queue");
+}
+
+void
+ghb_remove_queue_file()
+{
+ remove_plist("queue");
+}
+
+void
+ghb_presets_load()
+{
+ presetsPlist = load_plist("presets");
+ if (presetsPlist == NULL)
{
presetsPlist = ghb_plist_parse(
standardPresets, sizeof(standardPresets)-1);
+ presets_store();
}
- g_free(config);
}
void
diff --git a/gtk/src/presets.h b/gtk/src/presets.h
index 44f9cdd9b..b216c5580 100644
--- a/gtk/src/presets.h
+++ b/gtk/src/presets.h
@@ -33,5 +33,8 @@ void ghb_prefs_to_ui(signal_user_data_t *ud);
void ghb_prefs_save(GValue *settings);
void ghb_pref_save(GValue *settings, const gchar *key);
void ghb_set_preset_default(GValue *settings);
+void ghb_save_queue(GValue *queue);
+GValue* ghb_load_queue();
+void ghb_remove_queue_file(void);;
#endif // _GHB_PRESETS_H_
diff --git a/gtk/src/settings.c b/gtk/src/settings.c
index 4f2cacbb8..1fad691ce 100644
--- a/gtk/src/settings.c
+++ b/gtk/src/settings.c
@@ -193,19 +193,6 @@ ghb_settings_get_combo_option(GValue *settings, const gchar *key)
return g_strdup(cd->option);
}
-gchar*
-ghb_settings_get_combo_string(GValue *settings, const gchar *key)
-{
- const GValue* value;
- value = ghb_settings_get_value(settings, key);
- if (value == NULL) return g_strdup("");
- ghb_combodata_t *cd;
- if (G_VALUE_TYPE(value) != ghb_combodata_get_type())
- return g_strdup("");
- cd = g_value_get_boxed(value);
- return g_strdup(cd->svalue);
-}
-
// Map widget names to setting keys
// Widgets that map to settings have names
// of this format: s_<setting key>
diff --git a/gtk/src/settings.h b/gtk/src/settings.h
index 99d8e6866..cc89f1f7f 100644
--- a/gtk/src/settings.h
+++ b/gtk/src/settings.h
@@ -44,9 +44,11 @@ typedef struct
gchar *current_dvd_device;
gboolean debug;
gboolean dont_clear_presets;
+ gboolean cancel_encode;
GtkBuilder *builder;
GValue *settings;
GValue *queue;
+ GValue *current_job;
GIOChannel *activity_log;
} signal_user_data_t;
@@ -83,7 +85,6 @@ gdouble ghb_settings_get_double(GValue *settings, const gchar *key);
gchar* ghb_settings_get_string(GValue *settings, const gchar *key);
gint ghb_settings_get_combo_index(GValue *settings, const gchar *key);
gchar* ghb_settings_get_combo_option(GValue *settings, const gchar *name);
-gchar* ghb_settings_get_combo_string(GValue *settings, const gchar *key);
GValue* ghb_widget_value(GtkWidget *widget);
gchar* ghb_widget_string(GtkWidget *widget);