Source language: Translate to:

Changing shutdown behavior in System Tray Apps

Questions about using NeoBook's scripting language

Moderator: Neosoft Support

Changing shutdown behavior in System Tray Apps

Postby Enigman » Wed Mar 22, 2006 4:10 pm

Hello,

I have a small app compiled as a system tray application. I want the system window frame (title bar) buttons for minimize and close (the X) to do the same thing, namely minimize back to the system tray. Exiting the application would only be via the tray menu "Exit" command.

I have accomplished this by placing code in the book's shutdown tab that checks the value of a variable called [ExitOkay]. If it is FALSE or NULL, then it sets [ShutdownStatus] to FALSE and sets [WindowState] to "minimized". The system tray menu Exit option first sets [ExitOkay] to TRUE. Therefore, the program will exit normally when the menu Exit option is chosen.

This all works fine and as intended except for one huge problem. Whenever the app is sitting on the system tray, it is impossible to shutdown Windows. Windows tells the app to close and since it has not set the proper state for [ExitOkay] it refuses and blocks Windows from shutting down.

Has anyone come up with a solid way to work around this issue?

Thanks.
User avatar
Enigman
 
Posts: 314
Joined: Tue Apr 12, 2005 3:57 pm
Location: Foothill Ranch, CA

Postby Gaev » Wed Mar 22, 2006 6:39 pm

Enigman:

Has anyone come up with a solid way to work around this issue?
You say that ... When the user clicks on the Minimize Window or Close Window buttons on your applications's Title Bar, the application window is minimized ... I guess you accomplish this with something like ...
Code: Select all
If "[ExitOkay]" "=" ""
   SetVar "[ShutdownStatus]" "False"
   SetVar "[WindowState]" "minimized"
   SetVar "[ExitOkay]" "True"
   Return
EndIf
If "[ExitOkay]" "=" "False"
   SetVar "[ShutdownStatus]" "False"
   SetVar "[WindowState]" "minimized"
   SetVar "[ExitOkay]" "True"
   Return
EndIf

... [ExitOkay] must be "True"
SetVar "[ShutdownStatus]" "True"

... in the ShutDown section ... but you don't say how (what actions) the application window is Restored/Maximized again from its "minimized" state ? ... another System Tray menu item ? another (non-user) event ?

In any case, what if you were to check for the value of [WIndowState] (or one/more of [WindowLeft], [WindowTop], [WindowWidth] or [WindowHeight]) BEFORE checking for the value of [ExitOkay] in the ShutDown section i.e. ...
Code: Select all
If "[WindowState]" "=" "minimized"
   ... if window is already minimized, Shutdown request can only be made from Exit menu item in System Tray
   SetVar "[ShutdownStatus]" "True"
   Return
EndIf
... you would catch the situation where "Windows asks the application's permission" when it was already minimized (in the system tray) ... but I don't think it would catch one other situation ... viz. if the user tried to shutdown while your application was in a restored/maximized state ... in this state, there would be no way to differentiate between direct/specific user request (via application window's close button) and indirect request (via shutdown request to Windows) ... hopefully, user is smart enough to click on the application window's close button first ... and try shutdown again if need be.

I haven't actually tried this but if there is a flaw in the logic perhaps you can provide some of the answers to earlier questions.
User avatar
Gaev
 
Posts: 3737
Joined: Fri Apr 01, 2005 7:48 am
Location: Toronto, Canada

Postby Enigman » Wed Mar 22, 2006 7:59 pm

Gaev,

Thanks for replying.

Regarding the second code example, it doesn't do me any good to check the window state at shutdown time since all states must operate the same way in response to a Windows shutdown. You'll see why below.

In your first code example, there are three possible states for [ExitOkay]; True, False, and Null. You tested for Null and False which leaves True as the default. I need the opposite. If you reverse your logic you can reduce the code to this:

If "[ExitOkay]" "<>" "True"
SetVar "[ShutdownStatus]" "False"
SetVar "[WindowState]" "minimized"
EndIf

and then False is the default, which is exactly what I had and what it must be.

However, you cannot set [ExitOkay] to True inside the shutdown tab. If you did, then the next time the user opened the program and clicked the X button, the program would exit. In the same way it would not do any good to set [ShutdownStatus] back to True at the end of the script since the program would then minimize and continue to exit as the last act of the script. Even if it didn't exit, the next time anything except the tray menu Exit function tried to close the program, the If block in the shutdown tab would set it back to False before proceeding.

