src/plugins/volume/*: New plugin to display and adjust volume.
authorJim Huang <jserv.tw@gmail.com>
Sun, 8 Oct 2006 08:35:37 +0000 (08:35 +0000)
committerJim Huang <jserv.tw@gmail.com>
Sun, 8 Oct 2006 08:35:37 +0000 (08:35 +0000)
Fixes:
1) Added -rdynamic to linker when plugin loader is built.
2) Remove duplicated get_line function as the above change.

configure.ac
src/Makefile.am
src/plugins/Makefile.am
src/plugins/netstatus/netstatus.c
src/plugins/volume/Makefile.am [new file with mode: 0644]
src/plugins/volume/volume-impl.c [new file with mode: 0644]
src/plugins/volume/volume-impl.h [new file with mode: 0644]
src/plugins/volume/volume.c [new file with mode: 0644]
src/plugins/volume/volume_xpm.h [new file with mode: 0644]

index 45fc855..cc817b7 100644 (file)
@@ -24,6 +24,8 @@ AC_ARG_ENABLE([plugins-loading],
                       [disable plugin loading (default: enable)]),
                       plugins_loading=$enableval, plugins_loading="yes")
 
+AM_CONDITIONAL(BUILD_PLUGIN_LOADER, test x$plugins_loading = xyes)
+
 if test "$plugins_loading" = "no"; then
        AC_DEFINE(DISABLE_PLUGINS_LOADING, [1], [Disable plugin loading])
        AM_CONDITIONAL(BUILD_PLUGIN_NETSTATUS, no)
@@ -68,6 +70,7 @@ AC_CONFIG_FILES([
        src/Makefile
        src/plugins/Makefile
        src/plugins/netstatus/Makefile
+       src/plugins/volume/Makefile
        po/Makefile.in
        data/Makefile
        data/default
index dd678d3..cce1539 100644 (file)
@@ -32,6 +32,11 @@ lxpanel_SOURCES = \
        plugin.c plugin.h \
        gtk-run.c
 
+if BUILD_PLUGIN_LOADER
+DYNAMIC_FLAGS = -rdynamic
+endif
+lxpanel_LDFLAGS = $(DYNAMIC_FLAGS)
+
 lxpanel_LDADD = \
                $(BUILTIN_PLUGINS) \
                $(PACKAGE_LIBS) \
index 1fa2d51..f06ef69 100644 (file)
@@ -1,6 +1,12 @@
 ## Process this file with automake to produce Makefile.in
 
-SUBDIRS = netstatus
+if BUILD_PLUGIN_LOADER
+DYNAMIC_PLUGINS = \
+       netstatus \
+       volume
+endif
+
+SUBDIRS = $(DYNAMIC_PLUGINS)
 
 noinst_LIBRARIES = libbuiltin_plugins.a
 
index 097352a..9d8f99a 100644 (file)
@@ -31,45 +31,6 @@ netstatus_destructor(plugin *p)
     RET();
 }
 
-static  int
-_get_line(FILE *fp, line *s)
-{
-    gchar *tmp, *tmp2;
-
-    ENTER;
-    s->type = LINE_NONE;
-    if (!fp)
-        RET(s->type);
-    while (fgets(s->str, s->len, fp)) {
-        g_strstrip(s->str);
-
-        if (s->str[0] == '#' || s->str[0] == 0) {
-            continue;
-        }
-        if (!g_ascii_strcasecmp(s->str, "}")) {
-            s->type = LINE_BLOCK_END;
-            break;
-        }
-
-        s->t[0] = s->str;
-        for (tmp = s->str; isalnum(*tmp); tmp++);
-        for (tmp2 = tmp; isspace(*tmp2); tmp2++);
-        if (*tmp2 == '=') {
-            for (++tmp2; isspace(*tmp2); tmp2++);
-            s->t[1] = tmp2;
-            *tmp = 0;
-            s->type = LINE_VAR;
-        } else if  (*tmp2 == '{') {
-            *tmp = 0;
-            s->type = LINE_BLOCK_START;
-        } else {
-            ERR( "parser: unknown token: '%c'\n", *tmp2);
-        }
-        break;
-    }
-    RET(s->type);
-}
-
 static void on_response( GtkDialog* dlg, gint response, netstatus *ns )
 {
     switch( response )
@@ -113,7 +74,7 @@ netstatus_constructor(plugin *p)
     ns = g_new0(netstatus, 1);
     g_return_val_if_fail(ns != NULL, 0);
     p->priv = ns;
-    while (_get_line(p->fp, &s) != LINE_BLOCK_END) {
+    while (get_line(p->fp, &s) != LINE_BLOCK_END) {
         if (s.type == LINE_NONE) {
             ERR( "netstatus: illegal token %s\n", s.str);
             goto error;
diff --git a/src/plugins/volume/Makefile.am b/src/plugins/volume/Makefile.am
new file mode 100644 (file)
index 0000000..6098ea9
--- /dev/null
@@ -0,0 +1,22 @@
+INCLUDES = \
+       -I. \
+       -I$(top_srcdir)/src \
+       $(PACKAGE_CFLAGS)
+
+module_LTLIBRARIES = volume.la
+
+moduledir = ${prefix}/share/lxpanel/plugins
+
+volume_la_SOURCES = \
+       volume_xpm.h \
+       volume-impl.h \
+       volume-impl.c \
+       volume.c
+
+volume_la_LIBADD = \
+       $(PACKAGE_CFLAGS)
+
+volume_la_LDFLAGS = \
+       -avoid-version \
+       -rpath $(moduledir) \
+       -module
diff --git a/src/plugins/volume/volume-impl.c b/src/plugins/volume/volume-impl.c
new file mode 100644 (file)
index 0000000..65dbd73
--- /dev/null
@@ -0,0 +1,170 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include "volume-impl.h"
+
+#include <linux/soundcard.h>
+#include <fcntl.h>
+
+extern int mixer_fd;
+
+typedef struct stereovolume
+{
+       unsigned char left;
+       unsigned char right;
+} StereoVolume;
+
+static StereoVolume tmpvol;
+
+static struct originalset orig;
+
+static GtkWidget *volume_window;
+static GtkWidget *vbox1;
+static GtkWidget *hbox1;
+static GtkWidget *spinbutton1;
+static GtkWidget *hbox3;
+static GtkWidget *vscale1;
+static GtkAccelGroup *accel_group;
+static GtkAdjustment *vol_adjustment;
+static GtkWidget *hbox4;
+static GtkWidget *frame;
+
+static gboolean
+on_spinbutton1_button_release_event (GtkWidget *widget,
+                                     GdkEventButton *event,
+                                     gpointer user_data);
+
+static gboolean
+on_vscale1_button_release_event (GtkWidget *widget,
+                                 GdkEventButton *event,
+                                 gpointer user_data);
+
+static void 
+get_current_levels() 
+{
+       ioctl(mixer_fd, MIXER_READ(SOUND_MIXER_VOLUME), &tmpvol);
+       orig.mainvol = tmpvol.left;
+       gtk_adjustment_set_value(GTK_ADJUSTMENT(vol_adjustment), (double) tmpvol.left);
+}
+
+GtkWidget*
+create_volume_window (void)
+{
+       accel_group = gtk_accel_group_new ();
+
+       volume_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+       gtk_widget_set_size_request (volume_window, 60, 240);
+       gtk_container_set_border_width (GTK_CONTAINER (volume_window), 2);
+
+       gtk_window_set_resizable (GTK_WINDOW (volume_window), FALSE);
+       gtk_window_set_position (GTK_WINDOW (volume_window), GTK_WIN_POS_MOUSE);
+       gtk_window_set_decorated (GTK_WINDOW (volume_window), FALSE);
+
+       frame = gtk_frame_new ("Volume");
+
+       vbox1 = gtk_vbox_new (FALSE, 0);
+       gtk_widget_show (vbox1);
+       gtk_container_add (GTK_CONTAINER (frame), vbox1);
+       gtk_container_add (GTK_CONTAINER (volume_window), frame);
+       gtk_widget_show (frame);
+       vol_adjustment=GTK_ADJUSTMENT (gtk_adjustment_new (1, 0, 100, 1, 10, 0));
+
+       /* get original adjustments */
+       get_current_levels();
+
+       hbox1 = gtk_hbox_new (FALSE, 0);
+       gtk_widget_show (hbox1);
+       gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, TRUE, 8);
+
+
+       spinbutton1 = gtk_spin_button_new (GTK_ADJUSTMENT (vol_adjustment),1,0); /* ajustment, climb rate, digits */
+       gtk_widget_show (spinbutton1);
+       gtk_box_pack_start (GTK_BOX (hbox1), spinbutton1, TRUE, FALSE, 0);
+       gtk_widget_set_size_request (spinbutton1, -1, 22);
+       g_signal_connect ((gpointer) spinbutton1, "value_changed",
+                         G_CALLBACK (on_spinbutton1_button_release_event),
+                         NULL);
+       g_object_set_data_full(G_OBJECT (volume_window), "spinbutton1", 
+                              gtk_widget_ref (spinbutton1),
+                              (GDestroyNotify) gtk_widget_unref);
+
+       hbox3 = gtk_hbox_new (FALSE, 0);
+       gtk_widget_show (hbox3);
+       gtk_box_pack_start (GTK_BOX (vbox1), hbox3, TRUE, TRUE, 5);
+
+       vscale1 = gtk_vscale_new (GTK_ADJUSTMENT (vol_adjustment));
+       gtk_widget_show (vscale1);
+       gtk_range_set_inverted (GTK_RANGE (vscale1), TRUE);
+       gtk_box_pack_start (GTK_BOX (hbox3), vscale1, TRUE, TRUE, 0);
+       gtk_scale_set_draw_value (GTK_SCALE (vscale1), FALSE);
+       g_signal_connect ((gpointer) vscale1, "button_release_event",
+                         G_CALLBACK (on_vscale1_button_release_event),
+                         vol_adjustment);
+       g_object_set_data_full(G_OBJECT (volume_window), "vscale1",
+                              gtk_widget_ref (vscale1),
+                              (GDestroyNotify) gtk_widget_unref);
+
+       hbox4 = gtk_hbox_new (FALSE, 0);
+       gtk_widget_show (hbox4);
+       gtk_box_pack_start (GTK_BOX (vbox1), hbox4, FALSE, TRUE, 8);
+
+       g_signal_connect ((gpointer) volume_window, "destroy",
+                         G_CALLBACK (gtk_widget_destroy),
+                         NULL);
+
+       g_object_set_data (G_OBJECT (volume_window), "volume_window", volume_window);
+       g_object_set_data_full (G_OBJECT (volume_window), "frame",
+                               gtk_widget_ref (frame), 
+                               (GDestroyNotify) gtk_widget_unref);
+       g_object_set_data_full (G_OBJECT (volume_window), "vbox1",
+                               gtk_widget_ref (vbox1), 
+                               (GDestroyNotify) gtk_widget_unref);
+       g_object_set_data_full (G_OBJECT (volume_window), "hbox1",
+                               gtk_widget_ref (hbox1), 
+                               (GDestroyNotify) gtk_widget_unref);
+       g_object_set_data_full (G_OBJECT (volume_window), "hbox3",
+                               gtk_widget_ref (hbox3), 
+                               (GDestroyNotify) gtk_widget_unref);
+       g_object_set_data_full (G_OBJECT (volume_window), "hbox4",
+                               gtk_widget_ref (hbox4), 
+                               (GDestroyNotify) gtk_widget_unref);
+
+       gtk_window_add_accel_group (GTK_WINDOW (volume_window), accel_group);
+
+       return volume_window;
+}
+
+static StereoVolume vol;
+extern int mixer_fd;                    
+
+static gboolean 
+on_spinbutton1_button_release_event (GtkWidget *widget, 
+                                    GdkEventButton *event,
+                                    gpointer user_data)
+{
+       GtkSpinButton *spin;
+       extern GtkWidget *spinbutton1;
+       spin = GTK_SPIN_BUTTON (spinbutton1);
+       vol.left = vol.right = (int) gtk_spin_button_get_value_as_int (spin);
+       ioctl(mixer_fd,MIXER_WRITE(SOUND_MIXER_VOLUME), &vol);
+
+       return FALSE;
+}
+
+static gboolean
+on_vscale1_button_release_event (GtkWidget *widget,
+                                GdkEventButton *event,
+                                gpointer user_data)
+{
+       vol.left = vol.right = 
+               (int) gtk_adjustment_get_value(GTK_ADJUSTMENT(user_data));
+       ioctl(mixer_fd, MIXER_WRITE(SOUND_MIXER_VOLUME), &vol);
+       return FALSE;
+}
diff --git a/src/plugins/volume/volume-impl.h b/src/plugins/volume/volume-impl.h
new file mode 100644 (file)
index 0000000..03f5b78
--- /dev/null
@@ -0,0 +1,16 @@
+
+GtkWidget* create_volume_window (void);
+
+struct originalset
+{
+  unsigned char mainvol;
+  unsigned char pcm;
+  unsigned char speaker;
+  unsigned char line1;
+  unsigned char cd;
+  unsigned char mic;
+};
+
+
+
+
diff --git a/src/plugins/volume/volume.c b/src/plugins/volume/volume.c
new file mode 100644 (file)
index 0000000..be0fc3b
--- /dev/null
@@ -0,0 +1,114 @@
+#include <gtk/gtk.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "panel.h"
+#include "misc.h"
+#include "plugin.h"
+
+#include "dbg.h"
+
+#include "volume-impl.h"
+
+#include "volume_xpm.h"
+
+int mixer_fd;
+
+typedef struct {
+       GtkWidget *mainw;
+       GtkWidget *dlg;
+} volume_t;
+
+static void
+volume_destructor(plugin *p)
+{
+       volume_t *ns = (volume_t *) p->priv;
+
+       ENTER;
+       gtk_widget_destroy(ns->mainw);
+       if (mixer_fd)
+               close(mixer_fd);
+       g_free(ns);
+       RET();
+}
+
+static void on_volume_focus (GtkWidget* dlg, GdkEventFocus *event, volume_t *ns)
+{
+       /* FIXME: use smarter method */
+       gtk_widget_destroy( dlg );
+       ns->dlg = NULL;
+}
+
+static void on_button_press (GtkWidget* widget, GdkEventButton* evt, plugin* p)
+{
+       volume_t *ns = (volume_t*) p->priv;
+
+       if( evt->button == 1 ) { /*  Left click*/
+               if( ! ns->dlg ) {
+                       ns->dlg = create_volume_window();
+                       g_signal_connect( ns->dlg, "focus-out-event", on_volume_focus, ns );
+               }
+               gtk_window_present( GTK_WINDOW(ns->dlg) );
+       }
+}
+
+static int
+volume_constructor(plugin *p)
+{
+       volume_t *ns;
+       line s;
+       GdkPixbuf *icon;
+       GtkWidget *image;
+
+       ENTER;
+       s.len = 256;  
+       ns = g_new0(volume_t, 1);
+       g_return_val_if_fail(ns != NULL, 0);
+       p->priv = ns;
+
+       /* check if OSS mixer device could be open */
+       mixer_fd = open ("/dev/mixer", O_RDWR, 0);
+       if (mixer_fd < 0) {
+               RET(0);
+       }
+
+       ns->mainw = gtk_event_box_new();
+
+       icon = gdk_pixbuf_new_from_xpm_data(volume_xpm);
+       if(icon) {
+               image = gtk_image_new_from_pixbuf(icon);
+               gtk_container_add (GTK_CONTAINER (ns->mainw), image);
+       }
+
+       gtk_widget_add_events( ns->mainw, GDK_BUTTON_PRESS_MASK );
+       g_signal_connect( ns->mainw, "button-press-event",
+                       G_CALLBACK(on_button_press), p );
+       gtk_widget_set_size_request( ns->mainw, 24, 24 );
+
+       gtk_widget_show_all(ns->mainw);
+
+       gtk_container_add(GTK_CONTAINER(p->pwid), ns->mainw);
+
+       RET(1);
+
+error:
+       volume_destructor(p);
+       RET(0);
+}
+
+
+plugin_class volume_plugin_class = {
+       fname: NULL,
+       count: 0,
+
+       type : "volume",
+       name : "volume",
+       version: "1.0",
+       description : "Display and control volume",
+
+       constructor : volume_constructor,
+       destructor  : volume_destructor,
+};
diff --git a/src/plugins/volume/volume_xpm.h b/src/plugins/volume/volume_xpm.h
new file mode 100644 (file)
index 0000000..635ff78
--- /dev/null
@@ -0,0 +1,26 @@
+static char * volume_xpm[] = {
+       "16 16 7 1",
+       "       c None",
+       ".      c #000000",
+       "+      c #808000",
+       "@      c #808080",
+       "#      c #FFFF00",
+       "$      c #C0C0C0",
+       "%      c #FFFFFF",
+       "       ..       ",
+       "      +@.@      ",
+       "     +#.$$      ",
+       "    +#@@$%@   @ ",
+       "   +#%.$%%@  @  ",
+       " ++#%#.$%%@ @   ",
+       "+%$%#%..%%@     ",
+       "+#$#%#.$.%@     ",
+       "+#$%#%.@.%@ @@@@",
+       ".+@#%#..%%@     ",
+       " ..+#%.$%%@     ",
+       "   .+#.$%%@ @   ",
+       "    .+@@%%@  @  ",
+       "     .+.$$@   @ ",
+       "      .+.@      ",
+       "       ..       "
+};