Skip to content

Retrieve window dimensions #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 59 commits into from
Aug 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
ba301b4
(#17) Started window_manager.h interface
Aug 3, 2020
b780ff0
(#17) window_manager MacOS implementation to retrieve list of window …
Aug 3, 2020
5b8b55e
(#17) Updated CmakeLists.txt to include MacOS window_manager implemen…
Aug 3, 2020
1e1108c
(#17) Export getWindows and getWindowRect functions
Aug 3, 2020
65a1997
(#17) Added window_manager source files for both Linux and Windows
Aug 3, 2020
36ba190
(#17) Changed window handles to int64_t, added getWindowTitle function
s1hofmann Aug 3, 2020
c96a86a
(#17) Updated windowhandle types, added implementation for getWindowT…
s1hofmann Aug 3, 2020
4e92f3c
(#17) Windows implementation, WIP
s1hofmann Aug 3, 2020
e9d4d7f
(#17) Exported getWindowTitle
s1hofmann Aug 3, 2020
72b1609
(#17) Added window_manager source file in Windows
s1hofmann Aug 3, 2020
2f1cf9b
(#17) Added plattform specific typedef for window handles
Aug 5, 2020
aa4cc6f
(#17) Refactored window manager macOS implementation
Aug 5, 2020
b273dbb
(#17) Switched to typedef for windowhandle
Aug 5, 2020
c76079f
(#17) Changed point and size types to use int64_t
s1hofmann Aug 5, 2020
d656baa
(#17) Updated Windows implementation
s1hofmann Aug 5, 2020
c5bbe90
(#17) WindowHandle now refers to int64_t on all platforms
s1hofmann Aug 5, 2020
d934da5
(#17) Added Linux implementation of window_manager
s1hofmann Aug 5, 2020
b193e7a
(#17) Linux implementation, WIP
s1hofmann Aug 5, 2020
2cc06ac
(#22) Working retrival of window name in Linux
s1hofmann Aug 6, 2020
7240b4c
:(#22) Working retrival of window name in Linux
s1hofmann Aug 6, 2020
dc910e1
(#17) Retrival of window rect, WIP
s1hofmann Aug 6, 2020
fef4c28
(#17) Updated getWindows implementation on Linux
s1hofmann Aug 6, 2020
760e05b
(#15) getActiveWindow implementation on Linux
s1hofmann Aug 6, 2020
c068dac
(#15) getActiveWindow on macOS, fixed wrong order of width and height…
Aug 6, 2020
d412c3d
(#15) getActiveWindow implementation on Windows
s1hofmann Aug 6, 2020
37321e4
(#17) Updated typings
s1hofmann Aug 6, 2020
d96afeb
Merge branch 'feature/17/retrieve_window_dimensions' of github.com:nu…
s1hofmann Aug 6, 2020
c790569
(#17) Added integration test
s1hofmann Aug 6, 2020
7a86432
(#17) Added window integration tests to CI pipelines
s1hofmann Aug 6, 2020
7243b0e
(#17) Updated test code for window tests
s1hofmann Aug 6, 2020
b0325a8
(#17) Removed test code inside electron app
s1hofmann Aug 6, 2020
ac51ca0
(#17) Switched to Spectron + Jest tests
s1hofmann Aug 6, 2020
c3dced4
(#17) Shortened test script by using added 145 packages in 1.069s
s1hofmann Aug 6, 2020
785e5b9
(#17) Updated test to focus our Electron window due to problems with …
s1hofmann Aug 6, 2020
4cd61f6
(#17) Trying to work around the batch windows problem
s1hofmann Aug 6, 2020
430d6cb
(#17) Made window toplevel by default
s1hofmann Aug 6, 2020
01bbe79
(#17) Focus still does not work with batch windows
s1hofmann Aug 6, 2020
f108dd6
(#17) Fixed call of focus on browserWindow
s1hofmann Aug 6, 2020
3bd63cc
(#17) Add call to minimize before calling focus to fix window focus, …
s1hofmann Aug 6, 2020
cf18af3
(#17) Additional timeouts for focus handling
s1hofmann Aug 6, 2020
1394e9d
(#17) Added call to restore() to fix issues on macOS
s1hofmann Aug 6, 2020
2ec2fbe
(#17) Moved focus workaround from beforeEach to beforeAll
s1hofmann Aug 6, 2020
674b7cb
(#17) Removed border offset for x and y coordinates of window rect on…
s1hofmann Aug 6, 2020
e7d78d3
(#17) Also remove border from width and height
s1hofmann Aug 6, 2020
439de7a
(#17) Switched to using already existing XGetMainDisplay and XCloseMa…
s1hofmann Aug 6, 2020
277a948
(#17) Added extern declaration to avoid symbol mangeling
s1hofmann Aug 6, 2020
162d7c4
(#17) Fix type conversion
s1hofmann Aug 6, 2020
e0fccf1
(#17) Added additional tests for window handling
Aug 7, 2020
1017ea8
(#17) Reverted minimized window test since minimized windows are not …
Aug 7, 2020
95d50c4
(#17) Added proper interfaces for return types
Aug 7, 2020
107fb79
(#17) Refactored window_manager code on Linux to properly use existin…
Aug 7, 2020
19c2f5a
Update src/macos/window_manager.mm
s1hofmann Aug 10, 2020
ce2345c
Update src/win32/window_manager.cc
s1hofmann Aug 10, 2020
6d62a7c
(#17) Added doc comment regarding the use of instead of
Aug 10, 2020
b81d49e
(#17) Added doc comments to window_manager interface
Aug 10, 2020
63b74a7
(#17) Handling of possible value for
Aug 10, 2020
204ffdf
(#17) Added doc comment regarding EnumWindowsProc
Aug 10, 2020
c650f00
(#17) Added checks for valid windows
Aug 11, 2020
0021b37
(#17) Fixed removed variable
Aug 11, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,10 @@ script:
- npm run patch && npm i
- if [[ $TRAVIS_OS_NAME = "windows" ]]; then npm run build:release:win; else npm run build:release; fi
- cd test
- npm ci
- npm test
- cd ..
- npm cit
- cd window-integration-tests
- npm cit
- cd ../..

before_deploy:
- echo "//registry.npmjs.org/:_authToken=\${NPM_TOKEN}" >> $HOME/.npmrc 2> /dev/null
Expand Down
6 changes: 3 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ project(libnut)
# Source
set(SOURCE_FILES "src/main.cc" "src/deadbeef_rand.c" "src/keycode.c" "src/keypress.c" "src/MMBitmap.c" "src/mouse.c" "src/screen.c" "src/screengrab.c")
if (UNIX AND NOT APPLE)
set(SOURCE_FILES "${SOURCE_FILES}" "src/linux/xdisplay.c" "src/linux/highlightwindow.c")
set(SOURCE_FILES "${SOURCE_FILES}" "src/linux/xdisplay.c" "src/linux/highlightwindow.c" "src/linux/window_manager.cc")
elseif (UNIX AND APPLE)
set(SOURCE_FILES "${SOURCE_FILES}" "src/macos/highlightwindow.m")
set(SOURCE_FILES "${SOURCE_FILES}" "src/macos/highlightwindow.m" "src/macos/window_manager.mm")
elseif (WIN32)
set(SOURCE_FILES "${SOURCE_FILES}" "src/win32/highlightwindow.c")
set(SOURCE_FILES "${SOURCE_FILES}" "src/win32/highlightwindow.c" "src/win32/window_manager.cc")
endif()
add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${CMAKE_JS_SRC})

Expand Down
9 changes: 5 additions & 4 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ test_script:
- npm --version
# run tests
- cd test
- npm ci
- npm test test
- npm test run test:it
- cd ..
- npm cit
- npm run test:it
- cd window-integration-tests
- npm cit
- cd ../..

on_success:
- IF defined APPVEYOR_REPO_TAG_NAME npm publish
Expand Down
25 changes: 23 additions & 2 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,23 @@ export interface Screen {
highlight(x: number, y: number, width: number, height: number, duration: number, opacity: number): void;
}

export interface Point {
x: number;
y: number
}

export interface Size {
width: number;
height: number;
}

export interface Rect {
x: number;
y: number;
width: number;
height: number;
}

export function setKeyboardDelay(ms: number): void;
export function keyTap(key: string, modifier?: string | string[]): void;
export function keyToggle(
Expand All @@ -28,7 +45,11 @@ export function mouseClick(button?: string, double?: boolean): void;
export function mouseToggle(down?: string, button?: string): void;
export function dragMouse(x: number, y: number): void;
export function scrollMouse(x: number, y: number): void;
export function getMousePos(): { x: number; y: number };
export function getScreenSize(): { width: number; height: number };
export function getMousePos(): Point;
export function getScreenSize(): Size;
export function getWindows(): number[];
export function getActiveWindow(): number;
export function getWindowRect(handle: number): Rect;
export function getWindowTitle(handle: number): string;

export const screen: Screen;
70 changes: 70 additions & 0 deletions src/linux/window_manager.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "../window_manager.h"
extern "C" {
#include "../xdisplay.h"
}

WindowHandle getActiveWindow() {
Display* xServer = XGetMainDisplay();
Window window;
if (xServer != NULL) {
int32_t revertToWindow;
XGetInputFocus(xServer, &window, &revertToWindow);
return window;
}
return -1;
}

std::vector<WindowHandle> getWindows() {
Display* xServer = XGetMainDisplay();
std::vector<WindowHandle> windowHandles;
if (xServer != NULL) {
Window defaultRootWindow = DefaultRootWindow(xServer);
Window rootWindow;
Window parentWindow;
Window* windowList;
uint32_t windowCount;

Status queryTreeResult = XQueryTree(xServer, defaultRootWindow, &rootWindow, &parentWindow, &windowList, &windowCount);
if (queryTreeResult > 0) {
for (size_t idx = 0; idx < windowCount; ++idx) {
windowHandles.push_back(windowList[idx]);
}
}
}
return windowHandles;
}

std::string getWindowTitle(const WindowHandle windowHandle) {
Display* xServer = XGetMainDisplay();
std::string windowName = "";
if (xServer != NULL && windowHandle >= 0) {
/*
* While there's also `XFetchName` to retrieve a window's `WM_NAME` property, in my tests `XFetchName` always failed and return 0
* `XGetWMName` on the other hand just worked as expected.
* Keep that in mind in case you're considering changing this implementation
*/
XTextProperty windowTextProperty;
Status getWMNameResult = XGetWMName(xServer, windowHandle, &windowTextProperty);
if (getWMNameResult > 0) {
windowName = std::string(reinterpret_cast<const char*>(windowTextProperty.value));
}
}
return windowName;
}

MMRect getWindowRect(const WindowHandle windowHandle) {
Display* xServer = XGetMainDisplay();
MMRect windowRect = MMRectMake(0, 0, 0, 0);
if (xServer != NULL && windowHandle >= 0) {
Window rootWindow;
int32_t x, y;
uint32_t width, height, border_width, border_height;
Status getXGeometryResult = XGetGeometry(xServer, windowHandle, &rootWindow, &x, &y, &width, &height, &border_width, &border_height);
if (getXGeometryResult > 0) {
windowRect = MMRectMake(x, y, width, height);
}
}
return windowRect;
}
94 changes: 94 additions & 0 deletions src/macos/window_manager.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#import <ApplicationServices/ApplicationServices.h>
#include "../window_manager.h"

NSDictionary* getWindowInfo(int64_t windowHandle) {
CGWindowListOption listOptions = kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements;
CFArrayRef windowList = CGWindowListCopyWindowInfo(listOptions, kCGNullWindowID);

for (NSDictionary *info in (NSArray *)windowList) {
NSNumber *windowNumber = info[(id)kCGWindowNumber];

if (windowHandle == [windowNumber intValue]) {
CFRetain(info);
CFRelease(windowList);
return info;
}
}

if (windowList) {
CFRelease(windowList);
}

return nullptr;
}

WindowHandle getActiveWindow() {
CGWindowListOption listOptions = kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements;
CFArrayRef windowList = CGWindowListCopyWindowInfo(listOptions, kCGNullWindowID);

for (NSDictionary *info in (NSArray *)windowList) {
NSNumber *ownerPid = info[(id)kCGWindowOwnerPID];
NSNumber *windowNumber = info[(id)kCGWindowNumber];

auto app = [NSRunningApplication runningApplicationWithProcessIdentifier: [ownerPid intValue]];

if (![app isActive]) {
continue;
}

CFRelease(windowList);
return [windowNumber intValue];
}

if (windowList) {
CFRelease(windowList);
}
return -1;
}

std::vector<WindowHandle> getWindows() {
CGWindowListOption listOptions = kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements;
CFArrayRef windowList = CGWindowListCopyWindowInfo(listOptions, kCGNullWindowID);

std::vector<WindowHandle> windowHandles;

for (NSDictionary *info in (NSArray *)windowList) {
NSNumber *ownerPid = info[(id)kCGWindowOwnerPID];
NSNumber *windowNumber = info[(id)kCGWindowNumber];

auto app = [NSRunningApplication runningApplicationWithProcessIdentifier: [ownerPid intValue]];
auto path = app ? [app.bundleURL.path UTF8String] : "";

if (app && path != "") {
windowHandles.push_back([windowNumber intValue]);
}
}

if (windowList) {
CFRelease(windowList);
}

return windowHandles;
}

MMRect getWindowRect(const WindowHandle windowHandle) {
auto windowInfo = getWindowInfo(windowHandle);
if (windowInfo != nullptr && windowHandle >= 0) {
CGRect windowRect;
if (CGRectMakeWithDictionaryRepresentation((CFDictionaryRef)windowInfo[(id)kCGWindowBounds], &windowRect)) {
return MMRectMake(windowRect.origin.x, windowRect.origin.y, windowRect.size.width, windowRect.size.height);
}
}
return MMRectMake(0, 0, 0, 0);
}

std::string getWindowTitle(const WindowHandle windowHandle) {
auto windowInfo = getWindowInfo(windowHandle);
if (windowInfo != nullptr && windowHandle >= 0) {
NSString *windowName = windowInfo[(id)kCGWindowName];
return [windowName UTF8String];
}
return "";
}
47 changes: 47 additions & 0 deletions src/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "mouse.h"
#include "screen.h"
#include "screengrab.h"
#include "window_manager.h"

int mouseDelay = 10;
int keyboardDelay = 10;
Expand Down Expand Up @@ -668,6 +669,48 @@ Napi::Number _highlight(const Napi::CallbackInfo &info)
return Napi::Number::New(env, 1);
}

Napi::Number _getActiveWindow(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();

WindowHandle windowHandle = getActiveWindow();
return Napi::Number::New(env, windowHandle);
}

Napi::Array _getWindows(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();

std::vector<WindowHandle> windowHandles = getWindows();
auto arr = Napi::Array::New(env, windowHandles.size());

for (size_t idx = 0; idx < windowHandles.size(); ++idx) {
arr[idx] = windowHandles[idx];
}

return arr;
}

Napi::Object _getWindowRect(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();

WindowHandle windowHandle = info[0].As<Napi::Number>().Int64Value();
MMRect windowRect = getWindowRect(windowHandle);

Napi::Object obj = Napi::Object::New(env);
obj.Set(Napi::String::New(env, "x"), Napi::Number::New(env, windowRect.origin.x));
obj.Set(Napi::String::New(env, "y"), Napi::Number::New(env, windowRect.origin.y));
obj.Set(Napi::String::New(env, "width"), Napi::Number::New(env, windowRect.size.width));
obj.Set(Napi::String::New(env, "height"), Napi::Number::New(env, windowRect.size.height));

return obj;
}

Napi::String _getWindowTitle(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();

WindowHandle windowHandle = info[0].As<Napi::Number>().Int64Value();
return Napi::String::New(env, getWindowTitle(windowHandle));
}

Napi::Object _captureScreen(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
Expand Down Expand Up @@ -749,6 +792,10 @@ Napi::Object Init(Napi::Env env, Napi::Object exports) {

exports.Set(Napi::String::New(env, "getScreenSize"), Napi::Function::New(env, _getScreenSize));
exports.Set(Napi::String::New(env, "highlight"), Napi::Function::New(env, _highlight));
exports.Set(Napi::String::New(env, "getWindows"), Napi::Function::New(env, _getWindows));
exports.Set(Napi::String::New(env, "getActiveWindow"), Napi::Function::New(env, _getActiveWindow));
exports.Set(Napi::String::New(env, "getWindowRect"), Napi::Function::New(env, _getWindowRect));
exports.Set(Napi::String::New(env, "getWindowTitle"), Napi::Function::New(env, _getWindowTitle));
exports.Set(Napi::String::New(env, "captureScreen"), Napi::Function::New(env, _captureScreen));
exports.Set(Napi::String::New(env, "getXDisplayName"), Napi::Function::New(env, _getXDisplayName));
exports.Set(Napi::String::New(env, "setXDisplayName"), Napi::Function::New(env, _setXDisplayName));
Expand Down
17 changes: 10 additions & 7 deletions src/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,20 @@
#include "os.h"
#include "inline_keywords.h" /* For H_INLINE */
#include <stddef.h>
#include <stdint.h>

/* Some generic, cross-platform types. */

struct _MMPoint {
size_t x;
size_t y;
int64_t x;
int64_t y;
};

typedef struct _MMPoint MMPoint;

struct _MMSize {
size_t width;
size_t height;
int64_t width;
int64_t height;
};

typedef struct _MMSize MMSize;
Expand All @@ -29,23 +30,23 @@ struct _MMRect {

typedef struct _MMRect MMRect;

H_INLINE MMPoint MMPointMake(size_t x, size_t y)
H_INLINE MMPoint MMPointMake(int64_t x, int64_t y)
{
MMPoint point;
point.x = x;
point.y = y;
return point;
}

H_INLINE MMSize MMSizeMake(size_t width, size_t height)
H_INLINE MMSize MMSizeMake(int64_t width, int64_t height)
{
MMSize size;
size.width = width;
size.height = height;
return size;
}

H_INLINE MMRect MMRectMake(size_t x, size_t y, size_t width, size_t height)
H_INLINE MMRect MMRectMake(int64_t x, int64_t y, int64_t width, int64_t height)
{
MMRect rect;
rect.origin = MMPointMake(x, y);
Expand All @@ -66,4 +67,6 @@ H_INLINE MMRect MMRectMake(size_t x, size_t y, size_t width, size_t height)

#endif

typedef int64_t WindowHandle;

#endif /* TYPES_H */
Loading