"Decoupling" code without a Timer

Sometimes calling a UI-updating function (e.g. Invalidate, Refresh) has no effect whatsoever at a particular point in code. To make it work, we must use a Timer. Instead of making the call directly at that point in the code, put the call in the Timer’s Action event, and fire the timer. The Timer is “decoupled” from the code, so the system manages it separately, and then it works.

However, there are cases where the above solution will not work, i.e. when a MouseDown or MouseDrag event popup menu blocks all Timers.

Is there some other way to “decouple” the UI-update call in those cases?

Neither mousedown nor mousedrag in a canvas ever prevented timers to fire.

I just verified that on a test project to make sure. You made me doubt for an instant.

The only thing that can prevent a timer to fire is an event that does not return (any event AFAIK). How did you get the strange conception that MouseDown or Mousedrag could stop timers ? They return immediately. There is no reason they hold anything.

Unless you stuff some non ending loop in there, timers will happily fire.

Hm, you are right. I was confused by a case with a popup menu. Popup menus do stall Timers. Is there an alternative in those cases?

Listbox

You might be seeing the effect of resetting a timer in a mousedrag. Since mousedrags fire constantly during the drag, regardless of whether the mouse has moved, resetting a timer will cause the timer to never fire. If this is the case, just check the timer’s mode and only set it if it is unset.

if timer1.mode=0 then timer1.mode=1

Aaron, I don’t know where you get your information, but a quick test shows popupmenus don’t stall timers.

Before believing things, it is a good idea to verify facts.

on 64 bit OSX in the last few versions no screen redrawing is done until you exit your code and return to waiting for the next event to happen. I”m not sure when this started, but there is no way to even force the screen redraw to happen inline in the code. All the refresh and refreshNow or whatever else all act as “invalidate” now, which means redraw me when you get a chance and it won’t happen until you return from whatever you’re doing. They do this on purpose so that multiple screen redraws don’t stack up and redraw the same areas several times in the same loop I think. There doesn’t appear to be any way to force it redraw inline.

Thus the timer and or the thread. I’ve had to refactor a lot of stuff like this lately. The timer loads or works on some number of lines of updates and then ends so that the screen can update, then fires again very quickly to do the next block of work and returns so the screen can update.

There REALLY should be a way to force things to refresh inline and I’m not sure if there really isn’t one in the OS anymore or if it’s a bug in the 64 bit xojo libraries, but you simply can’t do it.

What you’re seeing might be an artifact of that, as has already been discussed timers do now keep firing when the mouse is down or when a menu is down and all that. Though back in carbon and pre-carbon days they did not. I remember when I first switched to using a “carbonTimer” in an early MBS plugin suite and could get things to keep going through menu actions :wink: That was quite a thrill :wink:

Actually, being able to refresh during an event, like accessing UI from a thread, should simply not be done.

Unfortunately, code written during the carbon era where everything went is not compliant.

In Xojo Web, there is simply no refresh at all during an event, so anyone who did a lot of Web already has taken all the good habits.

In Cocoa 32 bits, stuff like app.Doevent and Refresh still work, so it was still possible to keep bad code alive.

Let us face it, as systems evolve, they will less and less let old ways work. There are sensible reasons for that. One being that the framework moves more and more towards asynchronous. And threads become preemptive, or even multicore, as Grand Central Dispatch. In a multi core thread, accessing UI is simply out of the question.

There are principles I adhere to for any new development :

  • No more inline loops that last for more than a 10 ms. They should be replaced by multiple timers, with structures la C, where the timer stops when the maximum iterations is attained, or the condition in while-wend do-loop.
  • Long processes are systematically moved to thread.
  • Never expect a precise order of events. Each event handler code must be as self contained as possible
  • Most code is moved to the window, or better to methods that handles the events. Especially controls Open which is notorious for creating NOE when they try to access other controls. And added benefit of having a method for window open where everything is centralized is that I can restart the window entirely without closing and reopen.

These are not terribly difficult to implement in a new project.

Sure, refactoring old code can be difficult, especially when a large amount of spaghetti has grown inside. But there is no reason not to get good habits looking forward.

[quote=329653:@jim mckay]You might be seeing the effect of resetting a timer in a mousedrag. … If this is the case, just check the timer’s mode and only set it if it is unset.
if timer1.mode=0 then timer1.mode=1[/quote]

Thank you Jim. Yes, I try to use that behaviour to my advantage, in cases where something should not be called repeatedly. I’ve never used your method of checking the mode first for cases where something should happen repeatedly but only in a specified time interval. For that I’ve always checked Ticks() with a static value LastTicks in the method. Your way is also clever, and I will no doubt be using it in the future. Thanks again.

[quote=329664:@Michel Bujardet]Aaron, I don’t know where you get your information, but a quick test shows popupmenus don’t stall timers.

Before believing things, it is a good idea to verify facts.[/quote]

Excuse me, Michel, but you happen to be wrong, and I don’t appreciate this kind of lecturing, which I’ve seen you do before on this forum. Kindly keep these kind of mildly insulting remarks to yourself in the future. If you can’t reproduce a problem someone else describes, it does not mean they are deluded, and your “quick tests” don’t necessarily prove them wrong, as you see from this contribution from another programmer:

