Fix terminal resizing

Get snapping to character grid working again, avoid crashes when attempting
to resize below 1x1 character cell, only redraw when size actually changes.

Also, rename window_get_child_rectangle() to window_get_child_allocation().
dev
Kristian Høgsberg 14 years ago
parent 5fd89d255b
commit da846ca91d
  1. 34
      clients/dnd.c
  2. 48
      clients/gears.c
  3. 16
      clients/image.c
  4. 33
      clients/resizor.c
  5. 71
      clients/terminal.c
  6. 20
      clients/view.c
  7. 37
      clients/window.c
  8. 11
      clients/window.h

@ -169,20 +169,20 @@ item_create(struct display *display, int x, int y, int seed)
static void
dnd_draw(struct dnd *dnd)
{
struct rectangle rectangle;
struct rectangle allocation;
cairo_t *cr;
cairo_surface_t *wsurface, *surface;
int i;
window_draw(dnd->window);
window_get_child_rectangle(dnd->window, &rectangle);
window_get_child_allocation(dnd->window, &allocation);
wsurface = window_get_surface(dnd->window);
surface = cairo_surface_create_similar(wsurface,
CAIRO_CONTENT_COLOR_ALPHA,
rectangle.width,
rectangle.height);
allocation.width,
allocation.height);
cairo_surface_destroy(wsurface);
cr = cairo_create(surface);
@ -201,7 +201,7 @@ dnd_draw(struct dnd *dnd)
cairo_destroy(cr);
window_copy_surface(dnd->window, &rectangle, surface);
window_copy_surface(dnd->window, &allocation, surface);
cairo_surface_destroy(surface);
window_flush(dnd->window);
}
@ -251,13 +251,13 @@ static struct item *
dnd_get_item(struct dnd *dnd, int32_t x, int32_t y)
{
struct item *item;
struct rectangle rectangle;
struct rectangle allocation;
int i;
window_get_child_rectangle(dnd->window, &rectangle);
window_get_child_allocation(dnd->window, &allocation);
x -= rectangle.x;
y -= rectangle.y;
x -= allocation.x;
y -= allocation.y;
for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
item = dnd->items[i];
@ -559,16 +559,16 @@ dnd_button_handler(struct window *window,
struct dnd *dnd = data;
int32_t x, y;
struct item *item;
struct rectangle rectangle;
struct rectangle allocation;
struct dnd_drag *dnd_drag;
struct wl_drag *drag;
int i;
window_get_child_rectangle(dnd->window, &rectangle);
window_get_child_allocation(dnd->window, &allocation);
input_get_position(input, &x, &y);
item = dnd_get_item(dnd, x, y);
x -= rectangle.x;
y -= rectangle.y;
x -= allocation.x;
y -= allocation.y;
if (item && state == 1) {
fprintf(stderr, "start drag, item %p\n", item);
@ -624,7 +624,7 @@ dnd_create(struct display *display)
struct dnd *dnd;
gchar *title;
int i, x, y;
struct rectangle rectangle;
int32_t width, height;
dnd = malloc(sizeof *dnd);
if (dnd == NULL)
@ -656,9 +656,9 @@ dnd_create(struct display *display)
window_set_motion_handler(dnd->window,
dnd_motion_handler);
rectangle.width = 4 * (item_width + item_padding) + item_padding;
rectangle.height = 4 * (item_height + item_padding) + item_padding;
window_set_child_size(dnd->window, &rectangle);
width = 4 * (item_width + item_padding) + item_padding;
height = 4 * (item_height + item_padding) + item_padding;
window_set_child_size(dnd->window, width, height);
dnd_draw(dnd);

@ -49,7 +49,6 @@ struct gears {
struct window *window;
struct display *d;
struct rectangle rectangle;
EGLDisplay display;
EGLContext context;
@ -208,19 +207,8 @@ static void
allocate_buffer(struct gears *gears)
{
EGLImageKHR image;
struct rectangle allocation;
/* Constrain child size to be square and at least 300x300 */
window_get_child_rectangle(gears->window, &gears->rectangle);
if (gears->rectangle.width > gears->rectangle.height)
gears->rectangle.height = gears->rectangle.width;
else
gears->rectangle.width = gears->rectangle.height;
if (gears->rectangle.width < 300) {
gears->rectangle.width = 300;
gears->rectangle.height = 300;
}
window_set_child_size(gears->window, &gears->rectangle);
window_draw(gears->window);
gears->surface[gears->current] = window_get_surface(gears->window);
@ -239,16 +227,18 @@ allocate_buffer(struct gears *gears)
glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, image);
glBindRenderbuffer(GL_RENDERBUFFER_EXT, gears->depth_rbo);
window_get_child_allocation(gears->window, &allocation);
glRenderbufferStorage(GL_RENDERBUFFER_EXT,
GL_DEPTH_COMPONENT,
gears->rectangle.width + 20 + 32,
gears->rectangle.height + 60 + 32);
allocation.width + 20 + 32,
allocation.height + 60 + 32);
}
static void
draw_gears(struct gears *gears)
{
GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
struct rectangle allocation;
if (gears->surface[gears->current] == NULL)
allocate_buffer(gears);
@ -258,10 +248,11 @@ draw_gears(struct gears *gears)
GL_RENDERBUFFER_EXT,
gears->color_rbo[gears->current]);
glViewport(gears->rectangle.x, gears->rectangle.y,
gears->rectangle.width, gears->rectangle.height);
glScissor(gears->rectangle.x, gears->rectangle.y,
gears->rectangle.width, gears->rectangle.height);
window_get_child_allocation(gears->window, &allocation);
glViewport(allocation.x, allocation.y,
allocation.width, allocation.height);
glScissor(allocation.x, allocation.y,
allocation.width, allocation.height);
glEnable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -301,7 +292,8 @@ draw_gears(struct gears *gears)
}
static void
resize_handler(struct window *window, void *data)
resize_handler(struct window *window,
int32_t width, int32_t height, void *data)
{
struct gears *gears = data;
@ -309,6 +301,18 @@ resize_handler(struct window *window, void *data)
gears->surface[0] = NULL;
cairo_surface_destroy(gears->surface[1]);
gears->surface[1] = NULL;
/* Constrain child size to be square and at least 300x300 */
if (width > height)
height = width;
else
width = height;
if (width < 300) {
width = 300;
height = 300;
}
window_set_child_size(gears->window, width, height);
}
static void
@ -316,8 +320,10 @@ keyboard_focus_handler(struct window *window,
struct input *device, void *data)
{
struct gears *gears = data;
struct rectangle allocation;
resize_handler(window, gears);
window_get_child_allocation(gears->window, &allocation);
resize_handler(window, allocation.width, allocation.height, gears);
}
static void

@ -137,18 +137,18 @@ set_source_pixbuf(cairo_t *cr,
static void
image_draw(struct image *image)
{
struct rectangle rectangle;
struct rectangle allocation;
GdkPixbuf *pb;
cairo_t *cr;
cairo_surface_t *wsurface, *surface;
window_draw(image->window);
window_get_child_rectangle(image->window, &rectangle);
window_get_child_allocation(image->window, &allocation);
pb = gdk_pixbuf_new_from_file_at_size(image->filename,
rectangle.width,
rectangle.height,
allocation.width,
allocation.height,
NULL);
if (pb == NULL)
return;
@ -156,8 +156,8 @@ image_draw(struct image *image)
wsurface = window_get_surface(image->window);
surface = cairo_surface_create_similar(wsurface,
CAIRO_CONTENT_COLOR_ALPHA,
rectangle.width,
rectangle.height);
allocation.width,
allocation.height);
cairo_surface_destroy(wsurface);
cr = cairo_create(surface);
@ -166,14 +166,14 @@ image_draw(struct image *image)
cairo_paint(cr);
set_source_pixbuf(cr, pb,
0, 0,
rectangle.width, rectangle.height);
allocation.width, allocation.height);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_paint(cr);
cairo_destroy(cr);
g_object_unref(pb);
window_copy_surface(image->window, &rectangle, surface);
window_copy_surface(image->window, &allocation, surface);
window_flush(image->window);
cairo_surface_destroy(surface);
}

