Jump to content
IGNORED

New GUI for the Atari 8-bit


flashjazzcat

Recommended Posts

Something of note here is that the UI process - as designed - doesn't go to sleep waiting for messages, since it has to constantly snapshot the mouse to see if it's in the menu bar, which becomes highlighted without mouse clicks. Once the UI has checked the mouse, it immediately idles. I wondered if the UI could go to sleep completely and be woken by messages from the mouse and keyboard drivers (which buffer everything using queues already anyway), but this would be a little more complex and it seems to work for now with the UI just idling when it's done what it has to do. MrFish and I have ideas for tooltips and such (which are really simple to implement), and the mouse cursor will need to change shape contextually when it's over a text box, for example, so the UI process can't get away with sleeping until something is pressed or it receives a message from an application.

 

 

Would it be more economical (CPU wise) to work like Mac OS with pull down menus instead of drop down windows? Pull down, where it requires a click to pull down the menu vs drop down, like on the ST where the menu drops down when the mouse pointer moves into the menu bar region.

 

http://www.youtube.com/watch?v=hMENx28FueA

Link to comment
Share on other sites

The old demo's still available on my website, although it's way out of date. I never liked the way the menus pulled down in System 1-7, although there and in Mac OS X, nothing is highlighted in the bar until a menu actually opens. It's no big deal either way though: it takes a dozen or so cycles to see if the mouse has moved.

Link to comment
Share on other sites

 

 

I wondered if the UI could go to sleep completely and be woken by messages from the mouse and keyboard drivers (which buffer everything using queues already anyway), but this would be a little more complex and it seems to work for now with the UI just idling when it's done what it has to do.

 

I'd think that this would be the way to go, having special polling cases is always awkward. Also other apps might want to listen to mouse/key move/down/click events, and having the driver be the emitter of these events in a uniform manner system-wide would maybe make that easier. I suppose that one gotcha is that moving the direct polling out of the main UI would introduce some amount of reaction lag.

Link to comment
Share on other sites

I'd think that this would be the way to go, having special polling cases is always awkward. Also other apps might want to listen to mouse/key move/down/click events, and having the driver be the emitter of these events in a uniform manner system-wide would maybe make that easier. I suppose that one gotcha is that moving the direct polling out of the main UI would introduce some amount of reaction lag.

I'd be interested to know how SymbOS handles it: whether the mouse driver is effectively set up as another process which sends the UI (or "Desktop Manager" in SymbOS parlance) a wake-up message when a button is clicked. At the moment (and it's worked this way since long before the kernel was written), on the A8 the mouse driver pushes MOUSE_UP and MOUSE_DOWN messages into a queue during the VBI, and also samples the coordinates at this point (although they aren't buffered). This is how come you can click on the menu bar while windows are redrawing and the menu will open up when it gets around to it. But the mouse button queue is polled: the UI just does a quick check to see if the pointer has wandered into the menu bar, and if it has, it takes care of the menus and then pulls the next button event from the mouse queue. If there's nothing there, it just yields and will pick up further mouse movement next time around. Buffering the mouse buttons is a no-brainer, but movement is a different matter, since the driver would then be spewing out "the pointer moved" messages fifty or sixty times a second. It's hard to visualise just how that would pan out, and I doubt it's even an issue in SymbOS, since the UI can quite reasonably (since I'm unaware of any "hover" events) go to sleep until it gets a message or the mouse button is clicked.

 

As for direct polling of the mouse: there's a hierarchy at work. The UI interrogates the mouse and keyboard drivers first, and then passes anything it doesn't need to handle down the chain to the application (in the form of a message). Any mouse or keyboard actions in the menus or the non-client area of the window are completely invisible to the application. The app gets to hear about mouse clicks or key downs in the window client area, but even then only if the focused control in the client area didn't deal with the mouse or keyboard event itself.

 

Anyway: it's worth getting this right from the ground up. Obviously it's possible to look at things from a completely different perspective now that the thing multi-tasks: suddenly the mouse driver could be seen as a timer process rather than something arbitrarily attached to the IRQ vector.

 

More stack options come to mind too. Since the idle process is just that, we could have something like 6 x 40 byte stack slots (swappable) for applications and 1 x 16 byte slot (static) for the Idle Task.

Link to comment
Share on other sites

How does the actual redraw of the cursor work? Do you cache whatever is in the cursor area, draw the cursor and then paste back the cached background when it has moved to a new area?

 

Sorry if that wasn't an intelligible question :)

:) Yeah: the NMI fires a couple of lines before the first raster line of the pointer is generated, and background is cached, and the pointer drawn (once a quick check of VCOUNT tells us we're on exactly the right line). We then do a couple of STA WSYNCs (this - along with the earlier VCOUNT poll - ensures it works properly on a 65816 as well) to ensure the last raster line has been displayed, then erase it as fast as possible using the cached background. The source is somewhere back in the depths of the thread. It's effectively a hi-res PMG, and it wasn't my idea to do it this way - but I'm glad I got talked into it. :)

 

Related point: menus cache the background as well, so this means that any application which is continually updating its window content will cause problems when the menu closes. For this reason, window redraws are suspended while menus are open (and while windows are being moved, etc). Prodatron forewarned me that the UI process needs to keep pulling "redraw me" messages out of the message queue while in "session mode", otherwise the queue will overflow. Once the menus close or the window drag is finished, we just do a redraw on any window which received a bunch of discarded redraw requests.

Edited by flashjazzcat
  • Like 3
Link to comment
Share on other sites

:) Yeah: the NMI fires a couple of lines before the first raster line of the pointer is generated, and background is cached, and the pointer drawn (once a quick check of VCOUNT tells us we're on exactly the right line). We then do a couple of STA WSYNCs (this - along with the earlier VCOUNT poll - ensures it works properly on a 65816 as well) to ensure the last raster line has been displayed, then erase it as fast as possible using the cached background. The source is somewhere back in the depths of the thread. It's effectively a hi-res PMG, and it wasn't my idea to do it this way - but I'm glad I got talked into it. :)

 

