1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496 |
- /*
- ==============================================================================
- This file is part of the JUCE library.
- Copyright (c) 2013 - Raw Material Software Ltd.
- Permission is granted to use this software under the terms of either:
- a) the GPL v2 (or any later version)
- b) the Affero GPL v3
- Details of these licenses can be found at: www.gnu.org/licenses
- JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- ------------------------------------------------------------------------------
- To release a closed-source product which uses JUCE, commercial licenses are
- available: visit www.juce.com for more information.
- ==============================================================================
- */
- #undef GetSystemMetrics // multimon overrides this for some reason and causes a mess..
- // these are in the windows SDK, but need to be repeated here for GCC..
- #ifndef GET_APPCOMMAND_LPARAM
- #define GET_APPCOMMAND_LPARAM(lParam) ((short) (HIWORD (lParam) & ~FAPPCOMMAND_MASK))
- #define FAPPCOMMAND_MASK 0xF000
- #define APPCOMMAND_MEDIA_NEXTTRACK 11
- #define APPCOMMAND_MEDIA_PREVIOUSTRACK 12
- #define APPCOMMAND_MEDIA_STOP 13
- #define APPCOMMAND_MEDIA_PLAY_PAUSE 14
- #endif
- #ifndef WM_APPCOMMAND
- #define WM_APPCOMMAND 0x0319
- #endif
- extern void juce_repeatLastProcessPriority();
- extern void juce_checkCurrentlyFocusedTopLevelWindow(); // in juce_TopLevelWindow.cpp
- extern bool juce_isRunningInWine();
- typedef bool (*CheckEventBlockedByModalComps) (const MSG&);
- extern CheckEventBlockedByModalComps isEventBlockedByModalComps;
- static bool shouldDeactivateTitleBar = true;
- extern void* getUser32Function (const char*);
- //==============================================================================
- typedef BOOL (WINAPI* UpdateLayeredWinFunc) (HWND, HDC, POINT*, SIZE*, HDC, POINT*, COLORREF, BLENDFUNCTION*, DWORD);
- static UpdateLayeredWinFunc updateLayeredWindow = nullptr;
- bool Desktop::canUseSemiTransparentWindows() noexcept
- {
- if (updateLayeredWindow == nullptr && ! juce_isRunningInWine())
- updateLayeredWindow = (UpdateLayeredWinFunc) getUser32Function ("UpdateLayeredWindow");
- return updateLayeredWindow != nullptr;
- }
- //==============================================================================
- #ifndef WM_TOUCH
- #define WM_TOUCH 0x0240
- #define TOUCH_COORD_TO_PIXEL(l) ((l) / 100)
- #define TOUCHEVENTF_MOVE 0x0001
- #define TOUCHEVENTF_DOWN 0x0002
- #define TOUCHEVENTF_UP 0x0004
- #define TOUCHEVENTF_PRIMARY 0x0010
- DECLARE_HANDLE (HTOUCHINPUT);
- DECLARE_HANDLE (HGESTUREINFO);
- struct TOUCHINPUT
- {
- LONG x;
- LONG y;
- HANDLE hSource;
- DWORD dwID;
- DWORD dwFlags;
- DWORD dwMask;
- DWORD dwTime;
- ULONG_PTR dwExtraInfo;
- DWORD cxContact;
- DWORD cyContact;
- };
- struct GESTUREINFO
- {
- UINT cbSize;
- DWORD dwFlags;
- DWORD dwID;
- HWND hwndTarget;
- POINTS ptsLocation;
- DWORD dwInstanceID;
- DWORD dwSequenceID;
- ULONGLONG ullArguments;
- UINT cbExtraArgs;
- };
- #endif
- #ifndef MONITOR_DPI_TYPE
- enum Monitor_DPI_Type
- {
- MDT_Effective_DPI = 0,
- MDT_Angular_DPI = 1,
- MDT_Raw_DPI = 2,
- MDT_Default = MDT_Effective_DPI
- };
- enum Process_DPI_Awareness
- {
- Process_DPI_Unaware = 0,
- Process_System_DPI_Aware = 1,
- Process_Per_Monitor_DPI_Aware = 2
- };
- #endif
- typedef BOOL (WINAPI* RegisterTouchWindowFunc) (HWND, ULONG);
- typedef BOOL (WINAPI* GetTouchInputInfoFunc) (HTOUCHINPUT, UINT, TOUCHINPUT*, int);
- typedef BOOL (WINAPI* CloseTouchInputHandleFunc) (HTOUCHINPUT);
- typedef BOOL (WINAPI* GetGestureInfoFunc) (HGESTUREINFO, GESTUREINFO*);
- typedef BOOL (WINAPI* SetProcessDPIAwareFunc)();
- typedef BOOL (WINAPI* SetProcessDPIAwarenessFunc) (Process_DPI_Awareness);
- typedef HRESULT (WINAPI* GetDPIForMonitorFunc) (HMONITOR, Monitor_DPI_Type, UINT*, UINT*);
- static RegisterTouchWindowFunc registerTouchWindow = nullptr;
- static GetTouchInputInfoFunc getTouchInputInfo = nullptr;
- static CloseTouchInputHandleFunc closeTouchInputHandle = nullptr;
- static GetGestureInfoFunc getGestureInfo = nullptr;
- static SetProcessDPIAwareFunc setProcessDPIAware = nullptr;
- static SetProcessDPIAwarenessFunc setProcessDPIAwareness = nullptr;
- static GetDPIForMonitorFunc getDPIForMonitor = nullptr;
- static bool hasCheckedForMultiTouch = false;
- static bool canUseMultiTouch()
- {
- if (registerTouchWindow == nullptr && ! hasCheckedForMultiTouch)
- {
- hasCheckedForMultiTouch = true;
- registerTouchWindow = (RegisterTouchWindowFunc) getUser32Function ("RegisterTouchWindow");
- getTouchInputInfo = (GetTouchInputInfoFunc) getUser32Function ("GetTouchInputInfo");
- closeTouchInputHandle = (CloseTouchInputHandleFunc) getUser32Function ("CloseTouchInputHandle");
- getGestureInfo = (GetGestureInfoFunc) getUser32Function ("GetGestureInfo");
- }
- return registerTouchWindow != nullptr;
- }
- static Rectangle<int> rectangleFromRECT (const RECT& r) noexcept
- {
- return Rectangle<int>::leftTopRightBottom ((int) r.left, (int) r.top, (int) r.right, (int) r.bottom);
- }
- static void setWindowPos (HWND hwnd, Rectangle<int> bounds, UINT flags)
- {
- SetWindowPos (hwnd, 0, bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(), flags);
- }
- static RECT getWindowRect (HWND hwnd)
- {
- RECT r;
- GetWindowRect (hwnd, &r);
- return r;
- }
- static void setWindowZOrder (HWND hwnd, HWND insertAfter)
- {
- SetWindowPos (hwnd, insertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
- }
- //==============================================================================
- static void setDPIAwareness()
- {
- #if ! JUCE_DISABLE_WIN32_DPI_AWARENESS
- if (JUCEApplicationBase::isStandaloneApp())
- {
- if (setProcessDPIAwareness == nullptr)
- {
- HMODULE shcoreModule = GetModuleHandleA ("SHCore.dll");
- if (shcoreModule != 0)
- {
- setProcessDPIAwareness = (SetProcessDPIAwarenessFunc) GetProcAddress (shcoreModule, "SetProcessDpiAwareness");
- getDPIForMonitor = (GetDPIForMonitorFunc) GetProcAddress (shcoreModule, "GetDpiForMonitor");
- if (setProcessDPIAwareness != nullptr && getDPIForMonitor != nullptr
- // && SUCCEEDED (setProcessDPIAwareness (Process_Per_Monitor_DPI_Aware)))
- && SUCCEEDED (setProcessDPIAwareness (Process_System_DPI_Aware))) // (keep using this mode temporarily..)
- return;
- }
- if (setProcessDPIAware == nullptr)
- {
- setProcessDPIAware = (SetProcessDPIAwareFunc) getUser32Function ("SetProcessDPIAware");
- if (setProcessDPIAware != nullptr)
- setProcessDPIAware();
- }
- }
- }
- #endif
- }
- static double getGlobalDPI()
- {
- setDPIAwareness();
- HDC dc = GetDC (0);
- const double dpi = (GetDeviceCaps (dc, LOGPIXELSX)
- + GetDeviceCaps (dc, LOGPIXELSY)) / 2.0;
- ReleaseDC (0, dc);
- return dpi;
- }
- double Desktop::getDefaultMasterScale()
- {
- return JUCEApplicationBase::isStandaloneApp() ? getGlobalDPI() / 96.0
- : 1.0;
- }
- //==============================================================================
- Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
- {
- return upright;
- }
- int64 getMouseEventTime()
- {
- static int64 eventTimeOffset = 0;
- static LONG lastMessageTime = 0;
- const LONG thisMessageTime = GetMessageTime();
- if (thisMessageTime < lastMessageTime || lastMessageTime == 0)
- {
- lastMessageTime = thisMessageTime;
- eventTimeOffset = Time::currentTimeMillis() - thisMessageTime;
- }
- return eventTimeOffset + thisMessageTime;
- }
- //==============================================================================
- const int extendedKeyModifier = 0x10000;
- const int KeyPress::spaceKey = VK_SPACE;
- const int KeyPress::returnKey = VK_RETURN;
- const int KeyPress::escapeKey = VK_ESCAPE;
- const int KeyPress::backspaceKey = VK_BACK;
- const int KeyPress::deleteKey = VK_DELETE | extendedKeyModifier;
- const int KeyPress::insertKey = VK_INSERT | extendedKeyModifier;
- const int KeyPress::tabKey = VK_TAB;
- const int KeyPress::leftKey = VK_LEFT | extendedKeyModifier;
- const int KeyPress::rightKey = VK_RIGHT | extendedKeyModifier;
- const int KeyPress::upKey = VK_UP | extendedKeyModifier;
- const int KeyPress::downKey = VK_DOWN | extendedKeyModifier;
- const int KeyPress::homeKey = VK_HOME | extendedKeyModifier;
- const int KeyPress::endKey = VK_END | extendedKeyModifier;
- const int KeyPress::pageUpKey = VK_PRIOR | extendedKeyModifier;
- const int KeyPress::pageDownKey = VK_NEXT | extendedKeyModifier;
- const int KeyPress::F1Key = VK_F1 | extendedKeyModifier;
- const int KeyPress::F2Key = VK_F2 | extendedKeyModifier;
- const int KeyPress::F3Key = VK_F3 | extendedKeyModifier;
- const int KeyPress::F4Key = VK_F4 | extendedKeyModifier;
- const int KeyPress::F5Key = VK_F5 | extendedKeyModifier;
- const int KeyPress::F6Key = VK_F6 | extendedKeyModifier;
- const int KeyPress::F7Key = VK_F7 | extendedKeyModifier;
- const int KeyPress::F8Key = VK_F8 | extendedKeyModifier;
- const int KeyPress::F9Key = VK_F9 | extendedKeyModifier;
- const int KeyPress::F10Key = VK_F10 | extendedKeyModifier;
- const int KeyPress::F11Key = VK_F11 | extendedKeyModifier;
- const int KeyPress::F12Key = VK_F12 | extendedKeyModifier;
- const int KeyPress::F13Key = VK_F13 | extendedKeyModifier;
- const int KeyPress::F14Key = VK_F14 | extendedKeyModifier;
- const int KeyPress::F15Key = VK_F15 | extendedKeyModifier;
- const int KeyPress::F16Key = VK_F16 | extendedKeyModifier;
- const int KeyPress::numberPad0 = VK_NUMPAD0 | extendedKeyModifier;
- const int KeyPress::numberPad1 = VK_NUMPAD1 | extendedKeyModifier;
- const int KeyPress::numberPad2 = VK_NUMPAD2 | extendedKeyModifier;
- const int KeyPress::numberPad3 = VK_NUMPAD3 | extendedKeyModifier;
- const int KeyPress::numberPad4 = VK_NUMPAD4 | extendedKeyModifier;
- const int KeyPress::numberPad5 = VK_NUMPAD5 | extendedKeyModifier;
- const int KeyPress::numberPad6 = VK_NUMPAD6 | extendedKeyModifier;
- const int KeyPress::numberPad7 = VK_NUMPAD7 | extendedKeyModifier;
- const int KeyPress::numberPad8 = VK_NUMPAD8 | extendedKeyModifier;
- const int KeyPress::numberPad9 = VK_NUMPAD9 | extendedKeyModifier;
- const int KeyPress::numberPadAdd = VK_ADD | extendedKeyModifier;
- const int KeyPress::numberPadSubtract = VK_SUBTRACT | extendedKeyModifier;
- const int KeyPress::numberPadMultiply = VK_MULTIPLY | extendedKeyModifier;
- const int KeyPress::numberPadDivide = VK_DIVIDE | extendedKeyModifier;
- const int KeyPress::numberPadSeparator = VK_SEPARATOR | extendedKeyModifier;
- const int KeyPress::numberPadDecimalPoint = VK_DECIMAL | extendedKeyModifier;
- const int KeyPress::numberPadEquals = 0x92 /*VK_OEM_NEC_EQUAL*/ | extendedKeyModifier;
- const int KeyPress::numberPadDelete = VK_DELETE | extendedKeyModifier;
- const int KeyPress::playKey = 0x30000;
- const int KeyPress::stopKey = 0x30001;
- const int KeyPress::fastForwardKey = 0x30002;
- const int KeyPress::rewindKey = 0x30003;
- //==============================================================================
- class WindowsBitmapImage : public ImagePixelData
- {
- public:
- WindowsBitmapImage (const Image::PixelFormat format,
- const int w, const int h, const bool clearImage)
- : ImagePixelData (format, w, h)
- {
- jassert (format == Image::RGB || format == Image::ARGB);
- static bool alwaysUse32Bits = isGraphicsCard32Bit(); // NB: for 32-bit cards, it's faster to use a 32-bit image.
- pixelStride = (alwaysUse32Bits || format == Image::ARGB) ? 4 : 3;
- lineStride = -((w * pixelStride + 3) & ~3);
- zerostruct (bitmapInfo);
- bitmapInfo.bV4Size = sizeof (BITMAPV4HEADER);
- bitmapInfo.bV4Width = w;
- bitmapInfo.bV4Height = h;
- bitmapInfo.bV4Planes = 1;
- bitmapInfo.bV4CSType = 1;
- bitmapInfo.bV4BitCount = (unsigned short) (pixelStride * 8);
- if (format == Image::ARGB)
- {
- bitmapInfo.bV4AlphaMask = 0xff000000;
- bitmapInfo.bV4RedMask = 0xff0000;
- bitmapInfo.bV4GreenMask = 0xff00;
- bitmapInfo.bV4BlueMask = 0xff;
- bitmapInfo.bV4V4Compression = BI_BITFIELDS;
- }
- else
- {
- bitmapInfo.bV4V4Compression = BI_RGB;
- }
- HDC dc = GetDC (0);
- hdc = CreateCompatibleDC (dc);
- ReleaseDC (0, dc);
- SetMapMode (hdc, MM_TEXT);
- hBitmap = CreateDIBSection (hdc, (BITMAPINFO*) &(bitmapInfo), DIB_RGB_COLORS,
- (void**) &bitmapData, 0, 0);
- previousBitmap = SelectObject (hdc, hBitmap);
- if (format == Image::ARGB && clearImage)
- zeromem (bitmapData, (size_t) std::abs (h * lineStride));
- imageData = bitmapData - (lineStride * (h - 1));
- }
- ~WindowsBitmapImage()
- {
- SelectObject (hdc, previousBitmap); // Selecting the previous bitmap before deleting the DC avoids a warning in BoundsChecker
- DeleteDC (hdc);
- DeleteObject (hBitmap);
- }
- ImageType* createType() const override { return new NativeImageType(); }
- LowLevelGraphicsContext* createLowLevelContext() override
- {
- sendDataChangeMessage();
- return new LowLevelGraphicsSoftwareRenderer (Image (this));
- }
- void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode) override
- {
- bitmap.data = imageData + x * pixelStride + y * lineStride;
- bitmap.pixelFormat = pixelFormat;
- bitmap.lineStride = lineStride;
- bitmap.pixelStride = pixelStride;
- if (mode != Image::BitmapData::readOnly)
- sendDataChangeMessage();
- }
- ImagePixelData* clone() override
- {
- WindowsBitmapImage* im = new WindowsBitmapImage (pixelFormat, width, height, false);
- for (int i = 0; i < height; ++i)
- memcpy (im->imageData + i * lineStride, imageData + i * lineStride, (size_t) lineStride);
- return im;
- }
- void blitToWindow (HWND hwnd, HDC dc, const bool transparent,
- const int x, const int y,
- const uint8 updateLayeredWindowAlpha) noexcept
- {
- SetMapMode (dc, MM_TEXT);
- if (transparent)
- {
- RECT windowBounds = getWindowRect (hwnd);
- POINT p = { -x, -y };
- POINT pos = { windowBounds.left, windowBounds.top };
- SIZE size = { windowBounds.right - windowBounds.left,
- windowBounds.bottom - windowBounds.top };
- BLENDFUNCTION bf;
- bf.AlphaFormat = 1 /*AC_SRC_ALPHA*/;
- bf.BlendFlags = 0;
- bf.BlendOp = AC_SRC_OVER;
- bf.SourceConstantAlpha = updateLayeredWindowAlpha;
- updateLayeredWindow (hwnd, 0, &pos, &size, hdc, &p, 0, &bf, 2 /*ULW_ALPHA*/);
- }
- else
- {
- StretchDIBits (dc,
- x, y, width, height,
- 0, 0, width, height,
- bitmapData, (const BITMAPINFO*) &bitmapInfo,
- DIB_RGB_COLORS, SRCCOPY);
- }
- }
- HBITMAP hBitmap;
- HGDIOBJ previousBitmap;
- BITMAPV4HEADER bitmapInfo;
- HDC hdc;
- uint8* bitmapData;
- int pixelStride, lineStride;
- uint8* imageData;
- private:
- static bool isGraphicsCard32Bit()
- {
- HDC dc = GetDC (0);
- const int bitsPerPixel = GetDeviceCaps (dc, BITSPIXEL);
- ReleaseDC (0, dc);
- return bitsPerPixel > 24;
- }
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsBitmapImage)
- };
- //==============================================================================
- namespace IconConverters
- {
- Image createImageFromHBITMAP (HBITMAP bitmap)
- {
- Image im;
- if (bitmap != 0)
- {
- BITMAP bm;
- if (GetObject (bitmap, sizeof (BITMAP), &bm)
- && bm.bmWidth > 0 && bm.bmHeight > 0)
- {
- HDC tempDC = GetDC (0);
- HDC dc = CreateCompatibleDC (tempDC);
- ReleaseDC (0, tempDC);
- SelectObject (dc, bitmap);
- im = Image (Image::ARGB, bm.bmWidth, bm.bmHeight, true);
- Image::BitmapData imageData (im, Image::BitmapData::writeOnly);
- for (int y = bm.bmHeight; --y >= 0;)
- {
- for (int x = bm.bmWidth; --x >= 0;)
- {
- COLORREF col = GetPixel (dc, x, y);
- imageData.setPixelColour (x, y, Colour ((uint8) GetRValue (col),
- (uint8) GetGValue (col),
- (uint8) GetBValue (col)));
- }
- }
- DeleteDC (dc);
- }
- }
- return im;
- }
- Image createImageFromHICON (HICON icon)
- {
- ICONINFO info;
- if (GetIconInfo (icon, &info))
- {
- Image mask (createImageFromHBITMAP (info.hbmMask));
- Image image (createImageFromHBITMAP (info.hbmColor));
- if (mask.isValid() && image.isValid())
- {
- for (int y = image.getHeight(); --y >= 0;)
- {
- for (int x = image.getWidth(); --x >= 0;)
- {
- const float brightness = mask.getPixelAt (x, y).getBrightness();
- if (brightness > 0.0f)
- image.multiplyAlphaAt (x, y, 1.0f - brightness);
- }
- }
- return image;
- }
- }
- return Image::null;
- }
- HICON createHICONFromImage (const Image& image, const BOOL isIcon, int hotspotX, int hotspotY)
- {
- WindowsBitmapImage* nativeBitmap = new WindowsBitmapImage (Image::ARGB, image.getWidth(), image.getHeight(), true);
- Image bitmap (nativeBitmap);
- {
- Graphics g (bitmap);
- g.drawImageAt (image, 0, 0);
- }
- HBITMAP mask = CreateBitmap (image.getWidth(), image.getHeight(), 1, 1, 0);
- ICONINFO info;
- info.fIcon = isIcon;
- info.xHotspot = (DWORD) hotspotX;
- info.yHotspot = (DWORD) hotspotY;
- info.hbmMask = mask;
- info.hbmColor = nativeBitmap->hBitmap;
- HICON hi = CreateIconIndirect (&info);
- DeleteObject (mask);
- return hi;
- }
- }
- //==============================================================================
- class HWNDComponentPeer : public ComponentPeer
- {
- public:
- enum RenderingEngineType
- {
- softwareRenderingEngine = 0,
- direct2DRenderingEngine
- };
- //==============================================================================
- HWNDComponentPeer (Component& comp, const int windowStyleFlags, HWND parent, bool nonRepainting)
- : ComponentPeer (comp, windowStyleFlags),
- dontRepaint (nonRepainting),
- parentToAddTo (parent),
- currentRenderingEngine (softwareRenderingEngine),
- lastPaintTime (0),
- lastMagnifySize (0),
- fullScreen (false),
- isDragging (false),
- isMouseOver (false),
- hasCreatedCaret (false),
- constrainerIsResizing (false),
- currentWindowIcon (0),
- dropTarget (nullptr),
- updateLayeredWindowAlpha (255)
- {
- callFunctionIfNotLocked (&createWindowCallback, this);
- setTitle (component.getName());
- if ((windowStyleFlags & windowHasDropShadow) != 0
- && Desktop::canUseSemiTransparentWindows()
- && ((! hasTitleBar()) || SystemStats::getOperatingSystemType() < SystemStats::WinVista))
- {
- shadower = component.getLookAndFeel().createDropShadowerForComponent (&component);
- if (shadower != nullptr)
- shadower->setOwner (&component);
- }
- }
- ~HWNDComponentPeer()
- {
- shadower = nullptr;
- // do this before the next bit to avoid messages arriving for this window
- // before it's destroyed
- JuceWindowIdentifier::setAsJUCEWindow (hwnd, false);
- callFunctionIfNotLocked (&destroyWindowCallback, (void*) hwnd);
- if (currentWindowIcon != 0)
- DestroyIcon (currentWindowIcon);
- if (dropTarget != nullptr)
- {
- dropTarget->clear();
- dropTarget->Release();
- dropTarget = nullptr;
- }
- #if JUCE_DIRECT2D
- direct2DContext = nullptr;
- #endif
- }
- //==============================================================================
- void* getNativeHandle() const override { return hwnd; }
- void setVisible (bool shouldBeVisible) override
- {
- ShowWindow (hwnd, shouldBeVisible ? SW_SHOWNA : SW_HIDE);
- if (shouldBeVisible)
- InvalidateRect (hwnd, 0, 0);
- else
- lastPaintTime = 0;
- }
- void setTitle (const String& title) override
- {
- // Unfortunately some ancient bits of win32 mean you can only perform this operation from the message thread.
- jassert (MessageManager::getInstance()->isThisTheMessageThread());
- SetWindowText (hwnd, title.toWideCharPointer());
- }
- void repaintNowIfTransparent()
- {
- if (isUsingUpdateLayeredWindow() && lastPaintTime > 0 && Time::getMillisecondCounter() > lastPaintTime + 30)
- handlePaintMessage();
- }
- void updateBorderSize()
- {
- WINDOWINFO info;
- info.cbSize = sizeof (info);
- if (GetWindowInfo (hwnd, &info))
- windowBorder = BorderSize<int> (info.rcClient.top - info.rcWindow.top,
- info.rcClient.left - info.rcWindow.left,
- info.rcWindow.bottom - info.rcClient.bottom,
- info.rcWindow.right - info.rcClient.right);
- #if JUCE_DIRECT2D
- if (direct2DContext != nullptr)
- direct2DContext->resized();
- #endif
- }
- void setBounds (const Rectangle<int>& bounds, bool isNowFullScreen) override
- {
- fullScreen = isNowFullScreen;
- Rectangle<int> newBounds (windowBorder.addedTo (bounds));
- if (isUsingUpdateLayeredWindow())
- {
- if (HWND parentHwnd = GetParent (hwnd))
- {
- RECT parentRect = getWindowRect (parentHwnd);
- newBounds.translate (parentRect.left, parentRect.top);
- }
- }
- const Rectangle<int> oldBounds (getBounds());
- const bool hasMoved = (oldBounds.getPosition() != bounds.getPosition());
- const bool hasResized = (oldBounds.getWidth() != bounds.getWidth()
- || oldBounds.getHeight() != bounds.getHeight());
- DWORD flags = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER;
- if (! hasMoved) flags |= SWP_NOMOVE;
- if (! hasResized) flags |= SWP_NOSIZE;
- setWindowPos (hwnd, newBounds, flags);
- if (hasResized && isValidPeer (this))
- {
- updateBorderSize();
- repaintNowIfTransparent();
- }
- }
- Rectangle<int> getBounds() const override
- {
- Rectangle<int> bounds (rectangleFromRECT (getWindowRect (hwnd)));
- if (HWND parentH = GetParent (hwnd))
- {
- RECT r = getWindowRect (parentH);
- bounds.translate (-r.left, -r.top);
- }
- return windowBorder.subtractedFrom (bounds);
- }
- Point<int> getScreenPosition() const
- {
- RECT r = getWindowRect (hwnd);
- return Point<int> (r.left + windowBorder.getLeft(),
- r.top + windowBorder.getTop());
- }
- Point<float> localToGlobal (Point<float> relativePosition) override { return relativePosition + getScreenPosition().toFloat(); }
- Point<float> globalToLocal (Point<float> screenPosition) override { return screenPosition - getScreenPosition().toFloat(); }
- void setAlpha (float newAlpha) override
- {
- const uint8 intAlpha = (uint8) jlimit (0, 255, (int) (newAlpha * 255.0f));
- if (component.isOpaque())
- {
- if (newAlpha < 1.0f)
- {
- SetWindowLong (hwnd, GWL_EXSTYLE, GetWindowLong (hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
- SetLayeredWindowAttributes (hwnd, RGB (0, 0, 0), intAlpha, LWA_ALPHA);
- }
- else
- {
- SetWindowLong (hwnd, GWL_EXSTYLE, GetWindowLong (hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
- RedrawWindow (hwnd, 0, 0, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
- }
- }
- else
- {
- updateLayeredWindowAlpha = intAlpha;
- component.repaint();
- }
- }
- void setMinimised (bool shouldBeMinimised) override
- {
- if (shouldBeMinimised != isMinimised())
- ShowWindow (hwnd, shouldBeMinimised ? SW_MINIMIZE : SW_SHOWNORMAL);
- }
- bool isMinimised() const override
- {
- WINDOWPLACEMENT wp;
- wp.length = sizeof (WINDOWPLACEMENT);
- GetWindowPlacement (hwnd, &wp);
- return wp.showCmd == SW_SHOWMINIMIZED;
- }
- void setFullScreen (bool shouldBeFullScreen) override
- {
- setMinimised (false);
- if (isFullScreen() != shouldBeFullScreen)
- {
- fullScreen = shouldBeFullScreen;
- const WeakReference<Component> deletionChecker (&component);
- if (! fullScreen)
- {
- const Rectangle<int> boundsCopy (lastNonFullscreenBounds);
- if (hasTitleBar())
- ShowWindow (hwnd, SW_SHOWNORMAL);
- if (! boundsCopy.isEmpty())
- setBounds (ScalingHelpers::scaledScreenPosToUnscaled (component, boundsCopy), false);
- }
- else
- {
- if (hasTitleBar())
- ShowWindow (hwnd, SW_SHOWMAXIMIZED);
- else
- SendMessageW (hwnd, WM_SETTINGCHANGE, 0, 0);
- }
- if (deletionChecker != nullptr)
- handleMovedOrResized();
- }
- }
- bool isFullScreen() const override
- {
- if (! hasTitleBar())
- return fullScreen;
- WINDOWPLACEMENT wp;
- wp.length = sizeof (wp);
- GetWindowPlacement (hwnd, &wp);
- return wp.showCmd == SW_SHOWMAXIMIZED;
- }
- bool contains (Point<int> localPos, bool trueIfInAChildWindow) const override
- {
- RECT r = getWindowRect (hwnd);
- if (! (isPositiveAndBelow (localPos.x, (int) (r.right - r.left))
- && isPositiveAndBelow (localPos.y, (int) (r.bottom - r.top))))
- return false;
- POINT p = { localPos.x + r.left + windowBorder.getLeft(),
- localPos.y + r.top + windowBorder.getTop() };
- HWND w = WindowFromPoint (p);
- return w == hwnd || (trueIfInAChildWindow && (IsChild (hwnd, w) != 0));
- }
- BorderSize<int> getFrameSize() const override
- {
- return windowBorder;
- }
- bool setAlwaysOnTop (bool alwaysOnTop) override
- {
- const bool oldDeactivate = shouldDeactivateTitleBar;
- shouldDeactivateTitleBar = ((styleFlags & windowIsTemporary) == 0);
- setWindowZOrder (hwnd, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST);
- shouldDeactivateTitleBar = oldDeactivate;
- if (shadower != nullptr)
- handleBroughtToFront();
- return true;
- }
- void toFront (bool makeActive) override
- {
- setMinimised (false);
- const bool oldDeactivate = shouldDeactivateTitleBar;
- shouldDeactivateTitleBar = ((styleFlags & windowIsTemporary) == 0);
- callFunctionIfNotLocked (makeActive ? &toFrontCallback1 : &toFrontCallback2, hwnd);
- shouldDeactivateTitleBar = oldDeactivate;
- if (! makeActive)
- {
- // in this case a broughttofront call won't have occured, so do it now..
- handleBroughtToFront();
- }
- }
- void toBehind (ComponentPeer* other) override
- {
- if (HWNDComponentPeer* const otherPeer = dynamic_cast<HWNDComponentPeer*> (other))
- {
- setMinimised (false);
- // Must be careful not to try to put a topmost window behind a normal one, or Windows
- // promotes the normal one to be topmost!
- if (component.isAlwaysOnTop() == otherPeer->getComponent().isAlwaysOnTop())
- setWindowZOrder (hwnd, otherPeer->hwnd);
- else if (otherPeer->getComponent().isAlwaysOnTop())
- setWindowZOrder (hwnd, HWND_TOP);
- }
- else
- {
- jassertfalse; // wrong type of window?
- }
- }
- bool isFocused() const override
- {
- return callFunctionIfNotLocked (&getFocusCallback, 0) == (void*) hwnd;
- }
- void grabFocus() override
- {
- const bool oldDeactivate = shouldDeactivateTitleBar;
- shouldDeactivateTitleBar = ((styleFlags & windowIsTemporary) == 0);
- callFunctionIfNotLocked (&setFocusCallback, hwnd);
- shouldDeactivateTitleBar = oldDeactivate;
- }
- void textInputRequired (Point<int>, TextInputTarget&) override
- {
- if (! hasCreatedCaret)
- {
- hasCreatedCaret = true;
- CreateCaret (hwnd, (HBITMAP) 1, 0, 0);
- }
- ShowCaret (hwnd);
- SetCaretPos (0, 0);
- }
- void dismissPendingTextInput() override
- {
- imeHandler.handleSetContext (hwnd, false);
- }
- void repaint (const Rectangle<int>& area) override
- {
- const RECT r = { area.getX(), area.getY(), area.getRight(), area.getBottom() };
- InvalidateRect (hwnd, &r, FALSE);
- }
- void performAnyPendingRepaintsNow() override
- {
- if (component.isVisible())
- {
- WeakReference<Component> localRef (&component);
- MSG m;
- if (isUsingUpdateLayeredWindow() || PeekMessage (&m, hwnd, WM_PAINT, WM_PAINT, PM_REMOVE))
- if (localRef != nullptr) // (the PeekMessage call can dispatch messages, which may delete this comp)
- handlePaintMessage();
- }
- }
- //==============================================================================
- static HWNDComponentPeer* getOwnerOfWindow (HWND h) noexcept
- {
- if (h != 0 && JuceWindowIdentifier::isJUCEWindow (h))
- return (HWNDComponentPeer*) GetWindowLongPtr (h, 8);
- return nullptr;
- }
- //==============================================================================
- bool isInside (HWND h) const noexcept
- {
- return GetAncestor (hwnd, GA_ROOT) == h;
- }
- //==============================================================================
- static bool isKeyDown (const int key) noexcept { return (GetAsyncKeyState (key) & 0x8000) != 0; }
- static void updateKeyModifiers() noexcept
- {
- int keyMods = 0;
- if (isKeyDown (VK_SHIFT)) keyMods |= ModifierKeys::shiftModifier;
- if (isKeyDown (VK_CONTROL)) keyMods |= ModifierKeys::ctrlModifier;
- if (isKeyDown (VK_MENU)) keyMods |= ModifierKeys::altModifier;
- if (isKeyDown (VK_RMENU)) keyMods &= ~(ModifierKeys::ctrlModifier | ModifierKeys::altModifier);
- currentModifiers = currentModifiers.withOnlyMouseButtons().withFlags (keyMods);
- }
- static void updateModifiersFromWParam (const WPARAM wParam)
- {
- int mouseMods = 0;
- if (wParam & MK_LBUTTON) mouseMods |= ModifierKeys::leftButtonModifier;
- if (wParam & MK_RBUTTON) mouseMods |= ModifierKeys::rightButtonModifier;
- if (wParam & MK_MBUTTON) mouseMods |= ModifierKeys::middleButtonModifier;
- currentModifiers = currentModifiers.withoutMouseButtons().withFlags (mouseMods);
- updateKeyModifiers();
- }
- //==============================================================================
- bool dontRepaint;
- static ModifierKeys currentModifiers;
- static ModifierKeys modifiersAtLastCallback;
- //==============================================================================
- class JuceDropTarget : public ComBaseClassHelper<IDropTarget>
- {
- public:
- JuceDropTarget (HWNDComponentPeer& p) : ownerInfo (new OwnerInfo (p)) {}
- void clear()
- {
- ownerInfo = nullptr;
- }
- JUCE_COMRESULT DragEnter (IDataObject* pDataObject, DWORD grfKeyState, POINTL mousePos, DWORD* pdwEffect)
- {
- HRESULT hr = updateFileList (pDataObject);
- if (FAILED (hr))
- return hr;
- return DragOver (grfKeyState, mousePos, pdwEffect);
- }
- JUCE_COMRESULT DragLeave()
- {
- if (ownerInfo == nullptr)
- return S_FALSE;
- ownerInfo->owner.handleDragExit (ownerInfo->dragInfo);
- return S_OK;
- }
- JUCE_COMRESULT DragOver (DWORD /*grfKeyState*/, POINTL mousePos, DWORD* pdwEffect)
- {
- if (ownerInfo == nullptr)
- return S_FALSE;
- ownerInfo->dragInfo.position = ownerInfo->getMousePos (mousePos).roundToInt();
- const bool wasWanted = ownerInfo->owner.handleDragMove (ownerInfo->dragInfo);
- *pdwEffect = wasWanted ? (DWORD) DROPEFFECT_COPY : (DWORD) DROPEFFECT_NONE;
- return S_OK;
- }
- JUCE_COMRESULT Drop (IDataObject* pDataObject, DWORD /*grfKeyState*/, POINTL mousePos, DWORD* pdwEffect)
- {
- HRESULT hr = updateFileList (pDataObject);
- if (SUCCEEDED (hr))
- {
- ownerInfo->dragInfo.position = ownerInfo->getMousePos (mousePos).roundToInt();
- const bool wasWanted = ownerInfo->owner.handleDragDrop (ownerInfo->dragInfo);
- *pdwEffect = wasWanted ? (DWORD) DROPEFFECT_COPY : (DWORD) DROPEFFECT_NONE;
- hr = S_OK;
- }
- return hr;
- }
- private:
- struct OwnerInfo
- {
- OwnerInfo (HWNDComponentPeer& p) : owner (p) {}
- Point<float> getMousePos (const POINTL& mousePos) const
- {
- return owner.globalToLocal (Point<float> (static_cast<float> (mousePos.x),
- static_cast<float> (mousePos.y)));
- }
- template <typename CharType>
- void parseFileList (const CharType* names, const SIZE_T totalLen)
- {
- unsigned int i = 0;
- for (;;)
- {
- unsigned int len = 0;
- while (i + len < totalLen && names [i + len] != 0)
- ++len;
- if (len == 0)
- break;
- dragInfo.files.add (String (names + i, len));
- i += len + 1;
- }
- }
- HWNDComponentPeer& owner;
- ComponentPeer::DragInfo dragInfo;
- JUCE_DECLARE_NON_COPYABLE (OwnerInfo)
- };
- ScopedPointer<OwnerInfo> ownerInfo;
- struct DroppedData
- {
- DroppedData (IDataObject* const dataObject, const CLIPFORMAT type)
- : data (nullptr)
- {
- FORMATETC format = { type, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
- STGMEDIUM resetMedium = { TYMED_HGLOBAL, { 0 }, 0 };
- medium = resetMedium;
- if (SUCCEEDED (error = dataObject->GetData (&format, &medium)))
- {
- dataSize = GlobalSize (medium.hGlobal);
- data = GlobalLock (medium.hGlobal);
- }
- }
- ~DroppedData()
- {
- if (data != nullptr)
- GlobalUnlock (medium.hGlobal);
- }
- HRESULT error;
- STGMEDIUM medium;
- void* data;
- SIZE_T dataSize;
- };
- HRESULT updateFileList (IDataObject* const dataObject)
- {
- if (ownerInfo == nullptr)
- return S_FALSE;
- ownerInfo->dragInfo.clear();
- DroppedData textData (dataObject, CF_UNICODETEXT);
- if (SUCCEEDED (textData.error))
- {
- ownerInfo->dragInfo.text = String (CharPointer_UTF16 ((const WCHAR*) textData.data),
- CharPointer_UTF16 ((const WCHAR*) addBytesToPointer (textData.data, textData.dataSize)));
- }
- else
- {
- DroppedData fileData (dataObject, CF_HDROP);
- if (SUCCEEDED (fileData.error))
- {
- const LPDROPFILES dropFiles = static_cast<const LPDROPFILES> (fileData.data);
- const void* const names = addBytesToPointer (dropFiles, sizeof (DROPFILES));
- if (dropFiles->fWide)
- ownerInfo->parseFileList (static_cast<const WCHAR*> (names), fileData.dataSize);
- else
- ownerInfo->parseFileList (static_cast<const char*> (names), fileData.dataSize);
- }
- else
- {
- return fileData.error;
- }
- }
- return S_OK;
- }
- JUCE_DECLARE_NON_COPYABLE (JuceDropTarget)
- };
- #if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client
- static bool offerKeyMessageToJUCEWindow (MSG& m)
- {
- if (m.message == WM_KEYDOWN || m.message == WM_KEYUP)
- if (Component::getCurrentlyFocusedComponent() != nullptr)
- if (HWNDComponentPeer* h = getOwnerOfWindow (m.hwnd))
- if (m.message == WM_KEYDOWN ? h->doKeyDown (m.wParam)
- : h->doKeyUp (m.wParam))
- return true;
- return false;
- }
- #endif
- private:
- HWND hwnd, parentToAddTo;
- ScopedPointer<DropShadower> shadower;
- RenderingEngineType currentRenderingEngine;
- #if JUCE_DIRECT2D
- ScopedPointer<Direct2DLowLevelGraphicsContext> direct2DContext;
- #endif
- uint32 lastPaintTime;
- ULONGLONG lastMagnifySize;
- bool fullScreen, isDragging, isMouseOver, hasCreatedCaret, constrainerIsResizing;
- BorderSize<int> windowBorder;
- HICON currentWindowIcon;
- JuceDropTarget* dropTarget;
- uint8 updateLayeredWindowAlpha;
- MultiTouchMapper<DWORD> currentTouches;
- //==============================================================================
- class TemporaryImage : public Timer
- {
- public:
- TemporaryImage() {}
- Image& getImage (const bool transparent, const int w, const int h)
- {
- const Image::PixelFormat format = transparent ? Image::ARGB : Image::RGB;
- if ((! image.isValid()) || image.getWidth() < w || image.getHeight() < h || image.getFormat() != format)
- image = Image (new WindowsBitmapImage (format, (w + 31) & ~31, (h + 31) & ~31, false));
- startTimer (3000);
- return image;
- }
- void timerCallback() override
- {
- stopTimer();
- image = Image::null;
- }
- private:
- Image image;
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TemporaryImage)
- };
- TemporaryImage offscreenImageGenerator;
- //==============================================================================
- class WindowClassHolder : private DeletedAtShutdown
- {
- public:
- WindowClassHolder()
- {
- // this name has to be different for each app/dll instance because otherwise poor old Windows can
- // get a bit confused (even despite it not being a process-global window class).
- String windowClassName ("JUCE_");
- windowClassName << String::toHexString (Time::currentTimeMillis());
- HINSTANCE moduleHandle = (HINSTANCE) Process::getCurrentModuleInstanceHandle();
- TCHAR moduleFile [1024] = { 0 };
- GetModuleFileName (moduleHandle, moduleFile, 1024);
- WORD iconNum = 0;
- WNDCLASSEX wcex = { 0 };
- wcex.cbSize = sizeof (wcex);
- wcex.style = CS_OWNDC;
- wcex.lpfnWndProc = (WNDPROC) windowProc;
- wcex.lpszClassName = windowClassName.toWideCharPointer();
- wcex.cbWndExtra = 32;
- wcex.hInstance = moduleHandle;
- wcex.hIcon = ExtractAssociatedIcon (moduleHandle, moduleFile, &iconNum);
- iconNum = 1;
- wcex.hIconSm = ExtractAssociatedIcon (moduleHandle, moduleFile, &iconNum);
- atom = RegisterClassEx (&wcex);
- jassert (atom != 0);
- isEventBlockedByModalComps = checkEventBlockedByModalComps;
- }
- ~WindowClassHolder()
- {
- if (ComponentPeer::getNumPeers() == 0)
- UnregisterClass (getWindowClassName(), (HINSTANCE) Process::getCurrentModuleInstanceHandle());
- clearSingletonInstance();
- }
- LPCTSTR getWindowClassName() const noexcept { return (LPCTSTR) MAKELONG (atom, 0); }
- juce_DeclareSingleton_SingleThreaded_Minimal (WindowClassHolder)
- private:
- ATOM atom;
- static bool isHWNDBlockedByModalComponents (HWND h)
- {
- for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;)
- if (Component* const c = Desktop::getInstance().getComponent (i))
- if ((! c->isCurrentlyBlockedByAnotherModalComponent())
- && IsChild ((HWND) c->getWindowHandle(), h))
- return false;
- return true;
- }
- static bool checkEventBlockedByModalComps (const MSG& m)
- {
- if (Component::getNumCurrentlyModalComponents() == 0 || JuceWindowIdentifier::isJUCEWindow (m.hwnd))
- return false;
- switch (m.message)
- {
- case WM_MOUSEMOVE:
- case WM_NCMOUSEMOVE:
- case 0x020A: /* WM_MOUSEWHEEL */
- case 0x020E: /* WM_MOUSEHWHEEL */
- case WM_KEYUP:
- case WM_SYSKEYUP:
- case WM_CHAR:
- case WM_APPCOMMAND:
- case WM_LBUTTONUP:
- case WM_MBUTTONUP:
- case WM_RBUTTONUP:
- case WM_MOUSEACTIVATE:
- case WM_NCMOUSEHOVER:
- case WM_MOUSEHOVER:
- case WM_TOUCH:
- return isHWNDBlockedByModalComponents (m.hwnd);
- case WM_NCLBUTTONDOWN:
- case WM_NCLBUTTONDBLCLK:
- case WM_NCRBUTTONDOWN:
- case WM_NCRBUTTONDBLCLK:
- case WM_NCMBUTTONDOWN:
- case WM_NCMBUTTONDBLCLK:
- case WM_LBUTTONDOWN:
- case WM_LBUTTONDBLCLK:
- case WM_MBUTTONDOWN:
- case WM_MBUTTONDBLCLK:
- case WM_RBUTTONDOWN:
- case WM_RBUTTONDBLCLK:
- case WM_KEYDOWN:
- case WM_SYSKEYDOWN:
- if (isHWNDBlockedByModalComponents (m.hwnd))
- {
- if (Component* const modal = Component::getCurrentlyModalComponent (0))
- modal->inputAttemptWhenModal();
- return true;
- }
- break;
- default:
- break;
- }
- return false;
- }
- JUCE_DECLARE_NON_COPYABLE (WindowClassHolder)
- };
- //==============================================================================
- static void* createWindowCallback (void* userData)
- {
- static_cast<HWNDComponentPeer*> (userData)->createWindow();
- return nullptr;
- }
- void createWindow()
- {
- DWORD exstyle = 0;
- DWORD type = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
- if (hasTitleBar())
- {
- type |= WS_OVERLAPPED;
- if ((styleFlags & windowHasCloseButton) != 0)
- {
- type |= WS_SYSMENU;
- }
- else
- {
- // annoyingly, windows won't let you have a min/max button without a close button
- jassert ((styleFlags & (windowHasMinimiseButton | windowHasMaximiseButton)) == 0);
- }
- if ((styleFlags & windowIsResizable) != 0)
- type |= WS_THICKFRAME;
- }
- else if (parentToAddTo != 0)
- {
- type |= WS_CHILD;
- }
- else
- {
- type |= WS_POPUP | WS_SYSMENU;
- }
- if ((styleFlags & windowAppearsOnTaskbar) == 0)
- exstyle |= WS_EX_TOOLWINDOW;
- else
- exstyle |= WS_EX_APPWINDOW;
- if ((styleFlags & windowHasMinimiseButton) != 0) type |= WS_MINIMIZEBOX;
- if ((styleFlags & windowHasMaximiseButton) != 0) type |= WS_MAXIMIZEBOX;
- if ((styleFlags & windowIgnoresMouseClicks) != 0) exstyle |= WS_EX_TRANSPARENT;
- if ((styleFlags & windowIsSemiTransparent) != 0 && Desktop::canUseSemiTransparentWindows())
- exstyle |= WS_EX_LAYERED;
- hwnd = CreateWindowEx (exstyle, WindowClassHolder::getInstance()->getWindowClassName(),
- L"", type, 0, 0, 0, 0, parentToAddTo, 0,
- (HINSTANCE) Process::getCurrentModuleInstanceHandle(), 0);
- if (hwnd != 0)
- {
- SetWindowLongPtr (hwnd, 0, 0);
- SetWindowLongPtr (hwnd, 8, (LONG_PTR) this);
- JuceWindowIdentifier::setAsJUCEWindow (hwnd, true);
- if (dropTarget == nullptr)
- {
- HWNDComponentPeer* peer = nullptr;
- if (dontRepaint)
- peer = getOwnerOfWindow (parentToAddTo);
- if (peer == nullptr)
- peer = this;
- dropTarget = new JuceDropTarget (*peer);
- }
- RegisterDragDrop (hwnd, dropTarget);
- if (canUseMultiTouch())
- registerTouchWindow (hwnd, 0);
- setDPIAwareness();
- setMessageFilter();
- updateBorderSize();
- // Calling this function here is (for some reason) necessary to make Windows
- // correctly enable the menu items that we specify in the wm_initmenu message.
- GetSystemMenu (hwnd, false);
- const float alpha = component.getAlpha();
- if (alpha < 1.0f)
- setAlpha (alpha);
- }
- else
- {
- jassertfalse;
- }
- }
- static void* destroyWindowCallback (void* handle)
- {
- RevokeDragDrop ((HWND) handle);
- DestroyWindow ((HWND) handle);
- return nullptr;
- }
- static void* toFrontCallback1 (void* h)
- {
- SetForegroundWindow ((HWND) h);
- return nullptr;
- }
- static void* toFrontCallback2 (void* h)
- {
- setWindowZOrder ((HWND) h, HWND_TOP);
- return nullptr;
- }
- static void* setFocusCallback (void* h)
- {
- SetFocus ((HWND) h);
- return nullptr;
- }
- static void* getFocusCallback (void*)
- {
- return GetFocus();
- }
- bool isUsingUpdateLayeredWindow() const
- {
- return ! component.isOpaque();
- }
- bool hasTitleBar() const noexcept { return (styleFlags & windowHasTitleBar) != 0; }
- void setIcon (const Image& newIcon)
- {
- HICON hicon = IconConverters::createHICONFromImage (newIcon, TRUE, 0, 0);
- if (hicon != 0)
- {
- SendMessage (hwnd, WM_SETICON, ICON_BIG, (LPARAM) hicon);
- SendMessage (hwnd, WM_SETICON, ICON_SMALL, (LPARAM) hicon);
- if (currentWindowIcon != 0)
- DestroyIcon (currentWindowIcon);
- currentWindowIcon = hicon;
- }
- }
- void setMessageFilter()
- {
- typedef BOOL (WINAPI* ChangeWindowMessageFilterExFunc) (HWND, UINT, DWORD, PVOID);
- if (ChangeWindowMessageFilterExFunc changeMessageFilter
- = (ChangeWindowMessageFilterExFunc) getUser32Function ("ChangeWindowMessageFilterEx"))
- {
- changeMessageFilter (hwnd, WM_DROPFILES, 1 /*MSGFLT_ALLOW*/, nullptr);
- changeMessageFilter (hwnd, WM_COPYDATA, 1 /*MSGFLT_ALLOW*/, nullptr);
- changeMessageFilter (hwnd, 0x49, 1 /*MSGFLT_ALLOW*/, nullptr);
- }
- }
- struct ChildWindowClippingInfo
- {
- HDC dc;
- HWNDComponentPeer* peer;
- RectangleList<int>* clip;
- Point<int> origin;
- int savedDC;
- };
- static BOOL CALLBACK clipChildWindowCallback (HWND hwnd, LPARAM context)
- {
- if (IsWindowVisible (hwnd))
- {
- ChildWindowClippingInfo& info = *(ChildWindowClippingInfo*) context;
- HWND parent = GetParent (hwnd);
- if (parent == info.peer->hwnd)
- {
- RECT r = getWindowRect (hwnd);
- POINT pos = { r.left, r.top };
- ScreenToClient (GetParent (hwnd), &pos);
- Rectangle<int> clip (Rectangle<int> (pos.x, pos.y,
- r.right - r.left,
- r.bottom - r.top));
- info.clip->subtract (clip - info.origin);
- if (info.savedDC == 0)
- info.savedDC = SaveDC (info.dc);
- ExcludeClipRect (info.dc, clip.getX(), clip.getY(), clip.getRight(), clip.getBottom());
- }
- }
- return TRUE;
- }
- //==============================================================================
- void handlePaintMessage()
- {
- #if JUCE_DIRECT2D
- if (direct2DContext != nullptr)
- {
- RECT r;
- if (GetUpdateRect (hwnd, &r, false))
- {
- direct2DContext->start();
- direct2DContext->clipToRectangle (rectangleFromRECT (r));
- handlePaint (*direct2DContext);
- direct2DContext->end();
- }
- }
- else
- #endif
- HRGN rgn = CreateRectRgn (0, 0, 0, 0);
- const int regionType = GetUpdateRgn (hwnd, rgn, false);
- PAINTSTRUCT paintStruct;
- HDC dc = BeginPaint (hwnd, &paintStruct); // Note this can immediately generate a WM_NCPAINT
- // message and become re-entrant, but that's OK
- // if something in a paint handler calls, e.g. a message box, this can become reentrant and
- // corrupt the image it's using to paint into, so do a check here.
- static bool reentrant = false;
- if (! reentrant)
- {
- const ScopedValueSetter<bool> setter (reentrant, true, false);
- if (dontRepaint)
- component.handleCommandMessage (0); // (this triggers a repaint in the openGL context)
- else
- performPaint (dc, rgn, regionType, paintStruct);
- }
- DeleteObject (rgn);
- EndPaint (hwnd, &paintStruct);
- #ifndef JUCE_GCC
- _fpreset(); // because some graphics cards can unmask FP exceptions
- #endif
- lastPaintTime = Time::getMillisecondCounter();
- }
- void performPaint (HDC dc, HRGN rgn, int regionType, PAINTSTRUCT& paintStruct)
- {
- int x = paintStruct.rcPaint.left;
- int y = paintStruct.rcPaint.top;
- int w = paintStruct.rcPaint.right - x;
- int h = paintStruct.rcPaint.bottom - y;
- const bool transparent = isUsingUpdateLayeredWindow();
- if (transparent)
- {
- // it's not possible to have a transparent window with a title bar at the moment!
- jassert (! hasTitleBar());
- RECT r = getWindowRect (hwnd);
- x = y = 0;
- w = r.right - r.left;
- h = r.bottom - r.top;
- }
- if (w > 0 && h > 0)
- {
- Image& offscreenImage = offscreenImageGenerator.getImage (transparent, w, h);
- RectangleList<int> contextClip;
- const Rectangle<int> clipBounds (w, h);
- bool needToPaintAll = true;
- if (regionType == COMPLEXREGION && ! transparent)
- {
- HRGN clipRgn = CreateRectRgnIndirect (&paintStruct.rcPaint);
- CombineRgn (rgn, rgn, clipRgn, RGN_AND);
- DeleteObject (clipRgn);
- char rgnData [8192];
- const DWORD res = GetRegionData (rgn, sizeof (rgnData), (RGNDATA*) rgnData);
- if (res > 0 && res <= sizeof (rgnData))
- {
- const RGNDATAHEADER* const hdr = &(((const RGNDATA*) rgnData)->rdh);
- if (hdr->iType == RDH_RECTANGLES
- && hdr->rcBound.right - hdr->rcBound.left >= w
- && hdr->rcBound.bottom - hdr->rcBound.top >= h)
- {
- needToPaintAll = false;
- const RECT* rects = (const RECT*) (rgnData + sizeof (RGNDATAHEADER));
- for (int i = (int) ((RGNDATA*) rgnData)->rdh.nCount; --i >= 0;)
- {
- if (rects->right <= x + w && rects->bottom <= y + h)
- {
- const int cx = jmax (x, (int) rects->left);
- contextClip.addWithoutMerging (Rectangle<int> (cx - x, rects->top - y,
- rects->right - cx, rects->bottom - rects->top)
- .getIntersection (clipBounds));
- }
- else
- {
- needToPaintAll = true;
- break;
- }
- ++rects;
- }
- }
- }
- }
- if (needToPaintAll)
- {
- contextClip.clear();
- contextClip.addWithoutMerging (Rectangle<int> (w, h));
- }
- ChildWindowClippingInfo childClipInfo = { dc, this, &contextClip, Point<int> (x, y), 0 };
- EnumChildWindows (hwnd, clipChildWindowCallback, (LPARAM) &childClipInfo);
- if (! contextClip.isEmpty())
- {
- if (transparent)
- for (const Rectangle<int>* i = contextClip.begin(), * const e = contextClip.end(); i != e; ++i)
- offscreenImage.clear (*i);
- // if the component's not opaque, this won't draw properly unless the platform can support this
- jassert (Desktop::canUseSemiTransparentWindows() || component.isOpaque());
- {
- ScopedPointer<LowLevelGraphicsContext> context (component.getLookAndFeel()
- .createGraphicsContext (offscreenImage, Point<int> (-x, -y), contextClip));
- handlePaint (*context);
- }
- static_cast<WindowsBitmapImage*> (offscreenImage.getPixelData())
- ->blitToWindow (hwnd, dc, transparent, x, y, updateLayeredWindowAlpha);
- }
- if (childClipInfo.savedDC != 0)
- RestoreDC (dc, childClipInfo.savedDC);
- }
- }
- //==============================================================================
- void doMouseEvent (Point<float> position)
- {
- handleMouseEvent (0, position, currentModifiers, getMouseEventTime());
- }
- StringArray getAvailableRenderingEngines() override
- {
- StringArray s ("Software Renderer");
- #if JUCE_DIRECT2D
- if (SystemStats::getOperatingSystemType() >= SystemStats::Windows7)
- s.add ("Direct2D");
- #endif
- return s;
- }
- int getCurrentRenderingEngine() const override { return currentRenderingEngine; }
- #if JUCE_DIRECT2D
- void updateDirect2DContext()
- {
- if (currentRenderingEngine != direct2DRenderingEngine)
- direct2DContext = 0;
- else if (direct2DContext == 0)
- direct2DContext = new Direct2DLowLevelGraphicsContext (hwnd);
- }
- #endif
- void setCurrentRenderingEngine (int index) override
- {
- (void) index;
- #if JUCE_DIRECT2D
- if (getAvailableRenderingEngines().size() > 1)
- {
- currentRenderingEngine = index == 1 ? direct2DRenderingEngine : softwareRenderingEngine;
- updateDirect2DContext();
- repaint (component.getLocalBounds());
- }
- #endif
- }
- static int getMinTimeBetweenMouseMoves()
- {
- if (SystemStats::getOperatingSystemType() >= SystemStats::WinVista)
- return 0;
- return 1000 / 60; // Throttling the incoming mouse-events seems to still be needed in XP..
- }
- void doMouseMove (Point<float> position)
- {
- if (! isMouseOver)
- {
- isMouseOver = true;
- ModifierKeys::getCurrentModifiersRealtime(); // (This avoids a rare stuck-button problem when focus is lost unexpectedly)
- updateKeyModifiers();
- TRACKMOUSEEVENT tme;
- tme.cbSize = sizeof (tme);
- tme.dwFlags = TME_LEAVE;
- tme.hwndTrack = hwnd;
- tme.dwHoverTime = 0;
- if (! TrackMouseEvent (&tme))
- jassertfalse;
- Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate();
- }
- else if (! isDragging)
- {
- if (! contains (position.roundToInt(), false))
- return;
- }
- static uint32 lastMouseTime = 0;
- static int minTimeBetweenMouses = getMinTimeBetweenMouseMoves();
- const uint32 now = Time::getMillisecondCounter();
- if (now >= lastMouseTime + minTimeBetweenMouses)
- {
- lastMouseTime = now;
- doMouseEvent (position);
- }
- }
- void doMouseDown (Point<float> position, const WPARAM wParam)
- {
- if (GetCapture() != hwnd)
- SetCapture (hwnd);
- doMouseMove (position);
- if (isValidPeer (this))
- {
- updateModifiersFromWParam (wParam);
- isDragging = true;
- doMouseEvent (position);
- }
- }
- void doMouseUp (Point<float> position, const WPARAM wParam)
- {
- updateModifiersFromWParam (wParam);
- const bool wasDragging = isDragging;
- isDragging = false;
- // release the mouse capture if the user has released all buttons
- if ((wParam & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON)) == 0 && hwnd == GetCapture())
- ReleaseCapture();
- // NB: under some circumstances (e.g. double-clicking a native title bar), a mouse-up can
- // arrive without a mouse-down, so in that case we need to avoid sending a message.
- if (wasDragging)
- doMouseEvent (position);
- }
- void doCaptureChanged()
- {
- if (constrainerIsResizing)
- {
- if (constrainer != nullptr)
- constrainer->resizeEnd();
- constrainerIsResizing = false;
- }
- if (isDragging)
- doMouseUp (getCurrentMousePos(), (WPARAM) 0);
- }
- void doMouseExit()
- {
- isMouseOver = false;
- doMouseEvent (getCurrentMousePos());
- }
- ComponentPeer* findPeerUnderMouse (Point<float>& localPos)
- {
- const Point<int> globalPos (getCurrentMousePosGlobal().roundToInt());
- // Because Windows stupidly sends all wheel events to the window with the keyboard
- // focus, we have to redirect them here according to the mouse pos..
- POINT p = { globalPos.x, globalPos.y };
- HWNDComponentPeer* peer = getOwnerOfWindow (WindowFromPoint (p));
- if (peer == nullptr)
- peer = this;
- localPos = peer->globalToLocal (globalPos.toFloat());
- return peer;
- }
- void doMouseWheel (const WPARAM wParam, const bool isVertical)
- {
- updateKeyModifiers();
- const float amount = jlimit (-1000.0f, 1000.0f, 0.5f * (short) HIWORD (wParam));
- MouseWheelDetails wheel;
- wheel.deltaX = isVertical ? 0.0f : amount / -256.0f;
- wheel.deltaY = isVertical ? amount / 256.0f : 0.0f;
- wheel.isReversed = false;
- wheel.isSmooth = false;
- Point<float> localPos;
- if (ComponentPeer* const peer = findPeerUnderMouse (localPos))
- peer->handleMouseWheel (0, localPos, getMouseEventTime(), wheel);
- }
- bool doGestureEvent (LPARAM lParam)
- {
- GESTUREINFO gi;
- zerostruct (gi);
- gi.cbSize = sizeof (gi);
- if (getGestureInfo != nullptr && getGestureInfo ((HGESTUREINFO) lParam, &gi))
- {
- updateKeyModifiers();
- Point<float> localPos;
- if (ComponentPeer* const peer = findPeerUnderMouse (localPos))
- {
- switch (gi.dwID)
- {
- case 3: /*GID_ZOOM*/
- if (gi.dwFlags != 1 /*GF_BEGIN*/ && lastMagnifySize > 0)
- peer->handleMagnifyGesture (0, localPos, getMouseEventTime(),
- (float) (gi.ullArguments / (double) lastMagnifySize));
- lastMagnifySize = gi.ullArguments;
- return true;
- case 4: /*GID_PAN*/
- case 5: /*GID_ROTATE*/
- case 6: /*GID_TWOFINGERTAP*/
- case 7: /*GID_PRESSANDTAP*/
- default:
- break;
- }
- }
- }
- return false;
- }
- LRESULT doTouchEvent (const int numInputs, HTOUCHINPUT eventHandle)
- {
- if ((styleFlags & windowIgnoresMouseClicks) != 0)
- if (HWNDComponentPeer* const parent = getOwnerOfWindow (GetParent (hwnd)))
- if (parent != this)
- return parent->doTouchEvent (numInputs, eventHandle);
- HeapBlock<TOUCHINPUT> inputInfo (numInputs);
- if (getTouchInputInfo (eventHandle, numInputs, inputInfo, sizeof (TOUCHINPUT)))
- {
- for (int i = 0; i < numInputs; ++i)
- {
- const DWORD flags = inputInfo[i].dwFlags;
- if ((flags & (TOUCHEVENTF_DOWN | TOUCHEVENTF_MOVE | TOUCHEVENTF_UP)) != 0)
- if (! handleTouchInput (inputInfo[i], (flags & TOUCHEVENTF_PRIMARY) != 0,
- (flags & TOUCHEVENTF_DOWN) != 0, (flags & TOUCHEVENTF_UP) != 0))
- return 0; // abandon method if this window was deleted by the callback
- }
- }
- closeTouchInputHandle (eventHandle);
- return 0;
- }
- bool handleTouchInput (const TOUCHINPUT& touch, const bool isPrimary, const bool isDown, const bool isUp)
- {
- bool isCancel = false;
- const int touchIndex = currentTouches.getIndexOfTouch (touch.dwID);
- const int64 time = getMouseEventTime();
- const Point<float> pos (globalToLocal (Point<float> (static_cast<float> (TOUCH_COORD_TO_PIXEL (touch.x)),
- static_cast<float> (TOUCH_COORD_TO_PIXEL (touch.y)))));
- ModifierKeys modsToSend (currentModifiers);
- if (isDown)
- {
- currentModifiers = currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier);
- modsToSend = currentModifiers;
- if (! isPrimary)
- {
- // this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before.
- handleMouseEvent (touchIndex, pos.toFloat(), modsToSend.withoutMouseButtons(), time);
- if (! isValidPeer (this)) // (in case this component was deleted by the event)
- return false;
- }
- }
- else if (isUp)
- {
- modsToSend = modsToSend.withoutMouseButtons();
- currentTouches.clearTouch (touchIndex);
- if (! currentTouches.areAnyTouchesActive())
- isCancel = true;
- }
- else
- {
- modsToSend = currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier);
- }
- if (isCancel)
- {
- currentTouches.clear();
- currentModifiers = currentModifiers.withoutMouseButtons();
- }
- if (! isPrimary)
- {
- handleMouseEvent (touchIndex, pos.toFloat(), modsToSend, time);
- if (! isValidPeer (this)) // (in case this component was deleted by the event)
- return false;
- }
- if ((isUp || isCancel) && ! isPrimary)
- {
- handleMouseEvent (touchIndex, Point<float> (-10.0f, -10.0f), currentModifiers, time);
- if (! isValidPeer (this))
- return false;
- }
- return true;
- }
- //==============================================================================
- void sendModifierKeyChangeIfNeeded()
- {
- if (modifiersAtLastCallback != currentModifiers)
- {
- modifiersAtLastCallback = currentModifiers;
- handleModifierKeysChange();
- }
- }
- bool doKeyUp (const WPARAM key)
- {
- updateKeyModifiers();
- switch (key)
- {
- case VK_SHIFT:
- case VK_CONTROL:
- case VK_MENU:
- case VK_CAPITAL:
- case VK_LWIN:
- case VK_RWIN:
- case VK_APPS:
- case VK_NUMLOCK:
- case VK_SCROLL:
- case VK_LSHIFT:
- case VK_RSHIFT:
- case VK_LCONTROL:
- case VK_LMENU:
- case VK_RCONTROL:
- case VK_RMENU:
- sendModifierKeyChangeIfNeeded();
- }
- return handleKeyUpOrDown (false)
- || Component::getCurrentlyModalComponent() != nullptr;
- }
- bool doKeyDown (const WPARAM key)
- {
- updateKeyModifiers();
- bool used = false;
- switch (key)
- {
- case VK_SHIFT:
- case VK_LSHIFT:
- case VK_RSHIFT:
- case VK_CONTROL:
- case VK_LCONTROL:
- case VK_RCONTROL:
- case VK_MENU:
- case VK_LMENU:
- case VK_RMENU:
- case VK_LWIN:
- case VK_RWIN:
- case VK_CAPITAL:
- case VK_NUMLOCK:
- case VK_SCROLL:
- case VK_APPS:
- sendModifierKeyChangeIfNeeded();
- break;
- case VK_LEFT:
- case VK_RIGHT:
- case VK_UP:
- case VK_DOWN:
- case VK_PRIOR:
- case VK_NEXT:
- case VK_HOME:
- case VK_END:
- case VK_DELETE:
- case VK_INSERT:
- case VK_F1:
- case VK_F2:
- case VK_F3:
- case VK_F4:
- case VK_F5:
- case VK_F6:
- case VK_F7:
- case VK_F8:
- case VK_F9:
- case VK_F10:
- case VK_F11:
- case VK_F12:
- case VK_F13:
- case VK_F14:
- case VK_F15:
- case VK_F16:
- used = handleKeyUpOrDown (true);
- used = handleKeyPress (extendedKeyModifier | (int) key, 0) || used;
- break;
- default:
- used = handleKeyUpOrDown (true);
- {
- MSG msg;
- if (! PeekMessage (&msg, hwnd, WM_CHAR, WM_DEADCHAR, PM_NOREMOVE))
- {
- // if there isn't a WM_CHAR or WM_DEADCHAR message pending, we need to
- // manually generate the key-press event that matches this key-down.
- const UINT keyChar = MapVirtualKey ((UINT) key, 2);
- const UINT scanCode = MapVirtualKey ((UINT) key, 0);
- BYTE keyState[256];
- GetKeyboardState (keyState);
- WCHAR text[16] = { 0 };
- if (ToUnicode ((UINT) key, scanCode, keyState, text, 8, 0) != 1)
- text[0] = 0;
- used = handleKeyPress ((int) LOWORD (keyChar), (juce_wchar) text[0]) || used;
- }
- }
- break;
- }
- return used || (Component::getCurrentlyModalComponent() != nullptr);
- }
- bool doKeyChar (int key, const LPARAM flags)
- {
- updateKeyModifiers();
- juce_wchar textChar = (juce_wchar) key;
- const int virtualScanCode = (flags >> 16) & 0xff;
- if (key >= '0' && key <= '9')
- {
- switch (virtualScanCode) // check for a numeric keypad scan-code
- {
- case 0x52:
- case 0x4f:
- case 0x50:
- case 0x51:
- case 0x4b:
- case 0x4c:
- case 0x4d:
- case 0x47:
- case 0x48:
- case 0x49:
- key = (key - '0') + KeyPress::numberPad0;
- break;
- default:
- break;
- }
- }
- else
- {
- // convert the scan code to an unmodified character code..
- const UINT virtualKey = MapVirtualKey ((UINT) virtualScanCode, 1);
- UINT keyChar = MapVirtualKey (virtualKey, 2);
- keyChar = LOWORD (keyChar);
- if (keyChar != 0)
- key = (int) keyChar;
- // avoid sending junk text characters for some control-key combinations
- if (textChar < ' ' && currentModifiers.testFlags (ModifierKeys::ctrlModifier | ModifierKeys::altModifier))
- textChar = 0;
- }
- return handleKeyPress (key, textChar);
- }
- void forwardMessageToParent (UINT message, WPARAM wParam, LPARAM lParam) const
- {
- if (HWND parentH = GetParent (hwnd))
- PostMessage (parentH, message, wParam, lParam);
- }
- bool doAppCommand (const LPARAM lParam)
- {
- int key = 0;
- switch (GET_APPCOMMAND_LPARAM (lParam))
- {
- case APPCOMMAND_MEDIA_PLAY_PAUSE: key = KeyPress::playKey; break;
- case APPCOMMAND_MEDIA_STOP: key = KeyPress::stopKey; break;
- case APPCOMMAND_MEDIA_NEXTTRACK: key = KeyPress::fastForwardKey; break;
- case APPCOMMAND_MEDIA_PREVIOUSTRACK: key = KeyPress::rewindKey; break;
- default: break;
- }
- if (key != 0)
- {
- updateKeyModifiers();
- if (hwnd == GetActiveWindow())
- {
- handleKeyPress (key, 0);
- return true;
- }
- }
- return false;
- }
- bool isConstrainedNativeWindow() const
- {
- return constrainer != nullptr
- && (styleFlags & (windowHasTitleBar | windowIsResizable)) == (windowHasTitleBar | windowIsResizable)
- && ! isKioskMode();
- }
- Rectangle<int> getCurrentScaledBounds (float scale) const
- {
- return ScalingHelpers::unscaledScreenPosToScaled (scale, windowBorder.addedTo (ScalingHelpers::scaledScreenPosToUnscaled (scale, component.getBounds())));
- }
- LRESULT handleSizeConstraining (RECT& r, const WPARAM wParam)
- {
- if (isConstrainedNativeWindow())
- {
- const float scale = getComponent().getDesktopScaleFactor();
- Rectangle<int> pos (ScalingHelpers::unscaledScreenPosToScaled (scale, rectangleFromRECT (r)));
- const Rectangle<int> current (getCurrentScaledBounds (scale));
- constrainer->checkBounds (pos, current,
- Desktop::getInstance().getDisplays().getTotalBounds (true),
- wParam == WMSZ_TOP || wParam == WMSZ_TOPLEFT || wParam == WMSZ_TOPRIGHT,
- wParam == WMSZ_LEFT || wParam == WMSZ_TOPLEFT || wParam == WMSZ_BOTTOMLEFT,
- wParam == WMSZ_BOTTOM || wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_BOTTOMRIGHT,
- wParam == WMSZ_RIGHT || wParam == WMSZ_TOPRIGHT || wParam == WMSZ_BOTTOMRIGHT);
- pos = ScalingHelpers::scaledScreenPosToUnscaled (scale, pos);
- r.left = pos.getX();
- r.top = pos.getY();
- r.right = pos.getRight();
- r.bottom = pos.getBottom();
- }
- return TRUE;
- }
- LRESULT handlePositionChanging (WINDOWPOS& wp)
- {
- if (isConstrainedNativeWindow())
- {
- if ((wp.flags & (SWP_NOMOVE | SWP_NOSIZE)) != (SWP_NOMOVE | SWP_NOSIZE)
- && ! Component::isMouseButtonDownAnywhere())
- {
- const float scale = getComponent().getDesktopScaleFactor();
- Rectangle<int> pos (ScalingHelpers::unscaledScreenPosToScaled (scale, Rectangle<int> (wp.x, wp.y, wp.cx, wp.cy)));
- const Rectangle<int> current (getCurrentScaledBounds (scale));
- constrainer->checkBounds (pos, current,
- Desktop::getInstance().getDisplays().getTotalBounds (true),
- pos.getY() != current.getY() && pos.getBottom() == current.getBottom(),
- pos.getX() != current.getX() && pos.getRight() == current.getRight(),
- pos.getY() == current.getY() && pos.getBottom() != current.getBottom(),
- pos.getX() == current.getX() && pos.getRight() != current.getRight());
- pos = ScalingHelpers::scaledScreenPosToUnscaled (scale, pos);
- wp.x = pos.getX();
- wp.y = pos.getY();
- wp.cx = pos.getWidth();
- wp.cy = pos.getHeight();
- }
- }
- if (((wp.flags & SWP_SHOWWINDOW) != 0 && ! component.isVisible()))
- component.setVisible (true);
- else if (((wp.flags & SWP_HIDEWINDOW) != 0 && component.isVisible()))
- component.setVisible (false);
- return 0;
- }
- bool handlePositionChanged()
- {
- const Point<float> pos (getCurrentMousePos());
- if (contains (pos.roundToInt(), false))
- {
- doMouseEvent (pos);
- if (! isValidPeer (this))
- return true;
- }
- handleMovedOrResized();
- return ! dontRepaint; // to allow non-accelerated openGL windows to draw themselves correctly..
- }
- void handleAppActivation (const WPARAM wParam)
- {
- modifiersAtLastCallback = -1;
- updateKeyModifiers();
- if (isMinimised())
- {
- component.repaint();
- handleMovedOrResized();
- if (! isValidPeer (this))
- return;
- }
- Component* underMouse = component.getComponentAt (component.getMouseXYRelative());
- if (underMouse == nullptr)
- underMouse = &component;
- if (underMouse->isCurrentlyBlockedByAnotherModalComponent())
- {
- if (LOWORD (wParam) == WA_CLICKACTIVE)
- Component::getCurrentlyModalComponent()->inputAttemptWhenModal();
- else
- ModalComponentManager::getInstance()->bringModalComponentsToFront();
- }
- else
- {
- handleBroughtToFront();
- }
- }
- void handlePowerBroadcast (WPARAM wParam)
- {
- if (JUCEApplicationBase* const app = JUCEApplicationBase::getInstance())
- {
- switch (wParam)
- {
- case PBT_APMSUSPEND: app->suspended(); break;
- case PBT_APMQUERYSUSPENDFAILED:
- case PBT_APMRESUMECRITICAL:
- case PBT_APMRESUMESUSPEND:
- case PBT_APMRESUMEAUTOMATIC: app->resumed(); break;
- default: break;
- }
- }
- }
- void handleLeftClickInNCArea (WPARAM wParam)
- {
- if (! sendInputAttemptWhenModalMessage())
- {
- switch (wParam)
- {
- case HTBOTTOM:
- case HTBOTTOMLEFT:
- case HTBOTTOMRIGHT:
- case HTGROWBOX:
- case HTLEFT:
- case HTRIGHT:
- case HTTOP:
- case HTTOPLEFT:
- case HTTOPRIGHT:
- if (isConstrainedNativeWindow())
- {
- constrainerIsResizing = true;
- constrainer->resizeStart();
- }
- break;
- default:
- break;
- }
- }
- }
- void initialiseSysMenu (HMENU menu) const
- {
- if (! hasTitleBar())
- {
- if (isFullScreen())
- {
- EnableMenuItem (menu, SC_RESTORE, MF_BYCOMMAND | MF_ENABLED);
- EnableMenuItem (menu, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
- }
- else if (! isMinimised())
- {
- EnableMenuItem (menu, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
- }
- }
- }
- void doSettingChange()
- {
- Desktop& desktop = Desktop::getInstance();
- const_cast<Desktop::Displays&> (desktop.getDisplays()).refresh();
- if (fullScreen && ! isMinimised())
- {
- const Desktop::Displays::Display& display
- = desktop.getDisplays().getDisplayContaining (component.getScreenBounds().getCentre());
- setWindowPos (hwnd, display.userArea * display.scale,
- SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOSENDCHANGING);
- }
- }
- void handleDPIChange() // happens when a window moves to a screen with a different DPI.
- {
- }
- //==============================================================================
- public:
- static LRESULT CALLBACK windowProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam)
- {
- if (HWNDComponentPeer* const peer = getOwnerOfWindow (h))
- {
- jassert (isValidPeer (peer));
- return peer->peerWindowProc (h, message, wParam, lParam);
- }
- return DefWindowProcW (h, message, wParam, lParam);
- }
- private:
- static void* callFunctionIfNotLocked (MessageCallbackFunction* callback, void* userData)
- {
- if (MessageManager::getInstance()->currentThreadHasLockedMessageManager())
- return callback (userData);
- return MessageManager::getInstance()->callFunctionOnMessageThread (callback, userData);
- }
- static Point<float> getPointFromLParam (LPARAM lParam) noexcept
- {
- return Point<float> (static_cast<float> (GET_X_LPARAM (lParam)),
- static_cast<float> (GET_Y_LPARAM (lParam)));
- }
- static Point<float> getCurrentMousePosGlobal() noexcept
- {
- return getPointFromLParam (GetMessagePos());
- }
- Point<float> getCurrentMousePos() noexcept
- {
- return globalToLocal (getCurrentMousePosGlobal());
- }
- LRESULT peerWindowProc (HWND h, UINT message, WPARAM wParam, LPARAM lParam)
- {
- switch (message)
- {
- //==============================================================================
- case WM_NCHITTEST:
- if ((styleFlags & windowIgnoresMouseClicks) != 0)
- return HTTRANSPARENT;
- if (! hasTitleBar())
- return HTCLIENT;
- break;
- //==============================================================================
- case WM_PAINT:
- handlePaintMessage();
- return 0;
- case WM_NCPAINT:
- if (wParam != 1) // (1 = a repaint of the entire NC region)
- handlePaintMessage(); // this must be done, even with native titlebars, or there are rendering artifacts.
- if (hasTitleBar())
- break; // let the DefWindowProc handle drawing the frame.
- return 0;
- case WM_ERASEBKGND:
- case WM_NCCALCSIZE:
- if (hasTitleBar())
- break;
- return 1;
- //==============================================================================
- case WM_MOUSEMOVE: doMouseMove (getPointFromLParam (lParam)); return 0;
- case WM_MOUSELEAVE: doMouseExit(); return 0;
- case WM_LBUTTONDOWN:
- case WM_MBUTTONDOWN:
- case WM_RBUTTONDOWN: doMouseDown (getPointFromLParam (lParam), wParam); return 0;
- case WM_LBUTTONUP:
- case WM_MBUTTONUP:
- case WM_RBUTTONUP: doMouseUp (getPointFromLParam (lParam), wParam); return 0;
- case 0x020A: /* WM_MOUSEWHEEL */ doMouseWheel (wParam, true); return 0;
- case 0x020E: /* WM_MOUSEHWHEEL */ doMouseWheel (wParam, false); return 0;
- case WM_CAPTURECHANGED: doCaptureChanged(); return 0;
- case WM_NCMOUSEMOVE:
- if (hasTitleBar())
- break;
- return 0;
- case WM_TOUCH:
- if (getTouchInputInfo != nullptr)
- return doTouchEvent ((int) wParam, (HTOUCHINPUT) lParam);
- break;
- case 0x119: /* WM_GESTURE */
- if (doGestureEvent (lParam))
- return 0;
- break;
- //==============================================================================
- case WM_SIZING: return handleSizeConstraining (*(RECT*) lParam, wParam);
- case WM_WINDOWPOSCHANGING: return handlePositionChanging (*(WINDOWPOS*) lParam);
- case WM_WINDOWPOSCHANGED:
- if (handlePositionChanged())
- return 0;
- break;
- //==============================================================================
- case WM_KEYDOWN:
- case WM_SYSKEYDOWN:
- if (doKeyDown (wParam))
- return 0;
- forwardMessageToParent (message, wParam, lParam);
- break;
- case WM_KEYUP:
- case WM_SYSKEYUP:
- if (doKeyUp (wParam))
- return 0;
- forwardMessageToParent (message, wParam, lParam);
- break;
- case WM_CHAR:
- if (doKeyChar ((int) wParam, lParam))
- return 0;
- forwardMessageToParent (message, wParam, lParam);
- break;
- case WM_APPCOMMAND:
- if (doAppCommand (lParam))
- return TRUE;
- break;
- case WM_MENUCHAR: // triggered when alt+something is pressed
- return MNC_CLOSE << 16; // (avoids making the default system beep)
- //==============================================================================
- case WM_SETFOCUS:
- updateKeyModifiers();
- handleFocusGain();
- break;
- case WM_KILLFOCUS:
- if (hasCreatedCaret)
- {
- hasCreatedCaret = false;
- DestroyCaret();
- }
- handleFocusLoss();
- break;
- case WM_ACTIVATEAPP:
- // Windows does weird things to process priority when you swap apps,
- // so this forces an update when the app is brought to the front
- if (wParam != FALSE)
- juce_repeatLastProcessPriority();
- else
- Desktop::getInstance().setKioskModeComponent (nullptr); // turn kiosk mode off if we lose focus
- juce_checkCurrentlyFocusedTopLevelWindow();
- modifiersAtLastCallback = -1;
- return 0;
- case WM_ACTIVATE:
- if (LOWORD (wParam) == WA_ACTIVE || LOWORD (wParam) == WA_CLICKACTIVE)
- {
- handleAppActivation (wParam);
- return 0;
- }
- break;
- case WM_NCACTIVATE:
- // while a temporary window is being shown, prevent Windows from deactivating the
- // title bars of our main windows.
- if (wParam == 0 && ! shouldDeactivateTitleBar)
- wParam = TRUE; // change this and let it get passed to the DefWindowProc.
- break;
- case WM_MOUSEACTIVATE:
- if (! component.getMouseClickGrabsKeyboardFocus())
- return MA_NOACTIVATE;
- break;
- case WM_SHOWWINDOW:
- if (wParam != 0)
- {
- component.setVisible (true);
- handleBroughtToFront();
- }
- break;
- case WM_CLOSE:
- if (! component.isCurrentlyBlockedByAnotherModalComponent())
- handleUserClosingWindow();
- return 0;
- case WM_QUERYENDSESSION:
- if (JUCEApplicationBase* const app = JUCEApplicationBase::getInstance())
- {
- app->systemRequestedQuit();
- return MessageManager::getInstance()->hasStopMessageBeenSent();
- }
- return TRUE;
- case WM_POWERBROADCAST:
- handlePowerBroadcast (wParam);
- break;
- case WM_SYNCPAINT:
- return 0;
- case WM_DISPLAYCHANGE:
- InvalidateRect (h, 0, 0);
- // intentional fall-through...
- case WM_SETTINGCHANGE: // note the fall-through in the previous case!
- doSettingChange();
- break;
- case 0x2e0: // WM_DPICHANGED
- handleDPIChange();
- break;
- case WM_INITMENU:
- initialiseSysMenu ((HMENU) wParam);
- break;
- case WM_SYSCOMMAND:
- switch (wParam & 0xfff0)
- {
- case SC_CLOSE:
- if (sendInputAttemptWhenModalMessage())
- return 0;
- if (hasTitleBar())
- {
- PostMessage (h, WM_CLOSE, 0, 0);
- return 0;
- }
- break;
- case SC_KEYMENU:
- // (NB mustn't call sendInputAttemptWhenModalMessage() here because of very obscure
- // situations that can arise if a modal loop is started from an alt-key keypress).
- if (hasTitleBar() && h == GetCapture())
- ReleaseCapture();
- break;
- case SC_MAXIMIZE:
- if (! sendInputAttemptWhenModalMessage())
- setFullScreen (true);
- return 0;
- case SC_MINIMIZE:
- if (sendInputAttemptWhenModalMessage())
- return 0;
- if (! hasTitleBar())
- {
- setMinimised (true);
- return 0;
- }
- break;
- case SC_RESTORE:
- if (sendInputAttemptWhenModalMessage())
- return 0;
- if (hasTitleBar())
- {
- if (isFullScreen())
- {
- setFullScreen (false);
- return 0;
- }
- }
- else
- {
- if (isMinimised())
- setMinimised (false);
- else if (isFullScreen())
- setFullScreen (false);
- return 0;
- }
- break;
- }
- break;
- case WM_NCLBUTTONDOWN:
- handleLeftClickInNCArea (wParam);
- break;
- case WM_NCRBUTTONDOWN:
- case WM_NCMBUTTONDOWN:
- sendInputAttemptWhenModalMessage();
- break;
- case WM_IME_SETCONTEXT:
- imeHandler.handleSetContext (h, wParam == TRUE);
- lParam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
- break;
- case WM_IME_STARTCOMPOSITION: imeHandler.handleStartComposition (*this); return 0;
- case WM_IME_ENDCOMPOSITION: imeHandler.handleEndComposition (*this, h); break;
- case WM_IME_COMPOSITION: imeHandler.handleComposition (*this, h, lParam); return 0;
- case WM_GETDLGCODE:
- return DLGC_WANTALLKEYS;
- default:
- break;
- }
- return DefWindowProcW (h, message, wParam, lParam);
- }
- bool sendInputAttemptWhenModalMessage()
- {
- if (component.isCurrentlyBlockedByAnotherModalComponent())
- {
- if (Component* const current = Component::getCurrentlyModalComponent())
- current->inputAttemptWhenModal();
- return true;
- }
- return false;
- }
- //==============================================================================
- class IMEHandler
- {
- public:
- IMEHandler()
- {
- reset();
- }
- void handleSetContext (HWND hWnd, const bool windowIsActive)
- {
- if (compositionInProgress && ! windowIsActive)
- {
- compositionInProgress = false;
- if (HIMC hImc = ImmGetContext (hWnd))
- {
- ImmNotifyIME (hImc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
- ImmReleaseContext (hWnd, hImc);
- }
- }
- }
- void handleStartComposition (ComponentPeer& owner)
- {
- reset();
- if (TextInputTarget* const target = owner.findCurrentTextInputTarget())
- target->insertTextAtCaret (String::empty);
- }
- void handleEndComposition (ComponentPeer& owner, HWND hWnd)
- {
- if (compositionInProgress)
- {
- // If this occurs, the user has cancelled the composition, so clear their changes..
- if (TextInputTarget* const target = owner.findCurrentTextInputTarget())
- {
- target->setHighlightedRegion (compositionRange);
- target->insertTextAtCaret (String::empty);
- compositionRange.setLength (0);
- target->setHighlightedRegion (Range<int>::emptyRange (compositionRange.getEnd()));
- target->setTemporaryUnderlining (Array<Range<int> >());
- }
- if (HIMC hImc = ImmGetContext (hWnd))
- {
- ImmNotifyIME (hImc, NI_CLOSECANDIDATE, 0, 0);
- ImmReleaseContext (hWnd, hImc);
- }
- }
- reset();
- }
- void handleComposition (ComponentPeer& owner, HWND hWnd, const LPARAM lParam)
- {
- TextInputTarget* const target = owner.findCurrentTextInputTarget();
- HIMC hImc = ImmGetContext (hWnd);
- if (target == nullptr || hImc == 0)
- return;
- if (compositionRange.getStart() < 0)
- compositionRange = Range<int>::emptyRange (target->getHighlightedRegion().getStart());
- if ((lParam & GCS_RESULTSTR) != 0) // (composition has finished)
- {
- replaceCurrentSelection (target, getCompositionString (hImc, GCS_RESULTSTR),
- Range<int>::emptyRange (-1));
- reset();
- target->setTemporaryUnderlining (Array<Range<int> >());
- }
- else if ((lParam & GCS_COMPSTR) != 0) // (composition is still in-progress)
- {
- replaceCurrentSelection (target, getCompositionString (hImc, GCS_COMPSTR),
- getCompositionSelection (hImc, lParam));
- target->setTemporaryUnderlining (getCompositionUnderlines (hImc, lParam));
- compositionInProgress = true;
- }
- moveCandidateWindowToLeftAlignWithSelection (hImc, owner, target);
- ImmReleaseContext (hWnd, hImc);
- }
- private:
- //==============================================================================
- Range<int> compositionRange; // The range being modified in the TextInputTarget
- bool compositionInProgress;
- //==============================================================================
- void reset()
- {
- compositionRange = Range<int>::emptyRange (-1);
- compositionInProgress = false;
- }
- String getCompositionString (HIMC hImc, const DWORD type) const
- {
- jassert (hImc != 0);
- const int stringSizeBytes = ImmGetCompositionString (hImc, type, 0, 0);
- if (stringSizeBytes > 0)
- {
- HeapBlock<TCHAR> buffer;
- buffer.calloc (stringSizeBytes / sizeof (TCHAR) + 1);
- ImmGetCompositionString (hImc, type, buffer, (DWORD) stringSizeBytes);
- return String (buffer);
- }
- return String::empty;
- }
- int getCompositionCaretPos (HIMC hImc, LPARAM lParam, const String& currentIMEString) const
- {
- jassert (hImc != 0);
- if ((lParam & CS_NOMOVECARET) != 0)
- return compositionRange.getStart();
- if ((lParam & GCS_CURSORPOS) != 0)
- {
- const int localCaretPos = ImmGetCompositionString (hImc, GCS_CURSORPOS, 0, 0);
- return compositionRange.getStart() + jmax (0, localCaretPos);
- }
- return compositionRange.getStart() + currentIMEString.length();
- }
- // Get selected/highlighted range while doing composition:
- // returned range is relative to beginning of TextInputTarget, not composition string
- Range<int> getCompositionSelection (HIMC hImc, LPARAM lParam) const
- {
- jassert (hImc != 0);
- int selectionStart = 0;
- int selectionEnd = 0;
- if ((lParam & GCS_COMPATTR) != 0)
- {
- // Get size of attributes array:
- const int attributeSizeBytes = ImmGetCompositionString (hImc, GCS_COMPATTR, 0, 0);
- if (attributeSizeBytes > 0)
- {
- // Get attributes (8 bit flag per character):
- HeapBlock<char> attributes ((size_t) attributeSizeBytes);
- ImmGetCompositionString (hImc, GCS_COMPATTR, attributes, (DWORD) attributeSizeBytes);
- selectionStart = 0;
- for (selectionStart = 0; selectionStart < attributeSizeBytes; ++selectionStart)
- if (attributes[selectionStart] == ATTR_TARGET_CONVERTED || attributes[selectionStart] == ATTR_TARGET_NOTCONVERTED)
- break;
- for (selectionEnd = selectionStart; selectionEnd < attributeSizeBytes; ++selectionEnd)
- if (attributes [selectionEnd] != ATTR_TARGET_CONVERTED && attributes[selectionEnd] != ATTR_TARGET_NOTCONVERTED)
- break;
- }
- }
- return Range<int> (selectionStart, selectionEnd) + compositionRange.getStart();
- }
- void replaceCurrentSelection (TextInputTarget* const target, const String& newContent, Range<int> newSelection)
- {
- if (compositionInProgress)
- target->setHighlightedRegion (compositionRange);
- target->insertTextAtCaret (newContent);
- compositionRange.setLength (newContent.length());
- if (newSelection.getStart() < 0)
- newSelection = Range<int>::emptyRange (compositionRange.getEnd());
- target->setHighlightedRegion (newSelection);
- }
- Array<Range<int> > getCompositionUnderlines (HIMC hImc, LPARAM lParam) const
- {
- Array<Range<int> > result;
- if (hImc != 0 && (lParam & GCS_COMPCLAUSE) != 0)
- {
- const int clauseDataSizeBytes = ImmGetCompositionString (hImc, GCS_COMPCLAUSE, 0, 0);
- if (clauseDataSizeBytes > 0)
- {
- const size_t numItems = clauseDataSizeBytes / sizeof (uint32);
- HeapBlock<uint32> clauseData (numItems);
- if (ImmGetCompositionString (hImc, GCS_COMPCLAUSE, clauseData, (DWORD) clauseDataSizeBytes) > 0)
- for (size_t i = 0; i + 1 < numItems; ++i)
- result.add (Range<int> ((int) clauseData [i], (int) clauseData [i + 1]) + compositionRange.getStart());
- }
- }
- return result;
- }
- void moveCandidateWindowToLeftAlignWithSelection (HIMC hImc, ComponentPeer& peer, TextInputTarget* target) const
- {
- if (Component* const targetComp = dynamic_cast<Component*> (target))
- {
- const Rectangle<int> area (peer.getComponent().getLocalArea (targetComp, target->getCaretRectangle()));
- CANDIDATEFORM pos = { 0, CFS_CANDIDATEPOS, { area.getX(), area.getBottom() }, { 0, 0, 0, 0 } };
- ImmSetCandidateWindow (hImc, &pos);
- }
- }
- JUCE_DECLARE_NON_COPYABLE (IMEHandler)
- };
- IMEHandler imeHandler;
- //==============================================================================
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HWNDComponentPeer)
- };
- ModifierKeys HWNDComponentPeer::currentModifiers;
- ModifierKeys HWNDComponentPeer::modifiersAtLastCallback;
- ComponentPeer* Component::createNewPeer (int styleFlags, void* parentHWND)
- {
- return new HWNDComponentPeer (*this, styleFlags, (HWND) parentHWND, false);
- }
- ComponentPeer* createNonRepaintingEmbeddedWindowsPeer (Component& component, void* parentHWND)
- {
- return new HWNDComponentPeer (component, ComponentPeer::windowIgnoresMouseClicks,
- (HWND) parentHWND, true);
- }
- juce_ImplementSingleton_SingleThreaded (HWNDComponentPeer::WindowClassHolder)
- //==============================================================================
- void ModifierKeys::updateCurrentModifiers() noexcept
- {
- currentModifiers = HWNDComponentPeer::currentModifiers;
- }
- ModifierKeys ModifierKeys::getCurrentModifiersRealtime() noexcept
- {
- HWNDComponentPeer::updateKeyModifiers();
- int mouseMods = 0;
- if (HWNDComponentPeer::isKeyDown (VK_LBUTTON)) mouseMods |= ModifierKeys::leftButtonModifier;
- if (HWNDComponentPeer::isKeyDown (VK_RBUTTON)) mouseMods |= ModifierKeys::rightButtonModifier;
- if (HWNDComponentPeer::isKeyDown (VK_MBUTTON)) mouseMods |= ModifierKeys::middleButtonModifier;
- HWNDComponentPeer::currentModifiers
- = HWNDComponentPeer::currentModifiers.withoutMouseButtons().withFlags (mouseMods);
- return HWNDComponentPeer::currentModifiers;
- }
- //==============================================================================
- bool KeyPress::isKeyCurrentlyDown (const int keyCode)
- {
- SHORT k = (SHORT) keyCode;
- if ((keyCode & extendedKeyModifier) == 0
- && (k >= (SHORT) 'a' && k <= (SHORT) 'z'))
- k += (SHORT) 'A' - (SHORT) 'a';
- const SHORT translatedValues[] = { (SHORT) ',', VK_OEM_COMMA,
- (SHORT) '+', VK_OEM_PLUS,
- (SHORT) '-', VK_OEM_MINUS,
- (SHORT) '.', VK_OEM_PERIOD,
- (SHORT) ';', VK_OEM_1,
- (SHORT) ':', VK_OEM_1,
- (SHORT) '/', VK_OEM_2,
- (SHORT) '?', VK_OEM_2,
- (SHORT) '[', VK_OEM_4,
- (SHORT) ']', VK_OEM_6 };
- for (int i = 0; i < numElementsInArray (translatedValues); i += 2)
- if (k == translatedValues [i])
- k = translatedValues [i + 1];
- return HWNDComponentPeer::isKeyDown (k);
- }
- #if JUCE_MODULE_AVAILABLE_juce_audio_plugin_client
- bool offerKeyMessageToJUCEWindow (MSG& m) { return HWNDComponentPeer::offerKeyMessageToJUCEWindow (m); }
- #endif
- //==============================================================================
- bool JUCE_CALLTYPE Process::isForegroundProcess()
- {
- HWND fg = GetForegroundWindow();
- if (fg == 0)
- return true;
- // when running as a plugin in IE8, the browser UI runs in a different process to the plugin, so
- // process ID isn't a reliable way to check if the foreground window belongs to us - instead, we
- // have to see if any of our windows are children of the foreground window
- fg = GetAncestor (fg, GA_ROOT);
- for (int i = ComponentPeer::getNumPeers(); --i >= 0;)
- if (HWNDComponentPeer* const wp = dynamic_cast<HWNDComponentPeer*> (ComponentPeer::getPeer (i)))
- if (wp->isInside (fg))
- return true;
- return false;
- }
- // N/A on Windows as far as I know.
- void JUCE_CALLTYPE Process::makeForegroundProcess() {}
- void JUCE_CALLTYPE Process::hide() {}
- //==============================================================================
- static BOOL CALLBACK enumAlwaysOnTopWindows (HWND hwnd, LPARAM lParam)
- {
- if (IsWindowVisible (hwnd))
- {
- DWORD processID = 0;
- GetWindowThreadProcessId (hwnd, &processID);
- if (processID == GetCurrentProcessId())
- {
- WINDOWINFO info;
- if (GetWindowInfo (hwnd, &info)
- && (info.dwExStyle & WS_EX_TOPMOST) != 0)
- {
- *reinterpret_cast<bool*> (lParam) = true;
- return FALSE;
- }
- }
- }
- return TRUE;
- }
- bool juce_areThereAnyAlwaysOnTopWindows()
- {
- bool anyAlwaysOnTopFound = false;
- EnumWindows (&enumAlwaysOnTopWindows, (LPARAM) &anyAlwaysOnTopFound);
- return anyAlwaysOnTopFound;
- }
- //==============================================================================
- class WindowsMessageBox : public AsyncUpdater
- {
- public:
- WindowsMessageBox (AlertWindow::AlertIconType iconType,
- const String& boxTitle, const String& m,
- Component* associatedComponent, UINT extraFlags,
- ModalComponentManager::Callback* cb, const bool runAsync)
- : flags (extraFlags | getMessageBoxFlags (iconType)),
- owner (getWindowForMessageBox (associatedComponent)),
- title (boxTitle), message (m), callback (cb)
- {
- if (runAsync)
- triggerAsyncUpdate();
- }
- int getResult() const
- {
- const int r = MessageBox (owner, message.toWideCharPointer(), title.toWideCharPointer(), flags);
- return (r == IDYES || r == IDOK) ? 1 : (r == IDNO ? 2 : 0);
- }
- void handleAsyncUpdate() override
- {
- const int result = getResult();
- if (callback != nullptr)
- callback->modalStateFinished (result);
- delete this;
- }
- private:
- UINT flags;
- HWND owner;
- String title, message;
- ScopedPointer<ModalComponentManager::Callback> callback;
- static UINT getMessageBoxFlags (AlertWindow::AlertIconType iconType) noexcept
- {
- UINT flags = MB_TASKMODAL | MB_SETFOREGROUND;
- switch (iconType)
- {
- case AlertWindow::QuestionIcon: flags |= MB_ICONQUESTION; break;
- case AlertWindow::WarningIcon: flags |= MB_ICONWARNING; break;
- case AlertWindow::InfoIcon: flags |= MB_ICONINFORMATION; break;
- default: break;
- }
- return flags;
- }
- static HWND getWindowForMessageBox (Component* associatedComponent)
- {
- return associatedComponent != nullptr ? (HWND) associatedComponent->getWindowHandle() : 0;
- }
- };
- #if JUCE_MODAL_LOOPS_PERMITTED
- void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType iconType,
- const String& title, const String& message,
- Component* associatedComponent)
- {
- WindowsMessageBox box (iconType, title, message, associatedComponent, MB_OK, 0, false);
- (void) box.getResult();
- }
- #endif
- void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType iconType,
- const String& title, const String& message,
- Component* associatedComponent,
- ModalComponentManager::Callback* callback)
- {
- new WindowsMessageBox (iconType, title, message, associatedComponent, MB_OK, callback, true);
- }
- bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType iconType,
- const String& title, const String& message,
- Component* associatedComponent,
- ModalComponentManager::Callback* callback)
- {
- ScopedPointer<WindowsMessageBox> mb (new WindowsMessageBox (iconType, title, message, associatedComponent,
- MB_OKCANCEL, callback, callback != nullptr));
- if (callback == nullptr)
- return mb->getResult() != 0;
- mb.release();
- return false;
- }
- int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType iconType,
- const String& title, const String& message,
- Component* associatedComponent,
- ModalComponentManager::Callback* callback)
- {
- ScopedPointer<WindowsMessageBox> mb (new WindowsMessageBox (iconType, title, message, associatedComponent,
- MB_YESNOCANCEL, callback, callback != nullptr));
- if (callback == nullptr)
- return mb->getResult();
- mb.release();
- return 0;
- }
- //==============================================================================
- bool MouseInputSource::SourceList::addSource()
- {
- const int numSources = sources.size();
- if (numSources == 0 || canUseMultiTouch())
- {
- addSource (numSources, numSources == 0);
- return true;
- }
- return false;
- }
- Point<float> MouseInputSource::getCurrentRawMousePosition()
- {
- POINT mousePos;
- GetCursorPos (&mousePos);
- return Point<float> ((float) mousePos.x, (float) mousePos.y);
- }
- void MouseInputSource::setRawMousePosition (Point<float> newPosition)
- {
- SetCursorPos (roundToInt (newPosition.x),
- roundToInt (newPosition.y));
- }
- //==============================================================================
- class ScreenSaverDefeater : public Timer
- {
- public:
- ScreenSaverDefeater()
- {
- startTimer (10000);
- timerCallback();
- }
- void timerCallback() override
- {
- if (Process::isForegroundProcess())
- {
- INPUT input = { 0 };
- input.type = INPUT_MOUSE;
- input.mi.mouseData = MOUSEEVENTF_MOVE;
- SendInput (1, &input, sizeof (INPUT));
- }
- }
- };
- static ScopedPointer<ScreenSaverDefeater> screenSaverDefeater;
- void Desktop::setScreenSaverEnabled (const bool isEnabled)
- {
- if (isEnabled)
- screenSaverDefeater = nullptr;
- else if (screenSaverDefeater == nullptr)
- screenSaverDefeater = new ScreenSaverDefeater();
- }
- bool Desktop::isScreenSaverEnabled()
- {
- return screenSaverDefeater == nullptr;
- }
- //==============================================================================
- void LookAndFeel::playAlertSound()
- {
- MessageBeep (MB_OK);
- }
- //==============================================================================
- void SystemClipboard::copyTextToClipboard (const String& text)
- {
- if (OpenClipboard (0) != 0)
- {
- if (EmptyClipboard() != 0)
- {
- const size_t bytesNeeded = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer()) + 4;
- if (bytesNeeded > 0)
- {
- if (HGLOBAL bufH = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT, bytesNeeded + sizeof (WCHAR)))
- {
- if (WCHAR* const data = static_cast<WCHAR*> (GlobalLock (bufH)))
- {
- text.copyToUTF16 (data, bytesNeeded);
- GlobalUnlock (bufH);
- SetClipboardData (CF_UNICODETEXT, bufH);
- }
- }
- }
- }
- CloseClipboard();
- }
- }
- String SystemClipboard::getTextFromClipboard()
- {
- String result;
- if (OpenClipboard (0) != 0)
- {
- if (HANDLE bufH = GetClipboardData (CF_UNICODETEXT))
- {
- if (const WCHAR* const data = (const WCHAR*) GlobalLock (bufH))
- {
- result = String (data, (size_t) (GlobalSize (bufH) / sizeof (WCHAR)));
- GlobalUnlock (bufH);
- }
- }
- CloseClipboard();
- }
- return result;
- }
- //==============================================================================
- void Desktop::setKioskComponent (Component* kioskModeComponent, bool enableOrDisable, bool /*allowMenusAndBars*/)
- {
- if (TopLevelWindow* tlw = dynamic_cast<TopLevelWindow*> (kioskModeComponent))
- tlw->setUsingNativeTitleBar (! enableOrDisable);
- if (enableOrDisable)
- kioskModeComponent->setBounds (getDisplays().getMainDisplay().totalArea);
- }
- //==============================================================================
- struct MonitorInfo
- {
- MonitorInfo (Rectangle<int> rect, bool main, double d) noexcept
- : bounds (rect), dpi (d), isMain (main) {}
- Rectangle<int> bounds;
- double dpi;
- bool isMain;
- };
- static BOOL CALLBACK enumMonitorsProc (HMONITOR hm, HDC, LPRECT r, LPARAM userInfo)
- {
- MONITORINFO info = { 0 };
- info.cbSize = sizeof (info);
- GetMonitorInfo (hm, &info);
- const bool isMain = (info.dwFlags & 1 /* MONITORINFOF_PRIMARY */) != 0;
- double dpi = 0;
- if (getDPIForMonitor != nullptr)
- {
- UINT dpiX = 0, dpiY = 0;
- if (SUCCEEDED (getDPIForMonitor (hm, MDT_Default, &dpiX, &dpiY)))
- dpi = (dpiX + dpiY) / 2.0;
- }
- ((Array<MonitorInfo>*) userInfo)->add (MonitorInfo (rectangleFromRECT (*r), isMain, dpi));
- return TRUE;
- }
- void Desktop::Displays::findDisplays (float masterScale)
- {
- setDPIAwareness();
- Array<MonitorInfo> monitors;
- EnumDisplayMonitors (0, 0, &enumMonitorsProc, (LPARAM) &monitors);
- const double globalDPI = getGlobalDPI();
- if (monitors.size() == 0)
- monitors.add (MonitorInfo (rectangleFromRECT (getWindowRect (GetDesktopWindow())), true, globalDPI));
- // make sure the first in the list is the main monitor
- for (int i = 1; i < monitors.size(); ++i)
- if (monitors.getReference(i).isMain)
- monitors.swap (i, 0);
- RECT workArea;
- SystemParametersInfo (SPI_GETWORKAREA, 0, &workArea, 0);
- for (int i = 0; i < monitors.size(); ++i)
- {
- Display d;
- d.userArea = d.totalArea = monitors.getReference(i).bounds / masterScale;
- d.isMain = monitors.getReference(i).isMain;
- d.dpi = monitors.getReference(i).dpi;
- if (d.dpi == 0)
- {
- d.scale = masterScale;
- d.dpi = globalDPI;
- }
- else
- {
- d.scale = d.dpi / 96.0;
- }
- if (d.isMain)
- d.userArea = d.userArea.getIntersection (rectangleFromRECT (workArea) / masterScale);
- displays.add (d);
- }
- }
- //==============================================================================
- static HICON extractFileHICON (const File& file)
- {
- WORD iconNum = 0;
- WCHAR name [MAX_PATH * 2];
- file.getFullPathName().copyToUTF16 (name, sizeof (name));
- return ExtractAssociatedIcon ((HINSTANCE) Process::getCurrentModuleInstanceHandle(),
- name, &iconNum);
- }
- Image juce_createIconForFile (const File& file)
- {
- Image image;
- if (HICON icon = extractFileHICON (file))
- {
- image = IconConverters::createImageFromHICON (icon);
- DestroyIcon (icon);
- }
- return image;
- }
- //==============================================================================
- void* CustomMouseCursorInfo::create() const
- {
- const int maxW = GetSystemMetrics (SM_CXCURSOR);
- const int maxH = GetSystemMetrics (SM_CYCURSOR);
- Image im (image);
- int hotspotX = hotspot.x;
- int hotspotY = hotspot.y;
- if (im.getWidth() > maxW || im.getHeight() > maxH)
- {
- im = im.rescaled (maxW, maxH);
- hotspotX = (hotspotX * maxW) / image.getWidth();
- hotspotY = (hotspotY * maxH) / image.getHeight();
- }
- return IconConverters::createHICONFromImage (im, FALSE, hotspotX, hotspotY);
- }
- void MouseCursor::deleteMouseCursor (void* const cursorHandle, const bool isStandard)
- {
- if (cursorHandle != nullptr && ! isStandard)
- DestroyCursor ((HCURSOR) cursorHandle);
- }
- enum
- {
- hiddenMouseCursorHandle = 32500 // (arbitrary non-zero value to mark this type of cursor)
- };
- void* MouseCursor::createStandardMouseCursor (const MouseCursor::StandardCursorType type)
- {
- LPCTSTR cursorName = IDC_ARROW;
- switch (type)
- {
- case NormalCursor:
- case ParentCursor: break;
- case NoCursor: return (void*) hiddenMouseCursorHandle;
- case WaitCursor: cursorName = IDC_WAIT; break;
- case IBeamCursor: cursorName = IDC_IBEAM; break;
- case PointingHandCursor: cursorName = MAKEINTRESOURCE(32649); break;
- case CrosshairCursor: cursorName = IDC_CROSS; break;
- case CopyingCursor: break; // can't seem to find one of these in the system list..
- case LeftRightResizeCursor:
- case LeftEdgeResizeCursor:
- case RightEdgeResizeCursor: cursorName = IDC_SIZEWE; break;
- case UpDownResizeCursor:
- case TopEdgeResizeCursor:
- case BottomEdgeResizeCursor: cursorName = IDC_SIZENS; break;
- case TopLeftCornerResizeCursor:
- case BottomRightCornerResizeCursor: cursorName = IDC_SIZENWSE; break;
- case TopRightCornerResizeCursor:
- case BottomLeftCornerResizeCursor: cursorName = IDC_SIZENESW; break;
- case UpDownLeftRightResizeCursor: cursorName = IDC_SIZEALL; break;
- case DraggingHandCursor:
- {
- static void* dragHandCursor = nullptr;
- if (dragHandCursor == nullptr)
- {
- static const unsigned char dragHandData[] =
- { 71,73,70,56,57,97,16,0,16,0,145,2,0,0,0,0,255,255,255,0,0,0,0,0,0,33,249,4,1,0,0,2,0,44,0,0,0,0,16,0,
- 16,0,0,2,52,148,47,0,200,185,16,130,90,12,74,139,107,84,123,39,132,117,151,116,132,146,248,60,209,138,
- 98,22,203,114,34,236,37,52,77,217,247,154,191,119,110,240,193,128,193,95,163,56,60,234,98,135,2,0,59 };
- dragHandCursor = CustomMouseCursorInfo (ImageFileFormat::loadFrom (dragHandData, sizeof (dragHandData)), 8, 7).create();
- }
- return dragHandCursor;
- }
- default:
- jassertfalse; break;
- }
- HCURSOR cursorH = LoadCursor (0, cursorName);
- if (cursorH == 0)
- cursorH = LoadCursor (0, IDC_ARROW);
- return cursorH;
- }
- //==============================================================================
- void MouseCursor::showInWindow (ComponentPeer*) const
- {
- HCURSOR c = (HCURSOR) getHandle();
- if (c == 0)
- c = LoadCursor (0, IDC_ARROW);
- else if (c == (HCURSOR) hiddenMouseCursorHandle)
- c = 0;
- SetCursor (c);
- }
- void MouseCursor::showInAllWindows() const
- {
- showInWindow (nullptr);
- }
|