|
20 | 20 | #include "scintilla_bridge.h" |
21 | 21 | #include "handle_registry.h" |
22 | 22 | #include "settings_manager.h" |
| 23 | +#include "plugin_manager.h" |
| 24 | +#include "Notepad_plus_msgs.h" |
23 | 25 | #include "file_monitor_mac.h" |
24 | 26 | #include "brace_match.h" |
25 | 27 | #include "smart_highlight.h" |
@@ -251,12 +253,41 @@ - (void)applicationDidFinishLaunching:(NSNotification*)notification |
251 | 253 | return; |
252 | 254 | } |
253 | 255 |
|
| 256 | + // Register main Scintilla view with HandleRegistry so SendMessage(sciHandle, SCI_*, ...) works |
| 257 | + { |
| 258 | + HandleRegistry::WindowInfo sciInfo{}; |
| 259 | + sciInfo.nativeView = ctx().scintillaView; |
| 260 | + sciInfo.className = L"Scintilla"; |
| 261 | + sciInfo.isScintilla = true; |
| 262 | + sciInfo.parent = ctx().mainHwnd; |
| 263 | + ctx().scintillaMainHwnd = HandleRegistry::createWindow(std::move(sciInfo)); |
| 264 | + } |
| 265 | + |
254 | 266 | configureScintilla(ctx().scintillaView); |
255 | 267 | applyAppearance(); |
256 | 268 | if (ctx().documentMapEnabled) |
257 | 269 | initializeDocumentMap(); |
258 | 270 | setSyncScrollingEnabled(ctx().syncScrolling); |
259 | 271 |
|
| 272 | + // Pre-create the second Scintilla view (hidden) so plugins always have a valid handle. |
| 273 | + // doSplit() will reuse this view instead of creating a new one. |
| 274 | + { |
| 275 | + NSView* hiddenContainer = [[NSView alloc] initWithFrame:NSZeroRect]; |
| 276 | + hiddenContainer.hidden = YES; |
| 277 | + [ctx().editorContainer addSubview:hiddenContainer]; |
| 278 | + ctx().scintillaView2 = ScintillaBridge_createView((__bridge void*)hiddenContainer, 0, 0, 0, 0); |
| 279 | + if (ctx().scintillaView2) |
| 280 | + { |
| 281 | + HandleRegistry::WindowInfo sci2Info{}; |
| 282 | + sci2Info.nativeView = ctx().scintillaView2; |
| 283 | + sci2Info.className = L"Scintilla"; |
| 284 | + sci2Info.isScintilla = true; |
| 285 | + sci2Info.parent = ctx().mainHwnd; |
| 286 | + ctx().scintillaSecondHwnd = HandleRegistry::createWindow(std::move(sci2Info)); |
| 287 | + configureScintilla(ctx().scintillaView2); |
| 288 | + } |
| 289 | + } |
| 290 | + |
260 | 291 | // Scintilla notification callback for main view |
261 | 292 | ScintillaBridge_setNotifyCallback(ctx().scintillaView, (intptr_t)ctx().mainHwnd, |
262 | 293 | [](intptr_t windowid, unsigned int iMessage, uintptr_t wParam, uintptr_t lParam) { |
@@ -368,6 +399,9 @@ - (void)applicationDidFinishLaunching:(NSNotification*)notification |
368 | 399 | if (MacroManager::instance().isRecording()) |
369 | 400 | MacroManager::instance().recordStep(scn->message, scn->wParam, scn->lParam); |
370 | 401 | } |
| 402 | + |
| 403 | + // Forward Scintilla notifications to plugins |
| 404 | + pluginManager().notify(reinterpret_cast<const SCNotification*>(scn)); |
371 | 405 | } |
372 | 406 | }); |
373 | 407 |
|
@@ -515,6 +549,25 @@ - (void)applicationDidFinishLaunching:(NSNotification*)notification |
515 | 549 | bindDocumentMapToActiveView(); |
516 | 550 | updateDocumentMapViewport(); |
517 | 551 |
|
| 552 | + // Initialize plugin system |
| 553 | + { |
| 554 | + NppData nppData; |
| 555 | + nppData._nppHandle = ctx().mainHwnd; |
| 556 | + nppData._scintillaMainHandle = ctx().scintillaMainHwnd; |
| 557 | + nppData._scintillaSecondHandle = ctx().scintillaSecondHwnd; |
| 558 | + pluginManager().init(nppData); |
| 559 | + pluginManager().loadPlugins(); |
| 560 | + pluginManager().initMenu(getPluginsMenuHandle()); |
| 561 | + } |
| 562 | + |
| 563 | + // Notify plugins that initialization is complete |
| 564 | + { |
| 565 | + SCNotification readyNotif{}; |
| 566 | + readyNotif.nmhdr.hwndFrom = ctx().mainHwnd; |
| 567 | + readyNotif.nmhdr.code = NPPN_READY; |
| 568 | + pluginManager().notify(&readyNotif); |
| 569 | + } |
| 570 | + |
518 | 571 | NSLog(@"=== Notepad++ macOS Port — Phase 7 ==="); |
519 | 572 | NSLog(@"Settings, split view, edit commands, encoding, session, drag-and-drop!"); |
520 | 573 | } |
@@ -590,6 +643,26 @@ - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender |
590 | 643 |
|
591 | 644 | - (void)applicationWillTerminate:(NSNotification*)notification |
592 | 645 | { |
| 646 | + // Notify plugins that we are shutting down |
| 647 | + { |
| 648 | + SCNotification shutdownNotif{}; |
| 649 | + shutdownNotif.nmhdr.hwndFrom = ctx().mainHwnd; |
| 650 | + shutdownNotif.nmhdr.code = NPPN_SHUTDOWN; |
| 651 | + pluginManager().notify(&shutdownNotif); |
| 652 | + } |
| 653 | + |
| 654 | + // Destroy Scintilla HWNDs to release HandleRegistry-retained native views |
| 655 | + if (ctx().scintillaSecondHwnd) |
| 656 | + { |
| 657 | + HandleRegistry::destroyWindow(ctx().scintillaSecondHwnd); |
| 658 | + ctx().scintillaSecondHwnd = nullptr; |
| 659 | + } |
| 660 | + if (ctx().scintillaMainHwnd) |
| 661 | + { |
| 662 | + HandleRegistry::destroyWindow(ctx().scintillaMainHwnd); |
| 663 | + ctx().scintillaMainHwnd = nullptr; |
| 664 | + } |
| 665 | + |
593 | 666 | saveSession(); |
594 | 667 |
|
595 | 668 | auto& s = SettingsManager::instance().settings; |
|
0 commit comments