Related point: menus cache the background as well, so this means that any application which is continually updating its window content will cause problems when the menu closes. For this reason, window redraws are suspended while menus are open (and while windows are being moved, etc). Prodatron forewarned me that the UI process needs to keep pulling "redraw me" messages out of the message queue while in "session mode", otherwise the queue will overflow. Once the menus close or the window drag is finished, we just do a redraw on any window which received a bunch of discarded redraw requests.

 

 

can you upload an updated DEMO please ?

Link to comment
Share on other sites

Wow, the multitasking scheduler is working! Congratulation! :)

 

@Prodatron: the A8 kernel uses a timer IRQ for the scheduler, but I was wondering about the pros and cons of using the NMI VBLANK interrupt at some point in the future. One of the nice things about the timer IRQ, however, (aside from the fact it's masked with SEI) is that the timer can be restarted every context switch, so we don't - say - yield to the next task just a few cycles before yet another IRQ hits. I wondered how important this really is, though, or if SymbOS uses a fixed-frequency interrupt like the Atari's vertical blank NMI.

 

At least on the CPC, PCW and standard MSX2 I don't have the possibility to use such a timer IRQ, as it doesn't exist here. That's the reason why SymbOS uses a fixed-frequency interrupt (which is the 50Hz vertical blank NMI on the MSX and PCW, and a 300Hz one on the CPC, which is ignored in 5 of 6 cases to reach 50Hz as well).

 

 

I'd be interested to know how SymbOS handles it: whether the mouse driver is effectively set up as another process which sends the UI (or "Desktop Manager" in SymbOS parlance) a wake-up message when a button is clicked. At the moment (and it's worked this way since long before the kernel was written), on the A8 the mouse driver pushes MOUSE_UP and MOUSE_DOWN messages into a queue during the VBI, and also samples the coordinates at this point (although they aren't buffered). This is how come you can click on the menu bar while windows are redrawing and the menu will open up when it gets around to it. But the mouse button queue is polled: the UI just does a quick check to see if the pointer has wandered into the menu bar, and if it has, it takes care of the menus and then pulls the next button event from the mouse queue. If there's nothing there, it just yields and will pick up further mouse movement next time around. Buffering the mouse buttons is a no-brainer, but movement is a different matter, since the driver would then be spewing out "the pointer moved" messages fifty or sixty times a second. It's hard to visualise just how that would pan out, and I doubt it's even an issue in SymbOS, since the UI can quite reasonably (since I'm unaware of any "hover" events) go to sleep until it gets a message or the mouse button is clicked.

 

In SymbOS there are so-called "timer processes". These are structured like normal processes (with own stack etc.) but have a gauranteed execution period of 50Hz. There is one system timer process, which includes parts of the "device manager", which polls the keyboard and mouse. It will update the keyboard status (1 bit for each key), the 32byte keyboard buffer, the mouse position and the status of the mousekeys. IMHO it's quite important to check the keyboard and the mouse every 1/50second.

The "desktop manager" itself never goes into sleep mode. Beside processing messages from applications it uses the "device manager" to check, if there is something going on with the mouse keys and checks for new chars in the keyboard buffer. If there is nothing to do it goes into idle mode to be able to check mouse/keyboard again soon.

I am not sure, how much you will gain, if the UI goes into sleep mode as well, while the timer process sends messages if there happens something with the mouse and the keyboard. You will save some time for context switching, but you have the additional message overhead - moving the mouse will definitely cost more CPU power than currently. And there should be a flag which prevents the timer process to send more than 1 message to the desktop manager until it proceeded the events.

 

Regarding checking the mouse and keyboard in applications: They can always ask the device manager for the actual mouse position, mousekey status and keyboard status. Apps are not allowed to grab chars from the keyboard buffer directly. This is only done by the desktop manager, as these chars are only sent to the form/control, which currently owns the focus.

Edited by Prodatron
  • Like 1
Link to comment
Share on other sites

Thanks for the reassuring insight! :)

 

In SymbOS there are so-called "timer processes". These are structured like normal processes (with own stack etc.) but have a gauranteed execution period of 50Hz. There is one system timer process, which includes parts of the "device manager", which polls the keyboard and mouse. It will update the keyboard status (1 bit for each key), the 32byte keyboard buffer, the mouse position and the status of the mousekeys. IMHO it's quite important to check the keyboard and the mouse every 1/50second.

Fortunately we have a keyboard IRQ on the Atari, but the mouse has to be polled at a high frequency (although it's now done with very little overhead). The mouse IRQ accumulates relative position changes around sixteen times per frame and the vertical blank updates the pointer coordinates by adding the offsets to X and Y. Presumably on the CPC/PCW the mouse is a little easier to read if it's polled at 50Hz. Diamond GOS on the A8 used a slightly different technique to achieve the same goal: it placed high-frequency snapshots of the actual mouse port bits into a queue and a lower frequency interrupt then went through the readings and updated the coordinates.

 

The "desktop manager" itself never goes into sleep mode. Beside processing messages from applications it uses the "device manager" to check, if there is something going on with the mouse keys and checks for new chars in the keyboard buffer. If there is nothing to do it goes into idle mode to be able to check mouse/keyboard again soon.

I am not sure, how much you will gain, if the UI goes into sleep mode as well, while the timer process sends messages if there happens something with the mouse and the keyboard. You will save some time for context switching, but you have the additional message overhead - moving the mouse will definitely cost more CPU power than currently. And there should be a flag which prevents the timer process to send more than 1 message to the desktop manager until it proceeded the events.

Right - so our methods aren't a million miles apart, then. The flag makes good sense, were things to go down that route.

 

Regarding checking the mouse and keyboard in applications: They can always ask the device manager for the actual mouse position, mousekey status and keyboard status. Apps are not allowed to grab chars from the keyboard buffer directly. This is only done by the desktop manager, as these chars are only sent to the form/control, which currently owns the focus.

OK - I didn't realize that applications could bypass the desktop manager and interrogate the mouse directly. This ties in directly with what Dan was suggesting earlier.

Edited by flashjazzcat
Link to comment
Share on other sites

Seems, that the whole IRQ stuff is quite powerful on the A8!

 

OK - I didn't realize that applications could bypass the desktop manager and interrogate the mouse directly. This ties in directly with what Dan was suggesting earlier.

 

I am sure you want apps like this :grin:

mzl.xraoaysz.800x500-75.jpg

In SymbOS this also makes it possible to do hover effects (which is currently not supported by the desktop manager).

  • Like 1
Link to comment
Share on other sites

Haha!! The first really useful application was just defined :) Xeyes for the "GUI" - no wait - we really need a name for it!! Obviously its name is not "X" but something short would be wonderful. Like X65 and X65Eyes :)

 

