-
Notifications
You must be signed in to change notification settings - Fork 0
Application Entry Point and Initialization
Relevant source files
This document describes the application bootstrap process in the MouseMacros system. The MouseMacro class serves as the application entry point, executing the minimal initialization sequence required before the main UI can launch. This includes configuring the JNativeHook native library path and delegating UI creation to the Swing Event Dispatch Thread (EDT).
Related Pages:
- For
MainFramesingleton initialization and UI component setup, see Main Window (MainFrame)) - For
ConfigManager.CONFIG_DIRresolution and configuration loading, see ConfigManager - For JNativeHook integration and event capture setup, see Global Input Capture
The MouseMacro entry point is the first code executed by the JVM and serves as the initialization coordinator for the entire application. From the high-level architecture (Diagram 1), the entry point's responsibilities are:
- Configure JNativeHook library system properties before any hooks are registered
- Launch the
MainFramesingleton on the Swing EDT - Enable the
GlobalMouseListenerto access native libraries through proper path configuration
flowchart TD
JVM["JVM"]
MouseMacro["MouseMacro.main()"]
ConfigManagerStatic["ConfigManager.CONFIG_DIR<br>(static field)"]
SystemProperties["System.setProperty()<br>jnativehook.lib.path"]
SwingUtilities["SwingUtilities.invokeLater()"]
MAIN_FRAME["MainFrame.MAIN_FRAME<br>(singleton)"]
JVM --> MouseMacro
MouseMacro --> ConfigManagerStatic
MouseMacro --> SystemProperties
MouseMacro --> SwingUtilities
SwingUtilities --> MAIN_FRAME
Diagram: Entry Point Position in Application Layer
Sources: src/io/github/samera2022/mouse_macros/MouseMacro.java L1-L18
The MouseMacro class defines the application entry point through its main() method. This class has no instance methods, fields, or constructors—it exists solely to bootstrap the application.
| Property | Value |
|---|---|
| Package | io.github.samera2022.mouse_macros |
| Class Name | MouseMacro |
| Entry Method | public static void main(String[] args) |
| Source File | src/io/github/samera2022/mouse_macros/MouseMacro.java L9-L17 |
flowchart TD
MouseMacro["MouseMacro"]
SystemUtil["io.github.samera2022.mouse_macros.util.SystemUtil"]
SwingUtilities["javax.swing.SwingUtilities"]
MAIN_FRAME_Import["static import:<br>io.github.samera2022.mouse_macros.ui.frame.MainFrame.MAIN_FRAME"]
ConfigManager["io.github.samera2022.mouse_macros.manager.ConfigManager"]
MouseMacro --> SystemUtil
MouseMacro --> SwingUtilities
MouseMacro --> MAIN_FRAME_Import
MouseMacro --> ConfigManager
Diagram: MouseMacro Import Structure
The class imports:
-
SystemUtilsrc/io/github/samera2022/mouse_macros/MouseMacro.java L3 - imported but not used in the current implementation -
javax.swing.SwingUtilitiessrc/io/github/samera2022/mouse_macros/MouseMacro.java L5 - for EDT thread delegation - Static import of
MAIN_FRAMEconstant src/io/github/samera2022/mouse_macros/MouseMacro.java L7 - singleton instance reference -
ConfigManager.CONFIG_DIRvia fully qualified name src/io/github/samera2022/mouse_macros/MouseMacro.java L12 - configuration directory path
Sources: src/io/github/samera2022/mouse_macros/MouseMacro.java L1-L7
The main() method executes a two-phase initialization sequence:
sequenceDiagram
participant JVM
participant MouseMacro["MouseMacro.main()"]
participant ConfigManager["ConfigManager.CONFIG_DIR"]
participant FileSystem["File System"]
participant SystemProperties["System.setProperty()"]
participant SwingUtilities["SwingUtilities"]
participant EDT["Swing EDT"]
participant MAIN_FRAME["MainFrame.MAIN_FRAME"]
participant MouseMacro
participant FileSystem
participant ConfigManager
participant SystemProperties
participant MAIN_FRAME
participant SwingUtilities
participant EDT
JVM->>MouseMacro: "invoke main()"
note over MouseMacro,FileSystem: Phase 1: Native Library Configuration (Main Thread)
MouseMacro->>MouseMacro: "dllName = 'JNativeHook.x86_64.dll'"
MouseMacro->>ConfigManager: "access CONFIG_DIR"
ConfigManager-->>MouseMacro: "config directory path"
MouseMacro->>MouseMacro: "libDir = new File(configDir + '/libs/', dllName)"
MouseMacro->>FileSystem: "libDir.exists()?"
loop [Directory does not exist]
FileSystem-->>MouseMacro: "false"
MouseMacro->>FileSystem: "libDir.mkdirs()"
end
MouseMacro->>SystemProperties: "setProperty('jnativehook.lib.path', libDir.getAbsolutePath())"
note over MouseMacro,MAIN_FRAME: Phase 2: UI Initialization (EDT)
MouseMacro->>SwingUtilities: "invokeLater(() -> MAIN_FRAME.setVisible(true))"
SwingUtilities->>EDT: "enqueue lambda"
MouseMacro-->>JVM: "main() returns"
EDT->>MAIN_FRAME: "setVisible(true)"
note over MAIN_FRAME: Triggers MainFrame singleton initialization
Diagram: Complete Bootstrap Execution Flow
Executed synchronously on the main thread src/io/github/samera2022/mouse_macros/MouseMacro.java L11-L15
This phase must complete before JNativeHook classes are loaded, otherwise the JVM will fail to find the native library.
Critical ordering: System property jnativehook.lib.path must be set before any code references org.jnativehook.* classes.
Executed asynchronously on the EDT src/io/github/samera2022/mouse_macros/MouseMacro.java L16
The main thread enqueues the UI initialization task and terminates. All subsequent application logic runs on the EDT or background threads spawned by application components.
Sources: src/io/github/samera2022/mouse_macros/MouseMacro.java L10-L16
The first critical operation is configuring the JNativeHook native library path before any UI code executes.
flowchart TD
start["main() execution"]
dllName["Line 11:<br>dllName = 'JNativeHook.x86_64.dll'"]
configDir["Line 12:<br>configDir = ConfigManager.CONFIG_DIR"]
libDir["Line 13:<br>libDir = new File(configDir+'/libs/', dllName)"]
existsCheck["Line 14:<br>libDir.exists()"]
mkdirs["libDir.mkdirs()"]
setProperty["Line 15:<br>System.setProperty('jnativehook.lib.path',<br>libDir.getAbsolutePath())"]
start --> dllName
start --> configDir
dllName --> libDir
configDir --> libDir
libDir --> existsCheck
existsCheck --> mkdirs
existsCheck --> setProperty
mkdirs --> setProperty
Diagram: JNativeHook Native Library Path Configuration
The native library setup executes these operations:
| Line | Operation | Description |
|---|---|---|
| 11 | dllName = "JNativeHook.x86_64.dll" |
Hardcoded Windows x64 library name |
| 12 | configDir = ConfigManager.CONFIG_DIR |
Reads static field containing platform-specific config directory path |
| 13 | new File(configDir+"/libs/", dllName) |
Constructs path: {CONFIG_DIR}/libs/JNativeHook.x86_64.dll
|
| 14 | if (!libDir.exists()) libDir.mkdirs() |
Creates directory structure if missing |
| 15 | System.setProperty("jnativehook.lib.path", ...) |
Configures JVM system property for native library loading |
Important: The mkdirs() call creates both the libs/ directory and any missing parent directories. On first run, this ensures the entire directory structure exists.
After the first application launch, the directory structure is:
{CONFIG_DIR}/
├── config.cfg (created by ConfigManager)
├── cache.json (created by CacheManager)
└── libs/
└── JNativeHook.x86_64.dll (created by MouseMacro.main)
The libs/ directory and parent directories are created by mkdirs() at src/io/github/samera2022/mouse_macros/MouseMacro.java L14
JNativeHook will later extract and load the native DLL from this location when GlobalMouseListener registers hooks.
Platform-specific paths for CONFIG_DIR:
-
Windows:
%LOCALAPPDATA%\MouseMacros\ -
macOS:
~/Library/Application Support/MouseMacros/ -
Linux:
~/.local/share/MouseMacros/
See File and Path Utilities for CONFIG_DIR resolution logic.
Sources: src/io/github/samera2022/mouse_macros/MouseMacro.java L11-L14
After native library configuration, the main thread delegates UI creation to the Swing Event Dispatch Thread (EDT) using SwingUtilities.invokeLater() src/io/github/samera2022/mouse_macros/MouseMacro.java L16
flowchart TD
MainThread["Main Thread<br>(MouseMacro.main)"]
invokeLater["SwingUtilities.invokeLater()"]
lambda["Lambda:<br>() -> MAIN_FRAME.setVisible(true)"]
EDTQueue["EDT Event Queue"]
EDT["Event Dispatch Thread"]
setVisible["MAIN_FRAME.setVisible(true)"]
MainFrameInit["MainFrame singleton initialization"]
MainThreadEnd["Main thread terminates"]
MainThread --> invokeLater
invokeLater --> lambda
lambda --> EDTQueue
MainThread --> MainThreadEnd
EDTQueue --> EDT
EDT --> setVisible
setVisible --> MainFrameInit
Diagram: EDT Delegation via SwingUtilities.invokeLater()
Swing components are not thread-safe. All Swing operations (component creation, modification, event handling) must execute on a single thread: the EDT. Using SwingUtilities.invokeLater() ensures that:
- UI initialization happens on the EDT
- The main thread can terminate without blocking UI operations
- Thread safety constraints are satisfied
The MAIN_FRAME constant is statically imported src/io/github/samera2022/mouse_macros/MouseMacro.java L7
:
import static io.github.samera2022.mouse_macros.ui.frame.MainFrame.MAIN_FRAME;MAIN_FRAME is a public static final MainFrame field defined in the MainFrame class. When the lambda executes MAIN_FRAME.setVisible(true), it triggers:
-
Class Loading: The
MainFrameclass is loaded by the JVM classloader -
Static Initialization: The
MAIN_FRAMEsingleton is constructed - Constructor Execution: Complete UI initialization occurs (see Main Window (MainFrame)))
-
Window Display:
setVisible(true)displays the initialized window
The entire application UI is initialized lazily when MAIN_FRAME is first accessed.
Sources: src/io/github/samera2022/mouse_macros/MouseMacro.java L7-L16
The bootstrap sequence has strict ordering requirements to prevent runtime failures:
| Order | Operation | Thread | Line | Constraint |
|---|---|---|---|---|
| 1 | Set jnativehook.lib.path system property |
Main | 15 | Must execute before JNativeHook classes are loaded |
| 2 | Enqueue UI initialization lambda | Main | 16 | Must execute after library path configuration |
| 3 | Execute MAIN_FRAME.setVisible(true)
|
EDT | 16 | Must execute on EDT (Swing threading requirement) |
Native Library Loading: JNativeHook uses JNI (Java Native Interface) to load platform-specific DLLs. The JVM reads the jnativehook.lib.path system property when loading native code. If this property is not set before JNativeHook classes are accessed, the JVM will throw UnsatisfiedLinkError.
EDT Threading: Swing enforces single-threaded access to UI components. Calling setVisible() from the main thread would violate this constraint and could cause race conditions or deadlocks.
flowchart TD
JVM["JVM classloader"]
main["MouseMacro.main(args)<br>Line 10"]
configDir["ConfigManager.CONFIG_DIR<br>Line 12"]
libDirConstruct["new File(...)<br>Line 13"]
mkdirs["libDir.mkdirs()<br>Line 14"]
setProperty["System.setProperty()<br>Line 15"]
invokeLater["SwingUtilities.invokeLater()<br>Line 16"]
EDT["EDT execution"]
setVisible["MAIN_FRAME.setVisible(true)"]
MainFrameClassLoad["MainFrame class load"]
MainFrameSingleton["MAIN_FRAME field initialization"]
JVM --> main
main --> configDir
main --> libDirConstruct
libDirConstruct --> mkdirs
mkdirs --> setProperty
setProperty --> invokeLater
invokeLater --> EDT
EDT --> setVisible
setVisible --> MainFrameClassLoad
MainFrameClassLoad --> MainFrameSingleton
Diagram: Complete Method Invocation and Dependency Chain
The entry point performs minimal work—only 7 lines of executable code—before transferring control to MainFrame. This design keeps the bootstrap logic simple and focused.
Sources: src/io/github/samera2022/mouse_macros/MouseMacro.java L10-L16
The main() method signature includes the standard String[] args parameter src/io/github/samera2022/mouse_macros/MouseMacro.java L10
but this parameter is currently unused. The application does not support any command-line arguments.
All configuration is performed through:
- The
config.cfgfile - managed byConfigManager(see Configuration Files and Settings) - The settings dialogs -
SettingsDialogandMacroSettingsDialog(see Settings Dialog and Macro Settings Dialog)
If command-line argument parsing is added in the future, it should be inserted between lines 15 and 16:
System.setProperty("jnativehook.lib.path", libDir.getAbsolutePath());
// INSERT: parseCommandLineArgs(args) here
SwingUtilities.invokeLater(() -> MAIN_FRAME.setVisible(true));This ensures arguments are processed after native library setup but before UI initialization.
Sources: src/io/github/samera2022/mouse_macros/MouseMacro.java L10
The main() method does not implement explicit error handling. All exceptions propagate to the JVM's default uncaught exception handler, which prints a stack trace to stderr and terminates the process.
| Operation | Line | Failure Scenario | Exception Type | Recovery |
|---|---|---|---|---|
ConfigManager.CONFIG_DIR access |
12 | Static initialization failure | Various | None - application cannot start |
new File(...) |
13 | Invalid path characters | None thrown | Constructor succeeds with invalid path |
libDir.mkdirs() |
14 | Insufficient permissions | None thrown | Returns false, continues execution |
System.setProperty(...) |
15 | Security manager denies access | SecurityException |
JVM terminates |
SwingUtilities.invokeLater(...) |
16 | Null lambda (impossible here) | NullPointerException |
JVM terminates |
MAIN_FRAME initialization |
16 (EDT) | UI construction failure | Various (e.g., HeadlessException) |
EDT exception handler logs and terminates |
The application does not attempt graceful degradation on initialization failure. If the bootstrap sequence fails:
- The exception propagates to the JVM
- The JVM prints the stack trace
- The process terminates with non-zero exit code
Design Rationale: Bootstrap failures indicate severe environmental issues (missing directories, security restrictions, headless environment). Recovery is not practical, and early termination prevents the application from running in an invalid state.
Sources: src/io/github/samera2022/mouse_macros/MouseMacro.java L10-L16
The native library name is hardcoded as "JNativeHook.x86_64.dll" src/io/github/samera2022/mouse_macros/MouseMacro.java L11
which restricts the application to 64-bit Windows systems. The application will fail to start on other platforms because:
- JNativeHook cannot find the appropriately-named library file
- The Windows DLL format is incompatible with Linux/macOS
To support additional platforms, the entry point would need OS and architecture detection logic:
String osName = System.getProperty("os.name").toLowerCase();
String osArch = System.getProperty("os.arch").toLowerCase();
String dllName;
if (osName.contains("win")) {
dllName = "JNativeHook.x86_64.dll";
} else if (osName.contains("mac")) {
dllName = "libJNativeHook.x86_64.dylib";
} else if (osName.contains("nux")) {
dllName = "libJNativeHook.x86_64.so";
}
Required library files per platform:
| Platform | Architecture | Library File Name | Extension |
|---|---|---|---|
| Windows | x86_64 | JNativeHook.x86_64.dll |
Windows PE DLL |
| Linux | x86_64 | libJNativeHook.x86_64.so |
ELF Shared Object |
| macOS | x86_64 | libJNativeHook.x86_64.dylib |
Mach-O Dynamic Library |
| macOS | ARM64 (M1/M2) | libJNativeHook.arm64.dylib |
Mach-O Dynamic Library |
Note: SystemUtil is imported src/io/github/samera2022/mouse_macros/MouseMacro.java L3
but unused. This utility class could provide platform detection helpers for future multi-platform support.
Sources: src/io/github/samera2022/mouse_macros/MouseMacro.java L3-L11
The MouseMacro entry point integrates with:
-
ConfigManager: Retrieves
CONFIG_DIRfor library path construction src/io/github/samera2022/mouse_macros/MouseMacro.java L10 -
MainFrame: Accesses singleton
MAIN_FRAMEinstance src/io/github/samera2022/mouse_macros/MouseMacro.java L15 -
JVM System Properties: Sets
jnativehook.lib.pathsrc/io/github/samera2022/mouse_macros/MouseMacro.java L13 -
Swing EDT: Delegates UI work via
SwingUtilities.invokeLater()src/io/github/samera2022/mouse_macros/MouseMacro.java L15
flowchart TD
MouseMacro["MouseMacro.main()"]
ConfigManager["ConfigManager"]
MainFrame["MainFrame.MAIN_FRAME"]
SystemProps["System Properties"]
SwingEDT["Swing EDT"]
MouseMacro --> ConfigManager
MouseMacro --> SystemProps
MouseMacro --> SwingEDT
SwingEDT --> MainFrame
Diagram: Entry Point Dependencies
After the entry point completes, control flow passes entirely to the Event Dispatch Thread and the event-driven Swing framework. The main thread terminates after enqueueing the UI initialization task.
Sources: src/io/github/samera2022/mouse_macros/MouseMacro.java L8-L16