Browse Source

xdnd: can handle more than 3 different target types

Now dropping also works with Nemo and PCManFM(gtk)
Andreas Haas 9 years ago
parent
commit
2c9b28df13
1 changed files with 61 additions and 22 deletions
  1. 61 22
      platform/x11/os_x11.cpp

+ 61 - 22
platform/x11/os_x11.cpp

@@ -1180,6 +1180,57 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
 	input->parse_input_event( event);
 }
 
+struct Property
+{
+	unsigned char *data;
+	int format, nitems;
+	Atom type;
+};
+
+static Property read_property(Display* p_display, Window p_window, Atom p_property) {
+
+	Atom actual_type;
+	int actual_format;
+	unsigned long nitems;
+	unsigned long bytes_after;
+	unsigned char *ret=0;
+
+	int read_bytes = 1024;
+
+	//Keep trying to read the property until there are no
+	//bytes unread.
+	do
+	{
+		if(ret != 0)
+			XFree(ret);
+
+		XGetWindowProperty(p_display, p_window, p_property, 0, read_bytes, False, AnyPropertyType,
+					   &actual_type, &actual_format, &nitems, &bytes_after,
+					   &ret);
+
+		read_bytes *= 2;
+
+	}while(bytes_after != 0);
+
+	Property p = {ret, actual_format, nitems, actual_type};
+
+	return p;
+}
+
+static Atom pick_target_from_list(Display* p_display, Atom *p_list, int p_count) {
+
+	static const char* target_type = "text/uri-list";
+
+	for (int i = 0; i < p_count; i++) {
+
+		Atom atom = p_list[i];
+
+		if (atom != None && String(XGetAtomName(p_display, atom)) == target_type)
+				return atom;
+	}
+	return None;
+}
+
 static Atom pick_target_from_atoms(Display* p_disp, Atom p_t1, Atom p_t2, Atom p_t3) {
 
 	static const char* target_type = "text/uri-list";
@@ -1489,28 +1540,9 @@ void OS_X11::process_xevents() {
 
 			if (event.xselection.target == requested) {
 
-				Atom actual_type;
-				int actual_format;
-				unsigned long nitems;
-				unsigned long bytes_after;
-				unsigned char *ret=0;
-
-				int read_bytes = 1024;
+				Property p = read_property(x11_display, x11_window, XInternAtom(x11_display, "PRIMARY", 0));
 
-				//Keep trying to read the property until there are no
-				//bytes unread.
-				do
-				{
-					if(ret != 0)
-						XFree(ret);
-					XGetWindowProperty(x11_display, x11_window, XInternAtom(x11_display, "PRIMARY", 0), 0, read_bytes, False, AnyPropertyType,
-									   &actual_type, &actual_format, &nitems, &bytes_after,
-									   &ret);
-
-					read_bytes *= 2;
-				}while(bytes_after != 0);
-
-				Vector<String> files = String((char *)ret).split("\n", false);
+				Vector<String> files = String((char *)p.data).split("\n", false);
 				for (int i = 0; i < files.size(); i++) {
 					files[i] = files[i].replace("file://", "").replace("%20", " ").strip_escapes();
 				}
@@ -1541,7 +1573,14 @@ void OS_X11::process_xevents() {
 
 				//File(s) have been dragged over the window, check for supported target (text/uri-list)
 				xdnd_version = ( event.xclient.data.l[1] >> 24);
-				requested = pick_target_from_atoms(x11_display, event.xclient.data.l[2],event.xclient.data.l[3], event.xclient.data.l[4]);
+				Window source = event.xclient.data.l[0];
+				bool more_than_3 = event.xclient.data.l[1] & 1;
+				if (more_than_3) {
+					Property p = read_property(x11_display, source, XInternAtom(x11_display, "XdndTypeList", False));
+					requested = pick_target_from_list(x11_display, (Atom*)p.data, p.nitems);
+				}
+				else
+					requested = pick_target_from_atoms(x11_display, event.xclient.data.l[2],event.xclient.data.l[3], event.xclient.data.l[4]);
 			}
 			else if ((unsigned int)event.xclient.message_type == (unsigned int )xdnd_position) {