The problem is that there are two important events that I cannot trap "outside of the shutdown action script"; clicking the X and opening the program from the system tray. Likewise, Activate and Deactivate are not triggered from the system tray. Therefore, I cannot detect when the user has opened the program and the only event that I CAN trap is taking the Exit choice from the tray menu or from a program button. That means that the menu Exit event must set the [ExitOkay] = True, and all other events must rely on the default of Null or False.

The clash with Windows shutdown comes from the fact that the default state of [ExitOkay] is False and Window's attempt to close the program is not a trapable event so it remains False and the app simply loops back into a minimized running state no matter how hard Windows tries to kill it. The same thing happens if the app is left open during Windows shutdown. It simply minimizes and then clings to a running state.

I have other commercial programs that do what I want, such as ICQ, which can only be shutdown from a menu choice. If I was working in a "routine" compiled language I would probably have access to the system X event trap, but in NeoBook we don't have that (yet).

Of course, one solution I am using now is to shut off the system menu and title bar buttons and have a 'Close" button on the program screen, or I could eliminate the entire title bar and make minimize and maximize buttons of my own, but I really wanted the recognition factor of the system's own buttons and menu.

But even with such limitations, you know how we programmers are ... we often find back door workarounds, so I just had to ask if anyone has solved this before. :wink:

Thanks again.
User avatar
Enigman
 
Posts: 314
Joined: Tue Apr 12, 2005 3:57 pm
Location: Foothill Ranch, CA

Postby Gaev » Wed Mar 22, 2006 9:29 pm

Enigman:
However, you cannot set [ExitOkay] to True inside the shutdown tab. If you did, then the next time the user opened the program and clicked the X button, the program would exit.
... that is why I asked the question about how (what actions) the application window is Restored/Maximized again from its "minimized" state ? ... another System Tray menu item ? another (non-user) event ? ... to which I now know the answer ...I cannot trap ... opening the program from the system tray. ... which begs the question ...what event triggers the command to set the variable [ExitOkay] to "true" ?

There is a way to allow shutdown of the program by Windows (as part of the computer shutdown request) while it is in a minimized (tray) state ... by using a Timer object as described below.

However, there is no way to differentiate between a shutdown section being invoked by user clicking on the Close WIndow button and user requesting a shutdown of the computer (which in turn requests your application to shut itself down).


If your application can stand it, you could have a Timer object running all the time ... say every 250 MilliSeconds or so ...
Code: Select all
If "[WindowState]" "<>" "minimized"
   SetVar "[ExitOkay]" "False"
EndIf
... which would make sure that 250 MilliSeconds after the application window is activated, [ExitOkay] would be setup properly.

Now, consider this (consolidated) code for the application's ShutDown section ...
Code: Select all
If "[WindowState]" "=" "minimized"
   ... if window is already minimized, Shutdown request can only be made from Exit menu item in System Tray
   SetVar "[ShutdownStatus]" "True"
   Return
EndIf

If "[ExitOkay]" "<>" "True"
   SetVar "[ShutdownStatus]" "False"
   SetVar "[WindowState]" "minimized"
   SetVar "[ExitOkay]" "True"
   Return
Else
   SetVar "[ShutdownStatus]" "True"
   Return
EndIf
... note the minor difference from your code in that I have Return commands which cause immediate exit from the ShutDown section ... and NeoBook will then take appropriate action depending on the value of the (just set) variable [ShutdownStatus].

Of course, one solution I am using now is to shut off the system menu and title bar buttons and have a 'Close" button on the program screen, or I could eliminate the entire title bar and make minimize and maximize buttons of my own, but I really wanted the recognition factor of the system's own buttons and menu.
... this would be my choice as well.
User avatar
Gaev
 
Posts: 3737
Joined: Fri Apr 01, 2005 7:48 am
Location: Toronto, Canada

Postby Enigman » Thu Mar 23, 2006 12:46 am

Gaev,

which begs the question ...what event triggers the command to set the variable [ExitOkay] to "true" ?

The menu choice on the tray menu for "Exit" is defined as:

SetVar "[ExitOkay]" "True"
Exit "" ""

That is the one and only place [ExitOkay] can be set to True. Remember that the default for [ExitOkay] MUST be defaulted to "False" at all times, which is why I don't redefine it as True in the shutdown script. The reason for that is that no other events can be trapped "outside the shutdown script" except the tray menu Exit function. Therefore all attempts at closing the program that are not from the Tray menu Exit function must result in minimizing rather than exiting. This requires [ExitOkay] to be False at all times until just before a real exit. The problem is that system shutdown is also an untrappable event so [ExitOkay] remains False.

