1
0

Merge branch 'master' into feat/gltf-loader

This commit is contained in:
JosiahWI
2023-05-15 09:59:59 -05:00
185 changed files with 6431 additions and 9257 deletions

View File

@@ -24,6 +24,8 @@
#include "SIrrCreationParameters.h"
#include "SExposedVideoData.h"
#include "IGUISpriteBank.h"
#include "IImageLoader.h"
#include "IFileSystem.h"
#include <X11/XKBlib.h>
#include <X11/Xatom.h>
@@ -115,7 +117,7 @@ CIrrDeviceLinux::CIrrDeviceLinux(const SIrrlichtCreationParameters& param)
HasNetWM(false),
#endif
Width(param.WindowSize.Width), Height(param.WindowSize.Height),
WindowHasFocus(false), WindowMinimized(false),
WindowHasFocus(false), WindowMinimized(false), WindowMaximized(param.WindowMaximized),
ExternalWindow(false), AutorepeatSupport(0)
#if defined(_IRR_LINUX_X11_XINPUT2_)
, currentTouchedCount(0)
@@ -168,6 +170,11 @@ CIrrDeviceLinux::CIrrDeviceLinux(const SIrrlichtCreationParameters& param)
return;
createGUIAndScene();
if (param.WindowMaximized)
maximizeWindow();
setupTopLevelXorgWindow();
}
@@ -279,31 +286,97 @@ bool CIrrDeviceLinux::switchToFullscreen()
}
void CIrrDeviceLinux::setupTopLevelXorgWindow()
{
#ifdef _IRR_COMPILE_WITH_X11_
if (CreationParams.DriverType == video::EDT_NULL)
return; // no display and window
os::Printer::log("Configuring X11-specific top level window properties", ELL_DEBUG);
// Set application name and class hints. For now name and class are the same.
// Note: SDL uses the executable name here (i.e. "minetest").
XClassHint *classhint = XAllocClassHint();
classhint->res_name = const_cast<char *>("Minetest");
classhint->res_class = const_cast<char *>("Minetest");
XSetClassHint(XDisplay, XWindow, classhint);
XFree(classhint);
// FIXME: In the future WMNormalHints should be set ... e.g see the
// gtk/gdk code (gdk/x11/gdksurface-x11.c) for the setup_top_level
// method. But for now (as it would require some significant changes)
// leave the code as is.
// The following is borrowed from the above gdk source for setting top
// level windows. The source indicates and the Xlib docs suggest that
// this will set the WM_CLIENT_MACHINE and WM_LOCAL_NAME. This will not
// set the WM_CLIENT_MACHINE to a Fully Qualified Domain Name (FQDN) which is
// required by the Extended Window Manager Hints (EWMH) spec when setting
// the _NET_WM_PID (see further down) but running Minetest in an env
// where the window manager is on another machine from Minetest (therefore
// making the PID useless) is not expected to be a problem. Further
// more, using gtk/gdk as the model it would seem that not using a FQDN is
// not an issue for modern Xorg window managers.
os::Printer::log("Setting Xorg window manager Properties", ELL_DEBUG);
XSetWMProperties (XDisplay, XWindow, NULL, NULL, NULL, 0, NULL, NULL, NULL);
// Set the _NET_WM_PID window property according to the EWMH spec. _NET_WM_PID
// (in conjunction with WM_CLIENT_MACHINE) can be used by window managers to
// force a shutdown of an application if it doesn't respond to the destroy
// window message.
os::Printer::log("Setting Xorg _NET_WM_PID extended window manager property", ELL_DEBUG);
Atom NET_WM_PID = XInternAtom(XDisplay, "_NET_WM_PID", false);
pid_t pid = getpid();
XChangeProperty(XDisplay, XWindow, NET_WM_PID,
XA_CARDINAL, 32, PropModeReplace,
reinterpret_cast<unsigned char *>(&pid),1);
// Set the WM_CLIENT_LEADER window property here. Minetest has only one
// window and that window will always be the leader.
os::Printer::log("Setting Xorg WM_CLIENT_LEADER property", ELL_DEBUG);
Atom WM_CLIENT_LEADER = XInternAtom(XDisplay, "WM_CLIENT_LEADER", false);
XChangeProperty (XDisplay, XWindow, WM_CLIENT_LEADER,
XA_WINDOW, 32, PropModeReplace,
reinterpret_cast<unsigned char *>(&XWindow), 1);
#endif
}
#if defined(_IRR_COMPILE_WITH_X11_)
void IrrPrintXGrabError(int grabResult, const c8 * grabCommand )
{
if ( grabResult == GrabSuccess )
{
// os::Printer::log(grabCommand, ": GrabSuccess", ELL_INFORMATION);
// os::Printer::log(grabCommand, "GrabSuccess", ELL_INFORMATION);
return;
}
switch ( grabResult )
{
case AlreadyGrabbed:
os::Printer::log(grabCommand, ": AlreadyGrabbed", ELL_WARNING);
os::Printer::log(grabCommand, "AlreadyGrabbed", ELL_WARNING);
break;
case GrabNotViewable:
os::Printer::log(grabCommand, ": GrabNotViewable", ELL_WARNING);
os::Printer::log(grabCommand, "GrabNotViewable", ELL_WARNING);
break;
case GrabFrozen:
os::Printer::log(grabCommand, ": GrabFrozen", ELL_WARNING);
os::Printer::log(grabCommand, "GrabFrozen", ELL_WARNING);
break;
case GrabInvalidTime:
os::Printer::log(grabCommand, ": GrabInvalidTime", ELL_WARNING);
os::Printer::log(grabCommand, "GrabInvalidTime", ELL_WARNING);
break;
default:
os::Printer::log(grabCommand, ": grab failed with unknown problem", ELL_WARNING);
os::Printer::log(grabCommand, "grab failed with unknown problem", ELL_WARNING);
break;
}
}
@@ -377,7 +450,7 @@ bool CIrrDeviceLinux::createWindow()
}
#ifdef _DEBUG
else
os::Printer::log("Visual chosen: ", core::stringc(static_cast<u32>(VisualInfo->visualid)).c_str(), ELL_DEBUG);
os::Printer::log("Visual chosen", core::stringc(static_cast<u32>(VisualInfo->visualid)).c_str(), ELL_DEBUG);
#endif
// create color map
@@ -997,12 +1070,15 @@ bool CIrrDeviceLinux::run()
send_response(req->property);
};
if (req->selection != X_ATOM_CLIPBOARD ||
if ((req->selection != X_ATOM_CLIPBOARD &&
req->selection != XA_PRIMARY) ||
req->owner != XWindow) {
// we are not the owner, refuse request
send_response_refuse();
break;
}
const core::stringc &text_buffer = req->selection == X_ATOM_CLIPBOARD ?
Clipboard : PrimarySelection;
// for debugging:
//~ {
@@ -1023,8 +1099,8 @@ bool CIrrDeviceLinux::run()
req->target, X_ATOM_UTF8_STRING,
8, // format = 8-bit
PropModeReplace,
(unsigned char *)Clipboard.c_str(),
Clipboard.size());
(unsigned char *)text_buffer.c_str(),
text_buffer.size());
send_response(req->target);
break;
}
@@ -1049,8 +1125,8 @@ bool CIrrDeviceLinux::run()
set_property_and_notify(
X_ATOM_UTF8_STRING,
8,
Clipboard.c_str(),
Clipboard.size()
text_buffer.c_str(),
text_buffer.size()
);
} else {
@@ -1172,6 +1248,50 @@ void CIrrDeviceLinux::setWindowCaption(const wchar_t* text)
}
//! Sets the window icon.
bool CIrrDeviceLinux::setWindowIcon(const video::IImage *img)
{
if (CreationParams.DriverType == video::EDT_NULL)
return false; // no display and window
u32 height = img->getDimension().Height;
u32 width = img->getDimension().Width;
size_t icon_buffer_len = 2 + height * width;
long *icon_buffer = new long[icon_buffer_len];
icon_buffer[0] = width;
icon_buffer[1] = height;
for (u32 x = 0; x < width; x++) {
for (u32 y = 0; y < height; y++) {
video::SColor col = img->getPixel(x, y);
long pixel_val = 0;
pixel_val |= (u8)col.getAlpha() << 24;
pixel_val |= (u8)col.getRed() << 16;
pixel_val |= (u8)col.getGreen() << 8;
pixel_val |= (u8)col.getBlue();
icon_buffer[2 + x + y * width] = pixel_val;
}
}
if (XDisplay == NULL) {
os::Printer::log("Could not find x11 display for setting its icon.", ELL_ERROR);
delete[] icon_buffer;
return false;
}
Atom net_wm_icon = XInternAtom(XDisplay, "_NET_WM_ICON", False);
Atom cardinal = XInternAtom(XDisplay, "CARDINAL", False);
XChangeProperty(XDisplay, XWindow, net_wm_icon, cardinal, 32, PropModeReplace,
(const unsigned char *)icon_buffer, icon_buffer_len);
delete[] icon_buffer;
return true;
}
//! notifies the device that it should close itself
void CIrrDeviceLinux::closeDevice()
{
@@ -1200,6 +1320,13 @@ bool CIrrDeviceLinux::isWindowMinimized() const
}
//! returns last state from maximizeWindow() and restoreWindow()
bool CIrrDeviceLinux::isWindowMaximized() const
{
return WindowMaximized;
}
//! returns color format of the window.
video::ECOLOR_FORMAT CIrrDeviceLinux::getColorFormat() const
{
@@ -1284,6 +1411,8 @@ void CIrrDeviceLinux::maximizeWindow()
}
XMapWindow(XDisplay, XWindow);
WindowMaximized = true;
#endif
}
@@ -1310,6 +1439,8 @@ void CIrrDeviceLinux::restoreWindow()
}
XMapWindow(XDisplay, XWindow);
WindowMaximized = false;
#endif
}
@@ -1662,47 +1793,49 @@ void CIrrDeviceLinux::pollJoysticks()
}
#if defined(_IRR_COMPILE_WITH_X11_)
//! gets text from the clipboard
//! \return Returns 0 if no string is in there, otherwise utf-8 text.
const c8 *CIrrDeviceLinux::getTextFromClipboard() const
const c8 *CIrrDeviceLinux::getTextFromSelection(Atom selection, core::stringc &text_buffer) const
{
#if defined(_IRR_COMPILE_WITH_X11_)
Window ownerWindow = XGetSelectionOwner(XDisplay, X_ATOM_CLIPBOARD);
Window ownerWindow = XGetSelectionOwner(XDisplay, selection);
if (ownerWindow == XWindow) {
return Clipboard.c_str();
return text_buffer.c_str();
}
Clipboard = "";
text_buffer = "";
if (ownerWindow == None) {
return Clipboard.c_str();
return text_buffer.c_str();
}
// delete the property to be set beforehand
XDeleteProperty(XDisplay, XWindow, XA_PRIMARY);
XConvertSelection(XDisplay, X_ATOM_CLIPBOARD, X_ATOM_UTF8_STRING, XA_PRIMARY,
XConvertSelection(XDisplay, selection, X_ATOM_UTF8_STRING, XA_PRIMARY,
XWindow, CurrentTime);
XFlush(XDisplay);
// wait for event via a blocking call
XEvent event_ret;
std::pair<Window, Atom> args(XWindow, selection);
XIfEvent(XDisplay, &event_ret, [](Display *_display, XEvent *event, XPointer arg) {
auto p = reinterpret_cast<std::pair<Window, Atom> *>(arg);
return (Bool) (event->type == SelectionNotify &&
event->xselection.requestor == *(Window *)arg &&
event->xselection.selection == X_ATOM_CLIPBOARD &&
event->xselection.requestor == p->first &&
event->xselection.selection == p->second &&
event->xselection.target == X_ATOM_UTF8_STRING);
}, (XPointer)&XWindow);
}, (XPointer)&args);
_IRR_DEBUG_BREAK_IF(!(event_ret.type == SelectionNotify &&
event_ret.xselection.requestor == XWindow &&
event_ret.xselection.selection == X_ATOM_CLIPBOARD &&
event_ret.xselection.selection == selection &&
event_ret.xselection.target == X_ATOM_UTF8_STRING));
Atom property_set = event_ret.xselection.property;
if (event_ret.xselection.property == None) {
// request failed => empty string
return Clipboard.c_str();
return text_buffer.c_str();
}
// check for data
@@ -1729,15 +1862,15 @@ const c8 *CIrrDeviceLinux::getTextFromClipboard() const
// for debugging:
//~ {
//~ char *type_name = XGetAtomName(XDisplay, type);
//~ fprintf(stderr, "CIrrDeviceLinux::getTextFromClipboard: actual type: %s (=%ld)\n",
//~ fprintf(stderr, "CIrrDeviceLinux::getTextFromSelection: actual type: %s (=%ld)\n",
//~ type_name, type);
//~ XFree(type_name);
//~ }
if (type != X_ATOM_UTF8_STRING && type != X_ATOM_UTF8_MIME_TYPE) {
os::Printer::log("CIrrDeviceLinux::getTextFromClipboard: did not get utf-8 string",
os::Printer::log("CIrrDeviceLinux::getTextFromSelection: did not get utf-8 string",
ELL_WARNING);
return Clipboard.c_str();
return text_buffer.c_str();
}
if (bytesLeft > 0) {
@@ -1746,20 +1879,49 @@ const c8 *CIrrDeviceLinux::getTextFromClipboard() const
bytesLeft, 0, AnyPropertyType, &type, &format,
&numItems, &dummy, &data);
if (result == Success)
Clipboard = (irr::c8 *)data;
text_buffer = (irr::c8 *)data;
XFree (data);
}
// delete the property again, to inform the owner about the successful transfer
XDeleteProperty(XDisplay, XWindow, property_set);
return Clipboard.c_str();
return text_buffer.c_str();
}
#endif
//! gets text from the clipboard
//! \return Returns 0 if no string is in there, otherwise utf-8 text.
const c8 *CIrrDeviceLinux::getTextFromClipboard() const
{
#if defined(_IRR_COMPILE_WITH_X11_)
return getTextFromSelection(X_ATOM_CLIPBOARD, Clipboard);
#else
return nullptr;
#endif
}
//! gets text from the primary selection
//! \return Returns 0 if no string is in there, otherwise utf-8 text.
const c8 *CIrrDeviceLinux::getTextFromPrimarySelection() const
{
#if defined(_IRR_COMPILE_WITH_X11_)
return getTextFromSelection(XA_PRIMARY, PrimarySelection);
#else
return nullptr;
#endif
}
#if defined(_IRR_COMPILE_WITH_X11_)
bool CIrrDeviceLinux::becomeSelectionOwner(Atom selection) const
{
XSetSelectionOwner (XDisplay, selection, XWindow, CurrentTime);
XFlush (XDisplay);
Window owner = XGetSelectionOwner(XDisplay, selection);
return owner == XWindow;
}
#endif
//! copies text to the clipboard
void CIrrDeviceLinux::copyToClipboard(const c8 *text) const
{
@@ -1767,22 +1929,30 @@ void CIrrDeviceLinux::copyToClipboard(const c8 *text) const
// Actually there is no clipboard on X but applications just say they own the clipboard and return text when asked.
// Which btw. also means that on X you lose clipboard content when closing applications.
Clipboard = text;
XSetSelectionOwner (XDisplay, X_ATOM_CLIPBOARD, XWindow, CurrentTime);
XFlush (XDisplay);
Window owner = XGetSelectionOwner(XDisplay, X_ATOM_CLIPBOARD);
if (owner != XWindow) {
if (!becomeSelectionOwner(X_ATOM_CLIPBOARD)) {
os::Printer::log("CIrrDeviceLinux::copyToClipboard: failed to set owner", ELL_WARNING);
}
#endif
}
//! copies text to the primary selection
void CIrrDeviceLinux::copyToPrimarySelection(const c8 *text) const
{
#if defined(_IRR_COMPILE_WITH_X11_)
PrimarySelection = text;
if (!becomeSelectionOwner(XA_PRIMARY)) {
os::Printer::log("CIrrDeviceLinux::copyToPrimarySelection: failed to set owner", ELL_WARNING);
}
#endif
}
#ifdef _IRR_COMPILE_WITH_X11_
// return true if the passed event has the type passed in parameter arg
Bool PredicateIsEventType(Display *display, XEvent *event, XPointer arg)
{
if ( event && event->type == *(int*)arg )
{
// os::Printer::log("remove event:", core::stringc((int)arg).c_str(), ELL_INFORMATION);
// os::Printer::log("remove event", core::stringc((int)arg).c_str(), ELL_INFORMATION);
return True;
}
return False;
@@ -1810,6 +1980,28 @@ void CIrrDeviceLinux::clearSystemMessages()
#endif //_IRR_COMPILE_WITH_X11_
}
//! Get the display density in dots per inch.
float CIrrDeviceLinux::getDisplayDensity() const
{
#ifdef _IRR_COMPILE_WITH_X11_
if (XDisplay != NULL) {
/* try x direct */
int dh = DisplayHeight(XDisplay, 0);
int dw = DisplayWidth(XDisplay, 0);
int dh_mm = DisplayHeightMM(XDisplay, 0);
int dw_mm = DisplayWidthMM(XDisplay, 0);
if (dh_mm != 0 && dw_mm != 0) {
float dpi_height = floor(dh / (dh_mm * 0.039370) + 0.5);
float dpi_width = floor(dw / (dw_mm * 0.039370) + 0.5);
return std::max(dpi_height, dpi_width);
}
}
#endif //_IRR_COMPILE_WITH_X11_
return 0.0f;
}
void CIrrDeviceLinux::initXAtoms()
{
#ifdef _IRR_COMPILE_WITH_X11_