bool CWinSystemX11::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop) { m_userOutput = CSettings::GetInstance().GetString(CSettings::SETTING_VIDEOSCREEN_MONITOR); XOutput *out = NULL; if (m_userOutput.compare("Default") != 0) { out = g_xrandr.GetOutput(m_userOutput); if (out) { XMode mode = g_xrandr.GetCurrentMode(m_userOutput); if (!mode.isCurrent) { out = NULL; } } } if (!out) { std::vector<XOutput> outputs = g_xrandr.GetModes(); if (outputs.size() > 0) { m_userOutput = outputs[0].name; } } if(m_nWidth == newWidth && m_nHeight == newHeight && m_userOutput.compare(m_currentOutput) == 0) { UpdateCrtc(); return true; } if (!SetWindow(newWidth, newHeight, false, m_userOutput)) { return false; } m_nWidth = newWidth; m_nHeight = newHeight; m_bFullScreen = false; m_currentOutput = m_userOutput; return false; }
bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const std::string &output, int *winstate) { bool changeWindow = false; bool changeSize = false; float mouseX = 0.5; float mouseY = 0.5; if (!m_mainWindow) { CInputManager::GetInstance().SetMouseActive(false); } if (m_mainWindow && ((m_bFullScreen != fullscreen) || m_currentOutput.compare(output) != 0 || m_windowDirty)) { // set mouse to last known position // we can't trust values after an xrr event if (m_bIsInternalXrr && m_MouseX >= 0 && m_MouseY >= 0) { mouseX = (float)m_MouseX/m_nWidth; mouseY = (float)m_MouseY/m_nHeight; } else if (!m_windowDirty) { Window root_return, child_return; int root_x_return, root_y_return; int win_x_return, win_y_return; unsigned int mask_return; bool isInWin = XQueryPointer(m_dpy, m_mainWindow, &root_return, &child_return, &root_x_return, &root_y_return, &win_x_return, &win_y_return, &mask_return); if (isInWin) { mouseX = (float)win_x_return/m_nWidth; mouseY = (float)win_y_return/m_nHeight; } } CInputManager::GetInstance().SetMouseActive(false); OnLostDevice(); DestroyWindow(); m_windowDirty = true; } // create main window if (!m_mainWindow) { EnableSystemScreenSaver(false); Colormap cmap; XSetWindowAttributes swa; XVisualInfo *vi; int x0 = 0; int y0 = 0; XOutput *out = g_xrandr.GetOutput(output); if (!out) out = g_xrandr.GetOutput(m_currentOutput); if (out) { m_nScreen = out->screen; x0 = out->x; y0 = out->y; } vi = GetVisual(); if (!vi) { CLog::Log(LOGERROR, "Failed to find matching visual"); return false; } cmap = XCreateColormap(m_dpy, RootWindow(m_dpy, vi->screen), vi->visual, AllocNone); bool hasWM = HasWindowManager(); int def_vis = (vi->visual == DefaultVisual(m_dpy, vi->screen)); swa.override_redirect = hasWM ? False : True; swa.border_pixel = fullscreen ? 0 : 5; swa.background_pixel = def_vis ? BlackPixel(m_dpy, vi->screen) : 0; swa.colormap = cmap; swa.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | PropertyChangeMask | StructureNotifyMask | KeymapStateMask | EnterWindowMask | LeaveWindowMask | ExposureMask; unsigned long mask = CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect | CWEventMask; m_mainWindow = XCreateWindow(m_dpy, RootWindow(m_dpy, vi->screen), x0, y0, width, height, 0, vi->depth, InputOutput, vi->visual, mask, &swa); swa.override_redirect = False; swa.border_pixel = 0; swa.event_mask = ExposureMask; mask = CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect | CWColormap | CWEventMask; m_glWindow = XCreateWindow(m_dpy, m_mainWindow, 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual, mask, &swa); if (fullscreen && hasWM) { Atom fs = XInternAtom(m_dpy, "_NET_WM_STATE_FULLSCREEN", True); XChangeProperty(m_dpy, m_mainWindow, XInternAtom(m_dpy, "_NET_WM_STATE", True), XA_ATOM, 32, PropModeReplace, (unsigned char *) &fs, 1); // disable desktop compositing for KDE, when Kodi is in full-screen mode int one = 1; XChangeProperty(m_dpy, m_mainWindow, XInternAtom(m_dpy, "_KDE_NET_WM_BLOCK_COMPOSITING", True), XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &one, 1); } // define invisible cursor Pixmap bitmapNoData; XColor black; static char noData[] = { 0,0,0,0,0,0,0,0 }; black.red = black.green = black.blue = 0; bitmapNoData = XCreateBitmapFromData(m_dpy, m_mainWindow, noData, 8, 8); m_invisibleCursor = XCreatePixmapCursor(m_dpy, bitmapNoData, bitmapNoData, &black, &black, 0, 0); XFreePixmap(m_dpy, bitmapNoData); XDefineCursor(m_dpy,m_mainWindow, m_invisibleCursor); XFree(vi); //init X11 events CWinEventsX11Imp::Init(m_dpy, m_mainWindow); changeWindow = true; changeSize = true; } if (!CWinEventsX11Imp::HasStructureChanged() && ((width != m_nWidth) || (height != m_nHeight))) { changeSize = true; } if (changeSize || changeWindow) { XResizeWindow(m_dpy, m_mainWindow, width, height); } if ((width != m_nWidth) || (height != m_nHeight) || changeWindow) { XResizeWindow(m_dpy, m_glWindow, width, height); } if (changeWindow) { m_icon = None; { CreateIconPixmap(); XWMHints *wm_hints; XClassHint *class_hints; XTextProperty windowName, iconName; std::string titleString = CCompileInfo::GetAppName(); std::string classString = titleString; char *title = (char*)titleString.c_str(); XStringListToTextProperty(&title, 1, &windowName); XStringListToTextProperty(&title, 1, &iconName); wm_hints = XAllocWMHints(); wm_hints->initial_state = NormalState; wm_hints->icon_pixmap = m_icon; wm_hints->flags = StateHint | IconPixmapHint; class_hints = XAllocClassHint(); class_hints->res_class = (char*)classString.c_str(); class_hints->res_name = (char*)classString.c_str(); XSetWMProperties(m_dpy, m_mainWindow, &windowName, &iconName, NULL, 0, NULL, wm_hints, class_hints); XFree(class_hints); XFree(wm_hints); // register interest in the delete window message Atom wmDeleteMessage = XInternAtom(m_dpy, "WM_DELETE_WINDOW", False); XSetWMProtocols(m_dpy, m_mainWindow, &wmDeleteMessage, 1); } // placement of window may follow mouse XWarpPointer(m_dpy, None, m_mainWindow, 0, 0, 0, 0, mouseX*width, mouseY*height); XMapRaised(m_dpy, m_glWindow); XMapRaised(m_dpy, m_mainWindow); // discard events generated by creating the window, i.e. xrr events XSync(m_dpy, TRUE); if (winstate) *winstate = 1; } UpdateCrtc(); return true; }
bool CWinSystemX11::SetWindow(int width, int height, bool fullscreen, const std::string &output) { bool changeWindow = false; bool changeSize = false; float mouseX = 0.5; float mouseY = 0.5; if (!m_mainWindow) { CInputManager::GetInstance().SetMouseActive(false); } if (m_mainWindow && ((m_bFullScreen != fullscreen) || m_currentOutput.compare(output) != 0 || m_windowDirty)) { // set mouse to last known position // we can't trust values after an xrr event if (m_bIsInternalXrr && m_MouseX >= 0 && m_MouseY >= 0) { mouseX = (float)m_MouseX/m_nWidth; mouseY = (float)m_MouseY/m_nHeight; } else if (!m_windowDirty) { Window root_return, child_return; int root_x_return, root_y_return; int win_x_return, win_y_return; unsigned int mask_return; bool isInWin = XQueryPointer(m_dpy, m_mainWindow, &root_return, &child_return, &root_x_return, &root_y_return, &win_x_return, &win_y_return, &mask_return); if (isInWin) { mouseX = (float)win_x_return/m_nWidth; mouseY = (float)win_y_return/m_nHeight; } } CInputManager::GetInstance().SetMouseActive(false); OnLostDevice(); DestroyWindow(); m_windowDirty = true; } // create main window if (!m_mainWindow) { EnableSystemScreenSaver(false); #if defined(HAS_GLX) GLint att[] = { GLX_RGBA, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None }; #endif #if defined(HAS_EGL) EGLint att[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_BUFFER_SIZE, 32, EGL_DEPTH_SIZE, 24, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; #endif Colormap cmap; XSetWindowAttributes swa; XVisualInfo *vi; int x0 = 0; int y0 = 0; XOutput *out = g_xrandr.GetOutput(output); if (!out) out = g_xrandr.GetOutput(m_currentOutput); if (out) { m_nScreen = out->screen; x0 = out->x; y0 = out->y; } #if defined(HAS_GLX) vi = glXChooseVisual(m_dpy, m_nScreen, att); #endif #if defined(HAS_EGL) if (m_eglDisplay == EGL_NO_DISPLAY) { m_eglDisplay = eglGetDisplay((EGLNativeDisplayType)m_dpy); if (m_eglDisplay == EGL_NO_DISPLAY) { CLog::Log(LOGERROR, "failed to get egl display\n"); return false; } if (!eglInitialize(m_eglDisplay, NULL, NULL)) { CLog::Log(LOGERROR, "failed to initialize egl display\n"); return false; } } EGLint numConfigs; EGLConfig eglConfig = 0; if (!eglChooseConfig(m_eglDisplay, att, &eglConfig, 1, &numConfigs) || numConfigs == 0) { CLog::Log(LOGERROR, "Failed to choose a config %d\n", eglGetError()); } m_eglConfig=eglConfig; EGLint eglVisualid; if (!eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_NATIVE_VISUAL_ID, &eglVisualid)) { CLog::Log(LOGERROR, "Failed to query native visual id\n"); } XVisualInfo x11_visual_info_template; x11_visual_info_template.visualid = eglVisualid; int num_visuals; vi = XGetVisualInfo(m_dpy, VisualIDMask, &x11_visual_info_template, &num_visuals); #endif if(!vi) { CLog::Log(LOGERROR, "Failed to find matching visual"); return false; } cmap = XCreateColormap(m_dpy, RootWindow(m_dpy, vi->screen), vi->visual, AllocNone); bool hasWM = HasWindowManager(); int def_vis = (vi->visual == DefaultVisual(m_dpy, vi->screen)); swa.override_redirect = hasWM ? False : True; swa.border_pixel = fullscreen ? 0 : 5; swa.background_pixel = def_vis ? BlackPixel(m_dpy, vi->screen) : 0; swa.colormap = cmap; swa.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | PropertyChangeMask | StructureNotifyMask | KeymapStateMask | EnterWindowMask | LeaveWindowMask | ExposureMask; unsigned long mask = CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect | CWEventMask; m_mainWindow = XCreateWindow(m_dpy, RootWindow(m_dpy, vi->screen), x0, y0, width, height, 0, vi->depth, InputOutput, vi->visual, mask, &swa); swa.override_redirect = False; swa.border_pixel = 0; swa.event_mask = ExposureMask; mask = CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect | CWColormap | CWEventMask; m_glWindow = XCreateWindow(m_dpy, m_mainWindow, 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual, mask, &swa); if (fullscreen && hasWM) { Atom fs = XInternAtom(m_dpy, "_NET_WM_STATE_FULLSCREEN", True); XChangeProperty(m_dpy, m_mainWindow, XInternAtom(m_dpy, "_NET_WM_STATE", True), XA_ATOM, 32, PropModeReplace, (unsigned char *) &fs, 1); // disable desktop compositing for KDE, when Kodi is in full-screen mode int one = 1; XChangeProperty(m_dpy, m_mainWindow, XInternAtom(m_dpy, "_KDE_NET_WM_BLOCK_COMPOSITING", True), XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &one, 1); } // define invisible cursor Pixmap bitmapNoData; XColor black; static char noData[] = { 0,0,0,0,0,0,0,0 }; black.red = black.green = black.blue = 0; bitmapNoData = XCreateBitmapFromData(m_dpy, m_mainWindow, noData, 8, 8); m_invisibleCursor = XCreatePixmapCursor(m_dpy, bitmapNoData, bitmapNoData, &black, &black, 0, 0); XFreePixmap(m_dpy, bitmapNoData); XDefineCursor(m_dpy,m_mainWindow, m_invisibleCursor); //init X11 events CWinEventsX11Imp::Init(m_dpy, m_mainWindow); changeWindow = true; changeSize = true; #if defined(HAS_EGL) m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, m_glWindow, NULL); if (m_eglSurface == EGL_NO_SURFACE) { CLog::Log(LOGERROR, "failed to create egl window surface\n"); return false; } #endif } if (!CWinEventsX11Imp::HasStructureChanged() && ((width != m_nWidth) || (height != m_nHeight))) { changeSize = true; } if (changeSize || changeWindow) { XResizeWindow(m_dpy, m_mainWindow, width, height); } if ((width != m_nWidth) || (height != m_nHeight) || changeWindow) { XResizeWindow(m_dpy, m_glWindow, width, height); } if (changeWindow) { m_icon = None; { CreateIconPixmap(); XWMHints *wm_hints; XClassHint *class_hints; XTextProperty windowName, iconName; std::string titleString = CCompileInfo::GetAppName(); std::string classString = titleString; char *title = (char*)titleString.c_str(); XStringListToTextProperty(&title, 1, &windowName); XStringListToTextProperty(&title, 1, &iconName); wm_hints = XAllocWMHints(); wm_hints->initial_state = NormalState; wm_hints->icon_pixmap = m_icon; wm_hints->flags = StateHint | IconPixmapHint; class_hints = XAllocClassHint(); class_hints->res_class = (char*)classString.c_str(); class_hints->res_name = (char*)classString.c_str(); XSetWMProperties(m_dpy, m_mainWindow, &windowName, &iconName, NULL, 0, NULL, wm_hints, class_hints); XFree(class_hints); XFree(wm_hints); // register interest in the delete window message Atom wmDeleteMessage = XInternAtom(m_dpy, "WM_DELETE_WINDOW", False); XSetWMProtocols(m_dpy, m_mainWindow, &wmDeleteMessage, 1); } // placement of window may follow mouse XWarpPointer(m_dpy, None, m_mainWindow, 0, 0, 0, 0, mouseX*width, mouseY*height); XMapRaised(m_dpy, m_glWindow); XMapRaised(m_dpy, m_mainWindow); // discard events generated by creating the window, i.e. xrr events XSync(m_dpy, TRUE); CDirtyRegionList dr; RefreshGlxContext(m_currentOutput.compare(output) != 0); XSync(m_dpy, FALSE); g_graphicsContext.Clear(0); g_graphicsContext.Flip(dr); #if defined(HAS_GLX) g_Windowing.ResetVSync(); #endif m_windowDirty = false; m_bIsInternalXrr = false; // what's this??? #if defined(HAS_GLX) CSingleLock lock(m_resourceSection); // tell any shared resources for (std::vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); ++i) (*i)->OnResetDevice(); #endif } UpdateCrtc(); return true; }