Copyright (c) 2012-2016 Hyperion Entertainment and contributors.

BOOPSI Popup Menus - Part 1

From AmigaOS Documentation Wiki
Jump to: navigation, search

Author

Simon Archer
Copyright (c) 2011 Simon Archer
Used by Permission

Introduction

In readiness for the next AmigaOS SDK, we are going to take a look at the new popup menu feature of the BOOPSI window.class, and how it can be used, and expanded upon, by the programmer.

This is part one, and here we shall discuss the default options and how to interact with them. In part two, we will explore the possibilities of adding our own items to the popup menu to allow custom options specific to the application.

Overview

With the Release of AmigaOS 4.1 Update 3, the window.class BOOPSI object can now use a new titlebar gadget. Along with the usual depth, zoom and iconify gadgets, it is now possible to show a "popup" menu gadget.

The purpose of this gadget is to present the user with a popup menu with various options available. By default, this menu will include "Close" and "Iconify" items if the close gadget and the iconify gadget has been specified respectively in the window tags when it was created.

It is also possible to add a "Jump to Screen" option in the menu. The close and iconify options simply mirror the gadgets use of the same purpose, whereas the "Jump to Screen" option is passed to your application just like other events. We will take a look at how this is achieved below.

Adding the popup menu gadget

First of all we need to tell the window.class that we actually want to provide the popup menu gadget when the window object is created. We do this by providing the WINDOW_PopupGadget tag, and the window object will add the popup menu gadget to the title bar when it is opened.

PopupMenusPart1-1.jpg

The user can now use this menu to close and/or iconify the window object if the respective gadgets are present in the title bar. Due to the mechanism of setting attributes to achieve this functionality, it is safe to use this new feature with previous versions of window.class as the tags supplied are simply ignored. This means that users can automatically make use of the popup menu when upgrading their OS version without any changes to the code to accomodate this feature.

Understandably, this is not really of much use as it is, as it is only mirroring functionality that is available elsewhere. Luckily, there are some other options we can add, such as the "Jump to Screen" option.

Jump to Screen events

It may sometimes be useful to be able to push the window object (and by result your application) on to another public screen. A good example of this is the Calculator utility supplied with AmigaOS 4.1 Update 3, where putting it on the same screen as your application can save switching screens to use the Calculator.

In order to get the popup menu to show the "Jump to Screen" option, we need to supply the WINDOW_JumpScreensMenu tag as well as the WINDOW_PopupGadget tag at the window object creation time (OM_NEW). This menu option will now be shown to the user when more than one public screen is open where the window object could be moved to. For example, if your application is currently on the Workbench screen, and there is another public screen open, the menu will give the option to jump to that other screen. It will not show the Workbench screen as the window object is already being shown on it.

So now we have the menu, and we have the option to jump to other public screens, we shall now discuss how this is actually handled.

As with all window object events, they are received in the "event loop". This is usually a section of code which waits for the signal to come from the window objects event port, and then calling the WM_HANDLEINPUT method to get the type of event. Along with events such as WMHI_ICONIFY and WMHI_GADGETUP, there is now WMHI_JUMPSCREEN. This should be checked for just like any other events if you have specified the "Jump to Screen" menu option. A typical event loop may look something like this:

while( !done )
{
  IExec->Wait( winsig );
     
  while(( result = IIntuition->IDoMethod( winobj, WM_HANDLEINPUT, code )) != WMHI_LASTMSG )
  {
    switch( result & WMHI_CLASSMASK )
    {
      case WMHI_CLOSEWINDOW:
      done = TRUE;
      break;
     
      case WMHI_ICONIFY:
      break;
     
      case WMHI_GADGETUP:
      break;
     
      case WMHI_JUMPSCREEN:
      break;
    }
  }
}

So we can see that the event loop successfully checks for a "Jump to Screen" type event, and now we need to act upon it.

Firstly, we need to decide which screen the user has selected to move the window object on to. Luckily, the window object has done the hard work for us, and we simply need to get the WA_PubScreen attribute, like so:

struct Screen *newscr;
IIntuition->GetAttr( winobj, WA_PubScreen, &newscr );

We should obviously check to make sure this is valid by checking that the returned pointer is non-NULL. Now, in order to move the window object, we call the WM_CLOSE method, set the WA_PubScreen attribute to tell window.class we really want to open there, and lastly call the WM_OPEN method. The above code expanded to handle the WMHI_JUMPSCREEN event would look like this:

  case WMHI_JUMPSCREEN:
  {
    struct Screen *newscr;
    IIntuition->GetAttr( WA_PubScreen, winobj, &newscr );
    if( newscr )
    {
      IIntuition->IDoMethod( winobj, WM_CLOSE, NULL );
     
      IIntuition->SetAttrs( winobj, WA_PubScreen, newscr, TAG_END );
     
      IIntuition->IDoMethod( winobj, WM_OPEN, NULL );
  }
  break;

Some applications may require to lock the public screen that the window is going to open on when initially created in order to use the DrawInfo, or other such screen specific data. In this case, the data pointers should be dropped before closing the window object, and then re-acquired after the newscr pointer has been established. Caching the screen pointer, or any associated data may lead to problems should the user decide to move your application from one screen to another.

Summary

While it would be nice to have this totally automated, unfortunately there are too many applications out there that cache the screen pointer rather than querying the window object for the current screen pointer. Automatically moving the window object to a different screen would undoubtedly lead to problems where the application is acting on the screen data of the original screen rather than using the screen data of the newly jumped-to screen. For this reason, it has been decided that support for this feature should only come with newly written applications that can be capable of supporting the dynamics of jumping from screen to screen.

In part two, we shall look at how we can expand the popup menu options to include custom options, and how we can receive these events and implement them in the application code.