my dock menu always be added "Quit" and other 2 menu items automatically, how may I block / modify them?
updated:
really NO way to delete/block/redirect the "Quit" menu item.
used Peter's recommendation at last like blow
hope helpful to others
-(NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
if (needPassword)
{
[self checkPassword:self];
return NSTerminateCancel;
}
else
{
return NSTerminateNow;
}
}
-(void)checkPassword:(id)sender
{
if(passwordCorrect)
{
!needPassword;
[[NSApplication sharedApplication] terminate:self];
}
}
Trying to intercept all possible ways the user might tell your application to quit is bound to fail. (Did you remember the Quit Apple Event?)
It'll be both easier and more effective to just implement the applicationShouldTerminate: method in your application's delegate. Put up the password panel and return NSTerminateLater. Then, when the user either enters the correct password or cancels, send the application a replyToApplicationShouldTerminate: message.
Whichever Quit commands (menu items, etc.) you've already ripped out, put them back. Let the user invoke the normal Quit command in the normal way; that will trigger the aforementioned should-terminate procedure to determine whether the quit will actually happen.
1)Open the MainMenu.xib
2)Create your own dock menu
3)Right click on the File's Owner (NSApplication instance)
4)Connect the property "dockMenu" with your custom menu
If you want to do that because of learning purposes it's fine. However, when you want to sell this application you should reconsider this. Users expect your app to have a quit button in the dock menu.
Related
I have an application that manages different types of NSDocument subclasses (along with matching NSWindow subclasses).
For instance, it's possible that the app has one window of type A open, and two windows of type B.
Now, if a window of type B is active, and the user chooses "Close All" or hits cmd+option+W, all my app's windows are sent the close message.
But I only want all of the active window type's windows closed instead, i.e. only the two type B, not the type A window. How do I accomplish this?
I currently have no explicit menu entry for "Close All". Instead, macOS provides that automagically. If there perhaps a way to intercept a "closeAll" message? Can't find one, though.
AppKit will add the Close All menu item if there isn't one. Add an alternate menu item item with key equivalent cmd+option+W below the Close menu and connect it to your own action method.
You might succeed with overriding your document's canClose(withDelegate:,shouldClose:,contextInfo:) to return whether a document should be closed.
If this doesn't behave the way you want, you can create a subclass of NSDocumentController (if you don't have one already). Details on how to do that vary, but usually you have main (menu) XIB or main Storyboard, which has a "Document Controller" object: set its class to your custom class.
Then override closeAllDocuments(withDelegate:,didCloseAllSelector:,contextInfo:) and implement your custom logic.
Note that you should detect whether your app is about to quit and then really do close all you documents (unless you really want to prevent the app quit, e.g. because a document is dirty).
After some digging I figured out where the auto-generated "Close All" menu item sends its action to: To the closeAll: selector of the application target:
Thus my solution is to subclass NSApplication and implement the handler there, which then simply closes all windows that are of the same type (this assumes that I use specific subclasses for my different types of windows):
- (IBAction)closeAll:(id)sender {
Class windowClass = self.keyWindow.class;
for (NSWindow *w in self.windows) {
if (windowClass == w.class) {
[w performClose:sender];
}
}
}
Caution: If you adopt this pattern be aware that:
The closeAll: selector is not documented nor mentioned in the header files, meaning that Apple might feel free to change in a future SDK, though I find that unlikely. It will probably not break anything if that happens, but instead your custom handler won't be called any more.
The code simply tells all windows to close, ignoring the fact that one might reject to be closed, e.g. by user interaction. In that case you may want to stop the loop instead of continuing to close more windows (though I know of no easy way to accomplish that).
this is probably dead easy but I can't find a solution. I made a dialogue system and have a UI-button to click when the player should display a sentence next.
The issue is that the button is only triggered onMouseclick and I would like to change the input button to Enter. Would anyone know how to go about this?
If you need to determine if the button is selected first or not, I suggest you take a look at this page: https://docs.unity3d.com/ScriptReference/UI.Selectable.IsHighlighted.html
If you don't want pressing the button to have any functionality, you just wouldn't link it to any functions.
Working code might look something like this:
public class selectableExample : Selectable{
BaseEventData _event;
void Update()
{
if (IsHighlighted(_event) == true)
{
if (Input.GetKeyDown("enter")){
print("replace me with working function"); // whatever you want to have happen on button press
}
}
}
}
You simply attach this to your button and it should respond the same as being pressed. To be honest, it hardly seems like you actually need a button at all for this though, you'd probably be fine with just a label telling the player to press "Enter" and then simply checking for that input.
You can use the Event Trigger component to use one of the many event types. Select Submit (this is set to enter and return in the input settings at edit>project settings>input by default).
Don't set anything in the OnClick event.
The only thing needed now is to actively highlight the button from somewhere with ReferenceToButton.Select().
I am newbie to MFC. I have a native C++ MFC app. I want to show a dialog from main dialog. In the main dialog I am having three button (Back, Next, Cancel) respectively.
On the Next button click event I am calling DoModal to show another dialog by hiding the main dialog as follows,
void CFirstPage::OnBnNextButton()
{
::ShowWindow(this->GetSafeHwnd(),SW_HIDE);
CSecondPage secondDlg;
secondDlg.DoModal();
}
void CSecondPage::OnBnBackBtnClicked()
{
::ShowWindow(this->GetSafeHwnd(),SW_HIDE);
CFirstPage FirstPage;
FirstPage.DoModal();
}
After executing this code snippet, the main dialog got hidden and even the application icon also disappears from the taskbar and again appears when the other dialog pops up.
(Basically I am having the same icon for both the dialogs, the icon should not get disappeared and appear again. It has to remain same without appearing and disappearing .)
How can show the icon in the taskbar without any flickering effect?
During traversing from back to next in middle I clicked cancel and the Cancel event is handled as follows,
void CFirstPage::OnCancel()
{
CDialog::EndDialog(TRUE);//For closing the dialog.
}
void CSecondPage::OnCancel()
{
CDialog::EndDialog(TRUE);//For closing the dialog.
}
Steps1:Click Next in the main dialog
Step2: Click Cancel in the second page
Now the application closes. But still instance is active in the "TaskManager". As per my understanding no instance should be alive once windows is closed ?
I suspect as the first dialog is only hidden not ended that instance is still existing in the TaskManager. Is this understanding correct?
How can I resolve this issue?
Can anyone kindly help me to resolve this issue.
As said by Iinspectable property sheets are best suited for your your problem statement.A very good example on how to use CPropertysheets can be found in codeproject
CProperty sheet example
Probably your main windows is still hidden after you end dialog with second page. Ending dialog of CSecondPage does not close application only closes active CSecondPage dialog.
Also OnCancel/OnOK does not need to be overriden if you just EndDialog with it. There is default behaviour implemented in OnCancel, which will close the dialog.
After secondPage.DoModal() show your main dialog again, or close it if that is the behaviour you want to achieve.
FirstPage isn't the original first dialog now, so you should store the first dialog object by yourself. You can do that like this:
void CFirstPage::OnBnNextButton()
{
::ShowWindow(this->GetSafeHwnd(),SW_HIDE);
CSecondPage secondDlg;
secondDlg.setFirstDialog(this); //customer function to store first dialig object
secondDlg.DoModal();
}
void CSecondPage::OnBnBackBtnClicked()
{
::ShowWindow(this->GetSafeHwnd(),SW_HIDE);
::ShowWindow(m_firstDialog->GetSafeHwnd(), SW_SHOW);
}
I have an application with LSUIElement set to 1. It has a built-in editor, so I want the application to appear in Cmd+Tab cycle when the editor is open.
-(void)stepIntoForeground
{
if (NSAppKitVersionNumber < NSAppKitVersionNumber10_7) return;
if (counter == 0) {
ProcessSerialNumber psn = {0, kCurrentProcess};
OSStatus osstatus = TransformProcessType(&psn, kProcessTransformToForegroundApplication);
if (osstatus == 0) {
++counter;
} else {
//...
}
}
}
-(void)stepIntoBackground
{
if (NSAppKitVersionNumber < NSAppKitVersionNumber10_7) return;
if (counter == 0) return;
if (counter == 1) {
ProcessSerialNumber psn = {0, kCurrentProcess};
OSStatus osstatus = TransformProcessType(&psn, kProcessTransformToUIElementApplication);
if (osstatus == 0) {
--counter;
} else {
//..
}
}
}
The problems are:
there's also a Dock icon (not a big deal);
there's also Menu, that is not a big deal too, but they appear not always.
Is there any way to disable menu at all or to make it appear always in foreground? Thanks in advance.
This is how we do it.
(Works 10.7+)
DO NOT USE LSBackgroundOnly NOR LSUIElement in the app plist
Add and init your menu and NSStatusBar menu
After app initialized but not yet shown any window take a place where you might want to show the first window if any. We use applicationDidFinishLaunching.
If you do not want to show any window yet after app initialized use
[NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];
on 10.9 you can use at last the otherwise much correct
[NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
If you should open any window after app init finished than simply show the main window
Maintain your list of windows
If last window closed, call
[NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];
on 10.9 you can use at last the otherwise much correct
[NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
When your first window shown next time, call
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
[NSApp activateIgnoringOtherApps:YES];
[[self window] makeKeyAndOrderFront:nil];
This should do the trick, if at least one app window is visible you will have menu, dock icon with state signaled, and cmd+tab element with your app, if last app window closed only your NSStatusBar element stays.
Known issues:
The first step is important because without that if a system modal dialog suspends your startup (f.e. your app is downloaded from the net and become quarantined a confirmation dialog might appear at first startup depending on your security settings) your menubar might not be owned by your app after your first app window shown.
Workaround: Starting as normal app (step 1.) would solve this problem, but will cause another small one, your app icon might appear for a moment in the dock at startup even if you would like to startup without any window shown. (but we can deal with this, not owning the menubar was a bigger problem for us, so we chose this instead)
Changing between NSApplicationActivationPolicyRegular and NSApplicationActivationPolicyAccessory (or NSApplicationActivationPolicyProhibited on OSes bellow 10.9) will kill your tooltip of status bar menu element, the tooltip will be shown initially but will not ever after the second call of NSApplicationActivationPolicyAccessory -> NSApplicationActivationPolicyProhibited
Workaround: We could not find a working workaround for this and reported to Apple as a bug.
Changing from NSApplicationActivationPolicyRegular to NSApplicationActivationPolicyAccessory has other problems on some OS versions like there might be no more mouse events in visible app windows sometimes
Workaround: switch first to NSApplicationActivationPolicyProhibited (take care this leads to unwanted app messages, like NSApplicationWillResignActiveNotification, NSWindowDidResignMainNotification, etc. !)
Changing from NSApplicationActivationPolicyAccessory to NSApplicationActivationPolicyRegular is bogus as on some OS versions
the app main menu is frozen till the first app front status change
the app activated after this policy not always get placed front in the application order
Workaround: switch first to NSApplicationActivationPolicyProhibited, take care the final switch to the desired NSApplicationActivationPolicyRegular should be made delayed, use f.e. dispatch_async or similar
With swift 4, in applicationDidfinishLaunching(_:Notification)
NSApplication.shared.setActivationPolicy(.regular)
did the trick for me, but I was only trying to get keyboard focus to my programmatically created window. Thanks.
You can set App "Application is agent (UIElement)" to YES in your plist file.
EDIT:
I think there are some hacks to do this.
But it's really not the way it's meant to be.
Cmd+tab is for getting an application to foreground, but if you don't have a menu bar, it doesn't look like foreground to the user.
I'd rather make a menu bar to access the app.
I'm writing a super cool app with a preferences panel. If a user opens the preferences panel, makes a change to her preferences, and then closes the panel without saving those changes, she will be greeted by an NSAlert informing her of the dire consequences. The NSAlert sheet has two buttons, "OK" and "Cancel". If the user presses "OK", then the sheet and the prefs panel should close. If the user presses "Cancel", then the sheet should close, but not the prefs panel.
Here's a simplified version of the code in question:
def windowShouldClose
window_will_close = true
unless self.user_is_aware_of_unsaved_changes
window_will_close = false
alert = make_appropriate_NSAlert # this method returns an NSAlert
alert.beginSheetModalForWindow(self.window,
modalDelegate: self,
didEndSelector: :'userShouldBeAware:returnCode:contextInfo:',
contextInfo: nil)
end
window_will_close
end
def userShouldBeAware(alert, returnCode:returnCode, contextInfo:contextInfo)
if returnCode == NSAlertFirstButtonReturn
self.user_is_aware_of_unsaved_changes = true
end
end
def windowDidEndSheet(notification)
self.window.performClose(self) if self.user_is_aware_of_unsaved_changes
end
I believe that I have made my super cool app perform the necessary duties, but I am concerned that this is not the way Apple intended or would recommend for me to implement this feature. It feels like a hack, and I was nowhere told explicitly that this is the way to do it. I tried a number of things before stumbling upon this solution.
I would like to make model mac apps. Is there some patten or document that goes into more detail about this? I have read Apple's documentation for the NSAlert class and their article on Sheet Programming Topics.
Thanks!
First off, according to the HIG, preference panes should not ask to cancel or confirm. Just auto-save whenever the user changes something. For reference, see how iTunes handles its preferences.
If you do want a save dialog, here's what I do. It can come in handy for when the user closes the app window and there's things to save. I use a drawer. That's a panel that I store in my MainMenu .nib file. Then I make it available as instance variable doneWindow, all using InterfaceBuilder and some clicking. Some more clicking in InterfaceBuilder registers the following two methods to be invoked at the appropriate events.
def showSaveDialog
NSApp.beginSheet( doneWindow,
modalForWindow: mainWindow,
modalDelegate: self,
didEndSelector: "didEndSheet:returnCode:contextInfo:".to_sym,
contextInfo: nil)
end
def save(bla)
NSApp.endSheet doneWindow
Pomodoro.new(:text => doneText).save
notifyLabelUpdate
end
def didEndSheet(bla, returnCode: aCode, contextInfo: bla3)
doneWindow.orderOut self
end
Note that the guide on sheets that you point to is the most confusing guide I've seen anywhere on the Apple documentation.