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.
22 #define _WIN32_WINNT 0x0500
32 #if defined(NTDDI_WIN7) && !defined(DISABLE_D2D)
44 #include "Scintilla.h"
49 #include "StringCopy.h"
51 #include "LexerModule.h"
53 #include "SplitVector.h"
54 #include "Partitioning.h"
55 #include "RunStyles.h"
56 #include "ContractionState.h"
57 #include "CellBuffer.h"
60 #include "Indicator.h"
62 #include "LineMarker.h"
64 #include "ViewStyle.h"
65 #include "CharClassify.h"
66 #include "Decoration.h"
67 #include "CaseFolder.h"
69 #include "CaseConvert.h"
70 #include "UniConversion.h"
71 #include "Selection.h"
72 #include "PositionCache.h"
75 #include "AutoComplete.h"
76 #include "ScintillaBase.h"
79 #include "ExternalLexer.h"
84 #ifndef SPI_GETWHEELSCROLLLINES
85 #define SPI_GETWHEELSCROLLLINES 104
89 #define WM_UNICHAR 0x0109
92 #ifndef UNICODE_NOCHAR
93 #define UNICODE_NOCHAR 0xFFFF
100 #define SC_WIN_IDLE 5001
102 typedef BOOL (WINAPI
*TrackMouseEventSig
)(LPTRACKMOUSEEVENT
);
104 // GCC has trouble with the standard COM ABI so do it the old C way with explicit vtables.
106 const TCHAR scintillaClassName
[] = TEXT("Scintilla");
107 const TCHAR callClassName
[] = TEXT("CallTip");
110 using namespace Scintilla
;
113 static void *PointerFromWindow(HWND hWnd
) {
114 return reinterpret_cast<void *>(::GetWindowLongPtr(hWnd
, 0));
117 static void SetWindowPointer(HWND hWnd
, void *ptr
) {
118 ::SetWindowLongPtr(hWnd
, 0, reinterpret_cast<LONG_PTR
>(ptr
));
121 static void SetWindowID(HWND hWnd
, int identifier
) {
122 ::SetWindowLongPtr(hWnd
, GWLP_ID
, identifier
);
125 static Point
PointFromPOINT(POINT pt
) {
126 return Point::FromInts(pt
.x
, pt
.y
);
129 class ScintillaWin
; // Forward declaration for COM interface subobjects
131 typedef void VFunction(void);
133 static HMODULE commctrl32
= 0;
137 class FormatEnumerator
{
142 std::vector
<CLIPFORMAT
> formats
;
143 FormatEnumerator(int pos_
, CLIPFORMAT formats_
[], size_t formatsLen_
);
176 public ScintillaBase
{
178 bool lastKeyDownConsumed
;
181 bool trackedMouseLeave
;
182 TrackMouseEventSig TrackMouseEventFn
;
184 unsigned int linesPerScroll
; ///< Intellimouse support
185 int wheelDelta
; ///< Wheel delta from roll
191 CLIPFORMAT cfColumnSelect
;
192 CLIPFORMAT cfBorlandIDEBlockType
;
193 CLIPFORMAT cfLineSelect
;
200 static HINSTANCE hInstance
;
203 ID2D1HwndRenderTarget
*pRenderTarget
;
204 bool renderTargetValid
;
207 explicit ScintillaWin(HWND hwnd
);
208 ScintillaWin(const ScintillaWin
&);
209 virtual ~ScintillaWin();
210 ScintillaWin
&operator=(const ScintillaWin
&);
212 virtual void Initialise();
213 virtual void Finalise();
215 void EnsureRenderTarget();
216 void DropRenderTarget();
220 static sptr_t
DirectFunction(
221 sptr_t ptr
, UINT iMessage
, uptr_t wParam
, sptr_t lParam
);
222 static sptr_t PASCAL
SWndProc(
223 HWND hWnd
, UINT iMessage
, WPARAM wParam
, sptr_t lParam
);
224 static sptr_t PASCAL
CTWndProc(
225 HWND hWnd
, UINT iMessage
, WPARAM wParam
, sptr_t lParam
);
227 enum { invalidTimerID
, standardTimerID
, idleTimerID
};
229 virtual bool DragThreshold(Point ptStart
, Point ptNow
);
230 virtual void StartDrag();
231 sptr_t
WndPaint(uptr_t wParam
);
232 sptr_t
HandleComposition(uptr_t wParam
, sptr_t lParam
);
233 UINT
CodePageOfDocument();
234 virtual bool ValidCodePage(int codePage
) const;
235 virtual sptr_t
DefWndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
236 virtual bool SetIdle(bool on
);
237 virtual void SetTicking(bool on
);
238 virtual void SetMouseCapture(bool on
);
239 virtual bool HaveMouseCapture();
240 virtual void SetTrackMouseLeaveEvent(bool on
);
241 virtual bool PaintContains(PRectangle rc
);
242 virtual void ScrollText(int linesToMove
);
243 virtual void UpdateSystemCaret();
244 virtual void SetVerticalScrollPos();
245 virtual void SetHorizontalScrollPos();
246 virtual bool ModifyScrollBars(int nMax
, int nPage
);
247 virtual void NotifyChange();
248 virtual void NotifyFocus(bool focus
);
249 virtual void SetCtrlID(int identifier
);
250 virtual int GetCtrlID();
251 virtual void NotifyParent(SCNotification scn
);
252 virtual void NotifyParent(SCNotification
* scn
);
253 virtual void NotifyDoubleClick(Point pt
, int modifiers
);
254 virtual CaseFolder
*CaseFolderForEncoding();
255 virtual std::string
CaseMapString(const std::string
&s
, int caseMapping
);
257 virtual void CopyAllowLine();
258 virtual bool CanPaste();
259 virtual void Paste();
260 virtual void CreateCallTipWindow(PRectangle rc
);
261 virtual void AddToPopUp(const char *label
, int cmd
= 0, bool enabled
= true);
262 virtual void ClaimSelection();
265 void ImeStartComposition();
266 void ImeEndComposition();
268 void AddCharBytes(char b0
, char b1
);
270 void GetIntelliMouseParameters();
271 virtual void CopyToClipboard(const SelectionText
&selectedText
);
272 void ScrollMessage(WPARAM wParam
);
273 void HorizontalScrollMessage(WPARAM wParam
);
275 void FullPaintDC(HDC dc
);
276 bool IsCompatibleDC(HDC dc
);
277 DWORD
EffectFromState(DWORD grfKeyState
) const;
279 virtual int SetScrollInfo(int nBar
, LPCSCROLLINFO lpsi
, BOOL bRedraw
);
280 virtual bool GetScrollInfo(int nBar
, LPSCROLLINFO lpsi
);
281 void ChangeScrollPos(int barType
, int pos
);
282 sptr_t
GetTextLength();
283 sptr_t
GetText(uptr_t wParam
, sptr_t lParam
);
286 // Public for benefit of Scintilla_DirectFunction
287 virtual sptr_t
WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
289 /// Implement IUnknown
290 STDMETHODIMP
QueryInterface(REFIID riid
, PVOID
*ppv
);
291 STDMETHODIMP_(ULONG
)AddRef();
292 STDMETHODIMP_(ULONG
)Release();
294 /// Implement IDropTarget
295 STDMETHODIMP
DragEnter(LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
296 POINTL pt
, PDWORD pdwEffect
);
297 STDMETHODIMP
DragOver(DWORD grfKeyState
, POINTL pt
, PDWORD pdwEffect
);
298 STDMETHODIMP
DragLeave();
299 STDMETHODIMP
Drop(LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
300 POINTL pt
, PDWORD pdwEffect
);
302 /// Implement important part of IDataObject
303 STDMETHODIMP
GetData(FORMATETC
*pFEIn
, STGMEDIUM
*pSTM
);
305 static bool Register(HINSTANCE hInstance_
);
306 static bool Unregister();
308 friend class DropSource
;
309 friend class DataObject
;
310 friend class DropTarget
;
311 bool DragIsRectangularOK(CLIPFORMAT fmt
) const {
312 return drag
.rectangular
&& (fmt
== cfColumnSelect
);
316 // For use in creating a system caret
317 bool HasCaretSizeChanged() const;
318 BOOL
CreateSystemCaret();
319 BOOL
DestroySystemCaret();
320 HBITMAP sysCaretBitmap
;
323 bool keysAlwaysUnicode
;
326 HINSTANCE
ScintillaWin::hInstance
= 0;
328 ScintillaWin::ScintillaWin(HWND hwnd
) {
330 lastKeyDownConsumed
= false;
332 capturedMouse
= false;
333 trackedMouseLeave
= false;
334 TrackMouseEventFn
= 0;
337 wheelDelta
= 0; // Wheel delta from roll
343 // There does not seem to be a real standard for indicating that the clipboard
344 // contains a rectangular selection, so copy Developer Studio and Borland Delphi.
345 cfColumnSelect
= static_cast<CLIPFORMAT
>(
346 ::RegisterClipboardFormat(TEXT("MSDEVColumnSelect")));
347 cfBorlandIDEBlockType
= static_cast<CLIPFORMAT
>(
348 ::RegisterClipboardFormat(TEXT("Borland IDE Block Type")));
350 // Likewise for line-copy (copies a full line when no text is selected)
351 cfLineSelect
= static_cast<CLIPFORMAT
>(
352 ::RegisterClipboardFormat(TEXT("MSDEVLineSelect")));
368 renderTargetValid
= true;
371 keysAlwaysUnicode
= false;
373 caret
.period
= ::GetCaretBlinkTime();
374 if (caret
.period
< 0)
380 ScintillaWin::~ScintillaWin() {}
382 void ScintillaWin::Initialise() {
383 // Initialize COM. If the app has already done this it will have
384 // no effect. If the app hasnt, we really shouldnt ask them to call
385 // it just so this internal feature works.
386 hrOle
= ::OleInitialize(NULL
);
388 // Find TrackMouseEvent which is available on Windows > 95
389 HMODULE user32
= ::GetModuleHandle(TEXT("user32.dll"));
391 TrackMouseEventFn
= (TrackMouseEventSig
)::GetProcAddress(user32
, "TrackMouseEvent");
392 if (TrackMouseEventFn
== NULL
) {
393 // Windows 95 has an emulation in comctl32.dll:_TrackMouseEvent
395 commctrl32
= ::LoadLibrary(TEXT("comctl32.dll"));
396 if (commctrl32
!= NULL
) {
397 TrackMouseEventFn
= (TrackMouseEventSig
)
398 ::GetProcAddress(commctrl32
, "_TrackMouseEvent");
403 void ScintillaWin::Finalise() {
404 ScintillaBase::Finalise();
410 ::RevokeDragDrop(MainHWND());
411 if (SUCCEEDED(hrOle
)) {
418 void ScintillaWin::EnsureRenderTarget() {
419 if (!renderTargetValid
) {
421 renderTargetValid
= true;
423 if (pD2DFactory
&& !pRenderTarget
) {
425 HWND hw
= MainHWND();
426 GetClientRect(hw
, &rc
);
428 D2D1_SIZE_U size
= D2D1::SizeU(rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
430 // Create a Direct2D render target.
432 D2D1_HWND_RENDER_TARGET_PROPERTIES dhrtp
;
434 dhrtp
.pixelSize
= size
;
435 dhrtp
.presentOptions
= D2D1_PRESENT_OPTIONS_NONE
;
437 D2D1_RENDER_TARGET_PROPERTIES drtp
;
438 drtp
.type
= D2D1_RENDER_TARGET_TYPE_DEFAULT
;
439 drtp
.pixelFormat
.format
= DXGI_FORMAT_UNKNOWN
;
440 drtp
.pixelFormat
.alphaMode
= D2D1_ALPHA_MODE_UNKNOWN
;
443 drtp
.usage
= D2D1_RENDER_TARGET_USAGE_NONE
;
444 drtp
.minLevel
= D2D1_FEATURE_LEVEL_DEFAULT
;
446 pD2DFactory
->CreateHwndRenderTarget(drtp
, dhrtp
, &pRenderTarget
);
448 pD2DFactory
->CreateHwndRenderTarget(
449 D2D1::RenderTargetProperties(
450 D2D1_RENDER_TARGET_TYPE_DEFAULT
,
451 D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM
, D2D1_ALPHA_MODE_PREMULTIPLIED
),
452 96.0f
, 96.0f
, D2D1_RENDER_TARGET_USAGE_NONE
, D2D1_FEATURE_LEVEL_DEFAULT
),
453 D2D1::HwndRenderTargetProperties(hw
, size
),
456 // Pixmaps were created to be compatible with previous render target so
457 // need to be recreated.
462 void ScintillaWin::DropRenderTarget() {
464 pRenderTarget
->Release();
471 HWND
ScintillaWin::MainHWND() {
472 return reinterpret_cast<HWND
>(wMain
.GetID());
475 bool ScintillaWin::DragThreshold(Point ptStart
, Point ptNow
) {
476 int xMove
= static_cast<int>(abs(ptStart
.x
- ptNow
.x
));
477 int yMove
= static_cast<int>(abs(ptStart
.y
- ptNow
.y
));
478 return (xMove
> ::GetSystemMetrics(SM_CXDRAG
)) ||
479 (yMove
> ::GetSystemMetrics(SM_CYDRAG
));
482 void ScintillaWin::StartDrag() {
483 inDragDrop
= ddDragging
;
485 dropWentOutside
= true;
486 IDataObject
*pDataObject
= reinterpret_cast<IDataObject
*>(&dob
);
487 IDropSource
*pDropSource
= reinterpret_cast<IDropSource
*>(&ds
);
488 //Platform::DebugPrintf("About to DoDragDrop %x %x\n", pDataObject, pDropSource);
489 HRESULT hr
= ::DoDragDrop(
492 DROPEFFECT_COPY
| DROPEFFECT_MOVE
, &dwEffect
);
493 //Platform::DebugPrintf("DoDragDrop = %x\n", hr);
495 if ((hr
== DRAGDROP_S_DROP
) && (dwEffect
== DROPEFFECT_MOVE
) && dropWentOutside
) {
496 // Remove dragged out text
501 SetDragPosition(SelectionPosition(invalidPosition
));
504 // Avoid warnings everywhere for old style casts by concentrating them here
505 static WORD
LoWord(uptr_t l
) {
509 static WORD
HiWord(uptr_t l
) {
513 static int InputCodePage() {
514 HKL inputLocale
= ::GetKeyboardLayout(0);
515 LANGID inputLang
= LOWORD(inputLocale
);
517 int res
= ::GetLocaleInfoA(MAKELCID(inputLang
, SORT_DEFAULT
),
518 LOCALE_IDEFAULTANSICODEPAGE
, sCodePage
, sizeof(sCodePage
));
521 return atoi(sCodePage
);
524 /** Map the key codes to their equivalent SCK_ form. */
525 static int KeyTranslate(int keyIn
) {
526 //PLATFORM_ASSERT(!keyIn);
528 case VK_DOWN
: return SCK_DOWN
;
529 case VK_UP
: return SCK_UP
;
530 case VK_LEFT
: return SCK_LEFT
;
531 case VK_RIGHT
: return SCK_RIGHT
;
532 case VK_HOME
: return SCK_HOME
;
533 case VK_END
: return SCK_END
;
534 case VK_PRIOR
: return SCK_PRIOR
;
535 case VK_NEXT
: return SCK_NEXT
;
536 case VK_DELETE
: return SCK_DELETE
;
537 case VK_INSERT
: return SCK_INSERT
;
538 case VK_ESCAPE
: return SCK_ESCAPE
;
539 case VK_BACK
: return SCK_BACK
;
540 case VK_TAB
: return SCK_TAB
;
541 case VK_RETURN
: return SCK_RETURN
;
542 case VK_ADD
: return SCK_ADD
;
543 case VK_SUBTRACT
: return SCK_SUBTRACT
;
544 case VK_DIVIDE
: return SCK_DIVIDE
;
545 case VK_LWIN
: return SCK_WIN
;
546 case VK_RWIN
: return SCK_RWIN
;
547 case VK_APPS
: return SCK_MENU
;
548 case VK_OEM_2
: return '/';
549 case VK_OEM_3
: return '`';
550 case VK_OEM_4
: return '[';
551 case VK_OEM_5
: return '\\';
552 case VK_OEM_6
: return ']';
553 default: return keyIn
;
557 static bool BoundsContains(PRectangle rcBounds
, HRGN hRgnBounds
, PRectangle rcCheck
) {
558 bool contains
= true;
559 if (!rcCheck
.Empty()) {
560 if (!rcBounds
.Contains(rcCheck
)) {
562 } else if (hRgnBounds
) {
563 // In bounding rectangle so check more accurately using region
564 HRGN hRgnCheck
= ::CreateRectRgn(static_cast<int>(rcCheck
.left
), static_cast<int>(rcCheck
.top
),
565 static_cast<int>(rcCheck
.right
), static_cast<int>(rcCheck
.bottom
));
567 HRGN hRgnDifference
= ::CreateRectRgn(0, 0, 0, 0);
568 if (hRgnDifference
) {
569 int combination
= ::CombineRgn(hRgnDifference
, hRgnCheck
, hRgnBounds
, RGN_DIFF
);
570 if (combination
!= NULLREGION
) {
573 ::DeleteRgn(hRgnDifference
);
575 ::DeleteRgn(hRgnCheck
);
582 LRESULT
ScintillaWin::WndPaint(uptr_t wParam
) {
585 // Redirect assertions to debug output and save current state
586 bool assertsPopup
= Platform::ShowAssertionPopUps(false);
587 paintState
= painting
;
591 bool IsOcxCtrl
= (wParam
!= 0); // if wParam != 0, it contains
592 // a PAINSTRUCT* from the OCX
593 // Removed since this interferes with reporting other assertions as it occurs repeatedly
594 //PLATFORM_ASSERT(hRgnUpdate == NULL);
595 hRgnUpdate
= ::CreateRectRgn(0, 0, 0, 0);
597 pps
= reinterpret_cast<PAINTSTRUCT
*>(wParam
);
599 ::GetUpdateRgn(MainHWND(), hRgnUpdate
, FALSE
);
601 ::BeginPaint(MainHWND(), pps
);
603 rcPaint
= PRectangle::FromInts(pps
->rcPaint
.left
, pps
->rcPaint
.top
, pps
->rcPaint
.right
, pps
->rcPaint
.bottom
);
604 PRectangle rcClient
= GetClientRectangle();
605 paintingAllText
= BoundsContains(rcPaint
, hRgnUpdate
, rcClient
);
606 if (technology
== SC_TECHNOLOGY_DEFAULT
) {
607 AutoSurface
surfaceWindow(pps
->hdc
, this);
609 Paint(surfaceWindow
, rcPaint
);
610 surfaceWindow
->Release();
614 EnsureRenderTarget();
615 AutoSurface
surfaceWindow(pRenderTarget
, this);
617 pRenderTarget
->BeginDraw();
618 Paint(surfaceWindow
, rcPaint
);
619 surfaceWindow
->Release();
620 HRESULT hr
= pRenderTarget
->EndDraw();
621 if (hr
== D2DERR_RECREATE_TARGET
) {
623 paintState
= paintAbandoned
;
629 ::DeleteRgn(hRgnUpdate
);
634 ::EndPaint(MainHWND(), pps
);
635 if (paintState
== paintAbandoned
) {
636 // Painting area was insufficient to cover new styling or brace highlight positions
638 FullPaintDC(pps
->hdc
);
643 paintState
= notPainting
;
645 // Restore debug output state
646 Platform::ShowAssertionPopUps(assertsPopup
);
648 //Platform::DebugPrintf("Paint took %g\n", et.Duration());
652 sptr_t
ScintillaWin::HandleComposition(uptr_t wParam
, sptr_t lParam
) {
653 if (lParam
& GCS_RESULTSTR
) {
654 HIMC hIMC
= ::ImmGetContext(MainHWND());
656 const int maxLenInputIME
= 200;
657 wchar_t wcs
[maxLenInputIME
];
658 LONG bytes
= ::ImmGetCompositionStringW(hIMC
,
659 GCS_RESULTSTR
, wcs
, (maxLenInputIME
-1)*2);
660 int wides
= bytes
/ 2;
661 if (IsUnicodeMode()) {
662 char utfval
[maxLenInputIME
* 3];
663 unsigned int len
= UTF8Length(wcs
, wides
);
664 UTF8FromUTF16(wcs
, wides
, utfval
, len
);
666 AddCharUTF(utfval
, len
);
668 char dbcsval
[maxLenInputIME
* 2];
669 int size
= ::WideCharToMultiByte(InputCodePage(),
670 0, wcs
, wides
, dbcsval
, sizeof(dbcsval
) - 1, 0, 0);
671 for (int i
=0; i
<size
; i
++) {
675 // Set new position after converted
676 Point pos
= PointMainCaret();
677 COMPOSITIONFORM CompForm
;
678 CompForm
.dwStyle
= CFS_POINT
;
679 CompForm
.ptCurrentPos
.x
= static_cast<int>(pos
.x
);
680 CompForm
.ptCurrentPos
.y
= static_cast<int>(pos
.y
);
681 ::ImmSetCompositionWindow(hIMC
, &CompForm
);
682 ::ImmReleaseContext(MainHWND(), hIMC
);
686 return ::DefWindowProc(MainHWND(), WM_IME_COMPOSITION
, wParam
, lParam
);
689 // Translate message IDs from WM_* and EM_* to SCI_* so can partly emulate Windows Edit control
690 static unsigned int SciMessageFromEM(unsigned int iMessage
) {
692 case EM_CANPASTE
: return SCI_CANPASTE
;
693 case EM_CANUNDO
: return SCI_CANUNDO
;
694 case EM_EMPTYUNDOBUFFER
: return SCI_EMPTYUNDOBUFFER
;
695 case EM_FINDTEXTEX
: return SCI_FINDTEXT
;
696 case EM_FORMATRANGE
: return SCI_FORMATRANGE
;
697 case EM_GETFIRSTVISIBLELINE
: return SCI_GETFIRSTVISIBLELINE
;
698 case EM_GETLINECOUNT
: return SCI_GETLINECOUNT
;
699 case EM_GETSELTEXT
: return SCI_GETSELTEXT
;
700 case EM_GETTEXTRANGE
: return SCI_GETTEXTRANGE
;
701 case EM_HIDESELECTION
: return SCI_HIDESELECTION
;
702 case EM_LINEINDEX
: return SCI_POSITIONFROMLINE
;
703 case EM_LINESCROLL
: return SCI_LINESCROLL
;
704 case EM_REPLACESEL
: return SCI_REPLACESEL
;
705 case EM_SCROLLCARET
: return SCI_SCROLLCARET
;
706 case EM_SETREADONLY
: return SCI_SETREADONLY
;
707 case WM_CLEAR
: return SCI_CLEAR
;
708 case WM_COPY
: return SCI_COPY
;
709 case WM_CUT
: return SCI_CUT
;
710 case WM_SETTEXT
: return SCI_SETTEXT
;
711 case WM_PASTE
: return SCI_PASTE
;
712 case WM_UNDO
: return SCI_UNDO
;
717 UINT
CodePageFromCharSet(DWORD characterSet
, UINT documentCodePage
) {
718 if (documentCodePage
== SC_CP_UTF8
) {
721 switch (characterSet
) {
722 case SC_CHARSET_ANSI
: return 1252;
723 case SC_CHARSET_DEFAULT
: return documentCodePage
;
724 case SC_CHARSET_BALTIC
: return 1257;
725 case SC_CHARSET_CHINESEBIG5
: return 950;
726 case SC_CHARSET_EASTEUROPE
: return 1250;
727 case SC_CHARSET_GB2312
: return 936;
728 case SC_CHARSET_GREEK
: return 1253;
729 case SC_CHARSET_HANGUL
: return 949;
730 case SC_CHARSET_MAC
: return 10000;
731 case SC_CHARSET_OEM
: return 437;
732 case SC_CHARSET_RUSSIAN
: return 1251;
733 case SC_CHARSET_SHIFTJIS
: return 932;
734 case SC_CHARSET_TURKISH
: return 1254;
735 case SC_CHARSET_JOHAB
: return 1361;
736 case SC_CHARSET_HEBREW
: return 1255;
737 case SC_CHARSET_ARABIC
: return 1256;
738 case SC_CHARSET_VIETNAMESE
: return 1258;
739 case SC_CHARSET_THAI
: return 874;
740 case SC_CHARSET_8859_15
: return 28605;
742 case SC_CHARSET_CYRILLIC
: return documentCodePage
;
743 case SC_CHARSET_SYMBOL
: return documentCodePage
;
745 return documentCodePage
;
748 UINT
ScintillaWin::CodePageOfDocument() {
749 return CodePageFromCharSet(vs
.styles
[STYLE_DEFAULT
].characterSet
, pdoc
->dbcsCodePage
);
752 sptr_t
ScintillaWin::GetTextLength() {
753 if (::IsWindowUnicode(MainHWND())) {
754 if (pdoc
->Length() == 0)
756 std::vector
<char> docBytes(pdoc
->Length(), '\0');
757 pdoc
->GetCharRange(&docBytes
[0], 0, pdoc
->Length());
758 if (IsUnicodeMode()) {
759 return UTF16Length(&docBytes
[0], static_cast<unsigned int>(docBytes
.size()));
761 return ::MultiByteToWideChar(CodePageOfDocument(), 0, &docBytes
[0],
762 static_cast<int>(docBytes
.size()), NULL
, 0);
765 return pdoc
->Length();
769 sptr_t
ScintillaWin::GetText(uptr_t wParam
, sptr_t lParam
) {
770 if (::IsWindowUnicode(MainHWND())) {
771 wchar_t *ptr
= reinterpret_cast<wchar_t *>(lParam
);
772 if (pdoc
->Length() == 0) {
776 std::vector
<char> docBytes(pdoc
->Length(), '\0');
777 pdoc
->GetCharRange(&docBytes
[0], 0, pdoc
->Length());
778 if (IsUnicodeMode()) {
779 unsigned int lengthUTF16
= UTF16Length(&docBytes
[0], static_cast<unsigned int>(docBytes
.size()));
784 unsigned int uLen
= UTF16FromUTF8(&docBytes
[0], static_cast<unsigned int>(docBytes
.size()),
785 ptr
, static_cast<int>(wParam
) - 1);
790 // Convert to Unicode using the current Scintilla code page
791 const UINT cpSrc
= CodePageOfDocument();
792 int lengthUTF16
= ::MultiByteToWideChar(cpSrc
, 0, &docBytes
[0],
793 static_cast<int>(docBytes
.size()), NULL
, 0);
794 if (lengthUTF16
>= static_cast<int>(wParam
))
795 lengthUTF16
= static_cast<int>(wParam
)-1;
796 ::MultiByteToWideChar(cpSrc
, 0, &docBytes
[0],
797 static_cast<int>(docBytes
.size()),
799 ptr
[lengthUTF16
] = L
'\0';
804 return pdoc
->Length() + 1;
807 char *ptr
= reinterpret_cast<char *>(lParam
);
808 unsigned int iChar
= 0;
809 for (; iChar
< wParam
- 1; iChar
++)
810 ptr
[iChar
] = pdoc
->CharAt(iChar
);
816 sptr_t
ScintillaWin::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
818 //Platform::DebugPrintf("S M:%x WP:%x L:%x\n", iMessage, wParam, lParam);
819 iMessage
= SciMessageFromEM(iMessage
);
823 ctrlID
= ::GetDlgCtrlID(reinterpret_cast<HWND
>(wMain
.GetID()));
824 // Get Intellimouse scroll line parameters
825 GetIntelliMouseParameters();
826 ::RegisterDragDrop(MainHWND(), reinterpret_cast<IDropTarget
*>(&dt
));
830 Command(LoWord(wParam
));
834 return WndPaint(wParam
);
836 case WM_PRINTCLIENT
: {
837 HDC hdc
= reinterpret_cast<HDC
>(wParam
);
838 if (!IsCompatibleDC(hdc
)) {
839 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
846 ScrollMessage(wParam
);
850 HorizontalScrollMessage(wParam
);
855 if (paintState
== notPainting
) {
858 renderTargetValid
= false;
861 //Platform::DebugPrintf("Scintilla WM_SIZE %d %d\n", LoWord(lParam), HiWord(lParam));
867 // if autocomplete list active then send mousewheel message to it
869 HWND hWnd
= reinterpret_cast<HWND
>(ac
.lb
->GetID());
870 ::SendMessage(hWnd
, iMessage
, wParam
, lParam
);
874 // Don't handle datazoom.
875 // (A good idea for datazoom would be to "fold" or "unfold" details.
876 // i.e. if datazoomed out only class structures are visible, when datazooming in the control
877 // structures appear, then eventually the individual statements...)
878 if (wParam
& MK_SHIFT
) {
879 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
882 // Either SCROLL or ZOOM. We handle the wheel steppings calculation
883 wheelDelta
-= static_cast<short>(HiWord(wParam
));
884 if (abs(wheelDelta
) >= WHEEL_DELTA
&& linesPerScroll
> 0) {
885 int linesToScroll
= linesPerScroll
;
886 if (linesPerScroll
== WHEEL_PAGESCROLL
)
887 linesToScroll
= LinesOnScreen() - 1;
888 if (linesToScroll
== 0) {
891 linesToScroll
*= (wheelDelta
/ WHEEL_DELTA
);
893 wheelDelta
= wheelDelta
% WHEEL_DELTA
;
895 wheelDelta
= - (-wheelDelta
% WHEEL_DELTA
);
897 if (wParam
& MK_CONTROL
) {
898 // Zoom! We play with the font sizes in the styles.
899 // Number of steps/line is ignored, we just care if sizing up or down
900 if (linesToScroll
< 0) {
901 KeyCommand(SCI_ZOOMIN
);
903 KeyCommand(SCI_ZOOMOUT
);
907 ScrollTo(topLine
+ linesToScroll
);
913 if (wParam
== standardTimerID
&& timer
.ticking
) {
915 } else if (wParam
== idleTimerID
&& idler
.state
) {
916 SendMessage(MainHWND(), SC_WIN_IDLE
, 0, 1);
923 // wParam=dwTickCountInitial, or 0 to initialize. lParam=bSkipUserInputTest
925 if (lParam
|| (WAIT_TIMEOUT
== MsgWaitForMultipleObjects(0, 0, 0, 0, QS_INPUT
|QS_HOTKEY
))) {
927 // User input was given priority above, but all events do get a turn. Other
928 // messages, notifications, etc. will get interleaved with the idle messages.
930 // However, some things like WM_PAINT are a lower priority, and will not fire
931 // when there's a message posted. So, several times a second, we stop and let
932 // the low priority events have a turn (after which the timer will fire again).
934 DWORD dwCurrent
= GetTickCount();
935 DWORD dwStart
= wParam
? static_cast<DWORD
>(wParam
) : dwCurrent
;
936 const DWORD maxWorkTime
= 50;
938 if (dwCurrent
>= dwStart
&& dwCurrent
> maxWorkTime
&& dwCurrent
- maxWorkTime
< dwStart
)
939 PostMessage(MainHWND(), SC_WIN_IDLE
, dwStart
, 0);
947 case WM_GETMINMAXINFO
:
948 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
950 case WM_LBUTTONDOWN
: {
951 // For IME, set the composition string as the result string.
952 HIMC hIMC
= ::ImmGetContext(MainHWND());
953 ::ImmNotifyIME(hIMC
, NI_COMPOSITIONSTR
, CPS_COMPLETE
, 0);
954 ::ImmReleaseContext(MainHWND(), hIMC
);
956 //Platform::DebugPrintf("Buttdown %d %x %x %x %x %x\n",iMessage, wParam, lParam,
957 // Platform::IsKeyDown(VK_SHIFT),
958 // Platform::IsKeyDown(VK_CONTROL),
959 // Platform::IsKeyDown(VK_MENU));
960 ::SetFocus(MainHWND());
961 ButtonDown(Point::FromLong(static_cast<long>(lParam
)), ::GetMessageTime(),
962 (wParam
& MK_SHIFT
) != 0,
963 (wParam
& MK_CONTROL
) != 0,
964 Platform::IsKeyDown(VK_MENU
));
969 SetTrackMouseLeaveEvent(true);
970 ButtonMoveWithModifiers(Point::FromLong(static_cast<long>(lParam
)),
971 ((wParam
& MK_SHIFT
) != 0 ? SCI_SHIFT
: 0) |
972 ((wParam
& MK_CONTROL
) != 0 ? SCI_CTRL
: 0) |
973 (Platform::IsKeyDown(VK_MENU
) ? SCI_ALT
: 0));
977 SetTrackMouseLeaveEvent(false);
979 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
982 ButtonUp(Point::FromLong(static_cast<long>(lParam
)),
984 (wParam
& MK_CONTROL
) != 0);
988 ::SetFocus(MainHWND());
989 if (!PointInSelection(Point::FromLong(static_cast<long>(lParam
)))) {
991 SetEmptySelection(PositionFromLocation(Point::FromLong(static_cast<long>(lParam
))));
996 if (LoWord(lParam
) == HTCLIENT
) {
997 if (inDragDrop
== ddDragging
) {
998 DisplayCursor(Window::cursorUp
);
1000 // Display regular (drag) cursor over selection
1002 if (0 != ::GetCursorPos(&pt
)) {
1003 ::ScreenToClient(MainHWND(), &pt
);
1004 if (PointInSelMargin(PointFromPOINT(pt
))) {
1005 DisplayCursor(GetMarginCursor(PointFromPOINT(pt
)));
1006 } else if (PointInSelection(PointFromPOINT(pt
)) && !SelectionEmpty()) {
1007 DisplayCursor(Window::cursorArrow
);
1008 } else if (PointIsHotspot(PointFromPOINT(pt
))) {
1009 DisplayCursor(Window::cursorHand
);
1011 DisplayCursor(Window::cursorText
);
1017 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1021 if (((wParam
>= 128) || !iscntrl(static_cast<int>(wParam
))) || !lastKeyDownConsumed
) {
1022 if (::IsWindowUnicode(MainHWND()) || keysAlwaysUnicode
) {
1023 wchar_t wcs
[2] = {static_cast<wchar_t>(wParam
), 0};
1024 if (IsUnicodeMode()) {
1025 // For a wide character version of the window:
1027 unsigned int len
= UTF8Length(wcs
, 1);
1028 UTF8FromUTF16(wcs
, 1, utfval
, len
);
1029 AddCharUTF(utfval
, len
);
1031 UINT cpDest
= CodePageOfDocument();
1032 char inBufferCP
[20];
1033 int size
= ::WideCharToMultiByte(cpDest
,
1034 0, wcs
, 1, inBufferCP
, sizeof(inBufferCP
) - 1, 0, 0);
1035 inBufferCP
[size
] = '\0';
1036 AddCharUTF(inBufferCP
, size
);
1039 if (IsUnicodeMode()) {
1040 AddCharBytes('\0', LOBYTE(wParam
));
1042 AddChar(LOBYTE(wParam
));
1049 if (wParam
== UNICODE_NOCHAR
) {
1050 return IsUnicodeMode() ? 1 : 0;
1051 } else if (lastKeyDownConsumed
) {
1054 if (IsUnicodeMode()) {
1056 wchar_t wcs
[2] = {static_cast<wchar_t>(wParam
), 0};
1057 unsigned int len
= UTF8Length(wcs
, 1);
1058 UTF8FromUTF16(wcs
, 1, utfval
, len
);
1059 AddCharUTF(utfval
, len
);
1068 //Platform::DebugPrintf("S keydown %d %x %x %x %x\n",iMessage, wParam, lParam, ::IsKeyDown(VK_SHIFT), ::IsKeyDown(VK_CONTROL));
1069 lastKeyDownConsumed
= false;
1070 int ret
= KeyDown(KeyTranslate(static_cast<int>(wParam
)),
1071 Platform::IsKeyDown(VK_SHIFT
),
1072 Platform::IsKeyDown(VK_CONTROL
),
1073 Platform::IsKeyDown(VK_MENU
),
1074 &lastKeyDownConsumed
);
1075 if (!ret
&& !lastKeyDownConsumed
) {
1076 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1081 case WM_IME_KEYDOWN
:
1082 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1085 //Platform::DebugPrintf("S keyup %d %x %x\n",iMessage, wParam, lParam);
1086 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1088 case WM_SETTINGCHANGE
:
1089 //Platform::DebugPrintf("Setting Changed\n");
1090 InvalidateStyleData();
1091 // Get Intellimouse scroll line parameters
1092 GetIntelliMouseParameters();
1096 return DLGC_HASSETSEL
| DLGC_WANTALLKEYS
;
1098 case WM_KILLFOCUS
: {
1099 HWND wOther
= reinterpret_cast<HWND
>(wParam
);
1100 HWND wThis
= MainHWND();
1101 HWND wCT
= reinterpret_cast<HWND
>(ct
.wCallTip
.GetID());
1103 !(::IsChild(wThis
, wOther
) || (wOther
== wCT
))) {
1104 SetFocusState(false);
1105 DestroySystemCaret();
1111 SetFocusState(true);
1112 DestroySystemCaret();
1113 CreateSystemCaret();
1116 case WM_SYSCOLORCHANGE
:
1117 //Platform::DebugPrintf("Setting Changed\n");
1118 InvalidateStyleData();
1121 case WM_IME_STARTCOMPOSITION
: // dbcs
1122 ImeStartComposition();
1123 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1125 case WM_IME_ENDCOMPOSITION
: // dbcs
1126 ImeEndComposition();
1127 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1129 case WM_IME_COMPOSITION
:
1130 return HandleComposition(wParam
, lParam
);
1133 AddCharBytes(HIBYTE(wParam
), LOBYTE(wParam
));
1137 case WM_CONTEXTMENU
:
1138 if (displayPopupMenu
) {
1139 Point pt
= Point::FromLong(static_cast<long>(lParam
));
1140 if ((pt
.x
== -1) && (pt
.y
== -1)) {
1141 // Caused by keyboard so display menu near caret
1142 pt
= PointMainCaret();
1143 POINT spt
= {static_cast<int>(pt
.x
), static_cast<int>(pt
.y
)};
1144 ::ClientToScreen(MainHWND(), &spt
);
1145 pt
= PointFromPOINT(spt
);
1150 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1152 case WM_INPUTLANGCHANGE
:
1153 //::SetThreadLocale(LOWORD(lParam));
1154 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1156 case WM_INPUTLANGCHANGEREQUEST
:
1157 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1160 return 1; // Avoid any background erasure as whole window painted.
1162 case WM_CAPTURECHANGED
:
1163 capturedMouse
= false;
1166 // These are not handled in Scintilla and its faster to dispatch them here.
1167 // Also moves time out to here so profile doesn't count lots of empty message calls.
1170 case WM_MOUSEACTIVATE
:
1174 case WM_NCMOUSEMOVE
:
1175 case WM_NCLBUTTONDOWN
:
1176 case WM_IME_SETCONTEXT
:
1179 case WM_WINDOWPOSCHANGING
:
1180 case WM_WINDOWPOSCHANGED
:
1181 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1183 case WM_GETTEXTLENGTH
:
1184 return GetTextLength();
1187 return GetText(wParam
, lParam
);
1189 case EM_LINEFROMCHAR
:
1190 if (static_cast<int>(wParam
) < 0) {
1191 wParam
= SelectionStart().Position();
1193 return pdoc
->LineFromPosition(static_cast<int>(wParam
));
1195 case EM_EXLINEFROMCHAR
:
1196 return pdoc
->LineFromPosition(static_cast<int>(lParam
));
1200 *reinterpret_cast<int *>(wParam
) = SelectionStart().Position();
1203 *reinterpret_cast<int *>(lParam
) = SelectionEnd().Position();
1205 return MAKELONG(SelectionStart().Position(), SelectionEnd().Position());
1211 Sci_CharacterRange
*pCR
= reinterpret_cast<Sci_CharacterRange
*>(lParam
);
1212 pCR
->cpMin
= SelectionStart().Position();
1213 pCR
->cpMax
= SelectionEnd().Position();
1218 int nStart
= static_cast<int>(wParam
);
1219 int nEnd
= static_cast<int>(lParam
);
1220 if (nStart
== 0 && nEnd
== -1) {
1221 nEnd
= pdoc
->Length();
1224 nStart
= nEnd
; // Remove selection
1226 if (nStart
> nEnd
) {
1227 SetSelection(nEnd
, nStart
);
1229 SetSelection(nStart
, nEnd
);
1231 EnsureCaretVisible();
1239 Sci_CharacterRange
*pCR
= reinterpret_cast<Sci_CharacterRange
*>(lParam
);
1240 sel
.selType
= Selection::selStream
;
1241 if (pCR
->cpMin
== 0 && pCR
->cpMax
== -1) {
1242 SetSelection(pCR
->cpMin
, pdoc
->Length());
1244 SetSelection(pCR
->cpMin
, pCR
->cpMax
);
1246 EnsureCaretVisible();
1247 return pdoc
->LineFromPosition(SelectionStart().Position());
1250 case SCI_GETDIRECTFUNCTION
:
1251 return reinterpret_cast<sptr_t
>(DirectFunction
);
1253 case SCI_GETDIRECTPOINTER
:
1254 return reinterpret_cast<sptr_t
>(this);
1257 ::SetFocus(MainHWND());
1260 case SCI_SETKEYSUNICODE
:
1261 keysAlwaysUnicode
= wParam
!= 0;
1264 case SCI_GETKEYSUNICODE
:
1265 return keysAlwaysUnicode
;
1267 case SCI_SETTECHNOLOGY
:
1268 if ((wParam
== SC_TECHNOLOGY_DEFAULT
) || (wParam
== SC_TECHNOLOGY_DIRECTWRITE
)) {
1269 if (technology
!= static_cast<int>(wParam
)) {
1270 if (static_cast<int>(wParam
) == SC_TECHNOLOGY_DIRECTWRITE
) {
1271 #if defined(USE_D2D)
1273 // Failed to load Direct2D or DirectWrite so no effect
1279 technology
= static_cast<int>(wParam
);
1280 // Invalidate all cached information including layout.
1282 InvalidateStyleRedraw();
1288 case SCI_LOADLEXERLIBRARY
:
1289 LexerManager::GetInstance()->Load(reinterpret_cast<const char *>(lParam
));
1294 return ScintillaBase::WndProc(iMessage
, wParam
, lParam
);
1296 } catch (std::bad_alloc
&) {
1297 errorStatus
= SC_STATUS_BADALLOC
;
1299 errorStatus
= SC_STATUS_FAILURE
;
1304 bool ScintillaWin::ValidCodePage(int codePage
) const {
1305 return codePage
== 0 || codePage
== SC_CP_UTF8
||
1306 codePage
== 932 || codePage
== 936 || codePage
== 949 ||
1307 codePage
== 950 || codePage
== 1361;
1310 sptr_t
ScintillaWin::DefWndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
1311 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1314 void ScintillaWin::SetTicking(bool on
) {
1315 if (timer
.ticking
!= on
) {
1317 if (timer
.ticking
) {
1318 timer
.tickerID
= ::SetTimer(MainHWND(), standardTimerID
, timer
.tickSize
, NULL
)
1319 ? reinterpret_cast<TickerID
>(standardTimerID
) : 0;
1321 ::KillTimer(MainHWND(), reinterpret_cast<uptr_t
>(timer
.tickerID
));
1325 timer
.ticksToWait
= caret
.period
;
1328 bool ScintillaWin::SetIdle(bool on
) {
1329 // On Win32 the Idler is implemented as a Timer on the Scintilla window. This
1330 // takes advantage of the fact that WM_TIMER messages are very low priority,
1331 // and are only posted when the message queue is empty, i.e. during idle time.
1332 if (idler
.state
!= on
) {
1334 idler
.idlerID
= ::SetTimer(MainHWND(), idleTimerID
, 10, NULL
)
1335 ? reinterpret_cast<IdlerID
>(idleTimerID
) : 0;
1337 ::KillTimer(MainHWND(), reinterpret_cast<uptr_t
>(idler
.idlerID
));
1340 idler
.state
= idler
.idlerID
!= 0;
1345 void ScintillaWin::SetMouseCapture(bool on
) {
1346 if (mouseDownCaptures
) {
1348 ::SetCapture(MainHWND());
1356 bool ScintillaWin::HaveMouseCapture() {
1357 // Cannot just see if GetCapture is this window as the scroll bar also sets capture for the window
1358 return capturedMouse
;
1359 //return capturedMouse && (::GetCapture() == MainHWND());
1362 void ScintillaWin::SetTrackMouseLeaveEvent(bool on
) {
1363 if (on
&& TrackMouseEventFn
&& !trackedMouseLeave
) {
1364 TRACKMOUSEEVENT tme
;
1365 tme
.cbSize
= sizeof(tme
);
1366 tme
.dwFlags
= TME_LEAVE
;
1367 tme
.hwndTrack
= MainHWND();
1368 tme
.dwHoverTime
= HOVER_DEFAULT
; // Unused but triggers Dr. Memory if not initialized
1369 TrackMouseEventFn(&tme
);
1371 trackedMouseLeave
= on
;
1374 bool ScintillaWin::PaintContains(PRectangle rc
) {
1375 if (paintState
== painting
) {
1376 return BoundsContains(rcPaint
, hRgnUpdate
, rc
);
1381 void ScintillaWin::ScrollText(int /* linesToMove */) {
1382 //Platform::DebugPrintf("ScintillaWin::ScrollText %d\n", linesToMove);
1383 //::ScrollWindow(MainHWND(), 0,
1384 // vs.lineHeight * linesToMove, 0, 0);
1385 //::UpdateWindow(MainHWND());
1387 UpdateSystemCaret();
1390 void ScintillaWin::UpdateSystemCaret() {
1392 if (HasCaretSizeChanged()) {
1393 DestroySystemCaret();
1394 CreateSystemCaret();
1396 Point pos
= PointMainCaret();
1397 ::SetCaretPos(static_cast<int>(pos
.x
), static_cast<int>(pos
.y
));
1401 int ScintillaWin::SetScrollInfo(int nBar
, LPCSCROLLINFO lpsi
, BOOL bRedraw
) {
1402 return ::SetScrollInfo(MainHWND(), nBar
, lpsi
, bRedraw
);
1405 bool ScintillaWin::GetScrollInfo(int nBar
, LPSCROLLINFO lpsi
) {
1406 return ::GetScrollInfo(MainHWND(), nBar
, lpsi
) ? true : false;
1409 // Change the scroll position but avoid repaint if changing to same value
1410 void ScintillaWin::ChangeScrollPos(int barType
, int pos
) {
1412 sizeof(sci
), 0, 0, 0, 0, 0, 0
1414 sci
.fMask
= SIF_POS
;
1415 GetScrollInfo(barType
, &sci
);
1416 if (sci
.nPos
!= pos
) {
1419 SetScrollInfo(barType
, &sci
, TRUE
);
1423 void ScintillaWin::SetVerticalScrollPos() {
1424 ChangeScrollPos(SB_VERT
, topLine
);
1427 void ScintillaWin::SetHorizontalScrollPos() {
1428 ChangeScrollPos(SB_HORZ
, xOffset
);
1431 bool ScintillaWin::ModifyScrollBars(int nMax
, int nPage
) {
1432 bool modified
= false;
1434 sizeof(sci
), 0, 0, 0, 0, 0, 0
1436 sci
.fMask
= SIF_PAGE
| SIF_RANGE
;
1437 GetScrollInfo(SB_VERT
, &sci
);
1438 int vertEndPreferred
= nMax
;
1439 if (!verticalScrollBarVisible
)
1440 nPage
= vertEndPreferred
+ 1;
1441 if ((sci
.nMin
!= 0) ||
1442 (sci
.nMax
!= vertEndPreferred
) ||
1443 (sci
.nPage
!= static_cast<unsigned int>(nPage
)) ||
1445 sci
.fMask
= SIF_PAGE
| SIF_RANGE
;
1447 sci
.nMax
= vertEndPreferred
;
1451 SetScrollInfo(SB_VERT
, &sci
, TRUE
);
1455 PRectangle rcText
= GetTextRectangle();
1456 int horizEndPreferred
= scrollWidth
;
1457 if (horizEndPreferred
< 0)
1458 horizEndPreferred
= 0;
1459 unsigned int pageWidth
= static_cast<unsigned int>(rcText
.Width());
1460 if (!horizontalScrollBarVisible
|| Wrapping())
1461 pageWidth
= horizEndPreferred
+ 1;
1462 sci
.fMask
= SIF_PAGE
| SIF_RANGE
;
1463 GetScrollInfo(SB_HORZ
, &sci
);
1464 if ((sci
.nMin
!= 0) ||
1465 (sci
.nMax
!= horizEndPreferred
) ||
1466 (sci
.nPage
!= pageWidth
) ||
1468 sci
.fMask
= SIF_PAGE
| SIF_RANGE
;
1470 sci
.nMax
= horizEndPreferred
;
1471 sci
.nPage
= pageWidth
;
1474 SetScrollInfo(SB_HORZ
, &sci
, TRUE
);
1476 if (scrollWidth
< static_cast<int>(pageWidth
)) {
1477 HorizontalScrollTo(0);
1483 void ScintillaWin::NotifyChange() {
1484 ::SendMessage(::GetParent(MainHWND()), WM_COMMAND
,
1485 MAKELONG(GetCtrlID(), SCEN_CHANGE
),
1486 reinterpret_cast<LPARAM
>(MainHWND()));
1489 void ScintillaWin::NotifyFocus(bool focus
) {
1490 ::SendMessage(::GetParent(MainHWND()), WM_COMMAND
,
1491 MAKELONG(GetCtrlID(), focus
? SCEN_SETFOCUS
: SCEN_KILLFOCUS
),
1492 reinterpret_cast<LPARAM
>(MainHWND()));
1493 Editor::NotifyFocus(focus
);
1496 void ScintillaWin::SetCtrlID(int identifier
) {
1497 ::SetWindowID(reinterpret_cast<HWND
>(wMain
.GetID()), identifier
);
1500 int ScintillaWin::GetCtrlID() {
1501 return ::GetDlgCtrlID(reinterpret_cast<HWND
>(wMain
.GetID()));
1504 void ScintillaWin::NotifyParent(SCNotification scn
) {
1505 scn
.nmhdr
.hwndFrom
= MainHWND();
1506 scn
.nmhdr
.idFrom
= GetCtrlID();
1507 ::SendMessage(::GetParent(MainHWND()), WM_NOTIFY
,
1508 GetCtrlID(), reinterpret_cast<LPARAM
>(&scn
));
1511 void ScintillaWin::NotifyParent(SCNotification
* scn
) {
1512 scn
->nmhdr
.hwndFrom
= MainHWND();
1513 scn
->nmhdr
.idFrom
= GetCtrlID();
1514 ::SendMessage(::GetParent(MainHWND()), WM_NOTIFY
,
1515 GetCtrlID(), reinterpret_cast<LPARAM
>(scn
));
1518 void ScintillaWin::NotifyDoubleClick(Point pt
, int modifiers
) {
1519 //Platform::DebugPrintf("ScintillaWin Double click 0\n");
1520 ScintillaBase::NotifyDoubleClick(pt
, modifiers
);
1521 // Send myself a WM_LBUTTONDBLCLK, so the container can handle it too.
1522 ::SendMessage(MainHWND(),
1524 (modifiers
& SCI_SHIFT
) ? MK_SHIFT
: 0,
1525 MAKELPARAM(pt
.x
, pt
.y
));
1528 class CaseFolderDBCS
: public CaseFolderTable
{
1529 // Allocate the expandable storage here so that it does not need to be reallocated
1530 // for each call to Fold.
1531 std::vector
<wchar_t> utf16Mixed
;
1532 std::vector
<wchar_t> utf16Folded
;
1535 explicit CaseFolderDBCS(UINT cp_
) : cp(cp_
) {
1538 virtual size_t Fold(char *folded
, size_t sizeFolded
, const char *mixed
, size_t lenMixed
) {
1539 if ((lenMixed
== 1) && (sizeFolded
> 0)) {
1540 folded
[0] = mapping
[static_cast<unsigned char>(mixed
[0])];
1543 if (lenMixed
> utf16Mixed
.size()) {
1544 utf16Mixed
.resize(lenMixed
+ 8);
1546 size_t nUtf16Mixed
= ::MultiByteToWideChar(cp
, 0, mixed
,
1547 static_cast<int>(lenMixed
),
1549 static_cast<int>(utf16Mixed
.size()));
1551 if (nUtf16Mixed
== 0) {
1552 // Failed to convert -> bad input
1557 unsigned int lenFlat
= 0;
1558 for (size_t mixIndex
=0; mixIndex
< nUtf16Mixed
; mixIndex
++) {
1559 if ((lenFlat
+ 20) > utf16Folded
.size())
1560 utf16Folded
.resize(lenFlat
+ 60);
1561 const char *foldedUTF8
= CaseConvert(utf16Mixed
[mixIndex
], CaseConversionFold
);
1563 // Maximum length of a case conversion is 6 bytes, 3 characters
1564 wchar_t wFolded
[20];
1565 unsigned int charsConverted
= UTF16FromUTF8(foldedUTF8
,
1566 static_cast<unsigned int>(strlen(foldedUTF8
)),
1567 wFolded
, ELEMENTS(wFolded
));
1568 for (size_t j
=0; j
<charsConverted
; j
++)
1569 utf16Folded
[lenFlat
++] = wFolded
[j
];
1571 utf16Folded
[lenFlat
++] = utf16Mixed
[mixIndex
];
1575 size_t lenOut
= ::WideCharToMultiByte(cp
, 0,
1576 &utf16Folded
[0], lenFlat
,
1579 if (lenOut
< sizeFolded
) {
1580 ::WideCharToMultiByte(cp
, 0,
1581 &utf16Folded
[0], lenFlat
,
1582 folded
, static_cast<int>(lenOut
), NULL
, 0);
1591 CaseFolder
*ScintillaWin::CaseFolderForEncoding() {
1592 UINT cpDest
= CodePageOfDocument();
1593 if (cpDest
== SC_CP_UTF8
) {
1594 return new CaseFolderUnicode();
1596 if (pdoc
->dbcsCodePage
== 0) {
1597 CaseFolderTable
*pcf
= new CaseFolderTable();
1598 pcf
->StandardASCII();
1599 // Only for single byte encodings
1600 UINT cpDoc
= CodePageOfDocument();
1601 for (int i
=0x80; i
<0x100; i
++) {
1602 char sCharacter
[2] = "A";
1603 sCharacter
[0] = static_cast<char>(i
);
1604 wchar_t wCharacter
[20];
1605 unsigned int lengthUTF16
= ::MultiByteToWideChar(cpDoc
, 0, sCharacter
, 1,
1606 wCharacter
, ELEMENTS(wCharacter
));
1607 if (lengthUTF16
== 1) {
1608 const char *caseFolded
= CaseConvert(wCharacter
[0], CaseConversionFold
);
1611 unsigned int charsConverted
= UTF16FromUTF8(caseFolded
,
1612 static_cast<unsigned int>(strlen(caseFolded
)),
1613 wLower
, ELEMENTS(wLower
));
1614 if (charsConverted
== 1) {
1615 char sCharacterLowered
[20];
1616 unsigned int lengthConverted
= ::WideCharToMultiByte(cpDoc
, 0,
1617 wLower
, charsConverted
,
1618 sCharacterLowered
, ELEMENTS(sCharacterLowered
), NULL
, 0);
1619 if ((lengthConverted
== 1) && (sCharacter
[0] != sCharacterLowered
[0])) {
1620 pcf
->SetTranslation(sCharacter
[0], sCharacterLowered
[0]);
1628 return new CaseFolderDBCS(cpDest
);
1633 std::string
ScintillaWin::CaseMapString(const std::string
&s
, int caseMapping
) {
1634 if ((s
.size() == 0) || (caseMapping
== cmSame
))
1637 UINT cpDoc
= CodePageOfDocument();
1638 if (cpDoc
== SC_CP_UTF8
) {
1639 std::string
retMapped(s
.length() * maxExpansionCaseConversion
, 0);
1640 size_t lenMapped
= CaseConvertString(&retMapped
[0], retMapped
.length(), s
.c_str(), s
.length(),
1641 (caseMapping
== cmUpper
) ? CaseConversionUpper
: CaseConversionLower
);
1642 retMapped
.resize(lenMapped
);
1646 unsigned int lengthUTF16
= ::MultiByteToWideChar(cpDoc
, 0, s
.c_str(),
1647 static_cast<int>(s
.size()), NULL
, 0);
1648 if (lengthUTF16
== 0) // Failed to convert
1651 DWORD mapFlags
= LCMAP_LINGUISTIC_CASING
|
1652 ((caseMapping
== cmUpper
) ? LCMAP_UPPERCASE
: LCMAP_LOWERCASE
);
1654 // Change text to UTF-16
1655 std::vector
<wchar_t> vwcText(lengthUTF16
);
1656 ::MultiByteToWideChar(cpDoc
, 0, s
.c_str(), static_cast<int>(s
.size()), &vwcText
[0], lengthUTF16
);
1659 int charsConverted
= ::LCMapStringW(LOCALE_SYSTEM_DEFAULT
, mapFlags
,
1660 &vwcText
[0], lengthUTF16
, NULL
, 0);
1661 std::vector
<wchar_t> vwcConverted(charsConverted
);
1662 ::LCMapStringW(LOCALE_SYSTEM_DEFAULT
, mapFlags
,
1663 &vwcText
[0], lengthUTF16
, &vwcConverted
[0], charsConverted
);
1665 // Change back to document encoding
1666 unsigned int lengthConverted
= ::WideCharToMultiByte(cpDoc
, 0,
1667 &vwcConverted
[0], static_cast<int>(vwcConverted
.size()),
1669 std::vector
<char> vcConverted(lengthConverted
);
1670 ::WideCharToMultiByte(cpDoc
, 0,
1671 &vwcConverted
[0], static_cast<int>(vwcConverted
.size()),
1672 &vcConverted
[0], static_cast<int>(vcConverted
.size()), NULL
, 0);
1674 return std::string(&vcConverted
[0], vcConverted
.size());
1677 void ScintillaWin::Copy() {
1678 //Platform::DebugPrintf("Copy\n");
1680 SelectionText selectedText
;
1681 CopySelectionRange(&selectedText
);
1682 CopyToClipboard(selectedText
);
1686 void ScintillaWin::CopyAllowLine() {
1687 SelectionText selectedText
;
1688 CopySelectionRange(&selectedText
, true);
1689 CopyToClipboard(selectedText
);
1692 bool ScintillaWin::CanPaste() {
1693 if (!Editor::CanPaste())
1695 if (::IsClipboardFormatAvailable(CF_TEXT
))
1697 if (IsUnicodeMode())
1698 return ::IsClipboardFormatAvailable(CF_UNICODETEXT
) != 0;
1702 class GlobalMemory
{
1706 GlobalMemory() : hand(0), ptr(0) {
1708 explicit GlobalMemory(HGLOBAL hand_
) : hand(hand_
), ptr(0) {
1710 ptr
= ::GlobalLock(hand
);
1714 PLATFORM_ASSERT(!ptr
);
1716 void Allocate(size_t bytes
) {
1717 hand
= ::GlobalAlloc(GMEM_MOVEABLE
| GMEM_ZEROINIT
, bytes
);
1719 ptr
= ::GlobalLock(hand
);
1723 PLATFORM_ASSERT(ptr
);
1724 HGLOBAL handCopy
= hand
;
1725 ::GlobalUnlock(hand
);
1730 void SetClip(UINT uFormat
) {
1731 ::SetClipboardData(uFormat
, Unlock());
1733 operator bool() const {
1737 return ::GlobalSize(hand
);
1741 void ScintillaWin::Paste() {
1742 if (!::OpenClipboard(MainHWND()))
1745 const bool isLine
= SelectionEmpty() && (::IsClipboardFormatAvailable(cfLineSelect
) != 0);
1746 ClearSelection(multiPasteMode
== SC_MULTIPASTE_EACH
);
1747 bool isRectangular
= (::IsClipboardFormatAvailable(cfColumnSelect
) != 0);
1749 if (!isRectangular
) {
1750 // Evaluate "Borland IDE Block Type" explicitly
1751 GlobalMemory
memBorlandSelection(::GetClipboardData(cfBorlandIDEBlockType
));
1752 if (memBorlandSelection
) {
1753 isRectangular
= (memBorlandSelection
.Size() == 1) && (static_cast<BYTE
*>(memBorlandSelection
.ptr
)[0] == 0x02);
1754 memBorlandSelection
.Unlock();
1757 const PasteShape pasteShape
= isRectangular
? pasteRectangular
: (isLine
? pasteLine
: pasteStream
);
1759 // Always use CF_UNICODETEXT if available
1760 GlobalMemory
memUSelection(::GetClipboardData(CF_UNICODETEXT
));
1761 if (memUSelection
) {
1762 wchar_t *uptr
= static_cast<wchar_t *>(memUSelection
.ptr
);
1765 std::vector
<char> putf
;
1766 // Default Scintilla behaviour in Unicode mode
1767 if (IsUnicodeMode()) {
1768 unsigned int bytes
= static_cast<unsigned int>(memUSelection
.Size());
1769 len
= UTF8Length(uptr
, bytes
/ 2);
1770 putf
.resize(len
+ 1);
1771 UTF8FromUTF16(uptr
, bytes
/ 2, &putf
[0], len
);
1773 // CF_UNICODETEXT available, but not in Unicode mode
1774 // Convert from Unicode to current Scintilla code page
1775 UINT cpDest
= CodePageOfDocument();
1776 len
= ::WideCharToMultiByte(cpDest
, 0, uptr
, -1,
1777 NULL
, 0, NULL
, NULL
) - 1; // subtract 0 terminator
1778 putf
.resize(len
+ 1);
1779 ::WideCharToMultiByte(cpDest
, 0, uptr
, -1,
1780 &putf
[0], len
+ 1, NULL
, NULL
);
1783 InsertPasteShape(&putf
[0], len
, pasteShape
);
1785 memUSelection
.Unlock();
1787 // CF_UNICODETEXT not available, paste ANSI text
1788 GlobalMemory
memSelection(::GetClipboardData(CF_TEXT
));
1790 char *ptr
= static_cast<char *>(memSelection
.ptr
);
1792 unsigned int bytes
= static_cast<unsigned int>(memSelection
.Size());
1793 unsigned int len
= bytes
;
1794 for (unsigned int i
= 0; i
< bytes
; i
++) {
1795 if ((len
== bytes
) && (0 == ptr
[i
]))
1799 // In Unicode mode, convert clipboard text to UTF-8
1800 if (IsUnicodeMode()) {
1801 std::vector
<wchar_t> uptr(len
+1);
1803 unsigned int ulen
= ::MultiByteToWideChar(CP_ACP
, 0,
1804 ptr
, len
, &uptr
[0], len
+1);
1806 unsigned int mlen
= UTF8Length(&uptr
[0], ulen
);
1807 std::vector
<char> putf(mlen
+1);
1808 // CP_UTF8 not available on Windows 95, so use UTF8FromUTF16()
1809 UTF8FromUTF16(&uptr
[0], ulen
, &putf
[0], mlen
);
1811 InsertPasteShape(&putf
[0], mlen
, pasteShape
);
1813 InsertPasteShape(ptr
, len
, pasteShape
);
1816 memSelection
.Unlock();
1823 void ScintillaWin::CreateCallTipWindow(PRectangle
) {
1824 if (!ct
.wCallTip
.Created()) {
1825 ct
.wCallTip
= ::CreateWindow(callClassName
, TEXT("ACallTip"),
1826 WS_POPUP
, 100, 100, 150, 20,
1828 GetWindowInstance(MainHWND()),
1830 ct
.wDraw
= ct
.wCallTip
;
1834 void ScintillaWin::AddToPopUp(const char *label
, int cmd
, bool enabled
) {
1835 HMENU hmenuPopup
= reinterpret_cast<HMENU
>(popup
.GetID());
1837 ::AppendMenuA(hmenuPopup
, MF_SEPARATOR
, 0, "");
1839 ::AppendMenuA(hmenuPopup
, MF_STRING
, cmd
, label
);
1841 ::AppendMenuA(hmenuPopup
, MF_STRING
| MF_DISABLED
| MF_GRAYED
, cmd
, label
);
1844 void ScintillaWin::ClaimSelection() {
1845 // Windows does not have a primary selection
1848 /// Implement IUnknown
1850 STDMETHODIMP_(ULONG
)FormatEnumerator_AddRef(FormatEnumerator
*fe
);
1851 STDMETHODIMP
FormatEnumerator_QueryInterface(FormatEnumerator
*fe
, REFIID riid
, PVOID
*ppv
) {
1852 //Platform::DebugPrintf("EFE QI");
1854 if (riid
== IID_IUnknown
)
1855 *ppv
= reinterpret_cast<IEnumFORMATETC
*>(fe
);
1856 if (riid
== IID_IEnumFORMATETC
)
1857 *ppv
= reinterpret_cast<IEnumFORMATETC
*>(fe
);
1859 return E_NOINTERFACE
;
1860 FormatEnumerator_AddRef(fe
);
1863 STDMETHODIMP_(ULONG
)FormatEnumerator_AddRef(FormatEnumerator
*fe
) {
1866 STDMETHODIMP_(ULONG
)FormatEnumerator_Release(FormatEnumerator
*fe
) {
1873 /// Implement IEnumFORMATETC
1874 STDMETHODIMP
FormatEnumerator_Next(FormatEnumerator
*fe
, ULONG celt
, FORMATETC
*rgelt
, ULONG
*pceltFetched
) {
1875 if (rgelt
== NULL
) return E_POINTER
;
1876 unsigned int putPos
= 0;
1877 while ((fe
->pos
< fe
->formats
.size()) && (putPos
< celt
)) {
1878 rgelt
->cfFormat
= fe
->formats
[fe
->pos
];
1880 rgelt
->dwAspect
= DVASPECT_CONTENT
;
1882 rgelt
->tymed
= TYMED_HGLOBAL
;
1888 *pceltFetched
= putPos
;
1889 return putPos
? S_OK
: S_FALSE
;
1891 STDMETHODIMP
FormatEnumerator_Skip(FormatEnumerator
*fe
, ULONG celt
) {
1895 STDMETHODIMP
FormatEnumerator_Reset(FormatEnumerator
*fe
) {
1899 STDMETHODIMP
FormatEnumerator_Clone(FormatEnumerator
*fe
, IEnumFORMATETC
**ppenum
) {
1900 FormatEnumerator
*pfe
;
1902 pfe
= new FormatEnumerator(fe
->pos
, &fe
->formats
[0], fe
->formats
.size());
1904 return E_OUTOFMEMORY
;
1906 return FormatEnumerator_QueryInterface(pfe
, IID_IEnumFORMATETC
,
1907 reinterpret_cast<void **>(ppenum
));
1910 static VFunction
*vtFormatEnumerator
[] = {
1911 (VFunction
*)(FormatEnumerator_QueryInterface
),
1912 (VFunction
*)(FormatEnumerator_AddRef
),
1913 (VFunction
*)(FormatEnumerator_Release
),
1914 (VFunction
*)(FormatEnumerator_Next
),
1915 (VFunction
*)(FormatEnumerator_Skip
),
1916 (VFunction
*)(FormatEnumerator_Reset
),
1917 (VFunction
*)(FormatEnumerator_Clone
)
1920 FormatEnumerator::FormatEnumerator(int pos_
, CLIPFORMAT formats_
[], size_t formatsLen_
) {
1921 vtbl
= vtFormatEnumerator
;
1922 ref
= 0; // First QI adds first reference...
1924 formats
.insert(formats
.begin(), formats_
, formats_
+formatsLen_
);
1927 /// Implement IUnknown
1928 STDMETHODIMP
DropSource_QueryInterface(DropSource
*ds
, REFIID riid
, PVOID
*ppv
) {
1929 return ds
->sci
->QueryInterface(riid
, ppv
);
1931 STDMETHODIMP_(ULONG
)DropSource_AddRef(DropSource
*ds
) {
1932 return ds
->sci
->AddRef();
1934 STDMETHODIMP_(ULONG
)DropSource_Release(DropSource
*ds
) {
1935 return ds
->sci
->Release();
1938 /// Implement IDropSource
1939 STDMETHODIMP
DropSource_QueryContinueDrag(DropSource
*, BOOL fEsc
, DWORD grfKeyState
) {
1941 return DRAGDROP_S_CANCEL
;
1942 if (!(grfKeyState
& MK_LBUTTON
))
1943 return DRAGDROP_S_DROP
;
1947 STDMETHODIMP
DropSource_GiveFeedback(DropSource
*, DWORD
) {
1948 return DRAGDROP_S_USEDEFAULTCURSORS
;
1951 static VFunction
*vtDropSource
[] = {
1952 (VFunction
*)(DropSource_QueryInterface
),
1953 (VFunction
*)(DropSource_AddRef
),
1954 (VFunction
*)(DropSource_Release
),
1955 (VFunction
*)(DropSource_QueryContinueDrag
),
1956 (VFunction
*)(DropSource_GiveFeedback
)
1959 DropSource::DropSource() {
1960 vtbl
= vtDropSource
;
1964 /// Implement IUnkown
1965 STDMETHODIMP
DataObject_QueryInterface(DataObject
*pd
, REFIID riid
, PVOID
*ppv
) {
1966 //Platform::DebugPrintf("DO QI %x\n", pd);
1967 return pd
->sci
->QueryInterface(riid
, ppv
);
1969 STDMETHODIMP_(ULONG
)DataObject_AddRef(DataObject
*pd
) {
1970 return pd
->sci
->AddRef();
1972 STDMETHODIMP_(ULONG
)DataObject_Release(DataObject
*pd
) {
1973 return pd
->sci
->Release();
1975 /// Implement IDataObject
1976 STDMETHODIMP
DataObject_GetData(DataObject
*pd
, FORMATETC
*pFEIn
, STGMEDIUM
*pSTM
) {
1977 return pd
->sci
->GetData(pFEIn
, pSTM
);
1980 STDMETHODIMP
DataObject_GetDataHere(DataObject
*, FORMATETC
*, STGMEDIUM
*) {
1981 //Platform::DebugPrintf("DOB GetDataHere\n");
1985 STDMETHODIMP
DataObject_QueryGetData(DataObject
*pd
, FORMATETC
*pFE
) {
1986 if (pd
->sci
->DragIsRectangularOK(pFE
->cfFormat
) &&
1988 (pFE
->dwAspect
& DVASPECT_CONTENT
) != 0 &&
1989 pFE
->lindex
== -1 &&
1990 (pFE
->tymed
& TYMED_HGLOBAL
) != 0
1995 bool formatOK
= (pFE
->cfFormat
== CF_TEXT
) ||
1996 ((pFE
->cfFormat
== CF_UNICODETEXT
) && pd
->sci
->IsUnicodeMode());
1999 (pFE
->dwAspect
& DVASPECT_CONTENT
) == 0 ||
2000 pFE
->lindex
!= -1 ||
2001 (pFE
->tymed
& TYMED_HGLOBAL
) == 0
2003 //Platform::DebugPrintf("DOB QueryGetData No %x\n",pFE->cfFormat);
2004 //return DATA_E_FORMATETC;
2007 //Platform::DebugPrintf("DOB QueryGetData OK %x\n",pFE->cfFormat);
2011 STDMETHODIMP
DataObject_GetCanonicalFormatEtc(DataObject
*pd
, FORMATETC
*, FORMATETC
*pFEOut
) {
2012 //Platform::DebugPrintf("DOB GetCanon\n");
2013 if (pd
->sci
->IsUnicodeMode())
2014 pFEOut
->cfFormat
= CF_UNICODETEXT
;
2016 pFEOut
->cfFormat
= CF_TEXT
;
2018 pFEOut
->dwAspect
= DVASPECT_CONTENT
;
2019 pFEOut
->lindex
= -1;
2020 pFEOut
->tymed
= TYMED_HGLOBAL
;
2024 STDMETHODIMP
DataObject_SetData(DataObject
*, FORMATETC
*, STGMEDIUM
*, BOOL
) {
2025 //Platform::DebugPrintf("DOB SetData\n");
2029 STDMETHODIMP
DataObject_EnumFormatEtc(DataObject
*pd
, DWORD dwDirection
, IEnumFORMATETC
**ppEnum
) {
2031 //Platform::DebugPrintf("DOB EnumFormatEtc %d\n", dwDirection);
2032 if (dwDirection
!= DATADIR_GET
) {
2036 FormatEnumerator
*pfe
;
2037 if (pd
->sci
->IsUnicodeMode()) {
2038 CLIPFORMAT formats
[] = {CF_UNICODETEXT
, CF_TEXT
};
2039 pfe
= new FormatEnumerator(0, formats
, ELEMENTS(formats
));
2041 CLIPFORMAT formats
[] = {CF_TEXT
};
2042 pfe
= new FormatEnumerator(0, formats
, ELEMENTS(formats
));
2044 return FormatEnumerator_QueryInterface(pfe
, IID_IEnumFORMATETC
,
2045 reinterpret_cast<void **>(ppEnum
));
2046 } catch (std::bad_alloc
&) {
2047 pd
->sci
->errorStatus
= SC_STATUS_BADALLOC
;
2048 return E_OUTOFMEMORY
;
2050 pd
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2055 STDMETHODIMP
DataObject_DAdvise(DataObject
*, FORMATETC
*, DWORD
, IAdviseSink
*, PDWORD
) {
2056 //Platform::DebugPrintf("DOB DAdvise\n");
2060 STDMETHODIMP
DataObject_DUnadvise(DataObject
*, DWORD
) {
2061 //Platform::DebugPrintf("DOB DUnadvise\n");
2065 STDMETHODIMP
DataObject_EnumDAdvise(DataObject
*, IEnumSTATDATA
**) {
2066 //Platform::DebugPrintf("DOB EnumDAdvise\n");
2070 static VFunction
*vtDataObject
[] = {
2071 (VFunction
*)(DataObject_QueryInterface
),
2072 (VFunction
*)(DataObject_AddRef
),
2073 (VFunction
*)(DataObject_Release
),
2074 (VFunction
*)(DataObject_GetData
),
2075 (VFunction
*)(DataObject_GetDataHere
),
2076 (VFunction
*)(DataObject_QueryGetData
),
2077 (VFunction
*)(DataObject_GetCanonicalFormatEtc
),
2078 (VFunction
*)(DataObject_SetData
),
2079 (VFunction
*)(DataObject_EnumFormatEtc
),
2080 (VFunction
*)(DataObject_DAdvise
),
2081 (VFunction
*)(DataObject_DUnadvise
),
2082 (VFunction
*)(DataObject_EnumDAdvise
)
2085 DataObject::DataObject() {
2086 vtbl
= vtDataObject
;
2090 /// Implement IUnknown
2091 STDMETHODIMP
DropTarget_QueryInterface(DropTarget
*dt
, REFIID riid
, PVOID
*ppv
) {
2092 //Platform::DebugPrintf("DT QI %x\n", dt);
2093 return dt
->sci
->QueryInterface(riid
, ppv
);
2095 STDMETHODIMP_(ULONG
)DropTarget_AddRef(DropTarget
*dt
) {
2096 return dt
->sci
->AddRef();
2098 STDMETHODIMP_(ULONG
)DropTarget_Release(DropTarget
*dt
) {
2099 return dt
->sci
->Release();
2102 /// Implement IDropTarget by forwarding to Scintilla
2103 STDMETHODIMP
DropTarget_DragEnter(DropTarget
*dt
, LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
2104 POINTL pt
, PDWORD pdwEffect
) {
2106 return dt
->sci
->DragEnter(pIDataSource
, grfKeyState
, pt
, pdwEffect
);
2108 dt
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2112 STDMETHODIMP
DropTarget_DragOver(DropTarget
*dt
, DWORD grfKeyState
, POINTL pt
, PDWORD pdwEffect
) {
2114 return dt
->sci
->DragOver(grfKeyState
, pt
, pdwEffect
);
2116 dt
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2120 STDMETHODIMP
DropTarget_DragLeave(DropTarget
*dt
) {
2122 return dt
->sci
->DragLeave();
2124 dt
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2128 STDMETHODIMP
DropTarget_Drop(DropTarget
*dt
, LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
2129 POINTL pt
, PDWORD pdwEffect
) {
2131 return dt
->sci
->Drop(pIDataSource
, grfKeyState
, pt
, pdwEffect
);
2133 dt
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2138 static VFunction
*vtDropTarget
[] = {
2139 (VFunction
*)(DropTarget_QueryInterface
),
2140 (VFunction
*)(DropTarget_AddRef
),
2141 (VFunction
*)(DropTarget_Release
),
2142 (VFunction
*)(DropTarget_DragEnter
),
2143 (VFunction
*)(DropTarget_DragOver
),
2144 (VFunction
*)(DropTarget_DragLeave
),
2145 (VFunction
*)(DropTarget_Drop
)
2148 DropTarget::DropTarget() {
2149 vtbl
= vtDropTarget
;
2154 * DBCS: support Input Method Editor (IME).
2155 * Called when IME Window opened.
2157 void ScintillaWin::ImeStartComposition() {
2159 // Move IME Window to current caret position
2160 HIMC hIMC
= ::ImmGetContext(MainHWND());
2161 Point pos
= PointMainCaret();
2162 COMPOSITIONFORM CompForm
;
2163 CompForm
.dwStyle
= CFS_POINT
;
2164 CompForm
.ptCurrentPos
.x
= static_cast<int>(pos
.x
);
2165 CompForm
.ptCurrentPos
.y
= static_cast<int>(pos
.y
);
2167 ::ImmSetCompositionWindow(hIMC
, &CompForm
);
2169 // Set font of IME window to same as surrounded text.
2171 // Since the style creation code has been made platform independent,
2172 // The logfont for the IME is recreated here.
2173 int styleHere
= (pdoc
->StyleAt(sel
.MainCaret())) & 31;
2174 LOGFONTW lf
= {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, L
""};
2175 int sizeZoomed
= vs
.styles
[styleHere
].size
+ vs
.zoomLevel
* SC_FONT_SIZE_MULTIPLIER
;
2176 if (sizeZoomed
<= 2 * SC_FONT_SIZE_MULTIPLIER
) // Hangs if sizeZoomed <= 1
2177 sizeZoomed
= 2 * SC_FONT_SIZE_MULTIPLIER
;
2178 AutoSurface
surface(this);
2179 int deviceHeight
= sizeZoomed
;
2181 deviceHeight
= (sizeZoomed
* surface
->LogPixelsY()) / 72;
2183 // The negative is to allow for leading
2184 lf
.lfHeight
= -(abs(deviceHeight
/ SC_FONT_SIZE_MULTIPLIER
));
2185 lf
.lfWeight
= vs
.styles
[styleHere
].weight
;
2186 lf
.lfItalic
= static_cast<BYTE
>(vs
.styles
[styleHere
].italic
? 1 : 0);
2187 lf
.lfCharSet
= DEFAULT_CHARSET
;
2188 lf
.lfFaceName
[0] = '\0';
2189 if (vs
.styles
[styleHere
].fontName
) {
2190 const char* fontName
= vs
.styles
[styleHere
].fontName
;
2191 UTF16FromUTF8(fontName
, strlen(fontName
)+1, lf
.lfFaceName
, LF_FACESIZE
);
2193 ::ImmSetCompositionFontW(hIMC
, &lf
);
2195 ::ImmReleaseContext(MainHWND(), hIMC
);
2196 // Caret is displayed in IME window. So, caret in Scintilla is useless.
2201 /** Called when IME Window closed. */
2202 void ScintillaWin::ImeEndComposition() {
2203 ShowCaretAtCurrentPosition();
2206 void ScintillaWin::AddCharBytes(char b0
, char b1
) {
2208 int inputCodePage
= InputCodePage();
2209 if (inputCodePage
&& IsUnicodeMode()) {
2210 char utfval
[4] = "\0\0\0";
2213 if (b0
) { // Two bytes from IME
2216 ansiChars
[2] = '\0';
2217 ::MultiByteToWideChar(inputCodePage
, 0, ansiChars
, 2, wcs
, 1);
2220 ansiChars
[1] = '\0';
2221 ::MultiByteToWideChar(inputCodePage
, 0, ansiChars
, 1, wcs
, 1);
2223 unsigned int len
= UTF8Length(wcs
, 1);
2224 UTF8FromUTF16(wcs
, 1, utfval
, len
);
2226 AddCharUTF(utfval
, len
? len
: 1);
2231 dbcsChars
[2] = '\0';
2232 AddCharUTF(dbcsChars
, 2, true);
2238 void ScintillaWin::GetIntelliMouseParameters() {
2239 // This retrieves the number of lines per scroll as configured inthe Mouse Properties sheet in Control Panel
2240 ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0, &linesPerScroll
, 0);
2243 void ScintillaWin::CopyToClipboard(const SelectionText
&selectedText
) {
2244 if (!::OpenClipboard(MainHWND()))
2248 GlobalMemory uniText
;
2250 // Default Scintilla behaviour in Unicode mode
2251 if (IsUnicodeMode()) {
2252 int uchars
= UTF16Length(selectedText
.Data(),
2253 static_cast<int>(selectedText
.LengthWithTerminator()));
2254 uniText
.Allocate(2 * uchars
);
2256 UTF16FromUTF8(selectedText
.Data(), static_cast<int>(selectedText
.LengthWithTerminator()),
2257 static_cast<wchar_t *>(uniText
.ptr
), uchars
);
2261 // Convert to Unicode using the current Scintilla code page
2262 UINT cpSrc
= CodePageFromCharSet(
2263 selectedText
.characterSet
, selectedText
.codePage
);
2264 int uLen
= ::MultiByteToWideChar(cpSrc
, 0, selectedText
.Data(),
2265 static_cast<int>(selectedText
.LengthWithTerminator()), 0, 0);
2266 uniText
.Allocate(2 * uLen
);
2268 ::MultiByteToWideChar(cpSrc
, 0, selectedText
.Data(),
2269 static_cast<int>(selectedText
.LengthWithTerminator()),
2270 static_cast<wchar_t *>(uniText
.ptr
), uLen
);
2276 // Copy ANSI text to clipboard on Windows 9x
2277 // Convert from Unicode text, so other ANSI programs can
2279 // Windows NT, 2k, XP automatically generates CF_TEXT
2280 GlobalMemory ansiText
;
2281 ansiText
.Allocate(selectedText
.LengthWithTerminator());
2283 ::WideCharToMultiByte(CP_ACP
, 0, static_cast<wchar_t *>(uniText
.ptr
), -1,
2284 static_cast<char *>(ansiText
.ptr
),
2285 static_cast<int>(selectedText
.LengthWithTerminator()), NULL
, NULL
);
2286 ansiText
.SetClip(CF_TEXT
);
2289 uniText
.SetClip(CF_UNICODETEXT
);
2291 // There was a failure - try to copy at least ANSI text
2292 GlobalMemory ansiText
;
2293 ansiText
.Allocate(selectedText
.LengthWithTerminator());
2295 memcpy(static_cast<char *>(ansiText
.ptr
), selectedText
.Data(), selectedText
.LengthWithTerminator());
2296 ansiText
.SetClip(CF_TEXT
);
2300 if (selectedText
.rectangular
) {
2301 ::SetClipboardData(cfColumnSelect
, 0);
2303 GlobalMemory borlandSelection
;
2304 borlandSelection
.Allocate(1);
2305 if (borlandSelection
) {
2306 static_cast<BYTE
*>(borlandSelection
.ptr
)[0] = 0x02;
2307 borlandSelection
.SetClip(cfBorlandIDEBlockType
);
2311 if (selectedText
.lineCopy
) {
2312 ::SetClipboardData(cfLineSelect
, 0);
2318 void ScintillaWin::ScrollMessage(WPARAM wParam
) {
2319 //DWORD dwStart = timeGetTime();
2320 //Platform::DebugPrintf("Scroll %x %d\n", wParam, lParam);
2322 SCROLLINFO sci
= {};
2323 sci
.cbSize
= sizeof(sci
);
2324 sci
.fMask
= SIF_ALL
;
2326 GetScrollInfo(SB_VERT
, &sci
);
2328 //Platform::DebugPrintf("ScrollInfo %d mask=%x min=%d max=%d page=%d pos=%d track=%d\n", b,sci.fMask,
2329 //sci.nMin, sci.nMax, sci.nPage, sci.nPos, sci.nTrackPos);
2331 int topLineNew
= topLine
;
2332 switch (LoWord(wParam
)) {
2340 topLineNew
-= LinesToScroll(); break;
2341 case SB_PAGEDOWN
: topLineNew
+= LinesToScroll(); break;
2342 case SB_TOP
: topLineNew
= 0; break;
2343 case SB_BOTTOM
: topLineNew
= MaxScrollPos(); break;
2344 case SB_THUMBPOSITION
: topLineNew
= sci
.nTrackPos
; break;
2345 case SB_THUMBTRACK
: topLineNew
= sci
.nTrackPos
; break;
2347 ScrollTo(topLineNew
);
2350 void ScintillaWin::HorizontalScrollMessage(WPARAM wParam
) {
2352 PRectangle rcText
= GetTextRectangle();
2353 int pageWidth
= static_cast<int>(rcText
.Width() * 2 / 3);
2354 switch (LoWord(wParam
)) {
2358 case SB_LINEDOWN
: // May move past the logical end
2366 if (xPos
> scrollWidth
- rcText
.Width()) { // Hit the end exactly
2367 xPos
= scrollWidth
- static_cast<int>(rcText
.Width());
2376 case SB_THUMBPOSITION
:
2377 case SB_THUMBTRACK
: {
2378 // 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 =]
2380 si
.cbSize
= sizeof(si
);
2381 si
.fMask
= SIF_TRACKPOS
;
2382 if (GetScrollInfo(SB_HORZ
, &si
)) {
2383 xPos
= si
.nTrackPos
;
2388 HorizontalScrollTo(xPos
);
2392 * Redraw all of text area.
2393 * This paint will not be abandoned.
2395 void ScintillaWin::FullPaint() {
2396 if (technology
== SC_TECHNOLOGY_DEFAULT
) {
2397 HDC hdc
= ::GetDC(MainHWND());
2399 ::ReleaseDC(MainHWND(), hdc
);
2406 * Redraw all of text area on the specified DC.
2407 * This paint will not be abandoned.
2409 void ScintillaWin::FullPaintDC(HDC hdc
) {
2410 paintState
= painting
;
2411 rcPaint
= GetClientRectangle();
2412 paintingAllText
= true;
2413 if (technology
== SC_TECHNOLOGY_DEFAULT
) {
2414 AutoSurface
surfaceWindow(hdc
, this);
2415 if (surfaceWindow
) {
2416 Paint(surfaceWindow
, rcPaint
);
2417 surfaceWindow
->Release();
2420 #if defined(USE_D2D)
2421 EnsureRenderTarget();
2422 AutoSurface
surfaceWindow(pRenderTarget
, this);
2423 if (surfaceWindow
) {
2424 pRenderTarget
->BeginDraw();
2425 Paint(surfaceWindow
, rcPaint
);
2426 surfaceWindow
->Release();
2427 HRESULT hr
= pRenderTarget
->EndDraw();
2428 if (hr
== D2DERR_RECREATE_TARGET
) {
2434 paintState
= notPainting
;
2437 static bool CompareDevCap(HDC hdc
, HDC hOtherDC
, int nIndex
) {
2438 return ::GetDeviceCaps(hdc
, nIndex
) == ::GetDeviceCaps(hOtherDC
, nIndex
);
2441 bool ScintillaWin::IsCompatibleDC(HDC hOtherDC
) {
2442 HDC hdc
= ::GetDC(MainHWND());
2444 CompareDevCap(hdc
, hOtherDC
, TECHNOLOGY
) &&
2445 CompareDevCap(hdc
, hOtherDC
, LOGPIXELSY
) &&
2446 CompareDevCap(hdc
, hOtherDC
, LOGPIXELSX
) &&
2447 CompareDevCap(hdc
, hOtherDC
, BITSPIXEL
) &&
2448 CompareDevCap(hdc
, hOtherDC
, PLANES
);
2449 ::ReleaseDC(MainHWND(), hdc
);
2450 return isCompatible
;
2453 DWORD
ScintillaWin::EffectFromState(DWORD grfKeyState
) const {
2454 // These are the Wordpad semantics.
2456 if (inDragDrop
== ddDragging
) // Internal defaults to move
2457 dwEffect
= DROPEFFECT_MOVE
;
2459 dwEffect
= DROPEFFECT_COPY
;
2460 if (grfKeyState
& MK_ALT
)
2461 dwEffect
= DROPEFFECT_MOVE
;
2462 if (grfKeyState
& MK_CONTROL
)
2463 dwEffect
= DROPEFFECT_COPY
;
2467 /// Implement IUnknown
2468 STDMETHODIMP
ScintillaWin::QueryInterface(REFIID riid
, PVOID
*ppv
) {
2470 if (riid
== IID_IUnknown
)
2471 *ppv
= reinterpret_cast<IDropTarget
*>(&dt
);
2472 if (riid
== IID_IDropSource
)
2473 *ppv
= reinterpret_cast<IDropSource
*>(&ds
);
2474 if (riid
== IID_IDropTarget
)
2475 *ppv
= reinterpret_cast<IDropTarget
*>(&dt
);
2476 if (riid
== IID_IDataObject
)
2477 *ppv
= reinterpret_cast<IDataObject
*>(&dob
);
2479 return E_NOINTERFACE
;
2483 STDMETHODIMP_(ULONG
) ScintillaWin::AddRef() {
2487 STDMETHODIMP_(ULONG
) ScintillaWin::Release() {
2491 /// Implement IDropTarget
2492 STDMETHODIMP
ScintillaWin::DragEnter(LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
2493 POINTL
, PDWORD pdwEffect
) {
2494 if (pIDataSource
== NULL
)
2496 FORMATETC fmtu
= {CF_UNICODETEXT
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2497 HRESULT hrHasUText
= pIDataSource
->QueryGetData(&fmtu
);
2498 hasOKText
= (hrHasUText
== S_OK
);
2500 FORMATETC fmte
= {CF_TEXT
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2501 HRESULT hrHasText
= pIDataSource
->QueryGetData(&fmte
);
2502 hasOKText
= (hrHasText
== S_OK
);
2505 *pdwEffect
= DROPEFFECT_NONE
;
2509 *pdwEffect
= EffectFromState(grfKeyState
);
2513 STDMETHODIMP
ScintillaWin::DragOver(DWORD grfKeyState
, POINTL pt
, PDWORD pdwEffect
) {
2515 if (!hasOKText
|| pdoc
->IsReadOnly()) {
2516 *pdwEffect
= DROPEFFECT_NONE
;
2520 *pdwEffect
= EffectFromState(grfKeyState
);
2522 // Update the cursor.
2523 POINT rpt
= {pt
.x
, pt
.y
};
2524 ::ScreenToClient(MainHWND(), &rpt
);
2525 SetDragPosition(SPositionFromLocation(PointFromPOINT(rpt
), false, false, UserVirtualSpace()));
2529 errorStatus
= SC_STATUS_FAILURE
;
2534 STDMETHODIMP
ScintillaWin::DragLeave() {
2536 SetDragPosition(SelectionPosition(invalidPosition
));
2539 errorStatus
= SC_STATUS_FAILURE
;
2544 STDMETHODIMP
ScintillaWin::Drop(LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
2545 POINTL pt
, PDWORD pdwEffect
) {
2547 *pdwEffect
= EffectFromState(grfKeyState
);
2549 if (pIDataSource
== NULL
)
2552 SetDragPosition(SelectionPosition(invalidPosition
));
2554 STGMEDIUM medium
= {0, {0}, 0};
2556 std::vector
<char> data
; // Includes terminating NUL
2558 FORMATETC fmtu
= {CF_UNICODETEXT
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2559 HRESULT hr
= pIDataSource
->GetData(&fmtu
, &medium
);
2560 if (SUCCEEDED(hr
) && medium
.hGlobal
) {
2561 GlobalMemory
memUDrop(medium
.hGlobal
);
2562 wchar_t *udata
= static_cast<wchar_t *>(memUDrop
.ptr
);
2564 if (IsUnicodeMode()) {
2565 int tlen
= static_cast<int>(memUDrop
.Size());
2566 // Convert UTF-16 to UTF-8
2567 int dataLen
= UTF8Length(udata
, tlen
/2);
2568 data
.resize(dataLen
+1);
2569 UTF8FromUTF16(udata
, tlen
/2, &data
[0], dataLen
);
2571 // Convert UTF-16 to ANSI
2573 // Default Scintilla behavior in Unicode mode
2574 // CF_UNICODETEXT available, but not in Unicode mode
2575 // Convert from Unicode to current Scintilla code page
2576 UINT cpDest
= CodePageOfDocument();
2577 int tlen
= ::WideCharToMultiByte(cpDest
, 0, udata
, -1,
2578 NULL
, 0, NULL
, NULL
) - 1; // subtract 0 terminator
2579 data
.resize(tlen
+ 1);
2580 ::WideCharToMultiByte(cpDest
, 0, udata
, -1,
2581 &data
[0], tlen
+ 1, NULL
, NULL
);
2586 FORMATETC fmte
= {CF_TEXT
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2587 hr
= pIDataSource
->GetData(&fmte
, &medium
);
2588 if (SUCCEEDED(hr
) && medium
.hGlobal
) {
2589 GlobalMemory
memDrop(medium
.hGlobal
);
2590 const char *cdata
= static_cast<char *>(memDrop
.ptr
);
2592 data
.assign(cdata
, cdata
+strlen(cdata
)+1);
2597 if (!SUCCEEDED(hr
) || data
.empty()) {
2598 //Platform::DebugPrintf("Bad data format: 0x%x\n", hres);
2602 FORMATETC fmtr
= {cfColumnSelect
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2603 HRESULT hrRectangular
= pIDataSource
->QueryGetData(&fmtr
);
2605 POINT rpt
= {pt
.x
, pt
.y
};
2606 ::ScreenToClient(MainHWND(), &rpt
);
2607 SelectionPosition movePos
= SPositionFromLocation(PointFromPOINT(rpt
), false, false, UserVirtualSpace());
2609 DropAt(movePos
, &data
[0], data
.size() - 1, *pdwEffect
== DROPEFFECT_MOVE
, hrRectangular
== S_OK
);
2612 if (medium
.pUnkForRelease
!= NULL
)
2613 medium
.pUnkForRelease
->Release();
2615 ::GlobalFree(medium
.hGlobal
);
2619 errorStatus
= SC_STATUS_FAILURE
;
2624 /// Implement important part of IDataObject
2625 STDMETHODIMP
ScintillaWin::GetData(FORMATETC
*pFEIn
, STGMEDIUM
*pSTM
) {
2626 bool formatOK
= (pFEIn
->cfFormat
== CF_TEXT
) ||
2627 ((pFEIn
->cfFormat
== CF_UNICODETEXT
) && IsUnicodeMode());
2630 (pFEIn
->dwAspect
& DVASPECT_CONTENT
) == 0 ||
2631 pFEIn
->lindex
!= -1 ||
2632 (pFEIn
->tymed
& TYMED_HGLOBAL
) == 0
2634 //Platform::DebugPrintf("DOB GetData No %d %x %x fmt=%x\n", lenDrag, pFEIn, pSTM, pFEIn->cfFormat);
2635 return DATA_E_FORMATETC
;
2637 pSTM
->tymed
= TYMED_HGLOBAL
;
2638 //Platform::DebugPrintf("DOB GetData OK %d %x %x\n", lenDrag, pFEIn, pSTM);
2641 if (pFEIn
->cfFormat
== CF_UNICODETEXT
) {
2642 int uchars
= UTF16Length(drag
.Data(), static_cast<int>(drag
.LengthWithTerminator()));
2643 text
.Allocate(2 * uchars
);
2645 UTF16FromUTF8(drag
.Data(), static_cast<int>(drag
.LengthWithTerminator()),
2646 static_cast<wchar_t *>(text
.ptr
), uchars
);
2649 text
.Allocate(drag
.LengthWithTerminator());
2651 memcpy(static_cast<char *>(text
.ptr
), drag
.Data(), drag
.LengthWithTerminator());
2654 pSTM
->hGlobal
= text
? text
.Unlock() : 0;
2655 pSTM
->pUnkForRelease
= 0;
2659 bool ScintillaWin::Register(HINSTANCE hInstance_
) {
2661 hInstance
= hInstance_
;
2664 // Register the Scintilla class
2667 // Register Scintilla as a wide character window
2668 WNDCLASSEXW wndclass
;
2669 wndclass
.cbSize
= sizeof(wndclass
);
2670 wndclass
.style
= CS_GLOBALCLASS
| CS_HREDRAW
| CS_VREDRAW
;
2671 wndclass
.lpfnWndProc
= ScintillaWin::SWndProc
;
2672 wndclass
.cbClsExtra
= 0;
2673 wndclass
.cbWndExtra
= sizeof(ScintillaWin
*);
2674 wndclass
.hInstance
= hInstance
;
2675 wndclass
.hIcon
= NULL
;
2676 wndclass
.hCursor
= NULL
;
2677 wndclass
.hbrBackground
= NULL
;
2678 wndclass
.lpszMenuName
= NULL
;
2679 wndclass
.lpszClassName
= L
"Scintilla";
2680 wndclass
.hIconSm
= 0;
2681 result
= ::RegisterClassExW(&wndclass
) != 0;
2684 // Register Scintilla as a normal character window
2685 WNDCLASSEX wndclass
;
2686 wndclass
.cbSize
= sizeof(wndclass
);
2687 wndclass
.style
= CS_GLOBALCLASS
| CS_HREDRAW
| CS_VREDRAW
;
2688 wndclass
.lpfnWndProc
= ScintillaWin::SWndProc
;
2689 wndclass
.cbClsExtra
= 0;
2690 wndclass
.cbWndExtra
= sizeof(ScintillaWin
*);
2691 wndclass
.hInstance
= hInstance
;
2692 wndclass
.hIcon
= NULL
;
2693 wndclass
.hCursor
= NULL
;
2694 wndclass
.hbrBackground
= NULL
;
2695 wndclass
.lpszMenuName
= NULL
;
2696 wndclass
.lpszClassName
= scintillaClassName
;
2697 wndclass
.hIconSm
= 0;
2698 result
= ::RegisterClassEx(&wndclass
) != 0;
2702 // Register the CallTip class
2703 WNDCLASSEX wndclassc
;
2704 wndclassc
.cbSize
= sizeof(wndclassc
);
2705 wndclassc
.style
= CS_GLOBALCLASS
| CS_HREDRAW
| CS_VREDRAW
;
2706 wndclassc
.cbClsExtra
= 0;
2707 wndclassc
.cbWndExtra
= sizeof(ScintillaWin
*);
2708 wndclassc
.hInstance
= hInstance
;
2709 wndclassc
.hIcon
= NULL
;
2710 wndclassc
.hbrBackground
= NULL
;
2711 wndclassc
.lpszMenuName
= NULL
;
2712 wndclassc
.lpfnWndProc
= ScintillaWin::CTWndProc
;
2713 wndclassc
.hCursor
= ::LoadCursor(NULL
, IDC_ARROW
);
2714 wndclassc
.lpszClassName
= callClassName
;
2715 wndclassc
.hIconSm
= 0;
2717 result
= ::RegisterClassEx(&wndclassc
) != 0;
2723 bool ScintillaWin::Unregister() {
2724 bool result
= ::UnregisterClass(scintillaClassName
, hInstance
) != 0;
2725 if (::UnregisterClass(callClassName
, hInstance
) == 0)
2730 bool ScintillaWin::HasCaretSizeChanged() const {
2732 ( (0 != vs
.caretWidth
) && (sysCaretWidth
!= vs
.caretWidth
) )
2733 || ((0 != vs
.lineHeight
) && (sysCaretHeight
!= vs
.lineHeight
))
2740 BOOL
ScintillaWin::CreateSystemCaret() {
2741 sysCaretWidth
= vs
.caretWidth
;
2742 if (0 == sysCaretWidth
) {
2745 sysCaretHeight
= vs
.lineHeight
;
2746 int bitmapSize
= (((sysCaretWidth
+ 15) & ~15) >> 3) *
2748 std::vector
<char> bits(bitmapSize
);
2749 sysCaretBitmap
= ::CreateBitmap(sysCaretWidth
, sysCaretHeight
, 1,
2750 1, reinterpret_cast<BYTE
*>(&bits
[0]));
2751 BOOL retval
= ::CreateCaret(
2752 MainHWND(), sysCaretBitmap
,
2753 sysCaretWidth
, sysCaretHeight
);
2754 ::ShowCaret(MainHWND());
2758 BOOL
ScintillaWin::DestroySystemCaret() {
2759 ::HideCaret(MainHWND());
2760 BOOL retval
= ::DestroyCaret();
2761 if (sysCaretBitmap
) {
2762 ::DeleteObject(sysCaretBitmap
);
2768 sptr_t PASCAL
ScintillaWin::CTWndProc(
2769 HWND hWnd
, UINT iMessage
, WPARAM wParam
, sptr_t lParam
) {
2770 // Find C++ object associated with window.
2771 ScintillaWin
*sciThis
= reinterpret_cast<ScintillaWin
*>(PointerFromWindow(hWnd
));
2773 // ctp will be zero if WM_CREATE not seen yet
2775 if (iMessage
== WM_CREATE
) {
2776 // Associate CallTip object with window
2777 CREATESTRUCT
*pCreate
= reinterpret_cast<CREATESTRUCT
*>(lParam
);
2778 SetWindowPointer(hWnd
, pCreate
->lpCreateParams
);
2781 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2784 if (iMessage
== WM_NCDESTROY
) {
2785 ::SetWindowLong(hWnd
, 0, 0);
2786 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2787 } else if (iMessage
== WM_PAINT
) {
2789 ::BeginPaint(hWnd
, &ps
);
2790 Surface
*surfaceWindow
= Surface::Allocate(sciThis
->technology
);
2791 if (surfaceWindow
) {
2792 #if defined(USE_D2D)
2793 ID2D1HwndRenderTarget
*pCTRenderTarget
= 0;
2796 GetClientRect(hWnd
, &rc
);
2797 // Create a Direct2D render target.
2798 if (sciThis
->technology
== SC_TECHNOLOGY_DEFAULT
) {
2799 surfaceWindow
->Init(ps
.hdc
, hWnd
);
2801 #if defined(USE_D2D)
2802 D2D1_HWND_RENDER_TARGET_PROPERTIES dhrtp
;
2804 dhrtp
.pixelSize
= D2D1::SizeU(rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
2805 dhrtp
.presentOptions
= D2D1_PRESENT_OPTIONS_NONE
;
2807 D2D1_RENDER_TARGET_PROPERTIES drtp
;
2808 drtp
.type
= D2D1_RENDER_TARGET_TYPE_DEFAULT
;
2809 drtp
.pixelFormat
.format
= DXGI_FORMAT_UNKNOWN
;
2810 drtp
.pixelFormat
.alphaMode
= D2D1_ALPHA_MODE_UNKNOWN
;
2813 drtp
.usage
= D2D1_RENDER_TARGET_USAGE_NONE
;
2814 drtp
.minLevel
= D2D1_FEATURE_LEVEL_DEFAULT
;
2816 if (!SUCCEEDED(pD2DFactory
->CreateHwndRenderTarget(drtp
, dhrtp
, &pCTRenderTarget
))) {
2817 surfaceWindow
->Release();
2818 delete surfaceWindow
;
2819 ::EndPaint(hWnd
, &ps
);
2822 surfaceWindow
->Init(pCTRenderTarget
, hWnd
);
2823 pCTRenderTarget
->BeginDraw();
2826 surfaceWindow
->SetUnicodeMode(SC_CP_UTF8
== sciThis
->ct
.codePage
);
2827 surfaceWindow
->SetDBCSMode(sciThis
->ct
.codePage
);
2828 sciThis
->ct
.PaintCT(surfaceWindow
);
2829 #if defined(USE_D2D)
2830 if (pCTRenderTarget
)
2831 pCTRenderTarget
->EndDraw();
2833 surfaceWindow
->Release();
2834 delete surfaceWindow
;
2835 #if defined(USE_D2D)
2836 if (pCTRenderTarget
)
2837 pCTRenderTarget
->Release();
2840 ::EndPaint(hWnd
, &ps
);
2842 } else if ((iMessage
== WM_NCLBUTTONDOWN
) || (iMessage
== WM_NCLBUTTONDBLCLK
)) {
2844 pt
.x
= static_cast<short>(LOWORD(lParam
));
2845 pt
.y
= static_cast<short>(HIWORD(lParam
));
2846 ScreenToClient(hWnd
, &pt
);
2847 sciThis
->ct
.MouseClick(PointFromPOINT(pt
));
2848 sciThis
->CallTipClick();
2850 } else if (iMessage
== WM_LBUTTONDOWN
) {
2851 // This does not fire due to the hit test code
2852 sciThis
->ct
.MouseClick(Point::FromLong(static_cast<long>(lParam
)));
2853 sciThis
->CallTipClick();
2855 } else if (iMessage
== WM_SETCURSOR
) {
2856 ::SetCursor(::LoadCursor(NULL
, IDC_ARROW
));
2858 } else if (iMessage
== WM_NCHITTEST
) {
2861 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2865 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2867 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2870 sptr_t
ScintillaWin::DirectFunction(
2871 sptr_t ptr
, UINT iMessage
, uptr_t wParam
, sptr_t lParam
) {
2872 PLATFORM_ASSERT(::GetCurrentThreadId() == ::GetWindowThreadProcessId(reinterpret_cast<ScintillaWin
*>(ptr
)->MainHWND(), NULL
));
2873 return reinterpret_cast<ScintillaWin
*>(ptr
)->WndProc(iMessage
, wParam
, lParam
);
2877 #ifndef STATIC_BUILD
2878 __declspec(dllexport
)
2880 sptr_t __stdcall
Scintilla_DirectFunction(
2881 ScintillaWin
*sci
, UINT iMessage
, uptr_t wParam
, sptr_t lParam
) {
2882 return sci
->WndProc(iMessage
, wParam
, lParam
);
2885 sptr_t PASCAL
ScintillaWin::SWndProc(
2886 HWND hWnd
, UINT iMessage
, WPARAM wParam
, sptr_t lParam
) {
2887 //Platform::DebugPrintf("S W:%x M:%x WP:%x L:%x\n", hWnd, iMessage, wParam, lParam);
2889 // Find C++ object associated with window.
2890 ScintillaWin
*sci
= reinterpret_cast<ScintillaWin
*>(PointerFromWindow(hWnd
));
2891 // sci will be zero if WM_CREATE not seen yet
2894 if (iMessage
== WM_CREATE
) {
2895 // Create C++ object associated with window
2896 sci
= new ScintillaWin(hWnd
);
2897 SetWindowPointer(hWnd
, sci
);
2898 return sci
->WndProc(iMessage
, wParam
, lParam
);
2902 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2904 if (iMessage
== WM_NCDESTROY
) {
2910 ::SetWindowLong(hWnd
, 0, 0);
2911 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2913 return sci
->WndProc(iMessage
, wParam
, lParam
);
2918 // This function is externally visible so it can be called from container when building statically.
2919 // Must be called once only.
2920 int Scintilla_RegisterClasses(void *hInstance
) {
2921 Platform_Initialise(hInstance
);
2922 bool result
= ScintillaWin::Register(reinterpret_cast<HINSTANCE
>(hInstance
));
2924 Scintilla_LinkLexers();
2929 static int ResourcesRelease(bool fromDllMain
) {
2930 bool result
= ScintillaWin::Unregister();
2932 FreeLibrary(commctrl32
);
2935 Platform_Finalise(fromDllMain
);
2939 // This function is externally visible so it can be called from container when building statically.
2940 int Scintilla_ReleaseResources() {
2941 return ResourcesRelease(false);
2944 #ifndef STATIC_BUILD
2945 extern "C" int APIENTRY
DllMain(HINSTANCE hInstance
, DWORD dwReason
, LPVOID lpvReserved
) {
2946 //Platform::DebugPrintf("Scintilla::DllMain %d %d\n", hInstance, dwReason);
2947 if (dwReason
== DLL_PROCESS_ATTACH
) {
2948 if (!Scintilla_RegisterClasses(hInstance
))
2950 } else if (dwReason
== DLL_PROCESS_DETACH
) {
2951 if (lpvReserved
== NULL
) {
2952 ResourcesRelease(true);