How Windows 95 Handled System Tray Mouse Clicks
In Windows 95, the system tray—officially named the notification area—relied on a callback-driven messaging architecture to communicate user interactions back to applications. When a user clicked or double-clicked an icon, the Windows shell captured the raw hardware mouse event and redirected it as an application-defined window message to the application's message loop, where it had to be unpacked and handled.
The Shell_NotifyIcon Interface
Applications integrated with the system tray using the Win32 Shell
API function Shell_NotifyIcon, passing the
NIM_ADD message along with a pointer to a
NOTIFYICONDATA structure. This structure established the
communication link between the Windows 95 taskbar process
(explorer.exe) and the host application.
Key fields in NOTIFYICONDATA included:
hWnd: The handle to the window designated to receive notifications.uID: An application-defined identifier for the specific icon.uCallbackMessage: A custom window message identifier (typically defined usingWM_USER + norWM_APP + n).
By configuring uCallbackMessage, the developer
instructed the shell to send that custom message to hWnd
whenever mouse activity occurred over the icon's designated coordinate
space.
Message Forwarding and Parameter Encoding
When a user moved the mouse over the icon, clicked it, or
double-clicked it, the taskbar captured the event and sent the specified
uCallbackMessage directly to the registered
hWnd. The shell passed the interaction details inside the
standard Win32 message parameters:
wParam: Contained theuIDof the notification icon, allowing a single window procedure to differentiate between multiple tray icons owned by the same application.lParam: Contained the underlying mouse event constant, such asWM_MOUSEMOVE,WM_LBUTTONDOWN,WM_LBUTTONUP,WM_RBUTTONUP, orWM_LBUTTONDBLCLK.
Processing Click and Double-Click Sequences
In Windows 95, double-clicks are not isolated events; they are part of a continuous sequence. When a user double-clicked an icon, the application received the messages in the following order:
WM_LBUTTONDOWNWM_LBUTTONUPWM_LBUTTONDBLCLKWM_LBUTTONUP
Because WM_LBUTTONUP fired on the initial click before
WM_LBUTTONDBLCLK arrived, applications designed to support
both single-click and double-click behaviors had to handle the timing
carefully. Executing an action immediately on WM_LBUTTONUP
could result in unwanted behavior if the user intended to
double-click.
To manage this, developers used two primary implementation patterns:
- Distinct Action Allocation: Many applications
avoided conflicting actions by reserving the left double-click for
opening the primary interface (e.g., maximizing the window or launching
properties) while reserving single clicks for other purposes, such as
displaying a popup menu on
WM_RBUTTONUP(right-click). - Timer-Based Delay: If an application required
separate actions for single and double left-clicks, it set a system
timer via
SetTimeron the firstWM_LBUTTONUPmatching the duration returned byGetDoubleClickTime(). IfWM_LBUTTONDBLCLKarrived before the timer expired, the timer was cancelled viaKillTimerand the double-click handler executed. If the timer elapsed without a double-click arriving, the application executed the single-click routine.