~nickbp/gridmgr

f50998c880851c8f3e787865c98285930c3c1839 — Nicholas Parker 10 years ago 6475138
instead of all that margin math to get the window's exterior dimensions, lets just go by the parent dimensions
1 files changed, 67 insertions(+), 60 deletions(-)

M src/window.cpp
M src/window.cpp => src/window.cpp +67 -60
@@ 54,89 54,96 @@ namespace {
		}
	}

	void print_window(Display* disp, Window win) {
		if (!config::debug_enabled) { return; }
		Window root;
		int x, y;
		unsigned int width, height, border, depth;
		if (XGetGeometry(disp, win, &root, &x, &y, &width,
						&height, &border, &depth) == 0) {
			ERROR_DIR("get geometry failed");
			return;
		}
		DEBUG("  %dx %dy %uw %uh %ub", x, y, width, height, border);
	}

	bool get_window_size(Display* disp, Window win,
			ActiveWindow::Dimensions* out_exterior = NULL,
			unsigned int* out_margin_width = NULL,
			unsigned int* out_margin_height = NULL) {
		unsigned int margin_width, margin_height;
		Window root;
		unsigned int internal_width, internal_height;
		{
			size_t count = 0;
			unsigned int* widths;
			if (!(widths = (unsigned int*)x11_util::get_property(disp, win,
									XA_CARDINAL, "_NET_FRAME_EXTENTS", &count))) {
				//apparently fails with eg chrome, so just assume 0 and move on
				//(yet chrome oddly works fine with unmaximize_unshade_window())
				DEBUG_DIR("get frame extents failed, assuming extents = 0");
				margin_width = margin_height = 0;
			} else {
				if (count != 4) {
					ERROR("got size %lu, want %lu", count, 4);
					x11_util::free_property(widths);
					return false;
				}
				margin_width = widths[0] + widths[1];//left, right
				margin_height = widths[2] + widths[3];//top, bottom
				DEBUG("extents: width%u height%u",
						margin_width, margin_height);
				x11_util::free_property(widths);
			/* first, get the interior width/height from this window
			   (so that we can calculate margins) */
			int x, y;
			unsigned int border, depth;
			if (XGetGeometry(disp, win, &root, &x, &y, &internal_width,
							&internal_height, &border, &depth) == 0) {
				ERROR_DIR("get geometry failed");
				return false;
			}
		}

		//_NET_EXTENTS doesnt include window decoration (titlebar etc), get that here:
		if (win == root) {
			ERROR_DIR("this window is root! treating this as an error.");
			return false;
		}

		long exterior_x, exterior_y;
		unsigned int interior_width, interior_height;
		Window rootwin;
		/* now traverse up the parents until we reach the one JUST BEFORE root,
		   and get the external width/height and x/y from that. */
		Window just_before_root;
		{
			unsigned int color_depth, border;
			int margin_left_tmp, margin_top_tmp;
			if (XGetGeometry(disp, win, &rootwin, &margin_left_tmp, &margin_top_tmp,
							&interior_width, &interior_height,
							&border, &color_depth) == 0) {
				ERROR_DIR("get geometry failed");
				return false;
			}

			//also get window coords (given as internal, subtract XGetGeo to get external)
			int count = 1;
			Window parent = win;
			Window* children;
			unsigned int children_count;
			do {
				just_before_root = parent;
				if (XQueryTree(disp, just_before_root, &root,
								&parent, &children, &children_count) == 0) {
					ERROR_DIR("get query tree failed");
					return false;
				}
				if (children != NULL) {
					XFree(children);
				}
				DEBUG("%d window=%lu, parent=%lu, root=%lu",
						count, just_before_root, parent, root);
				print_window(disp, just_before_root);
			} while (++count < 50 && parent != root);
		}

			int interior_x, interior_y;
			if (XTranslateCoordinates(disp, win, rootwin, 0, 0,
							&interior_x, &interior_y, &rootwin) == 0) {
				ERROR_DIR("coordinate transform failed");
		int x, y;
		unsigned int external_width, external_height;
		{
			unsigned int border, depth;
			if (XGetGeometry(disp, just_before_root, &root, &x, &y, &external_width,
							&external_height, &border, &depth) == 0) {
				ERROR_DIR("get geometry failed");
				return false;
			}

			//only use XGetGeo margins when calculating exterior position:
			exterior_x = interior_x - margin_left_tmp - border;
			exterior_y = interior_y - margin_top_tmp - border;
			DEBUG("pos: interior %ldx %ldy - geomargins %dw %dh %ub = exterior %ldx %ldy",
					interior_x, interior_y,
					margin_left_tmp, margin_top_tmp, border,
					exterior_x, exterior_y);

			//but use BOTH XGetGeo AND _NET_EXTENTS in calculating overall margin:
			margin_width += margin_left_tmp + border + border;
			margin_height += margin_top_tmp + border + border;
		}

		if (out_exterior != NULL) {
			out_exterior->x = exterior_x;
			out_exterior->y = exterior_y;
			out_exterior->width = interior_width + margin_width;
			out_exterior->height = interior_height + margin_height;
			out_exterior->x = x;
			out_exterior->y = y;
			out_exterior->width = external_width;
			out_exterior->height = external_height;
		}

		if (out_margin_width != NULL) {
			*out_margin_width = margin_width;
			*out_margin_width = external_width - internal_width;
		}
		if (out_margin_height != NULL) {
			*out_margin_height = margin_height;
			*out_margin_height = external_height - internal_height;
		}

		DEBUG("size: interior %luw %luh + summargins %dw %dh = %uw %uh",
				interior_width, interior_height, margin_width, margin_height,
				interior_width + margin_width, interior_height + margin_height);

		DEBUG("size: exterior %uw %uh - interior %uw %uh = margins %dw %dh",
				external_width, external_height,
				internal_width, internal_height,
				external_width - internal_width,
				external_height - internal_height);
		return true;
	}