Next: , Previous: , Up: Canvas Object   [Contents][Index]


21.3.3 Canvas Interaction

The canvas class is designed to maximize the programmer’s ability to deal with situations where standard form classes may not be flexible enough. With canvases, the programmer has complete control over everything that can happen to a window. It thus doesn’t work like other objects that get returned by fl_do_forms() etc. or have their callbacks invoked.

Instead the user can request that for specific X events (not XForms object events like FL_PRESS, FL_KEYPRESS etc.!) callbacks are invoked that receive all information about the XEvent that led to their invocation. This obviously requires some understanding of how the X Window system works.

The interaction with a canvas is typically set up as follows. First, you register the X events you’re interested in and their handlers using the following routine

typedef int (*FL_HANDLE_CANVAS)(FL_OBJECT *obj, Window win,
                                int win_width, int win_height,
                                XEvent *xev, void *user_data);
void fl_add_canvas_handler(FL_OBJECT *obj, int event,
                           FL_HANDLE_CANVAS handler, void *user_data);

where event is the XEvent type, e.g., Expose etc. The fl_add_canvas_handler() function first registers a procedure with the event dispatching system of the Forms Library, then it figures out the event masks corresponding to the event event and invokes fl_addto_selected_xevent() to solicit the event from the server. Other book keeping (e.g., drawing the box that encloses the canvas, etc.) is done by the object handler.

When a canvas handler is installed the library tries to set the correct mask for the the XEvent (which then tells the X Window system which events to pass on to the Forms Library). But since translation from an XEvent to an XEvent mask is not unique, the default translation of the XEvent to a mask may or may not match exactly the intention of the application. Two events, namely MotionNotify and ButtonPress, are likely candidates that need further clarification from the application. There are two functions to add or delete from the mask, fl_addto_selected_xevent() and fl_remove_selected_xevent().

By default, when a mouse motion handler (i.e., for the MotionNotify events) is registered, it is assumed that, while the application wants to be informed about mouse movements, it’s not interested in a continous motion monitoring (tracking), thus per default MotionNotify events are requested with PointerMotionHintMask being set in the mask to reduce the number of events generated. If this is not the case and in fact the application wants to use the mouse motion as some type of graphics control, the default behavior would appear "jerky" as not every mouse motion is reported. To change the default behavior so that every mouse motion is reported, you need to call fl_remove_selected_xevent() with mask set to PointerMotionHintMask. Furthermore, the mouse motion is reported regardless if a mouse button is pressed or not. If the application is interested in mouse motion only when a mouse button is pressed fl_remove_selected_xevent() should be called with a mask of PointerMotionMask|PointerMotionHintMask.

With ButtonPress events you need to call fl_addto_selected_xevent() with a mask of OwnerGrabButtonMask if you are to add or remove other canvas handlers in the button press handler.

To remove a registered handler, use

void fl_remove_canvas_handler(FL_OBJECT *obj, int event,
                              FL_CANVAS_HANDLER handler);

After this function call the canvas ceases to receive the events for event. The corresponding default bits in the XEvent mask as were set by fl_add_canvas_handler() are cleared. If you added extra ones with fl_addto_selected_xevent() you should reset them using fl_remove_selected_xevent().

To obtain the window ID of a canvas, use

Window fl_get_canvas_id(FL_OBJECT *obj);

or use the generic function (macro) (recommended)

Window FL_ObjWin(FL_OBJECT *obj);

Of course, the window ID only has a meaning after the form/canvas is shown. When the canvas or the form the canvas is on is hidden (via fl_hide_object() or fl_hide_form()), the canvas window may be destroyed. If the canvas is shown again, a new window ID for the canvas may be created. Thus recording the canvas window ID in a static variable is not the right thing to do. It is much safer (and it doesn’t add any run-time overhead) to obtain the canvas window ID via FL_ObjWin() whenever it’s needed. If your application must show and hide the canvas/form repeatedly, you might consider to "unmap" the window, a way of removing the window from the screen without actually destroying it and later re-mapping the window to show it. The Xlib API functions for doing this are XUnmapWindow() and XMapWindow(). Both require two arguments. the display, which you can determine by calling fl_get_display() and the window ID, which can be obtained by using form->window if you want to (un)map a form or FL_ObjWin(obj) for a canvas.


Next: , Previous: , Up: Canvas Object   [Contents][Index]