[weston,v2,21/21] clients/clickdot: Add option for using a more complex confine region

Submitted by Jonas Ådahl on May 13, 2015, 10:26 a.m.

Details

Message ID 1431512802-6194-22-git-send-email-jadahl@gmail.com
State Superseded
Delegated to: Daniel Stone
Headers show

Not browsing as part of any series.

Commit Message

Jonas Ådahl May 13, 2015, 10:26 a.m.
By passing --complex-confine-region clickdot will draw an area looking
like a strange H in half transparent gray. This region will act as the
confine region when pointer confinement is activated (by right clicking).

Signed-off-by: Jonas Ådahl <jadahl@gmail.com>
---
 clients/clickdot.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 131 insertions(+)

Patch hide | download patch | download mbox

diff --git a/clients/clickdot.c b/clients/clickdot.c
index f20581f..bf5169e 100644
--- a/clients/clickdot.c
+++ b/clients/clickdot.c
@@ -41,6 +41,11 @@ 
 
 #include "window.h"
 
+#define NUM_COMPLEX_REGION_RECTS 9
+
+static int32_t option_complex_confine_region;
+static int32_t option_help;
+
 struct clickdot {
 	struct display *display;
 	struct window *window;
@@ -65,6 +70,10 @@  struct clickdot {
 	struct task cursor_timeout_task;
 
 	bool pointer_confined;
+
+	bool complex_confine_region_enabled;
+	bool complex_confine_region_dirty;
+	struct rectangle complex_confine_region[NUM_COMPLEX_REGION_RECTS];
 };
 
 static void
@@ -143,6 +152,92 @@  draw_line(struct clickdot *clickdot, cairo_t *cr,
 }
 
 static void
+calculate_complex_confine_region(struct clickdot *clickdot)
+{
+	struct rectangle allocation;
+	struct rectangle *rs = clickdot->complex_confine_region;
+
+	if (!clickdot->complex_confine_region_dirty)
+		return;
+
+	widget_get_allocation(clickdot->widget, &allocation);
+
+	/*
+	 * The code below constructs a region made up of rectangles that
+	 * is then used to set up both an illustrative shaded region in the
+	 * widget and a confine region used when confining the pointer.
+	 */
+
+	rs[0].x = allocation.x + (int)round(allocation.width * 0.05);
+	rs[0].y = allocation.y + (int)round(allocation.height * 0.15);
+	rs[0].width = (int)round(allocation.width * 0.35);
+	rs[0].height = (int)round(allocation.height * 0.7);
+
+	rs[1].x = rs[0].x + rs[0].width;
+	rs[1].y = allocation.y + (int)round(allocation.height * 0.45);
+	rs[1].width = (int)round(allocation.width * 0.09);
+	rs[1].height = (int)round(allocation.height * 0.1);
+
+	rs[2].x = rs[1].x + rs[1].width;
+	rs[2].y = allocation.y + (int)round(allocation.height * 0.48);
+	rs[2].width = (int)round(allocation.width * 0.02);
+	rs[2].height = (int)round(allocation.height * 0.04);
+
+	rs[3].x = rs[2].x + rs[2].width;
+	rs[3].y = allocation.y + (int)round(allocation.height * 0.45);
+	rs[3].width = (int)round(allocation.width * 0.09);
+	rs[3].height = (int)round(allocation.height * 0.1);
+
+	rs[4].x = rs[3].x + rs[3].width;
+	rs[4].y = allocation.y + (int)round(allocation.height * 0.15);
+	rs[4].width = (int)round(allocation.width * 0.35);
+	rs[4].height = (int)round(allocation.height * 0.7);
+
+	rs[5].x = allocation.x + (int)round(allocation.width * 0.05);
+	rs[5].y = allocation.y + (int)round(allocation.height * 0.05);
+	rs[5].width = rs[0].width + rs[1].width + rs[2].width +
+		rs[3].width + rs[4].width;
+	rs[5].height = (int)round(allocation.height * 0.10);
+
+	rs[6].x = allocation.x + (int)round(allocation.width * 0.1);
+	rs[6].y = rs[4].y + rs[4].height + (int)round(allocation.height * 0.02);
+	rs[6].width = (int)round(allocation.width * 0.8);
+	rs[6].height = (int)round(allocation.height * 0.03);
+
+	rs[7].x = allocation.x + (int)round(allocation.width * 0.05);
+	rs[7].y = rs[6].y + rs[6].height;
+	rs[7].width = (int)round(allocation.width * 0.9);
+	rs[7].height = (int)round(allocation.height * 0.03);
+
+	rs[8].x = allocation.x + (int)round(allocation.width * 0.1);
+	rs[8].y = rs[7].y + rs[7].height;
+	rs[8].width = (int)round(allocation.width * 0.8);
+	rs[8].height = (int)round(allocation.height * 0.03);
+
+	clickdot->complex_confine_region_dirty = false;
+}
+
+static void
+draw_complex_confine_region_mask(struct clickdot *clickdot, cairo_t *cr)
+{
+	int i;
+
+	calculate_complex_confine_region(clickdot);
+
+	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+
+	for (i = 0; i < NUM_COMPLEX_REGION_RECTS; i++) {
+		cairo_rectangle(cr,
+				clickdot->complex_confine_region[i].x,
+				clickdot->complex_confine_region[i].y,
+				clickdot->complex_confine_region[i].width,
+				clickdot->complex_confine_region[i].height);
+		cairo_set_source_rgba(cr, 0.14, 0.14, 0.14, 0.9);
+		cairo_fill(cr);
+	}
+}
+
+static void
 redraw_handler(struct widget *widget, void *data)
 {
 	static const double r = 10.0;
@@ -165,6 +260,10 @@  redraw_handler(struct widget *widget, void *data)
 	cairo_set_source_rgba(cr, 0, 0, 0, 0.8);
 	cairo_fill(cr);
 
+	if (clickdot->complex_confine_region_enabled) {
+		draw_complex_confine_region_mask(clickdot, cr);
+	}
+
 	draw_line(clickdot, cr, &allocation);
 
 	cairo_translate(cr, clickdot->dot.x + 0.5, clickdot->dot.y + 0.5);
@@ -218,6 +317,13 @@  toggle_pointer_confine(struct clickdot *clickdot, struct input *input)
 {
 	if (clickdot->pointer_confined) {
 		window_unconfine_pointer(clickdot->window);
+	} else if (clickdot->complex_confine_region_enabled) {
+		calculate_complex_confine_region(clickdot);
+		window_confine_pointer_to_rectangles(
+				clickdot->window,
+				input,
+				clickdot->complex_confine_region,
+				NUM_COMPLEX_REGION_RECTS);
 	} else {
 		window_confine_pointer_to_widget(clickdot->window,
 						 clickdot->widget,
@@ -281,6 +387,7 @@  resize_handler(struct widget *widget,
 	struct clickdot *clickdot = data;
 
 	clickdot->reset = 1;
+	clickdot->complex_confine_region_dirty = true;
 }
 
 static void
@@ -372,12 +479,31 @@  clickdot_destroy(struct clickdot *clickdot)
 	free(clickdot);
 }
 
+static const struct weston_option clickdot_options[] = {
+	{ WESTON_OPTION_BOOLEAN, "complex-confine-region", 0, &option_complex_confine_region },
+	{ WESTON_OPTION_BOOLEAN, "help", 0, &option_help },
+};
+
+static void
+print_help(const char *argv0)
+{
+	printf("Usage: %s [--complex-confine-region]\n", argv0);
+}
+
 int
 main(int argc, char *argv[])
 {
 	struct display *display;
 	struct clickdot *clickdot;
 
+	if (parse_options(clickdot_options,
+			  ARRAY_LENGTH(clickdot_options),
+			  &argc, argv) > 1 ||
+	    option_help) {
+		print_help(argv[0]);
+		return 0;
+	}
+
 	display = display_create(&argc, argv);
 	if (display == NULL) {
 		fprintf(stderr, "failed to create display: %m\n");
@@ -386,6 +512,11 @@  main(int argc, char *argv[])
 
 	clickdot = clickdot_create(display);
 
+	if (option_complex_confine_region) {
+		clickdot->complex_confine_region_dirty = true;
+		clickdot->complex_confine_region_enabled = true;
+	}
+
 	display_run(display);
 
 	clickdot_destroy(clickdot);