@ -38,7 +38,7 @@
struct resizor {
struct display *display;
struct window *window;
struct rectangle child_allocation;
int32_t width;
struct {
double current;
@ -71,9 +71,7 @@ frame_callback(void *data, uint32_t time)
resizor->height.previous = 200;
}
resizor->child_allocation.height = height + 0.5;
window_set_child_size(resizor->window,
&resizor->child_allocation);
window_set_child_size(resizor->window, resizor->width, height + 0.5);
window_schedule_redraw(resizor->window);
}
@ -83,21 +81,21 @@ resizor_draw(struct resizor *resizor)
{
cairo_surface_t *surface;
cairo_t *cr;
struct rectangle allocation;
window_draw(resizor->window);
window_get_child_rectangle(resizor->window,
&resizor->child_allocation);
window_get_child_allocation(resizor->window, &allocation);
surface = window_get_surface(resizor->window);
cr = cairo_create(surface);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_rectangle(cr,
resizor->child_allocation.x,
resizor->child_allocation.y,
resizor->child_allocation.width,
resizor->child_allocation.height);
allocation.x,
allocation.y,
allocation.width,
allocation.height);
cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
cairo_fill(cr);
cairo_destroy(cr);
@ -141,12 +139,10 @@ key_handler(struct window *window, uint32_t key, uint32_t sym,
switch (sym) {
case XK_Down:
resizor->height.target = 400;
resizor->height.current = resizor->child_allocation.height;
frame_callback(resizor, 0);
break;
case XK_Up:
resizor->height.target = 200;
resizor->height.current = resizor->child_allocation.height;
frame_callback(resizor, 0);
break;
}
@ -156,6 +152,7 @@ static struct resizor *
resizor_create(struct display *display)
{
struct resizor *resizor;
int32_t height;
resizor = malloc(sizeof *resizor);
if (resizor == NULL)
@ -171,15 +168,13 @@ resizor_create(struct display *display)
window_set_keyboard_focus_handler(resizor->window,
keyboard_focus_handler);
resizor->child_allocation.x = 0;
resizor->child_allocation.y = 0;
resizor->child_allocation.width = 300;
resizor->child_allocation.height = 400;
resizor->width = 300;
resizor->height.current = 400;
resizor->height.previous = 400;
resizor->height.target = 400;
resizor->height.previous = resizor->height.current;
resizor->height.target = resizor->height.current;
height = resizor->height.current + 0.5;
window_set_child_size(resizor->window, &resizor->child_allocation);
window_set_child_size(resizor->window, resizor->width, height);
resizor_draw(resizor);

@ -589,12 +589,28 @@ terminal_resize(struct terminal *terminal, int width, int height)
char *tab_ruler;
int data_pitch, attr_pitch;
int i, l, total_rows, start;
struct rectangle rectangle;
struct rectangle allocation;
struct winsize ws;
int32_t pixel_width, pixel_height;
if (width < 1)
width = 1;
if (height < 1)
height = 1;
if (terminal->width == width && terminal->height == height)
return;
if (!terminal->fullscreen) {
pixel_width = width *
terminal->extents.max_x_advance + 2 * terminal->margin;
pixel_height = height *
terminal->extents.height + 2 * terminal->margin;
window_set_child_size(terminal->window,
pixel_width, pixel_height);
}
window_schedule_redraw (terminal->window);
data_pitch = width * sizeof(union utf8_char);
size = data_pitch * height;
data = malloc(size);
@ -643,26 +659,12 @@ terminal_resize(struct terminal *terminal, int width, int height)
terminal->tab_ruler = tab_ruler;
terminal_init_tabs(terminal);
if (terminal->row >= terminal->height)
terminal->row = terminal->height - 1;
if (terminal->column >= terminal->width)
terminal->column = terminal->width - 1;
terminal->start = 0;
if (!terminal->fullscreen) {
rectangle.width = terminal->width *
terminal->extents.max_x_advance + 2 * terminal->margin;
rectangle.height = terminal->height *
terminal->extents.height + 2 * terminal->margin;
window_set_child_size(terminal->window, &rectangle);
}
/* Update the window size */
ws.ws_row = terminal->height;
ws.ws_col = terminal->width;
window_get_child_rectangle(terminal->window, &rectangle);
ws.ws_xpixel = rectangle.width;
ws.ws_ypixel = rectangle.height;
window_get_child_allocation(terminal->window, &allocation);
ws.ws_xpixel = allocation.width;
ws.ws_ypixel = allocation.height;
ioctl(terminal->master, TIOCSWINSZ, &ws);
}
@ -692,7 +694,7 @@ struct color_scheme DEFAULT_COLORS = {
static void
terminal_draw_contents(struct terminal *terminal)
{
struct rectangle rectangle;
struct rectangle allocation;
cairo_t *cr;
cairo_font_extents_t extents;
int top_margin, side_margin;
@ -710,9 +712,9 @@ terminal_draw_contents(struct terminal *terminal)
toShow.null = 0;
window_get_child_rectangle(terminal->window, &rectangle);
window_get_child_allocation(terminal->window, &allocation);
surface = display_create_surface(terminal->display, &rectangle);
surface = display_create_surface(terminal->display, &allocation);
cr = cairo_create(surface);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(cr,
@ -727,8 +729,8 @@ 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;
side_margin = (allocation.width - terminal->width * extents.max_x_advance) / 2;
top_margin = (allocation.height - terminal->height * extents.height) / 2;
cairo_set_line_width(cr, 1.0);
@ -819,31 +821,29 @@ terminal_draw_contents(struct terminal *terminal)
cairo_destroy(cr);
window_copy_surface(terminal->window,
&rectangle,
surface);
window_copy_surface(terminal->window, &allocation, surface);
cairo_surface_destroy(surface);
}
static void
terminal_draw(struct terminal *terminal)
resize_handler(struct window *window,
int32_t pixel_width, int32_t pixel_height, void *data)
{
struct rectangle rectangle;
struct terminal *terminal = data;
int32_t width, height;
window_get_child_rectangle(terminal->window, &rectangle);
width = (rectangle.width - 2 * terminal->margin) /
width = (pixel_width - 2 * terminal->margin) /
(int32_t) terminal->extents.max_x_advance;
height = (rectangle.height - 2 * terminal->margin) /
height = (pixel_height - 2 * terminal->margin) /
(int32_t) terminal->extents.height;
if (width < 0 || height < 0)
return;
terminal_resize(terminal, width, height);
}
static void
terminal_draw(struct terminal *terminal)
{
window_draw(terminal->window);
terminal_draw_contents(terminal);
window_flush(terminal->window);
@ -1838,6 +1838,7 @@ terminal_create(struct display *display, int fullscreen)
window_set_fullscreen(terminal->window, terminal->fullscreen);
window_set_user_data(terminal->window, terminal);
window_set_redraw_handler(terminal->window, redraw_handler);
window_set_resize_handler(terminal->window, resize_handler);
window_set_key_handler(terminal->window, key_handler);
window_set_keyboard_focus_handler(terminal->window,

@ -57,7 +57,7 @@ struct view {
static void
view_draw(struct view *view)
{
struct rectangle rectangle;
struct rectangle allocation;
cairo_surface_t *surface;
cairo_t *cr;
PopplerPage *page;
@ -65,15 +65,15 @@ view_draw(struct view *view)
window_draw(view->window);
window_get_child_rectangle(view->window, &rectangle);
window_get_child_allocation(view->window, &allocation);
page = poppler_document_get_page(view->document, view->page);
surface = window_get_surface(view->window);
cr = cairo_create(surface);
cairo_rectangle(cr, rectangle.x, rectangle.y,
rectangle.width, rectangle.height);
cairo_rectangle(cr, allocation.x, allocation.y,
allocation.width, allocation.height);
cairo_clip(cr);
cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
@ -81,16 +81,16 @@ view_draw(struct view *view)
cairo_paint(cr);
poppler_page_get_size(page, &width, &height);
doc_aspect = width / height;
window_aspect = (double) rectangle.width / rectangle.height;
window_aspect = (double) allocation.width / allocation.height;
if (doc_aspect < window_aspect)
scale = rectangle.height / height;
scale = allocation.height / height;
else
scale = rectangle.width / width;
cairo_translate(cr, rectangle.x, rectangle.y);
scale = allocation.width / width;
cairo_translate(cr, allocation.x, allocation.y);
cairo_scale(cr, scale, scale);
cairo_translate(cr,
(rectangle.width - width * scale) / 2 / scale,
(rectangle.height - height * scale) / 2 / scale);
(allocation.width - width * scale) / 2 / scale,
(allocation.height - height * scale) / 2 / scale);
cairo_rectangle(cr, 0, 0, width, height);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgb(cr, 1, 1, 1);

@ -1042,44 +1042,51 @@ handle_configure(void *data, struct wl_shell *shell,
struct wl_surface *surface, int32_t width, int32_t height)
{
struct window *window = wl_surface_get_user_data(surface);
int32_t child_width, child_height;
if (window->resize_handler) {
child_width = width - 20 - window->margin * 2;
child_height = height - 60 - window->margin * 2;
(*window->resize_handler)(window,
child_width, child_height,
window->user_data);
} else {
window->resize_edges = edges;
window->allocation.width = width;
window->allocation.height = height;
if (window->resize_handler)
(*window->resize_handler)(window, window->user_data);
if (window->redraw_handler)
window_schedule_redraw(window);
}
}
static const struct wl_shell_listener shell_listener = {
handle_configure,
};
void
window_get_child_rectangle(struct window *window,
struct rectangle *rectangle)
window_get_child_allocation(struct window *window,
struct rectangle *allocation)
{
if (window->fullscreen && !window->decoration) {
*rectangle = window->allocation;
*allocation = 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;
allocation->x = window->margin + 10;
allocation->y = window->margin + 50;
allocation->width =
window->allocation.width - 20 - window->margin * 2;
allocation->height =
window->allocation.height - 60 - window->margin * 2;
}
}
void
window_set_child_size(struct window *window,
struct rectangle *rectangle)
window_set_child_size(struct window *window, int32_t width, int32_t height)
{
if (!window->fullscreen) {
window->allocation.width =
rectangle->width + 20 + window->margin * 2;
window->allocation.height =
rectangle->height + 60 + window->margin * 2;
window->allocation.width = width + 20 + window->margin * 2;
window->allocation.height = height + 60 + window->margin * 2;
}
}

@ -105,7 +105,9 @@ enum pointer_type {
POINTER_HAND1,
};
typedef void (*window_resize_handler_t)(struct window *window, void *data);
typedef void (*window_resize_handler_t)(struct window *window,
int32_t width, int32_t height,
void *data);
typedef void (*window_redraw_handler_t)(struct window *window, void *data);
typedef void (*window_frame_handler_t)(struct window *window, uint32_t frame, uint32_t timestamp, void *data);
typedef void (*window_key_handler_t)(struct window *window, uint32_t key, uint32_t unicode,
@ -135,11 +137,10 @@ window_move(struct window *window, struct input *input, uint32_t time);
void
window_draw(struct window *window);
void
window_get_child_rectangle(struct window *window,
struct rectangle *rectangle);
window_get_child_allocation(struct window *window,
struct rectangle *allocation);
void
window_set_child_size(struct window *window,
struct rectangle *rectangle);
window_set_child_size(struct window *window, int32_t width, int32_t height);
void
window_copy_image(struct window *window,
struct rectangle *rectangle,

Loading…
Cancel
Save