FLEWindowSizePlugin.mm 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // Copyright 2018 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #import "FLEWindowSizePlugin.h"
  15. #import <AppKit/AppKit.h>
  16. namespace {
  17. // See window_size_channel.dart for documentation.
  18. NSString *const kChannelName = @"flutter/windowsize";
  19. NSString *const kGetScreenListMethod = @"getScreenList";
  20. NSString *const kGetWindowInfoMethod = @"getWindowInfo";
  21. NSString *const kSetWindowFrameMethod = @"setWindowFrame";
  22. NSString *const kSetWindowMinimumSizeMethod = @"setWindowMinimumSize";
  23. NSString *const kSetWindowMaximumSizeMethod = @"setWindowMaximumSize";
  24. NSString *const kSetWindowTitleMethod = @"setWindowTitle";
  25. NSString *const kSetWindowTitleRepresentedUrlMethod = @"setWindowTitleRepresentedUrl";
  26. NSString *const kSetWindowVisibilityMethod = @"setWindowVisibility";
  27. NSString *const kGetWindowMinimumSizeMethod = @"getWindowMinimumSize";
  28. NSString *const kGetWindowMaximumSizeMethod = @"getWindowMaximumSize";
  29. NSString *const kFrameKey = @"frame";
  30. NSString *const kVisibleFrameKey = @"visibleFrame";
  31. NSString *const kScaleFactorKey = @"scaleFactor";
  32. NSString *const kScreenKey = @"screen";
  33. /**
  34. * Returns the max Y coordinate across all screens.
  35. */
  36. CGFloat GetMaxScreenY() {
  37. CGFloat maxY = 0;
  38. for (NSScreen *screen in [NSScreen screens]) {
  39. maxY = MAX(maxY, CGRectGetMaxY(screen.frame));
  40. }
  41. return maxY;
  42. }
  43. /**
  44. * Given |frame| in screen coordinates, returns a frame flipped relative to
  45. * GetMaxScreenY().
  46. */
  47. NSRect GetFlippedRect(NSRect frame) {
  48. CGFloat maxY = GetMaxScreenY();
  49. return NSMakeRect(frame.origin.x, maxY - frame.origin.y - frame.size.height, frame.size.width,
  50. frame.size.height);
  51. }
  52. /**
  53. * Converts the channel representation for unconstrained maximum size `-1` to Cocoa's specific
  54. * maximum size of `FLT_MAX`.
  55. */
  56. double MaxDimensionFromChannelRepresentation(double size) { return size == -1.0 ? FLT_MAX : size; }
  57. /**
  58. * Converts Cocoa's specific maximum size of `FLT_MAX` to channel representation for unconstrained
  59. * maximum size `-1`.
  60. */
  61. double ChannelRepresentationForMaxDimension(double size) { return size == FLT_MAX ? -1 : size; }
  62. } // namespace
  63. @interface FLEWindowSizePlugin ()
  64. /// The view displaying Flutter content.
  65. @property(nonatomic, readonly) NSView *flutterView;
  66. /**
  67. * Extracts information from |screen| and returns the serializable form expected
  68. * by the platform channel.
  69. */
  70. - (NSDictionary *)platformChannelRepresentationForScreen:(NSScreen *)screen;
  71. /**
  72. * Extracts information from |window| and returns the serializable form expected
  73. * by the platform channel.
  74. */
  75. - (NSDictionary *)platformChannelRepresentationForWindow:(NSWindow *)window;
  76. /**
  77. * Returns the serializable form of |frame| expected by the platform channel.
  78. */
  79. - (NSArray *)platformChannelRepresentationForFrame:(NSRect)frame;
  80. @end
  81. @implementation FLEWindowSizePlugin {
  82. // The channel used to communicate with Flutter.
  83. FlutterMethodChannel *_channel;
  84. // A reference to the registrar holding the NSView used by the plugin. Holding a reference
  85. // since the view might be nil at the time the plugin is created.
  86. id<FlutterPluginRegistrar> _registrar;
  87. }
  88. - (NSView *)flutterView {
  89. return _registrar.view;
  90. }
  91. + (void)registerWithRegistrar:(id<FlutterPluginRegistrar>)registrar {
  92. FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:kChannelName
  93. binaryMessenger:registrar.messenger];
  94. FLEWindowSizePlugin *instance = [[FLEWindowSizePlugin alloc] initWithChannel:channel
  95. registrar:registrar];
  96. [registrar addMethodCallDelegate:instance channel:channel];
  97. }
  98. - (instancetype)initWithChannel:(FlutterMethodChannel *)channel
  99. registrar:(id<FlutterPluginRegistrar>)registrar {
  100. self = [super init];
  101. if (self) {
  102. _channel = channel;
  103. _registrar = registrar;
  104. }
  105. return self;
  106. }
  107. /**
  108. * Handles platform messages generated by the Flutter framework on the platform channel.
  109. */
  110. - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
  111. id methodResult = nil;
  112. if ([call.method isEqualToString:kGetScreenListMethod]) {
  113. NSMutableArray<NSDictionary *> *screenList =
  114. [NSMutableArray arrayWithCapacity:[NSScreen screens].count];
  115. for (NSScreen *screen in [NSScreen screens]) {
  116. [screenList addObject:[self platformChannelRepresentationForScreen:screen]];
  117. }
  118. methodResult = screenList;
  119. } else if ([call.method isEqualToString:kGetWindowInfoMethod]) {
  120. methodResult = [self platformChannelRepresentationForWindow:self.flutterView.window];
  121. } else if ([call.method isEqualToString:kSetWindowFrameMethod]) {
  122. NSArray<NSNumber *> *arguments = call.arguments;
  123. [self.flutterView.window
  124. setFrame:GetFlippedRect(NSMakeRect(arguments[0].doubleValue, arguments[1].doubleValue,
  125. arguments[2].doubleValue, arguments[3].doubleValue))
  126. display:YES];
  127. methodResult = nil;
  128. } else if ([call.method isEqualToString:kSetWindowMinimumSizeMethod]) {
  129. NSArray<NSNumber *> *arguments = call.arguments;
  130. self.flutterView.window.minSize =
  131. NSMakeSize(arguments[0].doubleValue, arguments[1].doubleValue);
  132. methodResult = nil;
  133. } else if ([call.method isEqualToString:kSetWindowMaximumSizeMethod]) {
  134. NSArray<NSNumber *> *arguments = call.arguments;
  135. self.flutterView.window.maxSize =
  136. NSMakeSize(MaxDimensionFromChannelRepresentation(arguments[0].doubleValue),
  137. MaxDimensionFromChannelRepresentation(arguments[1].doubleValue));
  138. methodResult = nil;
  139. } else if ([call.method isEqualToString:kGetWindowMinimumSizeMethod]) {
  140. NSSize size = self.flutterView.window.minSize;
  141. methodResult = @[ @(size.width), @(size.height) ];
  142. } else if ([call.method isEqualToString:kGetWindowMaximumSizeMethod]) {
  143. NSSize size = self.flutterView.window.maxSize;
  144. methodResult = @[
  145. @(ChannelRepresentationForMaxDimension(size.width)),
  146. @(ChannelRepresentationForMaxDimension(size.height))
  147. ];
  148. } else if ([call.method isEqualToString:kSetWindowTitleMethod]) {
  149. NSString *title = call.arguments;
  150. self.flutterView.window.title = title;
  151. methodResult = nil;
  152. } else if ([call.method isEqualToString:kSetWindowTitleRepresentedUrlMethod]) {
  153. NSURL *representedURL = [NSURL URLWithString:call.arguments];
  154. self.flutterView.window.representedURL = representedURL;
  155. methodResult = nil;
  156. } else if ([call.method isEqualToString:kSetWindowVisibilityMethod]) {
  157. bool visible = [call.arguments boolValue];
  158. if (visible) {
  159. [self.flutterView.window makeKeyAndOrderFront:self];
  160. } else {
  161. [self.flutterView.window orderOut:self];
  162. }
  163. methodResult = nil;
  164. } else {
  165. methodResult = FlutterMethodNotImplemented;
  166. }
  167. result(methodResult);
  168. }
  169. #pragma mark - Private methods
  170. - (NSDictionary *)platformChannelRepresentationForScreen:(NSScreen *)screen {
  171. return @{
  172. kFrameKey : [self platformChannelRepresentationForFrame:GetFlippedRect(screen.frame)],
  173. kVisibleFrameKey :
  174. [self platformChannelRepresentationForFrame:GetFlippedRect(screen.visibleFrame)],
  175. kScaleFactorKey : @(screen.backingScaleFactor),
  176. };
  177. }
  178. - (NSDictionary *)platformChannelRepresentationForWindow:(NSWindow *)window {
  179. return @{
  180. kFrameKey : [self platformChannelRepresentationForFrame:GetFlippedRect(window.frame)],
  181. kScreenKey : [self platformChannelRepresentationForScreen:window.screen],
  182. kScaleFactorKey : @(window.backingScaleFactor),
  183. };
  184. }
  185. - (NSArray *)platformChannelRepresentationForFrame:(NSRect)frame {
  186. return @[ @(frame.origin.x), @(frame.origin.y), @(frame.size.width), @(frame.size.height) ];
  187. }
  188. @end