diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl
index b4d6b3718e..95fe0deeac 100644
--- a/build/bakefiles/files.bkl
+++ b/build/bakefiles/files.bkl
@@ -3025,11 +3025,13 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file!
src/msw/richtooltip.cpp
src/msw/sound.cpp
src/msw/taskbar.cpp
+ src/msw/taskbarbutton.cpp
wx/msw/notifmsg.h
wx/msw/sound.h
wx/msw/taskbar.h
+ wx/msw/taskbarbutton.h
diff --git a/include/wx/msw/taskbarbutton.h b/include/wx/msw/taskbarbutton.h
new file mode 100644
index 0000000000..8637076711
--- /dev/null
+++ b/include/wx/msw/taskbarbutton.h
@@ -0,0 +1,35 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name: include/wx/msw/taskbarbutton.h
+// Purpose: Defines wxTaskBarButtonImpl class.
+// Author: Chaobin Zhang
+// Created: 2014-06-01
+// Copyright: (c) 2014 wxWidgets development team
+// Licence: wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_MSW_TASKBARBUTTON_H_
+#define _WX_MSW_TASKBARBUTTON_H_
+
+#if wxUSE_TASKBARBUTTON
+
+#include "wx/defs.h"
+
+struct ITaskbarList3;
+
+class wxTaskBarButtonImpl : public wxTaskBarButton {
+public:
+ virtual ~wxTaskBarButtonImpl();
+
+ virtual void SetProgressValue(int value) wxOVERRIDE;
+
+private:
+ friend class wxTopLevelWindowMSW;
+ wxTaskBarButtonImpl(WXWidget parent);
+
+ WXWidget m_hwnd;
+ ITaskbarList3 *m_taskbarList;
+};
+
+#endif // wxUSE_TASKBARBUTTON
+
+#endif // _WX_MSW_TASKBARBUTTON_H_
diff --git a/include/wx/msw/toplevel.h b/include/wx/msw/toplevel.h
index 93427a7a45..18d3365985 100644
--- a/include/wx/msw/toplevel.h
+++ b/include/wx/msw/toplevel.h
@@ -11,6 +11,8 @@
#ifndef _WX_MSW_TOPLEVEL_H_
#define _WX_MSW_TOPLEVEL_H_
+class WXDLLIMPEXP_FWD_ADV wxTaskBarButton;
+
// ----------------------------------------------------------------------------
// wxTopLevelWindowMSW
// ----------------------------------------------------------------------------
@@ -121,6 +123,31 @@ public:
// returns true if the platform should explicitly apply a theme border
virtual bool CanApplyThemeBorder() const { return false; }
+#if wxUSE_MENUS && !defined(__WXUNIVERSAL__)
+ bool HandleMenuSelect(WXWORD nItem, WXWORD nFlags, WXHMENU hMenu);
+
+ // handle WM_EXITMENULOOP message for Win95 only
+ bool HandleExitMenuLoop(WXWORD isPopup);
+
+ // handle WM_(UN)INITMENUPOPUP message to generate wxEVT_MENU_OPEN/CLOSE
+ bool HandleMenuPopup(wxEventType evtType, WXHMENU hMenu);
+
+ // Command part of HandleMenuPopup() and HandleExitMenuLoop().
+ bool DoSendMenuOpenCloseEvent(wxEventType evtType, wxMenu* menu, bool popup);
+
+ // Find the menu corresponding to the given handle.
+ virtual wxMenu* MSWFindMenuFromHMENU(WXHMENU hMenu);
+#endif // wxUSE_MENUS && !__WXUNIVERSAL__
+
+#if wxUSE_TASKBARBUTTON
+ // Return the taskbar button of the window.
+ //
+ // The pointer returned by this method belongs to the window and will be
+ // deleted when the window itself is, do not delete it yourself. May return
+ // NULL if the initialization of taskbar button failed.
+ wxTaskBarButton* MSWGetTaskBarButton();
+#endif // wxUSE_TASKBARBUTTON
+
protected:
// common part of all ctors
void Init();
@@ -235,6 +262,14 @@ private:
// MSWGetSystemMenu(). Owned by this window.
wxMenu *m_menuSystem;
+ // The number of currently opened menus: 0 initially, 1 when a top level
+ // menu is opened, 2 when its submenu is opened and so on.
+ int m_menuDepth;
+
+#if wxUSE_TASKBARBUTTON
+ wxTaskBarButton *m_taskBarButton;
+#endif
+
DECLARE_EVENT_TABLE()
wxDECLARE_NO_COPY_CLASS(wxTopLevelWindowMSW);
};
diff --git a/include/wx/taskbarbutton.h b/include/wx/taskbarbutton.h
new file mode 100644
index 0000000000..6b93be69be
--- /dev/null
+++ b/include/wx/taskbarbutton.h
@@ -0,0 +1,40 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name: include/taskbarbutton.h
+// Purpose: Defines wxTaskBarButton class for manipulating buttons on the
+// windows taskbar.
+// Author: Chaobin Zhang
+// Created: 2014-04-30
+// Copyright: (c) 2014 wxWidgets development team
+// Licence: wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_TASKBARBUTTON_H_
+#define _WX_TASKBARBUTTON_H_
+
+#if wxUSE_TASKBARBUTTON
+
+// ----------------------------------------------------------------------------
+// wxTaskBarButton: define wxTaskBarButton interface.
+// ----------------------------------------------------------------------------
+
+class WXDLLIMPEXP_ADV wxTaskBarButton
+{
+public:
+ wxTaskBarButton() { }
+ virtual ~wxTaskBarButton() { }
+
+ // Operations:
+ virtual void SetProgressValue(int value) = 0;
+
+private:
+ wxDECLARE_NO_COPY_CLASS(wxTaskBarButton);
+};
+
+
+#if defined(__WXMSW__)
+ #include "wx/msw/taskbarbutton.h"
+#endif
+
+#endif // wxUSE_TASKBARBUTTON
+
+#endif // _WX_TASKBARBUTTON_H_
diff --git a/samples/taskbarbutton/taskbarbutton.bkl b/samples/taskbarbutton/taskbarbutton.bkl
new file mode 100644
index 0000000000..c7c2d11203
--- /dev/null
+++ b/samples/taskbarbutton/taskbarbutton.bkl
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ taskbarbutton.cpp
+ adv
+ core
+ base
+
+
+
diff --git a/samples/taskbarbutton/taskbarbutton.cpp b/samples/taskbarbutton/taskbarbutton.cpp
new file mode 100644
index 0000000000..d4da7a9ab9
--- /dev/null
+++ b/samples/taskbarbutton/taskbarbutton.cpp
@@ -0,0 +1,98 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name: taskbarbutton.cpp
+// Purpose: wxTaskbarButton sample
+// Author: Chaobin Zhang
+// Created: 2014-04-30
+// Copyright: (c) 2014 wxWidgets development team
+// Licence: wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+ #include "wx/wx.h"
+#endif
+
+#include "wx/taskbarbutton.h"
+
+enum
+{
+ ProgressValueSlider = wxID_HIGHEST,
+};
+
+class MyApp : public wxApp
+{
+public:
+ virtual bool OnInit();
+};
+
+class MyFrame : public wxFrame
+{
+public:
+ MyFrame(const wxString& title);
+
+private:
+ wxDECLARE_EVENT_TABLE();
+
+ void OnSetProgressValue(wxScrollEvent& WXUNUSED(event));
+
+ wxSlider *m_slider;
+};
+
+IMPLEMENT_APP(MyApp)
+
+bool MyApp::OnInit()
+{
+ if ( !wxApp::OnInit() )
+ return false;
+
+ MyFrame *frame = new MyFrame("wxTaskbarButton App");
+ frame->Show(true);
+
+ return true;
+}
+
+MyFrame::MyFrame(const wxString& title)
+ : wxFrame(NULL, wxID_ANY, title)
+{
+ wxPanel *panel = new wxPanel(this);
+ wxBoxSizer *mainSizer = new wxBoxSizer(wxVERTICAL);
+ wxFlexGridSizer *gs = new wxFlexGridSizer(4, 2, 10, 10);
+
+ // SetProgressValue section.
+ wxStaticBoxSizer *spvSizer =
+ new wxStaticBoxSizer(wxVERTICAL, panel, wxT("SetProgressValue"));
+ int flags = wxSL_MIN_MAX_LABELS | wxSL_VALUE_LABEL | wxSL_AUTOTICKS;
+ m_slider = new wxSlider(spvSizer->GetStaticBox(), ProgressValueSlider,
+ 0, 0, 100,
+ wxDefaultPosition, wxSize(250, -1),
+ flags);
+ m_slider->SetTickFreq(10);
+ spvSizer->Add(m_slider);
+
+ gs->Add(spvSizer, 0, wxEXPAND);
+
+ wxStaticText *text = new wxStaticText(
+ panel, wxID_ANY, wxT("Welcome to wxTaskbarButton sample"));
+ mainSizer->Add(text, 0, wxALIGN_CENTRE_HORIZONTAL);
+ mainSizer->Add(gs);
+
+ panel->SetSizer(mainSizer);
+
+ SetIcon(wxICON(sample));
+ SetSize(537, 420);
+ Centre();
+}
+
+wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
+ EVT_COMMAND_SCROLL_CHANGED(ProgressValueSlider, MyFrame::OnSetProgressValue)
+wxEND_EVENT_TABLE()
+
+void MyFrame::OnSetProgressValue(wxScrollEvent& WXUNUSED(event))
+{
+ MSWGetTaskBarButton()->SetProgressValue(m_slider->GetValue());
+}
diff --git a/src/msw/taskbarbutton.cpp b/src/msw/taskbarbutton.cpp
new file mode 100644
index 0000000000..96f3142a65
--- /dev/null
+++ b/src/msw/taskbarbutton.cpp
@@ -0,0 +1,63 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name: src/msw/taskbarbutton.cpp
+// Purpose: Implements wxTaskbarButtonImpl class for manipulating buttons on
+// the Windows taskbar.
+// Author: Chaobin Zhang
+// Created: 2014-06-01
+// Copyright: (c) 2014 wxWidgets development team
+// Licence: wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+#if wxUSE_TASKBARBUTTON
+
+#include "wx/msw/wrapshl.h"
+#include "wx/msw/private.h"
+#include "wx/taskbarbutton.h"
+
+#include
+
+wxTaskBarButtonImpl::wxTaskBarButtonImpl(WXWidget parent) : m_hwnd(parent)
+{
+ HRESULT hr = CoCreateInstance
+ (
+ CLSID_TaskbarList,
+ NULL,
+ CLSCTX_ALL,
+ IID_ITaskbarList3,
+ reinterpret_cast(&m_taskbarList)
+ );
+ if ( FAILED(hr) )
+ {
+ wxLogApiError(wxT("CoCreateInstance(CLSID_TaskbarButtonList)"), hr);
+ return;
+ }
+
+ hr = m_taskbarList->HrInit();
+ if ( FAILED(hr) )
+ {
+ wxLogApiError(wxT("ITaskbarButtonList3::Init"), hr);
+ return;
+ }
+}
+
+wxTaskBarButtonImpl::~wxTaskBarButtonImpl()
+{
+ if ( m_taskbarList )
+ m_taskbarList->Release();
+}
+
+void wxTaskBarButtonImpl::SetProgressValue(int value)
+{
+ wxCHECK_RET( value >= 0 && value <= 100,
+ wxT("Invalid value, must be in the range of [0, 100].") );
+
+ m_taskbarList->SetProgressValue(m_hwnd, value, 100);
+}
+
+#endif // wxUSE_TASKBARBUTTON
diff --git a/src/msw/toplevel.cpp b/src/msw/toplevel.cpp
index 1305aad088..9764d06d20 100644
--- a/src/msw/toplevel.cpp
+++ b/src/msw/toplevel.cpp
@@ -55,6 +55,10 @@
#include "wx/display.h"
+#if wxUSE_TASKBARBUTTON
+#include "wx/taskbarbutton.h"
+#endif
+
#ifndef ICON_BIG
#define ICON_BIG 1
#endif
@@ -430,6 +434,7 @@ WXLRESULT wxTopLevelWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WX
#if wxUSE_TASKBARBUTTON
if ( message == gs_msgTaskbarButtonCreated )
{
+ m_taskBarButton = new wxTaskBarButtonImpl(GetHandle());
processed = true;
}
#endif
@@ -649,7 +654,9 @@ bool wxTopLevelWindowMSW::Create(wxWindow *parent,
#if defined(__SMARTPHONE__) && defined(__WXWINCE__)
SetRightMenu(); // to nothing for initialization
#endif
+
#if wxUSE_TASKBARBUTTON
+ m_taskBarButton = NULL;
gs_msgTaskbarButtonCreated =
::RegisterWindowMessage(wxT("TaskbarButtonCreated"));
#endif
@@ -1456,6 +1463,123 @@ void wxTopLevelWindowMSW::OnActivate(wxActivateEvent& event)
}
}
+#if wxUSE_MENUS && !defined(__WXUNIVERSAL__)
+
+bool
+wxTopLevelWindowMSW::HandleMenuSelect(WXWORD nItem, WXWORD flags, WXHMENU hMenu)
+{
+ // Ignore the special messages generated when the menu is closed (this is
+ // the only case when the flags are set to -1), in particular don't clear
+ // the help string in the status bar when this happens as it had just been
+ // restored by the base class code.
+ if ( !hMenu && flags == 0xffff )
+ return false;
+
+ // Unfortunately we also need to ignore another message which is sent after
+ // closing the currently active submenu of the menu bar by pressing Escape:
+ // in this case we get WM_UNINITMENUPOPUP, from which we generate
+ // wxEVT_MENU_CLOSE, and _then_ we get WM_MENUSELECT for the top level menu
+ // from which we overwrite the help string just restored by OnMenuClose()
+ // handler in wxFrameBase. To prevent this from happening we discard these
+ // messages but only in the case it's really the top level menu as we still
+ // need to clear the help string when a submenu is selected in a menu.
+ if ( flags == (MF_POPUP | MF_HILITE) && !m_menuDepth )
+ return false;
+
+ // sign extend to int from unsigned short we get from Windows
+ int item = (signed short)nItem;
+
+ // WM_MENUSELECT is generated for both normal items and menus, including
+ // the top level menus of the menu bar, which can't be represented using
+ // any valid identifier in wxMenuEvent so use an otherwise unused value for
+ // them
+ if ( flags & (MF_POPUP | MF_SEPARATOR) )
+ item = wxID_NONE;
+
+ wxMenuEvent event(wxEVT_MENU_HIGHLIGHT, item);
+ event.SetEventObject(this);
+
+ if ( HandleWindowEvent(event) )
+ return true;
+
+ // by default, i.e. if the event wasn't handled above, clear the status bar
+ // text when an item which can't have any associated help string in wx API
+ // is selected
+ if ( item == wxID_NONE )
+ DoGiveHelp(wxEmptyString, true);
+
+ return false;
+}
+
+bool
+wxTopLevelWindowMSW::DoSendMenuOpenCloseEvent(wxEventType evtType, wxMenu* menu, bool popup)
+{
+ // Update the menu depth when dealing with the top level menus.
+ if ( !popup )
+ {
+ if ( evtType == wxEVT_MENU_OPEN )
+ {
+ m_menuDepth++;
+ }
+ else if ( evtType == wxEVT_MENU_CLOSE )
+ {
+ wxASSERT_MSG( m_menuDepth > 0, wxS("No open menus?") );
+
+ m_menuDepth--;
+ }
+ else
+ {
+ wxFAIL_MSG( wxS("Unexpected menu event type") );
+ }
+ }
+
+ wxMenuEvent event(evtType, popup ? wxID_ANY : 0, menu);
+ event.SetEventObject(menu);
+
+ return HandleWindowEvent(event);
+}
+
+bool wxTopLevelWindowMSW::HandleExitMenuLoop(WXWORD isPopup)
+{
+ return DoSendMenuOpenCloseEvent(wxEVT_MENU_CLOSE,
+ isPopup ? wxCurrentPopupMenu : NULL,
+ isPopup != 0);
+}
+
+bool wxTopLevelWindowMSW::HandleMenuPopup(wxEventType evtType, WXHMENU hMenu)
+{
+ bool isPopup = false;
+ wxMenu* menu = NULL;
+ if ( wxCurrentPopupMenu && wxCurrentPopupMenu->GetHMenu() == hMenu )
+ {
+ menu = wxCurrentPopupMenu;
+ isPopup = true;
+ }
+ else
+ {
+ menu = MSWFindMenuFromHMENU(hMenu);
+ }
+
+
+ return DoSendMenuOpenCloseEvent(evtType, menu, isPopup);
+}
+
+wxMenu* wxTopLevelWindowMSW::MSWFindMenuFromHMENU(WXHMENU WXUNUSED(hMenu))
+{
+ // We don't have any menus at this level.
+ return NULL;
+}
+
+#endif // wxUSE_MENUS && !__WXUNIVERSAL__
+
+#if wxUSE_TASKBARBUTTON
+wxTaskBarButton* wxTopLevelWindowMSW::MSWGetTaskBarButton()
+{
+ return m_taskBarButton;
+}
+#endif // wxUSE_TASKBARBUTTON
+
+
// the DialogProc for all wxWidgets dialogs
LONG APIENTRY _EXPORT
wxDlgProc(HWND hDlg,