Skip to content

Commit 09ee070

Browse files
committed
first local commit
0 parents  commit 09ee070

File tree

1 file changed

+205
-0
lines changed

1 file changed

+205
-0
lines changed

quickgrab.m

+205
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
// Compile this way:
2+
// gcc -framework cocoa -x objective-c -o quickgrab quickgrab.m
3+
//
4+
5+
#define MYLog(...) do { if (__builtin_expect(kDebuggingEnabled, 0)) { NSLog(__VA_ARGS__); } } while(0)
6+
7+
#import <Cocoa/Cocoa.h>
8+
9+
// we start with debugging off...
10+
bool kDebuggingEnabled = NO;
11+
12+
13+
14+
// Neat NSLog like function to stdout...
15+
// http://stackoverflow.com/a/3487392/348694
16+
void NSPrint(NSString *format, ...) {
17+
va_list args;
18+
va_start(args, format);
19+
20+
fputs([[[[NSString alloc] initWithFormat:format arguments:args] autorelease] UTF8String], stdout);
21+
fputs("\n", stdout);
22+
va_end(args);
23+
}
24+
25+
26+
void showWindowList(int pid);
27+
void showWindowList(int pid)
28+
{
29+
MYLog(@"List of windows available for capture...");
30+
31+
CGWindowListOption listOptions = kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements;
32+
CFArrayRef windowList = CGWindowListCopyWindowInfo(listOptions, kCGNullWindowID);
33+
MYLog(@"Found %d windows\n", CFArrayGetCount(windowList));
34+
//MYLog(@"%@", windowList);
35+
36+
//Lets walk through the list
37+
for (NSMutableDictionary* entry in (NSArray*)windowList)
38+
{
39+
NSString *ownerName = [entry objectForKey: (id)kCGWindowOwnerName];
40+
NSInteger ownerPID = [[entry objectForKey: (id)kCGWindowOwnerPID] integerValue];
41+
NSString *name = [entry objectForKey: (id)kCGWindowName];
42+
NSNumber *wnumber = [entry objectForKey: (id)kCGWindowNumber];
43+
NSNumber *wlevel = [entry objectForKey: (id)kCGWindowLayer];
44+
45+
// Show all or specific app windows at 0 Level only
46+
if ( (pid == 0 || ownerPID == pid ) && [wlevel integerValue] == 0)
47+
NSPrint(@"App: %@, PID: %d, Window ID: %d, Window Title: %@", \
48+
ownerName, ownerPID, [wnumber integerValue], name);
49+
50+
}
51+
52+
}
53+
54+
void showHelp(void);
55+
void showHelp(void)
56+
{
57+
printf("usage: quickgrab [-pid <id>] [-winid <id>] [-showlist yes] [-debug yes] -file <file> \n\
58+
-pid <id> Process ID of application that you want to target. If there are \n\
59+
multiple windows, the first, as ordered by the system will be captured. \n\
60+
-winid <id> Window ID you want to capture. To get the ID use -showlist option. \n\
61+
-showlist yes Lists available windows with the Process IDs and Window IDs to use \n\
62+
with the other options.\n\
63+
-debug yes Enables output of debugging information. \n\
64+
-file <file> Where to save the image. \n\
65+
\n\
66+
It captures the top most window of the active application unless -pid and/or -winid \n\
67+
options are supplied. \n\
68+
\n \
69+
\n \
70+
Examples \n\
71+
\n\
72+
Capture the top window of active application after 2 seconds.\n\
73+
\n\
74+
$ sleep 2 ; ./quickgrab -file activewindow.png\n\
75+
\n\
76+
Taking continuous shots of top window every 2 seconds\n\
77+
\n\
78+
$ while true; do ./quickgrab -file topwindow.png ; sleep 2 ; done\n\
79+
\n\
80+
Like above but creating a new file for every shot with date/time as the filename...\n\
81+
\n\
82+
$ while true; do ./quickgrab -file `date \"+%%Y%%m%%d%%H%%M%%S\"`.png ; sleep 2 ; done\n\
83+
");
84+
}
85+
86+
87+
void grabWindow(int winid, NSString *filename);
88+
void grabWindow(int winid, NSString *filename)
89+
{
90+
MYLog(@"Getting image of window id: %d", winid);
91+
92+
CGImageRef cgImage = CGWindowListCreateImage(CGRectNull, \
93+
kCGWindowListOptionIncludingWindow, winid, kCGWindowImageDefault);
94+
95+
if(cgImage == NULL)
96+
exit(3);
97+
98+
MYLog(@"Image created...");
99+
100+
// Create a bitmap rep from the image...
101+
NSBitmapImageRep *bitmapRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage];
102+
103+
// Save the file
104+
NSData *data = [bitmapRep representationUsingType: NSPNGFileType properties: nil];
105+
[data writeToFile: filename atomically: NO];
106+
107+
CGImageRelease(cgImage);
108+
109+
MYLog(@"Image saved to %@", filename);
110+
}
111+
112+
113+
114+
int main(int argc, char *argv[])
115+
{
116+
id pool=[NSAutoreleasePool new];
117+
118+
// Get command line arguments
119+
NSUserDefaults *args = [NSUserDefaults standardUserDefaults];
120+
NSString *fileArg = [args stringForKey:@"file"];
121+
NSInteger pidArg = [args integerForKey:@"pid"];
122+
NSInteger widArg = [args integerForKey:@"winid"];
123+
BOOL listArg = [args boolForKey:@"showlist"];
124+
BOOL debugArg = [args boolForKey:@"debug"];
125+
126+
// Enable debugging if user asks
127+
if ( debugArg == 1)
128+
{
129+
kDebuggingEnabled = YES;
130+
}
131+
132+
MYLog(@"%@", [[NSProcessInfo processInfo] arguments]);
133+
MYLog(@"Output File(fileArg) = %@", fileArg);
134+
MYLog(@"Process ID(pidArg) = %d", pidArg);
135+
MYLog(@"Window ID(widArg) = %d", widArg);
136+
MYLog(@"Show Window List = %d", listArg);
137+
MYLog(@"Enable Debugging = %d", debugArg);
138+
139+
// if ( listArg )
140+
// {
141+
// showWindowList(pidArg);
142+
// exit(0);
143+
// }
144+
145+
// Stop, nothing to do!
146+
if ( fileArg == nil && !listArg)
147+
{
148+
showHelp();
149+
exit(1);
150+
}
151+
152+
MYLog(@"Getting list of windows available for capture...");
153+
154+
CGWindowListOption listOptions = kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements;
155+
CFArrayRef windowList = CGWindowListCopyWindowInfo(listOptions, kCGNullWindowID);
156+
MYLog(@"Found %d windows\n", CFArrayGetCount(windowList));
157+
//MYLog(@"%@", windowList);
158+
159+
//Lets walk through the list
160+
for (NSMutableDictionary* entry in (NSArray*)windowList)
161+
{
162+
NSString *ownerName = [entry objectForKey: (id)kCGWindowOwnerName];
163+
NSInteger ownerPID = [[entry objectForKey: (id)kCGWindowOwnerPID] integerValue];
164+
NSString *name = [entry objectForKey: (id)kCGWindowName];
165+
NSNumber *wnumber = [entry objectForKey: (id)kCGWindowNumber];
166+
NSNumber *wlevel = [entry objectForKey: (id)kCGWindowLayer];
167+
168+
// Only interested on windows at 0 level only
169+
if ([wlevel integerValue] == 0)
170+
if ( listArg )
171+
{
172+
if (pidArg == 0 || ownerPID == pidArg )
173+
NSPrint(@"App: %@, PID: %d, Window ID: %d, Window Title: %@", \
174+
ownerName, ownerPID, [wnumber integerValue], name);
175+
176+
}
177+
else
178+
{
179+
// User didn't say so we grab the first (top most) window
180+
if ( pidArg == 0 && widArg == 0 )
181+
{
182+
grabWindow([wnumber integerValue], fileArg);
183+
break;
184+
}
185+
186+
// if PID given we grab the first window of the app
187+
if ( ownerPID == pidArg && widArg == 0 )
188+
{
189+
grabWindow([wnumber integerValue], fileArg);
190+
break;
191+
}
192+
193+
// Finally if they gave a specific window id
194+
if ( widArg == [wnumber integerValue] )
195+
{
196+
grabWindow([wnumber integerValue], fileArg);
197+
break;
198+
}
199+
200+
}
201+
}
202+
203+
[pool drain];
204+
return 0;
205+
}

0 commit comments

Comments
 (0)