Skip to content

Commit 29189a3

Browse files
committed
Added thumbnail support. I'm doing some tricks to try to ensure fast rendering
but I need to verify that they actually help.
1 parent 0c6c06f commit 29189a3

8 files changed

Lines changed: 248 additions & 99 deletions

File tree

ChangeLog.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
0.2 (in progress):
2+
- Changed .tex UTI to agree with TeXShop's.
3+
- Let the system pick a different plugin if pygmentize fails
4+
5+
0.1: Initial release

Common.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Common.h
3+
* QLColorCode
4+
*
5+
* Created by Nathaniel Gray on 12/6/07.
6+
* Copyright 2007 Nathaniel Gray. All rights reserved.
7+
*
8+
*/
9+
#import <CoreFoundation/CoreFoundation.h>
10+
#import <Foundation/Foundation.h>
11+
12+
#ifdef DEBUG
13+
#define n8log(...) NSLog(__VA_ARGS__)
14+
#else
15+
#define n8log(...)
16+
#endif
17+
18+
// Status is 0 on success, nonzero on error (like a shell command)
19+
// If thumbnail is 1, only render the top 50 lines of the file
20+
NSData *colorizeURL(CFBundleRef myBundle, CFURLRef url, int *status,
21+
int thumbnail);

Common.m

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Common.c
3+
* QLColorCode
4+
*
5+
* Created by Nathaniel Gray on 12/6/07.
6+
* Copyright 2007 Nathaniel Gray. All rights reserved.
7+
*
8+
*/
9+
10+
#import <CoreFoundation/CoreFoundation.h>
11+
#import <CoreServices/CoreServices.h>
12+
#import <Foundation/Foundation.h>
13+
#import <limits.h> // PATH_MAX
14+
15+
#include "Common.h"
16+
17+
18+
NSData *runTask(NSString *script, int *exitCode) {
19+
NSTask *task = [[NSTask alloc] init];
20+
[task setCurrentDirectoryPath:@"/tmp"]; /* XXX: Fix this */
21+
//[task setEnvironment:env];
22+
[task setLaunchPath:@"/bin/sh"];
23+
[task setArguments:[NSArray arrayWithObjects:@"-c", script, nil]];
24+
25+
NSPipe *pipe;
26+
pipe = [NSPipe pipe];
27+
[task setStandardOutput: pipe];
28+
[task setStandardError: pipe];
29+
30+
NSFileHandle *file;
31+
file = [pipe fileHandleForReading];
32+
33+
[task launch];
34+
35+
NSData *data;
36+
data = [file readDataToEndOfFile];
37+
[task waitUntilExit];
38+
39+
*exitCode = [task terminationStatus];
40+
[task release];
41+
/* The docs claim this isn't needed, but we leak descriptors otherwise */
42+
[file closeFile];
43+
/*[pipe release];*/
44+
45+
return data;
46+
}
47+
48+
NSData *colorizeURL(CFBundleRef bundle, CFURLRef url, int *status, int thumbnail)
49+
{
50+
NSData *output = NULL;
51+
unsigned char *targetBuf = malloc(PATH_MAX);
52+
unsigned char *rsrcDirBuf = malloc(PATH_MAX);
53+
char *thumbString;
54+
CFURLRef rsrcDirURL = CFBundleCopyResourcesDirectoryURL(bundle);
55+
56+
if (!CFURLGetFileSystemRepresentation(url, YES, targetBuf, PATH_MAX)
57+
|| !CFURLGetFileSystemRepresentation(rsrcDirURL, YES, rsrcDirBuf, PATH_MAX))
58+
{
59+
NSLog(@"QLColorCode: CFURLGetFileSystemRepresentation failed");
60+
*status = 1;
61+
goto done;
62+
}
63+
if (thumbnail)
64+
thumbString = "1";
65+
else
66+
thumbString = "0";
67+
NSString *cmd = [NSString stringWithFormat:
68+
@"\"%s/colorize.sh\" \"%s\" \"%s\" %s",
69+
rsrcDirBuf, rsrcDirBuf, targetBuf, thumbString];
70+
71+
output = runTask(cmd, status);
72+
if (*status != 0) {
73+
NSLog(@"QLColorCode: colorize.sh failed with exit code %d", *status);
74+
}
75+
done:
76+
free(targetBuf);
77+
free(rsrcDirBuf);
78+
return output;
79+
}

GeneratePreviewForURL.m

Lines changed: 5 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
#import <CoreServices/CoreServices.h>
55
#import <Foundation/Foundation.h>
66
#import <QuickLook/QuickLook.h>
7-
8-
#import <limits.h> // PATH_MAX
7+
#import "Common.h"
98

109

1110
/* -----------------------------------------------------------------------------
@@ -14,78 +13,25 @@
1413
This function's job is to create preview for designated file
1514
----------------------------------------------------------------------------- */
1615

