Logo Search packages:      
Sourcecode: xdaliclock version File versions  Download package

AppController.m

/* xdaliclock - a melting digital clock
 * Copyright (c) 1991-2006 Jamie Zawinski <jwz@jwz.org>
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation.  No representations are made about the suitability of this
 * software for any purpose.  It is provided "as is" without express or
 * implied warranty.
 */

#import "AppController.h"
#import "DaliClockWindow.h"

char *progname = "Dali Clock";   // digital.c wants this for error messages.

@interface AppController (ForwardDeclarations)
- (void)createDaliClockWindow;
@end

@implementation AppController

+ (void)initialize;
{
  static BOOL initialized_p = NO;
  if (initialized_p)
    return;
  initialized_p = YES;
    
  // Set the defaults for all preferences.
  //
  NSColor *deffg = [NSColor blueColor];
  NSColor *defbg = [NSColor colorWithCalibratedHue:0.50
                                        saturation:1.00
                                        brightness:0.90
                                             alpha:0.30];
  NSDate *defdate = [NSDate dateWithTimeIntervalSinceNow:
                     (NSTimeInterval) 60 * 60 * 12];  // 12 hours from now
  
  NSDictionary* defaults = [NSDictionary dictionaryWithObjectsAndKeys:
    @"0", @"hourStyle",
    @"0", @"timeStyle",
    @"0", @"dateStyle",
    [NSArchiver archivedDataWithRootObject:deffg], @"initialForegroundColor",
    [NSArchiver archivedDataWithRootObject:defbg], @"initialBackgroundColor",
    @"10.0", @"cycleSpeed",
    @"NO", @"usesCountdownTimer",
    defdate,@"countdownDate",
    @"NO", @"windowTitlebarIsHidden",
    @"2", @"windowLevel",
    nil];
  
  [[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
  [[NSUserDefaultsController sharedUserDefaultsController]
    setInitialValues:defaults];
}


- (void)createDaliClockWindow;
{
  NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];

  BOOL title_p = ![prefs boolForKey:@"windowTitlebarIsHidden"];
  BOOL was_fullscreen_p = (fullscreen_window_level != 0);
  
  int level = [prefs integerForKey:@"windowLevel"];
  level = (level == 0 ? NSFloatingWindowLevel :
           level == 1 ? NSNormalWindowLevel-1 :
           NSNormalWindowLevel);

  if (was_fullscreen_p) {
    [NSCursor unhide];
    if (CGDisplayRelease (kCGDirectMainDisplay) != kCGErrorSuccess)
      NSLog ( @"Couldn't release the display!");
  }

  if (fullscreen_p) {
    if (CGDisplayCapture (kCGDirectMainDisplay) != kCGErrorSuccess) {
        NSLog(@"Couldn't capture the main display!");
      fullscreen_p = NO;
    }
  }

  if (fullscreen_p) {
    level = CGShieldingWindowLevel();
    fullscreen_window_level = level;
    title_p = NO;
    [NSCursor hide];
  }
  
  NSScreen *screen = [NSScreen mainScreen];
  
  // Set default size/position of the window if there is no autosave.
  //
  NSRect rect;
  rect.size.width = 625;
  rect.size.height = 128;
  rect.origin.x = ([screen frame].size.width  - rect.size.width)  / 2;
  rect.origin.y = ([screen frame].size.height - rect.size.height) / 2;
  
  NSRect default_rect = rect;
  
  // Nuke the old window if we're re-creating it.
  //
  BOOL keep_old_size_p = NO;
  if (window) {
    keep_old_size_p = !was_fullscreen_p;
    rect = [window contentRectForFrameRect:[window frame]];
    [window close];
    [window setFrameAutosaveName:@""];  // two windows can't have the same one
    [window autorelease];
    window = 0;
  }
 
  window = [[DaliClockWindow alloc]
            initWithContentRect:rect
                      styleMask:(title_p
                                 ? (NSTitledWindowMask |
                                    NSClosableWindowMask |
                                    NSMiniaturizableWindowMask |
                                    NSResizableWindowMask)
                                 : (NSBorderlessWindowMask))
                        backing:NSBackingStoreBuffered
                          defer:YES
                         screen:screen];
  [window setTitle:@"Dali Clock"];
  [window setOpaque:NO];
  [window setHasShadow:NO];  // windows with shadows flicker
  [window setLevel:level];
  [window setMovableByWindowBackground:!fullscreen_p];
  [window setReleasedWhenClosed:NO];
  [window setDelegate:self]; // for the "cancel" method
  
  if (fullscreen_p) {
    // don't save window sizes for fullscreen windows.
    [window setFrameAutosaveName:@""];
  } else {
    [window setFrameAutosaveName:@"clockWindow"];
    // need "force" for size to be updated when borderless.
    if (! [window setFrameUsingName:[window frameAutosaveName] force:YES]) {
      // If we weren't able to set the frame, then that means that no size
      // was yet saved; so instead of leaving it at the "full screen" size,
      // use the default size and position instead.
      [window setFrame:[window frameRectForContentRect:default_rect]
               display:NO];
    }
  }
  
  if (fullscreen_p)
    [window setFrame:[screen frame] display:NO];
  else if (keep_old_size_p)
    [window setFrame:[window frameRectForContentRect:rect] display:NO];
  
  // if we're re-creating the window, just move the existing view 
  // from the previous window.
  if (! view)
    view = [[DaliClockView alloc] initWithFrame:[window frame]];
  
  [window setContentView:view];
}


/* When the window closes, exit (even if prefs still open.)
 */
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)a
{
  return YES;
}


