[STOBJECT]
[reactos.git] / reactos / dll / shellext / stobject / volume.cpp
index 844bdd0..57d9a5d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * PROJECT:     ReactOS system libraries
  * LICENSE:     GPL - See COPYING in the top level directory
- * FILE:        dll\win32\stobject\volume.cpp
+ * FILE:        dll/shellext/stobject/volume.cpp
  * PURPOSE:     Volume notification icon handler
  * PROGRAMMERS: David Quintana <gigaherz@gmail.com>
  */
@@ -11,6 +11,9 @@
 #include <mmsystem.h>
 #include <mmddk.h>
 
+#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
+#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
+
 WINE_DEFAULT_DEBUG_CHANNEL(stobject);
 
 HICON g_hIconVolume;
@@ -28,13 +31,13 @@ BOOL g_IsMute = FALSE;
 static HRESULT __stdcall Volume_FindMixerControl(CSysTray * pSysTray)
 {
     MMRESULT result;
-    UINT mixerId    = 0;
+    UINT mixerId = 0;
     DWORD waveOutId = 0;
-    DWORD param2    = 0;
+    DWORD param2 = 0;
 
     TRACE("Volume_FindDefaultMixerID\n");
 
-    result = waveOutMessage((HWAVEOUT) WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR) &waveOutId, (DWORD_PTR) &param2);
+    result = waveOutMessage((HWAVEOUT)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR)&waveOutId, (DWORD_PTR)&param2);
     if (result)
         return E_FAIL;
 
