Revision: 7785
http://skim-app.svn.sourceforge.net/skim-app/?rev=7785&view=rev
Author: hofman
Date: 2012-11-05 10:40:58 +0000 (Mon, 05 Nov 2012)
Log Message:
-----------
revert previous changes because these singletons don't need to be thread safe
Modified Paths:
--------------
trunk/SKDownloadController.m
trunk/SKInfoWindowController.m
trunk/SKLineInspector.m
trunk/SKNotesPanelController.m
trunk/SKPDFSynchronizer.h
trunk/SKPDFSynchronizer.m
trunk/SKReleaseNotesController.m
Modified: trunk/SKDownloadController.m
===================================================================
--- trunk/SKDownloadController.m 2012-11-05 01:01:52 UTC (rev 7784)
+++ trunk/SKDownloadController.m 2012-11-05 10:40:58 UTC (rev 7785)
@@ -74,16 +74,16 @@
@synthesize arrayController, tableView, clearButton, prefButton;
+static SKDownloadController *sharedDownloadController = nil;
+
+ (id)sharedDownloadController {
- static SKDownloadController *sharedDownloadController = nil;
- static dispatch_once_t predicate;
- dispatch_once(&predicate, ^{
+ if (sharedDownloadController == nil)
sharedDownloadController = [[self alloc] init];
- });
return sharedDownloadController;
}
- (id)init {
+ if (sharedDownloadController) NSLog(@"Attempt to allocate second instance
of %@", [self class]);
self = [super initWithWindowNibName:@"DownloadsWindow"];
if (self) {
downloads = [[NSMutableArray alloc] init];
Modified: trunk/SKInfoWindowController.m
===================================================================
--- trunk/SKInfoWindowController.m 2012-11-05 01:01:52 UTC (rev 7784)
+++ trunk/SKInfoWindowController.m 2012-11-05 10:40:58 UTC (rev 7785)
@@ -84,17 +84,16 @@
[transformer release];
}
+static SKInfoWindowController *sharedInstance = nil;
+ (id)sharedInstance {
- static SKInfoWindowController *sharedInstance = nil;
- static dispatch_once_t predicate;
- dispatch_once(&predicate, ^{
+ if (sharedInstance == nil)
sharedInstance = [[self alloc] init];
- });
return sharedInstance;
}
- (id)init {
+ if (sharedInstance) NSLog(@"Attempt to allocate second instance of %@",
[self class]);
self = [super initWithWindowNibName:@"InfoWindow"];
if (self){
info = nil;
Modified: trunk/SKLineInspector.m
===================================================================
--- trunk/SKLineInspector.m 2012-11-05 01:01:52 UTC (rev 7784)
+++ trunk/SKLineInspector.m 2012-11-05 10:40:58 UTC (rev 7785)
@@ -60,10 +60,8 @@
static SKLineInspector *sharedLineInspector = nil;
+ (id)sharedLineInspector {
- static dispatch_once_t predicate;
- dispatch_once(&predicate, ^{
+ if (sharedLineInspector == nil)
sharedLineInspector = [[self alloc] init];
- });
return sharedLineInspector;
}
@@ -72,6 +70,7 @@
}
- (id)init {
+ if (sharedLineInspector) NSLog(@"Attempt to allocate second instance of
%@", [self class]);
self = [super initWithWindowNibName:@"LineInspector"];
if (self) {
style = kPDFBorderStyleSolid;
Modified: trunk/SKNotesPanelController.m
===================================================================
--- trunk/SKNotesPanelController.m 2012-11-05 01:01:52 UTC (rev 7784)
+++ trunk/SKNotesPanelController.m 2012-11-05 10:40:58 UTC (rev 7785)
@@ -47,10 +47,8 @@
static SKNotesPanelController *sharedController = nil;
+ (id)sharedController {
- static dispatch_once_t predicate;
- dispatch_once(&predicate, ^{
+ if (sharedController == nil)
sharedController = [[self alloc] init];
- });
return sharedController;
}
Modified: trunk/SKPDFSynchronizer.h
===================================================================
--- trunk/SKPDFSynchronizer.h 2012-11-05 01:01:52 UTC (rev 7784)
+++ trunk/SKPDFSynchronizer.h 2012-11-05 10:40:58 UTC (rev 7785)
@@ -37,6 +37,7 @@
*/
#import <Cocoa/Cocoa.h>
+#import "synctex_parser.h"
enum {
SKPDFSynchronizerDefaultOptions = 0,
@@ -49,13 +50,27 @@
@interface SKPDFSynchronizer : NSObject {
id <SKPDFSynchronizerDelegate> delegate;
- id server;
- id serverProxy;
- NSConnection *connection;
+ dispatch_queue_t queue;
+
+ NSString *fileName;
+ NSString *syncFileName;
+ NSDate *lastModDate;
+ BOOL isPdfsync;
+
+ NSFileManager *fileManager;
+
+ NSMutableArray *pages;
+ NSMapTable *lines;
+
+ NSMapTable *filenames;
+ synctex_scanner_t scanner;
+
+ volatile int32_t shouldKeepRunning;
}
@property (nonatomic, assign) id <SKPDFSynchronizerDelegate> delegate;
@property (copy) NSString *fileName;
+@property BOOL shouldKeepRunning;
- (void)findFileAndLineForLocation:(NSPoint)point inRect:(NSRect)rect
pageBounds:(NSRect)bounds atPageIndex:(NSUInteger)pageIndex;
- (void)findPageAndLocationForLine:(NSInteger)line inFile:(NSString *)file
options:(NSInteger)options;
Modified: trunk/SKPDFSynchronizer.m
===================================================================
--- trunk/SKPDFSynchronizer.m 2012-11-05 01:01:52 UTC (rev 7784)
+++ trunk/SKPDFSynchronizer.m 2012-11-05 10:40:58 UTC (rev 7785)
@@ -37,95 +37,576 @@
*/
#import "SKPDFSynchronizer.h"
-#import "SKPDFSynchronizerServer.h"
+#import <libkern/OSAtomic.h>
+#import "SKPDFSyncRecord.h"
+#import "NSCharacterSet_SKExtensions.h"
+#import "NSScanner_SKExtensions.h"
+#import <CoreFoundation/CoreFoundation.h>
+#import "NSFileManager_SKExtensions.h"
+#import "NSMapTable_SKExtensions.h"
+#define PDFSYNC_TO_PDF(coord) ((CGFloat)coord / 65536.0)
+// Offset of coordinates in PDFKit and what pdfsync tells us. Don't know what
they are; is this implementation dependent?
+static NSPoint pdfOffset = {0.0, 0.0};
+
+#define SKPDFSynchronizerPdfsyncExtension @"pdfsync"
+static NSArray *SKPDFSynchronizerTexExtensions = nil;
+
+#pragma mark -
+
@implementation SKPDFSynchronizer
@synthesize delegate;
@dynamic fileName;
++ (void)initialize {
+ SKINITIALIZE;
+ SKPDFSynchronizerTexExtensions = [[NSArray alloc] initWithObjects:@"tex",
@"ltx", @"latex", @"ctx", @"lyx", nil];
+}
+
- (id)init {
self = [super init];
if (self) {
- NSPort *port1 = [NSPort port];
- NSPort *port2 = [NSPort port];
+ queue = NULL;
- connection = [[NSConnection alloc] initWithReceivePort:port1
sendPort:port2];
- [connection setRootObject:self];
- [connection enableMultipleThreads];
+ fileName = nil;
+ syncFileName = nil;
+ lastModDate = nil;
+ isPdfsync = YES;
- server = [[SKPDFSynchronizerServer alloc] init];
- // this will be set when the background thread sets up
- serverProxy = nil;
+ pages = nil;
+ lines = nil;
- // let the server connect back with the ports in opposite order
- [server startDOServerForPorts:[NSArray arrayWithObjects:port2, port1,
nil]];
+ filenames = nil;
+ scanner = NULL;
+
+ shouldKeepRunning = 1;
+
+ // it is not safe to use the defaultManager on background threads
+ fileManager = [[NSFileManager alloc] init];
}
return self;
}
- (void)dealloc {
- SKDESTROY(server);
+ if (queue) dispatch_release(queue);
+ queue = NULL;
+ SKDESTROY(fileManager);
+ SKDESTROY(pages);
+ SKDESTROY(lines);
+ SKDESTROY(filenames);
+ SKDESTROY(fileName);
+ SKDESTROY(syncFileName);
+ SKDESTROY(lastModDate);
+ if (scanner) synctex_scanner_free(scanner);
+ scanner = NULL;
[super dealloc];
}
-#pragma mark DO Client
-
-#pragma mark | API
-
- (void)terminate {
- // tell the server thread to stop running, this is also necessary to
tickle the server thread so the runloop can finish
- [serverProxy stopRunning];
+ // make sure we're not calling our delegate
+ delegate = nil;
// set the stop flag immediately, so any running task may stop in its
tracks
- [server setShouldKeepRunning:NO];
-
- // clean up the connection in the main thread; don't invalidate the ports,
since they're still in use
- [connection setRootObject:nil];
- [connection invalidate];
- SKDESTROY(connection);
- SKDESTROY(serverProxy);
+ [self setShouldKeepRunning:NO];
}
-#pragma mark | Client protocol
+#pragma mark Thread safe accessors
-- (void)setServerProxy:(byref id)anObject {
- [anObject setProtocolForProxy:@protocol(SKPDFSynchronizerServer)];
- serverProxy = [anObject retain];
+- (BOOL)shouldKeepRunning {
+ OSMemoryBarrier();
+ return shouldKeepRunning == 1;
}
-#pragma mark Finding
+- (void)setShouldKeepRunning:(BOOL)flag {
+ int32_t old = flag ? 0 : 1, new = flag ? 1 : 0;
+ OSAtomicCompareAndSwap32Barrier(old, new, (int32_t *)&shouldKeepRunning);
+}
-#pragma mark | Accessors
-
- (NSString *)fileName {
- return [server fileName];
+ NSString *file = nil;
+ @synchronized(self) {
+ file = [[fileName retain] autorelease];
+ }
+ return file;
}
- (void)setFileName:(NSString *)newFileName {
- [server setFileName:newFileName];
+ // we compare filenames in canonical form throughout, so we need to make
sure fileName also is in canonical form
+ newFileName = [[newFileName stringByResolvingSymlinksInPath]
stringByStandardizingPath];
+ @synchronized(self) {
+ if (fileName != newFileName) {
+ if ([fileName isEqualToString:newFileName] == NO) {
+ SKDESTROY(syncFileName);
+ SKDESTROY(lastModDate);
+ }
+ [fileName release];
+ fileName = [newFileName retain];
+ }
+ }
}
-#pragma mark | API
+- (NSString *)syncFileName {
+ NSString *file = nil;
+ @synchronized(self) {
+ file = [[syncFileName retain] autorelease];
+ }
+ return file;
+}
-- (void)findFileAndLineForLocation:(NSPoint)point inRect:(NSRect)rect
pageBounds:(NSRect)bounds atPageIndex:(NSUInteger)pageIndex {
- [serverProxy findFileAndLineForLocation:point inRect:rect
pageBounds:bounds atPageIndex:pageIndex];
+// this should only be used from the server thread
+- (void)setSyncFileName:(NSString *)newSyncFileName {
+ @synchronized(self) {
+ if (syncFileName != newSyncFileName) {
+ [syncFileName release];
+ syncFileName = [newSyncFileName retain];
+ }
+ [lastModDate release];
+ lastModDate = [(syncFileName ? [[fileManager
attributesOfItemAtPath:syncFileName error:NULL] fileModificationDate] : nil)
retain];
+ }
}
-- (void)findPageAndLocationForLine:(NSInteger)line inFile:(NSString *)file
options:(NSInteger)options {
- [serverProxy findPageAndLocationForLine:line inFile:file options:options];
+- (NSDate *)lastModDate {
+ NSDate *date = nil;
+ @synchronized(self) {
+ date = [[lastModDate retain] autorelease];
+ }
+ return date;
}
-#pragma mark | Client protocol
+#pragma mark Support
-- (oneway void)foundLine:(NSInteger)line inFile:(bycopy NSString *)file {
- if ([server shouldKeepRunning])
- [delegate synchronizer:self foundLine:line inFile:file];
+- (NSString *)sourceFileForFileName:(NSString *)file isTeX:(BOOL)isTeX
removeQuotes:(BOOL)removeQuotes {
+ if (removeQuotes && [file length] > 2 && [file characterAtIndex:0] == '"'
&& [file characterAtIndex:[file length] - 1] == '"')
+ file = [file substringWithRange:NSMakeRange(1, [file length] - 2)];
+ if ([file isAbsolutePath] == NO)
+ file = [[[self fileName] stringByDeletingLastPathComponent]
stringByAppendingPathComponent:file];
+ if (isTeX && [fileManager fileExistsAtPath:file] == NO &&
[SKPDFSynchronizerTexExtensions containsObject:[[file pathExtension]
lowercaseString]] == NO) {
+ for (NSString *extension in SKPDFSynchronizerTexExtensions) {
+ NSString *tryFile = [file
stringByAppendingPathExtension:extension];
+ if ([fileManager fileExistsAtPath:tryFile]) {
+ file = tryFile;
+ break;
+ }
+ }
+ }
+ // the docs say -stringByStandardizingPath uses
-stringByResolvingSymlinksInPath, but it doesn't
+ return [[file stringByResolvingSymlinksInPath] stringByStandardizingPath];
}
-- (oneway void)foundLocation:(NSPoint)point atPageIndex:(NSUInteger)pageIndex
options:(NSInteger)options {
- if ([server shouldKeepRunning])
- [delegate synchronizer:self foundLocation:point atPageIndex:pageIndex
options:options];
+- (NSString *)sourceFileForFileSystemRepresentation:(const char *)fileRep
isTeX:(BOOL)isTeX {
+ NSString *file = (NSString
*)CFStringCreateWithFileSystemRepresentation(NULL, fileRep);
+ return [self sourceFileForFileName:[file autorelease] isTeX:isTeX
removeQuotes:NO];
}
+#pragma mark PDFSync
+
+- (BOOL)loadPdfsyncFile:(NSString *)theFileName {
+
+ if (pages)
+ [pages removeAllObjects];
+ else
+ pages = [[NSMutableArray alloc] init];
+ if (lines)
+ [lines removeAllObjects];
+ else
+ lines = [[NSMapTable alloc] initForCaseInsensitiveStringKeys];
+
+ [self setSyncFileName:theFileName];
+ isPdfsync = YES;
+
+ NSString *pdfsyncString = [NSString stringWithContentsOfFile:theFileName
encoding:NSUTF8StringEncoding error:NULL];
+ BOOL rv = NO;
+
+ if ([pdfsyncString length]) {
+
+ SKPDFSyncRecords *records = [[SKPDFSyncRecords alloc] init];
+ NSMutableArray *files = [[NSMutableArray alloc] init];
+ NSString *file;
+ NSInteger recordIndex, line, pageIndex;
+ double x, y;
+ SKPDFSyncRecord *record;
+ NSMutableArray *array;
+ unichar ch;
+ NSScanner *sc = [[NSScanner alloc] initWithString:pdfsyncString];
+ NSCharacterSet *newlines = [NSCharacterSet newlineCharacterSet];
+
+ [sc setCharactersToBeSkipped:[NSCharacterSet whitespaceCharacterSet]];
+
+ if ([sc scanUpToCharactersFromSet:newlines intoString:&file] &&
+ [sc scanCharactersFromSet:newlines intoString:NULL]) {
+
+ file = [self sourceFileForFileName:file isTeX:YES
removeQuotes:YES];
+ [files addObject:file];
+
+ array = [[NSMutableArray alloc] init];
+ [lines setObject:array forKey:file];
+ [array release];
+
+ // we ignore the version
+ if ([sc scanString:@"version" intoString:NULL] && [sc
scanInteger:NULL]) {
+
+ [sc scanCharactersFromSet:newlines intoString:NULL];
+
+ while ([self shouldKeepRunning] && [sc scanCharacter:&ch]) {
+
+ switch (ch) {
+ case 'l':
+ if ([sc scanInteger:&recordIndex] && [sc
scanInteger:&line]) {
+ // we ignore the column
+ [sc scanInteger:NULL];
+ record = [records recordForIndex:recordIndex];
+ [record setFile:file];
+ [record setLine:line];
+ [[lines objectForKey:file] addObject:record];
+ }
+ break;
+ case 'p':
+ // we ignore * and + modifiers
+ if ([sc scanString:@"*" intoString:NULL] == NO)
+ [sc scanString:@"+" intoString:NULL];
+ if ([sc scanInteger:&recordIndex] && [sc
scanDouble:&x] && [sc scanDouble:&y]) {
+ record = [records recordForIndex:recordIndex];
+ [record setPageIndex:[pages count] - 1];
+ [record setPoint:NSMakePoint(PDFSYNC_TO_PDF(x)
+ pdfOffset.x, PDFSYNC_TO_PDF(y) + pdfOffset.y)];
+ [[pages lastObject] addObject:record];
+ }
+ break;
+ case 's':
+ // start of a new page, the scanned integer should
always equal [pages count]+1
+ if ([sc scanInteger:&pageIndex] == NO) pageIndex =
[pages count] + 1;
+ while (pageIndex > (NSInteger)[pages count]) {
+ array = [[NSMutableArray alloc] init];
+ [pages addObject:array];
+ [array release];
+ }
+ break;
+ case '(':
+ // start of a new source file
+ if ([sc scanUpToCharactersFromSet:newlines
intoString:&file]) {
+ file = [self sourceFileForFileName:file
isTeX:YES removeQuotes:YES];
+ [files addObject:file];
+ if ([lines objectForKey:file] == nil) {
+ array = [[NSMutableArray alloc] init];
+ [lines setObject:array forKey:file];
+ [array release];
+ }
+ }
+ break;
+ case ')':
+ // closing of a source file
+ if ([files count]) {
+ [files removeLastObject];
+ file = [files lastObject];
+ }
+ break;
+ default:
+ // shouldn't reach
+ break;
+ }
+
+ [sc scanUpToCharactersFromSet:newlines intoString:NULL];
+ [sc scanCharactersFromSet:newlines intoString:NULL];
+ }
+
+ NSSortDescriptor *lineSortDescriptor = [[[NSSortDescriptor
alloc] initWithKey:@"line" ascending:YES] autorelease];
+ NSSortDescriptor *xSortDescriptor = [[[NSSortDescriptor alloc]
initWithKey:@"x" ascending:YES] autorelease];
+ NSSortDescriptor *ySortDescriptor = [[[NSSortDescriptor alloc]
initWithKey:@"y" ascending:NO] autorelease];
+ NSArray *lineSortDescriptors = [NSArray
arrayWithObjects:lineSortDescriptor, nil];
+
+ for (array in [lines objectEnumerator])
+ [array sortUsingDescriptors:lineSortDescriptors];
+ [pages
makeObjectsPerformSelector:@selector(sortUsingDescriptors:)
+ withObject:[NSArray
arrayWithObjects:ySortDescriptor, xSortDescriptor, nil]];
+
+ rv = [self shouldKeepRunning];
+ }
+ }
+
+ [records release];
+ [files release];
+ [sc release];
+ }
+
+ return rv;
+}
+
+- (BOOL)pdfsyncFindFileLine:(NSInteger *)linePtr file:(NSString **)filePtr
forLocation:(NSPoint)point inRect:(NSRect)rect pageBounds:(NSRect)bounds
atPageIndex:(NSUInteger)pageIndex {
+ BOOL rv = NO;
+ if (pageIndex < [pages count]) {
+
+ SKPDFSyncRecord *record = nil;
+ SKPDFSyncRecord *beforeRecord = nil;
+ SKPDFSyncRecord *afterRecord = nil;
+ NSMutableDictionary *atRecords = [NSMutableDictionary dictionary];
+
+ for (record in [pages objectAtIndex:pageIndex]) {
+ if ([record line] == 0)
+ continue;
+ NSPoint p = [record point];
+ if (p.y > NSMaxY(rect)) {
+ beforeRecord = record;
+ } else if (p.y < NSMinY(rect)) {
+ afterRecord = record;
+ break;
+ } else if (p.x < NSMinX(rect)) {
+ beforeRecord = record;
+ } else if (p.x > NSMaxX(rect)) {
+ afterRecord = record;
+ break;
+ } else {
+ [atRecords setObject:record forKey:[NSNumber
numberWithDouble:fabs(p.x - point.x)]];
+ }
+ }
+
+ record = nil;
+ if ([atRecords count]) {
+ NSNumber *nearest = [[[atRecords allKeys]
sortedArrayUsingSelector:@selector(compare:)] objectAtIndex:0];
+ record = [atRecords objectForKey:nearest];
+ } else if (beforeRecord && afterRecord) {
+ NSPoint beforePoint = [beforeRecord point];
+ NSPoint afterPoint = [afterRecord point];
+ if (beforePoint.y - point.y < point.y - afterPoint.y)
+ record = beforeRecord;
+ else if (beforePoint.y - point.y > point.y - afterPoint.y)
+ record = afterRecord;
+ else if (beforePoint.x - point.x < point.x - afterPoint.x)
+ record = beforeRecord;
+ else if (beforePoint.x - point.x > point.x - afterPoint.x)
+ record = afterRecord;
+ else
+ record = beforeRecord;
+ } else if (beforeRecord) {
+ record = beforeRecord;
+ } else if (afterRecord) {
+ record = afterRecord;
+ }
+
+ if (record) {
+ *linePtr = [record line];
+ *filePtr = [record file];
+ rv = YES;
+ }
+ }
+ if (rv == NO)
+ NSLog(@"PDFSync was unable to find file and line.");
+ return rv;
+}
+
+- (BOOL)pdfsyncFindPage:(NSUInteger *)pageIndexPtr location:(NSPoint
*)pointPtr forLine:(NSInteger)line inFile:(NSString *)file {
+ BOOL rv = NO;
+ NSArray *theLines = [lines objectForKey:file];
+ if (theLines) {
+
+ SKPDFSyncRecord *record = nil;
+ SKPDFSyncRecord *beforeRecord = nil;
+ SKPDFSyncRecord *afterRecord = nil;
+ SKPDFSyncRecord *atRecord = nil;
+
+ for (record in theLines) {
+ if ([record pageIndex] == NSNotFound)
+ continue;
+ NSInteger l = [record line];
+ if (l < line) {
+ beforeRecord = record;
+ } else if (l > line) {
+ afterRecord = record;
+ break;
+ } else {
+ atRecord = record;
+ break;
+ }
+ }
+
+ if (atRecord) {
+ record = atRecord;
+ } else if (beforeRecord && afterRecord) {
+ NSInteger beforeLine = [beforeRecord line];
+ NSInteger afterLine = [afterRecord line];
+ if (beforeLine - line > line - afterLine)
+ record = afterRecord;
+ else
+ record = beforeRecord;
+ } else if (beforeRecord) {
+ record = beforeRecord;
+ } else if (afterRecord) {
+ record = afterRecord;
+ }
+
+ if (record) {
+ *pageIndexPtr = [record pageIndex];
+ *pointPtr = [record point];
+ rv = YES;
+ }
+ }
+ if (rv == NO)
+ NSLog(@"PDFSync was unable to find location and page.");
+ return rv;
+}
+
+#pragma mark SyncTeX
+
+- (BOOL)loadSynctexFileForFile:(NSString *)theFileName {
+ BOOL rv = NO;
+ if (scanner)
+ synctex_scanner_free(scanner);
+ scanner = synctex_scanner_new_with_output_file([theFileName
fileSystemRepresentation], NULL, 1);
+ if (scanner) {
+ [self setSyncFileName:[self
sourceFileForFileSystemRepresentation:synctex_scanner_get_synctex(scanner)
isTeX:NO]];
+ if (filenames)
+ [filenames removeAllObjects];
+ else
+ filenames = [[NSMapTable alloc] initForCaseInsensitiveStringKeys];
+ const char *fileRep;
+ NSString *filename;
+ synctex_node_t node = synctex_scanner_input(scanner);
+ do {
+ if ((fileRep = synctex_scanner_get_name(scanner,
synctex_node_tag(node)))) {
+ filename = (NSString
*)CFStringCreateWithFileSystemRepresentation(NULL, fileRep);
+ [filenames setObject:filename forKey:[self
sourceFileForFileName:filename isTeX:YES removeQuotes:NO]];
+ [filename release];
+ }
+ } while (node = synctex_node_next(node));
+ isPdfsync = NO;
+ rv = [self shouldKeepRunning];
+ }
+ return rv;
+}
+
+- (BOOL)synctexFindFileLine:(NSInteger *)linePtr file:(NSString **)filePtr
forLocation:(NSPoint)point inRect:(NSRect)rect pageBounds:(NSRect)bounds
atPageIndex:(NSUInteger)pageIndex {
+ BOOL rv = NO;
+ if (synctex_edit_query(scanner, (int)pageIndex + 1, point.x,
NSMaxY(bounds) - point.y) > 0) {
+ synctex_node_t node;
+ const char *file;
+ while (rv == NO && (node = synctex_next_result(scanner))) {
+ if ((file = synctex_scanner_get_name(scanner,
synctex_node_tag(node)))) {
+ *linePtr = MAX(synctex_node_line(node), 1) - 1;
+ *filePtr = [self sourceFileForFileSystemRepresentation:file
isTeX:YES];
+ rv = YES;
+ }
+ }
+ }
+ if (rv == NO)
+ NSLog(@"SyncTeX was unable to find file and line.");
+ return rv;
+}
+
+- (BOOL)synctexFindPage:(NSUInteger *)pageIndexPtr location:(NSPoint
*)pointPtr forLine:(NSInteger)line inFile:(NSString *)file {
+ BOOL rv = NO;
+ NSString *filename = [filenames objectForKey:file] ?: [filenames
objectForKey:[[file stringByResolvingSymlinksInPath]
stringByStandardizingPath]];
+ if (filename == nil) {
+ for (NSString *fn in filenames) {
+ if ([[fn lastPathComponent] caseInsensitiveCompare:[file
lastPathComponent]] == NSOrderedSame) {
+ filename = [filenames objectForKey:file];
+ break;
+ }
+ }
+ if (filename == nil)
+ filename = [file lastPathComponent];
+ }
+ if (synctex_display_query(scanner, [filename fileSystemRepresentation],
(int)line + 1, 0) > 0) {
+ synctex_node_t node = synctex_next_result(scanner);
+ if (node) {
+ NSUInteger page = synctex_node_page(node);
+ *pageIndexPtr = MAX(page, 1u) - 1;
+ *pointPtr = NSMakePoint(synctex_node_visible_h(node),
synctex_node_visible_v(node));
+ rv = YES;
+ }
+ }
+ if (rv == NO)
+ NSLog(@"SyncTeX was unable to find location and page.");
+ return rv;
+}
+
+#pragma mark Generic
+
+- (BOOL)loadSyncFileIfNeeded {
+ NSString *theFileName = [self fileName];
+ BOOL rv = NO;
+
+ if (theFileName) {
+ NSString *theSyncFileName = [self syncFileName];
+
+ if (theSyncFileName && [fileManager fileExistsAtPath:theSyncFileName])
{
+ NSDate *modDate = [[fileManager attributesOfItemAtPath:theFileName
error:NULL] fileModificationDate];
+ NSDate *currentModDate = [self lastModDate];
+
+ if (currentModDate && [modDate compare:currentModDate] !=
NSOrderedDescending)
+ rv = YES;
+ else if (isPdfsync)
+ rv = [self loadPdfsyncFile:theSyncFileName];
+ else
+ rv = [self loadSynctexFileForFile:theFileName];
+ } else {
+ rv = [self loadSynctexFileForFile:theFileName];
+ if (rv == NO) {
+ theSyncFileName = [[theFileName stringByDeletingPathExtension]
stringByAppendingPathExtension:SKPDFSynchronizerPdfsyncExtension];
+ if ([fileManager fileExistsAtPath:theSyncFileName])
+ rv = [self loadPdfsyncFile:theSyncFileName];
+ }
+ }
+ }
+ if (rv == NO)
+ NSLog(@"Unable to find or load synctex or pdfsync file.");
+ return rv;
+}
+
+#pragma mark Queue
+
+- (dispatch_queue_t)queue {
+ if (queue == NULL)
+ queue =
dispatch_queue_create("net.sourceforge.skim-app.queue.SKPDFSynchronizer", NULL);
+ return queue;
+}
+
+#pragma mark Finding API
+
+- (void)findFileAndLineForLocation:(NSPoint)point inRect:(NSRect)rect
pageBounds:(NSRect)bounds atPageIndex:(NSUInteger)pageIndex {
+ dispatch_async([self queue], ^{
+ if ([self shouldKeepRunning] && [self loadSyncFileIfNeeded]) {
+ NSInteger foundLine = 0;
+ NSString *foundFile = nil;
+ BOOL success = NO;
+
+ if (isPdfsync)
+ success = [self pdfsyncFindFileLine:&foundLine file:&foundFile
forLocation:point inRect:rect pageBounds:bounds atPageIndex:pageIndex];
+ else
+ success = [self synctexFindFileLine:&foundLine file:&foundFile
forLocation:point inRect:rect pageBounds:bounds atPageIndex:pageIndex];
+
+ if (success && [self shouldKeepRunning]) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [delegate synchronizer:self foundLine:foundLine
inFile:foundFile];
+ });
+ }
+ }
+ });
+}
+
+- (void)findPageAndLocationForLine:(NSInteger)line inFile:(NSString *)file
options:(NSInteger)options {
+ dispatch_async([self queue], ^{
+ if (file && [self shouldKeepRunning] && [self loadSyncFileIfNeeded]) {
+ NSUInteger foundPageIndex = NSNotFound;
+ NSPoint foundPoint = NSZeroPoint;
+ NSInteger foundOptions = options;
+ BOOL success = NO;
+ NSString *fixedFile = [self sourceFileForFileName:file isTeX:YES
removeQuotes:NO];
+
+ if (isPdfsync)
+ success = [self pdfsyncFindPage:&foundPageIndex
location:&foundPoint forLine:line inFile:fixedFile];
+ else
+ success = [self synctexFindPage:&foundPageIndex
location:&foundPoint forLine:line inFile:fixedFile];
+
+ if (success && [self shouldKeepRunning]) {
+ if (isPdfsync)
+ foundOptions &= ~SKPDFSynchronizerFlippedMask;
+ else
+ foundOptions |= SKPDFSynchronizerFlippedMask;
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [delegate synchronizer:self foundLocation:foundPoint
atPageIndex:foundPageIndex options:foundOptions];
+ });
+ }
+ }
+ });
+}
+
@end
Modified: trunk/SKReleaseNotesController.m
===================================================================
--- trunk/SKReleaseNotesController.m 2012-11-05 01:01:52 UTC (rev 7784)
+++ trunk/SKReleaseNotesController.m 2012-11-05 10:40:58 UTC (rev 7785)
@@ -43,16 +43,16 @@
@synthesize textView;
+static SKReleaseNotesController *sharedReleaseNotesController = nil;
+
+ (id)sharedReleaseNotesController {
- static SKReleaseNotesController *sharedReleaseNotesController = nil;
- static dispatch_once_t predicate;
- dispatch_once(&predicate, ^{
+ if (sharedReleaseNotesController == nil)
sharedReleaseNotesController = [[self alloc] init];
- });
return sharedReleaseNotesController;
}
- (id)init {
+ if (sharedReleaseNotesController) NSLog(@"Attempt to allocate second
instance of %@", [self class]);
return [super initWithWindowNibName:@"ReleaseNotes"];
}
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
LogMeIn Central: Instant, anywhere, Remote PC access and management.
Stay in control, update software, and manage PCs from one command center
Diagnose problems and improve visibility into emerging IT issues
Automate, monitor and manage. Do more in less time with Central
http://p.sf.net/sfu/logmein12331_d2d
_______________________________________________
Skim-app-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/skim-app-commit