Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix image (and other) pasting #411

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions Messenger.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
3A9A9C7C1AD5D8ED008FABE9 /* JSNotification.js.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3A9A9C7B1AD5D8ED008FABE9 /* JSNotification.js.mm */; };
3A9A9C841AD5EA13008FABE9 /* JSObjWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A9A9C831AD5EA13008FABE9 /* JSObjWrapper.m */; };
3A9A9C861AD5EE4E008FABE9 /* JSNotifications.js.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3A9A9C851AD5EE4E008FABE9 /* JSNotifications.js.mm */; };
669511411B00A0E600526CFD /* MMFakeDragInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 669511401B00A0E600526CFD /* MMFakeDragInfo.m */; };
6ADC7FFE1DAD4024006362C3 /* PFMoveApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 6ADC7FFD1DAD4024006362C3 /* PFMoveApplication.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
CB4ACC4E1BF4B91F00930C59 /* WebViewZoomController.m in Sources */ = {isa = PBXBuildFile; fileRef = CB4ACC4D1BF4B91F00930C59 /* WebViewZoomController.m */; };
FC67C6201AD7027700459263 /* FBMApplication.mm in Sources */ = {isa = PBXBuildFile; fileRef = FC67C61F1AD7027700459263 /* FBMApplication.mm */; };
Expand Down Expand Up @@ -96,8 +95,6 @@
3AC5B7B41B7C357F00BCF9D0 /* WebViewPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebViewPrivate.h; sourceTree = "<group>"; };
3AEEEB881ADE3A9800F3A659 /* WebStorageManagerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebStorageManagerPrivate.h; sourceTree = "<group>"; };
3AEEEB891ADE3B0600F3A659 /* WebPreferencesPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebPreferencesPrivate.h; sourceTree = "<group>"; };
6695113F1B00A0E600526CFD /* MMFakeDragInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMFakeDragInfo.h; sourceTree = "<group>"; };
669511401B00A0E600526CFD /* MMFakeDragInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMFakeDragInfo.m; sourceTree = "<group>"; };
6ADC7FFC1DAD4024006362C3 /* PFMoveApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PFMoveApplication.h; path = letsmove/PFMoveApplication.h; sourceTree = SOURCE_ROOT; };
6ADC7FFD1DAD4024006362C3 /* PFMoveApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PFMoveApplication.m; path = letsmove/PFMoveApplication.m; sourceTree = SOURCE_ROOT; };
CB4ACC4C1BF4B91F00930C59 /* WebViewZoomController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewZoomController.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -168,8 +165,6 @@
FC67C61F1AD7027700459263 /* FBMApplication.mm */,
3A7F0BCE1C7639A70036F7AC /* FBMWindow.h */,
3A7F0BCF1C7639A70036F7AC /* FBMWindow.mm */,
6695113F1B00A0E600526CFD /* MMFakeDragInfo.h */,
669511401B00A0E600526CFD /* MMFakeDragInfo.m */,
CB4ACC4C1BF4B91F00930C59 /* WebViewZoomController.h */,
CB4ACC4D1BF4B91F00930C59 /* WebViewZoomController.m */,
3AEEEB891ADE3B0600F3A659 /* WebPreferencesPrivate.h */,
Expand Down Expand Up @@ -341,7 +336,6 @@
3A9A9C461AD5B407008FABE9 /* AppDelegate.mm in Sources */,
FC67C6201AD7027700459263 /* FBMApplication.mm in Sources */,
3A9A9C861AD5EE4E008FABE9 /* JSNotifications.js.mm in Sources */,
669511411B00A0E600526CFD /* MMFakeDragInfo.m in Sources */,
3A713BA01AD65F6500870D2A /* MEmbeddedRes.m in Sources */,
3A9A9C7C1AD5D8ED008FABE9 /* JSNotification.js.mm in Sources */,
6ADC7FFE1DAD4024006362C3 /* PFMoveApplication.m in Sources */,
Expand Down
66 changes: 38 additions & 28 deletions Messenger/AppDelegate.mm
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#import "WebViewZoomController.h"
#import "JSClass.hh"
#import "MEmbeddedRes.h"
#import "MMFakeDragInfo.h"
#import "FBMWindow.h"
#import "PFMoveApplication.h"

