99import com .tractionrec .recrec .ui .TypographyConstants ;
1010
1111import javax .swing .*;
12+ import javax .imageio .ImageIO ;
13+ import java .awt .*;
14+ import java .awt .image .BufferedImage ;
15+ import java .io .IOException ;
16+ import java .io .InputStream ;
17+ import java .util .ArrayList ;
18+ import java .util .Arrays ;
19+ import java .util .List ;
1220
1321public class RecRecApplication {
1422
1523 public static String MANIFEST_PROD_PROPERTY_NAME = "Element-Express-Production" ;
1624
1725 public static void main (String [] args ) {
26+ // Configure platform-specific properties before UI setup
27+ configurePlatformProperties ();
28+
1829 // Configure DNS caching for better performance with high concurrent requests
1930 configureDNSCaching ();
2031
2132 TractionRecTheme .setup ();
2233 RecRecState state = new RecRecState ();
2334 JFrame applicationFrame = new JFrame ("RecRec" );
35+
36+ // Set the taskbar icon with multiple approaches for better platform support
37+ setApplicationIcon (applicationFrame );
38+
2439 applicationFrame .setJMenuBar (buildMenuBar ());
2540 RecFormStack stack = new RecFormStack (applicationFrame );
2641 RecRecStart startForm = new RecRecStart (state , stack );
@@ -36,6 +51,64 @@ public static boolean isProduction() {
3651 return Manifests .exists (MANIFEST_PROD_PROPERTY_NAME ) && "true" .equals (Manifests .read (MANIFEST_PROD_PROPERTY_NAME ));
3752 }
3853
54+ /**
55+ * Set application icon using multiple approaches for maximum compatibility
56+ * @param frame The main application frame
57+ */
58+ private static void setApplicationIcon (JFrame frame ) {
59+ Image logoImage = loadLogoImage ();
60+ if (logoImage == null ) {
61+ System .err .println ("Warning: Could not load application logo" );
62+ return ;
63+ }
64+
65+ try {
66+ // Approach 1: Traditional JFrame icon (for window title bar and Alt+Tab)
67+ List <Image > iconImages = loadIconImages ();
68+ if (!iconImages .isEmpty ()) {
69+ frame .setIconImages (iconImages );
70+ }
71+
72+ // Approach 2: Modern Java 9+ Taskbar API (for dock/taskbar)
73+ if (Taskbar .isTaskbarSupported ()) {
74+ Taskbar taskbar = Taskbar .getTaskbar ();
75+ if (taskbar .isSupported (Taskbar .Feature .ICON_IMAGE )) {
76+ // Use a larger icon for taskbar (typically 64px or 128px works well)
77+ Image taskbarIcon = createSquareIcon (logoImage , 128 );
78+ taskbar .setIconImage (taskbarIcon );
79+ }
80+ }
81+
82+ } catch (Exception e ) {
83+ System .err .println ("Warning: Could not set application icon: " + e .getMessage ());
84+ // Fallback to basic approach
85+ frame .setIconImage (logoImage );
86+ }
87+ }
88+
89+ /**
90+ * Configure platform-specific properties for better application integration
91+ */
92+ private static void configurePlatformProperties () {
93+ // macOS specific properties
94+ if (System .getProperty ("os.name" ).toLowerCase ().contains ("mac" )) {
95+ // Set application name in dock
96+ System .setProperty ("apple.awt.application.name" , "RecRec" );
97+
98+ // Enable native look and feel integration
99+ System .setProperty ("apple.laf.useScreenMenuBar" , "true" );
100+
101+ // Set dock icon behavior
102+ System .setProperty ("apple.awt.application.appearance" , "system" );
103+ }
104+
105+ // Windows specific properties
106+ if (System .getProperty ("os.name" ).toLowerCase ().contains ("windows" )) {
107+ // Enable Windows-specific optimizations
108+ System .setProperty ("sun.java2d.d3d" , "true" );
109+ }
110+ }
111+
39112 /**
40113 * Configure DNS caching to prevent DNS resolution issues with high concurrent requests
41114 */
@@ -63,6 +136,16 @@ private static JMenuBar buildMenuBar() {
63136
64137 topMenuBar .add (Box .createHorizontalStrut (10 ));
65138
139+ // Add company logo
140+ ImageIcon logoIcon = loadLogoIcon (20 ); // 20px height for menu bar
141+ if (logoIcon != null ) {
142+ JLabel logoLabel = new JLabel (logoIcon );
143+ // Add vertical padding to better align with menu bar
144+ logoLabel .setBorder (BorderFactory .createEmptyBorder (4 , 0 , 4 , 0 ));
145+ topMenuBar .add (logoLabel );
146+ topMenuBar .add (Box .createHorizontalStrut (8 ));
147+ }
148+
66149 JLabel titleLabel = new JLabel ("RecRec" );
67150 titleLabel .setForeground (TractionRecTheme .TEXT_INVERSE );
68151 titleLabel .setFont (TypographyConstants .FONT_SUBHEADING );
@@ -103,4 +186,98 @@ private static JMenuBar buildMenuBar() {
103186 return topMenuBar ;
104187 }
105188
189+ /**
190+ * Load multiple sizes of the company logo for taskbar/dock icons
191+ * @return List of Image objects in different sizes
192+ */
193+ private static List <Image > loadIconImages () {
194+ List <Image > iconImages = new ArrayList <>();
195+ Image baseImage = loadLogoImage ();
196+
197+ if (baseImage != null ) {
198+ // Common icon sizes for different platforms
199+ int [] sizes = {16 , 20 , 24 , 32 , 40 , 48 , 64 , 128 , 256 };
200+
201+ for (int size : sizes ) {
202+ // For taskbar icons, we want to maintain aspect ratio but fit within square bounds
203+ Image scaledImage = createSquareIcon (baseImage , size );
204+ iconImages .add (scaledImage );
205+ }
206+ }
207+
208+ return iconImages ;
209+ }
210+
211+ /**
212+ * Create a square icon from the base image, maintaining aspect ratio and centering
213+ * @param baseImage The source image
214+ * @param size The target square size
215+ * @return Square image with the logo centered
216+ */
217+ private static Image createSquareIcon (Image baseImage , int size ) {
218+ int originalWidth = baseImage .getWidth (null );
219+ int originalHeight = baseImage .getHeight (null );
220+
221+ // Calculate scaling to fit within square while maintaining aspect ratio
222+ double scale = Math .min ((double ) size / originalWidth , (double ) size / originalHeight );
223+ int scaledWidth = (int ) (originalWidth * scale );
224+ int scaledHeight = (int ) (originalHeight * scale );
225+
226+ // Create a square buffered image with transparent background
227+ BufferedImage squareIcon = new BufferedImage (size , size , BufferedImage .TYPE_INT_ARGB );
228+ Graphics2D g2d = squareIcon .createGraphics ();
229+
230+ // Enable high-quality rendering
231+ g2d .setRenderingHint (RenderingHints .KEY_INTERPOLATION , RenderingHints .VALUE_INTERPOLATION_BILINEAR );
232+ g2d .setRenderingHint (RenderingHints .KEY_RENDERING , RenderingHints .VALUE_RENDER_QUALITY );
233+ g2d .setRenderingHint (RenderingHints .KEY_ANTIALIASING , RenderingHints .VALUE_ANTIALIAS_ON );
234+
235+ // Center the scaled image in the square
236+ int x = (size - scaledWidth ) / 2 ;
237+ int y = (size - scaledHeight ) / 2 ;
238+
239+ g2d .drawImage (baseImage , x , y , scaledWidth , scaledHeight , null );
240+ g2d .dispose ();
241+
242+ return squareIcon ;
243+ }
244+
245+ /**
246+ * Load the company logo image from resources
247+ * @return Image object or null if loading fails
248+ */
249+ public static Image loadLogoImage () {
250+ try {
251+ InputStream logoStream = RecRecApplication .class .getResourceAsStream ("/logo.png" );
252+ if (logoStream != null ) {
253+ BufferedImage logoImage = ImageIO .read (logoStream );
254+ logoStream .close ();
255+ return logoImage ;
256+ }
257+ } catch (IOException e ) {
258+ System .err .println ("Failed to load logo image: " + e .getMessage ());
259+ }
260+ return null ;
261+ }
262+
263+ /**
264+ * Load the company logo as an ImageIcon scaled to the specified height
265+ * @param height The desired height in pixels
266+ * @return ImageIcon or null if loading fails
267+ */
268+ public static ImageIcon loadLogoIcon (int height ) {
269+ Image logoImage = loadLogoImage ();
270+ if (logoImage != null ) {
271+ // Calculate width to maintain aspect ratio
272+ int originalWidth = logoImage .getWidth (null );
273+ int originalHeight = logoImage .getHeight (null );
274+ int scaledWidth = (originalWidth * height ) / originalHeight ;
275+
276+ // Scale the image smoothly
277+ Image scaledImage = logoImage .getScaledInstance (scaledWidth , height , Image .SCALE_SMOOTH );
278+ return new ImageIcon (scaledImage );
279+ }
280+ return null ;
281+ }
282+
106283}
0 commit comments