mirror of
				https://github.com/swaywm/sway.git
				synced 2025-10-29 05:40:18 -04:00 
			
		
		
		
	R E N D E R I N G
This commit is contained in:
		
							parent
							
								
									e902de34db
								
							
						
					
					
						commit
						d053acbed6
					
				
					 5 changed files with 159 additions and 9 deletions
				
			
		|  | @ -28,7 +28,8 @@ cairo_surface_t *load_background_image(const char *path) { | ||||||
| 	GError *err = NULL; | 	GError *err = NULL; | ||||||
| 	GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(path, &err); | 	GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(path, &err); | ||||||
| 	if (!pixbuf) { | 	if (!pixbuf) { | ||||||
| 		wlr_log(L_ERROR, "Failed to load background image."); | 		wlr_log(L_ERROR, "Failed to load background image (%s).", | ||||||
|  | 				err->message); | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| 	image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf); | 	image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf); | ||||||
|  |  | ||||||
|  | @ -9,6 +9,14 @@ | ||||||
| #include "swaylock/seat.h" | #include "swaylock/seat.h" | ||||||
| #include "wlr-layer-shell-unstable-v1-client-protocol.h" | #include "wlr-layer-shell-unstable-v1-client-protocol.h" | ||||||
| 
 | 
 | ||||||
|  | enum auth_state { | ||||||
|  |     AUTH_STATE_IDLE, | ||||||
|  |     AUTH_STATE_INPUT, | ||||||
|  |     AUTH_STATE_BACKSPACE, | ||||||
|  |     AUTH_STATE_VALIDATING, | ||||||
|  |     AUTH_STATE_INVALID, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| struct swaylock_args { | struct swaylock_args { | ||||||
| 	uint32_t color; | 	uint32_t color; | ||||||
| 	enum background_mode mode; | 	enum background_mode mode; | ||||||
|  | @ -30,6 +38,7 @@ struct swaylock_state { | ||||||
| 	struct swaylock_args args; | 	struct swaylock_args args; | ||||||
| 	struct swaylock_password password; | 	struct swaylock_password password; | ||||||
| 	struct swaylock_xkb xkb; | 	struct swaylock_xkb xkb; | ||||||
|  | 	enum auth_state auth_state; | ||||||
| 	bool run_display; | 	bool run_display; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -48,5 +57,6 @@ struct swaylock_surface { | ||||||
| void swaylock_handle_key(struct swaylock_state *state, | void swaylock_handle_key(struct swaylock_state *state, | ||||||
| 		xkb_keysym_t keysym, uint32_t codepoint); | 		xkb_keysym_t keysym, uint32_t codepoint); | ||||||
| void render_frame(struct swaylock_surface *surface); | void render_frame(struct swaylock_surface *surface); | ||||||
|  | void render_frames(struct swaylock_state *state); | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -133,6 +133,7 @@ int main(int argc, char **argv) { | ||||||
| 		.color = 0xFFFFFFFF, | 		.color = 0xFFFFFFFF, | ||||||
| 		.show_indicator = true, | 		.show_indicator = true, | ||||||
| 	}; | 	}; | ||||||
|  | 	cairo_surface_t *background_image = NULL; | ||||||
| 	state.args = args; | 	state.args = args; | ||||||
| 	wlr_log_init(L_DEBUG, NULL); | 	wlr_log_init(L_DEBUG, NULL); | ||||||
| 
 | 
 | ||||||
|  | @ -150,8 +151,13 @@ int main(int argc, char **argv) { | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 		case 'i': | 		case 'i': | ||||||
| 			// TODO
 | 			// TODO: Multiple background images (bleh)
 | ||||||
| 			return 1; | 			background_image = load_background_image(optarg); | ||||||
|  | 			if (!background_image) { | ||||||
|  | 				return 1; | ||||||
|  | 			} | ||||||
|  | 			state.args.mode = BACKGROUND_MODE_FILL; | ||||||
|  | 			break; | ||||||
| 		case 's': | 		case 's': | ||||||
| 			state.args.mode = parse_background_mode(optarg); | 			state.args.mode = parse_background_mode(optarg); | ||||||
| 			if (state.args.mode == BACKGROUND_MODE_INVALID) { | 			if (state.args.mode == BACKGROUND_MODE_INVALID) { | ||||||
|  | @ -159,7 +165,7 @@ int main(int argc, char **argv) { | ||||||
| 			} | 			} | ||||||
| 			break; | 			break; | ||||||
| 		case 't': | 		case 't': | ||||||
| 			// TODO
 | 			state.args.mode = BACKGROUND_MODE_TILE; | ||||||
| 			break; | 			break; | ||||||
| 		case 'v': | 		case 'v': | ||||||
| #if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE | #if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE | ||||||
|  | @ -197,6 +203,8 @@ int main(int argc, char **argv) { | ||||||
| 
 | 
 | ||||||
| 	struct swaylock_surface *surface; | 	struct swaylock_surface *surface; | ||||||
| 	wl_list_for_each(surface, &state.surfaces, link) { | 	wl_list_for_each(surface, &state.surfaces, link) { | ||||||
|  | 		surface->image = background_image; | ||||||
|  | 
 | ||||||
| 		assert(surface->surface = | 		assert(surface->surface = | ||||||
| 				wl_compositor_create_surface(state.compositor)); | 				wl_compositor_create_surface(state.compositor)); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -50,21 +50,23 @@ static bool attempt_password(struct swaylock_password *pw) { | ||||||
| 		wlr_log(L_ERROR, "pam_end failed"); | 		wlr_log(L_ERROR, "pam_end failed"); | ||||||
| 		goto fail; | 		goto fail; | ||||||
| 	} | 	} | ||||||
| 	// PAM freed this
 | 	// PAM frees this
 | ||||||
| 	pw->buffer = NULL; | 	pw->buffer = NULL; | ||||||
| 	pw->len = pw->size = 0; | 	pw->len = pw->size = 0; | ||||||
| 	return true; | 	return true; | ||||||
| fail: | fail: | ||||||
| 	// PAM freed this
 | 	// PAM frees this
 | ||||||
| 	pw->buffer = NULL; | 	pw->buffer = NULL; | ||||||
| 	pw->len = pw->size = 0; | 	pw->len = pw->size = 0; | ||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void backspace(struct swaylock_password *pw) { | static bool backspace(struct swaylock_password *pw) { | ||||||
| 	if (pw->len != 0) { | 	if (pw->len != 0) { | ||||||
| 		pw->buffer[--pw->len] = 0; | 		pw->buffer[--pw->len] = 0; | ||||||
|  | 		return true; | ||||||
| 	} | 	} | ||||||
|  | 	return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void append_ch(struct swaylock_password *pw, uint32_t codepoint) { | static void append_ch(struct swaylock_password *pw, uint32_t codepoint) { | ||||||
|  | @ -97,17 +99,27 @@ void swaylock_handle_key(struct swaylock_state *state, | ||||||
| 	switch (keysym) { | 	switch (keysym) { | ||||||
| 		case XKB_KEY_KP_Enter: /* fallthrough */ | 		case XKB_KEY_KP_Enter: /* fallthrough */ | ||||||
| 		case XKB_KEY_Return: | 		case XKB_KEY_Return: | ||||||
|  | 			state->auth_state = AUTH_STATE_VALIDATING; | ||||||
|  | 			render_frames(state); | ||||||
| 			if (attempt_password(&state->password)) { | 			if (attempt_password(&state->password)) { | ||||||
| 				exit(0); | 				exit(0); | ||||||
| 			} | 			} | ||||||
|  | 			state->auth_state = AUTH_STATE_INVALID; | ||||||
|  | 			render_frames(state); | ||||||
| 			break; | 			break; | ||||||
| 		case XKB_KEY_BackSpace: | 		case XKB_KEY_BackSpace: | ||||||
| 			backspace(&state->password); | 			if (backspace(&state->password)) { | ||||||
|  | 				state->auth_state = AUTH_STATE_BACKSPACE; | ||||||
|  | 				render_frames(state); | ||||||
|  | 			} | ||||||
| 			break; | 			break; | ||||||
| 		default: | 		default: | ||||||
| 			if (codepoint) { | 			if (codepoint) { | ||||||
| 				append_ch(&state->password, codepoint); | 				append_ch(&state->password, codepoint); | ||||||
|  | 				state->auth_state = AUTH_STATE_INPUT; | ||||||
|  | 				render_frames(state); | ||||||
| 			} | 			} | ||||||
| 			break; | 			break; | ||||||
| 	} | 	} | ||||||
|  | 	// TODO: Expire state in a few seconds
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,21 +1,140 @@ | ||||||
| #include <wayland-client.h> | #include <wayland-client.h> | ||||||
|  | #include <math.h> | ||||||
| #include "cairo.h" | #include "cairo.h" | ||||||
| #include "background-image.h" | #include "background-image.h" | ||||||
| #include "swaylock/swaylock.h" | #include "swaylock/swaylock.h" | ||||||
| 
 | 
 | ||||||
|  | #define M_PI 3.14159265358979323846 | ||||||
|  | 
 | ||||||
| void render_frame(struct swaylock_surface *surface) { | void render_frame(struct swaylock_surface *surface) { | ||||||
| 	struct swaylock_state *state = surface->state; | 	struct swaylock_state *state = surface->state; | ||||||
| 	surface->current_buffer = get_next_buffer(state->shm, | 	surface->current_buffer = get_next_buffer(state->shm, | ||||||
| 			surface->buffers, surface->width, surface->height); | 			surface->buffers, surface->width, surface->height); | ||||||
| 	cairo_t *cairo = surface->current_buffer->cairo; | 	cairo_t *cairo = surface->current_buffer->cairo; | ||||||
|  | 	cairo_identity_matrix(cairo); | ||||||
| 	if (state->args.mode == BACKGROUND_MODE_SOLID_COLOR) { | 	if (state->args.mode == BACKGROUND_MODE_SOLID_COLOR) { | ||||||
| 		cairo_set_source_u32(cairo, state->args.color); | 		cairo_set_source_u32(cairo, state->args.color); | ||||||
| 		cairo_paint(cairo); | 		cairo_paint(cairo); | ||||||
| 	} else { | 	} else { | ||||||
|  | 		// TODO: hidpi
 | ||||||
| 		render_background_image(cairo, surface->image, | 		render_background_image(cairo, surface->image, | ||||||
| 				state->args.mode, surface->width, surface->height); | 				state->args.mode, surface->width, surface->height, 1); | ||||||
| 	} | 	} | ||||||
|  | 	cairo_identity_matrix(cairo); | ||||||
|  | 
 | ||||||
|  | 	const int ARC_RADIUS = 50; | ||||||
|  | 	const int ARC_THICKNESS = 10; | ||||||
|  | 	const float TYPE_INDICATOR_RANGE = M_PI / 3.0f; | ||||||
|  | 	const float TYPE_INDICATOR_BORDER_THICKNESS = M_PI / 128.0f; | ||||||
|  | 	if (state->args.show_indicator && state->auth_state != AUTH_STATE_IDLE) { | ||||||
|  | 		// Draw circle
 | ||||||
|  | 		cairo_set_line_width(cairo, ARC_THICKNESS); | ||||||
|  | 		cairo_arc(cairo, surface->width / 2, surface->height / 2, | ||||||
|  | 				ARC_RADIUS, 0, 2 * M_PI); | ||||||
|  | 		switch (state->auth_state) { | ||||||
|  | 		case AUTH_STATE_INPUT: | ||||||
|  | 		case AUTH_STATE_BACKSPACE: { | ||||||
|  | 			cairo_set_source_rgba(cairo, 0, 0, 0, 0.75); | ||||||
|  | 			cairo_fill_preserve(cairo); | ||||||
|  | 			cairo_set_source_rgb(cairo, 51.0 / 255, 125.0 / 255, 0); | ||||||
|  | 			cairo_stroke(cairo); | ||||||
|  | 		} break; | ||||||
|  | 		case AUTH_STATE_VALIDATING: { | ||||||
|  | 			cairo_set_source_rgba(cairo, 0, 114.0 / 255, 255.0 / 255, 0.75); | ||||||
|  | 			cairo_fill_preserve(cairo); | ||||||
|  | 			cairo_set_source_rgb(cairo, 51.0 / 255, 0, 250.0 / 255); | ||||||
|  | 			cairo_stroke(cairo); | ||||||
|  | 		} break; | ||||||
|  | 		case AUTH_STATE_INVALID: { | ||||||
|  | 			cairo_set_source_rgba(cairo, 250.0 / 255, 0, 0, 0.75); | ||||||
|  | 			cairo_fill_preserve(cairo); | ||||||
|  | 			cairo_set_source_rgb(cairo, 125.0 / 255, 51.0 / 255, 0); | ||||||
|  | 			cairo_stroke(cairo); | ||||||
|  | 		} break; | ||||||
|  | 		default: break; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// Draw a message
 | ||||||
|  | 		char *text = NULL; | ||||||
|  | 		cairo_set_source_rgb(cairo, 0, 0, 0); | ||||||
|  | 		cairo_select_font_face(cairo, "sans-serif", | ||||||
|  | 				CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); | ||||||
|  | 		cairo_set_font_size(cairo, ARC_RADIUS / 3.0f); | ||||||
|  | 		switch (state->auth_state) { | ||||||
|  | 		case AUTH_STATE_VALIDATING: | ||||||
|  | 			text = "verifying"; | ||||||
|  | 			break; | ||||||
|  | 		case AUTH_STATE_INVALID: | ||||||
|  | 			text = "wrong"; | ||||||
|  | 			break; | ||||||
|  | 		default: break; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (text) { | ||||||
|  | 			cairo_text_extents_t extents; | ||||||
|  | 			double x, y; | ||||||
|  | 			cairo_text_extents(cairo, text, &extents); | ||||||
|  | 			x = (surface->width / 2) - | ||||||
|  | 				(extents.width / 2 + extents.x_bearing); | ||||||
|  | 			y = (surface->height / 2) - | ||||||
|  | 				(extents.height / 2 + extents.y_bearing); | ||||||
|  | 
 | ||||||
|  | 			cairo_move_to(cairo, x, y); | ||||||
|  | 			cairo_show_text(cairo, text); | ||||||
|  | 			cairo_close_path(cairo); | ||||||
|  | 			cairo_new_sub_path(cairo); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// Typing indicator: Highlight random part on keypress
 | ||||||
|  | 		if (state->auth_state == AUTH_STATE_INPUT | ||||||
|  | 				|| state->auth_state == AUTH_STATE_BACKSPACE) { | ||||||
|  | 			static double highlight_start = 0; | ||||||
|  | 			highlight_start += | ||||||
|  | 				(rand() % (int)(M_PI * 100)) / 100.0 + M_PI * 0.5; | ||||||
|  | 			cairo_arc(cairo, surface->width / 2, surface->height / 2, | ||||||
|  | 					ARC_RADIUS, highlight_start, | ||||||
|  | 					highlight_start + TYPE_INDICATOR_RANGE); | ||||||
|  | 			if (state->auth_state == AUTH_STATE_INPUT) { | ||||||
|  | 				cairo_set_source_rgb(cairo, 51.0 / 255, 219.0 / 255, 0); | ||||||
|  | 			} else { | ||||||
|  | 				cairo_set_source_rgb(cairo, 219.0 / 255, 51.0 / 255, 0); | ||||||
|  | 			} | ||||||
|  | 			cairo_stroke(cairo); | ||||||
|  | 
 | ||||||
|  | 			// Draw borders
 | ||||||
|  | 			cairo_set_source_rgb(cairo, 0, 0, 0); | ||||||
|  | 			cairo_arc(cairo, surface->width / 2, surface->height / 2, | ||||||
|  | 					ARC_RADIUS, highlight_start, | ||||||
|  | 					highlight_start + TYPE_INDICATOR_BORDER_THICKNESS); | ||||||
|  | 			cairo_stroke(cairo); | ||||||
|  | 
 | ||||||
|  | 			cairo_arc(cairo, surface->width / 2, surface->height / 2, | ||||||
|  | 					ARC_RADIUS, highlight_start + TYPE_INDICATOR_RANGE, | ||||||
|  | 					highlight_start + TYPE_INDICATOR_RANGE + | ||||||
|  | 						TYPE_INDICATOR_BORDER_THICKNESS); | ||||||
|  | 			cairo_stroke(cairo); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// Draw inner + outer border of the circle
 | ||||||
|  | 		cairo_set_source_rgb(cairo, 0, 0, 0); | ||||||
|  | 		cairo_set_line_width(cairo, 2.0); | ||||||
|  | 		cairo_arc(cairo, surface->width / 2, surface->height / 2, | ||||||
|  | 				ARC_RADIUS - ARC_THICKNESS / 2, 0, 2 * M_PI); | ||||||
|  | 		cairo_stroke(cairo); | ||||||
|  | 		cairo_arc(cairo, surface->width / 2, surface->height / 2, | ||||||
|  | 				ARC_RADIUS + ARC_THICKNESS / 2, 0, 2 * M_PI); | ||||||
|  | 		cairo_stroke(cairo); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	wl_surface_attach(surface->surface, surface->current_buffer->buffer, 0, 0); | 	wl_surface_attach(surface->surface, surface->current_buffer->buffer, 0, 0); | ||||||
| 	wl_surface_damage(surface->surface, 0, 0, surface->width, surface->height); | 	wl_surface_damage(surface->surface, 0, 0, surface->width, surface->height); | ||||||
| 	wl_surface_commit(surface->surface); | 	wl_surface_commit(surface->surface); | ||||||
|  | 	wl_display_roundtrip(state->display); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void render_frames(struct swaylock_state *state) { | ||||||
|  | 	struct swaylock_surface *surface; | ||||||
|  | 	wl_list_for_each(surface, &state->surfaces, link) { | ||||||
|  | 		render_frame(surface); | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Drew DeVault
						Drew DeVault