From 26af01ddc3f7ede34e2d07f0f18a06f16912c3c5 Mon Sep 17 00:00:00 2001 From: Jason Francis Date: Tue, 6 Aug 2019 13:26:25 -0400 Subject: [PATCH] Reorder render list when clicking a display --- src/main.c | 91 +++++++++++++++++++++++++++---------------------- src/outputs.c | 10 ++++-- src/render.c | 39 +++++++++++++++------ src/wdisplays.h | 7 ++-- 4 files changed, 91 insertions(+), 56 deletions(-) diff --git a/src/main.c b/src/main.c index 35a9198..3d9875d 100644 --- a/src/main.c +++ b/src/main.c @@ -248,9 +248,9 @@ static gboolean redraw_canvas(GtkWidget *widget, GdkFrameClock *frame_clock, gpo static void update_tick_callback(struct wd_state *state) { bool any_animate = false; - for (int i = 0; i < state->render.head_count; i++) { - struct wd_render_head_data *head = &state->render.heads[i]; - if (state->render.updated_at < head->transition_begin + HOVER_USECS) { + struct wd_render_head_data *render; + wl_list_for_each(render, &state->render.heads, link) { + if (state->render.updated_at < render->transition_begin + HOVER_USECS) { any_animate = true; break; } @@ -299,31 +299,34 @@ static void update_hovered(struct wd_state *state) { GdkFrameClock *clock = gtk_widget_get_frame_clock(state->canvas); uint64_t tick = gdk_frame_clock_get_frame_time(clock); g_autoptr(GList) seats = gdk_display_list_seats(display); - struct wd_head *head; - wl_list_for_each(head, &state->heads, link) { - struct wd_render_head_data *render = head->render; - if (render != NULL) { - bool init_hovered = render->hovered; - render->hovered = false; - if (state->clicked == head) { - render->hovered = true; - } else if (state->clicked == NULL) { - for (GList *iter = seats; iter != NULL; iter = iter->next) { - double mouse_x; - double mouse_y; + bool any_hovered = false; + struct wd_render_head_data *render; + wl_list_for_each(render, &state->render.heads, link) { + bool init_hovered = render->hovered; + render->hovered = false; + if (any_hovered) { + continue; + } + if (state->clicked == render) { + render->hovered = true; + any_hovered = true; + } else if (state->clicked == NULL) { + for (GList *iter = seats; iter != NULL; iter = iter->next) { + double mouse_x; + double mouse_y; - GdkDevice *pointer = gdk_seat_get_pointer(GDK_SEAT(iter->data)); - gdk_window_get_device_position_double(window, pointer, &mouse_x, &mouse_y, NULL); - if (mouse_x >= render->x1 && mouse_x < render->x2 && - mouse_y >= render->y1 && mouse_y < render->y2) { - render->hovered = true; - break; - } + GdkDevice *pointer = gdk_seat_get_pointer(GDK_SEAT(iter->data)); + gdk_window_get_device_position_double(window, pointer, &mouse_x, &mouse_y, NULL); + if (mouse_x >= render->x1 && mouse_x < render->x2 && + mouse_y >= render->y1 && mouse_y < render->y2) { + render->hovered = true; + any_hovered = true; + break; } } - if (init_hovered != render->hovered) { - render->transition_begin = tick; - } + } + if (init_hovered != render->hovered) { + render->transition_begin = tick; } } update_cursor(state); @@ -353,7 +356,6 @@ static void queue_canvas_draw(struct wd_state *state) { cache_scroll(state); - state->render.head_count = 0; g_autoptr(GList) forms = gtk_container_get_children(GTK_CONTAINER(state->stack)); for (GList *form_iter = forms; form_iter != NULL; form_iter = form_iter->next) { GtkBuilder *builder = GTK_BUILDER(g_object_get_data(G_OBJECT(form_iter->data), "builder")); @@ -368,16 +370,15 @@ static void queue_canvas_draw(struct wd_state *state) { scale = 1.; struct wd_head *head = g_object_get_data(G_OBJECT(form_iter->data), "head"); - struct wd_render_head_data *render = &state->render.heads[state->render.head_count]; + if (head->render == NULL) { + head->render = calloc(1, sizeof(*head->render)); + wl_list_insert(&state->render.heads, &head->render->link); + } + struct wd_render_head_data *render = head->render; render->x1 = floor(x * state->zoom - state->render.scroll_x - state->render.x_origin); render->y1 = floor(y * state->zoom - state->render.scroll_y - state->render.y_origin); render->x2 = floor(render->x1 + w * state->zoom / scale); render->y2 = floor(render->y1 + h * state->zoom / scale); - head->render = render; - - state->render.head_count++; - if (state->render.head_count >= HEADS_MAX) - break; } } gtk_gl_area_queue_render(GTK_GL_AREA(state->canvas)); @@ -869,8 +870,8 @@ static gboolean canvas_click(GtkWidget *widget, GdkEvent *event, struct wd_state *state = data; if (event->button.type == GDK_BUTTON_PRESS) { if (event->button.button == 1) { - int i = 0; struct wd_head *head; + state->clicked = NULL; wl_list_for_each(head, &state->heads, link) { struct wd_render_head_data *render = head->render; if (render != NULL) { @@ -878,19 +879,27 @@ static gboolean canvas_click(GtkWidget *widget, GdkEvent *event, double mouse_y = event->button.y; if (mouse_x >= render->x1 && mouse_x < render->x2 && mouse_y >= render->y1 && mouse_y < render->y2) { - state->clicked = head; + state->clicked = render; state->click_offset.x = event->button.x - render->x1; state->click_offset.y = event->button.y - render->y1; break; } } - i++; } if (state->clicked != NULL) { + wl_list_remove(&state->clicked->link); + wl_list_insert(&state->render.heads, &state->clicked->link); + + struct wd_render_head_data *render; + wl_list_for_each(render, &state->render.heads, link) { + render->updated_at = 0; + render->preview = true; + } + gtk_gl_area_queue_render(GTK_GL_AREA(state->canvas)); g_autoptr(GList) forms = gtk_container_get_children(GTK_CONTAINER(state->stack)); for (GList *form_iter = forms; form_iter != NULL; form_iter = form_iter->next) { const struct wd_head *other = g_object_get_data(G_OBJECT(form_iter->data), "head"); - if (state->clicked == other) { + if (state->clicked == other->render) { gtk_stack_set_visible_child(GTK_STACK(state->stack), form_iter->data); break; } @@ -939,7 +948,7 @@ static gboolean canvas_motion(GtkWidget *widget, GdkEvent *event, g_autoptr(GList) forms = gtk_container_get_children(GTK_CONTAINER(state->stack)); for (GList *form_iter = forms; form_iter != NULL; form_iter = form_iter->next) { const struct wd_head *other = g_object_get_data(G_OBJECT(form_iter->data), "head"); - if (state->clicked == other) { + if (state->clicked == other->render) { form = form_iter->data; break; } @@ -965,7 +974,7 @@ static gboolean canvas_motion(GtkWidget *widget, GdkEvent *event, for (GList *form_iter = forms; form_iter != NULL; form_iter = form_iter->next) { const struct wd_head *other = g_object_get_data(G_OBJECT(form_iter->data), "head"); - if (other != state->clicked && !(event->motion.state & GDK_SHIFT_MASK)) { + if (other->render != state->clicked && !(event->motion.state & GDK_SHIFT_MASK)) { GtkBuilder *other_builder = GTK_BUILDER(g_object_get_data(G_OBJECT(form_iter->data), "builder")); double x1 = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(other_builder, "pos_x"))); double y1 = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(other_builder, "pos_y"))); @@ -1024,9 +1033,9 @@ static gboolean canvas_enter(GtkWidget *widget, GdkEvent *event, static gboolean canvas_leave(GtkWidget *widget, GdkEvent *event, gpointer data) { struct wd_state *state = data; - for (int i = 0; i < state->render.head_count; i++) { - struct wd_render_head_data *head = &state->render.heads[i]; - head->hovered = false; + struct wd_render_head_data *render; + wl_list_for_each(render, &state->render.heads, link) { + render->hovered = false; } update_tick_callback(state); return TRUE; diff --git a/src/outputs.c b/src/outputs.c index ea3b549..d84b2a4 100644 --- a/src/outputs.c +++ b/src/outputs.c @@ -312,10 +312,15 @@ static void wd_mode_destroy(struct wd_mode* mode) { } static void wd_head_destroy(struct wd_head *head) { - struct wd_mode *mode, *mode_tmp; - if (head->state->clicked == head) { + if (head->state->clicked == head->render) { head->state->clicked = NULL; } + if (head->render != NULL) { + wl_list_remove(&head->render->link); + free(head->render); + head->render = NULL; + } + struct wd_mode *mode, *mode_tmp; wl_list_for_each_safe(mode, mode_tmp, &head->modes, link) { zwlr_output_mode_v1_destroy(mode->wlr_mode); free(mode); @@ -630,6 +635,7 @@ struct wd_state *wd_state_create(void) { state->capture = true; wl_list_init(&state->heads); wl_list_init(&state->outputs); + wl_list_init(&state->render.heads); return state; } diff --git a/src/render.c b/src/render.c index eb333bb..c6df033 100644 --- a/src/render.c +++ b/src/render.c @@ -27,6 +27,7 @@ #include #include #include +#include #define CANVAS_MARGIN 100 @@ -228,10 +229,15 @@ void wd_gl_render(struct wd_gl_data *res, struct wd_render_data *info, uint64_t tick) { unsigned int tris = 0; - if (info->head_count > res->texture_count) { - glGenTextures(info->head_count - res->texture_count, + unsigned int head_count = wl_list_length(&info->heads); + if (head_count >= HEADS_MAX) { + head_count = HEADS_MAX; + } + + if (head_count > res->texture_count) { + glGenTextures(head_count - res->texture_count, res->textures + res->texture_count); - for (int i = res->texture_count; i < info->head_count; i++) { + for (int i = res->texture_count; i < head_count; i++) { glBindTexture(GL_TEXTURE_2D, res->textures[i]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -239,11 +245,12 @@ void wd_gl_render(struct wd_gl_data *res, struct wd_render_data *info, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } glBindTexture(GL_TEXTURE_2D, 0); - res->texture_count = info->head_count; + res->texture_count = head_count; } - for (int i = 0; i < info->head_count; i++) { - struct wd_render_head_data *head = &info->heads[i]; + struct wd_render_head_data *head; + int i = 0; + wl_list_for_each_reverse(head, &info->heads, link) { float *tri_ptr = res->tris + i * BT_UV_QUAD_SIZE; float x1 = head->x1; float y1 = head->y1; @@ -261,6 +268,10 @@ void wd_gl_render(struct wd_gl_data *res, struct wd_render_data *info, PUSH_POINT_UV(tri_ptr, x2, y2, 1.f, t2) tris += 6; + i++; + if (i >= HEADS_MAX) { + break; + } } glClearColor(info->bg_color[0], info->bg_color[1], info->bg_color[2], 1.f); @@ -284,8 +295,8 @@ void wd_gl_render(struct wd_gl_data *res, struct wd_render_data *info, glUniform1i(res->texture_texture_uniform, 0); glActiveTexture(GL_TEXTURE0); - for (int i = 0; i < info->head_count; i++) { - struct wd_render_head_data *head = &info->heads[i]; + i = 0; + wl_list_for_each_reverse(head, &info->heads, link) { glBindTexture(GL_TEXTURE_2D, res->textures[i]); if (head->updated_at == tick) { glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, head->tex_stride / 4); @@ -297,14 +308,18 @@ void wd_gl_render(struct wd_gl_data *res, struct wd_render_data *info, glUniformMatrix4fv(res->texture_color_transform_uniform, 1, GL_FALSE, head->swap_rgb ? TRANSFORM_RGB : TRANSFORM_BGR); glDrawArrays(GL_TRIANGLES, i * 6, 6); + i++; + if (i >= HEADS_MAX) { + break; + } } } tris = 0; int j = 0; - for (int i = 0; i < info->head_count; i++) { - struct wd_render_head_data *head = &info->heads[i]; + i = 0; + wl_list_for_each_reverse(head, &info->heads, link) { if (head->hovered || tick < head->transition_begin + HOVER_USECS) { float *tri_ptr = res->tris + j++ * BT_COLOR_QUAD_SIZE; float x1 = head->x1; @@ -343,6 +358,10 @@ void wd_gl_render(struct wd_gl_data *res, struct wd_render_data *info, tris += 6; } + i++; + if (i >= HEADS_MAX) { + break; + } } if (tris > 0) { diff --git a/src/wdisplays.h b/src/wdisplays.h index 896d578..a8fcd1e 100644 --- a/src/wdisplays.h +++ b/src/wdisplays.h @@ -144,6 +144,8 @@ struct wd_head { struct wd_gl_data; struct wd_render_head_data { + struct wl_list link; + float x1; float y1; float x2; @@ -177,8 +179,7 @@ struct wd_render_data { int y_origin; uint64_t updated_at; - unsigned int head_count; - struct wd_render_head_data heads[HEADS_MAX]; + struct wl_list heads; }; struct wd_point { @@ -200,7 +201,7 @@ struct wd_state { bool capture; double zoom; - struct wd_head *clicked; + struct wd_render_head_data *clicked; /* top left, bottom right */ struct wd_point click_offset; bool panning;