diff options
Diffstat (limited to 'mixer/applet.c')
-rw-r--r-- | mixer/applet.c | 1494 |
1 files changed, 0 insertions, 1494 deletions
diff --git a/mixer/applet.c b/mixer/applet.c deleted file mode 100644 index 9ad53bb8..00000000 --- a/mixer/applet.c +++ /dev/null @@ -1,1494 +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 <glib-object.h> -#include <gdk/gdkkeysyms.h> - -#include <gtk/gtk.h> - -#include <gio/gio.h> - -#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); - -static void mate_volume_applet_background (MatePanelApplet *mate_panel_applet, - MatePanelAppletBackgroundType type, - GdkColor *colour, - GdkPixmap *pixmap); -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; - matepanelapplet_class->change_background = mate_volume_applet_background; - - /* 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 */ - 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) -{ - GtkObject *adj; - 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; - - applet->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (50, 0, 100, - 4, 10, 0)); - /* 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 */ - gtk_widget_hide_all (GTK_WIDGET (applet->dock)); - - /* 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: /* move */ - 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); -} - -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; - } -} - -/* - * 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)), - "ghelp: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"); -} |