anyway I'm totally stunned about this awe-inspiring live code blog :) Wonderful to watch discussions between Prodatron and Jon. Just the perfect dream team :))

 

greetings,

twh

Edited by twh/f2
  • Like 2
Link to comment
Share on other sites

For a second I thought Prodatron had posted a video of the MSX version of SymbOS driving some insane hi-res graphics card. :D

 

Apart from anything else, getting this multitasking stuff operational is a LOT of fun, especially after months of coding with no immediate gratification. Yeah - I guess 8-bit multitasking kernels have been around a long time, but it's all new to me and it's a gas doing it on the little A8, and with a GUI on top.

 

Prodatron is the best thing that happened to this project since MrFish got involved.

 

EDIT: added a fifth process, which invoked stack copying for the first time, and found an off-by-one error which caused a crash. Simple fix (DEY before loop entry); works great now.

Edited by flashjazzcat
  • Like 4
Link to comment
Share on other sites

Hi,

 

I'd be interested to know how SymbOS handles it: whether the mouse driver is effectively set up as another process which sends the UI (or "Desktop Manager" in SymbOS parlance) a wake-up message when a button is clicked. At the moment (and it's worked this way since long before the kernel was written), on the A8 the mouse driver pushes MOUSE_UP and MOUSE_DOWN messages into a queue during the VBI, and also samples the coordinates at this point (although they aren't buffered). This is how come you can click on the menu bar while windows are redrawing and the menu will open up when it gets around to it. But the mouse button queue is polled: the UI just does a quick check to see if the pointer has wandered into the menu bar, and if it has, it takes care of the menus and then pulls the next button event from the mouse queue. If there's nothing there, it just yields and will pick up further mouse movement next time around. Buffering the mouse buttons is a no-brainer, but movement is a different matter, since the driver would then be spewing out "the pointer moved" messages fifty or sixty times a second. It's hard to visualise just how that would pan out, and I doubt it's even an issue in SymbOS, since the UI can quite reasonably (since I'm unaware of any "hover" events) go to sleep until it gets a message or the mouse button is clicked.

 

At least in X11, the server generates an "enter" and "leave" message whenever the mouse enters or exits any window. You can implement all the highlighting effects using those.

 

The server continuously tracks the window bellow the mouse pointer, and sends events based on the event-mask associated with the window, so you receive the messages only if you activate them:

  rect r = currentWindow.pos;
  if( ! isInRect(x,y,r) )
  {
    // We are outside the current window, send leave:
    if( currentWindow.eventMask & LeaveWindowMask )
     sendEvent( currentWindow.id, LeaveNotify );
    // Get new window
    currentWindow = getWindowAt(x,y);
    // Send enter event
    if( currentWindow.eventMask & EnterWindowMask )
     sendEvent( currentWindow.id, EnterNotify );
   }
   // ... other events ...
   if( currentWindow.eventMask & PointerMotionMask )
    sendEvent( currentWindow.id, MotionNotify, x, y );

I think that this kind of event handling could be programmed in the 6502 cheaply enough....

 

Regards,

 

Daniel.

  • Like 1
Link to comment
Share on other sites

Hi again :-),

 

Related point: menus cache the background as well, so this means that any application which is continually updating its window content will cause problems when the menu closes. For this reason, window redraws are suspended while menus are open (and while windows are being moved, etc). Prodatron forewarned me that the UI process needs to keep pulling "redraw me" messages out of the message queue while in "session mode", otherwise the queue will overflow.

 

I think you can implement "event compression" into the queue. The idea is that certain events, specially the exposure event (or "redraw"), don't need repeating, so only one event should be in the queue. If you need to add a new event in the queue, you simply update the existing event.

 

This can also be applied to motion events (in X11 you can subscribe to "motion hints" events, that only sends one big step instead of all individual movements), or pairs of "enter"/"leave", etc.

 

Daniel.

  • Like 1
Link to comment
Share on other sites

At least in X11, the server generates an "enter" and "leave" message whenever the mouse enters or exits any window. You can implement all the highlighting effects using those.

 

The server continuously tracks the window bellow the mouse pointer, and sends events based on the event-mask associated with the window, so you receive the messages only if you activate them:

...

 

I think that this kind of event handling could be programmed in the 6502 cheaply enough....

I agree. The menus are a special case, since they're entirely handled by the UI (which is anyway watching the mouse pointer) anyway, and the only event messages sent out to applications pertain to menu items which aren't parents of cascading sub-menus being clicked. But if the application wishes to perform highlighting effects inside of a window, "enter" and "leave" messages would be a good way to facilitate it.

 

I think you can implement "event compression" into the queue. The idea is that certain events, specially the exposure event (or "redraw"), don't need repeating, so only one event should be in the queue. If you need to add a new event in the queue, you simply update the existing event.

 

This can also be applied to motion events (in X11 you can subscribe to "motion hints" events, that only sends one big step instead of all individual movements), or pairs of "enter"/"leave", etc.

Interesting, although this would mean some list walking when sending a new message. Thanks! Perhaps I should go and read up on X11. :)

