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.
21 #define _WIN32_WINNT 0x0500
27 #if defined(_MSC_VER) && (_MSC_VER > 1200)
39 #include "Scintilla.h"
43 #include "LexerModule.h"
45 #include "SplitVector.h"
46 #include "Partitioning.h"
47 #include "RunStyles.h"
48 #include "ContractionState.h"
49 #include "CellBuffer.h"
52 #include "Indicator.h"
54 #include "LineMarker.h"
56 #include "AutoComplete.h"
57 #include "ViewStyle.h"
58 #include "CharClassify.h"
59 #include "Decoration.h"
61 #include "Selection.h"
62 #include "PositionCache.h"
64 #include "ScintillaBase.h"
65 #include "UniConversion.h"
69 #include "ExternalLexer.h"
72 #ifndef SPI_GETWHEELSCROLLLINES
73 #define SPI_GETWHEELSCROLLLINES 104
77 #define WM_UNICHAR 0x0109
80 #ifndef UNICODE_NOCHAR
81 #define UNICODE_NOCHAR 0xFFFF
84 #ifndef WM_IME_STARTCOMPOSITION
98 #define SC_WIN_IDLE 5001
100 typedef BOOL (WINAPI
*TrackMouseEventSig
)(LPTRACKMOUSEEVENT
);
102 // GCC has trouble with the standard COM ABI so do it the old C way with explicit vtables.
104 const TCHAR scintillaClassName
[] = TEXT("Scintilla");
105 const TCHAR callClassName
[] = TEXT("CallTip");
108 using namespace Scintilla
;
111 // Take care of 32/64 bit pointers
112 #ifdef GetWindowLongPtr
113 static void *PointerFromWindow(HWND hWnd
) {
114 return reinterpret_cast<void *>(::GetWindowLongPtr(hWnd
, 0));
116 static void SetWindowPointer(HWND hWnd
, void *ptr
) {
117 ::SetWindowLongPtr(hWnd
, 0, reinterpret_cast<LONG_PTR
>(ptr
));
119 static void SetWindowID(HWND hWnd
, int identifier
) {
120 ::SetWindowLongPtr(hWnd
, GWLP_ID
, identifier
);
123 static void *PointerFromWindow(HWND hWnd
) {
124 return reinterpret_cast<void *>(::GetWindowLong(hWnd
, 0));
126 static void SetWindowPointer(HWND hWnd
, void *ptr
) {
127 ::SetWindowLong(hWnd
, 0, reinterpret_cast<LONG
>(ptr
));
129 static void SetWindowID(HWND hWnd
, int identifier
) {
130 ::SetWindowLong(hWnd
, GWL_ID
, identifier
);
134 class ScintillaWin
; // Forward declaration for COM interface subobjects
136 typedef void VFunction(void);
140 class FormatEnumerator
{
145 CLIPFORMAT formats
[2];
147 FormatEnumerator(int pos_
, CLIPFORMAT formats_
[], int formatsLen_
);
180 public ScintillaBase
{
182 bool lastKeyDownConsumed
;
185 bool trackedMouseLeave
;
186 TrackMouseEventSig TrackMouseEventFn
;
188 unsigned int linesPerScroll
; ///< Intellimouse support
189 int wheelDelta
; ///< Wheel delta from roll
195 CLIPFORMAT cfColumnSelect
;
196 CLIPFORMAT cfLineSelect
;
203 static HINSTANCE hInstance
;
206 ID2D1HwndRenderTarget
*pRenderTarget
;
207 bool renderTargetValid
;
210 ScintillaWin(HWND hwnd
);
211 ScintillaWin(const ScintillaWin
&);
212 virtual ~ScintillaWin();
213 ScintillaWin
&operator=(const ScintillaWin
&);
215 virtual void Initialise();
216 virtual void Finalise();
217 void EnsureRenderTarget();
218 void DropRenderTarget();
221 static sptr_t
DirectFunction(
222 ScintillaWin
*sci
, UINT iMessage
, uptr_t wParam
, sptr_t lParam
);
223 static sptr_t PASCAL
SWndProc(
224 HWND hWnd
, UINT iMessage
, WPARAM wParam
, sptr_t lParam
);
225 static sptr_t PASCAL
CTWndProc(
226 HWND hWnd
, UINT iMessage
, WPARAM wParam
, sptr_t lParam
);
228 enum { invalidTimerID
, standardTimerID
, idleTimerID
};
230 virtual bool DragThreshold(Point ptStart
, Point ptNow
);
231 virtual void StartDrag();
232 sptr_t
WndPaint(uptr_t wParam
);
233 sptr_t
HandleComposition(uptr_t wParam
, sptr_t lParam
);
234 UINT
CodePageOfDocument();
235 virtual bool ValidCodePage(int codePage
) const;
236 virtual sptr_t
DefWndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
237 virtual bool SetIdle(bool on
);
238 virtual void SetTicking(bool on
);
239 virtual void SetMouseCapture(bool on
);
240 virtual bool HaveMouseCapture();
241 virtual void SetTrackMouseLeaveEvent(bool on
);
242 virtual bool PaintContains(PRectangle rc
);
243 virtual void ScrollText(int linesToMove
);
244 virtual void UpdateSystemCaret();
245 virtual void SetVerticalScrollPos();
246 virtual void SetHorizontalScrollPos();
247 virtual bool ModifyScrollBars(int nMax
, int nPage
);
248 virtual void NotifyChange();
249 virtual void NotifyFocus(bool focus
);
250 virtual void SetCtrlID(int identifier
);
251 virtual int GetCtrlID();
252 virtual void NotifyParent(SCNotification scn
);
253 virtual void NotifyParent(SCNotification
* scn
);
254 virtual void NotifyDoubleClick(Point pt
, bool shift
, bool ctrl
, bool alt
);
255 virtual CaseFolder
*CaseFolderForEncoding();
256 virtual std::string
CaseMapString(const std::string
&s
, int caseMapping
);
258 virtual void CopyAllowLine();
259 virtual bool CanPaste();
260 virtual void Paste();
261 virtual void CreateCallTipWindow(PRectangle rc
);
262 virtual void AddToPopUp(const char *label
, int cmd
= 0, bool enabled
= true);
263 virtual void ClaimSelection();
266 void ImeStartComposition();
267 void ImeEndComposition();
269 void AddCharBytes(char b0
, char b1
);
271 void GetIntelliMouseParameters();
272 virtual void CopyToClipboard(const SelectionText
&selectedText
);
273 void ScrollMessage(WPARAM wParam
);
274 void HorizontalScrollMessage(WPARAM wParam
);
276 void FullPaintDC(HDC dc
);
277 bool IsCompatibleDC(HDC dc
);
278 DWORD
EffectFromState(DWORD grfKeyState
);
280 virtual int SetScrollInfo(int nBar
, LPCSCROLLINFO lpsi
, BOOL bRedraw
);
281 virtual bool GetScrollInfo(int nBar
, LPSCROLLINFO lpsi
);
282 void ChangeScrollPos(int barType
, int pos
);
284 void InsertPasteText(const char *text
, int len
, SelectionPosition selStart
, bool isRectangular
, bool isLine
);
287 // Public for benefit of Scintilla_DirectFunction
288 virtual sptr_t
WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
290 /// Implement IUnknown
291 STDMETHODIMP
QueryInterface(REFIID riid
, PVOID
*ppv
);
292 STDMETHODIMP_(ULONG
)AddRef();
293 STDMETHODIMP_(ULONG
)Release();
295 /// Implement IDropTarget
296 STDMETHODIMP
DragEnter(LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
297 POINTL pt
, PDWORD pdwEffect
);
298 STDMETHODIMP
DragOver(DWORD grfKeyState
, POINTL pt
, PDWORD pdwEffect
);
299 STDMETHODIMP
DragLeave();
300 STDMETHODIMP
Drop(LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
301 POINTL pt
, PDWORD pdwEffect
);
303 /// Implement important part of IDataObject
304 STDMETHODIMP
GetData(FORMATETC
*pFEIn
, STGMEDIUM
*pSTM
);
306 static bool Register(HINSTANCE hInstance_
);
307 static bool Unregister();
309 friend class DropSource
;
310 friend class DataObject
;
311 friend class DropTarget
;
312 bool DragIsRectangularOK(CLIPFORMAT fmt
) {
313 return drag
.rectangular
&& (fmt
== cfColumnSelect
);
317 // For use in creating a system caret
318 bool HasCaretSizeChanged();
319 BOOL
CreateSystemCaret();
320 BOOL
DestroySystemCaret();
321 HBITMAP sysCaretBitmap
;
324 bool keysAlwaysUnicode
;
327 HINSTANCE
ScintillaWin::hInstance
= 0;
329 ScintillaWin::ScintillaWin(HWND hwnd
) {
331 lastKeyDownConsumed
= false;
333 capturedMouse
= false;
334 trackedMouseLeave
= false;
335 TrackMouseEventFn
= 0;
338 wheelDelta
= 0; // Wheel delta from roll
344 // There does not seem to be a real standard for indicating that the clipboard
345 // contains a rectangular selection, so copy Developer Studio.
346 cfColumnSelect
= static_cast<CLIPFORMAT
>(
347 ::RegisterClipboardFormat(TEXT("MSDEVColumnSelect")));
349 // Likewise for line-copy (copies a full line when no text is selected)
350 cfLineSelect
= static_cast<CLIPFORMAT
>(
351 ::RegisterClipboardFormat(TEXT("MSDEVLineSelect")));
367 renderTargetValid
= true;
370 keysAlwaysUnicode
= false;
372 caret
.period
= ::GetCaretBlinkTime();
373 if (caret
.period
< 0)
379 ScintillaWin::~ScintillaWin() {}
381 void ScintillaWin::Initialise() {
382 // Initialize COM. If the app has already done this it will have
383 // no effect. If the app hasnt, we really shouldnt ask them to call
384 // it just so this internal feature works.
385 hrOle
= ::OleInitialize(NULL
);
387 // Find TrackMouseEvent which is available on Windows > 95
388 HMODULE user32
= ::GetModuleHandle(TEXT("user32.dll"));
390 TrackMouseEventFn
= (TrackMouseEventSig
)::GetProcAddress(user32
, "TrackMouseEvent");
391 if (TrackMouseEventFn
== NULL
) {
392 // Windows 95 has an emulation in comctl32.dll:_TrackMouseEvent
393 HMODULE commctrl32
= ::LoadLibrary(TEXT("comctl32.dll"));
394 if (commctrl32
!= NULL
) {
395 TrackMouseEventFn
= (TrackMouseEventSig
)
396 ::GetProcAddress(commctrl32
, "_TrackMouseEvent");
401 void ScintillaWin::Finalise() {
402 ScintillaBase::Finalise();
406 ::RevokeDragDrop(MainHWND());
407 if (SUCCEEDED(hrOle
)) {
412 void ScintillaWin::EnsureRenderTarget() {
414 if (!renderTargetValid
) {
416 renderTargetValid
= true;
418 if (pD2DFactory
&& !pRenderTarget
) {
420 HWND hw
= MainHWND();
421 GetClientRect(hw
, &rc
);
423 D2D1_SIZE_U size
= D2D1::SizeU(rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
425 // Create a Direct2D render target.
427 pD2DFactory
->CreateHwndRenderTarget(
428 D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT
, D2D1::PixelFormat(), 96.0, 96.0),
429 D2D1::HwndRenderTargetProperties(hw
, size
),
432 pD2DFactory
->CreateHwndRenderTarget(
433 D2D1::RenderTargetProperties(
434 D2D1_RENDER_TARGET_TYPE_DEFAULT
,
435 D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM
, D2D1_ALPHA_MODE_PREMULTIPLIED
),
436 96.0f
, 96.0f
, D2D1_RENDER_TARGET_USAGE_NONE
, D2D1_FEATURE_LEVEL_DEFAULT
),
437 D2D1::HwndRenderTargetProperties(hw
, size
),
440 // Pixmaps were created to be compatible with previous render target so
441 // need to be recreated.
447 void ScintillaWin::DropRenderTarget() {
450 pRenderTarget
->Release();
456 HWND
ScintillaWin::MainHWND() {
457 return reinterpret_cast<HWND
>(wMain
.GetID());
460 bool ScintillaWin::DragThreshold(Point ptStart
, Point ptNow
) {
461 int xMove
= abs(ptStart
.x
- ptNow
.x
);
462 int yMove
= abs(ptStart
.y
- ptNow
.y
);
463 return (xMove
> ::GetSystemMetrics(SM_CXDRAG
)) ||
464 (yMove
> ::GetSystemMetrics(SM_CYDRAG
));
467 void ScintillaWin::StartDrag() {
468 inDragDrop
= ddDragging
;
470 dropWentOutside
= true;
471 IDataObject
*pDataObject
= reinterpret_cast<IDataObject
*>(&dob
);
472 IDropSource
*pDropSource
= reinterpret_cast<IDropSource
*>(&ds
);
473 //Platform::DebugPrintf("About to DoDragDrop %x %x\n", pDataObject, pDropSource);
474 HRESULT hr
= ::DoDragDrop(
477 DROPEFFECT_COPY
| DROPEFFECT_MOVE
, &dwEffect
);
478 //Platform::DebugPrintf("DoDragDrop = %x\n", hr);
480 if ((hr
== DRAGDROP_S_DROP
) && (dwEffect
== DROPEFFECT_MOVE
) && dropWentOutside
) {
481 // Remove dragged out text
486 SetDragPosition(SelectionPosition(invalidPosition
));
489 // Avoid warnings everywhere for old style casts by concentrating them here
490 static WORD
LoWord(DWORD l
) {
494 static WORD
HiWord(DWORD l
) {
498 static int InputCodePage() {
499 HKL inputLocale
= ::GetKeyboardLayout(0);
500 LANGID inputLang
= LOWORD(inputLocale
);
502 int res
= ::GetLocaleInfoA(MAKELCID(inputLang
, SORT_DEFAULT
),
503 LOCALE_IDEFAULTANSICODEPAGE
, sCodePage
, sizeof(sCodePage
));
506 return atoi(sCodePage
);
510 static const int VK_OEM_2
=0xbf;
511 static const int VK_OEM_3
=0xc0;
512 static const int VK_OEM_4
=0xdb;
513 static const int VK_OEM_5
=0xdc;
514 static const int VK_OEM_6
=0xdd;
517 /** Map the key codes to their equivalent SCK_ form. */
518 static int KeyTranslate(int keyIn
) {
519 //PLATFORM_ASSERT(!keyIn);
521 case VK_DOWN
: return SCK_DOWN
;
522 case VK_UP
: return SCK_UP
;
523 case VK_LEFT
: return SCK_LEFT
;
524 case VK_RIGHT
: return SCK_RIGHT
;
525 case VK_HOME
: return SCK_HOME
;
526 case VK_END
: return SCK_END
;
527 case VK_PRIOR
: return SCK_PRIOR
;
528 case VK_NEXT
: return SCK_NEXT
;
529 case VK_DELETE
: return SCK_DELETE
;
530 case VK_INSERT
: return SCK_INSERT
;
531 case VK_ESCAPE
: return SCK_ESCAPE
;
532 case VK_BACK
: return SCK_BACK
;
533 case VK_TAB
: return SCK_TAB
;
534 case VK_RETURN
: return SCK_RETURN
;
535 case VK_ADD
: return SCK_ADD
;
536 case VK_SUBTRACT
: return SCK_SUBTRACT
;
537 case VK_DIVIDE
: return SCK_DIVIDE
;
538 case VK_LWIN
: return SCK_WIN
;
539 case VK_RWIN
: return SCK_RWIN
;
540 case VK_APPS
: return SCK_MENU
;
541 case VK_OEM_2
: return '/';
542 case VK_OEM_3
: return '`';
543 case VK_OEM_4
: return '[';
544 case VK_OEM_5
: return '\\';
545 case VK_OEM_6
: return ']';
546 default: return keyIn
;
550 LRESULT
ScintillaWin::WndPaint(uptr_t wParam
) {
553 // Redirect assertions to debug output and save current state
554 bool assertsPopup
= Platform::ShowAssertionPopUps(false);
555 paintState
= painting
;
559 bool IsOcxCtrl
= (wParam
!= 0); // if wParam != 0, it contains
560 // a PAINSTRUCT* from the OCX
561 // Removed since this interferes with reporting other assertions as it occurs repeatedly
562 //PLATFORM_ASSERT(hRgnUpdate == NULL);
563 hRgnUpdate
= ::CreateRectRgn(0, 0, 0, 0);
565 pps
= reinterpret_cast<PAINTSTRUCT
*>(wParam
);
567 ::GetUpdateRgn(MainHWND(), hRgnUpdate
, FALSE
);
569 ::BeginPaint(MainHWND(), pps
);
571 if (technology
== SC_TECHNOLOGY_DEFAULT
) {
572 AutoSurface
surfaceWindow(pps
->hdc
, this);
574 rcPaint
= PRectangle(pps
->rcPaint
.left
, pps
->rcPaint
.top
, pps
->rcPaint
.right
, pps
->rcPaint
.bottom
);
575 PRectangle rcClient
= GetClientRectangle();
576 paintingAllText
= rcPaint
.Contains(rcClient
);
577 Paint(surfaceWindow
, rcPaint
);
578 surfaceWindow
->Release();
582 EnsureRenderTarget();
583 AutoSurface
surfaceWindow(pRenderTarget
, this);
585 pRenderTarget
->BeginDraw();
586 rcPaint
= PRectangle(pps
->rcPaint
.left
, pps
->rcPaint
.top
, pps
->rcPaint
.right
, pps
->rcPaint
.bottom
);
587 PRectangle rcClient
= GetClientRectangle();
588 paintingAllText
= rcPaint
.Contains(rcClient
);
589 if (paintingAllText
) {
590 //Platform::DebugPrintf("Performing full text paint\n");
592 //Platform::DebugPrintf("Performing partial paint %d .. %d\n", rcPaint.top, rcPaint.bottom);
594 Paint(surfaceWindow
, rcPaint
);
595 surfaceWindow
->Release();
596 HRESULT hr
= pRenderTarget
->EndDraw();
597 if (hr
== D2DERR_RECREATE_TARGET
) {
604 ::DeleteRgn(hRgnUpdate
);
609 ::EndPaint(MainHWND(), pps
);
610 if (paintState
== paintAbandoned
) {
611 // Painting area was insufficient to cover new styling or brace highlight positions
614 paintState
= notPainting
;
616 // Restore debug output state
617 Platform::ShowAssertionPopUps(assertsPopup
);
619 //Platform::DebugPrintf("Paint took %g\n", et.Duration());
623 sptr_t
ScintillaWin::HandleComposition(uptr_t wParam
, sptr_t lParam
) {
625 // Digital Mars compiler does not include Imm library
628 if (lParam
& GCS_RESULTSTR
) {
629 HIMC hIMC
= ::ImmGetContext(MainHWND());
631 const int maxLenInputIME
= 200;
632 wchar_t wcs
[maxLenInputIME
];
633 LONG bytes
= ::ImmGetCompositionStringW(hIMC
,
634 GCS_RESULTSTR
, wcs
, (maxLenInputIME
-1)*2);
635 int wides
= bytes
/ 2;
636 if (IsUnicodeMode()) {
637 char utfval
[maxLenInputIME
* 3];
638 unsigned int len
= UTF8Length(wcs
, wides
);
639 UTF8FromUTF16(wcs
, wides
, utfval
, len
);
641 AddCharUTF(utfval
, len
);
643 char dbcsval
[maxLenInputIME
* 2];
644 int size
= ::WideCharToMultiByte(InputCodePage(),
645 0, wcs
, wides
, dbcsval
, sizeof(dbcsval
) - 1, 0, 0);
646 for (int i
=0; i
<size
; i
++) {
650 // Set new position after converted
651 Point pos
= PointMainCaret();
652 COMPOSITIONFORM CompForm
;
653 CompForm
.dwStyle
= CFS_POINT
;
654 CompForm
.ptCurrentPos
.x
= pos
.x
;
655 CompForm
.ptCurrentPos
.y
= pos
.y
;
656 ::ImmSetCompositionWindow(hIMC
, &CompForm
);
657 ::ImmReleaseContext(MainHWND(), hIMC
);
661 return ::DefWindowProc(MainHWND(), WM_IME_COMPOSITION
, wParam
, lParam
);
665 // Translate message IDs from WM_* and EM_* to SCI_* so can partly emulate Windows Edit control
666 static unsigned int SciMessageFromEM(unsigned int iMessage
) {
668 case EM_CANPASTE
: return SCI_CANPASTE
;
669 case EM_CANUNDO
: return SCI_CANUNDO
;
670 case EM_EMPTYUNDOBUFFER
: return SCI_EMPTYUNDOBUFFER
;
671 case EM_FINDTEXTEX
: return SCI_FINDTEXT
;
672 case EM_FORMATRANGE
: return SCI_FORMATRANGE
;
673 case EM_GETFIRSTVISIBLELINE
: return SCI_GETFIRSTVISIBLELINE
;
674 case EM_GETLINECOUNT
: return SCI_GETLINECOUNT
;
675 case EM_GETSELTEXT
: return SCI_GETSELTEXT
;
676 case EM_GETTEXTRANGE
: return SCI_GETTEXTRANGE
;
677 case EM_HIDESELECTION
: return SCI_HIDESELECTION
;
678 case EM_LINEINDEX
: return SCI_POSITIONFROMLINE
;
679 case EM_LINESCROLL
: return SCI_LINESCROLL
;
680 case EM_REPLACESEL
: return SCI_REPLACESEL
;
681 case EM_SCROLLCARET
: return SCI_SCROLLCARET
;
682 case EM_SETREADONLY
: return SCI_SETREADONLY
;
683 case WM_CLEAR
: return SCI_CLEAR
;
684 case WM_COPY
: return SCI_COPY
;
685 case WM_CUT
: return SCI_CUT
;
686 case WM_GETTEXT
: return SCI_GETTEXT
;
687 case WM_SETTEXT
: return SCI_SETTEXT
;
688 case WM_GETTEXTLENGTH
: return SCI_GETTEXTLENGTH
;
689 case WM_PASTE
: return SCI_PASTE
;
690 case WM_UNDO
: return SCI_UNDO
;
695 static UINT
CodePageFromCharSet(DWORD characterSet
, UINT documentCodePage
) {
696 if (documentCodePage
== SC_CP_UTF8
) {
697 // The system calls here are a little slow so avoid if known case.
700 CHARSETINFO ci
= { 0, 0, { { 0, 0, 0, 0 }, { 0, 0 } } };
701 BOOL bci
= ::TranslateCharsetInfo((DWORD
*)characterSet
,
702 &ci
, TCI_SRCCHARSET
);
708 cp
= documentCodePage
;
711 if (!IsValidCodePage(cp
) && !GetCPInfo(cp
, &cpi
))
717 UINT
ScintillaWin::CodePageOfDocument() {
718 return CodePageFromCharSet(vs
.styles
[STYLE_DEFAULT
].characterSet
, pdoc
->dbcsCodePage
);
721 sptr_t
ScintillaWin::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
723 //Platform::DebugPrintf("S M:%x WP:%x L:%x\n", iMessage, wParam, lParam);
724 iMessage
= SciMessageFromEM(iMessage
);
728 ctrlID
= ::GetDlgCtrlID(reinterpret_cast<HWND
>(wMain
.GetID()));
729 // Get Intellimouse scroll line parameters
730 GetIntelliMouseParameters();
731 ::RegisterDragDrop(MainHWND(), reinterpret_cast<IDropTarget
*>(&dt
));
735 Command(LoWord(wParam
));
739 return WndPaint(wParam
);
741 case WM_PRINTCLIENT
: {
742 HDC hdc
= reinterpret_cast<HDC
>(wParam
);
743 if (!IsCompatibleDC(hdc
)) {
744 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
751 ScrollMessage(wParam
);
755 HorizontalScrollMessage(wParam
);
760 if (paintState
== notPainting
) {
763 renderTargetValid
= false;
766 //Platform::DebugPrintf("Scintilla WM_SIZE %d %d\n", LoWord(lParam), HiWord(lParam));
772 // if autocomplete list active then send mousewheel message to it
774 HWND hWnd
= reinterpret_cast<HWND
>(ac
.lb
->GetID());
775 ::SendMessage(hWnd
, iMessage
, wParam
, lParam
);
779 // Don't handle datazoom.
780 // (A good idea for datazoom would be to "fold" or "unfold" details.
781 // i.e. if datazoomed out only class structures are visible, when datazooming in the control
782 // structures appear, then eventually the individual statements...)
783 if (wParam
& MK_SHIFT
) {
784 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
787 // Either SCROLL or ZOOM. We handle the wheel steppings calculation
788 wheelDelta
-= static_cast<short>(HiWord(wParam
));
789 if (abs(wheelDelta
) >= WHEEL_DELTA
&& linesPerScroll
> 0) {
790 int linesToScroll
= linesPerScroll
;
791 if (linesPerScroll
== WHEEL_PAGESCROLL
)
792 linesToScroll
= LinesOnScreen() - 1;
793 if (linesToScroll
== 0) {
796 linesToScroll
*= (wheelDelta
/ WHEEL_DELTA
);
798 wheelDelta
= wheelDelta
% WHEEL_DELTA
;
800 wheelDelta
= - (-wheelDelta
% WHEEL_DELTA
);
802 if (wParam
& MK_CONTROL
) {
803 // Zoom! We play with the font sizes in the styles.
804 // Number of steps/line is ignored, we just care if sizing up or down
805 if (linesToScroll
< 0) {
806 KeyCommand(SCI_ZOOMIN
);
808 KeyCommand(SCI_ZOOMOUT
);
812 ScrollTo(topLine
+ linesToScroll
);
818 if (wParam
== standardTimerID
&& timer
.ticking
) {
820 } else if (wParam
== idleTimerID
&& idler
.state
) {
821 SendMessage(MainHWND(), SC_WIN_IDLE
, 0, 1);
828 // wParam=dwTickCountInitial, or 0 to initialize. lParam=bSkipUserInputTest
830 if (lParam
|| (WAIT_TIMEOUT
== MsgWaitForMultipleObjects(0, 0, 0, 0, QS_INPUT
|QS_HOTKEY
))) {
832 // User input was given priority above, but all events do get a turn. Other
833 // messages, notifications, etc. will get interleaved with the idle messages.
835 // However, some things like WM_PAINT are a lower priority, and will not fire
836 // when there's a message posted. So, several times a second, we stop and let
837 // the low priority events have a turn (after which the timer will fire again).
839 DWORD dwCurrent
= GetTickCount();
840 DWORD dwStart
= wParam
? wParam
: dwCurrent
;
841 const DWORD maxWorkTime
= 50;
843 if (dwCurrent
>= dwStart
&& dwCurrent
> maxWorkTime
&& dwCurrent
- maxWorkTime
< dwStart
)
844 PostMessage(MainHWND(), SC_WIN_IDLE
, dwStart
, 0);
852 case WM_GETMINMAXINFO
:
853 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
855 case WM_LBUTTONDOWN
: {
857 // Digital Mars compiler does not include Imm library
858 // For IME, set the composition string as the result string.
859 HIMC hIMC
= ::ImmGetContext(MainHWND());
860 ::ImmNotifyIME(hIMC
, NI_COMPOSITIONSTR
, CPS_COMPLETE
, 0);
861 ::ImmReleaseContext(MainHWND(), hIMC
);
864 //Platform::DebugPrintf("Buttdown %d %x %x %x %x %x\n",iMessage, wParam, lParam,
865 // Platform::IsKeyDown(VK_SHIFT),
866 // Platform::IsKeyDown(VK_CONTROL),
867 // Platform::IsKeyDown(VK_MENU));
868 ::SetFocus(MainHWND());
869 ButtonDown(Point::FromLong(lParam
), ::GetMessageTime(),
870 (wParam
& MK_SHIFT
) != 0,
871 (wParam
& MK_CONTROL
) != 0,
872 Platform::IsKeyDown(VK_MENU
));
877 SetTrackMouseLeaveEvent(true);
878 ButtonMove(Point::FromLong(lParam
));
882 SetTrackMouseLeaveEvent(false);
884 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
887 ButtonUp(Point::FromLong(lParam
),
889 (wParam
& MK_CONTROL
) != 0);
893 ::SetFocus(MainHWND());
894 if (!PointInSelection(Point::FromLong(lParam
))) {
896 SetEmptySelection(PositionFromLocation(Point::FromLong(lParam
)));
901 if (LoWord(lParam
) == HTCLIENT
) {
902 if (inDragDrop
== ddDragging
) {
903 DisplayCursor(Window::cursorUp
);
905 // Display regular (drag) cursor over selection
907 if (0 != ::GetCursorPos(&pt
)) {
908 ::ScreenToClient(MainHWND(), &pt
);
909 if (PointInSelMargin(Point(pt
.x
, pt
.y
))) {
910 DisplayCursor(GetMarginCursor(Point(pt
.x
, pt
.y
)));
911 } else if (PointInSelection(Point(pt
.x
, pt
.y
)) && !SelectionEmpty()) {
912 DisplayCursor(Window::cursorArrow
);
913 } else if (PointIsHotspot(Point(pt
.x
, pt
.y
))) {
914 DisplayCursor(Window::cursorHand
);
916 DisplayCursor(Window::cursorText
);
922 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
926 if (((wParam
>= 128) || !iscntrl(wParam
)) || !lastKeyDownConsumed
) {
927 if (::IsWindowUnicode(MainHWND()) || keysAlwaysUnicode
) {
928 wchar_t wcs
[2] = {static_cast<wchar_t>(wParam
), 0};
929 if (IsUnicodeMode()) {
930 // For a wide character version of the window:
932 unsigned int len
= UTF8Length(wcs
, 1);
933 UTF8FromUTF16(wcs
, 1, utfval
, len
);
934 AddCharUTF(utfval
, len
);
936 UINT cpDest
= CodePageOfDocument();
938 int size
= ::WideCharToMultiByte(cpDest
,
939 0, wcs
, 1, inBufferCP
, sizeof(inBufferCP
) - 1, 0, 0);
940 inBufferCP
[size
] = '\0';
941 AddCharUTF(inBufferCP
, size
);
944 if (IsUnicodeMode()) {
945 AddCharBytes('\0', LOBYTE(wParam
));
947 AddChar(LOBYTE(wParam
));
954 if (wParam
== UNICODE_NOCHAR
) {
955 return IsUnicodeMode() ? 1 : 0;
956 } else if (lastKeyDownConsumed
) {
959 if (IsUnicodeMode()) {
961 wchar_t wcs
[2] = {static_cast<wchar_t>(wParam
), 0};
962 unsigned int len
= UTF8Length(wcs
, 1);
963 UTF8FromUTF16(wcs
, 1, utfval
, len
);
964 AddCharUTF(utfval
, len
);
973 //Platform::DebugPrintf("S keydown %d %x %x %x %x\n",iMessage, wParam, lParam, ::IsKeyDown(VK_SHIFT), ::IsKeyDown(VK_CONTROL));
974 lastKeyDownConsumed
= false;
975 int ret
= KeyDown(KeyTranslate(wParam
),
976 Platform::IsKeyDown(VK_SHIFT
),
977 Platform::IsKeyDown(VK_CONTROL
),
978 Platform::IsKeyDown(VK_MENU
),
979 &lastKeyDownConsumed
);
980 if (!ret
&& !lastKeyDownConsumed
) {
981 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
987 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
990 //Platform::DebugPrintf("S keyup %d %x %x\n",iMessage, wParam, lParam);
991 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
993 case WM_SETTINGCHANGE
:
994 //Platform::DebugPrintf("Setting Changed\n");
995 InvalidateStyleData();
996 // Get Intellimouse scroll line parameters
997 GetIntelliMouseParameters();
1001 return DLGC_HASSETSEL
| DLGC_WANTALLKEYS
;
1003 case WM_KILLFOCUS
: {
1004 HWND wOther
= reinterpret_cast<HWND
>(wParam
);
1005 HWND wThis
= MainHWND();
1006 HWND wCT
= reinterpret_cast<HWND
>(ct
.wCallTip
.GetID());
1008 !(::IsChild(wThis
, wOther
) || (wOther
== wCT
))) {
1009 SetFocusState(false);
1010 DestroySystemCaret();
1016 SetFocusState(true);
1017 DestroySystemCaret();
1018 CreateSystemCaret();
1021 case WM_SYSCOLORCHANGE
:
1022 //Platform::DebugPrintf("Setting Changed\n");
1023 InvalidateStyleData();
1026 case WM_IME_STARTCOMPOSITION
: // dbcs
1027 ImeStartComposition();
1028 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1030 case WM_IME_ENDCOMPOSITION
: // dbcs
1031 ImeEndComposition();
1032 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1034 case WM_IME_COMPOSITION
:
1035 return HandleComposition(wParam
, lParam
);
1038 AddCharBytes(HIBYTE(wParam
), LOBYTE(wParam
));
1042 case WM_CONTEXTMENU
:
1043 if (displayPopupMenu
) {
1044 Point pt
= Point::FromLong(lParam
);
1045 if ((pt
.x
== -1) && (pt
.y
== -1)) {
1046 // Caused by keyboard so display menu near caret
1047 pt
= PointMainCaret();
1048 POINT spt
= {static_cast<int>(pt
.x
), static_cast<int>(pt
.y
)};
1049 ::ClientToScreen(MainHWND(), &spt
);
1050 pt
= Point(spt
.x
, spt
.y
);
1055 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1057 case WM_INPUTLANGCHANGE
:
1058 //::SetThreadLocale(LOWORD(lParam));
1059 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1061 case WM_INPUTLANGCHANGEREQUEST
:
1062 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1065 return 1; // Avoid any background erasure as whole window painted.
1067 case WM_CAPTURECHANGED
:
1068 capturedMouse
= false;
1071 // These are not handled in Scintilla and its faster to dispatch them here.
1072 // Also moves time out to here so profile doesn't count lots of empty message calls.
1075 case WM_MOUSEACTIVATE
:
1079 case WM_NCMOUSEMOVE
:
1080 case WM_NCLBUTTONDOWN
:
1081 case WM_IME_SETCONTEXT
:
1084 case WM_WINDOWPOSCHANGING
:
1085 case WM_WINDOWPOSCHANGED
:
1086 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1088 case EM_LINEFROMCHAR
:
1089 if (static_cast<int>(wParam
) < 0) {
1090 wParam
= SelectionStart().Position();
1092 return pdoc
->LineFromPosition(wParam
);
1094 case EM_EXLINEFROMCHAR
:
1095 return pdoc
->LineFromPosition(lParam
);
1099 *reinterpret_cast<int *>(wParam
) = SelectionStart().Position();
1102 *reinterpret_cast<int *>(lParam
) = SelectionEnd().Position();
1104 return MAKELONG(SelectionStart().Position(), SelectionEnd().Position());
1110 Sci_CharacterRange
*pCR
= reinterpret_cast<Sci_CharacterRange
*>(lParam
);
1111 pCR
->cpMin
= SelectionStart().Position();
1112 pCR
->cpMax
= SelectionEnd().Position();
1117 int nStart
= static_cast<int>(wParam
);
1118 int nEnd
= static_cast<int>(lParam
);
1119 if (nStart
== 0 && nEnd
== -1) {
1120 nEnd
= pdoc
->Length();
1123 nStart
= nEnd
; // Remove selection
1125 if (nStart
> nEnd
) {
1126 SetSelection(nEnd
, nStart
);
1128 SetSelection(nStart
, nEnd
);
1130 EnsureCaretVisible();
1138 Sci_CharacterRange
*pCR
= reinterpret_cast<Sci_CharacterRange
*>(lParam
);
1139 sel
.selType
= Selection::selStream
;
1140 if (pCR
->cpMin
== 0 && pCR
->cpMax
== -1) {
1141 SetSelection(pCR
->cpMin
, pdoc
->Length());
1143 SetSelection(pCR
->cpMin
, pCR
->cpMax
);
1145 EnsureCaretVisible();
1146 return pdoc
->LineFromPosition(SelectionStart().Position());
1149 case SCI_GETDIRECTFUNCTION
:
1150 return reinterpret_cast<sptr_t
>(DirectFunction
);
1152 case SCI_GETDIRECTPOINTER
:
1153 return reinterpret_cast<sptr_t
>(this);
1156 ::SetFocus(MainHWND());
1159 case SCI_SETKEYSUNICODE
:
1160 keysAlwaysUnicode
= wParam
!= 0;
1163 case SCI_GETKEYSUNICODE
:
1164 return keysAlwaysUnicode
;
1166 case SCI_SETTECHNOLOGY
:
1167 if ((wParam
== SC_TECHNOLOGY_DEFAULT
) || (wParam
== SC_TECHNOLOGY_DIRECTWRITE
)) {
1168 if (technology
!= static_cast<int>(wParam
)) {
1169 if (static_cast<int>(wParam
) == SC_TECHNOLOGY_DIRECTWRITE
) {
1170 #if defined(USE_D2D)
1172 // Failed to load Direct2D or DirectWrite so no effect
1178 technology
= wParam
;
1179 // Invalidate all cached information including layout.
1181 InvalidateStyleRedraw();
1187 case SCI_LOADLEXERLIBRARY
:
1188 LexerManager::GetInstance()->Load(reinterpret_cast<const char *>(lParam
));
1193 return ScintillaBase::WndProc(iMessage
, wParam
, lParam
);
1195 } catch (std::bad_alloc
&) {
1196 errorStatus
= SC_STATUS_BADALLOC
;
1198 errorStatus
= SC_STATUS_FAILURE
;
1203 bool ScintillaWin::ValidCodePage(int codePage
) const {
1204 return codePage
== 0 || codePage
== SC_CP_UTF8
||
1205 codePage
== 932 || codePage
== 936 || codePage
== 949 ||
1206 codePage
== 950 || codePage
== 1361;
1209 sptr_t
ScintillaWin::DefWndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
1210 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1213 void ScintillaWin::SetTicking(bool on
) {
1214 if (timer
.ticking
!= on
) {
1216 if (timer
.ticking
) {
1217 timer
.tickerID
= ::SetTimer(MainHWND(), standardTimerID
, timer
.tickSize
, NULL
)
1218 ? reinterpret_cast<TickerID
>(standardTimerID
) : 0;
1220 ::KillTimer(MainHWND(), reinterpret_cast<uptr_t
>(timer
.tickerID
));
1224 timer
.ticksToWait
= caret
.period
;
1227 bool ScintillaWin::SetIdle(bool on
) {
1228 // On Win32 the Idler is implemented as a Timer on the Scintilla window. This
1229 // takes advantage of the fact that WM_TIMER messages are very low priority,
1230 // and are only posted when the message queue is empty, i.e. during idle time.
1231 if (idler
.state
!= on
) {
1233 idler
.idlerID
= ::SetTimer(MainHWND(), idleTimerID
, 10, NULL
)
1234 ? reinterpret_cast<IdlerID
>(idleTimerID
) : 0;
1236 ::KillTimer(MainHWND(), reinterpret_cast<uptr_t
>(idler
.idlerID
));
1239 idler
.state
= idler
.idlerID
!= 0;
1244 void ScintillaWin::SetMouseCapture(bool on
) {
1245 if (mouseDownCaptures
) {
1247 ::SetCapture(MainHWND());
1255 bool ScintillaWin::HaveMouseCapture() {
1256 // Cannot just see if GetCapture is this window as the scroll bar also sets capture for the window
1257 return capturedMouse
;
1258 //return capturedMouse && (::GetCapture() == MainHWND());
1261 void ScintillaWin::SetTrackMouseLeaveEvent(bool on
) {
1262 if (on
&& TrackMouseEventFn
&& !trackedMouseLeave
) {
1263 TRACKMOUSEEVENT tme
;
1264 tme
.cbSize
= sizeof(tme
);
1265 tme
.dwFlags
= TME_LEAVE
;
1266 tme
.hwndTrack
= MainHWND();
1267 TrackMouseEventFn(&tme
);
1269 trackedMouseLeave
= on
;
1272 bool ScintillaWin::PaintContains(PRectangle rc
) {
1273 bool contains
= true;
1274 if ((paintState
== painting
) && (!rc
.Empty())) {
1275 if (!rcPaint
.Contains(rc
)) {
1278 // In bounding rectangle so check more accurately using region
1279 HRGN hRgnRange
= ::CreateRectRgn(rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
1281 HRGN hRgnDest
= ::CreateRectRgn(0, 0, 0, 0);
1283 int combination
= ::CombineRgn(hRgnDest
, hRgnRange
, hRgnUpdate
, RGN_DIFF
);
1284 if (combination
!= NULLREGION
) {
1287 ::DeleteRgn(hRgnDest
);
1289 ::DeleteRgn(hRgnRange
);
1296 void ScintillaWin::ScrollText(int /* linesToMove */) {
1297 //Platform::DebugPrintf("ScintillaWin::ScrollText %d\n", linesToMove);
1298 //::ScrollWindow(MainHWND(), 0,
1299 // vs.lineHeight * linesToMove, 0, 0);
1300 //::UpdateWindow(MainHWND());
1304 void ScintillaWin::UpdateSystemCaret() {
1306 if (HasCaretSizeChanged()) {
1307 DestroySystemCaret();
1308 CreateSystemCaret();
1310 Point pos
= PointMainCaret();
1311 ::SetCaretPos(pos
.x
, pos
.y
);
1315 int ScintillaWin::SetScrollInfo(int nBar
, LPCSCROLLINFO lpsi
, BOOL bRedraw
) {
1316 return ::SetScrollInfo(MainHWND(), nBar
, lpsi
, bRedraw
);
1319 bool ScintillaWin::GetScrollInfo(int nBar
, LPSCROLLINFO lpsi
) {
1320 return ::GetScrollInfo(MainHWND(), nBar
, lpsi
) ? true : false;
1323 // Change the scroll position but avoid repaint if changing to same value
1324 void ScintillaWin::ChangeScrollPos(int barType
, int pos
) {
1326 sizeof(sci
), 0, 0, 0, 0, 0, 0
1328 sci
.fMask
= SIF_POS
;
1329 GetScrollInfo(barType
, &sci
);
1330 if (sci
.nPos
!= pos
) {
1333 SetScrollInfo(barType
, &sci
, TRUE
);
1337 void ScintillaWin::SetVerticalScrollPos() {
1338 ChangeScrollPos(SB_VERT
, topLine
);
1341 void ScintillaWin::SetHorizontalScrollPos() {
1342 ChangeScrollPos(SB_HORZ
, xOffset
);
1345 bool ScintillaWin::ModifyScrollBars(int nMax
, int nPage
) {
1346 bool modified
= false;
1348 sizeof(sci
), 0, 0, 0, 0, 0, 0
1350 sci
.fMask
= SIF_PAGE
| SIF_RANGE
;
1351 GetScrollInfo(SB_VERT
, &sci
);
1352 int vertEndPreferred
= nMax
;
1353 if (!verticalScrollBarVisible
)
1354 nPage
= vertEndPreferred
+ 1;
1355 if ((sci
.nMin
!= 0) ||
1356 (sci
.nMax
!= vertEndPreferred
) ||
1357 (sci
.nPage
!= static_cast<unsigned int>(nPage
)) ||
1359 sci
.fMask
= SIF_PAGE
| SIF_RANGE
;
1361 sci
.nMax
= vertEndPreferred
;
1365 SetScrollInfo(SB_VERT
, &sci
, TRUE
);
1369 PRectangle rcText
= GetTextRectangle();
1370 int horizEndPreferred
= scrollWidth
;
1371 if (horizEndPreferred
< 0)
1372 horizEndPreferred
= 0;
1373 unsigned int pageWidth
= rcText
.Width();
1374 if (!horizontalScrollBarVisible
|| (wrapState
!= eWrapNone
))
1375 pageWidth
= horizEndPreferred
+ 1;
1376 sci
.fMask
= SIF_PAGE
| SIF_RANGE
;
1377 GetScrollInfo(SB_HORZ
, &sci
);
1378 if ((sci
.nMin
!= 0) ||
1379 (sci
.nMax
!= horizEndPreferred
) ||
1380 (sci
.nPage
!= pageWidth
) ||
1382 sci
.fMask
= SIF_PAGE
| SIF_RANGE
;
1384 sci
.nMax
= horizEndPreferred
;
1385 sci
.nPage
= pageWidth
;
1388 SetScrollInfo(SB_HORZ
, &sci
, TRUE
);
1390 if (scrollWidth
< static_cast<int>(pageWidth
)) {
1391 HorizontalScrollTo(0);
1397 void ScintillaWin::NotifyChange() {
1398 ::SendMessage(::GetParent(MainHWND()), WM_COMMAND
,
1399 MAKELONG(GetCtrlID(), SCEN_CHANGE
),
1400 reinterpret_cast<LPARAM
>(MainHWND()));
1403 void ScintillaWin::NotifyFocus(bool focus
) {
1404 ::SendMessage(::GetParent(MainHWND()), WM_COMMAND
,
1405 MAKELONG(GetCtrlID(), focus
? SCEN_SETFOCUS
: SCEN_KILLFOCUS
),
1406 reinterpret_cast<LPARAM
>(MainHWND()));
1409 void ScintillaWin::SetCtrlID(int identifier
) {
1410 ::SetWindowID(reinterpret_cast<HWND
>(wMain
.GetID()), identifier
);
1413 int ScintillaWin::GetCtrlID() {
1414 return ::GetDlgCtrlID(reinterpret_cast<HWND
>(wMain
.GetID()));
1417 void ScintillaWin::NotifyParent(SCNotification scn
) {
1418 scn
.nmhdr
.hwndFrom
= MainHWND();
1419 scn
.nmhdr
.idFrom
= GetCtrlID();
1420 ::SendMessage(::GetParent(MainHWND()), WM_NOTIFY
,
1421 GetCtrlID(), reinterpret_cast<LPARAM
>(&scn
));
1424 void ScintillaWin::NotifyParent(SCNotification
* scn
) {
1425 scn
->nmhdr
.hwndFrom
= MainHWND();
1426 scn
->nmhdr
.idFrom
= GetCtrlID();
1427 ::SendMessage(::GetParent(MainHWND()), WM_NOTIFY
,
1428 GetCtrlID(), reinterpret_cast<LPARAM
>(scn
));
1431 void ScintillaWin::NotifyDoubleClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
1432 //Platform::DebugPrintf("ScintillaWin Double click 0\n");
1433 ScintillaBase::NotifyDoubleClick(pt
, shift
, ctrl
, alt
);
1434 // Send myself a WM_LBUTTONDBLCLK, so the container can handle it too.
1435 ::SendMessage(MainHWND(),
1437 shift
? MK_SHIFT
: 0,
1438 MAKELPARAM(pt
.x
, pt
.y
));
1441 class CaseFolderUTF8
: public CaseFolderTable
{
1442 // Allocate the expandable storage here so that it does not need to be reallocated
1443 // for each call to Fold.
1444 std::vector
<wchar_t> utf16Mixed
;
1445 std::vector
<wchar_t> utf16Folded
;
1450 virtual size_t Fold(char *folded
, size_t sizeFolded
, const char *mixed
, size_t lenMixed
) {
1451 if ((lenMixed
== 1) && (sizeFolded
> 0)) {
1452 folded
[0] = mapping
[static_cast<unsigned char>(mixed
[0])];
1455 if (lenMixed
> utf16Mixed
.size()) {
1456 utf16Mixed
.resize(lenMixed
+ 8);
1458 size_t nUtf16Mixed
= ::MultiByteToWideChar(65001, 0, mixed
,
1459 static_cast<int>(lenMixed
),
1461 static_cast<int>(utf16Mixed
.size()));
1463 if (nUtf16Mixed
== 0) {
1464 // Failed to convert -> bad UTF-8
1469 if (nUtf16Mixed
* 4 > utf16Folded
.size()) { // Maximum folding expansion factor of 4
1470 utf16Folded
.resize(nUtf16Mixed
* 4 + 8);
1472 int lenFlat
= ::LCMapStringW(LOCALE_SYSTEM_DEFAULT
,
1473 LCMAP_LINGUISTIC_CASING
| LCMAP_LOWERCASE
,
1475 static_cast<int>(nUtf16Mixed
),
1477 static_cast<int>(utf16Folded
.size()));
1479 size_t lenOut
= UTF8Length(&utf16Folded
[0], lenFlat
);
1480 if (lenOut
< sizeFolded
) {
1481 UTF8FromUTF16(&utf16Folded
[0], lenFlat
, folded
, static_cast<int>(lenOut
));
1490 class CaseFolderDBCS
: public CaseFolderTable
{
1491 // Allocate the expandable storage here so that it does not need to be reallocated
1492 // for each call to Fold.
1493 std::vector
<wchar_t> utf16Mixed
;
1494 std::vector
<wchar_t> utf16Folded
;
1497 CaseFolderDBCS(UINT cp_
) : cp(cp_
) {
1500 virtual size_t Fold(char *folded
, size_t sizeFolded
, const char *mixed
, size_t lenMixed
) {
1501 if ((lenMixed
== 1) && (sizeFolded
> 0)) {
1502 folded
[0] = mapping
[static_cast<unsigned char>(mixed
[0])];
1505 if (lenMixed
> utf16Mixed
.size()) {
1506 utf16Mixed
.resize(lenMixed
+ 8);
1508 size_t nUtf16Mixed
= ::MultiByteToWideChar(cp
, 0, mixed
,
1509 static_cast<int>(lenMixed
),
1511 static_cast<int>(utf16Mixed
.size()));
1513 if (nUtf16Mixed
== 0) {
1514 // Failed to convert -> bad input
1519 if (nUtf16Mixed
* 4 > utf16Folded
.size()) { // Maximum folding expansion factor of 4
1520 utf16Folded
.resize(nUtf16Mixed
* 4 + 8);
1522 int lenFlat
= ::LCMapStringW(LOCALE_SYSTEM_DEFAULT
,
1523 LCMAP_LINGUISTIC_CASING
| LCMAP_LOWERCASE
,
1525 static_cast<int>(nUtf16Mixed
),
1527 static_cast<int>(utf16Folded
.size()));
1529 size_t lenOut
= ::WideCharToMultiByte(cp
, 0,
1530 &utf16Folded
[0], lenFlat
,
1533 if (lenOut
< sizeFolded
) {
1534 ::WideCharToMultiByte(cp
, 0,
1535 &utf16Folded
[0], lenFlat
,
1536 folded
, static_cast<int>(lenOut
), NULL
, 0);
1545 CaseFolder
*ScintillaWin::CaseFolderForEncoding() {
1546 UINT cpDest
= CodePageOfDocument();
1547 if (cpDest
== SC_CP_UTF8
) {
1548 return new CaseFolderUTF8();
1550 if (pdoc
->dbcsCodePage
== 0) {
1551 CaseFolderTable
*pcf
= new CaseFolderTable();
1552 pcf
->StandardASCII();
1553 // Only for single byte encodings
1554 UINT cpDoc
= CodePageOfDocument();
1555 for (int i
=0x80; i
<0x100; i
++) {
1556 char sCharacter
[2] = "A";
1557 sCharacter
[0] = static_cast<char>(i
);
1558 wchar_t wCharacter
[20];
1559 unsigned int lengthUTF16
= ::MultiByteToWideChar(cpDoc
, 0, sCharacter
, 1,
1560 wCharacter
, sizeof(wCharacter
)/sizeof(wCharacter
[0]));
1561 if (lengthUTF16
== 1) {
1563 int charsConverted
= ::LCMapStringW(LOCALE_SYSTEM_DEFAULT
,
1564 LCMAP_LINGUISTIC_CASING
| LCMAP_LOWERCASE
,
1565 wCharacter
, lengthUTF16
, wLower
, sizeof(wLower
)/sizeof(wLower
[0]));
1566 char sCharacterLowered
[20];
1567 unsigned int lengthConverted
= ::WideCharToMultiByte(cpDoc
, 0,
1568 wLower
, charsConverted
,
1569 sCharacterLowered
, sizeof(sCharacterLowered
), NULL
, 0);
1570 if ((lengthConverted
== 1) && (sCharacter
[0] != sCharacterLowered
[0])) {
1571 pcf
->SetTranslation(sCharacter
[0], sCharacterLowered
[0]);
1577 return new CaseFolderDBCS(cpDest
);
1582 std::string
ScintillaWin::CaseMapString(const std::string
&s
, int caseMapping
) {
1584 return std::string();
1586 if (caseMapping
== cmSame
)
1589 UINT cpDoc
= CodePageOfDocument();
1591 unsigned int lengthUTF16
= ::MultiByteToWideChar(cpDoc
, 0, s
.c_str(),
1592 static_cast<int>(s
.size()), NULL
, 0);
1593 if (lengthUTF16
== 0) // Failed to convert
1596 DWORD mapFlags
= LCMAP_LINGUISTIC_CASING
|
1597 ((caseMapping
== cmUpper
) ? LCMAP_UPPERCASE
: LCMAP_LOWERCASE
);
1599 // Many conversions performed by search function are short so optimize this case.
1600 enum { shortSize
=20 };
1602 if (s
.size() > shortSize
) {
1603 // Use dynamic allocations for long strings
1605 // Change text to UTF-16
1606 std::vector
<wchar_t> vwcText(lengthUTF16
);
1607 ::MultiByteToWideChar(cpDoc
, 0, s
.c_str(), static_cast<int>(s
.size()), &vwcText
[0], lengthUTF16
);
1610 int charsConverted
= ::LCMapStringW(LOCALE_SYSTEM_DEFAULT
, mapFlags
,
1611 &vwcText
[0], lengthUTF16
, NULL
, 0);
1612 std::vector
<wchar_t> vwcConverted(charsConverted
);
1613 ::LCMapStringW(LOCALE_SYSTEM_DEFAULT
, mapFlags
,
1614 &vwcText
[0], lengthUTF16
, &vwcConverted
[0], charsConverted
);
1616 // Change back to document encoding
1617 unsigned int lengthConverted
= ::WideCharToMultiByte(cpDoc
, 0,
1618 &vwcConverted
[0], static_cast<int>(vwcConverted
.size()),
1620 std::vector
<char> vcConverted(lengthConverted
);
1621 ::WideCharToMultiByte(cpDoc
, 0,
1622 &vwcConverted
[0], static_cast<int>(vwcConverted
.size()),
1623 &vcConverted
[0], static_cast<int>(vcConverted
.size()), NULL
, 0);
1625 return std::string(&vcConverted
[0], vcConverted
.size());
1628 // Use static allocations for short strings as much faster
1629 // A factor of 15 for single character strings
1631 // Change text to UTF-16
1632 wchar_t vwcText
[shortSize
];
1633 ::MultiByteToWideChar(cpDoc
, 0, s
.c_str(), static_cast<int>(s
.size()),
1634 vwcText
, lengthUTF16
);
1637 int charsConverted
= ::LCMapStringW(LOCALE_SYSTEM_DEFAULT
, mapFlags
,
1638 vwcText
, lengthUTF16
, NULL
, 0);
1639 // Full mapping may produce up to 3 characters per input character
1640 wchar_t vwcConverted
[shortSize
*3];
1641 ::LCMapStringW(LOCALE_SYSTEM_DEFAULT
, mapFlags
, vwcText
, lengthUTF16
,
1642 vwcConverted
, charsConverted
);
1644 // Change back to document encoding
1645 unsigned int lengthConverted
= ::WideCharToMultiByte(cpDoc
, 0,
1646 vwcConverted
, charsConverted
,
1648 // Each UTF-16 code unit may need up to 3 bytes in UTF-8
1649 char vcConverted
[shortSize
* 3 * 3];
1650 ::WideCharToMultiByte(cpDoc
, 0,
1651 vwcConverted
, charsConverted
,
1652 vcConverted
, lengthConverted
, NULL
, 0);
1654 return std::string(vcConverted
, lengthConverted
);
1658 void ScintillaWin::Copy() {
1659 //Platform::DebugPrintf("Copy\n");
1661 SelectionText selectedText
;
1662 CopySelectionRange(&selectedText
);
1663 CopyToClipboard(selectedText
);
1667 void ScintillaWin::CopyAllowLine() {
1668 SelectionText selectedText
;
1669 CopySelectionRange(&selectedText
, true);
1670 CopyToClipboard(selectedText
);
1673 bool ScintillaWin::CanPaste() {
1674 if (!Editor::CanPaste())
1676 if (::IsClipboardFormatAvailable(CF_TEXT
))
1678 if (IsUnicodeMode())
1679 return ::IsClipboardFormatAvailable(CF_UNICODETEXT
) != 0;
1683 class GlobalMemory
{
1687 GlobalMemory() : hand(0), ptr(0) {
1689 GlobalMemory(HGLOBAL hand_
) : hand(hand_
), ptr(0) {
1691 ptr
= ::GlobalLock(hand
);
1695 PLATFORM_ASSERT(!ptr
);
1697 void Allocate(size_t bytes
) {
1698 hand
= ::GlobalAlloc(GMEM_MOVEABLE
| GMEM_ZEROINIT
, bytes
);
1700 ptr
= ::GlobalLock(hand
);
1704 PLATFORM_ASSERT(ptr
);
1705 HGLOBAL handCopy
= hand
;
1706 ::GlobalUnlock(hand
);
1711 void SetClip(UINT uFormat
) {
1712 ::SetClipboardData(uFormat
, Unlock());
1714 operator bool() const {
1718 return ::GlobalSize(hand
);
1722 void ScintillaWin::InsertPasteText(const char *text
, int len
, SelectionPosition selStart
, bool isRectangular
, bool isLine
) {
1723 if (isRectangular
) {
1724 PasteRectangular(selStart
, text
, len
);
1726 char *convertedText
= 0;
1727 if (convertPastes
) {
1728 // Convert line endings of the paste into our local line-endings mode
1729 convertedText
= Document::TransformLineEnds(&len
, text
, len
, pdoc
->eolMode
);
1730 text
= convertedText
;
1733 int insertPos
= pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret()));
1734 pdoc
->InsertString(insertPos
, text
, len
);
1735 // add the newline if necessary
1736 if ((len
> 0) && (text
[len
-1] != '\n' && text
[len
-1] != '\r')) {
1737 const char *endline
= StringFromEOLMode(pdoc
->eolMode
);
1738 pdoc
->InsertString(insertPos
+ len
, endline
, static_cast<int>(strlen(endline
)));
1739 len
+= static_cast<int>(strlen(endline
));
1741 if (sel
.MainCaret() == insertPos
) {
1742 SetEmptySelection(sel
.MainCaret() + len
);
1745 InsertPaste(selStart
, text
, len
);
1747 delete []convertedText
;
1751 void ScintillaWin::Paste() {
1752 if (!::OpenClipboard(MainHWND()))
1755 bool isLine
= SelectionEmpty() && (::IsClipboardFormatAvailable(cfLineSelect
) != 0);
1756 ClearSelection(multiPasteMode
== SC_MULTIPASTE_EACH
);
1757 SelectionPosition selStart
= sel
.IsRectangular() ?
1758 sel
.Rectangular().Start() :
1759 sel
.Range(sel
.Main()).Start();
1760 bool isRectangular
= ::IsClipboardFormatAvailable(cfColumnSelect
) != 0;
1762 // Always use CF_UNICODETEXT if available
1763 GlobalMemory
memUSelection(::GetClipboardData(CF_UNICODETEXT
));
1764 if (memUSelection
) {
1765 wchar_t *uptr
= static_cast<wchar_t *>(memUSelection
.ptr
);
1769 // Default Scintilla behaviour in Unicode mode
1770 if (IsUnicodeMode()) {
1771 unsigned int bytes
= memUSelection
.Size();
1772 len
= UTF8Length(uptr
, bytes
/ 2);
1773 putf
= new char[len
+ 1];
1774 UTF8FromUTF16(uptr
, bytes
/ 2, putf
, len
);
1776 // CF_UNICODETEXT available, but not in Unicode mode
1777 // Convert from Unicode to current Scintilla code page
1778 UINT cpDest
= CodePageOfDocument();
1779 len
= ::WideCharToMultiByte(cpDest
, 0, uptr
, -1,
1780 NULL
, 0, NULL
, NULL
) - 1; // subtract 0 terminator
1781 putf
= new char[len
+ 1];
1782 ::WideCharToMultiByte(cpDest
, 0, uptr
, -1,
1783 putf
, len
+ 1, NULL
, NULL
);
1786 InsertPasteText(putf
, len
, selStart
, isRectangular
, isLine
);
1789 memUSelection
.Unlock();
1791 // CF_UNICODETEXT not available, paste ANSI text
1792 GlobalMemory
memSelection(::GetClipboardData(CF_TEXT
));
1794 char *ptr
= static_cast<char *>(memSelection
.ptr
);
1796 unsigned int bytes
= memSelection
.Size();
1797 unsigned int len
= bytes
;
1798 for (unsigned int i
= 0; i
< bytes
; i
++) {
1799 if ((len
== bytes
) && (0 == ptr
[i
]))
1803 // In Unicode mode, convert clipboard text to UTF-8
1804 if (IsUnicodeMode()) {
1805 wchar_t *uptr
= new wchar_t[len
+1];
1807 unsigned int ulen
= ::MultiByteToWideChar(CP_ACP
, 0,
1808 ptr
, len
, uptr
, len
+1);
1810 unsigned int mlen
= UTF8Length(uptr
, ulen
);
1811 char *putf
= new char[mlen
+ 1];
1813 // CP_UTF8 not available on Windows 95, so use UTF8FromUTF16()
1814 UTF8FromUTF16(uptr
, ulen
, putf
, mlen
);
1820 InsertPasteText(putf
, mlen
, selStart
, isRectangular
, isLine
);
1824 InsertPasteText(ptr
, len
, selStart
, isRectangular
, isLine
);
1827 memSelection
.Unlock();
1834 void ScintillaWin::CreateCallTipWindow(PRectangle
) {
1835 if (!ct
.wCallTip
.Created()) {
1836 ct
.wCallTip
= ::CreateWindow(callClassName
, TEXT("ACallTip"),
1837 WS_POPUP
, 100, 100, 150, 20,
1839 GetWindowInstance(MainHWND()),
1841 ct
.wDraw
= ct
.wCallTip
;
1845 void ScintillaWin::AddToPopUp(const char *label
, int cmd
, bool enabled
) {
1846 HMENU hmenuPopup
= reinterpret_cast<HMENU
>(popup
.GetID());
1848 ::AppendMenuA(hmenuPopup
, MF_SEPARATOR
, 0, "");
1850 ::AppendMenuA(hmenuPopup
, MF_STRING
, cmd
, label
);
1852 ::AppendMenuA(hmenuPopup
, MF_STRING
| MF_DISABLED
| MF_GRAYED
, cmd
, label
);
1855 void ScintillaWin::ClaimSelection() {
1856 // Windows does not have a primary selection
1859 /// Implement IUnknown
1861 STDMETHODIMP_(ULONG
)FormatEnumerator_AddRef(FormatEnumerator
*fe
);
1862 STDMETHODIMP
FormatEnumerator_QueryInterface(FormatEnumerator
*fe
, REFIID riid
, PVOID
*ppv
) {
1863 //Platform::DebugPrintf("EFE QI");
1865 if (riid
== IID_IUnknown
)
1866 *ppv
= reinterpret_cast<IEnumFORMATETC
*>(fe
);
1867 if (riid
== IID_IEnumFORMATETC
)
1868 *ppv
= reinterpret_cast<IEnumFORMATETC
*>(fe
);
1870 return E_NOINTERFACE
;
1871 FormatEnumerator_AddRef(fe
);
1874 STDMETHODIMP_(ULONG
)FormatEnumerator_AddRef(FormatEnumerator
*fe
) {
1877 STDMETHODIMP_(ULONG
)FormatEnumerator_Release(FormatEnumerator
*fe
) {
1884 /// Implement IEnumFORMATETC
1885 STDMETHODIMP
FormatEnumerator_Next(FormatEnumerator
*fe
, ULONG celt
, FORMATETC
*rgelt
, ULONG
*pceltFetched
) {
1886 //Platform::DebugPrintf("EFE Next %d %d", fe->pos, celt);
1887 if (rgelt
== NULL
) return E_POINTER
;
1888 // We only support one format, so this is simple.
1889 unsigned int putPos
= 0;
1890 while ((fe
->pos
< fe
->formatsLen
) && (putPos
< celt
)) {
1891 rgelt
->cfFormat
= fe
->formats
[fe
->pos
];
1893 rgelt
->dwAspect
= DVASPECT_CONTENT
;
1895 rgelt
->tymed
= TYMED_HGLOBAL
;
1900 *pceltFetched
= putPos
;
1901 return putPos
? S_OK
: S_FALSE
;
1903 STDMETHODIMP
FormatEnumerator_Skip(FormatEnumerator
*fe
, ULONG celt
) {
1907 STDMETHODIMP
FormatEnumerator_Reset(FormatEnumerator
*fe
) {
1911 STDMETHODIMP
FormatEnumerator_Clone(FormatEnumerator
*fe
, IEnumFORMATETC
**ppenum
) {
1912 FormatEnumerator
*pfe
;
1914 pfe
= new FormatEnumerator(fe
->pos
, fe
->formats
, fe
->formatsLen
);
1916 return E_OUTOFMEMORY
;
1918 return FormatEnumerator_QueryInterface(pfe
, IID_IEnumFORMATETC
,
1919 reinterpret_cast<void **>(ppenum
));
1922 static VFunction
*vtFormatEnumerator
[] = {
1923 (VFunction
*)(FormatEnumerator_QueryInterface
),
1924 (VFunction
*)(FormatEnumerator_AddRef
),
1925 (VFunction
*)(FormatEnumerator_Release
),
1926 (VFunction
*)(FormatEnumerator_Next
),
1927 (VFunction
*)(FormatEnumerator_Skip
),
1928 (VFunction
*)(FormatEnumerator_Reset
),
1929 (VFunction
*)(FormatEnumerator_Clone
)
1932 FormatEnumerator::FormatEnumerator(int pos_
, CLIPFORMAT formats_
[], int formatsLen_
) {
1933 vtbl
= vtFormatEnumerator
;
1934 ref
= 0; // First QI adds first reference...
1936 formatsLen
= formatsLen_
;
1937 for (int i
=0; i
<formatsLen
; i
++)
1938 formats
[i
] = formats_
[i
];
1941 /// Implement IUnknown
1942 STDMETHODIMP
DropSource_QueryInterface(DropSource
*ds
, REFIID riid
, PVOID
*ppv
) {
1943 return ds
->sci
->QueryInterface(riid
, ppv
);
1945 STDMETHODIMP_(ULONG
)DropSource_AddRef(DropSource
*ds
) {
1946 return ds
->sci
->AddRef();
1948 STDMETHODIMP_(ULONG
)DropSource_Release(DropSource
*ds
) {
1949 return ds
->sci
->Release();
1952 /// Implement IDropSource
1953 STDMETHODIMP
DropSource_QueryContinueDrag(DropSource
*, BOOL fEsc
, DWORD grfKeyState
) {
1955 return DRAGDROP_S_CANCEL
;
1956 if (!(grfKeyState
& MK_LBUTTON
))
1957 return DRAGDROP_S_DROP
;
1961 STDMETHODIMP
DropSource_GiveFeedback(DropSource
*, DWORD
) {
1962 return DRAGDROP_S_USEDEFAULTCURSORS
;
1965 static VFunction
*vtDropSource
[] = {
1966 (VFunction
*)(DropSource_QueryInterface
),
1967 (VFunction
*)(DropSource_AddRef
),
1968 (VFunction
*)(DropSource_Release
),
1969 (VFunction
*)(DropSource_QueryContinueDrag
),
1970 (VFunction
*)(DropSource_GiveFeedback
)
1973 DropSource::DropSource() {
1974 vtbl
= vtDropSource
;
1978 /// Implement IUnkown
1979 STDMETHODIMP
DataObject_QueryInterface(DataObject
*pd
, REFIID riid
, PVOID
*ppv
) {
1980 //Platform::DebugPrintf("DO QI %x\n", pd);
1981 return pd
->sci
->QueryInterface(riid
, ppv
);
1983 STDMETHODIMP_(ULONG
)DataObject_AddRef(DataObject
*pd
) {
1984 return pd
->sci
->AddRef();
1986 STDMETHODIMP_(ULONG
)DataObject_Release(DataObject
*pd
) {
1987 return pd
->sci
->Release();
1989 /// Implement IDataObject
1990 STDMETHODIMP
DataObject_GetData(DataObject
*pd
, FORMATETC
*pFEIn
, STGMEDIUM
*pSTM
) {
1991 return pd
->sci
->GetData(pFEIn
, pSTM
);
1994 STDMETHODIMP
DataObject_GetDataHere(DataObject
*, FORMATETC
*, STGMEDIUM
*) {
1995 //Platform::DebugPrintf("DOB GetDataHere\n");
1999 STDMETHODIMP
DataObject_QueryGetData(DataObject
*pd
, FORMATETC
*pFE
) {
2000 if (pd
->sci
->DragIsRectangularOK(pFE
->cfFormat
) &&
2002 (pFE
->dwAspect
& DVASPECT_CONTENT
) != 0 &&
2003 pFE
->lindex
== -1 &&
2004 (pFE
->tymed
& TYMED_HGLOBAL
) != 0
2009 bool formatOK
= (pFE
->cfFormat
== CF_TEXT
) ||
2010 ((pFE
->cfFormat
== CF_UNICODETEXT
) && pd
->sci
->IsUnicodeMode());
2013 (pFE
->dwAspect
& DVASPECT_CONTENT
) == 0 ||
2014 pFE
->lindex
!= -1 ||
2015 (pFE
->tymed
& TYMED_HGLOBAL
) == 0
2017 //Platform::DebugPrintf("DOB QueryGetData No %x\n",pFE->cfFormat);
2018 //return DATA_E_FORMATETC;
2021 //Platform::DebugPrintf("DOB QueryGetData OK %x\n",pFE->cfFormat);
2025 STDMETHODIMP
DataObject_GetCanonicalFormatEtc(DataObject
*pd
, FORMATETC
*, FORMATETC
*pFEOut
) {
2026 //Platform::DebugPrintf("DOB GetCanon\n");
2027 if (pd
->sci
->IsUnicodeMode())
2028 pFEOut
->cfFormat
= CF_UNICODETEXT
;
2030 pFEOut
->cfFormat
= CF_TEXT
;
2032 pFEOut
->dwAspect
= DVASPECT_CONTENT
;
2033 pFEOut
->lindex
= -1;
2034 pFEOut
->tymed
= TYMED_HGLOBAL
;
2038 STDMETHODIMP
DataObject_SetData(DataObject
*, FORMATETC
*, STGMEDIUM
*, BOOL
) {
2039 //Platform::DebugPrintf("DOB SetData\n");
2043 STDMETHODIMP
DataObject_EnumFormatEtc(DataObject
*pd
, DWORD dwDirection
, IEnumFORMATETC
**ppEnum
) {
2045 //Platform::DebugPrintf("DOB EnumFormatEtc %d\n", dwDirection);
2046 if (dwDirection
!= DATADIR_GET
) {
2050 FormatEnumerator
*pfe
;
2051 if (pd
->sci
->IsUnicodeMode()) {
2052 CLIPFORMAT formats
[] = {CF_UNICODETEXT
, CF_TEXT
};
2053 pfe
= new FormatEnumerator(0, formats
, 2);
2055 CLIPFORMAT formats
[] = {CF_TEXT
};
2056 pfe
= new FormatEnumerator(0, formats
, 1);
2058 return FormatEnumerator_QueryInterface(pfe
, IID_IEnumFORMATETC
,
2059 reinterpret_cast<void **>(ppEnum
));
2060 } catch (std::bad_alloc
&) {
2061 pd
->sci
->errorStatus
= SC_STATUS_BADALLOC
;
2062 return E_OUTOFMEMORY
;
2064 pd
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2069 STDMETHODIMP
DataObject_DAdvise(DataObject
*, FORMATETC
*, DWORD
, IAdviseSink
*, PDWORD
) {
2070 //Platform::DebugPrintf("DOB DAdvise\n");
2074 STDMETHODIMP
DataObject_DUnadvise(DataObject
*, DWORD
) {
2075 //Platform::DebugPrintf("DOB DUnadvise\n");
2079 STDMETHODIMP
DataObject_EnumDAdvise(DataObject
*, IEnumSTATDATA
**) {
2080 //Platform::DebugPrintf("DOB EnumDAdvise\n");
2084 static VFunction
*vtDataObject
[] = {
2085 (VFunction
*)(DataObject_QueryInterface
),
2086 (VFunction
*)(DataObject_AddRef
),
2087 (VFunction
*)(DataObject_Release
),
2088 (VFunction
*)(DataObject_GetData
),
2089 (VFunction
*)(DataObject_GetDataHere
),
2090 (VFunction
*)(DataObject_QueryGetData
),
2091 (VFunction
*)(DataObject_GetCanonicalFormatEtc
),
2092 (VFunction
*)(DataObject_SetData
),
2093 (VFunction
*)(DataObject_EnumFormatEtc
),
2094 (VFunction
*)(DataObject_DAdvise
),
2095 (VFunction
*)(DataObject_DUnadvise
),
2096 (VFunction
*)(DataObject_EnumDAdvise
)
2099 DataObject::DataObject() {
2100 vtbl
= vtDataObject
;
2104 /// Implement IUnknown
2105 STDMETHODIMP
DropTarget_QueryInterface(DropTarget
*dt
, REFIID riid
, PVOID
*ppv
) {
2106 //Platform::DebugPrintf("DT QI %x\n", dt);
2107 return dt
->sci
->QueryInterface(riid
, ppv
);
2109 STDMETHODIMP_(ULONG
)DropTarget_AddRef(DropTarget
*dt
) {
2110 return dt
->sci
->AddRef();
2112 STDMETHODIMP_(ULONG
)DropTarget_Release(DropTarget
*dt
) {
2113 return dt
->sci
->Release();
2116 /// Implement IDropTarget by forwarding to Scintilla
2117 STDMETHODIMP
DropTarget_DragEnter(DropTarget
*dt
, LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
2118 POINTL pt
, PDWORD pdwEffect
) {
2120 return dt
->sci
->DragEnter(pIDataSource
, grfKeyState
, pt
, pdwEffect
);
2122 dt
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2126 STDMETHODIMP
DropTarget_DragOver(DropTarget
*dt
, DWORD grfKeyState
, POINTL pt
, PDWORD pdwEffect
) {
2128 return dt
->sci
->DragOver(grfKeyState
, pt
, pdwEffect
);
2130 dt
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2134 STDMETHODIMP
DropTarget_DragLeave(DropTarget
*dt
) {
2136 return dt
->sci
->DragLeave();
2138 dt
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2142 STDMETHODIMP
DropTarget_Drop(DropTarget
*dt
, LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
2143 POINTL pt
, PDWORD pdwEffect
) {
2145 return dt
->sci
->Drop(pIDataSource
, grfKeyState
, pt
, pdwEffect
);
2147 dt
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2152 static VFunction
*vtDropTarget
[] = {
2153 (VFunction
*)(DropTarget_QueryInterface
),
2154 (VFunction
*)(DropTarget_AddRef
),
2155 (VFunction
*)(DropTarget_Release
),
2156 (VFunction
*)(DropTarget_DragEnter
),
2157 (VFunction
*)(DropTarget_DragOver
),
2158 (VFunction
*)(DropTarget_DragLeave
),
2159 (VFunction
*)(DropTarget_Drop
)
2162 DropTarget::DropTarget() {
2163 vtbl
= vtDropTarget
;
2168 * DBCS: support Input Method Editor (IME).
2169 * Called when IME Window opened.
2171 void ScintillaWin::ImeStartComposition() {
2173 // Digital Mars compiler does not include Imm library
2175 // Move IME Window to current caret position
2176 HIMC hIMC
= ::ImmGetContext(MainHWND());
2177 Point pos
= PointMainCaret();
2178 COMPOSITIONFORM CompForm
;
2179 CompForm
.dwStyle
= CFS_POINT
;
2180 CompForm
.ptCurrentPos
.x
= pos
.x
;
2181 CompForm
.ptCurrentPos
.y
= pos
.y
;
2183 ::ImmSetCompositionWindow(hIMC
, &CompForm
);
2185 // Set font of IME window to same as surrounded text.
2187 // Since the style creation code has been made platform independent,
2188 // The logfont for the IME is recreated here.
2189 int styleHere
= (pdoc
->StyleAt(sel
.MainCaret())) & 31;
2190 LOGFONTA lf
= {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ""};
2191 int sizeZoomed
= vs
.styles
[styleHere
].size
+ vs
.zoomLevel
* SC_FONT_SIZE_MULTIPLIER
;
2192 if (sizeZoomed
<= 2 * SC_FONT_SIZE_MULTIPLIER
) // Hangs if sizeZoomed <= 1
2193 sizeZoomed
= 2 * SC_FONT_SIZE_MULTIPLIER
;
2194 AutoSurface
surface(this);
2195 int deviceHeight
= sizeZoomed
;
2197 deviceHeight
= (sizeZoomed
* surface
->LogPixelsY()) / 72;
2199 // The negative is to allow for leading
2200 lf
.lfHeight
= -(abs(deviceHeight
/ SC_FONT_SIZE_MULTIPLIER
));
2201 lf
.lfWeight
= vs
.styles
[styleHere
].weight
;
2202 lf
.lfItalic
= static_cast<BYTE
>(vs
.styles
[styleHere
].italic
? 1 : 0);
2203 lf
.lfCharSet
= DEFAULT_CHARSET
;
2204 lf
.lfFaceName
[0] = '\0';
2205 if (vs
.styles
[styleHere
].fontName
)
2206 strcpy(lf
.lfFaceName
, vs
.styles
[styleHere
].fontName
);
2208 ::ImmSetCompositionFontA(hIMC
, &lf
);
2210 ::ImmReleaseContext(MainHWND(), hIMC
);
2211 // Caret is displayed in IME window. So, caret in Scintilla is useless.
2217 /** Called when IME Window closed. */
2218 void ScintillaWin::ImeEndComposition() {
2219 ShowCaretAtCurrentPosition();
2222 void ScintillaWin::AddCharBytes(char b0
, char b1
) {
2224 int inputCodePage
= InputCodePage();
2225 if (inputCodePage
&& IsUnicodeMode()) {
2226 char utfval
[4] = "\0\0\0";
2229 if (b0
) { // Two bytes from IME
2232 ansiChars
[2] = '\0';
2233 ::MultiByteToWideChar(inputCodePage
, 0, ansiChars
, 2, wcs
, 1);
2236 ansiChars
[1] = '\0';
2237 ::MultiByteToWideChar(inputCodePage
, 0, ansiChars
, 1, wcs
, 1);
2239 unsigned int len
= UTF8Length(wcs
, 1);
2240 UTF8FromUTF16(wcs
, 1, utfval
, len
);
2242 AddCharUTF(utfval
, len
? len
: 1);
2247 dbcsChars
[2] = '\0';
2248 AddCharUTF(dbcsChars
, 2, true);
2254 void ScintillaWin::GetIntelliMouseParameters() {
2255 // This retrieves the number of lines per scroll as configured inthe Mouse Properties sheet in Control Panel
2256 ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0, &linesPerScroll
, 0);
2259 void ScintillaWin::CopyToClipboard(const SelectionText
&selectedText
) {
2260 if (!::OpenClipboard(MainHWND()))
2264 GlobalMemory uniText
;
2266 // Default Scintilla behaviour in Unicode mode
2267 if (IsUnicodeMode()) {
2268 int uchars
= UTF16Length(selectedText
.s
, selectedText
.len
);
2269 uniText
.Allocate(2 * uchars
);
2271 UTF16FromUTF8(selectedText
.s
, selectedText
.len
, static_cast<wchar_t *>(uniText
.ptr
), uchars
);
2275 // Convert to Unicode using the current Scintilla code page
2276 UINT cpSrc
= CodePageFromCharSet(
2277 selectedText
.characterSet
, selectedText
.codePage
);
2278 int uLen
= ::MultiByteToWideChar(cpSrc
, 0, selectedText
.s
, selectedText
.len
, 0, 0);
2279 uniText
.Allocate(2 * uLen
);
2281 ::MultiByteToWideChar(cpSrc
, 0, selectedText
.s
, selectedText
.len
,
2282 static_cast<wchar_t *>(uniText
.ptr
), uLen
);
2288 // Copy ANSI text to clipboard on Windows 9x
2289 // Convert from Unicode text, so other ANSI programs can
2291 // Windows NT, 2k, XP automatically generates CF_TEXT
2292 GlobalMemory ansiText
;
2293 ansiText
.Allocate(selectedText
.len
);
2295 ::WideCharToMultiByte(CP_ACP
, 0, static_cast<wchar_t *>(uniText
.ptr
), -1,
2296 static_cast<char *>(ansiText
.ptr
), selectedText
.len
, NULL
, NULL
);
2297 ansiText
.SetClip(CF_TEXT
);
2300 uniText
.SetClip(CF_UNICODETEXT
);
2302 // There was a failure - try to copy at least ANSI text
2303 GlobalMemory ansiText
;
2304 ansiText
.Allocate(selectedText
.len
);
2306 memcpy(static_cast<char *>(ansiText
.ptr
), selectedText
.s
, selectedText
.len
);
2307 ansiText
.SetClip(CF_TEXT
);
2311 if (selectedText
.rectangular
) {
2312 ::SetClipboardData(cfColumnSelect
, 0);
2315 if (selectedText
.lineCopy
) {
2316 ::SetClipboardData(cfLineSelect
, 0);
2322 void ScintillaWin::ScrollMessage(WPARAM wParam
) {
2323 //DWORD dwStart = timeGetTime();
2324 //Platform::DebugPrintf("Scroll %x %d\n", wParam, lParam);
2327 memset(&sci
, 0, sizeof(sci
));
2328 sci
.cbSize
= sizeof(sci
);
2329 sci
.fMask
= SIF_ALL
;
2331 GetScrollInfo(SB_VERT
, &sci
);
2333 //Platform::DebugPrintf("ScrollInfo %d mask=%x min=%d max=%d page=%d pos=%d track=%d\n", b,sci.fMask,
2334 //sci.nMin, sci.nMax, sci.nPage, sci.nPos, sci.nTrackPos);
2336 int topLineNew
= topLine
;
2337 switch (LoWord(wParam
)) {
2345 topLineNew
-= LinesToScroll(); break;
2346 case SB_PAGEDOWN
: topLineNew
+= LinesToScroll(); break;
2347 case SB_TOP
: topLineNew
= 0; break;
2348 case SB_BOTTOM
: topLineNew
= MaxScrollPos(); break;
2349 case SB_THUMBPOSITION
: topLineNew
= sci
.nTrackPos
; break;
2350 case SB_THUMBTRACK
: topLineNew
= sci
.nTrackPos
; break;
2352 ScrollTo(topLineNew
);
2355 void ScintillaWin::HorizontalScrollMessage(WPARAM wParam
) {
2357 PRectangle rcText
= GetTextRectangle();
2358 int pageWidth
= rcText
.Width() * 2 / 3;
2359 switch (LoWord(wParam
)) {
2363 case SB_LINEDOWN
: // May move past the logical end
2371 if (xPos
> scrollWidth
- rcText
.Width()) { // Hit the end exactly
2372 xPos
= scrollWidth
- rcText
.Width();
2381 case SB_THUMBPOSITION
:
2382 case SB_THUMBTRACK
: {
2383 // 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 =]
2385 si
.cbSize
= sizeof(si
);
2386 si
.fMask
= SIF_TRACKPOS
;
2387 if (GetScrollInfo(SB_HORZ
, &si
)) {
2388 xPos
= si
.nTrackPos
;
2393 HorizontalScrollTo(xPos
);
2397 * Redraw all of text area.
2398 * This paint will not be abandoned.
2400 void ScintillaWin::FullPaint() {
2401 if (technology
== SC_TECHNOLOGY_DEFAULT
) {
2402 HDC hdc
= ::GetDC(MainHWND());
2404 ::ReleaseDC(MainHWND(), hdc
);
2411 * Redraw all of text area on the specified DC.
2412 * This paint will not be abandoned.
2414 void ScintillaWin::FullPaintDC(HDC hdc
) {
2415 paintState
= painting
;
2416 rcPaint
= GetClientRectangle();
2417 paintingAllText
= true;
2418 if (technology
== SC_TECHNOLOGY_DEFAULT
) {
2419 AutoSurface
surfaceWindow(hdc
, this);
2420 if (surfaceWindow
) {
2421 Paint(surfaceWindow
, rcPaint
);
2422 surfaceWindow
->Release();
2425 #if defined(USE_D2D)
2426 EnsureRenderTarget();
2427 AutoSurface
surfaceWindow(pRenderTarget
, this);
2428 if (surfaceWindow
) {
2429 pRenderTarget
->BeginDraw();
2430 Paint(surfaceWindow
, rcPaint
);
2431 surfaceWindow
->Release();
2432 HRESULT hr
= pRenderTarget
->EndDraw();
2433 if (hr
== D2DERR_RECREATE_TARGET
) {
2439 paintState
= notPainting
;
2442 static bool CompareDevCap(HDC hdc
, HDC hOtherDC
, int nIndex
) {
2443 return ::GetDeviceCaps(hdc
, nIndex
) == ::GetDeviceCaps(hOtherDC
, nIndex
);
2446 bool ScintillaWin::IsCompatibleDC(HDC hOtherDC
) {
2447 HDC hdc
= ::GetDC(MainHWND());
2449 CompareDevCap(hdc
, hOtherDC
, TECHNOLOGY
) &&
2450 CompareDevCap(hdc
, hOtherDC
, LOGPIXELSY
) &&
2451 CompareDevCap(hdc
, hOtherDC
, LOGPIXELSX
) &&
2452 CompareDevCap(hdc
, hOtherDC
, BITSPIXEL
) &&
2453 CompareDevCap(hdc
, hOtherDC
, PLANES
);
2454 ::ReleaseDC(MainHWND(), hdc
);
2455 return isCompatible
;
2458 DWORD
ScintillaWin::EffectFromState(DWORD grfKeyState
) {
2459 // These are the Wordpad semantics.
2461 if (inDragDrop
== ddDragging
) // Internal defaults to move
2462 dwEffect
= DROPEFFECT_MOVE
;
2464 dwEffect
= DROPEFFECT_COPY
;
2465 if (grfKeyState
& MK_ALT
)
2466 dwEffect
= DROPEFFECT_MOVE
;
2467 if (grfKeyState
& MK_CONTROL
)
2468 dwEffect
= DROPEFFECT_COPY
;
2472 /// Implement IUnknown
2473 STDMETHODIMP
ScintillaWin::QueryInterface(REFIID riid
, PVOID
*ppv
) {
2475 if (riid
== IID_IUnknown
)
2476 *ppv
= reinterpret_cast<IDropTarget
*>(&dt
);
2477 if (riid
== IID_IDropSource
)
2478 *ppv
= reinterpret_cast<IDropSource
*>(&ds
);
2479 if (riid
== IID_IDropTarget
)
2480 *ppv
= reinterpret_cast<IDropTarget
*>(&dt
);
2481 if (riid
== IID_IDataObject
)
2482 *ppv
= reinterpret_cast<IDataObject
*>(&dob
);
2484 return E_NOINTERFACE
;
2488 STDMETHODIMP_(ULONG
) ScintillaWin::AddRef() {
2492 STDMETHODIMP_(ULONG
) ScintillaWin::Release() {
2496 /// Implement IDropTarget
2497 STDMETHODIMP
ScintillaWin::DragEnter(LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
2498 POINTL
, PDWORD pdwEffect
) {
2499 if (pIDataSource
== NULL
)
2501 FORMATETC fmtu
= {CF_UNICODETEXT
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2502 HRESULT hrHasUText
= pIDataSource
->QueryGetData(&fmtu
);
2503 hasOKText
= (hrHasUText
== S_OK
);
2505 FORMATETC fmte
= {CF_TEXT
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2506 HRESULT hrHasText
= pIDataSource
->QueryGetData(&fmte
);
2507 hasOKText
= (hrHasText
== S_OK
);
2510 *pdwEffect
= DROPEFFECT_NONE
;
2514 *pdwEffect
= EffectFromState(grfKeyState
);
2518 STDMETHODIMP
ScintillaWin::DragOver(DWORD grfKeyState
, POINTL pt
, PDWORD pdwEffect
) {
2520 if (!hasOKText
|| pdoc
->IsReadOnly()) {
2521 *pdwEffect
= DROPEFFECT_NONE
;
2525 *pdwEffect
= EffectFromState(grfKeyState
);
2527 // Update the cursor.
2528 POINT rpt
= {pt
.x
, pt
.y
};
2529 ::ScreenToClient(MainHWND(), &rpt
);
2530 SetDragPosition(SPositionFromLocation(Point(rpt
.x
, rpt
.y
), false, false, UserVirtualSpace()));
2534 errorStatus
= SC_STATUS_FAILURE
;
2539 STDMETHODIMP
ScintillaWin::DragLeave() {
2541 SetDragPosition(SelectionPosition(invalidPosition
));
2544 errorStatus
= SC_STATUS_FAILURE
;
2549 STDMETHODIMP
ScintillaWin::Drop(LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
2550 POINTL pt
, PDWORD pdwEffect
) {
2552 *pdwEffect
= EffectFromState(grfKeyState
);
2554 if (pIDataSource
== NULL
)
2557 SetDragPosition(SelectionPosition(invalidPosition
));
2559 STGMEDIUM medium
= {0, {0}, 0};
2562 bool dataAllocated
= false;
2564 FORMATETC fmtu
= {CF_UNICODETEXT
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2565 HRESULT hr
= pIDataSource
->GetData(&fmtu
, &medium
);
2566 if (SUCCEEDED(hr
) && medium
.hGlobal
) {
2567 wchar_t *udata
= static_cast<wchar_t *>(::GlobalLock(medium
.hGlobal
));
2568 if (IsUnicodeMode()) {
2569 int tlen
= ::GlobalSize(medium
.hGlobal
);
2570 // Convert UTF-16 to UTF-8
2571 int dataLen
= UTF8Length(udata
, tlen
/2);
2572 data
= new char[dataLen
+1];
2573 UTF8FromUTF16(udata
, tlen
/2, data
, dataLen
);
2574 dataAllocated
= true;
2576 // Convert UTF-16 to ANSI
2578 // Default Scintilla behavior in Unicode mode
2579 // CF_UNICODETEXT available, but not in Unicode mode
2580 // Convert from Unicode to current Scintilla code page
2581 UINT cpDest
= CodePageOfDocument();
2582 int tlen
= ::WideCharToMultiByte(cpDest
, 0, udata
, -1,
2583 NULL
, 0, NULL
, NULL
) - 1; // subtract 0 terminator
2584 data
= new char[tlen
+ 1];
2585 memset(data
, 0, (tlen
+1));
2586 ::WideCharToMultiByte(cpDest
, 0, udata
, -1,
2587 data
, tlen
+ 1, NULL
, NULL
);
2588 dataAllocated
= true;
2593 FORMATETC fmte
= {CF_TEXT
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2594 hr
= pIDataSource
->GetData(&fmte
, &medium
);
2595 if (SUCCEEDED(hr
) && medium
.hGlobal
) {
2596 data
= static_cast<char *>(::GlobalLock(medium
.hGlobal
));
2600 if (data
&& convertPastes
) {
2601 // Convert line endings of the drop into our local line-endings mode
2602 int len
= static_cast<int>(strlen(data
));
2603 char *convertedText
= Document::TransformLineEnds(&len
, data
, len
, pdoc
->eolMode
);
2606 data
= convertedText
;
2607 dataAllocated
= true;
2611 //Platform::DebugPrintf("Bad data format: 0x%x\n", hres);
2615 FORMATETC fmtr
= {cfColumnSelect
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2616 HRESULT hrRectangular
= pIDataSource
->QueryGetData(&fmtr
);
2618 POINT rpt
= {pt
.x
, pt
.y
};
2619 ::ScreenToClient(MainHWND(), &rpt
);
2620 SelectionPosition movePos
= SPositionFromLocation(Point(rpt
.x
, rpt
.y
), false, false, UserVirtualSpace());
2622 DropAt(movePos
, data
, *pdwEffect
== DROPEFFECT_MOVE
, hrRectangular
== S_OK
);
2624 ::GlobalUnlock(medium
.hGlobal
);
2627 if (medium
.pUnkForRelease
!= NULL
)
2628 medium
.pUnkForRelease
->Release();
2630 ::GlobalFree(medium
.hGlobal
);
2637 errorStatus
= SC_STATUS_FAILURE
;
2642 /// Implement important part of IDataObject
2643 STDMETHODIMP
ScintillaWin::GetData(FORMATETC
*pFEIn
, STGMEDIUM
*pSTM
) {
2644 bool formatOK
= (pFEIn
->cfFormat
== CF_TEXT
) ||
2645 ((pFEIn
->cfFormat
== CF_UNICODETEXT
) && IsUnicodeMode());
2648 (pFEIn
->dwAspect
& DVASPECT_CONTENT
) == 0 ||
2649 pFEIn
->lindex
!= -1 ||
2650 (pFEIn
->tymed
& TYMED_HGLOBAL
) == 0
2652 //Platform::DebugPrintf("DOB GetData No %d %x %x fmt=%x\n", lenDrag, pFEIn, pSTM, pFEIn->cfFormat);
2653 return DATA_E_FORMATETC
;
2655 pSTM
->tymed
= TYMED_HGLOBAL
;
2656 //Platform::DebugPrintf("DOB GetData OK %d %x %x\n", lenDrag, pFEIn, pSTM);
2659 if (pFEIn
->cfFormat
== CF_UNICODETEXT
) {
2660 int uchars
= UTF16Length(drag
.s
, drag
.len
);
2661 text
.Allocate(2 * uchars
);
2663 UTF16FromUTF8(drag
.s
, drag
.len
, static_cast<wchar_t *>(text
.ptr
), uchars
);
2666 text
.Allocate(drag
.len
);
2668 memcpy(static_cast<char *>(text
.ptr
), drag
.s
, drag
.len
);
2671 pSTM
->hGlobal
= text
? text
.Unlock() : 0;
2672 pSTM
->pUnkForRelease
= 0;
2676 bool ScintillaWin::Register(HINSTANCE hInstance_
) {
2678 hInstance
= hInstance_
;
2681 // Register the Scintilla class
2684 // Register Scintilla as a wide character window
2685 WNDCLASSEXW 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
= L
"Scintilla";
2697 wndclass
.hIconSm
= 0;
2698 result
= ::RegisterClassExW(&wndclass
) != 0;
2701 // Register Scintilla as a normal character window
2702 WNDCLASSEX wndclass
;
2703 wndclass
.cbSize
= sizeof(wndclass
);
2704 wndclass
.style
= CS_GLOBALCLASS
| CS_HREDRAW
| CS_VREDRAW
;
2705 wndclass
.lpfnWndProc
= ScintillaWin::SWndProc
;
2706 wndclass
.cbClsExtra
= 0;
2707 wndclass
.cbWndExtra
= sizeof(ScintillaWin
*);
2708 wndclass
.hInstance
= hInstance
;
2709 wndclass
.hIcon
= NULL
;
2710 wndclass
.hCursor
= NULL
;
2711 wndclass
.hbrBackground
= NULL
;
2712 wndclass
.lpszMenuName
= NULL
;
2713 wndclass
.lpszClassName
= scintillaClassName
;
2714 wndclass
.hIconSm
= 0;
2715 result
= ::RegisterClassEx(&wndclass
) != 0;
2719 // Register the CallTip class
2720 WNDCLASSEX wndclassc
;
2721 wndclassc
.cbSize
= sizeof(wndclassc
);
2722 wndclassc
.style
= CS_GLOBALCLASS
| CS_HREDRAW
| CS_VREDRAW
;
2723 wndclassc
.cbClsExtra
= 0;
2724 wndclassc
.cbWndExtra
= sizeof(ScintillaWin
*);
2725 wndclassc
.hInstance
= hInstance
;
2726 wndclassc
.hIcon
= NULL
;
2727 wndclassc
.hbrBackground
= NULL
;
2728 wndclassc
.lpszMenuName
= NULL
;
2729 wndclassc
.lpfnWndProc
= ScintillaWin::CTWndProc
;
2730 wndclassc
.hCursor
= ::LoadCursor(NULL
, IDC_ARROW
);
2731 wndclassc
.lpszClassName
= callClassName
;
2732 wndclassc
.hIconSm
= 0;
2734 result
= ::RegisterClassEx(&wndclassc
) != 0;
2740 bool ScintillaWin::Unregister() {
2741 bool result
= ::UnregisterClass(scintillaClassName
, hInstance
) != 0;
2742 if (::UnregisterClass(callClassName
, hInstance
) == 0)
2747 bool ScintillaWin::HasCaretSizeChanged() {
2749 ( (0 != vs
.caretWidth
) && (sysCaretWidth
!= vs
.caretWidth
) )
2750 || ((0 != vs
.lineHeight
) && (sysCaretHeight
!= vs
.lineHeight
))
2757 BOOL
ScintillaWin::CreateSystemCaret() {
2758 sysCaretWidth
= vs
.caretWidth
;
2759 if (0 == sysCaretWidth
) {
2762 sysCaretHeight
= vs
.lineHeight
;
2763 int bitmapSize
= (((sysCaretWidth
+ 15) & ~15) >> 3) *
2765 char *bits
= new char[bitmapSize
];
2766 memset(bits
, 0, bitmapSize
);
2767 sysCaretBitmap
= ::CreateBitmap(sysCaretWidth
, sysCaretHeight
, 1,
2768 1, reinterpret_cast<BYTE
*>(bits
));
2770 BOOL retval
= ::CreateCaret(
2771 MainHWND(), sysCaretBitmap
,
2772 sysCaretWidth
, sysCaretHeight
);
2773 ::ShowCaret(MainHWND());
2777 BOOL
ScintillaWin::DestroySystemCaret() {
2778 ::HideCaret(MainHWND());
2779 BOOL retval
= ::DestroyCaret();
2780 if (sysCaretBitmap
) {
2781 ::DeleteObject(sysCaretBitmap
);
2787 sptr_t PASCAL
ScintillaWin::CTWndProc(
2788 HWND hWnd
, UINT iMessage
, WPARAM wParam
, sptr_t lParam
) {
2789 // Find C++ object associated with window.
2790 ScintillaWin
*sciThis
= reinterpret_cast<ScintillaWin
*>(PointerFromWindow(hWnd
));
2792 // ctp will be zero if WM_CREATE not seen yet
2794 if (iMessage
== WM_CREATE
) {
2795 // Associate CallTip object with window
2796 CREATESTRUCT
*pCreate
= reinterpret_cast<CREATESTRUCT
*>(lParam
);
2797 SetWindowPointer(hWnd
, pCreate
->lpCreateParams
);
2800 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2803 if (iMessage
== WM_NCDESTROY
) {
2804 ::SetWindowLong(hWnd
, 0, 0);
2805 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2806 } else if (iMessage
== WM_PAINT
) {
2808 ::BeginPaint(hWnd
, &ps
);
2809 Surface
*surfaceWindow
= Surface::Allocate(sciThis
->technology
);
2810 if (surfaceWindow
) {
2811 #if defined(USE_D2D)
2812 ID2D1HwndRenderTarget
*pCTRenderTarget
= 0;
2815 GetClientRect(hWnd
, &rc
);
2816 // Create a Direct2D render target.
2817 if (sciThis
->technology
== SC_TECHNOLOGY_DEFAULT
) {
2818 surfaceWindow
->Init(ps
.hdc
, hWnd
);
2820 #if defined(USE_D2D)
2821 pD2DFactory
->CreateHwndRenderTarget(
2822 D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT
, D2D1::PixelFormat(), 96.0, 96.0),
2823 D2D1::HwndRenderTargetProperties(hWnd
, D2D1::SizeU(rc
.right
- rc
.left
, rc
.bottom
- rc
.top
)),
2825 surfaceWindow
->Init(pCTRenderTarget
, hWnd
);
2826 pCTRenderTarget
->BeginDraw();
2829 surfaceWindow
->SetUnicodeMode(SC_CP_UTF8
== sciThis
->ct
.codePage
);
2830 surfaceWindow
->SetDBCSMode(sciThis
->ct
.codePage
);
2831 sciThis
->ct
.PaintCT(surfaceWindow
);
2832 #if defined(USE_D2D)
2833 if (pCTRenderTarget
)
2834 pCTRenderTarget
->EndDraw();
2836 surfaceWindow
->Release();
2837 delete surfaceWindow
;
2838 #if defined(USE_D2D)
2839 if (pCTRenderTarget
)
2840 pCTRenderTarget
->Release();
2843 ::EndPaint(hWnd
, &ps
);
2845 } else if ((iMessage
== WM_NCLBUTTONDOWN
) || (iMessage
== WM_NCLBUTTONDBLCLK
)) {
2847 pt
.x
= static_cast<short>(LOWORD(lParam
));
2848 pt
.y
= static_cast<short>(HIWORD(lParam
));
2849 ScreenToClient(hWnd
, &pt
);
2850 sciThis
->ct
.MouseClick(Point(pt
.x
, pt
.y
));
2851 sciThis
->CallTipClick();
2853 } else if (iMessage
== WM_LBUTTONDOWN
) {
2854 // This does not fire due to the hit test code
2855 sciThis
->ct
.MouseClick(Point::FromLong(lParam
));
2856 sciThis
->CallTipClick();
2858 } else if (iMessage
== WM_SETCURSOR
) {
2859 ::SetCursor(::LoadCursor(NULL
, IDC_ARROW
));
2861 } else if (iMessage
== WM_NCHITTEST
) {
2864 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2868 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2870 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2873 sptr_t
ScintillaWin::DirectFunction(
2874 ScintillaWin
*sci
, UINT iMessage
, uptr_t wParam
, sptr_t lParam
) {
2875 PLATFORM_ASSERT(::GetCurrentThreadId() == ::GetWindowThreadProcessId(sci
->MainHWND(), NULL
));
2876 return sci
->WndProc(iMessage
, wParam
, lParam
);
2880 #ifndef STATIC_BUILD
2881 __declspec(dllexport
)
2883 sptr_t __stdcall
Scintilla_DirectFunction(
2884 ScintillaWin
*sci
, UINT iMessage
, uptr_t wParam
, sptr_t lParam
) {
2885 return sci
->WndProc(iMessage
, wParam
, lParam
);
2888 sptr_t PASCAL
ScintillaWin::SWndProc(
2889 HWND hWnd
, UINT iMessage
, WPARAM wParam
, sptr_t lParam
) {
2890 //Platform::DebugPrintf("S W:%x M:%x WP:%x L:%x\n", hWnd, iMessage, wParam, lParam);
2892 // Find C++ object associated with window.
2893 ScintillaWin
*sci
= reinterpret_cast<ScintillaWin
*>(PointerFromWindow(hWnd
));
2894 // sci will be zero if WM_CREATE not seen yet
2897 if (iMessage
== WM_CREATE
) {
2898 // Create C++ object associated with window
2899 sci
= new ScintillaWin(hWnd
);
2900 SetWindowPointer(hWnd
, sci
);
2901 return sci
->WndProc(iMessage
, wParam
, lParam
);
2905 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2907 if (iMessage
== WM_NCDESTROY
) {
2913 ::SetWindowLong(hWnd
, 0, 0);
2914 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2916 return sci
->WndProc(iMessage
, wParam
, lParam
);
2921 // This function is externally visible so it can be called from container when building statically.
2922 // Must be called once only.
2923 int Scintilla_RegisterClasses(void *hInstance
) {
2924 Platform_Initialise(hInstance
);
2925 bool result
= ScintillaWin::Register(reinterpret_cast<HINSTANCE
>(hInstance
));
2927 Scintilla_LinkLexers();
2932 // This function is externally visible so it can be called from container when building statically.
2933 int Scintilla_ReleaseResources() {
2934 bool result
= ScintillaWin::Unregister();
2935 Platform_Finalise();
2939 #ifndef STATIC_BUILD
2940 extern "C" int APIENTRY
DllMain(HINSTANCE hInstance
, DWORD dwReason
, LPVOID
) {
2941 //Platform::DebugPrintf("Scintilla::DllMain %d %d\n", hInstance, dwReason);
2942 if (dwReason
== DLL_PROCESS_ATTACH
) {
2943 if (!Scintilla_RegisterClasses(hInstance
))
2945 } else if (dwReason
== DLL_PROCESS_DETACH
) {
2946 Scintilla_ReleaseResources();