color_panel_bridge.mm 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/remote_cocoa/app_shim/color_panel_bridge.h"
  5. #import <Cocoa/Cocoa.h>
  6. #include "skia/ext/skia_utils_mac.h"
  7. namespace {
  8. // The currently active bridge, to which the ColorPanelListener will forward
  9. // its observations.
  10. remote_cocoa::ColorPanelBridge* g_current_panel_bridge = nullptr;
  11. } // namespace
  12. // A singleton listener class to act as a event target for NSColorPanel and
  13. // send the results to the C++ class, ColorPanelBridge.
  14. @interface ColorPanelListener : NSObject {
  15. @protected
  16. // We don't call DidChooseColor if the change wasn't caused by the user
  17. // interacting with the panel.
  18. BOOL _nonUserChange;
  19. }
  20. // Called from NSNotificationCenter.
  21. - (void)windowWillClose:(NSNotification*)notification;
  22. // Called from NSColorPanel.
  23. - (void)didChooseColor:(NSColorPanel*)panel;
  24. // The singleton instance.
  25. + (ColorPanelListener*)instance;
  26. // Show the NSColorPanel.
  27. - (void)showColorPanel;
  28. // Sets color to the NSColorPanel as a non user change.
  29. - (void)setColor:(NSColor*)color;
  30. @end
  31. @implementation ColorPanelListener
  32. - (instancetype)init {
  33. if ((self = [super init])) {
  34. NSColorPanel* panel = [NSColorPanel sharedColorPanel];
  35. NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
  36. [nc addObserver:self
  37. selector:@selector(windowWillClose:)
  38. name:NSWindowWillCloseNotification
  39. object:panel];
  40. [nc addObserver:self
  41. selector:@selector(windowDidResignKey:)
  42. name:NSWindowDidResignKeyNotification
  43. object:panel];
  44. }
  45. return self;
  46. }
  47. - (void)dealloc {
  48. // This object is never freed.
  49. NOTREACHED();
  50. [super dealloc];
  51. }
  52. - (void)windowWillClose:(NSNotification*)notification {
  53. if (g_current_panel_bridge)
  54. g_current_panel_bridge->host()->DidCloseColorPanel();
  55. _nonUserChange = NO;
  56. }
  57. - (void)windowDidResignKey:(NSNotification*)notification {
  58. // Close the color panel when the user clicks away.
  59. [self windowWillClose:notification];
  60. [[NSColorPanel sharedColorPanel] close];
  61. }
  62. - (void)didChooseColor:(NSColorPanel*)panel {
  63. if (_nonUserChange) {
  64. _nonUserChange = NO;
  65. return;
  66. }
  67. _nonUserChange = NO;
  68. NSColor* color = [panel color];
  69. if ([[color colorSpaceName] isEqualToString:NSNamedColorSpace]) {
  70. color = [color colorUsingColorSpace:[NSColorSpace genericRGBColorSpace]];
  71. // Some colors in "Developer" palette in "Color Palettes" tab can't be
  72. // converted to RGB. We just ignore such colors.
  73. // TODO(tkent): We should notice the rejection to users.
  74. if (!color)
  75. return;
  76. }
  77. SkColor skColor = 0;
  78. if ([color colorSpace] == [NSColorSpace genericRGBColorSpace]) {
  79. // genericRGB -> deviceRGB conversion isn't ignorable. We'd like to use RGB
  80. // values shown in NSColorPanel UI.
  81. CGFloat red, green, blue, alpha;
  82. [color getRed:&red green:&green blue:&blue alpha:&alpha];
  83. skColor = SkColorSetARGB(
  84. SkScalarRoundToInt(255.0 * alpha), SkScalarRoundToInt(255.0 * red),
  85. SkScalarRoundToInt(255.0 * green), SkScalarRoundToInt(255.0 * blue));
  86. } else {
  87. skColor = skia::NSDeviceColorToSkColor(
  88. [[panel color] colorUsingColorSpaceName:NSDeviceRGBColorSpace]);
  89. }
  90. if (g_current_panel_bridge)
  91. g_current_panel_bridge->host()->DidChooseColorInColorPanel(skColor);
  92. }
  93. + (ColorPanelListener*)instance {
  94. static ColorPanelListener* listener = [[ColorPanelListener alloc] init];
  95. return listener;
  96. }
  97. - (void)showColorPanel {
  98. NSColorPanel* panel = [NSColorPanel sharedColorPanel];
  99. [panel setShowsAlpha:NO];
  100. [panel setTarget:self];
  101. [panel setAction:@selector(didChooseColor:)];
  102. [panel makeKeyAndOrderFront:nil];
  103. }
  104. - (void)setColor:(NSColor*)color {
  105. _nonUserChange = YES;
  106. [[NSColorPanel sharedColorPanel] setColor:color];
  107. }
  108. @end
  109. namespace remote_cocoa {
  110. ColorPanelBridge::ColorPanelBridge(
  111. mojo::PendingRemote<mojom::ColorPanelHost> host)
  112. : host_(std::move(host)) {
  113. g_current_panel_bridge = this;
  114. }
  115. ColorPanelBridge::~ColorPanelBridge() {
  116. if (g_current_panel_bridge == this)
  117. g_current_panel_bridge = nullptr;
  118. }
  119. void ColorPanelBridge::Show(uint32_t initial_color, ShowCallback callback) {
  120. ColorPanelListener* listener = [ColorPanelListener instance];
  121. [listener setColor:skia::SkColorToDeviceNSColor(initial_color)];
  122. [listener showColorPanel];
  123. std::move(callback).Run();
  124. }
  125. void ColorPanelBridge::SetSelectedColor(uint32_t color,
  126. SetSelectedColorCallback callback) {
  127. ColorPanelListener* listener = [ColorPanelListener instance];
  128. [listener setColor:skia::SkColorToDeviceNSColor(color)];
  129. std::move(callback).Run();
  130. }
  131. } // namespace remote_cocoa