diff options
Diffstat (limited to 'intern/ghost/intern/GHOST_WindowX11.cpp')
-rw-r--r-- | intern/ghost/intern/GHOST_WindowX11.cpp | 345 |
1 files changed, 264 insertions, 81 deletions
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 97f8ae73d2d..613b4dfe4be 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -29,6 +29,10 @@ * \ingroup GHOST */ +/* For standard X11 cursors */ +#include <X11/cursorfont.h> +#include <X11/Xatom.h> +#include <X11/Xutil.h> #include "GHOST_WindowX11.h" #include "GHOST_SystemX11.h" @@ -45,11 +49,6 @@ # include "GHOST_ContextGLX.h" #endif - -/* For standard X11 cursors */ -#include <X11/cursorfont.h> -#include <X11/Xatom.h> - #if defined(__sun__) || defined(__sun) || defined(__sparc) || defined(__sparc__) || defined(_AIX) # include <strings.h> #endif @@ -57,6 +56,9 @@ #include <cstring> #include <cstdio> +/* gethostname */ +#include <unistd.h> + #include <algorithm> #include <string> @@ -72,6 +74,9 @@ typedef struct { #define MWM_HINTS_DECORATIONS (1L << 1) +#ifndef HOST_NAME_MAX +# define HOST_NAME_MAX 64 +#endif // #define GHOST_X11_GRAB @@ -153,7 +158,118 @@ static long BLENDER_ICON_48x48x32[] = { 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, }; +static XVisualInfo *x11_visualinfo_from_glx( + Display *display, + bool stereoVisual, GHOST_TUns16 *r_numOfAASamples) +{ + XVisualInfo *visualInfo = NULL; + GHOST_TUns16 numOfAASamples = *r_numOfAASamples; + /* Set up the minimum attributes that we require and see if + * X can find us a visual matching those requirements. */ + + std::vector<int> attribs; + attribs.reserve(40); + + int glx_major, glx_minor; /* GLX version: major.minor */ + + if (!glXQueryVersion(display, &glx_major, &glx_minor)) { + fprintf(stderr, + "%s:%d: X11 glXQueryVersion() failed, " + "verify working openGL system!\n", + __FILE__, __LINE__); + + return NULL; + } + +#ifdef GHOST_OPENGL_ALPHA + const bool needAlpha = true; +#else + const bool needAlpha = false; +#endif + +#ifdef GHOST_OPENGL_STENCIL + const bool needStencil = true; +#else + const bool needStencil = false; +#endif + /* Find the display with highest samples, starting at level requested */ + GHOST_TUns16 actualSamples = numOfAASamples; + for (;;) { + attribs.clear(); + + if (stereoVisual) + attribs.push_back(GLX_STEREO); + + attribs.push_back(GLX_RGBA); + + attribs.push_back(GLX_DOUBLEBUFFER); + + attribs.push_back(GLX_RED_SIZE); + attribs.push_back(1); + + attribs.push_back(GLX_BLUE_SIZE); + attribs.push_back(1); + + attribs.push_back(GLX_GREEN_SIZE); + attribs.push_back(1); + + attribs.push_back(GLX_DEPTH_SIZE); + attribs.push_back(1); + + if (needAlpha) { + attribs.push_back(GLX_ALPHA_SIZE); + attribs.push_back(1); + } + + if (needStencil) { + attribs.push_back(GLX_STENCIL_SIZE); + attribs.push_back(1); + } + + /* GLX >= 1.4 required for multi-sample */ + if (actualSamples > 0 && ((glx_major > 1) || (glx_major == 1 && glx_minor >= 4))) { + attribs.push_back(GLX_SAMPLE_BUFFERS); + attribs.push_back(1); + + attribs.push_back(GLX_SAMPLES); + attribs.push_back(actualSamples); + } + + attribs.push_back(None); + + visualInfo = glXChooseVisual(display, DefaultScreen(display), &attribs[0]); + + /* Any sample level or even zero, which means oversampling disabled, is good + * but we need a valid visual to continue */ + if (visualInfo != NULL) { + if (actualSamples < numOfAASamples) { + fprintf(stderr, + "Warning! Unable to find a multisample pixel format that supports exactly %d samples. " + "Substituting one that uses %d samples.\n", + numOfAASamples, actualSamples); + } + break; + } + + if (actualSamples == 0) { + /* All options exhausted, cannot continue */ + fprintf(stderr, + "%s:%d: X11 glXChooseVisual() failed, " + "verify working openGL system!\n", + __FILE__, __LINE__); + + return NULL; + } + else { + --actualSamples; + } + } + + *r_numOfAASamples = actualSamples; + + return visualInfo; +} GHOST_WindowX11:: GHOST_WindowX11( @@ -172,6 +288,7 @@ GHOST_WindowX11( const GHOST_TUns16 numOfAASamples) : GHOST_Window(width, height, state, stereoVisual, exclusive, numOfAASamples), m_display(display), + m_visualInfo(NULL), m_normal_state(GHOST_kWindowStateNormal), m_system(system), m_valid_setup(false), @@ -180,7 +297,20 @@ GHOST_WindowX11( m_custom_cursor(None), m_visible_cursor(None) { - int natom; + if (type == GHOST_kDrawingContextTypeOpenGL) { + m_visualInfo = x11_visualinfo_from_glx(m_display, stereoVisual, &m_wantNumOfAASamples); + } + else { + XVisualInfo tmp = {0}; + int n; + m_visualInfo = XGetVisualInfo(m_display, 0, &tmp, &n); + } + + /* exit if this is the first window */ + if (m_visualInfo == NULL) { + fprintf(stderr, "initial window could not find the GLX extension, exit!\n"); + exit(EXIT_FAILURE); + } unsigned int xattributes_valuemask = 0; @@ -206,24 +336,28 @@ GHOST_WindowX11( xattributes.override_redirect = True; } + xattributes_valuemask |= CWColormap; + xattributes.colormap = XCreateColormap( + m_display, + RootWindow(m_display, m_visualInfo->screen), + m_visualInfo->visual, + AllocNone + ); + /* create the window! */ if (parentWindow == 0) { - m_window = XCreateWindow(m_display, - RootWindow(m_display, DefaultScreen(m_display)), - left, - top, - width, - height, - 0, /* no border. */ - CopyFromParent, - InputOutput, - CopyFromParent, - xattributes_valuemask, - &xattributes - ); + m_window = XCreateWindow( + m_display, + RootWindow(m_display, m_visualInfo->screen), + left, top, width, height, + 0, /* no border. */ + m_visualInfo->depth, + InputOutput, + m_visualInfo->visual, + xattributes_valuemask, + &xattributes); } else { - Window root_return; int x_return, y_return; unsigned int w_return, h_return, border_w_return, depth_return; @@ -237,19 +371,16 @@ GHOST_WindowX11( height = h_return; - m_window = XCreateWindow(m_display, - parentWindow, /* reparent against embedder */ - left, - top, - width, - height, - 0, /* no border. */ - CopyFromParent, - InputOutput, - CopyFromParent, - xattributes_valuemask, - &xattributes - ); + m_window = XCreateWindow( + m_display, + parentWindow, /* reparent against embedder */ + left, top, width, height, + 0, /* no border. */ + m_visualInfo->depth, + InputOutput, + m_visualInfo->visual, + xattributes_valuemask, + &xattributes); XSelectInput(m_display, parentWindow, SubstructureNotifyMask); @@ -301,36 +432,43 @@ GHOST_WindowX11( m_post_state = GHOST_kWindowStateNormal; } + /* Create some hints for the window manager on how * we want this window treated. */ + { + XSizeHints *xsizehints = XAllocSizeHints(); + xsizehints->flags = PPosition | PSize | PMinSize | PMaxSize; + xsizehints->x = left; + xsizehints->y = top; + xsizehints->width = width; + xsizehints->height = height; + xsizehints->min_width = 320; /* size hints, could be made apart of the ghost api */ + xsizehints->min_height = 240; /* limits are also arbitrary, but should not allow 1x1 window */ + xsizehints->max_width = 65535; + xsizehints->max_height = 65535; + XSetWMNormalHints(m_display, m_window, xsizehints); + XFree(xsizehints); + } + + + /* XClassHint, title */ + { + XClassHint *xclasshint = XAllocClassHint(); + const int len = title.Length() + 1; + char *wmclass = (char *)malloc(sizeof(char) * len); + memcpy(wmclass, title.ReadPtr(), len * sizeof(char)); + xclasshint->res_name = wmclass; + xclasshint->res_class = wmclass; + XSetClassHint(m_display, m_window, xclasshint); + free(wmclass); + XFree(xclasshint); + } - XSizeHints *xsizehints = XAllocSizeHints(); - xsizehints->flags = PPosition | PSize | PMinSize | PMaxSize; - xsizehints->x = left; - xsizehints->y = top; - xsizehints->width = width; - xsizehints->height = height; - xsizehints->min_width = 320; /* size hints, could be made apart of the ghost api */ - xsizehints->min_height = 240; /* limits are also arbitrary, but should not allow 1x1 window */ - xsizehints->max_width = 65535; - xsizehints->max_height = 65535; - XSetWMNormalHints(m_display, m_window, xsizehints); - XFree(xsizehints); - - XClassHint *xclasshint = XAllocClassHint(); - const int len = title.Length() + 1; - char *wmclass = (char *)malloc(sizeof(char) * len); - strncpy(wmclass, (const char *)title, sizeof(char) * len); - xclasshint->res_name = wmclass; - xclasshint->res_class = wmclass; - XSetClassHint(m_display, m_window, xclasshint); - free(wmclass); - XFree(xclasshint); /* The basic for a good ICCCM "work" */ if (m_system->m_atom.WM_PROTOCOLS) { Atom atoms[2]; - natom = 0; + int natom = 0; if (m_system->m_atom.WM_DELETE_WINDOW) { atoms[natom] = m_system->m_atom.WM_DELETE_WINDOW; @@ -352,21 +490,49 @@ GHOST_WindowX11( m_xic = NULL; #endif + /* Set the window hints */ - XWMHints *xwmhints = XAllocWMHints(); - xwmhints->initial_state = NormalState; - xwmhints->input = True; - xwmhints->flags = InputHint | StateHint; - XSetWMHints(display, m_window, xwmhints); - XFree(xwmhints); - /* done setting the hints */ + { + XWMHints *xwmhints = XAllocWMHints(); + xwmhints->initial_state = NormalState; + xwmhints->input = True; + xwmhints->flags = InputHint | StateHint; + XSetWMHints(display, m_window, xwmhints); + XFree(xwmhints); + } + /* set the icon */ - Atom _NET_WM_ICON = XInternAtom(m_display, "_NET_WM_ICON", False); - XChangeProperty(m_display, m_window, _NET_WM_ICON, XA_CARDINAL, - 32, PropModeReplace, (unsigned char *)BLENDER_ICON_48x48x32, - BLENDER_ICON_48x48x32[0] * BLENDER_ICON_48x48x32[1] + 2); - /* done setting the icon */ + { + Atom _NET_WM_ICON = XInternAtom(m_display, "_NET_WM_ICON", False); + XChangeProperty(m_display, m_window, _NET_WM_ICON, XA_CARDINAL, + 32, PropModeReplace, (unsigned char *)BLENDER_ICON_48x48x32, + BLENDER_ICON_48x48x32[0] * BLENDER_ICON_48x48x32[1] + 2); + } + + /* set the process ID (_NET_WM_PID) */ + { + Atom _NET_WM_PID = XInternAtom(m_display, "_NET_WM_PID", False); + pid_t pid = getpid(); + XChangeProperty(m_display, m_window, _NET_WM_PID, XA_CARDINAL, + 32, PropModeReplace, (unsigned char *)&pid, 1); + } + + + /* set the hostname (WM_CLIENT_MACHINE) */ + { + char hostname[HOST_NAME_MAX]; + char *text_array[1]; + XTextProperty text_prop; + + gethostname(hostname, sizeof(hostname)); + hostname[sizeof(hostname) - 1] = '\0'; + text_array[0] = hostname; + + XStringListToTextProperty(text_array, 1, &text_prop); + XSetWMClientMachine(m_display, m_window, &text_prop); + XFree(text_prop.value); + } #ifdef WITH_X11_XINPUT initXInputDevices(); @@ -374,6 +540,7 @@ GHOST_WindowX11( m_tabletData.Active = GHOST_kTabletModeNone; #endif + /* now set up the rendering context. */ if (setDrawingContextType(type) == GHOST_kSuccess) { m_valid_setup = true; @@ -442,23 +609,32 @@ void GHOST_WindowX11::initXInputDevices() if (version && (version != (XExtensionVersion *)NoSuchExtension)) { if (version->present) { GHOST_SystemX11::GHOST_TabletX11 &xtablet = m_system->GetXTablet(); - XEventClass xevents[10], ev; + XEventClass xevents[8], ev; int dcount = 0; + /* With modern XInput (xlib 1.6.2 at least and/or evdev 2.9.0) and some 'no-name' tablets + * like 'UC-LOGIC Tablet WP5540U', we also need to 'select' ButtonPress for motion event, + * otherwise we do not get any tablet motion event once pen is pressed... See T43367. + */ + if (xtablet.StylusDevice) { DeviceMotionNotify(xtablet.StylusDevice, xtablet.MotionEvent, ev); if (ev) xevents[dcount++] = ev; + DeviceButtonPress(xtablet.StylusDevice, xtablet.PressEvent, ev); + if (ev) xevents[dcount++] = ev; ProximityIn(xtablet.StylusDevice, xtablet.ProxInEvent, ev); if (ev) xevents[dcount++] = ev; ProximityOut(xtablet.StylusDevice, xtablet.ProxOutEvent, ev); if (ev) xevents[dcount++] = ev; } if (xtablet.EraserDevice) { - DeviceMotionNotify(xtablet.EraserDevice, xtablet.MotionEvent, ev); + DeviceMotionNotify(xtablet.EraserDevice, xtablet.MotionEventEraser, ev); + if (ev) xevents[dcount++] = ev; + DeviceButtonPress(xtablet.EraserDevice, xtablet.PressEventEraser, ev); if (ev) xevents[dcount++] = ev; - ProximityIn(xtablet.EraserDevice, xtablet.ProxInEvent, ev); + ProximityIn(xtablet.EraserDevice, xtablet.ProxInEventEraser, ev); if (ev) xevents[dcount++] = ev; - ProximityOut(xtablet.EraserDevice, xtablet.ProxOutEvent, ev); + ProximityOut(xtablet.EraserDevice, xtablet.ProxOutEventEraser, ev); if (ev) xevents[dcount++] = ev; } @@ -602,7 +778,7 @@ screenToClient( Window temp; XTranslateCoordinates(m_display, - RootWindow(m_display, DefaultScreen(m_display)), + RootWindow(m_display, m_visualInfo->screen), m_window, inX, inY, &ax, &ay, @@ -625,7 +801,7 @@ clientToScreen( XTranslateCoordinates( m_display, m_window, - RootWindow(m_display, DefaultScreen(m_display)), + RootWindow(m_display, m_visualInfo->screen), inX, inY, &ax, &ay, &temp); @@ -648,7 +824,7 @@ void GHOST_WindowX11::icccmSetState(int state) xev.xclient.format = 32; xev.xclient.message_type = m_system->m_atom.WM_CHANGE_STATE; xev.xclient.data.l[0] = state; - XSendEvent(m_display, RootWindow(m_display, DefaultScreen(m_display)), + XSendEvent(m_display, RootWindow(m_display, m_visualInfo->screen), False, SubstructureNotifyMask | SubstructureRedirectMask, &xev); } @@ -694,7 +870,7 @@ void GHOST_WindowX11::netwmMaximized(bool set) xev.xclient.data.l[2] = m_system->m_atom._NET_WM_STATE_MAXIMIZED_VERT; xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = 0; - XSendEvent(m_display, RootWindow(m_display, DefaultScreen(m_display)), + XSendEvent(m_display, RootWindow(m_display, m_visualInfo->screen), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); } @@ -750,7 +926,7 @@ void GHOST_WindowX11::netwmFullScreen(bool set) xev.xclient.data.l[2] = 0; xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = 0; - XSendEvent(m_display, RootWindow(m_display, DefaultScreen(m_display)), + XSendEvent(m_display, RootWindow(m_display, m_visualInfo->screen), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); } @@ -969,7 +1145,7 @@ setOrder( xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = 0; - root = RootWindow(m_display, DefaultScreen(m_display)), + root = RootWindow(m_display, m_visualInfo->screen), eventmask = SubstructureRedirectMask | SubstructureNotifyMask; XSendEvent(m_display, root, False, eventmask, &xev); @@ -1068,6 +1244,10 @@ GHOST_WindowX11:: XSetSelectionOwner(m_display, Clipboard_atom, None, CurrentTime); } + if (m_visualInfo) { + XFree(m_visualInfo); + } + #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING) if (m_xic) { XDestroyIC(m_xic); @@ -1095,6 +1275,7 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type m_wantNumOfAASamples, m_window, m_display, + m_visualInfo, GLX_CONTEXT_OPENGL_CORE_PROFILE_BIT, 3, 2, GHOST_OPENGL_GLX_CONTEXT_FLAGS, @@ -1105,6 +1286,7 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type m_wantNumOfAASamples, m_window, m_display, + m_visualInfo, GLX_CONTEXT_ES2_PROFILE_BIT_EXT, 2, 0, GHOST_OPENGL_GLX_CONTEXT_FLAGS, @@ -1115,6 +1297,7 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type m_wantNumOfAASamples, m_window, m_display, + m_visualInfo, 0, // profile bit 0, 0, GHOST_OPENGL_GLX_CONTEXT_FLAGS, @@ -1231,13 +1414,13 @@ getEmptyCursor( ) { if (!m_empty_cursor) { Pixmap blank; - XColor dummy; + XColor dummy = {0}; char data[1] = {0}; /* make a blank cursor */ blank = XCreateBitmapFromData( m_display, - RootWindow(m_display, DefaultScreen(m_display)), + RootWindow(m_display, m_visualInfo->screen), data, 1, 1 ); @@ -1356,7 +1539,7 @@ setWindowCustomCursorShape( int fg_color, int bg_color) { - Colormap colormap = DefaultColormap(m_display, DefaultScreen(m_display)); + Colormap colormap = DefaultColormap(m_display, m_visualInfo->screen); Pixmap bitmap_pix, mask_pix; XColor fg, bg; |