[quote=329690:@James Sentman]on 64 bit OSX in the last few versions no screen redrawing is done until you exit your code and return to waiting for the next event to happen. I”m not sure when this started, but there is no way to even force the screen redraw to happen inline in the code. …
What you’re seeing might be an artifact of that, as has already been discussed timers do now keep firing when the mouse is down or when a menu is down and all that. Though back in carbon and pre-carbon days they did not. I remember when I first switched to using a “carbonTimer” in an early MBS plugin suite and could get things to keep going through menu actions :wink: That was quite a thrill ;)[/quote]

Thank you, James. This is exactly what I’m seeing. I also used to use the MBS carbonTimer and was equally thrilled by it, because my code would actually work.

If you ask me, it is beyond ridiculous to be unable to redraw something with a line of code. If this is now the “correct” behaviour, then I have an awful lot of code that will need to be refactored.

No need for misplaced susceptibility. I am sorry if you cannot take contradiction of any kind, especially in matters that require accuracy such as programming. Being wrong happens to the best. Persisting in error and taking offense is quite another matter.

James Sentman describes a 64 bit artefact. In 32 bits, timers do keep firing as ever during mouseDown or while a PopupMenu dropdown is visible.

Now, I had enough of this aggressiveness. Ignoring you from now on. Have a nice day, and be happy with your preconceptions.

I gladly accept this as a promise. Thank you.

I can provide 2 examples of where it might be used legitimately to force a UI element to update inline with the code.

In my programs Open event where a large amount of data is loaded it can take many seconds or longer depending on the user configuration for the program to become ready and usable. Previous to 64bit I provided a startup dialog that had a progress bar and some text describing what portion of the data was being loaded. I was careful not to update the UI too often, only every half second at most during the loops that loaded the data and scripts. Performing too many updates was not ever a problem and did not slow down the process, only provided some visual feedback so the user knew how long it was going to take and that it was actually working while they waited.

Yes, I could move the code to a thread to happen after the open event or to doing blocks in a timer but that has other problems in this case. The app is highly apple scriptable and may be being launched in response to an external script waiting to ask it something or telling it to do something. If I let the Open event return then as far as the OS is concerned I’m ready to receive apple events and they may start to come in but the database isn’t loaded so I can’t actually service them. I could set a flag and just return false to every event I received until I was ready, but that would mean that you couldn’t actually externally script my app if it wasn’t running as you’d just get errors. I could suspend any events I receive during that time and do something to service them after the database thread had finished loading, but Xojo does not supply any methods for suspending an event natively so it would have to be done with declares or with some features of the MBS plugins that now let you do that. It’s non-trivial to solve this problem once I let the Open event return. I might actually get the feature request pushed through if I told someone that I was going to receive the event and just call app.DoEvents() in a loop until the database was loaded :wink: That would work but I can just hear the sharp intake of breaths from everyone who reads that :wink:

The second example also has to do with saving the database in the application. And when I say database I don’t mean an SQL type connection, I mean just a lot of data in the app as well as a lot of stored applescripts which must be stored in order to save their current state and local variables. When a user wishes to make an archive or backup copy of the database I write it out inline displaying the same style of dialog I did when loading it in the first place so that they can see some progress is happening. By the time this is happening the app is fully running and there are dozens of timers running, dozens of sockets sending and receiving data, potentially receiving apple events and network data from many different places, as well as potentially dozens of shells running helper apps communicating through the shell streams, sockets and even some shared memory blocks. If I run my code inline all those things pause while its saving the data. If I allow data and processes to function while I’m saving off the database then it potentially won’t be in the same state as when you asked it to save or did a timed backup. It may contain partially updated parts and invalid data. I would need to set flags or semaphores in every socket and shell to stop them receiving data and wait to handle it later and pause every waiting timer event and reset them later.

This is not a trivial exercise either. Checking semaphores is actually a rather time consuming task for the program as such things go so I really don’t want to be checking them hundreds of times a second all the time just so I can update a progress bar when you archive the database. Doing that in line is the right way to do that except that now I cannot provide any useful interface feedback on the process.

There are valid reasons why you would want to force an update inline. Yes, you could do it horribly and force your program down to a crawl, but you could also do it properly and be able to provide feedback for longer tasks for which threading or moving into blocks in a timer would cause a huge amount of otherwise unnecessary complexity and all the bugs, difficulty in testing properly and unintended consequences that such things have. I don’t want the potential of adding so many bugs and difficult to diagnose crashes just to provide a progress bar update. I really should be able to do that inline I think.

It seems to me that a program will become unresponsive after about 10 seconds if loops or events last longer than that. At least on windows.

@James Sentman: in my installer I wanted to have a progress bar. The darn thing didn’t want to update properly. After rewriting everything to use the example from Xojo everything worked nicely.

What you do is “historically grown” as we say in German. This will work for a while and then you will start cursing. Do a clean rewrite now or keep my post so that I can later say “I told you so”.

Didn’t read the entire discussion here, but when I had the need to run timers while a popup menu was open, I’d use a special Timer class that MBS provides. If you want to go down that path, I can look up the details.

I tried those MBS timer classes some time back - but as far as i recall they too suffered the same problem menu-wise.

One of the reasons i’ve had to abandon XOJO is the unreliability or intermittently dodgy blocking behaviour due to timer and audio buffer ( portaudio/Coreaudio ) update-refresh issues.
This is critical to anything involving audio and low latency issues.
Tried using threads instead of timers but they have the same issue - if not worse.