Permalink
Browse files

A preference to automatically show the Dashboard after user inactivity

Shows dash after 4 minutes of inactivity. Fortunately OS X's inactivity
framework is awesome and VLC/Quicktime etc. already keep inactivity at 0 when
they are playing video
  • Loading branch information...
1 parent c1c600a commit 876f1bf3c248349f30bc29adc176df8b1b3e9ffa @mxcl committed Jul 8, 2009
Showing with 223 additions and 3 deletions.
  1. +10 −0 Audioscrobbler.xcodeproj/project.pbxproj
  2. +33 −0 AutoDash.h
  3. +105 −0 AutoDash.m
  4. +53 −3 English.lproj/main.xib
  5. +3 −0 StatusItemController.h
  6. +19 −0 StatusItemController.m
View
10 Audioscrobbler.xcodeproj/project.pbxproj
@@ -9,6 +9,8 @@
/* Begin PBXBuildFile section */
1DDD58160DA1D0A300B32029 /* main.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD58140DA1D0A300B32029 /* main.xib */; };
63024AEC0F9640A8001B8E9B /* Mediator.m in Sources */ = {isa = PBXBuildFile; fileRef = 63024AEB0F9640A8001B8E9B /* Mediator.m */; };
+ 630EF82F1004ACC200EB28C2 /* AutoDash.m in Sources */ = {isa = PBXBuildFile; fileRef = 630EF82E1004ACC200EB28C2 /* AutoDash.m */; };
+ 630EF8391004B61300EB28C2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 630EF8381004B61300EB28C2 /* IOKit.framework */; };
637F074E0FAF20AD006EE129 /* ScriptingBridge.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 637F074D0FAF20AD006EE129 /* ScriptingBridge.framework */; };
63906F0C0F9DE71E00797A14 /* ShareWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 63906F0B0F9DE71E00797A14 /* ShareWindow.xib */; };
63B5AA390F93565500DC9D8C /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 63B5AA380F93565500DC9D8C /* md5.c */; };
@@ -55,6 +57,9 @@
32CA4F630368D1EE00C91783 /* pc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pc.h; sourceTree = "<group>"; };
63024AE90F964063001B8E9B /* Mediator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Mediator.h; sourceTree = "<group>"; };
63024AEB0F9640A8001B8E9B /* Mediator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Mediator.m; sourceTree = "<group>"; };
+ 630EF82D1004ACC200EB28C2 /* AutoDash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AutoDash.h; sourceTree = "<group>"; };
+ 630EF82E1004ACC200EB28C2 /* AutoDash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AutoDash.m; sourceTree = "<group>"; };
+ 630EF8381004B61300EB28C2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; };
637F07050FAF180F006EE129 /* iTunes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iTunes.h; sourceTree = "<group>"; };
637F074D0FAF20AD006EE129 /* ScriptingBridge.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ScriptingBridge.framework; path = /System/Library/Frameworks/ScriptingBridge.framework; sourceTree = "<absolute>"; };
63906F0B0F9DE71E00797A14 /* ShareWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ShareWindow.xib; sourceTree = "<group>"; };
@@ -91,6 +96,7 @@
63D1D09F0F97FDB3004FBC05 /* Growl.framework in Frameworks */,
63D1D2990F9A0CB1004FBC05 /* Carbon.framework in Frameworks */,
637F074E0FAF20AD006EE129 /* ScriptingBridge.framework in Frameworks */,
+ 630EF8391004B61300EB28C2 /* IOKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -108,13 +114,16 @@
63D1D1030F980532004FBC05 /* lastfm.m */,
63D1D1A00F989847004FBC05 /* HistoryMenuController.h */,
63D1D1A10F989847004FBC05 /* HistoryMenuController.m */,
+ 630EF82D1004ACC200EB28C2 /* AutoDash.h */,
+ 630EF82E1004ACC200EB28C2 /* AutoDash.m */,
);
name = Classes;
sourceTree = "<group>";
};
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
isa = PBXGroup;
children = (
+ 630EF8381004B61300EB28C2 /* IOKit.framework */,
637F074D0FAF20AD006EE129 /* ScriptingBridge.framework */,
63D1D2980F9A0CB1004FBC05 /* Carbon.framework */,
63D1D09E0F97FDB3004FBC05 /* Growl.framework */,
@@ -305,6 +314,7 @@
63024AEC0F9640A8001B8E9B /* Mediator.m in Sources */,
63D1D1040F980532004FBC05 /* lastfm.m in Sources */,
63D1D1A20F989847004FBC05 /* HistoryMenuController.m in Sources */,
+ 630EF82F1004ACC200EB28C2 /* AutoDash.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
33 AutoDash.h
@@ -0,0 +1,33 @@
+/***************************************************************************
+ * Copyright 2005-2009 Last.fm Ltd. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+// Created by Max Howell <max@last.fm>
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface AutoDash:NSObject{
+ NSTimer* timer;
+@private
+ io_registry_entry_t io_obj;
+}
+
+-(id)init;
+
+@end
View
105 AutoDash.m
@@ -0,0 +1,105 @@
+/***************************************************************************
+ * Copyright 2005-2009 Last.fm Ltd. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+// Created by Max Howell <max@last.fm>
+// References:
+// http://ryanhomer.com/blog/2007/05/31/detecting-when-your-cocoa-application-is-idle/
+// http://meeu.me/blog/dashboard-expose-spaces/
+
+#import "AutoDash.h"
+#define INTERVAL 240
+#define MAKE_TIMER(interval) timer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(check) userInfo:nil repeats:NO]
+
+void CoreDockSendNotification(NSString *notificationName); // not public, but prolly safe
+
+@interface AutoDash(Private)
+-(void)check;
+-(uint32_t)systemIdleTime;
+@end
+
+
+@implementation AutoDash
+
+-(id)init
+{
+ [super init];
+
+ mach_port_t port;
+ IOMasterPort(MACH_PORT_NULL, &port);
+ io_iterator_t io_iterator;
+ IOServiceGetMatchingServices(port, IOServiceMatching("IOHIDSystem"), &io_iterator);
+ io_obj = IOIteratorNext(io_iterator);
+ IOObjectRelease(io_iterator);
+
+ MAKE_TIMER(INTERVAL);
+
+ return self;
+}
+
+-(void)dealloc
+{
+ IOObjectRelease(io_obj);
+ [timer invalidate];
+ [super dealloc];
+}
+
+-(void)check
+{
+ uint32_t const idletime = [self systemIdleTime];
+ uint32_t next_time;
+
+ NSLog(@"Idletime is %d", idletime);
+
+ if (idletime >= INTERVAL){
+ CoreDockSendNotification(@"com.apple.dashboard.awake");
+ // until we can know when the dashboard is deactivated, we have to keep
+ // making timers and activating the dashboard
+ next_time = INTERVAL;
+ }
+ else
+ next_time = INTERVAL - idletime;
+
+ MAKE_TIMER(next_time);
+}
+
+-(uint32_t)systemIdleTime
+{
+ CFMutableDictionaryRef properties = 0;
+ if (IORegistryEntryCreateCFProperties(io_obj, &properties, kCFAllocatorDefault, 0) != KERN_SUCCESS || properties == NULL)
+ return 0;
+
+ CFTypeRef o = CFDictionaryGetValue(properties, CFSTR("HIDIdleTime"));
+ if (o == NULL)
+ goto exit;
+
+ uint64_t t = 0;
+ CFTypeID type = CFGetTypeID(o);
+ if (type == CFDataGetTypeID())
+ CFDataGetBytes((CFDataRef)o, CFRangeMake(0, sizeof(t)), (UInt8*) &t);
+ else if (type == CFNumberGetTypeID())
+ CFNumberGetValue((CFNumberRef)o, kCFNumberSInt64Type, &t);
+
+ t >>= 30; // essentially divides by 10^9 (nanoseconds)
+
+exit:
+ CFRelease((CFTypeRef)properties);
+ return t;
+}
+
+@end
View
56 English.lproj/main.xib
@@ -8,7 +8,7 @@
<string key="IBDocument.HIToolboxVersion">353.00</string>
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
<bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="495"/>
+ <integer value="497"/>
</object>
<object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -178,6 +178,14 @@
<reference key="NSOnImage" ref="794915978"/>
<reference key="NSMixedImage" ref="273203663"/>
</object>
+ <object class="NSMenuItem" id="1026732470">
+ <reference key="NSMenu" ref="75340798"/>
+ <string key="NSTitle">Automatically Show Dashboard After Some Inactivity</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="794915978"/>
+ <reference key="NSMixedImage" ref="273203663"/>
+ </object>
</object>
</object>
</object>
@@ -211,6 +219,9 @@
<object class="NSCustomObject" id="52689697">
<string key="NSClassName">Mediator</string>
</object>
+ <object class="NSUserDefaultsController" id="518255893">
+ <bool key="NSSharedInstance">YES</bool>
+ </object>
</object>
<object class="IBObjectContainer" key="IBDocument.Objects">
<object class="NSMutableArray" key="connectionRecords">
@@ -303,6 +314,30 @@
</object>
<int key="connectionID">496</int>
</object>
+ <object class="IBConnectionRecord">
+ <object class="IBBindingConnection" key="connection">
+ <string key="label">value: values.AutoDash</string>
+ <reference key="source" ref="1026732470"/>
+ <reference key="destination" ref="518255893"/>
+ <object class="NSNibBindingConnector" key="connector">
+ <reference key="NSSource" ref="1026732470"/>
+ <reference key="NSDestination" ref="518255893"/>
+ <string key="NSLabel">value: values.AutoDash</string>
+ <string key="NSBinding">value</string>
+ <string key="NSKeyPath">values.AutoDash</string>
+ <int key="NSNibBindingConnectorVersion">2</int>
+ </object>
+ </object>
+ <int key="connectionID">499</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">activateAutoDash:</string>
+ <reference key="source" ref="1050762845"/>
+ <reference key="destination" ref="1026732470"/>
+ </object>
+ <int key="connectionID">500</int>
+ </object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
@@ -463,6 +498,7 @@
<reference ref="579663166"/>
<reference ref="325290597"/>
<reference ref="254191638"/>
+ <reference ref="1026732470"/>
</object>
<reference key="parent" ref="450328247"/>
</object>
@@ -481,6 +517,16 @@
<reference key="object" ref="254191638"/>
<reference key="parent" ref="75340798"/>
</object>
+ <object class="IBObjectRecord">
+ <int key="objectID">497</int>
+ <reference key="object" ref="1026732470"/>
+ <reference key="parent" ref="75340798"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">498</int>
+ <reference key="object" ref="518255893"/>
+ <reference key="parent" ref="1049"/>
+ </object>
</object>
</object>
<object class="NSMutableDictionary" key="flattenedProperties">
@@ -515,6 +561,7 @@
<string>488.IBPluginDependency</string>
<string>494.IBPluginDependency</string>
<string>495.IBPluginDependency</string>
+ <string>497.IBPluginDependency</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -541,7 +588,8 @@
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
- <string>{{364, 983}, {254, 53}}</string>
+ <string>{{364, 963}, {411, 73}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
@@ -568,7 +616,7 @@
</object>
</object>
<nil key="sourceID"/>
- <int key="maxID">496</int>
+ <int key="maxID">500</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
@@ -608,6 +656,7 @@
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSMutableArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
+ <string>activateAutoDash:</string>
<string>installDashboardWidget:</string>
<string>love:</string>
<string>share:</string>
@@ -621,6 +670,7 @@
<string>id</string>
<string>id</string>
<string>id</string>
+ <string>id</string>
</object>
</object>
<object class="NSMutableDictionary" key="outlets">
View
3 StatusItemController.h
@@ -21,20 +21,23 @@
#import <Growl/GrowlApplicationBridge.h>
#import <Cocoa/Cocoa.h>
+@class AutoDash;
@interface StatusItemController : NSObject <GrowlApplicationBridgeDelegate>
{
NSStatusItem* status_item;
IBOutlet NSMenu* menu;
IBOutlet NSMenuItem* start_at_login;
+ AutoDash* autodash;
}
-(IBAction)love:(id)sender;
-(IBAction)tag:(id)sender;
-(IBAction)share:(id)sender;
-(IBAction)startAtLogin:(id)sender;
-(IBAction)installDashboardWidget:(id)sender;
+-(IBAction)activateAutoDash:(id)sender;
@end
View
19 StatusItemController.m
@@ -19,6 +19,7 @@
// Created by Max Howell <max@last.fm>
+#import "AutoDash.h"
#import "lastfm.h"
#import "Mediator.h"
#import "scrobsub.h"
@@ -87,6 +88,13 @@ static LSSharedFileListItemRef audioscrobbler_session_login_item(LSSharedFileLis
@implementation StatusItemController
++(void)initialize
+{
+ [[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary
+ dictionaryWithObject:[NSNumber numberWithBool:false]
+ forKey:@"AutoDash"]];
+}
+
-(void)awakeFromNib
{
NSBundle* bundle = [NSBundle mainBundle];
@@ -105,6 +113,9 @@ -(void)awakeFromNib
[GrowlApplicationBridge setGrowlDelegate:self];
+ if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"AutoDash"] boolValue] == true)
+ autodash = [[AutoDash alloc] init];
+
/// Start at Login item
LSSharedFileListRef login_items_ref = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
if(login_items_ref){
@@ -289,6 +300,14 @@ -(IBAction)installDashboardWidget:(id)sender
[[NSWorkspace sharedWorkspace] openFile:[[task currentDirectoryPath] stringByAppendingPathComponent:@"Last.fm.wdgt"]];
}
+-(IBAction)activateAutoDash:(id)sender
+{
+ if ([sender state] == NSOnState)
+ autodash = [[AutoDash alloc] init];
+ else
+ [autodash release];
+}
+
@end

0 comments on commit 876f1bf

Please sign in to comment.