dev.stuconnolly.com / svn / safaritabs

  1. /*
  2.  *  STSafariPlugin.m
  3.  *
  4.  *  SafariTabs
  5.  *
  6.  *  Copyright (c) 2007 Stuart Connolly. All rights reserved.
  7.  *
  8.  *  This program is free software; you can redistribute it and/or
  9.  *  modify it under the terms of the GNU General Public License
  10.  *  as published by the Free Software Foundation; either version 2
  11.  *  of the License, or (at your option) any later version.
  12.  *
  13.  *  This program is distributed in the hope that it will be useful,
  14.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16.  *  GNU General Public License for more details.
  17.  *
  18.  *  You should have received a copy of the GNU General Public License
  19.  *  along with this program; if not, write to the Free Software
  20.  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  21.  */
  22.  
  23. #import "STSafariPlugin.h"
  24. #import "STAppController.h"
  25. #import "STBrowserWindowController.h"
  26. #import "STConstants.h"
  27.  
  28. typedef struct objc_method *Method;
  29.  
  30. struct objc_method {
  31.     SEL method_name;
  32.     char *method_types;
  33.     IMP method_imp;
  34. };
  35.  
  36. @implementation STSafariPlugin
  37.  
  38.  
  39. ////////////////////////////////////////////// *** renameSelector
  40.  
  41. + (BOOL)renameSelector:(Class)_class fromOldSelector:(SEL)_oldSelector toNewSelector:(SEL)_newSelector
  42. {
  43.     Method method = nil;
  44.    
  45.     method = class_getInstanceMethod(_class, _oldSelector);
  46.    
  47.     if (method == nil) {
  48.         return NO;
  49.     }
  50.    
  51.     method->method_name = _newSelector;
  52.    
  53.     return YES;
  54. }
  55.  
  56.  
  57. ////////////////////////////////////////////// *** load
  58.  
  59. + (void)load
  60. {
  61.     // A special method called by SIMBL once the application has started and all classes are initialized.
  62.    
  63.     // Exchange Safari's applicationWillTerminate: with custom one
  64.     [STSafariPlugin renameSelector:[AppController class] fromOldSelector:@selector(applicationShouldTerminate:) toNewSelector:@selector(_safari_applicationShouldTerminate:)];
  65.     [STSafariPlugin renameSelector:[AppController class] fromOldSelector:@selector(_st_applicationShouldTerminate:) toNewSelector:@selector(applicationShouldTerminate:)];
  66.    
  67.     // Exchange Safari's windowShouldClose: with custom one
  68.     [STSafariPlugin renameSelector:[BrowserWindowController class] fromOldSelector:@selector(windowShouldClose:) toNewSelector:@selector(_safari_windowShouldClose:)];
  69.     [STSafariPlugin renameSelector:[BrowserWindowController class] fromOldSelector:@selector(_st_windowShouldClose:) toNewSelector:@selector(windowShouldClose:)];
  70.    
  71.     // Exchange Safari's createTab: with custom one
  72.     [STSafariPlugin renameSelector:[BrowserWindowController class] fromOldSelector:@selector(createTab) toNewSelector:@selector(_safari_createTab)];
  73.     [STSafariPlugin renameSelector:[BrowserWindowController class] fromOldSelector:@selector(_st_createTab) toNewSelector:@selector(createTab)];
  74.    
  75.     // Exchange Safari's performQuickSearch: with custom one
  76.     [STSafariPlugin renameSelector:[BrowserWindowController class] fromOldSelector:@selector(performQuickSearch:) toNewSelector:@selector(_safari_performQuickSearch:)];
  77.     [STSafariPlugin renameSelector:[BrowserWindowController class] fromOldSelector:@selector(_st_performQuickSearch:) toNewSelector:@selector(performQuickSearch:)];
  78.    
  79.     // Load our custom menu items
  80.     [NSBundle loadNibNamed:@"MenuAdditions" owner:[STSafariPlugin sharedInstance]];
  81. }
  82.  
  83.  
  84. ////////////////////////////////////////////// *** sharedInstance
  85.  
  86. + (STSafariPlugin *)sharedInstance
  87. {
  88.     // Returns a single static instance of the plugin
  89.     static STSafariPlugin *plugin = nil;
  90.    
  91.     if (plugin == nil) {
  92.         plugin = [[STSafariPlugin alloc] init];
  93.     }
  94.    
  95.     return plugin;
  96. }
  97.  
  98.  
  99. ////////////////////////////////////////////// *** terminateWithoutWarning
  100.  
  101. - (BOOL)terminateWithoutWarning
  102. {
  103.     return terminateWithoutWarning;
  104. }
  105.  
  106.  
  107. ////////////////////////////////////////////// *** setTerminateWithoutWarning
  108.  
  109. - (void)setTerminateWithoutWarning:(BOOL)warning
  110. {
  111.     terminateWithoutWarning = warning;
  112. }
  113.  
  114.  
  115. ////////////////////////////////////////////// *** isLoaded
  116.  
  117. - (BOOL)isLoaded
  118. {
  119.     return YES;
  120. }
  121.  
  122.  
  123. ////////////////////////////////////////////// *** awakeFromNib
  124.  
  125. - (void)awakeFromNib
  126. {
  127.     NSMenu *safariMenuBar = [[NSApplication sharedApplication] mainMenu];
  128.     NSMenu *fileMenu = [[safariMenuBar itemAtIndex:1] submenu];
  129.    
  130.     NSMenuItem *closeWithoutWarningMenuItem = [menuAdditions itemAtIndex:0];
  131.     NSMenuItem *quitWithoutWarningMenuItem = [menuAdditions itemAtIndex:1];
  132.    
  133.     if ([[NSUserDefaults standardUserDefaults] boolForKey:STAddCloseNoWarningMenuItem]) {
  134.         NSEnumerator *itemEnumerator = [[fileMenu itemArray] objectEnumerator];
  135.         NSMenuItem *item;
  136.  
  137.         // Add the 'Close Window Without Warning' menu item
  138.         while(item = [itemEnumerator nextObject]) {
  139.             if ([item action] == @selector(performClose:)) {
  140.                 int index = [fileMenu indexOfItem:item];
  141.                 [fileMenu insertItem:[closeWithoutWarningMenuItem copy] atIndex:(index + 1)];
  142.                
  143.                 break;
  144.             }
  145.         }
  146.     }
  147.    
  148.     if ([[NSUserDefaults standardUserDefaults] boolForKey:STAddQuitNoWarningMenuItem]) {
  149.         // Add the 'Quit Safari Without Warning' menu item
  150.         [[[safariMenuBar itemAtIndex:0] submenu] addItem:[quitWithoutWarningMenuItem copy]];
  151.     }
  152.    
  153.     terminateWithoutWarning = NO;
  154. }
  155.  
  156.  
  157. ////////////////////////////////////////////// *** closeWindowWithoutWarning
  158.  
  159. - (IBAction)closeWindowWithoutWarning:(id)sender
  160. {
  161.     [[[NSApplication sharedApplication] mainWindow] close];
  162. }
  163.  
  164.  
  165. ////////////////////////////////////////////// *** quitWithoutWarning
  166.  
  167. - (IBAction)quitWithoutWarning:(id)sender
  168. {
  169.     terminateWithoutWarning = YES;
  170.     [[NSApplication sharedApplication] terminate:self];
  171. }
  172.  
  173.  
  174. ////////////////////////////////////////////// *** validateUserInterfaceItem
  175.  
  176. - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
  177. {
  178.     if ([item action] == @selector(closeWindowWithoutWarning:)) {
  179.         if ([[NSApplication sharedApplication] mainWindow]) {
  180.             return YES;
  181.         }
  182.     }
  183.     else if ([item action] == @selector(quitWithoutWarning:)) {
  184.         return YES;
  185.     }
  186.  
  187.     // Otherwise ask Safari to validate the item
  188.     return NO;
  189. }
  190.  
  191. @end