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,