The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
6.3KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 6 technical preview.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For this technical preview, this file is not subject to commercial licensing.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. namespace juce
  14. {
  15. #if defined (MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
  16. //==============================================================================
  17. class BluetoothMidiPairingWindowClass : public ObjCClass<NSObject>
  18. {
  19. public:
  20. struct Callbacks
  21. {
  22. std::unique_ptr<ModalComponentManager::Callback> modalExit;
  23. std::function<void()> windowClosed;
  24. };
  25. BluetoothMidiPairingWindowClass() : ObjCClass<NSObject> ("JUCEBluetoothMidiPairingWindowClass_")
  26. {
  27. addIvar<Callbacks*> ("callbacks");
  28. addIvar<CABTLEMIDIWindowController*> ("controller");
  29. JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
  30. addMethod (@selector (initWithCallbacks:), initWithCallbacks, "@@:^v");
  31. addMethod (@selector (show:), show, "v@:^v");
  32. addMethod (@selector (receivedWindowWillClose:), receivedWindowWillClose, "v@:^v");
  33. JUCE_END_IGNORE_WARNINGS_GCC_LIKE
  34. addMethod (@selector (dealloc), dealloc, "v@:");
  35. registerClass();
  36. }
  37. private:
  38. static CABTLEMIDIWindowController* getController (id self)
  39. {
  40. return getIvar<CABTLEMIDIWindowController*> (self, "controller");
  41. }
  42. static id initWithCallbacks (id self, SEL, Callbacks* cbs)
  43. {
  44. self = sendSuperclassMessage (self, @selector (init));
  45. object_setInstanceVariable (self, "callbacks", cbs);
  46. object_setInstanceVariable (self, "controller", [CABTLEMIDIWindowController new]);
  47. JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
  48. [[NSNotificationCenter defaultCenter] addObserver: self
  49. selector: @selector (receivedWindowWillClose:)
  50. name: @"NSWindowWillCloseNotification"
  51. object: [getController (self) window]];
  52. JUCE_END_IGNORE_WARNINGS_GCC_LIKE
  53. return self;
  54. }
  55. static void dealloc (id self, SEL)
  56. {
  57. [getController (self) release];
  58. sendSuperclassMessage (self, @selector (dealloc));
  59. }
  60. static void show (id self, SEL, Rectangle<int>* bounds)
  61. {
  62. if (bounds != nullptr)
  63. {
  64. auto nsBounds = makeNSRect (*bounds);
  65. auto mainScreenHeight = []
  66. {
  67. if ([[NSScreen screens] count] == 0)
  68. return (CGFloat) 0.0f;
  69. return [[[NSScreen screens] objectAtIndex: 0] frame].size.height;
  70. }();
  71. nsBounds.origin.y = mainScreenHeight - (nsBounds.origin.y + nsBounds.size.height);
  72. [getController (self).window setFrame: nsBounds
  73. display: YES];
  74. }
  75. [getController (self) showWindow: nil];
  76. }
  77. static void receivedWindowWillClose (id self, SEL, NSNotification*)
  78. {
  79. [[NSNotificationCenter defaultCenter] removeObserver: self];
  80. auto* cbs = getIvar<Callbacks*> (self, "callbacks");
  81. if (cbs->modalExit != nullptr)
  82. cbs->modalExit->modalStateFinished (0);
  83. cbs->windowClosed();
  84. }
  85. };
  86. class BluetoothMidiSelectorWindowHelper : public DeletedAtShutdown
  87. {
  88. public:
  89. BluetoothMidiSelectorWindowHelper (ModalComponentManager::Callback* exitCallback,
  90. Rectangle<int>* bounds)
  91. {
  92. std::unique_ptr<ModalComponentManager::Callback> exitCB (exitCallback);
  93. static BluetoothMidiPairingWindowClass cls;
  94. window.reset (cls.createInstance());
  95. WeakReference<BluetoothMidiSelectorWindowHelper> safeThis (this);
  96. auto deletionCB = [=]
  97. {
  98. if (auto* t = safeThis.get())
  99. delete t;
  100. };
  101. callbacks.reset (new BluetoothMidiPairingWindowClass::Callbacks { std::move (exitCB),
  102. std::move (deletionCB) });
  103. JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
  104. [window.get() performSelector: @selector (initWithCallbacks:)
  105. withObject: (id) callbacks.get()];
  106. [window.get() performSelector: @selector (show:)
  107. withObject: (id) bounds];
  108. JUCE_END_IGNORE_WARNINGS_GCC_LIKE
  109. }
  110. private:
  111. std::unique_ptr<NSObject, NSObjectDeleter> window;
  112. std::unique_ptr<BluetoothMidiPairingWindowClass::Callbacks> callbacks;
  113. JUCE_DECLARE_WEAK_REFERENCEABLE (BluetoothMidiSelectorWindowHelper)
  114. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BluetoothMidiSelectorWindowHelper)
  115. };
  116. //==============================================================================
  117. bool BluetoothMidiDevicePairingDialogue::open (ModalComponentManager::Callback* exitCallback,
  118. Rectangle<int>* bounds)
  119. {
  120. new BluetoothMidiSelectorWindowHelper (exitCallback, bounds);
  121. return true;
  122. }
  123. bool BluetoothMidiDevicePairingDialogue::isAvailable()
  124. {
  125. return true;
  126. }
  127. #else
  128. bool BluetoothMidiDevicePairingDialogue::open (ModalComponentManager::Callback* exitCallback,
  129. Rectangle<int>*)
  130. {
  131. std::unique_ptr<ModalComponentManager::Callback> cb (exitCallback);
  132. // This functionality is unavailable when targetting OSX < 10.11. Instead,
  133. // you should pair Bluetooth MIDI devices using the "Audio MIDI Setup" app
  134. // (located in /Applications/Utilities).
  135. jassertfalse;
  136. return false;
  137. }
  138. bool BluetoothMidiDevicePairingDialogue::isAvailable()
  139. {
  140. return false;
  141. }
  142. #endif
  143. } // namespace juce