17-
NSData *runTask(NSString *script, int *exitCode) {
18-
NSTask *task = [[NSTask alloc] init];
19-
[task setCurrentDirectoryPath:@"/tmp"]; /* XXX: Fix this */
20-
//[task setEnvironment:env];
21-
[task setLaunchPath:@"/bin/sh"];
22-
[task setArguments:[NSArray arrayWithObjects:@"-c", script, nil]];
23-
24-
NSPipe *pipe;
25-
pipe = [NSPipe pipe];
26-
[task setStandardOutput: pipe];
27-
[task setStandardError: pipe];
28-
29-
NSFileHandle *file;
30-
file = [pipe fileHandleForReading];
31-
32-
[task launch];
33-
34-
NSData *data;
35-
data = [file readDataToEndOfFile];
36-
[task waitUntilExit];
37-
38-
/* NSString *string;
39-
string = [[NSString alloc] initWithData: data
40-
encoding: NSUTF8StringEncoding]; */
41-
42-
*exitCode = [task terminationStatus];
43-
[task release];
44-
/* [data release]; */
45-
/* The docs claim this isn't needed, but we leak descriptors otherwise */
46-
[file closeFile];
47-
/*[pipe release];*/
48-
49-
return data;
50-
}
51-
52-
5316
OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview,
5417
CFURLRef url, CFStringRef contentTypeUTI,
5518
CFDictionaryRef options)
5619
{
20+
n8log(@"Generating Preview");
5721
if (QLPreviewRequestIsCancelled(preview))
5822
return noErr;
5923

6024
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6125

6226
// Invoke colorize.sh
63-
unsigned char *targetBuf = malloc(PATH_MAX);
64-
unsigned char *rsrcDirBuf = malloc(PATH_MAX);
6527
CFBundleRef bundle = QLPreviewRequestGetGeneratorBundle(preview);
66-
CFURLRef rsrcDirURL = CFBundleCopyResourcesDirectoryURL(bundle);
67-
68-
if (!CFURLGetFileSystemRepresentation(url, YES, targetBuf, PATH_MAX)
69-
|| !CFURLGetFileSystemRepresentation(rsrcDirURL, YES, rsrcDirBuf, PATH_MAX))
70-
{
71-
NSLog(@"QLColorCode: CFURLGetFileSystemRepresentation failed");
72-
goto done;
73-
}
74-
NSString *cmd = [NSString stringWithFormat:
75-
@"\"%s/colorize.sh\" \"%s\" \"%s\"",
76-
rsrcDirBuf, rsrcDirBuf, targetBuf];
77-
7828
int status;
79-
NSData *output = runTask(cmd, &status);
29+
NSData *output = colorizeURL(bundle, url, &status, 0);
8030

81-
if (status != 0) {
82-
NSLog(@"QLColorCode: colorize.sh failed with exit code %d", status);
83-
//goto done;
84-
}
85-
if (QLPreviewRequestIsCancelled(preview))
31+
if (status != 0 || QLPreviewRequestIsCancelled(preview)) {
8632
goto done;
33+
}
8734
// Now let WebKit do its thing
88-
//NSLog(@"**************** Passing the data along **********************");
8935
CFDictionaryRef emptydict =
9036
(CFDictionaryRef)[[[NSDictionary alloc] init] autorelease];
9137
QLPreviewRequestSetDataRepresentation(preview, (CFDataRef)output,
@@ -94,8 +40,6 @@ OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview,
9440
emptydict);
9541

9642
done:
97-
free(targetBuf);
98-
free(rsrcDirBuf);
9943
[pool release];
10044
return noErr;
10145
}

GenerateThumbnailForURL.m

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,89 @@
11
#include <CoreFoundation/CoreFoundation.h>
22
#include <CoreServices/CoreServices.h>
33
#include <QuickLook/QuickLook.h>
4+
#include <WebKit/WebKit.h>
5+
#import "Common.h"
6+
7+
#define minSize 32
48

59
/* -----------------------------------------------------------------------------
610
Generate a thumbnail for file
711
812
This function's job is to create thumbnail for designated file as fast as possible
913
----------------------------------------------------------------------------- */
1014

