diff --git a/.github/workflows/test_suite_linux.yml b/.github/workflows/test_suite_linux.yml
index ffed98d8c46..5c9ed5e2a9d 100644
--- a/.github/workflows/test_suite_linux.yml
+++ b/.github/workflows/test_suite_linux.yml
@@ -65,7 +65,7 @@ jobs:
export JAVA_HOME=/usr/lib/jvm/java-${{ matrix.JAVA_VERSION }}-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH
export LIBGL_ALWAYS_SOFTWARE=true
- xvfb-run --auto-servernum make distrib -j4
+ xvfb-run --auto-servernum make debug -j4
- name: Create/Update GitHub release
if: ${{ matrix.os == 'ubuntu-22.04' && (github.event_name == 'push' || github.event_name == 'schedule') }}
run: |
diff --git a/.github/workflows/test_suite_mac.yml b/.github/workflows/test_suite_mac.yml
index 94a2a1241b9..bb07c00142e 100644
--- a/.github/workflows/test_suite_mac.yml
+++ b/.github/workflows/test_suite_mac.yml
@@ -19,7 +19,7 @@ jobs:
if: ${{ contains(github.event.pull_request.labels.*.name, 'test webots build') }}
strategy:
matrix:
- os: [macos-13]
+ os: [macos-14]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
@@ -33,7 +33,7 @@ jobs:
if: ${{ github.event_name == 'push' || github.event_name == 'schedule' || contains(github.event.pull_request.labels.*.name, 'test distribution') || contains(github.event.pull_request.labels.*.name, 'test suite') }}
strategy:
matrix:
- os: [macos-13]
+ os: [macos-14]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
@@ -53,7 +53,7 @@ jobs:
run: |
export JAVA_HOME="$(/usr/libexec/java_home -v 16)"
export PATH=/Library/Frameworks/Python.framework/Versions/3.11/bin:/usr/local/bin/:$PATH
- make distrib -j4
+ make debug -j4
- name: Create/Update GitHub release
if: ${{ (github.event_name == 'push' || github.event_name == 'schedule') }}
run: |
@@ -70,7 +70,7 @@ jobs:
if: ${{ contains(github.event.pull_request.labels.*.name, 'test suite mac') }}
strategy:
matrix:
- os: [macos-13]
+ os: [macos-14]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
@@ -103,7 +103,7 @@ jobs:
if: ${{ always() && !contains(github.event.pull_request.labels.*.name, 'test distribution') && !contains(github.event.pull_request.labels.*.name, 'test webots build') }}
strategy:
matrix:
- os: [macos-13]
+ os: [macos-14]
runs-on: ubuntu-latest
steps:
- name: Delete artifacts
diff --git a/.github/workflows/test_suite_windows.yml b/.github/workflows/test_suite_windows.yml
index df7b819e089..f7fcc16f85f 100644
--- a/.github/workflows/test_suite_windows.yml
+++ b/.github/workflows/test_suite_windows.yml
@@ -78,7 +78,7 @@ jobs:
- name: Webots Package Creation
run: |
export WEBOTS_HOME=$GITHUB_WORKSPACE
- make distrib -j4
+ make debug -j4
- name: Create/Update GitHub release
if: ${{ (github.event_name == 'push' || github.event_name == 'schedule') }}
run: |
diff --git a/resources/translations/Makefile b/resources/translations/Makefile
index b07059c8706..b3d940e960b 100644
--- a/resources/translations/Makefile
+++ b/resources/translations/Makefile
@@ -1,4 +1,4 @@
-# Copyright 1996-2024 Cyberbotics Ltd.
+# Copyright 1996-2026 Cyberbotics Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -37,9 +37,14 @@ include $(WEBOTS_HOME_PATH)/resources/Makefile.os.include
WEBOTS_SRC_PATH = $(WEBOTS_HOME_PATH)/src/webots
ifeq ($(OSTYPE),windows)
+ifdef CI
LUPDATE = lupdate-qt6
LRELEASE = lrelease-qt6
else
+LUPDATE = lupdate
+LRELEASE = lrelease
+endif
+else
QT_BINARIES_PATH = $(WEBOTS_HOME_PATH)/bin/qt
ifeq ($(OSTYPE),linux)
diff --git a/scripts/install/msys64_installer.sh b/scripts/install/msys64_installer.sh
index 4c6cae84c90..7897a3a7a6e 100644
--- a/scripts/install/msys64_installer.sh
+++ b/scripts/install/msys64_installer.sh
@@ -15,7 +15,7 @@ declare -a BASE_PACKAGES=(
"zip" # robotbenchmark square path
"mingw-w64-x86_64-qt6-base" # Webots
"mingw-w64-x86_64-qt6-declarative" # Webots
- "mingw-w64-x86_64-qt6-tools" # Webots (translation: lrelease-qt6 and lupdate-qt6)
+ "mingw-w64-x86_64-qt6-tools" # Webots (translation: lrelease and lupdate)
"mingw-w64-x86_64-qt6-translations" # Webots
"mingw-w64-x86_64-qt6-websockets" # Webots
"mingw-w64-x86_64-libzip" # Webots
diff --git a/scripts/packaging/webots.metainfo.xml b/scripts/packaging/webots.metainfo.xml
index ad52a735d2c..ce4dbb12993 100644
--- a/scripts/packaging/webots.metainfo.xml
+++ b/scripts/packaging/webots.metainfo.xml
@@ -48,4 +48,11 @@
https://cyberbotics.com/doc/reference/changelog-r2025
+
+ robot simulator
+ robot development
+ robotics education
+ open source robotics
+ simulation software
+
diff --git a/src/webots/app/WbApplication.cpp b/src/webots/app/WbApplication.cpp
index 65dfca22607..156bee2fbc0 100644
--- a/src/webots/app/WbApplication.cpp
+++ b/src/webots/app/WbApplication.cpp
@@ -271,7 +271,8 @@ void WbApplication::loadWorld(QString worldName, bool reloading, bool isLoadingA
emit preWorldLoaded(reloading);
// create a file in tmp path for ipc extern controllers
QFile loading_file(WbStandardPaths::webotsTmpPath() + "loading");
- loading_file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
+ if (!loading_file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
+ WbLog::warning(tr("Could not create loading signal file: '%1'.").arg(loading_file.fileName()));
bool isFirstLoad = (mWorld == NULL);
delete mWorld;
diff --git a/src/webots/core/WbIniParser.cpp b/src/webots/core/WbIniParser.cpp
index 7dd1f1a025c..f7f6502dce6 100644
--- a/src/webots/core/WbIniParser.cpp
+++ b/src/webots/core/WbIniParser.cpp
@@ -21,7 +21,10 @@ WbIniParser::WbIniParser(const QString &filename) {
QFile file(filename);
QString line;
QString section;
- file.open(QIODevice::ReadOnly);
+ if (!file.open(QIODevice::ReadOnly)) {
+ mValid = false;
+ return;
+ }
mValid = true;
while (!file.atEnd()) {
line = file.readLine();
diff --git a/src/webots/gui/WbGuiApplication.cpp b/src/webots/gui/WbGuiApplication.cpp
index e1d88a9eb26..3f4233e974e 100644
--- a/src/webots/gui/WbGuiApplication.cpp
+++ b/src/webots/gui/WbGuiApplication.cpp
@@ -565,25 +565,26 @@ static void setDarkTitlebar(HWND hwnd) {
void WbGuiApplication::updateStyleSheet() {
mThemeLoaded = WbPreferences::instance()->value("General/theme").toString();
QFile qssFile(WbStandardPaths::resourcesPath() + mThemeLoaded);
- qssFile.open(QFile::ReadOnly);
- QString styleSheet = QString::fromUtf8(qssFile.readAll());
+ QString styleSheet;
+ if (qssFile.open(QFile::ReadOnly))
+ styleSheet = QString::fromUtf8(qssFile.readAll());
+ else
+ WbLog::warning(tr("Could not open theme file: '%1'.").arg(qssFile.fileName()));
#ifdef __APPLE__
- QFile macOSQssFile(WbStandardPaths::resourcesPath() + "stylesheet.macos.qss");
- macOSQssFile.open(QFile::ReadOnly);
- styleSheet += QString::fromUtf8(macOSQssFile.readAll());
-
+ const QString platformStylesheet = "stylesheet.macos.qss";
#elif defined(__linux__)
- QFile linuxQssFile(WbStandardPaths::resourcesPath() + "stylesheet.linux.qss");
- linuxQssFile.open(QFile::ReadOnly);
- styleSheet += QString::fromUtf8(linuxQssFile.readAll());
-
+ const QString platformStylesheet = "stylesheet.linux.qss";
#elif _WIN32
- QFile windowsQssFile(WbStandardPaths::resourcesPath() + "stylesheet.windows.qss");
- windowsQssFile.open(QFile::ReadOnly);
- styleSheet += QString::fromUtf8(windowsQssFile.readAll());
+ const QString platformStylesheet = "stylesheet.windows.qss";
#endif
+ QFile platformQssFile(WbStandardPaths::resourcesPath() + platformStylesheet);
+ if (platformQssFile.open(QFile::ReadOnly))
+ styleSheet += QString::fromUtf8(platformQssFile.readAll());
+ else
+ WbLog::warning(tr("Could not open stylesheet file: '%1'.").arg(platformQssFile.fileName()));
+
qApp->setStyleSheet(styleSheet);
#ifdef _WIN32
if (mThemeLoaded != "webots_classic.qss")
diff --git a/src/webots/gui/WbMainWindow.cpp b/src/webots/gui/WbMainWindow.cpp
index d2db2ee2363..a633eb4406e 100644
--- a/src/webots/gui/WbMainWindow.cpp
+++ b/src/webots/gui/WbMainWindow.cpp
@@ -2432,7 +2432,10 @@ void WbMainWindow::openFileInTextEditor(const QString &fileName, bool modify, bo
const QString webotsRepo = fileName.mid(0, index);
QFile localFile(fileToOpen);
- localFile.open(QIODevice::ReadWrite);
+ if (!localFile.open(QIODevice::ReadWrite)) {
+ WbLog::error(tr("Could not open file for editing: '%1'.").arg(fileToOpen));
+ return;
+ }
const QString contents = QString(localFile.readAll());
QStringList lines = contents.split('\n');
for (QString &line : lines) {
diff --git a/src/webots/gui/WbNewWorldWizard.cpp b/src/webots/gui/WbNewWorldWizard.cpp
index b916f115c99..0e0f4599010 100644
--- a/src/webots/gui/WbNewWorldWizard.cpp
+++ b/src/webots/gui/WbNewWorldWizard.cpp
@@ -17,6 +17,7 @@
#include "WbApplicationInfo.hpp"
#include "WbFileUtil.hpp"
#include "WbLineEdit.hpp"
+#include "WbLog.hpp"
#include "WbMessageBox.hpp"
#include "WbPreferences.hpp"
#include "WbProject.hpp"
@@ -49,7 +50,10 @@ int WbNewWorldWizard::exec() {
void WbNewWorldWizard::createWorldFile() {
QFile file(WbProject::current()->worldsPath() + fileName());
- file.open(QIODevice::WriteOnly);
+ if (!file.open(QIODevice::WriteOnly)) {
+ WbLog::error(tr("Could not create world file: '%1'.").arg(file.fileName()));
+ return;
+ }
QByteArray worldContent;
worldContent.append(QString("#VRML_SIM %1 utf8\n").arg(WbApplicationInfo::version().toString(false)).toUtf8());
QStringList externProtoList;
diff --git a/src/webots/nodes/WbBackground.cpp b/src/webots/nodes/WbBackground.cpp
index e623cb0f79b..4df5b7eff0d 100644
--- a/src/webots/nodes/WbBackground.cpp
+++ b/src/webots/nodes/WbBackground.cpp
@@ -638,12 +638,11 @@ void WbBackground::applySkyBoxToWren() {
} else { // otherwise, use a small uniform texture with the color of the sky
cm = wr_texture_cubemap_new();
size = 2;
- const int size2 = size * size;
wr_texture_set_internal_format(WR_TEXTURE(cm), WR_TEXTURE_INTERNAL_FORMAT_RGBA8);
- unsigned int data[size2];
+ unsigned int data[4];
const WbRgb &c = skyColor();
unsigned int color = c.redByte() * 0x10000 + c.greenByte() * 0x100 + c.blueByte();
- for (int i = 0; i < size2; i++)
+ for (int i = 0; i < 4; i++)
data[i] = color;
for (int i = 0; i < 6; i++)
wr_texture_cubemap_set_data(cm, reinterpret_cast(data), static_cast(i));
diff --git a/src/webots/scene_tree/WbSceneTree.cpp b/src/webots/scene_tree/WbSceneTree.cpp
index 71765c4def0..6c2ddfdffc2 100644
--- a/src/webots/scene_tree/WbSceneTree.cpp
+++ b/src/webots/scene_tree/WbSceneTree.cpp
@@ -1593,7 +1593,10 @@ void WbSceneTree::openTemplateInstanceInTextEditor() {
tmpDir.mkdir(generatedProtos);
QFile file(
QString("%1%2/%3.generated_proto").arg(WbStandardPaths::webotsTmpPath()).arg(generatedProtos).arg(node->proto()->name()));
- file.open(QIODevice::WriteOnly | QIODevice::Text);
+ if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ WbLog::error(tr("Could not create temporary file: '%1'.").arg(file.fileName()));
+ return;
+ }
file.write(node->protoInstanceTemplateContent());
file.close();
if (!file.fileName().isEmpty())
diff --git a/src/webots/sound/WbWaveFile.cpp b/src/webots/sound/WbWaveFile.cpp
index fbca03cc0ca..1b6546c0de1 100644
--- a/src/webots/sound/WbWaveFile.cpp
+++ b/src/webots/sound/WbWaveFile.cpp
@@ -14,6 +14,7 @@
#include "WbWaveFile.hpp"
+#include "WbLog.hpp"
#include "WbStandardPaths.hpp"
#include
@@ -187,7 +188,11 @@ void WbWaveFile::loadConvertedFile(int side) {
void WbWaveFile::loadConvertedFile(int side, const QString &filename) {
assert(mDevice == NULL);
mDevice = new QFile(filename);
- mDevice->open(QIODevice::ReadOnly);
+ if (!mDevice->open(QIODevice::ReadOnly)) {
+ delete mDevice;
+ mDevice = NULL;
+ throw QObject::tr("Could not open audio device: '%1'.").arg(filename);
+ }
loadConvertedFile(side);
mDevice->close();
delete mDevice;
@@ -216,7 +221,8 @@ void WbWaveFile::loadFromFile(const QString &extension, int side) {
if (mDevice) {
inputFilename = WbStandardPaths::webotsTmpPath() + "input." + extension;
QFile input(inputFilename);
- input.open(QFile::WriteOnly);
+ if (!input.open(QFile::WriteOnly))
+ throw QObject::tr("Could not create temporary audio file: '%1'.").arg(inputFilename);
input.write(mDevice->readAll());
input.close();
} else