2010-01-03 13 views
5

Próbuję ponownie napisać aplikację, którą mam dla Windows w Objective-C na moim Macu, i chcę móc zrobić coś takiego jak Mac's hot rogi. Jeśli przesuniemy mysz na lewą stronę ekranu, spowoduje to, że okno będzie widoczne, jeśli przeniesię ją poza lokalizację okna, okno ponownie się zasłoni. (okno zostanie przesunięte do lewej strony ekranu).Tworzenie okna i wyskakiwanie z krawędzi ekranu

Czy ktoś wie, gdzie mogę znaleźć kod demo (lub odniesienie), jak to zrobić, a przynajmniej jak określić, gdzie znajduje się mysz, nawet jeśli bieżąca aplikacja nie jest na wierzchu. (nie wiesz, jak to powiedzieć, zbyt często używane w świecie Windows).

Dziękuję

-Brad

+0

To brzmi bardziej jak Windows, takich jak rtęć i schowek na szelfie Historii i (opcjonalnie) Adium na liście kontaktów, które mogą pop i z boku ekranu, gdy mysz uderza że krawędź. Czy o tym myślisz? –

+0

Tak, właśnie o tym myślę. – Brad

Odpowiedz

1

Oto co wymyśliłem. Podziękowania dla Petera za powyższe wskazówki.

@interface SlidingWindow : NSWindow 
    { 
     CGRectEdge _slidingEdge; 
     NSView *_wrapperView; 
    } 


    @property (nonatomic, assign) CGRectEdge slidingEdge; 
    @property (nonatomic, retain) NSView *wrapperView; 

    -(id)initWithContentRect:(NSRect) contentRect 
        styleMask:(unsigned int) styleMask 
        backing:(NSBackingStoreType) backingType 
         defer:(BOOL) flag; 

    - (NSView*)wrapperViewWithFrame:(NSRect)bounds; 

    - (BOOL)mayOrderOut; 

    @end 

    @interface SlidingWindow() 

    - (void)adjustWrapperView; 

    - (void)setWindowWidth:(NSNumber*)width; 
    - (void)setWindowHeight:(NSNumber*)height; 

    @end 


    @implementation SlidingWindow 


@synthesize slidingEdge = _slidingEdge; 
@synthesize wrapperView = _wrapperView; 


- (id)initWithContentRect:(NSRect) contentRect 
       styleMask:(unsigned int) styleMask 
        backing:(NSBackingStoreType) backingType 
        defer:(BOOL) flag 
{ 

    if ((self = [super initWithContentRect:contentRect 
           styleMask:NSBorderlessWindowMask 
            backing:backingType 
            defer:flag])) { 
     /* May want to setup some other options, 
     like transparent background or something */ 

     [self setSlidingEdge:CGRectMaxYEdge]; 
     [self setHidesOnDeactivate:YES]; 
     [self setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces]; 
    } 

    return self; 
} 

- (NSView*)wrapperViewWithFrame:(NSRect)bounds 
{ 
    return [[[NSView alloc] initWithFrame:bounds] autorelease]; 
} 

- (void)adjustWrapperView 
{ 
    if (self.wrapperView == nil) { 
     NSRect frame = [self frame]; 
     NSRect bounds = NSMakeRect(0, 0, frame.size.width, frame.size.height); 
     NSView *wrapperView = [self wrapperViewWithFrame:bounds]; 
     NSArray *subviews = [[[[self contentView] subviews] copy] autorelease]; 

     for (NSView *view in subviews) { 
      [wrapperView addSubview:view]; 
     } 

     [wrapperView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; 
     [[self contentView] addSubview:wrapperView]; 

     self.wrapperView = wrapperView; 
    } 

    switch (self.slidingEdge) { 
     case CGRectMaxXEdge: 
      [self.wrapperView setAutoresizingMask:(NSViewHeightSizable | NSViewMaxXMargin)]; 
      break; 

     case CGRectMaxYEdge: 
      [self.wrapperView setAutoresizingMask:(NSViewWidthSizable | NSViewMaxYMargin)]; 
      break; 

     case CGRectMinXEdge: 
      [self.wrapperView setAutoresizingMask:(NSViewHeightSizable | NSViewMinXMargin)]; 
      break; 

     case CGRectMinYEdge: 
     default: 
      [self.wrapperView setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)]; 
    } 
} 

