diff --git a/uppsrc/CtrlCore/CocoApp.mm b/uppsrc/CtrlCore/CocoApp.mm index 9f8f447e3..2c93b868d 100644 --- a/uppsrc/CtrlCore/CocoApp.mm +++ b/uppsrc/CtrlCore/CocoApp.mm @@ -4,6 +4,22 @@ #ifdef PLATFORM_COCOA +@interface AppDelegate : NSObject +{ +} +@end + +namespace Upp { +NSMenu *Cocoa_DockMenu(); +}; + +@implementation AppDelegate +- (NSMenu *)applicationDockMenu:(NSApplication *)sender +{ + return Upp::Cocoa_DockMenu(); +} +@end + namespace Upp { int Ctrl::WndCaretTime; @@ -48,6 +64,8 @@ void CocoInit(int argc, const char **argv, const char **envptr) [appMenuItem setSubmenu:appMenu]; [NSApp setMainMenu:menubar]; + + [NSApp setDelegate:[[AppDelegate alloc] init]]; NSFont *sysfont = [NSFont systemFontOfSize:0]; Font::SetFace(0, ToString((CFStringRef)[sysfont familyName]), Font::TTF); diff --git a/uppsrc/CtrlCore/CocoCreate.mm b/uppsrc/CtrlCore/CocoCreate.mm index a41f9edef..f2b336714 100644 --- a/uppsrc/CtrlCore/CocoCreate.mm +++ b/uppsrc/CtrlCore/CocoCreate.mm @@ -27,6 +27,13 @@ return active && ctrl && ctrl->IsEnabled() && dynamic_cast(~ctrl) && !ctrl->GetOwner(); } +- (NSMenu *)applicationDockMenu:(NSApplication *)sender { + NSMenu *menu = [[[NSMenu alloc] initWithTitle:@"DocTile Menu"] autorelease]; + NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:@"Hello" action:@selector(hello) keyEquivalent:@"k"] autorelease]; + [menu addItem:item]; + return menu; +} + @end namespace Upp { @@ -45,7 +52,7 @@ Ctrl *Ctrl::GetActiveCtrl() for(Ctrl *p : mmtopctrl) if(p && p->top && p->top->coco && p->top->coco->window.keyWindow) return p; - return NULL; + return lastActive; } bool Ctrl::SetWndFocus() diff --git a/uppsrc/CtrlCore/CocoCtrl.h b/uppsrc/CtrlCore/CocoCtrl.h index 714303ec6..b609314dc 100644 --- a/uppsrc/CtrlCore/CocoCtrl.h +++ b/uppsrc/CtrlCore/CocoCtrl.h @@ -11,6 +11,7 @@ private: static bool WndCaretVisible; static bool local_dnd_copy; static void AnimateCaret(); + static Ptr lastActive; friend void CocoInit(int argc, const char **argv, const char **envptr); diff --git a/uppsrc/CtrlCore/CocoProc.mm b/uppsrc/CtrlCore/CocoProc.mm index 9119372dd..c723e4c9a 100644 --- a/uppsrc/CtrlCore/CocoProc.mm +++ b/uppsrc/CtrlCore/CocoProc.mm @@ -12,6 +12,8 @@ static bool coco_mouse_right; static int coco_flags; static Upp::Ptr coco_capture; +Upp::Ptr Upp::Ctrl::lastActive; + namespace Upp { extern id menubar; @@ -113,6 +115,7 @@ struct MMImp { static bool MouseDownEvent(CocoView *view, NSEvent *e, int button) { + Upp::Ctrl::lastActive = view->ctrl; if(Ctrl::ignoremouseup) { Ctrl::KillRepeat(); Ctrl::ignoreclick = false; @@ -179,6 +182,7 @@ struct MMImp { static void BecomeKey(Upp::Ctrl *ctrl) { LLOG("Become key " << Upp::Name(ctrl)); + Upp::Ctrl::lastActive = ctrl; ctrl->ActivateWnd(); auto tw = dynamic_cast(ctrl); if(tw && tw->placefocus) { diff --git a/uppsrc/CtrlCore/CocoTop.h b/uppsrc/CtrlCore/CocoTop.h index 18bce5daf..acbee0398 100644 --- a/uppsrc/CtrlCore/CocoTop.h +++ b/uppsrc/CtrlCore/CocoTop.h @@ -8,14 +8,18 @@ protected: virtual void MMClose() { WhenClose(); } - static TopWindow *GetMenuTopWindow(); static void SyncMainMenu(bool force); void *menubar = NULL; Event MainMenu; +public: // really private: + static TopWindow *GetMenuTopWindow(bool dock); + public: virtual bool HotKey(dword key); + + Event WhenDockMenu; void SetMainMenu(Event menu); //$ }; \ No newline at end of file diff --git a/uppsrc/CtrlCore/cocotodo.txt b/uppsrc/CtrlCore/cocotodo.txt index 921af073f..67e96e5ab 100644 --- a/uppsrc/CtrlCore/cocotodo.txt +++ b/uppsrc/CtrlCore/cocotodo.txt @@ -3,6 +3,8 @@ brew install gdb sooner: +- replace block dialog has wrong layout + - dropping DropList several times can lead to focus issue - cursor problem after local menu invocation (better, but still...) diff --git a/uppsrc/CtrlLib/MacMenu.mm b/uppsrc/CtrlLib/MacMenu.mm index aa51f77de..bcccc922f 100644 --- a/uppsrc/CtrlLib/MacMenu.mm +++ b/uppsrc/CtrlLib/MacMenu.mm @@ -25,6 +25,7 @@ namespace Upp { struct CocoMenuBar : public Bar { CocoMenu *cocomenu; int lock = 0; + bool dockmenu = false; struct Item : Bar::Item { NSMenuItem *nsitem; @@ -85,14 +86,27 @@ struct CocoMenuBar : public Bar { void Set(Event bar); - CocoMenuBar() { + void Clear() { + item.Clear(); + if(cocomenu) { + [cocomenu release]; + cocomenu = NULL; + } + } + void New() { + Clear(); cocomenu = [CocoMenu new]; cocomenu.autoenablesItems = NO; cocomenu->ptr = this; cocomenu.delegate = cocomenu; } + + CocoMenuBar() { + cocomenu = NULL; + New(); + } ~CocoMenuBar() { - [cocomenu release]; + Clear(); } }; @@ -189,6 +203,8 @@ bool CocoMenuBar::IsEmpty() const - (void)menuWillOpen:(NSMenu *)menu { CocoMenu *m = (CocoMenu *)menu; + if(m && m->ptr && m->ptr->dockmenu) + return; if(m && m->ptr && proc) { [m removeAllItems]; proc(*m->ptr); @@ -197,6 +213,8 @@ bool CocoMenuBar::IsEmpty() const - (void)menuDidClose:(NSMenu *)menu { CocoMenu *m = (CocoMenu *)menu; + if(m && m->ptr && m->ptr->dockmenu) + return; [m removeAllItems]; } @@ -234,15 +252,17 @@ bool TopWindow::HotKey(dword key) return Ctrl::HotKey(key); } -TopWindow *TopWindow::GetMenuTopWindow() +TopWindow *TopWindow::GetMenuTopWindow(bool dock) { Ctrl *q = GetFocusCtrl(); + if(!q) + q = GetActiveCtrl(); if(!q) return NULL; q = q->GetTopCtrl(); while(q) { TopWindow *w = dynamic_cast(q); - if(w && w->menubar) + if(w && (dock ? (bool)w->WhenDockMenu : (bool)w->menubar)) return w; q = q->GetOwner(); } @@ -251,7 +271,7 @@ TopWindow *TopWindow::GetMenuTopWindow() void TopWindow::SyncMainMenu(bool force) { - TopWindow *w = GetMenuTopWindow(); + TopWindow *w = GetMenuTopWindow(false); static TopWindow *current; if(w != current || force) { current = w; @@ -264,7 +284,7 @@ void TopWindow::SyncMainMenu(bool force) void MenuBar::ExecuteHostBar(Ctrl *owner, Point p) { - if(host_bar) { + if(host_bar && owner) { CocoMenuBar& bar = *(CocoMenuBar *)~host_bar; owner = owner->GetTopCtrl(); @@ -289,6 +309,25 @@ void MenuBar::CreateHostBar(One& bar) host_bar.Create(); } +NSMenu *Cocoa_DockMenu() { + Upp::TopWindow *w = Upp::TopWindow::GetMenuTopWindow(true); + + if(w && w->WhenDockMenu) { + static Upp::CocoMenuBar bar; + bar.dockmenu = true; + bar.Clear(); + bar.cocomenu = [[[CocoMenu alloc] initWithTitle:@"DocTile Menu"] autorelease]; + bar.cocomenu.autoenablesItems = NO; + bar.cocomenu->ptr = &bar; + bar.cocomenu.delegate = bar.cocomenu; + w->WhenDockMenu(bar); + CocoMenu *m = bar.cocomenu; + bar.cocomenu = NULL; + return m; + } + return nil; +} + }; #endif