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 "STBrowserDocument.h"
  27. #import "STConstants.h"
  28.  
  29. typedef struct objc_method *Method;
  30.  
  31. struct objc_method {
  32.     SEL method_name;
  33.     char *method_types;
  34.     IMP method_imp;
  35. };
  36.  
  37. @implementation STSafariPlugin
  38.  
  39.  
  40. ////////////////////////////////////////////// *** renameSelector
  41.  
  42. + (BOOL)renameSelector:(Class)_class fromOldSelector:(SEL)_oldSelector toNewSelector:(SEL)_newSelector
  43. {
  44.     Method method = nil;
  45.    
  46.     method = class_getInstanceMethod(_class, _oldSelector);
  47.    
  48.     if (method == nil) {
  49.         return NO;
  50.     }
  51.    
  52.     method->method_name = _newSelector;
  53.    
  54.     return YES;
  55. }
  56.  
  57.  
  58. ////////////////////////////////////////////// *** load
  59.  
  60. + (void)load
  61. {
  62.     // A special method called by SIMBL once the application has started and all classes are initialized.
  63.    
  64.     // Exchange Safari's applicationWillTerminate: with custom one
  65.     [STSafariPlugin renameSelector:[AppController class] fromOldSelector:@selector(applicationShouldTerminate:) toNewSelector:@selector(_safari_applicationShouldTerminate:)];
  66.     [STSafariPlugin renameSelector:[AppController class] fromOldSelector:@selector(_st_applicationShouldTerminate:) toNewSelector:@selector(applicationShouldTerminate:)];
  67.    
  68.     // Exchange Safari's windowShouldClose: with custom one
  69.     [STSafariPlugin renameSelector:[BrowserWindowController class] fromOldSelector:@selector(windowShouldClose:) toNewSelector:@selector(_safari_windowShouldClose:)];
  70.     [STSafariPlugin renameSelector:[BrowserWindowController class] fromOldSelector:@selector(_st_windowShouldClose:) toNewSelector:@selector(windowShouldClose:)];
  71.    
  72.     // Exchange Safari's createTab: with custom one
  73.     [STSafariPlugin renameSelector:[BrowserWindowController class] fromOldSelector:@selector(createTab) toNewSelector:@selector(_safari_createTab)];
  74.     [STSafariPlugin renameSelector:[BrowserWindowController class] fromOldSelector:@selector(_st_createTab) toNewSelector:@selector(createTab)];
  75.    
  76.     // Exchange Safari's createTab: with custom one
  77.     [STSafariPlugin renameSelector:[BrowserDocument class] fromOldSelector:@selector(searchWeb:) toNewSelector:@selector(_safari_searchWeb:)];
  78.     [STSafariPlugin renameSelector:[BrowserDocument class] fromOldSelector:@selector(_st_searchWeb:) toNewSelector:@selector(searchWeb:)];
  79.    
  80.     // Load our custom menu items
  81.     [NSBundle loadNibNamed:@"MenuAdditions" owner:[STSafariPlugin sharedInstance]];
  82. }
  83.  
  84.  
  85. ////////////////////////////////////////////// *** sharedInstance
  86.  
  87. + (STSafariPlugin *)sharedInstance
  88. {
  89.     // Returns a single static instance of the plugin
  90.     static STSafariPlugin *plugin = nil;
  91.    
  92.     if (plugin == nil) {
  93.         plugin = [[STSafariPlugin alloc] init];
  94.     }
  95.    
  96.     return plugin;
  97. }
  98.  
  99.  
  100. ////////////////////////////////////////////// *** terminateWithoutWarning
  101.  
  102. - (BOOL)terminateWithoutWarning
  103. {
  104.     return terminateWithoutWarning;
  105. }
  106.  
  107.  
  108. ////////////////////////////////////////////// *** setTerminateWithoutWarning
  109.  
  110. - (void)setTerminateWithoutWarning:(BOOL)warning
  111. {
  112.     terminateWithoutWarning = warning;
  113. }
  114.  
  115.  
  116. ////////////////////////////////////////////// *** isLoaded
  117.  
  118. - (BOOL)isLoaded
  119. {
  120.     return YES;
  121. }
  122.  
  123.  
  124. ////////////////////////////////////////////// *** awakeFromNib
  125.  
  126. - (void)awakeFromNib
  127. {
  128.     NSMenu *safariMenuBar = [[NSApplication sharedApplication] mainMenu];
  129.     NSMenu *fileMenu = [[safariMenuBar itemAtIndex:1] submenu];
  130.    
  131.     NSMenuItem *closeWithoutWarningMenuItem = [menuAdditions itemAtIndex:0];
  132.     NSMenuItem *quitWithoutWarningMenuItem = [menuAdditions itemAtIndex:1];
  133.    
  134.     if ([[NSUserDefaults standardUserDefaults] boolForKey:STAddCloseNoWarningMenuItem]) {
  135.         NSEnumerator *itemEnumerator = [[fileMenu itemArray] objectEnumerator];
  136.         NSMenuItem *item;
  137.  
  138.         // Add the 'Close Window Without Warning' menu item
  139.         while(item = [itemEnumerator nextObject]) {
  140.             if ([item action] == @selector(performClose:)) {
  141.                 int index = [fileMenu indexOfItem:item];
  142.                 [fileMenu insertItem:[closeWithoutWarningMenuItem copy] atIndex:(index + 1)];
  143.                
  144.                 break;
  145.             }
  146.         }
  147.     }
  148.    
  149.     if ([[NSUserDefaults standardUserDefaults] boolForKey:STAddQuitNoWarningMenuItem]) {
  150.         // Add the 'Quit Safari Without Warning' menu item
  151.         [[[safariMenuBar itemAtIndex:0] submenu] addItem:[quitWithoutWarningMenuItem copy]];
  152.     }
  153.    
  154.     terminateWithoutWarning = NO;
  155. }
  156.  
  157.  
  158. ////////////////////////////////////////////// *** closeWindowWithoutWarning
  159.  
  160. - (IBAction)closeWindowWithoutWarning:(id)sender
  161. {
  162.     [[[NSApplication sharedApplication] mainWindow] close];
  163. }
  164.  
  165.  
  166. ////////////////////////////////////////////// *** quitWithoutWarning
  167.  
  168. - (IBAction)quitWithoutWarning:(id)sender
  169. {
  170.     terminateWithoutWarning = YES;
  171.     [[NSApplication sharedApplication] terminate:self];
  172. }
  173.  
  174.  
  175. ////////////////////////////////////////////// *** validateUserInterfaceItem
  176.  
  177. - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
  178. {
  179.     if ([item action] == @selector(closeWindowWithoutWarning:)) {
  180.         if ([[NSApplication sharedApplication] mainWindow]) {
  181.             return YES;
  182.         }
  183.     }
  184.     else if ([item action] == @selector(quitWithoutWarning:)) {
  185.         return YES;
  186.     }
  187.  
  188.     // Otherwise ask Safari to validate the item
  189.     return NO;
  190. }
  191.  
  192. @end