Next: Other Canvas Routines, Previous: Canvas Types, 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: Other Canvas Routines, Previous: Canvas Types, Up: Canvas Object [Contents][Index]