11-
OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize)
15+
OSStatus GenerateThumbnailForURL(void *thisInterface,
16+
QLThumbnailRequestRef thumbnail,
17+
CFURLRef url,
18+
CFStringRef contentTypeUTI,
19+
CFDictionaryRef options,
20+
CGSize maxSize)
1221
{
22+
n8log(@"Generating Thumbnail");
23+
// For some reason we seem to get called for small thumbnails even though
24+
// we put a min size in our .plist file...
25+
if (maxSize.width < minSize || maxSize.height < minSize)
26+
return noErr;
27+
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
28+
29+
// Render as though there is an 600x800 window, and fill the thumbnail
30+
// vertically. This code could be more general. I'm assuming maxSize is
31+
// a square, though nothing horrible should happen if it isn't.
32+
33+
NSRect renderRect = NSMakeRect(0.0, 0.0, 600.0, 800.0);
34+
float scale = maxSize.height/800.0;
35+
NSSize scaleSize = NSMakeSize(scale, scale);
36+
CGSize thumbSize = NSSizeToCGSize(
37+
NSMakeSize((maxSize.width * (600.0/800.0)),
38+
maxSize.height));
39+
40+
/* Based on example code from quicklook-dev mailing list */
41+
// NSSize previewSize = NSSizeFromCGSize(maxSize);
42+
int status;
43+
CFBundleRef bundle = QLThumbnailRequestGetGeneratorBundle(thumbnail);
44+
NSData *data = colorizeURL(bundle, url, &status, 1);
45+
//NSLog(@"%s", [data bytes]);
46+
if (status != 0) {
47+
goto done;
48+
}
49+
//NSRect previewRect;
50+
//previewRect.size = previewSize;
51+
52+
WebView* webView = [[WebView alloc] initWithFrame:renderRect];
53+
[webView scaleUnitSquareToSize:scaleSize];
54+
[[[webView mainFrame] frameView] setAllowsScrolling:NO];
55+
56+
[[webView mainFrame] loadData:data MIMEType:@"text/html"
57+
textEncodingName:@"UTF-8" baseURL:nil];
58+
59+
while([webView isLoading]) {
60+
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
61+
}
62+
63+
// Get a context to render into
64+
CGContextRef context =
65+
QLThumbnailRequestCreateContext(thumbnail, thumbSize, false, NULL);
66+
67+
if(context != NULL) {
68+
NSGraphicsContext* nsContext =
69+
[NSGraphicsContext
70+
graphicsContextWithGraphicsPort:(void *)context
71+
flipped:[webView isFlipped]];
72+
73+
[webView displayRectIgnoringOpacity:[webView bounds]
74+
inContext:nsContext];
75+
76+
QLThumbnailRequestFlushContext(thumbnail, context);
77+
78+
CFRelease(context);
79+
}
80+
done:
81+
[pool release];
1382
return noErr;
1483
}
1584

16-
void CancelThumbnailGeneration(void* thisInterface, QLThumbnailRequestRef thumbnail)
85+
void CancelThumbnailGeneration(void* thisInterface,
86+
QLThumbnailRequestRef thumbnail)
1787
{
1888
// implement only if supported
1989
}

Info.plist

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
<string>public.source-code</string>
1515
<string>public.xml</string>
1616
<string>com.apple.property-list</string>
17+
<string>org.tug.tex</string>
1718
</array>
1819
</dict>
1920
</array>
@@ -60,7 +61,7 @@
6061
<!-- Change following property to indicate the minimum useful size for a thumbnail the generator
6162
can produce. If your generator is fast enough, you can remove the minimum size so to appear in lists -->
6263
<key>QLThumbnailMinimumSize</key>
63-
<real>48</real>
64+
<real>32</real>
6465
<!-- Change following properites to indicate the preview size to use if preview generation takes too long -->
6566
<key>QLPreviewWidth</key>
6667
<real>800</real>
@@ -151,24 +152,6 @@
151152
</array>
152153
</dict>
153154
</dict>
154-
<dict>
155-
<key>UTTypeIdentifier</key>
156-
<string>org.n8gray.tex-source</string>
157-
<key>UTTypeDescription</key>
158-
<string>Tex Source File</string>
159-
<key>UTTypeConformsTo</key>
160-
<array>
161-
<string>public.source-code</string>
162-
</array>
163-
<key>UTTypeTagSpecification</key>
164-
<dict>
165-
<key>public.filename-extension</key>
166-
<array>
167-
<string>tex</string>
168-
<string>sty</string>
169-
</array>
170-
</dict>
171-
</dict>
172155
<dict>
173156
<key>UTTypeIdentifier</key>
174157
<string>org.n8gray.scheme-source</string>
@@ -205,6 +188,31 @@
205188
<string>text/x-ini</string>
206189
</dict>
207190
</dict>
191+
<!-- This is from TexShop. I don't know if I agree with it, but they're
192+
a bigger fish as far as TeX is concerned... -->
193+
<dict>
194+
<key>UTTypeConformsTo</key>
195+
<array>
196+
<string>public.text</string>
197+
</array>
198+
<key>UTTypeDescription</key>
199+
<string>TeX text file</string>
200+
<key>UTTypeIdentifier</key>
201+
<string>org.tug.tex</string>
202+
<key>UTTypeTagSpecification</key>
203+
<dict>
204+
<key>com.apple.ostype</key>
205+
<string>TEXT</string>
206+
<key>public.filename-extension</key>
207+
<array>
208+
<string>tex</string>
209+
<string>latex</string>
210+
<string>ltx</string>
211+
<string>texi</string>
212+
<string>ctx</string>
213+
</array>
214+
</dict>
215+
</dict>
208216
</array>
209217
</dict>
210218
</plist>

0 commit comments

Comments
 (0)