Edited by flashjazzcat
Link to comment
Share on other sites

How does the actual redraw of the cursor work?

Further to this, I just realized you can see where the idle process isn't running while the mouse is drawn and erased by the NMI:

 

post-21964-0-03033400-1407933190_thumb.png

 

The broad coloured band gives a pretty good visual impression of where the interrupt fires and exits.

  • Like 2
Link to comment
Share on other sites

Hi,

 

Interesting, although this would mean some list walking when sending a new message. Thanks! Perhaps I should go and read up on X11. :)

 

A faster possibility is to simply update the event mask when you post an expose (or redraw) message, masking out the sending of further messages. Then, the application must reset the mask after retrieving the message.

 

The problem is that you can not alter the existing messages, so you need to always repaint the full application window.

 

And on reading about X11, I'm not sure, as the X11 protocol has too many unneeded complications and messages, mostly from the support of nested windows (windows inside another window) and server drawn primitives. Nowadays nobody thinks those are useful, as it is simpler and faster for each client to draw it's own contents and manage the application window life-cycle. Also, event compression is not part of the original X11 protocol.

 

IMHO, the UI manager should only post events to applications and provide methods for drawing standard controls and managing the window logic to be called from the applications.

 

On another tangent, a good and small windowing system was the original PalmOS. There, all application life-cycle was event based, the application received events on application-launch, application-stop, etc. And the UI was defined in memory using a very compact resource format, generated from text files on compilation. A minimal application with one form was about 1kB, a full scientific calculator about 30kB. And that includes icon images for the buttons and application.

 