- (void)makeKeyAndOrderFront:(id)sender 
{ 
    [self adjustWrapperView]; 

    if ([self isVisible]) { 
     [super makeKeyAndOrderFront:sender]; 
    } 
    else { 
     NSRect screenRect = [[NSScreen menubarScreen] visibleFrame]; 
     NSRect windowRect = [self frame]; 

     CGFloat x; 
     CGFloat y; 
     NSRect startWindowRect; 
     NSRect endWindowRect; 

     switch (self.slidingEdge) { 
      case CGRectMinXEdge: 
       x = 0; 
       y = (screenRect.size.height - windowRect.size.height)/2 + screenRect.origin.y; 
       startWindowRect = NSMakeRect(x - windowRect.size.width, y, 0, windowRect.size.height); 
       break; 

      case CGRectMinYEdge: 
       x = (screenRect.size.width - windowRect.size.width)/2 + screenRect.origin.x; 
       y = 0; 
       startWindowRect = NSMakeRect(x, y - windowRect.size.height, windowRect.size.width, 0); 
       break; 

      case CGRectMaxXEdge: 
       x = screenRect.size.width - windowRect.size.width + screenRect.origin.x; 
       y = (screenRect.size.height - windowRect.size.height)/2 + screenRect.origin.y; 
       startWindowRect = NSMakeRect(x + windowRect.size.width, y, 0, windowRect.size.height); 
       break; 

      case CGRectMaxYEdge: 
      default: 
       x = (screenRect.size.width - windowRect.size.width)/2 + screenRect.origin.x; 
       y = screenRect.size.height - windowRect.size.height + screenRect.origin.y; 
       startWindowRect = NSMakeRect(x, y + windowRect.size.height, windowRect.size.width, 0); 
     } 

     endWindowRect = NSMakeRect(x, y, windowRect.size.width, windowRect.size.height); 

     [self setFrame:startWindowRect display:NO animate:NO]; 

     [super makeKeyAndOrderFront:sender]; 

     [self setFrame:endWindowRect display:YES animate:YES]; 

     [self performSelector:@selector(makeResizable) 
        withObject:nil 
        afterDelay:1]; 
    } 
} 

