static void clutter_backend_win32_dispose (GObject *gobject) { ClutterBackend *backend = CLUTTER_BACKEND (gobject); ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (gobject); ClutterStageManager *stage_manager; CLUTTER_NOTE (BACKEND, "Disposing the of stages"); stage_manager = clutter_stage_manager_get_default (); g_object_unref (stage_manager); CLUTTER_NOTE (BACKEND, "Removing the event source"); _clutter_backend_win32_events_uninit (CLUTTER_BACKEND (backend_win32)); /* Unrealize all shaders, since the GL context is going away */ _clutter_shader_release_all (); G_OBJECT_CLASS (clutter_backend_win32_parent_class)->dispose (gobject); if (backend->cogl_context) { cogl_object_unref (backend->cogl_context); backend->cogl_context = NULL; } }
/** * clutter_win32_disable_event_retrieval * * Disables retrieval of Windows messages in the main loop. Use to * create event-less canvas. * * This function can only be called before calling clutter_init(). * * Since: 0.8 */ void clutter_win32_disable_event_retrieval (void) { ClutterBackendWin32 *backend; ClutterMainContext *clutter_context; clutter_context = clutter_context_get_default (); backend = CLUTTER_BACKEND_WIN32 (clutter_context->backend); backend->no_event_retrieval = TRUE; }
HCURSOR _clutter_backend_win32_get_invisible_cursor (ClutterBackend *backend) { ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend); if (backend_win32->invisible_cursor == NULL) backend_win32->invisible_cursor = LoadCursor (clutter_hinst, MAKEINTRESOURCE (42)); return backend_win32->invisible_cursor; }
void _clutter_backend_win32_events_uninit (ClutterBackend *backend) { ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend); if (backend_win32->event_source) { CLUTTER_NOTE (EVENT, "Destroying the event source"); g_source_destroy (backend_win32->event_source); g_source_unref (backend_win32->event_source); backend_win32->event_source = NULL; } }
static void clutter_backend_win32_init_events (ClutterBackend *backend) { ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend); CLUTTER_NOTE (EVENT, "initialising the event loop"); backend->device_manager = g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_WIN32, "backend", backend_win32, NULL); if (!_no_event_retrieval) _clutter_backend_win32_events_init (backend); }
static ClutterDeviceManager * clutter_backend_win32_get_device_manager (ClutterBackend *backend) { ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend); if (G_UNLIKELY (backend_win32->device_manager == NULL)) { backend_win32->device_manager = g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_WIN32, "backend", backend_win32, NULL); } return backend_win32->device_manager; }
void _clutter_backend_win32_events_init (ClutterBackend *backend) { ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend); GSource *source; ClutterEventSource *event_source; source = backend_win32->event_source = clutter_event_source_new (backend); event_source = (ClutterEventSource *) source; g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS); event_source->event_poll_fd.fd = G_WIN32_MSG_HANDLE; event_source->event_poll_fd.events = G_IO_IN; g_source_add_poll (source, &event_source->event_poll_fd); g_source_set_can_recurse (source, TRUE); g_source_attach (source, NULL); }
static ClutterStageWindow * clutter_backend_win32_create_stage (ClutterBackend *backend, ClutterStage *wrapper, GError **error) { ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend); ClutterStageWin32 *stage_win32; ClutterStageWindow *stage; stage = g_object_new (CLUTTER_TYPE_STAGE_WIN32, NULL); /* copy backend data into the stage */ stage_win32 = CLUTTER_STAGE_WIN32 (stage); stage_win32->backend = backend_win32; stage_win32->wrapper = wrapper; return stage; }
static GObject * clutter_backend_win32_constructor (GType gtype, guint n_params, GObjectConstructParam *params) { GObjectClass *parent_class; GObject *retval; if (!backend_singleton) { parent_class = G_OBJECT_CLASS (clutter_backend_win32_parent_class); retval = parent_class->constructor (gtype, n_params, params); backend_singleton = CLUTTER_BACKEND_WIN32 (retval); return retval; } g_warning ("Attempting to create a new backend object. This should " "never happen, so we return the singleton instance."); return g_object_ref (backend_singleton); }
static gboolean message_translate (ClutterBackend *backend, ClutterEvent *event, const MSG *msg, gboolean *call_def_window_proc) { ClutterBackendWin32 *backend_win32; ClutterStageWin32 *stage_win32; ClutterStage *stage; ClutterStageWindow *impl; gboolean res; backend_win32 = CLUTTER_BACKEND_WIN32 (backend); /* Do further processing only on events for the stage window */ stage = clutter_win32_get_stage_from_window (msg->hwnd); if (stage == NULL) return FALSE; impl = _clutter_stage_get_window (stage); stage_win32 = CLUTTER_STAGE_WIN32 (impl); event->any.stage = stage; res = TRUE; switch (msg->message) { case WM_SIZE: if (!stage_win32->is_foreign_win /* Ignore size changes resulting from the stage being minimized - otherwise the window size will be set to 0,0 */ && msg->wParam != SIZE_MINIMIZED) { WORD new_width = LOWORD (msg->lParam); WORD new_height = HIWORD (msg->lParam); guint old_width, old_height; clutter_actor_get_size (CLUTTER_ACTOR (stage), &old_width, &old_height); if (new_width != old_width || new_height != old_height) clutter_actor_set_size (CLUTTER_ACTOR (stage), new_width, new_height); } res = FALSE; break; case WM_SHOWWINDOW: if (msg->wParam) clutter_stage_win32_map (stage_win32); else clutter_stage_win32_unmap (stage_win32); res = FALSE; break; case WM_ACTIVATE: if (msg->wParam == WA_INACTIVE) { if (stage_win32->state & CLUTTER_STAGE_STATE_ACTIVATED) { stage_win32->state &= ~CLUTTER_STAGE_STATE_ACTIVATED; event->type = CLUTTER_STAGE_STATE; event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED; event->stage_state.new_state = stage_win32->state; } else res = FALSE; break; } else { if (!(stage_win32->state & CLUTTER_STAGE_STATE_ACTIVATED)) { stage_win32->state |= CLUTTER_STAGE_STATE_ACTIVATED; event->type = CLUTTER_STAGE_STATE; event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED; event->stage_state.new_state = stage_win32->state; } else res = FALSE; } break; case WM_PAINT: CLUTTER_NOTE (MULTISTAGE, "expose for stage:%p, redrawing", stage); clutter_redraw (stage); res = FALSE; break; case WM_DESTROY: CLUTTER_NOTE (EVENT, "WM_DESTROY"); event->type = CLUTTER_DESTROY_NOTIFY; break; case WM_CLOSE: CLUTTER_NOTE (EVENT, "WM_CLOSE"); event->type = CLUTTER_DELETE; /* The default window proc will destroy the window so we want to prevent this to allow applications to optionally destroy the window themselves */ if (call_def_window_proc) *call_def_window_proc = FALSE; break; case WM_LBUTTONDOWN: make_button_event (msg, event, 1, 1, FALSE); break; case WM_MBUTTONDOWN: make_button_event (msg, event, 2, 1, FALSE); break; case WM_RBUTTONDOWN: make_button_event (msg, event, 3, 1, FALSE); break; case WM_LBUTTONUP: make_button_event (msg, event, 1, 1, TRUE); break; case WM_MBUTTONUP: make_button_event (msg, event, 2, 1, TRUE); break; case WM_RBUTTONUP: make_button_event (msg, event, 3, 1, TRUE); break; case WM_LBUTTONDBLCLK: make_button_event (msg, event, 1, 2, FALSE); break; case WM_MBUTTONDBLCLK: make_button_event (msg, event, 2, 2, FALSE); break; case WM_RBUTTONDBLCLK: make_button_event (msg, event, 3, 2, FALSE); break; case WM_MOUSEWHEEL: stage_win32->scroll_pos += (SHORT) HIWORD (msg->wParam); event->type = CLUTTER_SCROLL; event->scroll.time = msg->time; event->scroll.modifier_state = get_modifier_state (LOWORD (msg->wParam)); /* conversion to window coordinates is required */ { POINT pt = { GET_X_LPARAM (msg->lParam), GET_Y_LPARAM (msg->lParam) }; ScreenToClient (msg->hwnd, &pt); event->scroll.x = pt.x; event->scroll.y = pt.y; } if (stage_win32->scroll_pos >= WHEEL_DELTA) { event->scroll.direction = CLUTTER_SCROLL_UP; stage_win32->scroll_pos -= WHEEL_DELTA; } else if (stage_win32->scroll_pos <= -WHEEL_DELTA) { event->scroll.direction = CLUTTER_SCROLL_DOWN; stage_win32->scroll_pos += WHEEL_DELTA; } else res = FALSE; break; case WM_MOUSEMOVE: event->type = CLUTTER_MOTION; event->motion.time = msg->time; event->motion.x = GET_X_LPARAM (msg->lParam); event->motion.y = GET_Y_LPARAM (msg->lParam); event->motion.modifier_state = get_modifier_state (msg->wParam); break; case WM_KEYDOWN: case WM_KEYUP: case WM_SYSKEYDOWN: case WM_SYSKEYUP: { int scan_code = (msg->lParam >> 16) & 0xff; int min = 0, max = CLUTTER_WIN32_KEY_MAP_SIZE, mid; BYTE key_states[256]; /* Get the keyboard modifier states. GetKeyboardState conveniently gets the key state that was current when the last keyboard message read was generated */ GetKeyboardState(key_states); /* Binary chop to check if we have a direct mapping for this key code */ while (min < max) { mid = (min + max) / 2; if (clutter_win32_key_map[mid].win_sym == msg->wParam) { event->key.keyval = clutter_win32_key_map[mid].clutter_sym; event->key.unicode_value = 0; break; } else if (clutter_win32_key_map[mid].win_sym < msg->wParam) min = mid + 1; else max = mid; } /* If we don't have a direct mapping then try getting the unicode value of the key sym */ if (min >= max) { WCHAR ch; BYTE shift_state[256]; /* Translate to a Unicode value, but only take into account the shift key. That way Ctrl+Shift+C will generate a capital C virtual key code with a zero unicode value for example */ memset (shift_state, 0, 256); shift_state[VK_SHIFT] = key_states[VK_SHIFT]; shift_state[VK_LSHIFT] = key_states[VK_LSHIFT]; shift_state[VK_RSHIFT] = key_states[VK_RSHIFT]; shift_state[VK_CAPITAL] = key_states[VK_CAPITAL]; if (ToUnicode (msg->wParam, scan_code, shift_state, &ch, 1, 0) == 1 /* The codes in this range directly match the Latin 1 codes so we can just use the Unicode value as the key sym */ && ch >= 0x20 && ch <= 0xff) event->key.keyval = ch; else /* Otherwise we don't know what the key means but the application might be able to do something with the scan code so we might as well still generate the event */ event->key.keyval = CLUTTER_VoidSymbol; /* Get the unicode value of the keypress again using the full modifier state */ if (ToUnicode (msg->wParam, scan_code, key_states, &ch, 1, 0) == 1) event->key.unicode_value = ch; else event->key.unicode_value = 0; } event->key.type = msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN ? CLUTTER_KEY_PRESS : CLUTTER_KEY_RELEASE; event->key.time = msg->time; event->key.modifier_state = get_key_modifier_state (key_states); event->key.hardware_keycode = scan_code; } break; case WM_GETMINMAXINFO: { MINMAXINFO *min_max_info = (MINMAXINFO *) msg->lParam; _clutter_stage_win32_get_min_max_info (stage_win32, min_max_info); if (call_def_window_proc) *call_def_window_proc = FALSE; } break; default: /* ignore every other message */ res = FALSE; break; } return res; }
static gboolean clutter_stage_win32_realize (ClutterStageWindow *stage_window) { ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window); ClutterBackend *backend; ClutterBackendWin32 *backend_win32; CoglFramebuffer *framebuffer; gfloat width; gfloat height; GError *error = NULL; CLUTTER_NOTE (MISC, "Realizing main stage"); backend = CLUTTER_BACKEND (stage_win32->backend); backend_win32 = CLUTTER_BACKEND_WIN32 (backend); clutter_actor_get_size (CLUTTER_ACTOR (stage_win32->wrapper), &width, &height); stage_win32->onscreen = cogl_onscreen_new (backend->cogl_context, width, height); if (stage_win32->hwnd == NULL) { ATOM window_class = clutter_stage_win32_get_window_class (); int win_xpos, win_ypos, win_width, win_height; if (window_class == 0) { g_critical ("Unable to register window class"); goto fail; } /* If we're in fullscreen mode then use the fullscreen rect instead */ if (_clutter_stage_is_fullscreen (stage_win32->wrapper)) { get_fullscreen_rect (stage_win32); win_xpos = stage_win32->fullscreen_rect.left; win_ypos = stage_win32->fullscreen_rect.top; win_width = stage_win32->fullscreen_rect.right - win_xpos; win_height = stage_win32->fullscreen_rect.bottom - win_ypos; } else { win_xpos = win_ypos = CW_USEDEFAULT; get_full_window_size (stage_win32, stage_win32->win_width, stage_win32->win_height, &win_width, &win_height); } if (stage_win32->wtitle == NULL) stage_win32->wtitle = g_utf8_to_utf16 (".", -1, NULL, NULL, NULL); stage_win32->hwnd = CreateWindowW ((LPWSTR) MAKEINTATOM (window_class), stage_win32->wtitle, get_window_style (stage_win32), win_xpos, win_ypos, win_width, win_height, NULL, NULL, GetModuleHandle (NULL), NULL); if (stage_win32->hwnd == NULL) { g_critical ("Unable to create stage window"); goto fail; } /* Store a pointer to the actor in the extra bytes of the window so we can quickly access it in the window procedure */ SetWindowLongPtrW (stage_win32->hwnd, 0, (LONG_PTR) stage_win32); } cogl_win32_onscreen_set_foreign_window (stage_win32->onscreen, stage_win32->hwnd); cogl_onscreen_set_swap_throttled (stage_win32->onscreen, _clutter_get_sync_to_vblank ()); framebuffer = COGL_FRAMEBUFFER (stage_win32->onscreen); if (!cogl_framebuffer_allocate (framebuffer, &error)) { g_warning ("Failed to allocate stage: %s", error->message); g_error_free (error); cogl_object_unref (stage_win32->onscreen); stage_win32->onscreen = NULL; goto fail; } /* Create a context. This will be a no-op if we already have one */ if (!_clutter_backend_create_context (CLUTTER_BACKEND (backend_win32), &error)) { g_critical ("Unable to realize stage: %s", error->message); g_error_free (error); goto fail; } CLUTTER_NOTE (BACKEND, "Successfully realized stage"); return TRUE; fail: return FALSE; }
static void clutter_stage_win32_realize (ClutterActor *actor) { ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (actor); ClutterBackendWin32 *backend_win32; PIXELFORMATDESCRIPTOR pfd; int pf; CLUTTER_NOTE (MISC, "Realizing main stage"); backend_win32 = CLUTTER_BACKEND_WIN32 (clutter_get_default_backend ()); if (stage_win32->hwnd == NULL) { ATOM window_class = clutter_stage_win32_get_window_class (); int win_xpos, win_ypos, win_width, win_height; if (window_class == 0) { g_critical ("Unable to register window class"); goto fail; } /* If we're in fullscreen mode then use the fullscreen rect instead */ if ((stage_win32->state & CLUTTER_STAGE_STATE_FULLSCREEN)) { get_fullscreen_rect (stage_win32); win_xpos = stage_win32->fullscreen_rect.left; win_ypos = stage_win32->fullscreen_rect.top; win_width = stage_win32->fullscreen_rect.right - win_xpos; win_height = stage_win32->fullscreen_rect.left - win_ypos; } else { win_xpos = win_ypos = CW_USEDEFAULT; get_full_window_size (stage_win32, stage_win32->win_width, stage_win32->win_height, &win_width, &win_height); } stage_win32->hwnd = CreateWindowW ((LPWSTR) MAKEINTATOM (window_class), L".", get_window_style (stage_win32), win_xpos, win_ypos, win_width, win_height, NULL, NULL, GetModuleHandle (NULL), NULL); if (stage_win32->hwnd == NULL) { g_critical ("Unable to create stage window"); goto fail; } /* Store a pointer to the actor in the extra bytes of the window so we can quickly access it in the window procedure */ SetWindowLongPtrW (stage_win32->hwnd, 0, (LONG_PTR) stage_win32); } if (stage_win32->client_dc) ReleaseDC (stage_win32->hwnd, stage_win32->client_dc); stage_win32->client_dc = GetDC (stage_win32->hwnd); pf = clutter_stage_win32_choose_pixel_format (stage_win32->client_dc, &pfd); if (pf == 0 || !SetPixelFormat (stage_win32->client_dc, pf, &pfd)) { g_critical ("Unable to find suitable GL pixel format"); goto fail; } if (backend_win32->gl_context == NULL) { backend_win32->gl_context = wglCreateContext (stage_win32->client_dc); if (backend_win32->gl_context == NULL) { g_critical ("Unable to create suitable GL context"); goto fail; } /* Make the context current so we can check the GL version */ wglMakeCurrent (stage_win32->client_dc, backend_win32->gl_context); if (!clutter_stage_win32_check_gl_version ()) { g_critical ("OpenGL version number is too low"); goto fail; } } CLUTTER_NOTE (BACKEND, "Successfully realized stage"); return; fail: CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED); }