Gem, which stands for the "Graphics and Events Manager", can be used independent of most of the rest of the Amulet. Gem uses the wrapper mechanism (for styles and fonts), but it does not use the ORE object system.
7.3 Drawonables
The primary data structure in gem is the Am_Drawonable, which is a C++ object that corresponds to a window-manager window or off-screen buffer (for example, in X/11 it corresponds to a "drawable"). We called it a "Drawonable" because it is something that you can draw on. We also wanted to reserve the word "Window" for the Opal level object that corresponds to the drawonable. In this manual, sometimes "window" is used for "drawonable" since drawonables are implemented as window-manager windows.7.3.1 Creating Drawonables
Programmers create a "root" drawonable at initialization, and then create other drawonables as children of the root (or as children of another drawonable). The typical initialization is:Am_Drawonable *root = Am_Drawonable::Get_Root_Drawonable();
At the Opal level, this is called automatically by Am_Initialize to set up the exported Am_Screen object. Under X/11, Get_Root_Drawonable takes an optional string parameter which is the name of the screen. You can call therefore call Get_Root_Drawonable multiple times to support multiple screens.
virtual Am_Drawonable* Create_Offscreen (
int width = 0, int height = 0,
Am_Style background_color = Am_No_Style) = 0;
The actual pixels drawn in a drawonable by the various drawing routines are described in detail in the Opal chapter of the Amulet manual. The Opal objects' slots are passed as parameters to the Gem level drawing routines. The Am_Style, Am_Image_Array, and Am_Font structures are also described there. That information will not be repeated here.
There is only one clip mask per root drawonable. All drawonables which have the same root share the same clip region. It is necessary to set the clip region for each window before drawing the contents of that window. For efficiency, it's a good idea to complete drawing in one window before resetting the clip region and drawing in other windows.
The clip region can be set with a rectangular region, or with an arbitrarily shaped Am_Region. Regions are described in Section 7.4.4. The root drawonable stores a stack of clipping regions. Use Push_Clip() and Pop_Clip() to push regions onto this stack, or to pop them off. The current clip region is the intersection of all of the regions currently on the stack.
class Am_Region {
public:
static Am_Region* Create ();
virtual void Destroy () = 0;
virtual void Clear () = 0;
virtual void Set (short left, short top, unsigned short width,
unsigned short height) = 0;
virtual void Push (Am_Region* region) = 0;
virtual void Push (short left, short top, unsigned short width,
unsigned short height) = 0;
virtual void Pop () = 0;
virtual void Union (short left, short top, unsigned short width,
unsigned short height) = 0;
virtual void Intersect (short left, short top, unsigned short width,
unsigned short height) = 0;
virtual bool In (short x, short y) = 0;
virtual bool In (short left, short top, unsigned short width,
unsigned short height, bool &total) = 0;
virtual bool In (Am_Region *rgn, bool &total) = 0;
};
7.4.5 Drawing Functions
All of the drawing functions take a Am_Draw_Function parameter which controls how the pixels of the drawn shape affect the screen. Since most programmers will use color screens, draw functions are not usually useful. The supported values for Am_Draw_Function are Am_DRAW_COPY, Am_DRAW_OR and Am_DRAW_XOR.
For example, each time the user hits a keyboard key over a certain window, that window's event handlers are retreived, and, the Input_Event_Notify member function is called, with information about what key was pressed, which drawonable received the keypress, and where the mouse was positioned within the window when the key was pressed.
Opal defines standard event handlers, so anyone programming at the Opal layer or above will not have to provide these event handlers. Instead, you should use an interactor for event handling, or create a new interactor if none of the available interactors is appropriate. To add or change the functionality of the standard opal event handlers, derive a new class from the C++ class Am_Standard_Opal_Handlers (exported in opal_advanced.h), and replace some of the virtual functions with your own event handlers.
Am_Input_Event_Handlers is defined as:
class Am_Input_Event_Handlers {
public:
virtual void Iconify_Notify (Am_Drawonable* draw, bool iconified) = 0;
virtual void Frame_Resize_Notify (Am_Drawonable* draw, int left,
int top, int right, int bottom) = 0;
virtual void Destroy_Notify (Am_Drawonable *draw) = 0;
virtual void Configure_Notify (Am_Drawonable *draw, int left, int top,
int width, int height) = 0;
virtual void Exposure_Notify (Am_Drawonable *draw,
int left, int top,
int width, int height) = 0;
virtual void Input_Event_Notify (Am_Drawonable *draw,
Am_Input_Event *ev)=0;
};The member functions are:
void Set_Input_Dispatch_Functions (Am_Input_Event_Handlers* evh)
void Get_Input_Dispatch_Functions (Am_Input_Event_Handlers*& evh)
class Am_Input_Event {
public:
Am_Input_Char input_char; //the char and modifier bits; see idefs.h
int x;
int y;
Am_Drawonable *draw; // Drawonable this event happened in
unsigned long time_stamp;
};
You can control which input events are generated for a drawonable using the following member functions of drawonables:
The difference between Process_Event and Process_Immediate_Event is that Process_Event waits for the next event, and processes exactly one input event and all non-input events (like refresh and configure_notify events) before and after that input event before returning. For example:
before after
xxxIyyyIzzz ---> Izzz
Process_Event returns when it encounters a second input event or when the queue is empty// Should Am_Drawonable::Main_Loop and Am_Main_Event_Loop keep running?
extern bool Am_Main_Loop_Go;
class Am_Drawonable {
public:
...
static void Main_Loop ();
static void Process_Event ();
static void Process_Immediate_Event ();
...
Am_Main_Event_Loop uses Process_Event, and Am_Do_Events uses Process_Immediate_Event.