- (void)makeResizable 
{ 
    NSView *wrapperView = self.wrapperView; 
    NSRect frame = [self frame]; 
    NSRect bounds = NSMakeRect(0, 0, frame.size.width, frame.size.height); 

    [wrapperView setFrame:bounds]; 
    [wrapperView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; 
} 

- (void)orderOut:(id)sender 
{ 
    [self adjustWrapperView]; 

    NSRect startWindowRect = [self frame]; 
    NSRect endWindowRect; 

    switch (self.slidingEdge) { 
     case CGRectMinXEdge: 
      endWindowRect = NSMakeRect(startWindowRect.origin.x, 
             startWindowRect.origin.y, 
             0, 
             startWindowRect.size.height); 
      break; 

     case CGRectMinYEdge: 
      endWindowRect = NSMakeRect(startWindowRect.origin.x, 
             startWindowRect.origin.y, 
             startWindowRect.size.width, 
             0); 
      break; 

     case CGRectMaxXEdge: 
      endWindowRect = NSMakeRect(startWindowRect.origin.x + startWindowRect.size.width, 
             startWindowRect.origin.y, 
             0, 
             startWindowRect.size.height); 
      break; 

     case CGRectMaxYEdge: 
     default: 
      endWindowRect = NSMakeRect(startWindowRect.origin.x, 
             startWindowRect.origin.y + startWindowRect.size.height, 
             startWindowRect.size.width, 
             0); 
    } 

    [self setFrame:endWindowRect display:YES animate:YES]; 

    switch (self.slidingEdge) { 
     case CGRectMaxXEdge: 
     case CGRectMinXEdge: 
      if (startWindowRect.size.width > 0) { 
       [self performSelector:@selector(setWindowWidth:) 
          withObject:[NSNumber numberWithDouble:startWindowRect.size.width] 
          afterDelay:0]; 
      } 
      break; 

     case CGRectMaxYEdge: 
     case CGRectMinYEdge: 
     default: 
      if (startWindowRect.size.height > 0) { 
       [self performSelector:@selector(setWindowHeight:) 
          withObject:[NSNumber numberWithDouble:startWindowRect.size.height] 
          afterDelay:0]; 
      } 
    } 

    [super orderOut:sender]; 
} 

- (void)setWindowWidth:(NSNumber*)width 
{ 
    NSRect startWindowRect = [self frame]; 
    NSRect endWindowRect = NSMakeRect(startWindowRect.origin.x, 
             startWindowRect.origin.y, 
             [width doubleValue], 
             startWindowRect.size.height); 

    [self setFrame:endWindowRect display:NO animate:NO];  
} 

- (void)setWindowHeight:(NSNumber*)height 
{ 
    NSRect startWindowRect = [self frame]; 
    NSRect endWindowRect = NSMakeRect(startWindowRect.origin.x, 
             startWindowRect.origin.y, 
             startWindowRect.size.width, 
             [height doubleValue]); 

    [self setFrame:endWindowRect display:NO animate:NO];  
} 

- (void)resignKeyWindow 
{ 
    [self orderOut:self]; 

    [super resignKeyWindow]; 
} 

- (BOOL)canBecomeKeyWindow 
{ 
    return YES; 
} 

- (void)performClose:(id)sender 
{ 
    [self close]; 
} 

- (void)dealloc 
{ 
    [_wrapperView release], _wrapperView = nil; 

    [super dealloc]; 
} 

@end 


@implementation NSScreen (MenubarScreen) 

+ (NSScreen*)menubarScreen 
{ 
    NSArray *screens = [self screens]; 

    if ([screens count] > 0) { 
     return [screens objectAtIndex:0]; 
    } 

    return nil; 
} 
@end 
+0

Słodkie, dziękuję za kod demo – Brad

+0

Po prostu zauważyłem, że miksowałem min & max w każdym miejscu, ale w -adjustWrapperView –

+0

@PierreBernard naprawiłeś min i max w odpowiedzi lub czy wciąż jest wstecz .. również, nie ma '@interface 'dla tego' @ implementacji' i nie jest _exactly_ jasne, co musiałoby być w nim ... na przykład, żaden z 'slidingEdge's nie jest zdefiniowany, itp. –

2

Będziesz chcą wprowadzić niewidzialną okno na krawędzi ekranu z rzędu okno Ustaw dlatego zawsze na wierzchu. Następnie możesz odsłuchać zdarzenia przeniesione myszą w tym oknie.

Aby ustawić okno, aby być niewidoczne i na górze, upewnij nazywa użycie okno podklasa jak:

[self setBackgroundColor:[NSColor clearColor]]; 
[self setExcludedFromWindowsMenu:YES]; 
[self setCanHide:NO]; 
[self setLevel:NSScreenSaverWindowLevel]; 
[self setAlphaValue:0.0f]; 
[self setOpaque:NO]; 
[self orderFrontRegardless]; 

Następnie, aby włączyć mysz przeniósł wydarzenia,

[self setAcceptsMouseMovedEvents:YES]; 

spowoduje okno aby uzyskać połączenia z:

- (void)mouseMoved:(NSEvent *)theEvent 
{ 
    NSLog(@"mouse moved into invisible window."); 
} 

Mam nadzieję, że wystarczy, aby zacząć.

-Ken

+0

Drugi element układanki sprawia, że ​​okno faktycznie pojawia się i znika. Musisz umieścić natychmiastowe subviews widoku zawartości okna w innym widoku i dokonać * tego * widoku zawartości. Ustaw maskę automatycznego nadpisywania widoku w widoku treści, aby nie zmieniać rozmiaru i zszywać jej początek do lewej krawędzi (w twoim przykładzie) widoku treści. Aby ukryć okno, zmień rozmiar okna na 1 piksel. Aby to pokazać, przywróć jego właściwy rozmiar. Jeśli chcesz zmienić rozmiar okna, musisz zmienić jego maskę po wyświetleniu/ukryciu okna. –

+0

Powodem, dla którego nie wystarczy po prostu przenieść i wyjąć okno, jest to, że użytkownik może mieć kolejny ekran w obszarze, do którego zostanie przeniesione okno. Wtedy nie ukrywasz okna, tylko przesuwasz je na inny ekran - a nie to, czego chce użytkownik. (Jeśli chodzi o sposób, w jaki użytkownik pokazywałby okno w tej sytuacji, użytkownik mógłby mieć okno w górę lub w dół za krawędzią mniejszego ekranu, dając mu coś do uderzenia.) –

+0

Niektóre rzeczy zapomniałem o oknie nakładki: [self setHasShadow: NO]; i [self setIgnoresMouseEvents: NO]; , więc Twoje niewidzialne okno w rzeczywistości nie blokuje kliknięć. Jestem w 99% pewien, że nadal będziesz mieć przeniesione zdarzenia myszy. –

2

Oto AutoHidingWindow - podklasą SlidingWindow który wyskakuje gdy mysz uderza krawędzi ekranu. Opinia mile widziany.

@interface ActivationWindow : NSWindow 
{ 
    AutoHidingWindow *_activationDelegate; 
    NSTrackingArea *_trackingArea; 
} 

- (ActivationWindow*)initWithDelegate:(AutoHidingWindow*)activationDelegate; 

@property (assign) AutoHidingWindow *activationDelegate; 
@property (retain) NSTrackingArea *trackingArea; 

- (void)adjustWindowFrame; 
- (void)adjustTrackingArea; 

@end 

@interface AutoHidingWindow() 

- (void)autoShow; 
- (void)autoHide; 

@end 


@implementation AutoHidingWindow 

- (id)initWithContentRect:(NSRect) contentRect 
       styleMask:(unsigned int) styleMask 
        backing:(NSBackingStoreType) backingType 
        defer:(BOOL) flag 
{ 

    if ((self = [super initWithContentRect:contentRect 
           styleMask:NSBorderlessWindowMask 
            backing:backingType 
            defer:flag])) { 
     _activationWindow = [[ActivationWindow alloc] initWithDelegate:self]; 
    } 

    return self; 
} 

@synthesize activationWindow = _activationWindow; 

- (void)dealloc 
{ 
    [_activationWindow release], _activationWindow = nil; 

    [super dealloc]; 
} 

- (void)makeKeyAndOrderFront:(id)sender 
{ 
    [super makeKeyAndOrderFront:sender]; 

} 

- (void)autoShow 
{ 
    [self makeKeyAndOrderFront:self]; 

    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(autoHide) object:nil]; 
    [self performSelector:@selector(autoHide) withObject:nil afterDelay:2]; 
} 

