+ case SelectionNotify:
+ {
+ Atom target = e.xselection.target;
+
+ fprintf(stderr, "DnD %s:%d: A selection notify has arrived!\n", __FILE__, __LINE__);
+ fprintf(stderr, "DnD %s:%d: Requestor = %lu\n", __FILE__, __LINE__, e.xselectionrequest.requestor);
+ fprintf(stderr, "DnD %s:%d: Selection atom = %s\n", __FILE__, __LINE__, GetAtomName(server.dsp, e.xselection.selection));
+ fprintf(stderr, "DnD %s:%d: Target atom = %s\n", __FILE__, __LINE__, GetAtomName(server.dsp, target));
+ fprintf(stderr, "DnD %s:%d: Property atom = %s\n", __FILE__, __LINE__, GetAtomName(server.dsp, e.xselection.property));
+
+ if (e.xselection.property != None && dnd_launcher_exec) {
+ Property prop = read_property(server.dsp, dnd_target_window, dnd_selection);
+
+ //If we're being given a list of targets (possible conversions)
+ if (target == server.atom.TARGETS && !dnd_sent_request) {
+ dnd_sent_request = 1;
+ dnd_atom = pick_target_from_targets(server.dsp, prop);
+
+ if (dnd_atom == None) {
+ fprintf(stderr, "No matching datatypes.\n");
+ } else {
+ //Request the data type we are able to select
+ fprintf(stderr, "Now requsting type %s", GetAtomName(server.dsp, dnd_atom));
+ XConvertSelection(server.dsp, dnd_selection, dnd_atom, dnd_selection, dnd_target_window, CurrentTime);
+ }
+ } else if (target == dnd_atom) {
+ //Dump the binary data
+ fprintf(stderr, "DnD %s:%d: Data begins:\n", __FILE__, __LINE__);
+ fprintf(stderr, "--------\n");
+ int i;
+ for (i = 0; i < prop.nitems * prop.format/8; i++)
+ fprintf(stderr, "%c", ((char*)prop.data)[i]);
+ fprintf(stderr, "--------\n");
+
+ int cmd_length = 0;
+ cmd_length += 1; // (
+ cmd_length += strlen(dnd_launcher_exec) + 1; // exec + space
+ cmd_length += 1; // open double quotes
+ for (i = 0; i < prop.nitems * prop.format/8; i++) {
+ char c = ((char*)prop.data)[i];
+ if (c == '\n') {
+ if (i < prop.nitems * prop.format/8 - 1) {
+ cmd_length += 3; // close double quotes, space, open double quotes
+ }
+ } else if (c == '\r') {
+ } else {
+ cmd_length += 1; // 1 character
+ if (c == '`' || c == '$' || c == '\\') {
+ cmd_length += 1; // escape with one backslash
+ }
+ }
+ }
+ cmd_length += 1; // close double quotes
+ cmd_length += 2; // &)
+ cmd_length += 1; // terminator
+
+ char *cmd = malloc(cmd_length);
+ cmd[0] = '\0';
+ strcat(cmd, "(");
+ strcat(cmd, dnd_launcher_exec);
+ strcat(cmd, " \"");
+ for (i = 0; i < prop.nitems * prop.format/8; i++) {
+ char c = ((char*)prop.data)[i];
+ if (c == '\n') {
+ if (i < prop.nitems * prop.format/8 - 1) {
+ strcat(cmd, "\" \"");
+ }
+ } else if (c == '\r') {
+ } else {
+ if (c == '`' || c == '$' || c == '\\') {
+ strcat(cmd, "\\");
+ }
+ char sc[2];
+ sc[0] = c;
+ sc[1] = '\0';
+ strcat(cmd, sc);
+ }
+ }
+ strcat(cmd, "\"");
+ strcat(cmd, "&)");
+ fprintf(stderr, "DnD %s:%d: Running command: %s\n", __FILE__, __LINE__, cmd);
+ tint_exec(cmd);
+ free(cmd);
+
+ // Reply OK.
+ XClientMessageEvent m;
+ memset(&m, sizeof(m), 0);
+ m.type = ClientMessage;
+ m.display = server.dsp;
+ m.window = dnd_source_window;
+ m.message_type = server.atom.XdndFinished;
+ m.format = 32;
+ m.data.l[0] = dnd_target_window;
+ m.data.l[1] = 1;
+ m.data.l[2] = server.atom.XdndActionCopy; //We only ever copy.
+ XSendEvent(server.dsp, dnd_source_window, False, NoEventMask, (XEvent*)&m);
+ XSync(server.dsp, False);
+ }
+
+ XFree(prop.data);
+ }
+
+ break;
+ }
+