Merge pull request #110 from tesselode/fixes
[wdl/wdl-ol.git] / WDL / swell / swellappmain.mm
blobfc76595c052c5e14c79ef1a06a963ab3a2f65b91
1 /* Cockos SWELL (Simple/Small Win32 Emulation Layer for Linux/OSX)
2    Copyright (C) 2006 and later, Cockos, Inc.
4     This software is provided 'as-is', without any express or implied
5     warranty.  In no event will the authors be held liable for any damages
6     arising from the use of this software.
8     Permission is granted to anyone to use this software for any purpose,
9     including commercial applications, and to alter it and redistribute it
10     freely, subject to the following restrictions:
12     1. The origin of this software must not be misrepresented; you must not
13        claim that you wrote the original software. If you use this software
14        in a product, an acknowledgment in the product documentation would be
15        appreciated but is not required.
16     2. Altered source versions must be plainly marked as such, and must not be
17        misrepresented as being the original software.
18     3. This notice may not be removed or altered from any source distribution.
20   
21 #import "swellappmain.h"
23 #include "swell.h"
24 #include "swell-internal.h"
27 HMENU SWELL_app_stocksysmenu; // exposed to app, simply the contents of the default system menu (as defined in the nib)
28 static bool IsMultiLineEditControl(NSView *cv, id fs)
30   if (fs && [fs isKindOfClass:[NSTextView class]])
31   {
32     NSTextView *v = (NSTextView *)fs;
33     if ([v isEditable])
34     {
35       NSView *a=[v superview];
36       while (a && a != cv)
37       {
38         if ([a isKindOfClass:[NSTextField class]]) return false;
39         a = [a superview];
40       }
41       return true;
42     }
43   }
44   return false;
47 @implementation SWELLApplication
48 - (void)sendEvent:(NSEvent *)anEvent
50   int etype = [anEvent type];
51   if (etype == NSKeyUp)
52   {
53     // toss keyup if next keydown is the same key
54     NSEvent *nextDown = [self nextEventMatchingMask:NSKeyDownMask untilDate:[NSDate dateWithTimeIntervalSinceNow:0.003] inMode:NSDefaultRunLoopMode dequeue:FALSE];
55     if (nextDown && [nextDown keyCode] == [anEvent keyCode]) return;
56   }
57   else if (etype == NSKeyDown)
58   {
59     NSEvent *nextDown = [self nextEventMatchingMask:NSKeyDownMask untilDate:[NSDate dateWithTimeIntervalSinceNow:0.003] inMode:NSDefaultRunLoopMode dequeue:FALSE];
60     if (nextDown && [nextDown keyCode] == [anEvent keyCode]) 
61     {
62 #if 0
63       // no need to check timestamps -- if a queued key is there, just ignore this one(prevent a backlog)
64       static double sc=0.0;
65       if (sc == 0.0) 
66       { 
67         struct mach_timebase_info inf={0,};
68         mach_timebase_info(&inf); 
69         if (inf.numer && inf.denom)  sc = inf.numer / (inf.denom * 1000.0 * 1000.0 * 1000.0);
70       }
71       
72       if (sc != 0.0 && [anEvent timestamp] < (double) mach_absolute_time() * sc - 0.05)
73 #endif
74         return;
75     }
76   }
77   
78   
79   NSWindow *modalWindow = [NSApp modalWindow];
80   
81   NSWindow *focwnd=[anEvent window];  
82   NSView *dest_view=NULL;    // only valid when key message
83   
84         if (etype==NSKeyDown||etype==NSKeyUp)
85         {
86     const UINT msgtype = etype==NSKeyDown ? WM_KEYDOWN : WM_KEYUP;
87     int flag,code=SWELL_MacKeyToWindowsKey(anEvent,&flag);
88     
89     if (focwnd)
90     {      
91       if (flag&(FCONTROL|FALT))
92       {
93         NSWindow *f = focwnd;    
94         // handle carbon windows, sending all cmd/alt modified keys to their parent NSView (to be handled later)
95         // perhaps it'd be good to have a flag on these to see if they want it .. i.e. SWELL_SetCarbonHostView_WantKeyFlgs()..
96         while (f)
97         {
98           if ((dest_view=(NSView *)[f delegate]) && [dest_view respondsToSelector:@selector(swellIsCarbonHostingView)] && [(SWELL_hwndCarbonHost*)dest_view swellIsCarbonHostingView])
99           {
100             focwnd = [dest_view window]; 
101             break;
102           }
103           dest_view=0;
104           f=[f parentWindow];
105         }
106       } 
107       if (!dest_view)  // get default dest_view, and validate it as a NSView
108       {
109         if ((dest_view=(NSView *)[focwnd firstResponder]) && ![dest_view isKindOfClass:[NSView class]]) dest_view=NULL;
110       }       
111     }       
112     if (!modalWindow && (!focwnd || dest_view))
113     {          
114       MSG msg={(HWND)dest_view,msgtype,(WPARAM)code,(LPARAM)flag}; // LPARAM is treated differently (giving modifier flags/FVIRTKEY etc) in sWELL's WM_KEYDOWN than in windows, deal with it
115       
116       if (SWELLAppMain(SWELLAPP_PROCESSMESSAGE,(INT_PTR)&msg,(INT_PTR)anEvent)>0) return; 
117     }  
118   }
119   // default window handling:
120   if (etype == NSKeyDown && focwnd && dest_view)
121   {
122     NSView *cv = [focwnd contentView];
123     if (cv && [cv respondsToSelector:@selector(onSwellMessage:p1:p2:)]) //only work for swell windows
124     {
125       int flag,code=SWELL_MacKeyToWindowsKey(anEvent,&flag);
126       int cmdid=0;
127       
128       // todo: other keys (such as shift+insert?)
129       if (((flag&~FVIRTKEY)==FCONTROL && (code=='V'||code=='C' ||code=='X')) && [dest_view isKindOfClass:[NSText class]])
130       {         
131         if (code=='V') [(NSText *)dest_view paste:(id)cv];
132         else if (code=='C') [(NSText *)dest_view copy:(id)cv];
133         else if (code=='X') [(NSText *)dest_view cut:(id)cv];
134         return;
135       }
136       
137       if ((!(flag&~(FVIRTKEY|FSHIFT)) && code == VK_ESCAPE) ||
138           ((flag&~FVIRTKEY)==FCONTROL && code=='W'))
139       {
140         if (code == 'W') cmdid= IDCANCEL; // cmd+w always idcancel's
141         else if (!dest_view || ![dest_view isKindOfClass:[NSTextView class]]) cmdid=IDCANCEL; // not text view, idcancel
142         else if (!(flag&FSHIFT) && !IsMultiLineEditControl(cv,dest_view)) cmdid=IDCANCEL; // if singleline edit and shift not set, idcancel
143         
144         if (!cmdid) 
145         {
146           SetFocus((HWND)cv);
147           return;
148         }
149       }
150       else if (!(flag&~FVIRTKEY) && code == VK_RETURN) 
151       {      
152         // get default button command id, if any, if enabled
153         if (!IsMultiLineEditControl(cv,dest_view))
154         {            
155             cmdid = SWELL_GetDefaultButtonID((HWND)cv,true); 
156             
157             if (!cmdid) // no action, set focus to parent
158             {
159               SetFocus((HWND)cv);
160               return;
161             }
162         }
163       }
164       
165       if (cmdid)
166       {
167         SendMessage((HWND)cv,WM_COMMAND,cmdid,0);
168         return;
169       }
170     } // is swell CV
171   } // key down
172   
173   [super sendEvent:anEvent];
175 @end
178 @implementation SWELLAppController
180 - (void)awakeFromNib
181 {      
182   SWELL_EnsureMultithreadedCocoa();
183   [NSApp setDelegate:self];
185   SWELL_POSTMESSAGE_INIT
186   
187   HMENU stockMenu=(HMENU)[NSApp mainMenu];
188   if (stockMenu)
189   {
190     HMENU nf = GetSubMenu(stockMenu,0);
191     if (nf) SWELL_app_stocksysmenu = SWELL_DuplicateMenu(nf);
192   }
193   
194   SWELLAppMain(SWELLAPP_ONLOAD,0,0);
197 -(IBAction)onSysMenuCommand:(id)sender
199   int a = [sender tag];
200   if (a) SWELLAppMain(SWELLAPP_ONCOMMAND,a,(INT_PTR)sender);
203 - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
205   char buf[4096];
206   buf[0]=0;
207   SWELL_CFStringToCString(filename,buf,sizeof(buf));
208   return buf[0] && SWELLAppMain(SWELLAPP_OPENFILE,(INT_PTR)buf,0)>0;
210 - (BOOL)applicationOpenUntitledFile:(NSApplication *)theApplication
212   return SWELLAppMain(SWELLAPP_NEWFILE,0,0)>0; 
215 - (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender
217   return SWELLAppMain(SWELLAPP_SHOULDOPENNEWFILE,0,0)>0;
220 -(void)applicationDidFinishLaunching:(NSNotification *)aNotification
222   SWELLAppMain(SWELLAPP_LOADED,0,0);
225 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
227   return SWELLAppMain(SWELLAPP_SHOULDDESTROY,0,0) > 0 ? NSTerminateLater : NSTerminateNow;
230 - (void)applicationWillTerminate:(NSNotification *)notification
232   SWELLAppMain(SWELLAPP_DESTROY,0,0);
235 - (void)applicationDidBecomeActive:(NSNotification *)aNotification
237   if (!SWELLAppMain(SWELLAPP_ACTIVATE,TRUE,0))
238     SWELL_BroadcastMessage(WM_ACTIVATEAPP,TRUE,0);
241 - (void)applicationDidResignActive:(NSNotification *)aNotification
243   if (!SWELLAppMain(SWELLAPP_ACTIVATE,FALSE,0))
244     SWELL_BroadcastMessage(WM_ACTIVATEAPP,FALSE,0);
247 SWELL_APPAPI_DELEGATE_IMPL
249 SWELL_POSTMESSAGE_DELEGATE_IMPL
252 @end