add xdnd code from xnedit
[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     XtGetSelectionValue(w, XdndSelection, selType, checkSelectionValue, NULL, 0);
81 }
82
83 static void xdnd_position(Widget w, XEvent *event, String *args, Cardinal *nArgs) {
84     //printf("xdnd_position\n");
85     
86     src = event->xclient.data.l[0];
87     
88     XEvent msg;
89     memset(&msg, 0, sizeof(XEvent));
90     msg.xany.type = ClientMessage;
91     msg.xany.display = XtDisplay(w);
92     msg.xclient.window = src;
93     msg.xclient.message_type = XdndStatus;
94     msg.xclient.format = 32;
95     msg.xclient.data.l[0] = XtWindow(w);
96     msg.xclient.data.l[1] = canDrop;
97     msg.xclient.data.l[4] = XdndActionCopy;
98     XSendEvent(XtDisplay(w), msg.xclient.window, 0, 0, &msg);
99 }
100
101 static void xdnd_drop(Widget w, XEvent *event, String *args, Cardinal *nArgs) {
102     //printf("xdnd_drop\n");
103     
104     XtGetSelectionValue(w, XdndSelection, selType, getSelectionValue, NULL, 0);
105     
106     canDrop = 0;
107 }
108
109 static void xdnd_leave(Widget w, XEvent *event, String *args, Cardinal *nArgs) {
110     //printf("xdnd_leave\n");
111     canDrop = 0;
112 }
113
114 static XtActionsRec xdndactions[] = {
115     {"xdnd_enter", xdnd_enter},
116     {"xdnd_position", xdnd_position},
117     {"xdnd_drop", xdnd_drop},
118     {"xdnd_leave", xdnd_leave}
119 };
120
121
122 void XdndInit(
123         Display *dpy,
124         XtAppContext app,
125         XtCallbackProc dropCB,
126         XtPointer dropCBData)
127 {
128     // init atoms
129     XdndAware = XInternAtom(dpy, "XdndAware", False);
130     XdndSelection = XInternAtom(dpy, "XdndSelection", False);
131     XdndStatus = XInternAtom(dpy, "XdndStatus", False);
132     XdndActionCopy = XInternAtom(dpy, "XdndActionCopy", False);
133     XdndFinished = XInternAtom(dpy, "XdndFinished", False);
134     selType = XInternAtom(dpy, "text/uri-list", False);
135     
136     XtAppAddActions(
137             app,
138             xdndactions,
139             sizeof(xdndactions) / sizeof(XtActionsRec));
140     
141     dropCallback = dropCB;
142     dropData = dropCBData;
143 }
144
145 void XdndEnable(Widget w) {
146     int version = 4;
147     XChangeProperty(
148             XtDisplay(w),
149             XtWindow(w),
150             XdndAware,
151             XA_ATOM,
152             32,
153             PropModeReplace,
154             (XtPointer)&version,
155             1);
156     
157     if(XtIsShell(w)) {
158         XtOverrideTranslations(w, XtParseTranslationTable(
159                 "<Message>XdndEnter:    xdnd_enter()\n"
160                 "<Message>XdndPosition: xdnd_position()\n"
161                 "<Message>XdndDrop:     xdnd_drop()\n"
162                 "<Message>XdndLeave:    xdnd_leave()\n"));
163     }
164 }