Modernize memory management of X11 types

This commit is contained in:
Chris Thrasher 2023-04-29 19:50:01 -06:00
parent b391be2316
commit 27542637aa
7 changed files with 232 additions and 180 deletions

View File

@ -123,6 +123,7 @@ elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD OR SFML_OS_NETBSD)
${SRCROOT}/Unix/SensorImpl.hpp ${SRCROOT}/Unix/SensorImpl.hpp
${SRCROOT}/Unix/Display.cpp ${SRCROOT}/Unix/Display.cpp
${SRCROOT}/Unix/Display.hpp ${SRCROOT}/Unix/Display.hpp
${SRCROOT}/Unix/Utils.hpp
${SRCROOT}/Unix/VideoModeImpl.cpp ${SRCROOT}/Unix/VideoModeImpl.cpp
${SRCROOT}/Unix/VulkanImplX11.cpp ${SRCROOT}/Unix/VulkanImplX11.cpp
${SRCROOT}/Unix/VulkanImplX11.hpp ${SRCROOT}/Unix/VulkanImplX11.hpp

View File

@ -39,6 +39,8 @@
#include <SFML/System/Android/Activity.hpp> #include <SFML/System/Android/Activity.hpp>
#endif #endif
#if defined(SFML_SYSTEM_LINUX) && !defined(SFML_USE_DRM) #if defined(SFML_SYSTEM_LINUX) && !defined(SFML_USE_DRM)
#include <SFML/Window/Unix/Utils.hpp>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#endif #endif
@ -424,10 +426,8 @@ XVisualInfo EglContext::selectBestVisual(::Display* XDisplay, unsigned int bitsP
vTemplate.visualid = static_cast<VisualID>(nativeVisualId); vTemplate.visualid = static_cast<VisualID>(nativeVisualId);
// Get X11 visuals compatible with this EGL config // Get X11 visuals compatible with this EGL config
XVisualInfo *availableVisuals, bestVisual;
int visualCount = 0; int visualCount = 0;
auto availableVisuals = X11Ptr<XVisualInfo[]> XGetVisualInfo(XDisplay, VisualIDMask, &vTemplate, &visualCount));
availableVisuals = XGetVisualInfo(XDisplay, VisualIDMask, &vTemplate, &visualCount);
if (visualCount == 0) if (visualCount == 0)
{ {
@ -438,10 +438,7 @@ XVisualInfo EglContext::selectBestVisual(::Display* XDisplay, unsigned int bitsP
} }
// Pick up the best one // Pick up the best one
bestVisual = availableVisuals[0]; return availableVisuals[0];
XFree(availableVisuals);
return bestVisual;
} }
#endif #endif

View File

