/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
Copyright (C) 2009 Alexey Yakovenko
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, see .
*/
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include
#include
#include
#include
#include
#include "callbacks.h"
#include "interface.h"
#include "support.h"
#include "common.h"
#include "playlist.h"
#include "gtkplaylist.h"
#include "messagepump.h"
#include "messages.h"
#include "codec.h"
#include "playback.h"
#include "search.h"
#include "streamer.h"
#include "progress.h"
#include "volume.h"
#include "session.h"
#include "conf.h"
#include "plugins.h"
//#include "cmp3.h"
//#include "cvorbis.h"
//#include "cdumb.h"
//#include "cgme.h"
//#include "cflac.h"
//#include "csid.h"
extern GtkWidget *mainwin;
extern gtkplaylist_t main_playlist;
extern gtkplaylist_t search_playlist;
void
main_playlist_init (GtkWidget *widget) {
// init playlist control structure, and put it into widget user-data
memset (&main_playlist, 0, sizeof (main_playlist));
main_playlist.playlist = widget;
main_playlist.header = lookup_widget (mainwin, "header");
main_playlist.scrollbar = lookup_widget (mainwin, "playscroll");
main_playlist.hscrollbar = lookup_widget (mainwin, "playhscroll");
main_playlist.pcurr = &playlist_current_ptr;
main_playlist.pcount = &pl_count;
main_playlist.iterator = PL_MAIN;
main_playlist.multisel = 1;
main_playlist.scrollpos = 0;
main_playlist.hscrollpos = 0;
main_playlist.row = -1;
main_playlist.clicktime = -1;
main_playlist.nvisiblerows = 0;
//main_playlist.fmtcache = NULL;
// int colwidths[pl_ncolumns] = { 50, 150, 50, 150, 50 };
// memcpy (main_playlist.colwidths, colwidths, sizeof (colwidths));
main_playlist.colwidths = session_get_main_colwidths_ptr ();
gtk_object_set_data (GTK_OBJECT (main_playlist.playlist), "ps", &main_playlist);
gtk_object_set_data (GTK_OBJECT (main_playlist.header), "ps", &main_playlist);
gtk_object_set_data (GTK_OBJECT (main_playlist.scrollbar), "ps", &main_playlist);
gtk_object_set_data (GTK_OBJECT (main_playlist.hscrollbar), "ps", &main_playlist);
}
void
search_playlist_init (GtkWidget *widget) {
extern GtkWidget *searchwin;
// init playlist control structure, and put it into widget user-data
memset (&search_playlist, 0, sizeof (search_playlist));
search_playlist.playlist = widget;
search_playlist.header = lookup_widget (searchwin, "searchheader");
search_playlist.scrollbar = lookup_widget (searchwin, "searchscroll");
search_playlist.hscrollbar = lookup_widget (searchwin, "searchhscroll");
assert (search_playlist.header);
assert (search_playlist.scrollbar);
// main_playlist.pcurr = &search_current;
search_playlist.pcount = &search_count;
search_playlist.multisel = 0;
search_playlist.iterator = PL_SEARCH;
search_playlist.scrollpos = 0;
search_playlist.hscrollpos = 0;
search_playlist.row = -1;
search_playlist.clicktime = -1;
search_playlist.nvisiblerows = 0;
//search_playlist.fmtcache = NULL;
// int colwidths[pl_ncolumns] = { 0, 150, 50, 150, 50 };
// memcpy (search_playlist.colwidths, colwidths, sizeof (colwidths));
search_playlist.colwidths = session_get_search_colwidths_ptr ();
gtk_object_set_data (GTK_OBJECT (search_playlist.playlist), "ps", &search_playlist);
gtk_object_set_data (GTK_OBJECT (search_playlist.header), "ps", &search_playlist);
gtk_object_set_data (GTK_OBJECT (search_playlist.scrollbar), "ps", &search_playlist);
gtk_object_set_data (GTK_OBJECT (search_playlist.hscrollbar), "ps", &search_playlist);
}
// redraw
gboolean
on_playlist_expose_event (GtkWidget *widget,
GdkEventExpose *event,
gpointer user_data)
{
GTKPL_PROLOGUE;
// draw visible area of playlist
gtkpl_expose (ps, event->area.x, event->area.y, event->area.width, event->area.height);
return FALSE;
}
gboolean
on_playlist_button_press_event (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
GTKPL_PROLOGUE;
if (event->button == 1) {
gtkpl_mouse1_pressed (ps, event->state, event->x, event->y, event->time);
}
return FALSE;
}
gboolean
on_playlist_button_release_event (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
GTKPL_PROLOGUE;
if (event->button == 1) {
gtkpl_mouse1_released (ps, event->state, event->x, event->y, event->time);
}
return FALSE;
}
gboolean
on_playlist_motion_notify_event (GtkWidget *widget,
GdkEventMotion *event,
gpointer user_data)
{
GTKPL_PROLOGUE;
gtkpl_mousemove (ps, event);
return FALSE;
}
void
on_playscroll_value_changed (GtkRange *widget,
gpointer user_data)
{
GTKPL_PROLOGUE;
int newscroll = gtk_range_get_value (GTK_RANGE (widget));
gtkpl_scroll (ps, newscroll);
}
void
on_open_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
GtkWidget *dlg = gtk_file_chooser_dialog_new ("Open file(s)...", GTK_WINDOW (mainwin), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
GtkFileFilter* flt;
flt = gtk_file_filter_new ();
gtk_file_filter_set_name (flt, "Supported music files");
DB_decoder_t **codecs = plug_get_decoder_list ();
for (int i = 0; codecs[i]; i++) {
if (codecs[i]->exts && codecs[i]->insert) {
const char **exts = codecs[i]->exts;
if (exts) {
for (int e = 0; exts[e]; e++) {
char filter[20];
snprintf (filter, 20, "*.%s", exts[e]);
gtk_file_filter_add_pattern (flt, filter);
char *p;
for (p = filter; *p; p++) {
*p = toupper (*p);
}
gtk_file_filter_add_pattern (flt, filter);
}
}
}
}
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dlg), flt);
flt = gtk_file_filter_new ();
gtk_file_filter_set_name (flt, "Other files (*)");
gtk_file_filter_add_pattern (flt, "*");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dlg), TRUE);
// restore folder
gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), session_get_directory ());
int response = gtk_dialog_run (GTK_DIALOG (dlg));
// store folder
gchar *folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dlg));
if (folder) {
session_set_directory (folder);
g_free (folder);
}
if (response == GTK_RESPONSE_OK)
{
pl_free ();
GSList *lst = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (dlg));
gtk_widget_destroy (dlg);
if (lst) {
messagepump_push (M_OPENFILES, (uintptr_t)lst, 0, 0);
}
}
else {
gtk_widget_destroy (dlg);
}
}
void
on_add_files_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
GtkWidget *dlg = gtk_file_chooser_dialog_new ("Add file(s) to playlist...", GTK_WINDOW (mainwin), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
GtkFileFilter* flt;
flt = gtk_file_filter_new ();
gtk_file_filter_set_name (flt, "Supported music files");
DB_decoder_t **codecs = plug_get_decoder_list ();
for (int i = 0; codecs[i]; i++) {
if (codecs[i]->exts && codecs[i]->insert) {
const char **exts = codecs[i]->exts;
if (exts) {
for (int e = 0; exts[e]; e++) {
char filter[20];
snprintf (filter, 20, "*.%s", exts[e]);
gtk_file_filter_add_pattern (flt, filter);
char *p;
for (p = filter; *p; p++) {
*p = toupper (*p);
}
gtk_file_filter_add_pattern (flt, filter);
}
}
}
}
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dlg), flt);
flt = gtk_file_filter_new ();
gtk_file_filter_set_name (flt, "Other files (*)");
gtk_file_filter_add_pattern (flt, "*");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dlg), TRUE);
// restore folder
gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), session_get_directory ());
int response = gtk_dialog_run (GTK_DIALOG (dlg));
// store folder
gchar *folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dlg));
if (folder) {
session_set_directory (folder);
g_free (folder);
}
if (response == GTK_RESPONSE_OK)
{
GSList *lst = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (dlg));
gtk_widget_destroy (dlg);
if (lst) {
messagepump_push (M_ADDFILES, (uintptr_t)lst, 0, 0);
}
}
else {
gtk_widget_destroy (dlg);
}
}
void
on_add_folders_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
GtkWidget *dlg = gtk_file_chooser_dialog_new ("Add folder(s) to playlist...", GTK_WINDOW (mainwin), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
GtkFileFilter* flt;
flt = gtk_file_filter_new ();
gtk_file_filter_set_name (flt, "Supported music files");
DB_decoder_t **codecs = plug_get_decoder_list ();
for (int i = 0; codecs[i]; i++) {
if (codecs[i]->exts && codecs[i]->insert) {
const char **exts = codecs[i]->exts;
if (exts) {
for (int e = 0; exts[e]; e++) {
char filter[20];
snprintf (filter, 20, "*.%s", exts[e]);
gtk_file_filter_add_pattern (flt, filter);
char *p;
for (p = filter; *p; p++) {
*p = toupper (*p);
}
gtk_file_filter_add_pattern (flt, filter);
}
}
}
}
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dlg), flt);
flt = gtk_file_filter_new ();
gtk_file_filter_set_name (flt, "Other files (*)");
gtk_file_filter_add_pattern (flt, "*");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dlg), TRUE);
// restore folder
gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), session_get_directory ());
int response = gtk_dialog_run (GTK_DIALOG (dlg));
// store folder
gchar *folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dlg));
if (folder) {
session_set_directory (folder);
g_free (folder);
}
if (response == GTK_RESPONSE_OK)
{
gchar *folder = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
GSList *lst = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (dlg));
gtk_widget_destroy (dlg);
if (lst) {
messagepump_push (M_ADDDIRS, (uintptr_t)lst, 0, 0);
}
}
else {
gtk_widget_destroy (dlg);
}
}
void
on_preferences1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
}
void
on_quit_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
progress_abort ();
messagepump_push (M_TERMINATE, 0, 0, 0);
}
void
on_clear1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
pl_free ();
gtkplaylist_t *ps = &main_playlist;
GtkWidget *widget = ps->playlist;
gtkpl_setup_scrollbar (ps);
gtkpl_draw_playlist (ps, 0, 0, widget->allocation.width, widget->allocation.height);
gtkpl_expose (ps, 0, 0, widget->allocation.width, widget->allocation.height);
search_refresh ();
}
void
on_select_all1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
pl_select_all ();
gtkplaylist_t *ps = &main_playlist;
GtkWidget *widget = ps->playlist;
gtkpl_draw_playlist (ps, 0, 0, widget->allocation.width, widget->allocation.height);
gdk_draw_drawable (widget->window, widget->style->black_gc, ps->backbuf, 0, 0, 0, 0, widget->allocation.width, widget->allocation.height);
}
void
on_remove1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
gtkplaylist_t *ps = &main_playlist;
GtkWidget *widget = ps->playlist;
pl_delete_selected ();
gtkpl_setup_scrollbar (ps);
gtkpl_draw_playlist (ps, 0, 0, widget->allocation.width, widget->allocation.height);
gtkpl_expose (ps, 0, 0, widget->allocation.width, widget->allocation.height);
search_refresh ();
}
void
on_crop1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
gtkplaylist_t *ps = &main_playlist;
GtkWidget *widget = ps->playlist;
pl_crop_selected ();
gtkpl_setup_scrollbar (ps);
gtkpl_draw_playlist (ps, 0, 0, widget->allocation.width, widget->allocation.height);
gtkpl_expose (ps, 0, 0, widget->allocation.width, widget->allocation.height);
search_refresh ();
}
void
on_about1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
GtkWidget *d = create_aboutdialog ();
gtk_dialog_run (GTK_DIALOG (d));
gtk_widget_destroy (d);
}
gboolean
on_playlist_scroll_event (GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
{
GTKPL_PROLOGUE;
GdkEventScroll *ev = (GdkEventScroll*)event;
gtkpl_handle_scroll_event (ps, ev->direction);
return FALSE;
}
void
on_stopbtn_clicked (GtkButton *button,
gpointer user_data)
{
messagepump_push (M_STOPSONG, 0, 0, 0);
}
void
on_playbtn_clicked (GtkButton *button,
gpointer user_data)
{
messagepump_push (M_PLAYSONG, 0, 0, 0);
}
void
on_pausebtn_clicked (GtkButton *button,
gpointer user_data)
{
messagepump_push (M_PAUSESONG, 0, 0, 0);
}
void
on_prevbtn_clicked (GtkButton *button,
gpointer user_data)
{
messagepump_push (M_PREVSONG, 0, 0, 0);
}
void
on_nextbtn_clicked (GtkButton *button,
gpointer user_data)
{
messagepump_push (M_NEXTSONG, 0, 0, 0);
}
void
on_playrand_clicked (GtkButton *button,
gpointer user_data)
{
messagepump_push (M_PLAYRANDOM, 0, 0, 0);
}
gboolean
on_mainwin_key_press_event (GtkWidget *widget,
GdkEventKey *event,
gpointer user_data)
{
gtkpl_keypress (&main_playlist, event->keyval, event->state);
return FALSE;
}
void
on_playlist_drag_begin (GtkWidget *widget,
GdkDragContext *drag_context,
gpointer user_data)
{
}
gboolean
on_playlist_drag_motion (GtkWidget *widget,
GdkDragContext *drag_context,
gint x,
gint y,
guint time,
gpointer user_data)
{
GTKPL_PROLOGUE;
gtkpl_track_dragdrop (ps, y);
return FALSE;
}
gboolean
on_playlist_drag_drop (GtkWidget *widget,
GdkDragContext *drag_context,
gint x,
gint y,
guint time,
gpointer user_data)
{
#if 0
if (drag_context->targets) {
GdkAtom target_type = GDK_POINTER_TO_ATOM (g_list_nth_data (drag_context->targets, TARGET_SAMEWIDGET));
if (!target_type) {
return FALSE;
}
gtk_drag_get_data (widget, drag_context, target_type, time);
return TRUE;
}
#endif
return FALSE;
}
void
on_playlist_drag_data_get (GtkWidget *widget,
GdkDragContext *drag_context,
GtkSelectionData *selection_data,
guint target_type,
guint time,
gpointer user_data)
{
switch (target_type) {
case TARGET_SAMEWIDGET:
{
// format as "STRING" consisting of array of pointers
int nsel = pl_getselcount ();
if (!nsel) {
break; // something wrong happened
}
uint32_t *ptr = malloc (nsel * sizeof (uint32_t));
int idx = 0;
int i = 0;
for (playItem_t *it = playlist_head[PL_MAIN]; it; it = it->next[PL_MAIN], idx++) {
if (it->selected) {
ptr[i] = idx;
i++;
}
}
gtk_selection_data_set (selection_data, selection_data->target, sizeof (uint32_t) * 8, (gchar *)ptr, nsel * sizeof (uint32_t));
free (ptr);
}
break;
default:
g_assert_not_reached ();
}
}
void
on_playlist_drag_data_received (GtkWidget *widget,
GdkDragContext *drag_context,
gint x,
gint y,
GtkSelectionData *data,
guint target_type,
guint time,
gpointer user_data)
{
GTKPL_PROLOGUE;
gchar *ptr=(char*)data->data;
if (target_type == 0) { // uris
if (!strncmp(ptr,"file:///",8)) {
gtkpl_handle_fm_drag_drop (ps, y, ptr, data->length);
}
}
else if (target_type == 1) {
uint32_t *d= (uint32_t *)ptr;
gtkpl_handle_drag_drop (ps, y, d, data->length/4);
}
gtk_drag_finish (drag_context, TRUE, FALSE, time);
}
void
on_playlist_drag_data_delete (GtkWidget *widget,
GdkDragContext *drag_context,
gpointer user_data)
{
}
gboolean
on_playlist_drag_failed (GtkWidget *widget,
GdkDragContext *arg1,
GtkDragResult arg2,
gpointer user_data)
{
return TRUE;
}
void
on_playlist_drag_leave (GtkWidget *widget,
GdkDragContext *drag_context,
guint time,
gpointer user_data)
{
GTKPL_PROLOGUE;
gtkpl_track_dragdrop (ps, -1);
}
void
on_voice1_clicked (GtkButton *button,
gpointer user_data)
{
codec_lock ();
if (str_playing_song.decoder && str_playing_song.decoder->mutevoice) {
str_playing_song.decoder->mutevoice (0, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 0 : 1);
}
codec_unlock ();
}
void
on_voice2_clicked (GtkButton *button,
gpointer user_data)
{
codec_lock ();
if (str_playing_song.decoder && str_playing_song.decoder->mutevoice) {
str_playing_song.decoder->mutevoice (1, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 0 : 1);
}
codec_unlock ();
}
void
on_voice3_clicked (GtkButton *button,
gpointer user_data)
{
codec_lock ();
if (str_playing_song.decoder && str_playing_song.decoder->mutevoice) {
str_playing_song.decoder->mutevoice (2, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 0 : 1);
}
codec_unlock ();
}
void
on_voice4_clicked (GtkButton *button,
gpointer user_data)
{
codec_lock ();
if (str_playing_song.decoder && str_playing_song.decoder->mutevoice) {
str_playing_song.decoder->mutevoice (3, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 0 : 1);
}
codec_unlock ();
}
void
on_voice5_clicked (GtkButton *button,
gpointer user_data)
{
codec_lock ();
if (str_playing_song.decoder && str_playing_song.decoder->mutevoice) {
str_playing_song.decoder->mutevoice (4, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 0 : 1);
}
codec_unlock ();
}
void
on_order_linear_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
session_set_playlist_order (0);
pl_set_order (0);
}
void
on_order_shuffle_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
session_set_playlist_order (1);
pl_set_order (1);
}
void
on_order_random_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
session_set_playlist_order (2);
pl_set_order (2);
}
void
on_loop_all_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
session_set_playlist_looping (0);
pl_set_loop_mode (0);
}
void
on_loop_single_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
session_set_playlist_looping (2);
pl_set_loop_mode (2);
}
void
on_loop_disable_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
session_set_playlist_looping (1);
pl_set_loop_mode (1);
}
void
on_playlist_realize (GtkWidget *widget,
gpointer user_data)
{
GtkTargetEntry entry = {
.target = "STRING",
.flags = GTK_TARGET_SAME_WIDGET/* | GTK_TARGET_OTHER_APP*/,
TARGET_SAMEWIDGET
};
// setup drag-drop source
// gtk_drag_source_set (widget, GDK_BUTTON1_MASK, &entry, 1, GDK_ACTION_MOVE);
// setup drag-drop target
gtk_drag_dest_set (widget, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, &entry, 1, GDK_ACTION_COPY | GDK_ACTION_MOVE);
gtk_drag_dest_add_uri_targets (widget);
// gtk_drag_dest_set_track_motion (widget, TRUE);
}
void
on_searchlist_realize (GtkWidget *widget,
gpointer user_data)
{
}
void
on_playlist_load_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
GtkWidget *dlg = gtk_file_chooser_dialog_new ("Load Playlist", GTK_WINDOW (mainwin), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
GtkFileFilter* flt;
flt = gtk_file_filter_new ();
gtk_file_filter_set_name (flt, "DeaDBeeF playlist files (*.dbpl)");
gtk_file_filter_add_pattern (flt, "*.dbpl");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
if (gtk_dialog_run (GTK_DIALOG (dlg)) == GTK_RESPONSE_OK)
{
gchar *fname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
gtk_widget_destroy (dlg);
if (fname) {
int res = pl_load (fname);
printf ("load result: %d\n", res);
g_free (fname);
gtkplaylist_t *ps = &main_playlist;
gtkpl_setup_scrollbar (ps);
gtkpl_draw_playlist (ps, 0, 0, ps->playlist->allocation.width, ps->playlist->allocation.height);
gtkpl_expose (ps, 0, 0, ps->playlist->allocation.width, ps->playlist->allocation.height);
search_refresh ();
}
}
else {
gtk_widget_destroy (dlg);
}
}
char last_playlist_save_name[1024] = "";
void
save_playlist_as (void) {
GtkWidget *dlg = gtk_file_chooser_dialog_new ("Save Playlist As", GTK_WINDOW (mainwin), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL);
GtkFileFilter* flt;
flt = gtk_file_filter_new ();
gtk_file_filter_set_name (flt, "DeaDBeeF playlist files (*.dbpl)");
gtk_file_filter_add_pattern (flt, "*.dbpl");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
if (gtk_dialog_run (GTK_DIALOG (dlg)) == GTK_RESPONSE_OK)
{
gchar *fname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
gtk_widget_destroy (dlg);
if (fname) {
int res = pl_save (fname);
printf ("save as res: %d\n", res);
if (res >= 0 && strlen (fname) < 1024) {
strcpy (last_playlist_save_name, fname);
}
g_free (fname);
}
}
else {
gtk_widget_destroy (dlg);
}
}
void
on_playlist_save_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
if (!last_playlist_save_name[0]) {
save_playlist_as ();
}
else {
int res = pl_save (last_playlist_save_name);
printf ("save res: %d\n", res);
}
}
void
on_playlist_save_as_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
save_playlist_as ();
}
static GdkPixmap *seekbar_backbuf;
enum
{
CORNER_NONE = 0,
CORNER_TOPLEFT = 1,
CORNER_TOPRIGHT = 2,
CORNER_BOTTOMLEFT = 4,
CORNER_BOTTOMRIGHT = 8,
CORNER_ALL = 15
};
static void
clearlooks_rounded_rectangle (cairo_t * cr,
double x, double y, double w, double h,
double radius, uint8_t corners)
{
if (radius < 0.01 || (corners == CORNER_NONE)) {
cairo_rectangle (cr, x, y, w, h);
return;
}
if (corners & CORNER_TOPLEFT)
cairo_move_to (cr, x + radius, y);
else
cairo_move_to (cr, x, y);
if (corners & CORNER_TOPRIGHT)
cairo_arc (cr, x + w - radius, y + radius, radius, M_PI * 1.5, M_PI * 2);
else
cairo_line_to (cr, x + w, y);
if (corners & CORNER_BOTTOMRIGHT)
cairo_arc (cr, x + w - radius, y + h - radius, radius, 0, M_PI * 0.5);
else
cairo_line_to (cr, x + w, y + h);
if (corners & CORNER_BOTTOMLEFT)
cairo_arc (cr, x + radius, y + h - radius, radius, M_PI * 0.5, M_PI);
else
cairo_line_to (cr, x, y + h);
if (corners & CORNER_TOPLEFT)
cairo_arc (cr, x + radius, y + radius, radius, M_PI, M_PI * 1.5);
else
cairo_line_to (cr, x, y);
}
int seekbar_moving = 0;
int seekbar_move_x = 0;
void
seekbar_draw (GtkWidget *widget) {
if (!widget) {
return;
}
gdk_draw_rectangle (seekbar_backbuf, widget->style->bg_gc[0], TRUE, 0, 0, widget->allocation.width, widget->allocation.height);
cairo_t *cr;
cr = gdk_cairo_create (seekbar_backbuf);
if (!cr) {
return;
}
float pos = 0;
if (seekbar_moving) {
int x = seekbar_move_x;
if (x < 0) {
x = 0;
}
if (x > widget->allocation.width-1) {
x = widget->allocation.width-1;
}
pos = x;
}
else {
if (str_playing_song.decoder && str_playing_song.duration > 0) {
pos = streamer_get_playpos () / str_playing_song.duration;
pos *= widget->allocation.width;
}
}
// left
if (pos > 0) {
theme_set_cairo_source_rgb (cr, COLO_SEEKBAR_FRONT);
cairo_rectangle (cr, 0, widget->allocation.height/2-4, pos, 8);
cairo_clip (cr);
clearlooks_rounded_rectangle (cr, 0, widget->allocation.height/2-4, widget->allocation.width, 8, 4, 0xff);
cairo_fill (cr);
cairo_reset_clip (cr);
}
// right
theme_set_cairo_source_rgb (cr, COLO_SEEKBAR_BACK);
cairo_rectangle (cr, pos, widget->allocation.height/2-4, widget->allocation.width-pos, 8);
cairo_clip (cr);
clearlooks_rounded_rectangle (cr, 0, widget->allocation.height/2-4, widget->allocation.width, 8, 4, 0xff);
cairo_fill (cr);
cairo_reset_clip (cr);
cairo_destroy (cr);
}
void
seekbar_expose (GtkWidget *widget, int x, int y, int w, int h) {
gdk_draw_drawable (widget->window, widget->style->black_gc, seekbar_backbuf, x, y, x, y, w, h);
}
gboolean
on_seekbar_configure_event (GtkWidget *widget,
GdkEventConfigure *event,
gpointer user_data)
{
if (seekbar_backbuf) {
g_object_unref (seekbar_backbuf);
seekbar_backbuf = NULL;
}
seekbar_backbuf = gdk_pixmap_new (widget->window, widget->allocation.width, widget->allocation.height, -1);
seekbar_draw (widget);
return FALSE;
}
gboolean
on_seekbar_expose_event (GtkWidget *widget,
GdkEventExpose *event,
gpointer user_data)
{
seekbar_expose (widget, event->area.x, event->area.y, event->area.width, event->area.height);
return FALSE;
}
gboolean
on_seekbar_motion_notify_event (GtkWidget *widget,
GdkEventMotion *event,
gpointer user_data)
{
if (seekbar_moving) {
seekbar_move_x = event->x;
seekbar_draw (widget);
seekbar_expose (widget, 0, 0, widget->allocation.width, widget->allocation.height);
}
return FALSE;
}
gboolean
on_seekbar_button_press_event (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
seekbar_moving = 1;
seekbar_move_x = event->x;
seekbar_draw (widget);
seekbar_expose (widget, 0, 0, widget->allocation.width, widget->allocation.height);
return FALSE;
}
gboolean
on_seekbar_button_release_event (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
seekbar_moving = 0;
seekbar_draw (widget);
seekbar_expose (widget, 0, 0, widget->allocation.width, widget->allocation.height);
float time = event->x * str_playing_song.duration / (widget->allocation.width);
if (time < 0) {
time = 0;
}
streamer_set_seek (time);
// messagepump_push (M_SONGSEEK, 0, time * 1000, 0);
return FALSE;
}
static GdkPixmap *volumebar_backbuf;
void
volumebar_draw (GtkWidget *widget) {
if (!widget) {
return;
}
gdk_draw_rectangle (volumebar_backbuf, widget->style->bg_gc[0], TRUE, 0, 0, widget->allocation.width, widget->allocation.height);
cairo_t *cr;
cr = gdk_cairo_create (volumebar_backbuf);
if (!cr) {
return;
}
float range = -volume_get_min_db ();
int n = widget->allocation.width / 4;
float vol = (range + volume_get_db ()) / range * n;
float h = 16;
for (int i = 0; i < n; i++) {
float iy = (float)i + 3;
if (i <= vol) {
theme_set_cairo_source_rgb (cr, COLO_VOLUMEBAR_FRONT);
}
else {
theme_set_cairo_source_rgb (cr, COLO_VOLUMEBAR_BACK);
}
cairo_rectangle (cr, i * 4, (widget->allocation.height/2-h/2) + h - 1 - (h* i / n), 3, h * iy / n);
cairo_fill (cr);
}
cairo_destroy (cr);
}
void
volumebar_expose (GtkWidget *widget, int x, int y, int w, int h) {
gdk_draw_drawable (widget->window, widget->style->black_gc, volumebar_backbuf, x, y, x, y, w, h);
}
gboolean
on_volumebar_configure_event (GtkWidget *widget,
GdkEventConfigure *event,
gpointer user_data)
{
if (volumebar_backbuf) {
g_object_unref (volumebar_backbuf);
volumebar_backbuf = NULL;
}
volumebar_backbuf = gdk_pixmap_new (widget->window, widget->allocation.width, widget->allocation.height, -1);
volumebar_draw (widget);
return FALSE;
}
gboolean
on_volumebar_expose_event (GtkWidget *widget,
GdkEventExpose *event,
gpointer user_data)
{
volumebar_expose (widget, event->area.x, event->area.y, event->area.width, event->area.height);
return FALSE;
}
gboolean
on_volumebar_motion_notify_event (GtkWidget *widget,
GdkEventMotion *event,
gpointer user_data)
{
if (event->state & GDK_BUTTON1_MASK) {
float range = -volume_get_min_db ();
float volume = event->x / widget->allocation.width * range - range;
if (volume > 0) {
volume = 0;
}
if (volume < -range) {
volume = -range;
}
volume_set_db (volume);
volumebar_draw (widget);
volumebar_expose (widget, 0, 0, widget->allocation.width, widget->allocation.height);
}
return FALSE;
}
gboolean
on_volumebar_button_press_event (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
float range = -volume_get_min_db ();
float volume = event->x / widget->allocation.width * range - range;
if (volume < -range) {
volume = -range;
}
if (volume > 0) {
volume = 0;
}
volume_set_db (volume);
volumebar_draw (widget);
volumebar_expose (widget, 0, 0, widget->allocation.width, widget->allocation.height);
return FALSE;
}
gboolean
on_volumebar_button_release_event (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
return FALSE;
}
void
volumebar_notify_changed (void) {
GtkWidget *widget = lookup_widget (mainwin, "volumebar");
volumebar_draw (widget);
volumebar_expose (widget, 0, 0, widget->allocation.width, widget->allocation.height);
}
gboolean
on_mainwin_delete_event (GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
{
if (conf_close_send_to_tray) {
gtk_widget_hide (widget);
}
else {
messagepump_push (M_TERMINATE, 0, 0, 0);
}
return TRUE;
}
gboolean
on_volumebar_scroll_event (GtkWidget *widget,
GdkEventScroll *event,
gpointer user_data)
{
float range = -volume_get_min_db ();
float vol = volume_get_db ();
if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_RIGHT) {
vol += 1;
}
else if (event->direction == GDK_SCROLL_DOWN || event->direction == GDK_SCROLL_LEFT) {
vol -= 1;
}
if (vol > 0) {
vol = 0;
}
else if (vol < -range) {
vol = -range;
}
volume_set_db (vol);
GtkWidget *volumebar = lookup_widget (mainwin, "volumebar");
volumebar_draw (volumebar);
volumebar_expose (volumebar, 0, 0, volumebar->allocation.width, volumebar->allocation.height);
return FALSE;
}
gboolean
on_mainwin_configure_event (GtkWidget *widget,
GdkEventConfigure *event,
gpointer user_data)
{
session_capture_window_attrs ((uintptr_t)widget);
return FALSE;
}
void
on_scroll_follows_playback_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
session_set_scroll_follows_playback (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem)));
}
void
on_find_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
search_start ();
}
void
on_help1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
GtkWidget *widget = create_helpwindow ();
gtk_window_set_transient_for (GTK_WINDOW (widget), GTK_WINDOW (mainwin));
GtkWidget *txt = lookup_widget (widget, "helptext");
GtkTextBuffer *buffer = gtk_text_buffer_new (NULL);
FILE *fp = fopen (PREFIX "/share/doc/deadbeef/help.txt", "rb");
if (fp) {
fseek (fp, 0, SEEK_END);
size_t s = ftell (fp);
rewind (fp);
char buf[s+1];
if (fread (buf, 1, s, fp) != s) {
fprintf (stderr, "error reading help file contents\n");
const char *error = "Failed while reading help file";
gtk_text_buffer_set_text (buffer, error, strlen (error));
}
else {
buf[s] = 0;
gtk_text_buffer_set_text (buffer, buf, s);
}
fclose (fp);
}
else {
const char *error = "Failed to load help file";
gtk_text_buffer_set_text (buffer, error, strlen (error));
}
gtk_text_view_set_buffer (GTK_TEXT_VIEW (txt), buffer);
gtk_widget_show (widget);
}
void
on_playhscroll_value_changed (GtkRange *widget,
gpointer user_data)
{
GTKPL_PROLOGUE;
int newscroll = gtk_range_get_value (GTK_RANGE (widget));
gtkpl_hscroll (ps, newscroll);
}
void
on_searchhscroll_value_changed (GtkRange *widget,
gpointer user_data)
{
GTKPL_PROLOGUE;
int newscroll = gtk_range_get_value (GTK_RANGE (widget));
gtkpl_hscroll (ps, newscroll);
}