d6b3ff4521244e32d792eb8f9de4014192be8d90
[uwplayer.git] / application / Sidebar.c
1 /*
2  * Copyright 2022 Olaf Wintermann
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a 
5  * copy of this software and associated documentation files (the "Software"), 
6  * to deal in the Software without restriction, including without limitation 
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
8  * and/or sell copies of the Software, and to permit persons to whom the 
9  * Software is furnished to do so, subject to the following conditions:
10  * 
11  * The above copyright notice and this permission notice shall be included in 
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
20  * DEALINGS IN THE SOFTWARE.
21  */
22
23 #include "Sidebar.h"
24 #include "SidebarP.h"
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30
31 #include "xdnd.h"
32 #include "utils.h"
33 #include "playlist.h"
34
35
36 static void sidebar_class_init(void);
37 static void sidebar_class_part_init (WidgetClass wc);
38 static void sidebar_init(Widget request, Widget neww, ArgList args, Cardinal *num_args);
39 static void sidebar_destroy(Widget widget);
40 static void sidebar_resize(Widget widget);
41 static void sidebar_realize(Widget widget, XtValueMask *mask, XSetWindowAttributes *attributes);
42 static void sidebar_expose(Widget widget, XEvent *event, Region region);
43 static Boolean sidebar_set_values(Widget old, Widget request, Widget neww, ArgList args, Cardinal *num_args);
44 static void sidebar_insert_child(Widget child);
45 Boolean sidebar_acceptfocus(Widget widget, Time *time);
46 static void FocusInAP(Widget w, XEvent *event, String *args, Cardinal *nArgs);
47
48 static void xdndEnterAP(Widget w, XEvent *event, String *args, Cardinal *nArgs);
49
50 static void sidebar_xdnd_callback(Widget w, XtPointer udata, XtPointer cdata);
51
52
53 static XtResource resources[] = {
54
55 };
56
57 static XtActionsRec actionslist[] = {
58   {"focusIn", FocusInAP},
59   {"xdnd_enter", xdndEnterAP},
60   {"NULL", NULL}
61 };
62
63 static char defaultTranslations[] = "<FocusIn>:                 focusIn()\n"
64                                     "<Message>XdndEnter:    xdnd_enter()\n";
65
66
67 static XtResource constraints[] = {};
68
69 SidebarClassRec sidebarWidgetClassRec = {
70     // Core Class
71     {
72         (WidgetClass)&xmManagerClassRec,
73         "XnSidebar",                         // class_name
74         sizeof(SidebarRec),                  // widget_size
75         sidebar_class_init,                  // class_initialize
76         sidebar_class_part_init,             // class_part_initialize
77         FALSE,                           // class_inited
78         sidebar_init,                        // initialize
79         NULL,                            // initialize_hook
80         sidebar_realize,                     // realize
81         actionslist,                     // actions
82         XtNumber(actionslist),           // num_actions
83         resources,                       // resources
84         XtNumber(resources),             // num_resources
85         NULLQUARK,                       // xrm_class
86         True,                            // compress_motion
87         True,                            // compress_exposure
88         True,                            // compress_enterleave
89         False,                           // visible_interest
90         sidebar_destroy,                     // destroy
91         sidebar_resize,                      // resize
92         sidebar_expose,                 // expose
93         sidebar_set_values,                  // set_values
94         NULL,                            // set_values_hook
95         XtInheritSetValuesAlmost,        // set_values_almost
96         NULL,                            // get_values_hook
97         sidebar_acceptfocus,                 // accept_focus
98         XtVersion,                       // version
99         NULL,                            // callback_offsets
100         defaultTranslations,             // tm_table
101         XtInheritQueryGeometry,          // query_geometry
102         XtInheritDisplayAccelerator,     // display_accelerator
103         NULL,                            // extension
104     },
105     // Composite Class
106     {
107         XtInheritGeometryManager, // geometry_manager 
108         XtInheritChangeManaged,   // change_managed
109         sidebar_insert_child,         // insert_child 
110         XtInheritDeleteChild,     // delete_child  
111         NULL,                     // extension   
112     },
113     // Constraint Class
114     {
115         constraints,                 // resources
116         XtNumber(constraints),       // num_resources   
117         sizeof(XmFormConstraintRec), // constraint_size  
118         NULL,                        // initialize 
119         NULL,                        // destroy
120         NULL,                        // set_value
121         NULL,                        // extension 
122     },
123     // XmManager Class
124     {
125         XtInheritTranslations, // translations
126         NULL, // syn_resources
127         0,    // num_syn_resources
128         NULL, // syn_constraint_resources
129         0,    // num_syn_constraint_resources
130         XmInheritParentProcess, // parent_process
131         NULL  // extension
132     },
133     // Sidebar Class
134     {
135         0
136     }
137 };
138
139 WidgetClass xnSidebarWidgetClass = (WidgetClass)&sidebarWidgetClassRec;
140
141
142 static void sidebar_class_init(void) {
143
144 }
145
146 static void sidebar_class_part_init (WidgetClass wc) {
147     SidebarClassRec *sidebarClass = (SidebarClassRec*)wc;
148     XmManagerClassRec *managerClass = (XmManagerClassRec*)xmManagerWidgetClass;
149     
150     sidebarClass->constraint_class.initialize = managerClass->constraint_class.initialize;
151     sidebarClass->constraint_class.set_values = managerClass->constraint_class.set_values;
152 }
153
154
155
156 static void sidebar_init(Widget request, Widget neww, ArgList args, Cardinal *num_args) {
157     Sidebar sb = (Sidebar)neww;
158     
159     XftColor fg, bg;
160     fg.color.red = 0;
161     fg.color.green = 0;
162     fg.color.blue = 0;
163     fg.color.alpha = 0xFFFF;
164     
165     bg.color.red = 0xFFFF;
166     bg.color.green = 0xFFFF;
167     bg.color.blue = 0xFFFF;
168     bg.color.alpha = 0xFFFF;
169     
170     sb->sidebar.fg = fg;
171     sb->sidebar.bg = bg;
172     
173     sb->sidebar.font = FontFromName(XtDisplay(neww), "Sans:size=11");
174     if(!sb->sidebar.font) {
175         fprintf(stderr, "Cannot open font.\nAbort.\n");
176         exit(-1);
177     }
178 }
179
180
181
182 static void sidebar_destroy(Widget widget) {
183     
184 }
185
186 static void sidebar_resize(Widget widget) {
187     
188 }
189
190 static int xdnd_initialized = 0;
191
192 static void sidebar_realize(Widget widget, XtValueMask *mask, XSetWindowAttributes *attributes) {
193     (xmManagerClassRec.core_class.realize)(widget, mask, attributes);
194     
195     if(!xdnd_initialized) {
196         XdndInit(XtDisplay(widget), XtWidgetToApplicationContext(widget), sidebar_xdnd_callback, widget);
197     }
198     XdndEnable(widget);
199     
200     Screen *screen = widget->core.screen;
201     Visual *visual = screen->root_visual;
202     for(int i=0;i<screen->ndepths;i++) {
203         Depth d = screen->depths[i];
204         if(d.depth == widget->core.depth) {
205             visual = d.visuals;
206             break;
207         }
208     }
209     
210     Sidebar sb = (Sidebar)widget;
211     sb->sidebar.d = XftDrawCreate(
212             XtDisplay(widget),
213             XtWindow(widget),
214             visual,
215             widget->core.colormap);
216 }
217
218 static void sidebar_expose(Widget widget, XEvent *event, Region region) {
219     printf("expose\n");
220     Dimension w, h;
221     XtMakeResizeRequest(widget, 200, 200, &w, &h);
222     
223     Sidebar s = (Sidebar)widget;
224     
225     XftDrawRect(s->sidebar.d, &s->sidebar.bg, 0, 0, s->core.width, s->core.height);
226     
227     int height = 20;
228     
229     printf("current track: %d\n", s->sidebar.window->playlist.current_track);
230     
231     int i = 0;
232     UCX_FOREACH(elm, s->sidebar.window->playlist.tracks) {
233         char *name = util_resource_name(elm->data);
234         XftColor *cg = &s->sidebar.fg;
235         if(i == s->sidebar.window->playlist.current_track) {
236             XftDrawRect(s->sidebar.d, &s->sidebar.fg, 0, i*height, s->core.width, height);
237             cg = &s->sidebar.bg;
238         }
239         
240         XftDrawString8(s->sidebar.d, cg, s->sidebar.font->fonts->font, 10, i*height + 15, (const FcChar8*)name, strlen(name));
241         
242         i++;
243     }
244 }
245
246 static Boolean sidebar_set_values(Widget old, Widget request, Widget neww, ArgList args, Cardinal *num_args) {
247     Boolean r = False;
248
249     return r;
250 }
251
252 static void sidebar_insert_child(Widget child) {
253     (xmManagerClassRec.composite_class.insert_child)(child);
254 }
255
256 Boolean sidebar_acceptfocus(Widget widget, Time *time) {
257     return 0;
258 }
259
260
261 static void FocusInAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) {
262     printf("focusin\n");
263     fflush(stdout);
264 }
265
266 static void xdndEnterAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) {
267     printf("xdndEnterAP\n");
268     fflush(stdout);
269 }
270
271
272
273
274 static void sidebar_xdnd_callback(Widget w, XtPointer udata, XtPointer cdata) {
275     printf("xdnd\n");
276     fflush(stdout);
277     
278     Sidebar s = (Sidebar)cdata;
279     
280     char *urilist = udata;
281     
282     size_t len = strlen(urilist);
283     
284     size_t start = 0;
285     if(len > 7 && !memcmp(urilist, "file://", 7)) {
286         start = 7;
287     }
288     
289     int err = 0;
290     
291     // urldecode
292     char *path = malloc(len + 1);
293     int k = 0;
294     for(int i=start;i<len;i++) {
295         char c = urilist[i];
296         if(c == '%') {
297             if(i + 2 < len) {
298                 char code[3];
299                 code[0] = urilist[i+1];
300                 code[1] = urilist[i+2];
301                 code[2] = '\0';
302                 
303                 errno = 0;
304                 char *end = NULL;
305                 int ascii = (int)strtol(code, &end, 16);
306                 if(errno == 0 && end == &code[2]) {
307                     path[k] = ascii;
308                     i += 2;
309                 } else {
310                     err = 1;
311                     break;
312                 }
313             } else {
314                 err = 1;
315                 break;
316             }
317         } else if(c == '\n' || c == '\r') {
318             break;
319         } else {
320             path[k] = c;
321         }
322         
323         k++;
324     }
325     path[k] = '\0';
326     
327     PlayListAddFile(s->sidebar.window, path);
328     
329     free(path);
330 }
331
332
333 /* --------------------------- public --------------------------- */
334
335 Widget CreateSidebar(
336         Widget parent,
337         String name,
338         ArgList arglist,
339         Cardinal argcount)
340 {
341     return XtCreateWidget(name, xnSidebarWidgetClass, parent, arglist, argcount);
342 }
343
344 void SidebarSetWindow(Widget widget, MainWindow *win) {
345     Sidebar sb = (Sidebar)widget;
346     sb->sidebar.window = win;
347 }