glselectrectangle.cpp 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  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. bool fx = xengine->m_mousex < m_x+m_width/2;
  209. bool fy = xengine->m_mousey < m_y+m_height/2;
  210. // Mouse behavior SUCKS
  211. if ( !fx && !fy ) {
  212. x += 1;
  213. y += 1;
  214. } else if ( fx && !fy ) {
  215. y += 1;
  216. } else if ( !fx && fy ) {
  217. x += 1;
  218. }
  219. int w = m_glassPixels;
  220. int h = m_glassPixels;
  221. constrainWithinMonitor( &x, &y, &w, &h );
  222. XImage* image = XGetImage( xengine->m_display, xengine->m_root, x, y, w, h, 0xffffffff, ZPixmap );
  223. glEnable(GL_TEXTURE_2D);
  224. glGenTextures(1, &m_texid);
  225. glBindTexture(GL_TEXTURE_2D, m_texid);
  226. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  227. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  228. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  229. glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, (void*)(&(image->data[0])));
  230. XDestroyImage( image );
  231. glDisable(GL_TEXTURE_2D);
  232. }
  233. void slop::GLSelectRectangle::setTheme( bool on, std::string name ) {
  234. if ( !on || name == "none" ) {
  235. return;
  236. }
  237. std::string root = resource->getRealPath( name );
  238. std::string tl = root + "/corner_tl.png";
  239. std::string bl = root + "/corner_bl.png";
  240. std::string tr = root + "/corner_tr.png";
  241. std::string br = root + "/corner_br.png";
  242. std::string straight = root + "/straight.png";
  243. // One of the textures didn't exist, so we cancel the theme.
  244. if (!resource->validatePath( tl ) ||
  245. !resource->validatePath( bl ) ||
  246. !resource->validatePath( tr ) ||
  247. !resource->validatePath( br ) ||
  248. !resource->validatePath( straight ) ) {
  249. fprintf( stderr, "One of the textures was missing in the theme... disabling.\n" );
  250. return;
  251. }
  252. // Otherwise we load each one :)
  253. loadImage( &(m_cornerids[0]), tl );
  254. loadImage( &(m_cornerids[1]), tr );
  255. loadImage( &(m_cornerids[2]), bl );
  256. loadImage( &(m_cornerids[3]), br );
  257. loadImage( &(m_straightid), straight );
  258. glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &m_straightwidth );
  259. glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &m_straightheight );
  260. m_themed = on;
  261. }
  262. unsigned int slop::GLSelectRectangle::loadImage( unsigned int* texture, std::string path ) {
  263. glActiveTexture(GL_TEXTURE0);
  264. glEnable(GL_TEXTURE_2D);
  265. glGenTextures( 1, texture );
  266. glBindTexture( GL_TEXTURE_2D, *texture );
  267. Imlib_Load_Error err;
  268. Imlib_Image image = imlib_load_image_with_error_return( path.c_str(), &err );
  269. if ( err != IMLIB_LOAD_ERROR_NONE ) {
  270. std::string message = "Failed to load image: ";
  271. message += path;
  272. message += "\n\t";
  273. switch( err ) {
  274. default: {
  275. message += "unknown error ";
  276. message += (int)err;
  277. message += "\n";
  278. break;
  279. }
  280. case IMLIB_LOAD_ERROR_OUT_OF_FILE_DESCRIPTORS:
  281. message += "out of file descriptors\n";
  282. break;
  283. case IMLIB_LOAD_ERROR_OUT_OF_MEMORY:
  284. message += "out of memory\n";
  285. break;
  286. case IMLIB_LOAD_ERROR_TOO_MANY_SYMBOLIC_LINKS:
  287. message += "path contains too many symbolic links\n";
  288. break;
  289. case IMLIB_LOAD_ERROR_PATH_POINTS_OUTSIDE_ADDRESS_SPACE:
  290. message += "path points outside address space\n";
  291. break;
  292. case IMLIB_LOAD_ERROR_PATH_COMPONENT_NOT_DIRECTORY:
  293. message += "path component is not a directory\n";
  294. break;
  295. case IMLIB_LOAD_ERROR_PATH_COMPONENT_NON_EXISTANT:
  296. message += "path component is non-existant (~ isn't expanded inside quotes!)\n";
  297. break;
  298. case IMLIB_LOAD_ERROR_PATH_TOO_LONG:
  299. message += "path is too long\n";
  300. break;
  301. case IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT:
  302. message += "no loader for file format (unsupported format)\n";
  303. break;
  304. case IMLIB_LOAD_ERROR_OUT_OF_DISK_SPACE: {
  305. message += "not enough disk space\n";
  306. break;
  307. }
  308. case IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST: {
  309. message += "file does not exist\n";
  310. break;
  311. }
  312. case IMLIB_LOAD_ERROR_FILE_IS_DIRECTORY: {
  313. message += "file is a directory\n";
  314. break;
  315. }
  316. case IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_WRITE:
  317. case IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_READ: {
  318. message += "permission denied\n";
  319. break;
  320. }
  321. }
  322. throw std::runtime_error( message.c_str() );
  323. return *texture;
  324. }
  325. imlib_context_set_image( image );
  326. DATA32* data = imlib_image_get_data_for_reading_only();
  327. glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, imlib_image_get_width(), imlib_image_get_height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, (void*)data );
  328. if ( GLEW_VERSION_3_0 ) {
  329. glHint( GL_GENERATE_MIPMAP_HINT, GL_NICEST );
  330. glGenerateMipmap( GL_TEXTURE_2D );
  331. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
  332. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR );
  333. } else {
  334. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  335. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  336. }
  337. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  338. imlib_free_image();
  339. glDisable(GL_TEXTURE_2D);
  340. return *texture;
  341. }
  342. slop::GLSelectRectangle::GLSelectRectangle( int sx, int sy, int ex, int ey, int border, bool highlight, float r, float g, float b, float a ) {
  343. m_x = std::min( sx, ex );
  344. m_y = std::min( sy, ey );
  345. m_width = std::max( sx, ex ) - m_x;
  346. m_height = std::max( sy, ey ) - m_y;
  347. m_r = r;
  348. m_g = g;
  349. m_b = b;
  350. m_a = a;
  351. m_border = border;
  352. m_window = None;
  353. m_highlight = highlight;
  354. m_glassPixels = 64;
  355. m_glassx = xengine->m_mousex;
  356. m_glassy = xengine->m_mousey;
  357. m_realglassx = xengine->m_mousex;
  358. m_realglassy = xengine->m_mousey;
  359. m_glassSize = 4;
  360. m_glassBorder = 1;
  361. m_monitors = xengine->getCRTCS();
  362. m_themed = false;
  363. m_shader = "simple";
  364. m_time = 0;
  365. // If we don't have a border, we don't exist, so just die.
  366. if ( m_border == 0 ) {
  367. return;
  368. }
  369. if ( m_highlight ) {
  370. m_border = 0;
  371. }
  372. static int visdata[] = {
  373. GLX_RENDER_TYPE, GLX_RGBA_BIT,
  374. GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
  375. GLX_DOUBLEBUFFER, True,
  376. GLX_RED_SIZE, 8,
  377. GLX_GREEN_SIZE, 8,
  378. GLX_BLUE_SIZE, 8,
  379. GLX_ALPHA_SIZE, 8,
  380. GLX_DEPTH_SIZE, 16,
  381. None
  382. };
  383. int numfbconfigs = 0;
  384. GLXFBConfig* fbconfigs = glXChooseFBConfig( xengine->m_display, DefaultScreen( xengine->m_display ), visdata, &numfbconfigs );
  385. m_fbconfig = 0;
  386. for ( int i=0; i<numfbconfigs; i++ ) {
  387. m_visual = (XVisualInfo*)glXGetVisualFromFBConfig( xengine->m_display, fbconfigs[i] );
  388. if ( !m_visual ) {
  389. continue;
  390. }
  391. m_pictFormat = XRenderFindVisualFormat( xengine->m_display, m_visual->visual );
  392. if ( !m_pictFormat ) {
  393. continue;
  394. }
  395. m_fbconfig = fbconfigs[i];
  396. if ( m_pictFormat->direct.alphaMask > 0 ) {
  397. break;
  398. }
  399. }
  400. if ( !m_fbconfig ) {
  401. fprintf( stderr, "Couldn't find a matching FB config for a transparent OpenGL window!\n");
  402. }
  403. m_cmap = XCreateColormap( xengine->m_display, xengine->m_root, m_visual->visual, AllocNone );
  404. XSetWindowAttributes attributes;
  405. attributes.colormap = m_cmap;
  406. attributes.background_pixmap = None;
  407. attributes.border_pixmap = None;
  408. attributes.border_pixel = 0;
  409. // Disable window decorations.
  410. attributes.override_redirect = True;
  411. // Make sure we know when we've been successfully destroyed later!
  412. attributes.event_mask = StructureNotifyMask;
  413. unsigned long valueMask = CWOverrideRedirect | CWEventMask | CWBackPixmap | CWColormap | CWBorderPixel;
  414. // Create the window
  415. m_window = XCreateWindow( xengine->m_display, xengine->m_root, 0, 0, xengine->getWidth(), xengine->getHeight(),
  416. 0, m_visual->depth, InputOutput,
  417. m_visual->visual, valueMask, &attributes );
  418. if ( !m_window ) {
  419. fprintf( stderr, "Couldn't create a GL window!\n");
  420. }
  421. m_glxWindow = m_window;
  422. static char title[] = "OpenGL Slop";
  423. XWMHints* startup_state = XAllocWMHints();
  424. startup_state->initial_state = NormalState;
  425. startup_state->flags = StateHint;
  426. XTextProperty textprop;
  427. textprop.value = (unsigned char*)title;
  428. textprop.encoding = XA_STRING;
  429. textprop.format = 8;
  430. textprop.nitems = strlen( title );
  431. XSizeHints sizehints;
  432. sizehints.x = 0;
  433. sizehints.y = 0;
  434. sizehints.width = xengine->getWidth();
  435. sizehints.height = xengine->getHeight();
  436. sizehints.flags = USPosition | USSize;
  437. XClassHint classhints;
  438. char name[] = "slop";
  439. classhints.res_name = name;
  440. classhints.res_class = name;
  441. XSetClassHint( xengine->m_display, m_window, &classhints );
  442. XSetWMProperties( xengine->m_display, m_window, &textprop, &textprop, NULL, 0, &sizehints, startup_state, NULL );
  443. XFree( startup_state );
  444. // Make it so all input falls through
  445. XRectangle rect;
  446. rect.x = rect.y = rect.width = rect.height = 0;
  447. XShapeCombineRectangles( xengine->m_display, m_window, ShapeInput, 0, 0, &rect, 1, ShapeSet, 0);
  448. XMapWindow( xengine->m_display, m_window );
  449. int dummy;
  450. if ( !glXQueryExtension( xengine->m_display, &dummy, &dummy ) ) {
  451. fprintf( stderr, "OpenGL is not supported!\n" );
  452. }
  453. m_renderContext = glXCreateNewContext( xengine->m_display, m_fbconfig, GLX_RGBA_TYPE, 0, True );
  454. if ( !m_renderContext ) {
  455. fprintf( stderr, "Failed to create a GL context.\n" );
  456. }
  457. if ( !glXMakeContextCurrent( xengine->m_display, m_glxWindow, m_glxWindow, m_renderContext ) ) {
  458. fprintf( stderr, "Failed to attach GL context to window!\n" );
  459. }
  460. GLenum err = glewInit();
  461. if ( GLEW_OK != err ) {
  462. /* Problem: glewInit failed, something is seriously wrong. */
  463. fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
  464. }
  465. // Get an image of the entire desktop for use in shaders.
  466. XImage* image = XGetImage( xengine->m_display, xengine->m_root, 0, 0, xengine->getWidth(), xengine->getHeight(), 0xffffffff, ZPixmap );
  467. glEnable(GL_TEXTURE_2D);
  468. glGenTextures(1, &m_desktop);
  469. glBindTexture(GL_TEXTURE_2D, m_desktop);
  470. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  471. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  472. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  473. glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, xengine->getWidth(), xengine->getHeight(), 0, GL_BGRA, GL_UNSIGNED_BYTE, (void*)(&(image->data[0])));
  474. XDestroyImage( image );
  475. glDisable(GL_TEXTURE_2D);
  476. m_framebuffer = new slop::Framebuffer( xengine->getWidth(), xengine->getHeight(), slop::Framebuffer::color, m_shader );
  477. m_framebuffer->bind();
  478. glEnable( GL_BLEND );
  479. glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
  480. glClearColor( 0, 0, 0, 0 );
  481. glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
  482. glXSwapBuffers( xengine->m_display, m_glxWindow );
  483. m_framebuffer->unbind();
  484. }
  485. void slop::GLSelectRectangle::setGeo( int sx, int sy, int ex, int ey ) {
  486. int x = std::min( sx, ex );
  487. int y = std::min( sy, ey );
  488. int w = std::max( sx, ex ) - x;
  489. int h = std::max( sy, ey ) - y;
  490. m_x = x;
  491. m_y = y;
  492. m_width = w;
  493. m_height = h;
  494. }
  495. void slop::GLSelectRectangle::update( double dt ) {
  496. m_time += dt;
  497. m_framebuffer->bind();
  498. glViewport( 0, 0, xengine->getWidth(), xengine->getHeight() );
  499. glClearColor( 0, 0, 0, 0 );
  500. glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
  501. glMatrixMode( GL_PROJECTION );
  502. glLoadIdentity();
  503. glOrtho( 0, xengine->getWidth(), xengine->getHeight(), 0, 1, -1 );
  504. glMatrixMode( GL_MODELVIEW );
  505. glLoadIdentity();
  506. if ( !m_themed ) {
  507. glColor4f( m_r, m_g, m_b, m_a );
  508. if ( m_highlight ) {
  509. glRecti( m_x-m_border, m_y+m_height+m_border, m_x+m_width+m_border, m_y-m_border );
  510. } else {
  511. glRecti( m_x-m_border, m_y, m_x+m_width+m_border, m_y-m_border );
  512. glRecti( m_x-m_border, m_y+m_height, m_x+m_width+m_border, m_y+m_height+m_border );
  513. glRecti( m_x-m_border, m_y, m_x, m_y+m_height );
  514. glRecti( m_x+m_width, m_y, m_x+m_width+m_border, m_y+m_height );
  515. }
  516. } else {
  517. glColor4f( m_r, m_g, m_b, m_a );
  518. glEnable( GL_TEXTURE_2D );
  519. if ( !m_highlight ) {
  520. glBindTexture( GL_TEXTURE_2D, m_straightid );
  521. float something = (float)(m_border)/(float)m_straightheight;
  522. float txoffset = (((float)m_width+m_border)/(float)m_straightwidth)/something;
  523. float tyoffset = (((float)m_height+m_border)/(float)m_straightwidth)/something;
  524. //float ratio = ((float)m_straightwidth/(float)m_straightheight);
  525. glBegin( GL_QUADS );
  526. // straight top
  527. glTexCoord2f(0.0, 0.0); glVertex2f( m_x-m_border/2, m_y-m_border );
  528. glTexCoord2f(txoffset, 0.0); glVertex2f( m_x+m_width+m_border/2, m_y-m_border );
  529. glTexCoord2f(txoffset, 1.0); glVertex2f( m_x+m_width+m_border/2, m_y );
  530. glTexCoord2f(0.0, 1.0); glVertex2f( m_x-m_border/2, m_y );
  531. // straight bot
  532. glTexCoord2f(0.0, 0.0); glVertex2f( m_x-m_border/2, m_y+m_height );
  533. glTexCoord2f(txoffset, 0.0); glVertex2f( m_x+m_width+m_border/2, m_y+m_height );
  534. glTexCoord2f(txoffset, 1.0); glVertex2f( m_x+m_width+m_border/2, m_y+m_height+m_border );
  535. glTexCoord2f(0.0, 1.0); glVertex2f( m_x-m_border/2, m_y+m_height+m_border );
  536. // straight left
  537. glTexCoord2f(0.0, 1.0); glVertex2f( m_x-m_border, m_y-m_border/2 );
  538. glTexCoord2f(0.0, 0.0); glVertex2f( m_x, m_y-m_border/2 );
  539. glTexCoord2f(tyoffset, 0.0); glVertex2f( m_x, m_y+m_height+m_border/2 );
  540. glTexCoord2f(tyoffset, 1.0); glVertex2f( m_x-m_border, m_y+m_height+m_border/2 );
  541. // straight right
  542. glTexCoord2f(0.0, 1.0); glVertex2f( m_x+m_width, m_y-m_border/2 );
  543. glTexCoord2f(0.0, 0.0); glVertex2f( m_x+m_width+m_border, m_y-m_border/2 );
  544. glTexCoord2f(tyoffset, 0.0); glVertex2f( m_x+m_width+m_border, m_y+m_height+m_border/2 );
  545. glTexCoord2f(tyoffset, 1.0); glVertex2f( m_x+m_width, m_y+m_height+m_border/2 );
  546. glEnd();
  547. // top left corner
  548. glBindTexture( GL_TEXTURE_2D, m_cornerids[0] );
  549. glBegin( GL_QUADS );
  550. glTexCoord2f(0.0, 0.0); glVertex2f( m_x-m_border, m_y-m_border );
  551. glTexCoord2f(1.0, 0.0); glVertex2f( m_x, m_y-m_border );
  552. glTexCoord2f(1.0, 1.0); glVertex2f( m_x, m_y );
  553. glTexCoord2f(0.0, 1.0); glVertex2f( m_x-m_border, m_y );
  554. glEnd();
  555. // top right
  556. glBindTexture( GL_TEXTURE_2D, m_cornerids[1] );
  557. glBegin( GL_QUADS );
  558. glTexCoord2f(0.0, 0.0); glVertex2f( m_x+m_width, m_y-m_border );
  559. glTexCoord2f(1.0, 0.0); glVertex2f( m_x+m_width+m_border, m_y-m_border );
  560. glTexCoord2f(1.0, 1.0); glVertex2f( m_x+m_width+m_border, m_y );
  561. glTexCoord2f(0.0, 1.0); glVertex2f( m_x+m_width, m_y );
  562. glEnd();
  563. // bottom left
  564. glBindTexture( GL_TEXTURE_2D, m_cornerids[2] );
  565. glBegin( GL_QUADS );
  566. glTexCoord2f(0.0, 0.0); glVertex2f( m_x-m_border, m_y+m_height );
  567. glTexCoord2f(1.0, 0.0); glVertex2f( m_x, m_y+m_height );
  568. glTexCoord2f(1.0, 1.0); glVertex2f( m_x, m_y+m_height+m_border );
  569. glTexCoord2f(0.0, 1.0); glVertex2f( m_x-m_border, m_y+m_height+m_border );
  570. glEnd();
  571. // bottom right
  572. glBindTexture( GL_TEXTURE_2D, m_cornerids[2] );
  573. glBegin( GL_QUADS );
  574. glTexCoord2f(0.0, 0.0); glVertex2f( m_x+m_width, m_y+m_height );
  575. glTexCoord2f(1.0, 0.0); glVertex2f( m_x+m_width+m_border, m_y+m_height );
  576. glTexCoord2f(1.0, 1.0); glVertex2f( m_x+m_width+m_border, m_y+m_height+m_border );
  577. glTexCoord2f(0.0, 1.0); glVertex2f( m_x+m_width, m_y+m_height+m_border );
  578. glEnd();
  579. } else {
  580. glBindTexture( GL_TEXTURE_2D, m_cornerids[0] );
  581. glBegin( GL_QUADS );
  582. // straight top
  583. glTexCoord2f(0.0, 1.0); glVertex2f( m_x-m_border, m_y+m_border+m_height );
  584. glTexCoord2f(1.0, 1.0); glVertex2f( m_x+m_width+m_border, m_y+m_border+m_height );
  585. glTexCoord2f(1.0, 0.0); glVertex2f( m_x+m_width+m_border, m_y-m_border );
  586. glTexCoord2f(0.0, 0.0); glVertex2f( m_x-m_border, m_y-m_border );
  587. glEnd();
  588. }
  589. glDisable( GL_TEXTURE_2D );
  590. }
  591. m_framebuffer->unbind();
  592. glClearColor( 0, 0, 0, 0 );
  593. glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
  594. m_framebuffer->draw( (float) m_time, m_desktop );
  595. if ( m_glassEnabled ) {
  596. generateMagnifyingGlass();
  597. findOptimalGlassPosition();
  598. // Takes .1 second to reach the real position. Used for easing.
  599. m_realglassx -= float(m_realglassx - (float)m_glassx) * dt * 10;
  600. m_realglassy -= float(m_realglassy - (float)m_glassy) * dt * 10;
  601. // Black outline...
  602. glColor4f( 0, 0, 0, 1 );
  603. glBegin( GL_QUADS );
  604. glTexCoord2f(0.0, 1.0); glVertex3f( m_realglassx+m_offsetx-m_glassBorder, m_realglassy+(m_glassSize*m_glassPixels)+m_offseth+m_glassBorder, 0.0);
  605. 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);
  606. glTexCoord2f(1.0, 0.0); glVertex3f( m_realglassx+(m_glassSize*m_glassPixels)+m_offsetw+m_glassBorder, m_realglassy+m_offsety-m_glassBorder, 0.0);
  607. glTexCoord2f(0.0, 0.0); glVertex3f( m_realglassx+m_offsetx-m_glassBorder, m_realglassy+m_offsety-m_glassBorder, 0.0);
  608. glEnd();
  609. glEnable( GL_TEXTURE_2D );
  610. glBindTexture( GL_TEXTURE_2D, m_texid );
  611. glColor4f( 1, 1, 1, 1 );
  612. glBegin( GL_QUADS );
  613. glTexCoord2f(0.0, 1.0); glVertex3f( m_realglassx+m_offsetx, m_realglassy+(m_glassSize*m_glassPixels)+m_offseth, 0.0);
  614. glTexCoord2f(1.0, 1.0); glVertex3f( m_realglassx+(m_glassSize*m_glassPixels)+m_offsetw, m_realglassy+(m_glassSize*m_glassPixels)+m_offseth, 0.0);
  615. glTexCoord2f(1.0, 0.0); glVertex3f( m_realglassx+(m_glassSize*m_glassPixels)+m_offsetw, m_realglassy+m_offsety, 0.0);
  616. glTexCoord2f(0.0, 0.0); glVertex3f( m_realglassx+m_offsetx, m_realglassy+m_offsety, 0.0);
  617. glEnd();
  618. glDisable( GL_TEXTURE_2D );
  619. glLogicOp(GL_INVERT);
  620. glEnable(GL_COLOR_LOGIC_OP);
  621. glLineWidth( 2 );
  622. glColor4f( 0, 0, 0, 1 );
  623. glBegin( GL_LINES );
  624. float cx = m_realglassx+(m_glassSize*m_glassPixels)/2;
  625. float cy = m_realglassy+(m_glassSize*m_glassPixels)/2;
  626. glVertex3f( cx-5, cy, 0 );
  627. glVertex3f( cx+5, cy, 0 );
  628. glVertex3f( cx, cy-5, 0 );
  629. glVertex3f( cx, cy+5, 0 );
  630. glEnd();
  631. glLogicOp(GL_NOOP);
  632. glDisable(GL_COLOR_LOGIC_OP);
  633. }
  634. glXSwapBuffers( xengine->m_display, m_glxWindow );
  635. }