diff options
Diffstat (limited to 'grecord/src/gsr-window.c')
-rw-r--r-- | grecord/src/gsr-window.c | 2759 |
1 files changed, 0 insertions, 2759 deletions
diff --git a/grecord/src/gsr-window.c b/grecord/src/gsr-window.c deleted file mode 100644 index 4d50a44..0000000 --- a/grecord/src/gsr-window.c +++ /dev/null @@ -1,2759 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: Iain Holmes <[email protected]> - * Johan Dahlin <[email protected]> - * Tim-Philipp Müller <tim centricular net> - * - * Copyright 2002 Iain Holmes - * - * 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. - * - * 4th Februrary 2005: Christian Schaller: changed license to LGPL with - * permission of Iain Holmes, Ronald Bultje, Leontine Binchy (SUN), Johan Dalhin - * and Joe Marcus Clarke - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <string.h> -#include <math.h> - -#include <glib/gi18n.h> -#include <gio/gio.h> -#include <gtk/gtk.h> -#include <mateconf/mateconf-client.h> -#include <gst/gst.h> -#include <gst/interfaces/mixer.h> - -#include <profiles/mate-media-profiles.h> - -#include "gsr-window.h" - -GST_DEBUG_CATEGORY_STATIC (gsr_debug); -#define GST_CAT_DEFAULT gsr_debug - -extern GtkWidget * gsr_open_window (const char *filename); -extern void gsr_quit (void); - -extern MateConfClient *mateconf_client; - -extern void gsr_add_recent (gchar *filename); - -#define MATECONF_DIR "/apps/mate-sound-recorder/" -#define KEY_OPEN_DIR MATECONF_DIR "system-state/open-file-directory" -#define KEY_SAVE_DIR MATECONF_DIR "system-state/save-file-directory" -#define KEY_LAST_PROFILE_ID MATECONF_DIR "last-profile-id" -#define KEY_LAST_INPUT MATECONF_DIR "last-input" -#define EBUSY_TRY_AGAIN 3 /* Empirical data */ - -typedef struct _GSRWindowPipeline { - GstElement *pipeline; - GstState state; /* last seen (async) pipeline state */ - GstBus *bus; - - GstElement *src; - GstElement *sink; - - guint tick_id; -} GSRWindowPipeline; - -enum { - PROP_0, - PROP_LOCATION -}; - -static GtkWindowClass *parent_class = NULL; - -#define GSR_WINDOW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), GSR_TYPE_WINDOW, GSRWindowPrivate)) - -struct _GSRWindowPrivate { - GtkWidget *main_vbox; - GtkWidget *scale; - GtkWidget *profile, *input; - GtkWidget *rate, *time_sec, *format, *channels; - GtkWidget *input_label; - GtkWidget *name_label; - GtkWidget *length_label; - GtkWidget *align; - GtkWidget *volume_label; - GtkWidget *level; - - gulong seek_id; - - GtkUIManager *ui_manager; - GtkActionGroup *action_group; - GtkWidget *recent_view; - GtkRecentFilter *recent_filter; - - /* statusbar */ - GtkWidget *statusbar; - guint status_message_cid; - guint tip_message_cid; - - /* Pipelines */ - GSRWindowPipeline *play; - GSRWindowPipeline *record; - char *record_filename; - char *filename; - char *extension; - char *working_file; /* Working file: Operations only occur on the - working file. The result of that operation then - becomes the new working file. */ - int record_fd; - - /* File info */ - int len_secs; /* In seconds */ - int get_length_attempts; - - /* ATOMIC access */ - struct { - gint n_channels; - gint bitrate; - gint samplerate; - } atomic; - - gboolean has_file; - gboolean saved; - gboolean dirty; - gboolean seek_in_progress; - - gboolean quit_after_save; - - guint32 tick_id; /* tick_callback timeout ID */ - guint32 record_id; /* record idle callback timeout ID */ - - GstElement *ebusy_pipeline; /* which pipeline we're trying to start */ - guint ebusy_timeout_id; - - GstElement *source; - GstMixer *mixer; -}; - -static gboolean make_record_source (GSRWindow *window); -static void fill_record_input (GSRWindow *window, gchar *selected); -static GSRWindowPipeline * make_record_pipeline (GSRWindow *window); -static GSRWindowPipeline * make_play_pipeline (GSRWindow *window); - -static void -show_error_dialog (GtkWindow *window, - const gchar *debug_message, - const gchar *format, ...) G_GNUC_PRINTF (3,4); - -static void -show_error_dialog (GtkWindow *win, const gchar *dbg, const gchar * format, ...) -{ - GtkWidget *dialog; - va_list args; - gchar *s; - - va_start (args, format); - s = g_strdup_vprintf (format, args); - va_end (args); - - dialog = gtk_message_dialog_new (win, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_CLOSE, - "%s", - s); - - if (dbg != NULL) { - g_printerr ("ERROR: %s\nDEBUG MESSAGE: %s\n", s, dbg); - } - - gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); - g_free (s); -} - -static void -show_missing_known_element_error (GtkWindow *win, gchar *description, - gchar *element, gchar *plugin, gchar *module) -{ - show_error_dialog (win, NULL, - _("Could not create the GStreamer %s element.\n" - "Please install the '%s' plugin from the '%s' module.\n" - "Verify that the installation is correct by running\n" - " gst-inspect-0.10 %s\n" - "and then restart mate-sound-recorder."), - description, plugin, module, element); -} - -static void -show_profile_error (GtkWindow *win, gchar *debug, gchar *description, - const char *profile) -{ - gchar *first; - - first = g_strdup_printf (description, profile); - show_error_dialog (win, debug, "%s%s", first, - _("Please verify its settings.\n" - "You may be missing the necessary plugins.")); - g_free (first); -} -/* Why do we need this? when a bin changes from READY => NULL state, its - * bus is set to flushing and we're unlikely to ever see any of its messages - * if the bin's state reaches NULL before we/the watch in the main thread - * collects them. That's why we set the state to READY first, process all - * messages 'manually', and then finally set it to NULL. This makes sure - * our state-changed handler actually gets to see all the state changes */ - -static void -set_pipeline_state_to_null (GstElement *pipeline) -{ - GstMessage *msg; - GstState cur_state, pending; - GstBus *bus; - - gst_element_get_state (pipeline, &cur_state, &pending, 0); - - if (cur_state == GST_STATE_NULL && pending == GST_STATE_VOID_PENDING) - return; - - if (cur_state == GST_STATE_NULL && pending != GST_STATE_VOID_PENDING) { - gst_element_set_state (pipeline, GST_STATE_NULL); - return; - } - - gst_element_set_state (pipeline, GST_STATE_READY); - gst_element_get_state (pipeline, NULL, NULL, -1); - - bus = gst_element_get_bus (pipeline); - while ((msg = gst_bus_pop (bus))) { - gst_bus_async_signal_func (bus, msg, NULL); - } - gst_object_unref (bus); - - gst_element_set_state (pipeline, GST_STATE_NULL); - /* maybe we should be paranoid and do _get_state() and check for - * the return value here, but then errors in shutdown should be - * rather unlikely */ -} - - -static void -shutdown_pipeline (GSRWindowPipeline *pipe) -{ - gst_bus_set_flushing (pipe->bus, TRUE); - gst_bus_remove_signal_watch (pipe->bus); - gst_element_set_state (pipe->pipeline, GST_STATE_NULL); - gst_object_unref (pipe->pipeline); - gst_object_unref (pipe->bus); -} - -static char * -seconds_to_string (guint seconds) -{ - int hour, min, sec; - - min = (seconds / 60); - hour = min / 60; - min -= (hour * 60); - sec = seconds - ((hour * 3600) + (min * 60)); - - if (hour > 0) { - return g_strdup_printf ("%d:%02d:%02d", hour, min, sec); - } else { - return g_strdup_printf ("%d:%02d", min, sec); - } -} - -static char * -seconds_to_full_string (guint seconds) -{ - long days, hours, minutes; - char *time = NULL; - const char *minutefmt; - const char *hourfmt; - const char *secondfmt; - - days = seconds / (60 * 60 * 24); - hours = (seconds / (60 * 60)); - minutes = (seconds / 60) - ((days * 24 * 60) + (hours * 60)); - seconds = seconds % 60; - - minutefmt = ngettext ("%ld minute", "%ld minutes", minutes); - hourfmt = ngettext ("%ld hour", "%ld hours", hours); - secondfmt = ngettext ("%ld second", "%ld seconds", seconds); - - if (hours > 0) { - if (minutes > 0) - if (seconds > 0) { - char *fmt; - /* Translators: the format is "X hours, X minutes and X seconds" */ - fmt = g_strdup_printf (_("%s, %s and %s"), hourfmt, minutefmt, secondfmt); - time = g_strdup_printf (fmt, hours, minutes, seconds); - g_free (fmt); - } else { - char *fmt; - /* Translators: the format is "X hours and X minutes" */ - fmt = g_strdup_printf (_("%s and %s"), hourfmt, minutefmt); - time = g_strdup_printf (fmt, hours, minutes); - g_free (fmt); - } - else - if (seconds > 0) { - char *fmt; - /* Translators: the format is "X minutes and X seconds" */ - fmt = g_strdup_printf (_("%s and %s"), minutefmt, secondfmt); - time = g_strdup_printf (fmt, minutes, seconds); - g_free (fmt); - } else { - time = g_strdup_printf (minutefmt, minutes); - } - } else { - if (minutes > 0) { - if (seconds > 0) { - char *fmt; - /* Translators: the format is "X minutes and X seconds" */ - fmt = g_strdup_printf (_("%s and %s"), minutefmt, secondfmt); - time = g_strdup_printf (fmt, minutes, seconds); - g_free (fmt); - } else { - time = g_strdup_printf (minutefmt, minutes); - } - - } else { - time = g_strdup_printf (secondfmt, seconds); - } - } - - return time; -} - -static void -set_action_sensitive (GSRWindow *window, - const char *name, - gboolean sensitive) -{ - GtkAction *action = gtk_action_group_get_action (window->priv->action_group, - name); - gtk_action_set_sensitive (action, sensitive); -} - -static void -file_new_cb (GtkAction *action, - GSRWindow *window) -{ - gsr_open_window (NULL); -} - -static void -file_open_cb (GtkAction *action, - GSRWindow *window) -{ - GtkWidget *file_chooser; - gchar *directory; - gchar *locale_directory = NULL; - gint response; - - g_return_if_fail (GSR_IS_WINDOW (window)); - - file_chooser = gtk_file_chooser_dialog_new (_("Open a File"), - GTK_WINDOW (window), - GTK_FILE_CHOOSER_ACTION_OPEN, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OPEN, GTK_RESPONSE_OK, - NULL); - - directory = mateconf_client_get_string (mateconf_client, KEY_OPEN_DIR, NULL); - - if (directory != NULL && *directory != 0) { - locale_directory = g_filename_from_utf8 (directory, -1, NULL, NULL, NULL); - if (!locale_directory || !g_file_test (locale_directory, G_FILE_TEST_EXISTS)) - locale_directory = g_strdup (directory); - gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (file_chooser), - locale_directory); - g_free (locale_directory); - } - - response = gtk_dialog_run (GTK_DIALOG (file_chooser)); - - if (response == GTK_RESPONSE_OK) { - gchar *name; - gchar *utf8_name = NULL; - - name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_chooser)); - if (name) { - gchar *dirname; - - utf8_name = g_filename_to_utf8 (name, -1, NULL, NULL, NULL); - dirname = g_path_get_dirname (utf8_name); - mateconf_client_set_string (mateconf_client, KEY_OPEN_DIR, dirname, NULL); - g_free (dirname); - g_free (utf8_name); - - if (window->priv->has_file == TRUE) { - /* Just open a new window with the file */ - gsr_open_window (name); - } else { - /* Set the file in this window */ - g_object_set (G_OBJECT (window), "location", name, NULL); - window->priv->dirty = FALSE; - } - - g_free (name); - } - } - - gtk_widget_destroy (file_chooser); - g_free (directory); -} - -static void -file_open_recent_cb (GtkRecentChooser *chooser, - GSRWindow *window) -{ - gchar *uri; - gchar *filename; - - uri = gtk_recent_chooser_get_current_uri (chooser); - g_return_if_fail (uri != NULL); - - if (!g_str_has_prefix (uri, "file://")) - return; - - filename = g_filename_from_uri (uri, NULL, NULL); - if (filename == NULL) - goto out; - - if (!g_file_test (filename, G_FILE_TEST_EXISTS)) { - gchar *filename_utf8; - GtkWidget *dlg; - - filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL); - dlg = gtk_message_dialog_new (GTK_WINDOW (window), - GTK_DIALOG_MODAL, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - _("Unable to load file:\n%s"), filename_utf8); - - gtk_widget_show (dlg); - gtk_dialog_run (GTK_DIALOG (dlg)); - gtk_widget_destroy (dlg); - - gtk_recent_manager_remove_item (gtk_recent_manager_get_default (), uri, NULL); - - g_free (filename_utf8); - goto out; - } - - if (window->priv->has_file == TRUE) { - /* Just open a new window with the file */ - gsr_open_window (filename); - } else { - /* Set the file in this window */ - g_object_set (G_OBJECT (window), "location", filename, NULL); - window->priv->dirty = FALSE; - } - - out: - g_free (filename); - g_free (uri); -} - -#if 0 -static gboolean -cb_iterate (GstBin *bin, - gpointer data) -{ - src = gst_element_get_child (bin, "sink"); - sink = gst_element_get_child (bin, "sink"); - - if (src && sink) { - gint64 pos, tot, enc; - GstFormat fmt = GST_FORMAT_BYTES; - - gst_element_query (src, GST_QUERY_POSITION, &fmt, &pos); - gst_element_query (src, GST_QUERY_TOTAL, &fmt, &tot); - gst_element_query (sink, GST_QUERY_POSITION, &fmt, &enc); - - g_print ("Iterate: %lld/%lld -> %lld\n", pos, tot, enc); - } else - g_print ("Iterate ?\n"); - - /* we don't do anything here */ - return FALSE; -} -#endif - -static gboolean -handle_ebusy_error (GSRWindow *window) -{ - g_return_val_if_fail (window->priv->ebusy_pipeline != NULL, FALSE); - - gst_element_set_state (window->priv->ebusy_pipeline, GST_STATE_NULL); - gst_element_get_state (window->priv->ebusy_pipeline, NULL, NULL, -1); - gst_element_set_state (window->priv->ebusy_pipeline, GST_STATE_PLAYING); - - /* Try only once */ - return FALSE; -} - -static GstElement * -notgst_element_get_toplevel (GstElement * element) -{ - g_return_val_if_fail (element != NULL, NULL); - g_return_val_if_fail (GST_IS_ELEMENT (element), NULL); - - do { - GstElement *parent; - - parent = (GstElement *) gst_element_get_parent (element); - - if (parent == NULL) - break; - - gst_object_unref (parent); - element = parent; - } while (1); - - return element; -} - -static void -pipeline_error_cb (GstBus * bus, GstMessage * msg, GSRWindow * window) -{ - GstElement *pipeline; - GError *error = NULL; - gchar *dbg = NULL; - - g_return_if_fail (GSR_IS_WINDOW (window)); - - gst_message_parse_error (msg, &error, &dbg); - g_return_if_fail (error != NULL); - - pipeline = notgst_element_get_toplevel (GST_ELEMENT (msg->src)); - - if (error->code == GST_RESOURCE_ERROR_BUSY) { - if (window->priv->ebusy_timeout_id == 0) { - set_action_sensitive (window, "FileSave", FALSE); - set_action_sensitive (window, "FileSaveAs", FALSE); - set_action_sensitive (window, "Play", FALSE); - set_action_sensitive (window, "Record", FALSE); - - window->priv->ebusy_pipeline = pipeline; - - window->priv->ebusy_timeout_id = - g_timeout_add_seconds (EBUSY_TRY_AGAIN, - (GSourceFunc) handle_ebusy_error, - window); - - g_error_free (error); - g_free (dbg); - return; - } - } - - if (window->priv->ebusy_timeout_id) { - g_source_remove (window->priv->ebusy_timeout_id); - window->priv->ebusy_timeout_id = 0; - window->priv->ebusy_pipeline = NULL; - } - - - /* set pipeline to NULL before showing error dialog to make sure - * the audio device is freed, in case any accessability software - * wants to make use of it to read out the error message */ - set_pipeline_state_to_null (pipeline); - - show_error_dialog (GTK_WINDOW (window), dbg, "%s", error->message); - - gdk_window_set_cursor (gtk_widget_get_window (window->priv->main_vbox), NULL); - - set_action_sensitive (window, "Stop", FALSE); - set_action_sensitive (window, "Play", TRUE); - set_action_sensitive (window, "Record", TRUE); - set_action_sensitive (window, "FileSave", TRUE); - set_action_sensitive (window, "FileSaveAs", TRUE); - gtk_widget_set_sensitive (window->priv->scale, TRUE); - - gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar), - window->priv->status_message_cid); - gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar), - window->priv->status_message_cid, - _("Ready")); - - g_error_free (error); - g_free (dbg); -} - -static GtkWidget * -gsr_dialog_add_button (GtkDialog *dialog, - const gchar *text, - const gchar *stock_id, - gint response_id) -{ - GtkWidget *button; - - g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL); - g_return_val_if_fail (text != NULL, NULL); - g_return_val_if_fail (stock_id != NULL, NULL); - - button = gtk_button_new_with_mnemonic (text); - gtk_button_set_image (GTK_BUTTON (button), - gtk_image_new_from_stock (stock_id, - GTK_ICON_SIZE_BUTTON)); - - gtk_widget_set_can_default (button, TRUE); - - gtk_widget_show (button); - - gtk_dialog_add_action_widget (dialog, button, response_id); - - return button; -} - -static gboolean -replace_dialog (GtkWindow *parent, - const gchar *message, - const gchar *file_name) -{ - GtkWidget *message_dialog; - gint ret; - - g_return_val_if_fail (file_name != NULL, FALSE); - - message_dialog = gtk_message_dialog_new (parent, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_NONE, - message, - file_name); - /* Add cancel button */ - gtk_dialog_add_button (GTK_DIALOG (message_dialog), - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL); - /* Add replace button */ - gsr_dialog_add_button (GTK_DIALOG (message_dialog), _("_Replace"), - GTK_STOCK_REFRESH, - GTK_RESPONSE_YES); - - gtk_dialog_set_default_response (GTK_DIALOG (message_dialog), GTK_RESPONSE_CANCEL); - gtk_window_set_resizable (GTK_WINDOW (message_dialog), FALSE); - ret = gtk_dialog_run (GTK_DIALOG (message_dialog)); - gtk_widget_destroy (GTK_WIDGET (message_dialog)); - - return (ret == GTK_RESPONSE_YES); -} - -static gboolean -replace_existing_file (GtkWindow *parent, - const gchar *file_name) -{ - return replace_dialog (parent, - _("A file named \"%s\" already exists. \n" - "Do you want to replace it with the " - "one you are saving?"), - file_name); -} - -static void -do_save_file (GSRWindow *window, - const char *_name) -{ - GSRWindowPrivate *priv; - char *name; - GFile *src, *dst; - GError *error = NULL; - - priv = window->priv; - - if (window->priv->extension == NULL || - g_str_has_suffix (_name, window->priv->extension)) - name = g_strdup (_name); - else - name = g_strdup_printf ("%s.%s", _name, - window->priv->extension); - if (g_file_test (name, G_FILE_TEST_EXISTS)) { - char *utf8_name; - utf8_name = g_filename_to_utf8 (name, -1, NULL, NULL, NULL); - if (!replace_existing_file (GTK_WINDOW (window), utf8_name)) { - g_free (utf8_name); - return; - } - g_free (utf8_name); - } - src = g_file_new_for_path(priv->record_filename); - dst = g_file_new_for_path(name); - - /* TODO: Show progress? Where? */ - if (g_file_copy(src, dst, G_FILE_COPY_OVERWRITE, - NULL, NULL, NULL, &error)) { - g_object_set (G_OBJECT (window), "location", name, NULL); - priv->dirty = FALSE; - window->priv->saved = TRUE; - if (window->priv->quit_after_save == TRUE) { - gsr_window_close (window); - } - } else { - char *utf8_name; - utf8_name = g_filename_to_utf8 (name, -1, NULL, NULL, NULL); - show_error_dialog (GTK_WINDOW (window), NULL, - _("Could not save the file \"%s\""), utf8_name); - g_free (utf8_name); - } - - g_object_unref(src); - g_object_unref(dst); - g_free (name); -} - -static void -file_save_as_cb (GtkAction *action, - GSRWindow *window) -{ - GtkWidget *file_chooser; - gchar *directory; - gchar *locale_directory = NULL; - gint response; - - g_return_if_fail (GSR_IS_WINDOW (window)); - - file_chooser = gtk_file_chooser_dialog_new (_("Save file as"), - GTK_WINDOW (window), - GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_OK, - NULL); - - directory = mateconf_client_get_string (mateconf_client, KEY_SAVE_DIR, NULL); - if (directory != NULL && *directory != 0) { - locale_directory = g_filename_from_utf8 (directory, -1, NULL, NULL, NULL); - if (!locale_directory || !g_file_test (locale_directory, G_FILE_TEST_EXISTS)) - locale_directory = g_strdup (directory); - gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (file_chooser), locale_directory); - g_free (locale_directory); - } - g_free (directory); - - if (window->priv->filename != NULL) { - char *locale_basename; - char *basename = NULL; - gchar *filename, *filename_ext, *extension; - gint length; - - locale_basename = g_path_get_basename (window->priv->filename); - basename = g_filename_to_utf8 (locale_basename, -1, NULL, NULL, NULL); - length = strlen (basename); - extension = g_strrstr (basename, "."); - - if (extension != NULL) { - length = length - strlen (extension); - } - - filename = g_strndup (basename,length); - if (window->priv->extension) - filename_ext = g_strdup_printf ("%s.%s", filename, - window->priv->extension); - else - filename_ext = g_strdup (filename); - gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (file_chooser), - filename_ext); - g_free (filename); - g_free (filename_ext); - g_free (basename); - g_free (locale_basename); - } - - response = gtk_dialog_run (GTK_DIALOG (file_chooser)); - - if (response == GTK_RESPONSE_OK) { - gchar *name; - gchar *utf8_name = NULL; - - name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_chooser)); - if (name) { - gchar *dirname; - - utf8_name= g_filename_to_utf8 (name, -1, NULL, NULL, NULL); - dirname = g_path_get_dirname (utf8_name); - mateconf_client_set_string (mateconf_client, KEY_SAVE_DIR, dirname, NULL); - g_free (dirname); - g_free (utf8_name); - - do_save_file (window, name); - g_free (name); - } - } - - gtk_widget_destroy (file_chooser); -} - -static void -file_save_cb (GtkAction *action, - GSRWindow *window) -{ - if (!window->priv->has_file) { - file_save_as_cb (NULL, window); - } else { - do_save_file (window, window->priv->filename); - } -} - -static void -run_mixer_cb (GtkAction *action, - GSRWindow *window) -{ - char *mixer_path; - char *argv[4] = {NULL, "--page", "recording", NULL}; - GError *error = NULL; - gboolean ret; - - /* Open the mixer */ - mixer_path = g_find_program_in_path ("mate-volume-control"); - if (mixer_path == NULL) { - show_error_dialog (GTK_WINDOW (window), NULL, - _("%s is not installed in the path."), - "mate-volume-control"); - return; - } - - argv[0] = mixer_path; - ret = g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, NULL, &error); - if (ret == FALSE) { - show_error_dialog (GTK_WINDOW (window), NULL, - _("There was an error starting %s: %s"), - mixer_path, error->message); - g_error_free (error); - } - - g_free (mixer_path); -} - -gboolean -gsr_window_is_saved (GSRWindow *window) -{ - return window->priv->saved; -} - -gboolean -gsr_discard_confirmation_dialog (GSRWindow *window, gboolean closing) -{ - GtkWidget *confirmation_dialog; - AtkObject *atk_obj; - gint response_id; - gboolean ret = TRUE; - - confirmation_dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (window), - GTK_DIALOG_MODAL, - GTK_MESSAGE_WARNING, - GTK_BUTTONS_NONE, - "<span weight=\"bold\" size=\"larger\">%s</span>", - closing ? - _("Save recording before closing?") : - _("Save recording?")); - - gtk_dialog_add_buttons (GTK_DIALOG (confirmation_dialog), - closing ? - _("Close _without Saving") : - _("Continue _without Saving"), - GTK_RESPONSE_YES, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE_AS, GTK_RESPONSE_NO, NULL); - gtk_dialog_set_default_response (GTK_DIALOG (confirmation_dialog), - GTK_RESPONSE_NO); - - gtk_window_set_title (GTK_WINDOW (confirmation_dialog), ""); - - atk_obj = gtk_widget_get_accessible (confirmation_dialog); - atk_object_set_name (atk_obj, _("Question")); - - response_id = gtk_dialog_run (GTK_DIALOG (confirmation_dialog)); - - switch (response_id) { - case GTK_RESPONSE_NO: - /* hiding the confirmation dialog allows the user to - see only one dialog at a time if the user click cancel - in the file dialog, they won't expect to return to the - confirmation dialog*/ - gtk_widget_hide (confirmation_dialog); - file_save_as_cb (NULL, window); - ret = window->priv->has_file; - break; - - case GTK_RESPONSE_YES: - ret = TRUE; - break; - - case GTK_RESPONSE_CANCEL: - default: - ret = FALSE; - break; - } - - gtk_widget_destroy (confirmation_dialog); - - return ret; -} - -static GtkWidget * -make_title_label (const char *text) -{ - GtkWidget *label; - char *fulltext; - - fulltext = g_strdup_printf ("<span weight=\"bold\">%s</span>", text); - label = gtk_label_new (fulltext); - g_free (fulltext); - - gtk_label_set_use_markup (GTK_LABEL (label), TRUE); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.0); - return label; -} - -static GtkWidget * -make_info_label (const char *text) -{ - GtkWidget *label; - - label = gtk_label_new (text); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - gtk_label_set_selectable (GTK_LABEL (label), TRUE); - gtk_label_set_line_wrap (GTK_LABEL (label), GTK_WRAP_WORD); - - return label; -} - -static void -pack_table_widget (GtkWidget *table, - GtkWidget *widget, - int left, - int top) -{ - gtk_table_attach (GTK_TABLE (table), widget, - left, left + 1, top, top + 1, - GTK_FILL, GTK_FILL, 0, 0); -} - -struct _file_props { - GtkWidget *dialog; - - GtkWidget *dirname; - GtkWidget *filename; - GtkWidget *size; - GtkWidget *length; - GtkWidget *samplerate; - GtkWidget *channels; - GtkWidget *bitrate; -}; - -static void -fill_in_information (GSRWindow *window, - struct _file_props *fp) -{ - struct stat buf; - guint64 file_size = 0; - gchar *text, *name; - gchar *utf8_name = NULL; - gint n_channels, bitrate, samplerate; - - /* dirname */ - if (window->priv->dirty) { - gtk_label_set_text (GTK_LABEL (fp->dirname), ""); - } else { - name = g_path_get_dirname (window->priv->filename); - text = g_filename_to_utf8 (name, -1, NULL, NULL, NULL); - gtk_label_set_text (GTK_LABEL (fp->dirname), text); - g_free (text); - g_free (name); - } - - /* filename */ - name = g_path_get_basename (window->priv->filename); - utf8_name = g_filename_to_utf8 (name, -1, NULL, NULL, NULL); - - if (window->priv->dirty) { - text = g_strdup_printf (_("%s (Has not been saved)"), utf8_name); - } else { - text = g_strdup (utf8_name); - } - gtk_label_set_text (GTK_LABEL (fp->filename), text); - g_free (text); - g_free (utf8_name); - g_free (name); - - /* Size */ - if (stat (window->priv->working_file, &buf) == 0) { - gchar *human; - - file_size = (guint64) buf.st_size; - human = g_format_size_for_display (file_size); - - text = g_strdup_printf (ngettext ("%s (%llu byte)", "%s (%llu bytes)", - file_size), human, file_size); - g_free (human); - } else { - text = g_strdup (_("Unknown size")); - } - gtk_label_set_text (GTK_LABEL (fp->size), text); - g_free (text); - - /* FIXME: Set up and run our own pipeline - * till we can get the info */ - /* Length */ - if (window->priv->len_secs == 0) { - text = g_strdup (_("Unknown")); - } else { - text = seconds_to_full_string (window->priv->len_secs); - } - gtk_label_set_text (GTK_LABEL (fp->length), text); - g_free (text); - - /* sample rate */ - samplerate = g_atomic_int_get (&window->priv->atomic.samplerate); - if (samplerate == 0) { - text = g_strdup (_("Unknown")); - } else { - text = g_strdup_printf (_("%.1f kHz"), (float) samplerate / 1000); - } - gtk_label_set_text (GTK_LABEL (fp->samplerate), text); - g_free (text); - - /* bit rate */ - bitrate = g_atomic_int_get (&window->priv->atomic.bitrate); - if (bitrate > 0) { - text = g_strdup_printf (_("%.0f kb/s"), (float) bitrate / 1000); - } else if (window->priv->len_secs > 0 && file_size > 0) { - bitrate = (file_size * 8.0) / window->priv->len_secs; - text = g_strdup_printf (_("%.0f kb/s (Estimated)"), - (float) bitrate / 1000); - } else { - text = g_strdup (_("Unknown")); - } - gtk_label_set_text (GTK_LABEL (fp->bitrate), text); - g_free (text); - - /* channels */ - n_channels = g_atomic_int_get (&window->priv->atomic.n_channels); - switch (n_channels) { - case 0: - text = g_strdup (_("Unknown")); - break; - case 1: - text = g_strdup (_("1 (mono)")); - break; - case 2: - text = g_strdup (_("2 (stereo)")); - break; - default: - text = g_strdup_printf ("%d", n_channels); - break; - } - gtk_label_set_text (GTK_LABEL (fp->channels), text); - g_free (text); -} - -static void -dialog_closed_cb (GtkDialog *dialog, - guint response_id, - struct _file_props *fp) -{ - gtk_widget_destroy (fp->dialog); - g_free (fp); -} - -static void -file_properties_cb (GtkAction *action, - GSRWindow *window) -{ - GtkWidget *dialog, *vbox, *inner_vbox, *hbox, *table, *label; - char *title, *shortname; - struct _file_props *fp; - shortname = g_path_get_basename (window->priv->filename); - title = g_strdup_printf (_("%s Information"), shortname); - g_free (shortname); - - dialog = gtk_dialog_new_with_buttons (title, GTK_WINDOW (window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); - g_free (title); -#if !GTK_CHECK_VERSION (2, 21, 8) - gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); -#endif - gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); - gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); - gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2); - fp = g_new (struct _file_props, 1); - fp->dialog = dialog; - - g_signal_connect (G_OBJECT (dialog), "response", - G_CALLBACK (dialog_closed_cb), fp); - - vbox = gtk_vbox_new (FALSE, 18); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); - gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), vbox, TRUE, TRUE, 0); - - inner_vbox = gtk_vbox_new (FALSE, 6); - gtk_box_pack_start (GTK_BOX (vbox), inner_vbox, FALSE, FALSE,0); - - label = make_title_label (_("File Information")); - gtk_box_pack_start (GTK_BOX (inner_vbox), label, FALSE, FALSE, 0); - - hbox = gtk_hbox_new (FALSE, 0); - gtk_box_pack_start (GTK_BOX (inner_vbox), hbox, TRUE, TRUE, 0); - - label = gtk_label_new (" "); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - /* File properties */ - table = gtk_table_new (3, 2, FALSE); - gtk_table_set_col_spacings (GTK_TABLE (table), 12); - gtk_table_set_row_spacings (GTK_TABLE (table), 6); - gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0); - - label = make_info_label (_("Folder:")); - pack_table_widget (table, label, 0, 0); - - fp->dirname = make_info_label (""); - pack_table_widget (table, fp->dirname, 1, 0); - - label = make_info_label (_("Filename:")); - pack_table_widget (table, label, 0, 1); - - fp->filename = make_info_label (""); - pack_table_widget (table, fp->filename, 1, 1); - - label = make_info_label (_("File size:")); - pack_table_widget (table, label, 0, 2); - - fp->size = make_info_label (""); - pack_table_widget (table, fp->size, 1, 2); - - inner_vbox = gtk_vbox_new (FALSE, 6); - gtk_box_pack_start (GTK_BOX (vbox), inner_vbox, FALSE, FALSE, 0); - - label = make_title_label (_("Audio Information")); - gtk_box_pack_start (GTK_BOX (inner_vbox), label, FALSE, FALSE, 0); - - hbox = gtk_hbox_new (FALSE, 0); - gtk_box_pack_start (GTK_BOX (inner_vbox), hbox, TRUE, TRUE, 0); - - label = gtk_label_new (" "); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - /* Audio info */ - table = gtk_table_new (4, 2, FALSE); - gtk_table_set_col_spacings (GTK_TABLE (table), 12); - gtk_table_set_row_spacings (GTK_TABLE (table), 6); - gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0); - - label = make_info_label (_("File duration:")); - pack_table_widget (table, label, 0, 0); - - fp->length = make_info_label (""); - pack_table_widget (table, fp->length, 1, 0); - - label = make_info_label (_("Number of channels:")); - pack_table_widget (table, label, 0, 1); - - fp->channels = make_info_label (""); - pack_table_widget (table, fp->channels, 1, 1); - - label = make_info_label (_("Sample rate:")); - pack_table_widget (table, label, 0, 2); - - fp->samplerate = make_info_label (""); - pack_table_widget (table, fp->samplerate, 1, 2); - - label = make_info_label (_("Bit rate:")); - pack_table_widget (table, label, 0, 3); - - fp->bitrate = make_info_label (""); - pack_table_widget (table, fp->bitrate, 1, 3); - - fill_in_information (window, fp); - gtk_widget_show_all (dialog); -} - -void -gsr_window_close (GSRWindow *window) -{ - gtk_widget_destroy (GTK_WIDGET (window)); -} - -static void -file_close_cb (GtkAction *action, - GSRWindow *window) -{ - if (gsr_window_is_saved (window) || gsr_discard_confirmation_dialog (window, TRUE)) - gsr_window_close (window); -} - -static void -quit_cb (GtkAction *action, - GSRWindow *window) -{ - gsr_quit (); -} - -static void -help_contents_cb (GtkAction *action, - GSRWindow *window) -{ - GError *error = NULL; - - gtk_show_uri (gtk_window_get_screen (GTK_WINDOW (window)), - "ghelp:mate-sound-recorder", - gtk_get_current_event_time (), &error); - - if (error != NULL) - { - g_warning ("%s", error->message); - - g_error_free (error); - } -} - -static void -about_cb (GtkAction *action, - GSRWindow *window) -{ - const char * const authors[] = {"Iain Holmes <[email protected]>", - "Ronald Bultje <[email protected]>", - "Johan Dahlin <[email protected]>", - "Tim-Philipp M\303\274ller <tim centricular net>", - NULL}; - const char * const documenters[] = {"Sun Microsystems", NULL}; - - gtk_show_about_dialog (GTK_WINDOW (window), - "name", _("Sound Recorder"), - "version", VERSION, - "copyright", "Copyright \xc2\xa9 2002 Iain Holmes", - "comments", _("A sound recorder for MATE\n [email protected]"), - "authors", authors, - "documenters", documenters, - "logo-icon-name", "mate-sound-recorder", - NULL); -} - -static void -play_cb (GtkAction *action, - GSRWindow *window) -{ - GSRWindowPrivate *priv = window->priv; - - if (priv->has_file == FALSE && !priv->working_file) - return; - - if (priv->play) { - shutdown_pipeline (priv->play); - } - - if ((priv->play = make_play_pipeline (window))) { - gchar *uri; - gchar *usefile; - GFile *file; - - if(priv->has_file == FALSE && priv->working_file) usefile = priv->working_file; - else usefile = priv->filename; - - file = g_file_new_for_commandline_arg (usefile); - uri = g_file_get_uri (file); - g_object_unref (file); - g_object_set (window->priv->play->pipeline, "uri", uri, NULL); - g_free (uri); - - if (priv->record && priv->record->state == GST_STATE_PLAYING) { - set_pipeline_state_to_null (priv->record->pipeline); - } - - gst_element_set_state (priv->play->pipeline, GST_STATE_PLAYING); - } -} - -static void -stop_cb (GtkAction *action, - GSRWindow *window) -{ - GSRWindowPrivate *priv = window->priv; - - /* Work out what's playing */ - if (priv->play && priv->play->state >= GST_STATE_PAUSED) { - GST_DEBUG ("Stopping play pipeline"); - set_pipeline_state_to_null (priv->play->pipeline); - } else if (priv->record && priv->record->state == GST_STATE_PLAYING) { - GST_DEBUG ("Stopping recording source"); - /* GstBaseSrc will automatically send an EOS when stopping */ - gst_element_set_state (priv->record->src, GST_STATE_NULL); - gst_element_get_state (priv->record->src, NULL, NULL, -1); - gst_element_set_locked_state (priv->record->src, TRUE); - - GST_DEBUG ("Stopping recording pipeline"); - set_pipeline_state_to_null (priv->record->pipeline); - gtk_widget_set_sensitive (window->priv->level, FALSE); - gtk_widget_set_sensitive (window->priv->volume_label, FALSE); - gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (window->priv->level), 0.0); - } -} - -static void -record_cb (GtkAction *action, - GSRWindow *window) -{ - if (!gsr_window_is_saved(window) && !gsr_discard_confirmation_dialog (window, FALSE)) - return; - - GSRWindowPrivate *priv = window->priv; - - if (priv->record) { - char *current_source; - shutdown_pipeline (priv->record); - if (!make_record_source (window)) - return; - current_source = gtk_combo_box_get_active_text (GTK_COMBO_BOX (window->priv->input)); - fill_record_input (window, current_source); - } - - if ((priv->record = make_record_pipeline (window))) { - window->priv->len_secs = 0; - window->priv->saved = FALSE; - - g_print ("%s", priv->record_filename); - g_object_set (G_OBJECT (priv->record->sink), - "location", priv->record_filename, - NULL); - - gst_element_set_state (priv->record->pipeline, GST_STATE_PLAYING); - gtk_widget_set_sensitive (window->priv->level, TRUE); - gtk_widget_set_sensitive (window->priv->volume_label, TRUE); - - } -} - -static gboolean -seek_started (GtkRange *range, - GdkEventButton *event, - GSRWindow *window) -{ - g_return_val_if_fail (window->priv != NULL, FALSE); - - window->priv->seek_in_progress = TRUE; - return FALSE; -} - -static gboolean -seek_to (GtkRange *range, - GdkEventButton *gdkevent, - GSRWindow *window) -{ - gdouble value; - gint64 time; - - if (window->priv->play->state < GST_STATE_PLAYING) - return FALSE; - - value = gtk_adjustment_get_value (gtk_range_get_adjustment (range)); - time = ((value / 100.0) * window->priv->len_secs) * GST_SECOND; - - gst_element_seek (window->priv->play->pipeline, 1.0, GST_FORMAT_TIME, - GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, time, - GST_SEEK_TYPE_NONE, 0); - - window->priv->seek_in_progress = FALSE; - - return FALSE; -} - -static gboolean -play_tick_callback (GSRWindow *window) -{ - GstElement *playbin; - GstFormat format = GST_FORMAT_TIME; - gint64 val = -1; - - g_return_val_if_fail (window->priv->play != NULL, FALSE); - g_return_val_if_fail (window->priv->play->pipeline != NULL, FALSE); - - playbin = window->priv->play->pipeline; - - /* This check stops us from doing an unnecessary query */ - if (window->priv->play->state != GST_STATE_PLAYING) { - GST_DEBUG ("pipeline in wrong state: %s", - gst_element_state_get_name (window->priv->play->state)); - window->priv->play->tick_id = 0; - return FALSE; - } - - if (gst_element_query_duration (playbin, &format, &val) && val != -1) { - gchar *len_str; - - window->priv->len_secs = val / GST_SECOND; - - len_str = seconds_to_full_string (window->priv->len_secs); - gtk_label_set_text (GTK_LABEL (window->priv->length_label), - len_str); - g_free (len_str); - } else { - if (window->priv->get_length_attempts <= 0) { - /* Attempts to get length ran out. */ - gtk_label_set_text (GTK_LABEL (window->priv->length_label), _("Unknown")); - } else { - --window->priv->get_length_attempts; - } - } - - if (window->priv->seek_in_progress) { - GST_DEBUG ("seek in progress, try again later"); - return TRUE; - } - - if (window->priv->len_secs == 0) { - GST_DEBUG ("no duration, try again later"); - return TRUE; - } - - if (gst_element_query_position (playbin, &format, &val) && val != -1) { - gdouble pos, len, percentage; - - pos = (gdouble) (val - (val % GST_SECOND)); - len = (gdouble) window->priv->len_secs * GST_SECOND; - percentage = pos / len * 100.0; - - gtk_adjustment_set_value (gtk_range_get_adjustment (GTK_RANGE (window->priv->scale)), - CLAMP (percentage + 0.5, 0.0, 100.0)); - } else { - GST_DEBUG ("failed to query position"); - } - - return TRUE; -} - -static gboolean -record_tick_callback (GSRWindow *window) -{ - GstElement *pipeline; - GstFormat format = GST_FORMAT_TIME; - gint64 val = -1; - gint secs; - - /* This check stops us from doing an unnecessary query */ - if (window->priv->record->state != GST_STATE_PLAYING) { - GST_DEBUG ("pipeline in wrong state: %s", - gst_element_state_get_name (window->priv->record->state)); - return FALSE; - } - - if (window->priv->seek_in_progress) - return TRUE; - - pipeline = window->priv->record->pipeline; - - if (gst_element_query_position (pipeline, &format, &val) && val != -1) { - gchar* len_str; - - secs = val / GST_SECOND; - - len_str = seconds_to_full_string (secs); - window->priv->len_secs = secs; - gtk_label_set_text (GTK_LABEL (window->priv->length_label), - len_str); - g_free (len_str); - } else { - GST_DEBUG ("failed to query position"); - } - - return TRUE; -} - -static void -play_state_changed_cb (GstBus * bus, GstMessage * msg, GSRWindow * window) -{ - GstState new_state; - - gst_message_parse_state_changed (msg, NULL, &new_state, NULL); - - g_return_if_fail (GSR_IS_WINDOW (window)); - - /* we are only interested in state changes of the top-level pipeline */ - if (msg->src != GST_OBJECT (window->priv->play->pipeline)) - return; - - window->priv->play->state = new_state; - - GST_DEBUG ("playbin state: %s", gst_element_state_get_name (new_state)); - - switch (new_state) { - case GST_STATE_PLAYING: - if (window->priv->play->tick_id == 0) { - window->priv->play->tick_id = - g_timeout_add (200, (GSourceFunc) play_tick_callback, window); - } - - set_action_sensitive (window, "Stop", TRUE); - set_action_sensitive (window, "Play", FALSE); - set_action_sensitive (window, "Record", FALSE); - set_action_sensitive (window, "FileSave", FALSE); - set_action_sensitive (window, "FileSaveAs", FALSE); - gtk_widget_set_sensitive (window->priv->scale, TRUE); - - gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar), - window->priv->status_message_cid); - gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar), - window->priv->status_message_cid, - _("Playing…")); - - if (window->priv->ebusy_timeout_id) { - g_source_remove (window->priv->ebusy_timeout_id); - window->priv->ebusy_timeout_id = 0; - window->priv->ebusy_pipeline = NULL; - } - break; - - case GST_STATE_READY: - if (window->priv->play->tick_id > 0) { - g_source_remove (window->priv->play->tick_id); - window->priv->play->tick_id = 0; - } - gtk_adjustment_set_value (gtk_range_get_adjustment (GTK_RANGE (window->priv->scale)), 0.0); - gtk_widget_set_sensitive (window->priv->scale, FALSE); - /* fallthrough */ - case GST_STATE_PAUSED: - set_action_sensitive (window, "Stop", FALSE); - set_action_sensitive (window, "Play", TRUE); - set_action_sensitive (window, "Record", TRUE); - set_action_sensitive (window, "FileSave", TRUE); - set_action_sensitive (window, "FileSaveAs", TRUE); - - gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar), - window->priv->status_message_cid); - gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar), - window->priv->status_message_cid, - _("Ready")); - break; - default: - break; - } -} - -static void -pipeline_deep_notify_caps_cb (GstObject *pipeline, - GstObject *object, - GParamSpec *pspec, - GSRWindow *window) -{ - GSRWindowPrivate *priv; - GstPadDirection direction; - - if (!GST_IS_PAD (object)) - return; - - priv = window->priv; - if (priv->play && pipeline == GST_OBJECT_CAST (priv->play->pipeline)) { - direction = GST_PAD_SRC; - } else if (priv->record && pipeline == GST_OBJECT_CAST (priv->record->pipeline)) { - direction = GST_PAD_SINK; - } else { - g_return_if_reached (); - } - - if (GST_PAD_DIRECTION (object) == direction) { - GstObject *pad_parent; - - pad_parent = gst_object_get_parent (object); - if (GST_IS_ELEMENT (pad_parent)) { - GstElementFactory *factory; - GstElement *element; - const gchar *klass; - - element = GST_ELEMENT_CAST (pad_parent); - if ((factory = gst_element_get_factory (element)) && - (klass = gst_element_factory_get_klass (factory)) && - strstr (klass, "Audio") && - (strstr (klass, "Decoder") || strstr (klass, "Encoder"))) { - GstCaps *caps; - - caps = gst_pad_get_negotiated_caps (GST_PAD_CAST (object)); - if (caps) { - GstStructure *s; - gint val; - - s = gst_caps_get_structure (caps, 0); - if (gst_structure_get_int (s, "channels", &val)) { - gst_atomic_int_set (&priv->atomic.n_channels, val); - } - if (gst_structure_get_int (s, "rate", &val)) { - gst_atomic_int_set (&priv->atomic.samplerate, val); - } - gst_caps_unref (caps); - } - } - } - if (pad_parent) - gst_object_unref (pad_parent); - } -} - -/* callback for when the recording profile has been changed */ -static void -profile_changed_cb (GObject *object, GSRWindow *window) -{ - GMAudioProfile *profile; - gchar *id; - - g_return_if_fail (GTK_IS_COMBO_BOX (object)); - - profile = gm_audio_profile_choose_get_active (GTK_WIDGET (object)); - - if (profile != NULL) { - id = g_strdup (gm_audio_profile_get_id (profile)); - GST_DEBUG ("profile changed to %s", GST_STR_NULL (id)); - mateconf_client_set_string (mateconf_client, KEY_LAST_PROFILE_ID, id, NULL); - g_free (id); - } -} - -static void -play_eos_msg_cb (GstBus * bus, GstMessage * msg, GSRWindow * window) -{ - g_return_if_fail (GSR_IS_WINDOW (window)); - - GST_DEBUG ("EOS"); - - stop_cb (NULL, window); -} - -static GSRWindowPipeline * -make_play_pipeline (GSRWindow *window) -{ - GSRWindowPipeline *obj; - GstElement *playbin; - GstElement *audiosink; - - audiosink = gst_element_factory_make ("mateconfaudiosink", "sink"); - if (audiosink == NULL) { - show_missing_known_element_error (NULL, - _("MateConf audio output"), "mateconfaudiosink", "mateconfelements", - "gst-plugins-good"); - return NULL; - } - - playbin = gst_element_factory_make ("playbin", "playbin"); - if (playbin == NULL) { - gst_object_unref (audiosink); - show_missing_known_element_error (NULL, - _("Playback"), "playbin", "playback", - "gst-plugins-base"); - return NULL; - } - - obj = g_new0 (GSRWindowPipeline, 1); - obj->pipeline = playbin; - obj->src = NULL; /* don't need that for playback */ - obj->sink = NULL; /* don't need that for playback */ - - g_object_set (playbin, "audio-sink", audiosink, NULL); - - /* we ultimately want to find out the caps on the decoder's source pad */ - g_signal_connect (playbin, "deep-notify::caps", - G_CALLBACK (pipeline_deep_notify_caps_cb), - window); - - obj->bus = gst_element_get_bus (playbin); - - gst_bus_add_signal_watch_full (obj->bus, G_PRIORITY_HIGH); - - g_signal_connect (obj->bus, "message::state-changed", - G_CALLBACK (play_state_changed_cb), - window); - - g_signal_connect (obj->bus, "message::error", - G_CALLBACK (pipeline_error_cb), - window); - - g_signal_connect (obj->bus, "message::eos", - G_CALLBACK (play_eos_msg_cb), - window); - - return obj; -} - -static void -record_eos_msg_cb (GstBus * bus, GstMessage * msg, GSRWindow * window) -{ - g_return_if_fail (GSR_IS_WINDOW (window)); - - GST_DEBUG ("EOS. Finished recording"); - - /* FIXME: this was READY before (why?) */ - set_pipeline_state_to_null (window->priv->record->pipeline); - - g_free (window->priv->working_file); - window->priv->working_file = g_strdup (window->priv->record_filename); - - g_free (window->priv->filename); - window->priv->filename = g_strdup (window->priv->record_filename); - - window->priv->has_file = TRUE; -} - -extern int gsr_sample_count; - -static gboolean -record_start (gpointer user_data) -{ - GSRWindow *window = GSR_WINDOW (user_data); - gchar *name; - - g_assert (window->priv->tick_id == 0); - - window->priv->get_length_attempts = 16; - window->priv->tick_id = g_timeout_add (200, (GSourceFunc) record_tick_callback, window); - - set_action_sensitive (window, "Stop", TRUE); - set_action_sensitive (window, "Play", FALSE); - set_action_sensitive (window, "Record", FALSE); - set_action_sensitive (window, "FileSave", FALSE); - set_action_sensitive (window, "FileSaveAs", FALSE); - gtk_widget_set_sensitive (window->priv->scale, FALSE); - - gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar), - window->priv->status_message_cid); - gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar), - window->priv->status_message_cid, - _("Recording…")); - - window->priv->record_id = 0; - - /* Translator comment: untitled here implies that - * there is no active sound sample. Any newly - * recorded samples will be saved to disk with this - * name as default value. */ - if (gsr_sample_count == 1) { - name = g_strdup (_("Untitled")); - } else { - name = g_strdup_printf (_("Untitled-%d"), gsr_sample_count); - } - ++gsr_sample_count; - gtk_window_set_title (GTK_WINDOW(window), name); - - g_free (name); - - return FALSE; -} - -static void -record_state_changed_cb (GstBus *bus, GstMessage *msg, GSRWindow *window) -{ - GstState new_state; - GMAudioProfile *profile; - - gst_message_parse_state_changed (msg, NULL, &new_state, NULL); - - g_return_if_fail (GSR_IS_WINDOW (window)); - - /* we are only interested in state changes of the top-level pipeline */ - if (msg->src != GST_OBJECT (window->priv->record->pipeline)) - return; - - window->priv->record->state = new_state; - - GST_DEBUG ("record pipeline state: %s", gst_element_state_get_name (new_state)); - - switch (new_state) { - case GST_STATE_PLAYING: - window->priv->record_id = g_idle_add (record_start, window); - g_free (window->priv->extension); - profile = gm_audio_profile_choose_get_active (window->priv->profile); - window->priv->extension = g_strdup (profile ? gm_audio_profile_get_extension (profile) : NULL); - gtk_widget_set_sensitive (window->priv->profile, FALSE); - gtk_widget_set_sensitive (window->priv->input, FALSE); - break; - case GST_STATE_READY: - gtk_adjustment_set_value (gtk_range_get_adjustment (GTK_RANGE (window->priv->scale)), 0.0); - gtk_widget_set_sensitive (window->priv->scale, FALSE); - gtk_widget_set_sensitive (window->priv->profile, TRUE); - gtk_widget_set_sensitive (window->priv->input, GST_IS_MIXER (window->priv->mixer)); - /* fall through */ - case GST_STATE_PAUSED: - set_action_sensitive (window, "Stop", FALSE); - set_action_sensitive (window, "Play", TRUE); - set_action_sensitive (window, "Record", TRUE); - set_action_sensitive (window, "FileSave", TRUE); - set_action_sensitive (window, "FileSaveAs", TRUE); - gtk_widget_set_sensitive (window->priv->scale, FALSE); - gtk_widget_set_sensitive (window->priv->profile, TRUE); - gtk_widget_set_sensitive (window->priv->input, TRUE); - - gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar), - window->priv->status_message_cid); - gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar), - window->priv->status_message_cid, - _("Ready")); - if (window->priv->tick_id > 0) { - g_source_remove (window->priv->tick_id); - window->priv->tick_id = 0; - } - break; - default: - break; - } -} - -/* create the mateconf-based source for recording. - * store the source and the mixer in it in our window-private data - */ -static gboolean -make_record_source (GSRWindow *window) -{ - GstElement *source, *e; - - source = gst_element_factory_make ("mateconfaudiosrc", "mateconfaudiosource"); - if (source == NULL) { - show_missing_known_element_error (NULL, - _("MateConf audio recording"), "mateconfaudiosrc", - "mateconfelements", "gst-plugins-good"); - return FALSE; - } - - /* instantiate the underlying element so we can query it */ - /* FIXME: maybe we want to trap errors in this case ? */ - if (!gst_element_set_state (source, GST_STATE_READY)) { - show_error_dialog (NULL, NULL, - _("Your audio capture settings are invalid. " - "Please correct them with the \"Sound Preferences\" " - "under the System Preferences menu.")); - return FALSE; - } - window->priv->source = source; - e = gst_bin_get_by_interface (GST_BIN (source), GST_TYPE_MIXER); - window->priv->mixer = GST_MIXER (e); - - return TRUE; -} - -static void -record_input_changed_cb (GtkComboBox *input, GSRWindow *window) -{ - const gchar *text; - const GList *l; - GstMixerTrack *t = NULL, *new = NULL; - static GstMixerTrack *selected = NULL; - - text = gtk_combo_box_get_active_text (input); - GST_DEBUG ("record input changed to '%s'", GST_STR_NULL (text)); - - if (text == NULL) - return; - - /* The pipeline has been destroyed already, we'll try and remember - * the input for the next record run in fill_record_input() */ - if (GST_IS_MIXER (window->priv->mixer) == FALSE) - return; - - for (l = gst_mixer_list_tracks (window->priv->mixer); - l != NULL; l = l->next) { - t = l->data; - if (t == NULL || t->label == NULL) - continue; - if ((g_str_equal (t->label, text)) && - (t->flags & GST_MIXER_TRACK_INPUT)) { - if (new == NULL) - new = g_object_ref (t); - /* FIXME selected == t is equivalent to NULL == t in this case, - * selected, after its initialization to NULL, was never written to - * before this read access to it - * and NULL == t is equivalent to FALSE, because of the check - * "if (t == NULL || t->label == NULL)" above - */ - } else if (selected == t) - /* re-mute old one */ - gst_mixer_set_record (window->priv->mixer, - selected, FALSE); - } - - /* FIXME selected _is_ NULL always at this point - same as 5 lines above*/ - if (selected != NULL) - g_object_unref (selected); - if (!(selected = new)) - return; - - gst_mixer_set_record (window->priv->mixer, selected, TRUE); - GST_DEBUG ("input changed to: %s\n", selected->label); - mateconf_client_set_string (mateconf_client, KEY_LAST_INPUT, selected->label, NULL); -} - -static void -fill_record_input (GSRWindow *window, gchar *selected) -{ - const GList *l; - int i = 0; - int last_possible_i = 0; - GtkTreeModel *model; - - model = gtk_combo_box_get_model (GTK_COMBO_BOX (window->priv->input)); - - if (model) - gtk_list_store_clear (GTK_LIST_STORE (model)); - - if (GST_IS_MIXER (window->priv->mixer) == FALSE - || gst_mixer_list_tracks (window->priv->mixer) == NULL) { - gtk_widget_hide (window->priv->input); - gtk_widget_hide (window->priv->input_label); - return; - } - - gtk_widget_set_sensitive (window->priv->input, GST_IS_MIXER (window->priv->mixer)); - if (!GST_IS_MIXER (window->priv->mixer)) - return; - - for (l = gst_mixer_list_tracks (window->priv->mixer); l != NULL; l = l->next) { - GstMixerTrack *t = l->data; - if (t->label == NULL) - continue; - if (t->flags & GST_MIXER_TRACK_INPUT) { - gtk_combo_box_append_text (GTK_COMBO_BOX (window->priv->input), t->label); - ++i; - } - if (t->flags & GST_MIXER_TRACK_RECORD) { - if (selected == NULL) { - gtk_combo_box_set_active (GTK_COMBO_BOX (window->priv->input), i - 1); - } else { - last_possible_i = i; - } - } - if ((selected != NULL) && g_str_equal (selected, t->label)) { - gtk_combo_box_set_active (GTK_COMBO_BOX (window->priv->input), i - 1); - } - } - - if (gtk_combo_box_get_active (GTK_COMBO_BOX (window->priv->input)) == -1) { - gtk_combo_box_set_active (GTK_COMBO_BOX (window->priv->input), last_possible_i - 1); - } - - gtk_widget_show (window->priv->input); - gtk_widget_show (window->priv->input_label); -} - -static gboolean -level_message_handler_cb (GstBus * bus, GstMessage * message, GSRWindow *window) -{ - GSRWindowPrivate *priv = window->priv; - - if (message->type == GST_MESSAGE_ELEMENT) { - const GstStructure *s = gst_message_get_structure (message); - const gchar *name = gst_structure_get_name (s); - - if (g_str_equal (name, "level")) { - gint channels; - gdouble peak_dB; - gdouble myind; - const GValue *list; - const GValue *value; - - gint i; - /* we can get the number of channels as the length of any of the value - * lists */ - - list = gst_structure_get_value (s, "rms"); - channels = gst_value_list_get_size (list); - - for (i = 0; i < channels; ++i) { - list = gst_structure_get_value (s, "peak"); - value = gst_value_list_get_value (list, i); - peak_dB = g_value_get_double (value); - myind = exp (peak_dB / 20); - if (myind > 1.0) - myind = 1.0; - gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (priv->level), myind); - } - } - } - /* we handled the message we want, and ignored the ones we didn't want. - * so the core can unref the message for us */ - return TRUE; -} - -static GSRWindowPipeline * -make_record_pipeline (GSRWindow *window) -{ - GSRWindowPipeline *pipeline; - GMAudioProfile *profile; - const gchar *profile_pipeline_desc; - GstElement *encoder, *source, *filesink, *level; - GError *err = NULL; - gchar *pipeline_desc; - const char *name; - - source = window->priv->source; - - /* Any reason we are not using matevfssink here? (tpm) */ - filesink = gst_element_factory_make ("filesink", "sink"); - if (filesink == NULL) - { - show_missing_known_element_error (NULL, - _("file output"), "filesink", "coreelements", - "gstreamer"); - gst_object_unref (source); - return NULL; - } - - pipeline = g_new (GSRWindowPipeline, 1); - - pipeline->pipeline = gst_pipeline_new ("record-pipeline"); - pipeline->src = source; - pipeline->sink = filesink; - - gst_bin_add (GST_BIN (pipeline->pipeline), source); - - level = gst_element_factory_make ("level", "level"); - if (level == NULL) - { - show_missing_known_element_error (NULL, - _("level"), "level", "level", - "gstreamer"); - gst_object_unref (source); - return NULL; - } - gst_element_set_name (level, "level"); - - profile = gm_audio_profile_choose_get_active (window->priv->profile); - if (profile == NULL) - return NULL; - profile_pipeline_desc = gm_audio_profile_get_pipeline (profile); - name = gm_audio_profile_get_name (profile); - - GST_DEBUG ("encoder profile pipeline: '%s'", - GST_STR_NULL (profile_pipeline_desc)); - - pipeline_desc = g_strdup_printf ("audioconvert ! %s", profile_pipeline_desc); - GST_DEBUG ("making encoder bin from description '%s'", pipeline_desc); - encoder = gst_parse_bin_from_description (pipeline_desc, TRUE, &err); - g_free (pipeline_desc); - pipeline_desc = NULL; - - if (err) { - show_profile_error (NULL, err->message, - _("Could not parse the '%s' audio profile. "), name); - g_printerr ("Failed to create GStreamer encoder plugins [%s]: %s\n", - profile_pipeline_desc, err->message); - g_error_free (err); - gst_object_unref (pipeline->pipeline); - gst_object_unref (filesink); - g_free (pipeline); - return NULL; - } - - gst_bin_add (GST_BIN (pipeline->pipeline), level); - gst_bin_add (GST_BIN (pipeline->pipeline), encoder); - gst_bin_add (GST_BIN (pipeline->pipeline), filesink); - - /* now link it all together */ - if (!(gst_element_link_many (source, level, encoder, NULL))) { - show_profile_error (NULL, NULL, - _("Could not capture using the '%s' audio profile. "), - name); - gst_object_unref (pipeline->pipeline); - g_free (pipeline); - return NULL; - } - - if (!gst_element_link (encoder, filesink)) { - show_profile_error (NULL, NULL, - _("Could not write to a file using the '%s' audio profile. "), - name); - gst_object_unref (pipeline->pipeline); - g_free (pipeline); - return NULL; - } - - /* we ultimately want to find out the caps on the encoder's source pad */ - g_signal_connect (pipeline->pipeline, "deep-notify::caps", - G_CALLBACK (pipeline_deep_notify_caps_cb), - window); - - pipeline->bus = gst_element_get_bus (pipeline->pipeline); - - gst_bus_add_signal_watch (pipeline->bus); - - g_signal_connect (pipeline->bus, "message::element", - G_CALLBACK (level_message_handler_cb), - window); - - g_signal_connect (pipeline->bus, "message::state-changed", - G_CALLBACK (record_state_changed_cb), - window); - - g_signal_connect (pipeline->bus, "message::error", - G_CALLBACK (pipeline_error_cb), - window); - - g_signal_connect (pipeline->bus, "message::eos", - G_CALLBACK (record_eos_msg_cb), - window); - - return pipeline; -} - -static char * -calculate_format_value (GtkScale *scale, - double value, - GSRWindow *window) -{ - gint seconds; - - if (window->priv->record && window->priv->record->state == GST_STATE_PLAYING) { - seconds = value; - return seconds_to_string (seconds); - } else { - seconds = window->priv->len_secs * (value / 100); - return seconds_to_string (seconds); - } -} - -static const GtkActionEntry menu_entries[] = -{ - /* File menu. */ - { "File", NULL, N_("_File") }, - { "FileNew", GTK_STOCK_NEW, NULL, NULL, - N_("Create a new sample"), G_CALLBACK (file_new_cb) }, - { "FileOpen", GTK_STOCK_OPEN, NULL, NULL, - N_("Open a file"), G_CALLBACK (file_open_cb) }, - { "FileSave", GTK_STOCK_SAVE, NULL, NULL, - N_("Save the current file"), G_CALLBACK (file_save_cb) }, - { "FileSaveAs", GTK_STOCK_SAVE_AS, NULL, "<shift><control>S", - N_("Save the current file with a different name"), G_CALLBACK (file_save_as_cb) }, - { "RunMixer", GTK_STOCK_EXECUTE, N_("Open Volu_me Control"), NULL, - N_("Open the audio mixer"), G_CALLBACK (run_mixer_cb) }, - { "FileProperties", GTK_STOCK_PROPERTIES, NULL, "<control>I", - N_("Show information about the current file"), G_CALLBACK (file_properties_cb) }, - { "FileClose", GTK_STOCK_CLOSE, NULL, NULL, - N_("Close the current file"), G_CALLBACK (file_close_cb) }, - { "Quit", GTK_STOCK_QUIT, NULL, NULL, - N_("Quit the program"), G_CALLBACK (quit_cb) }, - - /* Control menu */ - { "Control", NULL, N_("_Control") }, - { "Record", GTK_STOCK_MEDIA_RECORD, NULL, "<control>R", - N_("Record sound"), G_CALLBACK (record_cb) }, - { "Play", GTK_STOCK_MEDIA_PLAY, NULL, "<control>P", - N_("Play sound"), G_CALLBACK (play_cb) }, - { "Stop", GTK_STOCK_MEDIA_STOP, NULL, "<control>X", - N_("Stop sound"), G_CALLBACK (stop_cb) }, - - /* Help menu */ - { "Help", NULL, N_("_Help") }, - {"HelpContents", GTK_STOCK_HELP, N_("Contents"), "F1", - N_("Open the manual"), G_CALLBACK (help_contents_cb) }, - { "About", GTK_STOCK_ABOUT, NULL, NULL, - N_("About this application"), G_CALLBACK (about_cb) } -}; - -static void -menu_item_select_cb (GtkMenuItem *proxy, - GSRWindow *window) -{ - GtkAction *action; - char *message; - - action = g_object_get_data (G_OBJECT (proxy), "gtk-action"); - g_return_if_fail (action != NULL); - - g_object_get (G_OBJECT (action), "tooltip", &message, NULL); - if (message) { - gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar), - window->priv->tip_message_cid, message); - g_free (message); - } -} - -static void -menu_item_deselect_cb (GtkMenuItem *proxy, - GSRWindow *window) -{ - gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar), - window->priv->tip_message_cid); -} - -static void -connect_proxy_cb (GtkUIManager *manager, - GtkAction *action, - GtkWidget *proxy, - GSRWindow *window) -{ - if (GTK_IS_MENU_ITEM (proxy)) { - g_signal_connect (proxy, "select", - G_CALLBACK (menu_item_select_cb), window); - g_signal_connect (proxy, "deselect", - G_CALLBACK (menu_item_deselect_cb), window); - } -} - -static void -disconnect_proxy_cb (GtkUIManager *manager, - GtkAction *action, - GtkWidget *proxy, - GSRWindow *window) -{ - if (GTK_IS_MENU_ITEM (proxy)) { - g_signal_handlers_disconnect_by_func - (proxy, G_CALLBACK (menu_item_select_cb), window); - g_signal_handlers_disconnect_by_func - (proxy, G_CALLBACK (menu_item_deselect_cb), window); - } -} - -/* find the given filename in the uninstalled or installed ui dir */ -static gchar * -find_ui_file (const gchar * filename) -{ - gchar * path; - - path = g_build_filename (GSR_UIDIR_UNINSTALLED, filename, NULL); - if (g_file_test (path, G_FILE_TEST_EXISTS)) - return path; - - g_free (path); - path = g_build_filename (GSR_UIDIR, filename, NULL); - if (g_file_test (path, G_FILE_TEST_EXISTS)) - return path; - - g_free (path); - return NULL; -} - -static void -gsr_window_init (GSRWindow *window) -{ - GSRWindowPrivate *priv; - GError *error = NULL; - GtkWidget *main_vbox; - GtkWidget *menubar; - GtkWidget *file_menu; - GtkWidget *submenu; - GtkWidget *rec_menu; - GtkWidget *toolbar; - GtkWidget *content_vbox; - GtkWidget *hbox; - GtkWidget *label; - GtkWidget *table; - GtkWidget *align; - GtkWidget *frame; - gchar *id; - gchar *last_input; - gchar *path; - GtkAction *action; - GtkShadowType shadow_type; - window->priv = GSR_WINDOW_GET_PRIVATE (window); - priv = window->priv; - - /* treat mateconf client as a singleton */ - if (mateconf_client == NULL) - mateconf_client = mateconf_client_get_default (); - - main_vbox = gtk_vbox_new (FALSE, 0); - gtk_container_add (GTK_CONTAINER (window), main_vbox); - priv->main_vbox = main_vbox; - gtk_widget_show (main_vbox); - - /* menu & toolbar */ - priv->ui_manager = gtk_ui_manager_new (); - - gtk_window_add_accel_group (GTK_WINDOW (window), - gtk_ui_manager_get_accel_group (priv->ui_manager)); - - path = find_ui_file ("ui.xml"); - gtk_ui_manager_add_ui_from_file (priv->ui_manager, path, &error); - - if (error != NULL) - { - show_error_dialog (GTK_WINDOW (window), error->message, - _("Could not load UI file. The program may not be properly installed.")); - g_error_free (error); - exit (1); - } - g_free (path); - - /* show tooltips in the statusbar */ - g_signal_connect (priv->ui_manager, "connect_proxy", - G_CALLBACK (connect_proxy_cb), window); - g_signal_connect (priv->ui_manager, "disconnect_proxy", - G_CALLBACK (disconnect_proxy_cb), window); - - priv->action_group = gtk_action_group_new ("GSRWindowActions"); - gtk_action_group_set_translation_domain (priv->action_group, NULL); - gtk_action_group_add_actions (priv->action_group, - menu_entries, - G_N_ELEMENTS (menu_entries), - window); - - gtk_ui_manager_insert_action_group (priv->ui_manager, priv->action_group, 0); - - /* set short labels to use in the toolbar */ - action = gtk_action_group_get_action (priv->action_group, "FileOpen"); - g_object_set (action, "short_label", _("Open"), NULL); - action = gtk_action_group_get_action (priv->action_group, "FileSave"); - g_object_set (action, "short_label", _("Save"), NULL); - action = gtk_action_group_get_action (priv->action_group, "FileSaveAs"); - g_object_set (action, "short_label", _("Save As"), NULL); - - set_action_sensitive (window, "FileSave", FALSE); - set_action_sensitive (window, "FileSaveAs", FALSE); - set_action_sensitive (window, "Play", FALSE); - set_action_sensitive (window, "Stop", FALSE); - - menubar = gtk_ui_manager_get_widget (priv->ui_manager, "/MenuBar"); - gtk_box_pack_start (GTK_BOX (main_vbox), menubar, FALSE, FALSE, 0); - gtk_widget_show (menubar); - - toolbar = gtk_ui_manager_get_widget (priv->ui_manager, "/ToolBar"); - gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), FALSE); - gtk_box_pack_start (GTK_BOX (main_vbox), toolbar, FALSE, FALSE, 0); - gtk_widget_show (toolbar); - - /* recent files */ - file_menu = gtk_ui_manager_get_widget (priv->ui_manager, - "/MenuBar/FileMenu"); - submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (file_menu)); - rec_menu = gtk_ui_manager_get_widget (priv->ui_manager, - "/MenuBar/FileMenu/FileRecentMenu"); - priv->recent_view = gtk_recent_chooser_menu_new (); - gtk_recent_chooser_set_local_only (GTK_RECENT_CHOOSER (priv->recent_view), TRUE); - gtk_recent_chooser_set_limit (GTK_RECENT_CHOOSER (priv->recent_view), 5); - priv->recent_filter = gtk_recent_filter_new (); - gtk_recent_filter_add_application (priv->recent_filter, g_get_application_name ()); - gtk_recent_chooser_set_filter (GTK_RECENT_CHOOSER (priv->recent_view), priv->recent_filter); - g_signal_connect (priv->recent_view, "item-activated", - G_CALLBACK (file_open_recent_cb), window); - - /* window content: hscale, labels, etc */ - content_vbox = gtk_vbox_new (FALSE, 7); - gtk_container_set_border_width (GTK_CONTAINER (content_vbox), 6); - gtk_box_pack_start (GTK_BOX (main_vbox), content_vbox, TRUE, TRUE, 0); - gtk_widget_show (content_vbox); - - priv->scale = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, 0, 100, 1, 1, 0))); - priv->seek_in_progress = FALSE; - g_signal_connect (priv->scale, "format-value", - G_CALLBACK (calculate_format_value), window); - g_signal_connect (priv->scale, "button-press-event", - G_CALLBACK (seek_started), window); - g_signal_connect (priv->scale, "button-release-event", - G_CALLBACK (seek_to), window); - - gtk_scale_set_value_pos (GTK_SCALE (window->priv->scale), GTK_POS_BOTTOM); - /* We can't seek until we find out the length */ - gtk_widget_set_sensitive (window->priv->scale, FALSE); - gtk_box_pack_start (GTK_BOX (content_vbox), priv->scale, FALSE, FALSE, 6); - gtk_widget_show (window->priv->scale); - - /* create source and choose mixer input */ - hbox = gtk_hbox_new (FALSE, 12); - gtk_box_pack_start (GTK_BOX (content_vbox), hbox, FALSE, FALSE, 0); - - priv->input_label = gtk_label_new_with_mnemonic (_("Record from _input:")); - gtk_misc_set_alignment (GTK_MISC (priv->input_label), 0, 0.5); - gtk_box_pack_start (GTK_BOX (hbox), priv->input_label, FALSE, FALSE, 0); - - priv->input = gtk_combo_box_new_text (); - gtk_label_set_mnemonic_widget (GTK_LABEL (priv->input_label), priv->input); - gtk_box_pack_start (GTK_BOX (hbox), priv->input, TRUE, TRUE, 0); - - if (!make_record_source (window)) - exit (1); - - g_signal_connect (priv->input, "changed", - G_CALLBACK (record_input_changed_cb), window); - - /* choose profile */ - hbox = gtk_hbox_new (FALSE, 12); - gtk_box_pack_start (GTK_BOX (content_vbox), hbox, FALSE, FALSE, 0); - - label = gtk_label_new_with_mnemonic (_("_Record as:")); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - priv->profile = gm_audio_profile_choose_new (); - gtk_label_set_mnemonic_widget (GTK_LABEL (label), priv->profile); - gtk_box_pack_start (GTK_BOX (hbox), window->priv->profile, TRUE, TRUE, 0); - gtk_widget_show (window->priv->profile); - - atk_object_add_relationship (gtk_widget_get_accessible (GTK_WIDGET (priv->profile)), - ATK_RELATION_LABELLED_BY, - gtk_widget_get_accessible (GTK_WIDGET (label))); - - id = mateconf_client_get_string (mateconf_client, KEY_LAST_PROFILE_ID, NULL); - if (id) { - gm_audio_profile_choose_set_active (window->priv->profile, id); - g_free (id); - } - - g_signal_connect (priv->profile, "changed", - G_CALLBACK (profile_changed_cb), window); - - hbox = gtk_hbox_new (FALSE, 0); - gtk_box_pack_start (GTK_BOX (content_vbox), hbox, FALSE, FALSE, 0); - - label = gtk_label_new (" "); /* FIXME: better padding? */ - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - table = gtk_table_new (3, 2, FALSE); - gtk_table_set_col_spacings (GTK_TABLE (table), 12); - gtk_table_set_row_spacings (GTK_TABLE (table), 6); - gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0); - - label = make_title_label (_("File Information")); - - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - gtk_table_attach (GTK_TABLE (table), label, - 0, 2, 0, 1, - GTK_FILL, 0, 0, 0); - - label = gtk_label_new (_("Filename:")); - - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - gtk_table_attach (GTK_TABLE (table), label, - 0, 1, 1, 2, - GTK_FILL, 0, 0, 0); - - priv->name_label = gtk_label_new (_("<none>")); - gtk_label_set_selectable (GTK_LABEL (priv->name_label), TRUE); - gtk_label_set_line_wrap (GTK_LABEL (priv->name_label), GTK_WRAP_WORD); - gtk_misc_set_alignment (GTK_MISC (priv->name_label), 0, 0.5); - gtk_table_attach (GTK_TABLE (table), priv->name_label, - 1, 2, 1, 2, - GTK_FILL | GTK_EXPAND, 0, - 0, 0); - - atk_object_add_relationship (gtk_widget_get_accessible (GTK_WIDGET (priv->name_label)), - ATK_RELATION_LABELLED_BY, - gtk_widget_get_accessible (GTK_WIDGET (label))); - - - label = gtk_label_new (_("Length:")); - - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); - gtk_table_attach (GTK_TABLE (table), label, - 0, 1, 2, 3, - GTK_FILL, 0, 0, 0); - - priv->length_label = gtk_label_new (""); - gtk_label_set_selectable (GTK_LABEL (priv->length_label), TRUE); - gtk_misc_set_alignment (GTK_MISC (priv->length_label), 0, 0.5); - gtk_table_attach (GTK_TABLE (table), priv->length_label, - 1, 2, 2, 3, - GTK_FILL | GTK_EXPAND, 0, - 0, 0); - - atk_object_add_relationship (gtk_widget_get_accessible (GTK_WIDGET (priv->length_label)), - ATK_RELATION_LABELLED_BY, - gtk_widget_get_accessible (GTK_WIDGET (label))); - - /* statusbar */ - priv->statusbar = gtk_statusbar_new (); - gtk_widget_set_can_focus (priv->statusbar, TRUE); - gtk_box_pack_end (GTK_BOX (main_vbox), priv->statusbar, FALSE, FALSE, 0); - gtk_widget_show (priv->statusbar); - - /* hack to get the same shadow as the status bar.. */ - gtk_widget_style_get (GTK_WIDGET (priv->statusbar), "shadow-type", &shadow_type, NULL); - - frame = gtk_frame_new (NULL); - gtk_frame_set_shadow_type (GTK_FRAME (frame), shadow_type); - gtk_widget_show (frame); - - gtk_box_pack_end (GTK_BOX (priv->statusbar), frame, FALSE, TRUE, 0); - - hbox = gtk_hbox_new (FALSE, 0); - gtk_container_add (GTK_CONTAINER (frame), hbox); - gtk_box_set_spacing (GTK_BOX (hbox), 6); - - priv->volume_label = gtk_label_new (_("Level:")); - gtk_box_pack_start (GTK_BOX (hbox), priv->volume_label, FALSE, TRUE, 0); - - /* initialize priv->level */ - align = gtk_aspect_frame_new ("", 0.0, 0.0, 20, FALSE); - gtk_frame_set_shadow_type (GTK_FRAME (align), GTK_SHADOW_NONE); - gtk_widget_show (align); - gtk_box_pack_start (GTK_BOX (hbox), align, FALSE, FALSE, 0); - - priv->level = gtk_progress_bar_new (); - gtk_container_add (GTK_CONTAINER (align), priv->level); - - gtk_widget_set_sensitive (window->priv->volume_label, FALSE); - gtk_widget_set_sensitive (window->priv->level, FALSE); - - priv->status_message_cid = gtk_statusbar_get_context_id - (GTK_STATUSBAR (priv->statusbar), "status_message"); - priv->tip_message_cid = gtk_statusbar_get_context_id - (GTK_STATUSBAR (priv->statusbar), "tip_message"); - - gtk_statusbar_push (GTK_STATUSBAR (priv->statusbar), - priv->status_message_cid, - _("Ready")); - - gtk_widget_show_all (main_vbox); - last_input = mateconf_client_get_string (mateconf_client, KEY_LAST_INPUT, NULL); - fill_record_input (window, last_input); - if (last_input) { - g_free (last_input); - } - - /* Make the pipelines */ - priv->play = NULL; - priv->record = NULL; - - priv->len_secs = 0; - priv->get_length_attempts = 16; - priv->dirty = TRUE; -} - -static void -gsr_window_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GSRWindow *window; - GSRWindowPrivate *priv; - struct stat buf; - char *title, *short_name; - char *utf8_name = NULL; - const char *ext; - - window = GSR_WINDOW (object); - priv = window->priv; - - switch (prop_id) { - case PROP_LOCATION: - if (priv->filename != NULL) { - if (g_value_get_string (value) == NULL) - return; - if (g_str_equal (g_value_get_string (value), priv->filename)) { - return; - } - } - - g_free (priv->filename); - g_free (priv->working_file); - - priv->filename = g_value_dup_string (value); - priv->working_file = g_strdup (priv->filename); - priv->len_secs = 0; - - short_name = g_path_get_basename (priv->filename); - if (stat (priv->filename, &buf) == 0) { - window->priv->has_file = TRUE; - } else { - window->priv->has_file = FALSE; - } - - g_free (window->priv->extension); - if ((ext = strrchr (short_name, '.')) && ext[1] != '\0') - window->priv->extension = g_strdup (&ext[1]); - else - window->priv->extension = NULL; - - utf8_name = g_filename_to_utf8 (short_name, -1, NULL, NULL, NULL); - if (priv->name_label != NULL) { - gtk_label_set_text (GTK_LABEL (priv->name_label), - utf8_name); - } - - gsr_add_recent (priv->filename); - - /*Translators: this is the window title, %s is the currently open file's name or Untitled*/ - title = g_strdup_printf (_("%s — Sound Recorder"), utf8_name); - gtk_window_set_title (GTK_WINDOW (window), title); - g_free (title); - g_free (utf8_name); - g_free (short_name); - - set_action_sensitive (window, "Play", window->priv->has_file ? TRUE : FALSE); - set_action_sensitive (window, "Stop", FALSE); - set_action_sensitive (window, "Record", TRUE); - set_action_sensitive (window, "FileSave", window->priv->has_file ? TRUE : FALSE); - set_action_sensitive (window, "FileSaveAs", TRUE); - break; - default: - break; - } -} - -static void -gsr_window_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - switch (prop_id) { - case PROP_LOCATION: - g_value_set_string (value, GSR_WINDOW (object)->priv->filename); - break; - - default: - break; - } -} - -static void -gsr_window_finalize (GObject *object) -{ - GSRWindow *window; - GSRWindowPrivate *priv; - - window = GSR_WINDOW (object); - priv = window->priv; - - GST_DEBUG ("finalizing ..."); - - if (priv == NULL) { - return; - } - - if (priv->ui_manager) { - g_object_unref (priv->ui_manager); - priv->ui_manager = NULL; - } - - if (priv->action_group) { - g_object_unref (priv->action_group); - priv->action_group = NULL; - } - - if (priv->tick_id > 0) { - g_source_remove (priv->tick_id); - window->priv->play->tick_id = 0; - } - - if (priv->record_id > 0) { - g_source_remove (priv->record_id); - } - - if (priv->ebusy_timeout_id > 0) { - g_source_remove (window->priv->ebusy_timeout_id); - } - - g_idle_remove_by_data (window); - - if (priv->play != NULL) { - shutdown_pipeline (priv->play); - g_free (priv->play); - } - - if (priv->record != NULL) { - shutdown_pipeline (priv->record); - g_free (priv->record); - } - - unlink (priv->record_filename); - g_free (priv->record_filename); - - g_free (priv->working_file); - g_free (priv->filename); - - G_OBJECT_CLASS (parent_class)->finalize (object); - - window->priv = NULL; -} - -static void -gsr_window_class_init (GSRWindowClass *klass) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = gsr_window_finalize; - object_class->set_property = gsr_window_set_property; - object_class->get_property = gsr_window_get_property; - - parent_class = g_type_class_peek_parent (klass); - - g_object_class_install_property (object_class, - PROP_LOCATION, - g_param_spec_string ("location", - "Location", - "", - /* Translator comment: default trackname is 'untitled', which - * has as effect that the user cannot save to this file. The - * 'save' action will open the save-as dialog instead to give - * a proper filename. See mate-record.c:94. */ - _("Untitled"), - G_PARAM_READWRITE)); - - g_type_class_add_private (object_class, sizeof (GSRWindowPrivate)); - - GST_DEBUG_CATEGORY_INIT (gsr_debug, "gsr", 0, "Mate Sound Recorder"); -} - -GType -gsr_window_get_type (void) -{ - static GType type = 0; - - if (G_UNLIKELY (type == 0)) { - GTypeInfo info = { - sizeof (GSRWindowClass), - NULL, NULL, - (GClassInitFunc) gsr_window_class_init, - NULL, NULL, - sizeof (GSRWindow), 0, - (GInstanceInitFunc) gsr_window_init - }; - - type = g_type_register_static (GTK_TYPE_WINDOW, - "GSRWindow", - &info, 0); - } - - return type; -} - -GtkWidget * -gsr_window_new (const char *filename) -{ - GSRWindow *window; - char *template; - - /* filename has been changed to be without extension */ - window = g_object_new (GSR_TYPE_WINDOW, - "location", filename, - NULL); - /* FIXME: check extension too */ - window->priv->filename = g_strdup (filename); - if (g_file_test (filename, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR) != FALSE) { - window->priv->has_file = TRUE; - window->priv->dirty = FALSE; - } else { - window->priv->has_file = FALSE; - } - - template = g_strdup_printf ("gsr-record-%s-%d.XXXXXX", filename, getpid ()); - window->priv->record_fd = g_file_open_tmp (template, &window->priv->record_filename, NULL); - g_free (template); - close (window->priv->record_fd); - - if (window->priv->has_file == FALSE) { - g_free (window->priv->working_file); - window->priv->working_file = g_strdup (window->priv->record_filename); - } else { - g_free (window->priv->working_file); - window->priv->working_file = g_strdup (filename); - } - - window->priv->saved = TRUE; - - gtk_window_set_default_size (GTK_WINDOW (window), 512, 200); - - return GTK_WIDGET (window); -} |