- (void)autoHide 
{ 
    NSPoint mouseLocation = [NSEvent mouseLocation]; 
    NSRect windowFrame = [self frame]; 

    if (NSPointInRect(mouseLocation, windowFrame)) { 
     [self performSelector:@selector(autoHide) withObject:nil afterDelay:2]; 
    } 
    else { 
     [self orderOut:self]; 
    } 
} 

@end 


@implementation ActivationWindow 

- (ActivationWindow*)initWithDelegate:(AutoHidingWindow*)activationDelegate 
{ 
    if ((self = [super initWithContentRect:[[NSScreen mainScreen] frame] 
           styleMask:NSBorderlessWindowMask 
            backing:NSBackingStoreBuffered 
            defer:NO]) != nil) { 
     _activationDelegate = activationDelegate; 

     [self setBackgroundColor:[NSColor clearColor]]; 
     [self setExcludedFromWindowsMenu:YES]; 
     [self setCanHide:NO]; 
     [self setHasShadow:NO]; 
     [self setLevel:NSScreenSaverWindowLevel]; 
     [self setAlphaValue:0.0]; 
     [self setIgnoresMouseEvents:YES]; 
     [self setOpaque:NO]; 
     [self orderFrontRegardless]; 

     [self adjustWindowFrame]; 
     [self.activationDelegate addObserver:self 
           forKeyPath:@"slidingEdge" 
            options:0 
            context:@"slidingEdge"]; 
     [[NSNotificationCenter defaultCenter] addObserver:self 
               selector:@selector(screenParametersChanged:) 
                name:NSApplicationDidChangeScreenParametersNotification 
                object:nil];  
    } 

    return self; 
} 

