add playlist data structure
[uwplayer.git] / application / xdnd.c
1 /*
2  * Copyright 2020 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 "xdnd.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 static Atom XdndAware;
30 static Atom XdndSelection;
31 static Atom XdndStatus;
32 static Atom XdndActionCopy;
33 static Atom XdndFinished;
34
35 static Window src;
36
37 static Atom selType;
38
39 static int canDrop;
40
41 XtCallbackProc dropCallback;
42 XtPointer dropData;
43
44 static void checkSelectionValue(Widget w, XtPointer clientData, Atom *selType,
45         Atom *type, XtPointer value, unsigned long *length, int *format)
46 {
47     if(value) {
48         canDrop = 1; // we have a text/uri-list value
49         XtFree(value);
50     }
51 }
52
53 static void getSelectionValue(Widget w, XtPointer clientData, Atom *selType,
54         Atom *type, XtPointer value, unsigned long *length, int *format)
55 {
56     if(value) {
57         if(dropCallback) {
58             dropCallback(w, value, dropData);
59         }
60         XtFree(value);
61         
62         // XdndFinished
63         if(src != 0) {
64             XEvent msg;
65             memset(&msg, 0, sizeof(XEvent));
66             msg.xany.type = ClientMessage;
67             msg.xany.display = XtDisplay(w);
68             msg.xclient.window = src;
69             msg.xclient.message_type = XdndFinished;
70             msg.xclient.format = 32;
71             msg.xclient.data.l[0] = XtWindow(w);
72             XSendEvent(XtDisplay(w), msg.xclient.window, 0, 0, &msg);
73             src = 0;
74         }
75     }
76 }
77
78 static void xdnd_enter(Widget w, XEvent *event, String *args, Cardinal *nArgs) {
79     printf("xdnd_enter\n");
80     fflush(stdout);
81     XtGetSelectionValue(w, XdndSelection, selType, checkSelectionValue, NULL, 0);
82 }
83
84 static void xdnd_position(Widget w, XEvent *event, String *args, Cardinal *nArgs) {
85     //printf("xdnd_position\n");
86     
87     src = event->xclient.data.l[0];
88     
89     XEvent msg;
90     memset(&msg, 0, sizeof(XEvent));
91     msg.xany.type = ClientMessage;
92     msg.xany.display = XtDisplay(w);
93     msg.xclient.window = src;
94     msg.xclient.message_type = XdndStatus;
95     msg.xclient.format = 32;
96     msg.xclient.data.l[0] = XtWindow(w);
97     msg.xclient.data.l[1] = canDrop;
98     msg.xclient.data.l[4] = XdndActionCopy;
99     XSendEvent(XtDisplay(w), msg.xclient.window, 0, 0, &msg);
100 }
101
102 static void xdnd_drop(Widget w, XEvent *event, String *args, Cardinal *nArgs) {
103     //printf("xdnd_drop\n");
104     
105     XtGetSelectionValue(w, XdndSelection, selType, getSelectionValue, NULL, 0);
106     
107     canDrop = 0;
108 }
109
110 static void xdnd_leave(Widget w, XEvent *event, String *args, Cardinal *nArgs) {
111     //printf("xdnd_leave\n");
112     canDrop = 0;
113 }
114
115 static XtActionsRec xdndactions[] = {
116     {"xdnd_enter", xdnd_enter},
117     {"xdnd_position", xdnd_position},
118     {"xdnd_drop", xdnd_drop},
119     {"xdnd_leave", xdnd_leave}
120 };
121
122
123 void XdndInit(
124         Display *dpy,
125         XtAppContext app,
126         XtCallbackProc dropCB,
127         XtPointer dropCBData)
128 {
129     // init atoms
130     XdndAware = XInternAtom(dpy, "XdndAware", False);
131     XdndSelection = XInternAtom(dpy, "XdndSelection", False);
132     XdndStatus = XInternAtom(dpy, "XdndStatus", False);
133     XdndActionCopy = XInternAtom(dpy, "XdndActionCopy", False);
134     XdndFinished = XInternAtom(dpy, "XdndFinished", False);
135     selType = XInternAtom(dpy, "text/uri-list", False);
136     
137     XtAppAddActions(
138             app,
139             xdndactions,
140             sizeof(xdndactions) / sizeof(XtActionsRec));
141     
142     dropCallback = dropCB;
143     dropData = dropCBData;
144 }
145
146 void XdndEnable(Widget w) {  
147     int version = 4;
148     XChangeProperty(
149             XtDisplay(w),
150             XtWindow(w),
151             XdndAware,
152             XA_ATOM,
153             32,
154             PropModeReplace,
155             (XtPointer)&version,
156             1);
157     
158     if(XtIsShell(w)) {
159         XtOverrideTranslations(w, XtParseTranslationTable(
160                 "<Message>XdndEnter:    xdnd_enter()\n"
161                 "<Message>XdndPosition: xdnd_position()\n"
162                 "<Message>XdndDrop:     xdnd_drop()\n"
163                 "<Message>XdndLeave:    xdnd_leave()\n"));
164     }
165 }