├── SyncTabs.glyphsPlugin └── Contents │ ├── MacOS │ └── plugin │ ├── Info.plist │ └── Resources │ └── plugin.py ├── Synced Tabs ├── Synced Tabs │ ├── Synced Tabs-Prefix.pch │ ├── MFSyncedTabs.h │ ├── Info.plist │ └── MFSyncedTabs.m └── Synced Tabs.xcodeproj │ └── project.pbxproj └── README.md /SyncTabs.glyphsPlugin/Contents/MacOS/plugin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mark2Mark/Synced-Tabs/HEAD/SyncTabs.glyphsPlugin/Contents/MacOS/plugin -------------------------------------------------------------------------------- /Synced Tabs/Synced Tabs/Synced Tabs-Prefix.pch: -------------------------------------------------------------------------------- 1 | 2 | #if DEBUG 3 | #define GSLog(args...) (void)printf("%i %s: %s\n", __LINE__, __PRETTY_FUNCTION__, [[NSString stringWithFormat:args] UTF8String]) 4 | #else 5 | #define GSLog(args...) // stubbed out 6 | #endif 7 | 8 | -------------------------------------------------------------------------------- /Synced Tabs/Synced Tabs/MFSyncedTabs.h: -------------------------------------------------------------------------------- 1 | // 2 | // MFSyncedTabs.h 3 | // Synced Tabs 4 | // 5 | // Created by Georg Seifert on 27.03.19. 6 | //Copyright © 2019 markfromberg. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface MFSyncedTabs : NSObject 13 | @end 14 | -------------------------------------------------------------------------------- /Synced Tabs/Synced Tabs/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleVersion 18 | 1 19 | NSPrincipalClass 20 | MFSyncedTabs 21 | 22 | 23 | -------------------------------------------------------------------------------- /SyncTabs.glyphsPlugin/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | plugin 9 | CFBundleIdentifier 10 | com.markfromberg.SyncTabs 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | SyncTabs 15 | CFBundleShortVersionString 16 | 1.1.1 17 | CFBundleVersion 18 | 7 19 | NSHumanReadableCopyright 20 | Copyright, Mark Frömberg (@mark2mark) and Toshi Omagari (@Tosche), 2025 21 | NSPrincipalClass 22 | SyncTabs 23 | 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Buy Me a Coffee at ko-fi.com 3 |

4 | 5 | # Synced Tabs 6 | 7 | This is a plugin for the [Glyphs font editor](http://glyphsapp.com/). 8 | 9 | It is based on the **great idea and script** [Sync Edit Views.py](https://github.com/Tosche/Glyphs-Scripts/blob/master/Sync%20Edit%20Views.py) by [Tosche](https://github.com/Tosche). 10 | 11 | If active, it keeps all tabs from all open fonts in sync with the currently active tab. In **realtime!** 12 | 13 | ### How to use 14 | 15 | When ever you need it, toggle `Show Synced Tabs` from the view menu or the [Roporter Toggler](https://github.com/Mark2Mark/Reporter-Toggler). 16 | 17 | ### Examples 18 | 19 |

20 | Synched Tabs 21 |

