From e4f6edddad6a9a9d948ea28e3c002e49241fa253 Mon Sep 17 00:00:00 2001
From: "B. Watson" <urchlay@slackware.uk>
Date: Thu, 1 Feb 2024 03:03:42 -0500
Subject: Use XParseGeometry(), simplify argument processing.

---
 xdeadzone.1   | 26 ++++++++++++++------------
 xdeadzone.c   | 46 ++++++++++++++++++++++------------------------
 xdeadzone.rst | 22 ++++++++++++----------
 3 files changed, 48 insertions(+), 46 deletions(-)

diff --git a/xdeadzone.1 b/xdeadzone.1
index 3bb3184..29929d0 100644
--- a/xdeadzone.1
+++ b/xdeadzone.1
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .in \\n[rst2man-indent\\n[rst2man-indent-level]]u
 ..
-.TH "XDEADZONE" 1 "2024-01-31" "0.1" "Urchlay's Misc Stuff"
+.TH "XDEADZONE" 1 "2024-02-01" "0.1" "Urchlay's Misc Stuff"
 .SH NAME
 xdeadzone \- keep the mouse pointer out of the dead zone, on mismatched multihead displays.
 .\" RST source for xdeadzone(1) man page. Convert with:
@@ -36,7 +36,7 @@ xdeadzone \- keep the mouse pointer out of the dead zone, on mismatched multihea
 .
 .SH SYNOPSIS
 .sp
-xdeadzone [\fB\-nw\fP | \fB\-ne\fP | \fB\-sw\fP | \fB\-se\fP | \fB\-abs\fP \fIx\-position\fP \fIy\-position\fP] \fIwidth\fP \fIheight\fP
+xdeadzone [\fB\-nw\fP | \fB\-ne\fP | \fB\-sw\fP | \fB\-se\fP | \fB\-abs\fP] \fIgeometry\fP
 .sp
 xdeadzone \fB\-\-help\fP | \fB\-\-version\fP
 .SH DESCRIPTION
@@ -85,15 +85,17 @@ Place window at southwest (bottom left) corner of display.
 .B \fB\-se\fP
 Place window at southeast (bottom right) corner of display.
 .TP
-.B \fB\-abs\fP \fIx\-position\fP \fIy\-position\fP
-Place window at the given coordinates. Negative numbers will be
-treated as offsets from the right/bottom of the display.
-.TP
-.B \fBwidth\fP
-Width of the dead zone. Required; must be a positive integer.
+.B \fB\-abs\fP
+Place window at the coordinates given by \fBgeometry\fP\&.
 .TP
