CContext.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #include <iostream>
  2. #include <X11/Xlib.h>
  3. #include <X11/Xatom.h>
  4. #include <X11/extensions/Xrandr.h>
  5. #include <GL/glew.h>
  6. #include <GL/glx.h>
  7. #include "CContext.h"
  8. #include "CVideo.h"
  9. using namespace WallpaperEngine::Render;
  10. CContext::CContext (std::vector <std::string> screens) :
  11. m_wallpaper (nullptr),
  12. m_screens (std::move (screens)),
  13. m_isRootWindow (m_screens.empty () == false),
  14. m_defaultViewport ({0, 0, 1920, 1080})
  15. {
  16. this->initializeViewports ();
  17. }
  18. void CContext::initializeViewports ()
  19. {
  20. if (this->m_isRootWindow == false || this->m_screens.empty () == true)
  21. return;
  22. this->m_display = XOpenDisplay (nullptr);
  23. int xrandr_result, xrandr_error;
  24. if (!XRRQueryExtension (this->m_display, &xrandr_result, &xrandr_error))
  25. {
  26. std::cerr << "XRandr is not present, cannot detect specified screens, running in window mode" << std::endl;
  27. return;
  28. }
  29. Window root = DefaultRootWindow (this->m_display);
  30. int fullWidth = DisplayWidth (this->m_display, DefaultScreen (this->m_display));
  31. int fullHeight = DisplayHeight (this->m_display, DefaultScreen (this->m_display));
  32. XRRScreenResources* screenResources = XRRGetScreenResources (this->m_display, DefaultRootWindow (this->m_display));
  33. // there are some situations where xrandr returns null (like screen not using the extension)
  34. if (screenResources == nullptr)
  35. return;
  36. // create the pixmap and gc used for this display, most situations only have one "display"
  37. this->m_pixmap = XCreatePixmap (this->m_display, DefaultRootWindow (this->m_display), fullWidth, fullHeight, 24);
  38. this->m_gc = XCreateGC (this->m_display, this->m_pixmap, 0, nullptr);
  39. // fill the whole pixmap with black for now
  40. XFillRectangle (this->m_display, this->m_pixmap, this->m_gc, 0, 0, fullWidth, fullHeight);
  41. for (int i = 0; i < screenResources->noutput; i ++)
  42. {
  43. XRROutputInfo* info = XRRGetOutputInfo (this->m_display, screenResources, screenResources->outputs [i]);
  44. // there are some situations where xrandr returns null (like screen not using the extension)
  45. if (info == nullptr)
  46. continue;
  47. auto cur = this->m_screens.begin ();
  48. auto end = this->m_screens.end ();
  49. for (; cur != end; cur ++)
  50. {
  51. if (info->connection == RR_Connected && strcmp (info->name, (*cur).c_str ()) == 0)
  52. {
  53. XRRCrtcInfo* crtc = XRRGetCrtcInfo (this->m_display, screenResources, info->crtc);
  54. std::cout << "Found requested screen: " << info->name << " -> " << crtc->x << "x" << crtc->y << ":" << crtc->width << "x" << crtc->height << std::endl;
  55. glm::ivec4 viewport = {
  56. crtc->x, fullHeight - (crtc->y + crtc->height), crtc->width, crtc->height
  57. };
  58. this->m_viewports.push_back (viewport);
  59. XRRFreeCrtcInfo (crtc);
  60. }
  61. }
  62. XRRFreeOutputInfo (info);
  63. }
  64. XRRFreeScreenResources (screenResources);
  65. // create the fbo that will handle the screen
  66. this->m_fbo = new CFBO("_sc_FullFrameBuffer", ITexture::TextureFormat::ARGB8888, 1.0, fullWidth, fullHeight, fullWidth, fullHeight);
  67. // set the window background so the pixmap is drawn
  68. XSetWindowBackgroundPixmap(this->m_display, root, this->m_pixmap);
  69. this->m_imageData = new char [fullWidth * fullHeight * 4];
  70. // create the image for X11 to be able to copy it over
  71. this->m_image = XCreateImage (this->m_display, CopyFromParent, 24, ZPixmap, 0, this->m_imageData, fullWidth, fullHeight, 32, 0);
  72. // Cause of issue for issue #59 origial issue
  73. // glfwWindowHintPointer (GLFW_NATIVE_PARENT_HANDLE, reinterpret_cast <void*> (DefaultRootWindow (display)));
  74. }
  75. void CContext::render ()
  76. {
  77. if (this->m_wallpaper == nullptr)
  78. return;
  79. if (this->m_viewports.empty () == false)
  80. {
  81. bool firstFrame = true;
  82. bool renderFrame = true;
  83. auto cur = this->m_viewports.begin ();
  84. auto end = this->m_viewports.end ();
  85. int fullWidth = DisplayWidth (this->m_display, DefaultScreen (this->m_display));
  86. int fullHeight = DisplayHeight (this->m_display, DefaultScreen (this->m_display));
  87. Window root = DefaultRootWindow (this->m_display);
  88. for (; cur != end; cur ++)
  89. {
  90. // render the background
  91. this->m_wallpaper->render (*cur, renderFrame, firstFrame);
  92. // scenes need to render a new frame for each viewport as they produce different results
  93. // but videos should only be rendered once per group of viewports
  94. firstFrame = false;
  95. renderFrame = !this->m_wallpaper->is <CVideo> ();
  96. }
  97. // read the full texture into the image
  98. glReadPixels (0, 0, fullWidth, fullHeight, GL_BGRA, GL_UNSIGNED_BYTE, (void*) this->m_imageData);
  99. // put the image back into the screen
  100. XPutImage (this->m_display, this->m_pixmap, this->m_gc, this->m_image, 0, 0, 0, 0, fullWidth, fullHeight);
  101. // _XROOTPMAP_ID & ESETROOT_PMAP_ID allow other programs (compositors) to
  102. // edit the background. Without these, other programs will clear the screen.
  103. // it also forces the compositor to refresh the background (tested with picom)
  104. Atom prop_root = XInternAtom(this->m_display, "_XROOTPMAP_ID", False);
  105. Atom prop_esetroot = XInternAtom(this->m_display, "ESETROOT_PMAP_ID", False);
  106. XChangeProperty(this->m_display, root, prop_root, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &this->m_pixmap, 1);
  107. XChangeProperty(this->m_display, root, prop_esetroot, XA_PIXMAP, 32, PropModeReplace, (unsigned char *) &this->m_pixmap, 1);
  108. XClearWindow(this->m_display, root);
  109. XFlush(this->m_display);
  110. }
  111. else
  112. this->m_wallpaper->render (this->m_defaultViewport);
  113. }
  114. void CContext::setWallpaper (CWallpaper* wallpaper)
  115. {
  116. this->m_wallpaper = wallpaper;
  117. // update the wallpaper's texcoords based on the mode we're running
  118. if (this->m_screens.empty () == false)
  119. {
  120. GLfloat texCoords [] = {
  121. 0.0f, 1.0f,
  122. 1.0f, 1.0f,
  123. 0.0f, 0.0f,
  124. 0.0f, 0.0f,
  125. 1.0f, 1.0f,
  126. 1.0f, 0.0f
  127. };
  128. this->m_wallpaper->updateTexCoord (texCoords, sizeof (texCoords));
  129. this->m_wallpaper->setDestinationFramebuffer (this->m_fbo->getFramebuffer ());
  130. }
  131. }
  132. void CContext::setDefaultViewport (glm::vec4 defaultViewport)
  133. {
  134. this->m_defaultViewport = defaultViewport;
  135. }
  136. CMouseInput* CContext::getMouse () const
  137. {
  138. return this->m_mouse;
  139. }
  140. void CContext::setMouse (CMouseInput* mouse)
  141. {
  142. this->m_mouse = mouse;
  143. }