[prev in list] [next in list] [prev in thread] [next in thread] 

List:       vim-mac
Subject:    HIView + compositing mode
From:       "Jjgod Jiang" <gzjjgod () gmail ! com>
Date:       2007-04-08 8:18:13
Message-ID: ddd65cda0704080118j4ae2640ax67b4ce718f8a45fe () mail ! gmail ! com
[Download RAW message or body]

Hi all,

On moving gvim towards modern Carbon APIs, we hope to replace
current QuickDraw stuff with Quartz, and instead of drawing
directly to the window port, we obtain a content HIView first.

But according to HIView Programming Guide [1],

    The HIView drawing model does not support drawing to the
    screen outside of a kEventControlDraw handler. If you
    want to redraw a view, you should mark areas as being
    invalid (using the HIViewSetNeedsDisplay,
    HIViewSetNeedsDisplayInRegion or, in Mac OS X v10.4 and
    later, HIViewSetNeedsDisplayInRect and
    HIViewSetNeedsDisplayInShape functions) and draw only
    when the system tells you to do so. This delayed drawing
    model is required to support correct compositing of
    overlapping views.

We all know a lot of incoming calls in gui_mch_* are not
following this model (but they fits in QuickDraw model quite
well), for example, gui_mch_draw_string() will request to
have a line of string drawing immediately, gui_mch_clear_all()
will request to clear the window content immediately,
gui_mch_delete_lines() will request to move some lines up
immediately... How to make them fit the current "delayed
drawing model"?

My current approach is create a drawing_request queue:

    enum drawing_request_type {
        REQ_CLEAR_ALL,
        REQ_CLEAR_BLOCK,
        REQ_INVERT_RECT,
        REQ_FLASH,
        REQ_DRAW_STRING,
        REQ_DELETE_LINES,
        REQ_INSERT_LINES
    };

    typedef struct drawing_request {
        enum drawing_request_type type;

        union {
            /* REQ_DRAW_STRING */
            struct {
                int row;
                int col;
                char_u *s;
                int len;
                int flag;
            } str;

            /* REQ_CLEAR_BLOCK, REQ_INVERT_RECT */
            CGRect rect;
        } u;

        struct drawing_request *next;
    } drawing_request;

and new incoming drawing request will be append to the
queue, then call HIViewSetNeedsDisplay(),

    void gui_mch_draw_string(int row, int col, char_u *s,
                             int len, int flags)
    {
        request_draw_string(row, col, s, len, flags);
    }

    drawing_request *request_draw_string(int row, int col,
                                         char_u *s, int len,
                                         int flag)
    {
        drawing_request *req;

        req = (drawing_request *)
            malloc(sizeof(drawing_request));

        req->type = REQ_DRAW_STRING;
        req->u.str.row  = row;
        req->u.str.col  = row;
        // Is simply save the pointer ok? will vim change
        // it's content after the gui_mch_draw_string call?
        req->u.str.s    = s;
        req->u.str.len  = len;
        req->u.str.flag = flag;

        req->next = NULL;

        request_append(req);
        HIViewSetNeedsDisplay(gui.mainView, true);

        return req;
    }

When handling kEventControlDraw event for the content HIView,
we can:

    for (req = req_queue_head; req != NULL; req = req->next)
    {
        switch (req->type)
        {
        case REQ_DRAW_STRING:
            ... (do real drawing stuff)
            break;

        case REQ_CLEAR_ALL:
            ...
            break;

        ...
        }
    }

    // clean up the queue after all processing is finished
    request_clean_up();

What do you think of this approach?

- jjgod
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic