More work on per window logo

This commit is contained in:
Kovid Goyal 2021-12-03 13:13:37 +05:30
parent e04919098f
commit 3d2877eeb9
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
8 changed files with 168 additions and 20 deletions

View file

@ -65,9 +65,9 @@ typedef enum MouseTrackingProtocols { NORMAL_PROTOCOL, UTF8_PROTOCOL, SGR_PROTOC
typedef enum MouseShapes { BEAM, HAND, ARROW } MouseShape;
typedef enum { NONE, MENUBAR, WINDOW, ALL } WindowTitleIn;
typedef enum { TILING, SCALED, MIRRORED, CLAMPED } BackgroundImageLayout;
typedef struct {
float x, y;
} BackgroundImageAnchor;
typedef struct ImageAnchorPosition {
float canvas_x, canvas_y, image_x, image_y;
} ImageAnchorPosition;
#define MAX_CHILDREN 512
#define BLANK_CHAR 0

View file

@ -541,6 +541,7 @@ make_os_window_context_current(OSWindow *w) {
GLFWwindow *current_context = glfwGetCurrentContext();
if (w->handle != current_context) {
glfwMakeContextCurrent(w->handle);
global_state.current_opengl_context_id = w->id;
}
}
@ -870,6 +871,7 @@ create_os_window(PyObject UNUSED *self, PyObject *args, PyObject *kw) {
w->cursor_blink_zero_time = now;
w->last_mouse_activity_at = now;
w->is_semi_transparent = is_semi_transparent;
global_state.current_opengl_context_id = w->id;
if (want_semi_transparent && !w->is_semi_transparent) {
static bool warned = false;
if (!warned) {

View file

@ -78,19 +78,19 @@ bglayout(PyObject *layout_name) {
return TILING;
}
static BackgroundImageAnchor
static ImageAnchorPosition
bganchor(PyObject *anchor_name) {
const char *name = PyUnicode_AsUTF8(anchor_name);
BackgroundImageAnchor anchor = { .x = 0.5f, .y = 0.5f };
ImageAnchorPosition anchor = {0.5f, 0.5f, 0.5f, 0.5f};
if (strstr(name, "top") != NULL) {
anchor.y = 0.0f;
anchor.canvas_y = 0.f; anchor.image_y = 0.f;
} else if (strstr(name, "bottom") != NULL) {
anchor.y = 1.0f;
anchor.canvas_y = 1.f; anchor.image_y = 1.f;
}
if (strstr(name, "left") != NULL) {
anchor.x = 0.0f;
anchor.canvas_x = 0.f; anchor.image_x = 0.f;
} else if (strstr(name, "right") != NULL) {
anchor.x = 1.0f;
anchor.canvas_x = 1.f; anchor.image_x = 1.f;
}
return anchor;
}

View file

@ -9,6 +9,7 @@
#include "gl.h"
#include "colors.h"
#include <stddef.h>
#include "window_logo.h"
#define BLEND_ONTO_OPAQUE glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // blending onto opaque colors
#define BLEND_PREMULT glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // blending of pre-multiplied colors
@ -578,6 +579,19 @@ render_window_title(OSWindow *os_window, Screen *screen UNUSED, GLfloat xstart,
return 2.f * (GLfloat)bar_height / (GLfloat)os_window->viewport_height;
}
static void
draw_window_logo(int program, OSWindow *os_window, const WindowLogoRenderData *wl, GLfloat window_left_gl, GLfloat window_top_gl, GLfloat window_width_gl, GLfloat window_height_gl) {
GLfloat logo_width_gl = 2.f * ((float)wl->instance->width) / os_window->viewport_width;
GLfloat logo_height_gl = 2.f * ((float)wl->instance->height) / os_window->viewport_height;
GLfloat logo_left_gl = window_left_gl + window_width_gl * wl->position.canvas_x - logo_width_gl * wl->position.image_x;
GLfloat logo_top_gl = window_top_gl - window_height_gl * wl->position.canvas_y + logo_height_gl * wl->position.image_y;
static ImageRenderData ird = {.group_count=1};
ird.texture_id = wl->instance->texture_id;
gpu_data_for_image(&ird, logo_left_gl, logo_top_gl, logo_left_gl + logo_width_gl, logo_top_gl - logo_height_gl);
send_graphics_data_to_gpu(1, os_window->gvao_idx, &ird);
draw_graphics(program, 0, os_window->gvao_idx, &ird, 0, 1);
}
static void
draw_window_number(OSWindow *os_window, Screen *screen, GLfloat xstart, GLfloat ystart, GLfloat width, GLfloat height, Window *window, GLfloat dx, GLfloat dy) {
GLfloat left = os_window->viewport_width * (xstart + 1.f) / 2.f;
@ -652,7 +666,7 @@ draw_visual_bell_flash(GLfloat intensity, GLfloat xstart, GLfloat ystart, GLfloa
}
static void
draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, OSWindow *w, GLfloat xstart, GLfloat ystart, GLfloat width, GLfloat height) {
draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, OSWindow *w, GLfloat xstart, GLfloat ystart, GLfloat width, GLfloat height, const WindowLogoRenderData *wl) {
glEnable(GL_BLEND);
BLEND_ONTO_OPAQUE;
@ -667,10 +681,11 @@ draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, OSWind
BLEND_ONTO_OPAQUE;
}
if (screen->grman->num_of_below_refs || has_bgimage(w)) {
if (screen->grman->num_of_below_refs || has_bgimage(w) || wl) {
if (wl) draw_window_logo(GRAPHICS_PROGRAM, w, wl, xstart, ystart, width, height);
bind_program(CELL_BG_PROGRAM);
if (screen->grman->num_of_below_refs) draw_graphics(
GRAPHICS_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, 0, screen->grman->num_of_below_refs);
bind_program(CELL_BG_PROGRAM);
// draw background for non-default bg cells
glUniform1ui(cell_program_layouts[CELL_BG_PROGRAM].draw_bg_bitfield_location, 2);
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, screen->lines * screen->columns);
@ -692,7 +707,7 @@ draw_cells_interleaved(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, OSWind
}
static void
draw_cells_interleaved_premult(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, OSWindow *os_window, GLfloat xstart, GLfloat ystart, GLfloat width, GLfloat height) {
draw_cells_interleaved_premult(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen, OSWindow *os_window, GLfloat xstart, GLfloat ystart, GLfloat width, GLfloat height, const WindowLogoRenderData *wl) {
if (OPT(background_tint) > 0.f) {
glEnable(GL_BLEND);
BLEND_PREMULT;
@ -722,7 +737,8 @@ draw_cells_interleaved_premult(ssize_t vao_idx, ssize_t gvao_idx, Screen *screen
glEnable(GL_BLEND);
BLEND_PREMULT;
if (screen->grman->num_of_below_refs || has_bgimage(os_window)) {
if (screen->grman->num_of_below_refs || has_bgimage(os_window) || wl) {
if (wl) draw_window_logo(GRAPHICS_PREMULT_PROGRAM, os_window, wl, xstart, ystart, width, height);
if (screen->grman->num_of_below_refs) draw_graphics(
GRAPHICS_PREMULT_PROGRAM, vao_idx, gvao_idx, screen->grman->render_data, 0, screen->grman->num_of_below_refs);
bind_program(CELL_BG_PROGRAM);
@ -841,13 +857,19 @@ draw_cells(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GL
(GLsizei)roundf(SCALE(height, h / 2.f)) // height
);
#undef SCALE
bool has_underlying_image = has_bgimage(os_window);
WindowLogoRenderData *wl = &window->window_logo;
if (wl->instance && wl->instance->load_from_disk_ok) {
has_underlying_image = true;
set_on_gpu_state(window->window_logo.instance, true);
} else wl = NULL;
if (os_window->is_semi_transparent) {
if (screen->grman->count || has_bgimage(os_window)) draw_cells_interleaved_premult(
vao_idx, gvao_idx, screen, os_window, xstart, ystart, w, h);
if (screen->grman->count || has_underlying_image) draw_cells_interleaved_premult(
vao_idx, gvao_idx, screen, os_window, xstart, ystart, w, h, wl);
else draw_cells_simple(vao_idx, gvao_idx, screen);
} else {
if (screen->grman->num_of_negative_refs || screen->grman->num_of_below_refs || has_bgimage(os_window)) draw_cells_interleaved(
vao_idx, gvao_idx, screen, os_window, xstart, ystart, w, h);
if (screen->grman->num_of_negative_refs || screen->grman->num_of_below_refs || has_underlying_image) draw_cells_interleaved(
vao_idx, gvao_idx, screen, os_window, xstart, ystart, w, h, wl);
else draw_cells_simple(vao_idx, gvao_idx, screen);
}

View file

@ -224,12 +224,30 @@ release_gpu_resources_for_window(Window *w) {
w->render_data.gvao_idx = -1;
}
static void
set_default_window_logo(Window *w) {
if (OPT(default_window_logo)) {
WindowLogo *wl = find_or_create_window_logo(&global_state.all_window_logos, OPT(default_window_logo));
if (wl) {
w->window_logo.instance = wl;
w->window_logo.position = OPT(window_logo_position);
} else if (PyErr_Occurred()) {
log_error("Failed to load default window logo: %s", OPT(default_window_logo));
PyErr_Print();
}
} else {
decref_window_logo(&global_state.all_window_logos, &w->window_logo.instance);
}
w->window_logo.using_default = true;
}
static void
initialize_window(Window *w, PyObject *title, bool init_gpu_resources) {
w->id = ++global_state.window_id_counter;
w->visible = true;
w->title = title;
Py_XINCREF(title);
set_default_window_logo(w);
if (init_gpu_resources) create_gpu_resources_for_window(w);
else {
w->render_data.vao_idx = -1;
@ -290,6 +308,7 @@ destroy_window(Window *w) {
Py_CLEAR(w->render_data.screen); Py_CLEAR(w->title);
free(w->title_bar_data.buf); w->title_bar_data.buf = NULL;
release_gpu_resources_for_window(w);
decref_window_logo(&global_state.all_window_logos, &w->window_logo.instance);
}
static void

View file

@ -8,6 +8,7 @@
#include "data-types.h"
#include "screen.h"
#include "monotonic.h"
#include "window_logo.h"
#define OPT(name) global_state.opts.name
@ -47,7 +48,7 @@ typedef struct {
char *background_image, *default_window_logo;
BackgroundImageLayout background_image_layout;
BackgroundImageAnchor window_logo_position;
ImageAnchorPosition window_logo_position;
bool background_image_linear;
float background_tint;
@ -81,6 +82,12 @@ typedef struct {
} tab_bar_margin_height;
} Options;
typedef struct WindowLogoRenderData {
WindowLogo *instance;
ImageAnchorPosition position;
bool using_default;
} WindowLogoRenderData;
typedef struct {
ssize_t vao_idx, gvao_idx;
float xstart, ystart, dx, dy;
@ -116,6 +123,7 @@ typedef struct {
CursorShape last_cursor_shape;
PyObject *title;
ScreenRenderData render_data;
WindowLogoRenderData window_logo;
MousePosition mouse_pos;
struct {
unsigned int left, top, right, bottom;
@ -205,7 +213,7 @@ typedef struct {
typedef struct {
Options opts;
id_type os_window_id_counter, tab_id_counter, window_id_counter;
id_type os_window_id_counter, tab_id_counter, window_id_counter, current_opengl_context_id;
PyObject *boss;
BackgroundImage *bgimage;
OSWindow *os_windows;
@ -222,6 +230,7 @@ typedef struct {
int active_drag_button;
CloseRequest quit_request;
bool redirect_mouse_handling;
WindowLogo *all_window_logos;
} GlobalState;
extern GlobalState global_state;

67
kitty/window_logo.c Normal file
View file

@ -0,0 +1,67 @@
/*
* window_logo.c
* Copyright (C) 2021 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#include "window_logo.h"
#include "state.h"
typedef struct WindowLogoItem {
WindowLogoHead
unsigned int refcnt;
char *path;
UT_hash_handle hh;
} WindowLogoItem;
static void
free_window_logo(WindowLogoItem **head, WindowLogoItem **itemref) {
WindowLogoItem *item = *itemref;
free(item->path);
free(item->bitmap);
if (item->texture_id) free_texture(&item->texture_id);
HASH_DEL(*head, item);
free(item); itemref = NULL;
}
static void
send_logo_to_gpu(WindowLogoItem *s) {
send_image_to_gpu(&s->texture_id, s->bitmap, s->width, s->height, false, true, true, REPEAT_CLAMP);
}
void
set_on_gpu_state(WindowLogo *x, bool on_gpu) {
WindowLogoItem *s = (WindowLogoItem*)x;
if (s->load_from_disk_ok) {
if (on_gpu) { if (!s->texture_id) send_logo_to_gpu(s); }
else if (s->texture_id) free_texture(&s->texture_id);
}
}
WindowLogo*
find_or_create_window_logo(WindowLogo **head_, const char *path) {
WindowLogoItem **head = (WindowLogoItem**)head_;
WindowLogoItem *s = NULL;
HASH_FIND_STR(*head, path, s);
if (s) return (WindowLogo*)s;
s = calloc(1, sizeof *s);
size_t size;
if (!s) { PyErr_NoMemory(); return NULL; }
s->path = strdup(path);
if (!s->path) { free(s->bitmap); free(s); PyErr_NoMemory(); return NULL; }
if (png_path_to_bitmap(path, &s->bitmap, &s->width, &s->height, &size)) s->load_from_disk_ok = true;
s->refcnt++;
HASH_ADD_KEYPTR(hh, *head, s->path, strlen(s->path), s);
return (WindowLogo*)s;
}
void
decref_window_logo(WindowLogo **head_, WindowLogo** logo) {
WindowLogoItem **head = (WindowLogoItem**)head_;
WindowLogoItem **s = (WindowLogoItem**)logo;
if (*s) { if ((*s)->refcnt < 2) free_window_logo(head, s); else (*s)->refcnt--; }
}

29
kitty/window_logo.h Normal file
View file

@ -0,0 +1,29 @@
/*
* Copyright (C) 2021 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#pragma once
#include "kitty-uthash.h"
#define WindowLogoHead \
unsigned int height, width; \
bool load_from_disk_ok; \
uint32_t texture_id; \
uint8_t* bitmap;
typedef struct WindowLogo {
WindowLogoHead
} WindowLogo;
WindowLogo*
find_or_create_window_logo(WindowLogo **head, const char *path);
void
decref_window_logo(WindowLogo **head, WindowLogo** logo);
void
set_on_gpu_state(WindowLogo *logo, bool on_gpu);