Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 44 additions & 4 deletions jdm-core/src/main/java/jdiskmark/App.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package jdiskmark;

import static jdiskmark.Benchmark.BenchmarkType;
import static jdiskmark.Benchmark.BlockSequence;
import static jdiskmark.Benchmark.IOMode.READ;
import static jdiskmark.Benchmark.IOMode.WRITE;
import static jdiskmark.DriveAccessChecker.validateTargetDirectory;

import picocli.CommandLine;
Expand Down Expand Up @@ -109,6 +105,50 @@ public String toString() {
}
}

/**
* Branding icon variants for the application window, taskbar, and installer.
* Change {@link #activeIcon} to switch the icon across all display contexts.
*/
public enum AppIcon {
BETA("/icons/icon-jdm-beta.png"),
/** Custom JDiskMark turtle logo — the default project brand. */
TURTLE("/icons/icon-jdm-turtle.png"),
/** Duke, the BSD-licensed Java mascot from the OpenJDK project. */
DUKE("/icons/icon-duke.png");

public final String resourcePath;

AppIcon(String resourcePath) {
this.resourcePath = resourcePath;
}

/**
* Load this icon as an ImageIcon, or {@code null} if the resource
* is not found on the classpath.
*/
public javax.swing.ImageIcon load() {
java.io.InputStream is = App.class.getResourceAsStream(resourcePath);
if (is == null) {
java.util.logging.Logger.getLogger(App.class.getName()).warning(
"Icon resource not found: " + resourcePath);
return null;
}
try (is) {
return new javax.swing.ImageIcon(is.readAllBytes());
Comment thread
jamesmarkchan marked this conversation as resolved.
} catch (java.io.IOException e) {
java.util.logging.Logger.getLogger(App.class.getName()).log(
java.util.logging.Level.WARNING, "Could not load icon: " + resourcePath, e);
return null;
}
}
}

/**
* Active branding icon — change this single line to switch the icon
* used for the window title bar, taskbar, and About dialog.
*/
public static AppIcon activeIcon = AppIcon.TURTLE;