Daniel.

Link to comment
Share on other sites

Originally, applications drew their own window content (via calls to the UI manager), and later (second revision) they registered their own redraw callback which the GUI ran directly when it needed to redraw the window (instead of sending redraw events to the application). Both methods were abandoned when I read (and finally understood) the SymbOS developer docs. Now applications define window content as records, so if the GUI needs to redraw the whole window content it can do so without any interaction with the application (or callbacks, which is important since we use IPC now, and no callbacks). Similarly, when I first designed the GUI data structures, I went for a right-threaded binary tree representation, which was memory-hungry and complex. SymbOS uses an efficient resource format (flat records containing arrays of controls), so the binary trees went the same way as the client redraw callbacks. :) Certainly complexity and footprint were dramatically reduced. So - a few designs have been tried, and a number of rewrites undertaken, but I guess that's how we end up with the best solutions. I was pretty reluctant to abandon a few proprietary(ish) methods (such as using masks for overlapping windows), but Prodatron finally piqued my interest with talk of rectangle lists last year and so I abandoned a whole lot more code and rewrote everything. At least direction is clear now. :)

 

Anyway: that's just to say a lot of different stuff's been tried, but I'm always on the lookout for ideas. While the basic structure of SymbOS is being followed, there are some obvious deviations in terms of the interface (no task bar, "Mac" style menu bar, etc), and of course there'll be significant deviations in the implementation. Prodatron has been very candid about the workings of SymbOS, but part of the fun is reimplementing the data structures and API on a completely different platform without reference to extremely detailed information or source code. Hopefully this approach will continue to work as well as it has done so far.

 

I certainly expect applications to be small. One of the pressing reasons to put the GUI on a cartridge was so I can throw lots of code at complex controls.A text editor, for example, should consist of a menu structure, a few custom dialogs, some calls to the file selector, and a main window containing a multi-line text control mapped to a buffer allocated by the application. All these resource structures are defined at assembly time and are used as-is by the UI manager. I think for many small, simple applications, there'll be twice or three times as much resource data as actual code. And this is good: when I wrote a text-mode word processor, a significant amount of code was devoted to the editor display and the file selector. I reckon that 30KB application would be half the size if running under a GUI.

  • Like 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...