+ if (t1 != None)
+ atoms[n++] = t1;
+
+ if (t2 != None)
+ atoms[n++] = t2;
+
+ if (t3 != None)
+ atoms[n++] = t3;
+
+ return pick_target_from_list(disp, atoms, n);
+}
+
+// Finds the best target given a local copy of a property.
+Atom pick_target_from_targets(Display* disp, Property p)
+{
+ //The list of targets is a list of atoms, so it should have type XA_ATOM
+ //but it may have the type TARGETS instead.
+
+ if ((p.type != XA_ATOM && p.type != server.atom.TARGETS) || p.format != 32) {
+ //This would be really broken. Targets have to be an atom list
+ //and applications should support this. Nevertheless, some
+ //seem broken (MATLAB 7, for instance), so ask for STRING
+ //next instead as the lowest common denominator
+ return XA_STRING;
+ } else {
+ Atom *atom_list = (Atom*)p.data;
+
+ return pick_target_from_list(disp, atom_list, p.nitems);
+ }
+}
+
+void dnd_enter(XClientMessageEvent *e)
+{
+ dnd_atom = None;
+ int more_than_3 = e->data.l[1] & 1;
+ dnd_source_window = e->data.l[0];
+ dnd_version = (e->data.l[1] >> 24);
+
+ fprintf(stderr, "DnD %s:%d: DnDEnter\n", __FILE__, __LINE__);
+ fprintf(stderr, "DnD %s:%d: DnDEnter. Supports > 3 types = %s\n", __FILE__, __LINE__, more_than_3 ? "yes" : "no");
+ fprintf(stderr, "DnD %s:%d: Protocol version = %d\n", __FILE__, __LINE__, dnd_version);
+ fprintf(stderr, "DnD %s:%d: Type 1 = %s\n", __FILE__, __LINE__, GetAtomName(server.dsp, e->data.l[2]));
+ fprintf(stderr, "DnD %s:%d: Type 2 = %s\n", __FILE__, __LINE__, GetAtomName(server.dsp, e->data.l[3]));
+ fprintf(stderr, "DnD %s:%d: Type 3 = %s\n", __FILE__, __LINE__, GetAtomName(server.dsp, e->data.l[4]));
+
+ //Query which conversions are available and pick the best
+
+ if (more_than_3) {
+ //Fetch the list of possible conversions
+ //Notice the similarity to TARGETS with paste.
+ Property p = read_property(server.dsp, dnd_source_window, server.atom.XdndTypeList);
+ dnd_atom = pick_target_from_targets(server.dsp, p);
+ XFree(p.data);
+ } else {
+ //Use the available list
+ dnd_atom = pick_target_from_atoms(server.dsp, e->data.l[2], e->data.l[3], e->data.l[4]);
+ }
+
+ fprintf(stderr, "DnD %s:%d: Requested type = %s\n", __FILE__, __LINE__, GetAtomName(server.dsp, dnd_atom));
+}
+
+void dnd_position(XClientMessageEvent *e)
+{
+ dnd_target_window = e->window;
+ int accept = 0;
+ Panel *panel = get_panel(e->window);
+ int x, y, mapX, mapY;
+ Window child;
+ x = (e->data.l[2] >> 16) & 0xFFFF;
+ y = e->data.l[2] & 0xFFFF;
+ XTranslateCoordinates(server.dsp, server.root_win, e->window, x, y, &mapX, &mapY, &child);
+ Task* task = click_task(panel, mapX, mapY);
+ if (task) {
+ if (task->desktop != server.desktop )
+ set_desktop (task->desktop);
+ window_action(task, TOGGLE);
+ } else {
+ LauncherIcon *icon = click_launcher_icon(panel, mapX, mapY);
+ if (icon) {
+ accept = 1;
+ dnd_launcher_exec = icon->cmd;
+ } else {
+ dnd_launcher_exec = 0;
+ }
+ }
+
+ // send XdndStatus event to get more XdndPosition events
+ XClientMessageEvent se;
+ se.type = ClientMessage;
+ se.window = e->data.l[0];
+ se.message_type = server.atom.XdndStatus;
+ se.format = 32;
+ se.data.l[0] = e->window; // XID of the target window
+ se.data.l[1] = accept ? 1 : 0; // bit 0: accept drop bit 1: send XdndPosition events if inside rectangle
+ se.data.l[2] = 0; // Rectangle x,y for which no more XdndPosition events
+ se.data.l[3] = (1 << 16) | 1; // Rectangle w,h for which no more XdndPosition events
+ if (accept) {
+ se.data.l[4] = dnd_version >= 2 ? e->data.l[4] : server.atom.XdndActionCopy;
+ } else {
+ se.data.l[4] = None; // None = drop will not be accepted