Factor out session switching stuff to struct wlsc_session.
authorKristian Høgsberg <krh@redhat.com>
Tue, 17 Mar 2009 20:12:51 +0000 (16:12 -0400)
committerKristian Høgsberg <krh@redhat.com>
Tue, 17 Mar 2009 20:12:51 +0000 (16:12 -0400)
wayland-system-compositor.c

index 1358c58..daca339 100644 (file)
@@ -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";
@@ -318,21 +328,6 @@ wlsc_matrix_rotate(struct wlsc_matrix *matrix,
 }
 
 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,
                  int32_t x, int32_t y, int32_t width, int32_t height)
@@ -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)
@@ -556,6 +541,24 @@ wlsc_surface_draw(struct wlsc_surface *es)
 }
 
 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)
 {
        v1->x += v2->x;
@@ -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
@@ -728,6 +731,9 @@ surface_attach(struct wl_client *client,
 }
 
 static void
+wlsc_session_update_matrix(struct wlsc_session *session);
+
+static void
 surface_map(struct wl_client *client,
            struct wl_surface *surface,
            int32_t x, int32_t y, int32_t width, int32_t height)
@@ -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;
 }