From 1e4681c09375d0a2aece4ebdcd4a3d5badee5fc6 Mon Sep 17 00:00:00 2001 From: Olaf Wintermann Date: Sat, 3 Sep 2022 18:17:01 +0200 Subject: [PATCH] add playlist data structure --- application/Makefile | 1 + application/Sidebar.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++-- application/SidebarP.h | 2 +- application/player.c | 19 ++++------- application/playlist.c | 66 +++++++++++++++++++++++++++++++++++++++ application/playlist.h | 43 +++++++++++++++++++++++++ application/window.c | 57 ++++++++++++++++----------------- application/window.h | 19 ++++++++--- application/xdnd.c | 5 +-- 9 files changed, 245 insertions(+), 52 deletions(-) create mode 100644 application/playlist.c create mode 100644 application/playlist.h diff --git a/application/Makefile b/application/Makefile index db09a6c..837774b 100644 --- a/application/Makefile +++ b/application/Makefile @@ -40,6 +40,7 @@ SRC += utils.c SRC += json.c SRC += Sidebar.c SRC += xdnd.c +SRC += playlist.c OBJ = $(SRC:%.c=$(BUILD_ROOT)/build/application/%.$(OBJ_EXT)) diff --git a/application/Sidebar.c b/application/Sidebar.c index b8c2f02..a3dd20a 100644 --- a/application/Sidebar.c +++ b/application/Sidebar.c @@ -26,6 +26,9 @@ #include #include #include +#include + +#include "xdnd.h" static void sidebar_class_init(void); @@ -40,6 +43,10 @@ static void sidebar_insert_child(Widget child); Boolean sidebar_acceptfocus(Widget widget, Time *time); static void FocusInAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); +static void xdndEnterAP(Widget w, XEvent *event, String *args, Cardinal *nArgs); + +static void sidebar_xdnd_callback(Widget w, XtPointer udata, XtPointer cdata); + static XtResource resources[] = { @@ -47,10 +54,12 @@ static XtResource resources[] = { static XtActionsRec actionslist[] = { {"focusIn", FocusInAP}, + {"xdnd_enter", xdndEnterAP}, {"NULL", NULL} }; -static char defaultTranslations[] = ": focusIn()"; +static char defaultTranslations[] = ": focusIn()\n" + "XdndEnter: xdnd_enter()\n"; static XtResource constraints[] = {}; @@ -156,10 +165,15 @@ static void sidebar_resize(Widget widget) { } +static int xdnd_initialized = 0; + static void sidebar_realize(Widget widget, XtValueMask *mask, XSetWindowAttributes *attributes) { (xmManagerClassRec.core_class.realize)(widget, mask, attributes); - + if(!xdnd_initialized) { + XdndInit(XtDisplay(widget), XtWidgetToApplicationContext(widget), sidebar_xdnd_callback, widget); + } + XdndEnable(widget); } static void sidebar_expose(Widget widget, XEvent *event, Region region) { @@ -184,11 +198,76 @@ Boolean sidebar_acceptfocus(Widget widget, Time *time) { static void FocusInAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { - + printf("focusin\n"); + fflush(stdout); +} + +static void xdndEnterAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { + printf("xdndEnterAP\n"); + fflush(stdout); } + +static void sidebar_xdnd_callback(Widget w, XtPointer udata, XtPointer cdata) { + printf("xdnd\n"); + fflush(stdout); + + char *urilist = udata; + + size_t len = strlen(urilist); + + size_t start = 0; + if(len > 7 && !memcmp(urilist, "file://", 7)) { + start = 7; + } + + int err = 0; + + // urldecode + char *path = malloc(len + 1); + int k = 0; + for(int i=start;ifile) { - free(file); - } - win->file = file; - PlayerOpenFile(win); + PlayListPlayNext(win, false); return 0; } void PlayerEOF(Player *p) { MainWindow *win = GetMainWindow(); - if(win->repeatTrack) { + if(win->playlist.repeatTrack) { char *cmd = "{ \"command\": [\"set_property\", \"playback-time\", 0] }\n"; write(p->ipc, cmd, strlen(cmd)); - } else if(win->autoplayFolder) { - char *next_file = util_find_next_file(win->file); - if(next_file) { - AppExecProc(open_next_file, next_file); - } + } else { + AppExecProc(play_next, NULL); } } diff --git a/application/playlist.c b/application/playlist.c new file mode 100644 index 0000000..06172c3 --- /dev/null +++ b/application/playlist.c @@ -0,0 +1,66 @@ +/* + * Copyright 2022 Olaf Wintermann + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "playlist.h" + +#include "player.h" +#include "utils.h" + +void PlayListInit(MainWindow *win) { + win->playlist.current_track = -1; +} + +void PlayListAddFile(MainWindow *win, const char *file) { + char *f = strdup(file); + win->playlist.tracks = ucx_list_append(win->playlist.tracks, f); +} + +void PlayListPlayNext(MainWindow *win, bool force) { + UcxList *tracks = win->playlist.tracks; + if(!tracks) return; + size_t len = ucx_list_size(tracks); + + int current = win->playlist.current_track; + if(win->playlist.repeatTrack) { + if(force) { + current++; + } + } else if(current < len) { + current++; + } else if(win->playlist.autoplayFolder) { + char *next_file = util_find_next_file(win->file); + win->playlist.tracks = ucx_list_append(win->playlist.tracks, next_file); + current = len; + } else { + current = 0; + } + + win->playlist.current_track = current; + + UcxList *fileElm = ucx_list_get(tracks, current); + if(!fileElm) { + return; + } + win->file = fileElm->data; + + PlayerOpenFile(win); +} diff --git a/application/playlist.h b/application/playlist.h new file mode 100644 index 0000000..abb4e62 --- /dev/null +++ b/application/playlist.h @@ -0,0 +1,43 @@ +/* + * Copyright 2022 Olaf Wintermann + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef PLAYLIST_H +#define PLAYLIST_H + +#include "window.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void PlayListInit(MainWindow *win); + +void PlayListAddFile(MainWindow *win, const char *file); + +void PlayListPlayNext(MainWindow *win, bool force); + +#ifdef __cplusplus +} +#endif + +#endif /* PLAYLIST_H */ + diff --git a/application/window.c b/application/window.c index f2c8091..3be3985 100644 --- a/application/window.c +++ b/application/window.c @@ -27,6 +27,8 @@ #include "window.h" #include "main.h" #include "player.h" +#include "playlist.h" +#include "xdnd.h" #include "Fsb.h" #include "Sidebar.h" @@ -92,18 +94,16 @@ static void resizeEH(Widget widget, XtPointer data, XEvent *event, Boolean *disp static void WindowRealized(MainWindow *win) { char *open_file = GetOpenFileArg(); if(open_file) { - size_t len = strlen(open_file); - char *file = XtMalloc(len+1); - memcpy(file, open_file, len); - file[len] = 0; - WindowSetFile(win, file); - PlayerOpenFile(win); + PlayListAddFile(win, open_file); + PlayListPlayNext(win, true); CleanOpenFileArg(); } if(!blank_cursor_init) { init_blank_cursor(win->player_widget); } + + XdndEnable(win->window); } static void playerWidgetInputCB(Widget widget, XtPointer u, XtPointer c) { @@ -248,6 +248,8 @@ void WindowHandlePlayerEvent(MainWindow *win, XEvent *event) { } } + + MainWindow* WindowCreate(Display *display) { Arg args[32]; int n; @@ -255,7 +257,7 @@ MainWindow* WindowCreate(Display *display) { MainWindow *window = malloc(sizeof(MainWindow)); memset(window, 0, sizeof(MainWindow)); main_window = window; - + // toplevel window n = 0; XtSetArg(args[n], XmNtitle, APP_NAME); n++; @@ -305,7 +307,7 @@ MainWindow* WindowCreate(Display *display) { XtSetArg(args[n], XmNwidth, 300); n++; window->sidebar = CreateSidebar(container, "sidebar", args, n); //XtManageChild(window->sidebar); - + n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; @@ -326,6 +328,9 @@ MainWindow* WindowCreate(Display *display) { // get F keycode keycodeF = XKeysymToKeycode(XtDisplay(window->window), XStringToKeysym("F")); + + PlayListInit(window); + return window; } @@ -533,13 +538,6 @@ void WindowMenubarSetVisible(MainWindow *win, bool visible) { } } -void WindowSetFile(MainWindow *win, char *file) { - if(win->file) { - XtFree(win->file); - } - win->file = file; -} - static void filedialog_end( Widget widget, MainWindow *data, @@ -558,10 +556,9 @@ static void filedialog_select( if(selection->value) { XmStringGetLtoR(selection->value, XmSTRING_DEFAULT_CHARSET, &value); if(value) { - WindowSetFile(data, value); - // no need to free the value, because it is stored in MainWindow - - PlayerOpenFile(data); + PlayListAddFile(data, value); + PlayListPlayNext(data, true); + XtFree(value); } } filedialog_end(widget, data, NULL); @@ -594,27 +591,27 @@ static void FileQuitCB(Widget w, void *udata, void *cdata) { static void PlayRepeatCB(Widget w, void *udata, void *cdata) { MainWindow *win = udata; - win->repeatTrack = XmToggleButtonGadgetGetState(w); - win->repeatList = 0; - win->autoplayFolder = 0; + win->playlist.repeatTrack = XmToggleButtonGadgetGetState(w); + win->playlist.repeatList = 0; + win->playlist.autoplayFolder = 0; XtVaSetValues(win->playRepeatListButton, XmNset, 0, NULL); XtVaSetValues(win->playAutoPlayButton, XmNset, 0, NULL); } static void PlayRepeatListCB(Widget w, void *udata, void *cdata) { MainWindow *win = udata; - win->repeatList = XmToggleButtonGadgetGetState(w); - win->repeatTrack = 0; - win->autoplayFolder = 0; + win->playlist.repeatList = XmToggleButtonGadgetGetState(w); + win->playlist.repeatTrack = 0; + win->playlist.autoplayFolder = 0; XtVaSetValues(win->playRepeatTrackButton, XmNset, 0, NULL); XtVaSetValues(win->playAutoPlayButton, XmNset, 0, NULL); } static void PlayAutoPlayCB(Widget w, void *udata, void *cdata) { MainWindow *win = udata; - win->autoplayFolder = XmToggleButtonGadgetGetState(w); - win->repeatTrack = 0; - win->repeatList = 0; + win->playlist.autoplayFolder = XmToggleButtonGadgetGetState(w); + win->playlist.repeatTrack = 0; + win->playlist.repeatList = 0; XtVaSetValues(win->playRepeatTrackButton, XmNset, 0, NULL); XtVaSetValues(win->playRepeatListButton, XmNset, 0, NULL); } @@ -700,3 +697,7 @@ void WindowShowSidebar(MainWindow *win) { XtVaSetValues(win->player_widget, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, win->sidebar, NULL); } + + + + diff --git a/application/window.h b/application/window.h index e3202c0..617ff71 100644 --- a/application/window.h +++ b/application/window.h @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -46,7 +47,16 @@ typedef struct Player { int height; int osd_height; } Player; + +typedef struct { + UcxList *tracks; + int current_track; + Boolean repeatTrack; + Boolean repeatList; + Boolean autoplayFolder; +} PlayList; + typedef struct MainWindow { Widget window; Widget menubar; @@ -66,15 +76,15 @@ typedef struct MainWindow { Widget playAutoPlayButton; Widget viewSidebarButton; + PlayList playlist; + Time player_event_time; Time button_press_time; double motion_playback_time; int mouse_x; int mouse_y; - Boolean repeatTrack; - Boolean repeatList; - Boolean autoplayFolder; + } MainWindow; MainWindow* WindowCreate(Display *dp); @@ -87,8 +97,6 @@ void WindowFullscreen(MainWindow *win, bool enableFullscreen); void WindowMenubarSetVisible(MainWindow *win, bool visible); -void WindowSetFile(MainWindow *win, char *file); - void WindowAdjustAspectRatio(MainWindow *win); void WindowClosePlayer(MainWindow *win); @@ -101,6 +109,7 @@ void WindowHandlePlayerEvent(MainWindow *win, XEvent *event); void WindowHideSidebar(MainWindow *win); void WindowShowSidebar(MainWindow *win); + #ifdef __cplusplus } #endif diff --git a/application/xdnd.c b/application/xdnd.c index 09b10eb..ed33030 100644 --- a/application/xdnd.c +++ b/application/xdnd.c @@ -76,7 +76,8 @@ static void getSelectionValue(Widget w, XtPointer clientData, Atom *selType, } static void xdnd_enter(Widget w, XEvent *event, String *args, Cardinal *nArgs) { - //printf("xdnd_enter\n"); + printf("xdnd_enter\n"); + fflush(stdout); XtGetSelectionValue(w, XdndSelection, selType, checkSelectionValue, NULL, 0); } @@ -142,7 +143,7 @@ void XdndInit( dropData = dropCBData; } -void XdndEnable(Widget w) { +void XdndEnable(Widget w) { int version = 4; XChangeProperty( XtDisplay(w), -- 1.8.3.1