Index: channels/dnd.py ================================================================== --- channels/dnd.py +++ channels/dnd.py @@ -107,11 +107,10 @@ # Hook to main, and extend channel tabs def __init__(self, parent): self.parent = parent parent.hooks["init"].append(self.add_dnd) conf.add_plugin_defaults(self.meta, self.module) - log.colors["DND"] = "1;33;41m" # Attach drag and drop handlers to each channels´ station TreeView def add_dnd(self, parent): @@ -124,10 +123,16 @@ w.connect('drag-data-get', self.data_get) # bind DESTINATION events w.enable_model_drag_dest(self.drag_types, gtk.gdk.ACTION_DEFAULT|gtk.gdk.ACTION_COPY) w.connect('drag-drop', self.drop) w.connect('drag-data-received', self.data_received) + + # register bookmarks category as destination too + w = parent.bookmarks.gtk_cat + w.enable_model_drag_dest([self.drag_types[0]], gtk.gdk.ACTION_DEFAULT|gtk.gdk.ACTION_MOVE) + w.connect('drag-data-received', self.data_received) + # -- SOURCE, drag'n'drop from ST2 to elsewhere -- @@ -134,11 +139,12 @@ # Starting to drag a row def begin(self, widget, context): log.DND("source→out: begin-drag, store current row") self.row = self.treelist_row() self.buf = {} - uikit.do(context.set_icon_stock, gtk.STOCK_ADD, 16, 16) + if "set_icon_stock" in dir(context): + uikit.do(context.set_icon_stock, gtk.STOCK_ADD, 16, 16) return "url" in self.row # Keep currently selected row when source dragging starts def treelist_row(self): cn = self.parent.channel() @@ -152,14 +158,16 @@ # Target window/app requests data for offered drop def data_get(self, widget, context, selection, info, time): log.DND("source→out: data-get, send and convert to requested target type:", info, selection.get_target()) # Return prepared data func, data = self.export_row(info, self.row) + log.DND("data==", func, data) if func.find("text") >= 0: # Yay for trial and error. Nay for docs. PyGtks selection.set_text() doesn't # actually work unless the requested target type is an Atom. Therefore "STRING". selection.set("STRING", 8, data) + # Neither gtk.gdk.TARGET_STRING nor selection.get_target() satisfy Gtk3 however if func.find("uris") >= 0: selection.set_uris(data) return True # Handles the conversion from the stored .row to the desired selection data @@ -186,13 +194,18 @@ # Text sources are assumed to understand the literal URL or expect a description block elif info >= 5: buf = 'text', "{url}\n# Title: {title}\n# Homepage: {homepage}\n\n".format(**r) # Create temporary PLS file, because "text/uri-list" is widely misunderstood and just implemented for file:// IRLs else: - tmpfn = "{}/{}.{}".format(conf.tmp, re.sub("[^\w-]+", " ", r["title"]).strip(), conf.dnd_format) + title = re.sub("[^\w-]+", "_", r["title"]).strip() + tmpfn = "{}/{}.{}".format(conf.tmp, title, conf.dnd_format) + log.DND("tmpfn", tmpfn) cnv.file(rows=[r], dest=conf.dnd_format, fn=tmpfn) - buf = 'uris', ["file://{}".format(tmpfn)] if (info==4) else tmpfn + if info == 4: + buf = 'uris', ["file://{}".format(tmpfn)] + else: + buf = 'text', tmpfn # Keep in type request buffer self.buf[info] = buf return buf Index: config.py ================================================================== --- config.py +++ config.py @@ -500,10 +500,11 @@ colors = { "ERR": "31m", # red ERROR "INIT": "31m", # red INIT ERROR "PROC": "32m", # green PROCESS "CONF": "33m", # brown CONFIG DATA + "DND": "1;33;41m", # DRAG'N'DROP "UI": "34m", # blue USER INTERFACE BEHAVIOUR "UIKIT":"38;5;222;48;5;235m", # THREAD/UIKIT/IDLE TASKS "HTTP": "35m", # magenta HTTP REQUEST "DATA": "36m", # cyan DATA "INFO": "37m", # gray INFO