// application mode
public static Mode mode = Mode.CLI;
// elevated priviledges
Expand Down
18 changes: 18 additions & 0 deletions jdm-core/src/main/java/jdiskmark/Gui.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ public static void configureDarkLaf() {
} else if (App.os.contains("Linux")) {
UIManager.setLookAndFeel(new FlatDarkLaf());
}
// Enable FlatLaf custom window decorations (unified title bar + menu bar)
javax.swing.JFrame.setDefaultLookAndFeelDecorated(true);
javax.swing.JDialog.setDefaultLookAndFeelDecorated(true);
} catch (UnsupportedLookAndFeelException e) {
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
Expand All @@ -126,6 +129,8 @@ public static void configureDarkLaf() {
public static void configureDarculaLaf() {
try {
UIManager.setLookAndFeel(new FlatDarculaLaf());
javax.swing.JFrame.setDefaultLookAndFeelDecorated(true);
javax.swing.JDialog.setDefaultLookAndFeelDecorated(true);
} catch (UnsupportedLookAndFeelException e) {
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
Expand All @@ -149,6 +154,8 @@ public static void configureLightLaf() {
} else if (App.os.contains("Linux")) {
UIManager.setLookAndFeel(new FlatLightLaf());
}
javax.swing.JFrame.setDefaultLookAndFeelDecorated(true);
javax.swing.JDialog.setDefaultLookAndFeelDecorated(true);
} catch (UnsupportedLookAndFeelException e) {
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
Expand Down Expand Up @@ -228,6 +235,17 @@ public static void init() {
}

mainFrame = new MainFrame();

// Embed the menu bar into the FlatLaf custom title bar (VS Code style)
mainFrame.getRootPane().putClientProperty(
com.formdev.flatlaf.FlatClientProperties.MENU_BAR_EMBEDDED, true);

// Apply branding icon to the window title bar and taskbar
javax.swing.ImageIcon icon = App.activeIcon.load();
if (icon != null) {
mainFrame.setIconImage(icon.getImage());
}

if (runPanel != null) {
runPanel.hideFirstColumn();
}
Expand Down
13 changes: 11 additions & 2 deletions jdm-core/src/main/java/jdiskmark/MainFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -839,8 +839,17 @@ private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-
}//GEN-LAST:event_exitMenuItemActionPerformed

private void aboutMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_aboutMenuItemActionPerformed
JOptionPane.showMessageDialog(Gui.mainFrame,
"JDiskMark " + App.VERSION, "About...", JOptionPane.PLAIN_MESSAGE);
javax.swing.ImageIcon rawIcon = App.activeIcon.load();
javax.swing.ImageIcon icon = rawIcon;
if (rawIcon != null) {
int w = rawIcon.getIconWidth() / 2;
int h = rawIcon.getIconHeight() / 2;
java.awt.Image scaled = rawIcon.getImage()
.getScaledInstance(w, h, java.awt.Image.SCALE_SMOOTH);
icon = new javax.swing.ImageIcon(scaled);
}
JOptionPane.showMessageDialog(Gui.mainFrame,
"JDiskMark " + App.VERSION, "About...", JOptionPane.PLAIN_MESSAGE, icon);
}//GEN-LAST:event_aboutMenuItemActionPerformed

private void openLocButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openLocButtonActionPerformed
Expand Down
Binary file added jdm-core/src/main/resources/icons/icon-duke.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions jdm-core/src/test/java/jdiskmark/AppTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package jdiskmark;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import static org.junit.jupiter.api.Assertions.*;

/**
Expand All @@ -23,4 +25,16 @@ void sharePortal_onStartup_isFalse() {
assertFalse(App.sharePortal,
"sharePortal must default to false — network activity requires explicit user opt-in each session");
}

/**
* Every AppIcon enum entry must resolve to an actual classpath resource.
* This guards against icon renames or path typos that would cause the
* About dialog (and taskbar/title-bar) to silently display no icon.
*/
@ParameterizedTest
@EnumSource(App.AppIcon.class)
void appIcon_load_isNonNull(App.AppIcon icon) {
assertNotNull(icon.load(),
"Icon resource not found on classpath: " + icon.resourcePath);
}
}
24 changes: 24 additions & 0 deletions jdm-dist/jdm-deb-slim/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,30 @@
<group>root</group>
</mapper>
</data>
<!-- App icon — installed to /usr/share/pixmaps for XDG icon resolution -->
<data>
<src>${project.basedir}/../../jdm-core/src/main/resources/icons/icon-jdm-turtle.png</src>
<type>file</type>
<dst>/usr/share/pixmaps/jdiskmark.png</dst>
<mapper>
<type>perm</type>
<filemode>644</filemode>
<user>root</user>
<group>root</group>
</mapper>
</data>
<!-- Desktop entry — includes Icon= and StartupWMClass for GNOME taskbar -->
<data>
<src>${project.basedir}/src/deb/share/jdiskmark.desktop</src>
<type>file</type>
<mapper>
<type>perm</type>
<prefix>/usr/share/applications</prefix>
<filemode>644</filemode>
<user>root</user>
<group>root</group>
</mapper>
</data>
</dataSet>
</configuration>
</execution>
Expand Down
12 changes: 12 additions & 0 deletions jdm-dist/jdm-deb-slim/src/deb/share/jdiskmark.desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[Desktop Entry]
Type=Application
Version=1.0
Name=JDiskMark
GenericName=Disk Benchmark
Comment=Java disk benchmark utility for read/write performance testing
Exec=/usr/bin/jdiskmark
Icon=jdiskmark
Terminal=false
Categories=Utility;System;
Keywords=disk;benchmark;performance;storage;speed;
StartupWMClass=jdiskmark-App
46 changes: 46 additions & 0 deletions jdm-dist/jdm-deb/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,55 @@
<argument>--java-options</argument><argument>${jvm.run.options}</argument>
<argument>--linux-shortcut</argument>
<argument>--linux-menu-group</argument><argument>Utility</argument>
<argument>--icon</argument><argument>${project.basedir}/../../jdm-core/src/main/resources/icons/icon-jdm-turtle.png</argument>
<argument>--resource-dir</argument><argument>${project.basedir}/src/main/jpackage-resources</argument>
</arguments>
</configuration>
</execution>

<!-- Inject fields that jpackage does not generate into the desktop
entry inside the DEB: Name=JDiskMark (display name),
StartupWMClass (for GNOME taskbar icon matching),
GenericName, and Keywords.
The file is patched in-place; no renaming is done so that
xdg-desktop-menu's vendor-prefix requirement is satisfied. -->
<execution>
<id>patch-deb-desktop</id>
<phase>verify</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>bash</executable>
<arguments>
<argument>-c</argument>
<argument><![CDATA[
set -e
mapfile -t DEBS < <(find "${project.build.directory}" -maxdepth 1 -type f -name "*.deb" | sort)
if [ "${#DEBS[@]}" -ne 1 ]; then
echo "[patch] Expected exactly one .deb in ${project.build.directory}, found ${#DEBS[@]}" >&2
printf ' %s\n' "${DEBS[@]}" >&2
exit 1
fi
DEB="${DEBS[0]}"
WORK="${project.build.directory}/deb-repack"
echo "[patch] Patching desktop entry in $DEB"
rm -rf "$WORK" && mkdir -p "$WORK/pkg"
dpkg-deb -R "$DEB" "$WORK/pkg"
DESKTOP=$(find "$WORK/pkg/opt" -name "*.desktop" | grep -v runtime | head -1)
if [ -n "$DESKTOP" ]; then
sed -i 's|^Name=jdiskmark$|Name=JDiskMark|' "$DESKTOP"
sed -i 's|^Categories=\(.*\)|GenericName=Disk Benchmark\nCategories=\1\nKeywords=disk;benchmark;performance;storage;speed;\nStartupWMClass=jdiskmark-App|' "$DESKTOP"
echo "[patch] Result ($(basename $DESKTOP)):"
cat "$DESKTOP"
fi
dpkg-deb -b "$WORK/pkg" "$DEB"
echo "[patch] Done."
]]></argument>
</arguments>
</configuration>
</execution>

</executions>
</plugin>
</plugins>
Expand Down
12 changes: 12 additions & 0 deletions jdm-dist/jdm-deb/src/main/jpackage-resources/template.desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[Desktop Entry]
Name=APPLICATION_NAME
GenericName=Disk Benchmark
Comment=APPLICATION_DESCRIPTION
Exec=APPLICATION_LAUNCHER
Icon=APPLICATION_ICON
Terminal=false
Type=Application
Categories=DEPLOY_BUNDLE_CATEGORY
Keywords=disk;benchmark;performance;storage;speed;
StartupWMClass=jdiskmark-App
DESKTOP_MIMES
38 changes: 38 additions & 0 deletions jdm-dist/jdm-deb/src/main/jpackage-resources/template.postinst
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/bin/sh
# postinst script for APPLICATION_PACKAGE
#
# see: dh_installdeb(1)

set -e

# summary of how this script can be called:
# * <postinst> `configure' <most-recently-configured-version>
# * <old-postinst> `abort-upgrade' <new version>
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
# <new-version>
# * <postinst> `abort-remove'
# * <deconfigured's-postinst> `abort-configure' `in-favour'
# <failed-install-package> <version> `removing'
# <conflicting-package> <version>
# for details, see https://www.debian.org/doc/debian-policy/ or
# the debian-policy package

package_type=deb
LAUNCHER_AS_SERVICE_SCRIPTS

case "$1" in
configure)
DESKTOP_COMMANDS_INSTALL
LAUNCHER_AS_SERVICE_COMMANDS_INSTALL
;;

abort-upgrade|abort-remove|abort-deconfigure)
;;

*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac

exit 0
Loading