-.B \fBheight\fP
-Height of the dead zone. Required; must be a positive integer.
+.B \fBgeometry\fP
+This is a standard X11 geometry specification. Its format is
+<\fIwidth\fP>x<\fIheight\fP> for all modes other than \fB\-\-abs\fP\&. For \fB\-\-abs\fP,
+it\(aqs <\fIwidth\fP>x<\fIheight\fP>[\fI+\-\fP]<\fIxpos\fP>[\fI+\-\fP]<\fIypos\fP>.
+Negative xpos and ypos will be
+treated as offsets from the right/bottom of the display.
+.sp
+Examples: \fB200x100\fP, \fB64x64\-0\-0\fP, \fB50x60+100+100\fP\&.
 .UNINDENT
 .SH ENVIRONMENT
 .INDENT 0.0
@@ -124,7 +126,7 @@ To avoid losing the pointer, you can run this:
 .sp
 .nf
 .ft C
-xdeadzone \-se 1280 56 &
+xdeadzone \-se 1280x56 &
 .ft P
 .fi
 .UNINDENT
@@ -141,7 +143,7 @@ losing the mouse there:
 .sp
 .nf
 .ft C
-xdeadzone \-ne 640 1024 &
+xdeadzone \-ne 640x1024 &
 .ft P
 .fi
 .UNINDENT
diff --git a/xdeadzone.c b/xdeadzone.c
index ab36f8c..6ec1e10 100644
--- a/xdeadzone.c
+++ b/xdeadzone.c
@@ -7,6 +7,7 @@
 
 #include <X11/Xlib.h>
 #include <X11/Xatom.h>
+#include <X11/Xutil.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -18,7 +19,7 @@
 #define NAME "XDeadZone"
 
 /* define this to print some debug info at runtime. */
-// #define DEBUG
+#define DEBUG
 
 #ifdef DEBUG
 #  define DBG(x) x
@@ -44,8 +45,8 @@ void usage(const int ret) {
 	banner();
 	printf(
 			"Usage:\n  %s "
-			"[-nw | -ne | -sw | -se | -abs xpos ypos] [width] [height]"
-			"\n",
+			"[-nw | -ne | -sw | -se | -abs] <geometry>\n\n"
+			"  <geometry> is WxH for all modes but -abs, or\n  WxH[+-]xpos[+-]ypos for -abs\n",
 			exe_name);
 	exit(ret);
 }
@@ -67,36 +68,33 @@ int main(int argc, char **argv) {
 	XWindowAttributes attr;
 	XSetWindowAttributes setattr;
 
-	int x = 0, y = 0, width = 0, height = 0;
+	int x = -1, y = -1, gflags;
+	unsigned int width, height;
 
 	set_exe_name(argv[0]);
 
-	if(argc < 2)
-		usage(1);
-
 	if(argc == 2) {
 	  	if(streq(argv[1], "--help")) {
 			usage(0);
 		} else if(streq(argv[1], "--version")) {
 			banner();
 			exit(0);
-		} else {
-			usage(1);
 		}
 	}
 
+	if(argc != 3)
+		errmsg("wrong number of arguments (try --help)");
+
+	gflags = XParseGeometry(argv[2], &x, &y, &width, &height);
+	if(!(gflags & (WidthValue | HeightValue)))
+		errmsg("bad geometry (can't parse width and height)");
+
 	if(streq(argv[1], "-abs")) {
-		if(argc != 6)
-			errmsg("wrong number of arguments for -abs");
-		x = atoi(argv[2]);
-		y = atoi(argv[3]);
-		width = atoi(argv[4]);
-		height = atoi(argv[5]);
+		if(!(gflags & (XValue | YValue)))
+			errmsg("bad geometry: -abs requires X and Y coords");
 	} else {
-		if(argc != 4)
-			errmsg("wrong number of arguments for non-abs mode");
-		width = atoi(argv[2]);
-		height = atoi(argv[3]);
+		if(gflags & (XValue | YValue))
+			errmsg("bad geometry: don't give X and Y coords with -nw/-ne/-sw/-se");
 		if(streq(argv[1], "-nw")) {
 			x = 0; y = 0;
 		} else if(streq(argv[1], "-ne")) {
@@ -106,19 +104,19 @@ int main(int argc, char **argv) {
 		} else if(streq(argv[1], "-se")) {
 			x = -width; y = -height;
 		} else {
-			errmsg("invalid first argument (not -abs/-nw/-ne/-sw/-se)");
+			errmsg("bad first argument (not -abs/-nw/-ne/-sw/-se)");
 		}
 	}
 
-	if(width <= 0 || height <= 0)
-		errmsg("width and height must be positive and non-zero");
+	if(width == 0 || height == 0)
+		errmsg("bad geometry: width and height must be non-zero");
 
 	if(!(d = XOpenDisplay(NULL)))
 		errmsg("can't open X display");
 
 	XGetWindowAttributes(d, DefaultRootWindow(d), &attr);
-	if(x < 0) x = attr.width  + x;
-	if(y < 0) y = attr.height + y;
+	if(gflags & XNegative) x = (attr.width  + x) - width;
+	if(gflags & YNegative) y = (attr.height + y) - height;
 
 	DBG(printf("X size %d x %d, x %d, y %d, width %d, height %d\n",
 				attr.width, attr.height, x, y, width, height));
diff --git a/xdeadzone.rst b/xdeadzone.rst
index 20e9c90..ea80766 100644
--- a/xdeadzone.rst
+++ b/xdeadzone.rst
@@ -20,7 +20,7 @@ keep the mouse pointer out of the dead zone, on mismatched multihead displays.
 SYNOPSIS
 ========
 
-xdeadzone [**-nw** | **-ne** | **-sw** | **-se** | **-abs** *x-position* *y-position*] *width* *height*
+xdeadzone [**-nw** | **-ne** | **-sw** | **-se** | **-abs**] *geometry*
 
 xdeadzone **--help** | **--version**
 
@@ -70,15 +70,17 @@ OPTIONS
 **-se**
   Place window at southeast (bottom right) corner of display.
 
-**-abs** *x-position* *y-position*
-  Place window at the given coordinates. Negative numbers will be
-  treated as offsets from the right/bottom of the display.
+**-abs**
+  Place window at the coordinates given by **geometry**.
 
-**width**
-  Width of the dead zone. Required; must be a positive integer.
+**geometry**
+  This is a standard X11 geometry specification. Its format is
+  <*width*>x<*height*> for all modes other than **--abs**. For **--abs**,
+  it's <*width*>x<*height*>[*+-*]<*xpos*>[*+-*]<*ypos*>.
+  Negative xpos and ypos will be
+  treated as offsets from the right/bottom of the display.
 
-**height**
-  Height of the dead zone. Required; must be a positive integer.
+  Examples: **200x100**, **64x64-0-0**, **50x60+100+100**.
 
 ENVIRONMENT
 ===========
@@ -108,7 +110,7 @@ obvious what happened to it.
 
 To avoid losing the pointer, you can run this::
 
-  xdeadzone -se 1280 56 &
+  xdeadzone -se 1280x56 &
 
 ...from your ~/.xinitrc (or whatever you use to run commands at X startup).
 
@@ -117,7 +119,7 @@ with the 1280x1024 one on top, you'll have a 640x1024 vertical strip
 of 'dead zone' beyond the right edge of the top monitor. To avoid
 losing the mouse there::
 
-  xdeadzone -ne 640 1024 &
+  xdeadzone -ne 640x1024 &
 
 If the dead zone were on the left of the top monitor, you'd use **-nw** instead
 of **-ne**.
-- 
cgit v1.2.3