summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac10
-rw-r--r--deadbeef.h16
-rw-r--r--metacache.c12
-rw-r--r--metacache.h6
-rw-r--r--playlist.c30
-rw-r--r--playlist.h10
-rw-r--r--plugins.c13
-rw-r--r--plugins/artwork/artwork.c19
-rw-r--r--plugins/gtkui/Makefile.am3
-rw-r--r--plugins/gtkui/callbacks.c54
-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.c34
-rw-r--r--plugins/gtkui/ddbcellrenderertextmultiline.h8
-rw-r--r--plugins/gtkui/ddbequalizer.c28
-rw-r--r--plugins/gtkui/ddbequalizer.h4
-rw-r--r--plugins/gtkui/ddblistview.c46
-rw-r--r--plugins/gtkui/ddbseekbar.c8
-rw-r--r--plugins/gtkui/ddbseekbar.h4
-rw-r--r--plugins/gtkui/ddbtabstrip.c37
-rw-r--r--plugins/gtkui/deadbeef.glade83
-rw-r--r--plugins/gtkui/fileman.c16
-rw-r--r--plugins/gtkui/gtkui.c178
-rw-r--r--plugins/gtkui/gtkui.h7
-rw-r--r--plugins/gtkui/gtkui_api.h27
-rw-r--r--plugins/gtkui/interface.c130
-rw-r--r--plugins/gtkui/mainplaylist.c26
-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.c1151
-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
40 files changed, 2117 insertions, 424 deletions
diff --git a/configure.ac b/configure.ac
index 99b78310..493926ec 100644
--- a/configure.ac
+++ b/configure.ac
@@ -108,6 +108,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])
if test "x$enable_staticlink" != "xno" ; then
AC_DEFINE_UNQUOTED([STATICLINK], [1], [Define if building static version])
@@ -549,7 +550,11 @@ if test "x$enable_converter" != "xno" ; then
fi
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"
+if test "x$enable_medialib" != "xno" ; then
+ HAVE_MEDIALIB=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/medialib"
AM_CONDITIONAL(HAVE_VORBIS, test "x$HAVE_VORBISPLUGIN" = "xyes")
AM_CONDITIONAL(HAVE_FLAC, test "x$HAVE_FLACPLUGIN" = "xyes")
@@ -592,6 +597,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")
AC_SUBST(PLUGINS_DIRS)
@@ -653,6 +659,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"])
echo
@@ -694,6 +701,7 @@ plugins/dsp_libsrc/Makefile
plugins/m3u/Makefile
plugins/vfs_zip/Makefile
plugins/converter/Makefile
+plugins/medialib/Makefile
intl/Makefile
po/Makefile.in
deadbeef.desktop
diff --git a/deadbeef.h b/deadbeef.h
index 10f50422..700b4a35 100644
--- a/deadbeef.h
+++ b/deadbeef.h
@@ -76,7 +76,7 @@ extern "C" {
// 0.1 -- deadbeef-0.2.0
#define DB_API_VERSION_MAJOR 1
-#define DB_API_VERSION_MINOR 1
+#define DB_API_VERSION_MINOR 2
#define DDB_PLUGIN_SET_API_VERSION\
.plugin.api_vmajor = DB_API_VERSION_MAJOR,\
@@ -267,6 +267,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
@@ -725,6 +728,17 @@ typedef struct {
int (*dsp_preset_load) (const char *fname, struct ddb_dsp_context_s **head);
int (*dsp_preset_save) (const char *fname, struct ddb_dsp_context_s *head);
void (*dsp_preset_free) (struct ddb_dsp_context_s *head);
+
+ // new 1.2 APIs
+ ddb_playlist_t *(*plt_alloc) (const char *title);
+ void (*plt_free) (ddb_playlist_t *plt);
+ //int (*plt_insert) (ddb_playlist_t *plt, int before);
+ void (*plt_set_fast_mode) (ddb_playlist_t *plt, int fast);
+ int (*plt_is_fast_mode) (ddb_playlist_t *plt);
+ const char * (*metacache_add_string) (const char *str);
+ void (*metacache_remove_string) (const char *str);
+ void (*metacache_ref) (const char *str);
+ void (*metacache_unref) (const char *str);
} DB_functions_t;
enum {
diff --git a/metacache.c b/metacache.c
index 84acaa91..13616516 100644
--- a/metacache.c
+++ b/metacache.c
@@ -114,3 +114,15 @@ metacache_remove_string (const char *str) {
chain = chain->next;
}
}
+
+void
+metacache_ref (const char *str) {
+ uint32_t *refc = (uint32_t)(str-5);
+ *refc++;
+}
+
+void
+metacache_unref (const char *str) {
+ uint32_t *refc = (uint32_t *)(str-5);
+ *refc--;
+}
diff --git a/metacache.h b/metacache.h
index b5187c0f..50c5cb7f 100644
--- a/metacache.h
+++ b/metacache.h
@@ -25,4 +25,10 @@ metacache_add_string (const char *str);
void
metacache_remove_string (const char *str);
+void
+metacache_ref (const char *str);
+
+void
+metacache_unref (const char *str);
+
#endif
diff --git a/playlist.c b/playlist.c
index 9aee5540..da4ea15f 100644
--- a/playlist.c
+++ b/playlist.c
@@ -327,6 +327,15 @@ plt_get_sel_count (int plt) {
return 0;
}
+playlist_t *
+plt_alloc (const char *title) {
+ playlist_t *plt = malloc (sizeof (playlist_t));
+ memset (plt, 0, sizeof (playlist_t));
+ plt->refc = 1;
+ plt->title = strdup (title);
+ return plt;
+}
+
int
plt_add (int before, const char *title) {
assert (before >= 0);
@@ -335,10 +344,7 @@ plt_add (int before, const char *title) {
fprintf (stderr, "can't create more than 100 playlists. sorry.\n");
return -1;
}
- playlist_t *plt = malloc (sizeof (playlist_t));
- memset (plt, 0, sizeof (playlist_t));
- plt->refc = 1;
- plt->title = strdup (title);
+ playlist_t *plt = plt_alloc (title);
plt_modified (plt);
LOCK;
@@ -398,7 +404,7 @@ plt_add (int before, const char *title) {
conf_save ();
messagepump_push (DB_EV_PLAYLISTSWITCHED, 0, 0, 0);
}
- return playlists_count-1;
+ return before;
}
// NOTE: caller must ensure that configuration is saved after that call
@@ -980,7 +986,7 @@ plt_process_cue_track (playlist_t *playlist, playItem_t *after, const char *fnam
pl_set_item_replaygain (it, DDB_REPLAYGAIN_TRACKPEAK, atof (replaygain_track_peak));
}
it->_flags |= DDB_IS_SUBTRACK | DDB_TAG_CUESHEET;
- after = pl_insert_item (after, it);
+ after = plt_insert_item (playlist, after, it);
pl_item_unref (it);
*prev = it;
return it;
@@ -2876,7 +2882,7 @@ pl_format_time (float t, char *dur, int size) {
}
}
else {
- strcpy (dur, "-:--");
+ strcpy (dur, "∞");
}
}
@@ -3897,3 +3903,13 @@ plt_init_shuffle_albums (playlist_t *plt, int r) {
}
pl_unlock ();
}
+
+void
+plt_set_fast_mode (playlist_t *plt, int fast) {
+ plt->fast_mode = (unsigned)fast;
+}
+
+int
+plt_is_fast_mode (playlist_t *plt) {
+ return plt->fast_mode;
+}
diff --git a/playlist.h b/playlist.h
index 23f74459..2f9a9d6a 100644
--- a/playlist.h
+++ b/playlist.h
@@ -56,6 +56,7 @@ typedef struct playlist_s {
int current_row[PL_MAX_ITERATORS]; // current row (cursor)
struct DB_metaInfo_s *meta; // linked list storing metainfo
int refc;
+ unsigned fast_mode : 1;
} playlist_t;
// global playlist control functions
@@ -92,6 +93,9 @@ plt_ref (playlist_t *plt);
void
plt_unref (playlist_t *plt);
+playlist_t *
+plt_alloc (const char *title);
+
void
plt_free (playlist_t *plt);
@@ -437,4 +441,10 @@ pl_get_playlist (playItem_t *it);
void
plt_init_shuffle_albums (playlist_t *plt, int r);
+void
+plt_set_fast_mode (playlist_t *plt, int fast);
+
+int
+plt_is_fast_mode (playlist_t *plt);
+
#endif // __PLAYLIST_H
diff --git a/plugins.c b/plugins.c
index 38abace1..23a9a1b1 100644
--- a/plugins.c
+++ b/plugins.c
@@ -45,6 +45,7 @@
#include "premix.h"
#include "dsppreset.h"
#include "pltmeta.h"
+#include "metacache.h"
#define trace(...) { fprintf(stderr, __VA_ARGS__); }
//#define trace(fmt,...)
@@ -316,7 +317,17 @@ static DB_functions_t deadbeef_api = {
// dsp preset management
.dsp_preset_load = dsp_preset_load,
.dsp_preset_save = dsp_preset_save,
- .dsp_preset_free = dsp_preset_free
+ .dsp_preset_free = dsp_preset_free,
+ // new 1.2 APIs
+ .plt_alloc = (ddb_playlist_t *(*)(const char *title))plt_alloc,
+ .plt_free = (void (*)(ddb_playlist_t *plt))plt_free,
+ //.plt_insert = plt_insert,
+ .plt_set_fast_mode = (void (*)(ddb_playlist_t *plt, int fast))plt_set_fast_mode,
+ .plt_is_fast_mode = (int (*)(ddb_playlist_t *plt))plt_is_fast_mode,
+ .metacache_add_string = metacache_add_string,
+ .metacache_remove_string = metacache_remove_string,
+ .metacache_ref = metacache_ref,
+ .metacache_unref = metacache_unref,
};
DB_functions_t *deadbeef = &deadbeef_api;
diff --git a/plugins/artwork/artwork.c b/plugins/artwork/artwork.c
index d603c06d..e395756d 100644
--- a/plugins/artwork/artwork.c
+++ b/plugins/artwork/artwork.c
@@ -117,6 +117,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
}
}
@@ -154,6 +157,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;
@@ -1044,6 +1050,7 @@ fetcher_thread (void *none)
}
if (param->callback) {
param->callback (param->fname, param->artist, param->album, param->user_data);
+ param->callback = NULL;
}
}
queue_pop ();
@@ -1098,16 +1105,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;
}
@@ -1126,6 +1142,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 329f14b2..7c82d4e5 100644
--- a/plugins/gtkui/Makefile.am
+++ b/plugins/gtkui/Makefile.am
@@ -36,7 +36,8 @@ GTKUI_SOURCES = gtkui.c gtkui.h\
dspconfig.c dspconfig.h\
tagwritersettings.c tagwritersettings.h\
wingeom.c wingeom.h\
- pluginconf.h
+ pluginconf.h\
+ widgets.c widgets.h
sdkdir = $(pkgincludedir)
sdk_HEADERS = gtkui_api.h
diff --git a/plugins/gtkui/callbacks.c b/plugins/gtkui/callbacks.c
index 4fdc73c3..ffff9a5a 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,...)
@@ -282,9 +283,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);
}
@@ -358,9 +358,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;
}
@@ -837,6 +834,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))) {
@@ -902,6 +901,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);
@@ -945,9 +946,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);
}
@@ -972,8 +972,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);
}
@@ -1132,9 +1131,7 @@ on_sort_by_title_activate (GtkMenuItem *menuitem,
deadbeef->plt_sort (plt, PL_MAIN, -1, "%t", 1);
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);
}
@@ -1146,9 +1143,7 @@ on_sort_by_track_nr_activate (GtkMenuItem *menuitem,
deadbeef->plt_sort (plt, PL_MAIN, -1, "%n", 1);
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);
}
@@ -1160,9 +1155,7 @@ on_sort_by_album_activate (GtkMenuItem *menuitem,
deadbeef->plt_sort (plt, PL_MAIN, -1, "%b", 1);
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);
}
@@ -1174,9 +1167,7 @@ on_sort_by_artist_activate (GtkMenuItem *menuitem,
deadbeef->plt_sort (plt, PL_MAIN, -1, "%a", 1);
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);
}
@@ -1188,9 +1179,7 @@ on_sort_by_date_activate (GtkMenuItem *menuitem,
deadbeef->plt_sort (plt, PL_MAIN, -1, "%y", 1);
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);
}
@@ -1224,11 +1213,18 @@ on_sort_by_custom_activate (GtkMenuItem *menuitem,
deadbeef->plt_sort (plt, PL_MAIN, -1, fmt, order == 0 ? 1 : 0);
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 fd92b376..1c407678 100644
--- a/plugins/gtkui/callbacks.h
+++ b/plugins/gtkui/callbacks.h
@@ -1155,3 +1155,7 @@ on_sort_by_custom_activate (GtkMenuItem *menuitem,
void
on_convert8to16_toggled (GtkToggleButton *togglebutton,
gpointer user_data);
+
+void
+on_design_mode1_activate (GtkMenuItem *menuitem,
+ gpointer user_data);
diff --git a/plugins/gtkui/coverart.c b/plugins/gtkui/coverart.c
index 4118aa66..e1dec261 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 689e0f80..aafec0d6 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 a6e95853..aff449b5 100644
--- a/plugins/gtkui/ddbcellrenderertextmultiline.c
+++ b/plugins/gtkui/ddbcellrenderertextmultiline.c
@@ -1,4 +1,4 @@
-/* ddbcellrenderertextmultiline.c generated by valac 0.10.2, the Vala compiler
+/* ddbcellrenderertextmultiline.c generated by valac, the Vala compiler
* generated from ddbcellrenderertextmultiline.vala, do not modify */
/*
@@ -25,8 +25,8 @@
#include <gtk/gtk.h>
#include <stdlib.h>
#include <string.h>
-#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
+#include <gdk/gdk.h>
#define DDB_TYPE_CELL_EDITABLE_TEXT_VIEW (ddb_cell_editable_text_view_get_type ())
@@ -84,16 +84,16 @@ 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
};
static gboolean ddb_cell_editable_text_view_real_key_press_event (GtkWidget* base, GdkEventKey* event);
-static void ddb_cell_editable_text_view_real_start_editing (GtkCellEditable* base, GdkEvent* event);
+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);
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
@@ -138,9 +138,8 @@ static gboolean ddb_cell_editable_text_view_real_key_press_event (GtkWidget* bas
}
-static void ddb_cell_editable_text_view_real_start_editing (GtkCellEditable* base, GdkEvent* event) {
- DdbCellEditableTextView * self;
- self = (DdbCellEditableTextView*) base;
+void ddb_cell_editable_text_view_start_editing (DdbCellEditableTextView* self, GdkEvent* event) {
+ g_return_if_fail (self != NULL);
g_return_if_fail (event != NULL);
}
@@ -166,7 +165,6 @@ static void ddb_cell_editable_text_view_class_init (DdbCellEditableTextViewClass
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);
- iface->start_editing = ddb_cell_editable_text_view_real_start_editing;
}
@@ -214,10 +212,10 @@ static void ddb_cell_renderer_text_multiline_gtk_cell_renderer_text_editing_done
buf = _g_object_ref0 (gtk_text_view_get_buffer ((GtkTextView*) entry));
gtk_text_buffer_get_iter_at_offset (buf, &begin, 0);
gtk_text_buffer_get_iter_at_offset (buf, &end, -1);
- new_text = gtk_text_buffer_get_text (buf, &begin, &end, TRUE);
+ new_text = g_strdup (gtk_text_buffer_get_text (buf, &begin, &end, TRUE));
g_signal_emit_by_name ((GtkCellRendererText*) _self_, "edited", entry->tree_path, new_text);
- _g_free0 (new_text);
_g_object_unref0 (buf);
+ _g_free0 (new_text);
}
@@ -242,14 +240,14 @@ static GtkCellEditable* ddb_cell_renderer_text_multiline_real_start_editing (Gtk
GtkListStore* store;
GtkTreeIter iter = {0};
GValue v = {0};
- GValue _tmp1_ = {0};
GValue _tmp2_;
+ GValue _tmp1_ = {0};
gint mult;
DdbCellEditableTextView* _tmp3_;
char* _tmp4_;
GtkTextBuffer* buf;
- char* _tmp5_ = NULL;
char* _tmp6_;
+ char* _tmp5_ = NULL;
gboolean _tmp7_;
self = (DdbCellRendererTextMultiline*) base;
g_return_val_if_fail (event != NULL, NULL);
@@ -273,8 +271,8 @@ static GtkCellEditable* ddb_cell_renderer_text_multiline_real_start_editing (Gtk
self->priv->entry->tree_path = (_tmp4_ = g_strdup (path), _g_free0 (self->priv->entry->tree_path), _tmp4_);
buf = gtk_text_buffer_new (NULL);
if ((_tmp7_ = (_tmp6_ = (g_object_get ((GtkCellRendererText*) self, "text", &_tmp5_, NULL), _tmp5_)) != NULL, _g_free0 (_tmp6_), _tmp7_)) {
- char* _tmp8_ = NULL;
char* _tmp9_;
+ char* _tmp8_ = NULL;
gtk_text_buffer_set_text (buf, _tmp9_ = (g_object_get ((GtkCellRendererText*) self, "text", &_tmp8_, NULL), _tmp8_), -1);
_g_free0 (_tmp9_);
}
@@ -284,11 +282,11 @@ static GtkCellEditable* ddb_cell_renderer_text_multiline_real_start_editing (Gtk
gtk_widget_set_size_request ((GtkWidget*) self->priv->entry, (*cell_area).width, (*cell_area).height);
gtk_widget_show ((GtkWidget*) self->priv->entry);
result = GTK_CELL_EDITABLE (self->priv->entry);
- _g_object_unref0 (buf);
- G_IS_VALUE (&v) ? (g_value_unset (&v), NULL) : NULL;
- _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 2fec6b26..55d4a82c 100644
--- a/plugins/gtkui/ddbcellrenderertextmultiline.h
+++ b/plugins/gtkui/ddbcellrenderertextmultiline.h
@@ -1,4 +1,4 @@
-/* ddbcellrenderertextmultiline.h generated by valac 0.10.2, the Vala compiler, do not modify */
+/* ddbcellrenderertextmultiline.h generated by valac, the Vala compiler, do not modify */
#ifndef __DDBCELLRENDERERTEXTMULTILINE_H__
@@ -8,6 +8,7 @@
#include <gtk/gtk.h>
#include <stdlib.h>
#include <string.h>
+#include <gdk/gdk.h>
G_BEGIN_DECLS
@@ -55,10 +56,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 7cd9ee4f..cf1c10eb 100644
--- a/plugins/gtkui/ddbequalizer.c
+++ b/plugins/gtkui/ddbequalizer.c
@@ -1,4 +1,4 @@
-/* ddbequalizer.c generated by valac 0.10.2, the Vala compiler
+/* ddbequalizer.c generated by valac, the Vala compiler
* generated from ddbequalizer.vala, do not modify */
/*
@@ -45,8 +45,8 @@ 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 _pango_font_description_free0(var) ((var == NULL) ? NULL : (var = (pango_font_description_free (var), NULL)))
struct _DdbEqualizer {
GtkDrawingArea parent_instance;
@@ -73,7 +73,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
@@ -82,8 +82,8 @@ enum {
#define DDB_EQUALIZER_spot_size 3
static gboolean ddb_equalizer_real_configure_event (GtkWidget* base, GdkEventConfigure* event);
static void ddb_equalizer_real_realize (GtkWidget* base);
-static gboolean ddb_equalizer_real_expose_event (GtkWidget* base, GdkEventExpose* event);
static inline double ddb_equalizer_scale (DdbEqualizer* self, double val);
+static gboolean ddb_equalizer_real_expose_event (GtkWidget* base, GdkEventExpose* event);
static gboolean ddb_equalizer_in_curve_area (DdbEqualizer* self, double x, double y);
static void ddb_equalizer_update_eq_drag (DdbEqualizer* self, double x, double y);
static gboolean ddb_equalizer_real_button_press_event (GtkWidget* base, GdkEventButton* event);
@@ -137,8 +137,8 @@ static gboolean ddb_equalizer_real_expose_event (GtkWidget* base, GdkEventExpose
gint width;
gint height;
GdkDrawable* d;
- GdkGCValues _tmp2_ = {0};
GdkGCValues _tmp3_;
+ GdkGCValues _tmp2_ = {0};
GdkGC* gc;
double step;
gint i = 0;
@@ -154,14 +154,14 @@ static gboolean ddb_equalizer_real_expose_event (GtkWidget* base, GdkEventExpose
char* _tmp10_;
const char* _tmp11_;
char* _tmp12_;
- GdkRectangle _tmp13_ = {0};
GdkRectangle _tmp14_;
+ GdkRectangle _tmp13_ = {0};
gint count;
- GdkRectangle _tmp16_ = {0};
GdkRectangle _tmp17_;
+ GdkRectangle _tmp16_ = {0};
gint bar_w;
- GdkRectangle _tmp22_ = {0};
GdkRectangle _tmp23_;
+ GdkRectangle _tmp22_ = {0};
self = (DdbEqualizer*) base;
fore_bright_color = (gtkui_get_bar_foreground_color (&_tmp0_), _tmp0_);
c1 = fore_bright_color;
@@ -328,8 +328,8 @@ static gboolean ddb_equalizer_real_expose_event (GtkWidget* base, GdkEventExpose
i = 0;
_tmp18_ = TRUE;
while (TRUE) {
- GdkRectangle _tmp19_ = {0};
GdkRectangle _tmp20_;
+ GdkRectangle _tmp19_ = {0};
if (!_tmp18_) {
i++;
}
@@ -363,12 +363,12 @@ static gboolean ddb_equalizer_real_expose_event (GtkWidget* base, GdkEventExpose
gdk_gc_set_line_attributes (gc, 1, GDK_LINE_ON_OFF_DASH, GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
gdk_draw_line (d, gc, self->priv->margin_left + 1, self->priv->mouse_y, width, self->priv->mouse_y);
result = FALSE;
- _g_free0 (tmp);
- _pango_font_description_free0 (fd);
- _g_object_unref0 (ctx);
- _g_object_unref0 (l);
- _g_object_unref0 (gc);
_g_object_unref0 (d);
+ _g_object_unref0 (gc);
+ _g_object_unref0 (l);
+ _g_object_unref0 (ctx);
+ _pango_font_description_free0 (fd);
+ _g_free0 (tmp);
return result;
}
diff --git a/plugins/gtkui/ddbequalizer.h b/plugins/gtkui/ddbequalizer.h
index 2ce2ba5c..b0493d52 100644
--- a/plugins/gtkui/ddbequalizer.h
+++ b/plugins/gtkui/ddbequalizer.h
@@ -1,4 +1,4 @@
-/* ddbequalizer.h generated by valac 0.10.2, the Vala compiler, do not modify */
+/* ddbequalizer.h generated by valac, the Vala compiler, do not modify */
#ifndef __DDBEQUALIZER_H__
@@ -33,7 +33,7 @@ struct _DdbEqualizerClass {
};
-GType ddb_equalizer_get_type (void) G_GNUC_CONST;
+GType ddb_equalizer_get_type (void);
void ddb_equalizer_set_band (DdbEqualizer* self, gint band, double v);
double ddb_equalizer_get_band (DdbEqualizer* self, gint band);
void ddb_equalizer_set_preamp (DdbEqualizer* self, double v);
diff --git a/plugins/gtkui/ddblistview.c b/plugins/gtkui/ddblistview.c
index b6140456..bc2ded0a 100644
--- a/plugins/gtkui/ddblistview.c
+++ b/plugins/gtkui/ddblistview.c
@@ -265,6 +265,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)
@@ -351,7 +359,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);
@@ -384,7 +394,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",
@@ -396,7 +406,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",
@@ -435,6 +445,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()
@@ -1413,6 +1427,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:
@@ -2415,7 +2430,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
@@ -2563,6 +2578,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);
@@ -2604,7 +2620,7 @@ ddb_listview_list_button_press_event (GtkWidget *widget,
UNREF (it);
}
}
- return FALSE;
+ return TRUE;
}
gboolean
@@ -2969,3 +2985,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 1ad285a7..d70ebc05 100644
--- a/plugins/gtkui/ddbseekbar.c
+++ b/plugins/gtkui/ddbseekbar.c
@@ -1,4 +1,4 @@
-/* ddbseekbar.c generated by valac 0.10.2, the Vala compiler
+/* ddbseekbar.c generated by valac, the Vala compiler
* generated from ddbseekbar.vala, do not modify */
/*
@@ -51,7 +51,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
};
@@ -138,8 +138,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 c975654e..28c69cd3 100644
--- a/plugins/gtkui/ddbseekbar.h
+++ b/plugins/gtkui/ddbseekbar.h
@@ -1,4 +1,4 @@
-/* ddbseekbar.h generated by valac 0.10.2, the Vala compiler, do not modify */
+/* ddbseekbar.h generated by valac, the Vala compiler, do not modify */
#ifndef __DDBSEEKBAR_H__
@@ -31,7 +31,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 f8f3e6c4..e1882d1e 100644
--- a/plugins/gtkui/ddbtabstrip.c
+++ b/plugins/gtkui/ddbtabstrip.c
@@ -25,7 +25,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, \
@@ -220,7 +220,6 @@ ddb_tabstrip_class_init(DdbTabStripClass *class)
widget_class->realize = ddb_tabstrip_realize;
widget_class->size_allocate = ddb_tabstrip_size_allocate;
widget_class->expose_event = on_tabstrip_expose_event;
- widget_class->button_press_event = on_tabstrip_button_press_event;
widget_class->button_release_event = on_tabstrip_button_release_event;
widget_class->configure_event = on_tabstrip_configure_event;
widget_class->motion_notify_event = on_tabstrip_motion_notify_event;
@@ -253,8 +252,6 @@ on_tabstrip_drag_data_received (GtkWidget *widget,
guint target_type,
guint time)
{
- DdbListview *ps = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
-
gchar *ptr=(char*)data->data;
if (target_type == 0) { // uris
// this happens when dropped from file manager
@@ -262,7 +259,7 @@ on_tabstrip_drag_data_received (GtkWidget *widget,
memcpy (mem, ptr, data->length);
mem[data->length] = 0;
// we don't pass control structure, but there's only one drag-drop view currently
- ps->binding->external_drag_n_drop (NULL, mem, data->length);
+ gtkui_receive_fm_drop (NULL, mem, data->length);
}
else if (target_type == 1) {
uint32_t *d= (uint32_t *)ptr;
@@ -271,7 +268,8 @@ on_tabstrip_drag_data_received (GtkWidget *widget,
int length = (data->length/4)-1;
ddb_playlist_t *p = deadbeef->plt_get_for_idx (plt);
if (p) {
- ps->binding->drag_n_drop (NULL, p, d, length, drag_context->action == GDK_ACTION_COPY ? 1 : 0);
+ //ps->binding->drag_n_drop (NULL, p, d, length, drag_context->action == GDK_ACTION_COPY ? 1 : 0);
+ main_drag_n_drop (NULL, p, d, length, drag_context->action == GDK_ACTION_COPY ? 1 : 0);
deadbeef->plt_unref (p);
}
}
@@ -283,16 +281,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() {
@@ -309,6 +307,9 @@ ddb_tabstrip_init(DdbTabStrip *tabstrip)
tabstrip->dragpt[1] = 0;
tabstrip->prev_x = 0;
tabstrip->movepos = 0;
+ g_signal_connect_after ((gpointer) tabstrip, "button_press_event",
+ G_CALLBACK (on_tabstrip_button_press_event),
+ NULL);
}
static int tab_clicked = -1;
@@ -713,8 +714,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);
@@ -845,7 +844,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 >= widget->allocation.width - arrow_widget_width) {
if (event->type == GDK_BUTTON_PRESS) {
@@ -853,7 +852,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) {
@@ -866,9 +865,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
@@ -904,21 +903,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 73759b65..926fa6ab 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>
@@ -444,6 +444,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>
@@ -472,7 +482,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>
@@ -482,7 +492,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>
@@ -493,7 +503,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>
@@ -528,7 +538,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>
@@ -538,7 +548,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>
@@ -627,7 +637,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>
@@ -687,7 +697,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>
@@ -708,7 +718,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>
@@ -928,47 +938,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>
@@ -980,8 +949,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 8947c821..4b1b6949 100644
--- a/plugins/gtkui/fileman.c
+++ b/plugins/gtkui/fileman.c
@@ -104,17 +104,15 @@ static void
open_files_worker (void *data) {
GSList *lst = (GSList *)data;
gtkpl_add_files (lst);
- 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);
@@ -164,13 +162,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;
}
@@ -182,7 +181,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 4dd222b1..a7378953 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,...)
@@ -337,7 +337,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 ();
@@ -352,14 +352,10 @@ redraw_queued_tracks (DdbListview *pl, int list) {
deadbeef->pl_unlock ();
}
-static gboolean
-redraw_queued_tracks_cb (gpointer nothing) {
- int iconified = gdk_window_get_state(mainwin->window) & 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);
+gboolean
+redraw_queued_tracks_cb (gpointer plt) {
+ DdbListview *list = plt;
+ redraw_queued_tracks (list);
return FALSE;
}
@@ -376,7 +372,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
@@ -415,8 +416,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");
@@ -441,22 +442,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 ();
}
@@ -473,26 +462,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;
}
@@ -825,40 +794,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;
@@ -882,8 +817,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);
}
@@ -941,11 +874,11 @@ volumebar_redraw (void) {
gdk_window_invalidate_rect (volumebar->window, 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;
@@ -970,8 +903,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);
@@ -991,9 +938,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;
@@ -1033,7 +980,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();
@@ -1074,16 +1058,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"));
@@ -1106,6 +1087,8 @@ gtkui_thread (void *ctx) {
gtk_main ();
+ w_free ();
+
if (refresh_timeout) {
g_source_remove (refresh_timeout);
refresh_timeout = 0;
@@ -1311,7 +1294,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;
}
@@ -1371,4 +1354,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 e2ed8dbf..f3b075d3 100644
--- a/plugins/gtkui/gtkui.h
+++ b/plugins/gtkui/gtkui.h
@@ -133,8 +133,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);
@@ -172,4 +172,7 @@ gtkui_get_curr_playlist_mod (void);
void
gtkui_trackinfochanged (DB_playItem_t *it);
+gboolean
+redraw_queued_tracks_cb (gpointer plt);
+
#endif
diff --git a/plugins/gtkui/gtkui_api.h b/plugins/gtkui/gtkui_api.h
index f20c411e..042c4fa5 100644
--- a/plugins/gtkui/gtkui_api.h
+++ b/plugins/gtkui/gtkui_api.h
@@ -25,9 +25,36 @@
#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);
+
+ 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 67d70dba..d09e9dc7 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;
@@ -78,6 +78,7 @@ create_mainwin (void)
GtkWidget *view_headers;
GtkWidget *view_tabs;
GtkWidget *view_eq;
+ GtkWidget *design_mode1;
GtkWidget *Playback;
GtkWidget *Playback_menu;
GtkWidget *Order;
@@ -101,16 +102,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;
@@ -125,9 +126,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;
@@ -161,9 +159,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);
@@ -174,17 +172,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);
@@ -222,9 +220,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);
@@ -237,9 +235,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);
@@ -270,9 +268,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);
@@ -348,6 +346,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);
@@ -366,16 +368,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));
@@ -394,11 +399,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));
@@ -445,9 +452,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);
@@ -475,17 +482,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);
@@ -580,27 +587,9 @@ create_mainwin (void)
GTK_WIDGET_UNSET_FLAGS (volumebar, GTK_CAN_FOCUS);
GTK_WIDGET_UNSET_FLAGS (volumebar, GTK_CAN_DEFAULT);
- 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_UNSET_FLAGS (tabstrip, GTK_CAN_FOCUS);
- GTK_WIDGET_UNSET_FLAGS (tabstrip, GTK_CAN_DEFAULT);
-
- 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_UNSET_FLAGS (playlist, GTK_CAN_FOCUS);
- GTK_WIDGET_UNSET_FLAGS (playlist, GTK_CAN_DEFAULT);
-
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);
@@ -711,6 +700,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);
@@ -785,12 +777,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");
@@ -798,18 +790,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");
@@ -828,6 +820,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");
@@ -849,16 +842,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");
@@ -873,9 +866,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 f04f9cb1..17083b7c 100644
--- a/plugins/gtkui/mainplaylist.c
+++ b/plugins/gtkui/mainplaylist.c
@@ -127,10 +127,11 @@ 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);
return TRUE;
}
return FALSE;
@@ -157,6 +158,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, GdkDrawable *drawable, DdbListviewIter it, int x, int y, int width, int height) {
@@ -251,6 +253,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,
@@ -287,7 +297,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,
@@ -329,8 +339,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));
@@ -347,9 +358,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 b17ef63d..56a076c1 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 41e3fdd8..5cc749d8 100644
--- a/plugins/gtkui/plcommon.c
+++ b/plugins/gtkui/plcommon.c
@@ -281,8 +281,7 @@ on_clear1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
deadbeef->pl_clear ();
- main_refresh ();
- search_refresh ();
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
void
@@ -290,8 +289,7 @@ on_remove1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
int cursor = deadbeef->pl_delete_selected ();
- main_refresh ();
- search_refresh ();
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
@@ -299,20 +297,16 @@ void
on_crop1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
deadbeef->pl_crop_selected ();
- 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 ();
- main_refresh ();
- search_refresh ();
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
void
@@ -348,8 +342,7 @@ on_remove_from_disk_activate (GtkMenuItem *menuitem,
int cursor = deadbeef->pl_delete_selected ();
deadbeef->pl_unlock ();
- main_refresh ();
- search_refresh ();
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
void
@@ -702,6 +695,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];
@@ -1034,14 +1037,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 6a3114c1..edd7d3f2 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 4f6207f4..d2d09300 100644
--- a/plugins/gtkui/prefwin.c
+++ b/plugins/gtkui/prefwin.c
@@ -860,8 +860,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);
}
@@ -876,8 +877,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);
}
@@ -892,8 +894,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
@@ -907,8 +910,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
@@ -922,8 +926,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
@@ -1084,8 +1089,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 e3d46819..d3665bf3 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 8dc5302d..5ff479ce 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, equals_ptr);
+ int n = get_field_value (val + ml, sizeof (val) - ml, key, deadbeef->pl_find_meta, 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 ccdaa69f..3604cccc 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..b3e1c32f
--- /dev/null
+++ b/plugins/gtkui/widgets.c
@@ -0,0 +1,1151 @@
+/*
+ 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;
+} 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);
+
+ 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");
+ 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");
+}
+
+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
+
+void
+w_tabs_add (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child) {
+ GtkWidget *label = gtk_label_new (child->type);
+ gtk_widget_show (label);
+ gtk_widget_show (child->widget);
+ gtk_notebook_append_page (GTK_NOTEBOOK (cont->widget), child->widget, label);
+}
+
+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; c = c->next, ntab++) {
+ if (c == child) {
+ newchild->next = c->next;
+ if (prev) {
+ prev->next = newchild;
+ }
+ else {
+ cont->children = newchild;
+ }
+ newchild->parent = cont;
+ w_destroy (c);
+ GtkWidget *label = gtk_label_new (newchild->type);
+ gtk_widget_show (label);
+ gtk_widget_show (newchild->widget);
+ int pos = gtk_notebook_insert_page (GTK_NOTEBOOK (cont->widget), newchild->widget, label, ntab);
+ gtk_notebook_set_page (GTK_NOTEBOOK (cont->widget), pos);
+ break;
+ }
+ }
+}
+
+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;
+
+ 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 20b89482..b7cda98b 100755
--- a/scripts/quickinstall.sh
+++ b/scripts/quickinstall.sh
@@ -42,3 +42,4 @@ cp ./plugins/converter/.libs/converter_gtkui.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/mono2stereo/mono2stereo.so /usr/local/lib/deadbeef/
+cp ./plugins/medialib/.libs/medialib.so /usr/local/lib/deadbeef/