2Copyright 2018-2021 Intel Corporation
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
19var GXxor = 0x6; // src XOR dst
21var ExposureMask = (1 << 15);
23function windows_monitorborder()
25 this._ObjectID = 'monitor-info';
26 var info = require('monitor-info');
27 var gm = require('_GenericMarshal');
28 var user32 = gm.CreateNativeProxy('user32.dll');
31 user32.CreateMethod('GetDC');
32 user32.CreateMethod('ReleaseDC');
33 user32.CreateMethod('FillRect');
34 user32.CreateMethod('InvalidateRect');
36 var gdi32 = gm.CreateNativeProxy('gdi32.dll');
37 gdi32.CreateMethod('CreateSolidBrush');
39 var redBrush = gdi32.CreateSolidBrush(red);
40 var yellowBrush = gdi32.CreateSolidBrush(yellow);
42 require('events').EventEmitter.call(this);
43 this.on('~', function () { this.Stop(); });
45 this.Stop = function Stop()
47 info.redInterval = null;
49 var drawRect = gm.CreateVariable(16);
50 var drawRectBuffer = drawRect.toBuffer();
52 for (var i in info.monitors)
55 drawRectBuffer.writeInt32LE(info.monitors[i].left, 0);
56 drawRectBuffer.writeInt32LE(info.monitors[i].top, 4);
57 drawRectBuffer.writeInt32LE(info.monitors[i].left + (info.monitors[i].right - info.monitors[i].left), 8);
58 drawRectBuffer.writeInt32LE(info.monitors[i].bottom - info.monitors[i].top, 12);
59 user32.InvalidateRect(0, drawRect, 0);
63 this.Start = function Start()
65 info.getInfo().then(function (mon)
67 var drawRect = gm.CreateVariable(16);
70 info.dc = user32.GetDC(0);
73 info.redInterval = setInterval(function ()
75 info.state = (info.state + 1) % 8;
77 var drawRectBuffer = drawRect.toBuffer();
78 for(var i in info.monitors)
80 drawRectBuffer.writeInt32LE(info.monitors[i].left, 0);
81 drawRectBuffer.writeInt32LE(info.monitors[i].top, 4);
82 drawRectBuffer.writeInt32LE(info.monitors[i].left + (info.monitors[i].right - info.monitors[i].left)/2, 8);
83 drawRectBuffer.writeInt32LE(5, 12);
84 user32.FillRect(info.dc, drawRect, (info.state == 0 || info.state == 4) ? yellowBrush : redBrush);
85 drawRectBuffer.writeInt32LE(info.monitors[i].left + (info.monitors[i].right - info.monitors[i].left) / 2, 0);
86 drawRectBuffer.writeInt32LE(info.monitors[i].top, 4);
87 drawRectBuffer.writeInt32LE(info.monitors[i].right, 8);
88 drawRectBuffer.writeInt32LE(5, 12);
89 user32.FillRect(info.dc, drawRect, (info.state == 1 || info.state == 5) ? yellowBrush : redBrush);
92 drawRectBuffer.writeInt32LE(info.monitors[i].right - 5, 0);
93 drawRectBuffer.writeInt32LE(info.monitors[i].top, 4);
94 drawRectBuffer.writeInt32LE(info.monitors[i].right, 8);
95 drawRectBuffer.writeInt32LE(info.monitors[i].top + (info.monitors[i].bottom - info.monitors[i].top)/2, 12);
96 user32.FillRect(info.dc, drawRect, (info.state == 2 || info.state == 6) ? yellowBrush : redBrush);
97 drawRectBuffer.writeInt32LE(info.monitors[i].right - 5, 0);
98 drawRectBuffer.writeInt32LE(info.monitors[i].top + (info.monitors[i].bottom - info.monitors[i].top) / 2, 4);
99 drawRectBuffer.writeInt32LE(info.monitors[i].right, 8);
100 drawRectBuffer.writeInt32LE(info.monitors[i].bottom, 12);
101 user32.FillRect(info.dc, drawRect, (info.state == 3 || info.state == 7) ? yellowBrush : redBrush);
104 drawRectBuffer.writeInt32LE(info.monitors[i].left + (info.monitors[i].right - info.monitors[i].left) / 2, 0);
105 drawRectBuffer.writeInt32LE(info.monitors[i].bottom - 5, 4);
106 drawRectBuffer.writeInt32LE(info.monitors[i].right, 8);
107 drawRectBuffer.writeInt32LE(info.monitors[i].bottom, 12);
108 user32.FillRect(info.dc, drawRect, (info.state == 4 || info.state == 0) ? yellowBrush : redBrush);
109 drawRectBuffer.writeInt32LE(info.monitors[i].left, 0);
110 drawRectBuffer.writeInt32LE(info.monitors[i].bottom - 5, 4);
111 drawRectBuffer.writeInt32LE(info.monitors[i].left + (info.monitors[i].right - info.monitors[i].left) / 2, 8);
112 drawRectBuffer.writeInt32LE(info.monitors[i].bottom, 12);
113 user32.FillRect(info.dc, drawRect, (info.state == 5 || info.state == 1) ? yellowBrush : redBrush);
116 drawRectBuffer.writeInt32LE(info.monitors[i].left, 0);
117 drawRectBuffer.writeInt32LE(info.monitors[i].top + (info.monitors[i].bottom - info.monitors[i].top) / 2, 4);
118 drawRectBuffer.writeInt32LE(info.monitors[i].left + 5, 8);
119 drawRectBuffer.writeInt32LE(info.monitors[i].bottom, 12);
120 user32.FillRect(info.dc, drawRect, (info.state == 6 || info.state == 2) ? yellowBrush : redBrush);
121 drawRectBuffer.writeInt32LE(info.monitors[i].left, 0);
122 drawRectBuffer.writeInt32LE(info.monitors[i].top, 4);
123 drawRectBuffer.writeInt32LE(info.monitors[i].left + 5, 8);
124 drawRectBuffer.writeInt32LE(info.monitors[i].top + (info.monitors[i].bottom - info.monitors[i].top) / 2, 12);
125 user32.FillRect(info.dc, drawRect, (info.state == 7 || info.state == 3) ? yellowBrush : redBrush);
132function linux_monitorborder()
136 this._ObjectID = 'monitor-info';
137 this._info = require('monitor-info');
138 this._isUnity = this._info.isUnity();
140 console.log('isUnity = ' + this._isUnity);
142 require('events').EventEmitter.call(this);
143 this.on('~', function () { this.Stop(); });
145 this.Stop = function Stop()
147 this._timeout = null;
150 for(var i=0; i < this.displays.length; ++i)
152 if(this.displays[i].GC1 && this.displays[i].rootWindow)
154 self._info._X11.XSetFunction(self.displays[i].display, self.displays[i].GC1, GXclear);
155 self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].rootWindow, self.displays[i].GC1, 0, 0, self.displays[i].right, 0);
156 self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].rootWindow, self.displays[i].GC1, self.displays[i].right, 0, self.displays[i].right, self.displays[i].bottom);
157 self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].rootWindow, self.displays[i].GC1, 0, self.displays[i].bottom, self.displays[i].right, self.displays[i].bottom);
158 self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].rootWindow, self.displays[i].GC1, 0, 0, 0, self.displays[i].bottom);
160 this._info._X11.XFlush(this.displays[i].display);
165 this.Start = function Start()
167 this._info.getInfo().then(function (mon)
170 console.log(mon.length + ' displays');
171 for(var i = 0; i<mon.length; ++i)
173 console.log('Width: ' + mon[i].right + ', Height: ' + mon[i].bottom);
174 mon[i].rootWindow = self._info._X11.XRootWindow(mon[i].display, mon[i].screenId);
178 // We are unity, so we have to fake the borders with borderless windows
179 var white = self._info._X11.XWhitePixel(mon[i].display, mon[i].screenId).Val;
182 mon[i].window_top = self._info._X11.XCreateSimpleWindow(mon[i].display, mon[i].rootWindow, 0, 0, mon[i].right, 5, 0, white, white);
183 mon[i].window_top.gc = self._info._X11.XCreateGC(mon[i].display, mon[i].window_top, 0, 0);
184 self._info._X11.XSetLineAttributes(mon[i].display, mon[i].window_top.gc, 10, 0, 1, 1);
185 self._info._X11.XSetSubwindowMode(mon[i].display, mon[i].window_top.gc, 1);
186 self._info.unDecorateWindow(mon[i].display, mon[i].window_top);
187 self._info.setWindowSizeHints(mon[i].display, mon[i].window_top, 0, 0, mon[i].right, 5);
190 mon[i].window_right = self._info._X11.XCreateSimpleWindow(mon[i].display, mon[i].rootWindow, mon[i].right - 5, 0, 5, mon[i].bottom, 0, white, white);
191 mon[i].window_right.gc = self._info._X11.XCreateGC(mon[i].display, mon[i].window_right, 0, 0);
192 self._info._X11.XSetLineAttributes(mon[i].display, mon[i].window_right.gc, 10, 0, 1, 1);
193 self._info._X11.XSetSubwindowMode(mon[i].display, mon[i].window_right.gc, 1);
194 self._info.unDecorateWindow(mon[i].display, mon[i].window_right);
195 self._info.setWindowSizeHints(mon[i].display, mon[i].window_right, mon[i].right - 5, 0, 5, mon[i].bottom);
198 mon[i].window_left = self._info._X11.XCreateSimpleWindow(mon[i].display, mon[i].rootWindow, 0, 0, 5, mon[i].bottom, 0, white, white);
199 mon[i].window_left.gc = self._info._X11.XCreateGC(mon[i].display, mon[i].window_left, 0, 0);
200 self._info._X11.XSetLineAttributes(mon[i].display, mon[i].window_left.gc, 10, 0, 1, 1);
201 self._info._X11.XSetSubwindowMode(mon[i].display, mon[i].window_left.gc, 1);
202 self._info.unDecorateWindow(mon[i].display, mon[i].window_left);
203 self._info.setWindowSizeHints(mon[i].display, mon[i].window_left, 0, 0, 5, mon[i].bottom);
206 mon[i].window_bottom = self._info._X11.XCreateSimpleWindow(mon[i].display, mon[i].rootWindow, 0, mon[i].bottom - 5, mon[i].right, 5, 0, white, white);
207 mon[i].window_bottom.gc = self._info._X11.XCreateGC(mon[i].display, mon[i].window_bottom, 0, 0);
208 self._info._X11.XSetLineAttributes(mon[i].display, mon[i].window_bottom.gc, 10, 0, 1, 1);
209 self._info._X11.XSetSubwindowMode(mon[i].display, mon[i].window_bottom.gc, 1);
210 self._info.unDecorateWindow(mon[i].display, mon[i].window_bottom);
211 self._info.setWindowSizeHints(mon[i].display, mon[i].window_bottom, 0, mon[i].bottom - 5, mon[i].right, 5);
213 self._info._X11.XMapWindow(mon[i].display, mon[i].window_top);
214 self._info._X11.XMapWindow(mon[i].display, mon[i].window_right);
215 self._info._X11.XMapWindow(mon[i].display, mon[i].window_left);
216 self._info._X11.XMapWindow(mon[i].display, mon[i].window_bottom);
218 self._info.setAlwaysOnTop(mon[i].display, mon[i].rootWindow, mon[i].window_top);
219 self._info.hideWindowIcon(mon[i].display, mon[i].rootWindow, mon[i].window_top);
220 self._info.setAlwaysOnTop(mon[i].display, mon[i].rootWindow, mon[i].window_right);
221 self._info.hideWindowIcon(mon[i].display, mon[i].rootWindow, mon[i].window_right);
222 self._info.setAlwaysOnTop(mon[i].display, mon[i].rootWindow, mon[i].window_left);
223 self._info.hideWindowIcon(mon[i].display, mon[i].rootWindow, mon[i].window_left);
224 self._info.setAlwaysOnTop(mon[i].display, mon[i].rootWindow, mon[i].window_bottom);
225 self._info.hideWindowIcon(mon[i].display, mon[i].rootWindow, mon[i].window_bottom);
227 self._info._X11.XFlush(mon[i].display);
228 mon[i].borderState = 0;
232 // If we aren't unity, then we can just draw
233 mon[i].GC1 = self._info._X11.XCreateGC(mon[i].display, mon[i].rootWindow, 0, 0);
234 mon[i].borderState = 0;
236 self._info._X11.XSetForeground(mon[i].display, mon[i].GC1, self._info._X11.XWhitePixel(mon[i].display, mon[i].screenId).Val); // White
237 self._info._X11.XSetLineAttributes(mon[i].display, mon[i].GC1, 10, 0, 1, 1);
238 self._info._X11.XSetSubwindowMode(mon[i].display, mon[i].GC1, 1);
241 self._info._XEvent = self._info._gm.CreateVariable(192);
242 self._timeout = setTimeout(self._isUnity ? self.unity_drawBorder : self.timeoutHandler, 250);
246 this.timeoutHandler = function()
248 for (var i = 0; i < self.displays.length; ++i) {
249 self.displays[i].borderState = (self.displays[i].borderState + 1) % 8;
252 self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].GC1, (self.displays[i].borderState == 0 || self.displays[i].borderState == 4) ? 0xffff00 : 0xff0000);
253 self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].rootWindow, self.displays[i].GC1, 0, 0, self.displays[i].right / 2, 0);
254 self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].GC1, (self.displays[i].borderState == 1 || self.displays[i].borderState == 5) ? 0xffff00 : 0xff0000);
255 self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].rootWindow, self.displays[i].GC1, self.displays[i].right / 2, 0, self.displays[i].right, 0);
258 self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].GC1, (self.displays[i].borderState == 2 || self.displays[i].borderState == 6) ? 0xffff00 : 0xff0000);
259 self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].rootWindow, self.displays[i].GC1, self.displays[i].right, 0, self.displays[i].right, self.displays[i].bottom / 2);
260 self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].GC1, (self.displays[i].borderState == 3 || self.displays[i].borderState == 7) ? 0xffff00 : 0xff0000);
261 self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].rootWindow, self.displays[i].GC1, self.displays[i].right, self.displays[i].bottom / 2, self.displays[i].right, self.displays[i].bottom);
264 self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].GC1, (self.displays[i].borderState == 5 || self.displays[i].borderState == 1) ? 0xffff00 : 0xff0000);
265 self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].rootWindow, self.displays[i].GC1, 0, self.displays[i].bottom, self.displays[i].right / 2, self.displays[i].bottom);
266 self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].GC1, (self.displays[i].borderState == 4 || self.displays[i].borderState == 0) ? 0xffff00 : 0xff0000);
267 self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].rootWindow, self.displays[i].GC1, self.displays[i].right / 2, self.displays[i].bottom, self.displays[i].right, self.displays[i].bottom);
270 self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].GC1, (self.displays[i].borderState == 7 || self.displays[i].borderState == 3) ? 0xffff00 : 0xff0000);
271 self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].rootWindow, self.displays[i].GC1, 0, 0, 0, self.displays[i].bottom / 2);
272 self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].GC1, (self.displays[i].borderState == 6 || self.displays[i].borderState == 2) ? 0xffff00 : 0xff0000);
273 self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].rootWindow, self.displays[i].GC1, 0, self.displays[i].bottom / 2, 0, self.displays[i].bottom);
276 self._info._X11.XFlush(self.displays[i].display);
278 self._timeout = setTimeout(self._isUnity ? self.unity_drawBorder : self.timeoutHandler, 400);
280 this.unity_drawBorder = function unity_drawBorder()
282 for (var i = 0; i < self.displays.length; ++i)
284 self.displays[i].borderState = (self.displays[i].borderState + 1) % 8;
287 self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].window_top.gc, (self.displays[i].borderState == 0 || self.displays[i].borderState == 4) ? 0xffff00 : 0xff0000);
288 self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].window_top, self.displays[i].window_top.gc, 0, 0, self.displays[i].right / 2, 0);
289 self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].window_top.gc, (self.displays[i].borderState == 1 || self.displays[i].borderState == 5) ? 0xffff00 : 0xff0000);
290 self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].window_top, self.displays[i].window_top.gc, self.displays[i].right / 2, 0, self.displays[i].right, 0);
291 self._info._X11.XFlush(self.displays[i].display);
294 self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].window_right.gc, (self.displays[i].borderState == 2 || self.displays[i].borderState == 6) ? 0xffff00 : 0xff0000);
295 self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].window_right, self.displays[i].window_right.gc, 0, 0, 0, self.displays[i].bottom / 2);
296 self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].window_right.gc, (self.displays[i].borderState == 3 || self.displays[i].borderState == 7) ? 0xffff00 : 0xff0000);
297 self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].window_right, self.displays[i].window_right.gc, 0, self.displays[i].bottom / 2, 0, self.displays[i].bottom);
298 self._info._X11.XFlush(self.displays[i].display);
301 self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].window_bottom.gc, (self.displays[i].borderState == 5 || self.displays[i].borderState == 1) ? 0xffff00 : 0xff0000);
302 self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].window_bottom, self.displays[i].window_bottom.gc, 0, 0, self.displays[i].right / 2, 0);
303 self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].window_bottom.gc, (self.displays[i].borderState == 4 || self.displays[i].borderState == 0) ? 0xffff00 : 0xff0000);
304 self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].window_bottom, self.displays[i].window_bottom.gc, self.displays[i].right / 2, 0, self.displays[i].right, 0);
305 self._info._X11.XFlush(self.displays[i].display);
308 self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].window_left.gc, (self.displays[i].borderState == 7 || self.displays[i].borderState == 3) ? 0xffff00 : 0xff0000);
309 self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].window_left, self.displays[i].window_left.gc, 0, 0, 0, self.displays[i].bottom / 2);
310 self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].window_left.gc, (self.displays[i].borderState == 6 || self.displays[i].borderState == 2) ? 0xffff00 : 0xff0000);
311 self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].window_left, self.displays[i].window_left.gc, 0, self.displays[i].bottom / 2, 0, self.displays[i].bottom);
312 self._info._X11.XFlush(self.displays[i].display);
314 self._timeout = setTimeout(self._isUnity ? self.unity_drawBorder : self.timeoutHandler, 400);
318switch(process.platform)
321 module.exports = new windows_monitorborder();
324 module.exports = new linux_monitorborder();