1 module src.dlangui.platforms.x11.x11app; 2 3 version(linux) { 4 5 import std.string; 6 import std.c.linux.X11.xcb.xcb; 7 import std.c.linux.X11.xcb.shm; 8 import std.c.linux.X11.xcb.xproto; 9 import std.c.linux.X11.xcb.image; 10 import std.c.linux.X11.keysymdef; 11 import std.c.linux.linux; 12 import std.c.stdlib; 13 import std.conv; 14 15 import dlangui.core.logger; 16 import dlangui.core.events; 17 import dlangui.graphics.drawbuf; 18 import dlangui.graphics.fonts; 19 import dlangui.graphics.ftfonts; 20 import dlangui.graphics.resources; 21 import dlangui.widgets.styles; 22 import dlangui.platforms.common.platform; 23 24 version (USE_OPENGL) { 25 import dlangui.graphics.glsupport; 26 } 27 28 import derelict.opengl3.gl3; 29 import derelict.opengl3.glx; 30 31 // pragma(lib, "xcb"); 32 // pragma(lib, "xcb-shm"); 33 // pragma(lib, "xcb-image"); 34 // pragma(lib, "X11-xcb"); 35 // pragma(lib, "X11"); 36 // pragma(lib, "dl"); 37 38 extern (System) 39 xcb_connection_t *XGetXCBConnection(std.c.linux.X11.Xlib.Display *dpy); 40 enum XEventQueueOwner { XlibOwnsEventQueue = 0, XCBOwnsEventQueue }; 41 extern (System) 42 void XSetEventQueueOwner(std.c.linux.X11.Xlib.Display *dpy, XEventQueueOwner owner); 43 44 class XCBWindow : Window { 45 xcb_window_t _w; 46 xcb_gcontext_t _g; 47 xcb_image_t * _image; 48 xcb_shm_segment_info_t shminfo; 49 /* Create GLX Window */ 50 GLXDrawable _drawable; 51 GLXWindow _glxwindow; 52 53 private GLXContext _context; 54 private int _visualID = 0; 55 private xcb_colormap_t _colormap; 56 private GLXFBConfig _fb_config; 57 58 @property xcb_window_t windowId() { return _w; } 59 this(string caption, Window parent) { 60 _caption = caption; 61 Log.d("Creating XCB window"); 62 create(); 63 } 64 ~this() { 65 Log.d("Destroying window"); 66 } 67 68 bool create() { 69 import std.c.linux.X11.Xlib; 70 71 uint mask; 72 uint values[3]; 73 74 // disable opengl for testing 75 _enableOpengl = false; 76 /* create black graphics context */ 77 if (true || !_enableOpengl) { 78 _g = xcb_generate_id(_xcbconnection); 79 _w = _xcbscreen.root; 80 mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES; 81 values[0] = _xcbscreen.black_pixel; 82 values[1] = 0; 83 xcb_create_gc(_xcbconnection, _g, _w, mask, &values[0]); 84 } 85 86 ubyte depth = _xcbscreen.root_depth; 87 /* create window */ 88 _w = xcb_generate_id(_xcbconnection); 89 90 Log.d("window=", _w, " gc=", _g); 91 92 if (_enableOpengl) { 93 int visual_attribs[] = [ 94 GLX_RENDER_TYPE, GLX_RGBA_BIT, 95 GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, 96 GLX_DOUBLEBUFFER, 1, 97 GLX_RED_SIZE, 8, 98 GLX_GREEN_SIZE, 8, 99 GLX_BLUE_SIZE, 8, 100 std.c.linux.X11.Xlib.None]; 101 102 Log.d("Getting framebuffer config"); 103 int fbcount; 104 GLXFBConfig *fbc = glXChooseFBConfig(_display, DefaultScreen(_display), visual_attribs.ptr, &fbcount); 105 if (!fbc) 106 { 107 Log.d("Failed to retrieve a framebuffer config"); 108 //return 1; 109 } 110 111 Log.d("Getting XVisualInfo"); 112 _fb_config = fbc[0]; 113 auto vi = glXGetVisualFromFBConfig(_display, _fb_config); 114 115 //auto vi = glXChooseVisual(_display, std.c.linux.X11.Xlib.DefaultScreen(_display), attributeList.ptr); 116 _visualID = vi.visualid; 117 //swa.colormap = std.c.linux.X11.Xlib.XCreateColormap(_display, std.c.linux.X11.Xlib.RootWindow(_display, vi.screen), vi.visual, 0); // AllocNone 118 119 Log.d("Creating color map"); 120 _colormap = xcb_generate_id(_xcbconnection); 121 /* Create colormap */ 122 xcb_create_colormap( 123 _xcbconnection, 124 XCB_COLORMAP_ALLOC_NONE, 125 _colormap, 126 _xcbscreen.root, 127 _visualID 128 ); 129 depth = cast(ubyte)vi.depth; 130 } 131 //mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; 132 //values[0] = _xcbscreen.white_pixel; 133 134 int visualId; 135 uint eventmask = 136 XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE 137 | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_BUTTON_MOTION 138 | XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW 139 | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE 140 | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_VISIBILITY_CHANGE; 141 if (_enableOpengl) { 142 mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP; 143 values[0] = _xcbscreen.white_pixel; 144 values[1] = eventmask; 145 values[2] = _colormap; 146 //visualId = _xcbscreen.root_visual; 147 visualId = _visualID; 148 } else { 149 mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; 150 values[0] = _xcbscreen.white_pixel; 151 values[1] = eventmask; 152 visualId = _xcbscreen.root_visual; 153 } 154 Log.d("xcb_create_window - window=", _w, " VisualID=", _visualID); 155 auto res = xcb_create_window(_xcbconnection, 156 depth, //_xcbscreen.root_depth, 157 //XCB_COPY_FROM_PARENT,//_xcbscreen.root_depth, 158 _w, 159 _xcbscreen.root, 160 50, 50, 500, 400, 161 1, 162 XCB_WINDOW_CLASS_INPUT_OUTPUT, 163 visualId, 164 mask, 165 &values[0]); 166 xcb_flush(_xcbconnection); 167 windowCaption = _caption; 168 return true; 169 } 170 171 private int _imageDx; 172 private int _imageDy; 173 void createImage() { 174 if (_image) { 175 if (_imageDx == _imageDx && _imageDy == _dy) 176 return; // already have image of proper size 177 Log.i("CRXCBScreen::createImage - destroying existing image"); 178 xcb_image_destroy(_image); 179 _image = null; 180 } 181 _imageDx = _dx; 182 _imageDy = _dy; 183 Log.i("CRXCBScreen::createImage ", _dx, "x", _dy); 184 xcb_shm_query_version_reply_t * rep_shm; 185 rep_shm = xcb_shm_query_version_reply (_xcbconnection, 186 xcb_shm_query_version(_xcbconnection), 187 null); 188 if(rep_shm) { 189 xcb_image_format_t format; 190 int shmctl_status; 191 192 if (rep_shm.shared_pixmaps && 193 (rep_shm.major_version > 1 || rep_shm.minor_version > 0)) 194 format = cast(xcb_image_format_t)rep_shm.pixmap_format; 195 else 196 format = XCB_IMAGE_FORMAT_Z_PIXMAP; 197 198 _image = xcb_image_create_native (_xcbconnection, cast(short)_dx, cast(short)_dy, 199 format, _xcbscreendepth, null, ~0, null); 200 //format, depth, NULL, ~0, NULL); 201 //format, depth, NULL, ~0, NULL); 202 assert(_image); 203 204 shminfo.shmid = shmget (IPC_PRIVATE, 205 _image.stride*_image.height, 206 IPC_CREAT | octal!777); 207 assert(shminfo.shmid != cast(uint)-1); 208 shminfo.shmaddr = cast(ubyte*)shmat (shminfo.shmid, null, 0); 209 assert(shminfo.shmaddr); 210 _image.data = shminfo.shmaddr; 211 Log.d("Created image depth=", _image.depth, " bpp=", _image.bpp, " stride=", _image.stride ); 212 213 shminfo.shmseg = xcb_generate_id (_xcbconnection); 214 xcb_shm_attach (_xcbconnection, shminfo.shmseg, 215 shminfo.shmid, 0); 216 shmctl_status = shmctl(shminfo.shmid, IPC_RMID, null); 217 assert(shmctl_status != -1); 218 free(rep_shm); 219 } else { 220 Log.e("Can't get shms"); 221 } 222 } 223 224 void draw(ColorDrawBuf buf) { 225 int i; 226 i = xcb_image_shm_get(_xcbconnection, _w, 227 _image, shminfo, 228 0, 0, 229 XCB_ALL_PLANES); 230 if (!i) { 231 Log.e("cannot get shm image"); 232 return; 233 } 234 Rect rc; 235 rc.right = buf.width; 236 rc.bottom = buf.height; 237 switch ( _image.bpp ) { 238 case 32: 239 { 240 for (int y = rc.top; y<rc.bottom; y++) { 241 uint * src = buf.scanLine(y); 242 uint * dst = cast(uint *)(_image.data + _image.stride * y); 243 for ( int x = 0; x < rc.right; x++ ) { 244 uint data = src[x]; 245 dst[x] = data; 246 } 247 } 248 } 249 break; 250 default: 251 Log.d("image bit depth not supported: ", _image.bpp); 252 break; 253 } 254 xcb_image_shm_put(_xcbconnection, _w, _g, 255 _image, shminfo, 256 cast(short)rc.left, cast(short)rc.top, cast(short)rc.left, cast(short)rc.top, cast(ushort)rc.width(), cast(ushort)rc.height(), 0); 257 xcb_flush(_xcbconnection); 258 } 259 260 bool _derelictgl3Reloaded; 261 override void show() { 262 Log.d("XCBWindow.show()"); 263 /* map (show) the window */ 264 xcb_map_window(_xcbconnection, _w); 265 xcb_flush(_xcbconnection); 266 //_enableOpengl = false; // test 267 if (_enableOpengl && !_glxwindow) { 268 Log.d("Calling glXCreateWindow display=", _display, " fbconfig=", _fb_config, " window=", _w); 269 _glxwindow = glXCreateWindow( 270 _display, 271 _fb_config, 272 _w, 273 null); 274 if (!_glxwindow) { 275 Log.e("Failed to create GLX window: disabling OpenGL"); 276 _enableOpengl = false; 277 } else { 278 import derelict.opengl3.glxext; 279 import std.c.linux.X11.Xlib; 280 281 _drawable = _glxwindow; 282 283 if (!_derelictgl3Reloaded) { 284 285 int count; 286 glGetIntegerv( GL_NUM_EXTENSIONS, &count ); 287 Log.d("Number of extensions: ", count); 288 for( int i=0; i<count; ++i ) { 289 auto e = glGetStringi( GL_EXTENSIONS, i ); 290 Log.d("Extension: ", fromStringz(e)); 291 } 292 293 294 Log.e("Reloading DerelictGL3"); 295 _derelictgl3Reloaded = true; 296 _context = glXCreateNewContext(_display, _fb_config, GLX_RGBA_TYPE, null, true); 297 if (_context is null) { 298 Log.e("Cannot create temporary context"); 299 } 300 //glXMakeContextCurrent(_display, _drawable, _drawable, _context); 301 glXMakeContextCurrent(_display, _glxwindow, _glxwindow, _context); 302 //glXMakeCurrent(_display, _w, _context); 303 DerelictGL3.reload(); 304 Log.e("Reloaded DerelictGL3 - removing temporary context"); 305 glXMakeCurrent(_display, 0, null); 306 Log.e("Destroying context"); 307 glXDestroyContext(_display, _context); 308 Log.e("DerelictGL3 initialized"); 309 _context = null; 310 } 311 312 313 // Get the default screen's GLX extension list 314 const char *glxExts = glXQueryExtensionsString( _display, 315 DefaultScreen( _display ) ); 316 Log.d("GLX Extensions: ", fromStringz(glxExts)); 317 const char * exts = glGetString( GL_EXTENSIONS ); 318 Log.d("Extensions: ", fromStringz(exts)); 319 320 321 Log.d("GLX_ARB_get_proc_address=", GLX_ARB_get_proc_address); 322 Log.d("GLX_ARB_create_context=", GLX_ARB_create_context); 323 324 //da_glXCreateContextAttribsARB glXCreateContextAttribsARB; 325 //Log.d("getting address of glXCreateContextAttribsARB"); 326 //glXCreateContextAttribsARB = cast(da_glXCreateContextAttribsARB) 327 // glXGetProcAddressARB( cast(const GLubyte *)("glXCreateContextAttribsARB".toStringz)); 328 329 //Log.d("glXCreateContextAttribsARB = ", &glXCreateContextAttribsARB); 330 331 Log.d("Creating context"); 332 //_context = glXCreateNewContext(_display, _fb_config, GLX_RGBA_TYPE, null, true); 333 if (!GLX_ARB_create_context) { 334 Log.e("glXCreateContextAttribsARB function is not found"); 335 _context = glXCreateNewContext(_display, _fb_config, GLX_RGBA_TYPE, null, true); 336 } else { 337 int context_attribs[] = 338 [ 339 GLX_CONTEXT_MAJOR_VERSION_ARB, 3, 340 GLX_CONTEXT_MINOR_VERSION_ARB, 0, 341 None 342 ]; 343 Log.e("calling glXCreateContextAttribsARB"); 344 _context = glXCreateContextAttribsARB(_display, _fb_config, null, true, context_attribs.ptr); 345 } 346 Log.d("Created context: ", _context); 347 348 /* Create OpenGL context */ 349 //auto context = glXCreateNewContext(_display, _fb_config, GLX_RGBA_TYPE, null, true); 350 if (!_context) { 351 _enableOpengl = false; 352 Log.e("Failed to create OpenGL context"); 353 } else { 354 355 } 356 357 /* make OpenGL context current */ 358 if(!glXMakeContextCurrent(_display, _drawable, _drawable, _context) || !initShaders()) { 359 Log.e("Failed to make GL context current"); 360 _enableOpengl = false; 361 glXDestroyContext(_display, _context); 362 _context = null; 363 } else { 364 365 } 366 } 367 } 368 } 369 string _caption; 370 override @property string windowCaption() { 371 return _caption; 372 } 373 override @property void windowCaption(string caption) { 374 _caption = caption; 375 const char * title = _caption.toStringz; 376 xcb_change_property (_xcbconnection, 377 XCB_PROP_MODE_REPLACE, 378 _w, 379 XCB_ATOM_WM_NAME, 380 XCB_ATOM_STRING, 381 8, 382 cast(uint)_caption.length, 383 cast(void*)title); 384 } 385 386 void redraw() { 387 388 if (_enableOpengl) { 389 import std.c.linux.X11.Xlib; 390 Log.d("Drawing using opengl ", _dx, "x", _dy, " context=", _context); 391 //glXMakeContextCurrent(_display, _drawable, _drawable, _context); 392 glXMakeContextCurrent(_display, _glxwindow, _glxwindow, _context); 393 glEnable(GL_BLEND); 394 glDisable(GL_CULL_FACE); 395 glDisable(GL_DEPTH_TEST); 396 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 397 glViewport(0, 0, _dx, _dy); 398 Log.d("glClearColor"); 399 glClearColor(0.2f, 0.4f, 0.9f, 1.0f); 400 Log.d("glClear"); 401 glClear(GL_COLOR_BUFFER_BIT); 402 403 import dlangui.graphics.gldrawbuf; 404 GLDrawBuf buf = new GLDrawBuf(_dx, _dy); 405 buf.beforeDrawing(); 406 onDraw(buf); 407 buf.fillRect(Rect(0, 0, 100, 100), 0x805010); 408 buf.afterDrawing(); 409 destroy(buf); 410 Log.d("Calling glx swap buffers for drawable ", _drawable); 411 glXSwapBuffers(_display, _drawable); 412 //glXMakeContextCurrent(_display, _drawable, _drawable, null); 413 xcb_flush(_xcbconnection); 414 glXMakeContextCurrent (_display, None, None, null); 415 glXWaitGL(); 416 } else { 417 if (!_drawbuf) 418 _drawbuf = new ColorDrawBuf(_dx, _dy); 419 _drawbuf.resize(_dx, _dy); 420 _drawbuf.fill(_backgroundColor); 421 //Log.d("calling createImage"); 422 createImage(); 423 //Log.d("done createImage"); 424 onDraw(_drawbuf); 425 draw(_drawbuf); 426 /* 427 xcb_rectangle_t r = { 20, 20, 60, 60 }; 428 xcb_poly_fill_rectangle(_xcbconnection, _w, _g, 1, &r); 429 r = xcb_rectangle_t(cast(short)(_dx - 20 - 60), cast(short)(_dy - 20 - 60), 60, 60); 430 xcb_poly_fill_rectangle(_xcbconnection, _w, _g, 1, &r); 431 */ 432 xcb_flush(_xcbconnection); 433 } 434 } 435 436 ColorDrawBuf _drawbuf; 437 bool _exposeSent; 438 void processExpose(xcb_expose_event_t * event) { 439 redraw(); 440 _exposeSent = false; 441 } 442 443 /// request window redraw 444 override void invalidate() { 445 if (_exposeSent) 446 return; 447 _exposeSent = true; 448 xcb_expose_event_t * event = cast(xcb_expose_event_t*)std.c.stdlib.malloc(xcb_expose_event_t.sizeof); 449 event.response_type = XCB_EXPOSE; /* The type of the event, here it is XCB_EXPOSE */ 450 event.sequence = 0; 451 event.window = _w; /* The Id of the window that receives the event (in case */ 452 /* our application registered for events on several windows */ 453 event.x = 0; /* The x coordinate of the top-left part of the window that needs to be redrawn */ 454 event.y = 0; /* The y coordinate of the top-left part of the window that needs to be redrawn */ 455 event.width = cast(ushort)_dx; /* The width of the part of the window that needs to be redrawn */ 456 event.height = cast(ushort)_dy; /* The height of the part of the window that needs to be redrawn */ 457 event.count = 1; 458 459 xcb_void_cookie_t res = xcb_send_event(_xcbconnection, false, _w, XCB_EVENT_MASK_EXPOSURE, cast(char *)event); 460 xcb_flush(_xcbconnection); 461 } 462 463 protected ButtonDetails _lbutton; 464 protected ButtonDetails _mbutton; 465 protected ButtonDetails _rbutton; 466 void processMouseEvent(MouseAction action, ubyte detail, ushort state, short x, short y) { 467 MouseButton button = MouseButton.None; 468 short wheelDelta = 0; 469 ButtonDetails * pbuttonDetails = null; 470 ushort flags = 0; 471 if (state & XCB_BUTTON_MASK_1) 472 flags |= MouseFlag.LButton; 473 if (state & XCB_BUTTON_MASK_2) 474 flags |= MouseFlag.MButton; 475 if (state & XCB_BUTTON_MASK_3) 476 flags |= MouseFlag.RButton; 477 if (state & XCB_MOD_MASK_SHIFT) 478 flags |= MouseFlag.Shift; 479 if (state & XCB_MOD_MASK_CONTROL) 480 flags |= MouseFlag.Control; 481 if (state & XCB_MOD_MASK_LOCK) 482 flags |= MouseFlag.Alt; 483 if (action == MouseAction.ButtonDown || action == MouseAction.ButtonUp) { 484 switch (detail) { 485 case 1: 486 button = MouseButton.Left; 487 pbuttonDetails = &_lbutton; 488 if (action == MouseAction.ButtonDown) 489 flags |= MouseFlag.LButton; 490 else if (action == MouseAction.ButtonUp) 491 flags &= ~MouseFlag.LButton; 492 break; 493 case 2: 494 button = MouseButton.Middle; 495 pbuttonDetails = &_mbutton; 496 if (action == MouseAction.ButtonDown) 497 flags |= MouseFlag.MButton; 498 else if (action == MouseAction.ButtonUp) 499 flags &= ~MouseFlag.MButton; 500 break; 501 case 3: 502 button = MouseButton.Right; 503 pbuttonDetails = &_rbutton; 504 if (action == MouseAction.ButtonDown) 505 flags |= MouseFlag.RButton; 506 else if (action == MouseAction.ButtonUp) 507 flags &= ~MouseFlag.RButton; 508 break; 509 case 4: 510 if (action == MouseAction.ButtonUp) 511 return; 512 wheelDelta = -1; 513 action = MouseAction.Wheel; 514 break; 515 case 5: 516 if (action == MouseAction.ButtonUp) 517 return; 518 wheelDelta = 1; 519 action = MouseAction.Wheel; 520 break; 521 default: 522 // unknown button 523 return; 524 } 525 } 526 //Log.d("processMouseEvent ", action, " detail=", detail, " state=", state, " at coords ", x, ", ", y); 527 if (action == MouseAction.ButtonDown) { 528 pbuttonDetails.down(x, y, cast(ushort)flags); 529 } else if (action == MouseAction.ButtonUp) { 530 pbuttonDetails.up(x, y, cast(ushort)flags); 531 } 532 MouseEvent event = new MouseEvent(action, button, cast(ushort)flags, x, y, wheelDelta); 533 event.lbutton = _lbutton; 534 event.rbutton = _rbutton; 535 event.mbutton = _mbutton; 536 bool res = dispatchMouseEvent(event); 537 if (res) { 538 Log.d("Calling update() after mouse event"); 539 invalidate(); 540 } 541 } 542 543 } 544 545 private __gshared xcb_connection_t * _xcbconnection; 546 private __gshared xcb_screen_t * _xcbscreen; 547 private __gshared ubyte _xcbscreendepth; 548 private __gshared bool _enableOpengl; 549 private __gshared std.c.linux.X11.Xlib.Display * _display; 550 551 class XCBPlatform : Platform { 552 this() { 553 554 } 555 ~this() { 556 foreach(ref XCBWindow wnd; _windowMap) { 557 destroy(wnd); 558 wnd = null; 559 } 560 _windowMap.clear(); 561 disconnect(); 562 } 563 void disconnect() { 564 /* Cleanup */ 565 if (_display) { 566 Log.d("Closing X display"); 567 std.c.linux.X11.Xlib.XCloseDisplay(_display); 568 _display = null; 569 } else if (_xcbconnection) { 570 Log.d("Closing XCB connection"); 571 /* close connection to server */ 572 xcb_disconnect(_xcbconnection); 573 _xcbconnection = null; 574 } 575 } 576 bool connect() { 577 578 try { 579 DerelictGL3.load(); 580 _enableOpengl = true; 581 } catch (Exception e) { 582 Log.e("Cannot load opengl library", e); 583 } 584 //_enableOpengl = false; // test 585 // X 586 import std.c.linux.X11.Xlib; 587 int default_screen; 588 589 if (_enableOpengl) { 590 Log.d("Opening display via XLib"); 591 /* Open Xlib Display */ 592 _display = XOpenDisplay(null); 593 if (!_display) 594 { 595 Log.e("Failed to open display using Xlib"); 596 _enableOpengl = false; 597 } else { 598 // display is opened 599 default_screen = DefaultScreen(_display); 600 Log.d("Opened display ="); 601 /* Get the XCB connection from the display */ 602 _xcbconnection = XGetXCBConnection(_display); 603 if (!_xcbconnection) 604 { 605 XCloseDisplay(_display); 606 _display = null; 607 Log.e("Failed to get XCB connection from Xlib display"); 608 _enableOpengl = false; 609 } else { 610 /* Acquire event queue ownership */ 611 XSetEventQueueOwner(_display, XEventQueueOwner.XCBOwnsEventQueue); 612 } 613 } 614 } 615 616 if (_xcbconnection is null) { 617 Log.d("Opening XCB connection"); 618 /* open connection with the server */ 619 _xcbconnection = xcb_connect(null,null); 620 } 621 if (xcb_connection_has_error(_xcbconnection)) { 622 Log.e("Cannot open display"); 623 _xcbconnection = null; 624 return false; 625 } 626 //XSetEventQueueOwner(display, XCBOwnsEventQueue); 627 Log.d("Getting first screen"); 628 /* get the first screen */ 629 630 if (_enableOpengl) { 631 /* Find XCB screen */ 632 //xcb_screen_t *screen = null; 633 xcb_screen_iterator_t screen_iter = 634 xcb_setup_roots_iterator(xcb_get_setup(_xcbconnection)); 635 for(int screen_num = default_screen; 636 screen_iter.rem && screen_num > 0; 637 --screen_num, xcb_screen_next(&screen_iter)) { 638 } 639 _xcbscreen = screen_iter.data; 640 } else { 641 _xcbscreen = xcb_setup_roots_iterator( xcb_get_setup(_xcbconnection) ).data; 642 } 643 _xcbscreendepth = xcb_aux_get_depth(_xcbconnection, _xcbscreen); 644 645 if (_enableOpengl) { 646 647 int versionMajor; 648 int versionMinor; 649 if (!glXQueryVersion(_display, 650 &versionMajor, 651 &versionMinor)) { 652 Log.e("Cannot get GLX version"); 653 } else { 654 Log.e("GLX version: ", versionMajor, ".", versionMinor); 655 } 656 657 } 658 659 660 return true; 661 } 662 XCBWindow getWindow(xcb_window_t w) { 663 if (w in _windowMap) 664 return _windowMap[w]; 665 return null; 666 } 667 override Window createWindow(string windowCaption, Window parent) { 668 XCBWindow res = new XCBWindow(windowCaption, parent); 669 _windowMap[res.windowId] = res; 670 return res; 671 } 672 override int enterMessageLoop() { 673 Log.i("entering message loop"); 674 int done = 0; 675 xcb_generic_event_t *e; 676 /* event loop */ 677 do { 678 e = xcb_wait_for_event(_xcbconnection); 679 if (e is null) { 680 Log.w("NULL event received. Exiting message loop"); 681 break; 682 } 683 switch (e.response_type & ~0x80) { 684 case XCB_CREATE_NOTIFY: { 685 xcb_create_notify_event_t *event = cast(xcb_create_notify_event_t *)e; 686 Log.i("XCB_CREATE_NOTIFY"); 687 XCBWindow window = getWindow(event.window); 688 if (window !is null) { 689 // 690 } else { 691 Log.w("Received message for unknown window", event.window); 692 } 693 break; 694 } 695 case XCB_DESTROY_NOTIFY: { 696 xcb_destroy_notify_event_t *event = cast(xcb_destroy_notify_event_t *)e; 697 Log.i("XCB_DESTROY_NOTIFY"); 698 XCBWindow window = getWindow(event.window); 699 if (window !is null) { 700 // 701 } else { 702 Log.w("Received message for unknown window", event.window); 703 } 704 break; 705 } 706 case XCB_MAP_NOTIFY: { 707 xcb_map_notify_event_t *event = cast(xcb_map_notify_event_t *)e; 708 Log.i("XCB_MAP_NOTIFY"); 709 XCBWindow window = getWindow(event.window); 710 if (window !is null) { 711 // 712 } else { 713 Log.w("Received message for unknown window", event.window); 714 } 715 break; 716 } 717 case XCB_UNMAP_NOTIFY: { 718 xcb_unmap_notify_event_t *event = cast(xcb_unmap_notify_event_t *)e; 719 Log.i("XCB_UNMAP_NOTIFY"); 720 XCBWindow window = getWindow(event.window); 721 if (window !is null) { 722 // 723 } else { 724 Log.w("Received message for unknown window", event.window); 725 } 726 break; 727 } 728 case XCB_VISIBILITY_NOTIFY: { 729 xcb_visibility_notify_event_t *event = cast(xcb_visibility_notify_event_t *)e; 730 Log.i("XCB_VISIBILITY_NOTIFY ", event.state); 731 XCBWindow window = getWindow(event.window); 732 if (window !is null) { 733 // 734 } else { 735 Log.w("Received message for unknown window", event.window); 736 } 737 break; 738 } 739 case XCB_REPARENT_NOTIFY: { 740 xcb_reparent_notify_event_t *event = cast(xcb_reparent_notify_event_t *)e; 741 Log.i("XCB_REPARENT_NOTIFY"); 742 break; 743 } 744 case XCB_CONFIGURE_NOTIFY: { 745 xcb_configure_notify_event_t *event = cast(xcb_configure_notify_event_t *)e; 746 Log.i("XCB_CONFIGURE_NOTIFY ", event.width, "x", event.height); 747 XCBWindow window = getWindow(event.window); 748 if (window !is null) { 749 // 750 window.onResize(event.width, event.height); 751 } else { 752 Log.w("Received message for unknown window", event.window); 753 } 754 break; 755 } 756 case XCB_EXPOSE: { /* draw or redraw the window */ 757 xcb_expose_event_t *expose = cast(xcb_expose_event_t *)e; 758 Log.i("XCB_EXPOSE"); 759 XCBWindow window = getWindow(expose.window); 760 if (window !is null) { 761 window.processExpose(expose); 762 } else { 763 Log.w("Received message for unknown window", expose.window); 764 } 765 break; 766 } 767 case XCB_BUTTON_PRESS: { 768 xcb_button_press_event_t *bp = cast(xcb_button_press_event_t *)e; 769 Log.d("XCB_BUTTON_PRESS"); 770 XCBWindow window = getWindow(bp.event); 771 if (window !is null) { 772 // 773 window.processMouseEvent(MouseAction.ButtonDown, bp.detail, bp.state, bp.event_x, bp.event_y); 774 } else { 775 Log.w("Received message for unknown window", bp.event); 776 } 777 break; 778 } 779 case XCB_BUTTON_RELEASE: { 780 Log.d("XCB_BUTTON_RELEASE"); 781 xcb_button_release_event_t *br = cast(xcb_button_release_event_t *)e; 782 XCBWindow window = getWindow(br.event); 783 if (window !is null) { 784 // 785 window.processMouseEvent(MouseAction.ButtonUp, br.detail, br.state, br.event_x, br.event_y); 786 } else { 787 Log.w("Received message for unknown window", br.event); 788 } 789 break; 790 } 791 case XCB_MOTION_NOTIFY: { 792 xcb_motion_notify_event_t *motion = cast(xcb_motion_notify_event_t *)e; 793 //Log.d("XCB_MOTION_NOTIFY ", motion.event, " at coords ", motion.event_x, ", ", motion.event_y); 794 XCBWindow window = getWindow(motion.event); 795 if (window !is null) { 796 // 797 window.processMouseEvent(MouseAction.Move, 0, motion.state, motion.event_x, motion.event_y); 798 } else { 799 Log.w("Received message for unknown window", motion.event); 800 } 801 break; 802 } 803 case XCB_ENTER_NOTIFY: { 804 xcb_enter_notify_event_t *enter = cast(xcb_enter_notify_event_t *)e; 805 Log.d("XCB_ENTER_NOTIFY ", enter.event, " at coords ", enter.event_x, ", ", enter.event_y); 806 break; 807 } 808 case XCB_LEAVE_NOTIFY: { 809 xcb_leave_notify_event_t *leave = cast(xcb_leave_notify_event_t *)e; 810 Log.d("XCB_LEAVE_NOTIFY ", leave.event, " at coords ", leave.event_x, ", ", leave.event_y); 811 XCBWindow window = getWindow(leave.event); 812 if (window !is null) { 813 // 814 window.processMouseEvent(MouseAction.Leave, 0, leave.state, leave.event_x, leave.event_y); 815 } else { 816 Log.w("Received message for unknown window", leave.event); 817 } 818 break; 819 } 820 case XCB_KEY_PRESS: { 821 xcb_key_press_event_t *kp = cast(xcb_key_press_event_t *)e; 822 //print_modifiers(kp.state); 823 Log.d("XCB_KEY_PRESS ", kp.event, " key=", kp.detail); 824 if (kp.detail == XK_space) // exist by space 825 done = 1; 826 break; 827 } 828 case XCB_KEY_RELEASE: { 829 xcb_key_release_event_t *kr = cast(xcb_key_release_event_t *)e; 830 //print_modifiers(kr.state); 831 Log.d("XCB_KEY_RELEASE ", kr.event, " key=", kr.detail); 832 break; 833 } 834 default: 835 Log.v("unknown event: ", e.response_type & ~0x80); 836 break; 837 } 838 free(e); 839 } while(!done); 840 Log.i("exiting message loop"); 841 return 0; 842 } 843 XCBWindow[xcb_window_t] _windowMap; 844 } 845 846 // entry point 847 extern(C) int UIAppMain(string[] args); 848 849 int main(string[] args) 850 { 851 852 setStderrLogger(); 853 setLogLevel(LogLevel.Trace); 854 855 FreeTypeFontManager ft = new FreeTypeFontManager(); 856 ft.registerFont("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", FontFamily.SansSerif, "DejaVu", false, FontWeight.Normal); 857 FontManager.instance = ft; 858 859 currentTheme = createDefaultTheme(); 860 861 XCBPlatform xcb = new XCBPlatform(); 862 if (!xcb.connect()) { 863 return 1; 864 } 865 Platform.setInstance(xcb); 866 867 int res = 0; 868 869 static if (true) { 870 res = UIAppMain(args); 871 } else { 872 Window window = xcb.createWindow("Window Caption", null); 873 window.show(); 874 875 res = xcb.enterMessageLoop(); 876 } 877 878 Platform.setInstance(null); 879 Log.d("Destroying XCB platform"); 880 destroy(xcb); 881 882 currentTheme = null; 883 drawableCache = null; 884 imageCache = null; 885 FontManager.instance = null; 886 887 Log.d("Exiting main"); 888 889 return res; 890 } 891 892 }