Add a fullscreen mode to the terminal.
authorKristian Høgsberg <krh@redhat.com>
Mon, 22 Dec 2008 17:14:50 +0000 (12:14 -0500)
committerKristian Høgsberg <krh@redhat.com>
Mon, 22 Dec 2008 17:14:50 +0000 (12:14 -0500)
terminal.c
window.c
window.h

index 5855d2a..1010836 100644 (file)
@@ -43,6 +43,7 @@
 #include "cairo-util.h"
 #include "window.h"
 
+static int option_fullscreen;
 static const char gem_device[] = "/dev/dri/card0";
 static const char socket_name[] = "\0wayland";
 
@@ -65,6 +66,7 @@ struct terminal {
        int escape_length;
        int state;
        int margin;
+       int fullscreen;
 };
 
 static char *
@@ -129,7 +131,7 @@ terminal_draw_contents(struct terminal *terminal)
        cairo_surface_t *surface;
        cairo_t *cr;
        cairo_font_extents_t extents;
-       int i;
+       int i, top_margin, side_margin;
 
        window_get_child_rectangle(terminal->window, &rectangle);
 
@@ -148,9 +150,12 @@ terminal_draw_contents(struct terminal *terminal)
        cairo_set_font_size(cr, 14);
 
        cairo_font_extents(cr, &extents);
+       side_margin = (rectangle.width - terminal->width * extents.max_x_advance) / 2;
+       top_margin = (rectangle.height - terminal->height * extents.height) / 2;
+
        for (i = 0; i < terminal->height; i++) {
-               cairo_move_to(cr, terminal->margin,
-                             terminal->margin + extents.ascent + extents.height * i);
+               cairo_move_to(cr, side_margin,
+                             top_margin + extents.ascent + extents.height * i);
                cairo_show_text(cr, terminal_get_row(terminal, i));
        }
        cairo_destroy(cr);
@@ -170,7 +175,7 @@ terminal_draw(struct terminal *terminal)
        cairo_surface_t *surface;
        cairo_font_extents_t extents;
        cairo_t *cr;
-       int width, height;
+       int32_t width, height;
 
        window_get_child_rectangle(terminal->window, &rectangle);
 
@@ -188,10 +193,11 @@ terminal_draw(struct terminal *terminal)
        height = (rectangle.height - 2 * terminal->margin) / (int32_t) extents.height;
        terminal_resize(terminal, width, height);
 
-       rectangle.width = terminal->width * extents.max_x_advance + 2 * terminal->margin;
-       rectangle.height = terminal->height * extents.height + 2 * terminal->margin;
-
-       window_set_child_size(terminal->window, &rectangle);
+       if (!terminal->fullscreen) {
+               rectangle.width = terminal->width * extents.max_x_advance + 2 * terminal->margin;
+               rectangle.height = terminal->height * extents.height + 2 * terminal->margin;
+               window_set_child_size(terminal->window, &rectangle);
+       }
 
        window_draw(terminal->window);
        terminal_draw_contents(terminal);
@@ -495,6 +501,13 @@ key_handler(struct window *window, uint32_t key, uint32_t state, void *data)
        case KEY_RIGHTALT:
                mod = MOD_ALT;
                break;
+       case KEY_F11:
+               if (!state)
+                       break;
+               terminal->fullscreen ^= 1;
+               window_set_fullscreen(window, terminal->fullscreen);
+               terminal_schedule_redraw(terminal);
+               break;
        default:
                if (key < ARRAY_LENGTH(evdev_keymap)) {
                        if (terminal->modifiers & MOD_CTRL)
@@ -516,7 +529,7 @@ key_handler(struct window *window, uint32_t key, uint32_t state, void *data)
 }
 
 static struct terminal *