@@ -48,7 +51,7 @@ static HRESULT __stdcall Volume_FindMixerControl(CSysTray * pSysTray)
     {
         TRACE("waveOut default device is %d\n", waveOutId);
 
-        result = mixerGetID((HMIXEROBJ) waveOutId, &mixerId, MIXER_OBJECTF_WAVEOUT);
+        result = mixerGetID((HMIXEROBJ)waveOutId, &mixerId, MIXER_OBJECTF_WAVEOUT);
         if (result)
             return E_FAIL;
 
@@ -79,7 +82,7 @@ static HRESULT __stdcall Volume_FindMixerControl(CSysTray * pSysTray)
     {
         mixerLine.cbStruct = sizeof(mixerLine);
         mixerLine.dwDestination = idx;
-        if (!mixerGetLineInfoW((HMIXEROBJ) g_mixerId, &mixerLine, 0))
+        if (!mixerGetLineInfoW((HMIXEROBJ)g_mixerId, &mixerLine, 0))
         {
             if (mixerLine.dwComponentType >= MIXERLINE_COMPONENTTYPE_DST_SPEAKERS &&
                 mixerLine.dwComponentType <= MIXERLINE_COMPONENTTYPE_DST_HEADPHONES)
@@ -102,11 +105,11 @@ static HRESULT __stdcall Volume_FindMixerControl(CSysTray * pSysTray)
     mixerLineControls.pamxctrl = &mixerControl;
     mixerLineControls.cbmxctrl = sizeof(mixerControl);
 
-    if (mixerGetLineControlsW((HMIXEROBJ) g_mixerId, &mixerLineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE))
+    if (mixerGetLineControlsW((HMIXEROBJ)g_mixerId, &mixerLineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE))
         return E_FAIL;
 
     TRACE("Found control id %d for mute: %d\n", mixerControl.dwControlID);
-    
+
     g_muteControlID = mixerControl.dwControlID;
 
     return S_OK;
@@ -140,6 +143,7 @@ HRESULT Volume_IsMute()
 HRESULT STDMETHODCALLTYPE Volume_Init(_In_ CSysTray * pSysTray)
 {
     HRESULT hr;
+    WCHAR strTooltip[128];
 
     TRACE("Volume_Init\n");
 
@@ -163,22 +167,38 @@ HRESULT STDMETHODCALLTYPE Volume_Init(_In_ CSysTray * pSysTray)
     else
         icon = g_hIconVolume;
 
-    return pSysTray->NotifyIcon(NIM_ADD, ID_ICON_VOLUME, icon, L"Volume Control");
+    LoadStringW(g_hInstance, IDS_VOL_VOLUME, strTooltip, _countof(strTooltip));
+    return pSysTray->NotifyIcon(NIM_ADD, ID_ICON_VOLUME, icon, strTooltip);
 }
 
 HRESULT STDMETHODCALLTYPE Volume_Update(_In_ CSysTray * pSysTray)
 {
+    BOOL PrevState;
+
     TRACE("Volume_Update\n");
 
+    PrevState = g_IsMute;
     Volume_IsMute();
 
-    HICON icon;
-    if (g_IsMute)
-        icon = g_hIconMute;
-    else
-        icon = g_hIconVolume;
+    if (PrevState != g_IsMute)
+    {
+        WCHAR strTooltip[128];
+        HICON icon;
+        if (g_IsMute) {
+            icon = g_hIconMute;
+            LoadStringW(g_hInstance, IDS_VOL_MUTED, strTooltip, _countof(strTooltip));
+        }
+        else {
+            icon = g_hIconVolume;
+            LoadStringW(g_hInstance, IDS_VOL_VOLUME, strTooltip, _countof(strTooltip));
+        }
 
-    return pSysTray->NotifyIcon(NIM_MODIFY, ID_ICON_VOLUME, icon, L"Placeholder");
+        return pSysTray->NotifyIcon(NIM_MODIFY, ID_ICON_VOLUME, icon, strTooltip);
+    }
+    else
+    {
+        return S_OK;
+    }
 }
 
 HRESULT STDMETHODCALLTYPE Volume_Shutdown(_In_ CSysTray * pSysTray)
@@ -193,6 +213,49 @@ HRESULT Volume_OnDeviceChange(_In_ CSysTray * pSysTray, WPARAM wParam, LPARAM lP
     return Volume_FindMixerControl(pSysTray);
 }
 
+static void _RunVolume()
+{
+    // FIXME: ensure we are loading the right one
+    ShellExecuteW(NULL, NULL, L"sndvol32.exe", NULL, NULL, SW_SHOWNORMAL);
+}
+
+static void _RunMMCpl()
+{
+    ShellExecuteW(NULL, NULL, L"mmsys.cpl", NULL, NULL, SW_NORMAL);
+}
+
+static void _ShowContextMenu(CSysTray * pSysTray)
+{
+    WCHAR strAdjust[128];
+    WCHAR strOpen[128];
+    LoadStringW(g_hInstance, IDS_VOL_OPEN, strOpen, _countof(strOpen));
+    LoadStringW(g_hInstance, IDS_VOL_ADJUST, strAdjust, _countof(strAdjust));
+
+    HMENU hPopup = CreatePopupMenu();
+    AppendMenuW(hPopup, MF_STRING, IDS_VOL_OPEN, strOpen);
+    AppendMenuW(hPopup, MF_STRING, IDS_VOL_ADJUST, strAdjust);
+
+    DWORD flags = TPM_RETURNCMD | TPM_NONOTIFY | TPM_RIGHTALIGN | TPM_BOTTOMALIGN;
+    DWORD msgPos = GetMessagePos();
+
+    SetForegroundWindow(pSysTray->GetHWnd());
+    DWORD id = TrackPopupMenuEx(hPopup, flags,
+        GET_X_LPARAM(msgPos), GET_Y_LPARAM(msgPos),
+        pSysTray->GetHWnd(), NULL);
+
+    DestroyMenu(hPopup);
+
+    switch (id)
+    {
+    case IDS_VOL_OPEN:
+        _RunVolume();
+        break;
+    case IDS_VOL_ADJUST:
+        _RunMMCpl();
+        break;
+    }
+}
+
 HRESULT STDMETHODCALLTYPE Volume_Message(_In_ CSysTray * pSysTray, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
     if (uMsg == g_mmDeviceChange)
@@ -216,13 +279,12 @@ HRESULT STDMETHODCALLTYPE Volume_Message(_In_ CSysTray * pSysTray, UINT uMsg, WP
         TRACE("TODO: display volume slider\n");
         break;
     case WM_LBUTTONDBLCLK:
-        // FIXME: ensure we are loading the right one
-        ShellExecute(NULL, NULL, L"sndvol32.exe", NULL, NULL, SW_SHOWNORMAL);
+        _RunVolume();
         break;
     case WM_RBUTTONDOWN:
         break;
     case WM_RBUTTONUP:
-        break;
+        _ShowContextMenu(pSysTray);
     case WM_RBUTTONDBLCLK:
         break;
     case WM_MOUSEMOVE: