desktop-capturer.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. 'use strict'
  2. const ipcMain = require('@electron/internal/browser/ipc-main-internal')
  3. const { desktopCapturer } = process.atomBinding('desktop_capturer')
  4. const eventBinding = process.atomBinding('event')
  5. const deepEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b)
  6. // A queue for holding all requests from renderer process.
  7. let requestsQueue = []
  8. const electronSources = 'ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES'
  9. const capturerResult = (id) => `ELECTRON_RENDERER_DESKTOP_CAPTURER_RESULT_${id}`
  10. ipcMain.on(electronSources, (event, captureWindow, captureScreen, thumbnailSize, fetchWindowIcons, id) => {
  11. const customEvent = eventBinding.createWithSender(event.sender)
  12. event.sender.emit('desktop-capturer-get-sources', customEvent)
  13. if (customEvent.defaultPrevented) {
  14. event._replyInternal(capturerResult(id), [])
  15. return
  16. }
  17. const request = {
  18. id,
  19. options: {
  20. captureWindow,
  21. captureScreen,
  22. thumbnailSize,
  23. fetchWindowIcons
  24. },
  25. event
  26. }
  27. requestsQueue.push(request)
  28. if (requestsQueue.length === 1) {
  29. desktopCapturer.startHandling(captureWindow, captureScreen, thumbnailSize, fetchWindowIcons)
  30. }
  31. // If the WebContents is destroyed before receiving result, just remove the
  32. // reference from requestsQueue to make the module not send the result to it.
  33. event.sender.once('destroyed', () => {
  34. request.event = null
  35. })
  36. })
  37. desktopCapturer.emit = (event, name, sources, fetchWindowIcons) => {
  38. // Receiving sources result from main process, now send them back to renderer.
  39. const handledRequest = requestsQueue.shift()
  40. const unhandledRequestsQueue = []
  41. const result = sources.map(source => {
  42. return {
  43. id: source.id,
  44. name: source.name,
  45. thumbnail: source.thumbnail.toDataURL(),
  46. display_id: source.display_id,
  47. appIcon: (fetchWindowIcons && source.appIcon) ? source.appIcon.toDataURL() : null
  48. }
  49. })
  50. if (handledRequest.event) {
  51. handledRequest.event._replyInternal(capturerResult(handledRequest.id), result)
  52. }
  53. // Check the queue to see whether there is another identical request & handle
  54. requestsQueue.forEach(request => {
  55. const event = request.event
  56. if (deepEqual(handledRequest.options, request.options)) {
  57. if (event) {
  58. event._replyInternal(capturerResult(request.id), result)
  59. }
  60. } else {
  61. unhandledRequestsQueue.push(request)
  62. }
  63. })
  64. requestsQueue = unhandledRequestsQueue
  65. // If the requestsQueue is not empty, start a new request handling.
  66. if (requestsQueue.length > 0) {
  67. const { captureWindow, captureScreen, thumbnailSize, fetchWindowIcons } = requestsQueue[0].options
  68. return desktopCapturer.startHandling(captureWindow, captureScreen, thumbnailSize, fetchWindowIcons)
  69. }
  70. }