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
30 #if defined(NTDDI_WIN7) && !defined(DISABLE_D2D)
42 #include "Scintilla.h"
46 #include "LexerModule.h"
48 #include "SplitVector.h"
49 #include "Partitioning.h"
50 #include "RunStyles.h"
51 #include "ContractionState.h"
52 #include "CellBuffer.h"
55 #include "Indicator.h"
57 #include "LineMarker.h"
59 #include "AutoComplete.h"
60 #include "ViewStyle.h"
61 #include "CharClassify.h"
62 #include "Decoration.h"
63 #include "CaseFolder.h"
65 #include "Selection.h"
66 #include "PositionCache.h"
68 #include "ScintillaBase.h"
69 #include "UniConversion.h"
70 #include "CaseConvert.h"
75 #include "ExternalLexer.h"
78 #ifndef SPI_GETWHEELSCROLLLINES
79 #define SPI_GETWHEELSCROLLLINES 104
83 #define WM_UNICHAR 0x0109
86 #ifndef UNICODE_NOCHAR
87 #define UNICODE_NOCHAR 0xFFFF
90 #ifndef WM_IME_STARTCOMPOSITION
102 #define SC_WIN_IDLE 5001
104 typedef BOOL (WINAPI
*TrackMouseEventSig
)(LPTRACKMOUSEEVENT
);
106 // GCC has trouble with the standard COM ABI so do it the old C way with explicit vtables.
108 const TCHAR scintillaClassName
[] = TEXT("Scintilla");
109 const TCHAR callClassName
[] = TEXT("CallTip");
112 using namespace Scintilla
;
115 // Take care of 32/64 bit pointers
116 #ifdef GetWindowLongPtr
117 static void *PointerFromWindow(HWND hWnd
) {
118 return reinterpret_cast<void *>(::GetWindowLongPtr(hWnd
, 0));
120 static void SetWindowPointer(HWND hWnd
, void *ptr
) {
121 ::SetWindowLongPtr(hWnd
, 0, reinterpret_cast<LONG_PTR
>(ptr
));
123 static void SetWindowID(HWND hWnd
, int identifier
) {
124 ::SetWindowLongPtr(hWnd
, GWLP_ID
, identifier
);
127 static void *PointerFromWindow(HWND hWnd
) {
128 return reinterpret_cast<void *>(::GetWindowLong(hWnd
, 0));
130 static void SetWindowPointer(HWND hWnd
, void *ptr
) {
131 ::SetWindowLong(hWnd
, 0, reinterpret_cast<LONG
>(ptr
));
133 static void SetWindowID(HWND hWnd
, int identifier
) {
134 ::SetWindowLong(hWnd
, GWL_ID
, identifier
);
138 class ScintillaWin
; // Forward declaration for COM interface subobjects
140 typedef void VFunction(void);
144 class FormatEnumerator
{
149 CLIPFORMAT formats
[2];
151 FormatEnumerator(int pos_
, CLIPFORMAT formats_
[], int formatsLen_
);
184 public ScintillaBase
{
186 bool lastKeyDownConsumed
;
189 bool trackedMouseLeave
;
190 TrackMouseEventSig TrackMouseEventFn
;
192 unsigned int linesPerScroll
; ///< Intellimouse support
193 int wheelDelta
; ///< Wheel delta from roll
199 CLIPFORMAT cfColumnSelect
;
200 CLIPFORMAT cfBorlandIDEBlockType
;
201 CLIPFORMAT cfLineSelect
;
208 static HINSTANCE hInstance
;
211 ID2D1HwndRenderTarget
*pRenderTarget
;
212 bool renderTargetValid
;
215 ScintillaWin(HWND hwnd
);
216 ScintillaWin(const ScintillaWin
&);
217 virtual ~ScintillaWin();
218 ScintillaWin
&operator=(const ScintillaWin
&);
220 virtual void Initialise();
221 virtual void Finalise();
223 void EnsureRenderTarget();
224 void DropRenderTarget();
228 static sptr_t
DirectFunction(
229 ScintillaWin
*sci
, UINT iMessage
, uptr_t wParam
, sptr_t lParam
);
230 static sptr_t PASCAL
SWndProc(
231 HWND hWnd
, UINT iMessage
, WPARAM wParam
, sptr_t lParam
);
232 static sptr_t PASCAL
CTWndProc(
233 HWND hWnd
, UINT iMessage
, WPARAM wParam
, sptr_t lParam
);
235 enum { invalidTimerID
, standardTimerID
, idleTimerID
};
237 virtual bool DragThreshold(Point ptStart
, Point ptNow
);
238 virtual void StartDrag();
239 sptr_t
WndPaint(uptr_t wParam
);
240 sptr_t
HandleComposition(uptr_t wParam
, sptr_t lParam
);
241 UINT
CodePageOfDocument();
242 virtual bool ValidCodePage(int codePage
) const;
243 virtual sptr_t
DefWndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
244 virtual bool SetIdle(bool on
);
245 virtual void SetTicking(bool on
);
246 virtual void SetMouseCapture(bool on
);
247 virtual bool HaveMouseCapture();
248 virtual void SetTrackMouseLeaveEvent(bool on
);
249 virtual bool PaintContains(PRectangle rc
);
250 virtual void ScrollText(int linesToMove
);
251 virtual void UpdateSystemCaret();
252 virtual void SetVerticalScrollPos();
253 virtual void SetHorizontalScrollPos();
254 virtual bool ModifyScrollBars(int nMax
, int nPage
);
255 virtual void NotifyChange();
256 virtual void NotifyFocus(bool focus
);
257 virtual void SetCtrlID(int identifier
);
258 virtual int GetCtrlID();
259 virtual void NotifyParent(SCNotification scn
);
260 virtual void NotifyParent(SCNotification
* scn
);
261 virtual void NotifyDoubleClick(Point pt
, bool shift
, bool ctrl
, bool alt
);
262 virtual CaseFolder
*CaseFolderForEncoding();
263 virtual std::string
CaseMapString(const std::string
&s
, int caseMapping
);
265 virtual void CopyAllowLine();
266 virtual bool CanPaste();
267 virtual void Paste();
268 virtual void CreateCallTipWindow(PRectangle rc
);
269 virtual void AddToPopUp(const char *label
, int cmd
= 0, bool enabled
= true);
270 virtual void ClaimSelection();
273 void ImeStartComposition();
274 void ImeEndComposition();
276 void AddCharBytes(char b0
, char b1
);
278 void GetIntelliMouseParameters();
279 virtual void CopyToClipboard(const SelectionText
&selectedText
);
280 void ScrollMessage(WPARAM wParam
);
281 void HorizontalScrollMessage(WPARAM wParam
);
283 void FullPaintDC(HDC dc
);
284 bool IsCompatibleDC(HDC dc
);
285 DWORD
EffectFromState(DWORD grfKeyState
) const;
287 virtual int SetScrollInfo(int nBar
, LPCSCROLLINFO lpsi
, BOOL bRedraw
);
288 virtual bool GetScrollInfo(int nBar
, LPSCROLLINFO lpsi
);
289 void ChangeScrollPos(int barType
, int pos
);
291 void InsertPasteText(const char *text
, int len
, SelectionPosition selStart
, bool isRectangular
, bool isLine
);
294 // Public for benefit of Scintilla_DirectFunction
295 virtual sptr_t
WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
297 /// Implement IUnknown
298 STDMETHODIMP
QueryInterface(REFIID riid
, PVOID
*ppv
);
299 STDMETHODIMP_(ULONG
)AddRef();
300 STDMETHODIMP_(ULONG
)Release();
302 /// Implement IDropTarget
303 STDMETHODIMP
DragEnter(LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
304 POINTL pt
, PDWORD pdwEffect
);
305 STDMETHODIMP
DragOver(DWORD grfKeyState
, POINTL pt
, PDWORD pdwEffect
);
306 STDMETHODIMP
DragLeave();
307 STDMETHODIMP
Drop(LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
308 POINTL pt
, PDWORD pdwEffect
);
310 /// Implement important part of IDataObject
311 STDMETHODIMP
GetData(FORMATETC
*pFEIn
, STGMEDIUM
*pSTM
);
313 static bool Register(HINSTANCE hInstance_
);
314 static bool Unregister();
316 friend class DropSource
;
317 friend class DataObject
;
318 friend class DropTarget
;
319 bool DragIsRectangularOK(CLIPFORMAT fmt
) const {
320 return drag
.rectangular
&& (fmt
== cfColumnSelect
);
324 // For use in creating a system caret
325 bool HasCaretSizeChanged() const;
326 BOOL
CreateSystemCaret();
327 BOOL
DestroySystemCaret();
328 HBITMAP sysCaretBitmap
;
331 bool keysAlwaysUnicode
;
334 HINSTANCE
ScintillaWin::hInstance
= 0;
336 ScintillaWin::ScintillaWin(HWND hwnd
) {
338 lastKeyDownConsumed
= false;
340 capturedMouse
= false;
341 trackedMouseLeave
= false;
342 TrackMouseEventFn
= 0;
345 wheelDelta
= 0; // Wheel delta from roll
351 // There does not seem to be a real standard for indicating that the clipboard
352 // contains a rectangular selection, so copy Developer Studio and Borland Delphi.
353 cfColumnSelect
= static_cast<CLIPFORMAT
>(
354 ::RegisterClipboardFormat(TEXT("MSDEVColumnSelect")));
355 cfBorlandIDEBlockType
= static_cast<CLIPFORMAT
>(
356 ::RegisterClipboardFormat(TEXT("Borland IDE Block Type")));
358 // Likewise for line-copy (copies a full line when no text is selected)
359 cfLineSelect
= static_cast<CLIPFORMAT
>(
360 ::RegisterClipboardFormat(TEXT("MSDEVLineSelect")));
376 renderTargetValid
= true;
379 keysAlwaysUnicode
= false;
381 caret
.period
= ::GetCaretBlinkTime();
382 if (caret
.period
< 0)
388 ScintillaWin::~ScintillaWin() {}
390 void ScintillaWin::Initialise() {
391 // Initialize COM. If the app has already done this it will have
392 // no effect. If the app hasnt, we really shouldnt ask them to call
393 // it just so this internal feature works.
394 hrOle
= ::OleInitialize(NULL
);
396 // Find TrackMouseEvent which is available on Windows > 95
397 HMODULE user32
= ::GetModuleHandle(TEXT("user32.dll"));
399 TrackMouseEventFn
= (TrackMouseEventSig
)::GetProcAddress(user32
, "TrackMouseEvent");
400 if (TrackMouseEventFn
== NULL
) {
401 // Windows 95 has an emulation in comctl32.dll:_TrackMouseEvent
402 HMODULE commctrl32
= ::LoadLibrary(TEXT("comctl32.dll"));
403 if (commctrl32
!= NULL
) {
404 TrackMouseEventFn
= (TrackMouseEventSig
)
405 ::GetProcAddress(commctrl32
, "_TrackMouseEvent");
410 void ScintillaWin::Finalise() {
411 ScintillaBase::Finalise();
417 ::RevokeDragDrop(MainHWND());
418 if (SUCCEEDED(hrOle
)) {
425 void ScintillaWin::EnsureRenderTarget() {
426 if (!renderTargetValid
) {
428 renderTargetValid
= true;
430 if (pD2DFactory
&& !pRenderTarget
) {
432 HWND hw
= MainHWND();
433 GetClientRect(hw
, &rc
);
435 D2D1_SIZE_U size
= D2D1::SizeU(rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
437 // Create a Direct2D render target.
439 D2D1_HWND_RENDER_TARGET_PROPERTIES dhrtp
;
441 dhrtp
.pixelSize
= size
;
442 dhrtp
.presentOptions
= D2D1_PRESENT_OPTIONS_NONE
;
444 D2D1_RENDER_TARGET_PROPERTIES drtp
;
445 drtp
.type
= D2D1_RENDER_TARGET_TYPE_DEFAULT
;
446 drtp
.pixelFormat
.format
= DXGI_FORMAT_UNKNOWN
;
447 drtp
.pixelFormat
.alphaMode
= D2D1_ALPHA_MODE_UNKNOWN
;
450 drtp
.usage
= D2D1_RENDER_TARGET_USAGE_NONE
;
451 drtp
.minLevel
= D2D1_FEATURE_LEVEL_DEFAULT
;
453 pD2DFactory
->CreateHwndRenderTarget(drtp
, dhrtp
, &pRenderTarget
);
455 pD2DFactory
->CreateHwndRenderTarget(
456 D2D1::RenderTargetProperties(
457 D2D1_RENDER_TARGET_TYPE_DEFAULT
,
458 D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM
, D2D1_ALPHA_MODE_PREMULTIPLIED
),
459 96.0f
, 96.0f
, D2D1_RENDER_TARGET_USAGE_NONE
, D2D1_FEATURE_LEVEL_DEFAULT
),
460 D2D1::HwndRenderTargetProperties(hw
, size
),
463 // Pixmaps were created to be compatible with previous render target so
464 // need to be recreated.
469 void ScintillaWin::DropRenderTarget() {
471 pRenderTarget
->Release();
478 HWND
ScintillaWin::MainHWND() {
479 return reinterpret_cast<HWND
>(wMain
.GetID());
482 bool ScintillaWin::DragThreshold(Point ptStart
, Point ptNow
) {
483 int xMove
= abs(ptStart
.x
- ptNow
.x
);
484 int yMove
= abs(ptStart
.y
- ptNow
.y
);
485 return (xMove
> ::GetSystemMetrics(SM_CXDRAG
)) ||
486 (yMove
> ::GetSystemMetrics(SM_CYDRAG
));
489 void ScintillaWin::StartDrag() {
490 inDragDrop
= ddDragging
;
492 dropWentOutside
= true;
493 IDataObject
*pDataObject
= reinterpret_cast<IDataObject
*>(&dob
);
494 IDropSource
*pDropSource
= reinterpret_cast<IDropSource
*>(&ds
);
495 //Platform::DebugPrintf("About to DoDragDrop %x %x\n", pDataObject, pDropSource);
496 HRESULT hr
= ::DoDragDrop(
499 DROPEFFECT_COPY
| DROPEFFECT_MOVE
, &dwEffect
);
500 //Platform::DebugPrintf("DoDragDrop = %x\n", hr);
502 if ((hr
== DRAGDROP_S_DROP
) && (dwEffect
== DROPEFFECT_MOVE
) && dropWentOutside
) {
503 // Remove dragged out text
508 SetDragPosition(SelectionPosition(invalidPosition
));
511 // Avoid warnings everywhere for old style casts by concentrating them here
512 static WORD
LoWord(DWORD l
) {
516 static WORD
HiWord(DWORD l
) {
520 static int InputCodePage() {
521 HKL inputLocale
= ::GetKeyboardLayout(0);
522 LANGID inputLang
= LOWORD(inputLocale
);
524 int res
= ::GetLocaleInfoA(MAKELCID(inputLang
, SORT_DEFAULT
),
525 LOCALE_IDEFAULTANSICODEPAGE
, sCodePage
, sizeof(sCodePage
));
528 return atoi(sCodePage
);
532 static const int VK_OEM_2
=0xbf;
533 static const int VK_OEM_3
=0xc0;
534 static const int VK_OEM_4
=0xdb;
535 static const int VK_OEM_5
=0xdc;
536 static const int VK_OEM_6
=0xdd;
539 /** Map the key codes to their equivalent SCK_ form. */
540 static int KeyTranslate(int keyIn
) {
541 //PLATFORM_ASSERT(!keyIn);
543 case VK_DOWN
: return SCK_DOWN
;
544 case VK_UP
: return SCK_UP
;
545 case VK_LEFT
: return SCK_LEFT
;
546 case VK_RIGHT
: return SCK_RIGHT
;
547 case VK_HOME
: return SCK_HOME
;
548 case VK_END
: return SCK_END
;
549 case VK_PRIOR
: return SCK_PRIOR
;
550 case VK_NEXT
: return SCK_NEXT
;
551 case VK_DELETE
: return SCK_DELETE
;
552 case VK_INSERT
: return SCK_INSERT
;
553 case VK_ESCAPE
: return SCK_ESCAPE
;
554 case VK_BACK
: return SCK_BACK
;
555 case VK_TAB
: return SCK_TAB
;
556 case VK_RETURN
: return SCK_RETURN
;
557 case VK_ADD
: return SCK_ADD
;
558 case VK_SUBTRACT
: return SCK_SUBTRACT
;
559 case VK_DIVIDE
: return SCK_DIVIDE
;
560 case VK_LWIN
: return SCK_WIN
;
561 case VK_RWIN
: return SCK_RWIN
;
562 case VK_APPS
: return SCK_MENU
;
563 case VK_OEM_2
: return '/';
564 case VK_OEM_3
: return '`';
565 case VK_OEM_4
: return '[';
566 case VK_OEM_5
: return '\\';
567 case VK_OEM_6
: return ']';
568 default: return keyIn
;
572 LRESULT
ScintillaWin::WndPaint(uptr_t wParam
) {
575 // Redirect assertions to debug output and save current state
576 bool assertsPopup
= Platform::ShowAssertionPopUps(false);
577 paintState
= painting
;
581 bool IsOcxCtrl
= (wParam
!= 0); // if wParam != 0, it contains
582 // a PAINSTRUCT* from the OCX
583 // Removed since this interferes with reporting other assertions as it occurs repeatedly
584 //PLATFORM_ASSERT(hRgnUpdate == NULL);
585 hRgnUpdate
= ::CreateRectRgn(0, 0, 0, 0);
587 pps
= reinterpret_cast<PAINTSTRUCT
*>(wParam
);
589 ::GetUpdateRgn(MainHWND(), hRgnUpdate
, FALSE
);
591 ::BeginPaint(MainHWND(), pps
);
593 rcPaint
= PRectangle(pps
->rcPaint
.left
, pps
->rcPaint
.top
, pps
->rcPaint
.right
, pps
->rcPaint
.bottom
);
594 PRectangle rcClient
= GetClientRectangle();
595 paintingAllText
= rcPaint
.Contains(rcClient
);
596 if (technology
== SC_TECHNOLOGY_DEFAULT
) {
597 AutoSurface
surfaceWindow(pps
->hdc
, this);
599 Paint(surfaceWindow
, rcPaint
);
600 surfaceWindow
->Release();
604 EnsureRenderTarget();
605 AutoSurface
surfaceWindow(pRenderTarget
, this);
607 pRenderTarget
->BeginDraw();
608 Paint(surfaceWindow
, rcPaint
);
609 surfaceWindow
->Release();
610 HRESULT hr
= pRenderTarget
->EndDraw();
611 if (hr
== D2DERR_RECREATE_TARGET
) {
613 paintState
= paintAbandoned
;
619 ::DeleteRgn(hRgnUpdate
);
624 ::EndPaint(MainHWND(), pps
);
625 if (paintState
== paintAbandoned
) {
626 // Painting area was insufficient to cover new styling or brace highlight positions
628 FullPaintDC(pps
->hdc
);
633 paintState
= notPainting
;
635 // Restore debug output state
636 Platform::ShowAssertionPopUps(assertsPopup
);
638 //Platform::DebugPrintf("Paint took %g\n", et.Duration());
642 sptr_t
ScintillaWin::HandleComposition(uptr_t wParam
, sptr_t lParam
) {
643 if (lParam
& GCS_RESULTSTR
) {
644 HIMC hIMC
= ::ImmGetContext(MainHWND());
646 const int maxLenInputIME
= 200;
647 wchar_t wcs
[maxLenInputIME
];
648 LONG bytes
= ::ImmGetCompositionStringW(hIMC
,
649 GCS_RESULTSTR
, wcs
, (maxLenInputIME
-1)*2);
650 int wides
= bytes
/ 2;
651 if (IsUnicodeMode()) {
652 char utfval
[maxLenInputIME
* 3];
653 unsigned int len
= UTF8Length(wcs
, wides
);
654 UTF8FromUTF16(wcs
, wides
, utfval
, len
);
656 AddCharUTF(utfval
, len
);
658 char dbcsval
[maxLenInputIME
* 2];
659 int size
= ::WideCharToMultiByte(InputCodePage(),
660 0, wcs
, wides
, dbcsval
, sizeof(dbcsval
) - 1, 0, 0);
661 for (int i
=0; i
<size
; i
++) {
665 // Set new position after converted
666 Point pos
= PointMainCaret();
667 COMPOSITIONFORM CompForm
;
668 CompForm
.dwStyle
= CFS_POINT
;
669 CompForm
.ptCurrentPos
.x
= pos
.x
;
670 CompForm
.ptCurrentPos
.y
= pos
.y
;
671 ::ImmSetCompositionWindow(hIMC
, &CompForm
);
672 ::ImmReleaseContext(MainHWND(), hIMC
);
676 return ::DefWindowProc(MainHWND(), WM_IME_COMPOSITION
, wParam
, lParam
);
679 // Translate message IDs from WM_* and EM_* to SCI_* so can partly emulate Windows Edit control
680 static unsigned int SciMessageFromEM(unsigned int iMessage
) {
682 case EM_CANPASTE
: return SCI_CANPASTE
;
683 case EM_CANUNDO
: return SCI_CANUNDO
;
684 case EM_EMPTYUNDOBUFFER
: return SCI_EMPTYUNDOBUFFER
;
685 case EM_FINDTEXTEX
: return SCI_FINDTEXT
;
686 case EM_FORMATRANGE
: return SCI_FORMATRANGE
;
687 case EM_GETFIRSTVISIBLELINE
: return SCI_GETFIRSTVISIBLELINE
;
688 case EM_GETLINECOUNT
: return SCI_GETLINECOUNT
;
689 case EM_GETSELTEXT
: return SCI_GETSELTEXT
;
690 case EM_GETTEXTRANGE
: return SCI_GETTEXTRANGE
;
691 case EM_HIDESELECTION
: return SCI_HIDESELECTION
;
692 case EM_LINEINDEX
: return SCI_POSITIONFROMLINE
;
693 case EM_LINESCROLL
: return SCI_LINESCROLL
;
694 case EM_REPLACESEL
: return SCI_REPLACESEL
;
695 case EM_SCROLLCARET
: return SCI_SCROLLCARET
;
696 case EM_SETREADONLY
: return SCI_SETREADONLY
;
697 case WM_CLEAR
: return SCI_CLEAR
;
698 case WM_COPY
: return SCI_COPY
;
699 case WM_CUT
: return SCI_CUT
;
700 case WM_GETTEXT
: return SCI_GETTEXT
;
701 case WM_SETTEXT
: return SCI_SETTEXT
;
702 case WM_GETTEXTLENGTH
: return SCI_GETTEXTLENGTH
;
703 case WM_PASTE
: return SCI_PASTE
;
704 case WM_UNDO
: return SCI_UNDO
;
709 UINT
CodePageFromCharSet(DWORD characterSet
, UINT documentCodePage
) {
710 if (documentCodePage
== SC_CP_UTF8
) {
713 switch (characterSet
) {
714 case SC_CHARSET_ANSI
: return 1252;
715 case SC_CHARSET_DEFAULT
: return documentCodePage
;
716 case SC_CHARSET_BALTIC
: return 1257;
717 case SC_CHARSET_CHINESEBIG5
: return 950;
718 case SC_CHARSET_EASTEUROPE
: return 1250;
719 case SC_CHARSET_GB2312
: return 936;
720 case SC_CHARSET_GREEK
: return 1253;
721 case SC_CHARSET_HANGUL
: return 949;
722 case SC_CHARSET_MAC
: return 10000;
723 case SC_CHARSET_OEM
: return 437;
724 case SC_CHARSET_RUSSIAN
: return 1251;
725 case SC_CHARSET_SHIFTJIS
: return 932;
726 case SC_CHARSET_TURKISH
: return 1254;
727 case SC_CHARSET_JOHAB
: return 1361;
728 case SC_CHARSET_HEBREW
: return 1255;
729 case SC_CHARSET_ARABIC
: return 1256;
730 case SC_CHARSET_VIETNAMESE
: return 1258;
731 case SC_CHARSET_THAI
: return 874;
732 case SC_CHARSET_8859_15
: return 28605;
734 case SC_CHARSET_CYRILLIC
: return documentCodePage
;
735 case SC_CHARSET_SYMBOL
: return documentCodePage
;
737 return documentCodePage
;
740 UINT
ScintillaWin::CodePageOfDocument() {
741 return CodePageFromCharSet(vs
.styles
[STYLE_DEFAULT
].characterSet
, pdoc
->dbcsCodePage
);
744 sptr_t
ScintillaWin::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
746 //Platform::DebugPrintf("S M:%x WP:%x L:%x\n", iMessage, wParam, lParam);
747 iMessage
= SciMessageFromEM(iMessage
);
751 ctrlID
= ::GetDlgCtrlID(reinterpret_cast<HWND
>(wMain
.GetID()));
752 // Get Intellimouse scroll line parameters
753 GetIntelliMouseParameters();
754 ::RegisterDragDrop(MainHWND(), reinterpret_cast<IDropTarget
*>(&dt
));
758 Command(LoWord(wParam
));
762 return WndPaint(wParam
);
764 case WM_PRINTCLIENT
: {
765 HDC hdc
= reinterpret_cast<HDC
>(wParam
);
766 if (!IsCompatibleDC(hdc
)) {
767 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
774 ScrollMessage(wParam
);
778 HorizontalScrollMessage(wParam
);
783 if (paintState
== notPainting
) {
786 renderTargetValid
= false;
789 //Platform::DebugPrintf("Scintilla WM_SIZE %d %d\n", LoWord(lParam), HiWord(lParam));
795 // if autocomplete list active then send mousewheel message to it
797 HWND hWnd
= reinterpret_cast<HWND
>(ac
.lb
->GetID());
798 ::SendMessage(hWnd
, iMessage
, wParam
, lParam
);
802 // Don't handle datazoom.
803 // (A good idea for datazoom would be to "fold" or "unfold" details.
804 // i.e. if datazoomed out only class structures are visible, when datazooming in the control
805 // structures appear, then eventually the individual statements...)
806 if (wParam
& MK_SHIFT
) {
807 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
810 // Either SCROLL or ZOOM. We handle the wheel steppings calculation
811 wheelDelta
-= static_cast<short>(HiWord(wParam
));
812 if (abs(wheelDelta
) >= WHEEL_DELTA
&& linesPerScroll
> 0) {
813 int linesToScroll
= linesPerScroll
;
814 if (linesPerScroll
== WHEEL_PAGESCROLL
)
815 linesToScroll
= LinesOnScreen() - 1;
816 if (linesToScroll
== 0) {
819 linesToScroll
*= (wheelDelta
/ WHEEL_DELTA
);
821 wheelDelta
= wheelDelta
% WHEEL_DELTA
;
823 wheelDelta
= - (-wheelDelta
% WHEEL_DELTA
);
825 if (wParam
& MK_CONTROL
) {
826 // Zoom! We play with the font sizes in the styles.
827 // Number of steps/line is ignored, we just care if sizing up or down
828 if (linesToScroll
< 0) {
829 KeyCommand(SCI_ZOOMIN
);
831 KeyCommand(SCI_ZOOMOUT
);
835 ScrollTo(topLine
+ linesToScroll
);
841 if (wParam
== standardTimerID
&& timer
.ticking
) {
843 } else if (wParam
== idleTimerID
&& idler
.state
) {
844 SendMessage(MainHWND(), SC_WIN_IDLE
, 0, 1);
851 // wParam=dwTickCountInitial, or 0 to initialize. lParam=bSkipUserInputTest
853 if (lParam
|| (WAIT_TIMEOUT
== MsgWaitForMultipleObjects(0, 0, 0, 0, QS_INPUT
|QS_HOTKEY
))) {
855 // User input was given priority above, but all events do get a turn. Other
856 // messages, notifications, etc. will get interleaved with the idle messages.
858 // However, some things like WM_PAINT are a lower priority, and will not fire
859 // when there's a message posted. So, several times a second, we stop and let
860 // the low priority events have a turn (after which the timer will fire again).
862 DWORD dwCurrent
= GetTickCount();
863 DWORD dwStart
= wParam
? wParam
: dwCurrent
;
864 const DWORD maxWorkTime
= 50;
866 if (dwCurrent
>= dwStart
&& dwCurrent
> maxWorkTime
&& dwCurrent
- maxWorkTime
< dwStart
)
867 PostMessage(MainHWND(), SC_WIN_IDLE
, dwStart
, 0);
875 case WM_GETMINMAXINFO
:
876 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
878 case WM_LBUTTONDOWN
: {
879 // For IME, set the composition string as the result string.
880 HIMC hIMC
= ::ImmGetContext(MainHWND());
881 ::ImmNotifyIME(hIMC
, NI_COMPOSITIONSTR
, CPS_COMPLETE
, 0);
882 ::ImmReleaseContext(MainHWND(), hIMC
);
884 //Platform::DebugPrintf("Buttdown %d %x %x %x %x %x\n",iMessage, wParam, lParam,
885 // Platform::IsKeyDown(VK_SHIFT),
886 // Platform::IsKeyDown(VK_CONTROL),
887 // Platform::IsKeyDown(VK_MENU));
888 ::SetFocus(MainHWND());
889 ButtonDown(Point::FromLong(lParam
), ::GetMessageTime(),
890 (wParam
& MK_SHIFT
) != 0,
891 (wParam
& MK_CONTROL
) != 0,
892 Platform::IsKeyDown(VK_MENU
));
897 SetTrackMouseLeaveEvent(true);
898 ButtonMoveWithModifiers(Point::FromLong(lParam
),
899 ((wParam
& MK_SHIFT
) != 0 ? SCI_SHIFT
: 0) |
900 ((wParam
& MK_CONTROL
) != 0 ? SCI_CTRL
: 0) |
901 (Platform::IsKeyDown(VK_MENU
) ? SCI_ALT
: 0));
905 SetTrackMouseLeaveEvent(false);
907 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
910 ButtonUp(Point::FromLong(lParam
),
912 (wParam
& MK_CONTROL
) != 0);
916 ::SetFocus(MainHWND());
917 if (!PointInSelection(Point::FromLong(lParam
))) {
919 SetEmptySelection(PositionFromLocation(Point::FromLong(lParam
)));
924 if (LoWord(lParam
) == HTCLIENT
) {
925 if (inDragDrop
== ddDragging
) {
926 DisplayCursor(Window::cursorUp
);
928 // Display regular (drag) cursor over selection
930 if (0 != ::GetCursorPos(&pt
)) {
931 ::ScreenToClient(MainHWND(), &pt
);
932 if (PointInSelMargin(Point(pt
.x
, pt
.y
))) {
933 DisplayCursor(GetMarginCursor(Point(pt
.x
, pt
.y
)));
934 } else if (PointInSelection(Point(pt
.x
, pt
.y
)) && !SelectionEmpty()) {
935 DisplayCursor(Window::cursorArrow
);
936 } else if (PointIsHotspot(Point(pt
.x
, pt
.y
))) {
937 DisplayCursor(Window::cursorHand
);
939 DisplayCursor(Window::cursorText
);
945 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
949 if (((wParam
>= 128) || !iscntrl(wParam
)) || !lastKeyDownConsumed
) {
950 if (::IsWindowUnicode(MainHWND()) || keysAlwaysUnicode
) {
951 wchar_t wcs
[2] = {static_cast<wchar_t>(wParam
), 0};
952 if (IsUnicodeMode()) {
953 // For a wide character version of the window:
955 unsigned int len
= UTF8Length(wcs
, 1);
956 UTF8FromUTF16(wcs
, 1, utfval
, len
);
957 AddCharUTF(utfval
, len
);
959 UINT cpDest
= CodePageOfDocument();
961 int size
= ::WideCharToMultiByte(cpDest
,
962 0, wcs
, 1, inBufferCP
, sizeof(inBufferCP
) - 1, 0, 0);
963 inBufferCP
[size
] = '\0';
964 AddCharUTF(inBufferCP
, size
);
967 if (IsUnicodeMode()) {
968 AddCharBytes('\0', LOBYTE(wParam
));
970 AddChar(LOBYTE(wParam
));
977 if (wParam
== UNICODE_NOCHAR
) {
978 return IsUnicodeMode() ? 1 : 0;
979 } else if (lastKeyDownConsumed
) {
982 if (IsUnicodeMode()) {
984 wchar_t wcs
[2] = {static_cast<wchar_t>(wParam
), 0};
985 unsigned int len
= UTF8Length(wcs
, 1);
986 UTF8FromUTF16(wcs
, 1, utfval
, len
);
987 AddCharUTF(utfval
, len
);
996 //Platform::DebugPrintf("S keydown %d %x %x %x %x\n",iMessage, wParam, lParam, ::IsKeyDown(VK_SHIFT), ::IsKeyDown(VK_CONTROL));
997 lastKeyDownConsumed
= false;
998 int ret
= KeyDown(KeyTranslate(wParam
),
999 Platform::IsKeyDown(VK_SHIFT
),
1000 Platform::IsKeyDown(VK_CONTROL
),
1001 Platform::IsKeyDown(VK_MENU
),
1002 &lastKeyDownConsumed
);
1003 if (!ret
&& !lastKeyDownConsumed
) {
1004 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1009 case WM_IME_KEYDOWN
:
1010 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1013 //Platform::DebugPrintf("S keyup %d %x %x\n",iMessage, wParam, lParam);
1014 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1016 case WM_SETTINGCHANGE
:
1017 //Platform::DebugPrintf("Setting Changed\n");
1018 InvalidateStyleData();
1019 // Get Intellimouse scroll line parameters
1020 GetIntelliMouseParameters();
1024 return DLGC_HASSETSEL
| DLGC_WANTALLKEYS
;
1026 case WM_KILLFOCUS
: {
1027 HWND wOther
= reinterpret_cast<HWND
>(wParam
);
1028 HWND wThis
= MainHWND();
1029 HWND wCT
= reinterpret_cast<HWND
>(ct
.wCallTip
.GetID());
1031 !(::IsChild(wThis
, wOther
) || (wOther
== wCT
))) {
1032 SetFocusState(false);
1033 DestroySystemCaret();
1039 SetFocusState(true);
1040 DestroySystemCaret();
1041 CreateSystemCaret();
1044 case WM_SYSCOLORCHANGE
:
1045 //Platform::DebugPrintf("Setting Changed\n");
1046 InvalidateStyleData();
1049 case WM_IME_STARTCOMPOSITION
: // dbcs
1050 ImeStartComposition();
1051 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1053 case WM_IME_ENDCOMPOSITION
: // dbcs
1054 ImeEndComposition();
1055 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1057 case WM_IME_COMPOSITION
:
1058 return HandleComposition(wParam
, lParam
);
1061 AddCharBytes(HIBYTE(wParam
), LOBYTE(wParam
));
1065 case WM_CONTEXTMENU
:
1066 if (displayPopupMenu
) {
1067 Point pt
= Point::FromLong(lParam
);
1068 if ((pt
.x
== -1) && (pt
.y
== -1)) {
1069 // Caused by keyboard so display menu near caret
1070 pt
= PointMainCaret();
1071 POINT spt
= {static_cast<int>(pt
.x
), static_cast<int>(pt
.y
)};
1072 ::ClientToScreen(MainHWND(), &spt
);
1073 pt
= Point(spt
.x
, spt
.y
);
1078 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1080 case WM_INPUTLANGCHANGE
:
1081 //::SetThreadLocale(LOWORD(lParam));
1082 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1084 case WM_INPUTLANGCHANGEREQUEST
:
1085 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1088 return 1; // Avoid any background erasure as whole window painted.
1090 case WM_CAPTURECHANGED
:
1091 capturedMouse
= false;
1094 // These are not handled in Scintilla and its faster to dispatch them here.
1095 // Also moves time out to here so profile doesn't count lots of empty message calls.
1098 case WM_MOUSEACTIVATE
:
1102 case WM_NCMOUSEMOVE
:
1103 case WM_NCLBUTTONDOWN
:
1104 case WM_IME_SETCONTEXT
:
1107 case WM_WINDOWPOSCHANGING
:
1108 case WM_WINDOWPOSCHANGED
:
1109 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1111 case EM_LINEFROMCHAR
:
1112 if (static_cast<int>(wParam
) < 0) {
1113 wParam
= SelectionStart().Position();
1115 return pdoc
->LineFromPosition(wParam
);
1117 case EM_EXLINEFROMCHAR
:
1118 return pdoc
->LineFromPosition(lParam
);
1122 *reinterpret_cast<int *>(wParam
) = SelectionStart().Position();
1125 *reinterpret_cast<int *>(lParam
) = SelectionEnd().Position();
1127 return MAKELONG(SelectionStart().Position(), SelectionEnd().Position());
1133 Sci_CharacterRange
*pCR
= reinterpret_cast<Sci_CharacterRange
*>(lParam
);
1134 pCR
->cpMin
= SelectionStart().Position();
1135 pCR
->cpMax
= SelectionEnd().Position();
1140 int nStart
= static_cast<int>(wParam
);
1141 int nEnd
= static_cast<int>(lParam
);
1142 if (nStart
== 0 && nEnd
== -1) {
1143 nEnd
= pdoc
->Length();
1146 nStart
= nEnd
; // Remove selection
1148 if (nStart
> nEnd
) {
1149 SetSelection(nEnd
, nStart
);
1151 SetSelection(nStart
, nEnd
);
1153 EnsureCaretVisible();
1161 Sci_CharacterRange
*pCR
= reinterpret_cast<Sci_CharacterRange
*>(lParam
);
1162 sel
.selType
= Selection::selStream
;
1163 if (pCR
->cpMin
== 0 && pCR
->cpMax
== -1) {
1164 SetSelection(pCR
->cpMin
, pdoc
->Length());
1166 SetSelection(pCR
->cpMin
, pCR
->cpMax
);
1168 EnsureCaretVisible();
1169 return pdoc
->LineFromPosition(SelectionStart().Position());
1172 case SCI_GETDIRECTFUNCTION
:
1173 return reinterpret_cast<sptr_t
>(DirectFunction
);
1175 case SCI_GETDIRECTPOINTER
:
1176 return reinterpret_cast<sptr_t
>(this);
1179 ::SetFocus(MainHWND());
1182 case SCI_SETKEYSUNICODE
:
1183 keysAlwaysUnicode
= wParam
!= 0;
1186 case SCI_GETKEYSUNICODE
:
1187 return keysAlwaysUnicode
;
1189 case SCI_SETTECHNOLOGY
:
1190 if ((wParam
== SC_TECHNOLOGY_DEFAULT
) || (wParam
== SC_TECHNOLOGY_DIRECTWRITE
)) {
1191 if (technology
!= static_cast<int>(wParam
)) {
1192 if (static_cast<int>(wParam
) == SC_TECHNOLOGY_DIRECTWRITE
) {
1193 #if defined(USE_D2D)
1195 // Failed to load Direct2D or DirectWrite so no effect
1201 technology
= wParam
;
1202 // Invalidate all cached information including layout.
1204 InvalidateStyleRedraw();
1210 case SCI_LOADLEXERLIBRARY
:
1211 LexerManager::GetInstance()->Load(reinterpret_cast<const char *>(lParam
));
1216 return ScintillaBase::WndProc(iMessage
, wParam
, lParam
);
1218 } catch (std::bad_alloc
&) {
1219 errorStatus
= SC_STATUS_BADALLOC
;
1221 errorStatus
= SC_STATUS_FAILURE
;
1226 bool ScintillaWin::ValidCodePage(int codePage
) const {
1227 return codePage
== 0 || codePage
== SC_CP_UTF8
||
1228 codePage
== 932 || codePage
== 936 || codePage
== 949 ||
1229 codePage
== 950 || codePage
== 1361;
1232 sptr_t
ScintillaWin::DefWndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
1233 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1236 void ScintillaWin::SetTicking(bool on
) {
1237 if (timer
.ticking
!= on
) {
1239 if (timer
.ticking
) {
1240 timer
.tickerID
= ::SetTimer(MainHWND(), standardTimerID
, timer
.tickSize
, NULL
)
1241 ? reinterpret_cast<TickerID
>(standardTimerID
) : 0;
1243 ::KillTimer(MainHWND(), reinterpret_cast<uptr_t
>(timer
.tickerID
));
1247 timer
.ticksToWait
= caret
.period
;
1250 bool ScintillaWin::SetIdle(bool on
) {
1251 // On Win32 the Idler is implemented as a Timer on the Scintilla window. This
1252 // takes advantage of the fact that WM_TIMER messages are very low priority,
1253 // and are only posted when the message queue is empty, i.e. during idle time.
1254 if (idler
.state
!= on
) {
1256 idler
.idlerID
= ::SetTimer(MainHWND(), idleTimerID
, 10, NULL
)
1257 ? reinterpret_cast<IdlerID
>(idleTimerID
) : 0;
1259 ::KillTimer(MainHWND(), reinterpret_cast<uptr_t
>(idler
.idlerID
));
1262 idler
.state
= idler
.idlerID
!= 0;
1267 void ScintillaWin::SetMouseCapture(bool on
) {
1268 if (mouseDownCaptures
) {
1270 ::SetCapture(MainHWND());
1278 bool ScintillaWin::HaveMouseCapture() {
1279 // Cannot just see if GetCapture is this window as the scroll bar also sets capture for the window
1280 return capturedMouse
;
1281 //return capturedMouse && (::GetCapture() == MainHWND());
1284 void ScintillaWin::SetTrackMouseLeaveEvent(bool on
) {
1285 if (on
&& TrackMouseEventFn
&& !trackedMouseLeave
) {
1286 TRACKMOUSEEVENT tme
;
1287 tme
.cbSize
= sizeof(tme
);
1288 tme
.dwFlags
= TME_LEAVE
;
1289 tme
.hwndTrack
= MainHWND();
1290 TrackMouseEventFn(&tme
);
1292 trackedMouseLeave
= on
;
1295 bool ScintillaWin::PaintContains(PRectangle rc
) {
1296 bool contains
= true;
1297 if ((paintState
== painting
) && (!rc
.Empty())) {
1298 if (!rcPaint
.Contains(rc
)) {
1301 // In bounding rectangle so check more accurately using region
1302 HRGN hRgnRange
= ::CreateRectRgn(rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
1304 HRGN hRgnDest
= ::CreateRectRgn(0, 0, 0, 0);
1306 int combination
= ::CombineRgn(hRgnDest
, hRgnRange
, hRgnUpdate
, RGN_DIFF
);
1307 if (combination
!= NULLREGION
) {
1310 ::DeleteRgn(hRgnDest
);
1312 ::DeleteRgn(hRgnRange
);
1319 void ScintillaWin::ScrollText(int /* linesToMove */) {
1320 //Platform::DebugPrintf("ScintillaWin::ScrollText %d\n", linesToMove);
1321 //::ScrollWindow(MainHWND(), 0,
1322 // vs.lineHeight * linesToMove, 0, 0);
1323 //::UpdateWindow(MainHWND());
1327 void ScintillaWin::UpdateSystemCaret() {
1329 if (HasCaretSizeChanged()) {
1330 DestroySystemCaret();
1331 CreateSystemCaret();
1333 Point pos
= PointMainCaret();
1334 ::SetCaretPos(pos
.x
, pos
.y
);
1338 int ScintillaWin::SetScrollInfo(int nBar
, LPCSCROLLINFO lpsi
, BOOL bRedraw
) {
1339 return ::SetScrollInfo(MainHWND(), nBar
, lpsi
, bRedraw
);
1342 bool ScintillaWin::GetScrollInfo(int nBar
, LPSCROLLINFO lpsi
) {
1343 return ::GetScrollInfo(MainHWND(), nBar
, lpsi
) ? true : false;
1346 // Change the scroll position but avoid repaint if changing to same value
1347 void ScintillaWin::ChangeScrollPos(int barType
, int pos
) {
1349 sizeof(sci
), 0, 0, 0, 0, 0, 0
1351 sci
.fMask
= SIF_POS
;
1352 GetScrollInfo(barType
, &sci
);
1353 if (sci
.nPos
!= pos
) {
1356 SetScrollInfo(barType
, &sci
, TRUE
);
1360 void ScintillaWin::SetVerticalScrollPos() {
1361 ChangeScrollPos(SB_VERT
, topLine
);
1364 void ScintillaWin::SetHorizontalScrollPos() {
1365 ChangeScrollPos(SB_HORZ
, xOffset
);
1368 bool ScintillaWin::ModifyScrollBars(int nMax
, int nPage
) {
1369 bool modified
= false;
1371 sizeof(sci
), 0, 0, 0, 0, 0, 0
1373 sci
.fMask
= SIF_PAGE
| SIF_RANGE
;
1374 GetScrollInfo(SB_VERT
, &sci
);
1375 int vertEndPreferred
= nMax
;
1376 if (!verticalScrollBarVisible
)
1377 nPage
= vertEndPreferred
+ 1;
1378 if ((sci
.nMin
!= 0) ||
1379 (sci
.nMax
!= vertEndPreferred
) ||
1380 (sci
.nPage
!= static_cast<unsigned int>(nPage
)) ||
1382 sci
.fMask
= SIF_PAGE
| SIF_RANGE
;
1384 sci
.nMax
= vertEndPreferred
;
1388 SetScrollInfo(SB_VERT
, &sci
, TRUE
);
1392 PRectangle rcText
= GetTextRectangle();
1393 int horizEndPreferred
= scrollWidth
;
1394 if (horizEndPreferred
< 0)
1395 horizEndPreferred
= 0;
1396 unsigned int pageWidth
= rcText
.Width();
1397 if (!horizontalScrollBarVisible
|| Wrapping())
1398 pageWidth
= horizEndPreferred
+ 1;
1399 sci
.fMask
= SIF_PAGE
| SIF_RANGE
;
1400 GetScrollInfo(SB_HORZ
, &sci
);
1401 if ((sci
.nMin
!= 0) ||
1402 (sci
.nMax
!= horizEndPreferred
) ||
1403 (sci
.nPage
!= pageWidth
) ||
1405 sci
.fMask
= SIF_PAGE
| SIF_RANGE
;
1407 sci
.nMax
= horizEndPreferred
;
1408 sci
.nPage
= pageWidth
;
1411 SetScrollInfo(SB_HORZ
, &sci
, TRUE
);
1413 if (scrollWidth
< static_cast<int>(pageWidth
)) {
1414 HorizontalScrollTo(0);
1420 void ScintillaWin::NotifyChange() {
1421 ::SendMessage(::GetParent(MainHWND()), WM_COMMAND
,
1422 MAKELONG(GetCtrlID(), SCEN_CHANGE
),
1423 reinterpret_cast<LPARAM
>(MainHWND()));
1426 void ScintillaWin::NotifyFocus(bool focus
) {
1427 ::SendMessage(::GetParent(MainHWND()), WM_COMMAND
,
1428 MAKELONG(GetCtrlID(), focus
? SCEN_SETFOCUS
: SCEN_KILLFOCUS
),
1429 reinterpret_cast<LPARAM
>(MainHWND()));
1430 Editor::NotifyFocus(focus
);
1433 void ScintillaWin::SetCtrlID(int identifier
) {
1434 ::SetWindowID(reinterpret_cast<HWND
>(wMain
.GetID()), identifier
);
1437 int ScintillaWin::GetCtrlID() {
1438 return ::GetDlgCtrlID(reinterpret_cast<HWND
>(wMain
.GetID()));
1441 void ScintillaWin::NotifyParent(SCNotification scn
) {
1442 scn
.nmhdr
.hwndFrom
= MainHWND();
1443 scn
.nmhdr
.idFrom
= GetCtrlID();
1444 ::SendMessage(::GetParent(MainHWND()), WM_NOTIFY
,
1445 GetCtrlID(), reinterpret_cast<LPARAM
>(&scn
));
1448 void ScintillaWin::NotifyParent(SCNotification
* scn
) {
1449 scn
->nmhdr
.hwndFrom
= MainHWND();
1450 scn
->nmhdr
.idFrom
= GetCtrlID();
1451 ::SendMessage(::GetParent(MainHWND()), WM_NOTIFY
,
1452 GetCtrlID(), reinterpret_cast<LPARAM
>(scn
));
1455 void ScintillaWin::NotifyDoubleClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
1456 //Platform::DebugPrintf("ScintillaWin Double click 0\n");
1457 ScintillaBase::NotifyDoubleClick(pt
, shift
, ctrl
, alt
);
1458 // Send myself a WM_LBUTTONDBLCLK, so the container can handle it too.
1459 ::SendMessage(MainHWND(),
1461 shift
? MK_SHIFT
: 0,
1462 MAKELPARAM(pt
.x
, pt
.y
));
1465 class CaseFolderDBCS
: public CaseFolderTable
{
1466 // Allocate the expandable storage here so that it does not need to be reallocated
1467 // for each call to Fold.
1468 std::vector
<wchar_t> utf16Mixed
;
1469 std::vector
<wchar_t> utf16Folded
;
1472 CaseFolderDBCS(UINT cp_
) : cp(cp_
) {
1475 virtual size_t Fold(char *folded
, size_t sizeFolded
, const char *mixed
, size_t lenMixed
) {
1476 if ((lenMixed
== 1) && (sizeFolded
> 0)) {
1477 folded
[0] = mapping
[static_cast<unsigned char>(mixed
[0])];
1480 if (lenMixed
> utf16Mixed
.size()) {
1481 utf16Mixed
.resize(lenMixed
+ 8);
1483 size_t nUtf16Mixed
= ::MultiByteToWideChar(cp
, 0, mixed
,
1484 static_cast<int>(lenMixed
),
1486 static_cast<int>(utf16Mixed
.size()));
1488 if (nUtf16Mixed
== 0) {
1489 // Failed to convert -> bad input
1494 unsigned int lenFlat
= 0;
1495 for (size_t mixIndex
=0; mixIndex
< nUtf16Mixed
; mixIndex
++) {
1496 if ((lenFlat
+ 20) > utf16Folded
.size())
1497 utf16Folded
.resize(lenFlat
+ 60);
1498 const char *foldedUTF8
= CaseConvert(utf16Mixed
[mixIndex
], CaseConversionFold
);
1500 // Maximum length of a case conversion is 6 bytes, 3 characters
1501 wchar_t wFolded
[20];
1502 unsigned int charsConverted
= UTF16FromUTF8(foldedUTF8
,
1503 static_cast<unsigned int>(strlen(foldedUTF8
)),
1504 wFolded
, sizeof(wFolded
)/sizeof(wFolded
[0]));
1505 for (size_t j
=0;j
<charsConverted
;j
++)
1506 utf16Folded
[lenFlat
++] = wFolded
[j
];
1508 utf16Folded
[lenFlat
++] = utf16Mixed
[mixIndex
];
1512 size_t lenOut
= ::WideCharToMultiByte(cp
, 0,
1513 &utf16Folded
[0], lenFlat
,
1516 if (lenOut
< sizeFolded
) {
1517 ::WideCharToMultiByte(cp
, 0,
1518 &utf16Folded
[0], lenFlat
,
1519 folded
, static_cast<int>(lenOut
), NULL
, 0);
1528 CaseFolder
*ScintillaWin::CaseFolderForEncoding() {
1529 UINT cpDest
= CodePageOfDocument();
1530 if (cpDest
== SC_CP_UTF8
) {
1531 return new CaseFolderUnicode();
1533 if (pdoc
->dbcsCodePage
== 0) {
1534 CaseFolderTable
*pcf
= new CaseFolderTable();
1535 pcf
->StandardASCII();
1536 // Only for single byte encodings
1537 UINT cpDoc
= CodePageOfDocument();
1538 for (int i
=0x80; i
<0x100; i
++) {
1539 char sCharacter
[2] = "A";
1540 sCharacter
[0] = static_cast<char>(i
);
1541 wchar_t wCharacter
[20];
1542 unsigned int lengthUTF16
= ::MultiByteToWideChar(cpDoc
, 0, sCharacter
, 1,
1543 wCharacter
, sizeof(wCharacter
)/sizeof(wCharacter
[0]));
1544 if (lengthUTF16
== 1) {
1545 const char *caseFolded
= CaseConvert(wCharacter
[0], CaseConversionFold
);
1548 unsigned int charsConverted
= UTF16FromUTF8(caseFolded
,
1549 static_cast<unsigned int>(strlen(caseFolded
)),
1550 wLower
, sizeof(wLower
)/sizeof(wLower
[0]));
1551 if (charsConverted
== 1) {
1552 char sCharacterLowered
[20];
1553 unsigned int lengthConverted
= ::WideCharToMultiByte(cpDoc
, 0,
1554 wLower
, charsConverted
,
1555 sCharacterLowered
, sizeof(sCharacterLowered
), NULL
, 0);
1556 if ((lengthConverted
== 1) && (sCharacter
[0] != sCharacterLowered
[0])) {
1557 pcf
->SetTranslation(sCharacter
[0], sCharacterLowered
[0]);
1565 return new CaseFolderDBCS(cpDest
);
1570 std::string
ScintillaWin::CaseMapString(const std::string
&s
, int caseMapping
) {
1571 if ((s
.size() == 0) || (caseMapping
== cmSame
))
1574 UINT cpDoc
= CodePageOfDocument();
1575 if (cpDoc
== SC_CP_UTF8
) {
1576 std::string
retMapped(s
.length() * maxExpansionCaseConversion
, 0);
1577 size_t lenMapped
= CaseConvertString(&retMapped
[0], retMapped
.length(), s
.c_str(), s
.length(),
1578 (caseMapping
== cmUpper
) ? CaseConversionUpper
: CaseConversionLower
);
1579 retMapped
.resize(lenMapped
);
1583 unsigned int lengthUTF16
= ::MultiByteToWideChar(cpDoc
, 0, s
.c_str(),
1584 static_cast<int>(s
.size()), NULL
, 0);
1585 if (lengthUTF16
== 0) // Failed to convert
1588 DWORD mapFlags
= LCMAP_LINGUISTIC_CASING
|
1589 ((caseMapping
== cmUpper
) ? LCMAP_UPPERCASE
: LCMAP_LOWERCASE
);
1591 // Change text to UTF-16
1592 std::vector
<wchar_t> vwcText(lengthUTF16
);
1593 ::MultiByteToWideChar(cpDoc
, 0, s
.c_str(), static_cast<int>(s
.size()), &vwcText
[0], lengthUTF16
);
1596 int charsConverted
= ::LCMapStringW(LOCALE_SYSTEM_DEFAULT
, mapFlags
,
1597 &vwcText
[0], lengthUTF16
, NULL
, 0);
1598 std::vector
<wchar_t> vwcConverted(charsConverted
);
1599 ::LCMapStringW(LOCALE_SYSTEM_DEFAULT
, mapFlags
,
1600 &vwcText
[0], lengthUTF16
, &vwcConverted
[0], charsConverted
);
1602 // Change back to document encoding
1603 unsigned int lengthConverted
= ::WideCharToMultiByte(cpDoc
, 0,
1604 &vwcConverted
[0], static_cast<int>(vwcConverted
.size()),
1606 std::vector
<char> vcConverted(lengthConverted
);
1607 ::WideCharToMultiByte(cpDoc
, 0,
1608 &vwcConverted
[0], static_cast<int>(vwcConverted
.size()),
1609 &vcConverted
[0], static_cast<int>(vcConverted
.size()), NULL
, 0);
1611 return std::string(&vcConverted
[0], vcConverted
.size());
1614 void ScintillaWin::Copy() {
1615 //Platform::DebugPrintf("Copy\n");
1617 SelectionText selectedText
;
1618 CopySelectionRange(&selectedText
);
1619 CopyToClipboard(selectedText
);
1623 void ScintillaWin::CopyAllowLine() {
1624 SelectionText selectedText
;
1625 CopySelectionRange(&selectedText
, true);
1626 CopyToClipboard(selectedText
);
1629 bool ScintillaWin::CanPaste() {
1630 if (!Editor::CanPaste())
1632 if (::IsClipboardFormatAvailable(CF_TEXT
))
1634 if (IsUnicodeMode())
1635 return ::IsClipboardFormatAvailable(CF_UNICODETEXT
) != 0;
1639 class GlobalMemory
{
1643 GlobalMemory() : hand(0), ptr(0) {
1645 GlobalMemory(HGLOBAL hand_
) : hand(hand_
), ptr(0) {
1647 ptr
= ::GlobalLock(hand
);
1651 PLATFORM_ASSERT(!ptr
);
1653 void Allocate(size_t bytes
) {
1654 hand
= ::GlobalAlloc(GMEM_MOVEABLE
| GMEM_ZEROINIT
, bytes
);
1656 ptr
= ::GlobalLock(hand
);
1660 PLATFORM_ASSERT(ptr
);
1661 HGLOBAL handCopy
= hand
;
1662 ::GlobalUnlock(hand
);
1667 void SetClip(UINT uFormat
) {
1668 ::SetClipboardData(uFormat
, Unlock());
1670 operator bool() const {
1674 return ::GlobalSize(hand
);
1678 void ScintillaWin::InsertPasteText(const char *text
, int len
, SelectionPosition selStart
, bool isRectangular
, bool isLine
) {
1679 if (isRectangular
) {
1680 PasteRectangular(selStart
, text
, len
);
1682 std::string convertedText
;
1683 if (convertPastes
) {
1684 // Convert line endings of the paste into our local line-endings mode
1685 convertedText
= Document::TransformLineEnds(text
, len
, pdoc
->eolMode
);
1686 len
= static_cast<int>(convertedText
.length());
1687 text
= convertedText
.c_str();
1690 int insertPos
= pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret()));
1691 pdoc
->InsertString(insertPos
, text
, len
);
1692 // add the newline if necessary
1693 if ((len
> 0) && (text
[len
-1] != '\n' && text
[len
-1] != '\r')) {
1694 const char *endline
= StringFromEOLMode(pdoc
->eolMode
);
1695 pdoc
->InsertString(insertPos
+ len
, endline
, static_cast<int>(strlen(endline
)));
1696 len
+= static_cast<int>(strlen(endline
));
1698 if (sel
.MainCaret() == insertPos
) {
1699 SetEmptySelection(sel
.MainCaret() + len
);
1702 InsertPaste(selStart
, text
, len
);
1707 void ScintillaWin::Paste() {
1708 if (!::OpenClipboard(MainHWND()))
1711 bool isLine
= SelectionEmpty() && (::IsClipboardFormatAvailable(cfLineSelect
) != 0);
1712 ClearSelection(multiPasteMode
== SC_MULTIPASTE_EACH
);
1713 SelectionPosition selStart
= sel
.IsRectangular() ?
1714 sel
.Rectangular().Start() :
1715 sel
.Range(sel
.Main()).Start();
1716 bool isRectangular
= (::IsClipboardFormatAvailable(cfColumnSelect
) != 0);
1718 if (!isRectangular
) {
1719 // Evaluate "Borland IDE Block Type" explicitly
1720 GlobalMemory
memBorlandSelection(::GetClipboardData(cfBorlandIDEBlockType
));
1721 if (memBorlandSelection
) {
1722 isRectangular
= (memBorlandSelection
.Size() == 1) && (static_cast<BYTE
*>(memBorlandSelection
.ptr
)[0] == 0x02);
1723 memBorlandSelection
.Unlock();
1727 // Always use CF_UNICODETEXT if available
1728 GlobalMemory
memUSelection(::GetClipboardData(CF_UNICODETEXT
));
1729 if (memUSelection
) {
1730 wchar_t *uptr
= static_cast<wchar_t *>(memUSelection
.ptr
);
1733 std::vector
<char> putf
;
1734 // Default Scintilla behaviour in Unicode mode
1735 if (IsUnicodeMode()) {
1736 unsigned int bytes
= memUSelection
.Size();
1737 len
= UTF8Length(uptr
, bytes
/ 2);
1738 putf
.resize(len
+ 1);
1739 UTF8FromUTF16(uptr
, bytes
/ 2, &putf
[0], len
);
1741 // CF_UNICODETEXT available, but not in Unicode mode
1742 // Convert from Unicode to current Scintilla code page
1743 UINT cpDest
= CodePageOfDocument();
1744 len
= ::WideCharToMultiByte(cpDest
, 0, uptr
, -1,
1745 NULL
, 0, NULL
, NULL
) - 1; // subtract 0 terminator
1746 putf
.resize(len
+ 1);
1747 ::WideCharToMultiByte(cpDest
, 0, uptr
, -1,
1748 &putf
[0], len
+ 1, NULL
, NULL
);
1751 InsertPasteText(&putf
[0], len
, selStart
, isRectangular
, isLine
);
1753 memUSelection
.Unlock();
1755 // CF_UNICODETEXT not available, paste ANSI text
1756 GlobalMemory
memSelection(::GetClipboardData(CF_TEXT
));
1758 char *ptr
= static_cast<char *>(memSelection
.ptr
);
1760 unsigned int bytes
= memSelection
.Size();
1761 unsigned int len
= bytes
;
1762 for (unsigned int i
= 0; i
< bytes
; i
++) {
1763 if ((len
== bytes
) && (0 == ptr
[i
]))
1767 // In Unicode mode, convert clipboard text to UTF-8
1768 if (IsUnicodeMode()) {
1769 std::vector
<wchar_t> uptr(len
+1);
1771 unsigned int ulen
= ::MultiByteToWideChar(CP_ACP
, 0,
1772 ptr
, len
, &uptr
[0], len
+1);
1774 unsigned int mlen
= UTF8Length(&uptr
[0], ulen
);
1775 std::vector
<char> putf(mlen
+1);
1776 // CP_UTF8 not available on Windows 95, so use UTF8FromUTF16()
1777 UTF8FromUTF16(&uptr
[0], ulen
, &putf
[0], mlen
);
1779 InsertPasteText(&putf
[0], mlen
, selStart
, isRectangular
, isLine
);
1781 InsertPasteText(ptr
, len
, selStart
, isRectangular
, isLine
);
1784 memSelection
.Unlock();
1791 void ScintillaWin::CreateCallTipWindow(PRectangle
) {
1792 if (!ct
.wCallTip
.Created()) {
1793 ct
.wCallTip
= ::CreateWindow(callClassName
, TEXT("ACallTip"),
1794 WS_POPUP
, 100, 100, 150, 20,
1796 GetWindowInstance(MainHWND()),
1798 ct
.wDraw
= ct
.wCallTip
;
1802 void ScintillaWin::AddToPopUp(const char *label
, int cmd
, bool enabled
) {
1803 HMENU hmenuPopup
= reinterpret_cast<HMENU
>(popup
.GetID());
1805 ::AppendMenuA(hmenuPopup
, MF_SEPARATOR
, 0, "");
1807 ::AppendMenuA(hmenuPopup
, MF_STRING
, cmd
, label
);
1809 ::AppendMenuA(hmenuPopup
, MF_STRING
| MF_DISABLED
| MF_GRAYED
, cmd
, label
);
1812 void ScintillaWin::ClaimSelection() {
1813 // Windows does not have a primary selection
1816 /// Implement IUnknown
1818 STDMETHODIMP_(ULONG
)FormatEnumerator_AddRef(FormatEnumerator
*fe
);
1819 STDMETHODIMP
FormatEnumerator_QueryInterface(FormatEnumerator
*fe
, REFIID riid
, PVOID
*ppv
) {
1820 //Platform::DebugPrintf("EFE QI");
1822 if (riid
== IID_IUnknown
)
1823 *ppv
= reinterpret_cast<IEnumFORMATETC
*>(fe
);
1824 if (riid
== IID_IEnumFORMATETC
)
1825 *ppv
= reinterpret_cast<IEnumFORMATETC
*>(fe
);
1827 return E_NOINTERFACE
;
1828 FormatEnumerator_AddRef(fe
);
1831 STDMETHODIMP_(ULONG
)FormatEnumerator_AddRef(FormatEnumerator
*fe
) {
1834 STDMETHODIMP_(ULONG
)FormatEnumerator_Release(FormatEnumerator
*fe
) {
1841 /// Implement IEnumFORMATETC
1842 STDMETHODIMP
FormatEnumerator_Next(FormatEnumerator
*fe
, ULONG celt
, FORMATETC
*rgelt
, ULONG
*pceltFetched
) {
1843 //Platform::DebugPrintf("EFE Next %d %d", fe->pos, celt);
1844 if (rgelt
== NULL
) return E_POINTER
;
1845 // We only support one format, so this is simple.
1846 unsigned int putPos
= 0;
1847 while ((fe
->pos
< fe
->formatsLen
) && (putPos
< celt
)) {
1848 rgelt
->cfFormat
= fe
->formats
[fe
->pos
];
1850 rgelt
->dwAspect
= DVASPECT_CONTENT
;
1852 rgelt
->tymed
= TYMED_HGLOBAL
;
1857 *pceltFetched
= putPos
;
1858 return putPos
? S_OK
: S_FALSE
;
1860 STDMETHODIMP
FormatEnumerator_Skip(FormatEnumerator
*fe
, ULONG celt
) {
1864 STDMETHODIMP
FormatEnumerator_Reset(FormatEnumerator
*fe
) {
1868 STDMETHODIMP
FormatEnumerator_Clone(FormatEnumerator
*fe
, IEnumFORMATETC
**ppenum
) {
1869 FormatEnumerator
*pfe
;
1871 pfe
= new FormatEnumerator(fe
->pos
, fe
->formats
, fe
->formatsLen
);
1873 return E_OUTOFMEMORY
;
1875 return FormatEnumerator_QueryInterface(pfe
, IID_IEnumFORMATETC
,
1876 reinterpret_cast<void **>(ppenum
));
1879 static VFunction
*vtFormatEnumerator
[] = {
1880 (VFunction
*)(FormatEnumerator_QueryInterface
),
1881 (VFunction
*)(FormatEnumerator_AddRef
),
1882 (VFunction
*)(FormatEnumerator_Release
),
1883 (VFunction
*)(FormatEnumerator_Next
),
1884 (VFunction
*)(FormatEnumerator_Skip
),
1885 (VFunction
*)(FormatEnumerator_Reset
),
1886 (VFunction
*)(FormatEnumerator_Clone
)
1889 FormatEnumerator::FormatEnumerator(int pos_
, CLIPFORMAT formats_
[], int formatsLen_
) {
1890 vtbl
= vtFormatEnumerator
;
1891 ref
= 0; // First QI adds first reference...
1893 formatsLen
= formatsLen_
;
1894 for (int i
=0; i
<formatsLen
; i
++)
1895 formats
[i
] = formats_
[i
];
1898 /// Implement IUnknown
1899 STDMETHODIMP
DropSource_QueryInterface(DropSource
*ds
, REFIID riid
, PVOID
*ppv
) {
1900 return ds
->sci
->QueryInterface(riid
, ppv
);
1902 STDMETHODIMP_(ULONG
)DropSource_AddRef(DropSource
*ds
) {
1903 return ds
->sci
->AddRef();
1905 STDMETHODIMP_(ULONG
)DropSource_Release(DropSource
*ds
) {
1906 return ds
->sci
->Release();
1909 /// Implement IDropSource
1910 STDMETHODIMP
DropSource_QueryContinueDrag(DropSource
*, BOOL fEsc
, DWORD grfKeyState
) {
1912 return DRAGDROP_S_CANCEL
;
1913 if (!(grfKeyState
& MK_LBUTTON
))
1914 return DRAGDROP_S_DROP
;
1918 STDMETHODIMP
DropSource_GiveFeedback(DropSource
*, DWORD
) {
1919 return DRAGDROP_S_USEDEFAULTCURSORS
;
1922 static VFunction
*vtDropSource
[] = {
1923 (VFunction
*)(DropSource_QueryInterface
),
1924 (VFunction
*)(DropSource_AddRef
),
1925 (VFunction
*)(DropSource_Release
),
1926 (VFunction
*)(DropSource_QueryContinueDrag
),
1927 (VFunction
*)(DropSource_GiveFeedback
)
1930 DropSource::DropSource() {
1931 vtbl
= vtDropSource
;
1935 /// Implement IUnkown
1936 STDMETHODIMP
DataObject_QueryInterface(DataObject
*pd
, REFIID riid
, PVOID
*ppv
) {
1937 //Platform::DebugPrintf("DO QI %x\n", pd);
1938 return pd
->sci
->QueryInterface(riid
, ppv
);
1940 STDMETHODIMP_(ULONG
)DataObject_AddRef(DataObject
*pd
) {
1941 return pd
->sci
->AddRef();
1943 STDMETHODIMP_(ULONG
)DataObject_Release(DataObject
*pd
) {
1944 return pd
->sci
->Release();
1946 /// Implement IDataObject
1947 STDMETHODIMP
DataObject_GetData(DataObject
*pd
, FORMATETC
*pFEIn
, STGMEDIUM
*pSTM
) {
1948 return pd
->sci
->GetData(pFEIn
, pSTM
);
1951 STDMETHODIMP
DataObject_GetDataHere(DataObject
*, FORMATETC
*, STGMEDIUM
*) {
1952 //Platform::DebugPrintf("DOB GetDataHere\n");
1956 STDMETHODIMP
DataObject_QueryGetData(DataObject
*pd
, FORMATETC
*pFE
) {
1957 if (pd
->sci
->DragIsRectangularOK(pFE
->cfFormat
) &&
1959 (pFE
->dwAspect
& DVASPECT_CONTENT
) != 0 &&
1960 pFE
->lindex
== -1 &&
1961 (pFE
->tymed
& TYMED_HGLOBAL
) != 0
1966 bool formatOK
= (pFE
->cfFormat
== CF_TEXT
) ||
1967 ((pFE
->cfFormat
== CF_UNICODETEXT
) && pd
->sci
->IsUnicodeMode());
1970 (pFE
->dwAspect
& DVASPECT_CONTENT
) == 0 ||
1971 pFE
->lindex
!= -1 ||
1972 (pFE
->tymed
& TYMED_HGLOBAL
) == 0
1974 //Platform::DebugPrintf("DOB QueryGetData No %x\n",pFE->cfFormat);
1975 //return DATA_E_FORMATETC;
1978 //Platform::DebugPrintf("DOB QueryGetData OK %x\n",pFE->cfFormat);
1982 STDMETHODIMP
DataObject_GetCanonicalFormatEtc(DataObject
*pd
, FORMATETC
*, FORMATETC
*pFEOut
) {
1983 //Platform::DebugPrintf("DOB GetCanon\n");
1984 if (pd
->sci
->IsUnicodeMode())
1985 pFEOut
->cfFormat
= CF_UNICODETEXT
;
1987 pFEOut
->cfFormat
= CF_TEXT
;
1989 pFEOut
->dwAspect
= DVASPECT_CONTENT
;
1990 pFEOut
->lindex
= -1;
1991 pFEOut
->tymed
= TYMED_HGLOBAL
;
1995 STDMETHODIMP
DataObject_SetData(DataObject
*, FORMATETC
*, STGMEDIUM
*, BOOL
) {
1996 //Platform::DebugPrintf("DOB SetData\n");
2000 STDMETHODIMP
DataObject_EnumFormatEtc(DataObject
*pd
, DWORD dwDirection
, IEnumFORMATETC
**ppEnum
) {
2002 //Platform::DebugPrintf("DOB EnumFormatEtc %d\n", dwDirection);
2003 if (dwDirection
!= DATADIR_GET
) {
2007 FormatEnumerator
*pfe
;
2008 if (pd
->sci
->IsUnicodeMode()) {
2009 CLIPFORMAT formats
[] = {CF_UNICODETEXT
, CF_TEXT
};
2010 pfe
= new FormatEnumerator(0, formats
, 2);
2012 CLIPFORMAT formats
[] = {CF_TEXT
};
2013 pfe
= new FormatEnumerator(0, formats
, 1);
2015 return FormatEnumerator_QueryInterface(pfe
, IID_IEnumFORMATETC
,
2016 reinterpret_cast<void **>(ppEnum
));
2017 } catch (std::bad_alloc
&) {
2018 pd
->sci
->errorStatus
= SC_STATUS_BADALLOC
;
2019 return E_OUTOFMEMORY
;
2021 pd
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2026 STDMETHODIMP
DataObject_DAdvise(DataObject
*, FORMATETC
*, DWORD
, IAdviseSink
*, PDWORD
) {
2027 //Platform::DebugPrintf("DOB DAdvise\n");
2031 STDMETHODIMP
DataObject_DUnadvise(DataObject
*, DWORD
) {
2032 //Platform::DebugPrintf("DOB DUnadvise\n");
2036 STDMETHODIMP
DataObject_EnumDAdvise(DataObject
*, IEnumSTATDATA
**) {
2037 //Platform::DebugPrintf("DOB EnumDAdvise\n");
2041 static VFunction
*vtDataObject
[] = {
2042 (VFunction
*)(DataObject_QueryInterface
),
2043 (VFunction
*)(DataObject_AddRef
),
2044 (VFunction
*)(DataObject_Release
),
2045 (VFunction
*)(DataObject_GetData
),
2046 (VFunction
*)(DataObject_GetDataHere
),
2047 (VFunction
*)(DataObject_QueryGetData
),
2048 (VFunction
*)(DataObject_GetCanonicalFormatEtc
),
2049 (VFunction
*)(DataObject_SetData
),
2050 (VFunction
*)(DataObject_EnumFormatEtc
),
2051 (VFunction
*)(DataObject_DAdvise
),
2052 (VFunction
*)(DataObject_DUnadvise
),
2053 (VFunction
*)(DataObject_EnumDAdvise
)
2056 DataObject::DataObject() {
2057 vtbl
= vtDataObject
;
2061 /// Implement IUnknown
2062 STDMETHODIMP
DropTarget_QueryInterface(DropTarget
*dt
, REFIID riid
, PVOID
*ppv
) {
2063 //Platform::DebugPrintf("DT QI %x\n", dt);
2064 return dt
->sci
->QueryInterface(riid
, ppv
);
2066 STDMETHODIMP_(ULONG
)DropTarget_AddRef(DropTarget
*dt
) {
2067 return dt
->sci
->AddRef();
2069 STDMETHODIMP_(ULONG
)DropTarget_Release(DropTarget
*dt
) {
2070 return dt
->sci
->Release();
2073 /// Implement IDropTarget by forwarding to Scintilla
2074 STDMETHODIMP
DropTarget_DragEnter(DropTarget
*dt
, LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
2075 POINTL pt
, PDWORD pdwEffect
) {
2077 return dt
->sci
->DragEnter(pIDataSource
, grfKeyState
, pt
, pdwEffect
);
2079 dt
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2083 STDMETHODIMP
DropTarget_DragOver(DropTarget
*dt
, DWORD grfKeyState
, POINTL pt
, PDWORD pdwEffect
) {
2085 return dt
->sci
->DragOver(grfKeyState
, pt
, pdwEffect
);
2087 dt
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2091 STDMETHODIMP
DropTarget_DragLeave(DropTarget
*dt
) {
2093 return dt
->sci
->DragLeave();
2095 dt
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2099 STDMETHODIMP
DropTarget_Drop(DropTarget
*dt
, LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
2100 POINTL pt
, PDWORD pdwEffect
) {
2102 return dt
->sci
->Drop(pIDataSource
, grfKeyState
, pt
, pdwEffect
);
2104 dt
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2109 static VFunction
*vtDropTarget
[] = {
2110 (VFunction
*)(DropTarget_QueryInterface
),
2111 (VFunction
*)(DropTarget_AddRef
),
2112 (VFunction
*)(DropTarget_Release
),
2113 (VFunction
*)(DropTarget_DragEnter
),
2114 (VFunction
*)(DropTarget_DragOver
),
2115 (VFunction
*)(DropTarget_DragLeave
),
2116 (VFunction
*)(DropTarget_Drop
)
2119 DropTarget::DropTarget() {
2120 vtbl
= vtDropTarget
;
2125 * DBCS: support Input Method Editor (IME).
2126 * Called when IME Window opened.
2128 void ScintillaWin::ImeStartComposition() {
2130 // Move IME Window to current caret position
2131 HIMC hIMC
= ::ImmGetContext(MainHWND());
2132 Point pos
= PointMainCaret();
2133 COMPOSITIONFORM CompForm
;
2134 CompForm
.dwStyle
= CFS_POINT
;
2135 CompForm
.ptCurrentPos
.x
= pos
.x
;
2136 CompForm
.ptCurrentPos
.y
= pos
.y
;
2138 ::ImmSetCompositionWindow(hIMC
, &CompForm
);
2140 // Set font of IME window to same as surrounded text.
2142 // Since the style creation code has been made platform independent,
2143 // The logfont for the IME is recreated here.
2144 int styleHere
= (pdoc
->StyleAt(sel
.MainCaret())) & 31;
2145 LOGFONTA lf
= {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ""};
2146 int sizeZoomed
= vs
.styles
[styleHere
].size
+ vs
.zoomLevel
* SC_FONT_SIZE_MULTIPLIER
;
2147 if (sizeZoomed
<= 2 * SC_FONT_SIZE_MULTIPLIER
) // Hangs if sizeZoomed <= 1
2148 sizeZoomed
= 2 * SC_FONT_SIZE_MULTIPLIER
;
2149 AutoSurface
surface(this);
2150 int deviceHeight
= sizeZoomed
;
2152 deviceHeight
= (sizeZoomed
* surface
->LogPixelsY()) / 72;
2154 // The negative is to allow for leading
2155 lf
.lfHeight
= -(abs(deviceHeight
/ SC_FONT_SIZE_MULTIPLIER
));
2156 lf
.lfWeight
= vs
.styles
[styleHere
].weight
;
2157 lf
.lfItalic
= static_cast<BYTE
>(vs
.styles
[styleHere
].italic
? 1 : 0);
2158 lf
.lfCharSet
= DEFAULT_CHARSET
;
2159 lf
.lfFaceName
[0] = '\0';
2160 if (vs
.styles
[styleHere
].fontName
&& (strlen(vs
.styles
[styleHere
].fontName
) < sizeof(lf
.lfFaceName
)))
2161 strcpy(lf
.lfFaceName
, vs
.styles
[styleHere
].fontName
);
2163 ::ImmSetCompositionFontA(hIMC
, &lf
);
2165 ::ImmReleaseContext(MainHWND(), hIMC
);
2166 // Caret is displayed in IME window. So, caret in Scintilla is useless.
2171 /** Called when IME Window closed. */
2172 void ScintillaWin::ImeEndComposition() {
2173 ShowCaretAtCurrentPosition();
2176 void ScintillaWin::AddCharBytes(char b0
, char b1
) {
2178 int inputCodePage
= InputCodePage();
2179 if (inputCodePage
&& IsUnicodeMode()) {
2180 char utfval
[4] = "\0\0\0";
2183 if (b0
) { // Two bytes from IME
2186 ansiChars
[2] = '\0';
2187 ::MultiByteToWideChar(inputCodePage
, 0, ansiChars
, 2, wcs
, 1);
2190 ansiChars
[1] = '\0';
2191 ::MultiByteToWideChar(inputCodePage
, 0, ansiChars
, 1, wcs
, 1);
2193 unsigned int len
= UTF8Length(wcs
, 1);
2194 UTF8FromUTF16(wcs
, 1, utfval
, len
);
2196 AddCharUTF(utfval
, len
? len
: 1);
2201 dbcsChars
[2] = '\0';
2202 AddCharUTF(dbcsChars
, 2, true);
2208 void ScintillaWin::GetIntelliMouseParameters() {
2209 // This retrieves the number of lines per scroll as configured inthe Mouse Properties sheet in Control Panel
2210 ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0, &linesPerScroll
, 0);
2213 void ScintillaWin::CopyToClipboard(const SelectionText
&selectedText
) {
2214 if (!::OpenClipboard(MainHWND()))
2218 GlobalMemory uniText
;
2220 // Default Scintilla behaviour in Unicode mode
2221 if (IsUnicodeMode()) {
2222 int uchars
= UTF16Length(selectedText
.Data(),
2223 static_cast<int>(selectedText
.LengthWithTerminator()));
2224 uniText
.Allocate(2 * uchars
);
2226 UTF16FromUTF8(selectedText
.Data(), static_cast<int>(selectedText
.LengthWithTerminator()),
2227 static_cast<wchar_t *>(uniText
.ptr
), uchars
);
2231 // Convert to Unicode using the current Scintilla code page
2232 UINT cpSrc
= CodePageFromCharSet(
2233 selectedText
.characterSet
, selectedText
.codePage
);
2234 int uLen
= ::MultiByteToWideChar(cpSrc
, 0, selectedText
.Data(),
2235 static_cast<int>(selectedText
.LengthWithTerminator()), 0, 0);
2236 uniText
.Allocate(2 * uLen
);
2238 ::MultiByteToWideChar(cpSrc
, 0, selectedText
.Data(),
2239 static_cast<int>(selectedText
.LengthWithTerminator()),
2240 static_cast<wchar_t *>(uniText
.ptr
), uLen
);
2246 // Copy ANSI text to clipboard on Windows 9x
2247 // Convert from Unicode text, so other ANSI programs can
2249 // Windows NT, 2k, XP automatically generates CF_TEXT
2250 GlobalMemory ansiText
;
2251 ansiText
.Allocate(selectedText
.LengthWithTerminator());
2253 ::WideCharToMultiByte(CP_ACP
, 0, static_cast<wchar_t *>(uniText
.ptr
), -1,
2254 static_cast<char *>(ansiText
.ptr
),
2255 static_cast<int>(selectedText
.LengthWithTerminator()), NULL
, NULL
);
2256 ansiText
.SetClip(CF_TEXT
);
2259 uniText
.SetClip(CF_UNICODETEXT
);
2261 // There was a failure - try to copy at least ANSI text
2262 GlobalMemory ansiText
;
2263 ansiText
.Allocate(selectedText
.LengthWithTerminator());
2265 memcpy(static_cast<char *>(ansiText
.ptr
), selectedText
.Data(), selectedText
.LengthWithTerminator());
2266 ansiText
.SetClip(CF_TEXT
);
2270 if (selectedText
.rectangular
) {
2271 ::SetClipboardData(cfColumnSelect
, 0);
2273 GlobalMemory borlandSelection
;
2274 borlandSelection
.Allocate(1);
2275 if (borlandSelection
) {
2276 static_cast<BYTE
*>(borlandSelection
.ptr
)[0] = 0x02;
2277 borlandSelection
.SetClip(cfBorlandIDEBlockType
);
2281 if (selectedText
.lineCopy
) {
2282 ::SetClipboardData(cfLineSelect
, 0);
2288 void ScintillaWin::ScrollMessage(WPARAM wParam
) {
2289 //DWORD dwStart = timeGetTime();
2290 //Platform::DebugPrintf("Scroll %x %d\n", wParam, lParam);
2292 SCROLLINFO sci
= {};
2293 sci
.cbSize
= sizeof(sci
);
2294 sci
.fMask
= SIF_ALL
;
2296 GetScrollInfo(SB_VERT
, &sci
);
2298 //Platform::DebugPrintf("ScrollInfo %d mask=%x min=%d max=%d page=%d pos=%d track=%d\n", b,sci.fMask,
2299 //sci.nMin, sci.nMax, sci.nPage, sci.nPos, sci.nTrackPos);
2301 int topLineNew
= topLine
;
2302 switch (LoWord(wParam
)) {
2310 topLineNew
-= LinesToScroll(); break;
2311 case SB_PAGEDOWN
: topLineNew
+= LinesToScroll(); break;
2312 case SB_TOP
: topLineNew
= 0; break;
2313 case SB_BOTTOM
: topLineNew
= MaxScrollPos(); break;
2314 case SB_THUMBPOSITION
: topLineNew
= sci
.nTrackPos
; break;
2315 case SB_THUMBTRACK
: topLineNew
= sci
.nTrackPos
; break;
2317 ScrollTo(topLineNew
);
2320 void ScintillaWin::HorizontalScrollMessage(WPARAM wParam
) {
2322 PRectangle rcText
= GetTextRectangle();
2323 int pageWidth
= rcText
.Width() * 2 / 3;
2324 switch (LoWord(wParam
)) {
2328 case SB_LINEDOWN
: // May move past the logical end
2336 if (xPos
> scrollWidth
- rcText
.Width()) { // Hit the end exactly
2337 xPos
= scrollWidth
- rcText
.Width();
2346 case SB_THUMBPOSITION
:
2347 case SB_THUMBTRACK
: {
2348 // 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 =]
2350 si
.cbSize
= sizeof(si
);
2351 si
.fMask
= SIF_TRACKPOS
;
2352 if (GetScrollInfo(SB_HORZ
, &si
)) {
2353 xPos
= si
.nTrackPos
;
2358 HorizontalScrollTo(xPos
);
2362 * Redraw all of text area.
2363 * This paint will not be abandoned.
2365 void ScintillaWin::FullPaint() {
2366 if (technology
== SC_TECHNOLOGY_DEFAULT
) {
2367 HDC hdc
= ::GetDC(MainHWND());
2369 ::ReleaseDC(MainHWND(), hdc
);
2376 * Redraw all of text area on the specified DC.
2377 * This paint will not be abandoned.
2379 void ScintillaWin::FullPaintDC(HDC hdc
) {
2380 paintState
= painting
;
2381 rcPaint
= GetClientRectangle();
2382 paintingAllText
= true;
2383 if (technology
== SC_TECHNOLOGY_DEFAULT
) {
2384 AutoSurface
surfaceWindow(hdc
, this);
2385 if (surfaceWindow
) {
2386 Paint(surfaceWindow
, rcPaint
);
2387 surfaceWindow
->Release();
2390 #if defined(USE_D2D)
2391 EnsureRenderTarget();
2392 AutoSurface
surfaceWindow(pRenderTarget
, this);
2393 if (surfaceWindow
) {
2394 pRenderTarget
->BeginDraw();
2395 Paint(surfaceWindow
, rcPaint
);
2396 surfaceWindow
->Release();
2397 HRESULT hr
= pRenderTarget
->EndDraw();
2398 if (hr
== D2DERR_RECREATE_TARGET
) {
2404 paintState
= notPainting
;
2407 static bool CompareDevCap(HDC hdc
, HDC hOtherDC
, int nIndex
) {
2408 return ::GetDeviceCaps(hdc
, nIndex
) == ::GetDeviceCaps(hOtherDC
, nIndex
);
2411 bool ScintillaWin::IsCompatibleDC(HDC hOtherDC
) {
2412 HDC hdc
= ::GetDC(MainHWND());
2414 CompareDevCap(hdc
, hOtherDC
, TECHNOLOGY
) &&
2415 CompareDevCap(hdc
, hOtherDC
, LOGPIXELSY
) &&
2416 CompareDevCap(hdc
, hOtherDC
, LOGPIXELSX
) &&
2417 CompareDevCap(hdc
, hOtherDC
, BITSPIXEL
) &&
2418 CompareDevCap(hdc
, hOtherDC
, PLANES
);
2419 ::ReleaseDC(MainHWND(), hdc
);
2420 return isCompatible
;
2423 DWORD
ScintillaWin::EffectFromState(DWORD grfKeyState
) const {
2424 // These are the Wordpad semantics.
2426 if (inDragDrop
== ddDragging
) // Internal defaults to move
2427 dwEffect
= DROPEFFECT_MOVE
;
2429 dwEffect
= DROPEFFECT_COPY
;
2430 if (grfKeyState
& MK_ALT
)
2431 dwEffect
= DROPEFFECT_MOVE
;
2432 if (grfKeyState
& MK_CONTROL
)
2433 dwEffect
= DROPEFFECT_COPY
;
2437 /// Implement IUnknown
2438 STDMETHODIMP
ScintillaWin::QueryInterface(REFIID riid
, PVOID
*ppv
) {
2440 if (riid
== IID_IUnknown
)
2441 *ppv
= reinterpret_cast<IDropTarget
*>(&dt
);
2442 if (riid
== IID_IDropSource
)
2443 *ppv
= reinterpret_cast<IDropSource
*>(&ds
);
2444 if (riid
== IID_IDropTarget
)
2445 *ppv
= reinterpret_cast<IDropTarget
*>(&dt
);
2446 if (riid
== IID_IDataObject
)
2447 *ppv
= reinterpret_cast<IDataObject
*>(&dob
);
2449 return E_NOINTERFACE
;
2453 STDMETHODIMP_(ULONG
) ScintillaWin::AddRef() {
2457 STDMETHODIMP_(ULONG
) ScintillaWin::Release() {
2461 /// Implement IDropTarget
2462 STDMETHODIMP
ScintillaWin::DragEnter(LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
2463 POINTL
, PDWORD pdwEffect
) {
2464 if (pIDataSource
== NULL
)
2466 FORMATETC fmtu
= {CF_UNICODETEXT
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2467 HRESULT hrHasUText
= pIDataSource
->QueryGetData(&fmtu
);
2468 hasOKText
= (hrHasUText
== S_OK
);
2470 FORMATETC fmte
= {CF_TEXT
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2471 HRESULT hrHasText
= pIDataSource
->QueryGetData(&fmte
);
2472 hasOKText
= (hrHasText
== S_OK
);
2475 *pdwEffect
= DROPEFFECT_NONE
;
2479 *pdwEffect
= EffectFromState(grfKeyState
);
2483 STDMETHODIMP
ScintillaWin::DragOver(DWORD grfKeyState
, POINTL pt
, PDWORD pdwEffect
) {
2485 if (!hasOKText
|| pdoc
->IsReadOnly()) {
2486 *pdwEffect
= DROPEFFECT_NONE
;
2490 *pdwEffect
= EffectFromState(grfKeyState
);
2492 // Update the cursor.
2493 POINT rpt
= {pt
.x
, pt
.y
};
2494 ::ScreenToClient(MainHWND(), &rpt
);
2495 SetDragPosition(SPositionFromLocation(Point(rpt
.x
, rpt
.y
), false, false, UserVirtualSpace()));
2499 errorStatus
= SC_STATUS_FAILURE
;
2504 STDMETHODIMP
ScintillaWin::DragLeave() {
2506 SetDragPosition(SelectionPosition(invalidPosition
));
2509 errorStatus
= SC_STATUS_FAILURE
;
2514 STDMETHODIMP
ScintillaWin::Drop(LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
2515 POINTL pt
, PDWORD pdwEffect
) {
2517 *pdwEffect
= EffectFromState(grfKeyState
);
2519 if (pIDataSource
== NULL
)
2522 SetDragPosition(SelectionPosition(invalidPosition
));
2524 STGMEDIUM medium
= {0, {0}, 0};
2526 std::vector
<char> data
; // Includes terminating NUL
2528 FORMATETC fmtu
= {CF_UNICODETEXT
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2529 HRESULT hr
= pIDataSource
->GetData(&fmtu
, &medium
);
2530 if (SUCCEEDED(hr
) && medium
.hGlobal
) {
2531 GlobalMemory
memUDrop(medium
.hGlobal
);
2532 wchar_t *udata
= static_cast<wchar_t *>(memUDrop
.ptr
);
2534 if (IsUnicodeMode()) {
2535 int tlen
= memUDrop
.Size();
2536 // Convert UTF-16 to UTF-8
2537 int dataLen
= UTF8Length(udata
, tlen
/2);
2538 data
.resize(dataLen
+1);
2539 UTF8FromUTF16(udata
, tlen
/2, &data
[0], dataLen
);
2541 // Convert UTF-16 to ANSI
2543 // Default Scintilla behavior in Unicode mode
2544 // CF_UNICODETEXT available, but not in Unicode mode
2545 // Convert from Unicode to current Scintilla code page
2546 UINT cpDest
= CodePageOfDocument();
2547 int tlen
= ::WideCharToMultiByte(cpDest
, 0, udata
, -1,
2548 NULL
, 0, NULL
, NULL
) - 1; // subtract 0 terminator
2549 data
.resize(tlen
+ 1);
2550 ::WideCharToMultiByte(cpDest
, 0, udata
, -1,
2551 &data
[0], tlen
+ 1, NULL
, NULL
);
2556 FORMATETC fmte
= {CF_TEXT
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2557 hr
= pIDataSource
->GetData(&fmte
, &medium
);
2558 if (SUCCEEDED(hr
) && medium
.hGlobal
) {
2559 GlobalMemory
memDrop(medium
.hGlobal
);
2560 const char *cdata
= static_cast<char *>(memDrop
.ptr
);
2562 data
.assign(cdata
, cdata
+strlen(cdata
)+1);
2567 if (!data
.empty() && convertPastes
) {
2568 // Convert line endings of the drop into our local line-endings mode
2569 std::string convertedText
= Document::TransformLineEnds(&data
[0], data
.size() - 1, pdoc
->eolMode
);
2570 data
.assign(convertedText
.c_str(), convertedText
.c_str()+convertedText
.length()+1);
2573 if (!SUCCEEDED(hr
) || data
.empty()) {
2574 //Platform::DebugPrintf("Bad data format: 0x%x\n", hres);
2578 FORMATETC fmtr
= {cfColumnSelect
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2579 HRESULT hrRectangular
= pIDataSource
->QueryGetData(&fmtr
);
2581 POINT rpt
= {pt
.x
, pt
.y
};
2582 ::ScreenToClient(MainHWND(), &rpt
);
2583 SelectionPosition movePos
= SPositionFromLocation(Point(rpt
.x
, rpt
.y
), false, false, UserVirtualSpace());
2585 DropAt(movePos
, &data
[0], data
.size() - 1, *pdwEffect
== DROPEFFECT_MOVE
, hrRectangular
== S_OK
);
2588 if (medium
.pUnkForRelease
!= NULL
)
2589 medium
.pUnkForRelease
->Release();
2591 ::GlobalFree(medium
.hGlobal
);
2595 errorStatus
= SC_STATUS_FAILURE
;
2600 /// Implement important part of IDataObject
2601 STDMETHODIMP
ScintillaWin::GetData(FORMATETC
*pFEIn
, STGMEDIUM
*pSTM
) {
2602 bool formatOK
= (pFEIn
->cfFormat
== CF_TEXT
) ||
2603 ((pFEIn
->cfFormat
== CF_UNICODETEXT
) && IsUnicodeMode());
2606 (pFEIn
->dwAspect
& DVASPECT_CONTENT
) == 0 ||
2607 pFEIn
->lindex
!= -1 ||
2608 (pFEIn
->tymed
& TYMED_HGLOBAL
) == 0
2610 //Platform::DebugPrintf("DOB GetData No %d %x %x fmt=%x\n", lenDrag, pFEIn, pSTM, pFEIn->cfFormat);
2611 return DATA_E_FORMATETC
;
2613 pSTM
->tymed
= TYMED_HGLOBAL
;
2614 //Platform::DebugPrintf("DOB GetData OK %d %x %x\n", lenDrag, pFEIn, pSTM);
2617 if (pFEIn
->cfFormat
== CF_UNICODETEXT
) {
2618 int uchars
= UTF16Length(drag
.Data(), static_cast<int>(drag
.LengthWithTerminator()));
2619 text
.Allocate(2 * uchars
);
2621 UTF16FromUTF8(drag
.Data(), static_cast<int>(drag
.LengthWithTerminator()),
2622 static_cast<wchar_t *>(text
.ptr
), uchars
);
2625 text
.Allocate(drag
.LengthWithTerminator());
2627 memcpy(static_cast<char *>(text
.ptr
), drag
.Data(), drag
.LengthWithTerminator());
2630 pSTM
->hGlobal
= text
? text
.Unlock() : 0;
2631 pSTM
->pUnkForRelease
= 0;
2635 bool ScintillaWin::Register(HINSTANCE hInstance_
) {
2637 hInstance
= hInstance_
;
2640 // Register the Scintilla class
2643 // Register Scintilla as a wide character window
2644 WNDCLASSEXW wndclass
;
2645 wndclass
.cbSize
= sizeof(wndclass
);
2646 wndclass
.style
= CS_GLOBALCLASS
| CS_HREDRAW
| CS_VREDRAW
;
2647 wndclass
.lpfnWndProc
= ScintillaWin::SWndProc
;
2648 wndclass
.cbClsExtra
= 0;
2649 wndclass
.cbWndExtra
= sizeof(ScintillaWin
*);
2650 wndclass
.hInstance
= hInstance
;
2651 wndclass
.hIcon
= NULL
;
2652 wndclass
.hCursor
= NULL
;
2653 wndclass
.hbrBackground
= NULL
;
2654 wndclass
.lpszMenuName
= NULL
;
2655 wndclass
.lpszClassName
= L
"Scintilla";
2656 wndclass
.hIconSm
= 0;
2657 result
= ::RegisterClassExW(&wndclass
) != 0;
2660 // Register Scintilla as a normal character window
2661 WNDCLASSEX wndclass
;
2662 wndclass
.cbSize
= sizeof(wndclass
);
2663 wndclass
.style
= CS_GLOBALCLASS
| CS_HREDRAW
| CS_VREDRAW
;
2664 wndclass
.lpfnWndProc
= ScintillaWin::SWndProc
;
2665 wndclass
.cbClsExtra
= 0;
2666 wndclass
.cbWndExtra
= sizeof(ScintillaWin
*);
2667 wndclass
.hInstance
= hInstance
;
2668 wndclass
.hIcon
= NULL
;
2669 wndclass
.hCursor
= NULL
;
2670 wndclass
.hbrBackground
= NULL
;
2671 wndclass
.lpszMenuName
= NULL
;
2672 wndclass
.lpszClassName
= scintillaClassName
;
2673 wndclass
.hIconSm
= 0;
2674 result
= ::RegisterClassEx(&wndclass
) != 0;
2678 // Register the CallTip class
2679 WNDCLASSEX wndclassc
;
2680 wndclassc
.cbSize
= sizeof(wndclassc
);
2681 wndclassc
.style
= CS_GLOBALCLASS
| CS_HREDRAW
| CS_VREDRAW
;
2682 wndclassc
.cbClsExtra
= 0;
2683 wndclassc
.cbWndExtra
= sizeof(ScintillaWin
*);
2684 wndclassc
.hInstance
= hInstance
;
2685 wndclassc
.hIcon
= NULL
;
2686 wndclassc
.hbrBackground
= NULL
;
2687 wndclassc
.lpszMenuName
= NULL
;
2688 wndclassc
.lpfnWndProc
= ScintillaWin::CTWndProc
;
2689 wndclassc
.hCursor
= ::LoadCursor(NULL
, IDC_ARROW
);
2690 wndclassc
.lpszClassName
= callClassName
;
2691 wndclassc
.hIconSm
= 0;
2693 result
= ::RegisterClassEx(&wndclassc
) != 0;
2699 bool ScintillaWin::Unregister() {
2700 bool result
= ::UnregisterClass(scintillaClassName
, hInstance
) != 0;
2701 if (::UnregisterClass(callClassName
, hInstance
) == 0)
2706 bool ScintillaWin::HasCaretSizeChanged() const {
2708 ( (0 != vs
.caretWidth
) && (sysCaretWidth
!= vs
.caretWidth
) )
2709 || ((0 != vs
.lineHeight
) && (sysCaretHeight
!= vs
.lineHeight
))
2716 BOOL
ScintillaWin::CreateSystemCaret() {
2717 sysCaretWidth
= vs
.caretWidth
;
2718 if (0 == sysCaretWidth
) {
2721 sysCaretHeight
= vs
.lineHeight
;
2722 int bitmapSize
= (((sysCaretWidth
+ 15) & ~15) >> 3) *
2724 std::vector
<char> bits(bitmapSize
);
2725 sysCaretBitmap
= ::CreateBitmap(sysCaretWidth
, sysCaretHeight
, 1,
2726 1, reinterpret_cast<BYTE
*>(&bits
[0]));
2727 BOOL retval
= ::CreateCaret(
2728 MainHWND(), sysCaretBitmap
,
2729 sysCaretWidth
, sysCaretHeight
);
2730 ::ShowCaret(MainHWND());
2734 BOOL
ScintillaWin::DestroySystemCaret() {
2735 ::HideCaret(MainHWND());
2736 BOOL retval
= ::DestroyCaret();
2737 if (sysCaretBitmap
) {
2738 ::DeleteObject(sysCaretBitmap
);
2744 sptr_t PASCAL
ScintillaWin::CTWndProc(
2745 HWND hWnd
, UINT iMessage
, WPARAM wParam
, sptr_t lParam
) {
2746 // Find C++ object associated with window.
2747 ScintillaWin
*sciThis
= reinterpret_cast<ScintillaWin
*>(PointerFromWindow(hWnd
));
2749 // ctp will be zero if WM_CREATE not seen yet
2751 if (iMessage
== WM_CREATE
) {
2752 // Associate CallTip object with window
2753 CREATESTRUCT
*pCreate
= reinterpret_cast<CREATESTRUCT
*>(lParam
);
2754 SetWindowPointer(hWnd
, pCreate
->lpCreateParams
);
2757 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2760 if (iMessage
== WM_NCDESTROY
) {
2761 ::SetWindowLong(hWnd
, 0, 0);
2762 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2763 } else if (iMessage
== WM_PAINT
) {
2765 ::BeginPaint(hWnd
, &ps
);
2766 Surface
*surfaceWindow
= Surface::Allocate(sciThis
->technology
);
2767 if (surfaceWindow
) {
2768 #if defined(USE_D2D)
2769 ID2D1HwndRenderTarget
*pCTRenderTarget
= 0;
2772 GetClientRect(hWnd
, &rc
);
2773 // Create a Direct2D render target.
2774 if (sciThis
->technology
== SC_TECHNOLOGY_DEFAULT
) {
2775 surfaceWindow
->Init(ps
.hdc
, hWnd
);
2777 #if defined(USE_D2D)
2778 D2D1_HWND_RENDER_TARGET_PROPERTIES dhrtp
;
2780 dhrtp
.pixelSize
= D2D1::SizeU(rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
2781 dhrtp
.presentOptions
= D2D1_PRESENT_OPTIONS_NONE
;
2783 D2D1_RENDER_TARGET_PROPERTIES drtp
;
2784 drtp
.type
= D2D1_RENDER_TARGET_TYPE_DEFAULT
;
2785 drtp
.pixelFormat
.format
= DXGI_FORMAT_UNKNOWN
;
2786 drtp
.pixelFormat
.alphaMode
= D2D1_ALPHA_MODE_UNKNOWN
;
2789 drtp
.usage
= D2D1_RENDER_TARGET_USAGE_NONE
;
2790 drtp
.minLevel
= D2D1_FEATURE_LEVEL_DEFAULT
;
2792 if (!SUCCEEDED(pD2DFactory
->CreateHwndRenderTarget(drtp
, dhrtp
, &pCTRenderTarget
))) {
2793 surfaceWindow
->Release();
2794 delete surfaceWindow
;
2795 ::EndPaint(hWnd
, &ps
);
2798 surfaceWindow
->Init(pCTRenderTarget
, hWnd
);
2799 pCTRenderTarget
->BeginDraw();
2802 surfaceWindow
->SetUnicodeMode(SC_CP_UTF8
== sciThis
->ct
.codePage
);
2803 surfaceWindow
->SetDBCSMode(sciThis
->ct
.codePage
);
2804 sciThis
->ct
.PaintCT(surfaceWindow
);
2805 #if defined(USE_D2D)
2806 if (pCTRenderTarget
)
2807 pCTRenderTarget
->EndDraw();
2809 surfaceWindow
->Release();
2810 delete surfaceWindow
;
2811 #if defined(USE_D2D)
2812 if (pCTRenderTarget
)
2813 pCTRenderTarget
->Release();
2816 ::EndPaint(hWnd
, &ps
);
2818 } else if ((iMessage
== WM_NCLBUTTONDOWN
) || (iMessage
== WM_NCLBUTTONDBLCLK
)) {
2820 pt
.x
= static_cast<short>(LOWORD(lParam
));
2821 pt
.y
= static_cast<short>(HIWORD(lParam
));
2822 ScreenToClient(hWnd
, &pt
);
2823 sciThis
->ct
.MouseClick(Point(pt
.x
, pt
.y
));
2824 sciThis
->CallTipClick();
2826 } else if (iMessage
== WM_LBUTTONDOWN
) {
2827 // This does not fire due to the hit test code
2828 sciThis
->ct
.MouseClick(Point::FromLong(lParam
));
2829 sciThis
->CallTipClick();
2831 } else if (iMessage
== WM_SETCURSOR
) {
2832 ::SetCursor(::LoadCursor(NULL
, IDC_ARROW
));
2834 } else if (iMessage
== WM_NCHITTEST
) {
2837 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2841 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2843 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2846 sptr_t
ScintillaWin::DirectFunction(
2847 ScintillaWin
*sci
, UINT iMessage
, uptr_t wParam
, sptr_t lParam
) {
2848 PLATFORM_ASSERT(::GetCurrentThreadId() == ::GetWindowThreadProcessId(sci
->MainHWND(), NULL
));
2849 return sci
->WndProc(iMessage
, wParam
, lParam
);
2853 #ifndef STATIC_BUILD
2854 __declspec(dllexport
)
2856 sptr_t __stdcall
Scintilla_DirectFunction(
2857 ScintillaWin
*sci
, UINT iMessage
, uptr_t wParam
, sptr_t lParam
) {
2858 return sci
->WndProc(iMessage
, wParam
, lParam
);
2861 sptr_t PASCAL
ScintillaWin::SWndProc(
2862 HWND hWnd
, UINT iMessage
, WPARAM wParam
, sptr_t lParam
) {
2863 //Platform::DebugPrintf("S W:%x M:%x WP:%x L:%x\n", hWnd, iMessage, wParam, lParam);
2865 // Find C++ object associated with window.
2866 ScintillaWin
*sci
= reinterpret_cast<ScintillaWin
*>(PointerFromWindow(hWnd
));
2867 // sci will be zero if WM_CREATE not seen yet
2870 if (iMessage
== WM_CREATE
) {
2871 // Create C++ object associated with window
2872 sci
= new ScintillaWin(hWnd
);
2873 SetWindowPointer(hWnd
, sci
);
2874 return sci
->WndProc(iMessage
, wParam
, lParam
);
2878 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2880 if (iMessage
== WM_NCDESTROY
) {
2886 ::SetWindowLong(hWnd
, 0, 0);
2887 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2889 return sci
->WndProc(iMessage
, wParam
, lParam
);
2894 // This function is externally visible so it can be called from container when building statically.
2895 // Must be called once only.
2896 int Scintilla_RegisterClasses(void *hInstance
) {
2897 Platform_Initialise(hInstance
);
2898 bool result
= ScintillaWin::Register(reinterpret_cast<HINSTANCE
>(hInstance
));
2900 Scintilla_LinkLexers();
2905 // This function is externally visible so it can be called from container when building statically.
2906 int Scintilla_ReleaseResources() {
2907 bool result
= ScintillaWin::Unregister();
2908 Platform_Finalise();
2912 #ifndef STATIC_BUILD
2913 extern "C" int APIENTRY
DllMain(HINSTANCE hInstance
, DWORD dwReason
, LPVOID
) {
2914 //Platform::DebugPrintf("Scintilla::DllMain %d %d\n", hInstance, dwReason);
2915 if (dwReason
== DLL_PROCESS_ATTACH
) {
2916 if (!Scintilla_RegisterClasses(hInstance
))
2918 } else if (dwReason
== DLL_PROCESS_DETACH
) {
2919 Scintilla_ReleaseResources();