// Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // https://github.com/go-vgo/robotgo/blob/master/LICENSE // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #if defined(USE_X11) #include #endif Bounds get_client(uintptr pid, int8_t isPid); intptr scaleX(); double sys_scale(int32_t display_id) { #if defined(IS_MACOSX) CGDirectDisplayID displayID = (CGDirectDisplayID) display_id; if (displayID == -1) { displayID = CGMainDisplayID(); } CGDisplayModeRef modeRef = CGDisplayCopyDisplayMode(displayID); double pixelWidth = CGDisplayModeGetPixelWidth(modeRef); double targetWidth = CGDisplayModeGetWidth(modeRef); return pixelWidth / targetWidth; #elif defined(USE_X11) Display *dpy = XOpenDisplay(NULL); int scr = 0; /* Screen number */ double xres = ((((double) DisplayWidth(dpy, scr)) * 25.4) / ((double) DisplayWidthMM(dpy, scr))); char *rms = XResourceManagerString(dpy); if (rms) { XrmDatabase db = XrmGetStringDatabase(rms); if (db) { XrmValue value; char *type = NULL; if (XrmGetResource(db, "Xft.dpi", "String", &type, &value)) { if (value.addr) { xres = atof(value.addr); } } XrmDestroyDatabase(db); } } XCloseDisplay (dpy); return xres / 96.0; #elif defined(IS_WINDOWS) double s = scaleX() / 96.0; return s; #endif } intptr scaleX(){ #if defined(IS_MACOSX) return 0; #elif defined(USE_X11) return 0; #elif defined(IS_WINDOWS) // Get desktop dc HDC desktopDc = GetDC(NULL); // Get native resolution intptr horizontalDPI = GetDeviceCaps(desktopDc, LOGPIXELSX); return horizontalDPI; #endif } Bounds get_bounds(uintptr pid, int8_t isPid){ // Check if the window is valid Bounds bounds; if (!is_valid()) { return bounds; } #if defined(IS_MACOSX) // Bounds bounds; AXValueRef axp = NULL; AXValueRef axs = NULL; AXUIElementRef AxID = AXUIElementCreateApplication(pid); // Determine the current point of the window if (AXUIElementCopyAttributeValue(AxID, kAXPositionAttribute, (CFTypeRef*) &axp) != kAXErrorSuccess || axp == NULL){ goto exit; } // Determine the current size of the window if (AXUIElementCopyAttributeValue(AxID, kAXSizeAttribute, (CFTypeRef*) &axs) != kAXErrorSuccess || axs == NULL){ goto exit; } CGPoint p; CGSize s; // Attempt to convert both values into atomic types if (AXValueGetValue(axp, kAXValueCGPointType, &p) && AXValueGetValue(axs, kAXValueCGSizeType, &s)){ bounds.X = p.x; bounds.Y = p.y; bounds.W = s.width; bounds.H = s.height; } // return bounds; exit: if (axp != NULL) { CFRelease(axp); } if (axs != NULL) { CFRelease(axs); } return bounds; #elif defined(USE_X11) // Ignore X errors XDismissErrors(); MData win; win.XWin = (Window)pid; Bounds client = get_client(pid, isPid); Bounds frame = GetFrame(win); bounds.X = client.X - frame.X; bounds.Y = client.Y - frame.Y; bounds.W = client.W + frame.W; bounds.H = client.H + frame.H; return bounds; #elif defined(IS_WINDOWS) HWND hwnd; if (isPid == 0) { hwnd= GetHwndByPid(pid); } else { hwnd = (HWND)pid; } RECT rect = { 0 }; GetWindowRect(hwnd, &rect); bounds.X = rect.left; bounds.Y = rect.top; bounds.W = rect.right - rect.left; bounds.H = rect.bottom - rect.top; return bounds; #endif } Bounds get_client(uintptr pid, int8_t isPid) { // Check if the window is valid Bounds bounds; if (!is_valid()) { return bounds; } #if defined(IS_MACOSX) return get_bounds(pid, isPid); #elif defined(USE_X11) Display *rDisplay = XOpenDisplay(NULL); // Ignore X errors XDismissErrors(); MData win; win.XWin = (Window)pid; // Property variables Window root, parent; Window* children; unsigned int count; int32_t x = 0, y = 0; // Check if the window is the root XQueryTree(rDisplay, win.XWin, &root, &parent, &children, &count); if (children) { XFree(children); } // Retrieve window attributes XWindowAttributes attr = { 0 }; XGetWindowAttributes(rDisplay, win.XWin, &attr); // Coordinates must be translated if (parent != attr.root) { XTranslateCoordinates(rDisplay, win.XWin, attr.root, attr.x, attr.y, &x, &y, &parent); } else { x = attr.x; y = attr.y; } // Return resulting window bounds bounds.X = x; bounds.Y = y; bounds.W = attr.width; bounds.H = attr.height; XCloseDisplay(rDisplay); return bounds; #elif defined(IS_WINDOWS) HWND hwnd; if (isPid == 0) { hwnd = GetHwndByPid(pid); } else { hwnd = (HWND)pid; } RECT rect = { 0 }; GetClientRect(hwnd, &rect); POINT point; point.x = rect.left; point.y = rect.top; // Convert the client point to screen ClientToScreen(hwnd, &point); bounds.X = point.x; bounds.Y = point.y; bounds.W = rect.right - rect.left; bounds.H = rect.bottom - rect.top; return bounds; #endif }