Enable viewing all X11 cursor sizes
This commit is contained in:
		
							parent
							
								
									085f2d7eef
								
							
						
					
					
						commit
						c39ac1a9da
					
				
							
								
								
									
										68
									
								
								fastiv-io.c
									
									
									
									
									
								
							
							
						
						
									
										68
									
								
								fastiv-io.c
									
									
									
									
									
								
							| @ -955,39 +955,58 @@ open_xcursor(const gchar *data, gsize len, GError **error) | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	// Let's just arrange the pixel data in a recording surface.
 | ||||
| 	static cairo_user_data_key_t key = {}; | ||||
| 	cairo_surface_t *recording = | ||||
| 		cairo_recording_surface_create(CAIRO_CONTENT_COLOR_ALPHA, NULL); | ||||
| 	cairo_surface_set_user_data( | ||||
| 		recording, &key, images, (cairo_destroy_func_t) XcursorImagesDestroy); | ||||
| 	cairo_t *cr = cairo_create(recording); | ||||
| 	// Interpret cursors as animated pages.
 | ||||
| 	cairo_surface_t *pages = NULL, *frames_head = NULL, *frames_tail = NULL; | ||||
| 
 | ||||
| 	// Unpack horizontally by animation, vertically by size.
 | ||||
| 	// XXX: Assuming that all "nominal sizes" have the same dimensions.
 | ||||
