clutter-event-win32: Directly enqueue events in message_translate

Previously the window procedure for the stage window would always
create a ClutterEvent struct for every message and then pass that on
to message_translate to fill in the details. message_translate could
return FALSE to abandon the event. Instead of this, message_translate
now creates and queues the event itself whenever it sees a message
that could translate to an event. The function now returns void. This
has a number of advantages:

* It saves redundantly allocating events for messages that Clutter
  doesn't care about.

* A single message can now easily be translated into multiple events.

* There were some messages that were handled and did not fill in the
  event struct but did not cause the function to return FALSE. I think
  this would end up with a CLUTTER_NOTHING event being emitted.

http://bugzilla.clutter-project.org/show_bug.cgi?id=2135
This commit is contained in:
Neil Roberts 2010-06-24 18:07:20 +01:00
parent b4607f7a37
commit 2c8d73f047

View File

@ -201,15 +201,30 @@ get_modifier_state (WPARAM wparam)
return ret; return ret;
} }
static void
take_and_queue_event (ClutterEvent *event)
{
ClutterMainContext *clutter_context;
clutter_context = _clutter_context_get_default ();
/* The event is added directly to the queue instead of using
clutter_event_put so that it can avoid a copy. This takes
ownership of the event */
g_queue_push_head (clutter_context->events_queue, event);
}
static inline void static inline void
make_button_event (const MSG *msg, make_button_event (const MSG *msg,
ClutterEvent *event, ClutterStage *stage,
int button, int button,
int click_count, int click_count,
gboolean release, gboolean release,
ClutterInputDevice *device) ClutterInputDevice *device)
{ {
event->type = release ? CLUTTER_BUTTON_RELEASE : CLUTTER_BUTTON_PRESS; ClutterEvent *event = clutter_event_new (release ?
CLUTTER_BUTTON_RELEASE :
CLUTTER_BUTTON_PRESS);
event->button.time = msg->time; event->button.time = msg->time;
event->button.x = GET_X_LPARAM (msg->lParam); event->button.x = GET_X_LPARAM (msg->lParam);
event->button.y = GET_Y_LPARAM (msg->lParam); event->button.y = GET_Y_LPARAM (msg->lParam);
@ -217,6 +232,9 @@ make_button_event (const MSG *msg,
event->button.button = button; event->button.button = button;
event->button.click_count = click_count; event->button.click_count = click_count;
event->button.device = device; event->button.device = device;
event->any.stage = stage;
take_and_queue_event (event);
} }
/** /**
@ -325,9 +343,8 @@ get_key_modifier_state (const BYTE *key_states)
return ret; return ret;
} }
static gboolean static void
message_translate (ClutterBackend *backend, message_translate (ClutterBackend *backend,
ClutterEvent *event,
const MSG *msg, const MSG *msg,
gboolean *call_def_window_proc) gboolean *call_def_window_proc)
{ {
@ -337,7 +354,6 @@ message_translate (ClutterBackend *backend,
ClutterInputDevice *core_pointer, *core_keyboard; ClutterInputDevice *core_pointer, *core_keyboard;
ClutterStage *stage; ClutterStage *stage;
ClutterStageWindow *impl; ClutterStageWindow *impl;
gboolean res;
backend_win32 = CLUTTER_BACKEND_WIN32 (backend); backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
@ -345,20 +361,16 @@ message_translate (ClutterBackend *backend,
stage = clutter_win32_get_stage_from_window (msg->hwnd); stage = clutter_win32_get_stage_from_window (msg->hwnd);
if (stage == NULL) if (stage == NULL)
return FALSE; return;
impl = _clutter_stage_get_window (stage); impl = _clutter_stage_get_window (stage);
stage_win32 = CLUTTER_STAGE_WIN32 (impl); stage_win32 = CLUTTER_STAGE_WIN32 (impl);
event->any.stage = stage;
manager = clutter_device_manager_get_default (); manager = clutter_device_manager_get_default ();
core_pointer = core_pointer =
clutter_device_manager_get_core_device (manager, CLUTTER_POINTER_DEVICE); clutter_device_manager_get_core_device (manager, CLUTTER_POINTER_DEVICE);
core_keyboard = core_keyboard =
clutter_device_manager_get_core_device (manager, CLUTTER_KEYBOARD_DEVICE); clutter_device_manager_get_core_device (manager, CLUTTER_KEYBOARD_DEVICE);
res = TRUE;
switch (msg->message) switch (msg->message)
{ {
case WM_SIZE: case WM_SIZE:
@ -379,7 +391,6 @@ message_translate (ClutterBackend *backend,
clutter_actor_set_size (CLUTTER_ACTOR (stage), clutter_actor_set_size (CLUTTER_ACTOR (stage),
new_width, new_height); new_width, new_height);
} }
res = FALSE;
break; break;
case WM_SHOWWINDOW: case WM_SHOWWINDOW:
@ -387,7 +398,6 @@ message_translate (ClutterBackend *backend,
clutter_stage_win32_map (stage_win32); clutter_stage_win32_map (stage_win32);
else else
clutter_stage_win32_unmap (stage_win32); clutter_stage_win32_unmap (stage_win32);
res = FALSE;
break; break;
case WM_ACTIVATE: case WM_ACTIVATE:
@ -395,125 +405,148 @@ message_translate (ClutterBackend *backend,
{ {
if (stage_win32->state & CLUTTER_STAGE_STATE_ACTIVATED) if (stage_win32->state & CLUTTER_STAGE_STATE_ACTIVATED)
{ {
ClutterEvent *event = clutter_event_new (CLUTTER_STAGE_STATE);
stage_win32->state &= ~CLUTTER_STAGE_STATE_ACTIVATED; stage_win32->state &= ~CLUTTER_STAGE_STATE_ACTIVATED;
event->type = CLUTTER_STAGE_STATE; event->any.stage = stage;
event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED; event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
event->stage_state.new_state = stage_win32->state; event->stage_state.new_state = stage_win32->state;
take_and_queue_event (event);
} }
else
res = FALSE;
break;
} }
else else if (!(stage_win32->state & CLUTTER_STAGE_STATE_ACTIVATED))
{
if (!(stage_win32->state & CLUTTER_STAGE_STATE_ACTIVATED))
{ {
ClutterEvent *event = clutter_event_new (CLUTTER_STAGE_STATE);
stage_win32->state |= CLUTTER_STAGE_STATE_ACTIVATED; stage_win32->state |= CLUTTER_STAGE_STATE_ACTIVATED;
event->type = CLUTTER_STAGE_STATE; event->any.stage = stage;
event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED; event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
event->stage_state.new_state = stage_win32->state; event->stage_state.new_state = stage_win32->state;
}
else take_and_queue_event (event);
res = FALSE;
} }
break; break;
case WM_PAINT: case WM_PAINT:
CLUTTER_NOTE (MULTISTAGE, "expose for stage:%p, redrawing", stage); CLUTTER_NOTE (MULTISTAGE, "expose for stage:%p, redrawing", stage);
clutter_redraw (stage); clutter_redraw (stage);
res = FALSE;
break; break;
case WM_DESTROY: case WM_DESTROY:
{
ClutterEvent *event = clutter_event_new (CLUTTER_DESTROY_NOTIFY);
CLUTTER_NOTE (EVENT, "WM_DESTROY"); CLUTTER_NOTE (EVENT, "WM_DESTROY");
event->type = CLUTTER_DESTROY_NOTIFY;
event->any.stage = stage;
take_and_queue_event (event);
}
break; break;
case WM_CLOSE: case WM_CLOSE:
{
ClutterEvent *event = clutter_event_new (CLUTTER_DELETE);
CLUTTER_NOTE (EVENT, "WM_CLOSE"); CLUTTER_NOTE (EVENT, "WM_CLOSE");
event->type = CLUTTER_DELETE;
event->any.stage = stage;
take_and_queue_event (event);
/* The default window proc will destroy the window so we want to /* The default window proc will destroy the window so we want to
prevent this to allow applications to optionally destroy the prevent this to allow applications to optionally destroy the
window themselves */ window themselves */
if (call_def_window_proc) if (call_def_window_proc)
*call_def_window_proc = FALSE; *call_def_window_proc = FALSE;
}
break; break;
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
make_button_event (msg, event, 1, 1, FALSE, core_pointer); make_button_event (msg, stage, 1, 1, FALSE, core_pointer);
break; break;
case WM_MBUTTONDOWN: case WM_MBUTTONDOWN:
make_button_event (msg, event, 2, 1, FALSE, core_pointer); make_button_event (msg, stage, 2, 1, FALSE, core_pointer);
break; break;
case WM_RBUTTONDOWN: case WM_RBUTTONDOWN:
make_button_event (msg, event, 3, 1, FALSE, core_pointer); make_button_event (msg, stage, 3, 1, FALSE, core_pointer);
break; break;
case WM_LBUTTONUP: case WM_LBUTTONUP:
make_button_event (msg, event, 1, 1, TRUE, core_pointer); make_button_event (msg, stage, 1, 1, TRUE, core_pointer);
break; break;
case WM_MBUTTONUP: case WM_MBUTTONUP:
make_button_event (msg, event, 2, 1, TRUE, core_pointer); make_button_event (msg, stage, 2, 1, TRUE, core_pointer);
break; break;
case WM_RBUTTONUP: case WM_RBUTTONUP:
make_button_event (msg, event, 3, 1, TRUE, core_pointer); make_button_event (msg, stage, 3, 1, TRUE, core_pointer);
break; break;
case WM_LBUTTONDBLCLK: case WM_LBUTTONDBLCLK:
make_button_event (msg, event, 1, 2, FALSE, core_pointer); make_button_event (msg, stage, 1, 2, FALSE, core_pointer);
break; break;
case WM_MBUTTONDBLCLK: case WM_MBUTTONDBLCLK:
make_button_event (msg, event, 2, 2, FALSE, core_pointer); make_button_event (msg, stage, 2, 2, FALSE, core_pointer);
break; break;
case WM_RBUTTONDBLCLK: case WM_RBUTTONDBLCLK:
make_button_event (msg, event, 3, 2, FALSE, core_pointer); make_button_event (msg, stage, 3, 2, FALSE, core_pointer);
break; break;
case WM_MOUSEWHEEL: case WM_MOUSEWHEEL:
stage_win32->scroll_pos += (SHORT) HIWORD (msg->wParam); stage_win32->scroll_pos += (SHORT) HIWORD (msg->wParam);
event->type = CLUTTER_SCROLL; if (abs (stage_win32->scroll_pos) >= WHEEL_DELTA)
{
ClutterEvent *event = clutter_event_new (CLUTTER_SCROLL);
POINT pt;
event->scroll.time = msg->time; event->scroll.time = msg->time;
event->scroll.modifier_state = get_modifier_state (LOWORD (msg->wParam)); event->scroll.modifier_state =
get_modifier_state (LOWORD (msg->wParam));
event->scroll.device = core_pointer; event->scroll.device = core_pointer;
event->any.stage = stage;
/* conversion to window coordinates is required */ /* conversion to window coordinates is required */
{ pt.x = GET_X_LPARAM (msg->lParam);
POINT pt = { GET_X_LPARAM (msg->lParam), GET_Y_LPARAM (msg->lParam) }; pt.y = GET_Y_LPARAM (msg->lParam);
ScreenToClient (msg->hwnd, &pt); ScreenToClient (msg->hwnd, &pt);
event->scroll.x = pt.x; event->scroll.x = pt.x;
event->scroll.y = pt.y; event->scroll.y = pt.y;
}
if (stage_win32->scroll_pos >= WHEEL_DELTA) if (stage_win32->scroll_pos > 0)
{ {
event->scroll.direction = CLUTTER_SCROLL_UP; event->scroll.direction = CLUTTER_SCROLL_UP;
stage_win32->scroll_pos -= WHEEL_DELTA; stage_win32->scroll_pos -= WHEEL_DELTA;
} }
else if (stage_win32->scroll_pos <= -WHEEL_DELTA) else
{ {
event->scroll.direction = CLUTTER_SCROLL_DOWN; event->scroll.direction = CLUTTER_SCROLL_DOWN;
stage_win32->scroll_pos += WHEEL_DELTA; stage_win32->scroll_pos += WHEEL_DELTA;
} }
else
res = FALSE; take_and_queue_event (event);
}
break; break;
case WM_MOUSEMOVE: case WM_MOUSEMOVE:
event->type = CLUTTER_MOTION; {
ClutterEvent *event = clutter_event_new (CLUTTER_MOTION);
event->motion.time = msg->time; event->motion.time = msg->time;
event->motion.x = GET_X_LPARAM (msg->lParam); event->motion.x = GET_X_LPARAM (msg->lParam);
event->motion.y = GET_Y_LPARAM (msg->lParam); event->motion.y = GET_Y_LPARAM (msg->lParam);
event->motion.modifier_state = get_modifier_state (msg->wParam); event->motion.modifier_state = get_modifier_state (msg->wParam);
event->motion.device = core_pointer; event->motion.device = core_pointer;
event->any.stage = stage;
/* We need to start tracking when the mouse enters the stage if /* We need to start tracking when the mouse enters the stage if
we're not already */ we're not already */
@ -531,14 +564,20 @@ message_translate (ClutterBackend *backend,
stage_win32->tracking_mouse = TRUE; stage_win32->tracking_mouse = TRUE;
} }
take_and_queue_event (event);
}
break; break;
case WM_MOUSELEAVE: case WM_MOUSELEAVE:
event->crossing.type = CLUTTER_LEAVE; {
ClutterEvent *event = clutter_event_new (CLUTTER_LEAVE);
event->crossing.time = msg->time; event->crossing.time = msg->time;
event->crossing.x = msg->pt.x; event->crossing.x = msg->pt.x;
event->crossing.y = msg->pt.y; event->crossing.y = msg->pt.y;
event->crossing.device = core_pointer; event->crossing.device = core_pointer;
event->any.stage = stage;
/* we left the stage */ /* we left the stage */
_clutter_input_device_set_stage (event->crossing.device, NULL); _clutter_input_device_set_stage (event->crossing.device, NULL);
@ -547,6 +586,9 @@ message_translate (ClutterBackend *backend,
automatically cancelled so we'll need to start it again when automatically cancelled so we'll need to start it again when
the mouse next enters the window */ the mouse next enters the window */
stage_win32->tracking_mouse = FALSE; stage_win32->tracking_mouse = FALSE;
take_and_queue_event (event);
}
break; break;
case WM_KEYDOWN: case WM_KEYDOWN:
@ -554,6 +596,7 @@ message_translate (ClutterBackend *backend,
case WM_SYSKEYDOWN: case WM_SYSKEYDOWN:
case WM_SYSKEYUP: case WM_SYSKEYUP:
{ {
ClutterEvent *event = clutter_event_new (CLUTTER_EVENT_NONE);
int scan_code = (msg->lParam >> 16) & 0xff; int scan_code = (msg->lParam >> 16) & 0xff;
int min = 0, max = CLUTTER_WIN32_KEY_MAP_SIZE, mid; int min = 0, max = CLUTTER_WIN32_KEY_MAP_SIZE, mid;
BYTE key_states[256]; BYTE key_states[256];
@ -627,6 +670,9 @@ message_translate (ClutterBackend *backend,
event->key.modifier_state = get_key_modifier_state (key_states); event->key.modifier_state = get_key_modifier_state (key_states);
event->key.hardware_keycode = scan_code; event->key.hardware_keycode = scan_code;
event->key.device = core_keyboard; event->key.device = core_keyboard;
event->any.stage = stage;
take_and_queue_event (event);
} }
break; break;
@ -649,17 +695,8 @@ message_translate (ClutterBackend *backend,
*call_def_window_proc = FALSE; *call_def_window_proc = FALSE;
_clutter_stage_win32_update_cursor (stage_win32); _clutter_stage_win32_update_cursor (stage_win32);
} }
res = FALSE;
break;
default:
/* ignore every other message */
res = FALSE;
break; break;
} }
return res;
} }
LRESULT CALLBACK LRESULT CALLBACK
@ -676,12 +713,8 @@ _clutter_stage_win32_window_proc (HWND hwnd, UINT umsg,
{ {
ClutterBackendWin32 *backend_win32 = stage_win32->backend; ClutterBackendWin32 *backend_win32 = stage_win32->backend;
MSG msg; MSG msg;
ClutterEvent *event;
ClutterMainContext *clutter_context;
DWORD message_pos = GetMessagePos (); DWORD message_pos = GetMessagePos ();
clutter_context = _clutter_context_get_default ();
msg.hwnd = hwnd; msg.hwnd = hwnd;
msg.message = umsg; msg.message = umsg;
msg.wParam = wparam; msg.wParam = wparam;
@ -692,14 +725,8 @@ _clutter_stage_win32_window_proc (HWND hwnd, UINT umsg,
msg.pt.x = (SHORT) LOWORD (message_pos); msg.pt.x = (SHORT) LOWORD (message_pos);
msg.pt.y = (SHORT) HIWORD (message_pos); msg.pt.y = (SHORT) HIWORD (message_pos);
event = clutter_event_new (CLUTTER_NOTHING); message_translate (CLUTTER_BACKEND (backend_win32),
&msg, &call_def_window_proc);
if (message_translate (CLUTTER_BACKEND (backend_win32), event,
&msg, &call_def_window_proc))
/* push directly here to avoid copy of queue_put */
g_queue_push_head (clutter_context->events_queue, event);
else
clutter_event_free (event);
} }
if (call_def_window_proc) if (call_def_window_proc)