summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Jamfile12
-rw-r--r--callbacks.c277
-rw-r--r--callbacks.h37
-rw-r--r--cvorbis.c9
-rw-r--r--deadbeef.glade268
-rw-r--r--interface.c175
-rw-r--r--interface.h5
-rw-r--r--main.c19
-rw-r--r--playlist.c38
-rw-r--r--playlist.h9
-rw-r--r--psdl.c10
-rw-r--r--psdl.h3
-rw-r--r--support.c144
-rw-r--r--support.h44
14 files changed, 1042 insertions, 8 deletions
diff --git a/Jamfile b/Jamfile
index 607ab627..0c195a72 100644
--- a/Jamfile
+++ b/Jamfile
@@ -2,8 +2,16 @@ SubDir ROOT ;
CCFLAGS += -D_GNU_SOURCE ;
CCFLAGS += -std=c99 ;
+HDRS += /usr/include/gtk-2.0 ;
+HDRS += /usr/lib/gtk-2.0/include ;
+HDRS += /usr/include/glib-2.0 ;
+HDRS += /usr/lib/glib-2.0/include ;
+HDRS += /usr/include/atk-1.0 ;
+HDRS += /usr/include/pango-1.0 ;
+HDRS += /usr/include/cairo ;
+
Main deadbeef :
- cmod.c codec.c cvorbis.c cwav.c playlist.c psdl.c main.c ;
+ cmod.c codec.c cvorbis.c cwav.c playlist.c psdl.c main.c support.c interface.c callbacks.c ;
-LINKLIBS on deadbeef = -lmikmod -lm -lvorbis -logg -lvorbisfile -lmikmod -lSDL -lsamplerate ;
+LINKLIBS on deadbeef = -lmikmod -lm -lvorbis -logg -lvorbisfile -lmikmod -lSDL -lsamplerate -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lm -lpangocairo-1.0 -lpango-1.0 -lcairo -lgobject-2.0 -lgmodule-2.0 ;
diff --git a/callbacks.c b/callbacks.c
new file mode 100644
index 00000000..9470049e
--- /dev/null
+++ b/callbacks.c
@@ -0,0 +1,277 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <math.h>
+
+#include "callbacks.h"
+#include "interface.h"
+#include "support.h"
+
+#include "psdl.h"
+#include "playlist.h"
+
+#define min(x,y) ((x)<(y)?(x):(y))
+#define max(x,y) ((x)>(y)?(x):(y))
+
+extern GtkWidget *mainwin;
+static GdkPixmap *backbuf;
+static int rowheight = 12;
+#define trackerscroll 0
+static int playlist_row = -1;
+static double playlist_clicktime = 0;
+static double ps_lastpos[2];
+
+static void
+addfile_func (gpointer data, gpointer userdata) {
+ ps_add_file (data);
+ g_free (data);
+}
+
+ void
+on_addbtn_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ GtkWidget *dlg = gtk_file_chooser_dialog_new ("Add file(s) to playlist...", GTK_WINDOW (mainwin), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
+
+ GtkFileFilter* flt;
+ flt = gtk_file_filter_new ();
+ gtk_file_filter_set_name (flt, "Supported music files");
+ gtk_file_filter_add_pattern (flt, "*.ogg");
+ gtk_file_filter_add_pattern (flt, "*.mod");
+ gtk_file_filter_add_pattern (flt, "*.wav");
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
+ gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dlg), flt);
+ flt = gtk_file_filter_new ();
+ gtk_file_filter_set_name (flt, "Other files (*)");
+ gtk_file_filter_add_pattern (flt, "*");
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
+ gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dlg), TRUE);
+
+ if (gtk_dialog_run (GTK_DIALOG (dlg)) == GTK_RESPONSE_OK)
+ {
+ GSList *lst = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (dlg));
+ g_slist_foreach(lst, addfile_func, NULL);
+ g_slist_free (lst);
+ }
+ gtk_widget_destroy (dlg);
+}
+
+
+void
+on_playbtn_clicked (GtkButton *button,
+ gpointer user_data)
+{
+
+}
+
+
+void
+on_volume_value_changed (GtkRange *range,
+ gpointer user_data)
+{
+ psdl_set_volume (gtk_range_get_value (range) / 100);
+}
+
+
+void
+on_playpos_value_changed (GtkRange *range,
+ gpointer user_data)
+{
+
+}
+
+
+// change properties
+gboolean
+on_playlist_configure_event (GtkWidget *widget,
+ GdkEventConfigure *event,
+ gpointer user_data)
+{
+ if (backbuf) {
+ g_object_unref (backbuf);
+ }
+ backbuf = gdk_pixmap_new (widget->window, widget->allocation.width, widget->allocation.height, -1);
+
+ return FALSE;
+}
+
+void
+draw_ps_row_back (GdkDrawable *drawable, cairo_t *cr, int row) {
+ // draw background
+ float w;
+ int start, end;
+ int startx, endx;
+ int width, height;
+ gdk_drawable_get_size (drawable, &width, &height);
+ w = width;
+ if (row == playlist_row) {
+ cairo_set_source_rgb (cr, 0.22, 0.1, 0.1);
+ cairo_rectangle (cr, 0, row * rowheight - trackerscroll * rowheight, width, rowheight);
+ cairo_fill (cr);
+ }
+ else {
+ if (row % 2) {
+// cairo_set_source_rgb (cr, 0.22, 0.22, 0.22);
+// cairo_rectangle (cr, w, row * rowheight - trackerscroll * rowheight, width - w, rowheight);
+// cairo_fill (cr);
+ cairo_set_source_rgb (cr, 0.33, 0.33, 0.33);
+ cairo_rectangle (cr, 0, row * rowheight - trackerscroll * rowheight, w, rowheight);
+ cairo_fill (cr);
+ }
+ else {
+ cairo_set_source_rgb (cr, 0.22, 0.22, 0.22);
+ cairo_rectangle (cr, 0, row * rowheight - trackerscroll * rowheight, width, rowheight);
+ cairo_fill (cr);
+ }
+ }
+// start = min (vbstart[1], vbend[1]);
+// end = max (vbstart[1], vbend[1]);
+// startx = min (vbstart[0], vbend[0]);
+// endx = max (vbstart[0], vbend[0]);
+// if (tracker_vbmode && row >= start && row <= end) { // hilight selected notes
+// cairo_set_source_rgb (cr, 0.0, 0.44, 0.0);
+// cairo_rectangle (cr, startx * colwidth * COL_NUM_CHARS + colwidth * 3, row * rowheight - trackerscroll * rowheight, (endx - startx + 1) * colwidth * COL_NUM_CHARS, rowheight);
+// cairo_fill (cr);
+// }
+}
+
+static void
+text_draw (cairo_t *cr, int x, int y, const char *text) {
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_move_to (cr, x, y+rowheight-3);
+ cairo_show_text (cr, text);
+}
+
+void
+draw_ps_row (GdkDrawable *drawable, cairo_t *cr, int row, playItem_t *it) {
+ text_draw (cr, 0, row * rowheight - trackerscroll * rowheight, it->displayname);
+}
+
+void
+redraw_ps_row (GtkWidget *widget, int row) {
+ int x, y, w, h;
+
+ x = 0;
+ y = (row - trackerscroll) * rowheight;
+ w = widget->allocation.width;
+ h = rowheight;
+
+ cairo_t *cr;
+ cr = gdk_cairo_create (backbuf);
+ if (!cr) {
+ return;
+ }
+
+ cairo_select_font_face (cr, "fixed", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size (cr, rowheight);
+
+ playItem_t *it = ps_get_for_idx (row);
+ if (it) {
+ draw_ps_row_back (backbuf, cr, row);
+ draw_ps_row (backbuf, cr, row, it);
+ }
+ cairo_destroy (cr);
+ gdk_draw_drawable (widget->window, widget->style->black_gc, backbuf, x, y, x, y, w, h);
+}
+
+void draw_playlist (GtkWidget *widget, int x, int y, int w, int h) {
+ cairo_t *cr;
+ cr = gdk_cairo_create (backbuf);
+ if (!cr) {
+ return;
+ }
+
+ cairo_select_font_face (cr, "fixed", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size (cr, rowheight);
+ int row;
+ int row1;
+ int row2;
+ int row2_full;
+ row1 = max (0, y / rowheight + trackerscroll);
+ row2 = min (ps_getcount (), (y+h) / rowheight + trackerscroll + 1);
+ row2_full = (y+h) / rowheight + trackerscroll + 1;
+ // draw background
+ for (row = row1; row < row2_full; row++) {
+ draw_ps_row_back (backbuf, cr, row);
+ }
+ playItem_t *it = ps_get_for_idx (trackerscroll);
+ for (row = row1; row < row2; row++) {
+ draw_ps_row (backbuf, cr, row, it);
+ it = it->next;
+ }
+
+ cairo_destroy (cr);
+ gdk_draw_drawable (widget->window, widget->style->black_gc, backbuf, x, y, x, y, w, h);
+}
+
+
+// redraw
+gboolean
+on_playlist_expose_event (GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer user_data)
+{
+ // draw visible area of playlist
+ draw_playlist (widget, event->area.x, event->area.y, event->area.width, event->area.height);
+
+ return FALSE;
+}
+
+
+void
+on_playlist_realize (GtkWidget *widget,
+ gpointer user_data)
+{
+
+}
+
+
+gboolean
+on_playlist_button_press_event (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer user_data)
+{
+ // remember mouse coords for doubleclick detection
+ ps_lastpos[0] = event->x;
+ ps_lastpos[1] = event->y;
+ // select item
+ int y = event->y/rowheight - trackerscroll;
+ if (y < 0 && y >= ps_getcount ()) {
+ y = -1;
+ }
+
+ if (playlist_row != y) {
+ int old = playlist_row;
+ playlist_row = y;
+ if (old != -1) {
+ redraw_ps_row (widget, old);
+ }
+ if (playlist_row != -1) {
+ redraw_ps_row (widget, playlist_row);
+ }
+ }
+
+ if (event->time - playlist_clicktime < 0.5
+ && fabs(ps_lastpos[0] - event->x) < 3
+ && fabs(ps_lastpos[1] - event->y) < 3) {
+ // doubleclick - play this item
+ if (playlist_row != -1) {
+ playItem_t *it = ps_get_for_idx (playlist_row);
+ if (it) {
+ psdl_stop ();
+ psdl_play (it);
+ }
+ }
+
+
+ // prevent next click to trigger doubleclick
+ playlist_clicktime = event->time-1;
+ }
+ else {
+ playlist_clicktime = event->time;
+ }
+ return FALSE;
+}
+
diff --git a/callbacks.h b/callbacks.h
new file mode 100644
index 00000000..d828168f
--- /dev/null
+++ b/callbacks.h
@@ -0,0 +1,37 @@
+#include <gtk/gtk.h>
+
+
+void
+on_addbtn_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_playbtn_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_volume_value_changed (GtkRange *range,
+ gpointer user_data);
+
+void
+on_playpos_value_changed (GtkRange *range,
+ gpointer user_data);
+
+gboolean
+on_playlist_configure_event (GtkWidget *widget,
+ GdkEventConfigure *event,
+ gpointer user_data);
+
+gboolean
+on_playlist_expose_event (GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer user_data);
+
+void
+on_playlist_realize (GtkWidget *widget,
+ gpointer user_data);
+
+gboolean
+on_playlist_button_press_event (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer user_data);
diff --git a/cvorbis.c b/cvorbis.c
index 7ce772e1..e5965d38 100644
--- a/cvorbis.c
+++ b/cvorbis.c
@@ -32,9 +32,12 @@ int cvorbis_init (const char *fname) {
void
cvorbis_free (void) {
- fclose (file);
- ov_clear (&vorbis_file);
- vi = NULL;
+ if (file) {
+ ov_clear (&vorbis_file);
+ //fclose (file); -- ov_clear closes it
+ file = NULL;
+ vi = NULL;
+ }
}
int
diff --git a/deadbeef.glade b/deadbeef.glade
new file mode 100644
index 00000000..088e16ef
--- /dev/null
+++ b/deadbeef.glade
@@ -0,0 +1,268 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="mainwin">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">DeaDBeeF</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="default_width">750</property>
+ <property name="default_height">650</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <signal name="destroy" handler="gtk_main_quit" last_modification_time="Fri, 03 Jul 2009 23:48:26 GMT"/>
+
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkToolbar" id="toolbar1">
+ <property name="visible">True</property>
+ <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
+ <property name="toolbar_style">GTK_TOOLBAR_BOTH</property>
+ <property name="tooltips">True</property>
+ <property name="show_arrow">True</property>
+
+ <child>
+ <widget class="GtkToolItem" id="toolitem1">
+ <property name="visible">True</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+
+ <child>
+ <widget class="GtkButton" id="addbtn">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Add</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_addbtn_clicked" last_modification_time="Fri, 03 Jul 2009 23:36:03 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolItem" id="toolitem2">
+ <property name="visible">True</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+
+ <child>
+ <widget class="GtkButton" id="playbtn">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Play</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="on_playbtn_clicked" last_modification_time="Fri, 03 Jul 2009 23:36:16 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolItem" id="toolitem3">
+ <property name="visible">True</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+
+ <child>
+ <widget class="GtkButton" id="button3">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Stop</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox2">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Volume</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHScale" id="volume">
+ <property name="width_request">100</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="draw_value">False</property>
+ <property name="value_pos">GTK_POS_TOP</property>
+ <property name="digits">1</property>
+ <property name="update_policy">GTK_UPDATE_CONTINUOUS</property>
+ <property name="inverted">False</property>
+ <property name="adjustment">100 0 100 0 0 0</property>
+ <signal name="value_changed" handler="on_volume_value_changed" last_modification_time="Fri, 03 Jul 2009 23:43:47 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox3">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Play position</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHScale" id="playpos">
+ <property name="width_request">200</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="draw_value">False</property>
+ <property name="value_pos">GTK_POS_TOP</property>
+ <property name="digits">1</property>
+ <property name="update_policy">GTK_UPDATE_CONTINUOUS</property>
+ <property name="inverted">False</property>
+ <property name="adjustment">0 0 1000 0 0 0</property>
+ <signal name="value_changed" handler="on_playpos_value_changed" last_modification_time="Fri, 03 Jul 2009 23:43:55 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkDrawingArea" id="playlist">
+ <property name="visible">True</property>
+ <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK</property>
+ <signal name="configure_event" handler="on_playlist_configure_event" last_modification_time="Sat, 04 Jul 2009 00:03:23 GMT"/>
+ <signal name="expose_event" handler="on_playlist_expose_event" last_modification_time="Sat, 04 Jul 2009 00:03:29 GMT"/>
+ <signal name="realize" handler="on_playlist_realize" last_modification_time="Sat, 04 Jul 2009 00:03:36 GMT"/>
+ <signal name="button_press_event" handler="on_playlist_button_press_event" last_modification_time="Sat, 04 Jul 2009 00:41:38 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/interface.c b/interface.c
new file mode 100644
index 00000000..bf5b494e
--- /dev/null
+++ b/interface.c
@@ -0,0 +1,175 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include "callbacks.h"
+#include "interface.h"
+#include "support.h"
+
+#define GLADE_HOOKUP_OBJECT(component,widget,name) \
+ g_object_set_data_full (G_OBJECT (component), name, \
+ gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref)
+
+#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \
+ g_object_set_data (G_OBJECT (component), name, widget)
+
+GtkWidget*
+create_mainwin (void)
+{
+ GtkWidget *mainwin;
+ GtkWidget *vbox1;
+ GtkWidget *hbox1;
+ GtkWidget *toolbar1;
+ GtkIconSize tmp_toolbar_icon_size;
+ GtkWidget *toolitem1;
+ GtkWidget *addbtn;
+ GtkWidget *toolitem2;
+ GtkWidget *playbtn;
+ GtkWidget *toolitem3;
+ GtkWidget *button3;
+ GtkWidget *vbox2;
+ GtkWidget *label1;
+ GtkWidget *volume;
+ GtkWidget *vbox3;
+ GtkWidget *label2;
+ GtkWidget *playpos;
+ GtkWidget *playlist;
+
+ mainwin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (mainwin), "DeaDBeeF");
+ gtk_window_set_default_size (GTK_WINDOW (mainwin), 750, 650);
+
+ vbox1 = gtk_vbox_new (FALSE, 0);
+ gtk_widget_show (vbox1);
+ gtk_container_add (GTK_CONTAINER (mainwin), vbox1);
+
+ hbox1 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_show (hbox1);
+ gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, FALSE, 0);
+
+ toolbar1 = gtk_toolbar_new ();
+ gtk_widget_show (toolbar1);
+ gtk_box_pack_start (GTK_BOX (hbox1), toolbar1, TRUE, TRUE, 0);
+ gtk_toolbar_set_style (GTK_TOOLBAR (toolbar1), GTK_TOOLBAR_BOTH);
+ tmp_toolbar_icon_size = gtk_toolbar_get_icon_size (GTK_TOOLBAR (toolbar1));
+
+ toolitem1 = (GtkWidget*) gtk_tool_item_new ();
+ gtk_widget_show (toolitem1);
+ gtk_container_add (GTK_CONTAINER (toolbar1), toolitem1);
+
+ addbtn = gtk_button_new_with_mnemonic ("Add");
+ gtk_widget_show (addbtn);
+ gtk_container_add (GTK_CONTAINER (toolitem1), addbtn);
+
+ toolitem2 = (GtkWidget*) gtk_tool_item_new ();
+ gtk_widget_show (toolitem2);
+ gtk_container_add (GTK_CONTAINER (toolbar1), toolitem2);
+
+ playbtn = gtk_button_new_with_mnemonic ("Play");
+ gtk_widget_show (playbtn);
+ gtk_container_add (GTK_CONTAINER (toolitem2), playbtn);
+
+ toolitem3 = (GtkWidget*) gtk_tool_item_new ();
+ gtk_widget_show (toolitem3);
+ gtk_container_add (GTK_CONTAINER (toolbar1), toolitem3);
+
+ button3 = gtk_button_new_with_mnemonic ("Stop");
+ gtk_widget_show (button3);
+ gtk_container_add (GTK_CONTAINER (toolitem3), button3);
+
+ vbox2 = gtk_vbox_new (FALSE, 0);
+ gtk_widget_show (vbox2);
+ gtk_box_pack_start (GTK_BOX (hbox1), vbox2, FALSE, TRUE, 0);
+
+ label1 = gtk_label_new ("Volume");
+ gtk_widget_show (label1);
+ gtk_box_pack_start (GTK_BOX (vbox2), label1, FALSE, FALSE, 0);
+
+ volume = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (100, 0, 100, 0, 0, 0)));
+ gtk_widget_show (volume);
+ gtk_box_pack_start (GTK_BOX (vbox2), volume, TRUE, TRUE, 0);
+ gtk_widget_set_size_request (volume, 100, -1);
+ gtk_scale_set_draw_value (GTK_SCALE (volume), FALSE);
+
+ vbox3 = gtk_vbox_new (FALSE, 0);
+ gtk_widget_show (vbox3);
+ gtk_box_pack_start (GTK_BOX (hbox1), vbox3, FALSE, TRUE, 0);
+
+ label2 = gtk_label_new ("Play position");
+ gtk_widget_show (label2);
+ gtk_box_pack_start (GTK_BOX (vbox3), label2, FALSE, FALSE, 0);
+
+ playpos = gtk_hscale_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, 0, 1000, 0, 0, 0)));
+ gtk_widget_show (playpos);
+ gtk_box_pack_start (GTK_BOX (vbox3), playpos, TRUE, TRUE, 0);
+ gtk_widget_set_size_request (playpos, 200, -1);
+ gtk_scale_set_draw_value (GTK_SCALE (playpos), FALSE);
+
+ playlist = gtk_drawing_area_new ();
+ gtk_widget_show (playlist);
+ gtk_box_pack_start (GTK_BOX (vbox1), playlist, TRUE, TRUE, 0);
+ gtk_widget_set_events (playlist, GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
+
+ g_signal_connect ((gpointer) mainwin, "destroy",
+ G_CALLBACK (gtk_main_quit),
+ NULL);
+ g_signal_connect ((gpointer) addbtn, "clicked",
+ G_CALLBACK (on_addbtn_clicked),
+ NULL);
+ g_signal_connect ((gpointer) playbtn, "clicked",
+ G_CALLBACK (on_playbtn_clicked),
+ NULL);
+ g_signal_connect ((gpointer) volume, "value_changed",
+ G_CALLBACK (on_volume_value_changed),
+ NULL);
+ g_signal_connect ((gpointer) playpos, "value_changed",
+ G_CALLBACK (on_playpos_value_changed),
+ NULL);
+ g_signal_connect ((gpointer) playlist, "configure_event",
+ G_CALLBACK (on_playlist_configure_event),
+ NULL);
+ g_signal_connect ((gpointer) playlist, "expose_event",
+ G_CALLBACK (on_playlist_expose_event),
+ NULL);
+ g_signal_connect ((gpointer) playlist, "realize",
+ G_CALLBACK (on_playlist_realize),
+ NULL);
+ g_signal_connect ((gpointer) playlist, "button_press_event",
+ G_CALLBACK (on_playlist_button_press_event),
+ NULL);
+
+ /* Store pointers to all widgets, for use by lookup_widget(). */
+ GLADE_HOOKUP_OBJECT_NO_REF (mainwin, mainwin, "mainwin");
+ GLADE_HOOKUP_OBJECT (mainwin, vbox1, "vbox1");
+ GLADE_HOOKUP_OBJECT (mainwin, hbox1, "hbox1");
+ GLADE_HOOKUP_OBJECT (mainwin, toolbar1, "toolbar1");
+ GLADE_HOOKUP_OBJECT (mainwin, toolitem1, "toolitem1");
+ GLADE_HOOKUP_OBJECT (mainwin, addbtn, "addbtn");
+ GLADE_HOOKUP_OBJECT (mainwin, toolitem2, "toolitem2");
+ GLADE_HOOKUP_OBJECT (mainwin, playbtn, "playbtn");
+ GLADE_HOOKUP_OBJECT (mainwin, toolitem3, "toolitem3");
+ GLADE_HOOKUP_OBJECT (mainwin, button3, "button3");
+ GLADE_HOOKUP_OBJECT (mainwin, vbox2, "vbox2");
+ GLADE_HOOKUP_OBJECT (mainwin, label1, "label1");
+ GLADE_HOOKUP_OBJECT (mainwin, volume, "volume");
+ GLADE_HOOKUP_OBJECT (mainwin, vbox3, "vbox3");
+ GLADE_HOOKUP_OBJECT (mainwin, label2, "label2");
+ GLADE_HOOKUP_OBJECT (mainwin, playpos, "playpos");
+ GLADE_HOOKUP_OBJECT (mainwin, playlist, "playlist");
+
+ return mainwin;
+}
+
diff --git a/interface.h b/interface.h
new file mode 100644
index 00000000..4395ee18
--- /dev/null
+++ b/interface.h
@@ -0,0 +1,5 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+GtkWidget* create_mainwin (void);
diff --git a/main.c b/main.c
index 3113e750..dfd72ff6 100644
--- a/main.c
+++ b/main.c
@@ -1,8 +1,14 @@
+#include <gtk/gtk.h>
+#include "interface.h"
+#include "support.h"
#include <stdio.h>
#include "playlist.h"
#include "psdl.h"
#include "unistd.h"
+
+GtkWidget *mainwin;
+
int
main (int argc, char *argv[]) {
if (argc <= 1) {
@@ -13,11 +19,22 @@ main (int argc, char *argv[]) {
if (!ps_add_file (argv[1])) {
printf ("playing %s\n", argv[1]);
psdl_play (playlist_head);
- sleep (10);
}
else {
printf ("failed to play %s\n", argv[1]);
}
+ gtk_set_locale ();
+ gtk_init (&argc, &argv);
+
+ /*
+ * The following code was added by Glade to create one of each component
+ * (except popup menus), just so that you see something after building
+ * the project. Delete any components that you don't want shown initially.
+ */
+ mainwin = create_mainwin ();
+ gtk_widget_show (mainwin);
+ gtk_main ();
psdl_free ();
+ ps_free ();
return 0;
}
diff --git a/playlist.c b/playlist.c
index 33ef9996..2f25db67 100644
--- a/playlist.c
+++ b/playlist.c
@@ -2,6 +2,7 @@
#include <string.h>
#include <dirent.h>
#include <fnmatch.h>
+#include <stdio.h>
#include "playlist.h"
#include "codec.h"
#include "cwav.h"
@@ -11,6 +12,14 @@
playItem_t *playlist_head;
playItem_t *playlist_tail;
playItem_t *playlist_current;
+static int ps_count = 0;
+
+void
+ps_free (void) {
+ while (playlist_head) {
+ ps_remove (playlist_head);
+ }
+}
int
ps_add_file (const char *fname) {
@@ -37,9 +46,19 @@ ps_add_file (const char *fname) {
else {
return -1;
}
+ printf ("added %s to playlist\n", fname);
+ ps_count++;
// copy string
it->fname = strdup (fname);
- it->displayname = strdup (fname);
+ // find 1st slash from end
+ while (eol > fname && *eol != '/') {
+ eol--;
+ }
+ if (*eol=='/') {
+ eol++;
+ }
+
+ it->displayname = strdup (eol);
it->timestart = -1;
it->timeend = -1;
@@ -85,6 +104,7 @@ int
ps_remove (playItem_t *it) {
if (!it)
return -1;
+ ps_count--;
if (it->fname) {
free (it->fname);
}
@@ -107,3 +127,19 @@ ps_remove (playItem_t *it) {
return 0;
}
+int
+ps_getcount (void) {
+ return ps_count;
+}
+
+playItem_t *
+ps_get_for_idx (int idx) {
+ playItem_t *it = playlist_head;
+ while (idx--) {
+ if (!it)
+ return NULL;
+ it = it->next;
+ }
+ return it;
+}
+
diff --git a/playlist.h b/playlist.h
index 944230a0..92349943 100644
--- a/playlist.h
+++ b/playlist.h
@@ -25,4 +25,13 @@ ps_add_dir (const char *dirname);
int
ps_remove (playItem_t *i);
+void
+ps_free (void);
+
+int
+ps_getcount (void);
+
+playItem_t *
+ps_get_for_idx (int idx);
+
#endif // __PLAYLIST_H
diff --git a/psdl.c b/psdl.c
index b64e54fe..3e47837a 100644
--- a/psdl.c
+++ b/psdl.c
@@ -90,8 +90,11 @@ psdl_play (struct playItem_s *it) {
int
psdl_stop (void) {
- codec = NULL;
SDL_PauseAudio (1);
+ if (codec) {
+ codec->free ();
+ codec = NULL;
+ }
}
int
@@ -99,6 +102,11 @@ psdl_pause (void) {
SDL_PauseAudio (1);
}
+void
+psdl_set_volume (float vol) {
+ sdl_volume = vol;
+}
+
static void
psdl_callback (void* userdata, Uint8 *stream, int len) {
if (!codec) {
diff --git a/psdl.h b/psdl.h
index 6136c55f..8c34e311 100644
--- a/psdl.h
+++ b/psdl.h
@@ -18,4 +18,7 @@ psdl_stop (void);
int
psdl_pause (void);
+void
+psdl_set_volume (float vol);
+
#endif // __PSDL_H
diff --git a/support.c b/support.c
new file mode 100644
index 00000000..7dc3c78c
--- /dev/null
+++ b/support.c
@@ -0,0 +1,144 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <gtk/gtk.h>
+
+#include "support.h"
+
+GtkWidget*
+lookup_widget (GtkWidget *widget,
+ const gchar *widget_name)
+{
+ GtkWidget *parent, *found_widget;
+
+ for (;;)
+ {
+ if (GTK_IS_MENU (widget))
+ parent = gtk_menu_get_attach_widget (GTK_MENU (widget));
+ else
+ parent = widget->parent;
+ if (!parent)
+ parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey");
+ if (parent == NULL)
+ break;
+ widget = parent;
+ }
+
+ found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget),
+ widget_name);
+ if (!found_widget)
+ g_warning ("Widget not found: %s", widget_name);
+ return found_widget;
+}
+
+static GList *pixmaps_directories = NULL;
+
+/* Use this function to set the directory containing installed pixmaps. */
+void
+add_pixmap_directory (const gchar *directory)
+{
+ pixmaps_directories = g_list_prepend (pixmaps_directories,
+ g_strdup (directory));
+}
+
+/* This is an internally used function to find pixmap files. */
+static gchar*
+find_pixmap_file (const gchar *filename)
+{
+ GList *elem;
+
+ /* We step through each of the pixmaps directory to find it. */
+ elem = pixmaps_directories;
+ while (elem)
+ {
+ gchar *pathname = g_strdup_printf ("%s%s%s", (gchar*)elem->data,
+ G_DIR_SEPARATOR_S, filename);
+ if (g_file_test (pathname, G_FILE_TEST_EXISTS))
+ return pathname;
+ g_free (pathname);
+ elem = elem->next;
+ }
+ return NULL;
+}
+
+/* This is an internally used function to create pixmaps. */
+GtkWidget*
+create_pixmap (GtkWidget *widget,
+ const gchar *filename)
+{
+ gchar *pathname = NULL;
+ GtkWidget *pixmap;
+
+ if (!filename || !filename[0])
+ return gtk_image_new ();
+
+ pathname = find_pixmap_file (filename);
+
+ if (!pathname)
+ {
+ g_warning ("Couldn't find pixmap file: %s", filename);
+ return gtk_image_new ();
+ }
+
+ pixmap = gtk_image_new_from_file (pathname);
+ g_free (pathname);
+ return pixmap;
+}
+
+/* This is an internally used function to create pixmaps. */
+GdkPixbuf*
+create_pixbuf (const gchar *filename)
+{
+ gchar *pathname = NULL;
+ GdkPixbuf *pixbuf;
+ GError *error = NULL;
+
+ if (!filename || !filename[0])
+ return NULL;
+
+ pathname = find_pixmap_file (filename);
+
+ if (!pathname)
+ {
+ g_warning ("Couldn't find pixmap file: %s", filename);
+ return NULL;
+ }
+
+ pixbuf = gdk_pixbuf_new_from_file (pathname, &error);
+ if (!pixbuf)
+ {
+ fprintf (stderr, "Failed to load pixbuf file: %s: %s\n",
+ pathname, error->message);
+ g_error_free (error);
+ }
+ g_free (pathname);
+ return pixbuf;
+}
+
+/* This is used to set ATK action descriptions. */
+void
+glade_set_atk_action_description (AtkAction *action,
+ const gchar *action_name,
+ const gchar *description)
+{
+ gint n_actions, i;
+
+ n_actions = atk_action_get_n_actions (action);
+ for (i = 0; i < n_actions; i++)
+ {
+ if (!strcmp (atk_action_get_name (action, i), action_name))
+ atk_action_set_description (action, i, description);
+ }
+}
+
diff --git a/support.h b/support.h
new file mode 100644
index 00000000..2dea079c
--- /dev/null
+++ b/support.h
@@ -0,0 +1,44 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+
+/*
+ * Public Functions.
+ */
+
+/*
+ * This function returns a widget in a component created by Glade.
+ * Call it with the toplevel widget in the component (i.e. a window/dialog),
+ * or alternatively any widget in the component, and the name of the widget
+ * you want returned.
+ */
+GtkWidget* lookup_widget (GtkWidget *widget,
+ const gchar *widget_name);
+
+
+/* Use this function to set the directory containing installed pixmaps. */
+void add_pixmap_directory (const gchar *directory);
+
+
+/*
+ * Private Functions.
+ */
+
+/* This is used to create the pixmaps used in the interface. */
+GtkWidget* create_pixmap (GtkWidget *widget,
+ const gchar *filename);
+
+/* This is used to create the pixbufs used in the interface. */
+GdkPixbuf* create_pixbuf (const gchar *filename);
+
+/* This is used to set ATK action descriptions. */
+void glade_set_atk_action_description (AtkAction *action,
+ const gchar *action_name,
+ const gchar *description);
+