1 # Copyright (C) 2006, 2007 Ulrik Sverdrup
3 # dragbox -- Commandline drag-and-drop tool for GNOME
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
20 from sys
import exit
, argv
21 from os
import path
, fork
23 from utils
import print_error
, print_debug
25 class dragbox(object):
27 Dragbox application object
31 Entrance point for the dragbox application
38 # Read commandline switches
39 (files
, texts
, cli_flags
) = self
.read_opts(argv
[1:])
43 if not stdin
.isatty():
44 pipe_text
= stdin
.read()
48 self
.cli_flags
= cli_flags
50 get
= self
.cli_flags
.get("get")
51 list_names
= self
.cli_flags
.get("list-names")
52 nofork
= self
.cli_flags
.get("no-fork")
53 self
.identifier
= self
.cli_flags
.get("identifier")
58 self
.dbus_connection
= None
63 self
.dbus_connection
= self
.get_dbus_connection()
65 success
= self
.try_get_data()
67 elif not nofork
and self
.dbus_connection
:
68 self
.dbus_send(files
, texts
)
71 self
.dbus_service
= self
.start_dbus_service()
72 # Fork to disconnect from terminal
77 raise SystemExit(not success
)
79 (self
.data_controller
, self
.writer
) = self
.init_data()
80 self
.add_files(None, files
)
81 self
.add_texts(None, texts
)
86 Create the data controller and a connected plugins.Writer
88 return a tuple of data controller and writer
90 from data
import DataController
91 data_controller
= DataController()
93 quiet
= self
.cli_flags
.get("quiet", True)
94 onexit
= self
.cli_flags
.get("write-on-exit", False)
95 if onexit
or not quiet
:
96 writer
= self
.make_writer()
98 data_controller
.connect("item-added", writer
.print_item
)
101 return (data_controller
, writer
)
103 def make_writer(self
):
105 Return a plugins.Writer object
107 Initialized with current null termination and
110 from plugins
import Writer
111 null_term
= self
.cli_flags
.get("null", False)
112 paths
= self
.cli_flags
.get("paths", True)
113 writer
= Writer(paths
, null_term
)
116 def run_window(self
):
118 Retrieve the window controller, ready it and run the mainloop
120 from window
import WindowController
122 window_title
= self
.cli_flags
.get("window-title", "Dragbox")
124 window_title
+= (" (%s)" % self
.identifier
)
125 self
.wc
= WindowController(self
.data_controller
, window_title
)
126 self
.wc
.ready_window()
131 except KeyboardInterrupt:
132 # catch ctrl-c and exit nicely
137 def prepare_quit(self
):
138 exit
= self
.cli_flags
.get("write-on-exit")
139 if self
.writer
and exit
:
140 self
.writer
.print_all(self
.data_controller
)
142 def read_opts(self
, argv
):
144 Uses gnu getopt to read command line arguments
146 returns a tuple of (files, texts, options)
148 from getopt
import gnu_getopt
, GetoptError
149 short_opts
= "hf:t:nvpu0axm:"
167 (options
, arguments
) = gnu_getopt(argv
, short_opts
, long_opts
)
168 except GetoptError
, exception
:
169 print_error("%s" % exception
)
170 self
.print_usage(usage_error
=True)
172 # store command line flags in `prefs`
173 # quiet: if True, output async
174 # list-names: if True, list running instances
175 for (o
,a
) in options
:
176 if o
in ("-h", "--help"):
178 elif o
in ("-v", "--version"):
180 elif o
in ("-n", "--no-fork"):
181 prefs
["no-fork"] = True
182 prefs
["quiet"] = True
183 prefs
["write-on-exit"] = True
184 elif o
in ("-p", "--paths"):
185 prefs
["paths"] = True
186 elif o
in ("-u", "--uris"):
187 prefs
["paths"] = False
188 elif o
in ("-0", "--null-terminate"):
190 elif o
in ("--window-title"):
191 prefs
["window-title"] = a
192 elif o
in ("-x", "--write-on-exit"):
193 # don't write _asyncronously_
194 prefs
["quiet"] = True
195 prefs
["write-on-exit"] = True
196 elif o
in ("-a", "--write-async"):
197 # don't write _asyncronously_
198 prefs
["quiet"] = False
199 prefs
["write-on-exit"] = False
202 elif o
in ("-m", "--name"):
203 prefs
["identifier"] = a
204 elif o
in ("--list"):
205 prefs
["list-names"] = True
207 # Handle strongly typed items
210 for (o
, a
) in options
:
211 if o
in ("-f", "--file"):
212 path
= self
.check_file_exists(a
, warn
=True)
213 if path
: files
.append(path
)
214 elif o
in ("-t", "--text"):
217 # Try if they are files
219 for item
in arguments
:
220 path
= self
.check_file_exists(item
, warn
=False)
224 text
= text
+ " " + item
226 # Take rest as one text block
227 if text
: texts
.append(text
)
228 return (files
, texts
, prefs
)
230 def check_file_exists(self
, f
, warn
=True):
232 Check if a file exists
235 warn: If True, print an error message and exit if nonexistant
242 print_error("The file %s does not exist" % f
)
245 def get_dbus_connection(self
):
247 Tries to connect to already running instance
251 except ImportError, info
:
256 dclient
= dbuscontrol
.Connection(self
.identifier
)
257 except dbuscontrol
.ServiceUnavailable
, info
:
261 def dbus_send(self
, files
, texts
):
263 Sends files, texts and activates
265 # Send data to running Service
266 iface
= self
.dbus_connection
.get_interface()
267 if files
: iface
.send_files(files
)
268 if texts
: iface
.send_texts(texts
)
271 print_debug("Sent data to %s" % iface
)
273 def try_get_data(self
):
275 Send get_data method to another instance and try to get its data
277 from shelfitem
import make_item
278 if not self
.dbus_connection
:
279 # dbus is not available or the requested name
280 # is simply not there
281 name
= self
.identifier
and self
.identifier
or "Default"
282 print_error("Shelf %s not found" % name
)
283 self
.get_dbus_names()
285 datas
, types
= self
.dbus_connection
.get_interface().get_data()
286 writer
= self
.make_writer()
287 for data
, type in zip(datas
, types
):
288 writer
.print_item(None, make_item(data
, type))
291 def data_requested(self
, service
, send_callback
, error_callback
):
293 data-requested-callback from the dbus service
295 print_debug("Data requested from %s" % service
)
296 items
= self
.data_controller
.get_items()
297 datas
, types
= [], []
299 datas
.append(item
.get_object())
300 types
.append(item
.get_type())
301 send_callback(datas
, types
)
303 def start_dbus_service(self
):
305 Create a dbus Service object
307 Set up signals for the service
308 return the created service or None
312 dserver
= dbuscontrol
.make_service(self
.identifier
)
313 except Exception, info
:
314 from utils
import print_debug
, print_error
316 print_error("Failed to use dbus, might not be available")
319 dbus_service
= dserver
320 dbus_service
.connect("files-received", self
.add_files
)
321 dbus_service
.connect("texts-received", self
.add_texts
)
322 dbus_service
.connect("activate", self
.activate_application
)
323 dbus_service
.connect("data-requested", self
.data_requested
)
326 def get_dbus_names(self
):
327 from dbuscontrol
import list_names
328 from utils
import print_error
330 names
= list(list_names())
331 except Exception, info
:
334 print "%d shelves available" % len(names
)
337 print u
"\n ".join(names
)
339 def add_files(self
, service
, flist
):
341 Adds a list of files to the dragbox
343 flist: a list of absolute paths
345 from shelfitem
import FILE_TYPE
348 fileloc
= path
.abspath(f
)
349 self
.data_controller
.add_item(fileloc
, FILE_TYPE
)
351 def add_texts(self
, service
, tlist
):
353 Adds a list of text to the dragbox
355 tlist: a list of strings
357 from shelfitem
import TEXT_TYPE
360 self
.data_controller
.add_item(text
, TEXT_TYPE
)
362 def activate_application(self
, service
):
364 Activate and bring to front
366 self
.wc
.show_window()
368 def print_usage(self
, usage_error
=False):
370 Usage: dragbox [-naxpu0] [--get | --list] [--name id] [item ...]
372 item add item to dragbox
373 added as file if it is an existing path
375 -t, --text "text" add text
376 -f, --file file add file
378 --get output contents of a running dragbox
379 --list list running dragboxes by identifier
381 -m, --name name set identifier
382 --window-title title set window title
383 -n, --no-fork don't fork (also disables intercommunication)
386 -a, --write-async write items as they are recieved
387 -x, --write-on-exit write items on exit
388 -p, --paths print paths of dragged-in files (default)
389 -u, --uris print uris of dragged-in files
390 -0, --null-terminate separate output items with \\0, not \\n
393 -h, --help display this help
394 -v, --version display version information
397 raise SystemExit(usage_error
)
399 def print_version(self
):
401 print "%s %s\n\n%s" % (version
.package_name
, version
.version
, version
.copyright_info
)