diff --git a/misc/minetest-xorg-icon-128.png b/misc/minetest-xorg-icon-128.png new file mode 100644 index 000000000..0241a911c Binary files /dev/null and b/misc/minetest-xorg-icon-128.png differ diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp index a0781ef37..aa3c2d548 100644 --- a/src/client/clientlauncher.cpp +++ b/src/client/clientlauncher.cpp @@ -114,6 +114,9 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args) porting::setXorgClassHint(video_driver->getExposedVideoData(), PROJECT_NAME_C); + porting::setXorgWindowIcon(device, + porting::path_share + "/misc/minetest-xorg-icon-128.png"); + /* This changes the minimum allowed number of vertices in a VBO. Default is 500. diff --git a/src/porting.cpp b/src/porting.cpp index 02ce6174b..ddf8139ea 100644 --- a/src/porting.cpp +++ b/src/porting.cpp @@ -611,6 +611,93 @@ void setXorgClassHint(const video::SExposedVideoData &video_data, #endif } +bool setXorgWindowIcon(IrrlichtDevice *device, + const std::string &icon_file) +{ +#ifdef XORG_USED + + video::IVideoDriver *v_driver = device->getVideoDriver(); + + video::IImageLoader *image_loader = NULL; + for (u32 i = v_driver->getImageLoaderCount() - 1; i >= 0; i--) { + if (v_driver->getImageLoader(i)->isALoadableFileExtension(icon_file.c_str())) { + image_loader = v_driver->getImageLoader(i); + break; + } + } + + if (!image_loader) { + warningstream << "Could not find image loader for file '" + << icon_file << "'" << std::endl; + return false; + } + + io::IReadFile *icon_f = device->getFileSystem()->createAndOpenFile(icon_file.c_str()); + + if (!icon_f) { + warningstream << "Could not load icon file '" + << icon_file << "'" << std::endl; + return false; + } + + video::IImage *img = image_loader->loadImage(icon_f); + + if (!img) { + warningstream << "Could not load icon file '" + << icon_file << "'" << std::endl; + icon_f->drop(); + return false; + } + + 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; + } + } + + img->drop(); + icon_f->drop(); + + const video::SExposedVideoData &video_data = v_driver->getExposedVideoData(); + + Display *x11_dpl = (Display *)video_data.OpenGLLinux.X11Display; + + if (x11_dpl == NULL) { + warningstream << "Could not find x11 display for setting its icon." + << std::endl; + delete [] icon_buffer; + return false; + } + + Window x11_win = (Window)video_data.OpenGLLinux.X11Window; + + Atom net_wm_icon = XInternAtom(x11_dpl, "_NET_WM_ICON", False); + Atom cardinal = XInternAtom(x11_dpl, "CARDINAL", False); + XChangeProperty(x11_dpl, x11_win, + net_wm_icon, cardinal, 32, + PropModeReplace, (const unsigned char *)icon_buffer, + icon_buffer_len); + + delete [] icon_buffer; + + return true; +#endif +} //// //// Video/Display Information (Client-only) diff --git a/src/porting.h b/src/porting.h index d101a7324..40f6b4dc3 100644 --- a/src/porting.h +++ b/src/porting.h @@ -367,6 +367,9 @@ inline const char *getPlatformName() void setXorgClassHint(const video::SExposedVideoData &video_data, const std::string &name); +bool setXorgWindowIcon(IrrlichtDevice *device, + const std::string &icon_file); + // This only needs to be called at the start of execution, since all future // threads in the process inherit this exception handler void setWin32ExceptionHandler();