diff options
-rw-r--r-- | Jamfile | 12 | ||||
-rw-r--r-- | callbacks.c | 277 | ||||
-rw-r--r-- | callbacks.h | 37 | ||||
-rw-r--r-- | cvorbis.c | 9 | ||||
-rw-r--r-- | deadbeef.glade | 268 | ||||
-rw-r--r-- | interface.c | 175 | ||||
-rw-r--r-- | interface.h | 5 | ||||
-rw-r--r-- | main.c | 19 | ||||
-rw-r--r-- | playlist.c | 38 | ||||
-rw-r--r-- | playlist.h | 9 | ||||
-rw-r--r-- | psdl.c | 10 | ||||
-rw-r--r-- | psdl.h | 3 | ||||
-rw-r--r-- | support.c | 144 | ||||
-rw-r--r-- | support.h | 44 |
14 files changed, 1042 insertions, 8 deletions
@@ -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); @@ -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); @@ -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; } @@ -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; +} + @@ -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 @@ -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) { @@ -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); + |