@synthesize activationDelegate = _activationDelegate; 
@synthesize trackingArea = _trackingArea; 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{ 
    if ([@"slidingEdge" isEqual:context]) { 
     [self adjustTrackingArea]; 
    } 
    else { 
     [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 
    } 
} 


- (void)dealloc 
{ 
    [[NSNotificationCenter defaultCenter] removeObserver:self]; 

    [self.activationDelegate removeObserver:self forKeyPath:@"slidingEdge"]; 
    _activationDelegate = nil; 

    [_trackingArea release], _trackingArea = nil; 

    [super dealloc]; 
} 

- (void)screenParametersChanged:(NSNotification *)notification 
{ 
    [self adjustWindowFrame]; 
} 

- (void)adjustWindowFrame 
{ 
    NSScreen *mainScreen = [NSScreen mainScreen]; 
    CGFloat menuBarHeight = [NSMenuView menuBarHeight]; 
    NSRect windowFrame = [mainScreen frame]; 

    windowFrame.size.height -= menuBarHeight; 

    [self setFrame:windowFrame display:NO]; 
    [self adjustTrackingArea]; 
} 

- (void)adjustTrackingArea 
{ 
    NSView *contentView = [self contentView]; 
    NSRect trackingRect = contentView.bounds; 
    CGRectEdge slidingEdge = self.activationDelegate.slidingEdge; 
    CGFloat trackingRectSize = 2.0; 

    switch (slidingEdge) { 
     case CGRectMaxXEdge: 
      trackingRect.origin.x = trackingRect.origin.x + trackingRect.size.width - trackingRectSize; 
      trackingRect.size.width = trackingRectSize; 
      break; 

     case CGRectMaxYEdge: 
      trackingRect.origin.y = trackingRect.origin.y + trackingRect.size.height - trackingRectSize; 
      trackingRect.size.height = trackingRectSize; 
      break; 

     case CGRectMinXEdge: 
      trackingRect.origin.x = 0; 
      trackingRect.size.width = trackingRectSize; 
      break; 

     case CGRectMinYEdge: 
     default: 
      trackingRect.origin.y = 0; 
      trackingRect.size.height = trackingRectSize; 
    } 


    NSTrackingAreaOptions options = 
    NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | 
    NSTrackingActiveAlways | 
    NSTrackingEnabledDuringMouseDrag; 

    NSTrackingArea *trackingArea = self.trackingArea; 

    if (trackingArea != nil) { 
     [contentView removeTrackingArea:trackingArea]; 
    } 

    trackingArea = [[NSTrackingArea alloc] initWithRect:trackingRect 
               options:options 
                owner:self 
               userInfo:nil]; 

    [contentView addTrackingArea:trackingArea]; 

    self.trackingArea = [trackingArea autorelease]; 
} 

- (void)mouseEntered:(NSEvent *)theEvent 
{ 
    [self.activationDelegate autoShow]; 
} 


- (void)mouseMoved:(NSEvent *)theEvent 
{ 
    [self.activationDelegate autoShow]; 
} 

- (void)mouseExited:(NSEvent *)theEvent 
{ 
} 

@end 
Powiązane problemy