Use return code on dragbox --get when there is no running instance
[dragbox.git] / Dragbox / main.py
bloba6632c9e726f2af25e63890a95c5ddd2084cf6a7
1 # Copyright (C) 2006 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
18 # USA
20 from sys import exit, argv
21 from os import path, fork
23 from utils import print_error, print_debug
25 class dragbox(object):
26 """
27 Dragbox application object
28 """
29 def __init__(self):
30 """
31 This class runs one instance of dragbox
33 + Read commandline
34 + Try dbus connection
35 + Add items
36 + Run
37 """
38 # Read commandline switches
39 (files, texts, cli_flags) = self.read_opts(argv[1:])
41 # Read from stdin
42 from sys import stdin
43 if not stdin.isatty():
44 pipe_text = stdin.read()
45 if pipe_text:
46 texts += [pipe_text]
48 self.cli_flags = cli_flags
50 get = self.cli_flags.get("get")
51 nofork = self.cli_flags.get("no-fork") # there is a cli flag
52 if nofork:
53 self.dbus_connection = None
54 else:
55 self.dbus_connection = self.get_dbus_connection()
56 if get:
57 success = self.try_get_data()
58 raise SystemExit(not success)
59 elif not nofork and self.dbus_connection:
60 self.dbus_send(files, texts)
61 # Done, sent to other running instance
62 raise SystemExit
63 else:
64 self.start_dbus_service()
65 # Fork!
66 pid = fork()
67 if pid:
68 raise SystemExit
70 (self.data_controller, self.writer) = self.init_data()
71 self.add_files(None, files)
72 self.add_texts(None, texts)
73 self.run_window()
75 def init_data(self):
76 from data import DataController
77 data_controller = DataController()
79 quiet = self.cli_flags.get("quiet", True)
80 onexit = self.cli_flags.get("write-on-exit", False)
81 if onexit or not quiet:
82 writer = self.make_writer()
83 if not quiet:
84 data_controller.connect("item-added", writer.print_item)
85 else:
86 writer = None
87 return (data_controller, writer)
89 def make_writer(self):
90 """
91 Return a plugins.Writer object
93 Initialized with current null termination and
94 paths/uris settings
95 """
96 from plugins import Writer
97 null_term = self.cli_flags.get("null", False)
98 paths = self.cli_flags.get("paths", True)
99 writer = Writer(paths, null_term)
100 return writer
102 def run_window(self):
103 from window import WindowController
105 window_title = self.cli_flags.get("window-title", "Dragbox")
106 self.wc = WindowController(self.data_controller, window_title)
107 self.wc.ready_window()
109 try:
110 from gtk import main
111 main()
112 except KeyboardInterrupt:
113 # catch ctrl-c and exit nicely
114 pass
115 self.prepare_quit()
116 # quit
118 def prepare_quit(self):
119 exit = self.cli_flags.get("write-on-exit")
120 if self.writer and exit:
121 self.writer.print_all(self.data_controller)
123 def read_opts(self, argv):
125 Uses gnu getopt to read command line arguments
127 returns a tuple of (files, texts, options)
129 from getopt import gnu_getopt, GetoptError
130 short_opts = "nhf:t:vqpu0x"
131 long_opts = [
132 'help', 'file=', 'text=', 'no-fork',
133 'version', 'quiet' , 'paths', 'uris',
134 'null-terminate', 'window-title=',
135 'write-on-exit', 'no-quiet', 'get'
137 try:
138 (options, arguments) = gnu_getopt(argv, short_opts, long_opts)
139 except GetoptError, exception:
140 print_error("Sorry, %s" % exception)
141 self.print_usage(usage_error=True)
142 prefs = {}
143 # Search for preferences
144 for (o,a) in options:
145 if o in ("-h", "--help"):
146 self.print_usage()
147 elif o in ("-v", "--version"):
148 self.print_version()
149 elif o in ("-n", "--no-fork"):
150 prefs["no-fork"] = True
151 if not prefs.get("quiet"): # make sure we don't ow
152 prefs["quiet"] = False
153 elif o in ("-q", "--quiet"):
154 prefs["quiet"] = True
155 elif o in ("--no-quiet"):
156 prefs["quiet"] = False
157 elif o in ("-p", "--paths"):
158 prefs["paths"] = True
159 elif o in ("-u", "--uris"):
160 prefs["paths"] = False
161 elif o in ("-0", "--null-terminate"):
162 prefs["null"] = True
163 elif o in ("--window-title"):
164 prefs["window-title"] = a
165 elif o in ("-x", "--write-on-exit"):
166 # don't write _asyncronously_
167 prefs["quiet"] = True
168 prefs["write-on-exit"] = True
169 elif o in ("--get"):
170 prefs["get"] = True
172 # Handle strongly typed items
173 files = []
174 texts = []
175 for (o, a) in options:
176 if o in ("-f", "--file"):
177 path = self.check_file_exists(a, warn=True)
178 if path: files.append(path)
179 elif o in ("-t", "--text"):
180 texts.append(a)
181 # Handle rest
182 # Try if they are files
183 text = ""
184 for item in arguments :
185 path = self.check_file_exists(item, warn=False)
186 if path:
187 files.append(path)
188 else:
189 text = text + " " + item
191 # Take rest as one text block
192 if text: texts.append(text)
193 return (files, texts, prefs)
195 def get_dbus_connection(self):
197 Tries to connect ot already running instance
199 from version import dbus_enabled
200 if dbus_enabled != "yes":
201 return None #return with no success
203 try:
204 import dbuscontrol
205 except ImportError, info:
206 print_error(info)
207 return None
209 try:
210 dclient = dbuscontrol.Connection()
211 except dbuscontrol.ServiceUnavailable, info:
212 return None
213 return dclient
215 def dbus_send(self, files, texts):
217 Sends files, texts and activates
219 # Send data to running Service
220 iface = self.dbus_connection.get_interface()
221 if files: iface.send_files(files)
222 if texts: iface.send_texts(texts)
223 iface.activate()
224 send_success = True
225 print_debug("Sent data to %s" % iface)
227 def try_get_data(self):
229 Send get_data method to another instance and try to get its data
231 from shelfitem import make_item
232 if not self.dbus_connection:
233 print_error("No running instance found")
234 return False
235 datas, types = self.dbus_connection.get_interface().get_data()
236 writer = self.make_writer()
237 for data, type in zip(datas, types):
238 writer.print_item(None, make_item(data, type))
239 return True
241 def data_requested(self, service, send_callback, error_callback):
242 print_debug("Data requested from %s" % service)
243 items = self.data_controller.get_items()
244 datas, types = [], []
245 for item in items:
246 datas.append(item.get_object())
247 types.append(item.get_type())
248 send_callback(datas, types)
249 #error_callback(Exception())
251 def start_dbus_service(self):
253 Create a dbus Service object
255 Set up signals for the service
257 import dbuscontrol
258 try:
259 dserver = dbuscontrol.make_service()
260 except Exception, info:
261 from utils import print_debug, print_error
262 print_debug(info)
263 print_error("Failed to use dbus, might not be available")
264 else:
265 self.dbus_service = dserver
266 self.dbus_service.connect("files-received", self.add_files)
267 self.dbus_service.connect("texts-received", self.add_texts)
268 self.dbus_service.connect("activate", self.activate_application)
269 self.dbus_service.connect("data-requested", self.data_requested)
271 def check_file_exists(self, f, warn=True):
273 Check if a file exists
275 f: a local path
276 warn: If True, print an error message and exit if nonexistant
278 p = path.abspath(f)
279 if path.exists(p):
280 return p
281 if not warn:
282 return None
283 print_error("The file %s does not exist" % f)
284 raise SystemExit(1)
286 def add_files(self, service, flist):
288 Adds a list of files to the dragbox
290 flist: a list of absolute paths
292 from shelfitem import FILE_TYPE
294 for f in flist:
295 fileloc = path.abspath(f)
296 self.data_controller.add_item(fileloc, FILE_TYPE)
298 def add_texts(self, service, tlist):
300 Adds a list of text to the dragbox
302 tlist: a list of strings
304 from shelfitem import TEXT_TYPE
306 for text in tlist:
307 self.data_controller.add_item(text, TEXT_TYPE)
309 def activate_application(self, service):
311 Activate and bring to front
313 self.wc.show_window()
315 def print_usage(self, usage_error=False):
316 print """
317 Usage: %s [-nq] item [...]
319 item add item to dragbox
320 added as file if it is a valid path
322 -t, --text "text" add text
323 -f, --file file add file
325 --window-title name set window title to name
327 -n, --no-fork don't fork (also disables use of dbus)
329 The options below only apply with --no-fork:
330 -q, --quiet don't print dragged-in items
331 -p, --paths print paths of dragged-in files (default)
332 -u, --uris print uris of dragged-in files
333 -0, --null-terminate separate items' output with \\0, not \\n
334 -x, --write-on-exit only write contents on exit
337 -h, --help display this help
338 -v, --version display version information
339 """ % "dragbox"
340 raise SystemExit(usage_error)
342 def print_version(self):
343 import version
344 print "%s %s\n\n%s" % (version.package_name, version.version, version.copyright_info)
345 raise SystemExit