/* Connect the various preferences to accessor methods on (mostly)
   the DaliClockView.
 */
- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
  [self createDaliClockWindow];
  if (!view || !window) abort();

  NSUserDefaultsController *userDefaultsController =
    [NSUserDefaultsController sharedUserDefaultsController];

  [view    bind:@"hourStyle" 
       toObject:userDefaultsController
    withKeyPath:@"values.hourStyle" options:nil];
  [view    bind:@"timeStyle"
       toObject:userDefaultsController
    withKeyPath:@"values.timeStyle"
        options:nil];
  [view    bind:@"dateStyle"
       toObject:userDefaultsController 
    withKeyPath:@"values.dateStyle"
        options:nil];
  [view    bind:@"cycleSpeed" 
       toObject:userDefaultsController
    withKeyPath:@"values.cycleSpeed"
        options:nil];
  [view    bind:@"usesCountdownTimer"
       toObject:userDefaultsController
    withKeyPath:@"values.usesCountdownTimer"
        options:nil];
  [view    bind:@"countdownDate"
       toObject:userDefaultsController
    withKeyPath:@"values.countdownDate"
        options:nil];

  NSDictionary *colorBindingOptions = 
    [NSDictionary dictionaryWithObject:@"NSUnarchiveFromData" 
                                forKey:NSValueTransformerNameBindingOption];
  [view    bind:@"initialForegroundColor"
       toObject:userDefaultsController
    withKeyPath:@"values.initialForegroundColor"
        options:colorBindingOptions];
  [view    bind:@"initialBackgroundColor"
       toObject:userDefaultsController
    withKeyPath:@"values.initialBackgroundColor"
        options:colorBindingOptions];

  [userDefaultsController addObserver:self 
                           forKeyPath:@"values.windowLevel" 
                              options:nil 
                              context:@selector(windowLevelDidChange:)];
  [userDefaultsController addObserver:self 
                           forKeyPath:@"values.windowTitlebarIsHidden" 
                              options:nil 
                         context:@selector(windowTitlebarIsHiddenDidChange:)];
  
  [window makeKeyAndOrderFront:self];
}


- (void)windowLevelDidChange:(NSDictionary *)change
{
  NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
  int level = [prefs integerForKey:@"windowLevel"];
  level = (level == 0 ? NSFloatingWindowLevel :
           level == 1 ? NSNormalWindowLevel-1 :
           NSNormalWindowLevel);
  [window setLevel:level];
}


- (void)windowTitlebarIsHiddenDidChange:(NSDictionary *)change
{
  // re-create the window when the "Title Bar" preference changes.
  [self createDaliClockWindow];
  [window makeKeyAndOrderFront:self];
}


- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
  SEL dispatchSelector = (SEL)context;
  if (dispatchSelector != NULL) {
    [self performSelector:dispatchSelector withObject:change];
  } else {
    [super observeValueForKeyPath:keyPath
                         ofObject:object
                           change:change
                          context:context];
  }
}


/* Toggle, called by the "Window / Full Screen" menu item.
   This doesn't go through the preferences because it should not be saved.
 */
- (void)performFullscreen:(id)sender
{
  fullscreen_p = !fullscreen_p;
  [self createDaliClockWindow];
  [window makeKeyAndOrderFront:self];
}


/* "Window / Minimize".
   Normally this happens in NSWindow via FirstResponder, but we bind this to
   the menu directly so that it works when the window is borderless or full
   screen.  (To minimize a full-screen window, we have to take it out of
   full-screen mode first, which is why this can't be in DaliClockWindow
   like performClose is).
 */
- (void)performMiniaturize:(id)sender
{
  if (fullscreen_p)
    // turn off fullscreen mode before miniaturizing.
    // (it does not automatically turn back on when unminiaturizing.)
    [self performFullscreen:sender];
  
  //[window performMiniaturize:sender];  // beeps when borderless
  [window miniaturize:sender];
}


/* This is sent by ESC and Cmd-.
   Take us out of full-screen if it is active.
 */
- (void)cancel:(id)sender
{
  if (fullscreen_p) {
    [self performFullscreen:sender];
  }
}

@end

Generated by  Doxygen 1.6.0   Back to index