diff --git a/wayland-system-compositor.c b/wayland-system-compositor.c index 1358c582..daca3391 100644 --- a/wayland-system-compositor.c +++ b/wayland-system-compositor.c @@ -129,11 +129,17 @@ struct wlsc_compositor { uint32_t meta_state; struct wl_list animate_list; - struct wlsc_surface *primary; + + struct wlsc_session *primary; + struct wl_list session_list; }; #define META_DOWN 256 +struct wlsc_vector { + GLdouble x, y, z; +}; + struct wlsc_animate { struct wl_list link; void (*animate)(struct wlsc_animate *animate, @@ -141,8 +147,13 @@ struct wlsc_animate { uint32_t frame, uint32_t msecs); }; -struct wlsc_vector { - GLdouble x, y, z; +struct wlsc_session { + struct wlsc_surface *surface; + struct wlsc_vector target, current, previous; + GLdouble target_angle, current_angle, previous_angle; + struct wlsc_animate animate; + struct wl_list link; + struct wlsc_listener listener; }; struct wlsc_surface { @@ -156,9 +167,8 @@ struct wlsc_surface { struct wl_list link; struct wlsc_matrix matrix; - struct wlsc_vector target, current, previous; - GLdouble target_angle, current_angle, previous_angle; - struct wlsc_animate animate; + /* FIXME: This should be it's own object at some point. */ + struct wlsc_session session; }; static const char *option_background = "background.jpg"; @@ -317,21 +327,6 @@ wlsc_matrix_rotate(struct wlsc_matrix *matrix, wlsc_matrix_multiply(matrix, &rotate); } -static void -wlsc_surface_update_matrix(struct wlsc_surface *es) -{ - GLdouble tx, ty; - - tx = es->map.x + es->map.width / 2; - ty = es->map.y + es->map.height / 2; - - wlsc_matrix_init(&es->matrix); - wlsc_matrix_translate(&es->matrix, -tx, -ty, 0); - wlsc_matrix_rotate(&es->matrix, es->current_angle, 0, 1, 0); - wlsc_matrix_translate(&es->matrix, tx + es->current.x, - ty + es->current.y, es->current.z); -} - static void wlsc_surface_init(struct wlsc_surface *surface, struct wlsc_compositor *compositor, struct wl_visual *visual, @@ -345,17 +340,7 @@ wlsc_surface_init(struct wlsc_surface *surface, surface->map.height = height; surface->surface = EGL_NO_SURFACE; surface->visual = visual; - surface->current.x = 0; - surface->current.y = 0; - surface->current.z = 0; - surface->current_angle = 0; - surface->target.x = 0; - surface->target.y = 0; - surface->target.z = 0; - surface->target_angle = 0; - surface->previous_angle = 0; - - wlsc_surface_update_matrix(surface); + wlsc_matrix_init(&surface->matrix); } static struct wlsc_surface * @@ -391,17 +376,17 @@ static void wlsc_surface_destroy(struct wlsc_surface *surface, struct wlsc_compositor *compositor) { - struct wlsc_listener *l; + struct wlsc_listener *l, *next; l = container_of(compositor->surface_destroy_listener_list.next, struct wlsc_listener, link); while (&l->link != &compositor->surface_destroy_listener_list) { + next = container_of(l->link.next, struct wlsc_listener, link); l->func(l, surface); - l = container_of(l->link.next, struct wlsc_listener, link); + l = next; } wl_list_remove(&surface->link); - wl_list_remove(&surface->animate.link); glDeleteTextures(1, &surface->texture); if (surface->surface != EGL_NO_SURFACE) @@ -555,6 +540,24 @@ wlsc_surface_draw(struct wlsc_surface *es) glPopMatrix(); } +static void +wlsc_surface_raise(struct wlsc_surface *surface) +{ + struct wlsc_compositor *compositor = surface->compositor; + + wl_list_remove(&surface->link); + wl_list_insert(compositor->surface_list.prev, &surface->link); +} + +static void +wlsc_surface_lower(struct wlsc_surface *surface) +{ + struct wlsc_compositor *compositor = surface->compositor; + + wl_list_remove(&surface->link); + wl_list_insert(&compositor->surface_list, &surface->link); +} + static void wlsc_vector_add(struct wlsc_vector *v1, struct wlsc_vector *v2) { @@ -599,7 +602,7 @@ repaint_output(struct wlsc_output *output) output->height / s, -output->height / s, 1, 2 * s); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - glClearColor(0, 0, 0.2, 1); + glClearColor(0, 0, 0, 1); glTranslatef(-output->width / 2, -output->height / 2, -s / 2); @@ -671,14 +674,14 @@ repaint(void *data) } static void -schedule_repaint(struct wlsc_compositor *ec) +wlsc_compositor_schedule_repaint(struct wlsc_compositor *compositor) { struct wl_event_loop *loop; - ec->repaint_needed = 1; - if (!ec->repaint_on_timeout) { - loop = wl_display_get_event_loop(ec->wl_display); - wl_event_loop_add_idle(loop, repaint, ec); + compositor->repaint_needed = 1; + if (!compositor->repaint_on_timeout) { + loop = wl_display_get_event_loop(compositor->wl_display); + wl_event_loop_add_idle(loop, repaint, compositor); } } @@ -691,7 +694,7 @@ surface_destroy(struct wl_client *client, wlsc_surface_destroy(es, ec); - schedule_repaint(ec); + wlsc_compositor_schedule_repaint(ec); } static void @@ -727,6 +730,9 @@ surface_attach(struct wl_client *client, eglBindTexImage(ec->display, es->surface, GL_TEXTURE_2D); } +static void +wlsc_session_update_matrix(struct wlsc_session *session); + static void surface_map(struct wl_client *client, struct wl_surface *surface, @@ -738,7 +744,8 @@ surface_map(struct wl_client *client, es->map.y = y; es->map.width = width; es->map.height = height; - wlsc_surface_update_matrix(es); + + wlsc_session_update_matrix(&es->session); } static void @@ -782,71 +789,210 @@ const static struct wl_surface_interface surface_interface = { }; static void -animate_surface(struct wlsc_animate *animate, - struct wlsc_compositor *compositor, - uint32_t frame, uint32_t msecs) +wlsc_session_update_matrix(struct wlsc_session *session) { + GLdouble tx, ty; + struct wlsc_surface *s = session->surface; + + tx = s->map.x + s->map.width / 2; + ty = s->map.y + s->map.height / 2; + + wlsc_matrix_init(&s->matrix); + wlsc_matrix_translate(&s->matrix, -tx, -ty, 0); + wlsc_matrix_rotate(&s->matrix, session->current_angle, 0, 1, 0); + wlsc_matrix_translate(&s->matrix, tx + session->current.x, + ty + session->current.y, session->current.z); +} + +static void +wl_session_animate(struct wlsc_animate *animate, + struct wlsc_compositor *compositor, + uint32_t frame, uint32_t msecs) +{ + struct wlsc_session *session; struct wlsc_surface *s; double angle_force, angle; struct wlsc_vector force, tmp; - double step = 0.3; - double friction = 1; + double step = 0.2; + double friction = 1.5; double spring = 0.2; - s = container_of(animate, struct wlsc_surface, animate); + session = container_of(animate, struct wlsc_session, animate); + s = session->surface; - angle = s->current_angle; - angle_force = (s->target_angle - angle) * spring + - (s->previous_angle - angle) * friction; + angle = session->current_angle; + angle_force = (session->target_angle - angle) * spring + + (session->previous_angle - angle) * friction; - s->current_angle = angle + (angle - s->previous_angle) + angle_force * step; - s->previous_angle = angle; + session->current_angle = + angle + (angle - session->previous_angle) + angle_force * step; + session->previous_angle = angle; - force = s->target; - wlsc_vector_subtract(&force, &s->current); + force = session->target; + wlsc_vector_subtract(&force, &session->current); wlsc_vector_scalar(&force, spring); - tmp = s->previous; - wlsc_vector_subtract(&tmp, &s->current); + tmp = session->previous; + wlsc_vector_subtract(&tmp, &session->current); wlsc_vector_scalar(&tmp, friction); wlsc_vector_add(&force, &tmp); wlsc_vector_scalar(&force, step); - wlsc_vector_add(&force, &s->current); - wlsc_vector_subtract(&force, &s->previous); - s->previous = s->current; - wlsc_vector_add(&s->current, &force); + wlsc_vector_add(&force, &session->current); + wlsc_vector_subtract(&force, &session->previous); + session->previous = session->current; + wlsc_vector_add(&session->current, &force); - wlsc_surface_update_matrix(s); + wlsc_session_update_matrix(session); - tmp = s->current; - wlsc_vector_subtract(&tmp, &s->target); + tmp = session->current; + wlsc_vector_subtract(&tmp, &session->target); if (tmp.x * tmp.x + tmp.y * tmp.y + tmp.z * tmp.z > 0.001) { - schedule_repaint(compositor); + wlsc_compositor_schedule_repaint(compositor); } else { + wl_list_remove(&session->animate.link); + wl_list_init(&session->animate.link); + } +} + +static void +wlsc_session_activate(struct wlsc_compositor *compositor, struct wlsc_session *session) +{ + struct wlsc_session *s; + int i; + + compositor->primary = session; + if (wl_list_empty(&compositor->session_list)) + return; + + session->target.x = 0; + session->target.y = 0; + session->target.z = -600; + session->target_angle = 0; + wl_list_remove(&session->animate.link); + wl_list_insert(compositor->animate_list.prev, &session->animate.link); + + i = 0; + s = container_of(session->link.prev, + struct wlsc_session, link); + while (&s->link != &compositor->session_list) { + s->target.x = -1000 - 500 * i; + s->target.y = 0; + s->target.z = -2500; + s->target_angle = M_PI / 4; + wl_list_remove(&s->animate.link); + wl_list_insert(compositor->animate_list.prev, &s->animate.link); + wlsc_surface_lower(s->surface); + + s = container_of(s->link.prev, + struct wlsc_session, link); + i++; + } + + i = 0; + s = container_of(session->link.next, + struct wlsc_session, link); + while (&s->link != &compositor->session_list) { + s->target.x = 1000 + 500 * i; + s->target.y = 0; + s->target.z = -2500; + s->target_angle = -M_PI / 4; wl_list_remove(&s->animate.link); - wl_list_init(&s->animate.link); + wl_list_insert(compositor->animate_list.prev, &s->animate.link); + wlsc_surface_lower(s->surface); + + s = container_of(s->link.next, + struct wlsc_session, link); + i++; + } + + wlsc_compositor_schedule_repaint(compositor); +} + +static void +wlsc_session_handle_surface_destroy(struct wlsc_listener *listener, + struct wlsc_surface *surface) +{ + struct wlsc_session *session = + container_of(listener, struct wlsc_session, listener); + struct wlsc_compositor *compositor; + struct wlsc_session *primary; + + if (session->surface != surface) + return; + + compositor = session->surface->compositor; + if (compositor->primary == session) { + printf("destroy session %p [%p, %p]\n", session, session->link.prev, session->link.next); + if (session->link.next != &compositor->session_list) + primary = container_of(session->link.next, + struct wlsc_session, link); + else if (session->link.prev != &compositor->session_list) + primary = container_of(session->link.prev, + struct wlsc_session, link); + else + primary = NULL; + } + + wl_list_remove(&session->animate.link); + wl_list_remove(&session->link); + wl_list_remove(&session->listener.link); + + if (compositor->primary == session) { + printf("activating session %p\n", primary); + wlsc_session_activate(compositor, primary); } } +static void +wlsc_session_init(struct wlsc_session *session, struct wlsc_surface *surface) +{ + struct wlsc_compositor *c = surface->compositor; + + session->animate.animate = wl_session_animate; + wl_list_init(&session->animate.link); + wl_list_insert(c->session_list.prev, &session->link); + + session->surface = surface; + session->current.x = 0; + session->current.y = 0; + session->current.z = 0; + session->current_angle = 0; + session->target.x = 0; + session->target.y = 0; + session->target.z = 0; + session->target_angle = 0; + session->previous_angle = 0; + + wlsc_session_update_matrix(session); + + session->listener.func = wlsc_session_handle_surface_destroy; + wl_list_insert(c->surface_destroy_listener_list.prev, + &session->listener.link); + + printf("added session %p [%p, %p]\n", session, session->link.prev, session->link.next); + printf(" - prev [%p]\n", session->link.prev->prev); +} + static void compositor_create_surface(struct wl_client *client, struct wl_compositor *compositor, uint32_t id) { struct wlsc_compositor *ec = (struct wlsc_compositor *) compositor; - struct wlsc_surface *es; + struct wlsc_surface *surface; - es = malloc(sizeof *es); - if (es == NULL) + surface = malloc(sizeof *surface); + if (surface == NULL) /* FIXME: Send OOM event. */ return; - wlsc_surface_init(es, ec, NULL, 0, 0, 0, 0); - es->animate.animate = animate_surface; - wl_list_init(&es->animate.link); + wlsc_surface_init(surface, ec, NULL, 0, 0, 0, 0); - wl_list_insert(ec->surface_list.prev, &es->link); - wl_client_add_surface(client, &es->base, + wl_list_insert(ec->surface_list.prev, &surface->link); + wl_client_add_surface(client, &surface->base, &surface_interface, id); + + wlsc_session_init(&surface->session, surface); + wlsc_session_activate(ec, &surface->session); } static void @@ -855,7 +1001,7 @@ compositor_commit(struct wl_client *client, { struct wlsc_compositor *ec = (struct wlsc_compositor *) compositor; - schedule_repaint(ec); + wlsc_compositor_schedule_repaint(ec); wl_client_send_acknowledge(client, compositor, key, ec->current_frame); } @@ -982,121 +1128,100 @@ notify_motion(struct wlsc_input_device *device, int x, int y) device->sprite->map.x = x - hotspot_x; device->sprite->map.y = y - hotspot_y; - schedule_repaint(device->ec); + wlsc_compositor_schedule_repaint(device->ec); } void notify_button(struct wlsc_input_device *device, int32_t button, int32_t state) { - struct wlsc_surface *es; - struct wlsc_compositor *ec = device->ec; + struct wlsc_surface *surface; + struct wlsc_compositor *compositor = device->ec; int32_t sx, sy; - if (!ec->vt_active) + if (!compositor->vt_active) return; - es = pick_surface(device, &sx, &sy); - if (es) { - wl_list_remove(&es->link); - wl_list_insert(device->ec->surface_list.prev, &es->link); + surface = pick_surface(device, &sx, &sy); + if (surface) { + wlsc_surface_raise(surface); if (state) { - /* FIXME: We need callbacks when the surfaces - * we reference here go away. */ device->grab++; - device->grab_surface = es; - wlsc_input_device_set_keyboard_focus(device, es); + device->grab_surface = surface; + wlsc_input_device_set_keyboard_focus(device, + surface); } else { device->grab--; } /* FIXME: Swallow click on raise? */ - wl_surface_post_event(&es->base, &device->base, + wl_surface_post_event(&surface->base, &device->base, WL_INPUT_BUTTON, button, state, device->x, device->y, sx, sy); - schedule_repaint(device->ec); + wlsc_compositor_schedule_repaint(compositor); } } static void on_term_signal(int signal_number, void *data); -static void -update_surface_targets(struct wlsc_compositor *compositor, int primary) -{ - struct wlsc_surface *s; - int i; - - i = 0; - s = container_of(compositor->surface_list.next, - struct wlsc_surface, link); - while (&s->link != &compositor->surface_list) { - if (i < primary) { - s->target.x = -400 + 500 * (i - primary); - s->target.y = 0; - s->target.z = -1500; - s->target_angle = M_PI / 4; - } else if (i == primary) { - s->target.x = 0; - s->target.y = 0; - s->target.z = -1000; - s->target_angle = 0; - compositor->primary = s; - } else { - s->target.x = 400 + 500 * (i - primary); - s->target.y = 0; - s->target.z = -1500; - s->target_angle = -M_PI / 4; - } - wl_list_remove(&s->animate.link); - wl_list_insert(compositor->animate_list.prev, &s->animate.link); - s = container_of(s->link.next, - struct wlsc_surface, link); - i++; - } - - schedule_repaint(compositor); -} - void notify_key(struct wlsc_input_device *device, uint32_t key, uint32_t state) { - struct wlsc_compositor *ec = device->ec; + struct wlsc_compositor *compositor = device->ec; + struct wlsc_session *s; uint32_t *k, *end; - if (!ec->vt_active) + if (!compositor->vt_active) return; - switch (key | ec->meta_state) { + switch (key | compositor->meta_state) { case KEY_EJECTCD | META_DOWN: - on_term_signal(SIGTERM, ec); + on_term_signal(SIGTERM, compositor); return; - case KEY_1 | META_DOWN: - case KEY_2 | META_DOWN: - case KEY_3 | META_DOWN: - case KEY_4 | META_DOWN: - case KEY_5 | META_DOWN: - update_surface_targets(ec, key - KEY_1); - if (device->grab == 0) - wlsc_input_device_set_keyboard_focus(device, ec->primary); - device->keyboard_focus = ec->primary; + case KEY_LEFT | META_DOWN: + if (!compositor->primary || !state) + break; + s = container_of(compositor->primary->link.prev, + struct wlsc_session, link); + if (&s->link != &compositor->session_list) { + wlsc_session_activate(compositor, s); + if (device->grab == 0) + wlsc_input_device_set_keyboard_focus(device, s->surface); + } + return; + + + case KEY_RIGHT | META_DOWN: + if (!compositor->primary || !state) + break; + s = container_of(compositor->primary->link.next, + struct wlsc_session, link); + if (&s->link != &compositor->session_list) { + wlsc_session_activate(compositor, s); + if (device->grab == 0) + wlsc_input_device_set_keyboard_focus(device, s->surface); + + } return; case KEY_LEFTMETA: case KEY_RIGHTMETA: case KEY_LEFTMETA | META_DOWN: case KEY_RIGHTMETA | META_DOWN: - ec->meta_state = state ? META_DOWN : 0; - if (state == 0 && ec->primary != NULL) { - ec->primary->target.z = 0; - wl_list_remove(&ec->primary->animate.link); - wl_list_insert(&ec->animate_list, - &ec->primary->animate.link); - schedule_repaint(ec); + compositor->meta_state = state ? META_DOWN : 0; + + if (state == 0 && compositor->primary) { + s = compositor->primary; + s->target.z = 0; + wl_list_remove(&s->animate.link); + wl_list_insert(compositor->animate_list.prev, &s->animate.link); + wlsc_compositor_schedule_repaint(compositor); } + return; } @@ -1542,9 +1667,10 @@ wlsc_compositor_create(struct wl_display *display) setup_tty(ec, loop); ec->timer_source = wl_event_loop_add_timer(loop, repaint, ec); - schedule_repaint(ec); + wlsc_compositor_schedule_repaint(ec); wl_list_init(&ec->animate_list); + wl_list_init(&ec->session_list); return ec; }