There is a way to allow shutdown of the program by Windows (as part of the computer shutdown request) while it is in a minimized (tray) state ... by using a Timer object as described below.

I thought of this initially, but that brings two situations I don't want.

1) The program's behavior in response to a system shutdown would be different when open than when minimized. That makes it an "ill behaved" program.

2) The timer would consume system resources at all times, in this example four times per second, simply to overcome a limitation. I would sooner stick with the "Close" button and have a well behaved low resource consuming program.

One tip ... like [ExitOkay], it is not necessary to set the value of [ShutdownStatus] back to True from inside the shutdown script or anywhere else. Any action that calls the shutdown script starts by silently setting [ShutdownStatus] to True. Changing the value of [ShutdownStatus] from inside the shutdown script acts as a temporary flag to abort shutdown for that instance. I can leave it False after aborting shutdown and the next time I try to shutdown the value is automatically True again until I change it during the course of the shutdown script.

I have Return commands which cause immediate exit from the ShutDown section ...

I didn't know that you could use "Return" outside of the Subroutines tab. How predictable is that behavior? Will it work in any script?

Thanks.
User avatar
Enigman
 
Posts: 314
Joined: Tue Apr 12, 2005 3:57 pm
Location: Foothill Ranch, CA

Postby Gaev » Thu Mar 23, 2006 6:27 am

Enigman:

Bottom line is ... there is no way for a NeoBook application to distinguish between the origins of a request to shutdown the application (close button click or OS/computer shutdown request) ; so ...
I would sooner stick with the "Close" button and have a well behaved low resource consuming program.
... too bad the Book properties (Book>>>Book Properties>>>Window) do not permit a combination where the System menu/close button can be OFF but the Minimize button can be ON ... then, you would not need anything in the ShutDown section.

I didn't know that you could use "Return" outside of the Subroutines tab. How predictable is that behavior? Will it work in any script?
... just try it ... Help File description of command is Exit the current Action script or subroutine and return control to the previous one. ... and "subroutine" is not just one placed in the SubRoutines section ... also, the event triggers for objects (e.g. Click for buttons), and all the StartUp/ShutDown, PageChange, Activate/Deactivate etc. ... in fact, at the end of the description for the Return command it says The Return Action is most often used with Subroutines ... and if you click on the link, it takes you to the section dealing with stuff like StartUp/ShutDown.
One tip ... like [ExitOkay], it is not necessary to set the value of [ShutdownStatus] back to True from inside the shutdown script or anywhere else
... yes, I was aware ... just placed the commands in for ease of understanding.
User avatar
Gaev
 
Posts: 3737
Joined: Fri Apr 01, 2005 7:48 am
Location: Toronto, Canada

Postby Enigman » Thu Mar 23, 2006 8:35 am

Gaev,

Thanks for all your suggestions. I too would like to see a checkbox in the book properties, Windows section for disabling the X button alone. Dave? How about it? It would be useful for system tray apps...

Most of my applications are written in NB4 and I don't automatically convert them to NB5 until I have time to check every single function to make sure it works the same way. As I start to use NB5 more and more I am finding some pleasant surprises.

Thanks again.
User avatar
Enigman
 
Posts: 314
Joined: Tue Apr 12, 2005 3:57 pm
Location: Foothill Ranch, CA

Postby hlmonok3dz » Thu Mar 23, 2006 9:29 pm

I too would like to see a checkbox in the book properties, Windows section for disabling the X button alone.


That's a good suggestion. I will make sure that it's added to the list.
hlmonok3dz
 
Posts: 31
Joined: Fri Mar 10, 2006 10:02 pm

Postby Jay-Bird » Fri Mar 24, 2006 5:24 pm

That is a good suggestion...I have thought about it before, but not added it...Thanks for the reminder.
User avatar
Jay-Bird
 
Posts: 164
Joined: Fri Apr 01, 2005 7:01 am
Location: Louisiana , USA

Postby rcohen » Mon May 08, 2006 8:53 am

Here is some DELPHI code to detect a windows shutdown to prevent it......

http://bdn.borland.com/article/0,1410,16357,00.html

However what is stopping this information from simply setting a variable that can in turn be used to solve problems like this?

Perhaps Dave can engage this as a solution in an upcoming upgrade, or perhaps one of our plugin devs can offer access to this event ?

r
User avatar
rcohen
 
Posts: 279
Joined: Sun Apr 03, 2005 7:29 pm
Location: The Smokey Mountains, Tn


Return to NeoBook Action Commands

Who is online

Users browsing this forum: No registered users and 0 guests

cron