├── .gitignore ├── setup.sh ├── trashie.icns ├── trash-empty.png ├── trash-full.png ├── setup.py ├── README └── trashie.py /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build/* 3 | dist/* 4 | blog/* -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | rm -rf build dist 2 | python setup.py py2app -------------------------------------------------------------------------------- /trashie.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anandkunal/trashie/master/trashie.icns -------------------------------------------------------------------------------- /trash-empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anandkunal/trashie/master/trash-empty.png -------------------------------------------------------------------------------- /trash-full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anandkunal/trashie/master/trash-full.png -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | plist = dict( 4 | NSPrincipalClass='Trashie', 5 | LSBackgroundOnly=True, 6 | CFBundleIconFile='trashie', 7 | NSHumanReadableCopyright='Kunal Anand' 8 | ) 9 | 10 | setup( 11 | app=["trashie.py"], 12 | options=dict(py2app=dict( 13 | plist=plist, 14 | resources='trash-empty.png, trash-full.png, trashie.icns')), 15 | setup_requires=["py2app"], 16 | ) -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | INFO: 2 | Trashie is a utility that lets you monitor your OS X trash from the menu bar. 3 | It is written in PyObjC. 4 | Icons are snagged from the Tango Project. 5 | 6 | INSTALL: 7 | To get the party started, run `python setup.py py2app`. 8 | Alternatively, you can run `bash setup.sh`. 9 | 10 | TODO: 11 | 1. Research other areas where there might be trash (offer users a checkbox) 12 | - http://support.apple.com/kb/HT2963 13 | - sudo rm -rf ~/.Trash/ 14 | - sudo rm -rf /.Trashes/ 15 | - sudo rm -rf /Volumes//.Trashes/ -------------------------------------------------------------------------------- /trashie.py: -------------------------------------------------------------------------------- 1 | from AppKit import * 2 | import commands 3 | from Foundation import * 4 | import objc 5 | from PyObjCTools import AppHelper 6 | 7 | try: 8 | import Growl 9 | except: 10 | class Growl: 11 | def __init__(self, *args): pass 12 | class GrowlNotifier: 13 | def __init__(self, *args): pass 14 | def register(self, *args): pass 15 | def notify(self, *args): pass 16 | 17 | status_images = {'empty':'trash-empty.png', 'full':'trash-full.png'} 18 | 19 | class Trashie(NSObject): 20 | images = {} 21 | statusbar = None 22 | count = None 23 | poll_seconds = 3 24 | notifier = None 25 | 26 | def notify(self, type, message): 27 | self.notifier.notify(type,'trashie',message) 28 | 29 | def update_trashie(self): 30 | current_count = self.count 31 | command = 'find ~/.Trash/ -not \( -name "*.DS_Store" \) | wc -l' 32 | count = commands.getstatusoutput(command) 33 | 34 | if count[0] == 0: 35 | self.count = int(count[1].strip()) - 1 36 | 37 | if current_count != self.count: 38 | if self.count == 0: 39 | self.notify('empty', 'yay! the trash is empty!') 40 | self.statusitem.setImage_(self.images['empty']) 41 | if self.count == 1: 42 | self.notify('full', 'there is 1 thing in the trash') 43 | self.statusitem.setImage_(self.images['full']) 44 | if self.count > 1: 45 | self.notify('full', 'there are %s things in the trash' % str(self.count)) 46 | self.statusitem.setImage_(self.images['full']) 47 | 48 | self.statusitem.setToolTip_('Trashie') 49 | self.statusitem.setTitle_('(%d)' % (self.count)) 50 | 51 | def applicationDidFinishLaunching_(self, notification): 52 | notifier = Growl.GrowlNotifier() 53 | notifier.applicationName = 'trashie' 54 | notifier.applicationIcon = 'trashie.icns' 55 | notifier.notifications = ['initialized','empty','full'] 56 | notifier.register() 57 | self.notifier = notifier 58 | 59 | statusbar = NSStatusBar.systemStatusBar() 60 | self.statusitem = statusbar.statusItemWithLength_(NSVariableStatusItemLength) 61 | 62 | for i in status_images.keys(): 63 | self.images[i] = NSImage.alloc().initByReferencingFile_(status_images[i]) 64 | self.statusitem.setHighlightMode_(1) 65 | 66 | menu = NSMenu.alloc().init() 67 | menu.addItem_(NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('View Trash', 'view:', '')) 68 | menu.addItem_(NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('Empty Trash', 'empty:', '')) 69 | menu.addItem_(NSMenuItem.separatorItem()) 70 | menu.addItem_(NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('Count Trash Items', 'refresh:', '')) 71 | menu.addItem_(NSMenuItem.separatorItem()) 72 | menu.addItem_(NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('Quit Trashie', 'terminate:', '')) 73 | 74 | self.statusitem.setMenu_(menu) 75 | 76 | self.timer = NSTimer.alloc().initWithFireDate_interval_target_selector_userInfo_repeats_(NSDate.date(), self.poll_seconds, self, 'poll:', None, True) 77 | NSRunLoop.currentRunLoop().addTimer_forMode_(self.timer, NSDefaultRunLoopMode) 78 | self.timer.fire() 79 | 80 | def view_(self, notification): 81 | commands.getstatusoutput('open ~/.Trash/') 82 | 83 | def refresh_(self, notification): 84 | self.update_trashie() 85 | 86 | def empty_(self, notification): 87 | commands.getstatusoutput('rm -rf ~/.Trash/*') 88 | self.update_trashie() 89 | 90 | def poll_(self, notification): 91 | self.update_trashie() 92 | 93 | if __name__ == "__main__": 94 | app = NSApplication.sharedApplication() 95 | delegate = Trashie.alloc().init() 96 | app.setDelegate_(delegate) 97 | AppHelper.runEventLoop() --------------------------------------------------------------------------------