summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac10
-rw-r--r--deadbeef.h3
-rw-r--r--playlist.c2
-rw-r--r--plugins/artwork/artwork.c19
-rw-r--r--plugins/gtkui/Makefile.am1
-rw-r--r--plugins/gtkui/callbacks.c53
-rw-r--r--plugins/gtkui/callbacks.h4
-rw-r--r--plugins/gtkui/coverart.c68
-rw-r--r--plugins/gtkui/coverart.h4
-rw-r--r--plugins/gtkui/ddbcellrenderertextmultiline.c24
-rw-r--r--plugins/gtkui/ddbcellrenderertextmultiline.h9
-rw-r--r--plugins/gtkui/ddbequalizer.c3
-rw-r--r--plugins/gtkui/ddbequalizer.h3
-rw-r--r--plugins/gtkui/ddblistview.c46
-rw-r--r--plugins/gtkui/ddbseekbar.c6
-rw-r--r--plugins/gtkui/ddbseekbar.h5
-rw-r--r--plugins/gtkui/ddbtabstrip.c30
-rw-r--r--plugins/gtkui/deadbeef.glade83
-rw-r--r--plugins/gtkui/fileman.c16
-rw-r--r--plugins/gtkui/gtkui.c174
-rw-r--r--plugins/gtkui/gtkui.h7
-rw-r--r--plugins/gtkui/gtkui_api.h29
-rw-r--r--plugins/gtkui/interface.c130
-rw-r--r--plugins/gtkui/mainplaylist.c25
-rw-r--r--plugins/gtkui/mainplaylist.h5
-rw-r--r--plugins/gtkui/plcommon.c35
-rw-r--r--plugins/gtkui/plcommon.h12
-rw-r--r--plugins/gtkui/prefwin.c30
-rw-r--r--plugins/gtkui/search.c18
-rw-r--r--plugins/gtkui/trkproperties.c45
-rw-r--r--plugins/gtkui/trkproperties.h8
-rw-r--r--plugins/gtkui/widgets.c1324
-rw-r--r--plugins/gtkui/widgets.h87
-rw-r--r--plugins/medialib/Makefile.am8
-rw-r--r--plugins/medialib/medialib.c256
-rwxr-xr-xscripts/quickinstall.sh1
36 files changed, 2192 insertions, 391 deletions
diff --git a/configure.ac b/configure.ac
index 68b81e2f..9427c45b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -105,6 +105,7 @@ AC_ARG_ENABLE(m3u, [AS_HELP_STRING([--enable-m3u ], [build m3u plugin
AC_ARG_ENABLE(vfs-zip, [AS_HELP_STRING([--enable-vfs-zip ], [build vfs_zip plugin (default: auto)])], [enable_vfs_zip=$enableval], [enable_vfs_zip=yes])
AC_ARG_ENABLE(converter, [AS_HELP_STRING([--enable-converter ], [build converter plugin (default: auto)])], [enable_converter=$enableval], [enable_converter=yes])
AC_ARG_ENABLE(artwork-imlib2, [AS_HELP_STRING([--enable-artwork-imlib2 ], [use imlib2 in artwork plugin (default: auto)])], [enable_artwork_imlib2=$enableval], [enable_artwork_imlib2=yes])
+AC_ARG_ENABLE(medialib, [AS_HELP_STRING([--enable-medialib ], [build medialibrary plugin (default: auto)])], [enable_medialib=$enableval], [enable_medialib=yes])
AC_ARG_ENABLE(dumb, [AS_HELP_STRING([--enable-dumb ], [build DUMB plugin (default: auto)])], [enable_dumb=$enableval], [enable_dumb=yes])
AC_ARG_ENABLE(shn, [AS_HELP_STRING([--enable-shn ], [build SHN plugin (default: auto)])], [enable_shn=$enableval], [enable_shn=yes])
AC_ARG_ENABLE(psf, [AS_HELP_STRING([--enable-psf ], [build AOSDK-based PSF(,QSF,SSF,DSF) plugin (default: auto)])], [enable_psf=$enableval], [enable_psf=yes])
@@ -552,6 +553,10 @@ if test "x$enable_converter" != "xno" ; then
fi
fi
+if test "x$enable_medialib" != "xno" ; then
+ HAVE_MEDIALIB=yes
+fi
+
if test "x$enable_dumb" != "xno" ; then
HAVE_DUMB=yes
fi
@@ -568,7 +573,7 @@ if test "x$enable_mono2stereo" != "xno" ; then
HAVE_MONO2STEREO=yes
fi
-PLUGINS_DIRS="plugins/lastfm plugins/mpgmad plugins/vorbis plugins/flac plugins/wavpack plugins/sndfile plugins/vfs_curl plugins/cdda plugins/gtkui plugins/alsa plugins/ffmpeg plugins/hotkeys plugins/oss plugins/artwork plugins/adplug plugins/ffap plugins/sid plugins/nullout plugins/supereq plugins/vtx plugins/gme plugins/pulse plugins/notify plugins/musepack plugins/wildmidi plugins/tta plugins/dca plugins/aac plugins/mms plugins/shellexec plugins/dsp_libsrc plugins/m3u plugins/vfs_zip plugins/converter plugins/dumb plugins/shn plugins/ao plugins/mono2stereo"
+PLUGINS_DIRS="plugins/lastfm plugins/mpgmad plugins/vorbis plugins/flac plugins/wavpack plugins/sndfile plugins/vfs_curl plugins/cdda plugins/gtkui plugins/alsa plugins/ffmpeg plugins/hotkeys plugins/oss plugins/artwork plugins/adplug plugins/ffap plugins/sid plugins/nullout plugins/supereq plugins/vtx plugins/gme plugins/pulse plugins/notify plugins/musepack plugins/wildmidi plugins/tta plugins/dca plugins/aac plugins/mms plugins/shellexec plugins/dsp_libsrc plugins/m3u plugins/vfs_zip plugins/converter plugins/dumb plugins/shn plugins/ao plugins/mono2stereo plugins/medialib"
AM_CONDITIONAL(HAVE_VORBIS, test "x$HAVE_VORBISPLUGIN" = "xyes")
AM_CONDITIONAL(HAVE_FLAC, test "x$HAVE_FLACPLUGIN" = "xyes")
@@ -613,6 +618,7 @@ AM_CONDITIONAL(HAVE_IMLIB2, test "x$HAVE_IMLIB2" = "xyes")
AM_CONDITIONAL(HAVE_JPEG, test "x$HAVE_JPEG" = "xyes")
AM_CONDITIONAL(HAVE_PNG, test "x$HAVE_PNG" = "xyes")
AM_CONDITIONAL(HAVE_YASM, test "x$HAVE_YASM" = "xyes")
+AM_CONDITIONAL(HAVE_MEDIALIB, test "x$HAVE_MEDIALIB" = "xyes")
AM_CONDITIONAL(HAVE_DUMB, test "x$HAVE_DUMB" = "xyes")
AM_CONDITIONAL(HAVE_PSF, test "x$HAVE_PSF" = "xyes")
AM_CONDITIONAL(HAVE_SHN, test "x$HAVE_SHN" = "xyes")
@@ -677,6 +683,7 @@ PRINT_PLUGIN_INFO([dsp_src],[High quality samplerate conversion using libsampler
PRINT_PLUGIN_INFO([m3u],[M3U and PLS playlist support],[test "x$HAVE_M3U" = "xyes"])
PRINT_PLUGIN_INFO([vfs_zip],[zip archive support],[test "x$HAVE_VFS_ZIP" = "xyes"])
PRINT_PLUGIN_INFO([converter],[plugin for converting files to any formats],[test "x$HAVE_CONVERTER" = "xyes"])
+PRINT_PLUGIN_INFO([medialib],[media library support plugin],[test "x$HAVE_MEDIALIB" = "xyes"])
PRINT_PLUGIN_INFO([psf],[PSF format plugin, using AOSDK],[test "x$HAVE_PSF" = "xyes"])
PRINT_PLUGIN_INFO([dumb],[DUMB module plugin, for MOD, S3M, etc],[test "x$HAVE_DUMB" = "xyes"])
PRINT_PLUGIN_INFO([shn],[SHN plugin based on xmms-shn],[test "x$HAVE_SHN" = "xyes"])
@@ -722,6 +729,7 @@ plugins/dsp_libsrc/Makefile
plugins/m3u/Makefile
plugins/vfs_zip/Makefile
plugins/converter/Makefile
+plugins/medialib/Makefile
plugins/dumb/Makefile
plugins/ao/Makefile
plugins/shn/Makefile
diff --git a/deadbeef.h b/deadbeef.h
index f5b999ad..fb2289ba 100644
--- a/deadbeef.h
+++ b/deadbeef.h
@@ -269,6 +269,9 @@ enum {
DB_EV_PLAYLISTSWITCHED = 18, // playlist switch occured
DB_EV_SEEK = 19, // seek current track to position p1 (ms)
+ // new in 1.2
+ DB_EV_SELCHANGED = 20, // selection changed in playlist p1 iter p2
+
DB_EV_FIRST = 1000,
DB_EV_SONGCHANGED = 1000, // current song changed from one to another, ctx=ddb_event_trackchange_t
DB_EV_SONGSTARTED = 1001, // song started playing, ctx=ddb_event_track_t
diff --git a/playlist.c b/playlist.c
index 4975faf0..ebc68ce5 100644
--- a/playlist.c
+++ b/playlist.c
@@ -2684,7 +2684,7 @@ pl_format_time (float t, char *dur, int size) {
}
}
else {
- strcpy (dur, "-:--");
+ strcpy (dur, "∞");
}
}
diff --git a/plugins/artwork/artwork.c b/plugins/artwork/artwork.c
index 47aaf748..5dffd714 100644
--- a/plugins/artwork/artwork.c
+++ b/plugins/artwork/artwork.c
@@ -126,6 +126,9 @@ queue_add (const char *fname, const char *artist, const char *album, int img_siz
for (cover_query_t *q = queue; q; q = q->next) {
if (!strcasecmp (artist, q->artist) || !strcasecmp (album, q->album)) {
deadbeef->mutex_unlock (mutex);
+ if (callback) {
+ callback (NULL, NULL, NULL, user_data);
+ }
return; // already in queue
}
}
@@ -163,6 +166,9 @@ queue_pop (void) {
if (queue->album) {
free (queue->album);
}
+ if (queue->callback) {
+ queue->callback (NULL, NULL, NULL, queue->user_data);
+ }
free (queue);
}
queue = next;
@@ -1131,6 +1137,7 @@ fetcher_thread (void *none)
}
if (param->callback) {
param->callback (param->fname, param->artist, param->album, param->user_data);
+ param->callback = NULL;
}
}
queue_pop ();
@@ -1185,16 +1192,25 @@ get_album_art (const char *fname, const char *artist, const char *album, int siz
if (!*artist || !*album)
{
//give up
+ if (callback) {
+ callback (NULL, NULL, NULL, user_data);
+ }
return size == -1 ? strdup (get_default_cover ()) : NULL;
}
if (!deadbeef->is_local_file (fname)) {
+ if (callback) {
+ callback (NULL, NULL, NULL, user_data);
+ }
return size == -1 ? strdup (get_default_cover ()) : NULL;
}
make_cache_path (path, sizeof (path), album, artist, size);
char *p = find_image (path);
if (p) {
+ if (callback) {
+ callback (NULL, NULL, NULL, user_data);
+ }
return p;
}
@@ -1213,6 +1229,9 @@ get_album_art (const char *fname, const char *artist, const char *album, int siz
else {
int res = copy_file (unscaled_path, path, size);
if (!res) {
+ if (callback) {
+ callback (NULL, NULL, NULL, user_data);
+ }
return strdup (path);
}
}
diff --git a/plugins/gtkui/Makefile.am b/plugins/gtkui/Makefile.am
index 74889110..8d5c8860 100644
--- a/plugins/gtkui/Makefile.am
+++ b/plugins/gtkui/Makefile.am
@@ -23,6 +23,7 @@ GTKUI_SOURCES = gtkui.c gtkui.h\
tagwritersettings.c tagwritersettings.h\
wingeom.c wingeom.h\
pluginconf.h\
+ widgets.c widgets.h\
ddbseekbar.h ddbequalizer.h ddbcellrenderertextmultiline.h\
ddbseekbar.c ddbequalizer.c ddbcellrenderertextmultiline.c
diff --git a/plugins/gtkui/callbacks.c b/plugins/gtkui/callbacks.c
index be18328c..fae22fe1 100644
--- a/plugins/gtkui/callbacks.c
+++ b/plugins/gtkui/callbacks.c
@@ -44,6 +44,7 @@
#include "drawing.h"
#include "eq.h"
#include "wingeom.h"
+#include "widgets.h"
//#define trace(...) { fprintf (stderr, __VA_ARGS__); }
#define trace(fmt,...)
@@ -284,9 +285,8 @@ on_select_all1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
deadbeef->pl_select_all ();
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_refresh (pl, DDB_REFRESH_LIST);
- pl = DDB_LISTVIEW (lookup_widget (searchwin, "searchlist"));
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
+ DdbListview *pl = DDB_LISTVIEW (lookup_widget (searchwin, "searchlist"));
if (pl) {
ddb_listview_refresh (pl, DDB_REFRESH_LIST);
}
@@ -387,9 +387,6 @@ on_mainwin_key_press_event (GtkWidget *widget,
deadbeef->conf_set_int ("playlist.current", pl);
}
}
- else {
- ddb_listview_handle_keypress (DDB_LISTVIEW (lookup_widget (mainwin, "playlist")), event->keyval, event->state);
- }
return FALSE;
}
@@ -852,6 +849,8 @@ void
on_toggle_column_headers_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
+ // FIXME!
+ return;
GtkWidget *playlist = lookup_widget (mainwin, "playlist");
if (playlist) {
if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem))) {
@@ -918,6 +917,8 @@ void
on_toggle_tabs (GtkMenuItem *menuitem,
gpointer user_data)
{
+ // FIXME!
+ return;
GtkWidget *ts = lookup_widget (mainwin, "tabstrip");
if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem))) {
deadbeef->conf_set_int ("gtkui.tabs.visible", 0);
@@ -963,9 +964,8 @@ on_deselect_all1_activate (GtkMenuItem *menuitem,
it = next;
}
deadbeef->pl_unlock ();
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_refresh (pl, DDB_REFRESH_LIST);
- pl = DDB_LISTVIEW (lookup_widget (searchwin, "searchlist"));
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
+ DdbListview *pl = DDB_LISTVIEW (lookup_widget (searchwin, "searchlist"));
if (pl) {
ddb_listview_refresh (pl, DDB_REFRESH_LIST);
}
@@ -990,8 +990,7 @@ on_invert_selection1_activate (GtkMenuItem *menuitem,
it = next;
}
deadbeef->pl_unlock ();
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_refresh (pl, DDB_REFRESH_LIST);
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
@@ -1157,9 +1156,7 @@ on_sort_by_title_activate (GtkMenuItem *menuitem,
deadbeef->plt_sort (plt, PL_MAIN, -1, "%t", DDB_SORT_ASCENDING);
deadbeef->plt_unref (plt);
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_clear_sort (pl);
- ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_LIST_CHANGED);
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
@@ -1171,9 +1168,7 @@ on_sort_by_track_nr_activate (GtkMenuItem *menuitem,
deadbeef->plt_sort (plt, PL_MAIN, -1, "%n", DDB_SORT_ASCENDING);
deadbeef->plt_unref (plt);
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_clear_sort (pl);
- ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_LIST_CHANGED);
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
@@ -1185,9 +1180,7 @@ on_sort_by_album_activate (GtkMenuItem *menuitem,
deadbeef->plt_sort (plt, PL_MAIN, -1, "%b", DDB_SORT_ASCENDING);
deadbeef->plt_unref (plt);
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_clear_sort (pl);
- ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_LIST_CHANGED);
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
@@ -1199,9 +1192,7 @@ on_sort_by_artist_activate (GtkMenuItem *menuitem,
deadbeef->plt_sort (plt, PL_MAIN, -1, "%a", DDB_SORT_ASCENDING);
deadbeef->plt_unref (plt);
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_clear_sort (pl);
- ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_LIST_CHANGED);
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
@@ -1228,9 +1219,7 @@ on_sort_by_random_activate (GtkMenuItem *menuitem,
deadbeef->plt_unref (plt);
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_clear_sort (pl);
- ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_LIST_CHANGED);
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
@@ -1264,12 +1253,18 @@ on_sort_by_custom_activate (GtkMenuItem *menuitem,
deadbeef->plt_sort (plt, PL_MAIN, -1, fmt, order == 0 ? DDB_SORT_ASCENDING : DDB_SORT_DESCENDING);
deadbeef->plt_unref (plt);
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_clear_sort (pl);
- ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_LIST_CHANGED);
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
gtk_widget_destroy (dlg);
dlg = NULL;
}
+void
+on_design_mode1_activate (GtkMenuItem *menuitem,
+ gpointer user_data)
+{
+ gboolean act = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem));
+ w_set_design_mode (act ? 1 : 0);
+}
+
diff --git a/plugins/gtkui/callbacks.h b/plugins/gtkui/callbacks.h
index a354baca..1e4e66e3 100644
--- a/plugins/gtkui/callbacks.h
+++ b/plugins/gtkui/callbacks.h
@@ -1161,5 +1161,9 @@ on_convert8to16_toggled (GtkToggleButton *togglebutton,
gpointer user_data);
void
+on_design_mode1_activate (GtkMenuItem *menuitem,
+ gpointer user_data);
+
+void
on_reset_autostop_toggled (GtkToggleButton *togglebutton,
gpointer user_data);
diff --git a/plugins/gtkui/coverart.c b/plugins/gtkui/coverart.c
index e0451f5a..a2f1119a 100644
--- a/plugins/gtkui/coverart.c
+++ b/plugins/gtkui/coverart.c
@@ -45,6 +45,8 @@ typedef struct {
typedef struct load_query_s {
char *fname;
int width;
+ void (*callback) (void *user_data);
+ void *user_data;
struct load_query_s *next;
} load_query_t;
@@ -57,7 +59,7 @@ load_query_t *queue;
load_query_t *tail;
static void
-queue_add (const char *fname, int width) {
+queue_add (const char *fname, int width, void (*callback) (void *user_data), void *user_data) {
deadbeef->mutex_lock (mutex);
load_query_t *q;
for (q = queue; q; q = q->next) {
@@ -70,6 +72,8 @@ queue_add (const char *fname, int width) {
memset (q, 0, sizeof (load_query_t));
q->fname = strdup (fname);
q->width = width;
+ q->callback = callback;
+ q->user_data = user_data;
if (tail) {
tail->next = q;
tail = q;
@@ -108,7 +112,7 @@ loading_thread (void *none) {
for (;;) {
trace ("covercache: waiting for signal\n");
deadbeef->cond_wait (cond, mutex);
- trace ("covercache: signal received\n");
+ trace ("covercache: signal received (terminate=%d, queue=%p)\n", terminate, queue);
deadbeef->mutex_unlock (mutex);
while (!terminate && queue) {
int cache_min = 0;
@@ -144,6 +148,7 @@ loading_thread (void *none) {
if (stat (queue->fname, &stat_buf) < 0) {
trace ("failed to stat file %s\n", queue->fname);
}
+ trace ("covercache: caching pixbuf for %s\n", queue->fname);
GdkPixbuf *pixbuf = NULL;
GError *error = NULL;
pixbuf = gdk_pixbuf_new_from_file_at_scale (queue->fname, queue->width, queue->width, TRUE, &error);
@@ -182,8 +187,12 @@ loading_thread (void *none) {
struct stat stat_buf;
deadbeef->mutex_unlock (mutex);
}
+
+ if (queue->callback) {
+ queue->callback (queue->user_data);
+ }
queue_pop ();
- g_idle_add (redraw_playlist_cb, NULL);
+ //g_idle_add (redraw_playlist_cb, NULL);
}
if (terminate) {
break;
@@ -191,20 +200,30 @@ loading_thread (void *none) {
}
}
-void
+typedef struct {
+ int width;
+ void (*callback)(void *user_data);
+ void *user_data;
+} cover_avail_info_t;
+
+static void
cover_avail_callback (const char *fname, const char *artist, const char *album, void *user_data) {
+ if (!fname) {
+ free (user_data);
+ return;
+ }
+ cover_avail_info_t *dt = user_data;
// means requested image is now in disk cache
// load it into main memory
- GdkPixbuf *pb = get_cover_art (fname, artist, album, (intptr_t)user_data);
+ GdkPixbuf *pb = get_cover_art_callb (fname, artist, album, dt->width, dt->callback, dt->user_data);
if (pb) {
g_object_unref (pb);
- // already in cache, redraw
- g_idle_add (redraw_playlist_cb, NULL);
}
+ free (dt);
}
static GdkPixbuf *
-get_pixbuf (const char *fname, int width) {
+get_pixbuf (const char *fname, int width, void (*callback)(void *user_data), void *user_data) {
int requested_width = width;
// find in cache
deadbeef->mutex_lock (mutex);
@@ -232,18 +251,45 @@ get_pixbuf (const char *fname, int width) {
}
#endif
deadbeef->mutex_unlock (mutex);
- queue_add (fname, width);
+ queue_add (fname, width, callback, user_data);
return NULL;
}
+static void
+redraw_playlist (void *user_data) {
+ g_idle_add (redraw_playlist_cb, NULL);
+}
+
GdkPixbuf *
get_cover_art (const char *fname, const char *artist, const char *album, int width) {
if (!coverart_plugin) {
return NULL;
}
- char *image_fname = coverart_plugin->get_album_art (fname, artist, album, -1, cover_avail_callback, (void *)(intptr_t)width);
+ cover_avail_info_t *dt = malloc (sizeof (cover_avail_info_t));
+ dt->width = width;
+ dt->callback = redraw_playlist;
+ dt->user_data = NULL;
+ char *image_fname = coverart_plugin->get_album_art (fname, artist, album, -1, cover_avail_callback, (void*)dt);
+ if (image_fname) {
+ GdkPixbuf *pb = get_pixbuf (image_fname, width, redraw_playlist, NULL);
+ free (image_fname);
+ return pb;
+ }
+ return NULL;
+}
+
+GdkPixbuf *
+get_cover_art_callb (const char *fname, const char *artist, const char *album, int width, void (*callback) (void *user_data), void *user_data) {
+ if (!coverart_plugin) {
+ return NULL;
+ }
+ cover_avail_info_t *dt = malloc (sizeof (cover_avail_info_t));
+ dt->width = width;
+ dt->callback = callback;
+ dt->user_data = user_data;
+ char *image_fname = coverart_plugin->get_album_art (fname, artist, album, -1, cover_avail_callback, dt);
if (image_fname) {
- GdkPixbuf *pb = get_pixbuf (image_fname, width);
+ GdkPixbuf *pb = get_pixbuf (image_fname, width, callback, user_data);
free (image_fname);
return pb;
}
diff --git a/plugins/gtkui/coverart.h b/plugins/gtkui/coverart.h
index 490f62e1..a4914b6f 100644
--- a/plugins/gtkui/coverart.h
+++ b/plugins/gtkui/coverart.h
@@ -32,6 +32,10 @@
GdkPixbuf *
get_cover_art (const char *fname, const char *artist, const char *album, int width);
+GdkPixbuf *
+get_cover_art_callb (const char *fname, const char *artist, const char *album, int width, void
+(*cover_avail_callback) (void *user_data), void *user_data);
+
void
coverart_reset_queue (void);
diff --git a/plugins/gtkui/ddbcellrenderertextmultiline.c b/plugins/gtkui/ddbcellrenderertextmultiline.c
index 3b1ac61b..5bd97a9a 100644
--- a/plugins/gtkui/ddbcellrenderertextmultiline.c
+++ b/plugins/gtkui/ddbcellrenderertextmultiline.c
@@ -1,6 +1,3 @@
-/* ddbcellrenderertextmultiline.c generated by valac 0.14.0, the Vala compiler
- * generated from ddbcellrenderertextmultiline.vala, do not modify */
-
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
@@ -84,7 +81,7 @@ static gpointer ddb_cell_editable_text_view_parent_class = NULL;
static GtkCellEditableIface* ddb_cell_editable_text_view_gtk_cell_editable_parent_iface = NULL;
static gpointer ddb_cell_renderer_text_multiline_parent_class = NULL;
-GType ddb_cell_editable_text_view_get_type (void) G_GNUC_CONST;
+GType ddb_cell_editable_text_view_get_type (void);
enum {
DDB_CELL_EDITABLE_TEXT_VIEW_DUMMY_PROPERTY
};
@@ -96,7 +93,7 @@ static void ddb_cell_editable_text_view_real_editing_canceled (GtkCellRenderer*)
DdbCellEditableTextView* ddb_cell_editable_text_view_new (void);
DdbCellEditableTextView* ddb_cell_editable_text_view_construct (GType object_type);
static void ddb_cell_editable_text_view_finalize (GObject* obj);
-GType ddb_cell_renderer_text_multiline_get_type (void) G_GNUC_CONST;
+GType ddb_cell_renderer_text_multiline_get_type (void);
#define DDB_CELL_RENDERER_TEXT_MULTILINE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DDB_TYPE_CELL_RENDERER_TEXT_MULTILINE, DdbCellRendererTextMultilinePrivate))
enum {
DDB_CELL_RENDERER_TEXT_MULTILINE_DUMMY_PROPERTY
@@ -160,13 +157,13 @@ static gboolean ddb_cell_editable_text_view_real_key_press_event (GtkWidget* bas
return result;
}
-
static void ddb_cell_editable_text_view_real_start_editing (GtkCellEditable* base, GdkEvent* event) {
- DdbCellEditableTextView * self;
- self = (DdbCellEditableTextView*) base;
- g_return_if_fail (event != NULL);
+ DdbCellEditableTextView * self;
+ self = (DdbCellEditableTextView*) base;
+ g_return_if_fail (event != NULL);
}
+
#if GTK_CHECK_VERSION(2,20,0)
static void ddb_cell_editable_text_view_real_editing_canceled (GtkCellRenderer* base) {
}
@@ -190,6 +187,10 @@ static void ddb_cell_editable_text_view_class_init (DdbCellEditableTextViewClass
G_OBJECT_CLASS (klass)->finalize = ddb_cell_editable_text_view_finalize;
}
+void ddb_cell_editable_text_view_start_editing (DdbCellEditableTextView* self, GdkEvent* event) {
+ g_return_if_fail (self != NULL);
+ g_return_if_fail (event != NULL);
+}
static void ddb_cell_editable_text_view_gtk_cell_editable_interface_init (GtkCellEditableIface * iface) {
ddb_cell_editable_text_view_gtk_cell_editable_parent_iface = g_type_interface_peek_parent (iface);
@@ -279,6 +280,7 @@ static void ddb_cell_renderer_text_multiline_gtk_cell_renderer_text_editing_done
g_signal_emit_by_name ((GtkCellRendererText*) _tmp14_, "edited", _tmp16_, new_text);
_g_free0 (new_text);
_g_object_unref0 (buf);
+ _g_free0 (new_text);
}
@@ -435,6 +437,10 @@ static GtkCellEditable* ddb_cell_renderer_text_multiline_real_start_editing (Gtk
_g_object_unref0 (store);
_g_object_unref0 (tv);
_gtk_tree_path_free0 (p);
+ _g_object_unref0 (tv);
+ _g_object_unref0 (store);
+ G_IS_VALUE (&v) ? (g_value_unset (&v), NULL) : NULL;
+ _g_object_unref0 (buf);
return result;
}
diff --git a/plugins/gtkui/ddbcellrenderertextmultiline.h b/plugins/gtkui/ddbcellrenderertextmultiline.h
index b464472a..ca461f34 100644
--- a/plugins/gtkui/ddbcellrenderertextmultiline.h
+++ b/plugins/gtkui/ddbcellrenderertextmultiline.h
@@ -1,6 +1,3 @@
-/* ddbcellrenderertextmultiline.h generated by valac 0.14.0, the Vala compiler, do not modify */
-
-
#ifndef __DDBCELLRENDERERTEXTMULTILINE_H__
#define __DDBCELLRENDERERTEXTMULTILINE_H__
@@ -8,6 +5,7 @@
#include <gtk/gtk.h>
#include <stdlib.h>
#include <string.h>
+#include <gdk/gdk.h>
G_BEGIN_DECLS
@@ -55,10 +53,11 @@ struct _DdbCellRendererTextMultilineClass {
};
-GType ddb_cell_editable_text_view_get_type (void) G_GNUC_CONST;
+GType ddb_cell_editable_text_view_get_type (void);
+void ddb_cell_editable_text_view_start_editing (DdbCellEditableTextView* self, GdkEvent* event);
DdbCellEditableTextView* ddb_cell_editable_text_view_new (void);
DdbCellEditableTextView* ddb_cell_editable_text_view_construct (GType object_type);
-GType ddb_cell_renderer_text_multiline_get_type (void) G_GNUC_CONST;
+GType ddb_cell_renderer_text_multiline_get_type (void);
DdbCellRendererTextMultiline* ddb_cell_renderer_text_multiline_new (void);
DdbCellRendererTextMultiline* ddb_cell_renderer_text_multiline_construct (GType object_type);
diff --git a/plugins/gtkui/ddbequalizer.c b/plugins/gtkui/ddbequalizer.c
index 05f42547..02946aea 100644
--- a/plugins/gtkui/ddbequalizer.c
+++ b/plugins/gtkui/ddbequalizer.c
@@ -44,7 +44,6 @@ typedef struct _DdbEqualizerClass DdbEqualizerClass;
typedef struct _DdbEqualizerPrivate DdbEqualizerPrivate;
#define _gdk_cursor_unref0(var) ((var == NULL) ? NULL : (var = (gdk_cursor_unref (var), NULL)))
#define _g_free0(var) (var = (g_free (var), NULL))
-#define _pango_font_description_free0(var) ((var == NULL) ? NULL : (var = (pango_font_description_free (var), NULL)))
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
#define _cairo_destroy0(var) ((var == NULL) ? NULL : (var = (cairo_destroy (var), NULL)))
@@ -73,7 +72,7 @@ struct _DdbEqualizerPrivate {
static gpointer ddb_equalizer_parent_class = NULL;
-GType ddb_equalizer_get_type (void) G_GNUC_CONST;
+GType ddb_equalizer_get_type (void);
#define DDB_EQUALIZER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DDB_TYPE_EQUALIZER, DdbEqualizerPrivate))
enum {
DDB_EQUALIZER_DUMMY_PROPERTY
diff --git a/plugins/gtkui/ddbequalizer.h b/plugins/gtkui/ddbequalizer.h
index c9e49988..02df70af 100644
--- a/plugins/gtkui/ddbequalizer.h
+++ b/plugins/gtkui/ddbequalizer.h
@@ -1,6 +1,3 @@
-/* ddbequalizer.h generated by valac 0.14.0, the Vala compiler, do not modify */
-
-
#ifndef __DDBEQUALIZER_H__
#define __DDBEQUALIZER_H__
diff --git a/plugins/gtkui/ddblistview.c b/plugins/gtkui/ddblistview.c
index 6312a103..2aef74df 100644
--- a/plugins/gtkui/ddblistview.c
+++ b/plugins/gtkui/ddblistview.c
@@ -275,6 +275,14 @@ ddb_listview_motion_notify_event (GtkWidget *widget,
GdkEventMotion *event,
gpointer user_data);
+gboolean
+ddb_listview_list_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
+
+gboolean
+ddb_listview_list_focus_in_event (GtkWidget *widget, GdkEvent *event, gpointer user_data);
+
+gboolean
+ddb_listview_list_focus_out_event (GtkWidget *widget, GdkEvent *event, gpointer user_data);
static void
ddb_listview_class_init(DdbListviewClass *class)
@@ -361,7 +369,9 @@ ddb_listview_init(DdbListview *listview)
listview->list = gtk_drawing_area_new ();
gtk_widget_show (listview->list);
gtk_box_pack_start (GTK_BOX (vbox), listview->list, TRUE, TRUE, 0);
- gtk_widget_set_events (listview->list, 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);
+ GTK_WIDGET_SET_FLAGS (listview->list, GTK_CAN_FOCUS);
+ GTK_WIDGET_SET_FLAGS (listview->list, GTK_CAN_DEFAULT);
+ gtk_widget_set_events (listview->list, 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 | GDK_FOCUS_CHANGE_MASK);
listview->hscrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (gtk_adjustment_new (0, 0, 0, 0, 0, 0)));
gtk_widget_show (listview->hscrollbar);
@@ -400,7 +410,7 @@ ddb_listview_init(DdbListview *listview)
g_signal_connect ((gpointer) listview->header, "motion_notify_event",
G_CALLBACK (ddb_listview_header_motion_notify_event),
NULL);
- g_signal_connect ((gpointer) listview->header, "button_press_event",
+ g_signal_connect_after ((gpointer) listview->header, "button_press_event",
G_CALLBACK (ddb_listview_header_button_press_event),
NULL);
g_signal_connect ((gpointer) listview->header, "button_release_event",
@@ -418,7 +428,7 @@ ddb_listview_init(DdbListview *listview)
g_signal_connect ((gpointer) listview->list, "realize",
G_CALLBACK (ddb_listview_list_realize),
NULL);
- g_signal_connect ((gpointer) listview->list, "button_press_event",
+ g_signal_connect_after ((gpointer) listview->list, "button_press_event",
G_CALLBACK (ddb_listview_list_button_press_event),
NULL);
g_signal_connect ((gpointer) listview->list, "scroll_event",
@@ -457,6 +467,10 @@ ddb_listview_init(DdbListview *listview)
g_signal_connect ((gpointer) listview->hscrollbar, "value_changed",
G_CALLBACK (ddb_listview_hscroll_value_changed),
NULL);
+
+ g_signal_connect ((gpointer)listview->list, "key_press_event", G_CALLBACK (ddb_listview_list_key_press_event), NULL);
+ g_signal_connect ((gpointer)listview->list, "focus_in_event", G_CALLBACK (ddb_listview_list_focus_in_event), NULL);
+ g_signal_connect ((gpointer)listview->list, "focus_out_event", G_CALLBACK (ddb_listview_list_focus_out_event), NULL);
}
GtkWidget * ddb_listview_new()
@@ -1437,6 +1451,7 @@ ddb_listview_click_selection (DdbListview *ps, int ex, int ey, DdbListviewGroup
UNREF (it);
}
deadbeef->pl_unlock ();
+ deadbeef->sendmessage (DB_EV_SELCHANGED, 0, deadbeef->plt_get_curr_idx (), PL_MAIN);
}
// {{{ expected behaviour for mouse1 without modifiers:
@@ -2519,7 +2534,7 @@ ddb_listview_header_button_press_event (GtkWidget *widget,
}
ps->prev_header_x = -1;
ps->last_header_motion_ev = -1;
- return FALSE;
+ return TRUE;
}
gboolean
@@ -2669,6 +2684,7 @@ ddb_listview_list_button_press_event (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
+ gtk_widget_grab_focus (widget);
DdbListview *ps = DDB_LISTVIEW (g_object_get_data (G_OBJECT (widget), "owner"));
if (event->button == 1) {
ddb_listview_list_mouse1_pressed (ps, event->state, event->x, event->y, event->type);
@@ -2710,7 +2726,7 @@ ddb_listview_list_button_press_event (GtkWidget *widget,
UNREF (it);
}
}
- return FALSE;
+ return TRUE;
}
gboolean
@@ -3077,3 +3093,23 @@ ddb_listview_clear_sort (DdbListview *listview) {
}
gtk_widget_queue_draw (listview->header);
}
+
+gboolean
+ddb_listview_list_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data) {
+ DdbListview *listview = DDB_LISTVIEW (g_object_get_data (G_OBJECT (widget), "owner"));
+ ddb_listview_handle_keypress (listview, event->keyval, event->state);
+ return FALSE;
+
+}
+
+gboolean
+ddb_listview_list_focus_in_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) {
+ GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
+ return FALSE;
+}
+
+gboolean
+ddb_listview_list_focus_out_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) {
+ GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
+ return FALSE;
+}
diff --git a/plugins/gtkui/ddbseekbar.c b/plugins/gtkui/ddbseekbar.c
index bcb8b7fe..544083b9 100644
--- a/plugins/gtkui/ddbseekbar.c
+++ b/plugins/gtkui/ddbseekbar.c
@@ -48,7 +48,7 @@ struct _DdbSeekbarClass {
static gpointer ddb_seekbar_parent_class = NULL;
-GType ddb_seekbar_get_type (void) G_GNUC_CONST;
+GType ddb_seekbar_get_type (void);
enum {
DDB_SEEKBAR_DUMMY_PROPERTY
};
@@ -164,8 +164,8 @@ static gboolean ddb_seekbar_real_configure_event (GtkWidget* base, GdkEventConfi
DdbSeekbar* ddb_seekbar_construct (GType object_type) {
- DdbSeekbar * self = NULL;
- self = (DdbSeekbar*) gtk_widget_new (object_type, NULL);
+ DdbSeekbar * self;
+ self = g_object_newv (object_type, 0, NULL);
return self;
}
diff --git a/plugins/gtkui/ddbseekbar.h b/plugins/gtkui/ddbseekbar.h
index 71b753c0..ee455087 100644
--- a/plugins/gtkui/ddbseekbar.h
+++ b/plugins/gtkui/ddbseekbar.h
@@ -1,6 +1,3 @@
-/* ddbseekbar.h generated by valac 0.14.0, the Vala compiler, do not modify */
-
-
#ifndef __DDBSEEKBAR_H__
#define __DDBSEEKBAR_H__
@@ -31,7 +28,7 @@ struct _DdbSeekbarClass {
};
-GType ddb_seekbar_get_type (void) G_GNUC_CONST;
+GType ddb_seekbar_get_type (void);
DdbSeekbar* ddb_seekbar_new (void);
DdbSeekbar* ddb_seekbar_construct (GType object_type);
diff --git a/plugins/gtkui/ddbtabstrip.c b/plugins/gtkui/ddbtabstrip.c
index ab8fad1e..18151ff4 100644
--- a/plugins/gtkui/ddbtabstrip.c
+++ b/plugins/gtkui/ddbtabstrip.c
@@ -26,7 +26,7 @@
#include "gtkui.h"
#include "interface.h"
#include "support.h"
-#include "ddblistview.h"
+#include "mainplaylist.h"
#define GLADE_HOOKUP_OBJECT(component,widget,name) \
g_object_set_data_full (G_OBJECT (component), name, \
@@ -279,7 +279,7 @@ on_tabstrip_drag_data_received (GtkWidget *widget,
memcpy (mem, ptr, len);
mem[len] = 0;
// we don't pass control structure, but there's only one drag-drop view currently
- ps->binding->external_drag_n_drop (NULL, mem, len);
+ gtkui_receive_fm_drop (NULL, mem, len);
}
else if (target_type == 1) {
uint32_t *d= (uint32_t *)ptr;
@@ -288,7 +288,7 @@ on_tabstrip_drag_data_received (GtkWidget *widget,
int length = (len/4)-1;
ddb_playlist_t *p = deadbeef->plt_get_for_idx (plt);
if (p) {
- ps->binding->drag_n_drop (NULL, p, d, length, gdk_drag_context_get_selected_action (drag_context) == GDK_ACTION_COPY ? 1 : 0);
+ main_drag_n_drop (NULL, p, d, length, gdk_drag_context_get_selected_action (drag_context) == GDK_ACTION_COPY ? 1 : 0);
deadbeef->plt_unref (p);
}
}
@@ -300,16 +300,16 @@ on_tabstrip_drag_leave (GtkWidget *widget,
GdkDragContext *drag_context,
guint time)
{
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_list_drag_leave (pl->list, drag_context, time, NULL);
+// DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
+// ddb_listview_list_drag_leave (pl->list, drag_context, time, NULL);
}
void
on_tabstrip_drag_end (GtkWidget *widget,
GdkDragContext *drag_context)
{
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_list_drag_end (pl->list, drag_context, NULL);
+// DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
+// ddb_listview_list_drag_end (pl->list, drag_context, NULL);
}
GtkWidget * ddb_tabstrip_new() {
@@ -780,8 +780,6 @@ on_remove_playlist1_activate (GtkMenuItem *menuitem,
{
if (tab_clicked != -1) {
deadbeef->plt_remove (tab_clicked);
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_refresh (pl, DDB_LIST_CHANGED | DDB_REFRESH_LIST | DDB_REFRESH_VSCROLL);
search_refresh ();
int playlist = deadbeef->plt_get_curr_idx ();
deadbeef->conf_set_int ("playlist.current", playlist);
@@ -1055,7 +1053,7 @@ on_tabstrip_button_press_event(GtkWidget *widget,
ts->scroll_direction = -1;
ts->scroll_timer = g_timeout_add (300, tabstrip_scroll_cb, ts);
}
- return FALSE;
+ return TRUE;
}
else if (event->x >= a.width - arrow_widget_width) {
if (event->type == GDK_BUTTON_PRESS) {
@@ -1063,7 +1061,7 @@ on_tabstrip_button_press_event(GtkWidget *widget,
ts->scroll_direction = 1;
ts->scroll_timer = g_timeout_add (300, tabstrip_scroll_cb, ts);
}
- return FALSE;
+ return TRUE;
}
}
if (tab_clicked != -1) {
@@ -1076,9 +1074,9 @@ on_tabstrip_button_press_event(GtkWidget *widget,
if (playlist != -1) {
gtkui_playlist_set_curr (playlist);
}
- return FALSE;
+ return TRUE;
}
- return FALSE;
+ return TRUE;
}
// adjust scroll if clicked tab spans border
@@ -1114,21 +1112,19 @@ on_tabstrip_button_press_event(GtkWidget *widget,
if (playlist != -1) {
gtkui_playlist_set_curr (playlist);
}
- return FALSE;
+ return TRUE;
}
else if (deadbeef->conf_get_int ("gtkui.mmb_delete_playlist", 1)) {
if (tab_clicked != -1) {
deadbeef->plt_remove (tab_clicked);
// force invalidation of playlist cache
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_refresh (pl, DDB_LIST_CHANGED | DDB_REFRESH_LIST | DDB_REFRESH_VSCROLL);
search_refresh ();
int playlist = deadbeef->plt_get_curr_idx ();
deadbeef->conf_set_int ("playlist.current", playlist);
}
}
}
- return FALSE;
+ return TRUE;
}
diff --git a/plugins/gtkui/deadbeef.glade b/plugins/gtkui/deadbeef.glade
index 184b66fd..820c30a1 100644
--- a/plugins/gtkui/deadbeef.glade
+++ b/plugins/gtkui/deadbeef.glade
@@ -62,7 +62,7 @@
<accelerator key="O" modifiers="GDK_CONTROL_MASK" signal="activate"/>
<child internal-child="image">
- <widget class="GtkImage" id="image555">
+ <widget class="GtkImage" id="image563">
<property name="visible">True</property>
<property name="stock">gtk-open</property>
<property name="icon_size">1</property>
@@ -89,7 +89,7 @@
<signal name="activate" handler="on_add_files_activate" last_modification_time="Sat, 04 Jul 2009 13:04:01 GMT"/>
<child internal-child="image">
- <widget class="GtkImage" id="image556">
+ <widget class="GtkImage" id="image564">
<property name="visible">True</property>
<property name="stock">gtk-add</property>
<property name="icon_size">1</property>
@@ -110,7 +110,7 @@
<signal name="activate" handler="on_add_folders_activate" last_modification_time="Sun, 06 Sep 2009 17:51:40 GMT"/>
<child internal-child="image">
- <widget class="GtkImage" id="image557">
+ <widget class="GtkImage" id="image565">
<property name="visible">True</property>
<property name="stock">gtk-add</property>
<property name="icon_size">1</property>
@@ -181,7 +181,7 @@
<accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/>
<child internal-child="image">
- <widget class="GtkImage" id="image558">
+ <widget class="GtkImage" id="image566">
<property name="visible">True</property>
<property name="stock">gtk-quit</property>
<property name="icon_size">1</property>
@@ -215,7 +215,7 @@
<signal name="activate" handler="on_clear1_activate" last_modification_time="Sun, 06 Sep 2009 18:30:03 GMT"/>
<child internal-child="image">
- <widget class="GtkImage" id="image559">
+ <widget class="GtkImage" id="image567">
<property name="visible">True</property>
<property name="stock">gtk-clear</property>
<property name="icon_size">1</property>
@@ -274,7 +274,7 @@
<signal name="activate" handler="on_remove1_activate" last_modification_time="Sun, 06 Sep 2009 18:30:03 GMT"/>
<child internal-child="image">
- <widget class="GtkImage" id="image560">
+ <widget class="GtkImage" id="image568">
<property name="visible">True</property>
<property name="stock">gtk-remove</property>
<property name="icon_size">1</property>
@@ -453,6 +453,16 @@
<signal name="activate" handler="on_toggle_eq" last_modification_time="Sat, 20 Mar 2010 12:28:50 GMT"/>
</widget>
</child>
+
+ <child>
+ <widget class="GtkCheckMenuItem" id="design_mode1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Design mode</property>
+ <property name="use_underline">True</property>
+ <property name="active">False</property>
+ <signal name="activate" handler="on_design_mode1_activate" last_modification_time="Fri, 17 Jun 2011 19:10:50 GMT"/>
+ </widget>
+ </child>
</widget>
</child>
</widget>
@@ -481,7 +491,7 @@
<property name="visible">True</property>
<property name="label" translatable="yes">Linear</property>
<property name="use_underline">True</property>
- <property name="active">False</property>
+ <property name="active">True</property>
<signal name="activate" handler="on_order_linear_activate" last_modification_time="Sat, 08 Aug 2009 12:26:33 GMT"/>
</widget>
</child>
@@ -491,7 +501,7 @@
<property name="visible">True</property>
<property name="label" translatable="yes">Shuffle tracks</property>
<property name="use_underline">True</property>
- <property name="active">False</property>
+ <property name="active">True</property>
<property name="group">order_linear</property>
<signal name="activate" handler="on_order_shuffle_activate" last_modification_time="Fri, 21 Aug 2009 16:46:02 GMT"/>
</widget>
@@ -502,7 +512,7 @@
<property name="visible">True</property>
<property name="label" translatable="yes">Shuffle albums</property>
<property name="use_underline">True</property>
- <property name="active">False</property>
+ <property name="active">True</property>
<property name="group">order_linear</property>
<signal name="activate" handler="on_order_shuffle_albums_activate" last_modification_time="Sun, 12 Dec 2010 18:14:47 GMT"/>
</widget>
@@ -537,7 +547,7 @@
<property name="visible">True</property>
<property name="label" translatable="yes">Loop All</property>
<property name="use_underline">True</property>
- <property name="active">False</property>
+ <property name="active">True</property>
<signal name="activate" handler="on_loop_all_activate" last_modification_time="Sat, 08 Aug 2009 12:26:33 GMT"/>
</widget>
</child>
@@ -547,7 +557,7 @@
<property name="visible">True</property>
<property name="label" translatable="yes">Loop Single Song</property>
<property name="use_underline">True</property>
- <property name="active">False</property>
+ <property name="active">True</property>
<property name="group">loop_all</property>
<signal name="activate" handler="on_loop_single_activate" last_modification_time="Sat, 08 Aug 2009 12:26:33 GMT"/>
</widget>
@@ -636,7 +646,7 @@
<signal name="activate" handler="on_help1_activate" last_modification_time="Tue, 08 Sep 2009 17:32:06 GMT"/>
<child internal-child="image">
- <widget class="GtkImage" id="image561">
+ <widget class="GtkImage" id="image569">
<property name="visible">True</property>
<property name="stock">gtk-help</property>
<property name="icon_size">1</property>
@@ -696,7 +706,7 @@
<signal name="activate" handler="on_about1_activate" last_modification_time="Sat, 04 Jul 2009 12:57:58 GMT"/>
<child internal-child="image">
- <widget class="GtkImage" id="image562">
+ <widget class="GtkImage" id="image570">
<property name="visible">True</property>
<property name="stock">gtk-about</property>
<property name="icon_size">1</property>
@@ -717,7 +727,7 @@
<signal name="activate" handler="on_translators1_activate" last_modification_time="Sun, 19 Sep 2010 13:38:07 GMT"/>
<child internal-child="image">
- <widget class="GtkImage" id="image563">
+ <widget class="GtkImage" id="image571">
<property name="visible">True</property>
<property name="stock">gtk-about</property>
<property name="icon_size">1</property>
@@ -937,47 +947,6 @@
</child>
<child>
- <widget class="Custom" id="tabstrip">
- <property name="height_request">24</property>
- <property name="visible">True</property>
- <property name="creation_function">create_tabstrip_widget</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Thu, 18 Feb 2010 18:05:36 GMT</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkFrame" id="frame1">
- <property name="border_width">1</property>
- <property name="visible">True</property>
- <property name="label_xalign">0</property>
- <property name="label_yalign">0.5</property>
- <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
-
- <child>
- <widget class="Custom" id="playlist">
- <property name="visible">True</property>
- <property name="creation_function">create_ddb_listview_widget</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Sat, 13 Feb 2010 20:26:03 GMT</property>
- </widget>
- </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="plugins_bottom_vbox">
<property name="visible">True</property>
<property name="homogeneous">False</property>
@@ -989,8 +958,8 @@
</widget>
<packing>
<property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
</packing>
</child>
diff --git a/plugins/gtkui/fileman.c b/plugins/gtkui/fileman.c
index 36735cbe..69f016af 100644
--- a/plugins/gtkui/fileman.c
+++ b/plugins/gtkui/fileman.c
@@ -110,17 +110,15 @@ open_files_worker (void *data) {
gtkpl_add_files (lst);
deadbeef->pl_save_all ();
deadbeef->conf_save ();
- gtkui_playlist_changed ();
- extern GtkWidget *mainwin;
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_set_cursor (pl, 0);
+ deadbeef->pl_set_cursor (PL_MAIN, 0);
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
deadbeef->sendmessage (DB_EV_PLAY_CURRENT, 0, 1, 0);
}
void
gtkui_open_files (struct _GSList *lst) {
deadbeef->pl_clear ();
- playlist_refresh ();
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
intptr_t tid = deadbeef->thread_start (open_files_worker, lst);
deadbeef->thread_detach (tid);
@@ -170,13 +168,14 @@ strcopy_special (char *dest, const char *src, int len) {
static gboolean
set_dnd_cursor_idle (gpointer data) {
- DdbListview *listview = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
if (!data) {
- ddb_listview_set_cursor (listview, -1);
+ deadbeef->pl_set_cursor (PL_MAIN, -1);
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
return FALSE;
}
int cursor = deadbeef->pl_get_idx_of (DB_PLAYITEM (data));
- ddb_listview_set_cursor (listview, cursor);
+ deadbeef->pl_set_cursor (PL_MAIN, cursor);
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
return FALSE;
}
@@ -188,7 +187,6 @@ gtkpl_add_fm_dropped_files (DB_playItem_t *drop_before, char *ptr, int length) {
deadbeef->plt_unref (plt);
return;
}
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
DdbListviewIter first = NULL;
DdbListviewIter after = NULL;
diff --git a/plugins/gtkui/gtkui.c b/plugins/gtkui/gtkui.c
index a4593ea0..5bb3df1a 100644
--- a/plugins/gtkui/gtkui.c
+++ b/plugins/gtkui/gtkui.c
@@ -29,7 +29,6 @@
#include "../../gettext.h"
#include "gtkui.h"
#include "ddblistview.h"
-#include "mainplaylist.h"
#include "search.h"
#include "progress.h"
#include "interface.h"
@@ -47,6 +46,7 @@
#include "pluginconf.h"
#include "gtkui_api.h"
#include "wingeom.h"
+#include "widgets.h"
#define trace(...) { fprintf(stderr, __VA_ARGS__); }
//#define trace(fmt,...)
@@ -349,7 +349,7 @@ activate_cb (gpointer nothing) {
}
void
-redraw_queued_tracks (DdbListview *pl, int list) {
+redraw_queued_tracks (DdbListview *pl) {
DB_playItem_t *it;
int idx = 0;
deadbeef->pl_lock ();
@@ -364,14 +364,14 @@ redraw_queued_tracks (DdbListview *pl, int list) {
deadbeef->pl_unlock ();
}
-static gboolean
-redraw_queued_tracks_cb (gpointer nothing) {
+gboolean
+redraw_queued_tracks_cb (gpointer plt) {
+ DdbListview *list = plt;
int iconified = gdk_window_get_state(gtk_widget_get_window(mainwin)) & GDK_WINDOW_STATE_ICONIFIED;
if (!gtk_widget_get_visible (mainwin) || iconified) {
return FALSE;
}
- redraw_queued_tracks (DDB_LISTVIEW (lookup_widget (mainwin, "playlist")), PL_MAIN);
- redraw_queued_tracks (DDB_LISTVIEW (lookup_widget (searchwin, "searchlist")), PL_SEARCH);
+ redraw_queued_tracks (list);
return FALSE;
}
@@ -388,7 +388,12 @@ gtkpl_songchanged_wrapper (DB_playItem_t *from, DB_playItem_t *to) {
}
g_idle_add (update_win_title_idle, ft);
g_idle_add (redraw_seekbar_cb, NULL);
- g_idle_add (redraw_queued_tracks_cb, NULL);
+ if (searchwin && searchwin->window) {
+ int iconified = gdk_window_get_state(searchwin->window) & GDK_WINDOW_STATE_ICONIFIED;
+ if (gtk_widget_get_visible (searchwin) && !iconified) {
+ g_idle_add (redraw_queued_tracks_cb, DDB_LISTVIEW (lookup_widget (searchwin, "searchlist")));
+ }
+ }
}
void
@@ -427,8 +432,8 @@ trackinfochanged_wrapper (DdbListview *playlist, DB_playItem_t *track, int iter)
void
gtkui_trackinfochanged (DB_playItem_t *track) {
- GtkWidget *playlist = lookup_widget (mainwin, "playlist");
- trackinfochanged_wrapper (DDB_LISTVIEW (playlist), track, PL_MAIN);
+// GtkWidget *playlist = lookup_widget (mainwin, "playlist");
+// trackinfochanged_wrapper (DDB_LISTVIEW (playlist), track, PL_MAIN);
if (searchwin && gtk_widget_get_visible (searchwin)) {
GtkWidget *search = lookup_widget (searchwin, "searchlist");
@@ -453,22 +458,10 @@ trackinfochanged_cb (gpointer data) {
return FALSE;
}
-static gboolean
-paused_cb (gpointer nothing) {
- DB_playItem_t *curr = deadbeef->streamer_get_playing_track ();
- if (curr) {
- int idx = deadbeef->pl_get_idx_of (curr);
- GtkWidget *playlist = lookup_widget (mainwin, "playlist");
- ddb_listview_draw_row (DDB_LISTVIEW (playlist), idx, (DdbListviewIter)curr);
- deadbeef->pl_item_unref (curr);
- }
- return FALSE;
-}
-
void
playlist_refresh (void) {
- DdbListview *ps = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_refresh (ps, DDB_REFRESH_LIST | DDB_REFRESH_VSCROLL);
+// DdbListview *ps = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
+// ddb_listview_refresh (ps, DDB_REFRESH_LIST | DDB_REFRESH_VSCROLL);
search_refresh ();
}
@@ -485,26 +478,6 @@ gtkui_playlist_changed (void) {
static gboolean
playlistswitch_cb (gpointer none) {
- GtkWidget *tabstrip = lookup_widget (mainwin, "tabstrip");
- int curr = deadbeef->plt_get_curr_idx ();
- char conf[100];
- snprintf (conf, sizeof (conf), "playlist.scroll.%d", curr);
- int scroll = deadbeef->conf_get_int (conf, 0);
- snprintf (conf, sizeof (conf), "playlist.cursor.%d", curr);
- int cursor = deadbeef->conf_get_int (conf, -1);
- ddb_tabstrip_refresh (DDB_TABSTRIP (tabstrip));
- DdbListview *listview = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- deadbeef->pl_set_cursor (PL_MAIN, cursor);
- if (cursor != -1) {
- DB_playItem_t *it = deadbeef->pl_get_for_idx_and_iter (cursor, PL_MAIN);
- if (it) {
- deadbeef->pl_set_selected (it, 1);
- deadbeef->pl_item_unref (it);
- }
- }
-
- ddb_listview_refresh (listview, DDB_LIST_CHANGED | DDB_REFRESH_LIST | DDB_REFRESH_VSCROLL);
- ddb_listview_set_vscroll (listview, scroll);
search_refresh ();
return FALSE;
}
@@ -837,40 +810,6 @@ on_add_location_activate (GtkMenuItem *menuitem,
gtk_widget_destroy (dlg);
}
-static void
-songchanged (DdbListview *ps, DB_playItem_t *from, DB_playItem_t *to) {
- int to_idx = -1;
- if (!ddb_listview_is_scrolling (ps) && to) {
- int cursor_follows_playback = deadbeef->conf_get_int ("playlist.scroll.cursorfollowplayback", 0);
- int scroll_follows_playback = deadbeef->conf_get_int ("playlist.scroll.followplayback", 0);
- int plt = deadbeef->streamer_get_current_playlist ();
- if (plt != -1) {
- if (cursor_follows_playback && plt != deadbeef->plt_get_curr_idx ()) {
- deadbeef->plt_set_curr_idx (plt);
- }
- to_idx = deadbeef->pl_get_idx_of (to);
- if (to_idx != -1) {
- if (cursor_follows_playback) {
- ddb_listview_set_cursor_noscroll (ps, to_idx);
- }
- if (scroll_follows_playback && plt == deadbeef->plt_get_curr_idx ()) {
- ddb_listview_scroll_to (ps, to_idx);
- }
- }
- }
- }
-
- if (from) {
- int idx = deadbeef->pl_get_idx_of (from);
- if (idx != -1) {
- ddb_listview_draw_row (ps, idx, from);
- }
- }
- if (to && to_idx != -1) {
- ddb_listview_draw_row (ps, to_idx, to);
- }
-}
-
static gboolean
update_win_title_idle (gpointer data) {
struct fromto_t *ft = (struct fromto_t *)data;
@@ -894,8 +833,6 @@ update_win_title_idle (gpointer data) {
gtkui_set_titlebar (NULL);
}
}
- // update playlist view
- songchanged (DDB_LISTVIEW (lookup_widget (mainwin, "playlist")), from, to);
if (from) {
deadbeef->pl_item_unref (from);
}
@@ -953,11 +890,11 @@ volumebar_redraw (void) {
gdk_window_invalidate_rect (gtk_widget_get_window (volumebar), NULL, FALSE);
}
-void
-tabstrip_redraw (void) {
- GtkWidget *ts = lookup_widget (mainwin, "tabstrip");
- ddb_tabstrip_refresh (DDB_TABSTRIP (ts));
-}
+//void
+//tabstrip_redraw (void) {
+// GtkWidget *ts = lookup_widget (mainwin, "tabstrip");
+// ddb_tabstrip_refresh (DDB_TABSTRIP (ts));
+//}
static int gtk_initialized = 0;
static gint refresh_timeout = 0;
@@ -982,8 +919,22 @@ gtkui_setup_gui_refresh (void) {
refresh_timeout = g_timeout_add (tm, gtkui_on_frameupdate, NULL);
}
+static void
+send_messages_to_widgets (ddb_gtkui_widget_t *w, uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) {
+ for (ddb_gtkui_widget_t *c = w->children; c; c = c->next) {
+ send_messages_to_widgets (c, id, ctx, p1, p2);
+ }
+ if (w->message) {
+ w->message (w, id, ctx, p1, p2);
+ }
+}
+
int
gtkui_message (uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) {
+ ddb_gtkui_widget_t *rootwidget = w_get_rootwidget ();
+ if (rootwidget) {
+ send_messages_to_widgets (rootwidget, id, ctx, p1, p2);
+ }
switch (id) {
case DB_EV_ACTIVATED:
g_idle_add (activate_cb, NULL);
@@ -1003,9 +954,9 @@ gtkui_message (uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) {
g_idle_add (trackinfochanged_cb, ev->track);
}
break;
- case DB_EV_PAUSED:
- g_idle_add (paused_cb, NULL);
- break;
+// case DB_EV_PAUSED:
+// g_idle_add (paused_cb, NULL);
+// break;
case DB_EV_PLAYLISTCHANGED:
gtkui_playlist_changed ();
break;
@@ -1045,7 +996,44 @@ gtkui_thread (void *ctx) {
gtk_disable_setlocale ();
gtk_init (&argc, (char ***)&argv);
+ // register widget types
+ w_reg_widget ("tabbed_playlist", _("Playlist with tabs"), w_tabbed_playlist_create);
+ w_reg_widget ("box", NULL, w_box_create);
+ w_reg_widget ("vsplitter", _("Splitter (top and bottom)"), w_vsplitter_create);
+ w_reg_widget ("hsplitter", _("Splitter (left and right)"), w_hsplitter_create);
+ w_reg_widget ("placeholder", NULL, w_placeholder_create);
+ w_reg_widget ("tabs", _("Tabs"), w_tabs_create);
+ w_reg_widget ("tabstrip", _("Playlist tabs"), w_tabstrip_create);
+ w_reg_widget ("playlist", _("Playlist"), w_playlist_create);
+ w_reg_widget ("selproperties", _("Selection properties"), w_selproperties_create);
+ w_reg_widget ("coverart", _("Album art display"), w_coverart_create);
+
mainwin = create_mainwin ();
+
+ // construct mainwindow widgets
+ {
+
+ w_init ();
+ ddb_gtkui_widget_t *rootwidget = w_get_rootwidget ();
+ gtk_widget_show (rootwidget->widget);
+ gtk_box_pack_start (GTK_BOX(lookup_widget(mainwin, "plugins_bottom_vbox")), rootwidget->widget, TRUE, TRUE, 0);
+
+ // load layout
+ char layout[1024];
+ deadbeef->conf_get_str ("gtkui.layout", "tabbed_playlist { }", layout, sizeof (layout));
+
+ ddb_gtkui_widget_t *w = NULL;
+ w_create_from_string (layout, &w);
+ if (!w) {
+ ddb_gtkui_widget_t *plt = w_create ("tabbed_playlist");
+ w_append (rootwidget, plt);
+ gtk_widget_show (plt->widget);
+ }
+ else {
+ w_append (rootwidget, w);
+ }
+ }
+
gtkpl_init ();
GtkIconTheme *theme = gtk_icon_theme_get_default();
@@ -1087,16 +1075,13 @@ gtkui_thread (void *ctx) {
searchwin = create_searchwin ();
gtk_window_set_transient_for (GTK_WINDOW (searchwin), GTK_WINDOW (mainwin));
- DdbListview *main_playlist = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- main_playlist_init (GTK_WIDGET (main_playlist));
-
+// DdbListview *main_playlist = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
+// main_playlist_init (GTK_WIDGET (main_playlist));
if (deadbeef->conf_get_int ("gtkui.headers.visible", 1)) {
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (header_mi), TRUE);
- ddb_listview_show_header (main_playlist, 1);
}
else {
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (header_mi), FALSE);
- ddb_listview_show_header (main_playlist, 0);
}
DdbListview *search_playlist = DDB_LISTVIEW (lookup_widget (searchwin, "searchlist"));
@@ -1119,6 +1104,8 @@ gtkui_thread (void *ctx) {
gtk_main ();
+ w_free ();
+
if (refresh_timeout) {
g_source_remove (refresh_timeout);
refresh_timeout = 0;
@@ -1332,7 +1319,7 @@ gtkui_stop (void) {
deadbeef->thread_join (gtk_tid);
trace ("gtk thread finished\n");
gtk_tid = 0;
- main_playlist_free ();
+ //main_playlist_free ();
trace ("gtkui_stop completed\n");
return 0;
}
@@ -1408,4 +1395,5 @@ static ddb_gtkui_t plugin = {
.gui.plugin.message = gtkui_message,
.gui.run_dialog = gtkui_run_dialog_root,
.get_mainwin = gtkui_get_mainwin,
+ .api_version = GTKUI_API_VERSION,
};
diff --git a/plugins/gtkui/gtkui.h b/plugins/gtkui/gtkui.h
index 13e3e9cb..afef4788 100644
--- a/plugins/gtkui/gtkui.h
+++ b/plugins/gtkui/gtkui.h
@@ -115,8 +115,8 @@ on_seekbar_motion_notify_event (GtkWidget *widget,
void
volumebar_redraw (void);
-void
-tabstrip_redraw (void);
+//void
+//tabstrip_redraw (void);
void
gtkui_playlist_changed (void);
@@ -154,6 +154,9 @@ gtkui_get_curr_playlist_mod (void);
void
gtkui_trackinfochanged (DB_playItem_t *it);
+gboolean
+redraw_queued_tracks_cb (gpointer plt);
+
extern DB_playItem_t * (*gtkui_original_plt_load) (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname, int *pabort, int (*cb)(DB_playItem_t *it, void *data), void *user_data);
#endif
diff --git a/plugins/gtkui/gtkui_api.h b/plugins/gtkui/gtkui_api.h
index 7fa7944f..34b4d9d1 100644
--- a/plugins/gtkui/gtkui_api.h
+++ b/plugins/gtkui/gtkui_api.h
@@ -25,9 +25,38 @@
#ifndef __GTKUI_API_H
#define __GTKUI_API_H
+#define GTKUI_API_VERSION 1 // for compile-time checking
+
+typedef struct ddb_gtkui_widget_s {
+ const char *type;
+
+ struct ddb_gtkui_widget_s *parent;
+
+ GtkWidget *widget;
+
+ uint32_t flags;
+
+ void (*destroy) (struct ddb_gtkui_widget_s *w);
+
+ void (*append) (struct ddb_gtkui_widget_s *container, struct ddb_gtkui_widget_s *child);
+ void (*remove) (struct ddb_gtkui_widget_s *container, struct ddb_gtkui_widget_s *child);
+ void (*replace) (struct ddb_gtkui_widget_s *container, struct ddb_gtkui_widget_s *child, struct ddb_gtkui_widget_s *newchild);
+
+ int (*message) (struct ddb_gtkui_widget_s *w, uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2);
+
+ void (*initmenu) (struct ddb_gtkui_widget_s *w, GtkWidget *menu);
+
+ struct ddb_gtkui_widget_s *children;
+ struct ddb_gtkui_widget_s *next; // points to next widget in the same container
+} ddb_gtkui_widget_t;
+
typedef struct {
DB_gui_t gui;
+ int api_version;
GtkWidget * (*get_mainwin) (void);
+ void (*reg_widget) (const char *type, ddb_gtkui_widget_t *(*create_func) (void));
+ void (*unreg_widget) (const char *type);
+ ddb_gtkui_widget_t * (*get_root_widget) (void);
} ddb_gtkui_t;
#endif
diff --git a/plugins/gtkui/interface.c b/plugins/gtkui/interface.c
index 84649092..7ccc50de 100644
--- a/plugins/gtkui/interface.c
+++ b/plugins/gtkui/interface.c
@@ -35,12 +35,12 @@ create_mainwin (void)
GtkWidget *File;
GtkWidget *File_menu;
GtkWidget *open;
- GtkWidget *image555;
+ GtkWidget *image563;
GtkWidget *separator2;
GtkWidget *add_files;
- GtkWidget *image556;
+ GtkWidget *image564;
GtkWidget *add_folders;
- GtkWidget *image557;
+ GtkWidget *image565;
GtkWidget *add_location1;
GtkWidget *separatormenuitem1;
GtkWidget *new_playlist1;
@@ -48,18 +48,18 @@ create_mainwin (void)
GtkWidget *playlist_save_as;
GtkWidget *separator8;
GtkWidget *quit;
- GtkWidget *image558;
+ GtkWidget *image566;
GtkWidget *Edit;
GtkWidget *Edit_menu;
GtkWidget *clear1;
- GtkWidget *image559;
+ GtkWidget *image567;
GtkWidget *select_all1;
GtkWidget *deselect_all1;
GtkWidget *invert_selection1;
GtkWidget *Selection;
GtkWidget *Selection_menu;
GtkWidget *remove1;
- GtkWidget *image560;
+ GtkWidget *image568;
GtkWidget *crop1;
GtkWidget *find1;
GtkWidget *sort_by1;
@@ -79,6 +79,7 @@ create_mainwin (void)
GtkWidget *view_headers;
GtkWidget *view_tabs;
GtkWidget *view_eq;
+ GtkWidget *design_mode1;
GtkWidget *Playback;
GtkWidget *Playback_menu;
GtkWidget *Order;
@@ -102,16 +103,16 @@ create_mainwin (void)
GtkWidget *Help;
GtkWidget *Help_menu;
GtkWidget *help1;
- GtkWidget *image561;
+ GtkWidget *image569;
GtkWidget *changelog1;
GtkWidget *separator10;
GtkWidget *gpl1;
GtkWidget *lgpl1;
GtkWidget *separator9;
GtkWidget *about1;
- GtkWidget *image562;
+ GtkWidget *image570;
GtkWidget *translators1;
- GtkWidget *image563;
+ GtkWidget *image571;
GtkWidget *hbox2;
GtkWidget *hbox3;
GtkWidget *stopbtn;
@@ -126,9 +127,6 @@ create_mainwin (void)
GtkWidget *image5;
GtkWidget *seekbar;
GtkWidget *volumebar;
- GtkWidget *tabstrip;
- GtkWidget *frame1;
- GtkWidget *playlist;
GtkWidget *plugins_bottom_vbox;
GtkWidget *statusbar;
GtkAccelGroup *accel_group;
@@ -162,9 +160,9 @@ create_mainwin (void)
GDK_O, (GdkModifierType) GDK_CONTROL_MASK,
GTK_ACCEL_VISIBLE);
- image555 = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_MENU);
- gtk_widget_show (image555);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (open), image555);
+ image563 = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image563);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (open), image563);
separator2 = gtk_separator_menu_item_new ();
gtk_widget_show (separator2);
@@ -175,17 +173,17 @@ create_mainwin (void)
gtk_widget_show (add_files);
gtk_container_add (GTK_CONTAINER (File_menu), add_files);
- image556 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU);
- gtk_widget_show (image556);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_files), image556);
+ image564 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image564);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_files), image564);
add_folders = gtk_image_menu_item_new_with_mnemonic (_("Add folder(s)"));
gtk_widget_show (add_folders);
gtk_container_add (GTK_CONTAINER (File_menu), add_folders);
- image557 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU);
- gtk_widget_show (image557);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_folders), image557);
+ image565 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image565);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_folders), image565);
add_location1 = gtk_menu_item_new_with_mnemonic (_("Add location"));
gtk_widget_show (add_location1);
@@ -223,9 +221,9 @@ create_mainwin (void)
GDK_Q, (GdkModifierType) GDK_CONTROL_MASK,
GTK_ACCEL_VISIBLE);
- image558 = gtk_image_new_from_stock ("gtk-quit", GTK_ICON_SIZE_MENU);
- gtk_widget_show (image558);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (quit), image558);
+ image566 = gtk_image_new_from_stock ("gtk-quit", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image566);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (quit), image566);
Edit = gtk_menu_item_new_with_mnemonic (_("_Edit"));
gtk_widget_show (Edit);
@@ -238,9 +236,9 @@ create_mainwin (void)
gtk_widget_show (clear1);
gtk_container_add (GTK_CONTAINER (Edit_menu), clear1);
- image559 = gtk_image_new_from_stock ("gtk-clear", GTK_ICON_SIZE_MENU);
- gtk_widget_show (image559);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (clear1), image559);
+ image567 = gtk_image_new_from_stock ("gtk-clear", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image567);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (clear1), image567);
select_all1 = gtk_menu_item_new_with_mnemonic (_("Select all"));
gtk_widget_show (select_all1);
@@ -271,9 +269,9 @@ create_mainwin (void)
gtk_widget_show (remove1);
gtk_container_add (GTK_CONTAINER (Selection_menu), remove1);
- image560 = gtk_image_new_from_stock ("gtk-remove", GTK_ICON_SIZE_MENU);
- gtk_widget_show (image560);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (remove1), image560);
+ image568 = gtk_image_new_from_stock ("gtk-remove", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image568);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (remove1), image568);
crop1 = gtk_menu_item_new_with_mnemonic (_("Crop"));
gtk_widget_show (crop1);
@@ -353,6 +351,10 @@ create_mainwin (void)
gtk_widget_show (view_eq);
gtk_container_add (GTK_CONTAINER (View_menu), view_eq);
+ design_mode1 = gtk_check_menu_item_new_with_mnemonic (_("Design mode"));
+ gtk_widget_show (design_mode1);
+ gtk_container_add (GTK_CONTAINER (View_menu), design_mode1);
+
Playback = gtk_menu_item_new_with_mnemonic (_("_Playback"));
gtk_widget_show (Playback);
gtk_container_add (GTK_CONTAINER (menubar1), Playback);
@@ -371,16 +373,19 @@ create_mainwin (void)
order_linear_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (order_linear));
gtk_widget_show (order_linear);
gtk_container_add (GTK_CONTAINER (Order_menu), order_linear);
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (order_linear), TRUE);
order_shuffle = gtk_radio_menu_item_new_with_mnemonic (order_linear_group, _("Shuffle tracks"));
order_linear_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (order_shuffle));
gtk_widget_show (order_shuffle);
gtk_container_add (GTK_CONTAINER (Order_menu), order_shuffle);
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (order_shuffle), TRUE);
order_shuffle_albums = gtk_radio_menu_item_new_with_mnemonic (order_linear_group, _("Shuffle albums"));
order_linear_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (order_shuffle_albums));
gtk_widget_show (order_shuffle_albums);
gtk_container_add (GTK_CONTAINER (Order_menu), order_shuffle_albums);
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (order_shuffle_albums), TRUE);
order_random = gtk_radio_menu_item_new_with_mnemonic (order_linear_group, _("Random"));
order_linear_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (order_random));
@@ -399,11 +404,13 @@ create_mainwin (void)
loop_all_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (loop_all));
gtk_widget_show (loop_all);
gtk_container_add (GTK_CONTAINER (Looping_menu), loop_all);
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (loop_all), TRUE);
loop_single = gtk_radio_menu_item_new_with_mnemonic (loop_all_group, _("Loop Single Song"));
loop_all_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (loop_single));
gtk_widget_show (loop_single);
gtk_container_add (GTK_CONTAINER (Looping_menu), loop_single);
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (loop_single), TRUE);
loop_disable = gtk_radio_menu_item_new_with_mnemonic (loop_all_group, _("Don't Loop"));
loop_all_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (loop_disable));
@@ -450,9 +457,9 @@ create_mainwin (void)
gtk_widget_show (help1);
gtk_container_add (GTK_CONTAINER (Help_menu), help1);
- image561 = gtk_image_new_from_stock ("gtk-help", GTK_ICON_SIZE_MENU);
- gtk_widget_show (image561);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (help1), image561);
+ image569 = gtk_image_new_from_stock ("gtk-help", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image569);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (help1), image569);
changelog1 = gtk_menu_item_new_with_mnemonic (_("_ChangeLog"));
gtk_widget_show (changelog1);
@@ -480,17 +487,17 @@ create_mainwin (void)
gtk_widget_show (about1);
gtk_container_add (GTK_CONTAINER (Help_menu), about1);
- image562 = gtk_image_new_from_stock ("gtk-about", GTK_ICON_SIZE_MENU);
- gtk_widget_show (image562);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (about1), image562);
+ image570 = gtk_image_new_from_stock ("gtk-about", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image570);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (about1), image570);
translators1 = gtk_image_menu_item_new_with_mnemonic (_("_Translators"));
gtk_widget_show (translators1);
gtk_container_add (GTK_CONTAINER (Help_menu), translators1);
- image563 = gtk_image_new_from_stock ("gtk-about", GTK_ICON_SIZE_MENU);
- gtk_widget_show (image563);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (translators1), image563);
+ image571 = gtk_image_new_from_stock ("gtk-about", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image571);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (translators1), image571);
hbox2 = gtk_hbox_new (FALSE, 0);
gtk_widget_show (hbox2);
@@ -585,27 +592,9 @@ create_mainwin (void)
gtk_widget_set_can_focus(volumebar, FALSE);
gtk_widget_set_can_default(volumebar, FALSE);
- tabstrip = create_tabstrip_widget ("tabstrip", "", "", 0, 0);
- gtk_widget_show (tabstrip);
- gtk_box_pack_start (GTK_BOX (vbox1), tabstrip, FALSE, TRUE, 0);
- gtk_widget_set_size_request (tabstrip, -1, 24);
- gtk_widget_set_can_focus(tabstrip, FALSE);
- gtk_widget_set_can_default(tabstrip, FALSE);
-
- frame1 = gtk_frame_new (NULL);
- gtk_widget_show (frame1);
- gtk_box_pack_start (GTK_BOX (vbox1), frame1, TRUE, TRUE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (frame1), 1);
-
- playlist = create_ddb_listview_widget ("playlist", "", "", 0, 0);
- gtk_widget_show (playlist);
- gtk_container_add (GTK_CONTAINER (frame1), playlist);
- gtk_widget_set_can_focus(playlist, FALSE);
- gtk_widget_set_can_default(playlist, FALSE);
-
plugins_bottom_vbox = gtk_vbox_new (FALSE, 0);
gtk_widget_show (plugins_bottom_vbox);
- gtk_box_pack_start (GTK_BOX (vbox1), plugins_bottom_vbox, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox1), plugins_bottom_vbox, TRUE, TRUE, 0);
statusbar = gtk_statusbar_new ();
gtk_widget_show (statusbar);
@@ -719,6 +708,9 @@ create_mainwin (void)
g_signal_connect ((gpointer) view_eq, "activate",
G_CALLBACK (on_toggle_eq),
NULL);
+ g_signal_connect ((gpointer) design_mode1, "activate",
+ G_CALLBACK (on_design_mode1_activate),
+ NULL);
g_signal_connect ((gpointer) order_linear, "activate",
G_CALLBACK (on_order_linear_activate),
NULL);
@@ -793,12 +785,12 @@ create_mainwin (void)
GLADE_HOOKUP_OBJECT (mainwin, File, "File");
GLADE_HOOKUP_OBJECT (mainwin, File_menu, "File_menu");
GLADE_HOOKUP_OBJECT (mainwin, open, "open");
- GLADE_HOOKUP_OBJECT (mainwin, image555, "image555");
+ GLADE_HOOKUP_OBJECT (mainwin, image563, "image563");
GLADE_HOOKUP_OBJECT (mainwin, separator2, "separator2");
GLADE_HOOKUP_OBJECT (mainwin, add_files, "add_files");
- GLADE_HOOKUP_OBJECT (mainwin, image556, "image556");
+ GLADE_HOOKUP_OBJECT (mainwin, image564, "image564");
GLADE_HOOKUP_OBJECT (mainwin, add_folders, "add_folders");
- GLADE_HOOKUP_OBJECT (mainwin, image557, "image557");
+ GLADE_HOOKUP_OBJECT (mainwin, image565, "image565");
GLADE_HOOKUP_OBJECT (mainwin, add_location1, "add_location1");
GLADE_HOOKUP_OBJECT (mainwin, separatormenuitem1, "separatormenuitem1");
GLADE_HOOKUP_OBJECT (mainwin, new_playlist1, "new_playlist1");
@@ -806,18 +798,18 @@ create_mainwin (void)
GLADE_HOOKUP_OBJECT (mainwin, playlist_save_as, "playlist_save_as");
GLADE_HOOKUP_OBJECT (mainwin, separator8, "separator8");
GLADE_HOOKUP_OBJECT (mainwin, quit, "quit");
- GLADE_HOOKUP_OBJECT (mainwin, image558, "image558");
+ GLADE_HOOKUP_OBJECT (mainwin, image566, "image566");
GLADE_HOOKUP_OBJECT (mainwin, Edit, "Edit");
GLADE_HOOKUP_OBJECT (mainwin, Edit_menu, "Edit_menu");
GLADE_HOOKUP_OBJECT (mainwin, clear1, "clear1");
- GLADE_HOOKUP_OBJECT (mainwin, image559, "image559");
+ GLADE_HOOKUP_OBJECT (mainwin, image567, "image567");
GLADE_HOOKUP_OBJECT (mainwin, select_all1, "select_all1");
GLADE_HOOKUP_OBJECT (mainwin, deselect_all1, "deselect_all1");
GLADE_HOOKUP_OBJECT (mainwin, invert_selection1, "invert_selection1");
GLADE_HOOKUP_OBJECT (mainwin, Selection, "Selection");
GLADE_HOOKUP_OBJECT (mainwin, Selection_menu, "Selection_menu");
GLADE_HOOKUP_OBJECT (mainwin, remove1, "remove1");
- GLADE_HOOKUP_OBJECT (mainwin, image560, "image560");
+ GLADE_HOOKUP_OBJECT (mainwin, image568, "image568");
GLADE_HOOKUP_OBJECT (mainwin, crop1, "crop1");
GLADE_HOOKUP_OBJECT (mainwin, find1, "find1");
GLADE_HOOKUP_OBJECT (mainwin, sort_by1, "sort_by1");
@@ -837,6 +829,7 @@ create_mainwin (void)
GLADE_HOOKUP_OBJECT (mainwin, view_headers, "view_headers");
GLADE_HOOKUP_OBJECT (mainwin, view_tabs, "view_tabs");
GLADE_HOOKUP_OBJECT (mainwin, view_eq, "view_eq");
+ GLADE_HOOKUP_OBJECT (mainwin, design_mode1, "design_mode1");
GLADE_HOOKUP_OBJECT (mainwin, Playback, "Playback");
GLADE_HOOKUP_OBJECT (mainwin, Playback_menu, "Playback_menu");
GLADE_HOOKUP_OBJECT (mainwin, Order, "Order");
@@ -858,16 +851,16 @@ create_mainwin (void)
GLADE_HOOKUP_OBJECT (mainwin, Help, "Help");
GLADE_HOOKUP_OBJECT (mainwin, Help_menu, "Help_menu");
GLADE_HOOKUP_OBJECT (mainwin, help1, "help1");
- GLADE_HOOKUP_OBJECT (mainwin, image561, "image561");
+ GLADE_HOOKUP_OBJECT (mainwin, image569, "image569");
GLADE_HOOKUP_OBJECT (mainwin, changelog1, "changelog1");
GLADE_HOOKUP_OBJECT (mainwin, separator10, "separator10");
GLADE_HOOKUP_OBJECT (mainwin, gpl1, "gpl1");
GLADE_HOOKUP_OBJECT (mainwin, lgpl1, "lgpl1");
GLADE_HOOKUP_OBJECT (mainwin, separator9, "separator9");
GLADE_HOOKUP_OBJECT (mainwin, about1, "about1");
- GLADE_HOOKUP_OBJECT (mainwin, image562, "image562");
+ GLADE_HOOKUP_OBJECT (mainwin, image570, "image570");
GLADE_HOOKUP_OBJECT (mainwin, translators1, "translators1");
- GLADE_HOOKUP_OBJECT (mainwin, image563, "image563");
+ GLADE_HOOKUP_OBJECT (mainwin, image571, "image571");
GLADE_HOOKUP_OBJECT (mainwin, hbox2, "hbox2");
GLADE_HOOKUP_OBJECT (mainwin, hbox3, "hbox3");
GLADE_HOOKUP_OBJECT (mainwin, stopbtn, "stopbtn");
@@ -882,9 +875,6 @@ create_mainwin (void)
GLADE_HOOKUP_OBJECT (mainwin, image5, "image5");
GLADE_HOOKUP_OBJECT (mainwin, seekbar, "seekbar");
GLADE_HOOKUP_OBJECT (mainwin, volumebar, "volumebar");
- GLADE_HOOKUP_OBJECT (mainwin, tabstrip, "tabstrip");
- GLADE_HOOKUP_OBJECT (mainwin, frame1, "frame1");
- GLADE_HOOKUP_OBJECT (mainwin, playlist, "playlist");
GLADE_HOOKUP_OBJECT (mainwin, plugins_bottom_vbox, "plugins_bottom_vbox");
GLADE_HOOKUP_OBJECT (mainwin, statusbar, "statusbar");
diff --git a/plugins/gtkui/mainplaylist.c b/plugins/gtkui/mainplaylist.c
index 21661f6d..b781feaa 100644
--- a/plugins/gtkui/mainplaylist.c
+++ b/plugins/gtkui/mainplaylist.c
@@ -128,8 +128,8 @@ void main_external_drag_n_drop (DdbListviewIter before, char *mem, int length) {
gboolean
playlist_tooltip_handler (GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, gpointer unused)
{
- GtkWidget *pl = lookup_widget (mainwin, "playlist");
- DB_playItem_t *it = (DB_playItem_t *)ddb_listview_get_iter_from_coord (DDB_LISTVIEW (pl), 0, y);
+ DdbListview *pl = DDB_LISTVIEW (g_object_get_data (G_OBJECT (widget), "owner"));
+ DB_playItem_t *it = (DB_playItem_t *)ddb_listview_get_iter_from_coord (pl, 0, y);
if (it) {
gtk_tooltip_set_text (tooltip, deadbeef->pl_find_meta (it, ":URI"));
deadbeef->pl_item_unref (it);
@@ -159,6 +159,7 @@ void main_selection_changed (DdbListviewIter it, int idx) {
else {
ddb_listview_draw_row (search, search_get_idx ((DB_playItem_t *)it), it);
}
+ deadbeef->sendmessage (DB_EV_SELCHANGED, 0, deadbeef->plt_get_curr_idx (), PL_MAIN);
}
void main_draw_group_title (DdbListview *listview, cairo_t *drawable, DdbListviewIter it, int x, int y, int width, int height) {
@@ -254,6 +255,14 @@ main_vscroll_changed (int pos) {
deadbeef->conf_set_int (conf, pos);
}
+void
+main_header_context_menu (DdbListview *ps, int column) {
+ GtkWidget *menu = create_headermenu (1);
+ set_last_playlist_cm (ps); // playlist ptr for context menu
+ set_active_column_cm (column);
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, ps, 3, gtk_get_current_event_time());
+}
+
DdbListviewBinding main_binding = {
// rows
.count = main_get_count,
@@ -290,7 +299,7 @@ DdbListviewBinding main_binding = {
// callbacks
.handle_doubleclick = main_handle_doubleclick,
.selection_changed = main_selection_changed,
- .header_context_menu = header_context_menu,
+ .header_context_menu = main_header_context_menu,
.list_context_menu = list_context_menu,
.delete_selected = main_delete_selected,
.vscroll_changed = main_vscroll_changed,
@@ -332,8 +341,9 @@ main_playlist_init (GtkWidget *widget) {
GValue value = {0, };
g_value_init (&value, G_TYPE_BOOLEAN);
g_value_set_boolean (&value, TRUE);
- g_object_set_property (G_OBJECT (widget), "has-tooltip", &value);
- g_signal_connect (G_OBJECT (widget), "query-tooltip", G_CALLBACK (playlist_tooltip_handler), NULL);
+ DdbListview *pl = DDB_LISTVIEW (widget);
+ g_object_set_property (G_OBJECT (pl->list), "has-tooltip", &value);
+ g_signal_connect (G_OBJECT (pl->list), "query-tooltip", G_CALLBACK (playlist_tooltip_handler), NULL);
}
deadbeef->conf_lock ();
strncpy (group_by_str, deadbeef->conf_get_str_fast ("playlist.group_by", ""), sizeof (group_by_str));
@@ -350,9 +360,6 @@ main_playlist_free (void) {
void
main_refresh (void) {
- if (mainwin && gtk_widget_get_visible (mainwin)) {
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_refresh (pl, DDB_REFRESH_VSCROLL | DDB_REFRESH_LIST);
- }
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
diff --git a/plugins/gtkui/mainplaylist.h b/plugins/gtkui/mainplaylist.h
index 34cc67bc..1b25ca6b 100644
--- a/plugins/gtkui/mainplaylist.h
+++ b/plugins/gtkui/mainplaylist.h
@@ -19,6 +19,8 @@
#ifndef __MAINPLAYLIST_H
#define __MAINPLAYLIST_H
+#include "ddblistview.h"
+
void
main_playlist_init (GtkWidget *widget);
@@ -31,4 +33,7 @@ main_refresh (void);
int
main_get_idx (DdbListviewIter it);
+void
+main_drag_n_drop (DdbListviewIter before, DdbPlaylistHandle from_playlist, uint32_t *indices, int length, int copy);
+
#endif
diff --git a/plugins/gtkui/plcommon.c b/plugins/gtkui/plcommon.c
index 09b65353..748bd90b 100644
--- a/plugins/gtkui/plcommon.c
+++ b/plugins/gtkui/plcommon.c
@@ -291,8 +291,7 @@ on_clear1_activate (GtkMenuItem *menuitem,
{
deadbeef->pl_clear ();
deadbeef->pl_save_all ();
- main_refresh ();
- search_refresh ();
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
void
@@ -301,8 +300,7 @@ on_remove1_activate (GtkMenuItem *menuitem,
{
int cursor = deadbeef->pl_delete_selected ();
deadbeef->pl_save_all ();
- main_refresh ();
- search_refresh ();
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
@@ -310,22 +308,18 @@ void
on_crop1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
deadbeef->pl_crop_selected ();
deadbeef->pl_save_all ();
- main_refresh ();
- search_refresh ();
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
void
on_remove2_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
- GtkWidget *widget = GTK_WIDGET (menuitem);
int cursor = deadbeef->pl_delete_selected ();
deadbeef->pl_save_all ();
- main_refresh ();
- search_refresh ();
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
void
@@ -362,8 +356,7 @@ on_remove_from_disk_activate (GtkMenuItem *menuitem,
deadbeef->pl_save_all ();
deadbeef->pl_unlock ();
- main_refresh ();
- search_refresh ();
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
void
@@ -717,6 +710,16 @@ static DdbListview *last_playlist;
static int active_column;
void
+set_last_playlist_cm (DdbListview *pl) {
+ last_playlist = pl;
+}
+
+void
+set_active_column_cm (int col) {
+ active_column = col;
+}
+
+void
append_column_from_textdef (DdbListview *listview, const uint8_t *def) {
// syntax: "title" "format" id width alignright
char token[MAX_TOKEN];
@@ -1049,14 +1052,6 @@ create_headermenu (int groupby)
}
void
-header_context_menu (DdbListview *ps, int column) {
- GtkWidget *menu = create_headermenu (GTK_WIDGET (ps) == lookup_widget (mainwin, "playlist") ? 1 : 0);
- last_playlist = ps;
- active_column = column;
- gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, ps, 3, gtk_get_current_event_time());
-}
-
-void
add_column_helper (DdbListview *listview, const char *title, int width, int id, const char *format, int align_right) {
if (!format) {
format = "";
diff --git a/plugins/gtkui/plcommon.h b/plugins/gtkui/plcommon.h
index 3c24f00f..f5c04e35 100644
--- a/plugins/gtkui/plcommon.h
+++ b/plugins/gtkui/plcommon.h
@@ -41,12 +41,18 @@ void
list_context_menu (DdbListview *listview, DdbListviewIter it, int idx);
void
-header_context_menu (DdbListview *ps, int column);
-
-void
append_column_from_textdef (DdbListview *listview, const uint8_t *def);
void
add_column_helper (DdbListview *listview, const char *title, int width, int id, const char *format, int align_right);
+GtkWidget*
+create_headermenu (int groupby);
+
+void
+set_last_playlist_cm (DdbListview *pl);
+
+void
+set_active_column_cm (int col);
+
#endif // __PLCOLUMNS_H
diff --git a/plugins/gtkui/prefwin.c b/plugins/gtkui/prefwin.c
index 6f447792..81bb49e1 100644
--- a/plugins/gtkui/prefwin.c
+++ b/plugins/gtkui/prefwin.c
@@ -875,8 +875,9 @@ on_tabstrip_light_color_set (GtkColorButton *colorbutton,
deadbeef->conf_set_str ("gtkui.color.tabstrip_light", str);
deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
- redraw_headers ();
- tabstrip_redraw ();
+// redraw_headers ();
+// tabstrip_redraw ();
+ gtk_widget_queue_draw (mainwin);
}
@@ -891,8 +892,9 @@ on_tabstrip_mid_color_set (GtkColorButton *colorbutton,
deadbeef->conf_set_str ("gtkui.color.tabstrip_mid", str);
deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
- redraw_headers ();
- tabstrip_redraw ();
+// redraw_headers ();
+// tabstrip_redraw ();
+ gtk_widget_queue_draw (mainwin);
}
@@ -907,8 +909,9 @@ on_tabstrip_dark_color_set (GtkColorButton *colorbutton,
deadbeef->conf_set_str ("gtkui.color.tabstrip_dark", str);
deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
- redraw_headers ();
- tabstrip_redraw ();
+// redraw_headers ();
+// tabstrip_redraw ();
+ gtk_widget_queue_draw (mainwin);
}
void
@@ -922,8 +925,9 @@ on_tabstrip_base_color_set (GtkColorButton *colorbutton,
deadbeef->conf_set_str ("gtkui.color.tabstrip_base", str);
deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
- redraw_headers ();
- tabstrip_redraw ();
+// redraw_headers ();
+// tabstrip_redraw ();
+ gtk_widget_queue_draw (mainwin);
}
void
@@ -937,8 +941,9 @@ on_tabstrip_text_color_set (GtkColorButton *colorbutton,
deadbeef->conf_set_str ("gtkui.color.tabstrip_text", str);
deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
- redraw_headers ();
- tabstrip_redraw ();
+// redraw_headers ();
+// tabstrip_redraw ();
+ gtk_widget_queue_draw (mainwin);
}
void
@@ -1099,8 +1104,9 @@ on_override_tabstrip_colors_toggled (GtkToggleButton *togglebutton,
deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
prefwin_init_theme_colors ();
- redraw_headers ();
- tabstrip_redraw ();
+// redraw_headers ();
+// tabstrip_redraw ();
+ gtk_widget_queue_draw (mainwin);
}
void
diff --git a/plugins/gtkui/search.c b/plugins/gtkui/search.c
index 662839bf..87344e39 100644
--- a/plugins/gtkui/search.c
+++ b/plugins/gtkui/search.c
@@ -319,13 +319,7 @@ void search_handle_doubleclick (DdbListview *listview, DdbListviewIter iter, int
}
void search_selection_changed (DdbListviewIter it, int idx) {
- DdbListview *main = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- if (idx == -1) {
- ddb_listview_refresh (main, DDB_REFRESH_LIST);
- }
- else {
- ddb_listview_draw_row (main, main_get_idx ((DB_playItem_t *)it), it);
- }
+ deadbeef->sendmessage (DB_EV_SELCHANGED, 0, 0, 0);
}
void
@@ -335,6 +329,14 @@ search_delete_selected (void) {
search_refresh ();
}
+void
+search_header_context_menu (DdbListview *ps, int column) {
+ GtkWidget *menu = create_headermenu (0);
+ set_last_playlist_cm (ps); // playlist ptr for context menu
+ set_active_column_cm (column);
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, ps, 3, gtk_get_current_event_time());
+}
+
DdbListviewBinding search_binding = {
// rows
.count = search_get_count,
@@ -371,7 +373,7 @@ DdbListviewBinding search_binding = {
// callbacks
.handle_doubleclick = search_handle_doubleclick,
.selection_changed = search_selection_changed,
- .header_context_menu = header_context_menu,
+ .header_context_menu = search_header_context_menu,
.list_context_menu = list_context_menu,
.delete_selected = search_delete_selected,
.modification_idx = gtkui_get_curr_playlist_mod,
diff --git a/plugins/gtkui/trkproperties.c b/plugins/gtkui/trkproperties.c
index 590bf1fa..ff061cd9 100644
--- a/plugins/gtkui/trkproperties.c
+++ b/plugins/gtkui/trkproperties.c
@@ -52,8 +52,8 @@ static int numtracks;
static GtkWidget *progressdlg;
static int progress_aborted;
-static int
-build_key_list (const char ***pkeys, int props) {
+int
+build_key_list (const char ***pkeys, int props, DB_playItem_t **tracks, int numtracks) {
int sz = 20;
const char **keys = malloc (sizeof (const char *) * sz);
if (!keys) {
@@ -100,7 +100,7 @@ equals_ptr (const char *a, const char *b) {
}
static int
-get_field_value (char *out, int size, const char *key, const char *(*getter)(DB_playItem_t *it, const char *key), int (*equals)(const char *a, const char *b)) {
+get_field_value (char *out, int size, const char *key, const char *(*getter)(DB_playItem_t *it, const char *key), int (*equals)(const char *a, const char *b), DB_playItem_t **tracks, int numtracks) {
int multiple = 0;
*out = 0;
if (numtracks == 0) {
@@ -249,13 +249,13 @@ static const char *hc_props[] = {
};
void
-add_field (GtkListStore *store, const char *key, const char *title, int is_prop) {
+add_field (GtkListStore *store, const char *key, const char *title, int is_prop, DB_playItem_t **tracks, int numtracks) {
// get value to edit
const char *mult = is_prop ? "" : _("[Multiple values] ");
char val[1000];
size_t ml = strlen (mult);
memcpy (val, mult, ml+1);
- int n = get_field_value (val + ml, sizeof (val) - ml, key, deadbeef->pl_find_meta_raw, equals_ptr);
+ int n = get_field_value (val + ml, sizeof (val) - ml, key, deadbeef->pl_find_meta_raw, equals_ptr, tracks, numtracks);
GtkTreeIter iter;
gtk_list_store_append (store, &iter);
@@ -279,23 +279,20 @@ add_field (GtkListStore *store, const char *key, const char *title, int is_prop)
}
void
-trkproperties_fill_metadata (void) {
- if (!trackproperties) {
+trkproperties_fill_meta (GtkListStore *store, DB_playItem_t **tracks, int numtracks) {
+ gtk_list_store_clear (store);
+ if (!tracks) {
return;
}
- trkproperties_modified = 0;
- gtk_list_store_clear (store);
- gtk_list_store_clear (propstore);
- deadbeef->pl_lock ();
const char **keys = NULL;
- int nkeys = build_key_list (&keys, 0);
+ int nkeys = build_key_list (&keys, 0, tracks, numtracks);
int k;
// add "standard" fields
for (int i = 0; types[i]; i += 2) {
- add_field (store, types[i], _(types[i+1]), 0);
+ add_field (store, types[i], _(types[i+1]), 0, tracks, numtracks);
}
// add all other fields
@@ -314,19 +311,31 @@ trkproperties_fill_metadata (void) {
if (!types[i]) {
snprintf (title, sizeof (title), "<%s>", keys[k]);
}
- add_field (store, keys[k], title, 0);
+ add_field (store, keys[k], title, 0, tracks, numtracks);
}
if (keys) {
free (keys);
}
+}
+
+void
+trkproperties_fill_metadata (void) {
+ if (!trackproperties) {
+ return;
+ }
+ trkproperties_modified = 0;
+ deadbeef->pl_lock ();
+
+ trkproperties_fill_meta (store, tracks, numtracks);
+ gtk_list_store_clear (propstore);
// hardcoded properties
for (int i = 0; hc_props[i]; i += 2) {
- add_field (propstore, hc_props[i], _(hc_props[i+1]), 1);
+ add_field (propstore, hc_props[i], _(hc_props[i+1]), 1, tracks, numtracks);
}
// properties
- keys = NULL;
- nkeys = build_key_list (&keys, 1);
+ const char **keys = NULL;
+ int nkeys = build_key_list (&keys, 1, tracks, numtracks);
for (int k = 0; k < nkeys; k++) {
int i;
for (i = 0; hc_props[i]; i += 2) {
@@ -339,7 +348,7 @@ trkproperties_fill_metadata (void) {
}
char title[1000];
snprintf (title, sizeof (title), "<%s>", keys[k]+1);
- add_field (propstore, keys[k], title, 1);
+ add_field (propstore, keys[k], title, 1, tracks, numtracks);
}
if (keys) {
free (keys);
diff --git a/plugins/gtkui/trkproperties.h b/plugins/gtkui/trkproperties.h
index 8b2b6311..ef1e530c 100644
--- a/plugins/gtkui/trkproperties.h
+++ b/plugins/gtkui/trkproperties.h
@@ -19,6 +19,8 @@
#ifndef __TRKPROPERTIES_H
#define __TRKPROPERTIES_H
+#include "../../deadbeef.h"
+
struct DB_playItem_s;
void
@@ -30,4 +32,10 @@ trkproperties_destroy (void);
void
trkproperties_fill_metadata (void);
+int
+build_key_list (const char ***pkeys, int props, DB_playItem_t **tracks, int numtracks);
+
+void
+trkproperties_fill_meta (GtkListStore *store, DB_playItem_t **tracks, int numtracks);
+
#endif
diff --git a/plugins/gtkui/widgets.c b/plugins/gtkui/widgets.c
new file mode 100644
index 00000000..9cbed10b
--- /dev/null
+++ b/plugins/gtkui/widgets.c
@@ -0,0 +1,1324 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "gtkui.h"
+#include "widgets.h"
+#include "ddbtabstrip.h"
+#include "ddblistview.h"
+#include "mainplaylist.h"
+#include "../../gettext.h"
+#include "parser.h"
+#include "trkproperties.h"
+#include "coverart.h"
+
+#define min(x,y) ((x)<(y)?(x):(y))
+#define max(x,y) ((x)>(y)?(x):(y))
+
+typedef struct w_creator_s {
+ const char *type;
+ const char *title; // set to NULL to avoid exposing this widget type to user
+ ddb_gtkui_widget_t *(*create_func) (void);
+ struct w_creator_s *next;
+} w_creator_t;
+
+static w_creator_t *w_creators;
+
+typedef struct {
+ ddb_gtkui_widget_t base;
+} w_splitter_t;
+
+typedef struct {
+ ddb_gtkui_widget_t base;
+} w_box_t;
+
+typedef struct {
+ ddb_gtkui_widget_t base;
+} w_tabstrip_t;
+
+typedef struct {
+ ddb_gtkui_widget_t base;
+ DdbTabStrip *tabstrip;
+ DdbListview *list;
+} w_tabbed_playlist_t;
+
+typedef struct {
+ ddb_gtkui_widget_t base;
+} w_playlist_t;
+
+typedef struct {
+ ddb_gtkui_widget_t base;
+} w_placeholder_t;
+
+typedef struct {
+ ddb_gtkui_widget_t base;
+ int clicked_page;
+} w_tabs_t;
+
+typedef struct {
+ ddb_gtkui_widget_t base;
+ GtkWidget *tree;
+} w_selproperties_t;
+
+typedef struct {
+ ddb_gtkui_widget_t base;
+ GtkWidget *drawarea;
+} w_coverart_t;
+
+static int design_mode;
+static ddb_gtkui_widget_t *rootwidget;
+
+//// common functions
+
+void
+w_init (void) {
+ rootwidget = w_create ("box");
+}
+
+void
+w_free (void) {
+ w_creator_t *next = NULL;
+ for (w_creator_t *cr = w_creators; cr; cr = next) {
+ next = cr->next;
+ free (cr);
+ }
+ w_creators = NULL;
+}
+
+ddb_gtkui_widget_t *
+w_get_rootwidget (void) {
+ return rootwidget;
+}
+
+static void
+set_design_mode (ddb_gtkui_widget_t *w) {
+ for (ddb_gtkui_widget_t *c = w->children; c; c = c->next) {
+ set_design_mode (c);
+ }
+}
+
+void
+w_set_design_mode (int active) {
+ design_mode = active;
+ set_design_mode (rootwidget);
+}
+
+void
+w_append (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child) {
+ child->parent = cont;
+ if (!cont->children) {
+ cont->children = child;
+ }
+ else {
+ for (ddb_gtkui_widget_t *c = cont->children; c; c = c->next) {
+ if (!c->next) {
+ c->next = child;
+ break;
+ }
+ }
+ }
+
+ if (cont->append) {
+ cont->append (cont, child);
+ }
+}
+
+void
+w_remove (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child) {
+ if (cont->remove) {
+ cont->remove (cont, child);
+ }
+ child->widget = NULL;
+ ddb_gtkui_widget_t *prev = NULL;
+ for (ddb_gtkui_widget_t *c = cont->children; c; c = c->next) {
+ if (c == child) {
+ if (prev) {
+ prev->next = c->next;
+ }
+ else {
+ cont->children = c->next;
+ }
+ break;
+ }
+ prev = c;
+ }
+ child->parent = NULL;
+}
+
+void
+w_replace (ddb_gtkui_widget_t *w, ddb_gtkui_widget_t *from, ddb_gtkui_widget_t *to) {
+ if (w->replace) {
+ w->replace (w, from, to);
+ }
+ else {
+ w_remove (w, from);
+ w_destroy (from);
+ w_append (w, to);
+ }
+}
+
+const char *
+w_create_from_string (const char *s, ddb_gtkui_widget_t **parent) {
+ char t[MAX_TOKEN];
+ s = gettoken (s, t);
+ if (!s) {
+ return NULL;
+ }
+ ddb_gtkui_widget_t *w = w_create (t);
+ // nuke all default children
+ while (w->children) {
+ w_remove (w, w->children);
+ }
+
+ s = gettoken (s, t);
+ if (!s) {
+ w_destroy (w);
+ return NULL;
+ }
+ if (strcmp (t, "{")) {
+ w_destroy (w);
+ return NULL;
+ }
+
+ const char *back = s;
+ s = gettoken (s, t);
+ if (!s) {
+ w_destroy (w);
+ return NULL;
+ }
+ for (;;) {
+ if (!strcmp (t, "}")) {
+ break;
+ }
+
+ s = w_create_from_string (back, &w);
+ if (!s) {
+ w_destroy (w);
+ return NULL;
+ }
+
+ back = s;
+ s = gettoken (s, t);
+ if (!s) {
+ w_destroy (w);
+ return NULL;
+ }
+ }
+
+ if (*parent) {
+ w_append (*parent, w);
+ }
+ else {
+ *parent = w;
+ }
+ return s;
+}
+
+static ddb_gtkui_widget_t *current_widget;
+static int hidden = 0;
+
+gboolean
+w_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) {
+ if (hidden && user_data == current_widget) {
+ GdkColor clr = {
+ .red = 0x2d00,
+ .green = 0x0000,
+ .blue = 0xd600
+ };
+ GdkGC *gc = gdk_gc_new (widget->window);
+ gdk_gc_set_rgb_fg_color (gc, &clr);
+ if (GTK_WIDGET_NO_WINDOW (widget)) {
+ gdk_draw_rectangle (widget->window, gc, TRUE, widget->allocation.x, widget->allocation.y, widget->allocation.width, widget->allocation.height);
+ }
+ else {
+ gdk_draw_rectangle (widget->window, gc, TRUE, 0, 0, widget->allocation.width, widget->allocation.height);
+ }
+ g_object_unref (gc);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static char paste_buffer[1000];
+
+static void
+save_widget_to_string (char *str, ddb_gtkui_widget_t *w) {
+ strcat (str, w->type);
+ strcat (str, "{");
+ for (ddb_gtkui_widget_t *c = w->children; c; c = c->next) {
+ save_widget_to_string (str, c);
+ }
+ strcat (str, "} ");
+}
+
+void
+w_save (void) {
+ char buf[1000] = "";
+ save_widget_to_string (buf, rootwidget->children);
+ deadbeef->conf_set_str ("gtkui.layout", buf);
+ deadbeef->conf_save ();
+}
+
+static void
+on_replace_activate (GtkMenuItem *menuitem, gpointer user_data) {
+ for (w_creator_t *cr = w_creators; cr; cr = cr->next) {
+ if (cr->type == user_data) {
+ w_replace (current_widget->parent, current_widget, w_create (user_data));
+ }
+ }
+ w_save ();
+}
+
+static void
+on_delete_activate (GtkMenuItem *menuitem, gpointer user_data) {
+ ddb_gtkui_widget_t *parent = current_widget->parent;
+ if (!strcmp (current_widget->type, "placeholder")) {
+ return;
+ }
+ if (parent->replace) {
+ parent->replace (parent, current_widget, w_create ("placeholder"));
+ }
+ else {
+ w_remove (parent, current_widget);
+ w_destroy (current_widget);
+ current_widget = w_create ("placeholder");
+ w_append (parent, current_widget);
+ }
+ w_save ();
+}
+
+static void
+on_cut_activate (GtkMenuItem *menuitem, gpointer user_data) {
+ ddb_gtkui_widget_t *parent = current_widget->parent;
+ if (!strcmp (current_widget->type, "placeholder")) {
+ return;
+ }
+ // save hierarchy to string
+ // FIXME: use real clipboard
+ paste_buffer[0] = 0;
+ save_widget_to_string (paste_buffer, current_widget);
+
+ if (parent->replace) {
+ parent->replace (parent, current_widget, w_create ("placeholder"));
+ }
+ else {
+ w_remove (parent, current_widget);
+ w_destroy (current_widget);
+ current_widget = w_create ("placeholder");
+ w_append (parent, current_widget);
+ }
+ w_save ();
+}
+
+static void
+on_copy_activate (GtkMenuItem *menuitem, gpointer user_data) {
+ ddb_gtkui_widget_t *parent = current_widget->parent;
+ if (!strcmp (current_widget->type, "placeholder")) {
+ return;
+ }
+ // save hierarchy to string
+ // FIXME: use real clipboard
+ paste_buffer[0] = 0;
+ save_widget_to_string (paste_buffer, current_widget);
+}
+
+static void
+on_paste_activate (GtkMenuItem *menuitem, gpointer user_data) {
+ ddb_gtkui_widget_t *parent = current_widget->parent;
+ if (!paste_buffer[0]) {
+ return;
+ }
+ ddb_gtkui_widget_t *w = NULL;
+ w_create_from_string (paste_buffer, &w);
+ if (parent->replace) {
+ parent->replace (parent, current_widget, w);
+ }
+ else {
+ w_remove (parent, current_widget);
+ w_destroy (current_widget);
+ current_widget = w;
+ w_append (parent, current_widget);
+ }
+ w_save ();
+}
+
+void
+hide_widget (GtkWidget *widget, gpointer data) {
+ if (GTK_IS_CONTAINER (widget)) {
+ gtk_container_foreach (GTK_CONTAINER (widget), hide_widget, NULL);
+ }
+ gtk_widget_hide (widget);
+}
+
+void
+show_widget (GtkWidget *widget, gpointer data) {
+ if (GTK_IS_CONTAINER (widget)) {
+ gtk_container_foreach (GTK_CONTAINER (widget), show_widget, NULL);
+ }
+ gtk_widget_show (widget);
+}
+
+void
+w_menu_deactivate (GtkMenuShell *menushell, gpointer user_data) {
+ hidden = 0;
+ ddb_gtkui_widget_t *w = user_data;
+ if (GTK_IS_CONTAINER (w->widget)) {
+ gtk_container_foreach (GTK_CONTAINER (w->widget), show_widget, NULL);
+ }
+ gtk_widget_queue_draw (w->widget);
+}
+
+gboolean
+w_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data) {
+ if (!design_mode || event->button != 3) {
+ return FALSE;
+ }
+
+ current_widget = user_data;
+ hidden = 1;
+ if (GTK_IS_CONTAINER (widget)) {
+ gtk_container_foreach (GTK_CONTAINER (widget), hide_widget, NULL);
+ }
+ gtk_widget_queue_draw (((ddb_gtkui_widget_t *)user_data)->widget);
+ GtkWidget *menu;
+ GtkWidget *submenu;
+ GtkWidget *item;
+ menu = gtk_menu_new ();
+ if (strcmp (current_widget->type, "placeholder")) {
+ item = gtk_menu_item_new_with_mnemonic (_("Replace with..."));
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ }
+ else {
+ item = gtk_menu_item_new_with_mnemonic (_("Insert..."));
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ }
+
+ submenu = gtk_menu_new ();
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
+
+ for (w_creator_t *cr = w_creators; cr; cr = cr->next) {
+ if (cr->title) {
+ item = gtk_menu_item_new_with_mnemonic (cr->title);
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (submenu), item);
+ g_signal_connect ((gpointer) item, "activate",
+ G_CALLBACK (on_replace_activate),
+ (void *)cr->type);
+ }
+ }
+
+ if (strcmp (current_widget->type, "placeholder")) {
+ item = gtk_menu_item_new_with_mnemonic (_("Delete"));
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ g_signal_connect ((gpointer) item, "activate",
+ G_CALLBACK (on_delete_activate),
+ NULL);
+
+ item = gtk_menu_item_new_with_mnemonic (_("Cut"));
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ g_signal_connect ((gpointer) item, "activate",
+ G_CALLBACK (on_cut_activate),
+ NULL);
+
+ item = gtk_menu_item_new_with_mnemonic (_("Copy"));
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ g_signal_connect ((gpointer) item, "activate",
+ G_CALLBACK (on_copy_activate),
+ NULL);
+ }
+ item = gtk_menu_item_new_with_mnemonic ("Paste");
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ g_signal_connect ((gpointer) item, "activate",
+ G_CALLBACK (on_paste_activate),
+ NULL);
+
+ if (current_widget->initmenu) {
+ current_widget->initmenu (current_widget, menu);
+ }
+
+ g_signal_connect ((gpointer) menu, "deactivate", G_CALLBACK (w_menu_deactivate), user_data);
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, widget, 0, gtk_get_current_event_time());
+ return TRUE;
+}
+
+static void
+w_override_signals (GtkWidget *widget, gpointer user_data) {
+ g_signal_connect ((gpointer) widget, "button_press_event", G_CALLBACK (w_button_press_event), user_data);
+ g_signal_connect ((gpointer) widget, "expose_event", G_CALLBACK (w_expose_event), user_data);
+ if (GTK_IS_CONTAINER (widget)) {
+ gtk_container_forall (GTK_CONTAINER (widget), w_override_signals, user_data);
+ }
+}
+
+void
+w_reg_widget (const char *type, const char *title, ddb_gtkui_widget_t *(*create_func) (void)) {
+ w_creator_t *c;
+ for (c = w_creators; c; c = c->next) {
+ if (!strcmp (c->type, type)) {
+ fprintf (stderr, "gtkui w_reg_widget: widget type %s already registered\n", type);
+ return;
+ }
+ }
+ c = malloc (sizeof (w_creator_t));
+ memset (c, 0, sizeof (w_creator_t));
+ c->type = type;
+ c->title = title;
+ c->create_func = create_func;
+ c->next = w_creators;
+ w_creators = c;
+}
+
+void
+w_unreg_widget (const char *type) {
+ w_creator_t *c, *prev = NULL;
+ for (c = w_creators; c; c = c->next) {
+ if (!strcmp (c->type, type)) {
+ if (prev) {
+ prev->next = c->next;
+ }
+ else {
+ w_creators = c->next;
+ }
+ free (c);
+ return;
+ }
+ prev = c;
+ }
+ fprintf (stderr, "gtkui w_unreg_widget: widget type %s is not registered\n", type);
+}
+
+ddb_gtkui_widget_t *
+w_create (const char *type) {
+ for (w_creator_t *c = w_creators; c; c = c->next) {
+ if (!strcmp (c->type, type)) {
+ ddb_gtkui_widget_t *w = c->create_func ();
+ w->type = c->type;
+
+ return w;
+ }
+ }
+ return NULL;
+}
+
+void
+w_destroy (ddb_gtkui_widget_t *w) {
+ if (w->destroy) {
+ w->destroy (w);
+ }
+ if (w->widget) {
+ gtk_widget_destroy (w->widget);
+ }
+ free (w);
+}
+
+///// gtk_container convenience functions
+void
+w_container_add (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child) {
+ GtkWidget *container = NULL;
+ container = cont->widget;
+ gtk_container_add (GTK_CONTAINER (container), child->widget);
+ gtk_widget_show (child->widget);
+}
+
+void
+w_container_remove (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child) {
+ GtkWidget *container = NULL;
+ container = cont->widget;
+ gtk_container_remove (GTK_CONTAINER (container), child->widget);
+
+}
+
+////// placeholder widget
+
+gboolean
+w_placeholder_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) {
+ cairo_t *cr = gdk_cairo_create (widget->window);
+ cairo_set_source_rgb (cr, 255, 0, 0);
+ cairo_surface_t *checker;
+ cairo_t *cr2;
+
+ checker = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 12, 12);
+ cr2 = cairo_create (checker);
+
+ cairo_set_source_rgb (cr2, 0.5, 0.5 ,0.5);
+ cairo_paint (cr2);
+ cairo_set_source_rgb (cr2, 0, 0, 0);
+ cairo_move_to (cr2, 0, 0);
+ cairo_line_to (cr2, 12, 12);
+ cairo_move_to (cr2, 1, 12);
+ cairo_line_to (cr2, 12, 1);
+ cairo_set_line_width (cr2, 1);
+ cairo_set_antialias (cr2, CAIRO_ANTIALIAS_NONE);
+ cairo_stroke (cr2);
+ cairo_fill (cr2);
+ cairo_destroy (cr2);
+
+ cairo_set_source_surface (cr, checker, 0, 0);
+ cairo_pattern_t *pt = cairo_get_source(cr);
+ cairo_pattern_set_extend (pt, CAIRO_EXTEND_REPEAT);
+ cairo_rectangle (cr, 0, 0, widget->allocation.width, widget->allocation.height);
+ cairo_paint (cr);
+ cairo_surface_destroy (checker);
+ cairo_destroy (cr);
+ return FALSE;
+}
+
+ddb_gtkui_widget_t *
+w_placeholder_create (void) {
+ w_placeholder_t *w = malloc (sizeof (w_placeholder_t));
+ memset (w, 0, sizeof (w_placeholder_t));
+ w->base.widget = gtk_drawing_area_new ();
+ gtk_widget_set_events (w->base.widget, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
+ g_signal_connect ((gpointer) w->base.widget, "expose_event", G_CALLBACK (w_expose_event), w);
+ g_signal_connect_after ((gpointer) w->base.widget, "expose_event", G_CALLBACK (w_placeholder_expose_event), w);
+ g_signal_connect ((gpointer) w->base.widget, "button_press_event", G_CALLBACK (w_button_press_event), w);
+ return (ddb_gtkui_widget_t*)w;
+}
+
+////// vsplitter widget
+void
+w_splitter_replace (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child, ddb_gtkui_widget_t *newchild) {
+ int ntab = 0;
+ ddb_gtkui_widget_t *prev = NULL;
+ for (ddb_gtkui_widget_t *c = cont->children; c; c = c->next, ntab++) {
+ if (c == child) {
+ newchild->next = c->next;
+ if (prev) {
+ prev->next = newchild;
+ }
+ else {
+ cont->children = newchild;
+ }
+ newchild->parent = cont;
+ gtk_container_remove (GTK_CONTAINER(cont->widget), c->widget);
+ c->widget = NULL;
+ w_destroy (c);
+ gtk_widget_show (newchild->widget);
+ if (ntab == 0) {
+ gtk_paned_add1 (GTK_PANED (cont->widget), newchild->widget);
+ }
+ else {
+ gtk_paned_add2 (GTK_PANED (cont->widget), newchild->widget);
+ }
+ break;
+ }
+ prev = c;
+ }
+}
+
+ddb_gtkui_widget_t *
+w_vsplitter_create (void) {
+ w_splitter_t *w = malloc (sizeof (w_splitter_t));
+ memset (w, 0, sizeof (w_splitter_t));
+ w->base.widget = gtk_vpaned_new ();
+ w->base.append = w_container_add;
+ w->base.remove = w_container_remove;
+ w->base.replace = w_splitter_replace;
+
+ ddb_gtkui_widget_t *ph1, *ph2;
+ ph1 = w_create ("placeholder");
+ ph2 = w_create ("placeholder");
+ g_signal_connect ((gpointer) w->base.widget, "expose_event", G_CALLBACK (w_expose_event), w);
+ g_signal_connect ((gpointer) w->base.widget, "button_press_event", G_CALLBACK (w_button_press_event), w);
+
+ w_append ((ddb_gtkui_widget_t*)w, ph1);
+ w_append ((ddb_gtkui_widget_t*)w, ph2);
+
+ return (ddb_gtkui_widget_t*)w;
+}
+
+////// hsplitter widget
+
+ddb_gtkui_widget_t *
+w_hsplitter_create (void) {
+ w_splitter_t *w = malloc (sizeof (w_splitter_t));
+ memset (w, 0, sizeof (w_splitter_t));
+ w->base.widget = gtk_hpaned_new ();
+ w->base.append = w_container_add;
+ w->base.remove = w_container_remove;
+ w->base.replace = w_splitter_replace;
+
+ ddb_gtkui_widget_t *ph1, *ph2;
+ ph1 = w_create ("placeholder");
+ ph2 = w_create ("placeholder");
+ g_signal_connect ((gpointer) w->base.widget, "expose_event", G_CALLBACK (w_expose_event), w);
+ g_signal_connect ((gpointer) w->base.widget, "button_press_event", G_CALLBACK (w_button_press_event), w);
+
+ w_append ((ddb_gtkui_widget_t*)w, ph1);
+ w_append ((ddb_gtkui_widget_t*)w, ph2);
+
+ return (ddb_gtkui_widget_t*)w;
+}
+
+///// tabs widget
+static gboolean
+tab_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data);
+
+static void
+on_remove_tab_activate (GtkMenuItem *menuitem, gpointer user_data) {
+ w_tabs_t *w = user_data;
+
+ int i = 0;
+ for (ddb_gtkui_widget_t *c = w->base.children; c; c = c->next, i++) {
+ if (i == w->clicked_page) {
+ w_remove ((ddb_gtkui_widget_t *)w, c);
+ return;
+ }
+ }
+}
+
+static void
+on_add_tab_activate (GtkMenuItem *menuitem, gpointer user_data) {
+ w_tabs_t *w = user_data;
+
+ ddb_gtkui_widget_t *ph;
+ ph = w_create ("placeholder");
+ w_append ((ddb_gtkui_widget_t*)w, ph);
+
+ int i = 0;
+ for (ddb_gtkui_widget_t *c = w->base.children; c; c = c->next, i++);
+ w->clicked_page = i-1;
+ gtk_notebook_set_page (GTK_NOTEBOOK (w->base.widget), w->clicked_page);
+
+}
+
+static void
+on_move_tab_left_activate (GtkMenuItem *menuitem, gpointer user_data) {
+ w_tabs_t *w = user_data;
+ if (w->clicked_page <= 0) {
+ return;
+ }
+
+ // remove and save widget
+ int i = 0;
+ ddb_gtkui_widget_t *newchild = NULL;
+ ddb_gtkui_widget_t *prev = NULL;
+ for (ddb_gtkui_widget_t *c = w->base.children; c; c = c->next, i++) {
+ if (i == w->clicked_page) {
+ char buf[1000] = "";
+ save_widget_to_string (buf, c);
+ w_create_from_string (buf, &newchild);
+
+ w_remove ((ddb_gtkui_widget_t *)w, c);
+ break;
+ }
+ }
+ if (!newchild) {
+ return;
+ }
+
+ // add new child at new position
+ i = 0;
+ prev = NULL;
+ for (ddb_gtkui_widget_t *c = w->base.children; c; c = c->next, i++) {
+ if (i == w->clicked_page-1) {
+ if (prev) {
+ newchild->next = prev->next;
+ prev->next = newchild;
+ }
+ else {
+ newchild->next = w->base.children;
+ w->base.children = newchild;
+ }
+ GtkWidget *eventbox = gtk_event_box_new ();
+ GtkWidget *label = gtk_label_new (newchild->type);
+ gtk_widget_show (eventbox);
+ g_object_set_data (G_OBJECT (eventbox), "owner", w);
+ g_signal_connect ((gpointer) eventbox, "button_press_event", G_CALLBACK (tab_button_press_event), newchild->widget);
+ gtk_widget_show (label);
+ gtk_container_add (GTK_CONTAINER (eventbox), label);
+ gtk_widget_show (newchild->widget);
+
+ gtk_notebook_insert_page (GTK_NOTEBOOK (w->base.widget), newchild->widget, eventbox, w->clicked_page-1);
+ gtk_notebook_set_page (GTK_NOTEBOOK (w->base.widget), w->clicked_page-1);
+ w->clicked_page--;
+ break;
+ }
+ prev = c;
+ }
+}
+
+static void
+on_move_tab_right_activate (GtkMenuItem *menuitem, gpointer user_data) {
+ w_tabs_t *w = user_data;
+
+ int i = 0;
+ for (ddb_gtkui_widget_t *c = w->base.children; c; c = c->next, i++);
+ if (w->clicked_page >= i)
+ return;
+
+ gtk_notebook_set_page (GTK_NOTEBOOK (w->base.widget), ++w->clicked_page);
+ on_move_tab_left_activate (menuitem, user_data);
+ gtk_notebook_set_page (GTK_NOTEBOOK (w->base.widget), ++w->clicked_page);
+}
+
+static gboolean
+tab_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data) {
+ if (event->button != 3) {
+ return FALSE;
+ }
+ // user_data is child widget
+ if (design_mode) {
+ w_tabs_t *w = (w_tabs_t *)g_object_get_data (G_OBJECT (widget), "owner");
+ GtkWidget *menu;
+ GtkWidget *item;
+ menu = gtk_menu_new ();
+
+ item = gtk_menu_item_new_with_mnemonic (_("Move tab left"));
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ g_signal_connect ((gpointer) item, "activate",
+ G_CALLBACK (on_move_tab_left_activate),
+ w);
+
+ item = gtk_menu_item_new_with_mnemonic (_("Move tab right"));
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ g_signal_connect ((gpointer) item, "activate",
+ G_CALLBACK (on_move_tab_right_activate),
+ w);
+
+ item = gtk_menu_item_new_with_mnemonic (_("Remove tab"));
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ g_signal_connect ((gpointer) item, "activate",
+ G_CALLBACK (on_remove_tab_activate),
+ w);
+
+ item = gtk_menu_item_new_with_mnemonic (_("Rename tab"));
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+
+ w->clicked_page = gtk_notebook_page_num (GTK_NOTEBOOK (w->base.widget), user_data);
+ gtk_notebook_set_page (GTK_NOTEBOOK (w->base.widget), w->clicked_page);
+
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, widget, 0, gtk_get_current_event_time());
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void
+w_tabs_add (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child) {
+ GtkWidget *eventbox = gtk_event_box_new ();
+ GtkWidget *label = gtk_label_new (child->type);
+ gtk_widget_show (eventbox);
+ g_object_set_data (G_OBJECT (eventbox), "owner", cont);
+ g_signal_connect ((gpointer) eventbox, "button_press_event", G_CALLBACK (tab_button_press_event), child->widget);
+ gtk_widget_show (label);
+ gtk_container_add (GTK_CONTAINER (eventbox), label);
+ gtk_widget_show (child->widget);
+ gtk_notebook_append_page (GTK_NOTEBOOK (cont->widget), child->widget, eventbox);
+}
+
+void
+w_tabs_replace (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child, ddb_gtkui_widget_t *newchild) {
+ int ntab = 0;
+ ddb_gtkui_widget_t *prev = NULL;
+ for (ddb_gtkui_widget_t *c = cont->children; c; prev = c, c = c->next, ntab++) {
+ if (c == child) {
+ newchild->next = c->next;
+ if (prev) {
+ prev->next = newchild;
+ }
+ else {
+ cont->children = newchild;
+ }
+ newchild->parent = cont;
+ gtk_notebook_remove_page (GTK_NOTEBOOK(cont->widget), ntab);
+ c->widget = NULL;
+ w_destroy (c);
+ GtkWidget *eventbox = gtk_event_box_new ();
+ GtkWidget *label = gtk_label_new (newchild->type);
+ gtk_widget_show (eventbox);
+ g_object_set_data (G_OBJECT (eventbox), "owner", cont);
+ g_signal_connect ((gpointer) eventbox, "button_press_event", G_CALLBACK (tab_button_press_event), newchild->widget);
+ gtk_widget_show (label);
+ gtk_container_add (GTK_CONTAINER (eventbox), label);
+ gtk_widget_show (newchild->widget);
+ int pos = gtk_notebook_insert_page (GTK_NOTEBOOK (cont->widget), newchild->widget, eventbox, ntab);
+ gtk_notebook_set_page (GTK_NOTEBOOK (cont->widget), pos);
+ break;
+ }
+ }
+}
+
+void
+w_tabs_initmenu (struct ddb_gtkui_widget_s *w, GtkWidget *menu) {
+ GtkWidget *item;
+ item = gtk_menu_item_new_with_mnemonic (_("Add new tab"));
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ g_signal_connect ((gpointer) item, "activate",
+ G_CALLBACK (on_add_tab_activate),
+ w);
+}
+
+ddb_gtkui_widget_t *
+w_tabs_create (void) {
+ w_tabs_t *w = malloc (sizeof (w_tabs_t));
+ memset (w, 0, sizeof (w_tabs_t));
+ w->base.widget = gtk_notebook_new ();
+ w->base.append = w_tabs_add;
+ w->base.remove = w_container_remove;
+ w->base.replace = w_tabs_replace;
+ w->base.initmenu = w_tabs_initmenu;
+
+ ddb_gtkui_widget_t *ph1, *ph2, *ph3;
+ ph1 = w_create ("placeholder");
+ ph2 = w_create ("placeholder");
+ ph3 = w_create ("placeholder");
+
+ g_signal_connect ((gpointer) w->base.widget, "expose_event", G_CALLBACK (w_expose_event), w);
+ g_signal_connect ((gpointer) w->base.widget, "button_press_event", G_CALLBACK (w_button_press_event), w);
+
+ w_append ((ddb_gtkui_widget_t*)w, ph1);
+ w_append ((ddb_gtkui_widget_t*)w, ph2);
+ w_append ((ddb_gtkui_widget_t*)w, ph3);
+
+ return (ddb_gtkui_widget_t*)w;
+}
+
+//// box widget
+//// this widget should not be exposed to user, it is used as a top level
+//// container (rootwidget)
+
+ddb_gtkui_widget_t *
+w_box_create (void) {
+ w_box_t *w = malloc (sizeof (w_box_t));
+ memset (w, 0, sizeof (w_box_t));
+ w->base.widget = gtk_vbox_new (FALSE, 0);
+ w->base.append = w_container_add;
+ w->base.remove = w_container_remove;
+
+ return (ddb_gtkui_widget_t*)w;
+}
+
+//// tabstrip widget
+
+ddb_gtkui_widget_t *
+w_tabstrip_create (void) {
+ w_tabstrip_t *w = malloc (sizeof (w_tabstrip_t));
+ memset (w, 0, sizeof (w_tabstrip_t));
+ w->base.widget = ddb_tabstrip_new ();
+ w_override_signals (w->base.widget, w);
+ return (ddb_gtkui_widget_t*)w;
+}
+
+//// tabbed playlist widget
+
+typedef struct {
+ ddb_gtkui_widget_t *w;
+ DB_playItem_t *trk;
+} w_trackdata_t;
+
+static gboolean
+trackinfochanged_cb (gpointer p) {
+ w_trackdata_t *d = p;
+ w_tabbed_playlist_t *tp = (w_tabbed_playlist_t *)d->w;
+ ddb_playlist_t *plt = deadbeef->plt_get_curr ();
+ if (plt) {
+ int idx = deadbeef->plt_get_item_idx (plt, (DB_playItem_t *)d->trk, PL_MAIN);
+ if (idx != -1) {
+ ddb_listview_draw_row (tp->list, idx, (DdbListviewIter)d->trk);
+ }
+ deadbeef->plt_unref (plt);
+ }
+ if (d->trk) {
+ deadbeef->pl_item_unref (d->trk);
+ }
+ free (d);
+ return FALSE;
+}
+
+static gboolean
+paused_cb (gpointer p) {
+ w_tabbed_playlist_t *tp = (w_tabbed_playlist_t *)p;
+ DB_playItem_t *curr = deadbeef->streamer_get_playing_track ();
+ if (curr) {
+ int idx = deadbeef->pl_get_idx_of (curr);
+ ddb_listview_draw_row (tp->list, idx, (DdbListviewIter)curr);
+ deadbeef->pl_item_unref (curr);
+ }
+ return FALSE;
+}
+
+static gboolean
+refresh_cb (gpointer p) {
+ w_tabbed_playlist_t *tp = (w_tabbed_playlist_t *)p;
+ ddb_listview_clear_sort (tp->list);
+ ddb_listview_refresh (tp->list, DDB_REFRESH_LIST | DDB_REFRESH_VSCROLL);
+ return FALSE;
+}
+
+
+static gboolean
+playlistswitch_cb (gpointer p) {
+ w_tabbed_playlist_t *tp = (w_tabbed_playlist_t *)p;
+ int curr = deadbeef->plt_get_curr_idx ();
+ char conf[100];
+ snprintf (conf, sizeof (conf), "playlist.scroll.%d", curr);
+ int scroll = deadbeef->conf_get_int (conf, 0);
+ snprintf (conf, sizeof (conf), "playlist.cursor.%d", curr);
+ int cursor = deadbeef->conf_get_int (conf, -1);
+ ddb_tabstrip_refresh (tp->tabstrip);
+ deadbeef->pl_set_cursor (PL_MAIN, cursor);
+ if (cursor != -1) {
+ DB_playItem_t *it = deadbeef->pl_get_for_idx_and_iter (cursor, PL_MAIN);
+ if (it) {
+ deadbeef->pl_set_selected (it, 1);
+ deadbeef->pl_item_unref (it);
+ }
+ }
+
+ ddb_listview_refresh (tp->list, DDB_LIST_CHANGED | DDB_REFRESH_LIST | DDB_REFRESH_VSCROLL);
+ ddb_listview_set_vscroll (tp->list, scroll);
+ return FALSE;
+}
+
+struct fromto_t {
+ ddb_gtkui_widget_t *w;
+ DB_playItem_t *from;
+ DB_playItem_t *to;
+};
+
+static gboolean
+songchanged_cb (gpointer p) {
+ struct fromto_t *ft = p;
+ DB_playItem_t *from = ft->from;
+ DB_playItem_t *to = ft->to;
+ w_tabbed_playlist_t *tp = (w_tabbed_playlist_t *)ft->w;
+ int to_idx = -1;
+ if (!ddb_listview_is_scrolling (tp->list) && to) {
+ int cursor_follows_playback = deadbeef->conf_get_int ("playlist.scroll.cursorfollowplayback", 0);
+ int scroll_follows_playback = deadbeef->conf_get_int ("playlist.scroll.followplayback", 0);
+ int plt = deadbeef->streamer_get_current_playlist ();
+ if (plt != -1) {
+ if (cursor_follows_playback && plt != deadbeef->plt_get_curr_idx ()) {
+ deadbeef->plt_set_curr_idx (plt);
+ }
+ to_idx = deadbeef->pl_get_idx_of (to);
+ if (to_idx != -1) {
+ if (cursor_follows_playback) {
+ ddb_listview_set_cursor_noscroll (tp->list, to_idx);
+ }
+ if (scroll_follows_playback && plt == deadbeef->plt_get_curr_idx ()) {
+ ddb_listview_scroll_to (tp->list, to_idx);
+ }
+ }
+ }
+ }
+
+ if (from) {
+ int idx = deadbeef->pl_get_idx_of (from);
+ if (idx != -1) {
+ ddb_listview_draw_row (tp->list, idx, from);
+ }
+ }
+ if (to && to_idx != -1) {
+ ddb_listview_draw_row (tp->list, to_idx, to);
+ }
+ if (ft->from) {
+ deadbeef->pl_item_unref (ft->from);
+ }
+ if (ft->to) {
+ deadbeef->pl_item_unref (ft->to);
+ }
+ free (ft);
+ return FALSE;
+}
+
+static int
+w_tabbed_playlist_message (ddb_gtkui_widget_t *w, uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) {
+ w_tabbed_playlist_t *tp = (w_tabbed_playlist_t *)w;
+ switch (id) {
+ case DB_EV_SONGCHANGED:
+ g_idle_add (redraw_queued_tracks_cb, tp->list);
+ ddb_event_trackchange_t *ev = (ddb_event_trackchange_t *)ctx;
+ struct fromto_t *ft = malloc (sizeof (struct fromto_t));
+ ft->from = ev->from;
+ ft->to = ev->to;
+ if (ft->from) {
+ deadbeef->pl_item_ref (ft->from);
+ }
+ if (ft->to) {
+ deadbeef->pl_item_ref (ft->to);
+ }
+ ft->w = w;
+ g_idle_add (songchanged_cb, ft);
+ break;
+ case DB_EV_TRACKINFOCHANGED:
+ {
+ ddb_event_track_t *ev = (ddb_event_track_t *)ctx;
+ if (ev->track) {
+ deadbeef->pl_item_ref (ev->track);
+ }
+ w_trackdata_t *d = malloc (sizeof (w_trackdata_t));
+ memset (d, 0, sizeof (w_trackdata_t));
+ d->w = w;
+ d->trk = ev->track;
+ g_idle_add (trackinfochanged_cb, d);
+ }
+ break;
+ case DB_EV_PAUSED:
+ g_idle_add (paused_cb, w);
+ break;
+ case DB_EV_PLAYLISTCHANGED:
+ g_idle_add (refresh_cb, w);
+ break;
+ case DB_EV_PLAYLISTSWITCHED:
+ g_idle_add (playlistswitch_cb, w);
+ break;
+ }
+ return 0;
+}
+
+ddb_gtkui_widget_t *
+w_tabbed_playlist_create (void) {
+ w_tabbed_playlist_t *w = malloc (sizeof (w_tabbed_playlist_t));
+ memset (w, 0, sizeof (w_tabbed_playlist_t));
+
+ GtkWidget *vbox = gtk_vbox_new (FALSE, 0);
+ w->base.widget = vbox;
+ gtk_widget_show (vbox);
+
+ GtkWidget *tabstrip = ddb_tabstrip_new ();
+ w->tabstrip = (DdbTabStrip *)tabstrip;
+ gtk_widget_show (tabstrip);
+ GtkWidget *list = ddb_listview_new ();
+ w->list = (DdbListview *)list;
+ gtk_widget_show (list);
+ GtkWidget *frame = gtk_frame_new (NULL);
+ gtk_widget_show (frame);
+
+ gtk_box_pack_start (GTK_BOX (vbox), tabstrip, FALSE, TRUE, 0);
+ gtk_widget_set_size_request (tabstrip, -1, 24);
+ GTK_WIDGET_UNSET_FLAGS (tabstrip, GTK_CAN_FOCUS);
+ GTK_WIDGET_UNSET_FLAGS (tabstrip, GTK_CAN_DEFAULT);
+
+ gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (frame), 1);
+
+ gtk_container_add (GTK_CONTAINER (frame), list);
+ main_playlist_init (list);
+ if (deadbeef->conf_get_int ("gtkui.headers.visible", 1)) {
+ ddb_listview_show_header (w->list, 1);
+ }
+ else {
+ ddb_listview_show_header (w->list, 0);
+ }
+
+ gtk_container_forall (GTK_CONTAINER (w->base.widget), w_override_signals, w);
+
+ w->base.message = w_tabbed_playlist_message;
+ return (ddb_gtkui_widget_t*)w;
+}
+
+///// playlist widget
+
+ddb_gtkui_widget_t *
+w_playlist_create (void) {
+ w_playlist_t *w = malloc (sizeof (w_playlist_t));
+ memset (w, 0, sizeof (w_playlist_t));
+ w->base.widget = ddb_listview_new ();
+ main_playlist_init (w->base.widget);
+ if (deadbeef->conf_get_int ("gtkui.headers.visible", 1)) {
+ ddb_listview_show_header (DDB_LISTVIEW (w->base.widget), 1);
+ }
+ else {
+ ddb_listview_show_header (DDB_LISTVIEW (w->base.widget), 0);
+ }
+
+ w_override_signals (w->base.widget, w);
+
+ w->base.message = w_tabbed_playlist_message;
+ return (ddb_gtkui_widget_t*)w;
+}
+
+////// selection properties widget
+
+gboolean
+fill_selproperties_cb (gpointer data) {
+ w_selproperties_t *w = data;
+ DB_playItem_t **tracks = NULL;
+ int numtracks = 0;
+ deadbeef->pl_lock ();
+ int nsel = deadbeef->pl_getselcount ();
+ if (0 < nsel) {
+ tracks = malloc (sizeof (DB_playItem_t *) * nsel);
+ if (tracks) {
+ int n = 0;
+ DB_playItem_t *it = deadbeef->pl_get_first (PL_MAIN);
+ while (it) {
+ if (deadbeef->pl_is_selected (it)) {
+ assert (n < nsel);
+ deadbeef->pl_item_ref (it);
+ tracks[n++] = it;
+ }
+ DB_playItem_t *next = deadbeef->pl_get_next (it, PL_MAIN);
+ deadbeef->pl_item_unref (it);
+ it = next;
+ }
+ numtracks = nsel;
+ }
+ else {
+ deadbeef->pl_unlock ();
+ return FALSE;
+ }
+ }
+ GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (w->tree)));
+ trkproperties_fill_meta (store, tracks, numtracks);
+ if (tracks) {
+ for (int i = 0; i < numtracks; i++) {
+ deadbeef->pl_item_unref (tracks[i]);
+ }
+ free (tracks);
+ tracks = NULL;
+ numtracks = 0;
+ }
+ deadbeef->pl_unlock ();
+ return FALSE;
+}
+
+static int
+selproperties_message (ddb_gtkui_widget_t *w, uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) {
+ w_tabbed_playlist_t *tp = (w_tabbed_playlist_t *)w;
+ switch (id) {
+ case DB_EV_PLAYLISTCHANGED:
+ case DB_EV_SELCHANGED:
+ {
+ g_idle_add (fill_selproperties_cb, w);
+ }
+ break;
+ }
+ return 0;
+}
+
+ddb_gtkui_widget_t *
+w_selproperties_create (void) {
+ w_selproperties_t *w = malloc (sizeof (w_selproperties_t));
+ memset (w, 0, sizeof (w_selproperties_t));
+
+ w->base.widget = gtk_scrolled_window_new (NULL, NULL);
+ w->tree = gtk_tree_view_new ();
+ gtk_widget_show (w->tree);
+ gtk_container_add (GTK_CONTAINER (w->base.widget), w->tree);
+ w->base.message = selproperties_message;
+
+ GtkListStore *store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (w->tree), GTK_TREE_MODEL (store));
+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (w->tree), TRUE);
+
+ GtkCellRenderer *rend1 = gtk_cell_renderer_text_new ();
+ GtkCellRenderer *rend2 = gtk_cell_renderer_text_new ();
+ GtkTreeViewColumn *col1 = gtk_tree_view_column_new_with_attributes (_("Key"), rend1, "text", 0, NULL);
+ gtk_tree_view_column_set_resizable (col1, TRUE);
+ GtkTreeViewColumn *col2 = gtk_tree_view_column_new_with_attributes (_("Value"), rend2, "text", 1, NULL);
+ gtk_tree_view_column_set_resizable (col2, TRUE);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (w->tree), col1);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (w->tree), col2);
+ GtkCellRenderer *rend_propkey = gtk_cell_renderer_text_new ();
+ GtkCellRenderer *rend_propvalue = gtk_cell_renderer_text_new ();
+ gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW (w->tree), TRUE);
+ w_override_signals (w->base.widget, w);
+
+ return (ddb_gtkui_widget_t *)w;
+}
+
+///// cover art display
+void
+coverart_avail_callback (void *user_data) {
+ w_coverart_t *w = user_data;
+ gtk_widget_queue_draw (w->drawarea);
+}
+
+static gboolean
+coverart_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) {
+ DB_playItem_t *it = deadbeef->streamer_get_playing_track ();
+ if (!it) {
+ return FALSE;
+ }
+ int width = widget->allocation.width;
+ int height = widget->allocation.height;
+ const char *album = deadbeef->pl_find_meta (it, "album");
+ const char *artist = deadbeef->pl_find_meta (it, "artist");
+ if (!album || !*album) {
+ album = deadbeef->pl_find_meta (it, "title");
+ }
+ GdkPixbuf *pixbuf = get_cover_art_callb (deadbeef->pl_find_meta ((it), ":URI"), artist, album, min(width,height), coverart_avail_callback, user_data);
+ if (pixbuf) {
+ int pw = gdk_pixbuf_get_width (pixbuf);
+ int ph = gdk_pixbuf_get_height (pixbuf);
+ gdk_draw_pixbuf (widget->window, widget->style->white_gc, pixbuf, 0, 0, widget->allocation.width/2-pw/2, widget->allocation.height/2-ph/2, pw, ph, GDK_RGB_DITHER_NONE, 0, 0);
+ g_object_unref (pixbuf);
+ }
+ deadbeef->pl_item_unref (it);
+ return TRUE;
+}
+
+static gboolean
+coverart_redraw_cb (void *user_data) {
+ w_coverart_t *w = user_data;
+ gtk_widget_queue_draw (w->drawarea);
+ return FALSE;
+}
+
+static int
+coverart_message (ddb_gtkui_widget_t *w, uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) {
+ w_coverart_t *ca = (w_coverart_t *)w;
+ switch (id) {
+ case DB_EV_TRACKINFOCHANGED:
+ {
+ ddb_event_track_t *ev = (ddb_event_track_t *)ctx;
+ DB_playItem_t *it = deadbeef->streamer_get_playing_track ();
+ if (it == ev->track) {
+ g_idle_add (coverart_redraw_cb, w);
+ }
+ if (it) {
+ deadbeef->pl_item_unref (it);
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+ddb_gtkui_widget_t *
+w_coverart_create (void) {
+ w_coverart_t *w = malloc (sizeof (w_coverart_t));
+ memset (w, 0, sizeof (w_coverart_t));
+
+ w->base.widget = gtk_event_box_new ();
+ w->base.message = coverart_message;
+ w->drawarea = gtk_drawing_area_new ();
+ gtk_widget_show (w->drawarea);
+ gtk_container_add (GTK_CONTAINER (w->base.widget), w->drawarea);
+ g_signal_connect_after ((gpointer) w->drawarea, "expose_event", G_CALLBACK (coverart_expose_event), w);
+ w_override_signals (w->base.widget, w);
+ return (ddb_gtkui_widget_t *)w;
+}
diff --git a/plugins/gtkui/widgets.h b/plugins/gtkui/widgets.h
new file mode 100644
index 00000000..9263eb92
--- /dev/null
+++ b/plugins/gtkui/widgets.h
@@ -0,0 +1,87 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+#ifndef __WIDGETS_H
+#define __WIDGETS_H
+
+#include "gtkui_api.h"
+
+void
+w_init (void);
+
+void
+w_free (void);
+
+ddb_gtkui_widget_t *
+w_get_rootwidget (void);
+
+void
+w_set_design_mode (int active);
+
+void
+w_reg_widget (const char *type, const char *title, ddb_gtkui_widget_t *(*create_func) (void));
+
+void
+w_unreg_widget (const char *type);
+
+ddb_gtkui_widget_t *
+w_create (const char *type);
+
+const char *
+w_create_from_string (const char *s, ddb_gtkui_widget_t **parent);
+
+void
+w_destroy (ddb_gtkui_widget_t *w);
+
+void
+w_append (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child);
+
+void
+w_remove (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child);
+
+ddb_gtkui_widget_t *
+w_hsplitter_create (void);
+
+ddb_gtkui_widget_t *
+w_vsplitter_create (void);
+
+ddb_gtkui_widget_t *
+w_box_create (void);
+
+ddb_gtkui_widget_t *
+w_tabstrip_create (void);
+
+ddb_gtkui_widget_t *
+w_tabbed_playlist_create (void);
+
+ddb_gtkui_widget_t *
+w_playlist_create (void);
+
+ddb_gtkui_widget_t *
+w_placeholder_create (void);
+
+ddb_gtkui_widget_t *
+w_tabs_create (void);
+
+ddb_gtkui_widget_t *
+w_selproperties_create (void);
+
+ddb_gtkui_widget_t *
+w_coverart_create (void);
+
+#endif
diff --git a/plugins/medialib/Makefile.am b/plugins/medialib/Makefile.am
new file mode 100644
index 00000000..0406cac9
--- /dev/null
+++ b/plugins/medialib/Makefile.am
@@ -0,0 +1,8 @@
+if HAVE_MEDIALIB
+pkglib_LTLIBRARIES = medialib.la
+medialib_la_SOURCES = medialib.c
+medialib_la_LDFLAGS = -module
+
+medialib_la_LIBADD = $(LDADD)
+AM_CFLAGS = $(CFLAGS) -std=c99 -fPIC
+endif
diff --git a/plugins/medialib/medialib.c b/plugins/medialib/medialib.c
new file mode 100644
index 00000000..8a957156
--- /dev/null
+++ b/plugins/medialib/medialib.c
@@ -0,0 +1,256 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+#include <sys/time.h>
+#include <string.h>
+#include "../../deadbeef.h"
+
+DB_functions_t *deadbeef;
+
+typedef struct ml_string_s {
+ const char *text;
+ struct ml_string_s *next;
+} ml_string_t;
+
+typedef struct ml_entry_s {
+ const char *file;
+ const char *title;
+ int subtrack;
+ ml_string_t *artist;
+ ml_string_t *album;
+ ml_string_t *genre;
+ ml_string_t *folder;
+ struct ml_entry_s *next;
+} ml_entry_t;
+
+typedef struct {
+ ml_entry_t *tracks;
+
+ // index tables
+ ml_string_t *album;
+ ml_string_t *artist;
+ ml_string_t *genre;
+ ml_string_t *folder;
+} ml_db_t;
+
+#define REG_COL(col)\
+ml_string_t *\
+ml_reg_##col (ml_db_t *db, const char *col) {\
+ ml_string_t *s;\
+ int release = 0;\
+ if (!col) {\
+ col = deadbeef->metacache_add_string ("Unknown");\
+ release = 1;\
+ }\
+ for (s = db->col; s; s = s->next) {\
+ if (s->text == col) {\
+ if (release) {\
+ deadbeef->metacache_unref (col);\
+ }\
+ return s;\
+ }\
+ }\
+ if (!release) {\
+ deadbeef->metacache_ref (col);\
+ }\
+ s = malloc (sizeof (ml_string_t));\
+ memset (s, 0, sizeof (ml_string_t));\
+ s->text = col;\
+ s->next = db->col;\
+ db->col = s;\
+ return s;\
+}
+
+REG_COL(album);
+REG_COL(artist);
+REG_COL(genre);
+REG_COL(folder);
+
+DB_playItem_t *(*plt_insert_dir) (ddb_playlist_t *plt, DB_playItem_t *after, const char *dirname, int *pabort, int (*cb)(DB_playItem_t *it, void *data), void *user_data);
+
+uintptr_t tid;
+int scanner_terminate;
+
+static int
+add_file_info_cb (DB_playItem_t *it, void *data) {
+// fprintf (stderr, "added %s \r", deadbeef->pl_find_meta (it, ":URI"));
+ return 0;
+}
+
+static void
+scanner_thread (void *none) {
+ return;
+ // create invisible playlist
+ ddb_playlist_t *plt = deadbeef->plt_alloc ("scanner");
+
+ struct timeval tm1;
+ gettimeofday (&tm1, NULL);
+
+ plt_insert_dir (plt, NULL, "/backup/mus/en", &scanner_terminate, add_file_info_cb, NULL);
+
+ struct timeval tm2;
+ gettimeofday (&tm2, NULL);
+ int ms = (tm2.tv_sec*1000+tm2.tv_usec/1000) - (tm1.tv_sec*1000+tm1.tv_usec/1000);
+ fprintf (stderr, "initial scan time: %f seconds (%d tracks)\n", ms / 1000.f, deadbeef->plt_get_item_count (plt, PL_MAIN));
+
+ fprintf (stderr, "building index...\n");
+ gettimeofday (&tm1, NULL);
+ ml_db_t db;
+ memset (&db, 0, sizeof (db));
+
+ ml_entry_t *tail = NULL;
+
+ DB_playItem_t *it = deadbeef->plt_get_first (plt, PL_MAIN);
+ while (it) {
+
+ ml_entry_t *en = malloc (sizeof (ml_entry_t));
+ memset (en, 0, sizeof (ml_entry_t));
+
+ const char *uri = deadbeef->pl_find_meta (it, ":URI");
+ const char *title = deadbeef->pl_find_meta (it, "title");
+ const char *artist = deadbeef->pl_find_meta (it, "artist");
+ const char *album = deadbeef->pl_find_meta (it, "album");
+ const char *genre = deadbeef->pl_find_meta (it, "genre");
+
+ ml_string_t *alb = ml_reg_album (&db, album);
+ ml_string_t *art = ml_reg_artist (&db, artist);
+ ml_string_t *gnr = ml_reg_genre (&db, genre);
+
+ char *fn = strrchr (uri, '/');
+ ml_string_t *fld = NULL;
+ if (fn) {
+ char folder[fn-uri+1];
+ memcpy (folder, uri, fn-uri);
+ folder[fn-uri] = 0;
+ const char *s = deadbeef->metacache_add_string (folder);
+ fld = ml_reg_folder (&db, s);
+ deadbeef->metacache_unref (s); // there should be at least 1 ref left, so it's safe
+ }
+
+ deadbeef->metacache_ref (uri);
+ en->file = uri;
+ deadbeef->metacache_ref (title);
+ if (deadbeef->pl_get_item_flags (it) & DDB_IS_SUBTRACK) {
+ en->subtrack = deadbeef->pl_find_meta_int (it, ":TRACKNUM", -1);
+ }
+ else {
+ en->subtrack = -1;
+ }
+ en->title = title;
+ en->artist = art;
+ en->album = alb;
+ en->genre = gnr;
+ en->folder = fld;
+
+ if (tail) {
+ tail->next = en;
+ tail = en;
+ }
+ else {
+ tail = db.tracks = en;
+ }
+
+ DB_playItem_t *next = deadbeef->pl_get_next (it, PL_MAIN);
+ deadbeef->pl_item_unref (it);
+ it = next;
+ }
+ ms = (tm2.tv_sec*1000+tm2.tv_usec/1000) - (tm1.tv_sec*1000+tm1.tv_usec/1000);
+
+ int nalb = 0;
+ int nart = 0;
+ int ngnr = 0;
+ int nfld = 0;
+ ml_string_t *s;
+ for (s = db.album; s; s = s->next, nalb++);
+ for (s = db.artist; s; s = s->next, nart++);
+ for (s = db.genre; s; s = s->next, ngnr++);
+ for (s = db.folder; s; s = s->next, nfld++);
+
+ fprintf (stderr, "index build time: %f seconds (%d albums, %d artists, %d genres, %d folders)\n", ms / 1000.f, nalb, nart, ngnr, nfld);
+
+ deadbeef->plt_free (plt);
+}
+
+static int
+ml_connect (void) {
+ tid = deadbeef->thread_start_low_priority (scanner_thread, NULL);
+ return 0;
+}
+
+static int
+ml_stop (void) {
+ if (tid) {
+ scanner_terminate = 1;
+ deadbeef->thread_join (tid);
+ tid = 0;
+ }
+
+ return 0;
+}
+
+static int
+ml_message (uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) {
+ return 0;
+}
+
+typedef struct {
+ DB_misc_t plugin;
+} ddb_medialib_plugin_t;
+
+// define plugin interface
+static ddb_medialib_plugin_t plugin = {
+ .plugin.plugin.api_vmajor = 1,
+ .plugin.plugin.api_vminor = 0,
+ .plugin.plugin.version_major = 0,
+ .plugin.plugin.version_minor = 1,
+ .plugin.plugin.type = DB_PLUGIN_MISC,
+ .plugin.plugin.id = "medialib",
+ .plugin.plugin.name = "Media Library",
+ .plugin.plugin.descr = "Scans disk for music files and manages them as database",
+ .plugin.plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
+ .plugin.plugin.website = "http://deadbeef.sf.net",
+ .plugin.plugin.connect = ml_connect,
+ .plugin.plugin.stop = ml_stop,
+// .plugin.plugin.configdialog = settings_dlg,
+ .plugin.plugin.message = ml_message,
+};
+
+DB_plugin_t *
+medialib_load (DB_functions_t *api) {
+ deadbeef = api;
+
+ // hack: we need original function without overrides
+ plt_insert_dir = deadbeef->plt_insert_dir;
+ return DB_PLUGIN (&plugin);
+}
diff --git a/scripts/quickinstall.sh b/scripts/quickinstall.sh
index 0528ae7c..38f1ac7e 100755
--- a/scripts/quickinstall.sh
+++ b/scripts/quickinstall.sh
@@ -43,4 +43,5 @@ cp ./plugins/converter/.libs/converter_gtk2.so /usr/local/lib/deadbeef/
cp ./plugins/converter/.libs/converter_gtk3.so /usr/local/lib/deadbeef/
cp ./plugins/soundtouch/ddb_soundtouch.so /usr/local/lib/deadbeef/
cp ./plugins/vfs_zip/.libs/vfs_zip.so /usr/local/lib/deadbeef/
+cp ./plugins/medialib/.libs/medialib.so /usr/local/lib/deadbeef/
cp ./plugins/mono2stereo/.libs/ddb_mono2stereo.so /usr/local/lib/deadbeef/