@ -27,6 +27,7 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Window/Unix/CursorImpl.hpp> #include <SFML/Window/Unix/CursorImpl.hpp>
#include <SFML/Window/Unix/Display.hpp> #include <SFML/Window/Unix/Display.hpp>
#include <SFML/Window/Unix/Utils.hpp>
#include <X11/Xcursor/Xcursor.h> #include <X11/Xcursor/Xcursor.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
@ -39,6 +40,15 @@
namespace sf::priv namespace sf::priv
{ {
template <>
struct XDeleter<XcursorImage>
{
void operator()(XcursorImage* cursorImage) const
{
XcursorImageDestroy(cursorImage);
}
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
CursorImpl::CursorImpl() : m_display(openDisplay()) CursorImpl::CursorImpl() : m_display(openDisplay())
@ -71,7 +81,7 @@ bool CursorImpl::loadFromPixels(const std::uint8_t* pixels, Vector2u size, Vecto
bool CursorImpl::loadFromPixelsARGB(const std::uint8_t* pixels, Vector2u size, Vector2u hotspot) bool CursorImpl::loadFromPixelsARGB(const std::uint8_t* pixels, Vector2u size, Vector2u hotspot)
{ {
// Create cursor image, convert from RGBA to ARGB. // Create cursor image, convert from RGBA to ARGB.
XcursorImage* cursorImage = XcursorImageCreate(static_cast<int>(size.x), static_cast<int>(size.y)); auto cursorImage = X11Ptr<XcursorImage>(XcursorImageCreate(static_cast<int>(size.x), static_cast<int>(size.y)));
cursorImage->xhot = hotspot.x; cursorImage->xhot = hotspot.x;
cursorImage->yhot = hotspot.y; cursorImage->yhot = hotspot.y;
@ -84,10 +94,7 @@ bool CursorImpl::loadFromPixelsARGB(const std::uint8_t* pixels, Vector2u size, V
} }
// Create the cursor. // Create the cursor.
m_cursor = XcursorImageLoadCursor(m_display, cursorImage); m_cursor = XcursorImageLoadCursor(m_display, cursorImage.get());
// Free the resources
XcursorImageDestroy(cursorImage);
// We assume everything went fine... // We assume everything went fine...
return true; return true;

View File

@ -28,6 +28,7 @@
#include <SFML/Window/Unix/Display.hpp> #include <SFML/Window/Unix/Display.hpp>
#include <SFML/Window/Unix/GlxContext.hpp> #include <SFML/Window/Unix/GlxContext.hpp>
#include <SFML/Window/Unix/Utils.hpp>
#include <SFML/Window/Unix/WindowImplX11.hpp> #include <SFML/Window/Unix/WindowImplX11.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
@ -315,13 +316,13 @@ XVisualInfo GlxContext::selectBestVisual(::Display* display, unsigned int bitsPe
// Retrieve all the visuals // Retrieve all the visuals
int count; int count;
XVisualInfo* visuals = XGetVisualInfo(display, 0, nullptr, &count); auto visuals = X11Ptr<XVisualInfo[]>(XGetVisualInfo(display, 0, nullptr, &count));
if (visuals) if (visuals)
{ {
// Evaluate all the returned visuals, and pick the best one // Evaluate all the returned visuals, and pick the best one
int bestScore = 0x7FFFFFFF; int bestScore = 0x7FFFFFFF;
XVisualInfo bestVisual = XVisualInfo(); XVisualInfo bestVisual = XVisualInfo();
for (int i = 0; i < count; ++i) for (std::size_t i = 0; i < static_cast<std::size_t>(count); ++i)
{ {
// Filter by screen // Filter by screen
if (visuals[i].screen != screen) if (visuals[i].screen != screen)
@ -392,9 +393,6 @@ XVisualInfo GlxContext::selectBestVisual(::Display* display, unsigned int bitsPe
} }
} }
// Free the array of visuals
XFree(visuals);
return bestVisual; return bestVisual;
} }
else else
@ -462,14 +460,12 @@ void GlxContext::updateSettingsFromWindow()
tpl.screen = DefaultScreen(m_display); tpl.screen = DefaultScreen(m_display);
tpl.visualid = XVisualIDFromVisual(windowAttributes.visual); tpl.visualid = XVisualIDFromVisual(windowAttributes.visual);
int nbVisuals = 0; int nbVisuals = 0;
XVisualInfo* visualInfo = XGetVisualInfo(m_display, VisualIDMask | VisualScreenMask, &tpl, &nbVisuals); auto visualInfo = X11Ptr<XVisualInfo>(XGetVisualInfo(m_display, VisualIDMask | VisualScreenMask, &tpl, &nbVisuals));
if (!visualInfo) if (!visualInfo)
return; return;
updateSettingsFromVisualInfo(visualInfo); updateSettingsFromVisualInfo(visualInfo.get());
XFree(visualInfo);
} }
@ -500,11 +496,12 @@ void GlxContext::createSurface(GlxContext* shared, const Vector2u& size, unsigne
// the visual we are matching against was already // the visual we are matching against was already
// deemed suitable in selectBestVisual() // deemed suitable in selectBestVisual()
int nbConfigs = 0; int nbConfigs = 0;
GLXFBConfig* configs = glXChooseFBConfig(m_display, DefaultScreen(m_display), nullptr, &nbConfigs); auto configs = X11Ptr<GLXFBConfig[]>(
glXChooseFBConfig(m_display, DefaultScreen(m_display), nullptr, &nbConfigs));
for (int i = 0; configs && (i < nbConfigs); ++i) for (std::size_t i = 0; configs && (i < static_cast<std::size_t>(nbConfigs)); ++i)
{ {
XVisualInfo* visual = glXGetVisualFromFBConfig(m_display, configs[i]); auto visual = X11Ptr<XVisualInfo>(glXGetVisualFromFBConfig(m_display, configs[i]));
if (!visual) if (!visual)
continue; continue;
@ -512,11 +509,8 @@ void GlxContext::createSurface(GlxContext* shared, const Vector2u& size, unsigne
if (visual->visualid == visualInfo.visualid) if (visual->visualid == visualInfo.visualid)
{ {
config = &configs[i]; config = &configs[i];
XFree(visual);
break; break;
} }
XFree(visual);
} }
if (config) if (config)
@ -528,13 +522,8 @@ void GlxContext::createSurface(GlxContext* shared, const Vector2u& size, unsigne
updateSettingsFromVisualInfo(&visualInfo); updateSettingsFromVisualInfo(&visualInfo);
XFree(configs);
return; return;
} }
if (configs)
XFree(configs);
} }
} }
@ -583,7 +572,7 @@ void GlxContext::createContext(GlxContext* shared)
// Get a working copy of the context settings // Get a working copy of the context settings
const ContextSettings settings = m_settings; const ContextSettings settings = m_settings;
XVisualInfo* visualInfo = nullptr; X11Ptr<XVisualInfo> visualInfo;
if (m_pbuffer) if (m_pbuffer)
{ {
@ -594,13 +583,10 @@ void GlxContext::createContext(GlxContext* shared)
int attributes[] = {GLX_FBCONFIG_ID, static_cast<int>(fbConfigId), 0, 0}; int attributes[] = {GLX_FBCONFIG_ID, static_cast<int>(fbConfigId), 0, 0};
int count = 0; int count = 0;
GLXFBConfig* fbconfig = glXChooseFBConfig(m_display, DefaultScreen(m_display), attributes, &count); auto fbconfig = X11Ptr<GLXFBConfig>(glXChooseFBConfig(m_display, DefaultScreen(m_display), attributes, &count));
if (count == 1) if (count == 1)
visualInfo = glXGetVisualFromFBConfig(m_display, *fbconfig); visualInfo = X11Ptr<XVisualInfo>(glXGetVisualFromFBConfig(m_display, *fbconfig));
if (fbconfig)
XFree(fbconfig);
} }
else else
{ {
@ -617,7 +603,7 @@ void GlxContext::createContext(GlxContext* shared)
tpl.screen = DefaultScreen(m_display); tpl.screen = DefaultScreen(m_display);
tpl.visualid = XVisualIDFromVisual(windowAttributes.visual); tpl.visualid = XVisualIDFromVisual(windowAttributes.visual);
int nbVisuals = 0; int nbVisuals = 0;
visualInfo = XGetVisualInfo(m_display, VisualIDMask | VisualScreenMask, &tpl, &nbVisuals); visualInfo = X11Ptr<XVisualInfo>(XGetVisualInfo(m_display, VisualIDMask | VisualScreenMask, &tpl, &nbVisuals));
} }
if (!visualInfo) if (!visualInfo)
@ -649,11 +635,11 @@ void GlxContext::createContext(GlxContext* shared)
// the visual we are matching against was already // the visual we are matching against was already
// deemed suitable in selectBestVisual() // deemed suitable in selectBestVisual()
int nbConfigs = 0; int nbConfigs = 0;
GLXFBConfig* configs = glXChooseFBConfig(m_display, DefaultScreen(m_display), nullptr, &nbConfigs); auto configs = X11Ptr<GLXFBConfig[]>(glXChooseFBConfig(m_display, DefaultScreen(m_display), nullptr, &nbConfigs));
for (int i = 0; configs && (i < nbConfigs); ++i) for (std::size_t i = 0; configs && (i < static_cast<std::size_t>(nbConfigs)); ++i)
{ {
XVisualInfo* visual = glXGetVisualFromFBConfig(m_display, configs[i]); auto visual = X11Ptr<XVisualInfo>(glXGetVisualFromFBConfig(m_display, configs[i]));
if (!visual) if (!visual)
continue; continue;
@ -661,11 +647,8 @@ void GlxContext::createContext(GlxContext* shared)
if (visual->visualid == visualInfo->visualid) if (visual->visualid == visualInfo->visualid)
{ {
config = &configs[i]; config = &configs[i];
XFree(visual);
break; break;
} }
XFree(visual);
} }
if (!config) if (!config)
@ -753,9 +736,6 @@ void GlxContext::createContext(GlxContext* shared)
} }
} }
} }
if (configs)
XFree(configs);
} }
// If glXCreateContextAttribsARB failed, use glXCreateContext // If glXCreateContextAttribsARB failed, use glXCreateContext
@ -780,7 +760,7 @@ void GlxContext::createContext(GlxContext* shared)
} }
// Create the context, using the target window's visual // Create the context, using the target window's visual
m_context = glXCreateContext(m_display, visualInfo, toShare, true); m_context = glXCreateContext(m_display, visualInfo.get(), toShare, true);
#if defined(GLX_DEBUGGING) #if defined(GLX_DEBUGGING)
if (glxErrorOccurred) if (glxErrorOccurred)
@ -790,9 +770,6 @@ void GlxContext::createContext(GlxContext* shared)
if (!m_context) if (!m_context)
err() << "Failed to create an OpenGL context for this window" << std::endl; err() << "Failed to create an OpenGL context for this window" << std::endl;
// Free the visual info
XFree(visualInfo);
} }
} // namespace sf::priv } // namespace sf::priv

