Skip to content

Commit ee143df

Browse files
authored
Bugfix/macos screengrab (#1)
* Ported fix from bolt to libnut * Updated ci workflows with npm auth * Increase timeout between window switches
1 parent 6bbe582 commit ee143df

File tree

5 files changed

+41
-62
lines changed

5 files changed

+41
-62
lines changed

.github/workflows/ci.yaml

+5-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ jobs:
1212
matrix:
1313
os: [ ubuntu-20.04, macos-11, windows-2019 ]
1414
node: [ 18 ]
15+
env:
16+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
1517
runs-on: ${{matrix.os}}
1618
steps:
1719
- name: Set up Git repository
@@ -20,6 +22,7 @@ jobs:
2022
uses: actions/[email protected]
2123
with:
2224
node-version: ${{matrix.node}}
25+
registry-url: https://registry.npmjs.org
2326
- name: Configure Linux environment
2427
if: ${{matrix.os == 'ubuntu-20.04'}}
2528
run: sudo apt-get install -y cmake libx11-dev zlib1g-dev libpng-dev libxtst-dev build-essential
@@ -28,12 +31,12 @@ jobs:
2831
- name: Build
2932
run: npm run build:release
3033
- name: Run tests
31-
uses: GabrielBB/xvfb-action@v1
34+
uses: coactions/setup-xvfb@v1
3235
with:
3336
working-directory: ./test/
3437
run: npm cit
3538
- name: Run window tests
36-
uses: GabrielBB/xvfb-action@v1
39+
uses: coactions/setup-xvfb@v1
3740
with:
3841
working-directory: ./test/window-integration-tests
3942
run: npm cit

.github/workflows/snapshot_release.yaml

+5-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ jobs:
1616
matrix:
1717
os: [ ubuntu-20.04, macos-11, windows-2019 ]
1818
node: [ 18 ]
19+
env:
20+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
1921
runs-on: ${{matrix.os}}
2022
steps:
2123
- name: Set up Git repository
@@ -24,6 +26,7 @@ jobs:
2426
uses: actions/[email protected]
2527
with:
2628
node-version: ${{matrix.node}}
29+
registry-url: https://registry.npmjs.org
2730
- name: Configure Linux environment
2831
if: ${{matrix.os == 'ubuntu-20.04'}}
2932
run: sudo apt-get install -y cmake libx11-dev zlib1g-dev libpng-dev libxtst-dev build-essential
@@ -32,12 +35,12 @@ jobs:
3235
- name: Build
3336
run: npm run build:release
3437
- name: Run tests
35-
uses: GabrielBB/xvfb-action@v1
38+
uses: coactions/setup-xvfb@v1
3639
with:
3740
working-directory: ./test/
3841
run: npm cit
3942
- name: Run window tests
40-
uses: GabrielBB/xvfb-action@v1
43+
uses: coactions/setup-xvfb@v1
4144
with:
4245
working-directory: ./test/window-integration-tests
4346
run: npm cit

.github/workflows/tagged_release.yaml

+5-2
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@ jobs:
1111
os: [ ubuntu-20.04, macos-11, windows-2019 ]
1212
node: [ 18 ]
1313
runs-on: ${{matrix.os}}
14+
env:
15+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
1416
steps:
1517
- name: Set up Git repository
1618
uses: actions/[email protected]
1719
- name: Set up node
1820
uses: actions/[email protected]
1921
with:
2022
node-version: ${{matrix.node}}
23+
registry-url: https://registry.npmjs.org
2124
- name: Configure Linux environment
2225
if: ${{matrix.os == 'ubuntu-20.04'}}
2326
run: sudo apt-get install -y cmake libx11-dev zlib1g-dev libpng-dev libxtst-dev build-essential
@@ -26,12 +29,12 @@ jobs:
2629
- name: Build
2730
run: npm run build:release
2831
- name: Run tests
29-
uses: GabrielBB/xvfb-action@v1
32+
uses: coactions/setup-xvfb@v1
3033
with:
3134
working-directory: ./test/
3235
run: npm cit
3336
- name: Run window tests
34-
uses: GabrielBB/xvfb-action@v1
37+
uses: coactions/setup-xvfb@v1
3538
with:
3639
working-directory: ./test/window-integration-tests
3740
run: npm cit

src/macos/screengrab.m

+25-56
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,11 @@
11
#include "../screengrab.h"
22
#include "../endian.h"
33
#include <stdlib.h> /* malloc() */
4+
#include <stdio.h> /* printf() */
45

56
#include <ApplicationServices/ApplicationServices.h>
67
#import <Cocoa/Cocoa.h>
78

8-
static double getPixelDensity() {
9-
@autoreleasepool
10-
{
11-
NSScreen * mainScreen = [NSScreen
12-
mainScreen];
13-
if (mainScreen) {
14-
return mainScreen.backingScaleFactor;
15-
} else {
16-
return 1.0;
17-
}
18-
}
19-
}
20-
219
MMBitmapRef copyMMBitmapFromDisplayInRect(MMRect rect) {
2210

2311
CGDirectDisplayID displayID = CGMainDisplayID();
@@ -33,56 +21,37 @@ MMBitmapRef copyMMBitmapFromDisplayInRect(MMRect rect) {
3321

3422
if (!image) { return NULL; }
3523

36-
CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(image));
24+
size_t width = CGImageGetWidth(image);
25+
size_t height = CGImageGetHeight(image);
26+
CGDataProviderRef provider = CGImageGetDataProvider(image);
27+
28+
CFDataRef imageData = CGDataProviderCopyData(provider);
3729

3830
if (!imageData) { return NULL; }
3931

4032
long bufferSize = CFDataGetLength(imageData);
41-
size_t bytesPerPixel = (size_t) (CGImageGetBitsPerPixel(image) / 8);
42-
double pixelDensity = getPixelDensity();
43-
long expectedBufferSize = rect.size.width * pixelDensity * rect.size.height * pixelDensity * bytesPerPixel;
44-
45-
if (expectedBufferSize < bufferSize) {
46-
size_t reportedByteWidth = CGImageGetBytesPerRow(image);
47-
size_t expectedByteWidth = expectedBufferSize / (rect.size.height * pixelDensity);
48-
49-
uint8_t *buffer = malloc(expectedBufferSize);
33+
size_t bitsPerPixel = CGImageGetBitsPerPixel(image);
34+
size_t bytesPerPixel = bitsPerPixel / 8;
35+
size_t bytesPerRow = CGImageGetBytesPerRow(image);
36+
size_t actualBytesPerRow = width * bytesPerPixel;
37+
const UInt8 *dataPointer = CFDataGetBytePtr(imageData);
5038

51-
const uint8_t *dataPointer = CFDataGetBytePtr(imageData);
52-
size_t parts = bufferSize / reportedByteWidth;
39+
uint8_t *imageDataWithoutPadding = malloc(height * actualBytesPerRow);
5340

54-
for (size_t idx = 0; idx < parts - 1; ++idx) {
55-
memcpy(buffer + (idx * expectedByteWidth),
56-
dataPointer + (idx * reportedByteWidth),
57-
expectedByteWidth
58-
);
59-
}
60-
61-
MMBitmapRef bitmap = createMMBitmap(buffer,
62-
rect.size.width * pixelDensity,
63-
rect.size.height * pixelDensity,
64-
expectedByteWidth,
65-
CGImageGetBitsPerPixel(image),
66-
CGImageGetBitsPerPixel(image) / 8);
67-
68-
CFRelease(imageData);
69-
CGImageRelease(image);
70-
71-
return bitmap;
72-
} else {
73-
uint8_t *buffer = malloc(bufferSize);
74-
CFDataGetBytes(imageData, CFRangeMake(0, bufferSize), buffer);
75-
MMBitmapRef bitmap = createMMBitmap(buffer,
76-
CGImageGetWidth(image),
77-
CGImageGetHeight(image),
78-
CGImageGetBytesPerRow(image),
79-
CGImageGetBitsPerPixel(image),
80-
CGImageGetBitsPerPixel(image) / 8);
41+
for (size_t y = 0; y < height; ++y) {
42+
const UInt8 *rowPtr = dataPointer + y * bytesPerRow;
43+
memcpy(imageDataWithoutPadding + y * actualBytesPerRow, rowPtr, actualBytesPerRow);
44+
}
8145

82-
CFRelease(imageData);
46+
MMBitmapRef bitmap = createMMBitmap(imageDataWithoutPadding,
47+
width,
48+
height,
49+
actualBytesPerRow,
50+
bitsPerPixel,
51+
bytesPerPixel);
8352

84-
CGImageRelease(image);
53+
CFRelease(imageData);
54+
CGImageRelease(image);
8555

86-
return bitmap;
87-
}
56+
return bitmap;
8857
}

test/window-integration-tests/test.js

+1
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ describe("focusWindow", () => {
111111
win.focus();
112112
});
113113

114+
await sleep(3000);
114115
const result = libnut.focusWindow(openWindowHandle);
115116

116117
// THEN

0 commit comments

Comments
 (0)