3 #########################################################################
\r
5 # Author : Choopan RATTANAPOKA, Jie Yang, Arno Bakker
\r
7 # Description : Main ABC [Yet Another Bittorrent Client] python script.
\r
8 # you can run from source code by using
\r
10 # need Python, WxPython in order to run from source code.
\r
11 #########################################################################
\r
13 # Arno: M2Crypto overrides the method for https:// in the
\r
14 # standard Python libraries. This causes msnlib to fail and makes Tribler
\r
15 # freakout when "http://www.tribler.org/version" is redirected to
\r
16 # "https://www.tribler.org/version/" (which happened during our website
\r
17 # changeover) Until M2Crypto 0.16 is patched I'll restore the method to the
\r
18 # original, as follows.
\r
20 # This must be done in the first python file that is started.
\r
24 original_open_https = urllib.URLopener.open_https
\r
26 urllib.URLopener.open_https = original_open_https
\r
34 if sys.platform == "darwin":
\r
35 # on Mac, we can only load VLC libraries
\r
36 # relative to the location of tribler.py
\r
37 os.chdir(os.path.abspath(os.path.dirname(sys.argv[0])))
\r
39 from threading import Thread, Timer, Event,currentThread,enumerate
\r
40 from time import time, ctime, sleep
\r
41 from traceback import print_exc, print_stack
\r
42 from cStringIO import StringIO
\r
45 from interconn import ServerListener, ClientPassParam
\r
46 from launchmanycore import ABCLaunchMany
\r
48 from ABC.Toolbars.toolbars import ABCBottomBar2, ABCStatusBar, ABCMenuBar, ABCToolBar
\r
49 from ABC.GUI.menu import ABCMenu
\r
50 from ABC.Scheduler.scheduler import ABCScheduler
\r
52 from webservice import WebListener
\r
54 if (sys.platform == 'win32'):
\r
55 from Dialogs.regdialog import RegCheckDialog
\r
57 from ABC.GUI.list import ManagedList
\r
58 from Utility.utility import Utility
\r
59 from Utility.constants import * #IGNORE:W0611
\r
61 from Tribler.__init__ import tribler_init, tribler_done
\r
62 from BitTornado.__init__ import product_name
\r
63 from safeguiupdate import DelayedInvocation,FlaglessDelayedInvocation
\r
65 from Tribler.Dialogs.MugshotManager import MugshotManager
\r
66 from Tribler.vwxGUI.GuiUtility import GUIUtility
\r
67 import Tribler.vwxGUI.updateXRC as updateXRC
\r
68 from Tribler.Video.VideoPlayer import VideoPlayer,return_feasible_playback_modes,PLAYBACKMODE_INTERNAL
\r
69 from Tribler.Video.VideoServer import VideoHTTPServer
\r
70 from Tribler.Dialogs.GUIServer import GUIServer
\r
71 from Tribler.vwxGUI.TasteHeart import set_tasteheart_bitmaps
\r
72 from Tribler.vwxGUI.perfBar import set_perfBar_bitmaps
\r
73 from Tribler.Dialogs.BandwidthSelector import BandwidthSelector
\r
74 from Tribler.Subscriptions.rss_client import TorrentFeedThread
\r
75 from Tribler.Dialogs.activities import *
\r
76 from Tribler.DecentralizedTracking import mainlineDHT
\r
77 from Tribler.DecentralizedTracking.rsconvert import RawServerConverter
\r
78 from Tribler.DecentralizedTracking.mainlineDHTChecker import mainlineDHTChecker
\r
80 from Tribler.notification import init as notification_init
\r
81 from Tribler.vwxGUI.font import *
\r
82 from Tribler.Web2.util.update import Web2Updater
\r
84 from Tribler.CacheDB.CacheDBHandler import BarterCastDBHandler
\r
85 from Tribler.Overlay.permid import permid_for_user
\r
86 from BitTornado.download_bt1 import EVIL
\r
89 ALLOW_MULTIPLE = False
\r
94 ################################################################
\r
96 # Class: FileDropTarget
\r
98 # To enable drag and drop for ABC list in main menu
\r
100 ################################################################
\r
101 class FileDropTarget(wx.FileDropTarget):
\r
102 def __init__(self, utility):
\r
103 # Initialize the wsFileDropTarget Object
\r
104 wx.FileDropTarget.__init__(self)
\r
105 # Store the Object Reference for dropped files
\r
106 self.utility = utility
\r
108 def OnDropFiles(self, x, y, filenames):
\r
109 for filename in filenames:
\r
110 self.utility.queue.addtorrents.AddTorrentFromFile(filename)
\r
114 ##############################################################
\r
118 # ABC List class that contains the torrent list
\r
120 ##############################################################
\r
121 class ABCList(ManagedList):
\r
122 def __init__(self, parent):
\r
123 style = wx.LC_REPORT|wx.LC_VRULES|wx.CLIP_CHILDREN
\r
129 rightalign = [COL_PROGRESS,
\r
139 ManagedList.__init__(self, parent, style, prefix, minid, maxid, exclude, rightalign)
\r
141 dragdroplist = FileDropTarget(self.utility)
\r
142 self.SetDropTarget(dragdroplist)
\r
144 self.lastcolumnsorted = -1
\r
145 self.reversesort = 0
\r
147 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
\r
148 self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColLeftClick)
\r
150 self.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.OnItemSelected)
\r
152 # Bring up advanced details on left double click
\r
153 self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick)
\r
155 # Bring up local settings on middle double click
\r
156 self.Bind(wx.EVT_MIDDLE_DCLICK, self.utility.actions[ACTION_LOCALUPLOAD].action)
\r
158 # Do thing when keys are pressed down
\r
159 def OnKeyDown(self, event):
\r
160 keycode = event.GetKeyCode()
\r
161 if event.CmdDown():
\r
162 if keycode == ord('a') or keycode == ord('A'):
\r
163 # Select all files (CTRL-A)
\r
165 elif keycode == ord('x') or keycode == ord('X'):
\r
166 # Invert file selection (CTRL-X)
\r
167 self.invertSelection()
\r
168 elif keycode == wx.WXK_RETURN or keycode == wx.WXK_NUMPAD_ENTER:
\r
169 # Open advanced details (Enter)
\r
170 self.utility.actions[ACTION_DETAILS].action()
\r
171 elif keycode == wx.WXK_SPACE:
\r
172 # Open local settings (Space)
\r
173 self.utility.actions[ACTION_LOCALUPLOAD].action()
\r
174 elif keycode == 399:
\r
175 # Open right-click menu (windows menu key)
\r
176 self.OnItemSelected()
\r
180 def OnColLeftClick(self, event):
\r
181 rank = event.GetColumn()
\r
182 colid = self.columns.getIDfromRank(rank)
\r
183 if colid == self.lastcolumnsorted:
\r
184 self.reversesort = 1 - self.reversesort
\r
186 self.reversesort = 0
\r
187 self.lastcolumnsorted = colid
\r
188 self.utility.queue.sortList(colid, self.reversesort)
\r
190 def selectAll(self):
\r
191 self.updateSelected(select = range(0, self.GetItemCount()))
\r
193 def updateSelected(self, unselect = None, select = None):
\r
194 if unselect is not None:
\r
195 for index in unselect:
\r
196 self.SetItemState(index, 0, wx.LIST_STATE_SELECTED)
\r
197 if select is not None:
\r
198 for index in select:
\r
202 def getTorrentSelected(self, firstitemonly = False, reverse = False):
\r
203 queue = self.utility.queue
\r
205 torrentselected = []
\r
206 for index in self.getSelected(firstitemonly, reverse):
\r
207 ABCTorrentTemp = queue.getABCTorrent(index = index)
\r
208 if ABCTorrentTemp is not None:
\r
209 torrentselected.append(ABCTorrentTemp)
\r
210 return torrentselected
\r
212 def OnItemSelected(self, event = None):
\r
213 selected = self.getTorrentSelected()
\r
217 popupmenu = ABCMenu(self.utility, 'menu_listrightclick')
\r
219 # Popup the menu. If an item is selected then its handler
\r
220 # will be called before PopupMenu returns.
\r
222 # use the position of the first selected item (key event)
\r
223 ABCTorrentTemp = selected[0]
\r
224 position = self.GetItemPosition(ABCTorrentTemp.listindex)
\r
226 # use the cursor position (mouse event)
\r
227 position = event.GetPosition()
\r
229 self.PopupMenu(popupmenu, position)
\r
231 def OnLeftDClick(self, event):
\r
234 self.utility.actions[ACTION_DETAILS].action()
\r
239 ##############################################################
\r
243 # Main ABC Panel class
\r
245 ##############################################################
\r
246 class ABCPanel(wx.Panel):
\r
247 def __init__(self, parent):
\r
248 style = wx.CLIP_CHILDREN
\r
249 wx.Panel.__init__(self, parent, -1, style = style)
\r
252 sys.stdout.write('Preparing GUI.\n');
\r
254 self.utility = parent.utility
\r
255 self.utility.window = self
\r
256 self.queue = self.utility.queue
\r
258 # List of deleting torrents events that occur when the RateManager is active
\r
259 # Such events are processed after the RateManager finishes
\r
260 # postponedevents is a list of tupples : each tupple contains the method of ABCPanel to be called to
\r
261 # deal with the event and the event.
\r
262 self.postponedevents = []
\r
264 #Manual Bittorrent Adding UI
\r
265 ##############################
\r
266 colSizer = wx.BoxSizer(wx.VERTICAL)
\r
268 self.list = ABCList(self)
\r
269 self.utility.list = self.list
\r
270 colSizer.Add(self.list, 1, wx.ALL|wx.EXPAND, 3)
\r
274 statbarbox = wx.BoxSizer(wx.HORIZONTAL)
\r
275 self.sb_buttons = ABCStatusButtons(self,self.utility)
\r
276 statbarbox.Add(self.sb_buttons, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 0)
\r
277 self.abc_sb = ABCStatusBar(self,self.utility)
\r
278 statbarbox.Add(self.abc_sb, 1, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 0)
\r
279 colSizer.Add(statbarbox, 0, wx.ALL|wx.EXPAND, 0)
\r
282 #colSizer.Add(self.contentPanel, 1, wx.ALL|wx.EXPAND, 3)
\r
283 self.SetSizer(colSizer)
\r
284 self.SetAutoLayout(True)
\r
286 self.list.SetFocus()
\r
289 def getSelectedList(self, event = None):
\r
292 ######################################
\r
293 # Update ABC on-the-fly
\r
294 ######################################
\r
295 def updateColumns(self, force = False):
\r
296 # Update display in column for inactive torrent
\r
297 for ABCTorrentTemp in self.utility.torrents["all"]:
\r
298 ABCTorrentTemp.updateColumns(force = force)
\r
301 ##############################################################
\r
303 # Class : ABCTaskBarIcon
\r
307 ##############################################################
\r
308 class ABCTaskBarIcon(wx.TaskBarIcon):
\r
309 def __init__(self, parent):
\r
310 wx.TaskBarIcon.__init__(self)
\r
312 self.utility = parent.utility
\r
314 self.TBMENU_RESTORE = wx.NewId()
\r
316 # setup a taskbar icon, and catch some events from it
\r
317 self.Bind(wx.EVT_TASKBAR_LEFT_DCLICK, parent.onTaskBarActivate)
\r
318 self.Bind(wx.EVT_MENU, parent.onTaskBarActivate, id = self.TBMENU_RESTORE)
\r
320 self.updateIcon(False)
\r
322 def updateIcon(self,iconifying = False):
\r
325 mintray = self.utility.config.Read('mintray', "int")
\r
326 if (mintray >= 2) or ((mintray >= 1) and iconifying):
\r
329 if remove and self.IsIconInstalled():
\r
331 elif not remove and not self.IsIconInstalled():
\r
332 self.SetIcon(self.utility.icon, product_name)
\r
334 def CreatePopupMenu(self):
\r
337 self.utility.actions[ACTION_STOPALL].addToMenu(menu, bindto = self)
\r
338 self.utility.actions[ACTION_UNSTOPALL].addToMenu(menu, bindto = self)
\r
339 menu.AppendSeparator()
\r
340 menu.Append(self.TBMENU_RESTORE, self.utility.lang.get('showabcwindow'))
\r
341 self.utility.actions[ACTION_EXIT].addToMenu(menu, bindto = self)
\r
345 ##############################################################
\r
347 # Class : ABColdFrame
\r
349 # Main ABC Frame class that contains menu and menu bar management
\r
350 # and contains ABCPanel
\r
352 ##############################################################
\r
353 class ABCOldFrame(wx.Frame,FlaglessDelayedInvocation):
\r
354 def __init__(self, ID, params, utility):
\r
355 self.utility = utility
\r
356 #self.utility.frame = self
\r
358 title = "Old Interface"
\r
359 # Get window size and position from config file
\r
361 style = wx.DEFAULT_FRAME_STYLE | wx.CLIP_CHILDREN
\r
363 wx.Frame.__init__(self, None, ID, title, size = size, style = style)
\r
365 FlaglessDelayedInvocation.__init__(self)
\r
367 self.GUIupdate = True
\r
369 self.window = ABCPanel(self)
\r
370 self.Bind(wx.EVT_SET_FOCUS, self.onFocus)
\r
371 self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
\r
373 self.tb = ABCToolBar(self) # new Tribler gui has no toolbar
\r
374 self.SetToolBar(self.tb)
\r
377 def onFocus(self, event = None):
\r
378 if event is not None:
\r
380 self.window.getSelectedList(event).SetFocus()
\r
382 def OnCloseWindow(self, event = None):
\r
385 # Custom class loaded by XRC
\r
386 class ABCFrame(wx.Frame, DelayedInvocation):
\r
387 def __init__(self, *args):
\r
389 pre = wx.PreFrame()
\r
390 # the Create step is done by XRC.
\r
391 self.PostCreate(pre)
\r
392 self.Bind(wx.EVT_WINDOW_CREATE, self.OnCreate)
\r
394 wx.Frame.__init__(self, args[0], args[1], args[2], args[3])
\r
397 def OnCreate(self, event):
\r
398 self.Unbind(wx.EVT_WINDOW_CREATE)
\r
399 wx.CallAfter(self._PostInit)
\r
403 def _PostInit(self):
\r
405 self.guiUtility = GUIUtility.getInstance()
\r
406 self.utility = self.guiUtility.utility
\r
407 self.params = self.guiUtility.params
\r
408 self.utility.frame = self
\r
410 title = self.utility.lang.get('title') + \
\r
412 self.utility.lang.get('version')
\r
414 # Get window size and position from config file
\r
415 size, position = self.getWindowSettings()
\r
416 style = wx.DEFAULT_FRAME_STYLE | wx.CLIP_CHILDREN
\r
419 self.SetPosition(position)
\r
420 self.SetTitle(title)
\r
421 tt = self.GetToolTip()
\r
425 #wx.Frame.__init__(self, None, ID, title, position, size, style = style)
\r
427 self.doneflag = Event()
\r
428 DelayedInvocation.__init__(self)
\r
430 dragdroplist = FileDropTarget(self.utility)
\r
431 self.SetDropTarget(dragdroplist)
\r
435 # Arno: see ABCPanel
\r
436 #self.abc_sb = ABCStatusBar(self,self.utility)
\r
437 #self.SetStatusBar(self.abc_sb)
\r
441 statbarbox = wx.BoxSizer(wx.HORIZONTAL)
\r
442 self.sb_buttons = ABCStatusButtons(self,self.utility)
\r
443 statbarbox.Add(self.sb_buttons, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 0)
\r
444 self.abc_sb = ABCStatusBar(self,self.utility)
\r
445 statbarbox.Add(self.abc_sb, 1, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 0)
\r
446 #colSizer.Add(statbarbox, 0, wx.ALL|wx.EXPAND, 0)
\r
447 self.SetStatusBar(statbarbox)
\r
452 self.SetIcon(self.utility.icon)
\r
456 # Don't update GUI as often when iconized
\r
457 self.GUIupdate = True
\r
459 # Start the scheduler before creating the ListCtrl
\r
460 self.utility.queue = ABCScheduler(self.utility)
\r
461 #self.window = ABCPanel(self)
\r
462 #self.abc_sb = self.window.abc_sb
\r
465 self.oldframe = ABCOldFrame(-1, self.params, self.utility)
\r
466 self.oldframe.Refresh()
\r
467 self.oldframe.Layout()
\r
468 #self.oldframe.Show(True)
\r
470 self.window = self.GetChildren()[0]
\r
471 self.window.utility = self.utility
\r
474 self.list = ABCList(self.window)
\r
475 self.list.Show(False)
\r
476 self.utility.list = self.list
\r
477 print self.window.GetName()
\r
478 self.window.list = self.list
\r
479 self.utility.window = self.window
\r
481 #self.window.sb_buttons = ABCStatusButtons(self,self.utility)
\r
483 self.utility.window.postponedevents = []
\r
486 ############################
\r
487 menuBar = ABCMenuBar(self)
\r
488 if sys.platform == "darwin":
\r
489 wx.App.SetMacExitMenuItemId(wx.ID_CLOSE)
\r
490 self.SetMenuBar(menuBar)
\r
492 #self.tb = ABCToolBar(self) # new Tribler gui has no toolbar
\r
493 #self.SetToolBar(self.tb)
\r
495 self.buddyFrame = None
\r
496 self.fileFrame = None
\r
497 self.buddyFrame_page = 0
\r
498 self.buddyFrame_size = (800, 500)
\r
499 self.buddyFrame_pos = None
\r
500 self.fileFrame_size = (800, 500)
\r
501 self.fileFrame_pos = None
\r
504 ############################
\r
506 self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
\r
507 # self.Bind(wx.EVT_MENU, self.OnMenuExit, id = wx.ID_CLOSE)
\r
509 # leaving here for the time being:
\r
510 # wxMSW apparently sends the event to the App object rather than
\r
511 # the top-level Frame, but there seemed to be some possibility of
\r
513 self.Bind(wx.EVT_QUERY_END_SESSION, self.OnCloseWindow)
\r
514 self.Bind(wx.EVT_END_SESSION, self.OnCloseWindow)
\r
517 self.tbicon = ABCTaskBarIcon(self)
\r
520 self.Bind(wx.EVT_ICONIZE, self.onIconify)
\r
521 self.Bind(wx.EVT_SET_FOCUS, self.onFocus)
\r
522 self.Bind(wx.EVT_SIZE, self.onSize)
\r
523 self.Bind(wx.EVT_MAXIMIZE, self.onSize)
\r
524 #self.Bind(wx.EVT_IDLE, self.onIdle)
\r
526 # Start up the controller
\r
527 self.utility.controller = ABCLaunchMany(self.utility)
\r
528 self.utility.controller.start()
\r
530 # Start up mainline DHT
\r
531 # Arno: do this in a try block, as khashmir gives a very funky
\r
532 # error when started from a .dmg (not from cmd line) on Mac. In particular
\r
533 # it complains that it cannot find the 'hex' encoding method when
\r
534 # hstr.encode('hex') is called, and hstr is a string?!
\r
537 rsconvert = RawServerConverter(self.utility.controller.get_rawserver())
\r
538 mainlineDHT.init('', self.utility.listen_port, self.utility.getConfigPath(),rawserver=rsconvert)
\r
539 # Create torrent-liveliness checker based on DHT
\r
540 c = mainlineDHTChecker.getInstance()
\r
541 c.register(mainlineDHT.dht)
\r
545 # Give GUI time to set up stuff
\r
548 #if server start with params run it
\r
549 #####################################
\r
552 print >>sys.stderr,"abc: wxFrame: params is",self.params
\r
554 if self.params[0] != "":
\r
555 success, msg, ABCTorrentTemp = self.utility.queue.addtorrents.AddTorrentFromFile(self.params[0],caller=CALLER_ARGV)
\r
557 self.utility.queue.postInitTasks(self.params)
\r
559 if self.params[0] != "":
\r
560 # Update torrent.list, but after having read the old list of torrents, otherwise we get interference
\r
561 ABCTorrentTemp.torrentconfig.writeSrc(False)
\r
562 self.utility.torrentconfig.Flush()
\r
564 self.videoFrame = None
\r
565 feasible = return_feasible_playback_modes(self.utility.getPath())
\r
566 if PLAYBACKMODE_INTERNAL in feasible:
\r
567 # This means vlc is available
\r
568 from Tribler.Video.EmbeddedPlayer import VideoFrame
\r
569 self.videoFrame = VideoFrame(self)
\r
571 #self.videores = xrc.XmlResource("Tribler/vwxGUI/MyPlayer.xrc")
\r
572 #self.videoframe = self.videores.LoadFrame(None, "MyPlayer")
\r
573 #self.videoframe.Show()
\r
575 videoplayer = VideoPlayer.getInstance()
\r
576 videoplayer.set_parentwindow(self.videoFrame)
\r
578 videoplayer = VideoPlayer.getInstance()
\r
579 videoplayer.set_parentwindow(self)
\r
581 sys.stdout.write('GUI Complete.\n')
\r
586 # Just for debugging: add test permids and display top 5 peers from which the most is downloaded in bartercastdb
\r
587 bartercastdb = BarterCastDBHandler()
\r
588 mypermid = bartercastdb.my_permid
\r
591 bartercastdb.incrementItem((mypermid, "testpermid_1"), 'uploaded', 1024)
\r
592 bartercastdb.incrementItem((mypermid, "testpermid_1"), 'downloaded', 20000)
\r
594 bartercastdb.incrementItem((mypermid, "testpermid_2"), 'uploaded', 40000)
\r
595 bartercastdb.incrementItem((mypermid, "testpermid_2"), 'downloaded', 60000)
\r
597 top = bartercastdb.getTopNPeers(5)['top']
\r
599 print 'My Permid: ', permid_for_user(mypermid)
\r
601 print 'Top 5 BarterCast peers:'
\r
602 print '======================='
\r
605 for (permid, up, down) in top:
\r
606 print '%2d: %15s - %10d up %10d down' % (i, bartercastdb.getName(permid), up, down)
\r
610 # Check to see if ABC is associated with torrents
\r
611 #######################################################
\r
612 if (sys.platform == 'win32'):
\r
613 if self.utility.config.Read('associate', "boolean"):
\r
614 if self.utility.regchecker and not self.utility.regchecker.testRegistry():
\r
615 dialog = RegCheckDialog(self)
\r
619 self.checkVersion()
\r
622 def checkVersion(self):
\r
623 t = Timer(2.0, self._checkVersion)
\r
626 def _checkVersion(self):
\r
627 my_version = self.utility.getVersion()
\r
629 curr_status = urllib.urlopen('http://tribler.org/version').readlines()
\r
630 line1 = curr_status[0]
\r
631 if len(curr_status) > 1:
\r
632 self.update_url = curr_status[1].strip()
\r
634 self.update_url = 'http://tribler.org'
\r
635 _curr_status = line1.split()
\r
636 self.curr_version = _curr_status[0]
\r
637 if self.newversion(self.curr_version, my_version):
\r
638 # Arno: we are a separate thread, delegate GUI updates to MainThread
\r
639 self.upgradeCallback()
\r
641 # Also check new version of web2definitions for youtube etc. search
\r
642 Web2Updater(self.utility).checkUpdate()
\r
643 except Exception,e:
\r
644 print >> sys.stderr, "Tribler: Version check failed", ctime(time()), str(e)
\r
647 def newversion(self, curr_version, my_version):
\r
648 curr = curr_version.split('.')
\r
649 my = my_version.split('.')
\r
650 if len(my) >= len(curr):
\r
653 nversion = len(curr)
\r
654 for i in range(nversion):
\r
660 curr_v = int(curr[i])
\r
665 elif curr_v < my_v:
\r
669 def upgradeCallback(self):
\r
670 self.invokeLater(self.OnUpgrade)
\r
671 # TODO: warn multiple times?
\r
673 def OnUpgrade(self, event=None):
\r
674 self.setActivity(ACT_NEW_VERSION)
\r
676 def onFocus(self, event = None):
\r
677 if event is not None:
\r
679 #self.window.getSelectedList(event).SetFocus()
\r
681 def setGUIupdate(self, update):
\r
682 oldval = self.GUIupdate
\r
683 self.GUIupdate = update
\r
685 if self.GUIupdate and not oldval:
\r
686 # Force an update of all torrents
\r
687 for torrent in self.utility.torrents["all"]:
\r
688 torrent.updateColumns()
\r
689 torrent.updateColor()
\r
692 def taskbarCallback(self):
\r
693 self.invokeLater(self.onTaskBarActivate,[])
\r
696 #######################################
\r
697 # minimize to tray bar control
\r
698 #######################################
\r
699 def onTaskBarActivate(self, event = None):
\r
700 self.Iconize(False)
\r
704 if self.tbicon is not None:
\r
705 self.tbicon.updateIcon(False)
\r
707 #self.window.list.SetFocus()
\r
709 # Resume updating GUI
\r
710 self.setGUIupdate(True)
\r
712 def onIconify(self, event = None):
\r
713 # This event handler is called both when being minimalized
\r
714 # and when being restored.
\r
716 if event is not None:
\r
717 print >> sys.stderr,"abc: onIconify(",event.Iconized()
\r
719 print >> sys.stderr,"abc: onIconify event None"
\r
720 if event.Iconized():
\r
721 if (self.utility.config.Read('mintray', "int") > 0
\r
722 and self.tbicon is not None):
\r
723 self.tbicon.updateIcon(True)
\r
726 # Don't update GUI while minimized
\r
727 self.setGUIupdate(False)
\r
729 self.setGUIupdate(True)
\r
730 if event is not None:
\r
733 def onSize(self, event = None):
\r
734 # Arno: On Windows when I enable the tray icon and then change
\r
735 # virtual desktop (see MS DeskmanPowerToySetup.exe)
\r
736 # I get a onIconify(event.Iconized()==True) event, but when
\r
737 # I switch back, I don't get an event. As a result the GUIupdate
\r
738 # remains turned off. The wxWidgets wiki on the TaskBarIcon suggests
\r
739 # catching the onSize event.
\r
742 if event is not None:
\r
743 print >> sys.stderr,"abc: onSize:",self.GetSize()
\r
745 print >> sys.stderr,"abc: onSize: None"
\r
746 self.setGUIupdate(True)
\r
747 if event is not None:
\r
748 if event.GetEventType() == wx.EVT_MAXIMIZE:
\r
749 self.window.SetClientSize(self.GetClientSize())
\r
753 # Refresh subscreens
\r
754 self.refreshNeeded = True
\r
755 self.guiUtility.refreshOnResize()
\r
757 def onIdle(self, event = None):
\r
759 Only refresh screens (especially detailsPanel) when resizes are finished
\r
760 This gives less flickering, but doesnt look pretty, so i commented it out
\r
762 if self.refreshNeeded:
\r
763 self.guiUtility.refreshOnResize()
\r
764 self.refreshNeeded = False
\r
766 def getWindowSettings(self):
\r
767 width = self.utility.config.Read("window_width")
\r
768 height = self.utility.config.Read("window_height")
\r
770 size = wx.Size(int(width), int(height))
\r
772 size = wx.Size(710, 400)
\r
774 x = self.utility.config.Read("window_x")
\r
775 y = self.utility.config.Read("window_y")
\r
776 if (x == "" or y == ""):
\r
777 position = wx.DefaultPosition
\r
779 position = wx.Point(int(x), int(y))
\r
781 return size, position
\r
783 def saveWindowSettings(self):
\r
784 width, height = self.GetSizeTuple()
\r
785 x, y = self.GetPositionTuple()
\r
786 self.utility.config.Write("window_width", width)
\r
787 self.utility.config.Write("window_height", height)
\r
788 self.utility.config.Write("window_x", x)
\r
789 self.utility.config.Write("window_y", y)
\r
791 self.utility.config.Flush()
\r
793 ##################################
\r
795 ##################################
\r
797 def OnCloseWindow(self, event = None):
\r
799 nr = event.GetEventType()
\r
800 lookup = { wx.EVT_CLOSE.evtType[0]: "EVT_CLOSE", wx.EVT_QUERY_END_SESSION.evtType[0]: "EVT_QUERY_END_SESSION", wx.EVT_END_SESSION.evtType[0]: "EVT_END_SESSION" }
\r
801 if nr in lookup: nr = lookup[nr]
\r
802 print "Closing due to event ",nr
\r
803 print >>sys.stderr,"Closing due to event ",nr
\r
805 print "Closing untriggered by event"
\r
807 # Don't do anything if the event gets called twice for some reason
\r
808 if self.utility.abcquitting:
\r
811 # Check to see if we can veto the shutdown
\r
812 # (might not be able to in case of shutting down windows)
\r
813 if event is not None:
\r
815 if event.CanVeto() and self.utility.config.Read('confirmonclose', "boolean") and not event.GetEventType() == wx.EVT_QUERY_END_SESSION.evtType[0]:
\r
816 dialog = wx.MessageDialog(None, self.utility.lang.get('confirmmsg'), self.utility.lang.get('confirm'), wx.OK|wx.CANCEL)
\r
817 result = dialog.ShowModal()
\r
819 if result != wx.ID_OK:
\r
824 print_exc(file = data)
\r
825 sys.stderr.write(data.getvalue())
\r
828 self.utility.abcquitting = True
\r
829 self.GUIupdate = False
\r
831 self.guiUtility.guiOpen.clear()
\r
833 # Close the Torrent Maker
\r
834 self.utility.actions[ACTION_MAKETORRENT].closeWin()
\r
837 self.utility.webserver.stop()
\r
840 print_exc(file = data)
\r
841 sys.stderr.write(data.getvalue())
\r
845 # tell scheduler to close all active thread
\r
846 self.utility.queue.clearScheduler()
\r
849 print_exc(file = data)
\r
850 sys.stderr.write(data.getvalue())
\r
854 # Restore the window before saving size and position
\r
855 # (Otherwise we'll get the size of the taskbar button and a negative position)
\r
856 self.onTaskBarActivate()
\r
857 self.saveWindowSettings()
\r
859 #print_exc(file=sys.stderr)
\r
863 if self.buddyFrame is not None:
\r
864 self.buddyFrame.Destroy()
\r
865 if self.fileFrame is not None:
\r
866 self.fileFrame.Destroy()
\r
867 if self.videoFrame is not None:
\r
868 self.videoFrame.Destroy()
\r
872 self.oldframe.Destroy()
\r
875 if self.tbicon is not None:
\r
876 self.tbicon.RemoveIcon()
\r
877 self.tbicon.Destroy()
\r
881 print_exc(file = data)
\r
882 sys.stderr.write(data.getvalue())
\r
885 # Arno: at the moment, Tribler gets a segmentation fault when the
\r
886 # tray icon is always enabled. This SEGV occurs in the wx mainloop
\r
887 # which is entered as soon as we leave this method. Hence I placed
\r
888 # tribler_done() here, so the database are closed properly
\r
889 # before the crash.
\r
891 # Arno, 2007-02-28: Preferably this should be moved to the main
\r
892 # run() method below, that waits a while to allow threads to finish.
\r
893 # Ideally, the database should still be open while they finish up.
\r
894 # Because of the crash problem with the icontray this is the safer
\r
897 # Arno, 2007-08-10: When a torrentfile is passed on the command line,
\r
898 # the client will crash just after this point due to unknown reasons
\r
899 # (it even does it when we don't look at the cmd line args at all!)
\r
900 # Hence, for safety, I close the DB here already.
\r
901 #if sys.platform == 'linux2':
\r
904 #tribler_done(self.utility.getConfigPath())
\r
907 print >>sys.stderr,"abc: OnCloseWindow END"
\r
912 print >>sys.stderr,"abc: Thread still running",t.getName(),"daemon",t.isDaemon()
\r
916 def onWarning(self,exc):
\r
917 msg = self.utility.lang.get('tribler_startup_nonfatalerror')
\r
918 msg += str(exc.__class__)+':'+str(exc)
\r
919 dlg = wx.MessageDialog(None, msg, self.utility.lang.get('tribler_warning'), wx.OK|wx.ICON_WARNING)
\r
920 result = dlg.ShowModal()
\r
923 def onUPnPError(self,upnp_type,listenport,error_type,exc=None,listenproto='TCP'):
\r
925 if error_type == 0:
\r
926 errormsg = unicode(' UPnP mode '+str(upnp_type)+' ')+self.utility.lang.get('tribler_upnp_error1')
\r
927 elif error_type == 1:
\r
928 errormsg = unicode(' UPnP mode '+str(upnp_type)+' ')+self.utility.lang.get('tribler_upnp_error2')+unicode(str(exc))+self.utility.lang.get('tribler_upnp_error2_postfix')
\r
929 elif error_type == 2:
\r
930 errormsg = unicode(' UPnP mode '+str(upnp_type)+' ')+self.utility.lang.get('tribler_upnp_error3')
\r
932 errormsg = unicode(' UPnP mode '+str(upnp_type)+' Unknown error')
\r
934 msg = self.utility.lang.get('tribler_upnp_error_intro')
\r
935 msg += listenproto+' '
\r
936 msg += str(listenport)
\r
937 msg += self.utility.lang.get('tribler_upnp_error_intro_postfix')
\r
939 msg += self.utility.lang.get('tribler_upnp_error_extro')
\r
941 dlg = wx.MessageDialog(None, msg, self.utility.lang.get('tribler_warning'), wx.OK|wx.ICON_WARNING)
\r
942 result = dlg.ShowModal()
\r
945 def onReachable(self,event=None):
\r
946 """ Called by GUI thread """
\r
947 if self.firewallStatus is not None:
\r
948 self.firewallStatus.setToggled(True)
\r
949 tt = self.firewallStatus.GetToolTip()
\r
951 tt.SetTip(self.utility.lang.get('reachable_tooltip'))
\r
954 def setActivity(self,type,msg=u''):
\r
956 if currentThread().getName() != "MainThread":
\r
957 print >> sys.stderr,"abc: setActivity thread",currentThread().getName(),"is NOT MAIN THREAD"
\r
960 if type == ACT_NONE:
\r
963 elif type == ACT_UPNP:
\r
964 prefix = self.utility.lang.get('act_upnp')
\r
965 elif type == ACT_REACHABLE:
\r
966 prefix = self.utility.lang.get('act_reachable')
\r
967 elif type == ACT_GET_EXT_IP_FROM_PEERS:
\r
968 prefix = self.utility.lang.get('act_get_ext_ip_from_peers')
\r
969 elif type == ACT_MEET:
\r
970 prefix = self.utility.lang.get('act_meet')
\r
971 elif type == ACT_GOT_METADATA:
\r
972 prefix = self.utility.lang.get('act_got_metadata')
\r
973 elif type == ACT_RECOMMEND:
\r
974 prefix = self.utility.lang.get('act_recommend')
\r
975 elif type == ACT_DISK_FULL:
\r
976 prefix = self.utility.lang.get('act_disk_full')
\r
977 elif type == ACT_NEW_VERSION:
\r
978 prefix = self.utility.lang.get('act_new_version')
\r
982 text = unicode( prefix+u' '+msg)
\r
985 print >> sys.stderr,"abc: Setting activity",`text`,"EOT"
\r
986 self.messageField.SetLabel(text)
\r
989 class TorThread(Thread):
\r
991 def __init__(self):
\r
992 Thread.__init__(self)
\r
993 self.setDaemon(True)
\r
994 self.setName("TorThread"+self.getName())
\r
995 self.child_out = None
\r
996 self.child_in = None
\r
1001 print >>sys.stderr,"TorThread starting",currentThread().getName()
\r
1002 if sys.platform == "win32":
\r
1003 # Not "Nul:" but "nul" is /dev/null on Win32
\r
1006 elif sys.platform == "darwin":
\r
1008 sink = '/dev/null'
\r
1011 sink = '/dev/null'
\r
1013 (self.child_out,self.child_in) = os.popen2( "%s --log err-err > %s 2>&1" % (cmd,sink), 'b' )
\r
1016 print >>sys.stderr,"TorThread reading",currentThread().getName()
\r
1018 msg = self.child_in.read()
\r
1020 print >>sys.stderr,"TorThread: tor said",msg
\r
1027 def shutdown(self):
\r
1028 if self.child_out is not None:
\r
1029 self.child_out.close()
\r
1030 if self.child_in is not None:
\r
1031 self.child_in.close()
\r
1034 ##############################################################
\r
1038 # Main ABC application class that contains ABCFrame Object
\r
1040 ##############################################################
\r
1041 class ABCApp(wx.App,FlaglessDelayedInvocation):
\r
1042 def __init__(self, x, params, single_instance_checker, abcpath):
\r
1043 global start_time, start_time2
\r
1044 start_time2 = time()
\r
1045 #print "[StartUpDebug]----------- from ABCApp.__init__ ----------Tribler starts up at", ctime(start_time2), "after", start_time2 - start_time
\r
1046 self.params = params
\r
1047 self.single_instance_checker = single_instance_checker
\r
1048 self.abcpath = abcpath
\r
1050 self.torthread = None
\r
1051 wx.App.__init__(self, x)
\r
1055 self.utility = Utility(self.abcpath)
\r
1056 # Set locale to determine localisation
\r
1057 locale.setlocale(locale.LC_ALL, '')
\r
1059 sys.stdout.write('Client Starting Up.\n')
\r
1060 sys.stdout.write('Build: ' + self.utility.lang.get('build') + '\n')
\r
1062 bm = wx.Bitmap(os.path.join(self.utility.getPath(),'icons','splash.jpg'),wx.BITMAP_TYPE_JPEG)
\r
1063 #s = wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN
\r
1064 #s = wx.SIMPLE_BORDER|wx.FRAME_NO_TASKBAR|wx.FRAME_FLOAT_ON_PARENT
\r
1065 self.splash = wx.SplashScreen(bm, wx.SPLASH_CENTRE_ON_SCREEN|wx.SPLASH_TIMEOUT, 1000, None, -1)
\r
1067 wx.CallAfter(self.PostInit)
\r
1070 except Exception,e:
\r
1077 def PostInit(self):
\r
1079 tribler_init(self.utility.getConfigPath(),self.utility.getPath(),self.db_exception_handler)
\r
1080 self.utility.setTriblerVariables()
\r
1081 self.utility.postAppInit()
\r
1083 # Singleton for executing tasks that are too long for GUI thread and
\r
1085 self.guiserver = GUIServer.getInstance()
\r
1086 self.guiserver.register()
\r
1088 # Singleton for management of user's mugshots (i.e. icons/display pictures)
\r
1089 self.mm = MugshotManager.getInstance()
\r
1090 self.mm.register(self.utility.getConfigPath(),self.utility.getPath())
\r
1093 set_tasteheart_bitmaps(self.utility.getPath())
\r
1094 set_perfBar_bitmaps(self.utility.getPath())
\r
1096 # Put it here so an error is shown in the startup-error popup
\r
1097 self.serverlistener = ServerListener(self.utility)
\r
1099 # Check webservice for autostart webservice
\r
1100 #######################################################
\r
1101 WebListener(self.utility)
\r
1102 if self.utility.webconfig.Read("webautostart", "boolean"):
\r
1103 self.utility.webserver.start()
\r
1105 # Start single instance server listenner
\r
1106 ############################################
\r
1107 self.serverthread = Thread(target = self.serverlistener.start)
\r
1108 self.serverthread.setDaemon(True)
\r
1109 self.serverthread.setName("SingleInstanceServer"+self.serverthread.getName())
\r
1110 self.serverthread.start()
\r
1112 self.videoplayer = VideoPlayer.getInstance()
\r
1113 self.videoplayer.register(self.utility)
\r
1114 self.videoserver = VideoHTTPServer.getInstance()
\r
1115 self.videoserver.background_serve()
\r
1117 notification_init( self.utility )
\r
1119 # Change config when experiment ends, before ABCLaunchMany is created
\r
1121 if EVIL and time() > 1190099288.0:
\r
1123 end = self.utility.config.Read('lure_ended', "boolean")
\r
1125 self.utility.config.Write('lure_ended', 1, "boolean")
\r
1126 self.utility.config.Write('tor_enabled', 0, "boolean")
\r
1127 self.utility.config.Write('ut_pex_max_addrs_from_peer', 16)
\r
1129 msg = "The Tribler download accelerator using the TOR network has been turned off. For more information visit http://TV.seas.Harvard.edu/"
\r
1130 dlg = wx.MessageDialog(None, msg, "Tribler Warning", wx.OK|wx.ICON_INFORMATION)
\r
1131 result = dlg.ShowModal()
\r
1134 enabled = self.utility.config.Read('tor_enabled', "boolean")
\r
1136 self.torthread = TorThread()
\r
1137 self.torthread.start()
\r
1140 # Read and create GUI from .xrc files
\r
1142 #self.frame = ABCFrame(-1, self.params, self.utility)
\r
1143 self.guiUtility = GUIUtility.getInstance(self.utility, self.params)
\r
1144 updateXRC.main([os.path.join(self.utility.getPath(),'Tribler','vwxGUI')])
\r
1145 self.res = xrc.XmlResource(os.path.join(self.utility.getPath(),'Tribler','vwxGUI','MyFrame.xrc'))
\r
1146 self.guiUtility.xrcResource = self.res
\r
1147 self.frame = self.res.LoadFrame(None, "MyFrame")
\r
1148 self.guiUtility.frame = self.frame
\r
1149 self.guiUtility.scrollWindow = xrc.XRCCTRL(self.frame, "level0")
\r
1150 self.guiUtility.mainSizer = self.guiUtility.scrollWindow.GetSizer()
\r
1151 self.frame.topBackgroundRight = xrc.XRCCTRL(self.frame, "topBG3")
\r
1152 self.guiUtility.scrollWindow.SetScrollbars(1,1,1024,768)
\r
1153 self.guiUtility.scrollWindow.SetScrollRate(15,15)
\r
1154 self.frame.mainButtonPersons = xrc.XRCCTRL(self.frame, "mainButtonPersons")
\r
1157 self.frame.numberPersons = xrc.XRCCTRL(self.frame, "numberPersons")
\r
1158 numperslabel = xrc.XRCCTRL(self.frame, "persons")
\r
1159 self.frame.numberFiles = xrc.XRCCTRL(self.frame, "numberFiles")
\r
1160 numfileslabel = xrc.XRCCTRL(self.frame, "files")
\r
1161 self.frame.messageField = xrc.XRCCTRL(self.frame, "messageField")
\r
1162 self.frame.firewallStatus = xrc.XRCCTRL(self.frame, "firewallStatus")
\r
1163 tt = self.frame.firewallStatus.GetToolTip()
\r
1164 if tt is not None:
\r
1165 tt.SetTip(self.utility.lang.get('unknownreac_tooltip'))
\r
1167 if sys.platform == "linux2":
\r
1168 self.frame.numberPersons.SetFont(wx.Font(9,FONTFAMILY,FONTWEIGHT,wx.NORMAL,False,FONTFACE))
\r
1169 self.frame.numberFiles.SetFont(wx.Font(9,FONTFAMILY,FONTWEIGHT,wx.NORMAL,False,FONTFACE))
\r
1170 self.frame.messageField.SetFont(wx.Font(9,FONTFAMILY,FONTWEIGHT,wx.NORMAL,False,FONTFACE))
\r
1171 numperslabel.SetFont(wx.Font(9,FONTFAMILY,FONTWEIGHT,wx.NORMAL,False,FONTFACE))
\r
1172 numfileslabel.SetFont(wx.Font(9,FONTFAMILY,FONTWEIGHT,wx.NORMAL,False,FONTFACE))
\r
1174 searchfilebut = xrc.XRCCTRL(self.frame, "bt257cC")
\r
1175 searchfilebut.Bind(wx.EVT_LEFT_UP, self.guiUtility.buttonClicked)
\r
1176 searchpersbut = xrc.XRCCTRL(self.frame, "bt258cC")
\r
1177 searchpersbut.Bind(wx.EVT_LEFT_UP, self.guiUtility.buttonClicked)
\r
1179 self.frame.searchtxtctrl = xrc.XRCCTRL(self.frame, "tx220cCCC")
\r
1182 #self.frame.Refresh()
\r
1183 #self.frame.Layout()
\r
1184 self.frame.Show(True)
\r
1185 #===============================================================================
\r
1186 # global start_time2
\r
1187 # current_time = time()
\r
1188 # print "\n\n[StartUpDebug]-----------------------------------------"
\r
1189 # print "[StartUpDebug]"
\r
1190 # print "[StartUpDebug]----------- from ABCApp.OnInit ----------Tribler frame is shown after", current_time-start_time2
\r
1191 # print "[StartUpDebug]"
\r
1192 # print "[StartUpDebug]-----------------------------------------\n\n"
\r
1193 #===============================================================================
\r
1197 # - load standardGrid
\r
1198 # - gui utility > button mainButtonFiles = clicked
\r
1201 self.Bind(wx.EVT_QUERY_END_SESSION, self.frame.OnCloseWindow)
\r
1202 self.Bind(wx.EVT_END_SESSION, self.frame.OnCloseWindow)
\r
1205 #asked = self.utility.config.Read('askeduploadbw', 'boolean')
\r
1208 dlg = BandwidthSelector(self.frame,self.utility)
\r
1209 result = dlg.ShowModal()
\r
1210 if result == wx.ID_OK:
\r
1211 ulbw = dlg.getUploadBandwidth()
\r
1212 self.utility.config.Write('maxuploadrate',ulbw)
\r
1213 self.utility.config.Write('maxseeduploadrate',ulbw)
\r
1214 self.utility.config.Write('askeduploadbw','1')
\r
1217 # Arno, 2007-05-03: wxWidgets 2.8.3.0 and earlier have the MIME-type for .bmp
\r
1218 # files set to 'image/x-bmp' whereas 'image/bmp' is the official one.
\r
1221 hands = wx.Image.GetHandlers()
\r
1222 for hand in hands:
\r
1223 #print "Handler",hand.GetExtension(),hand.GetType(),hand.GetMimeType()
\r
1224 if hand.GetMimeType() == 'image/x-bmp':
\r
1227 #wx.Image.AddHandler()
\r
1228 if bmphand is not None:
\r
1229 bmphand.SetMimeType('image/bmp')
\r
1231 # wx < 2.7 don't like wx.Image.GetHandlers()
\r
1234 # Must be after ABCLaunchMany is created
\r
1235 self.torrentfeed = TorrentFeedThread.getInstance()
\r
1236 self.torrentfeed.register(self.utility)
\r
1237 self.torrentfeed.start()
\r
1239 #print "DIM",wx.GetDisplaySize()
\r
1240 #print "MM",wx.GetDisplaySizeMM()
\r
1242 wx.CallAfter(self.startWithRightView)
\r
1244 except Exception,e:
\r
1252 def onError(self,source=None):
\r
1253 # Don't use language independence stuff, self.utility may not be
\r
1255 msg = "Unfortunately, Tribler ran into an internal error:\n\n"
\r
1256 if source is not None:
\r
1258 msg += str(self.error.__class__)+':'+str(self.error)
\r
1260 msg += 'Please see the FAQ on www.tribler.org on how to act.'
\r
1261 dlg = wx.MessageDialog(None, msg, "Tribler Fatal Error", wx.OK|wx.ICON_ERROR)
\r
1262 result = dlg.ShowModal()
\r
1266 def MacOpenFile(self,filename):
\r
1267 self.utility.queue.addtorrents.AddTorrentFromFile(filename)
\r
1271 self.torrentfeed.shutdown()
\r
1272 if self.torthread is not None:
\r
1273 self.torthread.shutdown()
\r
1274 mainlineDHT.deinit()
\r
1276 if not ALLOW_MULTIPLE:
\r
1277 del self.single_instance_checker
\r
1278 ClientPassParam("Close Connection")
\r
1281 def db_exception_handler(self,e):
\r
1283 print >> sys.stderr,"abc: Database Exception handler called",e,"value",e.args,"#"
\r
1285 if e.args[1] == "DB object has been closed":
\r
1286 return # We caused this non-fatal error, don't show.
\r
1287 if self.error is not None and self.error.args[1] == e.args[1]:
\r
1288 return # don't repeat same error
\r
1290 print >> sys.stderr, "abc: db_exception_handler error", e, type(e)
\r
1294 self.invokeLater(self.onError,[],{'source':"The database layer reported: "})
\r
1296 def getConfigPath(self):
\r
1297 return self.utility.getConfigPath()
\r
1299 def startWithRightView(self):
\r
1300 if self.params[0] != "":
\r
1301 self.guiUtility.standardLibraryOverview()
\r
1304 class DummySingleInstanceChecker:
\r
1306 def __init__(self,basename):
\r
1309 def IsAnotherRunning(self):
\r
1310 "Uses pgrep to find other tribler.py processes"
\r
1311 # If no pgrep available, it will always start tribler
\r
1312 progressInfo = commands.getoutput('pgrep -fl tribler.py | grep -v pgrep')
\r
1313 numProcesses = len(progressInfo.split('\n'))
\r
1315 print 'ProgressInfo: %s, num: %d' % (progressInfo, numProcesses)
\r
1316 return numProcesses > 1
\r
1319 ##############################################################
\r
1321 # Main Program Start Here
\r
1323 ##############################################################
\r
1324 def run(params = None):
\r
1326 start_time = time()
\r
1327 if params is None:
\r
1330 if len(sys.argv) > 1:
\r
1331 params = sys.argv[1:]
\r
1333 # Create single instance semaphore
\r
1334 # Arno: On Linux and wxPython-2.8.1.1 the SingleInstanceChecker appears
\r
1335 # to mess up stderr, i.e., I get IOErrors when writing to it via print_exc()
\r
1337 # TEMPORARILY DISABLED on Linux
\r
1338 if sys.platform != 'linux2':
\r
1339 single_instance_checker = wx.SingleInstanceChecker("tribler-" + wx.GetUserId())
\r
1341 single_instance_checker = DummySingleInstanceChecker("tribler-")
\r
1343 #print "[StartUpDebug]---------------- 1", time()-start_time
\r
1344 if not ALLOW_MULTIPLE and single_instance_checker.IsAnotherRunning():
\r
1345 #Send torrent info to abc single instance
\r
1346 ClientPassParam(params[0])
\r
1347 #print "[StartUpDebug]---------------- 2", time()-start_time
\r
1349 abcpath = os.path.abspath(os.path.dirname(sys.argv[0]))
\r
1350 # Arno: don't chdir to allow testing as other user from other dir.
\r
1351 #os.chdir(abcpath)
\r
1353 # Launch first abc single instance
\r
1354 app = ABCApp(0, params, single_instance_checker, abcpath)
\r
1355 configpath = app.getConfigPath()
\r
1356 # print "[StartUpDebug]---------------- 3", time()-start_time
\r
1359 print "Client shutting down. Sleeping for a few seconds to allow other threads to finish"
\r
1362 # This is the right place to close the database, unfortunately Linux has
\r
1363 # a problem, see ABCFrame.OnCloseWindow
\r
1365 #if sys.platform != 'linux2':
\r
1366 # tribler_done(configpath)
\r
1369 if __name__ == '__main__':
\r