| 	XcursorDim last_nominal = -1; | ||||
| 	int x = 0, y = 0, row_height = 0; | ||||
| 	for (int i = 0; i < images->nimage; i++) { | ||||
| 		XcursorImage *image = images->images[i]; | ||||
| 		if (image->size != last_nominal) { | ||||
| 			x = 0; | ||||
| 			y += row_height; | ||||
| 			row_height = 0; | ||||
| 			last_nominal = image->size; | ||||
| 		} | ||||
| 
 | ||||
| 		// The library automatically byte swaps in _XcursorReadImage().
 | ||||
| 		cairo_surface_t *source = cairo_image_surface_create_for_data( | ||||
| 		cairo_surface_t *surface = cairo_image_surface_create_for_data( | ||||
| 			(unsigned char *) image->pixels, CAIRO_FORMAT_ARGB32, | ||||
| 			image->width, image->height, image->width * sizeof *image->pixels); | ||||
| 		cairo_set_source_surface(cr, source, x, y); | ||||
| 		cairo_surface_destroy(source); | ||||
| 		cairo_paint(cr); | ||||
| 		cairo_surface_set_user_data(surface, &fastiv_io_key_frame_duration, | ||||
| 			(void *) (intptr_t) image->delay, NULL); | ||||
| 
 | ||||
| 		x += image->width; | ||||
| 		row_height = MAX(row_height, (int) image->height); | ||||
| 		if (pages && image->size == last_nominal) { | ||||
| 			cairo_surface_set_user_data(surface, | ||||
| 				&fastiv_io_key_frame_previous, frames_tail, NULL); | ||||
| 			cairo_surface_set_user_data(frames_tail, | ||||
| 				&fastiv_io_key_frame_next, surface, | ||||
| 				(cairo_destroy_func_t) cairo_surface_destroy); | ||||
| 		} else if (frames_head) { | ||||
| 			cairo_surface_set_user_data(frames_head, | ||||
| 				&fastiv_io_key_frame_previous, frames_tail, NULL); | ||||
| 
 | ||||
| 			cairo_surface_set_user_data(frames_head, | ||||
| 				&fastiv_io_key_page_next, surface, | ||||
| 				(cairo_destroy_func_t) cairo_surface_destroy); | ||||
| 			cairo_surface_set_user_data(surface, | ||||
| 				&fastiv_io_key_page_previous, frames_head, NULL); | ||||
| 			frames_head = surface; | ||||
| 		} else { | ||||
| 			pages = frames_head = surface; | ||||
| 		} | ||||
| 
 | ||||
| 		frames_tail = surface; | ||||
| 		last_nominal = image->size; | ||||
| 	} | ||||
| 	cairo_destroy(cr); | ||||
| 	return recording; | ||||
| 	if (!pages) { | ||||
| 		XcursorImagesDestroy(images); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	// Wrap around animations in the last page.
 | ||||
| 	cairo_surface_set_user_data( | ||||
| 		frames_head, &fastiv_io_key_frame_previous, frames_tail, NULL); | ||||
| 
 | ||||
| 	// There is no need to copy data, assign it to the surface.
 | ||||
| 	static cairo_user_data_key_t key = {}; | ||||
| 	cairo_surface_set_user_data( | ||||
| 		pages, &key, images, (cairo_destroy_func_t) XcursorImagesDestroy); | ||||
| 	return pages; | ||||
| } | ||||
| 
 | ||||
| #endif  // HAVE_XCURSOR --------------------------------------------------------
 | ||||
| @ -1041,6 +1060,9 @@ cairo_user_data_key_t fastiv_io_key_frame_previous; | ||||
| cairo_user_data_key_t fastiv_io_key_frame_duration; | ||||
| cairo_user_data_key_t fastiv_io_key_loops; | ||||
| 
 | ||||
| cairo_user_data_key_t fastiv_io_key_page_next; | ||||
| cairo_user_data_key_t fastiv_io_key_page_previous; | ||||
| 
 | ||||
| cairo_surface_t * | ||||
| fastiv_io_open(const gchar *path, GError **error) | ||||
| { | ||||
|  | ||||
| @ -46,6 +46,13 @@ extern cairo_user_data_key_t fastiv_io_key_frame_duration; | ||||
| /// How many times to repeat the animation, or zero for +inf, as a uintptr_t.
 | ||||
| extern cairo_user_data_key_t fastiv_io_key_loops; | ||||
| 
 | ||||
| /// The first frame of the next page, as a surface, in a chain.
 | ||||
| /// There is no wrap-around.
 | ||||
| extern cairo_user_data_key_t fastiv_io_key_page_next; | ||||
| /// The first frame of the previous page, as a surface, in a chain.
 | ||||
| /// There is no wrap-around. This is a weak pointer.
 | ||||
| extern cairo_user_data_key_t fastiv_io_key_page_previous; | ||||
| 
 | ||||
| cairo_surface_t *fastiv_io_open(const gchar *path, GError **error); | ||||
| cairo_surface_t *fastiv_io_open_from_data( | ||||
| 	const char *data, size_t len, const gchar *path, GError **error); | ||||
|  | ||||
| @ -31,8 +31,9 @@ | ||||
| 
 | ||||
| struct _FastivView { | ||||
| 	GtkWidget parent_instance; | ||||
| 	cairo_surface_t *surface;           ///< The loaded image (sequence)
 | ||||
| 	cairo_surface_t *frame;             ///< Current frame within, unreferenced
 | ||||
| 	cairo_surface_t *image;             ///< The loaded image (sequence)
 | ||||
| 	cairo_surface_t *page;              ///< Current page within image, weak
 | ||||
| 	cairo_surface_t *frame;             ///< Current frame within page, weak
 | ||||
| 	FastivIoOrientation orientation;    ///< Current orientation
 | ||||
| 	bool filter; | ||||
| 	bool scale_to_fit; | ||||
| @ -89,7 +90,7 @@ static void | ||||
| fastiv_view_finalize(GObject *gobject) | ||||
| { | ||||
| 	FastivView *self = FASTIV_VIEW(gobject); | ||||
| 	cairo_surface_destroy(self->surface); | ||||
| 	cairo_surface_destroy(self->image); | ||||
| 
 | ||||
| 	G_OBJECT_CLASS(fastiv_view_parent_class)->finalize(gobject); | ||||
| } | ||||
| @ -115,28 +116,28 @@ static void | ||||
| get_surface_dimensions(FastivView *self, double *width, double *height) | ||||
| { | ||||
| 	*width = *height = 0; | ||||
| 	if (!self->surface) | ||||
| 	if (!self->image) | ||||
| 		return; | ||||
| 
 | ||||
| 	cairo_rectangle_t extents = {}; | ||||
| 	switch (cairo_surface_get_type(self->surface)) { | ||||
| 	switch (cairo_surface_get_type(self->page)) { | ||||
| 	case CAIRO_SURFACE_TYPE_IMAGE: | ||||
| 		switch (self->orientation) { | ||||
| 		case FastivIoOrientation90: | ||||
| 		case FastivIoOrientationMirror90: | ||||
| 		case FastivIoOrientation270: | ||||
| 		case FastivIoOrientationMirror270: | ||||
| 			*width = cairo_image_surface_get_height(self->surface); | ||||
| 			*height = cairo_image_surface_get_width(self->surface); | ||||
| 			*width = cairo_image_surface_get_height(self->page); | ||||
| 			*height = cairo_image_surface_get_width(self->page); | ||||
| 			break; | ||||
| 		default: | ||||
| 			*width = cairo_image_surface_get_width(self->surface); | ||||
| 			*height = cairo_image_surface_get_height(self->surface); | ||||
| 			*width = cairo_image_surface_get_width(self->page); | ||||
| 			*height = cairo_image_surface_get_height(self->page); | ||||
| 		} | ||||
| 		return; | ||||
| 	case CAIRO_SURFACE_TYPE_RECORDING: | ||||
| 		if (!cairo_recording_surface_get_extents(self->surface, &extents)) { | ||||
| 			cairo_recording_surface_ink_extents(self->surface, | ||||
| 		if (!cairo_recording_surface_get_extents(self->page, &extents)) { | ||||
| 			cairo_recording_surface_ink_extents(self->page, | ||||
| 				&extents.x, &extents.y, &extents.width, &extents.height); | ||||
| 		} | ||||
| 
 | ||||
| @ -198,7 +199,7 @@ fastiv_view_size_allocate(GtkWidget *widget, GtkAllocation *allocation) | ||||
| 		->size_allocate(widget, allocation); | ||||
| 
 | ||||
| 	FastivView *self = FASTIV_VIEW(widget); | ||||
| 	if (!self->surface || !self->scale_to_fit) | ||||
| 	if (!self->image || !self->scale_to_fit) | ||||
| 		return; | ||||
| 
 | ||||
| 	double w, h; | ||||
| @ -271,7 +272,7 @@ fastiv_view_draw(GtkWidget *widget, cairo_t *cr) | ||||
| 		allocation.width, allocation.height); | ||||
| 
 | ||||
| 	FastivView *self = FASTIV_VIEW(widget); | ||||
| 	if (!self->surface || | ||||
| 	if (!self->image || | ||||
| 		!gtk_cairo_should_draw_window(cr, gtk_widget_get_window(widget))) | ||||
| 		return TRUE; | ||||
| 
 | ||||
| @ -408,7 +409,7 @@ static gboolean | ||||
| fastiv_view_scroll_event(GtkWidget *widget, GdkEventScroll *event) | ||||
| { | ||||
| 	FastivView *self = FASTIV_VIEW(widget); | ||||
| 	if (!self->surface) | ||||
| 	if (!self->image) | ||||
| 		return FALSE; | ||||
| 	if (event->state & gtk_accelerator_get_default_mod_mask()) | ||||
| 		return FALSE; | ||||
| @ -431,7 +432,7 @@ fastiv_view_key_press_event(GtkWidget *widget, GdkEventKey *event) | ||||
| 	FastivView *self = FASTIV_VIEW(widget); | ||||
| 	if (event->state & ~GDK_SHIFT_MASK & gtk_accelerator_get_default_mod_mask()) | ||||
| 		return FALSE; | ||||
| 	if (!self->surface) | ||||
| 	if (!self->image) | ||||
| 		return FALSE; | ||||
| 
 | ||||
| 	switch (event->keyval) { | ||||
| @ -462,16 +463,33 @@ fastiv_view_key_press_event(GtkWidget *widget, GdkEventKey *event) | ||||
| 		gtk_widget_queue_resize(widget); | ||||
| 		return TRUE; | ||||
| 
 | ||||
| 	case GDK_KEY_bracketleft: | ||||
| 	case GDK_KEY_bracketleft: { | ||||
| 		cairo_surface_t *page = cairo_surface_get_user_data( | ||||
| 			self->page, &fastiv_io_key_page_previous); | ||||
| 		if (page) | ||||
| 			self->frame = self->page = page; | ||||
| 		gtk_widget_queue_resize(widget); | ||||
| 		return TRUE; | ||||
| 	} | ||||
| 	case GDK_KEY_bracketright: { | ||||
| 		cairo_surface_t *page = cairo_surface_get_user_data( | ||||
| 			self->page, &fastiv_io_key_page_next); | ||||
| 		if (page) | ||||
| 			self->frame = self->page = page; | ||||
| 		gtk_widget_queue_resize(widget); | ||||
| 		return TRUE; | ||||
| 	} | ||||
| 
 | ||||
| 	case GDK_KEY_braceleft: | ||||
| 		if (!(self->frame = cairo_surface_get_user_data( | ||||
| 				self->frame, &fastiv_io_key_frame_previous))) | ||||
| 			self->frame = self->surface; | ||||
| 			self->frame = self->page; | ||||
| 		gtk_widget_queue_draw(widget); | ||||
| 		return TRUE; | ||||
| 	case GDK_KEY_bracketright: | ||||
| 	case GDK_KEY_braceright: | ||||
| 		if (!(self->frame = cairo_surface_get_user_data( | ||||
| 				self->frame, &fastiv_io_key_frame_next))) | ||||
| 			self->frame = self->surface; | ||||
| 			self->frame = self->page; | ||||
| 		gtk_widget_queue_draw(widget); | ||||
| 		return TRUE; | ||||
| 	} | ||||
| @ -527,14 +545,15 @@ fastiv_view_open(FastivView *self, const gchar *path, GError **error) | ||||
| 	cairo_surface_t *surface = fastiv_io_open(path, error); | ||||
| 	if (!surface) | ||||
| 		return FALSE; | ||||
| 	if (self->surface) | ||||
| 		cairo_surface_destroy(self->surface); | ||||
| 	if (self->image) | ||||
| 		cairo_surface_destroy(self->image); | ||||
| 
 | ||||
| 	self->frame = self->surface = surface; | ||||
| 	self->frame = self->page = self->image = surface; | ||||
| 	set_scale_to_fit(self, true); | ||||
| 
 | ||||
| 	// TODO(p): This is actually per-page.
 | ||||
| 	if ((self->orientation = (uintptr_t) cairo_surface_get_user_data( | ||||
| 			 self->surface, &fastiv_io_key_orientation)) == | ||||
| 			 self->image, &fastiv_io_key_orientation)) == | ||||
| 		FastivIoOrientationUnknown) | ||||
| 		self->orientation = FastivIoOrientation0; | ||||
| 	return TRUE; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user