Expand Down Expand Up @@ -477,48 +476,59 @@ - (IBAction)findPeopleAndGroups:(id)sender {

- (IBAction)paste:(id)sender {
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];

// If we've got an image, let's paste it!
// Ain't nobody got time for dirty hax with React.
if ([pasteboard canReadObjectForClasses:@[[NSImage class]] options:nil]) {
NSImage *pastedImage = [[pasteboard readObjectsForClasses:@[[NSImage class]] options:nil] firstObject];

// Try to grab the URL to the image being pasted (if it's available) to just repurpose the already useable pasteboard.
NSURL *pastedFileURL = [[pasteboard readObjectsForClasses:@[[NSURL class]] options:nil] firstObject];

// If we haven't got a file URL (screenshot), we need to write it out first.
if (pastedFileURL == nil) {
// Convert the pasteboard image to a PNG.

// Safari views don't seem to want to paste anything that isn't a URL (or plain text), so if it's not one of those we try to fix that.
NSURL *pastedFileURL = [[pasteboard readObjectsForClasses:@[[NSURL class]] options:nil] firstObject];

// NOTE: if the clipboard simply contains plain text, it won't have a URL, but none of the methods in this will handle it, so it will fall through at the end just fine.
// We can't pre-emptively check whether the pasteboard contains NSString, because this is basically always true (e.g. plain text filename)
// Structured this way, we ONLY mess around with the pasteboard data if it contains image data with no URL (more handlers can be added later if needed)
// Note that we need a file URL, images copied from Safari include a web URL when the user actually wants to paste the image.
if (!(pastedFileURL != nil && [pastedFileURL isFileURL])) {
// Image data with no URL (e.g. a screenshot or copied from somewhere)
if ([pasteboard canReadObjectForClasses:@[[NSImage class]] options:nil]) {
NSImage *pastedImage = [[pasteboard readObjectsForClasses:@[[NSImage class]] options:nil] firstObject];

// Convert the pasteboard image to a JPEG. NSPNGFileType does not offer any compression at all, and we don't want to upload huge files.
NSRect proposedRect = NSMakeRect(0, 0, pastedImage.size.width, pastedImage.size.height);
CGImageRef pastedImageRef = [pastedImage CGImageForProposedRect:&proposedRect
context:NULL
hints:nil];
NSBitmapImageRep *bitmapImageRep = [[NSBitmapImageRep alloc] initWithCGImage:pastedImageRef];
NSData *PNGImageData = [bitmapImageRep representationUsingType:NSPNGFileType properties:@{}];

// Save it as JPEG at near highest quality; we don't need lossless because Facebook will ruin it anyway
NSData *JPEGImageData = [bitmapImageRep representationUsingType:NSJPEGFileType properties:@{ NSImageCompressionFactor : @0.99 }];

// Save it (temporarily with a new name).
NSString *uniqueFilename = [[NSUUID UUID].UUIDString stringByAppendingString:@".png"];
NSString *uniqueFilename = [[NSUUID UUID].UUIDString stringByAppendingString:@".jpeg"];
NSString *tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:uniqueFilename];
[PNGImageData writeToFile:tmpPath atomically:YES];

[JPEGImageData writeToFile:tmpPath atomically:YES];
pastedFileURL = [NSURL fileURLWithPath:tmpPath];

// Write our newly saved file to the pasteboard.
[pasteboard clearContents];
[pasteboard declareTypes:@[NSFilenamesPboardType] owner:self];
[pasteboard writeObjects:@[pastedFileURL]];
}

if (pastedFileURL != nil) {
// Fire off a completely falsified (and bs) drag+drop event. >:D
MMFakeDragInfo *info = [[MMFakeDragInfo alloc] initWithImage:pastedImage pasteboard:pasteboard];
[_webView draggingEntered:info];
[_webView draggingUpdated:info];
[_webView performDragOperation:info];
}
else {
// We can't paste directories, show an error
// TODO: in future, try silently zipping up the directory and sending that?
NSNumber *res;
[pastedFileURL getResourceValue:&res forKey:NSURLIsDirectoryKey error:nil];
if ([res boolValue]) {
NSAlert *alert = [NSAlert new];
[alert addButtonWithTitle:@"OK"];
[alert setMessageText:@"Could not send attachment"];
[alert setInformativeText:@"Directories cannot be sent. Zip it up first and try again."];
[alert setAlertStyle:NSAlertStyleWarning];
[alert beginSheetModalForWindow:self.mainWindow completionHandler:nil];
return;
}
} else {
[[NSApplication sharedApplication] sendAction:@selector(paste:) to:nil from:self];
}

// forward the paste action to the webview, now that we've fixed the paste data (if needed)
[[NSApplication sharedApplication] sendAction:@selector(paste:) to:_webView from:self];
}

- (IBAction)openMainMenu:(id)sender {
Expand Down
23 changes: 0 additions & 23 deletions Messenger/MMFakeDragInfo.h

This file was deleted.

79 changes: 0 additions & 79 deletions Messenger/MMFakeDragInfo.m

This file was deleted.