30 #define LSB_BIT_SET(p, n) (p[(n)/8] |= (1 <<((n)%8)))
55 m_glxContext =
nullptr;
213 internalOpenDisplay();
215 internalChooseGLVisual();
216 internalCreateGLContext();
217 internalCreateWindow();
222 if(m_cursor != None) {
223 XUndefineCursor(m_display, m_window);
228 XFreeCursor(m_display, m_hiddenCursor);
232 for(Cursor cursor : m_cursors)
233 XFreeCursor(m_display, cursor);
237 XDestroyWindow(m_display, m_window);
242 XFreeColormap(m_display, m_colormap);
246 internalDestroyGLContext();
264 XCloseDisplay(m_display);
271 void X11Window::internalOpenDisplay()
273 m_display = XOpenDisplay(
nullptr);
276 m_screen = DefaultScreen(m_display);
279 void X11Window::internalCreateWindow()
283 unsigned int attrsMask;
284 XSetWindowAttributes attrs;
285 memset(&attrs, 0,
sizeof(attrs));
287 attrs.event_mask = KeyPressMask | KeyReleaseMask |
288 ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
289 ExposureMask | VisibilityChangeMask |
290 StructureNotifyMask | FocusChangeMask;
292 m_colormap = XCreateColormap(m_display, m_rootWindow, m_visual->visual, AllocNone);
293 attrs.colormap = m_colormap;
294 attrs.border_pixel = 0;
295 attrs.override_redirect = False;
296 vis = m_visual->visual;
297 depth = m_visual->depth;
298 attrsMask = CWEventMask | CWBorderPixel | CWColormap;
301 attrs.override_redirect = False;
302 attrsMask |= CWOverrideRedirect;
306 m_window = XCreateWindow(m_display, m_rootWindow,
321 hints.flags = InputHint;
322 XSetWMHints(m_display, m_window, &hints);
328 m_wmDelete = XInternAtom(m_display,
"WM_DELETE_WINDOW", True);
329 XSetWMProtocols(m_display, m_window, &m_wmDelete , 1);
331 if(!internalSetupWindowInput())
332 g_logger.
warning(
"Input of special keys may be messed up, because window input initialization failed");
334 internalConnectGLContext();
337 bool X11Window::internalSetupWindowInput()
340 if(!XSupportsLocale()) {
345 XSetLocaleModifiers(
"");
346 m_xim = XOpenIM(m_display,
nullptr,
nullptr,
nullptr);
352 m_xic = XCreateIC(m_xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, m_window, NULL);
361 void X11Window::internalCheckGL()
364 m_eglDisplay = eglGetDisplay((EGLNativeDisplayType)m_display);
365 if(m_eglDisplay == EGL_NO_DISPLAY)
368 if(!eglInitialize(m_eglDisplay, NULL, NULL))
371 if(!glXQueryExtension(m_display,
nullptr,
nullptr))
376 void X11Window::internalChooseGLVisual()
379 static int attrList[] = {
381 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
383 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
393 XVisualInfo visTemplate;
396 if(!eglChooseConfig(m_eglDisplay, attrList, &m_eglConfig, 1, &numConfig))
403 if(!eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_NATIVE_VISUAL_ID, &vid))
406 memset(&visTemplate, 0,
sizeof(visTemplate));
407 visTemplate.visualid = vid;
408 m_visual = XGetVisualInfo(m_display, VisualIDMask, &visTemplate, &numVisuals);
410 g_logger.
fatal(
"Couldn't choose RGBA, double buffered visual");
412 m_rootWindow = DefaultRootWindow(m_display);
414 static int attrList[] = {
415 GLX_RENDER_TYPE, GLX_RGBA_BIT,
416 GLX_DOUBLEBUFFER, True,
425 m_fbConfig = glXChooseFBConfig(m_display, m_screen, attrList, &nelements);
427 g_logger.
fatal(
"Couldn't choose RGBA, double buffered fbconfig");
429 m_visual = glXGetVisualFromFBConfig(m_display, *m_fbConfig);
431 g_logger.
fatal(
"Couldn't choose RGBA, double buffered visual");
433 m_rootWindow = RootWindow(m_display, m_visual->screen);
437 void X11Window::internalCreateGLContext()
440 EGLint attrList[] = {
442 EGL_CONTEXT_CLIENT_VERSION, 2,
444 EGL_CONTEXT_CLIENT_VERSION, 1,
449 m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, attrList);
450 if(m_eglContext == EGL_NO_CONTEXT )
453 m_glxContext = glXCreateContext(m_display, m_visual,
nullptr, True);
458 if(!glXIsDirect(m_display, m_glxContext))
463 void X11Window::internalDestroyGLContext()
468 eglDestroyContext(m_eglDisplay, m_eglContext);
472 eglDestroySurface(m_eglDisplay, m_eglSurface);
475 eglTerminate(m_eglDisplay);
480 glXMakeCurrent(m_display, None,
nullptr);
481 glXDestroyContext(m_display, m_glxContext);
482 m_glxContext =
nullptr;
487 void X11Window::internalConnectGLContext()
490 m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, m_window, NULL);
491 if(m_eglSurface == EGL_NO_SURFACE)
493 if(!eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext))
494 g_logger.
fatal(
"Unable to connect EGL context into X11 window");
496 if(!glXMakeCurrent(m_display, m_window, m_glxContext))
501 void *X11Window::getExtensionProcAddress(
const char *ext)
507 return (
void *)glXGetProcAddressARB((
const GLubyte*)ext);
511 bool X11Window::isExtensionSupported(
const char *ext)
517 const char *exts = glXQueryExtensionsString(m_display, m_screen);
518 if(strstr(exts, ext))
537 XResizeWindow(m_display, m_window, size.
width(), size.
height());
544 XMapWindow(m_display, m_window);
556 XUnmapWindow(m_display, m_window);
563 Atom wmState = XInternAtom(m_display,
"_NET_WM_STATE", False);
564 Atom wmStateMaximizedVert = XInternAtom(m_display,
"_NET_WM_STATE_MAXIMIZED_VERT", False);
565 Atom wmStateMaximizedHorz = XInternAtom(m_display,
"_NET_WM_STATE_MAXIMIZED_HORZ", False);
568 e.xany.type = ClientMessage;
569 e.xclient.send_event = True;
570 e.xclient.message_type = wmState;
571 e.xclient.format = 32;
572 e.xclient.window = m_window;
573 e.xclient.data.l[0] = 1;
574 e.xclient.data.l[1] = wmStateMaximizedVert;
575 e.xclient.data.l[2] = wmStateMaximizedHorz;
576 e.xclient.data.l[3] = 0;
578 XSendEvent(m_display, m_rootWindow, 0, SubstructureNotifyMask | SubstructureRedirectMask, &e);
586 bool needsResizeUpdate =
false;
588 XEvent event, peekEvent;
589 while(XPending(m_display) > 0) {
590 XNextEvent(m_display, &event);
593 bool repatedKeyRelease =
false;
594 if(event.type == KeyRelease && XPending(m_display)) {
595 XPeekEvent(m_display, &peekEvent);
596 if((peekEvent.type == KeyPress) && (peekEvent.xkey.keycode == event.xkey.keycode) && ((peekEvent.xkey.time-event.xkey.time) < 2))
597 repatedKeyRelease =
true;
601 if(event.type == KeyPress || (event.type == KeyRelease && !repatedKeyRelease)) {
603 XKeyEvent xkey =
event.xkey;
604 xkey.state &= ~(ShiftMask | LockMask);
609 XLookupString(&xkey, buf,
sizeof(buf), &keysym,
nullptr);
615 if(event.type == KeyPress)
617 else if(event.type == KeyRelease)
622 if(XFilterEvent(&event, m_window))
626 if(repatedKeyRelease)
630 case ClientMessage: {
632 if((Atom)event.xclient.data.l[0] == m_wmDelete &&
m_onClose)
636 case ConfigureNotify: {
637 Size newSize(event.xconfigure.width, event.xconfigure.height);
638 Point newPos(event.xconfigure.x, event.xconfigure.y);
643 needsResizeUpdate =
true;
649 Atom wmState = XInternAtom(m_display,
"_NET_WM_STATE", False);
650 Atom wmStateMaximizedVert = XInternAtom(m_display,
"_NET_WM_STATE_MAXIMIZED_VERT", False);
651 Atom wmStateMaximizedHorz = XInternAtom(m_display,
"_NET_WM_STATE_MAXIMIZED_HORZ", False);
653 ulong i, numItems, bytesAfter;
654 uchar *propertyValue =
nullptr;
657 if(XGetWindowProperty(m_display, m_window, wmState,
658 0, 1024, False, XA_ATOM, &actualType,
659 &actualFormat, &numItems, &bytesAfter,
660 &propertyValue) == Success) {
661 Atom *atoms = (Atom*)propertyValue;
662 int maximizedMask = 0;
664 for(i=0; i<numItems; ++i) {
665 if(atoms[i] == wmStateMaximizedVert)
667 else if(atoms[i] == wmStateMaximizedHorz)
671 if(maximizedMask == 3)
674 XFree(propertyValue);
684 case SelectionRequest: {
686 XSelectionRequestEvent *req = &(
event.xselectionrequest);
688 Atom targets = XInternAtom(m_display,
"TARGETS", False);
689 if(req->target == targets) {
690 Atom typeList[] = { XInternAtom(m_display,
"UTF8_STRING", False),
691 XInternAtom(m_display,
"TEXT", False),
692 XInternAtom(m_display,
"STRING", False),
693 XInternAtom(m_display,
"text/plain;charset=UTF-8", False),
694 XInternAtom(m_display,
"text/plain", False),
695 XInternAtom(m_display,
"COMPOUND_TEXT", False),
698 XChangeProperty(m_display, req->requestor,
699 req->property, req->target,
703 respond.xselection.property = req->property;
706 XChangeProperty(m_display,
708 req->property, req->target,
711 (
uchar *)clipboardText.c_str(),
712 clipboardText.length());
713 respond.xselection.property = req->property;
716 respond.xselection.type = SelectionNotify;
717 respond.xselection.display = req->display;
718 respond.xselection.requestor = req->requestor;
719 respond.xselection.selection = req->selection;
720 respond.xselection.target = req->target;
721 respond.xselection.time = req->time;
722 XSendEvent(m_display, req->requestor, 0, 0, &respond);
729 if(event.xkey.state & ControlMask || event.xkey.state & Mod1Mask)
741 len = XmbLookupString(m_xic, &event.xkey, buf,
sizeof(buf), &keysym, &status);
743 static XComposeStatus compose = {
nullptr, 0};
744 len = XLookupString(&event.xkey, buf,
sizeof(buf), &keysym, &compose);
748 if(len == 0 || (
uchar)(buf[0]) < 32 || keysym == XK_BackSpace || keysym == XK_Return || keysym == XK_Delete || keysym == XK_Escape)
750 std::string text = buf;
762 case ButtonRelease: {
765 switch(event.xbutton.button) {
779 if(event.type == ButtonPress) {
787 if(event.type == ButtonPress) {
806 Point newMousePos(event.xbutton.x, event.xbutton.y);
815 needsResizeUpdate =
true;
844 eglSwapBuffers(m_eglDisplay, m_eglSurface);
846 glXSwapBuffers(m_display, m_window);
860 if(m_hiddenCursor == None) {
861 char bm[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
862 Pixmap pix = XCreateBitmapFromData(m_display, m_window, bm, 8, 8);
864 memset(&black, 0,
sizeof(black));
865 black.flags = DoRed | DoGreen | DoBlue;
866 m_hiddenCursor = XCreatePixmapCursor(m_display, pix, pix, &black, &black, 0, 0);
867 XFreePixmap(m_display, pix);
870 m_cursor = m_hiddenCursor;
871 XDefineCursor(m_display, m_window, m_cursor);
876 if(cursorId >= (
int)m_cursors.size() || cursorId < 0)
882 m_cursor = m_cursors[cursorId];
883 XDefineCursor(m_display, m_window, m_cursor);
888 XUndefineCursor(m_display, m_window);
894 int width = image->getWidth();
895 int height = image->getHeight();
896 int numbits = width * height;
897 int numbytes = (width * height)/8;
907 std::vector<uchar> mapBits(numbytes, 0);
908 std::vector<uchar> maskBits(numbytes, 0);
910 for(
int i=0;i<numbits;++i) {
912 if(rgba == 0xffffffff) {
914 }
else if(rgba == 0xff000000) {
920 Pixmap cp = XCreateBitmapFromData(m_display, m_window, (
char*)&mapBits[0], width, height);
921 Pixmap mp = XCreateBitmapFromData(m_display, m_window, (
char*)&maskBits[0], width, height);
922 Cursor cursor = XCreatePixmapCursor(m_display, cp, mp, &fg, &bg, hotSpot.
x, hotSpot.
y);
923 XFreePixmap(m_display, cp);
924 XFreePixmap(m_display, mp);
926 m_cursors.push_back(cursor);
927 return m_cursors.size()-1;
932 XStoreName(m_display, m_window, title.c_str());
933 XSetIconName(m_display, m_window, title.c_str());
938 XSizeHints sizeHints;
939 memset(&sizeHints, 0,
sizeof(sizeHints));
940 sizeHints.flags = PMinSize;
941 sizeHints.min_width = minimumSize.
width();
942 sizeHints.min_height= minimumSize.
height();
943 XSetWMSizeHints(m_display, m_window, &sizeHints, XA_WM_NORMAL_HINTS);
949 Atom wmState = XInternAtom(m_display,
"_NET_WM_STATE", False);
950 Atom wmStateFullscreen = XInternAtom(m_display,
"_NET_WM_STATE_FULLSCREEN", False);
953 xev.xclient.type = ClientMessage;
954 xev.xclient.serial = 0;
955 xev.xclient.send_event = True;
956 xev.xclient.window = m_window;
957 xev.xclient.message_type = wmState;
958 xev.xclient.format = 32;
959 xev.xclient.data.l[0] = fullscreen ? 1 : 0;
960 xev.xclient.data.l[1] = wmStateFullscreen;
961 xev.xclient.data.l[2] = 0;
963 XSendEvent(m_display, m_rootWindow, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
974 typedef GLint (*glSwapIntervalProc)(GLint);
975 glSwapIntervalProc glSwapInterval =
nullptr;
977 if(isExtensionSupported(
"GLX_MESA_swap_control"))
978 glSwapInterval = (glSwapIntervalProc)getExtensionProcAddress(
"glXSwapIntervalMESA");
979 else if(isExtensionSupported(
"GLX_SGI_swap_control"))
980 glSwapInterval = (glSwapIntervalProc)getExtensionProcAddress(
"glXSwapIntervalSGI");
983 glSwapInterval(enable ? 1 : 0);
996 if(image->getBpp() != 4) {
1001 int n = image->getWidth() * image->getHeight();
1002 std::vector<unsigned long int> iconData(n + 2);
1003 iconData[0] = image->getWidth();
1004 iconData[1] = image->getHeight();
1005 for(
int i=0; i < n;++i) {
1007 pixel[2] = *(image->getPixelData() + (i * 4) + 0);
1008 pixel[1] = *(image->getPixelData() + (i * 4) + 1);
1009 pixel[0] = *(image->getPixelData() + (i * 4) + 2);
1010 pixel[3] = *(image->getPixelData() + (i * 4) + 3);
1013 Atom
property = XInternAtom(m_display,
"_NET_WM_ICON", 0);
1014 if(!XChangeProperty(m_display, m_window, property, XA_CARDINAL, 32, PropModeReplace, (
const unsigned char*)&iconData[0], iconData.size()))
1020 m_clipboardText = text;
1021 Atom clipboard = XInternAtom(m_display,
"CLIPBOARD", False);
1022 XSetSelectionOwner(m_display, clipboard, m_window, CurrentTime);
1028 return Size(XDisplayWidth(m_display, m_screen), XDisplayHeight(m_display, m_screen));
1033 Atom clipboard = XInternAtom(m_display,
"CLIPBOARD", False);
1034 Window ownerWindow = XGetSelectionOwner(m_display, clipboard);
1035 if(ownerWindow == m_window)
1036 return m_clipboardText;
1038 std::string clipboardText;
1039 if(ownerWindow != None) {
1040 XConvertSelection(m_display, clipboard, XA_STRING, XA_PRIMARY, ownerWindow, CurrentTime);
1050 ulong len, bytesLeft;
1052 XGetWindowProperty(m_display, ownerWindow,
1053 XA_PRIMARY, 0, 10000000L, 0, XA_STRING,
1063 clipboardText = data;
1067 return clipboardText;