1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-27 16:31:31 +00:00

Merge pull request #505 from TomHarte/MacScreenshots

Attempts to introduce screenshot capture for macOS.
This commit is contained in:
Thomas Harte 2018-07-27 23:43:13 -04:00 committed by GitHub
commit 85ce21c79f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 70 additions and 1 deletions

View File

@ -111,6 +111,12 @@
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
<menuItem title="Save Screenshot" keyEquivalent="D" id="BVJ-oQ-hUp">
<connections>
<action selector="saveScreenshot:" target="-1" id="7ky-xD-tip"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="rXU-KX-GkZ"/>
<menuItem title="Page Setup…" enabled="NO" keyEquivalent="P" id="qIS-W8-SiK">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>

View File

@ -4,6 +4,8 @@
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.assets.pictures.read-write</key>
<true/>
<key>com.apple.security.device.bluetooth</key>
<true/>
<key>com.apple.security.device.usb</key>

View File

@ -6,8 +6,8 @@
// Copyright 2016 Thomas Harte. All rights reserved.
//
import Cocoa
import AudioToolbox
import Cocoa
class MachineDocument:
NSDocument,
@ -310,6 +310,29 @@ class MachineDocument:
return super.validateUserInterfaceItem(item)
}
// Screenshot capture.
@IBAction func saveScreenshot(_ sender: AnyObject!) {
// Grab a date formatter and form a file name.
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .short
dateFormatter.timeStyle = .long
let filename = ("Clock Signal Screen Shot " + dateFormatter.string(from: Date()) + ".png").replacingOccurrences(of: "/", with: "-")
.replacingOccurrences(of: ":", with: ".")
let pictursURL = FileManager.default.urls(for: .picturesDirectory, in: .userDomainMask)[0]
let url = pictursURL.appendingPathComponent(filename)
// Obtain the machine's current display.
var imageRepresentation: NSBitmapImageRep? = nil
self.openGLView.perform {
imageRepresentation = self.machine.imageRepresentation
}
// Encode as a PNG and save.
let pngData = imageRepresentation!.representation(using: .png, properties: [:])
try! pngData?.write(to: url)
}
// MARK: Activity display.
class LED {
let levelIndicator: NSLevelIndicator

View File

@ -64,6 +64,7 @@ typedef NS_ENUM(NSInteger, CSMachineKeyboardInputMode) {
@property (nonatomic, readonly, nonnull) NSString *userDefaultsPrefix;
- (void)paste:(nonnull NSString *)string;
@property (nonatomic, readonly, nonnull) NSBitmapImageRep *imageRepresentation;
@property (nonatomic, assign) BOOL useFastLoadingHack;
@property (nonatomic, assign) CSMachineVideoSignal videoSignal;

View File

@ -243,6 +243,43 @@ struct ActivityObserver: public Activity::Observer {
keyboardMachine->type_string([paste UTF8String]);
}
- (NSBitmapImageRep *)imageRepresentation {
// Get the current viewport to establish framebuffer size. Then determine how wide the
// centre 4/3 of that would be.
GLint dimensions[4];
glGetIntegerv(GL_VIEWPORT, dimensions);
GLint proportionalWidth = (dimensions[3] * 4) / 3;
// Grab the framebuffer contents.
std::vector<uint8_t> temporaryData(static_cast<size_t>(proportionalWidth * dimensions[3] * 3));
glReadPixels((dimensions[2] - proportionalWidth) >> 1, 0, proportionalWidth, dimensions[3], GL_RGB, GL_UNSIGNED_BYTE, temporaryData.data());
// Generate an NSBitmapImageRep and populate it with a vertical flip
// of the original data.
NSBitmapImageRep *const result =
[[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:NULL
pixelsWide:proportionalWidth
pixelsHigh:dimensions[3]
bitsPerSample:8
samplesPerPixel:3
hasAlpha:NO
isPlanar:NO
colorSpaceName:NSDeviceRGBColorSpace
bytesPerRow:3 * proportionalWidth
bitsPerPixel:0];
const size_t line_size = static_cast<size_t>(proportionalWidth * 3);
for(GLint y = 0; y < dimensions[3]; ++y) {
memcpy(
&result.bitmapData[static_cast<size_t>(y) * line_size],
&temporaryData[static_cast<size_t>(dimensions[3] - y - 1) * line_size],
line_size);
}
return result;
}
- (void)applyMedia:(const Analyser::Static::Media &)media {
@synchronized(self) {
MediaTarget::Machine *const mediaTarget = _machine->media_target();