View File

@ -0,0 +1,61 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2023 Laurent Gomila (laurent@sfml-dev.org)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
#pragma once
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <X11/Xlib.h>
#include <memory>
#include <type_traits>
namespace sf::priv
{
////////////////////////////////////////////////////////////
/// \brief Class template for freeing X11 pointers
///
/// Specialized elsewhere for types that are freed through
/// other means than XFree(). XFree() is the most common use
/// case though so it is the default.
///
////////////////////////////////////////////////////////////
template <typename T>
struct XDeleter
{
void operator()(T* data) const
{
XFree(data);
}
};
////////////////////////////////////////////////////////////
/// \brief Class template for wrapping owning raw pointers from X11
///
////////////////////////////////////////////////////////////
template <typename T>
using X11Ptr = std::unique_ptr<T, XDeleter<std::remove_all_extents_t<T>>>;
} // namespace sf::priv

View File

@ -26,6 +26,7 @@
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Window/Unix/Display.hpp> #include <SFML/Window/Unix/Display.hpp>
#include <SFML/Window/Unix/Utils.hpp>
#include <SFML/Window/VideoModeImpl.hpp> #include <SFML/Window/VideoModeImpl.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
@ -39,6 +40,17 @@
namespace sf::priv namespace sf::priv
{ {
////////////////////////////////////////////////////////////
template <>
struct XDeleter<XRRScreenConfiguration>
{
void operator()(XRRScreenConfiguration* config) const
{
XRRFreeScreenConfigInfo(config);
}
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
std::vector<VideoMode> VideoModeImpl::getFullscreenModes() std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
{ {
@ -56,21 +68,21 @@ std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
if (XQueryExtension(display, "RANDR", &version, &version, &version)) if (XQueryExtension(display, "RANDR", &version, &version, &version))
{ {
// Get the current configuration // Get the current configuration
XRRScreenConfiguration* config = XRRGetScreenInfo(display, RootWindow(display, screen)); auto config = X11Ptr<XRRScreenConfiguration>(XRRGetScreenInfo(display, RootWindow(display, screen)));
if (config) if (config)
{ {
// Get the available screen sizes // Get the available screen sizes
int nbSizes; int nbSizes;
XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes); XRRScreenSize* sizes = XRRConfigSizes(config.get(), &nbSizes);
if (sizes && (nbSizes > 0)) if (sizes && (nbSizes > 0))
{ {
// Get the list of supported depths // Get the list of supported depths
int nbDepths = 0; int nbDepths = 0;
int* depths = XListDepths(display, screen, &nbDepths); auto depths = X11Ptr<int[]>(XListDepths(display, screen, &nbDepths));
if (depths && (nbDepths > 0)) if (depths && (nbDepths > 0))
{ {
// Combine depths and sizes to fill the array of supported modes // Combine depths and sizes to fill the array of supported modes
for (int i = 0; i < nbDepths; ++i) for (std::size_t i = 0; i < static_cast<std::size_t>(nbDepths); ++i)
{ {
for (int j = 0; j < nbSizes; ++j) for (int j = 0; j < nbSizes; ++j)
{ {
@ -80,7 +92,7 @@ std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
static_cast<unsigned int>(depths[i])); static_cast<unsigned int>(depths[i]));
Rotation currentRotation; Rotation currentRotation;
XRRConfigRotations(config, &currentRotation); XRRConfigRotations(config.get(), &currentRotation);
if (currentRotation == RR_Rotate_90 || currentRotation == RR_Rotate_270) if (currentRotation == RR_Rotate_90 || currentRotation == RR_Rotate_270)
std::swap(mode.size.x, mode.size.y); std::swap(mode.size.x, mode.size.y);
@ -90,14 +102,8 @@ std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
modes.push_back(mode); modes.push_back(mode);
} }
} }
// Free the array of depths
XFree(depths);
} }
} }
// Free the configuration instance
XRRFreeScreenConfigInfo(config);
} }
else else
{ {
@ -142,16 +148,16 @@ VideoMode VideoModeImpl::getDesktopMode()
if (XQueryExtension(display, "RANDR", &version, &version, &version)) if (XQueryExtension(display, "RANDR", &version, &version, &version))
{ {
// Get the current configuration // Get the current configuration
XRRScreenConfiguration* config = XRRGetScreenInfo(display, RootWindow(display, screen)); auto config = X11Ptr<XRRScreenConfiguration>(XRRGetScreenInfo(display, RootWindow(display, screen)));
if (config) if (config)
{ {
// Get the current video mode // Get the current video mode
Rotation currentRotation; Rotation currentRotation;
const int currentMode = XRRConfigCurrentConfiguration(config, &currentRotation); const int currentMode = XRRConfigCurrentConfiguration(config.get(), &currentRotation);
// Get the available screen sizes // Get the available screen sizes
int nbSizes; int nbSizes;
XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes); XRRScreenSize* sizes = XRRConfigSizes(config.get(), &nbSizes);
if (sizes && (nbSizes > 0)) if (sizes && (nbSizes > 0))
{ {
desktopMode = VideoMode({static_cast<unsigned int>(sizes[currentMode].width), desktopMode = VideoMode({static_cast<unsigned int>(sizes[currentMode].width),
@ -159,14 +165,11 @@ VideoMode VideoModeImpl::getDesktopMode()
static_cast<unsigned int>(DefaultDepth(display, screen))); static_cast<unsigned int>(DefaultDepth(display, screen)));
Rotation modeRotation; Rotation modeRotation;
XRRConfigRotations(config, &modeRotation); XRRConfigRotations(config.get(), &modeRotation);
if (modeRotation == RR_Rotate_90 || modeRotation == RR_Rotate_270) if (modeRotation == RR_Rotate_90 || modeRotation == RR_Rotate_270)
std::swap(desktopMode.size.x, desktopMode.size.y); std::swap(desktopMode.size.x, desktopMode.size.y);
} }
// Free the configuration instance
XRRFreeScreenConfigInfo(config);
} }
else else
{ {

View File

@ -30,6 +30,7 @@
#include <SFML/Window/Unix/Display.hpp> #include <SFML/Window/Unix/Display.hpp>
#include <SFML/Window/Unix/InputImpl.hpp> #include <SFML/Window/Unix/InputImpl.hpp>
#include <SFML/Window/Unix/KeyboardImpl.hpp> #include <SFML/Window/Unix/KeyboardImpl.hpp>
#include <SFML/Window/Unix/Utils.hpp>
#include <SFML/Window/Unix/WindowImplX11.hpp> #include <SFML/Window/Unix/WindowImplX11.hpp>
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
@ -374,6 +375,50 @@ bool isWMAbsolutePositionGood()
namespace sf::priv namespace sf::priv
{ {
////////////////////////////////////////////////////////////
template <>
struct XDeleter<XImage>
{
void operator()(XImage* image) const
{
XDestroyImage(image);
}
};
////////////////////////////////////////////////////////////
template <>
struct XDeleter<XRRScreenResources>
{
void operator()(XRRScreenResources* res) const
{
XRRFreeScreenResources(res);
}
};
////////////////////////////////////////////////////////////
template <>
struct XDeleter<XRROutputInfo>
{
void operator()(XRROutputInfo* outputInfo) const
{
XRRFreeOutputInfo(outputInfo);
}
};
////////////////////////////////////////////////////////////
template <>
struct XDeleter<XRRCrtcInfo>
{
void operator()(XRRCrtcInfo* crtcInfo) const
{
XRRFreeCrtcInfo(crtcInfo);
}
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
WindowImplX11::WindowImplX11(WindowHandle handle) : m_isExternal(true) WindowImplX11::WindowImplX11(WindowHandle handle) : m_isExternal(true)
{ {
@ -486,11 +531,10 @@ m_cursorGrabbed(m_fullscreen)
setProtocols(); setProtocols();
// Set the WM initial state to the normal state // Set the WM initial state to the normal state
XWMHints* xHints = XAllocWMHints(); XWMHints xHints{};
xHints->flags = StateHint; xHints.flags = StateHint;
xHints->initial_state = NormalState; xHints.initial_state = NormalState;
XSetWMHints(m_display, m_window, xHints); XSetWMHints(m_display, m_window, &xHints);
XFree(xHints);
// If not in fullscreen, set the window's style (tell the window manager to // If not in fullscreen, set the window's style (tell the window manager to
// change our window's decorations and functions according to the requested style) // change our window's decorations and functions according to the requested style)
@ -566,18 +610,17 @@ m_cursorGrabbed(m_fullscreen)
if (!(style & Style::Resize)) if (!(style & Style::Resize))
{ {
m_useSizeHints = true; m_useSizeHints = true;
XSizeHints* sizeHints = XAllocSizeHints(); XSizeHints sizeHints{};
sizeHints->flags = PMinSize | PMaxSize | USPosition; sizeHints.flags = PMinSize | PMaxSize | USPosition;
sizeHints->min_width = sizeHints->max_width = static_cast<int>(width); sizeHints.min_width = sizeHints.max_width = static_cast<int>(width);
sizeHints->min_height = sizeHints->max_height = static_cast<int>(height); sizeHints.min_height = sizeHints.max_height = static_cast<int>(height);
sizeHints->x = windowPosition.x; sizeHints.x = windowPosition.x;
sizeHints->y = windowPosition.y; sizeHints.y = windowPosition.y;
XSetWMNormalHints(m_display, m_window, sizeHints); XSetWMNormalHints(m_display, m_window, &sizeHints);
XFree(sizeHints);
} }
// Set the window's WM class (this can be used by window managers) // Set the window's WM class (this can be used by window managers)
XClassHint* hint = XAllocClassHint(); XClassHint hint{};
// The instance name should be something unique to this invocation // The instance name should be something unique to this invocation
// of the application but is rarely if ever used these days. // of the application but is rarely if ever used these days.
@ -585,7 +628,7 @@ m_cursorGrabbed(m_fullscreen)
std::string executableName = findExecutableName().string(); std::string executableName = findExecutableName().string();
std::vector<char> windowInstance(executableName.size() + 1, 0); std::vector<char> windowInstance(executableName.size() + 1, 0);
std::copy(executableName.begin(), executableName.end(), windowInstance.begin()); std::copy(executableName.begin(), executableName.end(), windowInstance.begin());
hint->res_name = windowInstance.data(); hint.res_name = windowInstance.data();
// The class name identifies a class of windows that // The class name identifies a class of windows that
// "are of the same type". We simply use the initial window name as // "are of the same type". We simply use the initial window name as
@ -593,11 +636,9 @@ m_cursorGrabbed(m_fullscreen)
std::string ansiTitle = title.toAnsiString(); std::string ansiTitle = title.toAnsiString();
std::vector<char> windowClass(ansiTitle.size() + 1, 0); std::vector<char> windowClass(ansiTitle.size() + 1, 0);
std::copy(ansiTitle.begin(), ansiTitle.end(), windowClass.begin()); std::copy(ansiTitle.begin(), ansiTitle.end(), windowClass.begin());
hint->res_class = windowClass.data(); hint.res_class = windowClass.data();
XSetClassHint(m_display, m_window, hint); XSetClassHint(m_display, m_window, &hint);
XFree(hint);
// Set the window's name // Set the window's name
setTitle(title); setTitle(title);
@ -610,12 +651,11 @@ m_cursorGrabbed(m_fullscreen)
{ {
// Disable hint for min and max size, // Disable hint for min and max size,
// otherwise some windows managers will not remove window decorations // otherwise some windows managers will not remove window decorations
XSizeHints* sizeHints = XAllocSizeHints(); XSizeHints sizeHints{};
long flags = 0; long flags = 0;
XGetWMNormalHints(m_display, m_window, sizeHints, &flags); XGetWMNormalHints(m_display, m_window, &sizeHints, &flags);
sizeHints->flags &= ~(PMinSize | PMaxSize); sizeHints.flags &= ~(PMinSize | PMaxSize);
XSetWMNormalHints(m_display, m_window, sizeHints); XSetWMNormalHints(m_display, m_window, &sizeHints);
XFree(sizeHints);
setVideoMode(mode); setVideoMode(mode);
switchToFullscreen(); switchToFullscreen();
@ -841,12 +881,11 @@ void WindowImplX11::setSize(const Vector2u& size)
// If resizing is disable for the window we have to update the size hints (required by some window managers). // If resizing is disable for the window we have to update the size hints (required by some window managers).
if (m_useSizeHints) if (m_useSizeHints)
{ {
XSizeHints* sizeHints = XAllocSizeHints(); XSizeHints sizeHints{};
sizeHints->flags = PMinSize | PMaxSize; sizeHints.flags = PMinSize | PMaxSize;
sizeHints->min_width = sizeHints->max_width = static_cast<int>(size.x); sizeHints.min_width = sizeHints.max_width = static_cast<int>(size.x);
sizeHints->min_height = sizeHints->max_height = static_cast<int>(size.y); sizeHints.min_height = sizeHints.max_height = static_cast<int>(size.y);
XSetWMNormalHints(m_display, m_window, sizeHints); XSetWMNormalHints(m_display, m_window, &sizeHints);
XFree(sizeHints);
} }
XResizeWindow(m_display, m_window, size.x, size.y); XResizeWindow(m_display, m_window, size.x, size.y);
@ -925,7 +964,7 @@ void WindowImplX11::setTitle(const String& title)
void WindowImplX11::setIcon(const Vector2u& size, const std::uint8_t* pixels) void WindowImplX11::setIcon(const Vector2u& size, const std::uint8_t* pixels)
{ {
// X11 wants BGRA pixels: swap red and blue channels // X11 wants BGRA pixels: swap red and blue channels
// Note: this memory will be freed by XDestroyImage // Note: this memory will be freed by X11Ptr<XImage> deleter
auto* iconPixels = static_cast<std::uint8_t*>( auto* iconPixels = static_cast<std::uint8_t*>(
std::malloc(static_cast<std::size_t>(size.x) * static_cast<std::size_t>(size.y) * 4)); std::malloc(static_cast<std::size_t>(size.x) * static_cast<std::size_t>(size.y) * 4));
for (std::size_t i = 0; i < static_cast<std::size_t>(size.x) * static_cast<std::size_t>(size.y); ++i) for (std::size_t i = 0; i < static_cast<std::size_t>(size.x) * static_cast<std::size_t>(size.y); ++i)
@ -939,16 +978,8 @@ void WindowImplX11::setIcon(const Vector2u& size, const std::uint8_t* pixels)
// Create the icon pixmap // Create the icon pixmap
Visual* defVisual = DefaultVisual(m_display, m_screen); Visual* defVisual = DefaultVisual(m_display, m_screen);
auto defDepth = static_cast<unsigned int>(DefaultDepth(m_display, m_screen)); auto defDepth = static_cast<unsigned int>(DefaultDepth(m_display, m_screen));
XImage* iconImage = XCreateImage(m_display, auto iconImage = X11Ptr<XImage>(
defVisual, XCreateImage(m_display, defVisual, defDepth, ZPixmap, 0, reinterpret_cast<char*>(iconPixels), size.x, size.y, 32, 0));
defDepth,
ZPixmap,
0,
reinterpret_cast<char*>(iconPixels),
size.x,
size.y,
32,
0);
if (!iconImage) if (!iconImage)
{ {
err() << "Failed to set the window's icon" << std::endl; err() << "Failed to set the window's icon" << std::endl;
@ -964,9 +995,8 @@ void WindowImplX11::setIcon(const Vector2u& size, const std::uint8_t* pixels)
m_iconPixmap = XCreatePixmap(m_display, RootWindow(m_display, m_screen), size.x, size.y, defDepth); m_iconPixmap = XCreatePixmap(m_display, RootWindow(m_display, m_screen), size.x, size.y, defDepth);
XGCValues values; XGCValues values;
GC iconGC = XCreateGC(m_display, m_iconPixmap, 0, &values); GC iconGC = XCreateGC(m_display, m_iconPixmap, 0, &values);
XPutImage(m_display, m_iconPixmap, iconGC, iconImage, 0, 0, 0, 0, size.x, size.y); XPutImage(m_display, m_iconPixmap, iconGC, iconImage.get(), 0, 0, 0, 0, size.x, size.y);
XFreeGC(m_display, iconGC); XFreeGC(m_display, iconGC);
XDestroyImage(iconImage);
// Create the mask pixmap (must have 1 bit depth) // Create the mask pixmap (must have 1 bit depth)
const std::size_t pitch = (size.x + 7) / 8; const std::size_t pitch = (size.x + 7) / 8;
@ -995,12 +1025,11 @@ void WindowImplX11::setIcon(const Vector2u& size, const std::uint8_t* pixels)
1); 1);
// Send our new icon to the window through the WMHints // Send our new icon to the window through the WMHints
XWMHints* hints = XAllocWMHints(); XWMHints hints{};
hints->flags = IconPixmapHint | IconMaskHint; hints.flags = IconPixmapHint | IconMaskHint;
hints->icon_pixmap = m_iconPixmap; hints.icon_pixmap = m_iconPixmap;
hints->icon_mask = m_iconMaskPixmap; hints.icon_mask = m_iconMaskPixmap;
XSetWMHints(m_display, m_window, hints); XSetWMHints(m_display, m_window, &hints);
XFree(hints);
// ICCCM wants BGRA pixels: swap red and blue channels // ICCCM wants BGRA pixels: swap red and blue channels
// ICCCM also wants the first 2 unsigned 32-bit values to be width and height // ICCCM also wants the first 2 unsigned 32-bit values to be width and height
@ -1170,14 +1199,13 @@ void WindowImplX11::requestFocus()
{ {
// Otherwise: display urgency hint (flashing application logo) // Otherwise: display urgency hint (flashing application logo)
// Ensure WM hints exist, allocate if necessary // Ensure WM hints exist, allocate if necessary
XWMHints* hints = XGetWMHints(m_display, m_window); auto hints = X11Ptr<XWMHints>(XGetWMHints(m_display, m_window));
if (hints == nullptr) if (hints == nullptr)
hints = XAllocWMHints(); hints.reset(XAllocWMHints());
// Add urgency (notification) flag to hints // Add urgency (notification) flag to hints
hints->flags |= XUrgencyHint; hints->flags |= XUrgencyHint;
XSetWMHints(m_display, m_window, hints); XSetWMHints(m_display, m_window, hints.get());
XFree(hints);
} }
} }
@ -1265,35 +1293,27 @@ void WindowImplX11::setVideoMode(const VideoMode& mode)
::Window rootWindow = RootWindow(m_display, m_screen); ::Window rootWindow = RootWindow(m_display, m_screen);
// Get the screen resources // Get the screen resources
XRRScreenResources* res = XRRGetScreenResources(m_display, rootWindow); auto res = X11Ptr<XRRScreenResources>(XRRGetScreenResources(m_display, rootWindow));
if (!res) if (!res)
{ {
err() << "Failed to get the current screen resources for fullscreen mode, switching to window mode" << std::endl; err() << "Failed to get the current screen resources for fullscreen mode, switching to window mode" << std::endl;
return; return;
} }
RROutput output = getOutputPrimary(rootWindow, res, xRandRMajor, xRandRMinor); RROutput output = getOutputPrimary(rootWindow, res.get(), xRandRMajor, xRandRMinor);
// Get output info from output // Get output info from output
XRROutputInfo* outputInfo = XRRGetOutputInfo(m_display, res, output); auto outputInfo = X11Ptr<XRROutputInfo>(XRRGetOutputInfo(m_display, res.get(), output));
if (!outputInfo || outputInfo->connection == RR_Disconnected) if (!outputInfo || outputInfo->connection == RR_Disconnected)
{ {
XRRFreeScreenResources(res);
// If outputInfo->connection == RR_Disconnected, free output info
if (outputInfo)
XRRFreeOutputInfo(outputInfo);
err() << "Failed to get output info for fullscreen mode, switching to window mode" << std::endl; err() << "Failed to get output info for fullscreen mode, switching to window mode" << std::endl;
return; return;
} }
// Retrieve current RRMode, screen position and rotation // Retrieve current RRMode, screen position and rotation
XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(m_display, res, outputInfo->crtc); auto crtcInfo = X11Ptr<XRRCrtcInfo>(XRRGetCrtcInfo(m_display, res.get(), outputInfo->crtc));
if (!crtcInfo) if (!crtcInfo)
{ {
XRRFreeScreenResources(res);
XRRFreeOutputInfo(outputInfo);
err() << "Failed to get crtc info for fullscreen mode, switching to window mode" << std::endl; err() << "Failed to get crtc info for fullscreen mode, switching to window mode" << std::endl;
return; return;
} }
@ -1317,8 +1337,6 @@ void WindowImplX11::setVideoMode(const VideoMode& mode)
if (!modeFound) if (!modeFound)
{ {
XRRFreeScreenResources(res);
XRRFreeOutputInfo(outputInfo);
err() << "Failed to find a matching RRMode for fullscreen mode, switching to window mode" << std::endl; err() << "Failed to find a matching RRMode for fullscreen mode, switching to window mode" << std::endl;
return; return;
} }
@ -1328,14 +1346,19 @@ void WindowImplX11::setVideoMode(const VideoMode& mode)
m_oldRRCrtc = outputInfo->crtc; m_oldRRCrtc = outputInfo->crtc;
// Switch to fullscreen mode // Switch to fullscreen mode
XRRSetCrtcConfig(m_display, res, outputInfo->crtc, CurrentTime, crtcInfo->x, crtcInfo->y, xRandMode, crtcInfo->rotation, &output, 1); XRRSetCrtcConfig(m_display,
res.get(),
outputInfo->crtc,
CurrentTime,
crtcInfo->x,
crtcInfo->y,
xRandMode,
crtcInfo->rotation,
&output,
1);
// Set "this" as the current fullscreen window // Set "this" as the current fullscreen window
fullscreenWindow = this; fullscreenWindow = this;
XRRFreeScreenResources(res);
XRRFreeOutputInfo(outputInfo);
XRRFreeCrtcInfo(crtcInfo);
} }
@ -1352,7 +1375,7 @@ void WindowImplX11::resetVideoMode()
int xRandRMinor; int xRandRMinor;
if (checkXRandR(xRandRMajor, xRandRMinor)) if (checkXRandR(xRandRMajor, xRandRMinor))
{ {
XRRScreenResources* res = XRRGetScreenResources(m_display, DefaultRootWindow(m_display)); auto res = X11Ptr<XRRScreenResources>(XRRGetScreenResources(m_display, DefaultRootWindow(m_display)));
if (!res) if (!res)
{ {
err() << "Failed to get the current screen resources to reset the video mode" << std::endl; err() << "Failed to get the current screen resources to reset the video mode" << std::endl;
@ -1360,10 +1383,9 @@ void WindowImplX11::resetVideoMode()
} }
// Retrieve current screen position and rotation // Retrieve current screen position and rotation
XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(m_display, res, m_oldRRCrtc); auto crtcInfo = X11Ptr<XRRCrtcInfo>(XRRGetCrtcInfo(m_display, res.get(), m_oldRRCrtc));
if (!crtcInfo) if (!crtcInfo)
{ {
XRRFreeScreenResources(res);
err() << "Failed to get crtc info to reset the video mode" << std::endl; err() << "Failed to get crtc info to reset the video mode" << std::endl;
return; return;
} }
@ -1385,7 +1407,7 @@ void WindowImplX11::resetVideoMode()
} }
XRRSetCrtcConfig(m_display, XRRSetCrtcConfig(m_display,
res, res.get(),
m_oldRRCrtc, m_oldRRCrtc,
CurrentTime, CurrentTime,
crtcInfo->x, crtcInfo->x,
@ -1394,9 +1416,6 @@ void WindowImplX11::resetVideoMode()
crtcInfo->rotation, crtcInfo->rotation,
&output, &output,
1); 1);
XRRFreeCrtcInfo(crtcInfo);
XRRFreeScreenResources(res);
} }
// Reset the fullscreen window // Reset the fullscreen window
@ -1695,13 +1714,12 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
pushEvent(event); pushEvent(event);
// If the window has been previously marked urgent (notification) as a result of a focus request, undo that // If the window has been previously marked urgent (notification) as a result of a focus request, undo that
XWMHints* hints = XGetWMHints(m_display, m_window); auto hints = X11Ptr<XWMHints>(XGetWMHints(m_display, m_window));
if (hints != nullptr) if (hints != nullptr)
{ {
// Remove urgency (notification) flag from hints // Remove urgency (notification) flag from hints
hints->flags &= ~XUrgencyHint; hints->flags &= ~XUrgencyHint;
XSetWMHints(m_display, m_window, hints); XSetWMHints(m_display, m_window, hints.get());
XFree(hints);
} }
break; break;
@ -2117,7 +2135,7 @@ Vector2i WindowImplX11::getPrimaryMonitorPosition()
::Window rootWindow = RootWindow(m_display, m_screen); ::Window rootWindow = RootWindow(m_display, m_screen);
// Get the screen resources // Get the screen resources
XRRScreenResources* res = XRRGetScreenResources(m_display, rootWindow); auto res = X11Ptr<XRRScreenResources>(XRRGetScreenResources(m_display, rootWindow));
if (!res) if (!res)
{ {
err() << "Failed to get the current screen resources for primary monitor position" << std::endl; err() << "Failed to get the current screen resources for primary monitor position" << std::endl;
@ -2130,28 +2148,20 @@ Vector2i WindowImplX11::getPrimaryMonitorPosition()
if (!checkXRandR(xRandRMajor, xRandRMinor)) if (!checkXRandR(xRandRMajor, xRandRMinor))
xRandRMajor = xRandRMinor = 0; xRandRMajor = xRandRMinor = 0;
const RROutput output = getOutputPrimary(rootWindow, res, xRandRMajor, xRandRMinor); const RROutput output = getOutputPrimary(rootWindow, res.get(), xRandRMajor, xRandRMinor);
// Get output info from output // Get output info from output
XRROutputInfo* outputInfo = XRRGetOutputInfo(m_display, res, output); auto outputInfo = X11Ptr<XRROutputInfo>(XRRGetOutputInfo(m_display, res.get(), output));
if (!outputInfo || outputInfo->connection == RR_Disconnected) if (!outputInfo || outputInfo->connection == RR_Disconnected)
{ {
XRRFreeScreenResources(res);
// If outputInfo->connection == RR_Disconnected, free output info
if (outputInfo)
XRRFreeOutputInfo(outputInfo);
err() << "Failed to get output info for primary monitor position" << std::endl; err() << "Failed to get output info for primary monitor position" << std::endl;
return monitorPosition; return monitorPosition;
} }
// Retrieve current RRMode, screen position and rotation // Retrieve current RRMode, screen position and rotation
XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(m_display, res, outputInfo->crtc); auto crtcInfo = X11Ptr<XRRCrtcInfo>(XRRGetCrtcInfo(m_display, res.get(), outputInfo->crtc));
if (!crtcInfo) if (!crtcInfo)
{ {
XRRFreeScreenResources(res);
XRRFreeOutputInfo(outputInfo);
err() << "Failed to get crtc info for primary monitor position" << std::endl; err() << "Failed to get crtc info for primary monitor position" << std::endl;
return monitorPosition; return monitorPosition;
} }
@ -2159,10 +2169,6 @@ Vector2i WindowImplX11::getPrimaryMonitorPosition()
monitorPosition.x = crtcInfo->x; monitorPosition.x = crtcInfo->x;
monitorPosition.y = crtcInfo->y; monitorPosition.y = crtcInfo->y;
XRRFreeCrtcInfo(crtcInfo);
XRRFreeOutputInfo(outputInfo);
XRRFreeScreenResources(res);
return monitorPosition; return monitorPosition;
} }