22 | 23 | ##### Known Issues 24 | 25 | - None so far 26 | 27 | ##### TODO 28 | 29 | - selectedLayerOrigin [https://docu.glyphsapp.com/#selectedLayerOrigin] 30 | - Make the same check for placeholder Layer as it is implemented for the newLine (GSControlLayer) 31 | 32 | ##### Pull Requests 33 | 34 | Feel free to comment or pull requests for any improvements. 35 | 36 | ##### License 37 | 38 | Copyright 2017 [Mark Frömberg](http://www.markfromberg.com/) *@Mark2Mark* and(!) [Tosche](https://github.com/Tosche) 39 | 40 | Made possible with the GlyphsSDK by Georg Seifert (@schriftgestalt) and Rainer Erich Scheichelbauer (@mekkablue). 41 | 42 | Licensed under the Apache License, Version 2.0 (the "License"); 43 | you may not use this file except in compliance with the License. 44 | You may obtain a copy of the License at 45 | 46 | http://www.apache.org/licenses/LICENSE-2.0 47 | 48 | See the License file included in this repository for further details. 49 | -------------------------------------------------------------------------------- /SyncTabs.glyphsPlugin/Contents/Resources/plugin.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | from __future__ import division, print_function, unicode_literals 3 | 4 | ########################################################################################################### 5 | # 6 | # 7 | # General Plugin 8 | # 9 | # Read the docs: 10 | # https://github.com/schriftgestalt/GlyphsSDK/tree/master/Python%20Templates/General%20Plugin 11 | # 12 | # 13 | ########################################################################################################### 14 | 15 | import objc 16 | from GlyphsApp import Glyphs, VIEW_MENU, UPDATEINTERFACE, ONSTATE, OFFSTATE, NSMenuItem 17 | from GlyphsApp.plugins import GeneralPlugin 18 | 19 | MENU = VIEW_MENU 20 | HOOKS = (UPDATEINTERFACE, "GSUpdateEditViewFrame") # UPDATEEDITVIEWFRAME 21 | 22 | 23 | class SyncTabs(GeneralPlugin): 24 | 25 | @objc.python_method 26 | def settings(self): 27 | self.name = Glyphs.localize({ 28 | 'en': 'Sync Tabs', 29 | 'de': 'Tabs synchron halten', 30 | 'fr': 'Synchroniser les onglets', 31 | 'es': 'Sincronizar pestañas', 32 | }) 33 | 34 | @objc.python_method 35 | def start(self): 36 | Glyphs.registerDefault("com.markfromberg.SyncTabs.state", False) 37 | if Glyphs.buildNumber >= 3320: 38 | from GlyphsApp.UI import MenuItem 39 | self.menuItem = MenuItem(self.name, action=self.toggleSyncing_, target=self) 40 | else: 41 | newMenuItem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(self.name, self.toggleSyncing_, "") 42 | newMenuItem.setTarget_(self) 43 | 44 | Glyphs.menu[MENU].append(self.menuItem) 45 | 46 | self.setSyncState(Glyphs.boolDefaults["com.markfromberg.SyncTabs.state"]) 47 | 48 | def __del__(self): 49 | self.setSyncState(False) 50 | 51 | def toggleSyncing_(self, sender): 52 | Glyphs.boolDefaults["com.markfromberg.SyncTabs.state"] = not Glyphs.boolDefaults["com.markfromberg.SyncTabs.state"] 53 | self.setSyncState(Glyphs.boolDefaults["com.markfromberg.SyncTabs.state"]) 54 | 55 | @objc.python_method 56 | def setSyncState(self, state): 57 | try: 58 | if not state: 59 | for HOOK in HOOKS: 60 | Glyphs.removeCallback(self.syncEditViews_, callbackType=HOOK) 61 | else: 62 | for HOOK in HOOKS: 63 | Glyphs.addCallback(self.syncEditViews_, HOOK) 64 | except: 65 | import traceback 66 | print(traceback.format_exc()) 67 | 68 | self.menuItem.setState_(ONSTATE if state else OFFSTATE) 69 | 70 | def syncEditViews_(self, sender=None): 71 | try: 72 | sourceFont = Glyphs.font 73 | sourceTab = sourceFont.currentTab 74 | 75 | sendingTab = sender.object() 76 | if sendingTab != sourceTab: 77 | return 78 | if sourceTab and len(Glyphs.fonts) > 1: 79 | sourceMasterIndex = sourceFont.masterIndex 80 | sourceTool = sourceFont.tool 81 | sourceScale = sourceTab.scale 82 | sourceVisibleRect = sourceTab.viewPort 83 | sourceText = sourceTab.text 84 | sourceTextCursor = sourceTab.textCursor 85 | sourceTextRange = sourceTab.textRange 86 | sourceDoSpacing = sourceTab.graphicView().doSpacing() 87 | sourceDoKerning = sourceTab.graphicView().doKerning() 88 | sourceKerningMode = sourceTab.graphicView().kerningMode() 89 | 90 | for otherFont in Glyphs.fonts[1:]: 91 | if not otherFont.parent.windowForSheet().reallyVisible(): # Only apply to visible Fonts 92 | continue 93 | 94 | try: 95 | otherFont.masterIndex = sourceMasterIndex 96 | except: 97 | pass 98 | 99 | otherTab = otherFont.currentTab 100 | if not otherTab: 101 | otherTab = otherFont.newTab() 102 | 103 | # otherView = otherTab.graphicView() 104 | 105 | if otherTab.text != sourceText or otherTab.textCursor != sourceTextCursor: 106 | try: 107 | otherTab.text = sourceText 108 | otherTab.textCursor = sourceTextCursor 109 | otherTab.textRange = sourceTextRange 110 | except: 111 | pass 112 | 113 | try: 114 | otherTab.graphicView().setDoSpacing_(sourceDoSpacing) 115 | otherTab.graphicView().setDoKerning_(sourceDoKerning) 116 | otherTab.graphicView().setKerningMode_(sourceKerningMode) 117 | except: 118 | pass 119 | 120 | try: 121 | otherFont.tool = sourceTool 122 | except: 123 | pass 124 | 125 | try: 126 | otherTab.viewPort = sourceVisibleRect 127 | # otherTab.graphicView().viewWillDraw() 128 | otherTab.scale = sourceScale 129 | except: 130 | pass 131 | except: 132 | import traceback 133 | print(traceback.format_exc()) 134 | 135 | @objc.python_method 136 | def __file__(self): 137 | """Please leave this method unchanged""" 138 | return __file__ 139 | -------------------------------------------------------------------------------- /Synced Tabs/Synced Tabs/MFSyncedTabs.m: -------------------------------------------------------------------------------- 1 | // 2 | // MFSyncedTabs.m 3 | // Synced Tabs 4 | // 5 | // Created by Georg Seifert on 27.03.19. 6 | //Copyright © 2019 markfromberg. All rights reserved. 7 | // 8 | 9 | #import "MFSyncedTabs.h" 10 | #import 11 | #import 12 | #import 13 | #import 14 | #import 15 | #import 16 | #import 17 | #import 18 | #import 19 | #import 20 | #import 21 | #import 22 | 23 | @interface NSApplication (private) 24 | - (NSArray *)fontDocuments; 25 | @end 26 | 27 | @interface NSDocument (private) 28 | - (GSFont *)font; 29 | - (NSWindowController*) windowController; 30 | @end 31 | 32 | @interface NSView (private) 33 | - (NSString *)displayString; 34 | - (void)setDisplayString:(NSString *)displayString; 35 | - (void)scrollPointToCentre:(NSPoint)aPoint; 36 | @end 37 | 38 | @interface NSViewController (private) 39 | - (CGFloat)previewHeight; 40 | - (void)setPreviewHeight:(CGFloat)previewHeight; 41 | @end 42 | 43 | static char *vID = "com.markfromberg.syncedTabs"; 44 | 45 | @implementation MFSyncedTabs { 46 | NSViewController* _editViewController; 47 | BOOL _activeGlyphChanged; 48 | BOOL _activeZoomChanged; 49 | BOOL _activeViewPanChanged; 50 | BOOL _activeMasterIndexChanged; 51 | BOOL _activeToolChanged; 52 | 53 | NSString *_currentGlyphName; 54 | NSRange _currentCaretPosition; 55 | CGFloat _currentZoom; 56 | NSUInteger _currentMasterIndex; 57 | NSUInteger _currentToolIndex; 58 | NSRect _currentViewPan; 59 | } 60 | 61 | - (id)init { 62 | self = [super init]; 63 | if (self) { 64 | // do stuff 65 | } 66 | return self; 67 | } 68 | 69 | - (void)loadPlugin { 70 | // Is called when the plugin is loaded. 71 | } 72 | 73 | - (NSUInteger)interfaceVersion { 74 | // Distinguishes the API verison the plugin was built for. Return 1. 75 | return 1; 76 | } 77 | 78 | - (NSString*)title { 79 | // This is the name as it appears in the menu in combination with 'Show'. 80 | // E.g. 'return @"Nodes";' will make the menu item read "Show Nodes". 81 | return @"Synced Tabs"; 82 | 83 | // or localise it: 84 | // return NSLocalizedStringFromTableInBundle(@"TITLE", nil, [NSBundle bundleForClass:[self class]], @"DESCRIPTION"); 85 | } 86 | 87 | - (void)syncEditViews { 88 | /* 89 | Based on the code from Tosche : `Sync Edit Views.py` @Github 90 | */ 91 | 92 | BOOL doSyncTools = [[NSUserDefaults standardUserDefaults] boolForKey:[NSString stringWithFormat:@"%s.doSyncTools", vID]]; 93 | 94 | @try { 95 | GSFont *sourceFont = [_editViewController representedObject]; 96 | NSUInteger sourceMasterIndex = _editViewController.masterIndex; 97 | 98 | CGFloat sourceScale = _editViewController.scale; 99 | NSRect sourceVisibleRect = [_editViewController.frameView visibleRect]; 100 | NSPoint layerPos = [[_editViewController graphicView] activePosition]; 101 | NSPoint layerCentre = NSMakePoint(NSMidX(sourceVisibleRect) - layerPos.x, NSMidY(sourceVisibleRect) - layerPos.y); 102 | 103 | CGFloat sourcePreviewHeight = [_editViewController previewHeight]; 104 | 105 | NSView *sourceGraphicView = _editViewController.graphicView; 106 | NSRange sourceSelection = [sourceGraphicView selectedRange]; 107 | BOOL doKern = [sourceGraphicView doKerning]; 108 | BOOL doSpace = [sourceGraphicView doSpacing]; 109 | 110 | NSArray *fontDocuments = [NSApp fontDocuments]; 111 | 112 | NSString *displayString = [sourceGraphicView displayString]; 113 | 114 | for (NSDocument *otherDoc in fontDocuments) { 115 | GSFont *otherFont = [otherDoc font]; 116 | 117 | if (otherFont == sourceFont) { 118 | continue; 119 | } 120 | 121 | if (![[otherDoc windowForSheet] isVisible]) { // Only apply to visible Fonts 122 | continue; 123 | } 124 | NSLog(@"__sync %@", otherFont); 125 | 126 | NSUInteger otherFontLastToolIndex = [[otherDoc windowController] selectedToolIndex]; 127 | 128 | NSViewController *otherTab = [[otherDoc windowController] activeEditViewController]; 129 | 130 | @try { 131 | otherTab.masterIndex = sourceMasterIndex; 132 | } @catch (NSException *exception) { 133 | // print traceback.format_exc() 134 | } 135 | NSView *otherView = [otherTab graphicView]; 136 | if (_activeGlyphChanged) { // dont reset the content all the time. 137 | // TODO: fix layer synconisation for views that where nevers synced. 138 | //# verify glyph in font 139 | 140 | // normalizedText, currentLayers = [], [] 141 | // for l in sourceTab.layers: 142 | // @try { 143 | // currentLayers.append(l.parent.name) 144 | // } @catch (NSException *exception) { 145 | // currentLayers.append(newLine) 146 | // for g in currentLayers: # for g in sourceTab.text: 147 | // if g != newLine: 148 | // if g in otherFont.glyphs: 149 | // normalizedText.append(g) 150 | // } else { 151 | // normalizedText.append("space") 152 | // } else { 153 | // normalizedText.append(newLine) 154 | // 155 | // normalizedText = "/" + "/".join([x for x in normalizedText]) 156 | [otherView setDisplayString:displayString]; 157 | } 158 | [otherView setSelectedRange:sourceSelection]; 159 | otherTab.scale = sourceScale; 160 | if ([otherView doKerning] != doKern) { 161 | [otherView setDoKerning:doKern]; 162 | } 163 | if ([otherView doSpacing] != doSpace) { 164 | [otherView setDoSpacing:doSpace]; 165 | } 166 | 167 | // # A) 168 | if (doSyncTools) { 169 | //[[otherDoc windowController] setSelectedToolIndex:<#(NSUInteger)#> = sourceFont.tool; 170 | } 171 | else { 172 | //otherFont.tool = otherFontLastTool; 173 | } 174 | 175 | // // B) **UC** 176 | // if sourceFont.parent.windowController().toolTempSelection(): 177 | // otherFont.tool = 'SelectTool' 178 | // } else { 179 | // otherFont.tool = otherFontLastTool 180 | 181 | 182 | // # C) 183 | // if doSyncTools: 184 | // if sourceFont.parent.windowController().toolTempSelection().title() == "Hand": 185 | // otherFont.tool = "HandTool" 186 | // print "A Hand Tool" 187 | // } else { 188 | // otherFont.tool = sourceFont.tool 189 | // print "A sourceFont Tool" 190 | // } else { 191 | // if sourceFont.parent.windowController().toolTempSelection().title() == "Hand": 192 | // otherFont.tool = "HandTool" 193 | // print "B Hand Tool" 194 | // } else { 195 | // otherFont.tool = otherFontLastTool 196 | // print "B sourceFont Tool" 197 | 198 | if (fabs(otherTab.previewHeight - sourcePreviewHeight)) { 199 | [otherTab setPreviewHeight:sourcePreviewHeight]; 200 | } 201 | 202 | // Step B: Scroll to view if possible 203 | //otherTab.viewPort = sourceVisibleRect 204 | 205 | NSPoint otherLayerPos = [[otherTab graphicView] activePosition]; 206 | NSPoint otherLayerCentre = NSMakePoint(otherLayerPos.x + layerCentre.x, otherLayerPos.y + layerCentre.y); 207 | 208 | [(NSView *)[otherTab frameView] scrollPointToCentre:otherLayerCentre]; 209 | [otherView viewWillDraw]; 210 | } 211 | } 212 | @catch (NSException *exception) { 213 | NSLog(@"exception %@", exception); 214 | } 215 | } 216 | 217 | - (void)observeGlyphChange { 218 | /* 219 | Catch the event: `active glyph was changed in the edit tab`. 220 | Convert to str() !!! otherwise they are pyobj objects. 221 | 222 | Calling the own layer here to make sure it is always the one from the active font. 223 | Otherwise, if passing in the `layer` as argument, the observer will always take the 224 | layer from each font during the loop. Hence it will endlessly loop into a glyphChangeObservation 225 | when a glyph is selected that doesnt appear in the other fonts. 226 | */ 227 | // global currentGlyphName 228 | // global currentCaretPosition 229 | 230 | //ff = Glyphs.font 231 | 232 | GSLayer *layer = [_editViewController activeLayer]; 233 | 234 | @try { 235 | if (!layer) { 236 | if (_currentGlyphName) { 237 | _activeGlyphChanged = YES; 238 | } 239 | _currentGlyphName = nil; 240 | return; 241 | } 242 | NSString *thisGlyphName = layer.parent.name; 243 | if (nilEqual(_currentGlyphName, thisGlyphName)) { 244 | _currentGlyphName = thisGlyphName; 245 | // print "Observe Glyph Change" 246 | _activeGlyphChanged = YES; 247 | } 248 | else { 249 | // ## If same glyph, check if position in tab (Otherwise changing from one /b to another in one tab wont trigger) 250 | // position = layer.parent.parent.currentTab.graphicView().textStorage().selectedRange() # deprecated 251 | NSRange position = [[_editViewController graphicView] selectedRange]; // new 252 | if (_currentCaretPosition.location != position.location || _currentCaretPosition.location != position.location) { 253 | _currentCaretPosition = position; 254 | _activeGlyphChanged = YES; 255 | // print "Observe Glyph Change" 256 | return; 257 | // ## End: optional, but needed for this plugin 258 | } 259 | _activeGlyphChanged = YES; 260 | return; 261 | } 262 | } 263 | @catch (NSException *exception) { 264 | // pass # print traceback.format_exc() 265 | } 266 | } 267 | 268 | - (void)observeZoom { 269 | //global currentZoom 270 | 271 | @try { 272 | CGFloat thisZoom = _editViewController.scale; 273 | if (fabs(_currentZoom - thisZoom) > 0.001) { 274 | _currentZoom = thisZoom; 275 | _activeZoomChanged = YES; 276 | // print "Observe Zoom Change" 277 | return; 278 | } 279 | else { 280 | _activeZoomChanged = NO; 281 | return; 282 | } 283 | } 284 | @catch (NSException *exception) { 285 | // pass # print traceback.format_exc() 286 | } 287 | } 288 | 289 | - (void)observeMasterChange { 290 | //global currentMasterIndex 291 | 292 | @try { 293 | NSUInteger thisMasterIndex = [_editViewController masterIndex]; 294 | if (_currentMasterIndex != thisMasterIndex) { 295 | _currentMasterIndex = thisMasterIndex; 296 | _activeMasterIndexChanged = YES; 297 | // print "Observe Master Change" 298 | return; 299 | } else { 300 | _activeMasterIndexChanged = NO; 301 | return; 302 | } 303 | } @catch (NSException *exception) { 304 | //pass # print traceback.format_exc() 305 | } 306 | } 307 | 308 | - (void)observeToolChange { 309 | // global currentTool 310 | /* 311 | @try { 312 | NSUInteger thisToolIndex = Glyphs.font.tool; 313 | if currentTool != thisTool: 314 | currentTool = thisTool 315 | self.activeToolChanged = True 316 | // print "Observe Tool Change" 317 | return True 318 | } 319 | else { 320 | _activeToolChanged = NO; 321 | return 322 | } @catch (NSException *exception) { 323 | pass # print traceback.format_exc() 324 | } 325 | */ 326 | } 327 | 328 | 329 | //def observeMasterSwitch { 330 | //# Perhaps not nessecary anymore? Seems to update already ... 331 | 332 | - (void)observeViewPanning { 333 | //global currentViewPan 334 | 335 | @try { 336 | // thisViewPan = Glyphs.font.currentTab.graphicView().visibleRect().origin 337 | NSRect thisViewPan = [[_editViewController frameView] visibleRect]; 338 | if (GSCompareRect(_currentViewPan, thisViewPan)) { 339 | _currentViewPan = thisViewPan; 340 | _activeViewPanChanged = YES; 341 | // print "Observe Pan Change" 342 | return; 343 | } else { 344 | _activeViewPanChanged = NO; 345 | return; 346 | } 347 | } @catch (NSException *exception) { 348 | // pass # print traceback.format_exc() 349 | } 350 | } 351 | 352 | - (void)drawForegroundWithOptions:(NSDictionary *)options { 353 | 354 | if (![[[_editViewController view] window] isMainWindow]) { 355 | return; 356 | } 357 | 358 | [self observeGlyphChange]; 359 | [self observeZoom]; 360 | [self observeViewPanning]; 361 | [self observeMasterChange]; 362 | [self observeToolChange]; 363 | 364 | if (_activeGlyphChanged || _activeZoomChanged || _activeViewPanChanged || _activeMasterIndexChanged || _activeToolChanged) { 365 | [self syncEditViews]; 366 | } 367 | 368 | // if (layer and layer.parent.parent == Glyphs.font) { 369 | // self.drawKammerakindRahmen(layer.parent.parent) 370 | // } 371 | } 372 | 373 | - (BOOL)needsExtraMainOutlineDrawingForInactiveLayer:(GSLayer*)Layer { 374 | return YES; 375 | } 376 | 377 | - (NSViewController*)controller { 378 | return _editViewController; 379 | } 380 | 381 | - (void)setController:(NSViewController *)editViewController { 382 | _editViewController = editViewController; 383 | } 384 | @end 385 | -------------------------------------------------------------------------------- /Synced Tabs/Synced Tabs.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 565D9412224BB530006B6F1B /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 565D9411224BB530006B6F1B /* Cocoa.framework */; }; 11 | 565D9415224BB530006B6F1B /* Synced Tabs-Prefix.pch in Resources */ = {isa = PBXBuildFile; fileRef = 565D9414224BB530006B6F1B /* Synced Tabs-Prefix.pch */; }; 12 | 565D9418224BB530006B6F1B /* GlyphsCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 565D9417224BB530006B6F1B /* GlyphsCore.framework */; }; 13 | 565D941B224BB530006B6F1B /* MFSyncedTabs.m in Sources */ = {isa = PBXBuildFile; fileRef = 565D941A224BB530006B6F1B /* MFSyncedTabs.m */; }; 14 | /* End PBXBuildFile section */ 15 | 16 | /* Begin PBXFileReference section */ 17 | 565D940E224BB530006B6F1B /* Synced Tabs.glyphsReporter */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Synced Tabs.glyphsReporter"; sourceTree = BUILT_PRODUCTS_DIR; }; 18 | 565D9411224BB530006B6F1B /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 19 | 565D9414224BB530006B6F1B /* Synced Tabs-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Synced Tabs-Prefix.pch"; sourceTree = ""; }; 20 | 565D9417224BB530006B6F1B /* GlyphsCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GlyphsCore.framework; path = /Applications/Glyphs.app/Contents/Frameworks/GlyphsCore.framework; sourceTree = ""; }; 21 | 565D9419224BB530006B6F1B /* MFSyncedTabs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MFSyncedTabs.h; sourceTree = ""; }; 22 | 565D941A224BB530006B6F1B /* MFSyncedTabs.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MFSyncedTabs.m; sourceTree = ""; }; 23 | 565D941C224BB530006B6F1B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 24 | /* End PBXFileReference section */ 25 | 26 | /* Begin PBXFrameworksBuildPhase section */ 27 | 565D940B224BB530006B6F1B /* Frameworks */ = { 28 | isa = PBXFrameworksBuildPhase; 29 | buildActionMask = 2147483647; 30 | files = ( 31 | 565D9418224BB530006B6F1B /* GlyphsCore.framework in Frameworks */, 32 | 565D9412224BB530006B6F1B /* Cocoa.framework in Frameworks */, 33 | ); 34 | runOnlyForDeploymentPostprocessing = 0; 35 | }; 36 | /* End PBXFrameworksBuildPhase section */ 37 | 38 | /* Begin PBXGroup section */ 39 | 565D9405224BB530006B6F1B = { 40 | isa = PBXGroup; 41 | children = ( 42 | 565D9413224BB530006B6F1B /* Synced Tabs */, 43 | 565D9410224BB530006B6F1B /* Frameworks */, 44 | 565D940F224BB530006B6F1B /* Products */, 45 | ); 46 | sourceTree = ""; 47 | }; 48 | 565D940F224BB530006B6F1B /* Products */ = { 49 | isa = PBXGroup; 50 | children = ( 51 | 565D940E224BB530006B6F1B /* Synced Tabs.glyphsReporter */, 52 | ); 53 | name = Products; 54 | sourceTree = ""; 55 | }; 56 | 565D9410224BB530006B6F1B /* Frameworks */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | 565D9411224BB530006B6F1B /* Cocoa.framework */, 60 | ); 61 | name = Frameworks; 62 | sourceTree = ""; 63 | }; 64 | 565D9413224BB530006B6F1B /* Synced Tabs */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | 565D9414224BB530006B6F1B /* Synced Tabs-Prefix.pch */, 68 | 565D9419224BB530006B6F1B /* MFSyncedTabs.h */, 69 | 565D941A224BB530006B6F1B /* MFSyncedTabs.m */, 70 | 565D941C224BB530006B6F1B /* Info.plist */, 71 | 565D9416224BB530006B6F1B /* Supporting Files */, 72 | ); 73 | path = "Synced Tabs"; 74 | sourceTree = ""; 75 | }; 76 | 565D9416224BB530006B6F1B /* Supporting Files */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | 565D9417224BB530006B6F1B /* GlyphsCore.framework */, 80 | ); 81 | name = "Supporting Files"; 82 | sourceTree = ""; 83 | }; 84 | /* End PBXGroup section */ 85 | 86 | /* Begin PBXNativeTarget section */ 87 | 565D940D224BB530006B6F1B /* Synced Tabs */ = { 88 | isa = PBXNativeTarget; 89 | buildConfigurationList = 565D941F224BB530006B6F1B /* Build configuration list for PBXNativeTarget "Synced Tabs" */; 90 | buildPhases = ( 91 | 565D940A224BB530006B6F1B /* Sources */, 92 | 565D940B224BB530006B6F1B /* Frameworks */, 93 | 565D940C224BB530006B6F1B /* Resources */, 94 | ); 95 | buildRules = ( 96 | ); 97 | dependencies = ( 98 | ); 99 | name = "Synced Tabs"; 100 | productName = "Synced Tabs"; 101 | productReference = 565D940E224BB530006B6F1B /* Synced Tabs.glyphsReporter */; 102 | productType = "com.apple.product-type.bundle"; 103 | }; 104 | /* End PBXNativeTarget section */ 105 | 106 | /* Begin PBXProject section */ 107 | 565D9406224BB530006B6F1B /* Project object */ = { 108 | isa = PBXProject; 109 | attributes = { 110 | LastUpgradeCheck = 1010; 111 | ORGANIZATIONNAME = markfromberg; 112 | TargetAttributes = { 113 | 565D940D224BB530006B6F1B = { 114 | CreatedOnToolsVersion = 10.1; 115 | }; 116 | }; 117 | }; 118 | buildConfigurationList = 565D9409224BB530006B6F1B /* Build configuration list for PBXProject "Synced Tabs" */; 119 | compatibilityVersion = "Xcode 9.3"; 120 | developmentRegion = en; 121 | hasScannedForEncodings = 0; 122 | knownRegions = ( 123 | en, 124 | ); 125 | mainGroup = 565D9405224BB530006B6F1B; 126 | productRefGroup = 565D940F224BB530006B6F1B /* Products */; 127 | projectDirPath = ""; 128 | projectRoot = ""; 129 | targets = ( 130 | 565D940D224BB530006B6F1B /* Synced Tabs */, 131 | ); 132 | }; 133 | /* End PBXProject section */ 134 | 135 | /* Begin PBXResourcesBuildPhase section */ 136 | 565D940C224BB530006B6F1B /* Resources */ = { 137 | isa = PBXResourcesBuildPhase; 138 | buildActionMask = 2147483647; 139 | files = ( 140 | 565D9415224BB530006B6F1B /* Synced Tabs-Prefix.pch in Resources */, 141 | ); 142 | runOnlyForDeploymentPostprocessing = 0; 143 | }; 144 | /* End PBXResourcesBuildPhase section */ 145 | 146 | /* Begin PBXSourcesBuildPhase section */ 147 | 565D940A224BB530006B6F1B /* Sources */ = { 148 | isa = PBXSourcesBuildPhase; 149 | buildActionMask = 2147483647; 150 | files = ( 151 | 565D941B224BB530006B6F1B /* MFSyncedTabs.m in Sources */, 152 | ); 153 | runOnlyForDeploymentPostprocessing = 0; 154 | }; 155 | /* End PBXSourcesBuildPhase section */ 156 | 157 | /* Begin XCBuildConfiguration section */ 158 | 565D941D224BB530006B6F1B /* Debug */ = { 159 | isa = XCBuildConfiguration; 160 | buildSettings = { 161 | ALWAYS_SEARCH_USER_PATHS = NO; 162 | CLANG_ANALYZER_NONNULL = YES; 163 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 164 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 165 | CLANG_CXX_LIBRARY = "libc++"; 166 | CLANG_ENABLE_MODULES = YES; 167 | CLANG_ENABLE_OBJC_ARC = YES; 168 | CLANG_ENABLE_OBJC_WEAK = YES; 169 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 170 | CLANG_WARN_BOOL_CONVERSION = YES; 171 | CLANG_WARN_COMMA = YES; 172 | CLANG_WARN_CONSTANT_CONVERSION = YES; 173 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 174 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 175 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 176 | CLANG_WARN_EMPTY_BODY = YES; 177 | CLANG_WARN_ENUM_CONVERSION = YES; 178 | CLANG_WARN_INFINITE_RECURSION = YES; 179 | CLANG_WARN_INT_CONVERSION = YES; 180 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 181 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 182 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 183 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 184 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 185 | CLANG_WARN_STRICT_PROTOTYPES = YES; 186 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 187 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 188 | CLANG_WARN_UNREACHABLE_CODE = YES; 189 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 190 | CODE_SIGN_IDENTITY = "Mac Developer"; 191 | COPY_PHASE_STRIP = NO; 192 | DEBUG_INFORMATION_FORMAT = dwarf; 193 | ENABLE_STRICT_OBJC_MSGSEND = YES; 194 | ENABLE_TESTABILITY = YES; 195 | GCC_C_LANGUAGE_STANDARD = gnu11; 196 | GCC_DYNAMIC_NO_PIC = NO; 197 | GCC_NO_COMMON_BLOCKS = YES; 198 | GCC_OPTIMIZATION_LEVEL = 0; 199 | GCC_PREPROCESSOR_DEFINITIONS = ( 200 | "DEBUG=1", 201 | "$(inherited)", 202 | ); 203 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 204 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 205 | GCC_WARN_UNDECLARED_SELECTOR = YES; 206 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 207 | GCC_WARN_UNUSED_FUNCTION = YES; 208 | GCC_WARN_UNUSED_VARIABLE = YES; 209 | MACOSX_DEPLOYMENT_TARGET = 10.13; 210 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 211 | MTL_FAST_MATH = YES; 212 | ONLY_ACTIVE_ARCH = YES; 213 | SDKROOT = macosx; 214 | }; 215 | name = Debug; 216 | }; 217 | 565D941E224BB530006B6F1B /* Release */ = { 218 | isa = XCBuildConfiguration; 219 | buildSettings = { 220 | ALWAYS_SEARCH_USER_PATHS = NO; 221 | CLANG_ANALYZER_NONNULL = YES; 222 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 223 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 224 | CLANG_CXX_LIBRARY = "libc++"; 225 | CLANG_ENABLE_MODULES = YES; 226 | CLANG_ENABLE_OBJC_ARC = YES; 227 | CLANG_ENABLE_OBJC_WEAK = YES; 228 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 229 | CLANG_WARN_BOOL_CONVERSION = YES; 230 | CLANG_WARN_COMMA = YES; 231 | CLANG_WARN_CONSTANT_CONVERSION = YES; 232 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 233 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 234 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 235 | CLANG_WARN_EMPTY_BODY = YES; 236 | CLANG_WARN_ENUM_CONVERSION = YES; 237 | CLANG_WARN_INFINITE_RECURSION = YES; 238 | CLANG_WARN_INT_CONVERSION = YES; 239 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 240 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 241 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 242 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 243 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 244 | CLANG_WARN_STRICT_PROTOTYPES = YES; 245 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 246 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 247 | CLANG_WARN_UNREACHABLE_CODE = YES; 248 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 249 | CODE_SIGN_IDENTITY = "Mac Developer"; 250 | COPY_PHASE_STRIP = NO; 251 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 252 | ENABLE_NS_ASSERTIONS = NO; 253 | ENABLE_STRICT_OBJC_MSGSEND = YES; 254 | GCC_C_LANGUAGE_STANDARD = gnu11; 255 | GCC_NO_COMMON_BLOCKS = YES; 256 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 257 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 258 | GCC_WARN_UNDECLARED_SELECTOR = YES; 259 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 260 | GCC_WARN_UNUSED_FUNCTION = YES; 261 | GCC_WARN_UNUSED_VARIABLE = YES; 262 | MACOSX_DEPLOYMENT_TARGET = 10.13; 263 | MTL_ENABLE_DEBUG_INFO = NO; 264 | MTL_FAST_MATH = YES; 265 | SDKROOT = macosx; 266 | }; 267 | name = Release; 268 | }; 269 | 565D9420224BB530006B6F1B /* Debug */ = { 270 | isa = XCBuildConfiguration; 271 | buildSettings = { 272 | CODE_SIGN_IDENTITY = "Developer ID Application"; 273 | CODE_SIGN_STYLE = Manual; 274 | COMBINE_HIDPI_IMAGES = YES; 275 | DEPLOYMENT_LOCATION = YES; 276 | DEVELOPMENT_TEAM = X2L8375ZQ7; 277 | DSTROOT = "$(USER_LIBRARY_DIR)/Application Support/Glyphs/Plugins"; 278 | FRAMEWORK_SEARCH_PATHS = "$(SYSTEM_APPS_DIR)/Glyphs.app/Contents/Frameworks"; 279 | GCC_PREFIX_HEADER = "Synced Tabs/Synced Tabs-Prefix.pch"; 280 | INFOPLIST_FILE = "Synced Tabs/Info.plist"; 281 | INSTALL_PATH = /; 282 | MACOSX_DEPLOYMENT_TARGET = 10.9; 283 | PRODUCT_BUNDLE_IDENTIFIER = com.markfromberg.SyncedTabs; 284 | PRODUCT_NAME = "$(TARGET_NAME)"; 285 | PROVISIONING_PROFILE_SPECIFIER = ""; 286 | WRAPPER_EXTENSION = glyphsReporter; 287 | }; 288 | name = Debug; 289 | }; 290 | 565D9421224BB530006B6F1B /* Release */ = { 291 | isa = XCBuildConfiguration; 292 | buildSettings = { 293 | CODE_SIGN_IDENTITY = "Developer ID Application"; 294 | CODE_SIGN_STYLE = Manual; 295 | COMBINE_HIDPI_IMAGES = YES; 296 | DEVELOPMENT_TEAM = X2L8375ZQ7; 297 | FRAMEWORK_SEARCH_PATHS = "$(SYSTEM_APPS_DIR)/Glyphs.app/Contents/Frameworks"; 298 | GCC_PREFIX_HEADER = "Synced Tabs/Synced Tabs-Prefix.pch"; 299 | INFOPLIST_FILE = "Synced Tabs/Info.plist"; 300 | INSTALL_PATH = /; 301 | MACOSX_DEPLOYMENT_TARGET = 10.9; 302 | PRODUCT_BUNDLE_IDENTIFIER = com.markfromberg.SyncedTabs; 303 | PRODUCT_NAME = "$(TARGET_NAME)"; 304 | PROVISIONING_PROFILE_SPECIFIER = ""; 305 | WRAPPER_EXTENSION = glyphsReporter; 306 | }; 307 | name = Release; 308 | }; 309 | /* End XCBuildConfiguration section */ 310 | 311 | /* Begin XCConfigurationList section */ 312 | 565D9409224BB530006B6F1B /* Build configuration list for PBXProject "Synced Tabs" */ = { 313 | isa = XCConfigurationList; 314 | buildConfigurations = ( 315 | 565D941D224BB530006B6F1B /* Debug */, 316 | 565D941E224BB530006B6F1B /* Release */, 317 | ); 318 | defaultConfigurationIsVisible = 0; 319 | defaultConfigurationName = Release; 320 | }; 321 | 565D941F224BB530006B6F1B /* Build configuration list for PBXNativeTarget "Synced Tabs" */ = { 322 | isa = XCConfigurationList; 323 | buildConfigurations = ( 324 | 565D9420224BB530006B6F1B /* Debug */, 325 | 565D9421224BB530006B6F1B /* Release */, 326 | ); 327 | defaultConfigurationIsVisible = 0; 328 | defaultConfigurationName = Release; 329 | }; 330 | /* End XCConfigurationList section */ 331 | }; 332 | rootObject = 565D9406224BB530006B6F1B /* Project object */; 333 | } 334 | --------------------------------------------------------------------------------