glselectrectangle.cpp 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. /* glrectangle.hpp: Handles creating hardware accelerated rectangles on the screen using X11 and OpenGL.
  2. *
  3. * Copyright (C) 2014: Dalton Nell, Slop Contributors (https://github.com/naelstrof/slop/graphs/contributors).
  4. *
  5. * This file is part of Slop.
  6. *
  7. * Slop is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * Slop is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with Slop. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include "glselectrectangle.hpp"
  21. static Bool isDestroyNotify( Display* dpy, XEvent* ev, XPointer win ) {
  22. return ev->type == DestroyNotify && ev->xdestroywindow.window == *((Window*)win);
  23. }
  24. slop::GLSelectRectangle::~GLSelectRectangle() {
  25. if ( m_window == None ) {
  26. return;
  27. }
  28. xengine->freeCRTCS( m_monitors );
  29. delete m_framebuffer;
  30. // Try to erase the window before destroying it.
  31. glClearColor( 0, 0, 0, 0 );
  32. glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
  33. glXSwapBuffers( xengine->m_display, m_glxWindow );
  34. // Sleep for 0.1 seconds in hope that the rectangle was erased.
  35. usleep( 10000 );
  36. XDestroyWindow( xengine->m_display, m_window );
  37. XEvent event;
  38. // Block until the window is actually completely removed.
  39. XIfEvent( xengine->m_display, &event, &isDestroyNotify, (XPointer)&m_window );
  40. // Sleep for 0.1 seconds in hope that the screen actually cleared the window.
  41. usleep( 10000 );
  42. }
  43. void slop::GLSelectRectangle::constrainWithinMonitor( int* x, int* y, int* w, int* h ) {
  44. m_offsetx = 0;
  45. m_offsety = 0;
  46. m_offsetw = 0;
  47. m_offseth = 0;
  48. for ( unsigned int i=0;i<m_monitors.size();i++ ) {
  49. XRRCrtcInfo* monitor = m_monitors[ i ];
  50. if ( !((int)xengine->m_mousex >= (int)monitor->x && (int)xengine->m_mousey >= (int)monitor->y &&
  51. (int)xengine->m_mousex <= (int)(monitor->x+monitor->width) && (int)xengine->m_mousey <= (int)(monitor->y+monitor->height) ) ) {
  52. continue;
  53. }
  54. if ( (int)*x < (int)monitor->x ) {
  55. m_offsetx = monitor->x-*x;
  56. *w += *x-monitor->x;
  57. *x = monitor->x;
  58. }
  59. if ( (int)(*x+*w) >= (int)(monitor->x+monitor->width) ) {
  60. m_offsetw = (monitor->width-1-(*x-monitor->x+*w));
  61. *w = monitor->width-1-(*x-monitor->x);
  62. }
  63. if ( (int)*y < (int)monitor->y ) {
  64. m_offsety = monitor->y-*y;
  65. *h += *y-monitor->y;
  66. *y = monitor->y;
  67. }
  68. if ( (int)(*y+*h) >= (int)(monitor->y+monitor->height) ) {
  69. m_offseth = (monitor->height-1-(*y-monitor->y+*h));
  70. *h = monitor->height-1-(*y-monitor->y);
  71. }
  72. break;
  73. }
  74. m_offsetx *= m_glassSize;
  75. m_offsety *= m_glassSize;
  76. m_offsetw *= m_glassSize;
  77. m_offseth *= m_glassSize;
  78. }
  79. void slop::GLSelectRectangle::setShader( std::string shader ) {
  80. m_shader = shader;
  81. m_framebuffer->setShader( shader );
  82. }
  83. void slop::GLSelectRectangle::setMagnifySettings( bool on, float magstrength, unsigned int pixels ) {
  84. m_glassSize = magstrength;
  85. m_glassPixels = pixels;
  86. m_glassEnabled = on;
  87. m_glassx = xengine->m_mousex;
  88. m_glassy = xengine->m_mousey;
  89. m_realglassx = xengine->m_mousex;
  90. m_realglassy = xengine->m_mousey;
  91. }
  92. void slop::GLSelectRectangle::pushOut( int* x, int* y, int w, int h, int rx, int ry, int rw, int rh ) {
  93. // AABB to test for collision
  94. if (!(
  95. *x < rx + rw &&
  96. *x + w > rx &&
  97. *y < ry + rh &&
  98. h + *y > ry
  99. )) {
  100. // No collision, so we do nothing.
  101. return;
  102. }
  103. // Otherwise we find an optimal angle to push ourselves out at.
  104. int centerx = rx+rw/2;
  105. int centery = ry+rh/2;
  106. float ang = -atan2( (float)(*y+(float)h/2.f)-(float)centery, (float)(*x+(float)w/2.f)-(float)centerx );
  107. float pi = 3.1415926535897;
  108. float upright = pi/2 - atan( (2.f*float(rx+rw)-2.f*(float)centerx)/(float)rh );
  109. float upleft = pi/2 - atan( (2.f*(float)rx-2.f*(float)centerx)/(float)rh );
  110. float downright = -upright;
  111. float downleft = -upleft;
  112. if ( ang >= upright && ang <= upleft ) {
  113. *x = centerx + ((rh*cos(ang))/(2*sin(ang))) - w/2;
  114. *y = centery - rh/2 - h;
  115. } else if ( ang <= downright && ang >= downleft) {
  116. *x = centerx - ((rh*cos(ang))/(2*sin(ang))) - w/2;
  117. *y = centery + rh/2;
  118. } else if ( ang < downleft || ang > upleft ) {
  119. *x = centerx - rw/2 - w;
  120. *y = centery + (rw*sin(ang))/(2*cos(ang)) - h/2;
  121. } else {
  122. *x = centerx + rw/2;
  123. *y = centery - (rw*sin(ang))/(2*cos(ang)) - h/2;
  124. }
  125. }
  126. void slop::GLSelectRectangle::pushIn( int* x, int* y, int w, int h, int rx, int ry, int rw, int rh ) {
  127. if ( *x > rx && *y > ry &&
  128. *x+w < rx+rw && *y+h < ry+rh ) {
  129. // We're already fully contained...
  130. return;
  131. }
  132. // Otherwise we find an optimal angle to push ourselves in at.
  133. int centerx = rx+rw/2;
  134. int centery = ry+rh/2;
  135. float ang = -atan2( (float)(*y+(float)h/2.f)-(float)centery, (float)(*x+(float)w/2.f)-(float)centerx );
  136. float pi = 3.1415926535897;
  137. float upright = pi/2 - atan( (2.f*float(rx+rw)-2.f*(float)centerx)/(float)rh );
  138. float upleft = pi/2 - atan( (2.f*(float)rx-2.f*(float)centerx)/(float)rh );
  139. float downright = -upright;
  140. float downleft = -upleft;
  141. if ( ang >= upright && ang <= upleft ) {
  142. *x = centerx + ((rh*cos(ang))/(2*sin(ang))) - w/2;
  143. *y = centery - rh/2;
  144. } else if ( ang <= downright && ang >= downleft) {
  145. *x = centerx - ((rh*cos(ang))/(2*sin(ang))) - w/2;
  146. *y = centery + rh/2 - h;
  147. } else if ( ang < downleft || ang > upleft ) {
  148. *x = centerx - rw/2;
  149. *y = centery + (rw*sin(ang))/(2*cos(ang)) - h/2;
  150. } else {
  151. *x = centerx + rw/2 - w;
  152. *y = centery - (rw*sin(ang))/(2*cos(ang)) - h/2;
  153. }
  154. if ( !(*x > rx && *y > ry &&
  155. *x+w < rx+rw && *y+h < ry+rh) ) {
  156. if ( *x+w > rx+rw ) {
  157. *x -= w/2;
  158. }
  159. if ( *x < rx ) {
  160. *x += w/2;
  161. }
  162. if ( *y+h > ry+rh ) {
  163. *y -= h/2;
  164. }
  165. if ( *y < ry ) {
  166. *y += h/2;
  167. }
  168. }
  169. }
  170. void slop::GLSelectRectangle::findOptimalGlassPosition() {
  171. // Try to move the glass next to the mouse.
  172. m_glassx = xengine->m_mousex+m_glassPixels/2+5-m_glassBorder;
  173. m_glassy = xengine->m_mousey+m_glassPixels/2+5-m_glassBorder;
  174. XRectangle view, selection, combined;
  175. view.x = xengine->m_mousex-(m_glassPixels+1+m_glassBorder)/2;
  176. view.y = xengine->m_mousey-(m_glassPixels+1+m_glassBorder)/2;
  177. view.width = m_glassPixels+1;
  178. view.height = m_glassPixels+1;
  179. selection.x = m_x-m_border;
  180. selection.y = m_y-m_border;
  181. selection.width = m_width+m_border*2;
  182. selection.height = m_height+m_border*2;
  183. combined.x = std::min( selection.x, view.x );
  184. combined.y = std::min( selection.y, view.y );
  185. combined.width = selection.width + std::max( selection.x-view.x, (view.x+view.width)-(selection.x+selection.width) );
  186. combined.height = selection.height + std::max( selection.y-view.y, (view.y+view.height)-(selection.y+selection.height) );
  187. for ( unsigned int i=0;i<m_monitors.size();i++ ) {
  188. XRRCrtcInfo* monitor = m_monitors[ i ];
  189. // Push the glass inside the monitor the mouse is on.
  190. if ( (int)xengine->m_mousex >= (int)monitor->x && (int)xengine->m_mousex <= (int)(monitor->x + monitor->width) &&
  191. (int)xengine->m_mousey >= (int)monitor->y && (int)xengine->m_mousey <= (int)(monitor->y + monitor->height) ) {
  192. pushIn( &m_glassx, &m_glassy, m_glassPixels*m_glassSize+m_glassBorder*2, m_glassPixels*m_glassSize+m_glassBorder*2, monitor->x, monitor->y, monitor->width, monitor->height );
  193. break;
  194. }
  195. }
  196. // Push the glass outside of the selection, but only if we are left clicking, and always keep it out of the "shot"
  197. if ( xengine->getCursor() != slop::Left ) {
  198. pushOut( &m_glassx, &m_glassy, m_glassPixels*m_glassSize+m_glassBorder*2, m_glassPixels*m_glassSize+m_glassBorder*2, combined.x, combined.y, combined.width, combined.height );
  199. } else {
  200. pushOut( &m_glassx, &m_glassy, m_glassPixels*m_glassSize+m_glassBorder*2, m_glassPixels*m_glassSize+m_glassBorder*2, view.x, view.y, view.width, view.height );
  201. }
  202. m_glassx += m_glassBorder;
  203. m_glassy += m_glassBorder;
  204. }
  205. void slop::GLSelectRectangle::generateMagnifyingGlass() {
  206. int x = xengine->m_mousex-m_glassPixels/2;
  207. int y = xengine->m_mousey-m_glassPixels/2;
  208. int w = m_glassPixels;
  209. int h = m_glassPixels;
  210. constrainWithinMonitor( &x, &y, &w, &h );
  211. XImage* image = XGetImage( xengine->m_display, xengine->m_root, x, y, w, h, 0xffffffff, ZPixmap );
  212. glEnable(GL_TEXTURE_2D);
  213. glGenTextures(1, &m_texid);
  214. glBindTexture(GL_TEXTURE_2D, m_texid);
  215. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  216. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  217. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  218. glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, (void*)(&(image->data[0])));
  219. XDestroyImage( image );
  220. glDisable(GL_TEXTURE_2D);
  221. }
  222. void slop::GLSelectRectangle::setTheme( bool on, std::string name ) {
  223. if ( !on || name == "none" ) {
  224. return;
  225. }
  226. std::string root = resource->getRealPath( name );
  227. std::string tl = root + "/corner_tl.png";
  228. std::string bl = root + "/corner_bl.png";
  229. std::string tr = root + "/corner_tr.png";
  230. std::string br = root + "/corner_br.png";
  231. std::string straight = root + "/straight.png";
  232. // One of the textures didn't exist, so we cancel the theme.
  233. if (!resource->validatePath( tl ) ||
  234. !resource->validatePath( bl ) ||
  235. !resource->validatePath( tr ) ||
  236. !resource->validatePath( br ) ||
  237. !resource->validatePath( straight ) ) {
  238. fprintf( stderr, "One of the textures was missing in the theme... disabling.\n" );
  239. return;
  240. }
  241. // Otherwise we load each one :)
  242. loadImage( &(m_cornerids[0]), tl );
  243. loadImage( &(m_cornerids[1]), tr );
  244. loadImage( &(m_cornerids[2]), bl );
  245. loadImage( &(m_cornerids[3]), br );
  246. loadImage( &(m_straightid), straight );
  247. glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &m_straightwidth );
  248. glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &m_straightheight );
  249. m_themed = on;
  250. }
  251. unsigned int slop::GLSelectRectangle::loadImage( unsigned int* texture, std::string path ) {
  252. glActiveTexture(GL_TEXTURE0);
  253. glEnable(GL_TEXTURE_2D);
  254. glGenTextures( 1, texture );
  255. glBindTexture( GL_TEXTURE_2D, *texture );
  256. Imlib_Load_Error err;
  257. Imlib_Image image = imlib_load_image_with_error_return( path.c_str(), &err );
  258. if ( err != IMLIB_LOAD_ERROR_NONE ) {
  259. std::string message = "Failed to load image: ";
  260. message += path;
  261. message += "\n\t";
  262. switch( err ) {
  263. default: {
  264. message += "unknown error ";
  265. message += (int)err;
  266. message += "\n";
  267. break;
  268. }
  269. case IMLIB_LOAD_ERROR_OUT_OF_FILE_DESCRIPTORS:
  270. message += "out of file descriptors\n";
  271. break;
  272. case IMLIB_LOAD_ERROR_OUT_OF_MEMORY:
  273. message += "out of memory\n";
  274. break;
  275. case IMLIB_LOAD_ERROR_TOO_MANY_SYMBOLIC_LINKS:
  276. message += "path contains too many symbolic links\n";
  277. break;
  278. case IMLIB_LOAD_ERROR_PATH_POINTS_OUTSIDE_ADDRESS_SPACE:
  279. message += "path points outside address space\n";
  280. break;
  281. case IMLIB_LOAD_ERROR_PATH_COMPONENT_NOT_DIRECTORY:
  282. message += "path component is not a directory\n";
  283. break;
  284. case IMLIB_LOAD_ERROR_PATH_COMPONENT_NON_EXISTANT:
  285. message += "path component is non-existant (~ isn't expanded inside quotes!)\n";
  286. break;
  287. case IMLIB_LOAD_ERROR_PATH_TOO_LONG:
  288. message += "path is too long\n";
  289. break;
  290. case IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT:
  291. message += "no loader for file format (unsupported format)\n";
  292. break;
  293. case IMLIB_LOAD_ERROR_OUT_OF_DISK_SPACE: {
  294. message += "not enough disk space\n";
  295. break;
  296. }
  297. case IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST: {
  298. message += "file does not exist\n";
  299. break;
  300. }
  301. case IMLIB_LOAD_ERROR_FILE_IS_DIRECTORY: {
  302. message += "file is a directory\n";
  303. break;
  304. }
  305. case IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_WRITE:
  306. case IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_READ: {
  307. message += "permission denied\n";
  308. break;
  309. }
  310. }
  311. throw std::runtime_error( message.c_str() );
  312. return *texture;
  313. }
  314. imlib_context_set_image( image );
  315. DATA32* data = imlib_image_get_data_for_reading_only();
  316. glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, imlib_image_get_width(), imlib_image_get_height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, (void*)data );
  317. if ( GLEW_VERSION_3_0 ) {
  318. glHint( GL_GENERATE_MIPMAP_HINT, GL_NICEST );
  319. glGenerateMipmap( GL_TEXTURE_2D );
  320. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
  321. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR );
  322. } else {
  323. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  324. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  325. }
  326. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  327. imlib_free_image();
  328. glDisable(GL_TEXTURE_2D);
  329. return *texture;
  330. }
  331. slop::GLSelectRectangle::GLSelectRectangle( int sx, int sy, int ex, int ey, int border, bool highlight, float r, float g, float b, float a ) {
  332. m_x = std::min( sx, ex );
  333. m_y = std::min( sy, ey );
  334. m_width = std::max( sx, ex ) - m_x;
  335. m_height = std::max( sy, ey ) - m_y;
  336. m_r = r;
  337. m_g = g;
  338. m_b = b;
  339. m_a = a;
  340. m_border = border;
  341. m_window = None;
  342. m_highlight = highlight;
  343. m_glassPixels = 64;
  344. m_glassx = xengine->m_mousex;
  345. m_glassy = xengine->m_mousey;
  346. m_realglassx = xengine->m_mousex;
  347. m_realglassy = xengine->m_mousey;
  348. m_glassSize = 4;
  349. m_glassBorder = 1;
  350. m_monitors = xengine->getCRTCS();
  351. m_themed = false;
  352. m_shader = "simple";
  353. m_time = 0;
  354. // If we don't have a border, we don't exist, so just die.
  355. if ( m_border == 0 ) {
  356. return;
  357. }
  358. if ( m_highlight ) {
  359. m_border = 0;
  360. }
  361. static int visdata[] = {
  362. GLX_RENDER_TYPE, GLX_RGBA_BIT,
  363. GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
  364. GLX_DOUBLEBUFFER, True,
  365. GLX_RED_SIZE, 8,
  366. GLX_GREEN_SIZE, 8,
  367. GLX_BLUE_SIZE, 8,
  368. GLX_ALPHA_SIZE, 8,
  369. GLX_DEPTH_SIZE, 16,
  370. None
  371. };
  372. int numfbconfigs = 0;
  373. GLXFBConfig* fbconfigs = glXChooseFBConfig( xengine->m_display, DefaultScreen( xengine->m_display ), visdata, &numfbconfigs );
  374. m_fbconfig = 0;
  375. for ( int i=0; i<numfbconfigs; i++ ) {
  376. m_visual = (XVisualInfo*)glXGetVisualFromFBConfig( xengine->m_display, fbconfigs[i] );
  377. if ( !m_visual ) {
  378. continue;
  379. }
  380. m_pictFormat = XRenderFindVisualFormat( xengine->m_display, m_visual->visual );
  381. if ( !m_pictFormat ) {
  382. continue;
  383. }
  384. m_fbconfig = fbconfigs[i];
  385. if ( m_pictFormat->direct.alphaMask > 0 ) {
  386. break;
  387. }
  388. }
  389. if ( !m_fbconfig ) {
  390. fprintf( stderr, "Couldn't find a matching FB config for a transparent OpenGL window!\n");
  391. }
  392. m_cmap = XCreateColormap( xengine->m_display, xengine->m_root, m_visual->visual, AllocNone );
  393. XSetWindowAttributes attributes;
  394. attributes.colormap = m_cmap;
  395. attributes.background_pixmap = None;
  396. attributes.border_pixmap = None;
  397. attributes.border_pixel = 0;
  398. // Disable window decorations.
  399. attributes.override_redirect = True;
  400. // Make sure we know when we've been successfully destroyed later!
  401. attributes.event_mask = StructureNotifyMask;
  402. unsigned long valueMask = CWOverrideRedirect | CWEventMask | CWBackPixmap | CWColormap | CWBorderPixel;
  403. // Create the window
  404. m_window = XCreateWindow( xengine->m_display, xengine->m_root, 0, 0, xengine->getWidth(), xengine->getHeight(),
  405. 0, m_visual->depth, InputOutput,
  406. m_visual->visual, valueMask, &attributes );
  407. if ( !m_window ) {
  408. fprintf( stderr, "Couldn't create a GL window!\n");
  409. }
  410. m_glxWindow = m_window;
  411. static char title[] = "OpenGL Slop";
  412. XWMHints* startup_state = XAllocWMHints();
  413. startup_state->initial_state = NormalState;
  414. startup_state->flags = StateHint;
  415. XTextProperty textprop;
  416. textprop.value = (unsigned char*)title;
  417. textprop.encoding = XA_STRING;
  418. textprop.format = 8;
  419. textprop.nitems = strlen( title );
  420. XSizeHints sizehints;
  421. sizehints.x = 0;
  422. sizehints.y = 0;
  423. sizehints.width = xengine->getWidth();
  424. sizehints.height = xengine->getHeight();
  425. sizehints.flags = USPosition | USSize;
  426. XClassHint classhints;
  427. char name[] = "slop";
  428. classhints.res_name = name;
  429. classhints.res_class = name;
  430. XSetClassHint( xengine->m_display, m_window, &classhints );
  431. XSetWMProperties( xengine->m_display, m_window, &textprop, &textprop, NULL, 0, &sizehints, startup_state, NULL );
  432. XFree( startup_state );
  433. // Make it so all input falls through
  434. XRectangle rect;
  435. rect.x = rect.y = rect.width = rect.height = 0;
  436. XShapeCombineRectangles( xengine->m_display, m_window, ShapeInput, 0, 0, &rect, 1, ShapeSet, 0);
  437. XMapWindow( xengine->m_display, m_window );
  438. int dummy;
  439. if ( !glXQueryExtension( xengine->m_display, &dummy, &dummy ) ) {
  440. fprintf( stderr, "OpenGL is not supported!\n" );
  441. }
  442. m_renderContext = glXCreateNewContext( xengine->m_display, m_fbconfig, GLX_RGBA_TYPE, 0, True );
  443. if ( !m_renderContext ) {
  444. fprintf( stderr, "Failed to create a GL context.\n" );
  445. }
  446. if ( !glXMakeContextCurrent( xengine->m_display, m_glxWindow, m_glxWindow, m_renderContext ) ) {
  447. fprintf( stderr, "Failed to attach GL context to window!\n" );
  448. }
  449. GLenum err = glewInit();
  450. if ( GLEW_OK != err ) {
  451. /* Problem: glewInit failed, something is seriously wrong. */
  452. fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
  453. }
  454. // Get an image of the entire desktop for use in shaders.
  455. XImage* image = XGetImage( xengine->m_display, xengine->m_root, 0, 0, xengine->getWidth(), xengine->getHeight(), 0xffffffff, ZPixmap );
  456. glEnable(GL_TEXTURE_2D);
  457. glGenTextures(1, &m_desktop);
  458. glBindTexture(GL_TEXTURE_2D, m_desktop);
  459. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  460. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  461. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  462. glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, xengine->getWidth(), xengine->getHeight(), 0, GL_BGRA, GL_UNSIGNED_BYTE, (void*)(&(image->data[0])));
  463. XDestroyImage( image );
  464. glDisable(GL_TEXTURE_2D);
  465. m_framebuffer = new slop::Framebuffer( xengine->getWidth(), xengine->getHeight(), slop::Framebuffer::color, m_shader );
  466. m_framebuffer->bind();
  467. glEnable( GL_BLEND );
  468. glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
  469. glClearColor( 0, 0, 0, 0 );
  470. glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
  471. glXSwapBuffers( xengine->m_display, m_glxWindow );
  472. m_framebuffer->unbind();
  473. }
  474. void slop::GLSelectRectangle::setGeo( int sx, int sy, int ex, int ey ) {
  475. int x = std::min( sx, ex );
  476. int y = std::min( sy, ey );
  477. int w = std::max( sx, ex ) - x;
  478. int h = std::max( sy, ey ) - y;
  479. m_x = x;
  480. m_y = y;
  481. m_width = w;
  482. m_height = h;
  483. }
  484. void slop::GLSelectRectangle::update( double dt ) {
  485. m_time += dt;
  486. m_framebuffer->bind();
  487. glViewport( 0, 0, xengine->getWidth(), xengine->getHeight() );
  488. glClearColor( 0, 0, 0, 0 );
  489. glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
  490. glMatrixMode( GL_PROJECTION );
  491. glLoadIdentity();
  492. glOrtho( 0, xengine->getWidth(), xengine->getHeight(), 0, 1, -1 );
  493. glMatrixMode( GL_MODELVIEW );
  494. glLoadIdentity();
  495. if ( !m_themed ) {
  496. glColor4f( m_r, m_g, m_b, m_a );
  497. glRecti( m_x-m_border, m_y, m_x+m_width+m_border, m_y-m_border );
  498. glRecti( m_x-m_border, m_y+m_height, m_x+m_width+m_border, m_y+m_height+m_border );
  499. glRecti( m_x-m_border, m_y, m_x, m_y+m_height );
  500. glRecti( m_x+m_width, m_y, m_x+m_width+m_border, m_y+m_height );
  501. } else {
  502. glColor4f( m_r, m_g, m_b, m_a );
  503. glEnable( GL_TEXTURE_2D );
  504. glBindTexture( GL_TEXTURE_2D, m_straightid );
  505. float something = (float)(m_border)/(float)m_straightheight;
  506. float txoffset = (((float)m_width+m_border)/(float)m_straightwidth)/something;
  507. float tyoffset = (((float)m_height+m_border)/(float)m_straightwidth)/something;
  508. //float ratio = ((float)m_straightwidth/(float)m_straightheight);
  509. glBegin( GL_QUADS );
  510. // straight top
  511. glTexCoord2f(0.0, 0.0); glVertex2f( m_x-m_border/2, m_y-m_border );
  512. glTexCoord2f(txoffset, 0.0); glVertex2f( m_x+m_width+m_border/2, m_y-m_border );
  513. glTexCoord2f(txoffset, 1.0); glVertex2f( m_x+m_width+m_border/2, m_y );
  514. glTexCoord2f(0.0, 1.0); glVertex2f( m_x-m_border/2, m_y );
  515. // straight bot
  516. glTexCoord2f(0.0, 0.0); glVertex2f( m_x-m_border/2, m_y+m_height );
  517. glTexCoord2f(txoffset, 0.0); glVertex2f( m_x+m_width+m_border/2, m_y+m_height );
  518. glTexCoord2f(txoffset, 1.0); glVertex2f( m_x+m_width+m_border/2, m_y+m_height+m_border );
  519. glTexCoord2f(0.0, 1.0); glVertex2f( m_x-m_border/2, m_y+m_height+m_border );
  520. // straight left
  521. glTexCoord2f(0.0, 1.0); glVertex2f( m_x-m_border, m_y-m_border/2 );
  522. glTexCoord2f(0.0, 0.0); glVertex2f( m_x, m_y-m_border/2 );
  523. glTexCoord2f(tyoffset, 0.0); glVertex2f( m_x, m_y+m_height+m_border/2 );
  524. glTexCoord2f(tyoffset, 1.0); glVertex2f( m_x-m_border, m_y+m_height+m_border/2 );
  525. // straight right
  526. glTexCoord2f(0.0, 1.0); glVertex2f( m_x+m_width, m_y-m_border/2 );
  527. glTexCoord2f(0.0, 0.0); glVertex2f( m_x+m_width+m_border, m_y-m_border/2 );
  528. glTexCoord2f(tyoffset, 0.0); glVertex2f( m_x+m_width+m_border, m_y+m_height+m_border/2 );
  529. glTexCoord2f(tyoffset, 1.0); glVertex2f( m_x+m_width, m_y+m_height+m_border/2 );
  530. glEnd();
  531. // top left corner
  532. glBindTexture( GL_TEXTURE_2D, m_cornerids[0] );
  533. glBegin( GL_QUADS );
  534. glTexCoord2f(0.0, 0.0); glVertex2f( m_x-m_border, m_y-m_border );
  535. glTexCoord2f(1.0, 0.0); glVertex2f( m_x, m_y-m_border );
  536. glTexCoord2f(1.0, 1.0); glVertex2f( m_x, m_y );
  537. glTexCoord2f(0.0, 1.0); glVertex2f( m_x-m_border, m_y );
  538. glEnd();
  539. // top right
  540. glBindTexture( GL_TEXTURE_2D, m_cornerids[1] );
  541. glBegin( GL_QUADS );
  542. glTexCoord2f(0.0, 0.0); glVertex2f( m_x+m_width, m_y-m_border );
  543. glTexCoord2f(1.0, 0.0); glVertex2f( m_x+m_width+m_border, m_y-m_border );
  544. glTexCoord2f(1.0, 1.0); glVertex2f( m_x+m_width+m_border, m_y );
  545. glTexCoord2f(0.0, 1.0); glVertex2f( m_x+m_width, m_y );
  546. glEnd();
  547. // bottom left
  548. glBindTexture( GL_TEXTURE_2D, m_cornerids[2] );
  549. glBegin( GL_QUADS );
  550. glTexCoord2f(0.0, 0.0); glVertex2f( m_x-m_border, m_y+m_height );
  551. glTexCoord2f(1.0, 0.0); glVertex2f( m_x, m_y+m_height );
  552. glTexCoord2f(1.0, 1.0); glVertex2f( m_x, m_y+m_height+m_border );
  553. glTexCoord2f(0.0, 1.0); glVertex2f( m_x-m_border, m_y+m_height+m_border );
  554. glEnd();
  555. // bottom right
  556. glBindTexture( GL_TEXTURE_2D, m_cornerids[2] );
  557. glBegin( GL_QUADS );
  558. glTexCoord2f(0.0, 0.0); glVertex2f( m_x+m_width, m_y+m_height );
  559. glTexCoord2f(1.0, 0.0); glVertex2f( m_x+m_width+m_border, m_y+m_height );
  560. glTexCoord2f(1.0, 1.0); glVertex2f( m_x+m_width+m_border, m_y+m_height+m_border );
  561. glTexCoord2f(0.0, 1.0); glVertex2f( m_x+m_width, m_y+m_height+m_border );
  562. glEnd();
  563. }
  564. m_framebuffer->unbind();
  565. glClearColor( 0, 0, 0, 0 );
  566. glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
  567. m_framebuffer->draw( (float) m_time, m_desktop );
  568. if ( m_glassEnabled ) {
  569. generateMagnifyingGlass();
  570. findOptimalGlassPosition();
  571. // Takes .1 second to reach the real position. Used for easing.
  572. m_realglassx -= float(m_realglassx - (float)m_glassx) * dt * 10;
  573. m_realglassy -= float(m_realglassy - (float)m_glassy) * dt * 10;
  574. // Black outline...
  575. glColor4f( 0, 0, 0, 1 );
  576. glBegin( GL_QUADS );
  577. glTexCoord2f(0.0, 1.0); glVertex3f( m_realglassx+m_offsetx-m_glassBorder, m_realglassy+(m_glassSize*m_glassPixels)+m_offseth+m_glassBorder, 0.0);
  578. glTexCoord2f(1.0, 1.0); glVertex3f( m_realglassx+(m_glassSize*m_glassPixels)+m_offsetw+m_glassBorder, m_realglassy+(m_glassSize*m_glassPixels)+m_offseth+1, 0.0);
  579. glTexCoord2f(1.0, 0.0); glVertex3f( m_realglassx+(m_glassSize*m_glassPixels)+m_offsetw+m_glassBorder, m_realglassy+m_offsety-m_glassBorder, 0.0);
  580. glTexCoord2f(0.0, 0.0); glVertex3f( m_realglassx+m_offsetx-m_glassBorder, m_realglassy+m_offsety-m_glassBorder, 0.0);
  581. glEnd();
  582. glEnable( GL_TEXTURE_2D );
  583. glBindTexture( GL_TEXTURE_2D, m_texid );
  584. glColor4f( 1, 1, 1, 1 );
  585. glBegin( GL_QUADS );
  586. glTexCoord2f(0.0, 1.0); glVertex3f( m_realglassx+m_offsetx, m_realglassy+(m_glassSize*m_glassPixels)+m_offseth, 0.0);
  587. glTexCoord2f(1.0, 1.0); glVertex3f( m_realglassx+(m_glassSize*m_glassPixels)+m_offsetw, m_realglassy+(m_glassSize*m_glassPixels)+m_offseth, 0.0);
  588. glTexCoord2f(1.0, 0.0); glVertex3f( m_realglassx+(m_glassSize*m_glassPixels)+m_offsetw, m_realglassy+m_offsety, 0.0);
  589. glTexCoord2f(0.0, 0.0); glVertex3f( m_realglassx+m_offsetx, m_realglassy+m_offsety, 0.0);
  590. glEnd();
  591. glDisable( GL_TEXTURE_2D );
  592. glLogicOp(GL_INVERT);
  593. glEnable(GL_COLOR_LOGIC_OP);
  594. glLineWidth( 2 );
  595. glColor4f( 0, 0, 0, 1 );
  596. glBegin( GL_LINES );
  597. float cx = m_realglassx+(m_glassSize*m_glassPixels)/2;
  598. float cy = m_realglassy+(m_glassSize*m_glassPixels)/2;
  599. glVertex3f( cx-5, cy, 0 );
  600. glVertex3f( cx+5, cy, 0 );
  601. glVertex3f( cx, cy-5, 0 );
  602. glVertex3f( cx, cy+5, 0 );
  603. glEnd();
  604. glLogicOp(GL_NOOP);
  605. glDisable(GL_COLOR_LOGIC_OP);
  606. }
  607. glXSwapBuffers( xengine->m_display, m_glxWindow );
  608. }