summaryrefslogtreecommitdiff
path: root/gst-mixer-applet/applet.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst-mixer-applet/applet.c')
-rw-r--r--gst-mixer-applet/applet.c1525
1 files changed, 0 insertions, 1525 deletions
diff --git a/gst-mixer-applet/applet.c b/gst-mixer-applet/applet.c
deleted file mode 100644
index 377ed8e..0000000
--- a/gst-mixer-applet/applet.c
+++ /dev/null
@@ -1,1525 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 2 -*- */
-/* MATE Volume Applet
- * Copyright (C) 2004 Ronald Bultje <[email protected]>
- *
- * applet.c: the main applet
- *
- * 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., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-/* this is for lrint */
-#define _ISOC99_SOURCE
-#include <math.h>
-#include <string.h>
-
-#include <gtk/gtk.h>
-
-#include <glib-object.h>
-#include <gdk/gdkkeysyms.h>
-#if GTK_CHECK_VERSION (3, 0, 0)
-#include <gdk/gdkkeysyms-compat.h>
-#endif
-
-#include <gio/gio.h>
-
-#if GTK_CHECK_VERSION (3, 0, 0)
-#define MATE_DESKTOP_USE_UNSTABLE_API
-#include <libmate-desktop/mate-desktop-utils.h>
-#define gdk_spawn_command_line_on_screen mate_gdk_spawn_command_line_on_screen
-#endif
-
-#include "applet.h"
-#include "keys.h"
-#include "preferences.h"
-
-#define IS_PANEL_HORIZONTAL(o) \
- (o == MATE_PANEL_APPLET_ORIENT_UP || o == MATE_PANEL_APPLET_ORIENT_DOWN)
-
-/* This is defined is load.c, we're doing this instead of creating a load.h file
- * because nothing else is exported. */
-GList * mate_volume_applet_create_mixer_collection (void);
-
-static void mate_volume_applet_class_init (MateVolumeAppletClass *klass);
-static void mate_volume_applet_init (MateVolumeApplet *applet);
-static void mate_volume_applet_dispose (GObject *object);
-
-static void mate_volume_applet_size_allocate (GtkWidget *widget,
- GtkAllocation *allocation);
-
-static void mate_volume_applet_popup_dock (MateVolumeApplet *applet);
-static void mate_volume_applet_popdown_dock (MateVolumeApplet *applet);
-
-/* This function and mate_volume_applet_key are not static so we can
- * inject external events into the applet. Its to work around a GTK+
- * misfeature. See dock.c for details. */
-gboolean mate_volume_applet_scroll (GtkWidget *widget,
- GdkEventScroll *event);
-static gboolean mate_volume_applet_button (GtkWidget *widget,
- GdkEventButton *event);
-gboolean mate_volume_applet_key (GtkWidget *widget,
- GdkEventKey *event);
-static gdouble mate_volume_applet_get_volume (GstMixer *mixer,
- GstMixerTrack *track);
-
-#if !GTK_CHECK_VERSION (3, 0, 0)
-static void mate_volume_applet_background (MatePanelApplet *mate_panel_applet,
- MatePanelAppletBackgroundType type,
- GdkColor *colour,
- GdkPixmap *pixmap);
-#endif
-static void mate_volume_applet_orientation (MatePanelApplet *applet,
- MatePanelAppletOrient orient);
-
-static gboolean mate_volume_applet_refresh (MateVolumeApplet *applet,
- gboolean force_refresh,
- gdouble volume,
- gint mute);
-
-static void cb_notify_message (GstBus *bus, GstMessage *message, gpointer data);
-static gboolean cb_check (gpointer data);
-
-static void cb_volume (GtkAdjustment *adj,
- gpointer data);
-
-static void cb_gsettings (GSettings *settings,
- gchar *key,
- gpointer data);
-
-static void cb_verb (GtkAction *action,
- gpointer data);
-
-static void cb_theme_change (GtkIconTheme *icon_theme,
- gpointer data);
-static void cb_stop_scroll_events (GtkWidget *widget,
- GdkEvent *event);
-
-static MatePanelAppletClass *parent_class = NULL;
-
-
-G_DEFINE_TYPE (MateVolumeApplet, mate_volume_applet, PANEL_TYPE_APPLET)
-
-
-static void
-init_pixbufs (MateVolumeApplet *applet)
-{
- static const gchar *pix_filenames[] = {
- "audio-volume-muted",
- "audio-volume-low",
- "audio-volume-medium",
- "audio-volume-high",
- NULL
- };
- gint n;
-
- for (n = 0; pix_filenames[n] != NULL; n++) {
- if (applet->pix[n]) {
- g_object_unref (applet->pix[n]);
- applet->pix[n] = NULL; // mate_icon_theme_load_icon can call us
- // recursively, so we have to be careful.
- }
-
- applet->pix[n] = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
- pix_filenames[n],
- applet->panel_size - 4,
- 0,
- NULL);
- if (applet->pix[n] != NULL &&
- gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL) {
- GdkPixbuf *temp;
-
- temp = gdk_pixbuf_flip (applet->pix[n], TRUE);
- g_object_unref (G_OBJECT (applet->pix[n]));
- applet->pix[n] = temp;
- }
- }
-}
-
-static void
-mate_volume_applet_class_init (MateVolumeAppletClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS (klass);
- MatePanelAppletClass *matepanelapplet_class = MATE_PANEL_APPLET_CLASS (klass);
-
- parent_class = g_type_class_ref (PANEL_TYPE_APPLET);
-
- gobject_class->dispose = mate_volume_applet_dispose;
- gtkwidget_class->key_press_event = mate_volume_applet_key;
- gtkwidget_class->button_press_event = mate_volume_applet_button;
- gtkwidget_class->scroll_event = mate_volume_applet_scroll;
- gtkwidget_class->size_allocate = mate_volume_applet_size_allocate;
- matepanelapplet_class->change_orient = mate_volume_applet_orientation;
-#if !GTK_CHECK_VERSION (3, 0, 0)
- matepanelapplet_class->change_background = mate_volume_applet_background;
-#endif
-
- /* FIXME:
- * - style-set.
- */
-}
-
-static void
-mate_volume_applet_init (MateVolumeApplet *applet)
-{
- GtkWidget *image;
- AtkObject *ao;
-
- applet->timeout = 0;
- applet->elements = NULL;
- applet->settings = mate_panel_applet_settings_new (MATE_PANEL_APPLET (applet), "org.mate.panel.applet.mixer");
- applet->mixer = NULL;
- applet->tracks = NULL;
- applet->lock = FALSE;
- applet->state = -1;
- applet->prefs = NULL;
- applet->dock = NULL;
- applet->adjustment = NULL;
- applet->panel_size = 24;
-
- g_set_application_name (_("Volume Applet"));
-
- /* init pixbufs */
- init_pixbufs (applet);
-
- /* icon (our main UI) */
- image = gtk_image_new ();
- applet->image = GTK_IMAGE (image);
- gtk_container_add (GTK_CONTAINER (applet), image);
- gtk_widget_show (image);
- gtk_window_set_default_icon_name ("multimedia-volume-control");
-
- /* dock window (expanded UI) */
- applet->pop = FALSE;
-
- /* tooltip over applet */
- gtk_widget_set_tooltip_text (GTK_WIDGET (applet), _("Volume Control"));
-
- /* prevent scroll events from reaching the tooltip */
- g_signal_connect (G_OBJECT (applet),
- "event-after", G_CALLBACK (cb_stop_scroll_events),
- NULL);
-
- /* handle icon theme changes */
- g_signal_connect (gtk_icon_theme_get_default (),
- "changed", G_CALLBACK (cb_theme_change),
- applet);
-
- /* other stuff */
-#if GTK_CHECK_VERSION (3, 0, 0)
- mate_panel_applet_set_background_widget (MATE_PANEL_APPLET (applet), GTK_WIDGET (applet));
-#endif
- mate_panel_applet_set_flags (MATE_PANEL_APPLET (applet),
- MATE_PANEL_APPLET_EXPAND_MINOR);
-
- /* i18n */
- ao = gtk_widget_get_accessible (GTK_WIDGET (applet));
- atk_object_set_name (ao, _("Volume Control"));
-
- /* Watch for signals from GST. */
- applet->bus = gst_bus_new ();
- gst_bus_add_signal_watch (applet->bus);
- g_signal_connect (G_OBJECT (applet->bus), "message::element",
- (GCallback) cb_notify_message, applet);
-
-}
-
-/* Parse the list of tracks that are stored in GSettings */
-
-static char **
-parse_track_list (const char *track_list)
-{
- if (track_list)
- return g_strsplit (track_list, ":", 0);
- else
- return NULL;
-}
-
-static GList *
-select_tracks (GstElement *element,
- const char *active_track_names,
- gboolean reset_state)
-{
- const GList *tracks, *l;
- GstMixerTrack *track_fallback;
- GList *active_tracks;
- char **active_track_name_list;
-
- active_tracks = NULL;
- track_fallback = NULL;
- active_track_name_list = NULL;
-
- if (reset_state) {
- gst_element_set_state (element, GST_STATE_READY);
- if (gst_element_get_state(element, NULL, NULL, -1) != GST_STATE_CHANGE_SUCCESS)
- return NULL;
- }
-
- tracks = gst_mixer_list_tracks (GST_MIXER (element));
- if (active_track_names)
- active_track_name_list = parse_track_list (active_track_names);
-
- for (l = tracks; l; l = l->next) {
- GstMixerTrack *track = l->data;
- gint i;
-
- if (!track->num_channels)
- continue;
-
- if (!track_fallback)
- track_fallback = track;
-
- if (GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MASTER))
- track_fallback = track;
-
- if (active_track_name_list) {
- for (i = 0; active_track_name_list[i] != NULL; i++) {
- gchar *track_test = active_track_name_list[i];
-
- if (!strcmp (track_test, track->label))
- active_tracks = g_list_append (active_tracks, track);
- }
- }
- }
-
- /* if the list had no matches and we've got a fallback track,
- * then use it. */
-
- if (!active_tracks && track_fallback)
- active_tracks = g_list_append (active_tracks, track_fallback);
-
- if (!active_tracks && reset_state) {
- gst_element_set_state (element, GST_STATE_NULL);
- }
-
- g_strfreev (active_track_name_list);
- return active_tracks;
-}
-
-static gboolean
-select_element_and_track (MateVolumeApplet *applet,
- GList *elements,
- const char *active_element_name,
- const char *active_track_names)
-{
- GstElement *active_element;
- GList *active_tracks, *l;
-
- applet->elements = elements;
-
- active_element = NULL;
- active_tracks = NULL;
-
- if (active_element_name) {
- for (l = elements; l; l = l->next) {
- GstElement *element = l->data;
- const char *element_name;
-
- element_name = g_object_get_data (G_OBJECT (element),
- "mate-volume-applet-name");
-
- if (!strcmp (element_name, active_element_name)) {
- active_element = element;
- break;
- }
- }
- }
-
- if (active_element)
- active_tracks = select_tracks (active_element, active_track_names, TRUE);
-
- if (!active_tracks) {
- active_element = NULL;
- for (l = elements; l; l = l->next) {
- GstElement *element = l->data;
-
- if ((active_tracks = select_tracks (element, active_track_names, TRUE))) {
- active_element = element;
- break;
- }
- }
- }
-
- if (!active_element)
- return FALSE;
-
- applet->mixer = g_object_ref (active_element);
- gst_element_set_bus (GST_ELEMENT (applet->mixer), applet->bus);
- applet->tracks = active_tracks;
- g_list_foreach (applet->tracks, (GFunc) g_object_ref, NULL);
-
- return TRUE;
-}
-
-static void
-mate_volume_applet_setup_timeout (MateVolumeApplet *applet)
-{
- gboolean need_timeout = TRUE;
- need_timeout = ((gst_mixer_get_mixer_flags (GST_MIXER (applet->mixer)) &
- GST_MIXER_FLAG_AUTO_NOTIFICATIONS) == 0);
-
- if (need_timeout) {
- if (applet->timeout == 0) {
- applet->timeout = g_timeout_add (100, cb_check, applet);
- }
- }
- else {
- if (applet->timeout != 0) {
- g_source_remove (applet->timeout);
- applet->timeout = 0;
- }
- }
-}
-
-gboolean
-mate_volume_applet_setup (MateVolumeApplet *applet,
- GList *elements)
-{
-#if GTK_CHECK_VERSION (3, 0, 0)
- GtkAdjustment *adj;
-#else
- GtkObject *adj;
-#endif
- static const GtkActionEntry actions[] = {
- { "RunMixer", NULL, N_("_Open Volume Control"),
- NULL, NULL,
- G_CALLBACK (cb_verb) },
- { "Help", GTK_STOCK_HELP, N_("_Help"),
- NULL, NULL,
- G_CALLBACK (cb_verb) },
- { "About", GTK_STOCK_ABOUT, N_("_About"),
- NULL, NULL,
- G_CALLBACK (cb_verb) },
- { "Pref", GTK_STOCK_PROPERTIES, N_("_Preferences"),
- NULL, NULL,
- G_CALLBACK (cb_verb) }
- };
- static const GtkToggleActionEntry toggle_actions[] = {
- { "Mute", NULL, N_("Mu_te"),
- NULL, NULL,
- G_CALLBACK (cb_verb), FALSE }
- };
-
- gchar *active_element_name;
- gchar *active_track_name;
- gchar *ui_path;
- GstMixerTrack *first_track;
- gboolean res;
-
- active_element_name = g_settings_get_string (applet->settings,
- MATE_VOLUME_APPLET_KEY_ACTIVE_ELEMENT);
-
- active_track_name = g_settings_get_string (applet->settings,
- MATE_VOLUME_APPLET_KEY_ACTIVE_TRACK);
-
- res = select_element_and_track (applet, elements, active_element_name,
- active_track_name);
- g_free (active_element_name);
- g_free (active_track_name);
-
- if (res) {
- first_track = g_list_first (applet->tracks)->data;
-
-#if GTK_CHECK_VERSION (3, 0, 0)
- applet->adjustment = gtk_adjustment_new (50, 0, 100, 4, 10, 0);
-#else
- applet->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (50, 0, 100, 4, 10, 0));
-#endif
- /* We want a reference from the applet as well as from the dock it
- * will be attached to. */
- g_object_ref_sink (applet->adjustment);
- g_signal_connect (applet->adjustment, "value-changed",
- G_CALLBACK (cb_volume), applet);
-
- gtk_adjustment_set_value (applet->adjustment,
- mate_volume_applet_get_volume (applet->mixer,
- first_track));
- }
-
- mate_volume_applet_orientation (MATE_PANEL_APPLET (applet),
- mate_panel_applet_get_orient (MATE_PANEL_APPLET (applet)));
-
- /* menu */
- applet->action_group = gtk_action_group_new ("Mixer Applet Actions");
- gtk_action_group_set_translation_domain (applet->action_group, GETTEXT_PACKAGE);
- gtk_action_group_add_actions (applet->action_group,
- actions,
- G_N_ELEMENTS (actions),
- applet);
- gtk_action_group_add_toggle_actions (applet->action_group,
- toggle_actions,
- G_N_ELEMENTS (toggle_actions),
- applet);
- ui_path = g_build_filename (MIXER_MENU_UI_DIR, "mixer-applet-menu.xml", NULL);
- mate_panel_applet_setup_menu_from_file (MATE_PANEL_APPLET (applet),
- ui_path, applet->action_group);
- g_free (ui_path);
-
- mate_volume_applet_refresh (applet, TRUE, -1, -1);
- if (res) {
- mate_volume_applet_setup_timeout (applet);
-
- /* gsettings */
- g_signal_connect (applet->settings, "changed::" MATE_VOLUME_APPLET_KEY_ACTIVE_ELEMENT,
- G_CALLBACK (cb_gsettings), applet);
- g_signal_connect (applet->settings, "changed::" MATE_VOLUME_APPLET_KEY_ACTIVE_TRACK,
- G_CALLBACK (cb_gsettings), applet);
- }
-
- gtk_widget_show (GTK_WIDGET (applet));
-
- return TRUE;
-}
-
-static void
-mate_volume_applet_dispose (GObject *object)
-{
- MateVolumeApplet *applet = MATE_VOLUME_APPLET (object);
- gint n;
-
- mate_volume_applet_popdown_dock (applet);
-
- if (applet->action_group) {
- g_object_unref (applet->action_group);
- applet->action_group = NULL;
- }
-
- if (applet->elements) {
- GList *item;
-
- for (item = applet->elements; item != NULL; item = item->next) {
- GstElement *element = GST_ELEMENT (item->data);
-
- gst_element_set_state (element, GST_STATE_NULL);
- gst_object_unref (GST_OBJECT (element));
- }
- g_list_free (applet->elements);
- applet->elements = NULL;
- }
-
- if (applet->tracks) {
- g_list_foreach (applet->tracks, (GFunc) g_object_unref, NULL);
- g_list_free (applet->tracks);
- applet->tracks = NULL;
- }
-
- if (applet->mixer) {
- gst_object_unref (GST_OBJECT (applet->mixer));
- applet->mixer = NULL;
- }
-
- if (applet->timeout) {
- g_source_remove (applet->timeout);
- applet->timeout = 0;
- }
-
- if (applet->dock) {
- g_object_unref (applet->dock);
- applet->dock = NULL;
- }
-
- if (applet->adjustment) {
- g_object_unref (applet->adjustment);
- applet->adjustment = NULL;
- }
-
- for (n = 0; n < 5; n++) {
- if (applet->pix[n] != NULL) {
- g_object_unref (G_OBJECT (applet->pix[n]));
- applet->pix[n] = NULL;
- }
- }
-
- if (applet->bus) {
- gst_bus_remove_signal_watch (applet->bus);
- gst_object_unref (applet->bus);
- applet->bus = NULL;
- }
-
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-/*
- * Show a dialog (once) when no mixer is available.
- */
-
-static void
-show_no_mixer_dialog (MateVolumeApplet *applet)
-{
- static gboolean shown = FALSE;
- GtkWidget *dialog;
-
- if (shown)
- return;
- shown = TRUE;
-
- dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR,
- GTK_BUTTONS_CLOSE, "%s\n\n%s",
- _("The volume control did not find any elements and/or "
- "devices to control. This means either that you don't "
- "have the right GStreamer plugins installed, or that you "
- "don't have a sound card configured."),
- _("You can remove the volume control from the panel by "
- "right-clicking the speaker icon on the panel and "
- "selecting \"Remove From Panel\" from the menu."));
- gtk_widget_show (dialog);
- g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
-}
-
-/*
- * get position that the dock should get based on applet position.
- */
-
-static void
-mate_volume_applet_get_dock_position (MateVolumeApplet *applet,
- gint *_x, gint *_y)
-{
- GtkWidget *widget = GTK_WIDGET (applet);
- GtkAllocation widget_allocation, dock_allocation;
- gint x, y;
-
- gtk_widget_get_allocation (GTK_WIDGET (applet->dock), &dock_allocation);
- gtk_widget_get_allocation (widget, &widget_allocation);
-
- gdk_window_get_origin (gtk_widget_get_window (widget), &x, &y);
- switch (mate_panel_applet_get_orient (MATE_PANEL_APPLET (applet))) {
- case MATE_PANEL_APPLET_ORIENT_DOWN:
- x += widget_allocation.x;
- x -= (dock_allocation.width -
- widget_allocation.width) / 2;
- y += widget_allocation.height + widget_allocation.y;
- break;
- case MATE_PANEL_APPLET_ORIENT_UP:
- x += widget_allocation.x;
- x -= (dock_allocation.width -
- widget_allocation.width) / 2;
- y += widget_allocation.y;
- y -= dock_allocation.height;
- break;
- case MATE_PANEL_APPLET_ORIENT_RIGHT:
- x += widget_allocation.width + widget_allocation.x;
- y += widget_allocation.y;
- y -= (dock_allocation.height -
- widget_allocation.height) / 2;
- break;
- case MATE_PANEL_APPLET_ORIENT_LEFT:
- x += widget_allocation.x;
- x -= dock_allocation.width;
- y += widget_allocation.y;
- y -= (dock_allocation.height -
- widget_allocation.height) / 2;
- break;
- default:
- g_assert_not_reached ();
- }
-
- *_x = x;
- *_y = y;
-}
-
-/*
- * popup (show) or popdown (hide) the dock.
- */
-
-static void
-mate_volume_applet_popup_dock (MateVolumeApplet *applet)
-{
- GtkWidget *widget = GTK_WIDGET (applet);
- gint x, y;
-
- /* Get it in just about the right position so that it
- * doesn't flicker to obviously when we reposition it. */
- mate_volume_applet_get_dock_position (applet, &x, &y);
- gtk_window_move (GTK_WINDOW (applet->dock), x, y);
-
- gtk_widget_show_all (GTK_WIDGET (applet->dock));
-
- /* Reposition the window now that we know its actual size
- * and can center it. */
- mate_volume_applet_get_dock_position (applet, &x, &y);
- gtk_window_move (GTK_WINDOW (applet->dock), x, y);
-
- /* Set the keyboard focus in the correct place. */
- mate_volume_applet_dock_set_focus (applet->dock);
-
- /* set menu item as active */
- gtk_widget_set_state (GTK_WIDGET (applet), GTK_STATE_SELECTED);
-
- /* keep state */
- applet->pop = TRUE;
-}
-
-static void
-mate_volume_applet_popdown_dock (MateVolumeApplet *applet)
-{
- GtkWidget *widget = GTK_WIDGET (applet);
-
- if (!applet->pop)
- return;
-
- /* hide */
-#if GTK_CHECK_VERSION (3, 0, 0)
- gtk_widget_hide (GTK_WIDGET (applet->dock));
-#else
- gtk_widget_hide_all (GTK_WIDGET (applet->dock));
-#endif
-
- /* set menu item as active */
- gtk_widget_set_state (GTK_WIDGET (applet), GTK_STATE_NORMAL);
-
- /* keep state */
- applet->pop = FALSE;
-}
-
-static void
-mate_volume_applet_pop_dock (MateVolumeApplet *applet)
-{
- if (applet->pop) {
- mate_volume_applet_popdown_dock (applet);
- } else {
- mate_volume_applet_popup_dock (applet);
- }
-}
-
-static void
-mate_volume_applet_update_mute_action (MateVolumeApplet *applet,
- gboolean newmute)
-{
- GtkAction *action;
-
- if (!applet->action_group)
- return;
-
- action = gtk_action_group_get_action (applet->action_group, "Mute");
- if (newmute == gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)))
- return;
-
- gtk_action_block_activate (action);
- gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), newmute);
- gtk_action_unblock_activate (action);
-}
-
-gboolean
-mixer_is_muted (MateVolumeApplet *applet)
-{
- return applet->state & 1;
-}
-
-/*
- * Toggle mute.
- */
-
-void
-mate_volume_applet_toggle_mute (MateVolumeApplet *applet)
-{
- gboolean mute = mixer_is_muted (applet);
- gboolean newmute = !mute;
- GList *tracks;
-
- for (tracks = g_list_first (applet->tracks); tracks; tracks = tracks->next)
- gst_mixer_set_mute (applet->mixer, tracks->data, !mute);
-
- if (mute) {
- /* sync back actual volume */
- cb_volume (applet->adjustment, applet);
- }
-
- /* update menu */
- mate_volume_applet_update_mute_action (applet, newmute);
-
- /* update graphic - this should happen automagically after the next
- * idle call, but apparently doesn't for some people... */
- mate_volume_applet_refresh (applet, TRUE, -1, newmute);
-}
-
-/*
- * Run g-v-c.
- */
-
-void
-mate_volume_applet_run_mixer (MateVolumeApplet *applet)
-{
- GError *error = NULL;
-
- gdk_spawn_command_line_on_screen (gtk_widget_get_screen (GTK_WIDGET (applet)),
- "mate-volume-control", &error);
-
- if (error) {
- GtkWidget *dialog;
-
- dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR,
- GTK_BUTTONS_CLOSE,
- _("Failed to start Volume Control: %s"),
- error->message);
- g_signal_connect (dialog, "response",
- G_CALLBACK (gtk_widget_destroy), NULL);
- gtk_widget_show (dialog);
- g_error_free (error);
- }
-}
-
-/*
- * Control events, change volume and so on.
- */
-
-/* This is not static so we can inject external events
- * into the applet. Its to work around a GTK+ misfeature. See dock.c
- * for details. */
-
-gboolean
-mate_volume_applet_scroll (GtkWidget *widget,
- GdkEventScroll *event)
-{
- MateVolumeApplet *applet = MATE_VOLUME_APPLET (widget);
-
- if (!applet->mixer) {
- show_no_mixer_dialog (applet);
- return TRUE;
- }
-
- if (event->type == GDK_SCROLL) {
- switch (event->direction) {
- case GDK_SCROLL_UP:
- case GDK_SCROLL_DOWN: {
- gdouble volume = gtk_adjustment_get_value (applet->adjustment);
-
- if (event->direction == GDK_SCROLL_UP) {
- volume += gtk_adjustment_get_step_increment (applet->adjustment);
- if (volume > gtk_adjustment_get_upper (applet->adjustment))
- volume = gtk_adjustment_get_upper (applet->adjustment);
- } else {
- volume -= gtk_adjustment_get_step_increment (applet->adjustment);
- if (volume < gtk_adjustment_get_lower (applet->adjustment))
- volume = gtk_adjustment_get_lower (applet->adjustment);
- }
-
- gtk_adjustment_set_value (applet->adjustment, volume);
- return TRUE;
- }
- default:
- break;
- }
- }
-
- if (GTK_WIDGET_CLASS (parent_class)->scroll_event)
- return GTK_WIDGET_CLASS (parent_class)->scroll_event (widget, event);
- else
- return FALSE;
-}
-
-static gboolean
-mate_volume_applet_button (GtkWidget *widget,
- GdkEventButton *event)
-{
- MateVolumeApplet *applet = MATE_VOLUME_APPLET (widget);
-
- if (event->window != gtk_widget_get_window (GTK_WIDGET (applet)) &&
- event->type == GDK_BUTTON_PRESS) {
- mate_volume_applet_popdown_dock (applet);
- return TRUE;
- } else if (event->window == gtk_widget_get_window (GTK_WIDGET (applet))) {
- switch (event->button) {
- case 1:
- switch (event->type) {
- case GDK_BUTTON_PRESS:
- if (!applet->mixer) {
- show_no_mixer_dialog (applet);
- } else {
- mate_volume_applet_pop_dock (applet);
- }
- return TRUE;
- case GDK_2BUTTON_PRESS:
- if (applet->mixer) {
- mate_volume_applet_popdown_dock (applet);
- }
- mate_volume_applet_toggle_mute (applet);
- return TRUE;
- default:
- break;
- }
- break;
- case 2: /* mute */
- mate_volume_applet_toggle_mute (applet);
- return TRUE;
- case 3: /* menu */
- if (applet->pop) {
- mate_volume_applet_popdown_dock (applet);
- return TRUE;
- }
- break;
- default:
- break;
- }
- }
-
- if (GTK_WIDGET_CLASS (parent_class)->button_press_event)
- return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
-
- return FALSE;
-}
-
-/* This is not static so we can inject external events
- * into the applet. Its to work around a GTK+ misfeature. See dock.c
- * for details. */
-
-gboolean
-mate_volume_applet_key (GtkWidget *widget,
- GdkEventKey *event)
-{
- MateVolumeApplet *applet = MATE_VOLUME_APPLET (widget);
-
- if (!applet->mixer) {
- show_no_mixer_dialog (applet);
- } else switch (event->keyval) {
- case GDK_KP_Enter:
- case GDK_ISO_Enter:
- case GDK_3270_Enter:
- case GDK_Return:
- case GDK_space:
- case GDK_KP_Space:
- mate_volume_applet_pop_dock (applet);
- return TRUE;
- case GDK_m:
- if (event->state == GDK_CONTROL_MASK) {
- mate_volume_applet_toggle_mute (applet);
- return TRUE;
- }
- break;
- case GDK_o:
- if (event->state == GDK_CONTROL_MASK) {
- mate_volume_applet_run_mixer (applet);
- return TRUE;
- }
- break;
- case GDK_Escape:
- mate_volume_applet_popdown_dock (applet);
- return TRUE;
- case GDK_Page_Up:
- case GDK_Page_Down:
- case GDK_Left:
- case GDK_Right:
- case GDK_Up:
- case GDK_Down: {
- gdouble volume = gtk_adjustment_get_value (applet->adjustment);
- gdouble increment;
-
- if (event->state != 0)
- break;
-
- if (event->keyval == GDK_Up || event->keyval == GDK_Down
- ||event->keyval == GDK_Left)
- increment = gtk_adjustment_get_step_increment (applet->adjustment);
- else
- increment = gtk_adjustment_get_page_increment (applet->adjustment);
-
- if (event->keyval == GDK_Page_Up || event->keyval == GDK_Up
- ||event->keyval == GDK_Right) {
- volume += increment;
- if (volume > gtk_adjustment_get_upper (applet->adjustment))
- volume = gtk_adjustment_get_upper (applet->adjustment);
- } else {
- volume -= increment;
- if (volume < gtk_adjustment_get_lower (applet->adjustment))
- volume = gtk_adjustment_get_lower (applet->adjustment);
- }
-
- gtk_adjustment_set_value (applet->adjustment, volume);
- return TRUE;
- }
- default:
- break;
- }
-
- return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
-}
-
-static gboolean
-mate_volume_applet_dock_focus_out (GtkWidget *dock, GdkEventFocus *event,
- MateVolumeApplet *applet)
-{
- mate_volume_applet_popdown_dock (applet);
-
- return FALSE;
-}
-
-/*
- * Change orientation or size of panel.
- */
-
-static void
-mate_volume_applet_orientation (MatePanelApplet *_applet,
- MatePanelAppletOrient orientation)
-{
- MateVolumeApplet *applet = MATE_VOLUME_APPLET (_applet);
- GtkWidget *dock;
-
- if (applet->dock) {
- gtk_widget_destroy (GTK_WIDGET (applet->dock));
- }
- dock = mate_volume_applet_dock_new (GTK_ORIENTATION_VERTICAL,
- applet);
- g_object_ref_sink (dock); /* It isn't a child, but we do own it. */
- gtk_widget_add_events (dock, GDK_FOCUS_CHANGE_MASK);
- g_signal_connect (G_OBJECT (dock), "focus-out-event",
- G_CALLBACK (mate_volume_applet_dock_focus_out),
- applet);
- applet->dock = MATE_VOLUME_APPLET_DOCK (dock);
- mate_volume_applet_dock_change (applet->dock, applet->adjustment);
-
- if (MATE_PANEL_APPLET_CLASS (parent_class)->change_orient)
- MATE_PANEL_APPLET_CLASS (parent_class)->change_orient (_applet, orientation);
-}
-
-void mate_volume_applet_size_allocate (GtkWidget *widget,
- GtkAllocation *allocation)
-{
- MateVolumeApplet *applet = MATE_VOLUME_APPLET (widget);
- MatePanelAppletOrient orient;
-
- if (GTK_WIDGET_CLASS (parent_class)->size_allocate)
- GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
-
- orient = mate_panel_applet_get_orient (MATE_PANEL_APPLET (applet));
-
- if (orient == MATE_PANEL_APPLET_ORIENT_UP || orient == MATE_PANEL_APPLET_ORIENT_DOWN) {
- if (applet->panel_size == allocation->height)
- return;
- applet->panel_size = allocation->height;
- }
- else {
- if (applet->panel_size == allocation->width)
- return;
- applet->panel_size = allocation->width;
- }
-
- init_pixbufs (applet);
- mate_volume_applet_refresh (applet, TRUE, -1, -1);
-}
-
-#if !GTK_CHECK_VERSION (3, 0, 0)
-static void
-mate_volume_applet_background (MatePanelApplet *_applet,
- MatePanelAppletBackgroundType type,
- GdkColor *colour,
- GdkPixmap *pixmap)
-{
- MateVolumeApplet *applet = MATE_VOLUME_APPLET (_applet);
- GtkRcStyle *rc_style;
- GtkStyle *style;
-
- /* reset style */
- gtk_widget_set_style (GTK_WIDGET (applet), NULL);
- rc_style = gtk_rc_style_new ();
- gtk_widget_modify_style (GTK_WIDGET (applet), rc_style);
- g_object_unref (rc_style);
-
- switch (type) {
- case PANEL_NO_BACKGROUND:
- break;
- case PANEL_COLOR_BACKGROUND:
- gtk_widget_modify_bg (GTK_WIDGET (applet),
- GTK_STATE_NORMAL, colour);
- break;
- case PANEL_PIXMAP_BACKGROUND:
- style = gtk_style_copy (gtk_widget_get_style (GTK_WIDGET (applet)));
- if (style->bg_pixmap[GTK_STATE_NORMAL])
- g_object_unref (style->bg_pixmap[GTK_STATE_NORMAL]);
- style->bg_pixmap[GTK_STATE_NORMAL] = g_object_ref (pixmap);
- gtk_widget_set_style (GTK_WIDGET (applet), style);
- g_object_unref (style);
- break;
- }
-}
-#endif
-
-/*
- * This needs to be here because not all tracks have the same volume range,
- * so you can send this function the track and a new volume and it will be
- * scaled according to the volume range of the track in question.
- */
-
-void
-mate_volume_applet_adjust_volume (GstMixer *mixer,
- GstMixerTrack *track,
- gdouble volume)
-{
- int range = track->max_volume - track->min_volume;
- gdouble scale = ((gdouble) range) / 100;
- int *volumes, n, volint;
-
- if (volume == 1.0) {
- volint = track->max_volume;
- } else if (volume == 0.0) {
- volint = track->min_volume;
- } else {
- volume *= scale;
- volume += track->min_volume;
- volint = lrint (volume);
- }
-
- volumes = g_new (gint, track->num_channels);
- for (n = 0; n < track->num_channels; n++)
- volumes[n] = volint;
- gst_mixer_set_volume (mixer, track, volumes);
-
- g_free (volumes);
-}
-
-static gdouble
-mate_volume_applet_get_volume (GstMixer *mixer,
- GstMixerTrack *track)
-{
- int *volumes, n;
- gdouble j;
-
- if (!track || !mixer)
- return -1;
-
- volumes = g_new (gint, track->num_channels);
- gst_mixer_get_volume (mixer, track, volumes);
-
- j = 0;
- for (n = 0; n < track->num_channels; n++)
- j += volumes[n];
- g_free (volumes);
- j /= track->num_channels;
-
- return 100 * (j - track->min_volume) / (track->max_volume - track->min_volume);
-}
-
-/*
- * Volume changed.
- */
-
-static void
-cb_volume (GtkAdjustment *adj,
- gpointer data)
-{
- MateVolumeApplet *applet = data;
- gdouble v;
- GList *iter;
-
- if (applet->lock)
- return;
- applet->lock = TRUE;
-
- v = gtk_adjustment_get_value (adj);
-
- for (iter = g_list_first (applet->tracks); iter; iter = iter->next) {
- GstMixerTrack *track = iter->data;
- mate_volume_applet_adjust_volume (applet->mixer, track, v);
- }
-
- applet->lock = FALSE;
- applet->force_next_update = TRUE;
- mate_volume_applet_refresh (MATE_VOLUME_APPLET (data), FALSE, v, -1);
-}
-
-/*
- * Automatic timer. Check for changes.
- */
-
-#define STATE(vol,m) (((gint) vol << 1) | (m ? 1 : 0))
-
-static gboolean
-mate_volume_applet_refresh (MateVolumeApplet *applet,
- gboolean force_refresh,
- gdouble volume,
- gint mute)
-{
- GdkPixbuf *pixbuf;
- gint n;
- gboolean show_mute, did_change;
- gchar *tooltip_str;
- GstMixerTrack *first_track;
- GString *track_names;
- GList *iter;
-
- show_mute = 0;
-
- if (!applet->mixer) {
- n = 0;
- show_mute = 0;
- mute = 0;
- } else if (!applet->tracks) {
- return FALSE;
- } else {
- first_track = g_list_first (applet->tracks)->data;
- if (volume == -1) {
- /* only first track */
- volume = mate_volume_applet_get_volume (applet->mixer, first_track);
- }
- if (mute == -1) {
- mute = GST_MIXER_TRACK_HAS_FLAG (first_track,
- GST_MIXER_TRACK_MUTE) ? 1 : 0;
- }
- if (volume <= 0 || mute) {
- show_mute = 1;
- n = 0;
- }
- else {
- /* select image */
- n = 3 * volume / 100 + 1;
- if (n < 1)
- n = 1;
- if (n > 3)
- n = 3;
- }
- }
-
- did_change = (force_refresh || (STATE (volume, mute) != applet->state) ||
- applet->force_next_update);
- applet->force_next_update = FALSE;
-
- if (did_change) {
- if (show_mute) {
- pixbuf = applet->pix[0];
- } else {
- pixbuf = applet->pix[n];
- }
-
- gtk_image_set_from_pixbuf (applet->image, pixbuf);
- applet->state = STATE (volume, mute);
-
- if (applet->dock) {
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (applet->dock->mute),
- mute);
- }
- }
-
- if (!did_change || !applet->mixer)
- return did_change;
-
- /* build names of selecter tracks */
- track_names = g_string_new ("");
- for (iter = g_list_first (applet->tracks); iter; iter = iter->next) {
- GstMixerTrack *track = iter->data;
-
- if (iter->next != NULL)
- g_string_append_printf (track_names, "%s / ", track->label);
- else
- track_names = g_string_append (track_names, track->label);
- }
-
- if (show_mute) {
- tooltip_str = g_strdup_printf (_("%s: muted"), track_names->str);
- } else {
- /* Translator comment: I'm not all too sure if this makes sense
- * to mark as a translation, but anyway. The string is a list of
- * selected tracks, the number is the volume in percent. You
- * most likely want to keep this as-is. */
- tooltip_str = g_strdup_printf (_("%s: %d%%"), track_names->str,
- (int) volume);
- }
- g_string_free (track_names, TRUE);
-
- gtk_widget_set_tooltip_text (GTK_WIDGET (applet), tooltip_str);
- g_free (tooltip_str);
-
- applet->lock = TRUE;
- if (volume != 0) {
- gtk_adjustment_set_value (applet->adjustment, volume);
- }
- applet->lock = FALSE;
-
- /* update mute status */
- mate_volume_applet_update_mute_action (applet, mute);
-
- return did_change;
-}
-
-static void
-cb_notify_message (GstBus *bus, GstMessage *message, gpointer data)
-{
- MateVolumeApplet *applet = MATE_VOLUME_APPLET (data);
- GstMixerMessageType type;
- GstMixerTrack *first_track;
- GstMixerTrack *track = NULL;
- gint mute;
- gdouble volume;
-
- if (applet->tracks == NULL ||
- GST_MESSAGE_SRC (message) != GST_OBJECT (applet->mixer)) {
- /* No tracks, or not from our mixer - can't update anything anyway */
- return;
- }
-
- volume = mute = -1;
-
- first_track = g_list_first (applet->tracks)->data;
-
- /* This code only calls refresh if the first_track changes, because the
- * refresh code only retrieves the current value from that track anyway */
- type = gst_mixer_message_get_type (message);
- if (type == GST_MIXER_MESSAGE_MUTE_TOGGLED) {
- gboolean muted;
- gst_mixer_message_parse_mute_toggled (message, &track, &muted);
- mute = muted ? 1 : 0;
- }
- else if (type == GST_MIXER_MESSAGE_VOLUME_CHANGED) {
- gint n, num_channels, *vols;
- volume = 0.0;
-
- gst_mixer_message_parse_volume_changed (message, &track, &vols, &num_channels);
- for (n = 0; n < num_channels; n++)
- volume += vols[n];
- volume /= track->num_channels;
- volume = 100 * volume / (track->max_volume - track->min_volume);
- } else
- {
- return;
- }
-
- if (first_track == track)
- mate_volume_applet_refresh (MATE_VOLUME_APPLET (data), FALSE, volume, mute);
-}
-
-static gboolean
-cb_check (gpointer data)
-{
- static int time_counter = -1;
- static int timeout = 15;
- static gboolean recent_change = FALSE;
- gboolean did_change;
-
- time_counter++;
-
- /*
- * This timeout is called 10 times per second. Only do the update every
- * 15 times this function is called (every 1.5 seconds), unless the value
- * actually changed.
- */
- if (time_counter % timeout == 0 || recent_change) {
- did_change = mate_volume_applet_refresh (MATE_VOLUME_APPLET (data),
- FALSE, -1, -1);
-
- /*
- * If a change was done, set recent_change so that the update is
- * done 10 times a second for 10 seconds and reset the counter to 0.
- * This way we update frequently for 10 seconds after the last time
- * the value is actually changed.
- */
- if (did_change) {
- recent_change = TRUE;
- time_counter = 0;
- timeout = 100;
- } else if (time_counter % timeout == 0) {
- /*
- * When the counter gets to the timeout, reset recent_change and
- * time_counter so we go back to the behavior where we only check
- * every 15 times the function is called.
- */
- recent_change = FALSE;
- time_counter = 0;
- timeout = 15;
- }
- }
-
- return TRUE;
-}
-
-/*
- * GSettings callback.
- */
-
-static void
-cb_gsettings (GSettings *settings, gchar *key, gpointer data)
-{
- MateVolumeApplet *applet = data;
- const gchar *str;
- const GList *item;
- gboolean newdevice = FALSE;
- GList *active_tracks;
-
- active_tracks = NULL;
-
- g_list_free(applet->elements);
- applet->elements = mate_volume_applet_create_mixer_collection ();
-
- if (!strcmp (key, MATE_VOLUME_APPLET_KEY_ACTIVE_ELEMENT)) {
- for (item = applet->elements; item != NULL; item = item->next) {
- gchar *cur_el_str = g_object_get_data (item->data,
- "mate-volume-applet-name");
-
- if (!strcmp (cur_el_str, str)) {
- GstElement *old_element = GST_ELEMENT (applet->mixer),
- *new_element = item->data;
-
- if (new_element != old_element) {
- /* change element */
- gst_element_set_state (item->data, GST_STATE_READY);
- if (gst_element_get_state (item->data, NULL, NULL, -1) != GST_STATE_CHANGE_SUCCESS)
- continue;
-
- /* save */
- gst_object_replace ((GstObject **) &applet->mixer, item->data);
- gst_element_set_state (old_element, GST_STATE_NULL);
- mate_volume_applet_setup_timeout (applet);
- newdevice = TRUE;
- }
- break;
- }
- }
- }
-
- if (!strcmp (key, MATE_VOLUME_APPLET_KEY_ACTIVE_TRACK) || newdevice) {
- if (!active_tracks) {
- active_tracks = select_tracks (GST_ELEMENT (applet->mixer), str, FALSE);
- }
-
- if (active_tracks) {
- GstMixerTrack *first_track;
-
- /* copy the newly created track list over to the main list */
- g_list_free (applet->tracks);
- applet->tracks = g_list_copy (active_tracks);
-
- first_track = g_list_first (active_tracks)->data;
-
- /* dock */
- gtk_adjustment_set_value (applet->adjustment,
- mate_volume_applet_get_volume (applet->mixer,
- first_track));
-
- /* if preferences window is open, update */
- if (applet->prefs) {
- mate_volume_applet_preferences_change (
- MATE_VOLUME_APPLET_PREFERENCES (applet->prefs),
- applet->mixer, applet->tracks);
- }
-
- applet->force_next_update = TRUE;
- }
- }
-}
-
-/*
- * verb callback.
- */
-
-static void
-cb_prefs_destroy (GtkWidget *widget,
- gpointer data)
-{
- MATE_VOLUME_APPLET (data)->prefs = NULL;
-}
-
-static void
-cb_verb (GtkAction *action,
- gpointer data)
-{
- MateVolumeApplet *applet = MATE_VOLUME_APPLET (data);
- const gchar *verbname = gtk_action_get_name (action);
-
- if (!strcmp (verbname, "RunMixer")) {
- mate_volume_applet_run_mixer (applet);
- } else if (!strcmp (verbname, "Help")) {
- GError *error = NULL;
-
- gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (applet)),
- "help:mixer_applet2",
- gtk_get_current_event_time (),
- &error);
-
- if (error) {
- GtkWidget *dialog;
-
- dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR,
- GTK_BUTTONS_CLOSE,
- _("Failed to display help: %s"),
- error->message);
- g_signal_connect (dialog, "response",
- G_CALLBACK (gtk_widget_destroy), NULL);
- gtk_widget_show (dialog);
- g_error_free (error);
- }
- } else if (!strcmp (verbname, "About")) {
-
- const gchar *authors[] = { "Ronald Bultje <[email protected]>",
- NULL };
-
- char *comments = g_strdup_printf ("%s\n\n%s",
- _("Volume control for your MATE Panel."),
- _("Using GStreamer 0.10.")
- );
-
- gtk_show_about_dialog (NULL,
- "version", VERSION,
- "copyright", "\xC2\xA9 2004 Ronald Bultje",
- "comments", comments,
- "authors", authors,
- "translator-credits", _("translator-credits"),
- "logo-icon-name", "multimedia-volume-control",
- NULL);
-
- g_free (comments);
-
- } else if (!strcmp (verbname, "Pref")) {
- if (!applet->mixer) {
- show_no_mixer_dialog (applet);
- } else {
- if (applet->prefs)
- return;
-
- g_list_free(applet->elements);
- applet->elements = mate_volume_applet_create_mixer_collection ();
-
- applet->prefs = mate_volume_applet_preferences_new (applet,
- applet->elements,
- applet->mixer,
- applet->tracks);
- g_signal_connect (applet->prefs, "destroy",
- G_CALLBACK (cb_prefs_destroy), applet);
- gtk_widget_show (applet->prefs);
- }
- } else if (!strcmp (verbname, "Mute")) {
- if (!applet->mixer) {
- show_no_mixer_dialog (applet);
- } else {
- gboolean mute = applet->state & 1,
- want_mute = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
- if (mute != want_mute)
- mate_volume_applet_toggle_mute (applet);
- }
- } else {
- g_warning ("Unknown menu action '%s'", verbname);
- }
-}
-
-static void
-cb_theme_change (GtkIconTheme *icon_theme,
- gpointer data)
-{
- MateVolumeApplet *applet = MATE_VOLUME_APPLET (data);
-
- init_pixbufs (applet);
- mate_volume_applet_refresh (applet, TRUE, -1, -1);
-}
-
-/*
- * Block the tooltips event-after handler on scroll events.
- */
-
-static void
-cb_stop_scroll_events (GtkWidget *widget,
- GdkEvent *event)
-{
- if (event->type == GDK_SCROLL)
- g_signal_stop_emission_by_name (widget, "event-after");
-}