├── .gitignore ├── Package ├── Safari Omnibar.pmdoc │ ├── 01simbl-contents.xml │ ├── 01simbl.xml │ ├── 02safariomnibar-contents.xml │ ├── 02safariomnibar.xml │ └── index.xml └── postflight ├── README.md ├── SafariOmnibar.xcodeproj └── project.pbxproj └── SafariOmnibar ├── JRSwizzle.h ├── JRSwizzle.m ├── SafariOmnibar-Info.plist ├── SafariOmnibar-Prefix.pch ├── SafariOmnibar.h ├── SafariOmnibar.m ├── SearchProviders.plist ├── SearchProvidersEditor.xib ├── SearchProvidersEditorWindowController.h ├── SearchProvidersEditorWindowController.m ├── SparkleHelper.h ├── SparkleHelper.m └── en.lproj └── InfoPlist.strings /.gitignore: -------------------------------------------------------------------------------- 1 | *.xcworkspace 2 | xcuserdata/ 3 | .DS_Store 4 | Sparkle.framework/ 5 | -------------------------------------------------------------------------------- /Package/Safari Omnibar.pmdoc/01simbl-contents.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Package/Safari Omnibar.pmdoc/01simbl.xml: -------------------------------------------------------------------------------- 1 | net.culater.SIMBL.pkg14/Library/ScriptingAdditions/SIMBL.osax/Library/ScriptingAdditionsallowRevertlocationTypeinstallToscripts.postinstall.pathscripts.postinstall.isRelativeTypeinstallFrom.isRelativeTypeversionparentidentifierrequireAuthorizationinstallFrom.pathextraFilespostInstallpostflight/CVS$/\.svn$/\.cvsignore$/\.cvspass$/\.DS_Store$ -------------------------------------------------------------------------------- /Package/Safari Omnibar.pmdoc/02safariomnibar-contents.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Package/Safari Omnibar.pmdoc/02safariomnibar.xml: -------------------------------------------------------------------------------- 1 | net.rhapsodyk.SafariOmnibar.pkg1.6/Users/rs/Library/Application Support/SIMBL/Plugins/SafariOmnibar.bundle/Library/Application Support/SIMBL/Plugins/SafariOmnibar.bundleinstallTo.pathinstallTopostInstallinstallFrom.pathidentifierparentrequireAuthorizationversionincludeRootextraFiles02safariomnibar-contents.xml/CVS$/\.svn$/\.cvsignore$/\.cvspass$/\.DS_Store$ -------------------------------------------------------------------------------- /Package/Safari Omnibar.pmdoc/index.xml: -------------------------------------------------------------------------------- 1 | Safari Omnibar/Users/rs/Desktop/Safari Omnibar-1.5.pkgnet.rhapsodykFailureThis version of SIMBL only works with Mac OS X 10.5.x and newer.01simbl.xml02safariomnibar.xmldescriptionproperties.titleproperties.anywhereDomainpostinstallActions.actionsproperties.customizeOptionproperties.systemDomainextraFiles -------------------------------------------------------------------------------- /Package/postflight: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright 2003-2009, Mike Solomon 3 | # SIMBL is released under the GNU General Public License v2. 4 | # http://www.opensource.org/licenses/gpl-2.0.php 5 | 6 | PACKAGE_PATH="$1" 7 | INSTALL_PATH="$2" 8 | INSTALL_VOLUME="$3" 9 | SYSTEM_ROOT="$4" 10 | 11 | RESOURCES="${PACKAGE_PATH}/Contents/Resources" 12 | 13 | # FIXME(mike) maybe we should copy this out of the install package instead? 14 | LAUNCHD_PLIST="/Library/ScriptingAdditions/SIMBL.osax/Contents/Resources/SIMBL Agent.app/Contents/Resources/net.culater.SIMBL.Agent.plist" 15 | OSAX_PLIST="/Library/ScriptingAdditions/SIMBL.osax/Contents/Info.plist" 16 | 17 | # remove old InputManager if it exists, otherwise these 18 | # two will contend when applications run under 32-bit mode 19 | SIMBL_INPUTMANAGER="/Library/InputManagers/SIMBL" 20 | if [ -d "$SIMBL_INPUTMANAGER" ]; then 21 | rm -rf "$SIMBL_INPUTMANAGER" 22 | fi 23 | 24 | LAUNCH_AGENTS_DIR="/Library/LaunchAgents" 25 | if [ ! -d "$LAUNCH_AGENTS_DIR" ]; then 26 | mkdir -p "$LAUNCH_AGENTS_DIR" 27 | chown root:wheel "$LAUNCH_AGENTS_DIR" 28 | fi 29 | # ensure agents are world-readable, but must be no more permissive 30 | # than 755, otherwise they are just skipped. 31 | chmod 755 "$LAUNCH_AGENTS_DIR" 32 | 33 | # ensure that this loads on restart 34 | cp "$LAUNCHD_PLIST" "$LAUNCH_AGENTS_DIR" 35 | if [ $? != 0 ]; then 36 | exit 1 37 | fi 38 | 39 | # create a system-wide location for plugins 40 | SIMBL_PLUGINS_DIR="/Library/Application Support/SIMBL/Plugins" 41 | if [ ! -d "$SIMBL_PLUGINS_DIR" ]; then 42 | mkdir -p "$SIMBL_PLUGINS_DIR" 43 | chown root:admin "$SIMBL_PLUGINS_DIR" 44 | fi 45 | # ensure plugins are world-readable 46 | chmod 775 "$SIMBL_PLUGINS_DIR" 47 | 48 | # ensure that ScriptingAdditions is world-readable 49 | SCRIPTING_ADDITIONS_DIR="/Library/ScriptingAdditions" 50 | chown root:admin "$SCRIPTING_ADDITIONS_DIR" 51 | chmod 775 "$SCRIPTING_ADDITIONS_DIR" 52 | if [ $? != 0 ]; then 53 | exit 1 54 | fi 55 | 56 | # stop any running agent by unloading it, in case we have made changes 57 | # to the agent that won't take effect until the application is restarted 58 | # NOTE: this runs *as* root, but $USER is the user that launched Installer.app 59 | # we don't want the agent running as root, nor do we want to force the user to 60 | # logout, so we try to kill any agents and then start the new version just for 61 | # this user. 62 | echo "Stop SIMBL Agent" 63 | echo su -l "$USER" /bin/bash -c "/bin/launchctl unload -F -S Aqua \"${LAUNCHD_PLIST}\"" 64 | sudo -u "$USER" -- /bin/launchctl unload -F -S Aqua "${LAUNCHD_PLIST}" 65 | 66 | 67 | # This clears out any buggy instance we may have started with previous versions 68 | # of the package. 69 | echo "Stop root SIMBL Agent" 70 | /bin/launchctl unload -F -S Aqua "${LAUNCHD_PLIST}" 71 | 72 | # If there are other users, kill the current agents - launchd will restart 73 | # them with the newly installed code 74 | /usr/bin/killall "SIMBL Agent" 75 | 76 | echo "Start SIMBL Agent" 77 | echo su -l "$USER" /bin/bash -c "/bin/launchctl load -F -S Aqua \"${LAUNCHD_PLIST}\"" 78 | sudo -u "$USER" -- /bin/launchctl load -F -S Aqua "${LAUNCHD_PLIST}" 79 | if [ $? != 0 ]; then 80 | exit 1 81 | fi 82 | 83 | # Under 10.6, the Leopard-compatible OSAX event causes a spurious entry in the 84 | # console. This is harmless and the warning is completely pointless, the event 85 | # won't ever be triggered on Snow Leopard. Equally pointless are the complaints 86 | # about this. If one reads the output of the Console, the least one can do is 87 | # be prepared to understand the statements made there. 88 | sw_vers | grep "ProductVersion:.*10\.6" 89 | if [ $? == 0 ]; then 90 | echo "pruning Leopard event handler" 91 | /usr/libexec/PlistBuddy -c "Delete :OSAXHandlers:Events:SIMeleop" "$OSAX_PLIST" 92 | fi 93 | 94 | exit 0 95 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | What is this? 2 | ============= 3 | 4 | Safari Omnibar is a Safari SIMBL plugin aiming at mimicing the Chrome's smart location bar which combines location and search. 5 | 6 | [Changelog](http://rsparkle.herokuapp.com/SafariOmnibar/changes.html) 7 | 8 | Requirement 9 | =========== 10 | 11 | - Intel Mac ([PPC port](https://github.com/stefanschmidt/SafariOmnibar)) 12 | - Safari 5.0 (Snow Leopard) or 5.1 (Lion) 13 | - [SIMBL](http://www.culater.net/software/SIMBL/SIMBL.php) 0.9.9 (packaged with the installer) 14 | 15 | Installation 16 | ============ 17 | 18 | Download our [installer](http://rsparkle.herokuapp.com/SafariOmnibar/last) and run it then restart Safari. 19 | 20 | Uninstallation 21 | ============== 22 | 23 | Remove the file `/Library/Application\ Support/SIMBL/Plugins/SafariOmnibar.bundle` 24 | 25 | Usage 26 | ===== 27 | 28 | Just type a search query in the location bar and it will perform a Google search. 29 | 30 | TODO 31 | ==== 32 | 33 | - Preference Panel 34 | - Let the user choose not to hide the Safari's search field 35 | - Search engine editor with keyword support just like Chrome's 36 | - Google auto-suggests injection in the completion menu 37 | -------------------------------------------------------------------------------- /SafariOmnibar.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1C8F02A713DB765600A3632D /* SearchProvidersEditorWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C8F02A613DB765600A3632D /* SearchProvidersEditorWindowController.m */; }; 11 | 1C8F02AA13DB7B2C00A3632D /* SearchProvidersEditor.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1C8F02A913DB7B2C00A3632D /* SearchProvidersEditor.xib */; }; 12 | 53B2999813CA4BD800CDB6FF /* JRSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 53B2999713CA4BD800CDB6FF /* JRSwizzle.m */; }; 13 | 53B299A913CB306800CDB6FF /* SearchProviders.plist in Resources */ = {isa = PBXBuildFile; fileRef = 53B299A813CB306800CDB6FF /* SearchProviders.plist */; }; 14 | 53DDD7FB13E810C000039E90 /* SparkleHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 53DDD7FA13E810C000039E90 /* SparkleHelper.m */; }; 15 | 53DDD80513E8157300039E90 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 53DDD80313E8155400039E90 /* Sparkle.framework */; }; 16 | 53F7E26C13CA2680007FFA53 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53F7E26B13CA2680007FFA53 /* Cocoa.framework */; }; 17 | 53F7E27613CA2680007FFA53 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 53F7E27413CA2680007FFA53 /* InfoPlist.strings */; }; 18 | 53F7E27F13CA26BC007FFA53 /* SafariOmnibar.m in Sources */ = {isa = PBXBuildFile; fileRef = 53F7E27E13CA26BC007FFA53 /* SafariOmnibar.m */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXCopyFilesBuildPhase section */ 22 | 53DDD80013E814E300039E90 /* CopyFiles */ = { 23 | isa = PBXCopyFilesBuildPhase; 24 | buildActionMask = 2147483647; 25 | dstPath = ""; 26 | dstSubfolderSpec = 10; 27 | files = ( 28 | 53DDD80513E8157300039E90 /* Sparkle.framework in CopyFiles */, 29 | ); 30 | runOnlyForDeploymentPostprocessing = 0; 31 | }; 32 | /* End PBXCopyFilesBuildPhase section */ 33 | 34 | /* Begin PBXFileReference section */ 35 | 1C8F02A513DB765600A3632D /* SearchProvidersEditorWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchProvidersEditorWindowController.h; sourceTree = ""; }; 36 | 1C8F02A613DB765600A3632D /* SearchProvidersEditorWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchProvidersEditorWindowController.m; sourceTree = ""; }; 37 | 1C8F02A913DB7B2C00A3632D /* SearchProvidersEditor.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SearchProvidersEditor.xib; sourceTree = ""; }; 38 | 53B2999613CA4BD800CDB6FF /* JRSwizzle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JRSwizzle.h; sourceTree = ""; }; 39 | 53B2999713CA4BD800CDB6FF /* JRSwizzle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JRSwizzle.m; sourceTree = ""; }; 40 | 53B299A813CB306800CDB6FF /* SearchProviders.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = SearchProviders.plist; sourceTree = ""; }; 41 | 53DDD7F913E810C000039E90 /* SparkleHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SparkleHelper.h; sourceTree = ""; }; 42 | 53DDD7FA13E810C000039E90 /* SparkleHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SparkleHelper.m; sourceTree = ""; }; 43 | 53DDD80313E8155400039E90 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Sparkle.framework; sourceTree = ""; }; 44 | 53F7E26813CA2680007FFA53 /* SafariOmnibar.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SafariOmnibar.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | 53F7E26B13CA2680007FFA53 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 46 | 53F7E27313CA2680007FFA53 /* SafariOmnibar-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SafariOmnibar-Info.plist"; sourceTree = ""; }; 47 | 53F7E27513CA2680007FFA53 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 48 | 53F7E27713CA2680007FFA53 /* SafariOmnibar-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SafariOmnibar-Prefix.pch"; sourceTree = ""; }; 49 | 53F7E27D13CA26BC007FFA53 /* SafariOmnibar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SafariOmnibar.h; sourceTree = ""; }; 50 | 53F7E27E13CA26BC007FFA53 /* SafariOmnibar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SafariOmnibar.m; sourceTree = ""; }; 51 | /* End PBXFileReference section */ 52 | 53 | /* Begin PBXFrameworksBuildPhase section */ 54 | 53F7E26513CA2680007FFA53 /* Frameworks */ = { 55 | isa = PBXFrameworksBuildPhase; 56 | buildActionMask = 2147483647; 57 | files = ( 58 | 53F7E26C13CA2680007FFA53 /* Cocoa.framework in Frameworks */, 59 | ); 60 | runOnlyForDeploymentPostprocessing = 0; 61 | }; 62 | /* End PBXFrameworksBuildPhase section */ 63 | 64 | /* Begin PBXGroup section */ 65 | 53F7E25D13CA2680007FFA53 = { 66 | isa = PBXGroup; 67 | children = ( 68 | 53F7E27113CA2680007FFA53 /* SafariOmnibar */, 69 | 53F7E26A13CA2680007FFA53 /* Frameworks */, 70 | 53F7E26913CA2680007FFA53 /* Products */, 71 | ); 72 | sourceTree = ""; 73 | }; 74 | 53F7E26913CA2680007FFA53 /* Products */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 53F7E26813CA2680007FFA53 /* SafariOmnibar.bundle */, 78 | ); 79 | name = Products; 80 | sourceTree = ""; 81 | }; 82 | 53F7E26A13CA2680007FFA53 /* Frameworks */ = { 83 | isa = PBXGroup; 84 | children = ( 85 | 53DDD80313E8155400039E90 /* Sparkle.framework */, 86 | 53F7E26B13CA2680007FFA53 /* Cocoa.framework */, 87 | ); 88 | name = Frameworks; 89 | sourceTree = ""; 90 | }; 91 | 53F7E27113CA2680007FFA53 /* SafariOmnibar */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 53F7E27213CA2680007FFA53 /* Supporting Files */, 95 | 53F7E27D13CA26BC007FFA53 /* SafariOmnibar.h */, 96 | 53F7E27E13CA26BC007FFA53 /* SafariOmnibar.m */, 97 | 53DDD7F913E810C000039E90 /* SparkleHelper.h */, 98 | 53DDD7FA13E810C000039E90 /* SparkleHelper.m */, 99 | 1C8F02A513DB765600A3632D /* SearchProvidersEditorWindowController.h */, 100 | 1C8F02A613DB765600A3632D /* SearchProvidersEditorWindowController.m */, 101 | 1C8F02A913DB7B2C00A3632D /* SearchProvidersEditor.xib */, 102 | 53B2999613CA4BD800CDB6FF /* JRSwizzle.h */, 103 | 53B2999713CA4BD800CDB6FF /* JRSwizzle.m */, 104 | ); 105 | path = SafariOmnibar; 106 | sourceTree = ""; 107 | }; 108 | 53F7E27213CA2680007FFA53 /* Supporting Files */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 53F7E27313CA2680007FFA53 /* SafariOmnibar-Info.plist */, 112 | 53F7E27413CA2680007FFA53 /* InfoPlist.strings */, 113 | 53F7E27713CA2680007FFA53 /* SafariOmnibar-Prefix.pch */, 114 | 53B299A813CB306800CDB6FF /* SearchProviders.plist */, 115 | ); 116 | name = "Supporting Files"; 117 | sourceTree = ""; 118 | }; 119 | /* End PBXGroup section */ 120 | 121 | /* Begin PBXNativeTarget section */ 122 | 53F7E26713CA2680007FFA53 /* SafariOmnibar */ = { 123 | isa = PBXNativeTarget; 124 | buildConfigurationList = 53F7E27A13CA2680007FFA53 /* Build configuration list for PBXNativeTarget "SafariOmnibar" */; 125 | buildPhases = ( 126 | 53DDD7FD13E8112B00039E90 /* ShellScript */, 127 | 53F7E26413CA2680007FFA53 /* Sources */, 128 | 53F7E26513CA2680007FFA53 /* Frameworks */, 129 | 53F7E26613CA2680007FFA53 /* Resources */, 130 | 53DDD80013E814E300039E90 /* CopyFiles */, 131 | 53F7E28313CA2F46007FFA53 /* Run Script */, 132 | ); 133 | buildRules = ( 134 | ); 135 | dependencies = ( 136 | ); 137 | name = SafariOmnibar; 138 | productName = SafariOmnibar; 139 | productReference = 53F7E26813CA2680007FFA53 /* SafariOmnibar.bundle */; 140 | productType = "com.apple.product-type.bundle"; 141 | }; 142 | /* End PBXNativeTarget section */ 143 | 144 | /* Begin PBXProject section */ 145 | 53F7E25F13CA2680007FFA53 /* Project object */ = { 146 | isa = PBXProject; 147 | attributes = { 148 | LastUpgradeCheck = 0420; 149 | }; 150 | buildConfigurationList = 53F7E26213CA2680007FFA53 /* Build configuration list for PBXProject "SafariOmnibar" */; 151 | compatibilityVersion = "Xcode 3.2"; 152 | developmentRegion = English; 153 | hasScannedForEncodings = 0; 154 | knownRegions = ( 155 | en, 156 | ); 157 | mainGroup = 53F7E25D13CA2680007FFA53; 158 | productRefGroup = 53F7E26913CA2680007FFA53 /* Products */; 159 | projectDirPath = ""; 160 | projectRoot = ""; 161 | targets = ( 162 | 53F7E26713CA2680007FFA53 /* SafariOmnibar */, 163 | ); 164 | }; 165 | /* End PBXProject section */ 166 | 167 | /* Begin PBXResourcesBuildPhase section */ 168 | 53F7E26613CA2680007FFA53 /* Resources */ = { 169 | isa = PBXResourcesBuildPhase; 170 | buildActionMask = 2147483647; 171 | files = ( 172 | 53F7E27613CA2680007FFA53 /* InfoPlist.strings in Resources */, 173 | 53B299A913CB306800CDB6FF /* SearchProviders.plist in Resources */, 174 | 1C8F02AA13DB7B2C00A3632D /* SearchProvidersEditor.xib in Resources */, 175 | ); 176 | runOnlyForDeploymentPostprocessing = 0; 177 | }; 178 | /* End PBXResourcesBuildPhase section */ 179 | 180 | /* Begin PBXShellScriptBuildPhase section */ 181 | 53DDD7FD13E8112B00039E90 /* ShellScript */ = { 182 | isa = PBXShellScriptBuildPhase; 183 | buildActionMask = 2147483647; 184 | files = ( 185 | ); 186 | inputPaths = ( 187 | ); 188 | outputPaths = ( 189 | ); 190 | runOnlyForDeploymentPostprocessing = 0; 191 | shellPath = /bin/sh; 192 | shellScript = "if [ ! -d Sparkle.framework ]\nthen\n echo \"Downloading Sparkle Framework\"\n curl -s -o /tmp/$$.zip http://sparkle.andymatuschak.org/files/Sparkle%201.5b6.zip\n unzip -q /tmp/$$.zip Sparkle.framework/*\n rm -f /tmp/$$.zip\nfi"; 193 | }; 194 | 53F7E28313CA2F46007FFA53 /* Run Script */ = { 195 | isa = PBXShellScriptBuildPhase; 196 | buildActionMask = 2147483647; 197 | files = ( 198 | ); 199 | inputPaths = ( 200 | ); 201 | name = "Run Script"; 202 | outputPaths = ( 203 | ); 204 | runOnlyForDeploymentPostprocessing = 0; 205 | shellPath = /bin/sh; 206 | shellScript = "# ensure user-local SIMBL plugins folder exists\nmkdir -p \"${USER_LIBRARY_DIR}/Application Support/SIMBL/Plugins\"\n\n# clean up any previous products/symbolic links in the SIMBL Plugins folder\nif [ -a \"${USER_LIBRARY_DIR}/Application Support/SIMBL/Plugins/${FULL_PRODUCT_NAME}\" ]; then\nrm -Rf \"${USER_LIBRARY_DIR}/Application Support/SIMBL/Plugins/${FULL_PRODUCT_NAME}\"\nfi\n\n# Depending on the build configuration, either copy or link to the most recent product\nif [ \"${CONFIGURATION}\" == \"Debug\" ]; then\n# if we're debugging, add a symbolic link to the plug-in\nln -sf \"${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}\" \"${USER_LIBRARY_DIR}/Application Support/SIMBL/Plugins/${FULL_PRODUCT_NAME}\"\nelif [ \"${CONFIGURATION}\" == \"Release\" ]; then\n# if we're compiling for release, just copy the plugin to the SIMBL Plugins folder\ncp -Rfv \"${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}\" \"${USER_LIBRARY_DIR}/Application Support/SIMBL/Plugins/${FULL_PRODUCT_NAME}\"\nfi"; 207 | }; 208 | /* End PBXShellScriptBuildPhase section */ 209 | 210 | /* Begin PBXSourcesBuildPhase section */ 211 | 53F7E26413CA2680007FFA53 /* Sources */ = { 212 | isa = PBXSourcesBuildPhase; 213 | buildActionMask = 2147483647; 214 | files = ( 215 | 53F7E27F13CA26BC007FFA53 /* SafariOmnibar.m in Sources */, 216 | 53B2999813CA4BD800CDB6FF /* JRSwizzle.m in Sources */, 217 | 1C8F02A713DB765600A3632D /* SearchProvidersEditorWindowController.m in Sources */, 218 | 53DDD7FB13E810C000039E90 /* SparkleHelper.m in Sources */, 219 | ); 220 | runOnlyForDeploymentPostprocessing = 0; 221 | }; 222 | /* End PBXSourcesBuildPhase section */ 223 | 224 | /* Begin PBXVariantGroup section */ 225 | 53F7E27413CA2680007FFA53 /* InfoPlist.strings */ = { 226 | isa = PBXVariantGroup; 227 | children = ( 228 | 53F7E27513CA2680007FFA53 /* en */, 229 | ); 230 | name = InfoPlist.strings; 231 | sourceTree = ""; 232 | }; 233 | /* End PBXVariantGroup section */ 234 | 235 | /* Begin XCBuildConfiguration section */ 236 | 53F7E27813CA2680007FFA53 /* Debug */ = { 237 | isa = XCBuildConfiguration; 238 | buildSettings = { 239 | ALWAYS_SEARCH_USER_PATHS = NO; 240 | ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; 241 | CLANG_ENABLE_OBJC_ARC = NO; 242 | COPY_PHASE_STRIP = NO; 243 | GCC_C_LANGUAGE_STANDARD = gnu99; 244 | GCC_DYNAMIC_NO_PIC = NO; 245 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 246 | GCC_OPTIMIZATION_LEVEL = 0; 247 | GCC_PREPROCESSOR_DEFINITIONS = ( 248 | "DEBUG=1", 249 | "$(inherited)", 250 | ); 251 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 252 | GCC_VERSION = ""; 253 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 254 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 255 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 256 | GCC_WARN_UNUSED_VARIABLE = YES; 257 | MACOSX_DEPLOYMENT_TARGET = 10.7; 258 | ONLY_ACTIVE_ARCH = YES; 259 | RUN_CLANG_STATIC_ANALYZER = YES; 260 | SDKROOT = macosx; 261 | }; 262 | name = Debug; 263 | }; 264 | 53F7E27913CA2680007FFA53 /* Release */ = { 265 | isa = XCBuildConfiguration; 266 | buildSettings = { 267 | ALWAYS_SEARCH_USER_PATHS = NO; 268 | ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; 269 | CLANG_ENABLE_OBJC_ARC = NO; 270 | COPY_PHASE_STRIP = YES; 271 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 272 | GCC_C_LANGUAGE_STANDARD = gnu99; 273 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 274 | GCC_VERSION = ""; 275 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 276 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 277 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 278 | GCC_WARN_UNUSED_VARIABLE = YES; 279 | MACOSX_DEPLOYMENT_TARGET = 10.7; 280 | RUN_CLANG_STATIC_ANALYZER = YES; 281 | SDKROOT = macosx; 282 | }; 283 | name = Release; 284 | }; 285 | 53F7E27B13CA2680007FFA53 /* Debug */ = { 286 | isa = XCBuildConfiguration; 287 | buildSettings = { 288 | FRAMEWORK_SEARCH_PATHS = ( 289 | "$(inherited)", 290 | "\"$(SRCROOT)\"", 291 | ); 292 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 293 | GCC_PREFIX_HEADER = "SafariOmnibar/SafariOmnibar-Prefix.pch"; 294 | INFOPLIST_FILE = "SafariOmnibar/SafariOmnibar-Info.plist"; 295 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; 296 | PRODUCT_NAME = "$(TARGET_NAME)"; 297 | WRAPPER_EXTENSION = bundle; 298 | }; 299 | name = Debug; 300 | }; 301 | 53F7E27C13CA2680007FFA53 /* Release */ = { 302 | isa = XCBuildConfiguration; 303 | buildSettings = { 304 | FRAMEWORK_SEARCH_PATHS = ( 305 | "$(inherited)", 306 | "\"$(SRCROOT)\"", 307 | ); 308 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 309 | GCC_PREFIX_HEADER = "SafariOmnibar/SafariOmnibar-Prefix.pch"; 310 | INFOPLIST_FILE = "SafariOmnibar/SafariOmnibar-Info.plist"; 311 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; 312 | PRODUCT_NAME = "$(TARGET_NAME)"; 313 | WRAPPER_EXTENSION = bundle; 314 | }; 315 | name = Release; 316 | }; 317 | /* End XCBuildConfiguration section */ 318 | 319 | /* Begin XCConfigurationList section */ 320 | 53F7E26213CA2680007FFA53 /* Build configuration list for PBXProject "SafariOmnibar" */ = { 321 | isa = XCConfigurationList; 322 | buildConfigurations = ( 323 | 53F7E27813CA2680007FFA53 /* Debug */, 324 | 53F7E27913CA2680007FFA53 /* Release */, 325 | ); 326 | defaultConfigurationIsVisible = 0; 327 | defaultConfigurationName = Release; 328 | }; 329 | 53F7E27A13CA2680007FFA53 /* Build configuration list for PBXNativeTarget "SafariOmnibar" */ = { 330 | isa = XCConfigurationList; 331 | buildConfigurations = ( 332 | 53F7E27B13CA2680007FFA53 /* Debug */, 333 | 53F7E27C13CA2680007FFA53 /* Release */, 334 | ); 335 | defaultConfigurationIsVisible = 0; 336 | defaultConfigurationName = Release; 337 | }; 338 | /* End XCConfigurationList section */ 339 | }; 340 | rootObject = 53F7E25F13CA2680007FFA53 /* Project object */; 341 | } 342 | -------------------------------------------------------------------------------- /SafariOmnibar/JRSwizzle.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | JRSwizzle.h 3 | Copyright (c) 2007 Jonathan 'Wolf' Rentzsch: 4 | Some rights reserved: 5 | 6 | ***************************************************************************/ 7 | 8 | #import 9 | 10 | @interface NSObject (JRSwizzle) 11 | + (BOOL)jr_swizzleMethod:(SEL)origSel_ withMethod:(SEL)altSel_ error:(NSError**)error_; 12 | + (BOOL)jr_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError**)error_; 13 | @end 14 | -------------------------------------------------------------------------------- /SafariOmnibar/JRSwizzle.m: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | JRSwizzle.m 3 | Copyright (c) 2007 Jonathan 'Wolf' Rentzsch: 4 | Some rights reserved: 5 | 6 | ***************************************************************************/ 7 | 8 | #import "JRSwizzle.h" 9 | #import 10 | 11 | #define SetNSError(ERROR_VAR, FORMAT,...) \ 12 | if (ERROR_VAR) { \ 13 | NSString *errStr = [@"+[NSObject(JRSwizzle) jr_swizzleMethod:withMethod:error:]: " stringByAppendingFormat:FORMAT,##__VA_ARGS__]; \ 14 | *ERROR_VAR = [NSError errorWithDomain:@"NSCocoaErrorDomain" \ 15 | code:-1 \ 16 | userInfo:[NSDictionary dictionaryWithObject:errStr forKey:NSLocalizedDescriptionKey]]; \ 17 | } 18 | 19 | @implementation NSObject (JRSwizzle) 20 | 21 | + (BOOL)jr_swizzleMethod:(SEL)origSel_ withMethod:(SEL)altSel_ error:(NSError**)error_ { 22 | #if OBJC_API_VERSION >= 2 23 | Method origMethod = class_getInstanceMethod(self, origSel_); 24 | if (!origMethod) { 25 | SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self className]); 26 | return NO; 27 | } 28 | 29 | Method altMethod = class_getInstanceMethod(self, altSel_); 30 | if (!altMethod) { 31 | SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self className]); 32 | return NO; 33 | } 34 | 35 | class_addMethod(self, 36 | origSel_, 37 | class_getMethodImplementation(self, origSel_), 38 | method_getTypeEncoding(origMethod)); 39 | class_addMethod(self, 40 | altSel_, 41 | class_getMethodImplementation(self, altSel_), 42 | method_getTypeEncoding(altMethod)); 43 | 44 | method_exchangeImplementations(class_getInstanceMethod(self, origSel_), class_getInstanceMethod(self, altSel_)); 45 | return YES; 46 | #else 47 | // Scan for non-inherited methods. 48 | Method directOriginalMethod = NULL, directAlternateMethod = NULL; 49 | 50 | void *iterator = NULL; 51 | struct objc_method_list *mlist = class_nextMethodList(self, &iterator); 52 | while (mlist) { 53 | int method_index = 0; 54 | for (; method_index < mlist->method_count; method_index++) { 55 | if (mlist->method_list[method_index].method_name == origSel_) { 56 | assert(!directOriginalMethod); 57 | directOriginalMethod = &mlist->method_list[method_index]; 58 | } 59 | if (mlist->method_list[method_index].method_name == altSel_) { 60 | assert(!directAlternateMethod); 61 | directAlternateMethod = &mlist->method_list[method_index]; 62 | } 63 | } 64 | mlist = class_nextMethodList(self, &iterator); 65 | } 66 | 67 | // If either method is inherited, copy it up to the target class to make it non-inherited. 68 | if (!directOriginalMethod || !directAlternateMethod) { 69 | Method inheritedOriginalMethod = NULL, inheritedAlternateMethod = NULL; 70 | if (!directOriginalMethod) { 71 | inheritedOriginalMethod = class_getInstanceMethod(self, origSel_); 72 | if (!inheritedOriginalMethod) { 73 | SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self className]); 74 | return NO; 75 | } 76 | } 77 | if (!directAlternateMethod) { 78 | inheritedAlternateMethod = class_getInstanceMethod(self, altSel_); 79 | if (!inheritedAlternateMethod) { 80 | SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self className]); 81 | return NO; 82 | } 83 | } 84 | 85 | int hoisted_method_count = !directOriginalMethod && !directAlternateMethod ? 2 : 1; 86 | struct objc_method_list *hoisted_method_list = malloc(sizeof(struct objc_method_list) + (sizeof(struct objc_method)*(hoisted_method_count-1))); 87 | hoisted_method_list->method_count = hoisted_method_count; 88 | Method hoisted_method = hoisted_method_list->method_list; 89 | 90 | if (!directOriginalMethod) { 91 | bcopy(inheritedOriginalMethod, hoisted_method, sizeof(struct objc_method)); 92 | directOriginalMethod = hoisted_method++; 93 | } 94 | if (!directAlternateMethod) { 95 | bcopy(inheritedAlternateMethod, hoisted_method, sizeof(struct objc_method)); 96 | directAlternateMethod = hoisted_method; 97 | } 98 | class_addMethods(self, hoisted_method_list); 99 | } 100 | 101 | // Swizzle. 102 | IMP temp = directOriginalMethod->method_imp; 103 | directOriginalMethod->method_imp = directAlternateMethod->method_imp; 104 | directAlternateMethod->method_imp = temp; 105 | 106 | return YES; 107 | #endif 108 | } 109 | 110 | + (BOOL)jr_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError**)error_ { 111 | assert(0); 112 | return NO; 113 | } 114 | 115 | @end 116 | -------------------------------------------------------------------------------- /SafariOmnibar/SafariOmnibar-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | net.rhapsodyk.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | BNDL 19 | CFBundleShortVersionString 20 | 1.6 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.6 25 | NSHumanReadableCopyright 26 | Copyright © 2011 Olivier Poitrey. All rights reserved. 27 | NSPrincipalClass 28 | SafariOmnibar 29 | SIMBLTargetApplications 30 | 31 | 32 | BundleIdentifier 33 | com.apple.Safari 34 | MaxBundleVersion 35 | 7534 36 | MinBundleVersion 37 | 6533 38 | 39 | 40 | BundleIdentifier 41 | org.webkit.nightly.WebKit 42 | 43 | 44 | SUFeedURL 45 | https://rsparkle.herokuapp.com/SafariOmnibar/updates.xml 46 | SUEnableAutomaticChecks 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /SafariOmnibar/SafariOmnibar-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'SafariOmnibar' target in the 'SafariOmnibar' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /SafariOmnibar/SafariOmnibar.h: -------------------------------------------------------------------------------- 1 | // 2 | // SafariOmnibar.h 3 | // SafariOmnibar 4 | // 5 | // Created by Olivier Poitrey on 10/07/11. 6 | // Copyright 2011 Olivier Poitrey. All rights reserved. 7 | // 8 | 9 | @interface SafariOmnibar : NSObject 10 | { 11 | @private 12 | NSArray *searchProviders; 13 | NSDictionary *defaultSearchProvider; 14 | NSMenuItem *editSearchProvidersItem; 15 | NSMutableDictionary *locationFieldContext; 16 | } 17 | 18 | @property (nonatomic, readonly) NSArray *searchProviders; 19 | @property (nonatomic, readonly) NSDictionary *defaultSearchProvider; 20 | @property (nonatomic, readonly) NSString *pluginVersion; 21 | 22 | + (SafariOmnibar *)sharedInstance; 23 | - (NSDictionary *)searchProviderForKeyword:(NSString *)keyword; 24 | - (NSDictionary *)searchProviderForLocationField:(NSTextField *)locationField; 25 | - (void)resetSearchProviderForLocationField:(NSTextField *)locationField; 26 | - (void)updateSearchProviderForLocationField:(NSTextField *)locationField; 27 | - (NSDictionary *)previousSearchProviderForLocationField:(NSTextField *)locationField; 28 | - (void)saveSearchQuery:(NSString *)searchQuery forLocationField:(NSTextField *)locationField; 29 | - (NSString *)previousSearchQueryForLocationField:(NSTextField *)locationField; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /SafariOmnibar/SafariOmnibar.m: -------------------------------------------------------------------------------- 1 | // 2 | // SafariOmnibar.m 3 | // SafariOmnibar 4 | // 5 | // Created by Olivier Poitrey on 10/07/11. 6 | // Copyright 2011 Olivier Poitrey. All rights reserved. 7 | // 8 | 9 | #import "SafariOmnibar.h" 10 | #import "SparkleHelper.h" 11 | #import "SearchProvidersEditorWindowController.h" 12 | #import "JRSwizzle.h" 13 | 14 | NSString * const kOmnibarSearchProviders = @"SafariOmnibar_SearchProviders"; 15 | 16 | static BOOL is_search_query(NSString *string) 17 | { 18 | // Clean the input 19 | string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 20 | 21 | // If it starts by a known scheme, don't try to validate the URL format, user certainly want to enter a URL. 22 | // Even a bad one should shouldn't be treated as a search 23 | if ([string hasPrefix:@"http://"] || [string hasPrefix:@"https://"] || [string hasPrefix:@"file://"] 24 | || [string hasPrefix:@"javascript:"] || [string hasPrefix:@"feed:"] || [string hasPrefix:@"about:"]) 25 | return NO; 26 | 27 | // If it starts by a scheme handled by another app, let the target app validate the URL and do not catch it as a search 28 | if (LSGetApplicationForURL((CFURLRef)[NSURL URLWithString:string], kLSRolesAll, NULL, NULL) == 0) 29 | return NO; 30 | 31 | // If more than one word, it's certainly a search query 32 | if ([string rangeOfString:@" "].location != NSNotFound) 33 | return YES; 34 | 35 | NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@", string]]; 36 | 37 | // A single word that can't be parsed as an URL is certainly a search query 38 | if (!url) 39 | return YES; 40 | 41 | // Treat localhost specifically 42 | if ([url.host isEqualToString:@"localhost"]) 43 | return NO; 44 | 45 | // If the host part contains dot(s), treat the string as URL, the user certainly entered a URL manually with no scheme 46 | if ([url.host rangeOfString:@"."].location != NSNotFound) 47 | return NO; 48 | 49 | return YES; 50 | } 51 | 52 | @implementation NSWindowController(SO) 53 | 54 | - (void)SafariOmnibar_goToToolbarLocation:(NSTextField *)locationField 55 | { 56 | SafariOmnibar *plugin = [SafariOmnibar sharedInstance]; 57 | NSDictionary *provider = [plugin searchProviderForLocationField:locationField]; 58 | NSString *location = [locationField.stringValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 59 | NSString *searchTerms = location; 60 | NSString *searchURLTemplate = nil; 61 | 62 | if (provider) 63 | { 64 | // Custom search provider 65 | searchURLTemplate = [provider objectForKey:@"SearchURLTemplate"]; 66 | NSUInteger colonLoc = [location rangeOfString:@":"].location; 67 | if (colonLoc + 2 < location.length) 68 | { 69 | searchTerms = [location substringWithRange:NSMakeRange(colonLoc + 2, location.length - (colonLoc + 2))]; 70 | } 71 | else 72 | { 73 | searchTerms = @""; 74 | } 75 | [plugin resetSearchProviderForLocationField:locationField]; 76 | } 77 | else if (is_search_query(location)) 78 | { 79 | // If we detect a search query with not search provider keyword, use the default search provider 80 | searchURLTemplate = [[plugin defaultSearchProvider] objectForKey:@"SearchURLTemplate"]; 81 | } 82 | 83 | if (searchURLTemplate) 84 | { 85 | // Save untouched search terms in this fields' context 86 | [plugin saveSearchQuery:searchTerms forLocationField:locationField]; 87 | 88 | searchTerms = [searchTerms stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 89 | // escape more 90 | searchTerms = [searchTerms stringByReplacingOccurrencesOfString:@"&" withString:@"%26"]; 91 | searchTerms = [searchTerms stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"]; 92 | [locationField setStringValue:[searchURLTemplate stringByReplacingOccurrencesOfString:@"{searchTerms}" withString:searchTerms]]; 93 | } 94 | 95 | [self SafariOmnibar_goToToolbarLocation:locationField]; 96 | } 97 | 98 | @end 99 | 100 | @implementation NSDocument(SO) 101 | 102 | - (NSTextField *)SafariOmnibar_locationField 103 | { 104 | id windowController = nil; 105 | if ([self respondsToSelector:@selector(browserWindowControllerMac)]) // Safari 5.1 106 | { 107 | windowController = [self performSelector:@selector(browserWindowControllerMac)]; 108 | } 109 | else if ([self respondsToSelector:@selector(browserWindowController)]) // Safari 5.0 110 | { 111 | windowController = [self performSelector:@selector(browserWindowController)]; 112 | } 113 | if (windowController) 114 | { 115 | if ([windowController respondsToSelector:@selector(locationField)]) 116 | { 117 | return [windowController performSelector:@selector(locationField)]; 118 | } 119 | } 120 | return nil; 121 | } 122 | 123 | - (BOOL)SafariOmnibar_restoreLastSearch:(NSTextField *)locationField forced:(BOOL)forced 124 | { 125 | SafariOmnibar *plugin = [SafariOmnibar sharedInstance]; 126 | 127 | // If current location URL contains the last search (or forced is YES), replace the URL by the search so user can easily edit it 128 | NSString *lastSearch = [plugin previousSearchQueryForLocationField:locationField]; 129 | if (lastSearch 130 | && (forced || [[locationField.stringValue stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] rangeOfString:lastSearch].location != NSNotFound)) 131 | { 132 | NSDictionary *provider = [plugin previousSearchProviderForLocationField:locationField]; 133 | if (provider) 134 | { 135 | // Add back the former search provider keyword 136 | lastSearch = [NSString stringWithFormat:@"%@ %@", [provider objectForKey:@"Keyword"], lastSearch]; 137 | } 138 | if (lastSearch) 139 | { 140 | [locationField setStringValue:lastSearch]; 141 | if (provider) [plugin updateSearchProviderForLocationField:locationField]; 142 | return YES; 143 | } 144 | } 145 | 146 | return NO; 147 | } 148 | 149 | - (void)SafariOmnibar_searchWeb:(id)sender 150 | { 151 | // This is the action behind Edit > Find > Find Google... 152 | NSTextField *locationField = [self SafariOmnibar_locationField]; 153 | if (locationField) 154 | { 155 | if (![self SafariOmnibar_restoreLastSearch:locationField forced:YES]) 156 | { 157 | // Force default search provider 158 | [locationField setStringValue:@"?"]; 159 | [[SafariOmnibar sharedInstance] updateSearchProviderForLocationField:locationField]; 160 | } 161 | // Focus location field 162 | [locationField becomeFirstResponder]; 163 | // Move the caret at the end of the text's field 164 | [(NSText *)[[locationField window] firstResponder] setSelectedRange:NSMakeRange(locationField.stringValue.length, 0)]; 165 | } 166 | } 167 | 168 | - (void)SafariOmnibar_openLocation:(id)sender 169 | { 170 | // This is the action behind File > Open Location... 171 | NSTextField *locationField = [self SafariOmnibar_locationField]; 172 | if (locationField) 173 | { 174 | // Mimic Chrome behavior by selecting the content of the location text field, ready to be replaced 175 | [locationField selectText:nil]; 176 | } 177 | [self SafariOmnibar_openLocation:sender]; 178 | } 179 | 180 | @end 181 | 182 | @interface SafariOmnibar () 183 | 184 | @property (nonatomic, retain) NSMenuItem *editSearchProvidersItem; 185 | 186 | @end 187 | 188 | @implementation SafariOmnibar 189 | @synthesize searchProviders; 190 | @synthesize defaultSearchProvider; 191 | @synthesize editSearchProvidersItem; 192 | @dynamic pluginVersion; 193 | 194 | - (NSMutableDictionary *)contextForLocationField:(NSTextField *)locationField 195 | { 196 | return [locationFieldContext objectForKey:[NSNumber numberWithInteger:locationField.hash]]; 197 | } 198 | 199 | - (void)onLocationFieldChange:(NSNotification *)notification 200 | { 201 | [self updateSearchProviderForLocationField:notification.object]; 202 | } 203 | 204 | - (void)addContextMenuItemsToLocationField:(id)locationField 205 | { 206 | // To add an item to the location field's context menu, we need to add one 207 | // to its field editor. In Safari, this field editor appears to be unique 208 | // to the location field, and the same instance is shared throughout the 209 | // application. This lets us simply keep a reference to the menu item we 210 | // add and check its presence to stop from adding the menu item multiple 211 | // times. 212 | if (self.editSearchProvidersItem) return; 213 | self.editSearchProvidersItem = [[[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Edit Omnibar Search Providers…", @"location field context menu item") 214 | action:@selector(editSearchProviders:) 215 | keyEquivalent:@""] autorelease]; 216 | self.editSearchProvidersItem.target = self; 217 | NSWindow *window = [locationField performSelector:@selector(window)]; 218 | NSResponder *locationFieldEditor = [window fieldEditor:YES forObject:locationField]; 219 | [locationFieldEditor.menu addItem:[NSMenuItem separatorItem]]; 220 | [locationFieldEditor.menu addItem:self.editSearchProvidersItem]; 221 | } 222 | 223 | - (void)initBrowserWindow:(NSWindow *)window 224 | { 225 | NSWindowController *windowController = [window windowController]; 226 | if ([windowController respondsToSelector:@selector(searchField)] 227 | && [windowController respondsToSelector:@selector(locationField)]) 228 | { 229 | [[windowController performSelector:@selector(searchField)] removeFromSuperview]; 230 | 231 | NSTextField *locationField = [windowController performSelector:@selector(locationField)]; 232 | // Init Omnibar context for this field 233 | [locationFieldContext setObject:[NSMutableDictionary dictionary] forKey:[NSNumber numberWithInteger:locationField.hash]]; 234 | 235 | [[NSNotificationCenter defaultCenter] addObserver:self 236 | selector:@selector(onLocationFieldChange:) 237 | name:@"NSControlTextDidChangeNotification" 238 | object:locationField]; 239 | [self addContextMenuItemsToLocationField:locationField]; 240 | } 241 | } 242 | 243 | - (void)onNewWindow:(NSNotification *)notification 244 | { 245 | NSWindow *window = notification.object; 246 | [self initBrowserWindow:window]; 247 | } 248 | 249 | - (void)loadApplicationDefaults 250 | { 251 | NSString *path = [[NSBundle bundleForClass:self.class] pathForResource:@"SearchProviders" ofType:@"plist"]; 252 | NSDictionary *searchProvidersConf = [NSDictionary dictionaryWithContentsOfFile:path]; 253 | NSArray *defaultSearchProviders = [searchProvidersConf objectForKey:@"SearchProvidersList"]; 254 | NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:defaultSearchProviders 255 | forKey:kOmnibarSearchProviders]; 256 | [[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults]; 257 | } 258 | 259 | - (void)loadSearchProviders 260 | { 261 | [searchProviders release]; searchProviders = nil; 262 | [defaultSearchProvider release]; defaultSearchProvider = nil; 263 | 264 | searchProviders = [[[NSUserDefaults standardUserDefaults] arrayForKey:kOmnibarSearchProviders] retain]; 265 | 266 | for (NSDictionary *searchProvider in searchProviders) 267 | { 268 | if ([[searchProvider objectForKey:@"Default"] boolValue]) 269 | { 270 | defaultSearchProvider = [searchProvider retain]; 271 | break; 272 | } 273 | } 274 | } 275 | 276 | - (void)saveSearchProviders:(NSArray *)someSearchProviders 277 | { 278 | [[NSUserDefaults standardUserDefaults] setObject:someSearchProviders 279 | forKey:kOmnibarSearchProviders]; 280 | } 281 | 282 | - (NSDictionary *)searchProviderForKeyword:(NSString *)keyword 283 | { 284 | NSString *lcKeyword = [keyword lowercaseString]; 285 | for (NSDictionary *provider in searchProviders) 286 | { 287 | if ([lcKeyword isEqualToString:[[provider objectForKey:@"Keyword"] lowercaseString]]) 288 | { 289 | return provider; 290 | } 291 | } 292 | 293 | return nil; 294 | } 295 | 296 | - (void)updateSearchProviderForLocationField:(NSTextField *)locationField 297 | { 298 | NSString *location = locationField.stringValue; 299 | NSDictionary *provider = [self searchProviderForLocationField:locationField]; 300 | 301 | if (provider) 302 | { 303 | NSString *providerName = [provider objectForKey:@"Name"]; 304 | if (![location hasPrefix:[NSString stringWithFormat:@"%@: ", providerName]]) 305 | { 306 | [self resetSearchProviderForLocationField:locationField]; 307 | NSUInteger colonLoc = [location rangeOfString:@":"].location; 308 | if (colonLoc != NSNotFound) 309 | { 310 | location = [NSString stringWithFormat:@"%@%@", 311 | [provider objectForKey:@"Keyword"], 312 | [location substringWithRange:NSMakeRange(colonLoc + 1, location.length - (colonLoc + 1))]]; 313 | [locationField setStringValue:location]; 314 | } 315 | } 316 | } 317 | else 318 | { 319 | NSDictionary *provider = nil; 320 | NSString *terms = nil; 321 | 322 | if ([location hasPrefix:@"?"]) 323 | { 324 | // Force default search provider if location starts with "?" 325 | terms = [location substringFromIndex:1]; 326 | provider = [[SafariOmnibar sharedInstance] defaultSearchProvider]; 327 | } 328 | else 329 | { 330 | // Keyword custom search provider 331 | NSUInteger firstSpaceLoc = [location rangeOfString:@" "].location; 332 | 333 | if (firstSpaceLoc != NSNotFound && firstSpaceLoc > 0) 334 | { 335 | // Lookup for search provider keyword 336 | NSString *firstWord = [[location substringWithRange:NSMakeRange(0, firstSpaceLoc)] lowercaseString]; 337 | provider = [[SafariOmnibar sharedInstance] searchProviderForKeyword:firstWord]; 338 | if (provider) 339 | { 340 | // Remove the keyword from terms 341 | terms = [location substringFromIndex:firstSpaceLoc + 1]; 342 | } 343 | } 344 | } 345 | 346 | if (provider) 347 | { 348 | // Add the provider name 349 | locationField.stringValue = [NSString stringWithFormat:@"%@: %@", [provider objectForKey:@"Name"], terms]; 350 | // Save current provider for this field 351 | [[self contextForLocationField:locationField] setObject:provider forKey:@"provider"]; 352 | } 353 | } 354 | } 355 | 356 | - (NSDictionary *)searchProviderForLocationField:(NSTextField *)locationField 357 | { 358 | return [[self contextForLocationField:locationField] objectForKey:@"provider"]; 359 | } 360 | 361 | - (void)resetSearchProviderForLocationField:(NSTextField *)locationField 362 | { 363 | NSDictionary *lastProvider = [self searchProviderForLocationField:locationField]; 364 | if (lastProvider) 365 | { 366 | [[self contextForLocationField:locationField] removeObjectForKey:@"provider"]; 367 | [[self contextForLocationField:locationField] setObject:lastProvider forKey:@"last_provider"]; 368 | } 369 | } 370 | 371 | - (NSDictionary *)previousSearchProviderForLocationField:(NSTextField *)locationField 372 | { 373 | return [[self contextForLocationField:locationField] objectForKey:@"last_provider"]; 374 | } 375 | 376 | - (void)saveSearchQuery:(NSString *)searchQuery forLocationField:(NSTextField *)locationField 377 | { 378 | [[self contextForLocationField:locationField] setObject:searchQuery forKey:@"last_search"]; 379 | } 380 | 381 | - (NSString *)previousSearchQueryForLocationField:(NSTextField *)locationField 382 | { 383 | return [[self contextForLocationField:locationField] objectForKey:@"last_search"]; 384 | } 385 | 386 | 387 | - (void)editSearchProviders:(id)sender 388 | { 389 | NSMutableArray *mutableSearchProviders = [NSMutableArray array]; 390 | for (NSDictionary *provider in [SafariOmnibar sharedInstance].searchProviders) 391 | { 392 | [mutableSearchProviders addObject:[[provider mutableCopy] autorelease]]; 393 | } 394 | SearchProvidersEditorWindowController *editor = [[SearchProvidersEditorWindowController alloc] initWithSearchProviders:mutableSearchProviders]; 395 | [[NSApplication sharedApplication] beginSheet:editor.window 396 | modalForWindow:[[NSApplication sharedApplication] keyWindow] 397 | modalDelegate:self 398 | didEndSelector:@selector(didEndSheet:returnCode:contextInfo:) 399 | contextInfo:editor]; 400 | } 401 | 402 | - (void)didEndSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo 403 | { 404 | SearchProvidersEditorWindowController *editor = contextInfo; 405 | [self saveSearchProviders:editor.searchProviders]; 406 | [self loadSearchProviders]; 407 | [sheet orderOut:self]; 408 | [editor autorelease]; 409 | } 410 | 411 | - (id)init 412 | { 413 | if ((self = [super init])) 414 | { 415 | locationFieldContext = [[NSMutableDictionary alloc] init]; 416 | [self loadApplicationDefaults]; 417 | [self loadSearchProviders]; 418 | 419 | for (NSWindow *window in [[NSApplication sharedApplication] windows]) 420 | { 421 | [self initBrowserWindow:window]; 422 | } 423 | 424 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onNewWindow:) name:@"NSWindowDidBecomeMainNotification" object:nil]; 425 | 426 | if (NSClassFromString(@"BrowserWindowControllerMac")) 427 | { 428 | // Safari 5.1 429 | [NSClassFromString(@"BrowserWindowControllerMac") jr_swizzleMethod:@selector(goToToolbarLocation:) 430 | withMethod:@selector(SafariOmnibar_goToToolbarLocation:) error:NULL]; 431 | } 432 | else 433 | { 434 | // Safari 5.0 435 | [NSClassFromString(@"BrowserWindowController") jr_swizzleMethod:@selector(goToToolbarLocation:) 436 | withMethod:@selector(SafariOmnibar_goToToolbarLocation:) error:NULL]; 437 | } 438 | 439 | [NSClassFromString(@"BrowserDocument") jr_swizzleMethod:@selector(searchWeb:) 440 | withMethod:@selector(SafariOmnibar_searchWeb:) error:NULL]; 441 | [NSClassFromString(@"BrowserDocument") jr_swizzleMethod:@selector(openLocation:) 442 | withMethod:@selector(SafariOmnibar_openLocation:) error:NULL]; 443 | 444 | 445 | [SparkleHelper initUpdater]; 446 | } 447 | return self; 448 | } 449 | 450 | - (void)dealloc 451 | { 452 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 453 | [editSearchProvidersItem release], editSearchProvidersItem = nil; 454 | [locationFieldContext release], locationFieldContext = nil; 455 | [defaultSearchProvider release], defaultSearchProvider = nil; 456 | [searchProviders release], searchProviders = nil; 457 | [super dealloc]; 458 | } 459 | 460 | + (NSString *)pluginVersion 461 | { 462 | return [[[NSBundle bundleForClass:self] infoDictionary] objectForKey:@"CFBundleVersion"]; 463 | } 464 | 465 | + (SafariOmnibar *)sharedInstance 466 | { 467 | static SafariOmnibar *plugin = nil; 468 | 469 | if (plugin == nil) 470 | plugin = [[SafariOmnibar alloc] init]; 471 | 472 | return plugin; 473 | } 474 | 475 | + (void)load 476 | { 477 | [self sharedInstance]; 478 | NSLog(@"Safari Omnibar %@ Loaded", self.pluginVersion); 479 | } 480 | 481 | @end 482 | -------------------------------------------------------------------------------- /SafariOmnibar/SearchProviders.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SearchProvidersList 6 | 7 | 8 | Name 9 | Google 10 | Keyword 11 | g 12 | Default 13 | 14 | SearchURLTemplate 15 | http://www.google.com/search?client=safari&rls=en&q={searchTerms}&ie=UTF-8&oe=UTF-8 16 | 17 | 18 | Name 19 | Google Image 20 | Keyword 21 | image 22 | Default 23 | 24 | SearchURLTemplate 25 | http://images.google.com/images?hl=en&source=hp&q={searchTerms}&btnG=Search+Images&gbv=2&aq=f&oq=&aqi= 26 | 27 | 28 | Name 29 | DuckDuckGo 30 | Keyword 31 | ddg 32 | Default 33 | 34 | SearchURLTemplate 35 | https://duckduckgo.com/?q={searchTerms}&t=safariomnibar 36 | 37 | 38 | Name 39 | Wikipedia 40 | Keyword 41 | w 42 | Default 43 | 44 | SearchURLTemplate 45 | http://en.wikipedia.org/w/index.php?title=Special:Search&search={searchTerms} 46 | 47 | 48 | Name 49 | Dailymotion 50 | Keyword 51 | video 52 | Default 53 | 54 | SearchURLTemplate 55 | http://www.dailymotion.com?search={searchTerms} 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /SafariOmnibar/SearchProvidersEditor.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1070 5 | 11B26 6 | 1617 7 | 1138 8 | 566.00 9 | 10 | com.apple.InterfaceBuilder.CocoaPlugin 11 | 1617 12 | 13 | 14 | YES 15 | NSScroller 16 | NSArrayController 17 | NSButton 18 | NSTableHeaderView 19 | NSScrollView 20 | NSButtonCell 21 | NSTextFieldCell 22 | NSTableView 23 | NSCustomObject 24 | NSView 25 | NSWindowTemplate 26 | NSTextField 27 | NSTableColumn 28 | 29 | 30 | YES 31 | com.apple.InterfaceBuilder.CocoaPlugin 32 | 33 | 34 | YES 35 | 36 | YES 37 | 38 | 39 | 40 | 41 | YES 42 | 43 | SearchProvidersEditorWindowController 44 | 45 | 46 | FirstResponder 47 | 48 | 49 | NSApplication 50 | 51 | 52 | YES 53 | 54 | YES 55 | YES 56 | YES 57 | YES 58 | YES 59 | 60 | 61 | 31 62 | 2 63 | {{139, 81}, {480, 259}} 64 | -1535638528 65 | Window 66 | NSPanel 67 | 68 | 69 | 70 | 71 | 256 72 | 73 | YES 74 | 75 | 76 | 266 77 | {{17, 222}, {446, 17}} 78 | 79 | 80 | 81 | _NS:3936 82 | YES 83 | 84 | 68288064 85 | 272630784 86 | Edit Search Providers 87 | 88 | LucidaGrande-Bold 89 | 13 90 | 2072 91 | 92 | _NS:3936 93 | 94 | 95 | 6 96 | System 97 | controlColor 98 | 99 | 3 100 | MC42NjY2NjY2NjY3AA 101 | 102 | 103 | 104 | 6 105 | System 106 | controlTextColor 107 | 108 | 3 109 | MAA 110 | 111 | 112 | 113 | 114 | 115 | 116 | 274 117 | 118 | YES 119 | 120 | 121 | 2304 122 | 123 | YES 124 | 125 | 126 | 256 127 | {438, 147} 128 | 129 | 130 | 131 | _NS:1197 132 | YES 133 | 134 | 135 | 256 136 | {438, 17} 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | -2147483392 145 | {{224, 0}, {16, 17}} 146 | _NS:1202 147 | 148 | 149 | YES 150 | 151 | 101 152 | 40 153 | 1000 154 | 155 | 75628096 156 | 2048 157 | Search Provider 158 | 159 | LucidaGrande 160 | 11 161 | 3100 162 | 163 | 164 | 3 165 | MC4zMzMzMzI5ODU2AA 166 | 167 | 168 | 6 169 | System 170 | headerTextColor 171 | 172 | 173 | 174 | 175 | 337772096 176 | 2048 177 | Text Cell 178 | 179 | LucidaGrande 180 | 13 181 | 1044 182 | 183 | 184 | 185 | 6 186 | System 187 | controlBackgroundColor 188 | 189 | 190 | 191 | 192 | 3 193 | YES 194 | YES 195 | 196 | 197 | 198 | 66 199 | 40 200 | 1000 201 | 202 | 75628096 203 | 2048 204 | Keyword 205 | 206 | 207 | 208 | 209 | 210 | 337772096 211 | 2048 212 | Text Cell 213 | 214 | 215 | 216 | 217 | 218 | 3 219 | YES 220 | YES 221 | 222 | 223 | 224 | 262 225 | 10 226 | 3.4028234663852886e+38 227 | 228 | 75628096 229 | 2048 230 | URL 231 | 232 | 233 | 6 234 | System 235 | headerColor 236 | 237 | 3 238 | MQA 239 | 240 | 241 | 242 | 243 | 244 | 337772096 245 | 2048 246 | Text Cell 247 | 248 | 249 | 250 | 251 | 252 | 3 253 | YES 254 | YES 255 | 256 | 257 | 258 | 3 259 | 2 260 | 261 | 262 | 6 263 | System 264 | gridColor 265 | 266 | 3 267 | MC41AA 268 | 269 | 270 | 17 271 | 1447034880 272 | 273 | 274 | 4 275 | 15 276 | 0 277 | YES 278 | 1 279 | 1 280 | 281 | 282 | {{1, 17}, {438, 147}} 283 | 284 | 285 | 286 | _NS:1195 287 | 288 | 289 | 4 290 | 291 | 292 | 293 | -2147483392 294 | {{224, 17}, {15, 102}} 295 | 296 | 297 | 298 | _NS:1214 299 | 300 | _doScroller: 301 | 0.9932432432432432 302 | 303 | 304 | 305 | -2147483392 306 | {{1, 189}, {438, 15}} 307 | 308 | 309 | 310 | _NS:1216 311 | 1 312 | 313 | _doScroller: 314 | 0.99772209567198178 315 | 316 | 317 | 318 | 2304 319 | 320 | YES 321 | 322 | 323 | {{1, 0}, {438, 17}} 324 | 325 | 326 | 327 | 328 | 329 | 4 330 | 331 | 332 | {{20, 49}, {440, 165}} 333 | 334 | 335 | 336 | _NS:1193 337 | 133682 338 | 339 | 340 | 341 | 342 | QSAAAEEgAABBmAAAQZgAAA 343 | 344 | 345 | 346 | 289 347 | {{374, 13}, {92, 32}} 348 | 349 | 350 | 351 | _NS:161 352 | YES 353 | 354 | 67239424 355 | 134217728 356 | Done 357 | 358 | _NS:161 359 | 360 | -2038284033 361 | 129 362 | 363 | DQ 364 | 200 365 | 25 366 | 367 | 368 | 369 | 370 | 292 371 | {{77, 13}, {127, 32}} 372 | 373 | 374 | 375 | _NS:161 376 | YES 377 | 378 | 67239424 379 | 134217728 380 | Set as Default 381 | 382 | _NS:161 383 | 384 | -2038284033 385 | 129 386 | 387 | 388 | 200 389 | 25 390 | 391 | 392 | 393 | 394 | 292 395 | {{20, 19}, {28, 23}} 396 | 397 | 398 | 399 | _NS:1566 400 | YES 401 | 402 | -2080244224 403 | 134217728 404 | 405 | 406 | _NS:1566 407 | 408 | -2033434369 409 | 162 410 | 411 | NSImage 412 | NSAddTemplate 413 | 414 | 415 | 416 | 400 417 | 75 418 | 419 | 420 | 421 | 422 | 292 423 | {{47, 19}, {28, 23}} 424 | 425 | 426 | 427 | _NS:1566 428 | YES 429 | 430 | -2080244224 431 | 134217728 432 | 433 | 434 | _NS:1566 435 | 436 | -2033434369 437 | 162 438 | 439 | NSImage 440 | NSRemoveTemplate 441 | 442 | 443 | 444 | 400 445 | 75 446 | 447 | 448 | 449 | {480, 259} 450 | 451 | 452 | 453 | _NS:2837 454 | 455 | {{0, 0}, {1920, 1178}} 456 | {10000000000000, 10000000000000} 457 | OmnibarEditor 458 | YES 459 | 460 | 461 | 462 | 463 | YES 464 | 465 | 466 | contentArray: searchProviders 467 | 468 | 469 | 470 | 471 | 472 | contentArray: searchProviders 473 | contentArray 474 | searchProviders 475 | 2 476 | 477 | 478 | 21 479 | 480 | 481 | 482 | content: arrangedObjects 483 | 484 | 485 | 486 | 487 | 488 | content: arrangedObjects 489 | content 490 | arrangedObjects 491 | 2 492 | 493 | 494 | 61 495 | 496 | 497 | 498 | selectionIndexes: selectionIndexes 499 | 500 | 501 | 502 | 503 | 504 | selectionIndexes: selectionIndexes 505 | selectionIndexes 506 | selectionIndexes 507 | 508 | 2 509 | 510 | 511 | 62 512 | 513 | 514 | 515 | sortDescriptors: sortDescriptors 516 | 517 | 518 | 519 | 520 | 521 | sortDescriptors: sortDescriptors 522 | sortDescriptors 523 | sortDescriptors 524 | 525 | 2 526 | 527 | 528 | 63 529 | 530 | 531 | 532 | value: arrangedObjects.SearchURLTemplate 533 | 534 | 535 | 536 | 537 | 538 | value: arrangedObjects.SearchURLTemplate 539 | value 540 | arrangedObjects.SearchURLTemplate 541 | 2 542 | 543 | 544 | 64 545 | 546 | 547 | 548 | value: arrangedObjects.Name 549 | 550 | 551 | 552 | 553 | 554 | value: arrangedObjects.Name 555 | value 556 | arrangedObjects.Name 557 | 2 558 | 559 | 560 | 65 561 | 562 | 563 | 564 | value: arrangedObjects.Keyword 565 | 566 | 567 | 568 | 569 | 570 | value: arrangedObjects.Keyword 571 | value 572 | arrangedObjects.Keyword 573 | 2 574 | 575 | 576 | 67 577 | 578 | 579 | 580 | dismiss: 581 | 582 | 583 | 584 | 68 585 | 586 | 587 | 588 | window 589 | 590 | 591 | 592 | 69 593 | 594 | 595 | 596 | enabled: selection.Default 597 | 598 | 599 | 600 | 601 | 602 | enabled: selection.Default 603 | enabled 604 | selection.Default 605 | 606 | NSValueTransformerName 607 | NSNegateBoolean 608 | 609 | 2 610 | 611 | 612 | 75 613 | 614 | 615 | 616 | fontBold: arrangedObjects.Default 617 | 618 | 619 | 620 | 621 | 622 | fontBold: arrangedObjects.Default 623 | fontBold 624 | arrangedObjects.Default 625 | 2 626 | 627 | 628 | 77 629 | 630 | 631 | 632 | setSelectedProviderAsDefault: 633 | 634 | 635 | 636 | 78 637 | 638 | 639 | 640 | arrayController 641 | 642 | 643 | 644 | 79 645 | 646 | 647 | 648 | tableView 649 | 650 | 651 | 652 | 84 653 | 654 | 655 | 656 | addSearchProvider: 657 | 658 | 659 | 660 | 85 661 | 662 | 663 | 664 | removeSearchProvider: 665 | 666 | 667 | 668 | 86 669 | 670 | 671 | 672 | 673 | YES 674 | 675 | 0 676 | 677 | 678 | 679 | 680 | 681 | -2 682 | 683 | 684 | File's Owner 685 | 686 | 687 | -1 688 | 689 | 690 | First Responder 691 | 692 | 693 | -3 694 | 695 | 696 | Application 697 | 698 | 699 | 16 700 | 701 | 702 | 703 | 704 | 42 705 | 706 | 707 | YES 708 | 709 | 710 | 711 | 712 | 713 | 43 714 | 715 | 716 | YES 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 44 728 | 729 | 730 | YES 731 | 732 | 733 | 734 | 735 | 736 | 45 737 | 738 | 739 | YES 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 46 749 | 750 | 751 | YES 752 | 753 | 754 | 755 | 756 | 757 | 47 758 | 759 | 760 | 761 | 762 | 48 763 | 764 | 765 | YES 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 49 774 | 775 | 776 | 777 | 778 | 51 779 | 780 | 781 | 782 | 783 | 53 784 | 785 | 786 | YES 787 | 788 | 789 | 790 | 791 | 792 | 54 793 | 794 | 795 | YES 796 | 797 | 798 | 799 | 800 | 801 | 55 802 | 803 | 804 | YES 805 | 806 | 807 | 808 | 809 | 810 | 56 811 | 812 | 813 | 814 | 815 | 57 816 | 817 | 818 | 819 | 820 | 58 821 | 822 | 823 | 824 | 825 | 60 826 | 827 | 828 | 829 | 830 | 70 831 | 832 | 833 | YES 834 | 835 | 836 | 837 | 838 | 839 | 71 840 | 841 | 842 | 843 | 844 | 80 845 | 846 | 847 | YES 848 | 849 | 850 | 851 | 852 | 853 | 81 854 | 855 | 856 | 857 | 858 | 82 859 | 860 | 861 | YES 862 | 863 | 864 | 865 | 866 | 867 | 83 868 | 869 | 870 | 871 | 872 | 87 873 | 874 | 875 | 876 | 877 | 878 | 879 | YES 880 | 881 | YES 882 | -1.IBPluginDependency 883 | -2.IBPluginDependency 884 | -3.IBPluginDependency 885 | 16.IBPluginDependency 886 | 42.IBPluginDependency 887 | 42.NSWindowTemplate.visibleAtLaunch 888 | 43.IBPluginDependency 889 | 44.IBPluginDependency 890 | 45.IBPluginDependency 891 | 46.IBPluginDependency 892 | 47.IBPluginDependency 893 | 48.IBPluginDependency 894 | 49.IBPluginDependency 895 | 51.IBPluginDependency 896 | 53.IBPluginDependency 897 | 54.IBPluginDependency 898 | 55.IBPluginDependency 899 | 56.IBPluginDependency 900 | 57.IBPluginDependency 901 | 58.IBPluginDependency 902 | 60.IBPluginDependency 903 | 70.IBPluginDependency 904 | 71.IBPluginDependency 905 | 80.IBPluginDependency 906 | 81.IBPluginDependency 907 | 82.IBPluginDependency 908 | 83.IBPluginDependency 909 | 87.IBPluginDependency 910 | 911 | 912 | YES 913 | com.apple.InterfaceBuilder.CocoaPlugin 914 | com.apple.InterfaceBuilder.CocoaPlugin 915 | com.apple.InterfaceBuilder.CocoaPlugin 916 | com.apple.InterfaceBuilder.CocoaPlugin 917 | com.apple.InterfaceBuilder.CocoaPlugin 918 | 919 | com.apple.InterfaceBuilder.CocoaPlugin 920 | com.apple.InterfaceBuilder.CocoaPlugin 921 | com.apple.InterfaceBuilder.CocoaPlugin 922 | com.apple.InterfaceBuilder.CocoaPlugin 923 | com.apple.InterfaceBuilder.CocoaPlugin 924 | com.apple.InterfaceBuilder.CocoaPlugin 925 | com.apple.InterfaceBuilder.CocoaPlugin 926 | com.apple.InterfaceBuilder.CocoaPlugin 927 | com.apple.InterfaceBuilder.CocoaPlugin 928 | com.apple.InterfaceBuilder.CocoaPlugin 929 | com.apple.InterfaceBuilder.CocoaPlugin 930 | com.apple.InterfaceBuilder.CocoaPlugin 931 | com.apple.InterfaceBuilder.CocoaPlugin 932 | com.apple.InterfaceBuilder.CocoaPlugin 933 | com.apple.InterfaceBuilder.CocoaPlugin 934 | com.apple.InterfaceBuilder.CocoaPlugin 935 | com.apple.InterfaceBuilder.CocoaPlugin 936 | com.apple.InterfaceBuilder.CocoaPlugin 937 | com.apple.InterfaceBuilder.CocoaPlugin 938 | com.apple.InterfaceBuilder.CocoaPlugin 939 | com.apple.InterfaceBuilder.CocoaPlugin 940 | com.apple.InterfaceBuilder.CocoaPlugin 941 | 942 | 943 | 944 | YES 945 | 946 | 947 | 948 | 949 | 950 | YES 951 | 952 | 953 | 954 | 955 | 87 956 | 957 | 958 | 959 | YES 960 | 961 | SearchProvidersEditorWindowController 962 | NSWindowController 963 | 964 | YES 965 | 966 | YES 967 | addSearchProvider: 968 | dismiss: 969 | removeSearchProvider: 970 | setSelectedProviderAsDefault: 971 | 972 | 973 | YES 974 | id 975 | id 976 | id 977 | id 978 | 979 | 980 | 981 | YES 982 | 983 | YES 984 | addSearchProvider: 985 | dismiss: 986 | removeSearchProvider: 987 | setSelectedProviderAsDefault: 988 | 989 | 990 | YES 991 | 992 | addSearchProvider: 993 | id 994 | 995 | 996 | dismiss: 997 | id 998 | 999 | 1000 | removeSearchProvider: 1001 | id 1002 | 1003 | 1004 | setSelectedProviderAsDefault: 1005 | id 1006 | 1007 | 1008 | 1009 | 1010 | YES 1011 | 1012 | YES 1013 | arrayController 1014 | tableView 1015 | 1016 | 1017 | YES 1018 | NSArrayController 1019 | NSTableView 1020 | 1021 | 1022 | 1023 | YES 1024 | 1025 | YES 1026 | arrayController 1027 | tableView 1028 | 1029 | 1030 | YES 1031 | 1032 | arrayController 1033 | NSArrayController 1034 | 1035 | 1036 | tableView 1037 | NSTableView 1038 | 1039 | 1040 | 1041 | 1042 | IBProjectSource 1043 | ./Classes/SearchProvidersEditorWindowController.h 1044 | 1045 | 1046 | 1047 | 1048 | 0 1049 | IBCocoaFramework 1050 | 1051 | com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 1052 | 1053 | 1054 | YES 1055 | 3 1056 | 1057 | YES 1058 | 1059 | YES 1060 | NSAddTemplate 1061 | NSRemoveTemplate 1062 | 1063 | 1064 | YES 1065 | {8, 8} 1066 | {8, 8} 1067 | 1068 | 1069 | 1070 | 1071 | -------------------------------------------------------------------------------- /SafariOmnibar/SearchProvidersEditorWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SearchProvidersEditorWindowController.h 3 | // SafariOmnibar 4 | // 5 | // Created by Nolan Waite on 11-07-23. 6 | // 7 | 8 | #import 9 | 10 | @interface SearchProvidersEditorWindowController : NSWindowController 11 | { 12 | NSMutableArray *searchProviders; 13 | NSArrayController *arrayController; 14 | NSTableView *tableView; 15 | } 16 | 17 | @property (nonatomic, readonly, copy) NSMutableArray *searchProviders; 18 | @property (nonatomic, retain) IBOutlet NSArrayController *arrayController; 19 | @property (nonatomic, retain) IBOutlet NSTableView *tableView; 20 | 21 | - (id)initWithSearchProviders:(NSArray *)searchProviders; 22 | 23 | - (IBAction)addSearchProvider:(id)sender; 24 | - (IBAction)removeSearchProvider:(id)sender; 25 | - (IBAction)setSelectedProviderAsDefault:(id)sender; 26 | - (IBAction)dismiss:(id)sender; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /SafariOmnibar/SearchProvidersEditorWindowController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SearchProvidersEditorWindowController.m 3 | // SafariOmnibar 4 | // 5 | // Created by Nolan Waite on 11-07-23. 6 | // 7 | 8 | #import "SearchProvidersEditorWindowController.h" 9 | 10 | @implementation SearchProvidersEditorWindowController 11 | 12 | @synthesize searchProviders; 13 | @synthesize arrayController; 14 | @synthesize tableView; 15 | 16 | - (id)initWithSearchProviders:(NSArray *)someSearchProviders 17 | { 18 | if ((self = [super initWithWindowNibName:@"SearchProvidersEditor"])) 19 | { 20 | searchProviders = [someSearchProviders mutableCopy]; 21 | } 22 | return self; 23 | } 24 | 25 | static NSString *FirstHTTPURLStringOnGeneralPasteboard() 26 | { 27 | NSPasteboard *generalPasteboard = [NSPasteboard generalPasteboard]; 28 | NSArray *copiedStrings = [generalPasteboard readObjectsForClasses:[NSArray arrayWithObject:[NSString class]] options:nil]; 29 | for (NSString *maybeURLString in copiedStrings) 30 | { 31 | if ([maybeURLString hasPrefix:@"http"]) return maybeURLString; 32 | } 33 | return nil; 34 | } 35 | 36 | - (IBAction)addSearchProvider:(id)sender 37 | { 38 | NSMutableDictionary *newProvider = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"New Provider", @"Name", @"new", @"Keyword", @"http://example.com/search?q={searchTerms}", @"SearchURLTemplate", nil]; 39 | NSString *copiedURLString = FirstHTTPURLStringOnGeneralPasteboard(); 40 | if (copiedURLString != nil) 41 | { 42 | [newProvider setObject:copiedURLString forKey:@"SearchURLTemplate"]; 43 | } 44 | [self.arrayController addObject:newProvider]; 45 | [self.tableView editColumn:0 row:([self.searchProviders count] - 1) withEvent:nil select:YES]; 46 | } 47 | 48 | - (IBAction)removeSearchProvider:(id)sender 49 | { 50 | if ([self.searchProviders count] < 2) return; 51 | BOOL wasDefault = [[self.arrayController.selection valueForKey:@"Default"] boolValue]; 52 | [self.arrayController removeObjects:self.arrayController.selectedObjects]; 53 | if (wasDefault) 54 | { 55 | [self setSelectedProviderAsDefault:nil]; 56 | } 57 | } 58 | 59 | - (IBAction)setSelectedProviderAsDefault:(id)sender 60 | { 61 | [self.arrayController.arrangedObjects setValue:[NSNumber numberWithBool:NO] forKey:@"Default"]; 62 | [self.arrayController.selectedObjects setValue:[NSNumber numberWithBool:YES] forKey:@"Default"]; 63 | } 64 | 65 | - (IBAction)dismiss:(id)sender 66 | { 67 | [[NSApplication sharedApplication] endSheet:self.window]; 68 | } 69 | 70 | - (void)dealloc 71 | { 72 | [tableView release], tableView = nil; 73 | [arrayController release], arrayController = nil; 74 | [searchProviders release], searchProviders = nil; 75 | [super dealloc]; 76 | } 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /SafariOmnibar/SparkleHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // SparkleHelper.h 3 | // SafariOmnibar 4 | // 5 | // Created by Olivier Poitrey on 02/08/11. 6 | // Copyright 2011 Olivier Poitrey. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SparkleHelper : NSObject 12 | 13 | + (void)initUpdater; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /SafariOmnibar/SparkleHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // SparkleHelper.m 3 | // SafariOmnibar 4 | // 5 | // Created by Olivier Poitrey on 02/08/11. 6 | // Copyright 2011 Olivier Poitrey. All rights reserved. 7 | // 8 | 9 | #import "SparkleHelper.h" 10 | 11 | @implementation SparkleHelper 12 | 13 | + (void)initUpdater 14 | { 15 | if (self != SparkleHelper.class) return; 16 | 17 | Class SUUpdater_class = NSClassFromString(@"SUUpdater"); 18 | if (SUUpdater_class == Nil) 19 | { 20 | // Only load Sparkle if another bundle hasn't yet (i.e. WebKit or other SIMBL plugins) 21 | // Loading different versions of a framework is a Bad Idea 22 | NSString *sparklePath = [[[NSBundle bundleForClass:self] bundlePath] stringByAppendingString:@"/Contents/Frameworks/Sparkle.framework"]; 23 | [[NSBundle bundleWithPath:sparklePath] load]; 24 | SUUpdater_class = NSClassFromString(@"SUUpdater"); 25 | } 26 | 27 | id updater = nil; 28 | if ([SUUpdater_class respondsToSelector:@selector(updaterForBundle:)]) 29 | { 30 | updater = [SUUpdater_class performSelector:@selector(updaterForBundle:) withObject:[NSBundle bundleForClass:self]]; 31 | } 32 | 33 | if (updater) 34 | { 35 | [updater setDelegate:self]; 36 | if ([updater respondsToSelector:@selector(applicationDidFinishLaunching:)]) 37 | { 38 | [updater performSelector:@selector(applicationDidFinishLaunching:) withObject:nil]; 39 | } 40 | if ([updater respondsToSelector:@selector(resetUpdateCycle)]) 41 | { 42 | [updater performSelector:@selector(resetUpdateCycle) withObject:nil]; 43 | } 44 | } 45 | } 46 | 47 | + (NSString *)pathToRelaunchForUpdater:(id)updater 48 | { 49 | return [[NSBundle mainBundle] bundlePath]; 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /SafariOmnibar/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | --------------------------------------------------------------------------------