• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Accessing the FUS menu?
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Accessing the FUS menu?


  • Subject: Re: Accessing the FUS menu?
  • From: Bjoern Kriews <email@hidden>
  • Date: Tue, 30 Mar 2004 23:26:01 +0200

On 30.03.2004, at 17:36, Randall Meadows wrote:

Can anyone shed any light on how one might gain access to the Fast User Switching menu?

Do you want to be able to switch users programmatically ?

/System/Library/CoreServices/Menu\ Extras/User.menu/Contents/Resources/CGSession -switchToUserID <numeric id>

(undocumented, subject to break and cause confusion)

Or do you want to hack the menu ?

(even less documented, but I tried it to explore some advanced posing and because I wanted "bkr" instead of
the rather longish "Bjoern Kriews" in there. Accidentally, it adds a "Suspend" menu item -
I hear this one was available in early betas - well the code is still there -
and CGSession has a -suspend switch btw.

I wouldn't ship this to people who don't know about the undocumented-ness of this stuff,
therefore I release the following Code with NO WARRANTY under the GNU Public License,
see http://www.gnu.org/licenses/gpl.html.


create a bundle project with the following files or email me for a project archive.

Hope that helps, Bjoern

--- UserPoser.h ---

#import <Foundation/Foundation.h>

// make ourselves a subclass of "just something" - we will change that later

@interface UserPoser : NSView

+ (void)load;

// setAttributedString is used to receiving NSCFStrings
- (void)setAttributedString:(NSString *) aString isMenuDown:(char)isDown;

--- UserPoser.m ---

// All rights reversed.

#import "UserPoser.h"

#import <objc/objc-class.h>
#import <unistd.h>

@implementation UserPoser

+ (void)load
{
Class usv;
NSString *userExtraPath = @"/System/Library/CoreServices/Menu Extras/User.menu";
NSBundle *userExtraBundle;
NSString *mainBundleIdentifier;

mainBundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];

if( NO == [mainBundleIdentifier isEqualToString: @"com.apple.systemuiserver"] ) {
//NSLog(@"UserPoser not interested in '%@'", mainBundleIdentifier);
return;
}

if( nil == ( userExtraBundle = [NSBundle bundleWithPath: userExtraPath] ) ) {
NSLog(@"could not create bundle for '%@' - giving up", userExtraPath);
return;
}

if( NO == [userExtraBundle load] ) {
NSLog(@"could not load %@ - giving up", userExtraBundle);
return;
}

if( nil == ( usv = NSClassFromString(@"UserSwitcherView") ) ) {
NSLog(@"could not find class UserSwitcherView - giving up");
return;
}

//NSLog(@"UserPoser was %@", [UserPoser superclass]);

// we should _really_ not be doing that - but Objective-C is so inviting...
( (struct objc_class *) [UserPoser class] )->super_class = usv;

NSLog(@"UserPoser now posing for %@ in %@", [UserPoser superclass], mainBundleIdentifier);

[UserPoser poseAsClass: usv];
}

// called when switcher menu title is changed
// setAttributedString is used to receiving NSCFStrings
- (void)setAttributedString:(NSString *) aString isMenuDown:(char)isDown
{
unsigned int flags = [[NSApp currentEvent] modifierFlags];
NSString *shortName;

shortName = isDown ? ( flags & NSAlternateKeyMask ? [NSString stringWithFormat: @"%d", geteuid()] : @";-)" ) : NSUserName();

// NSLog(@"UserPoser: setAttributedString called with '%@' -> '%@', %d - ", aString, shortName, isDown);

[super setAttributedString: shortName isMenuDown:isDown]; // warning ok

if( isDown ) { // this should be in a AppleUser Posers -createMenu, but I didn't test that
id userSwitcher = nil;
NSMenu *menu = nil;
NSArray *items;

// need to talk straight here
object_getInstanceVariable( self, "mUserSwitcher", (void**) &userSwitcher ); /* = AppleUser:NSMenuExtra */
object_getInstanceVariable( userSwitcher, "_menu", (void**) &menu ); /* NSMenuExtra attribute */

items = [menu itemArray];

// since we are suboptimally called too often (see above) we have to check if kilroy was here
if( [[items lastObject] action] != @selector(SuspendAccount:) ) {
[[menu insertItemWithTitle: @"Suspense..." action: @selector(SuspendAccount:) keyEquivalent: @"" atIndex: [items count]] setTarget: userSwitcher];
}
}
}

@end

--- Info file to put in Library/InputManagers/UserPoser alogn with UserPoser.bundle ---
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<dict>
<key>BundleName</key>
<string>UserPoser.bundle</string>
<key>LoadBundleOnLaunch</key>
<string>YES</string>
<key>LocalizedNames</key>
<dict>
<key>English</key>
<string>UserPoser</string>
</dict>
<key>NoMenuEntry</key>
<string>YES</string>
</dict>
</plist>
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.


  • Follow-Ups:
    • Re: Accessing the FUS menu?
      • From: "Louis C. Sacha" <email@hidden>
References: 
 >Accessing the FUS menu? (From: Randall Meadows <email@hidden>)

  • Prev by Date: Re: creating local Log File in /Library/Logs...
  • Next by Date: Modifying the text attributes applied to an NSTextView
  • Previous by thread: Accessing the FUS menu?
  • Next by thread: Re: Accessing the FUS menu?
  • Index(es):
    • Date
    • Thread