1 // Scintilla source code edit control
2 /** @file ScintillaWin.cxx
3 ** Windows specific subclass of ScintillaBase.
5 // Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
24 #define _WIN32_WINNT 0x0500
34 #if defined(NTDDI_WIN7) && !defined(DISABLE_D2D)
46 #include "Scintilla.h"
51 #include "StringCopy.h"
53 #include "LexerModule.h"
55 #include "SplitVector.h"
56 #include "Partitioning.h"
57 #include "RunStyles.h"
58 #include "ContractionState.h"
59 #include "CellBuffer.h"
62 #include "Indicator.h"
64 #include "LineMarker.h"
66 #include "ViewStyle.h"
67 #include "CharClassify.h"
68 #include "Decoration.h"
69 #include "CaseFolder.h"
71 #include "CaseConvert.h"
72 #include "UniConversion.h"
73 #include "Selection.h"
74 #include "PositionCache.h"
75 #include "EditModel.h"
76 #include "MarginView.h"
80 #include "AutoComplete.h"
81 #include "ScintillaBase.h"
84 #include "ExternalLexer.h"
90 #ifndef SPI_GETWHEELSCROLLLINES
91 #define SPI_GETWHEELSCROLLLINES 104
95 #define WM_UNICHAR 0x0109
98 #ifndef UNICODE_NOCHAR
99 #define UNICODE_NOCHAR 0xFFFF
106 #define SC_WIN_IDLE 5001
108 #define SC_INDICATOR_INPUT INDIC_IME
109 #define SC_INDICATOR_TARGET INDIC_IME+1
110 #define SC_INDICATOR_CONVERTED INDIC_IME+2
111 #define SC_INDICATOR_UNKNOWN INDIC_IME_MAX
113 typedef BOOL (WINAPI
*TrackMouseEventSig
)(LPTRACKMOUSEEVENT
);
114 typedef UINT_PTR (WINAPI
*SetCoalescableTimerSig
)(HWND hwnd
, UINT_PTR nIDEvent
,
115 UINT uElapse
, TIMERPROC lpTimerFunc
, ULONG uToleranceDelay
);
117 // GCC has trouble with the standard COM ABI so do it the old C way with explicit vtables.
119 const TCHAR callClassName
[] = TEXT("CallTip");
122 using namespace Scintilla
;
125 static void *PointerFromWindow(HWND hWnd
) {
126 return reinterpret_cast<void *>(::GetWindowLongPtr(hWnd
, 0));
129 static void SetWindowPointer(HWND hWnd
, void *ptr
) {
130 ::SetWindowLongPtr(hWnd
, 0, reinterpret_cast<LONG_PTR
>(ptr
));
133 static void SetWindowID(HWND hWnd
, int identifier
) {
134 ::SetWindowLongPtr(hWnd
, GWLP_ID
, identifier
);
137 static Point
PointFromPOINT(POINT pt
) {
138 return Point::FromInts(pt
.x
, pt
.y
);
141 class ScintillaWin
; // Forward declaration for COM interface subobjects
143 typedef void VFunction(void);
145 static HMODULE commctrl32
= 0;
149 class FormatEnumerator
{
154 std::vector
<CLIPFORMAT
> formats
;
155 FormatEnumerator(int pos_
, CLIPFORMAT formats_
[], size_t formatsLen_
);
188 public ScintillaBase
{
190 bool lastKeyDownConsumed
;
193 bool trackedMouseLeave
;
194 TrackMouseEventSig TrackMouseEventFn
;
195 SetCoalescableTimerSig SetCoalescableTimerFn
;
197 unsigned int linesPerScroll
; ///< Intellimouse support
198 int wheelDelta
; ///< Wheel delta from roll
204 CLIPFORMAT cfColumnSelect
;
205 CLIPFORMAT cfBorlandIDEBlockType
;
206 CLIPFORMAT cfLineSelect
;
207 CLIPFORMAT cfVSLineTag
;
214 static HINSTANCE hInstance
;
215 static ATOM scintillaClassAtom
;
216 static ATOM callClassAtom
;
219 ID2D1RenderTarget
*pRenderTarget
;
220 bool renderTargetValid
;
223 explicit ScintillaWin(HWND hwnd
);
224 ScintillaWin(const ScintillaWin
&);
225 virtual ~ScintillaWin();
226 ScintillaWin
&operator=(const ScintillaWin
&);
228 virtual void Initialise();
229 virtual void Finalise();
231 void EnsureRenderTarget(HDC hdc
);
232 void DropRenderTarget();
236 static sptr_t
DirectFunction(
237 sptr_t ptr
, UINT iMessage
, uptr_t wParam
, sptr_t lParam
);
238 static sptr_t PASCAL
SWndProc(
239 HWND hWnd
, UINT iMessage
, WPARAM wParam
, sptr_t lParam
);
240 static sptr_t PASCAL
CTWndProc(
241 HWND hWnd
, UINT iMessage
, WPARAM wParam
, sptr_t lParam
);
243 enum { invalidTimerID
, standardTimerID
, idleTimerID
, fineTimerStart
};
245 virtual bool DragThreshold(Point ptStart
, Point ptNow
);
246 virtual void StartDrag();
247 int TargetAsUTF8(char *text
);
248 int EncodedFromUTF8(char *utf8
, char *encoded
) const;
249 sptr_t
WndPaint(uptr_t wParam
);
251 sptr_t
HandleCompositionWindowed(uptr_t wParam
, sptr_t lParam
);
252 sptr_t
HandleCompositionInline(uptr_t wParam
, sptr_t lParam
);
253 static bool KoreanIME();
254 void MoveImeCarets(int offset
);
255 void DrawImeIndicator(int indicator
, int len
);
256 void SetCandidateWindowPos();
257 void SelectionToHangul();
261 UINT
CodePageOfDocument() const;
262 virtual bool ValidCodePage(int codePage
) const;
263 virtual sptr_t
DefWndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
264 virtual bool SetIdle(bool on
);
265 UINT_PTR timers
[tickDwell
+1];
266 virtual bool FineTickerAvailable();
267 virtual bool FineTickerRunning(TickReason reason
);
268 virtual void FineTickerStart(TickReason reason
, int millis
, int tolerance
);
269 virtual void FineTickerCancel(TickReason reason
);
270 virtual void SetMouseCapture(bool on
);
271 virtual bool HaveMouseCapture();
272 virtual void SetTrackMouseLeaveEvent(bool on
);
273 virtual bool PaintContains(PRectangle rc
);
274 virtual void ScrollText(int linesToMove
);
275 virtual void UpdateSystemCaret();
276 virtual void SetVerticalScrollPos();
277 virtual void SetHorizontalScrollPos();
278 virtual bool ModifyScrollBars(int nMax
, int nPage
);
279 virtual void NotifyChange();
280 virtual void NotifyFocus(bool focus
);
281 virtual void SetCtrlID(int identifier
);
282 virtual int GetCtrlID();
283 virtual void NotifyParent(SCNotification scn
);
284 virtual void NotifyDoubleClick(Point pt
, int modifiers
);
285 virtual CaseFolder
*CaseFolderForEncoding();
286 virtual std::string
CaseMapString(const std::string
&s
, int caseMapping
);
288 virtual void CopyAllowLine();
289 virtual bool CanPaste();
290 virtual void Paste();
291 virtual void CreateCallTipWindow(PRectangle rc
);
292 virtual void AddToPopUp(const char *label
, int cmd
= 0, bool enabled
= true);
293 virtual void ClaimSelection();
296 void ImeStartComposition();
297 void ImeEndComposition();
299 void GetIntelliMouseParameters();
300 virtual void CopyToClipboard(const SelectionText
&selectedText
);
301 void ScrollMessage(WPARAM wParam
);
302 void HorizontalScrollMessage(WPARAM wParam
);
304 void FullPaintDC(HDC dc
);
305 bool IsCompatibleDC(HDC dc
);
306 DWORD
EffectFromState(DWORD grfKeyState
) const;
308 virtual int SetScrollInfo(int nBar
, LPCSCROLLINFO lpsi
, BOOL bRedraw
);
309 virtual bool GetScrollInfo(int nBar
, LPSCROLLINFO lpsi
);
310 void ChangeScrollPos(int barType
, int pos
);
311 sptr_t
GetTextLength();
312 sptr_t
GetText(uptr_t wParam
, sptr_t lParam
);
315 // Public for benefit of Scintilla_DirectFunction
316 virtual sptr_t
WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
318 /// Implement IUnknown
319 STDMETHODIMP
QueryInterface(REFIID riid
, PVOID
*ppv
);
320 STDMETHODIMP_(ULONG
)AddRef();
321 STDMETHODIMP_(ULONG
)Release();
323 /// Implement IDropTarget
324 STDMETHODIMP
DragEnter(LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
325 POINTL pt
, PDWORD pdwEffect
);
326 STDMETHODIMP
DragOver(DWORD grfKeyState
, POINTL pt
, PDWORD pdwEffect
);
327 STDMETHODIMP
DragLeave();
328 STDMETHODIMP
Drop(LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
329 POINTL pt
, PDWORD pdwEffect
);
331 /// Implement important part of IDataObject
332 STDMETHODIMP
GetData(FORMATETC
*pFEIn
, STGMEDIUM
*pSTM
);
334 static bool Register(HINSTANCE hInstance_
);
335 static bool Unregister();
337 friend class DropSource
;
338 friend class DataObject
;
339 friend class DropTarget
;
340 bool DragIsRectangularOK(CLIPFORMAT fmt
) const {
341 return drag
.rectangular
&& (fmt
== cfColumnSelect
);
345 // For use in creating a system caret
346 bool HasCaretSizeChanged() const;
347 BOOL
CreateSystemCaret();
348 BOOL
DestroySystemCaret();
349 HBITMAP sysCaretBitmap
;
354 HINSTANCE
ScintillaWin::hInstance
= 0;
355 ATOM
ScintillaWin::scintillaClassAtom
= 0;
356 ATOM
ScintillaWin::callClassAtom
= 0;
358 ScintillaWin::ScintillaWin(HWND hwnd
) {
360 lastKeyDownConsumed
= false;
362 capturedMouse
= false;
363 trackedMouseLeave
= false;
364 TrackMouseEventFn
= 0;
365 SetCoalescableTimerFn
= 0;
368 wheelDelta
= 0; // Wheel delta from roll
374 // There does not seem to be a real standard for indicating that the clipboard
375 // contains a rectangular selection, so copy Developer Studio and Borland Delphi.
376 cfColumnSelect
= static_cast<CLIPFORMAT
>(
377 ::RegisterClipboardFormat(TEXT("MSDEVColumnSelect")));
378 cfBorlandIDEBlockType
= static_cast<CLIPFORMAT
>(
379 ::RegisterClipboardFormat(TEXT("Borland IDE Block Type")));
381 // Likewise for line-copy (copies a full line when no text is selected)
382 cfLineSelect
= static_cast<CLIPFORMAT
>(
383 ::RegisterClipboardFormat(TEXT("MSDEVLineSelect")));
384 cfVSLineTag
= static_cast<CLIPFORMAT
>(
385 ::RegisterClipboardFormat(TEXT("VisualStudioEditorOperationsLineCutCopyClipboardTag")));
400 renderTargetValid
= true;
403 caret
.period
= ::GetCaretBlinkTime();
404 if (caret
.period
< 0)
410 ScintillaWin::~ScintillaWin() {}
412 void ScintillaWin::Initialise() {
413 // Initialize COM. If the app has already done this it will have
414 // no effect. If the app hasn't, we really shouldn't ask them to call
415 // it just so this internal feature works.
416 hrOle
= ::OleInitialize(NULL
);
418 // Find TrackMouseEvent which is available on Windows > 95
419 HMODULE user32
= ::GetModuleHandle(TEXT("user32.dll"));
421 TrackMouseEventFn
= (TrackMouseEventSig
)::GetProcAddress(user32
, "TrackMouseEvent");
422 SetCoalescableTimerFn
= (SetCoalescableTimerSig
)::GetProcAddress(user32
, "SetCoalescableTimer");
424 if (TrackMouseEventFn
== NULL
) {
425 // Windows 95 has an emulation in comctl32.dll:_TrackMouseEvent
427 commctrl32
= ::LoadLibrary(TEXT("comctl32.dll"));
428 if (commctrl32
!= NULL
) {
429 TrackMouseEventFn
= (TrackMouseEventSig
)
430 ::GetProcAddress(commctrl32
, "_TrackMouseEvent");
433 for (TickReason tr
= tickCaret
; tr
<= tickDwell
; tr
= static_cast<TickReason
>(tr
+ 1)) {
436 vs
.indicators
[SC_INDICATOR_UNKNOWN
] = Indicator(INDIC_HIDDEN
, ColourDesired(0, 0, 0xff));
437 vs
.indicators
[SC_INDICATOR_INPUT
] = Indicator(INDIC_DOTS
, ColourDesired(0, 0, 0xff));
438 vs
.indicators
[SC_INDICATOR_CONVERTED
] = Indicator(INDIC_COMPOSITIONTHICK
, ColourDesired(0, 0, 0xff));
439 vs
.indicators
[SC_INDICATOR_TARGET
] = Indicator(INDIC_STRAIGHTBOX
, ColourDesired(0, 0, 0xff));
442 void ScintillaWin::Finalise() {
443 ScintillaBase::Finalise();
444 for (TickReason tr
= tickCaret
; tr
<= tickDwell
; tr
= static_cast<TickReason
>(tr
+ 1)) {
445 FineTickerCancel(tr
);
451 ::RevokeDragDrop(MainHWND());
452 if (SUCCEEDED(hrOle
)) {
459 void ScintillaWin::EnsureRenderTarget(HDC hdc
) {
460 if (!renderTargetValid
) {
462 renderTargetValid
= true;
464 if (pD2DFactory
&& !pRenderTarget
) {
466 HWND hw
= MainHWND();
467 GetClientRect(hw
, &rc
);
469 D2D1_SIZE_U size
= D2D1::SizeU(rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
471 // Create a Direct2D render target.
473 D2D1_RENDER_TARGET_PROPERTIES drtp
;
474 drtp
.type
= D2D1_RENDER_TARGET_TYPE_DEFAULT
;
475 drtp
.pixelFormat
.format
= DXGI_FORMAT_UNKNOWN
;
476 drtp
.pixelFormat
.alphaMode
= D2D1_ALPHA_MODE_UNKNOWN
;
479 drtp
.usage
= D2D1_RENDER_TARGET_USAGE_NONE
;
480 drtp
.minLevel
= D2D1_FEATURE_LEVEL_DEFAULT
;
482 if (technology
== SC_TECHNOLOGY_DIRECTWRITEDC
) {
483 // Explicit pixel format needed.
484 drtp
.pixelFormat
= D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM
,
485 D2D1_ALPHA_MODE_IGNORE
);
487 ID2D1DCRenderTarget
*pDCRT
= NULL
;
488 HRESULT hr
= pD2DFactory
->CreateDCRenderTarget(&drtp
, &pDCRT
);
490 pRenderTarget
= pDCRT
;
492 Platform::DebugPrintf("Failed CreateDCRenderTarget 0x%x\n", hr
);
493 pRenderTarget
= NULL
;
497 D2D1_HWND_RENDER_TARGET_PROPERTIES dhrtp
;
499 dhrtp
.pixelSize
= size
;
500 dhrtp
.presentOptions
= (technology
== SC_TECHNOLOGY_DIRECTWRITERETAIN
) ?
501 D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS
: D2D1_PRESENT_OPTIONS_NONE
;
503 ID2D1HwndRenderTarget
*pHwndRenderTarget
= NULL
;
504 HRESULT hr
= pD2DFactory
->CreateHwndRenderTarget(drtp
, dhrtp
, &pHwndRenderTarget
);
506 pRenderTarget
= pHwndRenderTarget
;
508 Platform::DebugPrintf("Failed CreateHwndRenderTarget 0x%x\n", hr
);
509 pRenderTarget
= NULL
;
513 pD2DFactory
->CreateHwndRenderTarget(
514 D2D1::RenderTargetProperties(
515 D2D1_RENDER_TARGET_TYPE_DEFAULT
,
516 D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM
, D2D1_ALPHA_MODE_PREMULTIPLIED
),
517 96.0f
, 96.0f
, D2D1_RENDER_TARGET_USAGE_NONE
, D2D1_FEATURE_LEVEL_DEFAULT
),
518 D2D1::HwndRenderTargetProperties(hw
, size
),
521 // Pixmaps were created to be compatible with previous render target so
522 // need to be recreated.
526 if ((technology
== SC_TECHNOLOGY_DIRECTWRITEDC
) && pRenderTarget
) {
528 GetClientRect(MainHWND(), &rcWindow
);
529 HRESULT hr
= static_cast<ID2D1DCRenderTarget
*>(pRenderTarget
)->BindDC(hdc
, &rcWindow
);
531 Platform::DebugPrintf("BindDC failed 0x%x\n", hr
);
537 void ScintillaWin::DropRenderTarget() {
539 pRenderTarget
->Release();
546 HWND
ScintillaWin::MainHWND() {
547 return reinterpret_cast<HWND
>(wMain
.GetID());
550 bool ScintillaWin::DragThreshold(Point ptStart
, Point ptNow
) {
551 int xMove
= static_cast<int>(std::abs(ptStart
.x
- ptNow
.x
));
552 int yMove
= static_cast<int>(std::abs(ptStart
.y
- ptNow
.y
));
553 return (xMove
> ::GetSystemMetrics(SM_CXDRAG
)) ||
554 (yMove
> ::GetSystemMetrics(SM_CYDRAG
));
557 void ScintillaWin::StartDrag() {
558 inDragDrop
= ddDragging
;
560 dropWentOutside
= true;
561 IDataObject
*pDataObject
= reinterpret_cast<IDataObject
*>(&dob
);
562 IDropSource
*pDropSource
= reinterpret_cast<IDropSource
*>(&ds
);
563 //Platform::DebugPrintf("About to DoDragDrop %x %x\n", pDataObject, pDropSource);
564 HRESULT hr
= ::DoDragDrop(
567 DROPEFFECT_COPY
| DROPEFFECT_MOVE
, &dwEffect
);
568 //Platform::DebugPrintf("DoDragDrop = %x\n", hr);
570 if ((hr
== DRAGDROP_S_DROP
) && (dwEffect
== DROPEFFECT_MOVE
) && dropWentOutside
) {
571 // Remove dragged out text
576 SetDragPosition(SelectionPosition(invalidPosition
));
579 // Avoid warnings everywhere for old style casts by concentrating them here
580 static WORD
LoWord(uptr_t l
) {
584 static WORD
HiWord(uptr_t l
) {
588 static int InputCodePage() {
589 HKL inputLocale
= ::GetKeyboardLayout(0);
590 LANGID inputLang
= LOWORD(inputLocale
);
592 int res
= ::GetLocaleInfoA(MAKELCID(inputLang
, SORT_DEFAULT
),
593 LOCALE_IDEFAULTANSICODEPAGE
, sCodePage
, sizeof(sCodePage
));
596 return atoi(sCodePage
);
599 /** Map the key codes to their equivalent SCK_ form. */
600 static int KeyTranslate(int keyIn
) {
601 //PLATFORM_ASSERT(!keyIn);
603 case VK_DOWN
: return SCK_DOWN
;
604 case VK_UP
: return SCK_UP
;
605 case VK_LEFT
: return SCK_LEFT
;
606 case VK_RIGHT
: return SCK_RIGHT
;
607 case VK_HOME
: return SCK_HOME
;
608 case VK_END
: return SCK_END
;
609 case VK_PRIOR
: return SCK_PRIOR
;
610 case VK_NEXT
: return SCK_NEXT
;
611 case VK_DELETE
: return SCK_DELETE
;
612 case VK_INSERT
: return SCK_INSERT
;
613 case VK_ESCAPE
: return SCK_ESCAPE
;
614 case VK_BACK
: return SCK_BACK
;
615 case VK_TAB
: return SCK_TAB
;
616 case VK_RETURN
: return SCK_RETURN
;
617 case VK_ADD
: return SCK_ADD
;
618 case VK_SUBTRACT
: return SCK_SUBTRACT
;
619 case VK_DIVIDE
: return SCK_DIVIDE
;
620 case VK_LWIN
: return SCK_WIN
;
621 case VK_RWIN
: return SCK_RWIN
;
622 case VK_APPS
: return SCK_MENU
;
623 case VK_OEM_2
: return '/';
624 case VK_OEM_3
: return '`';
625 case VK_OEM_4
: return '[';
626 case VK_OEM_5
: return '\\';
627 case VK_OEM_6
: return ']';
628 default: return keyIn
;
632 static bool BoundsContains(PRectangle rcBounds
, HRGN hRgnBounds
, PRectangle rcCheck
) {
633 bool contains
= true;
634 if (!rcCheck
.Empty()) {
635 if (!rcBounds
.Contains(rcCheck
)) {
637 } else if (hRgnBounds
) {
638 // In bounding rectangle so check more accurately using region
639 HRGN hRgnCheck
= ::CreateRectRgn(static_cast<int>(rcCheck
.left
), static_cast<int>(rcCheck
.top
),
640 static_cast<int>(rcCheck
.right
), static_cast<int>(rcCheck
.bottom
));
642 HRGN hRgnDifference
= ::CreateRectRgn(0, 0, 0, 0);
643 if (hRgnDifference
) {
644 int combination
= ::CombineRgn(hRgnDifference
, hRgnCheck
, hRgnBounds
, RGN_DIFF
);
645 if (combination
!= NULLREGION
) {
648 ::DeleteRgn(hRgnDifference
);
650 ::DeleteRgn(hRgnCheck
);
657 // Returns the target converted to UTF8.
658 // Return the length in bytes.
659 int ScintillaWin::TargetAsUTF8(char *text
) {
660 int targetLength
= targetEnd
- targetStart
;
661 if (IsUnicodeMode()) {
663 pdoc
->GetCharRange(text
, targetStart
, targetLength
);
667 std::string s
= RangeText(targetStart
, targetEnd
);
668 int charsLen
= ::MultiByteToWideChar(CodePageOfDocument(), 0, &s
[0], targetLength
, NULL
, 0);
669 std::wstring
characters(charsLen
, '\0');
670 ::MultiByteToWideChar(CodePageOfDocument(), 0, &s
[0], targetLength
, &characters
[0], charsLen
);
672 int utf8Len
= ::WideCharToMultiByte(CP_UTF8
, 0, &characters
[0], charsLen
, NULL
, 0, 0, 0);
674 ::WideCharToMultiByte(CP_UTF8
, 0, &characters
[0], charsLen
, text
, utf8Len
, 0, 0);
675 text
[utf8Len
] = '\0';
682 // Translates a nul terminated UTF8 string into the document encoding.
683 // Return the length of the result in bytes.
684 int ScintillaWin::EncodedFromUTF8(char *utf8
, char *encoded
) const {
685 int inputLength
= (lengthForEncode
>= 0) ? lengthForEncode
: static_cast<int>(strlen(utf8
));
686 if (IsUnicodeMode()) {
688 memcpy(encoded
, utf8
, inputLength
);
693 int charsLen
= ::MultiByteToWideChar(CP_UTF8
, 0, utf8
, inputLength
, NULL
, 0);
694 std::wstring
characters(charsLen
, '\0');
695 ::MultiByteToWideChar(CP_UTF8
, 0, utf8
, inputLength
, &characters
[0], charsLen
);
697 int encodedLen
= ::WideCharToMultiByte(CodePageOfDocument(),
698 0, &characters
[0], charsLen
, NULL
, 0, 0, 0);
700 ::WideCharToMultiByte(CodePageOfDocument(), 0, &characters
[0], charsLen
, encoded
, encodedLen
, 0, 0);
701 encoded
[encodedLen
] = '\0';
707 LRESULT
ScintillaWin::WndPaint(uptr_t wParam
) {
710 // Redirect assertions to debug output and save current state
711 bool assertsPopup
= Platform::ShowAssertionPopUps(false);
712 paintState
= painting
;
716 bool IsOcxCtrl
= (wParam
!= 0); // if wParam != 0, it contains
717 // a PAINSTRUCT* from the OCX
718 // Removed since this interferes with reporting other assertions as it occurs repeatedly
719 //PLATFORM_ASSERT(hRgnUpdate == NULL);
720 hRgnUpdate
= ::CreateRectRgn(0, 0, 0, 0);
722 pps
= reinterpret_cast<PAINTSTRUCT
*>(wParam
);
724 ::GetUpdateRgn(MainHWND(), hRgnUpdate
, FALSE
);
726 ::BeginPaint(MainHWND(), pps
);
728 rcPaint
= PRectangle::FromInts(pps
->rcPaint
.left
, pps
->rcPaint
.top
, pps
->rcPaint
.right
, pps
->rcPaint
.bottom
);
729 PRectangle rcClient
= GetClientRectangle();
730 paintingAllText
= BoundsContains(rcPaint
, hRgnUpdate
, rcClient
);
731 if (technology
== SC_TECHNOLOGY_DEFAULT
) {
732 AutoSurface
surfaceWindow(pps
->hdc
, this);
734 Paint(surfaceWindow
, rcPaint
);
735 surfaceWindow
->Release();
739 EnsureRenderTarget(pps
->hdc
);
740 AutoSurface
surfaceWindow(pRenderTarget
, this);
742 pRenderTarget
->BeginDraw();
743 Paint(surfaceWindow
, rcPaint
);
744 surfaceWindow
->Release();
745 HRESULT hr
= pRenderTarget
->EndDraw();
746 if (hr
== D2DERR_RECREATE_TARGET
) {
748 paintState
= paintAbandoned
;
754 ::DeleteRgn(hRgnUpdate
);
759 ::EndPaint(MainHWND(), pps
);
760 if (paintState
== paintAbandoned
) {
761 // Painting area was insufficient to cover new styling or brace highlight positions
763 FullPaintDC(pps
->hdc
);
768 paintState
= notPainting
;
770 // Restore debug output state
771 Platform::ShowAssertionPopUps(assertsPopup
);
773 //Platform::DebugPrintf("Paint took %g\n", et.Duration());
777 sptr_t
ScintillaWin::HandleCompositionWindowed(uptr_t wParam
, sptr_t lParam
) {
778 if (lParam
& GCS_RESULTSTR
) {
779 HIMC hIMC
= ::ImmGetContext(MainHWND());
781 wchar_t wcs
[maxLenInputIME
];
782 LONG bytes
= ::ImmGetCompositionStringW(hIMC
,
783 GCS_RESULTSTR
, wcs
, (maxLenInputIME
-1)*2);
784 int wides
= bytes
/ 2;
785 if (IsUnicodeMode()) {
786 char utfval
[maxLenInputIME
* 3];
787 unsigned int len
= UTF8Length(wcs
, wides
);
788 UTF8FromUTF16(wcs
, wides
, utfval
, len
);
790 AddCharUTF(utfval
, len
);
792 char dbcsval
[maxLenInputIME
* 2];
793 int size
= ::WideCharToMultiByte(InputCodePage(),
794 0, wcs
, wides
, dbcsval
, sizeof(dbcsval
) - 1, 0, 0);
795 for (int i
=0; i
<size
; i
++) {
799 // Set new position after converted
800 Point pos
= PointMainCaret();
801 COMPOSITIONFORM CompForm
;
802 CompForm
.dwStyle
= CFS_POINT
;
803 CompForm
.ptCurrentPos
.x
= static_cast<int>(pos
.x
);
804 CompForm
.ptCurrentPos
.y
= static_cast<int>(pos
.y
);
805 ::ImmSetCompositionWindow(hIMC
, &CompForm
);
806 ::ImmReleaseContext(MainHWND(), hIMC
);
810 return ::DefWindowProc(MainHWND(), WM_IME_COMPOSITION
, wParam
, lParam
);
813 bool ScintillaWin::KoreanIME() {
814 const int codePage
= InputCodePage();
815 return codePage
== 949 || codePage
== 1361;
818 void ScintillaWin::MoveImeCarets(int offset
) {
819 // Move carets relatively by bytes.
820 for (size_t r
=0; r
<sel
.Count(); r
++) {
821 int positionInsert
= sel
.Range(r
).Start().Position();
822 sel
.Range(r
).caret
.SetPosition(positionInsert
+ offset
);
823 sel
.Range(r
).anchor
.SetPosition(positionInsert
+ offset
);
827 void ScintillaWin::DrawImeIndicator(int indicator
, int len
) {
828 // Emulate the visual style of IME characters with indicators.
829 // Draw an indicator on the character before caret by the character bytes of len
830 // so it should be called after addCharUTF().
831 // It does not affect caret positions.
832 if (indicator
< 8 || indicator
> INDIC_MAX
) {
835 pdoc
->decorations
.SetCurrentIndicator(indicator
);
836 for (size_t r
=0; r
<sel
.Count(); r
++) {
837 int positionInsert
= sel
.Range(r
).Start().Position();
838 pdoc
->DecorationFillRange(positionInsert
- len
, 1, len
);
842 void ScintillaWin::SetCandidateWindowPos() {
843 HIMC hIMC
= ::ImmGetContext(MainHWND());
845 Point pos
= PointMainCaret();
846 CANDIDATEFORM CandForm
;
847 CandForm
.dwIndex
= 0;
848 CandForm
.dwStyle
= CFS_CANDIDATEPOS
;
849 CandForm
.ptCurrentPos
.x
= static_cast<int>(pos
.x
);
850 CandForm
.ptCurrentPos
.y
= static_cast<int>(pos
.y
+ vs
.lineHeight
);
851 ::ImmSetCandidateWindow(hIMC
, &CandForm
);
852 ::ImmReleaseContext(MainHWND(), hIMC
);
856 static std::string
StringEncode(std::wstring s
, int codePage
) {
858 int cchMulti
= ::WideCharToMultiByte(codePage
, 0, s
.c_str(), static_cast<int>(s
.length()), NULL
, 0, NULL
, NULL
);
859 std::string
sMulti(cchMulti
, 0);
860 ::WideCharToMultiByte(codePage
, 0, s
.c_str(), static_cast<int>(s
.size()), &sMulti
[0], cchMulti
, NULL
, NULL
);
863 return std::string();
867 static std::wstring
StringDecode(std::string s
, int codePage
) {
869 int cchWide
= ::MultiByteToWideChar(codePage
, 0, s
.c_str(), static_cast<int>(s
.length()), NULL
, 0);
870 std::wstring
sWide(cchWide
, 0);
871 ::MultiByteToWideChar(codePage
, 0, s
.c_str(), static_cast<int>(s
.length()), &sWide
[0], cchWide
);
874 return std::wstring();
878 void ScintillaWin::SelectionToHangul() {
879 // Convert every hanja to hangul within the main range.
880 const int selStart
= sel
.RangeMain().Start().Position();
881 const int documentStrLen
= sel
.RangeMain().Length();
882 const int selEnd
= selStart
+ documentStrLen
;
883 const int utf16Len
= pdoc
->CountUTF16(selStart
, selEnd
);
886 std::string
documentStr(documentStrLen
, '\0');
887 pdoc
->GetCharRange(&documentStr
[0], selStart
, documentStrLen
);
889 std::wstring uniStr
= StringDecode(documentStr
, CodePageOfDocument());
890 int converted
= HanjaDict::GetHangulOfHanja(&uniStr
[0]);
891 documentStr
= StringEncode(uniStr
, CodePageOfDocument());
894 pdoc
->BeginUndoAction();
896 InsertPaste(&documentStr
[0], static_cast<int>(documentStr
.size()));
897 pdoc
->EndUndoAction();
902 void ScintillaWin::EscapeHanja() {
903 // The candidate box pops up to user to select a hanja.
904 // It comes into WM_IME_COMPOSITION with GCS_RESULTSTR.
905 // The existing hangul or hanja is replaced with it.
906 if (sel
.Count() > 1) {
907 return; // Do not allow multi carets.
909 int currentPos
= CurrentPosition();
910 int oneCharLen
= pdoc
->LenChar(currentPos
);
912 if (oneCharLen
< 2) {
913 return; // No need to handle SBCS.
916 // ImmEscapeW() may overwrite uniChar[] with a null terminated string.
917 // So enlarge it enough to Maximum 4 as in UTF-8.
918 unsigned int const safeLength
= UTF8MaxBytes
+1;
919 std::string
oneChar(safeLength
, '\0');
920 pdoc
->GetCharRange(&oneChar
[0], currentPos
, oneCharLen
);
922 std::wstring uniChar
= StringDecode(oneChar
, CodePageOfDocument());
924 HIMC hIMC
=ImmGetContext(MainHWND());
926 // Set the candidate box position since IME may show it.
927 SetCandidateWindowPos();
928 // IME_ESC_HANJA_MODE appears to receive the first character only.
929 if (ImmEscapeW(GetKeyboardLayout(0), hIMC
, IME_ESC_HANJA_MODE
, &uniChar
[0])) {
930 SetSelection (currentPos
, currentPos
+ oneCharLen
);
932 ::ImmReleaseContext(MainHWND(), hIMC
);
936 void ScintillaWin::ToggleHanja() {
937 // If selection, convert every hanja to hangul within the main range.
938 // If no selection, commit to IME.
939 if (sel
.Count() > 1) {
940 return; // Do not allow multi carets.
950 sptr_t
ScintillaWin::HandleCompositionInline(uptr_t
, sptr_t lParam
) {
951 // Copy & paste by johnsonj with a lot of helps of Neil.
952 // Great thanks for my foreruners, jiniya and BLUEnLIVE.
954 HIMC hIMC
= ::ImmGetContext(MainHWND());
959 if (pdoc
->TentativeActive()) {
960 pdoc
->TentativeUndo();
962 // No tentative undo means start of this composition so
963 // fill in any virtual spaces.
967 view
.imeCaretBlockOverride
= false;
969 if (lParam
& GCS_COMPSTR
) {
970 wchar_t wcs
[maxLenInputIME
] = { 0 };
971 long bytes
= ::ImmGetCompositionStringW
972 (hIMC
, GCS_COMPSTR
, wcs
, maxLenInputIME
);
973 unsigned int wcsLen
= bytes
/ 2;
975 if ((wcsLen
== 0) || (wcsLen
>= maxLenInputIME
)) {
976 ShowCaretAtCurrentPosition();
977 ::ImmReleaseContext(MainHWND(), hIMC
);
981 pdoc
->TentativeStart(); // TentativeActive from now on.
983 // Get attribute information from composition string.
984 BYTE compAttr
[maxLenInputIME
] = { 0 };
985 unsigned int imeCursorPos
= 0;
987 if (lParam
& GCS_COMPATTR
) {
988 ImmGetCompositionStringW(hIMC
, GCS_COMPATTR
, compAttr
, sizeof(compAttr
));
990 if (lParam
& GCS_CURSORPOS
) {
991 imeCursorPos
= ImmGetCompositionStringW(hIMC
, GCS_CURSORPOS
, NULL
, 0);
994 // Display character by character.
996 int imeCharPos
[maxLenInputIME
+ 1] = { 0 };
998 bool tmpRecordingMacro
= recordingMacro
;
999 recordingMacro
= false;
1000 for (size_t i
= 0; i
< wcsLen
; ) {
1001 const size_t ucWidth
= UTF16CharLength(wcs
[i
]);
1002 const std::wstring
uniChar(wcs
+i
, ucWidth
);
1003 char oneChar
[UTF8MaxBytes
+ 1] = "\0\0\0\0"; // Maximum 4 bytes in utf8
1004 unsigned int oneCharLen
= 0;
1006 if (IsUnicodeMode()) {
1007 oneCharLen
= UTF8Length(uniChar
.c_str(), static_cast<unsigned int>(uniChar
.length()));
1008 UTF8FromUTF16(uniChar
.c_str(), static_cast<unsigned int>(uniChar
.length()), oneChar
, oneCharLen
);
1010 oneCharLen
= ::WideCharToMultiByte(InputCodePage(), 0,
1011 uniChar
.c_str(), static_cast<unsigned int>(uniChar
.length()), oneChar
, sizeof(oneChar
)-1, 0, 0);
1013 oneChar
[oneCharLen
] = '\0';
1015 // Display a character.
1016 AddCharUTF(oneChar
, oneCharLen
);
1018 // Record compstr character positions for moving IME carets.
1019 numBytes
+= oneCharLen
;
1020 imeCharPos
[i
+ 1] = numBytes
;
1022 // Draw an indicator on the character.
1023 int indicator
= SC_INDICATOR_UNKNOWN
;
1024 switch ((int)compAttr
[i
]) {
1026 indicator
= SC_INDICATOR_INPUT
;
1028 case ATTR_TARGET_NOTCONVERTED
:
1029 case ATTR_TARGET_CONVERTED
:
1030 indicator
= SC_INDICATOR_TARGET
;
1032 case ATTR_CONVERTED
:
1033 indicator
= SC_INDICATOR_CONVERTED
;
1036 DrawImeIndicator(indicator
, oneCharLen
);
1039 recordingMacro
= tmpRecordingMacro
;
1041 // Move IME caret position.
1042 MoveImeCarets(-imeCharPos
[wcsLen
] + imeCharPos
[imeCursorPos
]);
1044 view
.imeCaretBlockOverride
= true;
1046 } else if (lParam
& GCS_RESULTSTR
) {
1047 wchar_t wcs
[maxLenInputIME
] = { 0 };
1048 long bytes
= ::ImmGetCompositionStringW
1049 (hIMC
, GCS_RESULTSTR
, wcs
, maxLenInputIME
);
1050 unsigned int wcsLen
= bytes
/ 2;
1052 for (size_t i
= 0; i
< wcsLen
;) {
1053 const size_t ucWidth
= UTF16CharLength(wcs
[i
]);
1054 const std::wstring
uniChar(wcs
+i
, ucWidth
);
1055 char oneChar
[UTF8MaxBytes
+1] = "\0\0\0\0"; // Maximum 4 bytes in UTF-8.
1056 unsigned int oneCharLen
= 0;
1058 if (IsUnicodeMode()) {
1059 oneCharLen
= UTF8Length(uniChar
.c_str(), static_cast<unsigned int>(uniChar
.length()));
1060 UTF8FromUTF16(uniChar
.c_str(), static_cast<unsigned int>(uniChar
.length()), oneChar
, oneCharLen
);
1062 oneCharLen
= ::WideCharToMultiByte(InputCodePage(), 0,
1063 uniChar
.c_str(), static_cast<unsigned int>(uniChar
.length()), oneChar
, sizeof(oneChar
)-1, 0, 0);
1065 oneChar
[oneCharLen
] = '\0';
1066 AddCharUTF(oneChar
, oneCharLen
);
1070 SetCandidateWindowPos();
1071 ShowCaretAtCurrentPosition();
1072 ::ImmReleaseContext(MainHWND(), hIMC
);
1076 // Translate message IDs from WM_* and EM_* to SCI_* so can partly emulate Windows Edit control
1077 static unsigned int SciMessageFromEM(unsigned int iMessage
) {
1079 case EM_CANPASTE
: return SCI_CANPASTE
;
1080 case EM_CANUNDO
: return SCI_CANUNDO
;
1081 case EM_EMPTYUNDOBUFFER
: return SCI_EMPTYUNDOBUFFER
;
1082 case EM_FINDTEXTEX
: return SCI_FINDTEXT
;
1083 case EM_FORMATRANGE
: return SCI_FORMATRANGE
;
1084 case EM_GETFIRSTVISIBLELINE
: return SCI_GETFIRSTVISIBLELINE
;
1085 case EM_GETLINECOUNT
: return SCI_GETLINECOUNT
;
1086 case EM_GETSELTEXT
: return SCI_GETSELTEXT
;
1087 case EM_GETTEXTRANGE
: return SCI_GETTEXTRANGE
;
1088 case EM_HIDESELECTION
: return SCI_HIDESELECTION
;
1089 case EM_LINEINDEX
: return SCI_POSITIONFROMLINE
;
1090 case EM_LINESCROLL
: return SCI_LINESCROLL
;
1091 case EM_REPLACESEL
: return SCI_REPLACESEL
;
1092 case EM_SCROLLCARET
: return SCI_SCROLLCARET
;
1093 case EM_SETREADONLY
: return SCI_SETREADONLY
;
1094 case WM_CLEAR
: return SCI_CLEAR
;
1095 case WM_COPY
: return SCI_COPY
;
1096 case WM_CUT
: return SCI_CUT
;
1097 case WM_SETTEXT
: return SCI_SETTEXT
;
1098 case WM_PASTE
: return SCI_PASTE
;
1099 case WM_UNDO
: return SCI_UNDO
;
1104 UINT
CodePageFromCharSet(DWORD characterSet
, UINT documentCodePage
) {
1105 if (documentCodePage
== SC_CP_UTF8
) {
1108 switch (characterSet
) {
1109 case SC_CHARSET_ANSI
: return 1252;
1110 case SC_CHARSET_DEFAULT
: return documentCodePage
;
1111 case SC_CHARSET_BALTIC
: return 1257;
1112 case SC_CHARSET_CHINESEBIG5
: return 950;
1113 case SC_CHARSET_EASTEUROPE
: return 1250;
1114 case SC_CHARSET_GB2312
: return 936;
1115 case SC_CHARSET_GREEK
: return 1253;
1116 case SC_CHARSET_HANGUL
: return 949;
1117 case SC_CHARSET_MAC
: return 10000;
1118 case SC_CHARSET_OEM
: return 437;
1119 case SC_CHARSET_RUSSIAN
: return 1251;
1120 case SC_CHARSET_SHIFTJIS
: return 932;
1121 case SC_CHARSET_TURKISH
: return 1254;
1122 case SC_CHARSET_JOHAB
: return 1361;
1123 case SC_CHARSET_HEBREW
: return 1255;
1124 case SC_CHARSET_ARABIC
: return 1256;
1125 case SC_CHARSET_VIETNAMESE
: return 1258;
1126 case SC_CHARSET_THAI
: return 874;
1127 case SC_CHARSET_8859_15
: return 28605;
1129 case SC_CHARSET_CYRILLIC
: return documentCodePage
;
1130 case SC_CHARSET_SYMBOL
: return documentCodePage
;
1132 return documentCodePage
;
1135 UINT
ScintillaWin::CodePageOfDocument() const {
1136 return CodePageFromCharSet(vs
.styles
[STYLE_DEFAULT
].characterSet
, pdoc
->dbcsCodePage
);
1139 sptr_t
ScintillaWin::GetTextLength() {
1140 if (pdoc
->Length() == 0)
1142 std::vector
<char> docBytes(pdoc
->Length(), '\0');
1143 pdoc
->GetCharRange(&docBytes
[0], 0, pdoc
->Length());
1144 if (IsUnicodeMode()) {
1145 return UTF16Length(&docBytes
[0], static_cast<unsigned int>(docBytes
.size()));
1147 return ::MultiByteToWideChar(CodePageOfDocument(), 0, &docBytes
[0],
1148 static_cast<int>(docBytes
.size()), NULL
, 0);
1152 sptr_t
ScintillaWin::GetText(uptr_t wParam
, sptr_t lParam
) {
1153 wchar_t *ptr
= reinterpret_cast<wchar_t *>(lParam
);
1154 if (pdoc
->Length() == 0) {
1158 std::vector
<char> docBytes(pdoc
->Length(), '\0');
1159 pdoc
->GetCharRange(&docBytes
[0], 0, pdoc
->Length());
1160 if (IsUnicodeMode()) {
1161 size_t lengthUTF16
= UTF16Length(&docBytes
[0], static_cast<unsigned int>(docBytes
.size()));
1166 size_t uLen
= UTF16FromUTF8(&docBytes
[0], docBytes
.size(),
1167 ptr
, static_cast<int>(wParam
) - 1);
1172 // Convert to Unicode using the current Scintilla code page
1173 const UINT cpSrc
= CodePageOfDocument();
1174 int lengthUTF16
= ::MultiByteToWideChar(cpSrc
, 0, &docBytes
[0],
1175 static_cast<int>(docBytes
.size()), NULL
, 0);
1176 if (lengthUTF16
>= static_cast<int>(wParam
))
1177 lengthUTF16
= static_cast<int>(wParam
)-1;
1178 ::MultiByteToWideChar(cpSrc
, 0, &docBytes
[0],
1179 static_cast<int>(docBytes
.size()),
1181 ptr
[lengthUTF16
] = L
'\0';
1186 sptr_t
ScintillaWin::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
1188 //Platform::DebugPrintf("S M:%x WP:%x L:%x\n", iMessage, wParam, lParam);
1189 iMessage
= SciMessageFromEM(iMessage
);
1193 ctrlID
= ::GetDlgCtrlID(reinterpret_cast<HWND
>(wMain
.GetID()));
1194 // Get Intellimouse scroll line parameters
1195 GetIntelliMouseParameters();
1196 ::RegisterDragDrop(MainHWND(), reinterpret_cast<IDropTarget
*>(&dt
));
1200 Command(LoWord(wParam
));
1204 return WndPaint(wParam
);
1206 case WM_PRINTCLIENT
: {
1207 HDC hdc
= reinterpret_cast<HDC
>(wParam
);
1208 if (!IsCompatibleDC(hdc
)) {
1209 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1216 ScrollMessage(wParam
);
1220 HorizontalScrollMessage(wParam
);
1224 #if defined(USE_D2D)
1225 if (paintState
== notPainting
) {
1228 renderTargetValid
= false;
1231 //Platform::DebugPrintf("Scintilla WM_SIZE %d %d\n", LoWord(lParam), HiWord(lParam));
1237 // if autocomplete list active then send mousewheel message to it
1239 HWND hWnd
= reinterpret_cast<HWND
>(ac
.lb
->GetID());
1240 ::SendMessage(hWnd
, iMessage
, wParam
, lParam
);
1244 // Don't handle datazoom.
1245 // (A good idea for datazoom would be to "fold" or "unfold" details.
1246 // i.e. if datazoomed out only class structures are visible, when datazooming in the control
1247 // structures appear, then eventually the individual statements...)
1248 if (wParam
& MK_SHIFT
) {
1249 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1252 // Either SCROLL or ZOOM. We handle the wheel steppings calculation
1253 wheelDelta
-= static_cast<short>(HiWord(wParam
));
1254 if (abs(wheelDelta
) >= WHEEL_DELTA
&& linesPerScroll
> 0) {
1255 int linesToScroll
= linesPerScroll
;
1256 if (linesPerScroll
== WHEEL_PAGESCROLL
)
1257 linesToScroll
= LinesOnScreen() - 1;
1258 if (linesToScroll
== 0) {
1261 linesToScroll
*= (wheelDelta
/ WHEEL_DELTA
);
1262 if (wheelDelta
>= 0)
1263 wheelDelta
= wheelDelta
% WHEEL_DELTA
;
1265 wheelDelta
= - (-wheelDelta
% WHEEL_DELTA
);
1267 if (wParam
& MK_CONTROL
) {
1268 // Zoom! We play with the font sizes in the styles.
1269 // Number of steps/line is ignored, we just care if sizing up or down
1270 if (linesToScroll
< 0) {
1271 KeyCommand(SCI_ZOOMIN
);
1273 KeyCommand(SCI_ZOOMOUT
);
1277 ScrollTo(topLine
+ linesToScroll
);
1283 if (wParam
== idleTimerID
&& idler
.state
) {
1284 SendMessage(MainHWND(), SC_WIN_IDLE
, 0, 1);
1286 TickFor(static_cast<TickReason
>(wParam
- fineTimerStart
));
1291 // wParam=dwTickCountInitial, or 0 to initialize. lParam=bSkipUserInputTest
1293 if (lParam
|| (WAIT_TIMEOUT
== MsgWaitForMultipleObjects(0, 0, 0, 0, QS_INPUT
|QS_HOTKEY
))) {
1295 // User input was given priority above, but all events do get a turn. Other
1296 // messages, notifications, etc. will get interleaved with the idle messages.
1298 // However, some things like WM_PAINT are a lower priority, and will not fire
1299 // when there's a message posted. So, several times a second, we stop and let
1300 // the low priority events have a turn (after which the timer will fire again).
1302 DWORD dwCurrent
= GetTickCount();
1303 DWORD dwStart
= wParam
? static_cast<DWORD
>(wParam
) : dwCurrent
;
1304 const DWORD maxWorkTime
= 50;
1306 if (dwCurrent
>= dwStart
&& dwCurrent
> maxWorkTime
&& dwCurrent
- maxWorkTime
< dwStart
)
1307 PostMessage(MainHWND(), SC_WIN_IDLE
, dwStart
, 0);
1315 case WM_GETMINMAXINFO
:
1316 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1318 case WM_LBUTTONDOWN
: {
1319 // For IME, set the composition string as the result string.
1320 HIMC hIMC
= ::ImmGetContext(MainHWND());
1321 ::ImmNotifyIME(hIMC
, NI_COMPOSITIONSTR
, CPS_COMPLETE
, 0);
1322 ::ImmReleaseContext(MainHWND(), hIMC
);
1324 //Platform::DebugPrintf("Buttdown %d %x %x %x %x %x\n",iMessage, wParam, lParam,
1325 // Platform::IsKeyDown(VK_SHIFT),
1326 // Platform::IsKeyDown(VK_CONTROL),
1327 // Platform::IsKeyDown(VK_MENU));
1328 ::SetFocus(MainHWND());
1329 ButtonDown(Point::FromLong(static_cast<long>(lParam
)), ::GetMessageTime(),
1330 (wParam
& MK_SHIFT
) != 0,
1331 (wParam
& MK_CONTROL
) != 0,
1332 Platform::IsKeyDown(VK_MENU
));
1336 case WM_MOUSEMOVE
: {
1337 const Point pt
= Point::FromLong(static_cast<long>(lParam
));
1339 // Windows might send WM_MOUSEMOVE even though the mouse has not been moved:
1340 // http://blogs.msdn.com/b/oldnewthing/archive/2003/10/01/55108.aspx
1341 if (ptMouseLast
.x
!= pt
.x
|| ptMouseLast
.y
!= pt
.y
) {
1342 SetTrackMouseLeaveEvent(true);
1343 ButtonMoveWithModifiers(pt
,
1344 ((wParam
& MK_SHIFT
) != 0 ? SCI_SHIFT
: 0) |
1345 ((wParam
& MK_CONTROL
) != 0 ? SCI_CTRL
: 0) |
1346 (Platform::IsKeyDown(VK_MENU
) ? SCI_ALT
: 0));
1352 SetTrackMouseLeaveEvent(false);
1354 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1357 ButtonUp(Point::FromLong(static_cast<long>(lParam
)),
1359 (wParam
& MK_CONTROL
) != 0);
1362 case WM_RBUTTONDOWN
:
1363 ::SetFocus(MainHWND());
1364 if (!PointInSelection(Point::FromLong(static_cast<long>(lParam
)))) {
1366 SetEmptySelection(PositionFromLocation(Point::FromLong(static_cast<long>(lParam
))));
1371 if (LoWord(lParam
) == HTCLIENT
) {
1372 if (inDragDrop
== ddDragging
) {
1373 DisplayCursor(Window::cursorUp
);
1375 // Display regular (drag) cursor over selection
1377 if (0 != ::GetCursorPos(&pt
)) {
1378 ::ScreenToClient(MainHWND(), &pt
);
1379 if (PointInSelMargin(PointFromPOINT(pt
))) {
1380 DisplayCursor(GetMarginCursor(PointFromPOINT(pt
)));
1381 } else if (PointInSelection(PointFromPOINT(pt
)) && !SelectionEmpty()) {
1382 DisplayCursor(Window::cursorArrow
);
1383 } else if (PointIsHotspot(PointFromPOINT(pt
))) {
1384 DisplayCursor(Window::cursorHand
);
1386 DisplayCursor(Window::cursorText
);
1392 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1396 if (((wParam
>= 128) || !iscntrl(static_cast<int>(wParam
))) || !lastKeyDownConsumed
) {
1397 wchar_t wcs
[2] = {static_cast<wchar_t>(wParam
), 0};
1398 if (IsUnicodeMode()) {
1399 // For a wide character version of the window:
1400 char utfval
[UTF8MaxBytes
];
1401 unsigned int len
= UTF8Length(wcs
, 1);
1402 UTF8FromUTF16(wcs
, 1, utfval
, len
);
1403 AddCharUTF(utfval
, len
);
1405 UINT cpDest
= CodePageOfDocument();
1406 char inBufferCP
[20];
1407 int size
= ::WideCharToMultiByte(cpDest
,
1408 0, wcs
, 1, inBufferCP
, sizeof(inBufferCP
) - 1, 0, 0);
1409 inBufferCP
[size
] = '\0';
1410 AddCharUTF(inBufferCP
, size
);
1416 if (wParam
== UNICODE_NOCHAR
) {
1417 return IsUnicodeMode() ? 1 : 0;
1418 } else if (lastKeyDownConsumed
) {
1421 if (IsUnicodeMode()) {
1422 char utfval
[UTF8MaxBytes
];
1423 wchar_t wcs
[2] = {static_cast<wchar_t>(wParam
), 0};
1424 unsigned int len
= UTF8Length(wcs
, 1);
1425 UTF8FromUTF16(wcs
, 1, utfval
, len
);
1426 AddCharUTF(utfval
, len
);
1435 //Platform::DebugPrintf("S keydown %d %x %x %x %x\n",iMessage, wParam, lParam, ::IsKeyDown(VK_SHIFT), ::IsKeyDown(VK_CONTROL));
1436 lastKeyDownConsumed
= false;
1437 int ret
= KeyDown(KeyTranslate(static_cast<int>(wParam
)),
1438 Platform::IsKeyDown(VK_SHIFT
),
1439 Platform::IsKeyDown(VK_CONTROL
),
1440 Platform::IsKeyDown(VK_MENU
),
1441 &lastKeyDownConsumed
);
1442 if (!ret
&& !lastKeyDownConsumed
) {
1443 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1448 case WM_IME_KEYDOWN
: {
1449 if (wParam
== VK_HANJA
) {
1452 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1456 //Platform::DebugPrintf("S keyup %d %x %x\n",iMessage, wParam, lParam);
1457 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1459 case WM_SETTINGCHANGE
:
1460 //Platform::DebugPrintf("Setting Changed\n");
1461 InvalidateStyleData();
1462 // Get Intellimouse scroll line parameters
1463 GetIntelliMouseParameters();
1467 return DLGC_HASSETSEL
| DLGC_WANTALLKEYS
;
1469 case WM_KILLFOCUS
: {
1470 HWND wOther
= reinterpret_cast<HWND
>(wParam
);
1471 HWND wThis
= MainHWND();
1472 HWND wCT
= reinterpret_cast<HWND
>(ct
.wCallTip
.GetID());
1474 !(::IsChild(wThis
, wOther
) || (wOther
== wCT
))) {
1475 SetFocusState(false);
1476 DestroySystemCaret();
1478 // Explicitly complete any IME composition
1479 HIMC hIMC
= ImmGetContext(MainHWND());
1481 ::ImmNotifyIME(hIMC
, NI_COMPOSITIONSTR
, CPS_COMPLETE
, 0);
1482 ::ImmReleaseContext(MainHWND(), hIMC
);
1488 SetFocusState(true);
1489 DestroySystemCaret();
1490 CreateSystemCaret();
1493 case WM_SYSCOLORCHANGE
:
1494 //Platform::DebugPrintf("Setting Changed\n");
1495 InvalidateStyleData();
1498 case WM_IME_STARTCOMPOSITION
: // dbcs
1499 if (KoreanIME() || imeInteraction
== imeInline
) {
1502 ImeStartComposition();
1503 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1506 case WM_IME_ENDCOMPOSITION
: // dbcs
1507 ImeEndComposition();
1508 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1510 case WM_IME_COMPOSITION
:
1511 if (KoreanIME() || imeInteraction
== imeInline
) {
1512 return HandleCompositionInline(wParam
, lParam
);
1514 return HandleCompositionWindowed(wParam
, lParam
);
1517 case WM_CONTEXTMENU
:
1518 if (displayPopupMenu
) {
1519 Point pt
= Point::FromLong(static_cast<long>(lParam
));
1520 if ((pt
.x
== -1) && (pt
.y
== -1)) {
1521 // Caused by keyboard so display menu near caret
1522 pt
= PointMainCaret();
1523 POINT spt
= {static_cast<int>(pt
.x
), static_cast<int>(pt
.y
)};
1524 ::ClientToScreen(MainHWND(), &spt
);
1525 pt
= PointFromPOINT(spt
);
1530 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1532 case WM_INPUTLANGCHANGE
:
1533 //::SetThreadLocale(LOWORD(lParam));
1534 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1536 case WM_INPUTLANGCHANGEREQUEST
:
1537 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1540 return 1; // Avoid any background erasure as whole window painted.
1542 case WM_CAPTURECHANGED
:
1543 capturedMouse
= false;
1546 case WM_IME_SETCONTEXT
:
1547 if (KoreanIME() || imeInteraction
== imeInline
) {
1549 LPARAM NoImeWin
= lParam
;
1550 NoImeWin
= NoImeWin
& (~ISC_SHOWUICOMPOSITIONWINDOW
);
1551 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, NoImeWin
);
1554 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1556 // These are not handled in Scintilla and its faster to dispatch them here.
1557 // Also moves time out to here so profile doesn't count lots of empty message calls.
1560 case WM_MOUSEACTIVATE
:
1564 case WM_NCMOUSEMOVE
:
1565 case WM_NCLBUTTONDOWN
:
1568 case WM_WINDOWPOSCHANGING
:
1569 case WM_WINDOWPOSCHANGED
:
1570 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1572 case WM_GETTEXTLENGTH
:
1573 return GetTextLength();
1576 return GetText(wParam
, lParam
);
1578 case EM_LINEFROMCHAR
:
1579 if (static_cast<int>(wParam
) < 0) {
1580 wParam
= SelectionStart().Position();
1582 return pdoc
->LineFromPosition(static_cast<int>(wParam
));
1584 case EM_EXLINEFROMCHAR
:
1585 return pdoc
->LineFromPosition(static_cast<int>(lParam
));
1589 *reinterpret_cast<int *>(wParam
) = SelectionStart().Position();
1592 *reinterpret_cast<int *>(lParam
) = SelectionEnd().Position();
1594 return MAKELONG(SelectionStart().Position(), SelectionEnd().Position());
1600 Sci_CharacterRange
*pCR
= reinterpret_cast<Sci_CharacterRange
*>(lParam
);
1601 pCR
->cpMin
= SelectionStart().Position();
1602 pCR
->cpMax
= SelectionEnd().Position();
1607 int nStart
= static_cast<int>(wParam
);
1608 int nEnd
= static_cast<int>(lParam
);
1609 if (nStart
== 0 && nEnd
== -1) {
1610 nEnd
= pdoc
->Length();
1613 nStart
= nEnd
; // Remove selection
1615 if (nStart
> nEnd
) {
1616 SetSelection(nEnd
, nStart
);
1618 SetSelection(nStart
, nEnd
);
1620 EnsureCaretVisible();
1628 Sci_CharacterRange
*pCR
= reinterpret_cast<Sci_CharacterRange
*>(lParam
);
1629 sel
.selType
= Selection::selStream
;
1630 if (pCR
->cpMin
== 0 && pCR
->cpMax
== -1) {
1631 SetSelection(pCR
->cpMin
, pdoc
->Length());
1633 SetSelection(pCR
->cpMin
, pCR
->cpMax
);
1635 EnsureCaretVisible();
1636 return pdoc
->LineFromPosition(SelectionStart().Position());
1639 case SCI_GETDIRECTFUNCTION
:
1640 return reinterpret_cast<sptr_t
>(DirectFunction
);
1642 case SCI_GETDIRECTPOINTER
:
1643 return reinterpret_cast<sptr_t
>(this);
1646 ::SetFocus(MainHWND());
1649 #ifdef INCLUDE_DEPRECATED_FEATURES
1650 case SCI_SETKEYSUNICODE
:
1653 case SCI_GETKEYSUNICODE
:
1657 case SCI_SETTECHNOLOGY
:
1658 if ((wParam
== SC_TECHNOLOGY_DEFAULT
) ||
1659 (wParam
== SC_TECHNOLOGY_DIRECTWRITERETAIN
) ||
1660 (wParam
== SC_TECHNOLOGY_DIRECTWRITEDC
) ||
1661 (wParam
== SC_TECHNOLOGY_DIRECTWRITE
)) {
1662 if (technology
!= static_cast<int>(wParam
)) {
1663 if (static_cast<int>(wParam
) > SC_TECHNOLOGY_DEFAULT
) {
1664 #if defined(USE_D2D)
1666 // Failed to load Direct2D or DirectWrite so no effect
1672 #if defined(USE_D2D)
1675 technology
= static_cast<int>(wParam
);
1676 // Invalidate all cached information including layout.
1678 InvalidateStyleRedraw();
1684 case SCI_LOADLEXERLIBRARY
:
1685 LexerManager::GetInstance()->Load(reinterpret_cast<const char *>(lParam
));
1689 case SCI_TARGETASUTF8
:
1690 return TargetAsUTF8(reinterpret_cast<char*>(lParam
));
1692 case SCI_ENCODEDFROMUTF8
:
1693 return EncodedFromUTF8(reinterpret_cast<char*>(wParam
),
1694 reinterpret_cast<char*>(lParam
));
1697 return ScintillaBase::WndProc(iMessage
, wParam
, lParam
);
1699 } catch (std::bad_alloc
&) {
1700 errorStatus
= SC_STATUS_BADALLOC
;
1702 errorStatus
= SC_STATUS_FAILURE
;
1707 bool ScintillaWin::ValidCodePage(int codePage
) const {
1708 return codePage
== 0 || codePage
== SC_CP_UTF8
||
1709 codePage
== 932 || codePage
== 936 || codePage
== 949 ||
1710 codePage
== 950 || codePage
== 1361;
1713 sptr_t
ScintillaWin::DefWndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
1714 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1718 * Report that this Editor subclass has a working implementation of FineTickerStart.
1720 bool ScintillaWin::FineTickerAvailable() {
1724 bool ScintillaWin::FineTickerRunning(TickReason reason
) {
1725 return timers
[reason
] != 0;
1728 void ScintillaWin::FineTickerStart(TickReason reason
, int millis
, int tolerance
) {
1729 FineTickerCancel(reason
);
1730 if (SetCoalescableTimerFn
&& tolerance
) {
1731 timers
[reason
] = SetCoalescableTimerFn(MainHWND(), fineTimerStart
+ reason
, millis
, NULL
, tolerance
);
1733 timers
[reason
] = ::SetTimer(MainHWND(), fineTimerStart
+ reason
, millis
, NULL
);
1737 void ScintillaWin::FineTickerCancel(TickReason reason
) {
1738 if (timers
[reason
]) {
1739 ::KillTimer(MainHWND(), timers
[reason
]);
1745 bool ScintillaWin::SetIdle(bool on
) {
1746 // On Win32 the Idler is implemented as a Timer on the Scintilla window. This
1747 // takes advantage of the fact that WM_TIMER messages are very low priority,
1748 // and are only posted when the message queue is empty, i.e. during idle time.
1749 if (idler
.state
!= on
) {
1751 idler
.idlerID
= ::SetTimer(MainHWND(), idleTimerID
, 10, NULL
)
1752 ? reinterpret_cast<IdlerID
>(idleTimerID
) : 0;
1754 ::KillTimer(MainHWND(), reinterpret_cast<uptr_t
>(idler
.idlerID
));
1757 idler
.state
= idler
.idlerID
!= 0;
1762 void ScintillaWin::SetMouseCapture(bool on
) {
1763 if (mouseDownCaptures
) {
1765 ::SetCapture(MainHWND());
1773 bool ScintillaWin::HaveMouseCapture() {
1774 // Cannot just see if GetCapture is this window as the scroll bar also sets capture for the window
1775 return capturedMouse
;
1776 //return capturedMouse && (::GetCapture() == MainHWND());
1779 void ScintillaWin::SetTrackMouseLeaveEvent(bool on
) {
1780 if (on
&& TrackMouseEventFn
&& !trackedMouseLeave
) {
1781 TRACKMOUSEEVENT tme
;
1782 tme
.cbSize
= sizeof(tme
);
1783 tme
.dwFlags
= TME_LEAVE
;
1784 tme
.hwndTrack
= MainHWND();
1785 tme
.dwHoverTime
= HOVER_DEFAULT
; // Unused but triggers Dr. Memory if not initialized
1786 TrackMouseEventFn(&tme
);
1788 trackedMouseLeave
= on
;
1791 bool ScintillaWin::PaintContains(PRectangle rc
) {
1792 if (paintState
== painting
) {
1793 return BoundsContains(rcPaint
, hRgnUpdate
, rc
);
1798 void ScintillaWin::ScrollText(int /* linesToMove */) {
1799 //Platform::DebugPrintf("ScintillaWin::ScrollText %d\n", linesToMove);
1800 //::ScrollWindow(MainHWND(), 0,
1801 // vs.lineHeight * linesToMove, 0, 0);
1802 //::UpdateWindow(MainHWND());
1804 UpdateSystemCaret();
1807 void ScintillaWin::UpdateSystemCaret() {
1809 if (HasCaretSizeChanged()) {
1810 DestroySystemCaret();
1811 CreateSystemCaret();
1813 Point pos
= PointMainCaret();
1814 ::SetCaretPos(static_cast<int>(pos
.x
), static_cast<int>(pos
.y
));
1818 int ScintillaWin::SetScrollInfo(int nBar
, LPCSCROLLINFO lpsi
, BOOL bRedraw
) {
1819 return ::SetScrollInfo(MainHWND(), nBar
, lpsi
, bRedraw
);
1822 bool ScintillaWin::GetScrollInfo(int nBar
, LPSCROLLINFO lpsi
) {
1823 return ::GetScrollInfo(MainHWND(), nBar
, lpsi
) ? true : false;
1826 // Change the scroll position but avoid repaint if changing to same value
1827 void ScintillaWin::ChangeScrollPos(int barType
, int pos
) {
1829 sizeof(sci
), 0, 0, 0, 0, 0, 0
1831 sci
.fMask
= SIF_POS
;
1832 GetScrollInfo(barType
, &sci
);
1833 if (sci
.nPos
!= pos
) {
1836 SetScrollInfo(barType
, &sci
, TRUE
);
1840 void ScintillaWin::SetVerticalScrollPos() {
1841 ChangeScrollPos(SB_VERT
, topLine
);
1844 void ScintillaWin::SetHorizontalScrollPos() {
1845 ChangeScrollPos(SB_HORZ
, xOffset
);
1848 bool ScintillaWin::ModifyScrollBars(int nMax
, int nPage
) {
1849 bool modified
= false;
1851 sizeof(sci
), 0, 0, 0, 0, 0, 0
1853 sci
.fMask
= SIF_PAGE
| SIF_RANGE
;
1854 GetScrollInfo(SB_VERT
, &sci
);
1855 int vertEndPreferred
= nMax
;
1856 if (!verticalScrollBarVisible
)
1857 nPage
= vertEndPreferred
+ 1;
1858 if ((sci
.nMin
!= 0) ||
1859 (sci
.nMax
!= vertEndPreferred
) ||
1860 (sci
.nPage
!= static_cast<unsigned int>(nPage
)) ||
1862 sci
.fMask
= SIF_PAGE
| SIF_RANGE
;
1864 sci
.nMax
= vertEndPreferred
;
1868 SetScrollInfo(SB_VERT
, &sci
, TRUE
);
1872 PRectangle rcText
= GetTextRectangle();
1873 int horizEndPreferred
= scrollWidth
;
1874 if (horizEndPreferred
< 0)
1875 horizEndPreferred
= 0;
1876 unsigned int pageWidth
= static_cast<unsigned int>(rcText
.Width());
1877 if (!horizontalScrollBarVisible
|| Wrapping())
1878 pageWidth
= horizEndPreferred
+ 1;
1879 sci
.fMask
= SIF_PAGE
| SIF_RANGE
;
1880 GetScrollInfo(SB_HORZ
, &sci
);
1881 if ((sci
.nMin
!= 0) ||
1882 (sci
.nMax
!= horizEndPreferred
) ||
1883 (sci
.nPage
!= pageWidth
) ||
1885 sci
.fMask
= SIF_PAGE
| SIF_RANGE
;
1887 sci
.nMax
= horizEndPreferred
;
1888 sci
.nPage
= pageWidth
;
1891 SetScrollInfo(SB_HORZ
, &sci
, TRUE
);
1893 if (scrollWidth
< static_cast<int>(pageWidth
)) {
1894 HorizontalScrollTo(0);
1900 void ScintillaWin::NotifyChange() {
1901 ::SendMessage(::GetParent(MainHWND()), WM_COMMAND
,
1902 MAKELONG(GetCtrlID(), SCEN_CHANGE
),
1903 reinterpret_cast<LPARAM
>(MainHWND()));
1906 void ScintillaWin::NotifyFocus(bool focus
) {
1907 ::SendMessage(::GetParent(MainHWND()), WM_COMMAND
,
1908 MAKELONG(GetCtrlID(), focus
? SCEN_SETFOCUS
: SCEN_KILLFOCUS
),
1909 reinterpret_cast<LPARAM
>(MainHWND()));
1910 Editor::NotifyFocus(focus
);
1913 void ScintillaWin::SetCtrlID(int identifier
) {
1914 ::SetWindowID(reinterpret_cast<HWND
>(wMain
.GetID()), identifier
);
1917 int ScintillaWin::GetCtrlID() {
1918 return ::GetDlgCtrlID(reinterpret_cast<HWND
>(wMain
.GetID()));
1921 void ScintillaWin::NotifyParent(SCNotification scn
) {
1922 scn
.nmhdr
.hwndFrom
= MainHWND();
1923 scn
.nmhdr
.idFrom
= GetCtrlID();
1924 ::SendMessage(::GetParent(MainHWND()), WM_NOTIFY
,
1925 GetCtrlID(), reinterpret_cast<LPARAM
>(&scn
));
1928 void ScintillaWin::NotifyDoubleClick(Point pt
, int modifiers
) {
1929 //Platform::DebugPrintf("ScintillaWin Double click 0\n");
1930 ScintillaBase::NotifyDoubleClick(pt
, modifiers
);
1931 // Send myself a WM_LBUTTONDBLCLK, so the container can handle it too.
1932 ::SendMessage(MainHWND(),
1934 (modifiers
& SCI_SHIFT
) ? MK_SHIFT
: 0,
1935 MAKELPARAM(pt
.x
, pt
.y
));
1938 class CaseFolderDBCS
: public CaseFolderTable
{
1939 // Allocate the expandable storage here so that it does not need to be reallocated
1940 // for each call to Fold.
1941 std::vector
<wchar_t> utf16Mixed
;
1942 std::vector
<wchar_t> utf16Folded
;
1945 explicit CaseFolderDBCS(UINT cp_
) : cp(cp_
) {
1948 virtual size_t Fold(char *folded
, size_t sizeFolded
, const char *mixed
, size_t lenMixed
) {
1949 if ((lenMixed
== 1) && (sizeFolded
> 0)) {
1950 folded
[0] = mapping
[static_cast<unsigned char>(mixed
[0])];
1953 if (lenMixed
> utf16Mixed
.size()) {
1954 utf16Mixed
.resize(lenMixed
+ 8);
1956 size_t nUtf16Mixed
= ::MultiByteToWideChar(cp
, 0, mixed
,
1957 static_cast<int>(lenMixed
),
1959 static_cast<int>(utf16Mixed
.size()));
1961 if (nUtf16Mixed
== 0) {
1962 // Failed to convert -> bad input
1967 unsigned int lenFlat
= 0;
1968 for (size_t mixIndex
=0; mixIndex
< nUtf16Mixed
; mixIndex
++) {
1969 if ((lenFlat
+ 20) > utf16Folded
.size())
1970 utf16Folded
.resize(lenFlat
+ 60);
1971 const char *foldedUTF8
= CaseConvert(utf16Mixed
[mixIndex
], CaseConversionFold
);
1973 // Maximum length of a case conversion is 6 bytes, 3 characters
1974 wchar_t wFolded
[20];
1975 size_t charsConverted
= UTF16FromUTF8(foldedUTF8
,
1977 wFolded
, ELEMENTS(wFolded
));
1978 for (size_t j
=0; j
<charsConverted
; j
++)
1979 utf16Folded
[lenFlat
++] = wFolded
[j
];
1981 utf16Folded
[lenFlat
++] = utf16Mixed
[mixIndex
];
1985 size_t lenOut
= ::WideCharToMultiByte(cp
, 0,
1986 &utf16Folded
[0], lenFlat
,
1989 if (lenOut
< sizeFolded
) {
1990 ::WideCharToMultiByte(cp
, 0,
1991 &utf16Folded
[0], lenFlat
,
1992 folded
, static_cast<int>(lenOut
), NULL
, 0);
2001 CaseFolder
*ScintillaWin::CaseFolderForEncoding() {
2002 UINT cpDest
= CodePageOfDocument();
2003 if (cpDest
== SC_CP_UTF8
) {
2004 return new CaseFolderUnicode();
2006 if (pdoc
->dbcsCodePage
== 0) {
2007 CaseFolderTable
*pcf
= new CaseFolderTable();
2008 pcf
->StandardASCII();
2009 // Only for single byte encodings
2010 UINT cpDoc
= CodePageOfDocument();
2011 for (int i
=0x80; i
<0x100; i
++) {
2012 char sCharacter
[2] = "A";
2013 sCharacter
[0] = static_cast<char>(i
);
2014 wchar_t wCharacter
[20];
2015 unsigned int lengthUTF16
= ::MultiByteToWideChar(cpDoc
, 0, sCharacter
, 1,
2016 wCharacter
, ELEMENTS(wCharacter
));
2017 if (lengthUTF16
== 1) {
2018 const char *caseFolded
= CaseConvert(wCharacter
[0], CaseConversionFold
);
2021 size_t charsConverted
= UTF16FromUTF8(caseFolded
,
2023 wLower
, ELEMENTS(wLower
));
2024 if (charsConverted
== 1) {
2025 char sCharacterLowered
[20];
2026 unsigned int lengthConverted
= ::WideCharToMultiByte(cpDoc
, 0,
2027 wLower
, static_cast<int>(charsConverted
),
2028 sCharacterLowered
, ELEMENTS(sCharacterLowered
), NULL
, 0);
2029 if ((lengthConverted
== 1) && (sCharacter
[0] != sCharacterLowered
[0])) {
2030 pcf
->SetTranslation(sCharacter
[0], sCharacterLowered
[0]);
2038 return new CaseFolderDBCS(cpDest
);
2043 std::string
ScintillaWin::CaseMapString(const std::string
&s
, int caseMapping
) {
2044 if ((s
.size() == 0) || (caseMapping
== cmSame
))
2047 UINT cpDoc
= CodePageOfDocument();
2048 if (cpDoc
== SC_CP_UTF8
) {
2049 std::string
retMapped(s
.length() * maxExpansionCaseConversion
, 0);
2050 size_t lenMapped
= CaseConvertString(&retMapped
[0], retMapped
.length(), s
.c_str(), s
.length(),
2051 (caseMapping
== cmUpper
) ? CaseConversionUpper
: CaseConversionLower
);
2052 retMapped
.resize(lenMapped
);
2056 unsigned int lengthUTF16
= ::MultiByteToWideChar(cpDoc
, 0, s
.c_str(),
2057 static_cast<int>(s
.size()), NULL
, 0);
2058 if (lengthUTF16
== 0) // Failed to convert
2061 DWORD mapFlags
= LCMAP_LINGUISTIC_CASING
|
2062 ((caseMapping
== cmUpper
) ? LCMAP_UPPERCASE
: LCMAP_LOWERCASE
);
2064 // Change text to UTF-16
2065 std::vector
<wchar_t> vwcText(lengthUTF16
);
2066 ::MultiByteToWideChar(cpDoc
, 0, s
.c_str(), static_cast<int>(s
.size()), &vwcText
[0], lengthUTF16
);
2069 int charsConverted
= ::LCMapStringW(LOCALE_SYSTEM_DEFAULT
, mapFlags
,
2070 &vwcText
[0], lengthUTF16
, NULL
, 0);
2071 std::vector
<wchar_t> vwcConverted(charsConverted
);
2072 ::LCMapStringW(LOCALE_SYSTEM_DEFAULT
, mapFlags
,
2073 &vwcText
[0], lengthUTF16
, &vwcConverted
[0], charsConverted
);
2075 // Change back to document encoding
2076 unsigned int lengthConverted
= ::WideCharToMultiByte(cpDoc
, 0,
2077 &vwcConverted
[0], static_cast<int>(vwcConverted
.size()),
2079 std::vector
<char> vcConverted(lengthConverted
);
2080 ::WideCharToMultiByte(cpDoc
, 0,
2081 &vwcConverted
[0], static_cast<int>(vwcConverted
.size()),
2082 &vcConverted
[0], static_cast<int>(vcConverted
.size()), NULL
, 0);
2084 return std::string(&vcConverted
[0], vcConverted
.size());
2087 void ScintillaWin::Copy() {
2088 //Platform::DebugPrintf("Copy\n");
2090 SelectionText selectedText
;
2091 CopySelectionRange(&selectedText
);
2092 CopyToClipboard(selectedText
);
2096 void ScintillaWin::CopyAllowLine() {
2097 SelectionText selectedText
;
2098 CopySelectionRange(&selectedText
, true);
2099 CopyToClipboard(selectedText
);
2102 bool ScintillaWin::CanPaste() {
2103 if (!Editor::CanPaste())
2105 if (::IsClipboardFormatAvailable(CF_TEXT
))
2107 if (IsUnicodeMode())
2108 return ::IsClipboardFormatAvailable(CF_UNICODETEXT
) != 0;
2112 class GlobalMemory
{
2116 GlobalMemory() : hand(0), ptr(0) {
2118 explicit GlobalMemory(HGLOBAL hand_
) : hand(hand_
), ptr(0) {
2120 ptr
= ::GlobalLock(hand
);
2124 PLATFORM_ASSERT(!ptr
);
2127 void Allocate(size_t bytes
) {
2129 hand
= ::GlobalAlloc(GMEM_MOVEABLE
| GMEM_ZEROINIT
, bytes
);
2131 ptr
= ::GlobalLock(hand
);
2135 PLATFORM_ASSERT(ptr
);
2136 HGLOBAL handCopy
= hand
;
2137 ::GlobalUnlock(hand
);
2142 void SetClip(UINT uFormat
) {
2143 ::SetClipboardData(uFormat
, Unlock());
2145 operator bool() const {
2149 return ::GlobalSize(hand
);
2153 void ScintillaWin::Paste() {
2154 if (!::OpenClipboard(MainHWND()))
2157 const bool isLine
= SelectionEmpty() &&
2158 (::IsClipboardFormatAvailable(cfLineSelect
) || ::IsClipboardFormatAvailable(cfVSLineTag
));
2159 ClearSelection(multiPasteMode
== SC_MULTIPASTE_EACH
);
2160 bool isRectangular
= (::IsClipboardFormatAvailable(cfColumnSelect
) != 0);
2162 if (!isRectangular
) {
2163 // Evaluate "Borland IDE Block Type" explicitly
2164 GlobalMemory
memBorlandSelection(::GetClipboardData(cfBorlandIDEBlockType
));
2165 if (memBorlandSelection
) {
2166 isRectangular
= (memBorlandSelection
.Size() == 1) && (static_cast<BYTE
*>(memBorlandSelection
.ptr
)[0] == 0x02);
2167 memBorlandSelection
.Unlock();
2170 const PasteShape pasteShape
= isRectangular
? pasteRectangular
: (isLine
? pasteLine
: pasteStream
);
2172 // Always use CF_UNICODETEXT if available
2173 GlobalMemory
memUSelection(::GetClipboardData(CF_UNICODETEXT
));
2174 if (memUSelection
) {
2175 wchar_t *uptr
= static_cast<wchar_t *>(memUSelection
.ptr
);
2178 std::vector
<char> putf
;
2179 // Default Scintilla behaviour in Unicode mode
2180 if (IsUnicodeMode()) {
2181 unsigned int bytes
= static_cast<unsigned int>(memUSelection
.Size());
2182 len
= UTF8Length(uptr
, bytes
/ 2);
2183 putf
.resize(len
+ 1);
2184 UTF8FromUTF16(uptr
, bytes
/ 2, &putf
[0], len
);
2186 // CF_UNICODETEXT available, but not in Unicode mode
2187 // Convert from Unicode to current Scintilla code page
2188 UINT cpDest
= CodePageOfDocument();
2189 len
= ::WideCharToMultiByte(cpDest
, 0, uptr
, -1,
2190 NULL
, 0, NULL
, NULL
) - 1; // subtract 0 terminator
2191 putf
.resize(len
+ 1);
2192 ::WideCharToMultiByte(cpDest
, 0, uptr
, -1,
2193 &putf
[0], len
+ 1, NULL
, NULL
);
2196 InsertPasteShape(&putf
[0], len
, pasteShape
);
2198 memUSelection
.Unlock();
2200 // CF_UNICODETEXT not available, paste ANSI text
2201 GlobalMemory
memSelection(::GetClipboardData(CF_TEXT
));
2203 char *ptr
= static_cast<char *>(memSelection
.ptr
);
2205 unsigned int bytes
= static_cast<unsigned int>(memSelection
.Size());
2206 unsigned int len
= bytes
;
2207 for (unsigned int i
= 0; i
< bytes
; i
++) {
2208 if ((len
== bytes
) && (0 == ptr
[i
]))
2212 // In Unicode mode, convert clipboard text to UTF-8
2213 if (IsUnicodeMode()) {
2214 std::vector
<wchar_t> uptr(len
+1);
2216 unsigned int ulen
= ::MultiByteToWideChar(CP_ACP
, 0,
2217 ptr
, len
, &uptr
[0], len
+1);
2219 unsigned int mlen
= UTF8Length(&uptr
[0], ulen
);
2220 std::vector
<char> putf(mlen
+1);
2221 UTF8FromUTF16(&uptr
[0], ulen
, &putf
[0], mlen
);
2223 InsertPasteShape(&putf
[0], mlen
, pasteShape
);
2225 InsertPasteShape(ptr
, len
, pasteShape
);
2228 memSelection
.Unlock();
2235 void ScintillaWin::CreateCallTipWindow(PRectangle
) {
2236 if (!ct
.wCallTip
.Created()) {
2237 ct
.wCallTip
= ::CreateWindow(callClassName
, TEXT("ACallTip"),
2238 WS_POPUP
, 100, 100, 150, 20,
2240 GetWindowInstance(MainHWND()),
2242 ct
.wDraw
= ct
.wCallTip
;
2246 void ScintillaWin::AddToPopUp(const char *label
, int cmd
, bool enabled
) {
2247 HMENU hmenuPopup
= reinterpret_cast<HMENU
>(popup
.GetID());
2249 ::AppendMenuA(hmenuPopup
, MF_SEPARATOR
, 0, "");
2251 ::AppendMenuA(hmenuPopup
, MF_STRING
, cmd
, label
);
2253 ::AppendMenuA(hmenuPopup
, MF_STRING
| MF_DISABLED
| MF_GRAYED
, cmd
, label
);
2256 void ScintillaWin::ClaimSelection() {
2257 // Windows does not have a primary selection
2260 /// Implement IUnknown
2262 STDMETHODIMP_(ULONG
)FormatEnumerator_AddRef(FormatEnumerator
*fe
);
2263 STDMETHODIMP
FormatEnumerator_QueryInterface(FormatEnumerator
*fe
, REFIID riid
, PVOID
*ppv
) {
2264 //Platform::DebugPrintf("EFE QI");
2266 if (riid
== IID_IUnknown
)
2267 *ppv
= reinterpret_cast<IEnumFORMATETC
*>(fe
);
2268 if (riid
== IID_IEnumFORMATETC
)
2269 *ppv
= reinterpret_cast<IEnumFORMATETC
*>(fe
);
2271 return E_NOINTERFACE
;
2272 FormatEnumerator_AddRef(fe
);
2275 STDMETHODIMP_(ULONG
)FormatEnumerator_AddRef(FormatEnumerator
*fe
) {
2278 STDMETHODIMP_(ULONG
)FormatEnumerator_Release(FormatEnumerator
*fe
) {
2285 /// Implement IEnumFORMATETC
2286 STDMETHODIMP
FormatEnumerator_Next(FormatEnumerator
*fe
, ULONG celt
, FORMATETC
*rgelt
, ULONG
*pceltFetched
) {
2287 if (rgelt
== NULL
) return E_POINTER
;
2288 unsigned int putPos
= 0;
2289 while ((fe
->pos
< fe
->formats
.size()) && (putPos
< celt
)) {
2290 rgelt
->cfFormat
= fe
->formats
[fe
->pos
];
2292 rgelt
->dwAspect
= DVASPECT_CONTENT
;
2294 rgelt
->tymed
= TYMED_HGLOBAL
;
2300 *pceltFetched
= putPos
;
2301 return putPos
? S_OK
: S_FALSE
;
2303 STDMETHODIMP
FormatEnumerator_Skip(FormatEnumerator
*fe
, ULONG celt
) {
2307 STDMETHODIMP
FormatEnumerator_Reset(FormatEnumerator
*fe
) {
2311 STDMETHODIMP
FormatEnumerator_Clone(FormatEnumerator
*fe
, IEnumFORMATETC
**ppenum
) {
2312 FormatEnumerator
*pfe
;
2314 pfe
= new FormatEnumerator(fe
->pos
, &fe
->formats
[0], fe
->formats
.size());
2316 return E_OUTOFMEMORY
;
2318 return FormatEnumerator_QueryInterface(pfe
, IID_IEnumFORMATETC
,
2319 reinterpret_cast<void **>(ppenum
));
2322 static VFunction
*vtFormatEnumerator
[] = {
2323 (VFunction
*)(FormatEnumerator_QueryInterface
),
2324 (VFunction
*)(FormatEnumerator_AddRef
),
2325 (VFunction
*)(FormatEnumerator_Release
),
2326 (VFunction
*)(FormatEnumerator_Next
),
2327 (VFunction
*)(FormatEnumerator_Skip
),
2328 (VFunction
*)(FormatEnumerator_Reset
),
2329 (VFunction
*)(FormatEnumerator_Clone
)
2332 FormatEnumerator::FormatEnumerator(int pos_
, CLIPFORMAT formats_
[], size_t formatsLen_
) {
2333 vtbl
= vtFormatEnumerator
;
2334 ref
= 0; // First QI adds first reference...
2336 formats
.insert(formats
.begin(), formats_
, formats_
+formatsLen_
);
2339 /// Implement IUnknown
2340 STDMETHODIMP
DropSource_QueryInterface(DropSource
*ds
, REFIID riid
, PVOID
*ppv
) {
2341 return ds
->sci
->QueryInterface(riid
, ppv
);
2343 STDMETHODIMP_(ULONG
)DropSource_AddRef(DropSource
*ds
) {
2344 return ds
->sci
->AddRef();
2346 STDMETHODIMP_(ULONG
)DropSource_Release(DropSource
*ds
) {
2347 return ds
->sci
->Release();
2350 /// Implement IDropSource
2351 STDMETHODIMP
DropSource_QueryContinueDrag(DropSource
*, BOOL fEsc
, DWORD grfKeyState
) {
2353 return DRAGDROP_S_CANCEL
;
2354 if (!(grfKeyState
& MK_LBUTTON
))
2355 return DRAGDROP_S_DROP
;
2359 STDMETHODIMP
DropSource_GiveFeedback(DropSource
*, DWORD
) {
2360 return DRAGDROP_S_USEDEFAULTCURSORS
;
2363 static VFunction
*vtDropSource
[] = {
2364 (VFunction
*)(DropSource_QueryInterface
),
2365 (VFunction
*)(DropSource_AddRef
),
2366 (VFunction
*)(DropSource_Release
),
2367 (VFunction
*)(DropSource_QueryContinueDrag
),
2368 (VFunction
*)(DropSource_GiveFeedback
)
2371 DropSource::DropSource() {
2372 vtbl
= vtDropSource
;
2376 /// Implement IUnkown
2377 STDMETHODIMP
DataObject_QueryInterface(DataObject
*pd
, REFIID riid
, PVOID
*ppv
) {
2378 //Platform::DebugPrintf("DO QI %x\n", pd);
2379 return pd
->sci
->QueryInterface(riid
, ppv
);
2381 STDMETHODIMP_(ULONG
)DataObject_AddRef(DataObject
*pd
) {
2382 return pd
->sci
->AddRef();
2384 STDMETHODIMP_(ULONG
)DataObject_Release(DataObject
*pd
) {
2385 return pd
->sci
->Release();
2387 /// Implement IDataObject
2388 STDMETHODIMP
DataObject_GetData(DataObject
*pd
, FORMATETC
*pFEIn
, STGMEDIUM
*pSTM
) {
2389 return pd
->sci
->GetData(pFEIn
, pSTM
);
2392 STDMETHODIMP
DataObject_GetDataHere(DataObject
*, FORMATETC
*, STGMEDIUM
*) {
2393 //Platform::DebugPrintf("DOB GetDataHere\n");
2397 STDMETHODIMP
DataObject_QueryGetData(DataObject
*pd
, FORMATETC
*pFE
) {
2398 if (pd
->sci
->DragIsRectangularOK(pFE
->cfFormat
) &&
2400 (pFE
->dwAspect
& DVASPECT_CONTENT
) != 0 &&
2401 pFE
->lindex
== -1 &&
2402 (pFE
->tymed
& TYMED_HGLOBAL
) != 0
2407 bool formatOK
= (pFE
->cfFormat
== CF_TEXT
) ||
2408 ((pFE
->cfFormat
== CF_UNICODETEXT
) && pd
->sci
->IsUnicodeMode());
2411 (pFE
->dwAspect
& DVASPECT_CONTENT
) == 0 ||
2412 pFE
->lindex
!= -1 ||
2413 (pFE
->tymed
& TYMED_HGLOBAL
) == 0
2415 //Platform::DebugPrintf("DOB QueryGetData No %x\n",pFE->cfFormat);
2416 //return DATA_E_FORMATETC;
2419 //Platform::DebugPrintf("DOB QueryGetData OK %x\n",pFE->cfFormat);
2423 STDMETHODIMP
DataObject_GetCanonicalFormatEtc(DataObject
*pd
, FORMATETC
*, FORMATETC
*pFEOut
) {
2424 //Platform::DebugPrintf("DOB GetCanon\n");
2425 if (pd
->sci
->IsUnicodeMode())
2426 pFEOut
->cfFormat
= CF_UNICODETEXT
;
2428 pFEOut
->cfFormat
= CF_TEXT
;
2430 pFEOut
->dwAspect
= DVASPECT_CONTENT
;
2431 pFEOut
->lindex
= -1;
2432 pFEOut
->tymed
= TYMED_HGLOBAL
;
2436 STDMETHODIMP
DataObject_SetData(DataObject
*, FORMATETC
*, STGMEDIUM
*, BOOL
) {
2437 //Platform::DebugPrintf("DOB SetData\n");
2441 STDMETHODIMP
DataObject_EnumFormatEtc(DataObject
*pd
, DWORD dwDirection
, IEnumFORMATETC
**ppEnum
) {
2443 //Platform::DebugPrintf("DOB EnumFormatEtc %d\n", dwDirection);
2444 if (dwDirection
!= DATADIR_GET
) {
2448 FormatEnumerator
*pfe
;
2449 if (pd
->sci
->IsUnicodeMode()) {
2450 CLIPFORMAT formats
[] = {CF_UNICODETEXT
, CF_TEXT
};
2451 pfe
= new FormatEnumerator(0, formats
, ELEMENTS(formats
));
2453 CLIPFORMAT formats
[] = {CF_TEXT
};
2454 pfe
= new FormatEnumerator(0, formats
, ELEMENTS(formats
));
2456 return FormatEnumerator_QueryInterface(pfe
, IID_IEnumFORMATETC
,
2457 reinterpret_cast<void **>(ppEnum
));
2458 } catch (std::bad_alloc
&) {
2459 pd
->sci
->errorStatus
= SC_STATUS_BADALLOC
;
2460 return E_OUTOFMEMORY
;
2462 pd
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2467 STDMETHODIMP
DataObject_DAdvise(DataObject
*, FORMATETC
*, DWORD
, IAdviseSink
*, PDWORD
) {
2468 //Platform::DebugPrintf("DOB DAdvise\n");
2472 STDMETHODIMP
DataObject_DUnadvise(DataObject
*, DWORD
) {
2473 //Platform::DebugPrintf("DOB DUnadvise\n");
2477 STDMETHODIMP
DataObject_EnumDAdvise(DataObject
*, IEnumSTATDATA
**) {
2478 //Platform::DebugPrintf("DOB EnumDAdvise\n");
2482 static VFunction
*vtDataObject
[] = {
2483 (VFunction
*)(DataObject_QueryInterface
),
2484 (VFunction
*)(DataObject_AddRef
),
2485 (VFunction
*)(DataObject_Release
),
2486 (VFunction
*)(DataObject_GetData
),
2487 (VFunction
*)(DataObject_GetDataHere
),
2488 (VFunction
*)(DataObject_QueryGetData
),
2489 (VFunction
*)(DataObject_GetCanonicalFormatEtc
),
2490 (VFunction
*)(DataObject_SetData
),
2491 (VFunction
*)(DataObject_EnumFormatEtc
),
2492 (VFunction
*)(DataObject_DAdvise
),
2493 (VFunction
*)(DataObject_DUnadvise
),
2494 (VFunction
*)(DataObject_EnumDAdvise
)
2497 DataObject::DataObject() {
2498 vtbl
= vtDataObject
;
2502 /// Implement IUnknown
2503 STDMETHODIMP
DropTarget_QueryInterface(DropTarget
*dt
, REFIID riid
, PVOID
*ppv
) {
2504 //Platform::DebugPrintf("DT QI %x\n", dt);
2505 return dt
->sci
->QueryInterface(riid
, ppv
);
2507 STDMETHODIMP_(ULONG
)DropTarget_AddRef(DropTarget
*dt
) {
2508 return dt
->sci
->AddRef();
2510 STDMETHODIMP_(ULONG
)DropTarget_Release(DropTarget
*dt
) {
2511 return dt
->sci
->Release();
2514 /// Implement IDropTarget by forwarding to Scintilla
2515 STDMETHODIMP
DropTarget_DragEnter(DropTarget
*dt
, LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
2516 POINTL pt
, PDWORD pdwEffect
) {
2518 return dt
->sci
->DragEnter(pIDataSource
, grfKeyState
, pt
, pdwEffect
);
2520 dt
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2524 STDMETHODIMP
DropTarget_DragOver(DropTarget
*dt
, DWORD grfKeyState
, POINTL pt
, PDWORD pdwEffect
) {
2526 return dt
->sci
->DragOver(grfKeyState
, pt
, pdwEffect
);
2528 dt
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2532 STDMETHODIMP
DropTarget_DragLeave(DropTarget
*dt
) {
2534 return dt
->sci
->DragLeave();
2536 dt
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2540 STDMETHODIMP
DropTarget_Drop(DropTarget
*dt
, LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
2541 POINTL pt
, PDWORD pdwEffect
) {
2543 return dt
->sci
->Drop(pIDataSource
, grfKeyState
, pt
, pdwEffect
);
2545 dt
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2550 static VFunction
*vtDropTarget
[] = {
2551 (VFunction
*)(DropTarget_QueryInterface
),
2552 (VFunction
*)(DropTarget_AddRef
),
2553 (VFunction
*)(DropTarget_Release
),
2554 (VFunction
*)(DropTarget_DragEnter
),
2555 (VFunction
*)(DropTarget_DragOver
),
2556 (VFunction
*)(DropTarget_DragLeave
),
2557 (VFunction
*)(DropTarget_Drop
)
2560 DropTarget::DropTarget() {
2561 vtbl
= vtDropTarget
;
2566 * DBCS: support Input Method Editor (IME).
2567 * Called when IME Window opened.
2569 void ScintillaWin::ImeStartComposition() {
2571 // Move IME Window to current caret position
2572 HIMC hIMC
= ::ImmGetContext(MainHWND());
2573 Point pos
= PointMainCaret();
2574 COMPOSITIONFORM CompForm
;
2575 CompForm
.dwStyle
= CFS_POINT
;
2576 CompForm
.ptCurrentPos
.x
= static_cast<int>(pos
.x
);
2577 CompForm
.ptCurrentPos
.y
= static_cast<int>(pos
.y
);
2579 ::ImmSetCompositionWindow(hIMC
, &CompForm
);
2581 // Set font of IME window to same as surrounded text.
2583 // Since the style creation code has been made platform independent,
2584 // The logfont for the IME is recreated here.
2585 int styleHere
= (pdoc
->StyleAt(sel
.MainCaret())) & 31;
2586 LOGFONTW lf
= {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L
""};
2587 int sizeZoomed
= vs
.styles
[styleHere
].size
+ vs
.zoomLevel
* SC_FONT_SIZE_MULTIPLIER
;
2588 if (sizeZoomed
<= 2 * SC_FONT_SIZE_MULTIPLIER
) // Hangs if sizeZoomed <= 1
2589 sizeZoomed
= 2 * SC_FONT_SIZE_MULTIPLIER
;
2590 AutoSurface
surface(this);
2591 int deviceHeight
= sizeZoomed
;
2593 deviceHeight
= (sizeZoomed
* surface
->LogPixelsY()) / 72;
2595 // The negative is to allow for leading
2596 lf
.lfHeight
= -(abs(deviceHeight
/ SC_FONT_SIZE_MULTIPLIER
));
2597 lf
.lfWeight
= vs
.styles
[styleHere
].weight
;
2598 lf
.lfItalic
= static_cast<BYTE
>(vs
.styles
[styleHere
].italic
? 1 : 0);
2599 lf
.lfCharSet
= DEFAULT_CHARSET
;
2600 lf
.lfFaceName
[0] = L
'\0';
2601 if (vs
.styles
[styleHere
].fontName
) {
2602 const char* fontName
= vs
.styles
[styleHere
].fontName
;
2603 UTF16FromUTF8(fontName
, strlen(fontName
)+1, lf
.lfFaceName
, LF_FACESIZE
);
2606 ::ImmSetCompositionFontW(hIMC
, &lf
);
2608 ::ImmReleaseContext(MainHWND(), hIMC
);
2609 // Caret is displayed in IME window. So, caret in Scintilla is useless.
2614 /** Called when IME Window closed. */
2615 void ScintillaWin::ImeEndComposition() {
2616 ShowCaretAtCurrentPosition();
2619 void ScintillaWin::GetIntelliMouseParameters() {
2620 // This retrieves the number of lines per scroll as configured inthe Mouse Properties sheet in Control Panel
2621 ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0, &linesPerScroll
, 0);
2624 void ScintillaWin::CopyToClipboard(const SelectionText
&selectedText
) {
2625 if (!::OpenClipboard(MainHWND()))
2629 GlobalMemory uniText
;
2631 // Default Scintilla behaviour in Unicode mode
2632 if (IsUnicodeMode()) {
2633 size_t uchars
= UTF16Length(selectedText
.Data(),
2634 static_cast<int>(selectedText
.LengthWithTerminator()));
2635 uniText
.Allocate(2 * uchars
);
2637 UTF16FromUTF8(selectedText
.Data(), selectedText
.LengthWithTerminator(),
2638 static_cast<wchar_t *>(uniText
.ptr
), uchars
);
2642 // Convert to Unicode using the current Scintilla code page
2643 UINT cpSrc
= CodePageFromCharSet(
2644 selectedText
.characterSet
, selectedText
.codePage
);
2645 int uLen
= ::MultiByteToWideChar(cpSrc
, 0, selectedText
.Data(),
2646 static_cast<int>(selectedText
.LengthWithTerminator()), 0, 0);
2647 uniText
.Allocate(2 * uLen
);
2649 ::MultiByteToWideChar(cpSrc
, 0, selectedText
.Data(),
2650 static_cast<int>(selectedText
.LengthWithTerminator()),
2651 static_cast<wchar_t *>(uniText
.ptr
), uLen
);
2656 uniText
.SetClip(CF_UNICODETEXT
);
2658 // There was a failure - try to copy at least ANSI text
2659 GlobalMemory ansiText
;
2660 ansiText
.Allocate(selectedText
.LengthWithTerminator());
2662 memcpy(static_cast<char *>(ansiText
.ptr
), selectedText
.Data(), selectedText
.LengthWithTerminator());
2663 ansiText
.SetClip(CF_TEXT
);
2667 if (selectedText
.rectangular
) {
2668 ::SetClipboardData(cfColumnSelect
, 0);
2670 GlobalMemory borlandSelection
;
2671 borlandSelection
.Allocate(1);
2672 if (borlandSelection
) {
2673 static_cast<BYTE
*>(borlandSelection
.ptr
)[0] = 0x02;
2674 borlandSelection
.SetClip(cfBorlandIDEBlockType
);
2678 if (selectedText
.lineCopy
) {
2679 ::SetClipboardData(cfLineSelect
, 0);
2680 ::SetClipboardData(cfVSLineTag
, 0);
2686 void ScintillaWin::ScrollMessage(WPARAM wParam
) {
2687 //DWORD dwStart = timeGetTime();
2688 //Platform::DebugPrintf("Scroll %x %d\n", wParam, lParam);
2690 SCROLLINFO sci
= {};
2691 sci
.cbSize
= sizeof(sci
);
2692 sci
.fMask
= SIF_ALL
;
2694 GetScrollInfo(SB_VERT
, &sci
);
2696 //Platform::DebugPrintf("ScrollInfo %d mask=%x min=%d max=%d page=%d pos=%d track=%d\n", b,sci.fMask,
2697 //sci.nMin, sci.nMax, sci.nPage, sci.nPos, sci.nTrackPos);
2699 int topLineNew
= topLine
;
2700 switch (LoWord(wParam
)) {
2708 topLineNew
-= LinesToScroll(); break;
2709 case SB_PAGEDOWN
: topLineNew
+= LinesToScroll(); break;
2710 case SB_TOP
: topLineNew
= 0; break;
2711 case SB_BOTTOM
: topLineNew
= MaxScrollPos(); break;
2712 case SB_THUMBPOSITION
: topLineNew
= sci
.nTrackPos
; break;
2713 case SB_THUMBTRACK
: topLineNew
= sci
.nTrackPos
; break;
2715 ScrollTo(topLineNew
);
2718 void ScintillaWin::HorizontalScrollMessage(WPARAM wParam
) {
2720 PRectangle rcText
= GetTextRectangle();
2721 int pageWidth
= static_cast<int>(rcText
.Width() * 2 / 3);
2722 switch (LoWord(wParam
)) {
2726 case SB_LINEDOWN
: // May move past the logical end
2734 if (xPos
> scrollWidth
- rcText
.Width()) { // Hit the end exactly
2735 xPos
= scrollWidth
- static_cast<int>(rcText
.Width());
2744 case SB_THUMBPOSITION
:
2745 case SB_THUMBTRACK
: {
2746 // Do NOT use wParam, its 16 bit and not enough for very long lines. Its still possible to overflow the 32 bit but you have to try harder =]
2748 si
.cbSize
= sizeof(si
);
2749 si
.fMask
= SIF_TRACKPOS
;
2750 if (GetScrollInfo(SB_HORZ
, &si
)) {
2751 xPos
= si
.nTrackPos
;
2756 HorizontalScrollTo(xPos
);
2760 * Redraw all of text area.
2761 * This paint will not be abandoned.
2763 void ScintillaWin::FullPaint() {
2764 if ((technology
== SC_TECHNOLOGY_DEFAULT
) || (technology
== SC_TECHNOLOGY_DIRECTWRITEDC
)) {
2765 HDC hdc
= ::GetDC(MainHWND());
2767 ::ReleaseDC(MainHWND(), hdc
);
2774 * Redraw all of text area on the specified DC.
2775 * This paint will not be abandoned.
2777 void ScintillaWin::FullPaintDC(HDC hdc
) {
2778 paintState
= painting
;
2779 rcPaint
= GetClientRectangle();
2780 paintingAllText
= true;
2781 if (technology
== SC_TECHNOLOGY_DEFAULT
) {
2782 AutoSurface
surfaceWindow(hdc
, this);
2783 if (surfaceWindow
) {
2784 Paint(surfaceWindow
, rcPaint
);
2785 surfaceWindow
->Release();
2788 #if defined(USE_D2D)
2789 EnsureRenderTarget(hdc
);
2790 AutoSurface
surfaceWindow(pRenderTarget
, this);
2791 if (surfaceWindow
) {
2792 pRenderTarget
->BeginDraw();
2793 Paint(surfaceWindow
, rcPaint
);
2794 surfaceWindow
->Release();
2795 HRESULT hr
= pRenderTarget
->EndDraw();
2796 if (hr
== D2DERR_RECREATE_TARGET
) {
2802 paintState
= notPainting
;
2805 static bool CompareDevCap(HDC hdc
, HDC hOtherDC
, int nIndex
) {
2806 return ::GetDeviceCaps(hdc
, nIndex
) == ::GetDeviceCaps(hOtherDC
, nIndex
);
2809 bool ScintillaWin::IsCompatibleDC(HDC hOtherDC
) {
2810 HDC hdc
= ::GetDC(MainHWND());
2812 CompareDevCap(hdc
, hOtherDC
, TECHNOLOGY
) &&
2813 CompareDevCap(hdc
, hOtherDC
, LOGPIXELSY
) &&
2814 CompareDevCap(hdc
, hOtherDC
, LOGPIXELSX
) &&
2815 CompareDevCap(hdc
, hOtherDC
, BITSPIXEL
) &&
2816 CompareDevCap(hdc
, hOtherDC
, PLANES
);
2817 ::ReleaseDC(MainHWND(), hdc
);
2818 return isCompatible
;
2821 DWORD
ScintillaWin::EffectFromState(DWORD grfKeyState
) const {
2822 // These are the Wordpad semantics.
2824 if (inDragDrop
== ddDragging
) // Internal defaults to move
2825 dwEffect
= DROPEFFECT_MOVE
;
2827 dwEffect
= DROPEFFECT_COPY
;
2828 if (grfKeyState
& MK_ALT
)
2829 dwEffect
= DROPEFFECT_MOVE
;
2830 if (grfKeyState
& MK_CONTROL
)
2831 dwEffect
= DROPEFFECT_COPY
;
2835 /// Implement IUnknown
2836 STDMETHODIMP
ScintillaWin::QueryInterface(REFIID riid
, PVOID
*ppv
) {
2838 if (riid
== IID_IUnknown
)
2839 *ppv
= reinterpret_cast<IDropTarget
*>(&dt
);
2840 if (riid
== IID_IDropSource
)
2841 *ppv
= reinterpret_cast<IDropSource
*>(&ds
);
2842 if (riid
== IID_IDropTarget
)
2843 *ppv
= reinterpret_cast<IDropTarget
*>(&dt
);
2844 if (riid
== IID_IDataObject
)
2845 *ppv
= reinterpret_cast<IDataObject
*>(&dob
);
2847 return E_NOINTERFACE
;
2851 STDMETHODIMP_(ULONG
) ScintillaWin::AddRef() {
2855 STDMETHODIMP_(ULONG
) ScintillaWin::Release() {
2859 /// Implement IDropTarget
2860 STDMETHODIMP
ScintillaWin::DragEnter(LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
2861 POINTL
, PDWORD pdwEffect
) {
2862 if (pIDataSource
== NULL
)
2864 FORMATETC fmtu
= {CF_UNICODETEXT
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2865 HRESULT hrHasUText
= pIDataSource
->QueryGetData(&fmtu
);
2866 hasOKText
= (hrHasUText
== S_OK
);
2868 FORMATETC fmte
= {CF_TEXT
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2869 HRESULT hrHasText
= pIDataSource
->QueryGetData(&fmte
);
2870 hasOKText
= (hrHasText
== S_OK
);
2873 *pdwEffect
= DROPEFFECT_NONE
;
2877 *pdwEffect
= EffectFromState(grfKeyState
);
2881 STDMETHODIMP
ScintillaWin::DragOver(DWORD grfKeyState
, POINTL pt
, PDWORD pdwEffect
) {
2883 if (!hasOKText
|| pdoc
->IsReadOnly()) {
2884 *pdwEffect
= DROPEFFECT_NONE
;
2888 *pdwEffect
= EffectFromState(grfKeyState
);
2890 // Update the cursor.
2891 POINT rpt
= {pt
.x
, pt
.y
};
2892 ::ScreenToClient(MainHWND(), &rpt
);
2893 SetDragPosition(SPositionFromLocation(PointFromPOINT(rpt
), false, false, UserVirtualSpace()));
2897 errorStatus
= SC_STATUS_FAILURE
;
2902 STDMETHODIMP
ScintillaWin::DragLeave() {
2904 SetDragPosition(SelectionPosition(invalidPosition
));
2907 errorStatus
= SC_STATUS_FAILURE
;
2912 STDMETHODIMP
ScintillaWin::Drop(LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
2913 POINTL pt
, PDWORD pdwEffect
) {
2915 *pdwEffect
= EffectFromState(grfKeyState
);
2917 if (pIDataSource
== NULL
)
2920 SetDragPosition(SelectionPosition(invalidPosition
));
2922 STGMEDIUM medium
= {0, {0}, 0};
2924 std::vector
<char> data
; // Includes terminating NUL
2926 FORMATETC fmtu
= {CF_UNICODETEXT
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2927 HRESULT hr
= pIDataSource
->GetData(&fmtu
, &medium
);
2928 if (SUCCEEDED(hr
) && medium
.hGlobal
) {
2929 GlobalMemory
memUDrop(medium
.hGlobal
);
2930 wchar_t *udata
= static_cast<wchar_t *>(memUDrop
.ptr
);
2932 if (IsUnicodeMode()) {
2933 int tlen
= static_cast<int>(memUDrop
.Size());
2934 // Convert UTF-16 to UTF-8
2935 int dataLen
= UTF8Length(udata
, tlen
/2);
2936 data
.resize(dataLen
+1);
2937 UTF8FromUTF16(udata
, tlen
/2, &data
[0], dataLen
);
2939 // Convert UTF-16 to ANSI
2941 // Default Scintilla behavior in Unicode mode
2942 // CF_UNICODETEXT available, but not in Unicode mode
2943 // Convert from Unicode to current Scintilla code page
2944 UINT cpDest
= CodePageOfDocument();
2945 int tlen
= ::WideCharToMultiByte(cpDest
, 0, udata
, -1,
2946 NULL
, 0, NULL
, NULL
) - 1; // subtract 0 terminator
2947 data
.resize(tlen
+ 1);
2948 ::WideCharToMultiByte(cpDest
, 0, udata
, -1,
2949 &data
[0], tlen
+ 1, NULL
, NULL
);
2954 FORMATETC fmte
= {CF_TEXT
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2955 hr
= pIDataSource
->GetData(&fmte
, &medium
);
2956 if (SUCCEEDED(hr
) && medium
.hGlobal
) {
2957 GlobalMemory
memDrop(medium
.hGlobal
);
2958 const char *cdata
= static_cast<char *>(memDrop
.ptr
);
2960 data
.assign(cdata
, cdata
+strlen(cdata
)+1);
2965 if (!SUCCEEDED(hr
) || data
.empty()) {
2966 //Platform::DebugPrintf("Bad data format: 0x%x\n", hres);
2970 FORMATETC fmtr
= {cfColumnSelect
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2971 HRESULT hrRectangular
= pIDataSource
->QueryGetData(&fmtr
);
2973 POINT rpt
= {pt
.x
, pt
.y
};
2974 ::ScreenToClient(MainHWND(), &rpt
);
2975 SelectionPosition movePos
= SPositionFromLocation(PointFromPOINT(rpt
), false, false, UserVirtualSpace());
2977 DropAt(movePos
, &data
[0], data
.size() - 1, *pdwEffect
== DROPEFFECT_MOVE
, hrRectangular
== S_OK
);
2980 if (medium
.pUnkForRelease
!= NULL
)
2981 medium
.pUnkForRelease
->Release();
2983 ::GlobalFree(medium
.hGlobal
);
2987 errorStatus
= SC_STATUS_FAILURE
;
2992 /// Implement important part of IDataObject
2993 STDMETHODIMP
ScintillaWin::GetData(FORMATETC
*pFEIn
, STGMEDIUM
*pSTM
) {
2994 bool formatOK
= (pFEIn
->cfFormat
== CF_TEXT
) ||
2995 ((pFEIn
->cfFormat
== CF_UNICODETEXT
) && IsUnicodeMode());
2998 (pFEIn
->dwAspect
& DVASPECT_CONTENT
) == 0 ||
2999 pFEIn
->lindex
!= -1 ||
3000 (pFEIn
->tymed
& TYMED_HGLOBAL
) == 0
3002 //Platform::DebugPrintf("DOB GetData No %d %x %x fmt=%x\n", lenDrag, pFEIn, pSTM, pFEIn->cfFormat);
3003 return DATA_E_FORMATETC
;
3005 pSTM
->tymed
= TYMED_HGLOBAL
;
3006 //Platform::DebugPrintf("DOB GetData OK %d %x %x\n", lenDrag, pFEIn, pSTM);
3009 if (pFEIn
->cfFormat
== CF_UNICODETEXT
) {
3010 size_t uchars
= UTF16Length(drag
.Data(), static_cast<int>(drag
.LengthWithTerminator()));
3011 text
.Allocate(2 * uchars
);
3013 UTF16FromUTF8(drag
.Data(), drag
.LengthWithTerminator(),
3014 static_cast<wchar_t *>(text
.ptr
), uchars
);
3017 text
.Allocate(drag
.LengthWithTerminator());
3019 memcpy(static_cast<char *>(text
.ptr
), drag
.Data(), drag
.LengthWithTerminator());
3022 pSTM
->hGlobal
= text
? text
.Unlock() : 0;
3023 pSTM
->pUnkForRelease
= 0;
3027 bool ScintillaWin::Register(HINSTANCE hInstance_
) {
3029 hInstance
= hInstance_
;
3032 // Register the Scintilla class
3033 // Register Scintilla as a wide character window
3034 WNDCLASSEXW wndclass
;
3035 wndclass
.cbSize
= sizeof(wndclass
);
3036 wndclass
.style
= CS_GLOBALCLASS
| CS_HREDRAW
| CS_VREDRAW
;
3037 wndclass
.lpfnWndProc
= ScintillaWin::SWndProc
;
3038 wndclass
.cbClsExtra
= 0;
3039 wndclass
.cbWndExtra
= sizeof(ScintillaWin
*);
3040 wndclass
.hInstance
= hInstance
;
3041 wndclass
.hIcon
= NULL
;
3042 wndclass
.hCursor
= NULL
;
3043 wndclass
.hbrBackground
= NULL
;
3044 wndclass
.lpszMenuName
= NULL
;
3045 wndclass
.lpszClassName
= L
"Scintilla";
3046 wndclass
.hIconSm
= 0;
3047 scintillaClassAtom
= ::RegisterClassExW(&wndclass
);
3048 result
= 0 != scintillaClassAtom
;
3051 // Register the CallTip class
3052 WNDCLASSEX wndclassc
;
3053 wndclassc
.cbSize
= sizeof(wndclassc
);
3054 wndclassc
.style
= CS_GLOBALCLASS
| CS_HREDRAW
| CS_VREDRAW
;
3055 wndclassc
.cbClsExtra
= 0;
3056 wndclassc
.cbWndExtra
= sizeof(ScintillaWin
*);
3057 wndclassc
.hInstance
= hInstance
;
3058 wndclassc
.hIcon
= NULL
;
3059 wndclassc
.hbrBackground
= NULL
;
3060 wndclassc
.lpszMenuName
= NULL
;
3061 wndclassc
.lpfnWndProc
= ScintillaWin::CTWndProc
;
3062 wndclassc
.hCursor
= ::LoadCursor(NULL
, IDC_ARROW
);
3063 wndclassc
.lpszClassName
= callClassName
;
3064 wndclassc
.hIconSm
= 0;
3066 callClassAtom
= ::RegisterClassEx(&wndclassc
);
3067 result
= 0 != callClassAtom
;
3073 bool ScintillaWin::Unregister() {
3075 if (0 != scintillaClassAtom
) {
3076 if (::UnregisterClass(MAKEINTATOM(scintillaClassAtom
), hInstance
) == 0) {
3079 scintillaClassAtom
= 0;
3081 if (0 != callClassAtom
) {
3082 if (::UnregisterClass(MAKEINTATOM(callClassAtom
), hInstance
) == 0) {
3090 bool ScintillaWin::HasCaretSizeChanged() const {
3092 ( (0 != vs
.caretWidth
) && (sysCaretWidth
!= vs
.caretWidth
) )
3093 || ((0 != vs
.lineHeight
) && (sysCaretHeight
!= vs
.lineHeight
))
3100 BOOL
ScintillaWin::CreateSystemCaret() {
3101 sysCaretWidth
= vs
.caretWidth
;
3102 if (0 == sysCaretWidth
) {
3105 sysCaretHeight
= vs
.lineHeight
;
3106 int bitmapSize
= (((sysCaretWidth
+ 15) & ~15) >> 3) *
3108 std::vector
<char> bits(bitmapSize
);
3109 sysCaretBitmap
= ::CreateBitmap(sysCaretWidth
, sysCaretHeight
, 1,
3110 1, reinterpret_cast<BYTE
*>(&bits
[0]));
3111 BOOL retval
= ::CreateCaret(
3112 MainHWND(), sysCaretBitmap
,
3113 sysCaretWidth
, sysCaretHeight
);
3114 if (technology
== SC_TECHNOLOGY_DEFAULT
) {
3115 // System caret interferes with Direct2D drawing so only show it for GDI.
3116 ::ShowCaret(MainHWND());
3121 BOOL
ScintillaWin::DestroySystemCaret() {
3122 ::HideCaret(MainHWND());
3123 BOOL retval
= ::DestroyCaret();
3124 if (sysCaretBitmap
) {
3125 ::DeleteObject(sysCaretBitmap
);
3131 sptr_t PASCAL
ScintillaWin::CTWndProc(
3132 HWND hWnd
, UINT iMessage
, WPARAM wParam
, sptr_t lParam
) {
3133 // Find C++ object associated with window.
3134 ScintillaWin
*sciThis
= reinterpret_cast<ScintillaWin
*>(PointerFromWindow(hWnd
));
3136 // ctp will be zero if WM_CREATE not seen yet
3138 if (iMessage
== WM_CREATE
) {
3139 // Associate CallTip object with window
3140 CREATESTRUCT
*pCreate
= reinterpret_cast<CREATESTRUCT
*>(lParam
);
3141 SetWindowPointer(hWnd
, pCreate
->lpCreateParams
);
3144 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
3147 if (iMessage
== WM_NCDESTROY
) {
3148 ::SetWindowLong(hWnd
, 0, 0);
3149 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
3150 } else if (iMessage
== WM_PAINT
) {
3152 ::BeginPaint(hWnd
, &ps
);
3153 Surface
*surfaceWindow
= Surface::Allocate(sciThis
->technology
);
3154 if (surfaceWindow
) {
3155 #if defined(USE_D2D)
3156 ID2D1HwndRenderTarget
*pCTRenderTarget
= 0;
3159 GetClientRect(hWnd
, &rc
);
3160 // Create a Direct2D render target.
3161 if (sciThis
->technology
== SC_TECHNOLOGY_DEFAULT
) {
3162 surfaceWindow
->Init(ps
.hdc
, hWnd
);
3164 #if defined(USE_D2D)
3165 D2D1_HWND_RENDER_TARGET_PROPERTIES dhrtp
;
3167 dhrtp
.pixelSize
= D2D1::SizeU(rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
3168 dhrtp
.presentOptions
= (sciThis
->technology
== SC_TECHNOLOGY_DIRECTWRITERETAIN
) ?
3169 D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS
: D2D1_PRESENT_OPTIONS_NONE
;
3171 D2D1_RENDER_TARGET_PROPERTIES drtp
;
3172 drtp
.type
= D2D1_RENDER_TARGET_TYPE_DEFAULT
;
3173 drtp
.pixelFormat
.format
= DXGI_FORMAT_UNKNOWN
;
3174 drtp
.pixelFormat
.alphaMode
= D2D1_ALPHA_MODE_UNKNOWN
;
3177 drtp
.usage
= D2D1_RENDER_TARGET_USAGE_NONE
;
3178 drtp
.minLevel
= D2D1_FEATURE_LEVEL_DEFAULT
;
3180 if (!SUCCEEDED(pD2DFactory
->CreateHwndRenderTarget(drtp
, dhrtp
, &pCTRenderTarget
))) {
3181 surfaceWindow
->Release();
3182 delete surfaceWindow
;
3183 ::EndPaint(hWnd
, &ps
);
3186 surfaceWindow
->Init(pCTRenderTarget
, hWnd
);
3187 pCTRenderTarget
->BeginDraw();
3190 surfaceWindow
->SetUnicodeMode(SC_CP_UTF8
== sciThis
->ct
.codePage
);
3191 surfaceWindow
->SetDBCSMode(sciThis
->ct
.codePage
);
3192 sciThis
->ct
.PaintCT(surfaceWindow
);
3193 #if defined(USE_D2D)
3194 if (pCTRenderTarget
)
3195 pCTRenderTarget
->EndDraw();
3197 surfaceWindow
->Release();
3198 delete surfaceWindow
;
3199 #if defined(USE_D2D)
3200 if (pCTRenderTarget
)
3201 pCTRenderTarget
->Release();
3204 ::EndPaint(hWnd
, &ps
);
3206 } else if ((iMessage
== WM_NCLBUTTONDOWN
) || (iMessage
== WM_NCLBUTTONDBLCLK
)) {
3208 pt
.x
= static_cast<short>(LOWORD(lParam
));
3209 pt
.y
= static_cast<short>(HIWORD(lParam
));
3210 ScreenToClient(hWnd
, &pt
);
3211 sciThis
->ct
.MouseClick(PointFromPOINT(pt
));
3212 sciThis
->CallTipClick();
3214 } else if (iMessage
== WM_LBUTTONDOWN
) {
3215 // This does not fire due to the hit test code
3216 sciThis
->ct
.MouseClick(Point::FromLong(static_cast<long>(lParam
)));
3217 sciThis
->CallTipClick();
3219 } else if (iMessage
== WM_SETCURSOR
) {
3220 ::SetCursor(::LoadCursor(NULL
, IDC_ARROW
));
3222 } else if (iMessage
== WM_NCHITTEST
) {
3225 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
3229 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
3231 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
3234 sptr_t
ScintillaWin::DirectFunction(
3235 sptr_t ptr
, UINT iMessage
, uptr_t wParam
, sptr_t lParam
) {
3236 PLATFORM_ASSERT(::GetCurrentThreadId() == ::GetWindowThreadProcessId(reinterpret_cast<ScintillaWin
*>(ptr
)->MainHWND(), NULL
));
3237 return reinterpret_cast<ScintillaWin
*>(ptr
)->WndProc(iMessage
, wParam
, lParam
);
3241 #ifndef STATIC_BUILD
3242 __declspec(dllexport
)
3244 sptr_t __stdcall
Scintilla_DirectFunction(
3245 ScintillaWin
*sci
, UINT iMessage
, uptr_t wParam
, sptr_t lParam
) {
3246 return sci
->WndProc(iMessage
, wParam
, lParam
);
3249 sptr_t PASCAL
ScintillaWin::SWndProc(
3250 HWND hWnd
, UINT iMessage
, WPARAM wParam
, sptr_t lParam
) {
3251 //Platform::DebugPrintf("S W:%x M:%x WP:%x L:%x\n", hWnd, iMessage, wParam, lParam);
3253 // Find C++ object associated with window.
3254 ScintillaWin
*sci
= reinterpret_cast<ScintillaWin
*>(PointerFromWindow(hWnd
));
3255 // sci will be zero if WM_CREATE not seen yet
3258 if (iMessage
== WM_CREATE
) {
3259 // Create C++ object associated with window
3260 sci
= new ScintillaWin(hWnd
);
3261 SetWindowPointer(hWnd
, sci
);
3262 return sci
->WndProc(iMessage
, wParam
, lParam
);
3266 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
3268 if (iMessage
== WM_NCDESTROY
) {
3274 ::SetWindowLong(hWnd
, 0, 0);
3275 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
3277 return sci
->WndProc(iMessage
, wParam
, lParam
);
3282 // This function is externally visible so it can be called from container when building statically.
3283 // Must be called once only.
3284 int Scintilla_RegisterClasses(void *hInstance
) {
3285 Platform_Initialise(hInstance
);
3286 bool result
= ScintillaWin::Register(reinterpret_cast<HINSTANCE
>(hInstance
));
3288 Scintilla_LinkLexers();
3293 static int ResourcesRelease(bool fromDllMain
) {
3294 bool result
= ScintillaWin::Unregister();
3296 FreeLibrary(commctrl32
);
3299 Platform_Finalise(fromDllMain
);
3303 // This function is externally visible so it can be called from container when building statically.
3304 int Scintilla_ReleaseResources() {
3305 return ResourcesRelease(false);
3308 #ifndef STATIC_BUILD
3309 extern "C" int APIENTRY
DllMain(HINSTANCE hInstance
, DWORD dwReason
, LPVOID lpvReserved
) {
3310 //Platform::DebugPrintf("Scintilla::DllMain %d %d\n", hInstance, dwReason);
3311 if (dwReason
== DLL_PROCESS_ATTACH
) {
3312 if (!Scintilla_RegisterClasses(hInstance
))
3314 } else if (dwReason
== DLL_PROCESS_DETACH
) {
3315 if (lpvReserved
== NULL
) {
3316 ResourcesRelease(true);