-terminal_create(struct wl_display *display, int fd)
+terminal_create(struct wl_display *display, int fd, int fullscreen)
 {
        struct terminal *terminal;
 
@@ -526,6 +539,7 @@ terminal_create(struct wl_display *display, int fd)
 
        memset(terminal, 0, sizeof *terminal);
        terminal->fd = fd;
+       terminal->fullscreen = fullscreen;
        terminal->window = window_create(display, fd, "Wayland Terminal",
                                         500, 100, 500, 400);
        terminal->display = display;
@@ -533,6 +547,7 @@ terminal_create(struct wl_display *display, int fd)
        terminal->margin = 5;
 
        terminal->compositor = wl_display_get_compositor(display);
+       window_set_fullscreen(terminal->window, terminal->fullscreen);
        window_set_resize_handler(terminal->window, resize_handler, terminal);
        window_set_acknowledge_handler(terminal->window, acknowledge_handler, terminal);
        window_set_key_handler(terminal->window, key_handler, terminal);
@@ -588,6 +603,12 @@ terminal_run(struct terminal *terminal, const char *path)
        return 0;
 }
 
+static const GOptionEntry option_entries[] = {
+       { "fullscreen", 'f', 0, G_OPTION_ARG_NONE,
+         &option_fullscreen, "Run in fullscreen mode" },
+       { NULL }
+};
+
 int main(int argc, char *argv[])
 {
        struct wl_display *display;
@@ -595,6 +616,15 @@ int main(int argc, char *argv[])
        GMainLoop *loop;
        GSource *source;
        struct terminal *terminal;
+       GOptionContext *context;
+       GError *error;
+
+       context = g_option_context_new(NULL);
+       g_option_context_add_main_entries(context, option_entries, "Wayland Terminal");
+       if (!g_option_context_parse(context, &argc, &argv, &error)) {
+               fprintf(stderr, "option parsing failed: %s\n", error->message);
+               exit(EXIT_FAILURE);
+       }
 
        fd = open(gem_device, O_RDWR);
        if (fd < 0) {
@@ -612,7 +642,7 @@ int main(int argc, char *argv[])
        source = wl_glib_source_new(display);
        g_source_attach(source, NULL);
 
-       terminal = terminal_create(display, fd);
+       terminal = terminal_create(display, fd, option_fullscreen);
        if (terminal_run(terminal, "/bin/bash"))
                exit(EXIT_FAILURE);
 
index 1ff59c2..3a67c74 100644 (file)
--- a/window.c
+++ b/window.c
@@ -44,11 +44,12 @@ struct window {
        struct wl_compositor *compositor;
        struct wl_surface *surface;
        const char *title;
-       int x, y, width, height;
+       struct rectangle allocation, saved_allocation;
        int minimum_width, minimum_height;
        int margin;
        int drag_x, drag_y;
        int state;
+       int fullscreen;
        uint32_t grab_device;
        uint32_t name;
        int fd;
@@ -76,8 +77,8 @@ rounded_rect(cairo_t *cr, int x0, int y0, int x1, int y1, int radius)
        cairo_close_path(cr);
 }
 
-void
-window_draw(struct window *window)
+static void
+window_draw_decorations(struct window *window)
 {
        cairo_surface_t *surface;
        cairo_t *cr;
@@ -85,10 +86,11 @@ window_draw(struct window *window)
        cairo_text_extents_t extents;
        cairo_pattern_t *gradient, *outline, *bright, *dim;
        struct wl_visual *visual;
+       int width, height;
 
        surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
-                                            window->width + window->margin * 2,
-                                            window->height + window->margin * 2);
+                                            window->allocation.width,
+                                            window->allocation.height);
 
        outline = cairo_pattern_create_rgb(0.1, 0.1, 0.1);
        bright = cairo_pattern_create_rgb(0.8, 0.8, 0.8);
@@ -96,26 +98,29 @@ window_draw(struct window *window)
 
        cr = cairo_create(surface);
 
+       width = window->allocation.width - window->margin * 2;
+       height = window->allocation.height - window->margin * 2;
+
        cairo_translate(cr, window->margin + 7, window->margin + 5);
        cairo_set_line_width (cr, border);
        cairo_set_source_rgba(cr, 0, 0, 0, 0.7);
-       rounded_rect(cr, 0, 0, window->width, window->height, radius);
+       rounded_rect(cr, 0, 0, width, height, radius);
        cairo_fill(cr);
        blur_surface(surface, 24 + radius);
 
        cairo_translate(cr, -7, -5);
        cairo_set_line_width (cr, border);
-       rounded_rect(cr, 1, 1, window->width - 1, window->height - 1, radius);
+       rounded_rect(cr, 1, 1, width - 1, height - 1, radius);
        cairo_set_source(cr, outline);
        cairo_stroke(cr);
-       rounded_rect(cr, 2, 2, window->width - 2, window->height - 2, radius - 1);
+       rounded_rect(cr, 2, 2, width - 2, height - 2, radius - 1);
        cairo_set_source(cr, bright);
        cairo_stroke(cr);
-       rounded_rect(cr, 3, 3, window->width - 2, window->height - 2, radius - 1);
+       rounded_rect(cr, 3, 3, width - 2, height - 2, radius - 1);
        cairo_set_source(cr, dim);
        cairo_stroke(cr);
 
-       rounded_rect(cr, 2, 2, window->width - 2, window->height - 2, radius - 1);
+       rounded_rect(cr, 2, 2, width - 2, height - 2, radius - 1);
        gradient = cairo_pattern_create_linear (0, 0, 0, 100);
        cairo_pattern_add_color_stop_rgb(gradient, 0, 0.6, 0.6, 0.4);
        cairo_pattern_add_color_stop_rgb(gradient, 1, 0.8, 0.8, 0.7);
@@ -125,17 +130,17 @@ window_draw(struct window *window)
 
        cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
        cairo_move_to(cr, 10, 50);
-       cairo_line_to(cr, window->width - 10, 50);
-       cairo_line_to(cr, window->width - 10, window->height - 10);
-       cairo_line_to(cr, 10, window->height - 10);
+       cairo_line_to(cr, width - 10, 50);
+       cairo_line_to(cr, width - 10, height - 10);
+       cairo_line_to(cr, 10, height - 10);
        cairo_close_path(cr);
        cairo_set_source(cr, dim);
        cairo_stroke(cr);
 
        cairo_move_to(cr, 11, 51);
-       cairo_line_to(cr, window->width - 10, 51);
-       cairo_line_to(cr, window->width - 10, window->height - 10);
-       cairo_line_to(cr, 11, window->height - 10);
+       cairo_line_to(cr, width - 10, 51);
+       cairo_line_to(cr, width - 10, height - 10);
+       cairo_line_to(cr, 11, height - 10);
        cairo_close_path(cr);
        cairo_set_source(cr, bright);
        cairo_stroke(cr);
@@ -143,7 +148,7 @@ window_draw(struct window *window)
        cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
        cairo_set_font_size(cr, 14);
        cairo_text_extents(cr, window->title, &extents);
-       cairo_move_to(cr, (window->width - extents.width) / 2, 10 - extents.y_bearing);
+       cairo_move_to(cr, (width - extents.width) / 2, 10 - extents.y_bearing);
        cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
        cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
        cairo_set_line_width (cr, 4);
@@ -166,10 +171,45 @@ window_draw(struct window *window)
                          visual);
 
        wl_surface_map(window->surface,
-                      window->x - window->margin,
-                      window->y - window->margin,
-                      window->width + 2 * window->margin,
-                      window->height + 2 * window->margin);
+                      window->allocation.x - window->margin,
+                      window->allocation.y - window->margin,
+                      window->allocation.width,
+                      window->allocation.height);
+}
+
+static void
+window_draw_fullscreen(struct window *window)
+{
+       struct wl_visual *visual;
+       int stride = window->allocation.width * 4;
+
+       window->buffer = buffer_create(window->fd,
+                                      window->allocation.width,
+                                      window->allocation.height,
+                                      stride);
+
+       visual = wl_display_get_premultiplied_argb_visual(window->display);
+       wl_surface_attach(window->surface,
+                         window->buffer->name,
+                         window->buffer->width,
+                         window->buffer->height,
+                         window->buffer->stride,
+                         visual);
+
+       wl_surface_map(window->surface,
+                      window->allocation.x,
+                      window->allocation.y,
+                      window->allocation.width,
+                      window->allocation.height);
+}
+
+void
+window_draw(struct window *window)
+{
+       if (window->fullscreen)
+               window_draw_fullscreen(window);
+       else
+               window_draw_decorations(window);
 }
 
 enum window_state {
@@ -196,7 +236,6 @@ event_handler(struct wl_display *display,
              uint32_t size, uint32_t *p, void *data)
 {
        struct window *window = data;
-       struct rectangle rectangle;
        int location;
        int grip_size = 16;
 
@@ -239,24 +278,27 @@ event_handler(struct wl_display *display,
 
                switch (window->state) {
                case WINDOW_MOVING:
+                       if (window->fullscreen)
+                               break;
                        if (window->grab_device != object)
                                break;
-                       window->x = window->drag_x + x;
-                       window->y = window->drag_y + y;
+                       window->allocation.x = window->drag_x + x;
+                       window->allocation.y = window->drag_y + y;
                        wl_surface_map(window->surface,
-                                      window->x - window->margin,
-                                      window->y - window->margin,
-                                      window->width + 2 * window->margin,
-                                      window->height + 2 * window->margin);
+                                      window->allocation.x - window->margin,
+                                      window->allocation.y - window->margin,
+                                      window->allocation.width,
+                                      window->allocation.height);
                        wl_compositor_commit(window->compositor, 1);
                        break;
                case WINDOW_RESIZING_LOWER_RIGHT:
+                       if (window->fullscreen)
+                               break;
                        if (window->grab_device != object)
                                break;
-                       window->width = window->drag_x + x;
-                       window->height = window->drag_y + y;
+                       window->allocation.width = window->drag_x + x;
+                       window->allocation.height = window->drag_y + y;
 
-                       window_get_child_rectangle(window, &rectangle);
                        if (window->resize_handler)
                                (*window->resize_handler)(window,
                                                          window->user_data);
@@ -266,14 +308,17 @@ event_handler(struct wl_display *display,
        } else if (opcode == 1) {
                int button = p[0], state = p[1];
                int32_t x = p[2], y = p[3];
-
-               if (window->x + window->width - grip_size <= x &&
-                   x < window->x + window->width &&
-                   window->y + window->height - grip_size <= y &&
-                   y < window->y + window->height) {
+               int32_t left = window->allocation.x;
+               int32_t right = window->allocation.x +
+                       window->allocation.width - window->margin * 2;
+               int32_t top = window->allocation.y;
+               int32_t bottom = window->allocation.y +
+                       window->allocation.height - window->margin * 2;
+
+               if (right - grip_size <= x && x < right &&
+                   bottom - grip_size <= y && y < bottom) {
                        location = LOCATION_LOWER_RIGHT;
-               } else if (window->x <= x && x < window->x + window->width &&
-                          window->y <= y && y < window->y + window->height) {
+               } else if (left <= x && x < right && top <= y && y < bottom) {
                        location = LOCATION_INTERIOR;
                } else {
                        location = LOCATION_OUTSIDE;
@@ -282,14 +327,14 @@ event_handler(struct wl_display *display,
                if (button == BTN_LEFT && state == 1) {
                        switch (location) {
                        case LOCATION_INTERIOR:
-                               window->drag_x = window->x - x;
-                               window->drag_y = window->y - y;
+                               window->drag_x = window->allocation.x - x;
+                               window->drag_y = window->allocation.y - y;
                                window->state = WINDOW_MOVING;
                                window->grab_device = object;
                                break;
                        case LOCATION_LOWER_RIGHT:
-                               window->drag_x = window->width - x;
-                               window->drag_y = window->height - y;
+                               window->drag_x = window->allocation.width - x;
+                               window->drag_y = window->allocation.height - y;
                                window->state = WINDOW_RESIZING_LOWER_RIGHT;
                                window->grab_device = object;
                                break;
@@ -312,18 +357,24 @@ void
 window_get_child_rectangle(struct window *window,
                           struct rectangle *rectangle)
 {
-       rectangle->x = 10;
-       rectangle->y = 50;
-       rectangle->width = window->width - 20;
-       rectangle->height = window->height - 60;
+       if (window->fullscreen) {
+               *rectangle = window->allocation;
+       } else {
+               rectangle->x = window->margin + 10;
+               rectangle->y = window->margin + 50;
+               rectangle->width = window->allocation.width - 20 - window->margin * 2;
+               rectangle->height = window->allocation.height - 60 - window->margin * 2;
+       }
 }
 
 void
 window_set_child_size(struct window *window,
                      struct rectangle *rectangle)
 {
-       window->width = rectangle->width + 20;
-       window->height = rectangle->height + 60;
+       if (!window->fullscreen) {
+               window->allocation.width = rectangle->width + 20 + window->margin * 2;
+               window->allocation.height = rectangle->height + 60 + window->margin * 2;
+       }
 }
 
 void
@@ -332,10 +383,28 @@ window_copy(struct window *window,
            uint32_t name, uint32_t stride)
 {
        wl_surface_copy(window->surface,
-                       window->margin + rectangle->x,
-                       window->margin + rectangle->y,
+                       rectangle->x,
+                       rectangle->y,
                        name, stride,
-                       0, 0, rectangle->width, rectangle->height);
+                       0, 0,
+                       rectangle->width,
+                       rectangle->height);
+}
+
+void
+window_set_fullscreen(struct window *window, int fullscreen)
+{
+       window->fullscreen = fullscreen;
+       if (window->fullscreen) {
+               window->saved_allocation = window->allocation;
+               window->allocation.x = 0;
+               window->allocation.y = 0;
+               wl_display_get_geometry(window->display,
+                                       &window->allocation.width,
+                                       &window->allocation.height);
+       } else {
+               window->allocation = window->saved_allocation;
+       }
 }
 
 void
@@ -370,13 +439,6 @@ window_set_key_handler(struct window *window,
        window->user_data = data;
 }
 
-void
-window_set_minimum_size(struct window *window, uint32_t width, int32_t height)
-{
-       window->minimum_width = width;
-       window->minimum_height = height;
-}
-
 struct window *
 window_create(struct wl_display *display, int fd,
              const char *title,
@@ -393,12 +455,11 @@ window_create(struct wl_display *display, int fd,
        window->title = strdup(title);
        window->compositor = wl_display_get_compositor(display);
        window->surface = wl_compositor_create_surface(window->compositor);
-       window->x = x;
-       window->y = y;
-       window->minimum_width = 100;
-       window->minimum_height = 100;
-       window->width = width;
-       window->height = height;
+       window->allocation.x = x;
+       window->allocation.y = y;
+       window->allocation.width = width;
+       window->allocation.height = height;
+       window->saved_allocation = window->allocation;
        window->margin = 16;
        window->state = WINDOW_STABLE;
        window->fd = fd;
index b4d524e..ffe81ad 100644 (file)
--- a/window.h
+++ b/window.h
@@ -44,9 +44,6 @@ window_create(struct wl_display *display, int fd,
              int32_t x, int32_t y, int32_t width, int32_t height);
 
 void
-window_set_minimum_size(struct window *window, uint32_t width, int32_t height);
-
-void
 window_draw(struct window *window);
 void
 window_get_child_rectangle(struct window *window,
@@ -60,6 +57,9 @@ window_copy(struct window *window,
            uint32_t name, uint32_t stride);
 
 void
+window_set_fullscreen(struct window *window, int fullscreen);
+
+void
 window_set_resize_handler(struct window *window,
                          window_resize_handler_t handler, void *data);
 void