mirror of
https://github.com/go-vgo/robotgo.git
synced 2025-05-29 21:43:55 +00:00
220 lines
5.3 KiB
C
220 lines
5.3 KiB
C
// 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 <LICENSE-APACHE or
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
// option. This file may not be copied, modified, or distributed
|
|
// except according to those terms.
|
|
|
|
#if defined(USE_X11)
|
|
#include <X11/Xresource.h>
|
|
#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
|
|
} |