Messages & Events

Sending Messages

// Synchronous: calls win->proc immediately; returns proc's return value
int  send_message(window_t *win, uint32_t msg, uint32_t wparam, void *lparam);

// Asynchronous: queued, delivered on the next repost_messages(-1) call
void post_message(window_t *win, uint32_t msg, uint32_t wparam, void *lparam);

Standard Window Messages

Constant When sent wparam / lparam
evCreate Window just created lparam = value from create_window
evDestroy Window about to be freed
evPaint Repaint requested
evNCPaint Non-client area repaint
evSetFocus Window gains focus
evKillFocus Window loses focus
evLeftButtonDown LMB pressed LOWORD=x, HIWORD=y (window-local)
evLeftButtonUp LMB released same
evRightButtonDown RMB pressed same
evMouseMove Mouse moved same
evMouseLeave Mouse left window
evKeyDown Key pressed SDL scancode
evKeyUp Key released SDL scancode
evTextInput Text character input lparam = const char * UTF-8
evWheel Mouse wheel LOWORD=dx, HIWORD=dy
evCommand Control notification LOWORD=id, HIWORD=notification code
evResize Window resized / moved
evStatusBar Update status bar text lparam = (void *)const char *
evHScroll Built-in H scrollbar moved wparam = new scroll position
evVScroll Built-in V scrollbar moved wparam = new scroll position
evHitTest Find child at point lparam = window_t **
evRefreshStencil Stencil buffer needs update
evUser (1000) First app-defined message

Control Notification Codes

Sent to the root window via evCommand:

Code Control Meaning
btnClicked Button / Checkbox Button was clicked
edUpdate Text edit Text content changed
cbSelectionChange Combobox Selected item changed
RVN_SELCHANGE ColumnView Single-click selection change
RVN_DBLCLK ColumnView Double-click on item
kMenuBarNotificationItemClick MenuBar Menu item selected

Decoding in the parent window procedure:

case evCommand: {
    uint16_t notif = HIWORD(wparam);  // notification code
    uint16_t id    = LOWORD(wparam);  // item ID
    window_t *ctrl = (window_t *)lparam;

    if (notif == btnClicked) {
        if (strcmp(ctrl->title, "OK") == 0) { /* … */ }
    }
    if (notif == kMenuBarNotificationItemClick) {
        switch (id) {
            case MY_MENU_OPEN:  open_file(); break;
            case MY_MENU_QUIT:  running = false; break;
        }
    }
    return true;
}

Toolbar Button Clicks

// Set up toolbar buttons once in evCreate
toolbar_button_t buttons[] = {
    { .icon = icon16_folder, .ident = ID_OPEN, .flags = 0 },
    { .icon = icon16_save,   .ident = ID_SAVE, .flags = 0 },
};
send_message(win, tbAddButtons,
             sizeof(buttons)/sizeof(buttons[0]), buttons);

// In window proc – receive toolbar click
case tbButtonClick:
    switch (wparam) {  // ident
        case ID_OPEN: open_file(); break;
        case ID_SAVE: save_file(); break;
    }
    return true;

Keyboard Input

case evKeyDown:
    switch (wparam) {
        case SDL_SCANCODE_ESCAPE: running = false; break;
        case SDL_SCANCODE_S:     save_file();     break;
    }
    return true;

case evTextInput:
    append_char(win, (const char *)lparam);
    return true;

Event Loop

extern bool running;

ui_event_t e;
while (running) {
    while (get_message(&e))   // blocks until event, then drains queue
        dispatch_message(&e);
    repost_messages();        // process posted (async) messages + repaint
}

get_message() sleeps with SDL_WaitEvent when the SDL queue is empty, so the process yields the CPU instead of spinning. Calls to post_message() (including invalidate_window()) push a lightweight wakeup event into the SDL queue so that the wait is interrupted and the internal message queue is processed promptly.

Message Hooks

Register a global hook to intercept any message before it reaches its target window:

void register_hook(uint32_t msg, winhook_func_t func, void *userdata);
void unregister_hook(uint32_t msg, winhook_func_t func);

Orion UI Framework – built on SDL2 and OpenGL 3.2+

This site uses Just the Docs, a documentation theme for Jekyll.