monitor-border.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*
  2. Copyright 2018-2021 Intel Corporation
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. var red = 0xFF;
  14. var yellow = 0xFFFF;
  15. var GXxor = 0x6; // src XOR dst
  16. var GXclear = 0x0;
  17. var ExposureMask = (1 << 15);
  18. function windows_monitorborder()
  19. {
  20. this._ObjectID = 'monitor-info';
  21. var info = require('monitor-info');
  22. var gm = require('_GenericMarshal');
  23. var user32 = gm.CreateNativeProxy('user32.dll');
  24. info.monitors = [];
  25. user32.CreateMethod('GetDC');
  26. user32.CreateMethod('ReleaseDC');
  27. user32.CreateMethod('FillRect');
  28. user32.CreateMethod('InvalidateRect');
  29. var gdi32 = gm.CreateNativeProxy('gdi32.dll');
  30. gdi32.CreateMethod('CreateSolidBrush');
  31. var redBrush = gdi32.CreateSolidBrush(red);
  32. var yellowBrush = gdi32.CreateSolidBrush(yellow);
  33. require('events').EventEmitter.call(this);
  34. this.on('~', function () { this.Stop(); });
  35. this.Stop = function Stop()
  36. {
  37. info.redInterval = null;
  38. var drawRect = gm.CreateVariable(16);
  39. var drawRectBuffer = drawRect.toBuffer();
  40. for (var i in info.monitors)
  41. {
  42. // Top
  43. drawRectBuffer.writeInt32LE(info.monitors[i].left, 0);
  44. drawRectBuffer.writeInt32LE(info.monitors[i].top, 4);
  45. drawRectBuffer.writeInt32LE(info.monitors[i].left + (info.monitors[i].right - info.monitors[i].left), 8);
  46. drawRectBuffer.writeInt32LE(info.monitors[i].bottom - info.monitors[i].top, 12);
  47. user32.InvalidateRect(0, drawRect, 0);
  48. }
  49. }
  50. this.Start = function Start()
  51. {
  52. info.getInfo().then(function (mon)
  53. {
  54. var drawRect = gm.CreateVariable(16);
  55. info.monitors = mon;
  56. info.dc = user32.GetDC(0);
  57. info.state = 0;
  58. info.redInterval = setInterval(function ()
  59. {
  60. info.state = (info.state + 1) % 8;
  61. var drawRectBuffer = drawRect.toBuffer();
  62. for(var i in info.monitors)
  63. {
  64. drawRectBuffer.writeInt32LE(info.monitors[i].left, 0);
  65. drawRectBuffer.writeInt32LE(info.monitors[i].top, 4);
  66. drawRectBuffer.writeInt32LE(info.monitors[i].left + (info.monitors[i].right - info.monitors[i].left)/2, 8);
  67. drawRectBuffer.writeInt32LE(5, 12);
  68. user32.FillRect(info.dc, drawRect, (info.state == 0 || info.state == 4) ? yellowBrush : redBrush);
  69. drawRectBuffer.writeInt32LE(info.monitors[i].left + (info.monitors[i].right - info.monitors[i].left) / 2, 0);
  70. drawRectBuffer.writeInt32LE(info.monitors[i].top, 4);
  71. drawRectBuffer.writeInt32LE(info.monitors[i].right, 8);
  72. drawRectBuffer.writeInt32LE(5, 12);
  73. user32.FillRect(info.dc, drawRect, (info.state == 1 || info.state == 5) ? yellowBrush : redBrush);
  74. drawRectBuffer.writeInt32LE(info.monitors[i].right - 5, 0);
  75. drawRectBuffer.writeInt32LE(info.monitors[i].top, 4);
  76. drawRectBuffer.writeInt32LE(info.monitors[i].right, 8);
  77. drawRectBuffer.writeInt32LE(info.monitors[i].top + (info.monitors[i].bottom - info.monitors[i].top)/2, 12);
  78. user32.FillRect(info.dc, drawRect, (info.state == 2 || info.state == 6) ? yellowBrush : redBrush);
  79. drawRectBuffer.writeInt32LE(info.monitors[i].right - 5, 0);
  80. drawRectBuffer.writeInt32LE(info.monitors[i].top + (info.monitors[i].bottom - info.monitors[i].top) / 2, 4);
  81. drawRectBuffer.writeInt32LE(info.monitors[i].right, 8);
  82. drawRectBuffer.writeInt32LE(info.monitors[i].bottom, 12);
  83. user32.FillRect(info.dc, drawRect, (info.state == 3 || info.state == 7) ? yellowBrush : redBrush);
  84. drawRectBuffer.writeInt32LE(info.monitors[i].left + (info.monitors[i].right - info.monitors[i].left) / 2, 0);
  85. drawRectBuffer.writeInt32LE(info.monitors[i].bottom - 5, 4);
  86. drawRectBuffer.writeInt32LE(info.monitors[i].right, 8);
  87. drawRectBuffer.writeInt32LE(info.monitors[i].bottom, 12);
  88. user32.FillRect(info.dc, drawRect, (info.state == 4 || info.state == 0) ? yellowBrush : redBrush);
  89. drawRectBuffer.writeInt32LE(info.monitors[i].left, 0);
  90. drawRectBuffer.writeInt32LE(info.monitors[i].bottom - 5, 4);
  91. drawRectBuffer.writeInt32LE(info.monitors[i].left + (info.monitors[i].right - info.monitors[i].left) / 2, 8);
  92. drawRectBuffer.writeInt32LE(info.monitors[i].bottom, 12);
  93. user32.FillRect(info.dc, drawRect, (info.state == 5 || info.state == 1) ? yellowBrush : redBrush);
  94. drawRectBuffer.writeInt32LE(info.monitors[i].left, 0);
  95. drawRectBuffer.writeInt32LE(info.monitors[i].top + (info.monitors[i].bottom - info.monitors[i].top) / 2, 4);
  96. drawRectBuffer.writeInt32LE(info.monitors[i].left + 5, 8);
  97. drawRectBuffer.writeInt32LE(info.monitors[i].bottom, 12);
  98. user32.FillRect(info.dc, drawRect, (info.state == 6 || info.state == 2) ? yellowBrush : redBrush);
  99. drawRectBuffer.writeInt32LE(info.monitors[i].left, 0);
  100. drawRectBuffer.writeInt32LE(info.monitors[i].top, 4);
  101. drawRectBuffer.writeInt32LE(info.monitors[i].left + 5, 8);
  102. drawRectBuffer.writeInt32LE(info.monitors[i].top + (info.monitors[i].bottom - info.monitors[i].top) / 2, 12);
  103. user32.FillRect(info.dc, drawRect, (info.state == 7 || info.state == 3) ? yellowBrush : redBrush);
  104. }
  105. }, 450);
  106. });
  107. }
  108. }
  109. function linux_monitorborder()
  110. {
  111. var self = this;
  112. this.displays = [];
  113. this._ObjectID = 'monitor-info';
  114. this._info = require('monitor-info');
  115. this._isUnity = this._info.isUnity();
  116. console.log('isUnity = ' + this._isUnity);
  117. require('events').EventEmitter.call(this);
  118. this.on('~', function () { this.Stop(); });
  119. this.Stop = function Stop()
  120. {
  121. this._timeout = null;
  122. if(!this._isUnity)
  123. {
  124. for(var i=0; i < this.displays.length; ++i)
  125. {
  126. if(this.displays[i].GC1 && this.displays[i].rootWindow)
  127. {
  128. self._info._X11.XSetFunction(self.displays[i].display, self.displays[i].GC1, GXclear);
  129. self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].rootWindow, self.displays[i].GC1, 0, 0, self.displays[i].right, 0);
  130. 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);
  131. 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);
  132. self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].rootWindow, self.displays[i].GC1, 0, 0, 0, self.displays[i].bottom);
  133. this._info._X11.XFlush(this.displays[i].display);
  134. }
  135. }
  136. }
  137. }
  138. this.Start = function Start()
  139. {
  140. this._info.getInfo().then(function (mon)
  141. {
  142. self.displays = mon;
  143. console.log(mon.length + ' displays');
  144. for(var i = 0; i<mon.length; ++i)
  145. {
  146. console.log('Width: ' + mon[i].right + ', Height: ' + mon[i].bottom);
  147. mon[i].rootWindow = self._info._X11.XRootWindow(mon[i].display, mon[i].screenId);
  148. if (self._isUnity)
  149. {
  150. // We are unity, so we have to fake the borders with borderless windows
  151. var white = self._info._X11.XWhitePixel(mon[i].display, mon[i].screenId).Val;
  152. // Top
  153. mon[i].window_top = self._info._X11.XCreateSimpleWindow(mon[i].display, mon[i].rootWindow, 0, 0, mon[i].right, 5, 0, white, white);
  154. mon[i].window_top.gc = self._info._X11.XCreateGC(mon[i].display, mon[i].window_top, 0, 0);
  155. self._info._X11.XSetLineAttributes(mon[i].display, mon[i].window_top.gc, 10, 0, 1, 1);
  156. self._info._X11.XSetSubwindowMode(mon[i].display, mon[i].window_top.gc, 1);
  157. self._info.unDecorateWindow(mon[i].display, mon[i].window_top);
  158. self._info.setWindowSizeHints(mon[i].display, mon[i].window_top, 0, 0, mon[i].right, 5);
  159. // Right
  160. 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);
  161. mon[i].window_right.gc = self._info._X11.XCreateGC(mon[i].display, mon[i].window_right, 0, 0);
  162. self._info._X11.XSetLineAttributes(mon[i].display, mon[i].window_right.gc, 10, 0, 1, 1);
  163. self._info._X11.XSetSubwindowMode(mon[i].display, mon[i].window_right.gc, 1);
  164. self._info.unDecorateWindow(mon[i].display, mon[i].window_right);
  165. self._info.setWindowSizeHints(mon[i].display, mon[i].window_right, mon[i].right - 5, 0, 5, mon[i].bottom);
  166. // Left
  167. mon[i].window_left = self._info._X11.XCreateSimpleWindow(mon[i].display, mon[i].rootWindow, 0, 0, 5, mon[i].bottom, 0, white, white);
  168. mon[i].window_left.gc = self._info._X11.XCreateGC(mon[i].display, mon[i].window_left, 0, 0);
  169. self._info._X11.XSetLineAttributes(mon[i].display, mon[i].window_left.gc, 10, 0, 1, 1);
  170. self._info._X11.XSetSubwindowMode(mon[i].display, mon[i].window_left.gc, 1);
  171. self._info.unDecorateWindow(mon[i].display, mon[i].window_left);
  172. self._info.setWindowSizeHints(mon[i].display, mon[i].window_left, 0, 0, 5, mon[i].bottom);
  173. // Bottom
  174. 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);
  175. mon[i].window_bottom.gc = self._info._X11.XCreateGC(mon[i].display, mon[i].window_bottom, 0, 0);
  176. self._info._X11.XSetLineAttributes(mon[i].display, mon[i].window_bottom.gc, 10, 0, 1, 1);
  177. self._info._X11.XSetSubwindowMode(mon[i].display, mon[i].window_bottom.gc, 1);
  178. self._info.unDecorateWindow(mon[i].display, mon[i].window_bottom);
  179. self._info.setWindowSizeHints(mon[i].display, mon[i].window_bottom, 0, mon[i].bottom - 5, mon[i].right, 5);
  180. self._info._X11.XMapWindow(mon[i].display, mon[i].window_top);
  181. self._info._X11.XMapWindow(mon[i].display, mon[i].window_right);
  182. self._info._X11.XMapWindow(mon[i].display, mon[i].window_left);
  183. self._info._X11.XMapWindow(mon[i].display, mon[i].window_bottom);
  184. self._info.setAlwaysOnTop(mon[i].display, mon[i].rootWindow, mon[i].window_top);
  185. self._info.hideWindowIcon(mon[i].display, mon[i].rootWindow, mon[i].window_top);
  186. self._info.setAlwaysOnTop(mon[i].display, mon[i].rootWindow, mon[i].window_right);
  187. self._info.hideWindowIcon(mon[i].display, mon[i].rootWindow, mon[i].window_right);
  188. self._info.setAlwaysOnTop(mon[i].display, mon[i].rootWindow, mon[i].window_left);
  189. self._info.hideWindowIcon(mon[i].display, mon[i].rootWindow, mon[i].window_left);
  190. self._info.setAlwaysOnTop(mon[i].display, mon[i].rootWindow, mon[i].window_bottom);
  191. self._info.hideWindowIcon(mon[i].display, mon[i].rootWindow, mon[i].window_bottom);
  192. self._info._X11.XFlush(mon[i].display);
  193. mon[i].borderState = 0;
  194. }
  195. else
  196. {
  197. // If we aren't unity, then we can just draw
  198. mon[i].GC1 = self._info._X11.XCreateGC(mon[i].display, mon[i].rootWindow, 0, 0);
  199. mon[i].borderState = 0;
  200. self._info._X11.XSetForeground(mon[i].display, mon[i].GC1, self._info._X11.XWhitePixel(mon[i].display, mon[i].screenId).Val); // White
  201. self._info._X11.XSetLineAttributes(mon[i].display, mon[i].GC1, 10, 0, 1, 1);
  202. self._info._X11.XSetSubwindowMode(mon[i].display, mon[i].GC1, 1);
  203. }
  204. }
  205. self._info._XEvent = self._info._gm.CreateVariable(192);
  206. self._timeout = setTimeout(self._isUnity ? self.unity_drawBorder : self.timeoutHandler, 250);
  207. });
  208. }
  209. this.timeoutHandler = function()
  210. {
  211. for (var i = 0; i < self.displays.length; ++i) {
  212. self.displays[i].borderState = (self.displays[i].borderState + 1) % 8;
  213. // Top
  214. self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].GC1, (self.displays[i].borderState == 0 || self.displays[i].borderState == 4) ? 0xffff00 : 0xff0000);
  215. self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].rootWindow, self.displays[i].GC1, 0, 0, self.displays[i].right / 2, 0);
  216. self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].GC1, (self.displays[i].borderState == 1 || self.displays[i].borderState == 5) ? 0xffff00 : 0xff0000);
  217. 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);
  218. // Right
  219. self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].GC1, (self.displays[i].borderState == 2 || self.displays[i].borderState == 6) ? 0xffff00 : 0xff0000);
  220. 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);
  221. self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].GC1, (self.displays[i].borderState == 3 || self.displays[i].borderState == 7) ? 0xffff00 : 0xff0000);
  222. 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);
  223. // Bottom
  224. self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].GC1, (self.displays[i].borderState == 5 || self.displays[i].borderState == 1) ? 0xffff00 : 0xff0000);
  225. 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);
  226. self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].GC1, (self.displays[i].borderState == 4 || self.displays[i].borderState == 0) ? 0xffff00 : 0xff0000);
  227. 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);
  228. // Left
  229. self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].GC1, (self.displays[i].borderState == 7 || self.displays[i].borderState == 3) ? 0xffff00 : 0xff0000);
  230. self._info._X11.XDrawLine(self.displays[i].display, self.displays[i].rootWindow, self.displays[i].GC1, 0, 0, 0, self.displays[i].bottom / 2);
  231. self._info._X11.XSetForeground(self.displays[i].display, self.displays[i].GC1, (self.displays[i].borderState == 6 || self.displays[i].borderState == 2) ? 0xffff00 : 0xff0000);
  232. 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);
  233. self._info._X11.XFlush(self.displays[i].display);
  234. }
  235. self._timeout = setTimeout(self._isUnity ? self.unity_drawBorder : self.timeoutHandler, 400);
  236. }
  237. this.unity_drawBorder = function unity_drawBorder()
  238. {
  239. for (var i = 0; i < self.displays.length; ++i)
  240. {
  241. self.displays[i].borderState = (self.displays[i].borderState + 1) % 8;
  242. // Top
  243. 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);
  244. 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);
  245. 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);
  246. 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);
  247. self._info._X11.XFlush(self.displays[i].display);
  248. // Right
  249. 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);
  250. 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);
  251. 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);
  252. 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);
  253. self._info._X11.XFlush(self.displays[i].display);
  254. // Bottom
  255. 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);
  256. 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);
  257. 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);
  258. 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);
  259. self._info._X11.XFlush(self.displays[i].display);
  260. // Left
  261. 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);
  262. 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);
  263. 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);
  264. 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);
  265. self._info._X11.XFlush(self.displays[i].display);
  266. }
  267. self._timeout = setTimeout(self._isUnity ? self.unity_drawBorder : self.timeoutHandler, 400);
  268. }
  269. }
  270. switch(process.platform)
  271. {
  272. case 'win32':
  273. module.exports = new windows_monitorborder();
  274. break;
  275. case 'linux':
  276. module.exports = new linux_monitorborder();
  277. break;
  278. default:
  279. break;
  280. }