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
30 #include "Scintilla.h"
34 #include "LexerModule.h"
36 #include "SplitVector.h"
37 #include "Partitioning.h"
38 #include "RunStyles.h"
39 #include "ContractionState.h"
40 #include "CellBuffer.h"
43 #include "Indicator.h"
45 #include "LineMarker.h"
47 #include "AutoComplete.h"
48 #include "ViewStyle.h"
49 #include "CharClassify.h"
50 #include "Decoration.h"
52 #include "Selection.h"
53 #include "PositionCache.h"
55 #include "ScintillaBase.h"
56 #include "UniConversion.h"
59 #include "ExternalLexer.h"
62 #ifndef SPI_GETWHEELSCROLLLINES
63 #define SPI_GETWHEELSCROLLLINES 104
67 #define WM_UNICHAR 0x0109
70 #ifndef UNICODE_NOCHAR
71 #define UNICODE_NOCHAR 0xFFFF
74 #ifndef WM_IME_STARTCOMPOSITION
88 #define SC_WIN_IDLE 5001
90 // Functions imported from PlatWin
92 extern void Platform_Initialise(void *hInstance
);
93 extern void Platform_Finalise();
95 typedef BOOL (WINAPI
*TrackMouseEventSig
)(LPTRACKMOUSEEVENT
);
97 // GCC has trouble with the standard COM ABI so do it the old C way with explicit vtables.
99 const TCHAR scintillaClassName
[] = TEXT("Scintilla");
100 const TCHAR callClassName
[] = TEXT("CallTip");
103 using namespace Scintilla
;
106 // Take care of 32/64 bit pointers
107 #ifdef GetWindowLongPtr
108 static void *PointerFromWindow(HWND hWnd
) {
109 return reinterpret_cast<void *>(::GetWindowLongPtr(hWnd
, 0));
111 static void SetWindowPointer(HWND hWnd
, void *ptr
) {
112 ::SetWindowLongPtr(hWnd
, 0, reinterpret_cast<LONG_PTR
>(ptr
));
114 static void SetWindowID(HWND hWnd
, int identifier
) {
115 ::SetWindowLongPtr(hWnd
, GWLP_ID
, identifier
);
118 static void *PointerFromWindow(HWND hWnd
) {
119 return reinterpret_cast<void *>(::GetWindowLong(hWnd
, 0));
121 static void SetWindowPointer(HWND hWnd
, void *ptr
) {
122 ::SetWindowLong(hWnd
, 0, reinterpret_cast<LONG
>(ptr
));
124 static void SetWindowID(HWND hWnd
, int identifier
) {
125 ::SetWindowLong(hWnd
, GWL_ID
, identifier
);
129 class ScintillaWin
; // Forward declaration for COM interface subobjects
131 typedef void VFunction(void);
135 class FormatEnumerator
{
140 CLIPFORMAT formats
[2];
142 FormatEnumerator(int pos_
, CLIPFORMAT formats_
[], int formatsLen_
);
175 public ScintillaBase
{
177 bool lastKeyDownConsumed
;
180 bool trackedMouseLeave
;
181 TrackMouseEventSig TrackMouseEventFn
;
183 unsigned int linesPerScroll
; ///< Intellimouse support
184 int wheelDelta
; ///< Wheel delta from roll
190 CLIPFORMAT cfColumnSelect
;
191 CLIPFORMAT cfLineSelect
;
198 static HINSTANCE hInstance
;
200 ScintillaWin(HWND hwnd
);
201 ScintillaWin(const ScintillaWin
&);
202 virtual ~ScintillaWin();
203 ScintillaWin
&operator=(const ScintillaWin
&);
205 virtual void Initialise();
206 virtual void Finalise();
209 static sptr_t
DirectFunction(
210 ScintillaWin
*sci
, UINT iMessage
, uptr_t wParam
, sptr_t lParam
);
211 static sptr_t PASCAL
SWndProc(
212 HWND hWnd
, UINT iMessage
, WPARAM wParam
, sptr_t lParam
);
213 static sptr_t PASCAL
CTWndProc(
214 HWND hWnd
, UINT iMessage
, WPARAM wParam
, sptr_t lParam
);
216 enum { invalidTimerID
, standardTimerID
, idleTimerID
};
218 virtual bool DragThreshold(Point ptStart
, Point ptNow
);
219 virtual void StartDrag();
220 sptr_t
WndPaint(uptr_t wParam
);
221 sptr_t
HandleComposition(uptr_t wParam
, sptr_t lParam
);
222 UINT
CodePageOfDocument();
223 virtual bool ValidCodePage(int codePage
) const;
224 virtual sptr_t
DefWndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
225 virtual bool SetIdle(bool on
);
226 virtual void SetTicking(bool on
);
227 virtual void SetMouseCapture(bool on
);
228 virtual bool HaveMouseCapture();
229 virtual void SetTrackMouseLeaveEvent(bool on
);
230 virtual bool PaintContains(PRectangle rc
);
231 virtual void ScrollText(int linesToMove
);
232 virtual void UpdateSystemCaret();
233 virtual void SetVerticalScrollPos();
234 virtual void SetHorizontalScrollPos();
235 virtual bool ModifyScrollBars(int nMax
, int nPage
);
236 virtual void NotifyChange();
237 virtual void NotifyFocus(bool focus
);
238 virtual void SetCtrlID(int identifier
);
239 virtual int GetCtrlID();
240 virtual void NotifyParent(SCNotification scn
);
241 virtual void NotifyDoubleClick(Point pt
, bool shift
, bool ctrl
, bool alt
);
242 virtual CaseFolder
*CaseFolderForEncoding();
243 virtual std::string
CaseMapString(const std::string
&s
, int caseMapping
);
245 virtual void CopyAllowLine();
246 virtual bool CanPaste();
247 virtual void Paste();
248 virtual void CreateCallTipWindow(PRectangle rc
);
249 virtual void AddToPopUp(const char *label
, int cmd
= 0, bool enabled
= true);
250 virtual void ClaimSelection();
253 void ImeStartComposition();
254 void ImeEndComposition();
256 void AddCharBytes(char b0
, char b1
);
258 void GetIntelliMouseParameters();
259 virtual void CopyToClipboard(const SelectionText
&selectedText
);
260 void ScrollMessage(WPARAM wParam
);
261 void HorizontalScrollMessage(WPARAM wParam
);
262 void RealizeWindowPalette(bool inBackGround
);
264 void FullPaintDC(HDC dc
);
265 bool IsCompatibleDC(HDC dc
);
266 DWORD
EffectFromState(DWORD grfKeyState
);
268 virtual int SetScrollInfo(int nBar
, LPCSCROLLINFO lpsi
, BOOL bRedraw
);
269 virtual bool GetScrollInfo(int nBar
, LPSCROLLINFO lpsi
);
270 void ChangeScrollPos(int barType
, int pos
);
272 void InsertPasteText(const char *text
, int len
, SelectionPosition selStart
, bool isRectangular
, bool isLine
);
275 // Public for benefit of Scintilla_DirectFunction
276 virtual sptr_t
WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
278 /// Implement IUnknown
279 STDMETHODIMP
QueryInterface(REFIID riid
, PVOID
*ppv
);
280 STDMETHODIMP_(ULONG
)AddRef();
281 STDMETHODIMP_(ULONG
)Release();
283 /// Implement IDropTarget
284 STDMETHODIMP
DragEnter(LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
285 POINTL pt
, PDWORD pdwEffect
);
286 STDMETHODIMP
DragOver(DWORD grfKeyState
, POINTL pt
, PDWORD pdwEffect
);
287 STDMETHODIMP
DragLeave();
288 STDMETHODIMP
Drop(LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
289 POINTL pt
, PDWORD pdwEffect
);
291 /// Implement important part of IDataObject
292 STDMETHODIMP
GetData(FORMATETC
*pFEIn
, STGMEDIUM
*pSTM
);
294 static bool Register(HINSTANCE hInstance_
);
295 static bool Unregister();
297 friend class DropSource
;
298 friend class DataObject
;
299 friend class DropTarget
;
300 bool DragIsRectangularOK(CLIPFORMAT fmt
) {
301 return drag
.rectangular
&& (fmt
== cfColumnSelect
);
305 // For use in creating a system caret
306 bool HasCaretSizeChanged();
307 BOOL
CreateSystemCaret();
308 BOOL
DestroySystemCaret();
309 HBITMAP sysCaretBitmap
;
312 bool keysAlwaysUnicode
;
315 HINSTANCE
ScintillaWin::hInstance
= 0;
317 ScintillaWin::ScintillaWin(HWND hwnd
) {
319 lastKeyDownConsumed
= false;
321 capturedMouse
= false;
322 trackedMouseLeave
= false;
323 TrackMouseEventFn
= 0;
326 wheelDelta
= 0; // Wheel delta from roll
332 // There does not seem to be a real standard for indicating that the clipboard
333 // contains a rectangular selection, so copy Developer Studio.
334 cfColumnSelect
= static_cast<CLIPFORMAT
>(
335 ::RegisterClipboardFormat(TEXT("MSDEVColumnSelect")));
337 // Likewise for line-copy (copies a full line when no text is selected)
338 cfLineSelect
= static_cast<CLIPFORMAT
>(
339 ::RegisterClipboardFormat(TEXT("MSDEVLineSelect")));
353 keysAlwaysUnicode
= false;
355 caret
.period
= ::GetCaretBlinkTime();
356 if (caret
.period
< 0)
362 ScintillaWin::~ScintillaWin() {}
364 void ScintillaWin::Initialise() {
365 // Initialize COM. If the app has already done this it will have
366 // no effect. If the app hasnt, we really shouldnt ask them to call
367 // it just so this internal feature works.
368 hrOle
= ::OleInitialize(NULL
);
370 // Find TrackMouseEvent which is available on Windows > 95
371 HMODULE user32
= ::GetModuleHandle(TEXT("user32.dll"));
372 TrackMouseEventFn
= (TrackMouseEventSig
)::GetProcAddress(user32
, "TrackMouseEvent");
373 if (TrackMouseEventFn
== NULL
) {
374 // Windows 95 has an emulation in comctl32.dll:_TrackMouseEvent
375 HMODULE commctrl32
= ::LoadLibrary(TEXT("comctl32.dll"));
376 if (commctrl32
!= NULL
) {
377 TrackMouseEventFn
= (TrackMouseEventSig
)
378 ::GetProcAddress(commctrl32
, "_TrackMouseEvent");
383 void ScintillaWin::Finalise() {
384 ScintillaBase::Finalise();
387 ::RevokeDragDrop(MainHWND());
388 if (SUCCEEDED(hrOle
)) {
393 HWND
ScintillaWin::MainHWND() {
394 return reinterpret_cast<HWND
>(wMain
.GetID());
397 bool ScintillaWin::DragThreshold(Point ptStart
, Point ptNow
) {
398 int xMove
= abs(ptStart
.x
- ptNow
.x
);
399 int yMove
= abs(ptStart
.y
- ptNow
.y
);
400 return (xMove
> ::GetSystemMetrics(SM_CXDRAG
)) ||
401 (yMove
> ::GetSystemMetrics(SM_CYDRAG
));
404 void ScintillaWin::StartDrag() {
405 inDragDrop
= ddDragging
;
407 dropWentOutside
= true;
408 IDataObject
*pDataObject
= reinterpret_cast<IDataObject
*>(&dob
);
409 IDropSource
*pDropSource
= reinterpret_cast<IDropSource
*>(&ds
);
410 //Platform::DebugPrintf("About to DoDragDrop %x %x\n", pDataObject, pDropSource);
411 HRESULT hr
= ::DoDragDrop(
414 DROPEFFECT_COPY
| DROPEFFECT_MOVE
, &dwEffect
);
415 //Platform::DebugPrintf("DoDragDrop = %x\n", hr);
417 if ((hr
== DRAGDROP_S_DROP
) && (dwEffect
== DROPEFFECT_MOVE
) && dropWentOutside
) {
418 // Remove dragged out text
423 SetDragPosition(SelectionPosition(invalidPosition
));
426 // Avoid warnings everywhere for old style casts by concentrating them here
427 static WORD
LoWord(DWORD l
) {
431 static WORD
HiWord(DWORD l
) {
435 static int InputCodePage() {
436 HKL inputLocale
= ::GetKeyboardLayout(0);
437 LANGID inputLang
= LOWORD(inputLocale
);
439 int res
= ::GetLocaleInfoA(MAKELCID(inputLang
, SORT_DEFAULT
),
440 LOCALE_IDEFAULTANSICODEPAGE
, sCodePage
, sizeof(sCodePage
));
443 return atoi(sCodePage
);
447 static const int VK_OEM_2
=0xbf;
448 static const int VK_OEM_3
=0xc0;
449 static const int VK_OEM_4
=0xdb;
450 static const int VK_OEM_5
=0xdc;
451 static const int VK_OEM_6
=0xdd;
454 /** Map the key codes to their equivalent SCK_ form. */
455 static int KeyTranslate(int keyIn
) {
456 //PLATFORM_ASSERT(!keyIn);
458 case VK_DOWN
: return SCK_DOWN
;
459 case VK_UP
: return SCK_UP
;
460 case VK_LEFT
: return SCK_LEFT
;
461 case VK_RIGHT
: return SCK_RIGHT
;
462 case VK_HOME
: return SCK_HOME
;
463 case VK_END
: return SCK_END
;
464 case VK_PRIOR
: return SCK_PRIOR
;
465 case VK_NEXT
: return SCK_NEXT
;
466 case VK_DELETE
: return SCK_DELETE
;
467 case VK_INSERT
: return SCK_INSERT
;
468 case VK_ESCAPE
: return SCK_ESCAPE
;
469 case VK_BACK
: return SCK_BACK
;
470 case VK_TAB
: return SCK_TAB
;
471 case VK_RETURN
: return SCK_RETURN
;
472 case VK_ADD
: return SCK_ADD
;
473 case VK_SUBTRACT
: return SCK_SUBTRACT
;
474 case VK_DIVIDE
: return SCK_DIVIDE
;
475 case VK_LWIN
: return SCK_WIN
;
476 case VK_RWIN
: return SCK_RWIN
;
477 case VK_APPS
: return SCK_MENU
;
478 case VK_OEM_2
: return '/';
479 case VK_OEM_3
: return '`';
480 case VK_OEM_4
: return '[';
481 case VK_OEM_5
: return '\\';
482 case VK_OEM_6
: return ']';
483 default: return keyIn
;
487 LRESULT
ScintillaWin::WndPaint(uptr_t wParam
) {
490 // Redirect assertions to debug output and save current state
491 bool assertsPopup
= Platform::ShowAssertionPopUps(false);
492 paintState
= painting
;
496 bool IsOcxCtrl
= (wParam
!= 0); // if wParam != 0, it contains
497 // a PAINSTRUCT* from the OCX
498 // Removed since this interferes with reporting other assertions as it occurs repeatedly
499 //PLATFORM_ASSERT(hRgnUpdate == NULL);
500 hRgnUpdate
= ::CreateRectRgn(0, 0, 0, 0);
502 pps
= reinterpret_cast<PAINTSTRUCT
*>(wParam
);
504 ::GetUpdateRgn(MainHWND(), hRgnUpdate
, FALSE
);
506 ::BeginPaint(MainHWND(), pps
);
508 AutoSurface
surfaceWindow(pps
->hdc
, this);
510 rcPaint
= PRectangle(pps
->rcPaint
.left
, pps
->rcPaint
.top
, pps
->rcPaint
.right
, pps
->rcPaint
.bottom
);
511 PRectangle rcClient
= GetClientRectangle();
512 paintingAllText
= rcPaint
.Contains(rcClient
);
513 if (paintingAllText
) {
514 //Platform::DebugPrintf("Performing full text paint\n");
516 //Platform::DebugPrintf("Performing partial paint %d .. %d\n", rcPaint.top, rcPaint.bottom);
518 Paint(surfaceWindow
, rcPaint
);
519 surfaceWindow
->Release();
522 ::DeleteRgn(hRgnUpdate
);
527 ::EndPaint(MainHWND(), pps
);
528 if (paintState
== paintAbandoned
) {
529 // Painting area was insufficient to cover new styling or brace highlight positions
532 paintState
= notPainting
;
534 // Restore debug output state
535 Platform::ShowAssertionPopUps(assertsPopup
);
537 //Platform::DebugPrintf("Paint took %g\n", et.Duration());
541 sptr_t
ScintillaWin::HandleComposition(uptr_t wParam
, sptr_t lParam
) {
543 // Digital Mars compiler does not include Imm library
546 if (lParam
& GCS_RESULTSTR
) {
547 HIMC hIMC
= ::ImmGetContext(MainHWND());
549 const int maxLenInputIME
= 200;
550 wchar_t wcs
[maxLenInputIME
];
551 LONG bytes
= ::ImmGetCompositionStringW(hIMC
,
552 GCS_RESULTSTR
, wcs
, (maxLenInputIME
-1)*2);
553 int wides
= bytes
/ 2;
554 if (IsUnicodeMode()) {
555 char utfval
[maxLenInputIME
* 3];
556 unsigned int len
= UTF8Length(wcs
, wides
);
557 UTF8FromUTF16(wcs
, wides
, utfval
, len
);
559 AddCharUTF(utfval
, len
);
561 char dbcsval
[maxLenInputIME
* 2];
562 int size
= ::WideCharToMultiByte(InputCodePage(),
563 0, wcs
, wides
, dbcsval
, sizeof(dbcsval
) - 1, 0, 0);
564 for (int i
=0; i
<size
; i
++) {
568 // Set new position after converted
569 Point pos
= PointMainCaret();
570 COMPOSITIONFORM CompForm
;
571 CompForm
.dwStyle
= CFS_POINT
;
572 CompForm
.ptCurrentPos
.x
= pos
.x
;
573 CompForm
.ptCurrentPos
.y
= pos
.y
;
574 ::ImmSetCompositionWindow(hIMC
, &CompForm
);
575 ::ImmReleaseContext(MainHWND(), hIMC
);
579 return ::DefWindowProc(MainHWND(), WM_IME_COMPOSITION
, wParam
, lParam
);
583 // Translate message IDs from WM_* and EM_* to SCI_* so can partly emulate Windows Edit control
584 static unsigned int SciMessageFromEM(unsigned int iMessage
) {
586 case EM_CANPASTE
: return SCI_CANPASTE
;
587 case EM_CANUNDO
: return SCI_CANUNDO
;
588 case EM_EMPTYUNDOBUFFER
: return SCI_EMPTYUNDOBUFFER
;
589 case EM_FINDTEXTEX
: return SCI_FINDTEXT
;
590 case EM_FORMATRANGE
: return SCI_FORMATRANGE
;
591 case EM_GETFIRSTVISIBLELINE
: return SCI_GETFIRSTVISIBLELINE
;
592 case EM_GETLINECOUNT
: return SCI_GETLINECOUNT
;
593 case EM_GETSELTEXT
: return SCI_GETSELTEXT
;
594 case EM_GETTEXTRANGE
: return SCI_GETTEXTRANGE
;
595 case EM_HIDESELECTION
: return SCI_HIDESELECTION
;
596 case EM_LINEINDEX
: return SCI_POSITIONFROMLINE
;
597 case EM_LINESCROLL
: return SCI_LINESCROLL
;
598 case EM_REPLACESEL
: return SCI_REPLACESEL
;
599 case EM_SCROLLCARET
: return SCI_SCROLLCARET
;
600 case EM_SETREADONLY
: return SCI_SETREADONLY
;
601 case WM_CLEAR
: return SCI_CLEAR
;
602 case WM_COPY
: return SCI_COPY
;
603 case WM_CUT
: return SCI_CUT
;
604 case WM_GETTEXT
: return SCI_GETTEXT
;
605 case WM_SETTEXT
: return SCI_SETTEXT
;
606 case WM_GETTEXTLENGTH
: return SCI_GETTEXTLENGTH
;
607 case WM_PASTE
: return SCI_PASTE
;
608 case WM_UNDO
: return SCI_UNDO
;
613 static UINT
CodePageFromCharSet(DWORD characterSet
, UINT documentCodePage
) {
614 if (documentCodePage
== SC_CP_UTF8
) {
615 // The system calls here are a little slow so avoid if known case.
618 CHARSETINFO ci
= { 0, 0, { { 0, 0, 0, 0 }, { 0, 0 } } };
619 BOOL bci
= ::TranslateCharsetInfo((DWORD
*)characterSet
,
620 &ci
, TCI_SRCCHARSET
);
626 cp
= documentCodePage
;
629 if (!IsValidCodePage(cp
) && !GetCPInfo(cp
, &cpi
))
635 UINT
ScintillaWin::CodePageOfDocument() {
636 return CodePageFromCharSet(vs
.styles
[STYLE_DEFAULT
].characterSet
, pdoc
->dbcsCodePage
);
639 sptr_t
ScintillaWin::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
641 //Platform::DebugPrintf("S M:%x WP:%x L:%x\n", iMessage, wParam, lParam);
642 iMessage
= SciMessageFromEM(iMessage
);
646 ctrlID
= ::GetDlgCtrlID(reinterpret_cast<HWND
>(wMain
.GetID()));
647 // Get Intellimouse scroll line parameters
648 GetIntelliMouseParameters();
649 ::RegisterDragDrop(MainHWND(), reinterpret_cast<IDropTarget
*>(&dt
));
653 Command(LoWord(wParam
));
657 return WndPaint(wParam
);
659 case WM_PRINTCLIENT
: {
660 HDC hdc
= reinterpret_cast<HDC
>(wParam
);
661 if (!IsCompatibleDC(hdc
)) {
662 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
669 ScrollMessage(wParam
);
673 HorizontalScrollMessage(wParam
);
677 //Platform::DebugPrintf("Scintilla WM_SIZE %d %d\n", LoWord(lParam), HiWord(lParam));
683 // if autocomplete list active then send mousewheel message to it
685 HWND hWnd
= reinterpret_cast<HWND
>(ac
.lb
->GetID());
686 ::SendMessage(hWnd
, iMessage
, wParam
, lParam
);
690 // Don't handle datazoom.
691 // (A good idea for datazoom would be to "fold" or "unfold" details.
692 // i.e. if datazoomed out only class structures are visible, when datazooming in the control
693 // structures appear, then eventually the individual statements...)
694 if (wParam
& MK_SHIFT
) {
695 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
698 // Either SCROLL or ZOOM. We handle the wheel steppings calculation
699 wheelDelta
-= static_cast<short>(HiWord(wParam
));
700 if (abs(wheelDelta
) >= WHEEL_DELTA
&& linesPerScroll
> 0) {
701 int linesToScroll
= linesPerScroll
;
702 if (linesPerScroll
== WHEEL_PAGESCROLL
)
703 linesToScroll
= LinesOnScreen() - 1;
704 if (linesToScroll
== 0) {
707 linesToScroll
*= (wheelDelta
/ WHEEL_DELTA
);
709 wheelDelta
= wheelDelta
% WHEEL_DELTA
;
711 wheelDelta
= - (-wheelDelta
% WHEEL_DELTA
);
713 if (wParam
& MK_CONTROL
) {
714 // Zoom! We play with the font sizes in the styles.
715 // Number of steps/line is ignored, we just care if sizing up or down
716 if (linesToScroll
< 0) {
717 KeyCommand(SCI_ZOOMIN
);
719 KeyCommand(SCI_ZOOMOUT
);
723 ScrollTo(topLine
+ linesToScroll
);
729 if (wParam
== standardTimerID
&& timer
.ticking
) {
731 } else if (wParam
== idleTimerID
&& idler
.state
) {
732 SendMessage(MainHWND(), SC_WIN_IDLE
, 0, 1);
739 // wParam=dwTickCountInitial, or 0 to initialize. lParam=bSkipUserInputTest
741 if (lParam
|| (WAIT_TIMEOUT
== MsgWaitForMultipleObjects(0, 0, 0, 0, QS_INPUT
|QS_HOTKEY
))) {
743 // User input was given priority above, but all events do get a turn. Other
744 // messages, notifications, etc. will get interleaved with the idle messages.
746 // However, some things like WM_PAINT are a lower priority, and will not fire
747 // when there's a message posted. So, several times a second, we stop and let
748 // the low priority events have a turn (after which the timer will fire again).
750 DWORD dwCurrent
= GetTickCount();
751 DWORD dwStart
= wParam
? wParam
: dwCurrent
;
753 if (dwCurrent
>= dwStart
&& dwCurrent
> 200 && dwCurrent
- 200 < dwStart
)
754 PostMessage(MainHWND(), SC_WIN_IDLE
, dwStart
, 0);
762 case WM_GETMINMAXINFO
:
763 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
765 case WM_LBUTTONDOWN
: {
767 // Digital Mars compiler does not include Imm library
768 // For IME, set the composition string as the result string.
769 HIMC hIMC
= ::ImmGetContext(MainHWND());
770 ::ImmNotifyIME(hIMC
, NI_COMPOSITIONSTR
, CPS_COMPLETE
, 0);
771 ::ImmReleaseContext(MainHWND(), hIMC
);
774 //Platform::DebugPrintf("Buttdown %d %x %x %x %x %x\n",iMessage, wParam, lParam,
775 // Platform::IsKeyDown(VK_SHIFT),
776 // Platform::IsKeyDown(VK_CONTROL),
777 // Platform::IsKeyDown(VK_MENU));
778 ::SetFocus(MainHWND());
779 ButtonDown(Point::FromLong(lParam
), ::GetMessageTime(),
780 (wParam
& MK_SHIFT
) != 0,
781 (wParam
& MK_CONTROL
) != 0,
782 Platform::IsKeyDown(VK_MENU
));
787 SetTrackMouseLeaveEvent(true);
788 ButtonMove(Point::FromLong(lParam
));
792 SetTrackMouseLeaveEvent(false);
794 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
797 ButtonUp(Point::FromLong(lParam
),
799 (wParam
& MK_CONTROL
) != 0);
803 ::SetFocus(MainHWND());
804 if (!PointInSelection(Point::FromLong(lParam
))) {
806 SetEmptySelection(PositionFromLocation(Point::FromLong(lParam
)));
811 if (LoWord(lParam
) == HTCLIENT
) {
812 if (inDragDrop
== ddDragging
) {
813 DisplayCursor(Window::cursorUp
);
815 // Display regular (drag) cursor over selection
818 ::ScreenToClient(MainHWND(), &pt
);
819 if (PointInSelMargin(Point(pt
.x
, pt
.y
))) {
820 DisplayCursor(GetMarginCursor(Point(pt
.x
, pt
.y
)));
821 } else if (PointInSelection(Point(pt
.x
, pt
.y
)) && !SelectionEmpty()) {
822 DisplayCursor(Window::cursorArrow
);
823 } else if (PointIsHotspot(Point(pt
.x
, pt
.y
))) {
824 DisplayCursor(Window::cursorHand
);
826 DisplayCursor(Window::cursorText
);
831 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
835 if (((wParam
>= 128) || !iscntrl(wParam
)) || !lastKeyDownConsumed
) {
836 if (::IsWindowUnicode(MainHWND()) || keysAlwaysUnicode
) {
837 wchar_t wcs
[2] = {wParam
, 0};
838 if (IsUnicodeMode()) {
839 // For a wide character version of the window:
841 unsigned int len
= UTF8Length(wcs
, 1);
842 UTF8FromUTF16(wcs
, 1, utfval
, len
);
843 AddCharUTF(utfval
, len
);
845 UINT cpDest
= CodePageOfDocument();
847 int size
= ::WideCharToMultiByte(cpDest
,
848 0, wcs
, 1, inBufferCP
, sizeof(inBufferCP
) - 1, 0, 0);
849 inBufferCP
[size
] = '\0';
850 AddCharUTF(inBufferCP
, size
);
853 if (IsUnicodeMode()) {
854 AddCharBytes('\0', LOBYTE(wParam
));
856 AddChar(LOBYTE(wParam
));
863 if (wParam
== UNICODE_NOCHAR
) {
864 return IsUnicodeMode() ? 1 : 0;
865 } else if (lastKeyDownConsumed
) {
868 if (IsUnicodeMode()) {
870 wchar_t wcs
[2] = {static_cast<wchar_t>(wParam
), 0};
871 unsigned int len
= UTF8Length(wcs
, 1);
872 UTF8FromUTF16(wcs
, 1, utfval
, len
);
873 AddCharUTF(utfval
, len
);
882 //Platform::DebugPrintf("S keydown %d %x %x %x %x\n",iMessage, wParam, lParam, ::IsKeyDown(VK_SHIFT), ::IsKeyDown(VK_CONTROL));
883 lastKeyDownConsumed
= false;
884 int ret
= KeyDown(KeyTranslate(wParam
),
885 Platform::IsKeyDown(VK_SHIFT
),
886 Platform::IsKeyDown(VK_CONTROL
),
887 Platform::IsKeyDown(VK_MENU
),
888 &lastKeyDownConsumed
);
889 if (!ret
&& !lastKeyDownConsumed
) {
890 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
896 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
899 //Platform::DebugPrintf("S keyup %d %x %x\n",iMessage, wParam, lParam);
900 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
902 case WM_SETTINGCHANGE
:
903 //Platform::DebugPrintf("Setting Changed\n");
904 InvalidateStyleData();
905 // Get Intellimouse scroll line parameters
906 GetIntelliMouseParameters();
910 return DLGC_HASSETSEL
| DLGC_WANTALLKEYS
;
913 HWND wOther
= reinterpret_cast<HWND
>(wParam
);
914 HWND wThis
= MainHWND();
915 HWND wCT
= reinterpret_cast<HWND
>(ct
.wCallTip
.GetID());
917 !(::IsChild(wThis
, wOther
) || (wOther
== wCT
))) {
918 SetFocusState(false);
919 DestroySystemCaret();
922 //RealizeWindowPalette(true);
927 RealizeWindowPalette(false);
928 DestroySystemCaret();
932 case WM_SYSCOLORCHANGE
:
933 //Platform::DebugPrintf("Setting Changed\n");
934 InvalidateStyleData();
937 case WM_PALETTECHANGED
:
938 if (wParam
!= reinterpret_cast<uptr_t
>(MainHWND())) {
939 //Platform::DebugPrintf("** Palette Changed\n");
940 RealizeWindowPalette(true);
944 case WM_QUERYNEWPALETTE
:
945 //Platform::DebugPrintf("** Query palette\n");
946 RealizeWindowPalette(false);
949 case WM_IME_STARTCOMPOSITION
: // dbcs
950 ImeStartComposition();
951 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
953 case WM_IME_ENDCOMPOSITION
: // dbcs
955 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
957 case WM_IME_COMPOSITION
:
958 return HandleComposition(wParam
, lParam
);
961 AddCharBytes(HIBYTE(wParam
), LOBYTE(wParam
));
966 if (displayPopupMenu
) {
967 Point pt
= Point::FromLong(lParam
);
968 if ((pt
.x
== -1) && (pt
.y
== -1)) {
969 // Caused by keyboard so display menu near caret
970 pt
= PointMainCaret();
971 POINT spt
= {pt
.x
, pt
.y
};
972 ::ClientToScreen(MainHWND(), &spt
);
973 pt
= Point(spt
.x
, spt
.y
);
978 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
980 case WM_INPUTLANGCHANGE
:
981 //::SetThreadLocale(LOWORD(lParam));
982 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
984 case WM_INPUTLANGCHANGEREQUEST
:
985 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
988 return 1; // Avoid any background erasure as whole window painted.
990 case WM_CAPTURECHANGED
:
991 capturedMouse
= false;
994 // These are not handled in Scintilla and its faster to dispatch them here.
995 // Also moves time out to here so profile doesn't count lots of empty message calls.
998 case WM_MOUSEACTIVATE
:
1002 case WM_NCMOUSEMOVE
:
1003 case WM_NCLBUTTONDOWN
:
1004 case WM_IME_SETCONTEXT
:
1007 case WM_WINDOWPOSCHANGING
:
1008 case WM_WINDOWPOSCHANGED
:
1009 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1011 case EM_LINEFROMCHAR
:
1012 if (static_cast<int>(wParam
) < 0) {
1013 wParam
= SelectionStart().Position();
1015 return pdoc
->LineFromPosition(wParam
);
1017 case EM_EXLINEFROMCHAR
:
1018 return pdoc
->LineFromPosition(lParam
);
1022 *reinterpret_cast<int *>(wParam
) = SelectionStart().Position();
1025 *reinterpret_cast<int *>(lParam
) = SelectionEnd().Position();
1027 return MAKELONG(SelectionStart().Position(), SelectionEnd().Position());
1033 Sci_CharacterRange
*pCR
= reinterpret_cast<Sci_CharacterRange
*>(lParam
);
1034 pCR
->cpMin
= SelectionStart().Position();
1035 pCR
->cpMax
= SelectionEnd().Position();
1040 int nStart
= static_cast<int>(wParam
);
1041 int nEnd
= static_cast<int>(lParam
);
1042 if (nStart
== 0 && nEnd
== -1) {
1043 nEnd
= pdoc
->Length();
1046 nStart
= nEnd
; // Remove selection
1048 if (nStart
> nEnd
) {
1049 SetSelection(nEnd
, nStart
);
1051 SetSelection(nStart
, nEnd
);
1053 EnsureCaretVisible();
1061 Sci_CharacterRange
*pCR
= reinterpret_cast<Sci_CharacterRange
*>(lParam
);
1062 sel
.selType
= Selection::selStream
;
1063 if (pCR
->cpMin
== 0 && pCR
->cpMax
== -1) {
1064 SetSelection(pCR
->cpMin
, pdoc
->Length());
1066 SetSelection(pCR
->cpMin
, pCR
->cpMax
);
1068 EnsureCaretVisible();
1069 return pdoc
->LineFromPosition(SelectionStart().Position());
1072 case SCI_GETDIRECTFUNCTION
:
1073 return reinterpret_cast<sptr_t
>(DirectFunction
);
1075 case SCI_GETDIRECTPOINTER
:
1076 return reinterpret_cast<sptr_t
>(this);
1079 ::SetFocus(MainHWND());
1082 case SCI_SETKEYSUNICODE
:
1083 keysAlwaysUnicode
= wParam
!= 0;
1086 case SCI_GETKEYSUNICODE
:
1087 return keysAlwaysUnicode
;
1090 case SCI_LOADLEXERLIBRARY
:
1091 LexerManager::GetInstance()->Load(reinterpret_cast<const char *>(lParam
));
1096 return ScintillaBase::WndProc(iMessage
, wParam
, lParam
);
1098 } catch (std::bad_alloc
&) {
1099 errorStatus
= SC_STATUS_BADALLOC
;
1101 errorStatus
= SC_STATUS_FAILURE
;
1106 bool ScintillaWin::ValidCodePage(int codePage
) const {
1107 return codePage
== 0 || codePage
== SC_CP_UTF8
||
1108 codePage
== 932 || codePage
== 936 || codePage
== 949 ||
1109 codePage
== 950 || codePage
== 1361;
1112 sptr_t
ScintillaWin::DefWndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
1113 return ::DefWindowProc(MainHWND(), iMessage
, wParam
, lParam
);
1116 void ScintillaWin::SetTicking(bool on
) {
1117 if (timer
.ticking
!= on
) {
1119 if (timer
.ticking
) {
1120 timer
.tickerID
= ::SetTimer(MainHWND(), standardTimerID
, timer
.tickSize
, NULL
)
1121 ? reinterpret_cast<TickerID
>(standardTimerID
) : 0;
1123 ::KillTimer(MainHWND(), reinterpret_cast<uptr_t
>(timer
.tickerID
));
1127 timer
.ticksToWait
= caret
.period
;
1130 bool ScintillaWin::SetIdle(bool on
) {
1131 // On Win32 the Idler is implemented as a Timer on the Scintilla window. This
1132 // takes advantage of the fact that WM_TIMER messages are very low priority,
1133 // and are only posted when the message queue is empty, i.e. during idle time.
1134 if (idler
.state
!= on
) {
1136 idler
.idlerID
= ::SetTimer(MainHWND(), idleTimerID
, 10, NULL
)
1137 ? reinterpret_cast<IdlerID
>(idleTimerID
) : 0;
1139 ::KillTimer(MainHWND(), reinterpret_cast<uptr_t
>(idler
.idlerID
));
1142 idler
.state
= idler
.idlerID
!= 0;
1147 void ScintillaWin::SetMouseCapture(bool on
) {
1148 if (mouseDownCaptures
) {
1150 ::SetCapture(MainHWND());
1158 bool ScintillaWin::HaveMouseCapture() {
1159 // Cannot just see if GetCapture is this window as the scroll bar also sets capture for the window
1160 return capturedMouse
;
1161 //return capturedMouse && (::GetCapture() == MainHWND());
1164 void ScintillaWin::SetTrackMouseLeaveEvent(bool on
) {
1165 if (on
&& TrackMouseEventFn
&& !trackedMouseLeave
) {
1166 TRACKMOUSEEVENT tme
;
1167 tme
.cbSize
= sizeof(tme
);
1168 tme
.dwFlags
= TME_LEAVE
;
1169 tme
.hwndTrack
= MainHWND();
1170 TrackMouseEventFn(&tme
);
1172 trackedMouseLeave
= on
;
1175 bool ScintillaWin::PaintContains(PRectangle rc
) {
1176 bool contains
= true;
1177 if ((paintState
== painting
) && (!rc
.Empty())) {
1178 if (!rcPaint
.Contains(rc
)) {
1181 // In bounding rectangle so check more accurately using region
1182 HRGN hRgnRange
= ::CreateRectRgn(rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
1184 HRGN hRgnDest
= ::CreateRectRgn(0, 0, 0, 0);
1186 int combination
= ::CombineRgn(hRgnDest
, hRgnRange
, hRgnUpdate
, RGN_DIFF
);
1187 if (combination
!= NULLREGION
) {
1190 ::DeleteRgn(hRgnDest
);
1192 ::DeleteRgn(hRgnRange
);
1199 void ScintillaWin::ScrollText(int linesToMove
) {
1200 //Platform::DebugPrintf("ScintillaWin::ScrollText %d\n", linesToMove);
1201 ::ScrollWindow(MainHWND(), 0,
1202 vs
.lineHeight
* linesToMove
, 0, 0);
1203 ::UpdateWindow(MainHWND());
1206 void ScintillaWin::UpdateSystemCaret() {
1208 if (HasCaretSizeChanged()) {
1209 DestroySystemCaret();
1210 CreateSystemCaret();
1212 Point pos
= PointMainCaret();
1213 ::SetCaretPos(pos
.x
, pos
.y
);
1217 int ScintillaWin::SetScrollInfo(int nBar
, LPCSCROLLINFO lpsi
, BOOL bRedraw
) {
1218 return ::SetScrollInfo(MainHWND(), nBar
, lpsi
, bRedraw
);
1221 bool ScintillaWin::GetScrollInfo(int nBar
, LPSCROLLINFO lpsi
) {
1222 return ::GetScrollInfo(MainHWND(), nBar
, lpsi
) ? true : false;
1225 // Change the scroll position but avoid repaint if changing to same value
1226 void ScintillaWin::ChangeScrollPos(int barType
, int pos
) {
1228 sizeof(sci
), 0, 0, 0, 0, 0, 0
1230 sci
.fMask
= SIF_POS
;
1231 GetScrollInfo(barType
, &sci
);
1232 if (sci
.nPos
!= pos
) {
1235 SetScrollInfo(barType
, &sci
, TRUE
);
1239 void ScintillaWin::SetVerticalScrollPos() {
1240 ChangeScrollPos(SB_VERT
, topLine
);
1243 void ScintillaWin::SetHorizontalScrollPos() {
1244 ChangeScrollPos(SB_HORZ
, xOffset
);
1247 bool ScintillaWin::ModifyScrollBars(int nMax
, int nPage
) {
1248 bool modified
= false;
1250 sizeof(sci
), 0, 0, 0, 0, 0, 0
1252 sci
.fMask
= SIF_PAGE
| SIF_RANGE
;
1253 GetScrollInfo(SB_VERT
, &sci
);
1254 int vertEndPreferred
= nMax
;
1255 if (!verticalScrollBarVisible
)
1256 vertEndPreferred
= 0;
1257 if ((sci
.nMin
!= 0) ||
1258 (sci
.nMax
!= vertEndPreferred
) ||
1259 (sci
.nPage
!= static_cast<unsigned int>(nPage
)) ||
1261 //Platform::DebugPrintf("Scroll info changed %d %d %d %d %d\n",
1262 // sci.nMin, sci.nMax, sci.nPage, sci.nPos, sci.nTrackPos);
1263 sci
.fMask
= SIF_PAGE
| SIF_RANGE
;
1265 sci
.nMax
= vertEndPreferred
;
1269 SetScrollInfo(SB_VERT
, &sci
, TRUE
);
1273 PRectangle rcText
= GetTextRectangle();
1274 int horizEndPreferred
= scrollWidth
;
1275 if (horizEndPreferred
< 0)
1276 horizEndPreferred
= 0;
1277 if (!horizontalScrollBarVisible
|| (wrapState
!= eWrapNone
))
1278 horizEndPreferred
= 0;
1279 unsigned int pageWidth
= rcText
.Width();
1280 sci
.fMask
= SIF_PAGE
| SIF_RANGE
;
1281 GetScrollInfo(SB_HORZ
, &sci
);
1282 if ((sci
.nMin
!= 0) ||
1283 (sci
.nMax
!= horizEndPreferred
) ||
1284 (sci
.nPage
!= pageWidth
) ||
1286 sci
.fMask
= SIF_PAGE
| SIF_RANGE
;
1288 sci
.nMax
= horizEndPreferred
;
1289 sci
.nPage
= pageWidth
;
1292 SetScrollInfo(SB_HORZ
, &sci
, TRUE
);
1294 if (scrollWidth
< static_cast<int>(pageWidth
)) {
1295 HorizontalScrollTo(0);
1301 void ScintillaWin::NotifyChange() {
1302 ::SendMessage(::GetParent(MainHWND()), WM_COMMAND
,
1303 MAKELONG(GetCtrlID(), SCEN_CHANGE
),
1304 reinterpret_cast<LPARAM
>(MainHWND()));
1307 void ScintillaWin::NotifyFocus(bool focus
) {
1308 ::SendMessage(::GetParent(MainHWND()), WM_COMMAND
,
1309 MAKELONG(GetCtrlID(), focus
? SCEN_SETFOCUS
: SCEN_KILLFOCUS
),
1310 reinterpret_cast<LPARAM
>(MainHWND()));
1313 void ScintillaWin::SetCtrlID(int identifier
) {
1314 ::SetWindowID(reinterpret_cast<HWND
>(wMain
.GetID()), identifier
);
1317 int ScintillaWin::GetCtrlID() {
1318 return ::GetDlgCtrlID(reinterpret_cast<HWND
>(wMain
.GetID()));
1321 void ScintillaWin::NotifyParent(SCNotification scn
) {
1322 scn
.nmhdr
.hwndFrom
= MainHWND();
1323 scn
.nmhdr
.idFrom
= GetCtrlID();
1324 ::SendMessage(::GetParent(MainHWND()), WM_NOTIFY
,
1325 GetCtrlID(), reinterpret_cast<LPARAM
>(&scn
));
1328 void ScintillaWin::NotifyDoubleClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
1329 //Platform::DebugPrintf("ScintillaWin Double click 0\n");
1330 ScintillaBase::NotifyDoubleClick(pt
, shift
, ctrl
, alt
);
1331 // Send myself a WM_LBUTTONDBLCLK, so the container can handle it too.
1332 ::SendMessage(MainHWND(),
1334 shift
? MK_SHIFT
: 0,
1335 MAKELPARAM(pt
.x
, pt
.y
));
1338 class CaseFolderUTF8
: public CaseFolderTable
{
1339 // Allocate the expandable storage here so that it does not need to be reallocated
1340 // for each call to Fold.
1341 std::vector
<wchar_t> utf16Mixed
;
1342 std::vector
<wchar_t> utf16Folded
;
1347 virtual size_t Fold(char *folded
, size_t sizeFolded
, const char *mixed
, size_t lenMixed
) {
1348 if ((lenMixed
== 1) && (sizeFolded
> 0)) {
1349 folded
[0] = mapping
[static_cast<unsigned char>(mixed
[0])];
1352 if (lenMixed
> utf16Mixed
.size()) {
1353 utf16Mixed
.resize(lenMixed
+ 8);
1355 size_t nUtf16Mixed
= ::MultiByteToWideChar(65001, 0, mixed
,
1356 static_cast<int>(lenMixed
),
1358 static_cast<int>(utf16Mixed
.size()));
1360 if (nUtf16Mixed
== 0) {
1361 // Failed to convert -> bad UTF-8
1366 if (nUtf16Mixed
* 4 > utf16Folded
.size()) { // Maximum folding expansion factor of 4
1367 utf16Folded
.resize(nUtf16Mixed
* 4 + 8);
1369 int lenFlat
= ::LCMapStringW(LOCALE_SYSTEM_DEFAULT
,
1370 LCMAP_LINGUISTIC_CASING
| LCMAP_LOWERCASE
,
1372 static_cast<int>(nUtf16Mixed
),
1374 static_cast<int>(utf16Folded
.size()));
1376 size_t lenOut
= UTF8Length(&utf16Folded
[0], lenFlat
);
1377 if (lenOut
< sizeFolded
) {
1378 UTF8FromUTF16(&utf16Folded
[0], lenFlat
, folded
, static_cast<int>(lenOut
));
1387 class CaseFolderDBCS
: public CaseFolderTable
{
1388 // Allocate the expandable storage here so that it does not need to be reallocated
1389 // for each call to Fold.
1390 std::vector
<wchar_t> utf16Mixed
;
1391 std::vector
<wchar_t> utf16Folded
;
1394 CaseFolderDBCS(UINT cp_
) : cp(cp_
) {
1397 virtual size_t Fold(char *folded
, size_t sizeFolded
, const char *mixed
, size_t lenMixed
) {
1398 if ((lenMixed
== 1) && (sizeFolded
> 0)) {
1399 folded
[0] = mapping
[static_cast<unsigned char>(mixed
[0])];
1402 if (lenMixed
> utf16Mixed
.size()) {
1403 utf16Mixed
.resize(lenMixed
+ 8);
1405 size_t nUtf16Mixed
= ::MultiByteToWideChar(cp
, 0, mixed
,
1406 static_cast<int>(lenMixed
),
1408 static_cast<int>(utf16Mixed
.size()));
1410 if (nUtf16Mixed
== 0) {
1411 // Failed to convert -> bad input
1416 if (nUtf16Mixed
* 4 > utf16Folded
.size()) { // Maximum folding expansion factor of 4
1417 utf16Folded
.resize(nUtf16Mixed
* 4 + 8);
1419 int lenFlat
= ::LCMapStringW(LOCALE_SYSTEM_DEFAULT
,
1420 LCMAP_LINGUISTIC_CASING
| LCMAP_LOWERCASE
,
1422 static_cast<int>(nUtf16Mixed
),
1424 static_cast<int>(utf16Folded
.size()));
1426 size_t lenOut
= ::WideCharToMultiByte(cp
, 0,
1427 &utf16Folded
[0], lenFlat
,
1430 if (lenOut
< sizeFolded
) {
1431 ::WideCharToMultiByte(cp
, 0,
1432 &utf16Folded
[0], lenFlat
,
1433 folded
, static_cast<int>(lenOut
), NULL
, 0);
1442 CaseFolder
*ScintillaWin::CaseFolderForEncoding() {
1443 UINT cpDest
= CodePageOfDocument();
1444 if (cpDest
== SC_CP_UTF8
) {
1445 return new CaseFolderUTF8();
1447 if (pdoc
->dbcsCodePage
== 0) {
1448 CaseFolderTable
*pcf
= new CaseFolderTable();
1449 pcf
->StandardASCII();
1450 // Only for single byte encodings
1451 UINT cpDoc
= CodePageOfDocument();
1452 for (int i
=0x80; i
<0x100; i
++) {
1453 char sCharacter
[2] = "A";
1454 sCharacter
[0] = static_cast<char>(i
);
1455 wchar_t wCharacter
[20];
1456 unsigned int lengthUTF16
= ::MultiByteToWideChar(cpDoc
, 0, sCharacter
, 1,
1457 wCharacter
, sizeof(wCharacter
)/sizeof(wCharacter
[0]));
1458 if (lengthUTF16
== 1) {
1460 int charsConverted
= ::LCMapStringW(LOCALE_SYSTEM_DEFAULT
,
1461 LCMAP_LINGUISTIC_CASING
| LCMAP_LOWERCASE
,
1462 wCharacter
, lengthUTF16
, wLower
, sizeof(wLower
)/sizeof(wLower
[0]));
1463 char sCharacterLowered
[20];
1464 unsigned int lengthConverted
= ::WideCharToMultiByte(cpDoc
, 0,
1465 wLower
, charsConverted
,
1466 sCharacterLowered
, sizeof(sCharacterLowered
), NULL
, 0);
1467 if ((lengthConverted
== 1) && (sCharacter
[0] != sCharacterLowered
[0])) {
1468 pcf
->SetTranslation(sCharacter
[0], sCharacterLowered
[0]);
1474 return new CaseFolderDBCS(cpDest
);
1479 std::string
ScintillaWin::CaseMapString(const std::string
&s
, int caseMapping
) {
1481 return std::string();
1483 if (caseMapping
== cmSame
)
1486 UINT cpDoc
= CodePageOfDocument();
1488 unsigned int lengthUTF16
= ::MultiByteToWideChar(cpDoc
, 0, s
.c_str(),
1489 static_cast<int>(s
.size()), NULL
, 0);
1490 if (lengthUTF16
== 0) // Failed to convert
1493 DWORD mapFlags
= LCMAP_LINGUISTIC_CASING
|
1494 ((caseMapping
== cmUpper
) ? LCMAP_UPPERCASE
: LCMAP_LOWERCASE
);
1496 // Many conversions performed by search function are short so optimize this case.
1497 enum { shortSize
=20 };
1499 if (s
.size() > shortSize
) {
1500 // Use dynamic allocations for long strings
1502 // Change text to UTF-16
1503 std::vector
<wchar_t> vwcText(lengthUTF16
);
1504 ::MultiByteToWideChar(cpDoc
, 0, s
.c_str(), static_cast<int>(s
.size()), &vwcText
[0], lengthUTF16
);
1507 int charsConverted
= ::LCMapStringW(LOCALE_SYSTEM_DEFAULT
, mapFlags
,
1508 &vwcText
[0], lengthUTF16
, NULL
, 0);
1509 std::vector
<wchar_t> vwcConverted(charsConverted
);
1510 ::LCMapStringW(LOCALE_SYSTEM_DEFAULT
, mapFlags
,
1511 &vwcText
[0], lengthUTF16
, &vwcConverted
[0], charsConverted
);
1513 // Change back to document encoding
1514 unsigned int lengthConverted
= ::WideCharToMultiByte(cpDoc
, 0,
1515 &vwcConverted
[0], static_cast<int>(vwcConverted
.size()),
1517 std::vector
<char> vcConverted(lengthConverted
);
1518 ::WideCharToMultiByte(cpDoc
, 0,
1519 &vwcConverted
[0], static_cast<int>(vwcConverted
.size()),
1520 &vcConverted
[0], static_cast<int>(vcConverted
.size()), NULL
, 0);
1522 return std::string(&vcConverted
[0], vcConverted
.size());
1525 // Use static allocations for short strings as much faster
1526 // A factor of 15 for single character strings
1528 // Change text to UTF-16
1529 wchar_t vwcText
[shortSize
];
1530 ::MultiByteToWideChar(cpDoc
, 0, s
.c_str(), static_cast<int>(s
.size()),
1531 vwcText
, lengthUTF16
);
1534 int charsConverted
= ::LCMapStringW(LOCALE_SYSTEM_DEFAULT
, mapFlags
,
1535 vwcText
, lengthUTF16
, NULL
, 0);
1536 // Full mapping may produce up to 3 characters per input character
1537 wchar_t vwcConverted
[shortSize
*3];
1538 ::LCMapStringW(LOCALE_SYSTEM_DEFAULT
, mapFlags
, vwcText
, lengthUTF16
,
1539 vwcConverted
, charsConverted
);
1541 // Change back to document encoding
1542 unsigned int lengthConverted
= ::WideCharToMultiByte(cpDoc
, 0,
1543 vwcConverted
, charsConverted
,
1545 // Each UTF-16 code unit may need up to 3 bytes in UTF-8
1546 char vcConverted
[shortSize
* 3 * 3];
1547 ::WideCharToMultiByte(cpDoc
, 0,
1548 vwcConverted
, charsConverted
,
1549 vcConverted
, lengthConverted
, NULL
, 0);
1551 return std::string(vcConverted
, lengthConverted
);
1555 void ScintillaWin::Copy() {
1556 //Platform::DebugPrintf("Copy\n");
1558 SelectionText selectedText
;
1559 CopySelectionRange(&selectedText
);
1560 CopyToClipboard(selectedText
);
1564 void ScintillaWin::CopyAllowLine() {
1565 SelectionText selectedText
;
1566 CopySelectionRange(&selectedText
, true);
1567 CopyToClipboard(selectedText
);
1570 bool ScintillaWin::CanPaste() {
1571 if (!Editor::CanPaste())
1573 if (::IsClipboardFormatAvailable(CF_TEXT
))
1575 if (IsUnicodeMode())
1576 return ::IsClipboardFormatAvailable(CF_UNICODETEXT
) != 0;
1580 class GlobalMemory
{
1584 GlobalMemory() : hand(0), ptr(0) {
1586 GlobalMemory(HGLOBAL hand_
) : hand(hand_
), ptr(0) {
1588 ptr
= ::GlobalLock(hand
);
1592 PLATFORM_ASSERT(!ptr
);
1594 void Allocate(size_t bytes
) {
1595 hand
= ::GlobalAlloc(GMEM_MOVEABLE
| GMEM_ZEROINIT
, bytes
);
1597 ptr
= ::GlobalLock(hand
);
1601 PLATFORM_ASSERT(ptr
);
1602 HGLOBAL handCopy
= hand
;
1603 ::GlobalUnlock(hand
);
1608 void SetClip(UINT uFormat
) {
1609 ::SetClipboardData(uFormat
, Unlock());
1611 operator bool() const {
1615 return ::GlobalSize(hand
);
1619 void ScintillaWin::InsertPasteText(const char *text
, int len
, SelectionPosition selStart
, bool isRectangular
, bool isLine
) {
1620 if (isRectangular
) {
1621 PasteRectangular(selStart
, text
, len
);
1623 char *convertedText
= 0;
1624 if (convertPastes
) {
1625 // Convert line endings of the paste into our local line-endings mode
1626 convertedText
= Document::TransformLineEnds(&len
, text
, len
, pdoc
->eolMode
);
1627 text
= convertedText
;
1630 int insertPos
= pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret()));
1631 pdoc
->InsertString(insertPos
, text
, len
);
1632 // add the newline if necessary
1633 if ((len
> 0) && (text
[len
-1] != '\n' && text
[len
-1] != '\r')) {
1634 const char *endline
= StringFromEOLMode(pdoc
->eolMode
);
1635 pdoc
->InsertString(insertPos
+ len
, endline
, static_cast<int>(strlen(endline
)));
1636 len
+= static_cast<int>(strlen(endline
));
1638 if (sel
.MainCaret() == insertPos
) {
1639 SetEmptySelection(sel
.MainCaret() + len
);
1642 InsertPaste(selStart
, text
, len
);
1644 delete []convertedText
;
1648 void ScintillaWin::Paste() {
1649 if (!::OpenClipboard(MainHWND()))
1652 bool isLine
= SelectionEmpty() && (::IsClipboardFormatAvailable(cfLineSelect
) != 0);
1653 ClearSelection(multiPasteMode
== SC_MULTIPASTE_EACH
);
1654 SelectionPosition selStart
= sel
.IsRectangular() ?
1655 sel
.Rectangular().Start() :
1656 sel
.Range(sel
.Main()).Start();
1657 bool isRectangular
= ::IsClipboardFormatAvailable(cfColumnSelect
) != 0;
1659 // Always use CF_UNICODETEXT if available
1660 GlobalMemory
memUSelection(::GetClipboardData(CF_UNICODETEXT
));
1661 if (memUSelection
) {
1662 wchar_t *uptr
= static_cast<wchar_t *>(memUSelection
.ptr
);
1666 // Default Scintilla behaviour in Unicode mode
1667 if (IsUnicodeMode()) {
1668 unsigned int bytes
= memUSelection
.Size();
1669 len
= UTF8Length(uptr
, bytes
/ 2);
1670 putf
= new char[len
+ 1];
1671 UTF8FromUTF16(uptr
, bytes
/ 2, putf
, len
);
1673 // CF_UNICODETEXT available, but not in Unicode mode
1674 // Convert from Unicode to current Scintilla code page
1675 UINT cpDest
= CodePageOfDocument();
1676 len
= ::WideCharToMultiByte(cpDest
, 0, uptr
, -1,
1677 NULL
, 0, NULL
, NULL
) - 1; // subtract 0 terminator
1678 putf
= new char[len
+ 1];
1679 ::WideCharToMultiByte(cpDest
, 0, uptr
, -1,
1680 putf
, len
+ 1, NULL
, NULL
);
1683 InsertPasteText(putf
, len
, selStart
, isRectangular
, isLine
);
1686 memUSelection
.Unlock();
1688 // CF_UNICODETEXT not available, paste ANSI text
1689 GlobalMemory
memSelection(::GetClipboardData(CF_TEXT
));
1691 char *ptr
= static_cast<char *>(memSelection
.ptr
);
1693 unsigned int bytes
= memSelection
.Size();
1694 unsigned int len
= bytes
;
1695 for (unsigned int i
= 0; i
< bytes
; i
++) {
1696 if ((len
== bytes
) && (0 == ptr
[i
]))
1700 // In Unicode mode, convert clipboard text to UTF-8
1701 if (IsUnicodeMode()) {
1702 wchar_t *uptr
= new wchar_t[len
+1];
1704 unsigned int ulen
= ::MultiByteToWideChar(CP_ACP
, 0,
1705 ptr
, len
, uptr
, len
+1);
1707 unsigned int mlen
= UTF8Length(uptr
, ulen
);
1708 char *putf
= new char[mlen
+ 1];
1710 // CP_UTF8 not available on Windows 95, so use UTF8FromUTF16()
1711 UTF8FromUTF16(uptr
, ulen
, putf
, mlen
);
1717 InsertPasteText(putf
, mlen
, selStart
, isRectangular
, isLine
);
1721 InsertPasteText(ptr
, len
, selStart
, isRectangular
, isLine
);
1724 memSelection
.Unlock();
1731 void ScintillaWin::CreateCallTipWindow(PRectangle
) {
1732 if (!ct
.wCallTip
.Created()) {
1733 ct
.wCallTip
= ::CreateWindow(callClassName
, TEXT("ACallTip"),
1734 WS_POPUP
, 100, 100, 150, 20,
1736 GetWindowInstance(MainHWND()),
1738 ct
.wDraw
= ct
.wCallTip
;
1742 void ScintillaWin::AddToPopUp(const char *label
, int cmd
, bool enabled
) {
1743 HMENU hmenuPopup
= reinterpret_cast<HMENU
>(popup
.GetID());
1745 ::AppendMenuA(hmenuPopup
, MF_SEPARATOR
, 0, "");
1747 ::AppendMenuA(hmenuPopup
, MF_STRING
, cmd
, label
);
1749 ::AppendMenuA(hmenuPopup
, MF_STRING
| MF_DISABLED
| MF_GRAYED
, cmd
, label
);
1752 void ScintillaWin::ClaimSelection() {
1753 // Windows does not have a primary selection
1756 /// Implement IUnknown
1758 STDMETHODIMP_(ULONG
)FormatEnumerator_AddRef(FormatEnumerator
*fe
);
1759 STDMETHODIMP
FormatEnumerator_QueryInterface(FormatEnumerator
*fe
, REFIID riid
, PVOID
*ppv
) {
1760 //Platform::DebugPrintf("EFE QI");
1762 if (riid
== IID_IUnknown
)
1763 *ppv
= reinterpret_cast<IEnumFORMATETC
*>(fe
);
1764 if (riid
== IID_IEnumFORMATETC
)
1765 *ppv
= reinterpret_cast<IEnumFORMATETC
*>(fe
);
1767 return E_NOINTERFACE
;
1768 FormatEnumerator_AddRef(fe
);
1771 STDMETHODIMP_(ULONG
)FormatEnumerator_AddRef(FormatEnumerator
*fe
) {
1774 STDMETHODIMP_(ULONG
)FormatEnumerator_Release(FormatEnumerator
*fe
) {
1781 /// Implement IEnumFORMATETC
1782 STDMETHODIMP
FormatEnumerator_Next(FormatEnumerator
*fe
, ULONG celt
, FORMATETC
*rgelt
, ULONG
*pceltFetched
) {
1783 //Platform::DebugPrintf("EFE Next %d %d", fe->pos, celt);
1784 if (rgelt
== NULL
) return E_POINTER
;
1785 // We only support one format, so this is simple.
1786 unsigned int putPos
= 0;
1787 while ((fe
->pos
< fe
->formatsLen
) && (putPos
< celt
)) {
1788 rgelt
->cfFormat
= fe
->formats
[fe
->pos
];
1790 rgelt
->dwAspect
= DVASPECT_CONTENT
;
1792 rgelt
->tymed
= TYMED_HGLOBAL
;
1797 *pceltFetched
= putPos
;
1798 return putPos
? S_OK
: S_FALSE
;
1800 STDMETHODIMP
FormatEnumerator_Skip(FormatEnumerator
*fe
, ULONG celt
) {
1804 STDMETHODIMP
FormatEnumerator_Reset(FormatEnumerator
*fe
) {
1808 STDMETHODIMP
FormatEnumerator_Clone(FormatEnumerator
*fe
, IEnumFORMATETC
**ppenum
) {
1809 FormatEnumerator
*pfe
;
1811 pfe
= new FormatEnumerator(fe
->pos
, fe
->formats
, fe
->formatsLen
);
1813 return E_OUTOFMEMORY
;
1815 return FormatEnumerator_QueryInterface(pfe
, IID_IEnumFORMATETC
,
1816 reinterpret_cast<void **>(ppenum
));
1819 static VFunction
*vtFormatEnumerator
[] = {
1820 (VFunction
*)(FormatEnumerator_QueryInterface
),
1821 (VFunction
*)(FormatEnumerator_AddRef
),
1822 (VFunction
*)(FormatEnumerator_Release
),
1823 (VFunction
*)(FormatEnumerator_Next
),
1824 (VFunction
*)(FormatEnumerator_Skip
),
1825 (VFunction
*)(FormatEnumerator_Reset
),
1826 (VFunction
*)(FormatEnumerator_Clone
)
1829 FormatEnumerator::FormatEnumerator(int pos_
, CLIPFORMAT formats_
[], int formatsLen_
) {
1830 vtbl
= vtFormatEnumerator
;
1831 ref
= 0; // First QI adds first reference...
1833 formatsLen
= formatsLen_
;
1834 for (int i
=0; i
<formatsLen
; i
++)
1835 formats
[i
] = formats_
[i
];
1838 /// Implement IUnknown
1839 STDMETHODIMP
DropSource_QueryInterface(DropSource
*ds
, REFIID riid
, PVOID
*ppv
) {
1840 return ds
->sci
->QueryInterface(riid
, ppv
);
1842 STDMETHODIMP_(ULONG
)DropSource_AddRef(DropSource
*ds
) {
1843 return ds
->sci
->AddRef();
1845 STDMETHODIMP_(ULONG
)DropSource_Release(DropSource
*ds
) {
1846 return ds
->sci
->Release();
1849 /// Implement IDropSource
1850 STDMETHODIMP
DropSource_QueryContinueDrag(DropSource
*, BOOL fEsc
, DWORD grfKeyState
) {
1852 return DRAGDROP_S_CANCEL
;
1853 if (!(grfKeyState
& MK_LBUTTON
))
1854 return DRAGDROP_S_DROP
;
1858 STDMETHODIMP
DropSource_GiveFeedback(DropSource
*, DWORD
) {
1859 return DRAGDROP_S_USEDEFAULTCURSORS
;
1862 static VFunction
*vtDropSource
[] = {
1863 (VFunction
*)(DropSource_QueryInterface
),
1864 (VFunction
*)(DropSource_AddRef
),
1865 (VFunction
*)(DropSource_Release
),
1866 (VFunction
*)(DropSource_QueryContinueDrag
),
1867 (VFunction
*)(DropSource_GiveFeedback
)
1870 DropSource::DropSource() {
1871 vtbl
= vtDropSource
;
1875 /// Implement IUnkown
1876 STDMETHODIMP
DataObject_QueryInterface(DataObject
*pd
, REFIID riid
, PVOID
*ppv
) {
1877 //Platform::DebugPrintf("DO QI %x\n", pd);
1878 return pd
->sci
->QueryInterface(riid
, ppv
);
1880 STDMETHODIMP_(ULONG
)DataObject_AddRef(DataObject
*pd
) {
1881 return pd
->sci
->AddRef();
1883 STDMETHODIMP_(ULONG
)DataObject_Release(DataObject
*pd
) {
1884 return pd
->sci
->Release();
1886 /// Implement IDataObject
1887 STDMETHODIMP
DataObject_GetData(DataObject
*pd
, FORMATETC
*pFEIn
, STGMEDIUM
*pSTM
) {
1888 return pd
->sci
->GetData(pFEIn
, pSTM
);
1891 STDMETHODIMP
DataObject_GetDataHere(DataObject
*, FORMATETC
*, STGMEDIUM
*) {
1892 //Platform::DebugPrintf("DOB GetDataHere\n");
1896 STDMETHODIMP
DataObject_QueryGetData(DataObject
*pd
, FORMATETC
*pFE
) {
1897 if (pd
->sci
->DragIsRectangularOK(pFE
->cfFormat
) &&
1899 (pFE
->dwAspect
& DVASPECT_CONTENT
) != 0 &&
1900 pFE
->lindex
== -1 &&
1901 (pFE
->tymed
& TYMED_HGLOBAL
) != 0
1906 bool formatOK
= (pFE
->cfFormat
== CF_TEXT
) ||
1907 ((pFE
->cfFormat
== CF_UNICODETEXT
) && pd
->sci
->IsUnicodeMode());
1910 (pFE
->dwAspect
& DVASPECT_CONTENT
) == 0 ||
1911 pFE
->lindex
!= -1 ||
1912 (pFE
->tymed
& TYMED_HGLOBAL
) == 0
1914 //Platform::DebugPrintf("DOB QueryGetData No %x\n",pFE->cfFormat);
1915 //return DATA_E_FORMATETC;
1918 //Platform::DebugPrintf("DOB QueryGetData OK %x\n",pFE->cfFormat);
1922 STDMETHODIMP
DataObject_GetCanonicalFormatEtc(DataObject
*pd
, FORMATETC
*, FORMATETC
*pFEOut
) {
1923 //Platform::DebugPrintf("DOB GetCanon\n");
1924 if (pd
->sci
->IsUnicodeMode())
1925 pFEOut
->cfFormat
= CF_UNICODETEXT
;
1927 pFEOut
->cfFormat
= CF_TEXT
;
1929 pFEOut
->dwAspect
= DVASPECT_CONTENT
;
1930 pFEOut
->lindex
= -1;
1931 pFEOut
->tymed
= TYMED_HGLOBAL
;
1935 STDMETHODIMP
DataObject_SetData(DataObject
*, FORMATETC
*, STGMEDIUM
*, BOOL
) {
1936 //Platform::DebugPrintf("DOB SetData\n");
1940 STDMETHODIMP
DataObject_EnumFormatEtc(DataObject
*pd
, DWORD dwDirection
, IEnumFORMATETC
**ppEnum
) {
1942 //Platform::DebugPrintf("DOB EnumFormatEtc %d\n", dwDirection);
1943 if (dwDirection
!= DATADIR_GET
) {
1947 FormatEnumerator
*pfe
;
1948 if (pd
->sci
->IsUnicodeMode()) {
1949 CLIPFORMAT formats
[] = {CF_UNICODETEXT
, CF_TEXT
};
1950 pfe
= new FormatEnumerator(0, formats
, 2);
1952 CLIPFORMAT formats
[] = {CF_TEXT
};
1953 pfe
= new FormatEnumerator(0, formats
, 1);
1955 return FormatEnumerator_QueryInterface(pfe
, IID_IEnumFORMATETC
,
1956 reinterpret_cast<void **>(ppEnum
));
1957 } catch (std::bad_alloc
&) {
1958 pd
->sci
->errorStatus
= SC_STATUS_BADALLOC
;
1959 return E_OUTOFMEMORY
;
1961 pd
->sci
->errorStatus
= SC_STATUS_FAILURE
;
1966 STDMETHODIMP
DataObject_DAdvise(DataObject
*, FORMATETC
*, DWORD
, IAdviseSink
*, PDWORD
) {
1967 //Platform::DebugPrintf("DOB DAdvise\n");
1971 STDMETHODIMP
DataObject_DUnadvise(DataObject
*, DWORD
) {
1972 //Platform::DebugPrintf("DOB DUnadvise\n");
1976 STDMETHODIMP
DataObject_EnumDAdvise(DataObject
*, IEnumSTATDATA
**) {
1977 //Platform::DebugPrintf("DOB EnumDAdvise\n");
1981 static VFunction
*vtDataObject
[] = {
1982 (VFunction
*)(DataObject_QueryInterface
),
1983 (VFunction
*)(DataObject_AddRef
),
1984 (VFunction
*)(DataObject_Release
),
1985 (VFunction
*)(DataObject_GetData
),
1986 (VFunction
*)(DataObject_GetDataHere
),
1987 (VFunction
*)(DataObject_QueryGetData
),
1988 (VFunction
*)(DataObject_GetCanonicalFormatEtc
),
1989 (VFunction
*)(DataObject_SetData
),
1990 (VFunction
*)(DataObject_EnumFormatEtc
),
1991 (VFunction
*)(DataObject_DAdvise
),
1992 (VFunction
*)(DataObject_DUnadvise
),
1993 (VFunction
*)(DataObject_EnumDAdvise
)
1996 DataObject::DataObject() {
1997 vtbl
= vtDataObject
;
2001 /// Implement IUnknown
2002 STDMETHODIMP
DropTarget_QueryInterface(DropTarget
*dt
, REFIID riid
, PVOID
*ppv
) {
2003 //Platform::DebugPrintf("DT QI %x\n", dt);
2004 return dt
->sci
->QueryInterface(riid
, ppv
);
2006 STDMETHODIMP_(ULONG
)DropTarget_AddRef(DropTarget
*dt
) {
2007 return dt
->sci
->AddRef();
2009 STDMETHODIMP_(ULONG
)DropTarget_Release(DropTarget
*dt
) {
2010 return dt
->sci
->Release();
2013 /// Implement IDropTarget by forwarding to Scintilla
2014 STDMETHODIMP
DropTarget_DragEnter(DropTarget
*dt
, LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
2015 POINTL pt
, PDWORD pdwEffect
) {
2017 return dt
->sci
->DragEnter(pIDataSource
, grfKeyState
, pt
, pdwEffect
);
2019 dt
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2023 STDMETHODIMP
DropTarget_DragOver(DropTarget
*dt
, DWORD grfKeyState
, POINTL pt
, PDWORD pdwEffect
) {
2025 return dt
->sci
->DragOver(grfKeyState
, pt
, pdwEffect
);
2027 dt
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2031 STDMETHODIMP
DropTarget_DragLeave(DropTarget
*dt
) {
2033 return dt
->sci
->DragLeave();
2035 dt
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2039 STDMETHODIMP
DropTarget_Drop(DropTarget
*dt
, LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
2040 POINTL pt
, PDWORD pdwEffect
) {
2042 return dt
->sci
->Drop(pIDataSource
, grfKeyState
, pt
, pdwEffect
);
2044 dt
->sci
->errorStatus
= SC_STATUS_FAILURE
;
2049 static VFunction
*vtDropTarget
[] = {
2050 (VFunction
*)(DropTarget_QueryInterface
),
2051 (VFunction
*)(DropTarget_AddRef
),
2052 (VFunction
*)(DropTarget_Release
),
2053 (VFunction
*)(DropTarget_DragEnter
),
2054 (VFunction
*)(DropTarget_DragOver
),
2055 (VFunction
*)(DropTarget_DragLeave
),
2056 (VFunction
*)(DropTarget_Drop
)
2059 DropTarget::DropTarget() {
2060 vtbl
= vtDropTarget
;
2065 * DBCS: support Input Method Editor (IME).
2066 * Called when IME Window opened.
2068 void ScintillaWin::ImeStartComposition() {
2070 // Digital Mars compiler does not include Imm library
2072 // Move IME Window to current caret position
2073 HIMC hIMC
= ::ImmGetContext(MainHWND());
2074 Point pos
= PointMainCaret();
2075 COMPOSITIONFORM CompForm
;
2076 CompForm
.dwStyle
= CFS_POINT
;
2077 CompForm
.ptCurrentPos
.x
= pos
.x
;
2078 CompForm
.ptCurrentPos
.y
= pos
.y
;
2080 ::ImmSetCompositionWindow(hIMC
, &CompForm
);
2082 // Set font of IME window to same as surrounded text.
2084 // Since the style creation code has been made platform independent,
2085 // The logfont for the IME is recreated here.
2086 int styleHere
= (pdoc
->StyleAt(sel
.MainCaret())) & 31;
2087 LOGFONTA lf
= {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ""};
2088 int sizeZoomed
= vs
.styles
[styleHere
].size
+ vs
.zoomLevel
;
2089 if (sizeZoomed
<= 2) // Hangs if sizeZoomed <= 1
2091 AutoSurface
surface(this);
2092 int deviceHeight
= sizeZoomed
;
2094 deviceHeight
= (sizeZoomed
* surface
->LogPixelsY()) / 72;
2096 // The negative is to allow for leading
2097 lf
.lfHeight
= -(abs(deviceHeight
));
2098 lf
.lfWeight
= vs
.styles
[styleHere
].bold
? FW_BOLD
: FW_NORMAL
;
2099 lf
.lfItalic
= static_cast<BYTE
>(vs
.styles
[styleHere
].italic
? 1 : 0);
2100 lf
.lfCharSet
= DEFAULT_CHARSET
;
2101 lf
.lfFaceName
[0] = '\0';
2102 if (vs
.styles
[styleHere
].fontName
)
2103 strcpy(lf
.lfFaceName
, vs
.styles
[styleHere
].fontName
);
2105 ::ImmSetCompositionFontA(hIMC
, &lf
);
2107 ::ImmReleaseContext(MainHWND(), hIMC
);
2108 // Caret is displayed in IME window. So, caret in Scintilla is useless.
2114 /** Called when IME Window closed. */
2115 void ScintillaWin::ImeEndComposition() {
2116 ShowCaretAtCurrentPosition();
2119 void ScintillaWin::AddCharBytes(char b0
, char b1
) {
2121 int inputCodePage
= InputCodePage();
2122 if (inputCodePage
&& IsUnicodeMode()) {
2123 char utfval
[4] = "\0\0\0";
2126 if (b0
) { // Two bytes from IME
2129 ansiChars
[2] = '\0';
2130 ::MultiByteToWideChar(inputCodePage
, 0, ansiChars
, 2, wcs
, 1);
2133 ansiChars
[1] = '\0';
2134 ::MultiByteToWideChar(inputCodePage
, 0, ansiChars
, 1, wcs
, 1);
2136 unsigned int len
= UTF8Length(wcs
, 1);
2137 UTF8FromUTF16(wcs
, 1, utfval
, len
);
2139 AddCharUTF(utfval
, len
? len
: 1);
2144 dbcsChars
[2] = '\0';
2145 AddCharUTF(dbcsChars
, 2, true);
2151 void ScintillaWin::GetIntelliMouseParameters() {
2152 // This retrieves the number of lines per scroll as configured inthe Mouse Properties sheet in Control Panel
2153 ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0, &linesPerScroll
, 0);
2156 void ScintillaWin::CopyToClipboard(const SelectionText
&selectedText
) {
2157 if (!::OpenClipboard(MainHWND()))
2161 GlobalMemory uniText
;
2163 // Default Scintilla behaviour in Unicode mode
2164 if (IsUnicodeMode()) {
2165 int uchars
= UTF16Length(selectedText
.s
, selectedText
.len
);
2166 uniText
.Allocate(2 * uchars
);
2168 UTF16FromUTF8(selectedText
.s
, selectedText
.len
, static_cast<wchar_t *>(uniText
.ptr
), uchars
);
2172 // Convert to Unicode using the current Scintilla code page
2173 UINT cpSrc
= CodePageFromCharSet(
2174 selectedText
.characterSet
, selectedText
.codePage
);
2175 int uLen
= ::MultiByteToWideChar(cpSrc
, 0, selectedText
.s
, selectedText
.len
, 0, 0);
2176 uniText
.Allocate(2 * uLen
);
2178 ::MultiByteToWideChar(cpSrc
, 0, selectedText
.s
, selectedText
.len
,
2179 static_cast<wchar_t *>(uniText
.ptr
), uLen
);
2185 // Copy ANSI text to clipboard on Windows 9x
2186 // Convert from Unicode text, so other ANSI programs can
2188 // Windows NT, 2k, XP automatically generates CF_TEXT
2189 GlobalMemory ansiText
;
2190 ansiText
.Allocate(selectedText
.len
);
2192 ::WideCharToMultiByte(CP_ACP
, 0, static_cast<wchar_t *>(uniText
.ptr
), -1,
2193 static_cast<char *>(ansiText
.ptr
), selectedText
.len
, NULL
, NULL
);
2194 ansiText
.SetClip(CF_TEXT
);
2197 uniText
.SetClip(CF_UNICODETEXT
);
2199 // There was a failure - try to copy at least ANSI text
2200 GlobalMemory ansiText
;
2201 ansiText
.Allocate(selectedText
.len
);
2203 memcpy(static_cast<char *>(ansiText
.ptr
), selectedText
.s
, selectedText
.len
);
2204 ansiText
.SetClip(CF_TEXT
);
2208 if (selectedText
.rectangular
) {
2209 ::SetClipboardData(cfColumnSelect
, 0);
2212 if (selectedText
.lineCopy
) {
2213 ::SetClipboardData(cfLineSelect
, 0);
2219 void ScintillaWin::ScrollMessage(WPARAM wParam
) {
2220 //DWORD dwStart = timeGetTime();
2221 //Platform::DebugPrintf("Scroll %x %d\n", wParam, lParam);
2224 memset(&sci
, 0, sizeof(sci
));
2225 sci
.cbSize
= sizeof(sci
);
2226 sci
.fMask
= SIF_ALL
;
2228 GetScrollInfo(SB_VERT
, &sci
);
2230 //Platform::DebugPrintf("ScrollInfo %d mask=%x min=%d max=%d page=%d pos=%d track=%d\n", b,sci.fMask,
2231 //sci.nMin, sci.nMax, sci.nPage, sci.nPos, sci.nTrackPos);
2233 int topLineNew
= topLine
;
2234 switch (LoWord(wParam
)) {
2242 topLineNew
-= LinesToScroll(); break;
2243 case SB_PAGEDOWN
: topLineNew
+= LinesToScroll(); break;
2244 case SB_TOP
: topLineNew
= 0; break;
2245 case SB_BOTTOM
: topLineNew
= MaxScrollPos(); break;
2246 case SB_THUMBPOSITION
: topLineNew
= sci
.nTrackPos
; break;
2247 case SB_THUMBTRACK
: topLineNew
= sci
.nTrackPos
; break;
2249 ScrollTo(topLineNew
);
2252 void ScintillaWin::HorizontalScrollMessage(WPARAM wParam
) {
2254 PRectangle rcText
= GetTextRectangle();
2255 int pageWidth
= rcText
.Width() * 2 / 3;
2256 switch (LoWord(wParam
)) {
2260 case SB_LINEDOWN
: // May move past the logical end
2268 if (xPos
> scrollWidth
- rcText
.Width()) { // Hit the end exactly
2269 xPos
= scrollWidth
- rcText
.Width();
2278 case SB_THUMBPOSITION
:
2279 case SB_THUMBTRACK
: {
2280 // 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 =]
2282 si
.cbSize
= sizeof(si
);
2283 si
.fMask
= SIF_TRACKPOS
;
2284 if (GetScrollInfo(SB_HORZ
, &si
)) {
2285 xPos
= si
.nTrackPos
;
2290 HorizontalScrollTo(xPos
);
2293 void ScintillaWin::RealizeWindowPalette(bool inBackGround
) {
2295 HDC hdc
= ::GetDC(MainHWND());
2296 // Select a stock font to prevent warnings from BoundsChecker
2297 ::SelectObject(hdc
, GetStockFont(DEFAULT_GUI_FONT
));
2298 AutoSurface
surfaceWindow(hdc
, this);
2299 if (surfaceWindow
) {
2300 int changes
= surfaceWindow
->SetPalette(&palette
, inBackGround
);
2303 surfaceWindow
->Release();
2305 ::ReleaseDC(MainHWND(), hdc
);
2309 * Redraw all of text area.
2310 * This paint will not be abandoned.
2312 void ScintillaWin::FullPaint() {
2313 HDC hdc
= ::GetDC(MainHWND());
2315 ::ReleaseDC(MainHWND(), hdc
);
2319 * Redraw all of text area on the specified DC.
2320 * This paint will not be abandoned.
2322 void ScintillaWin::FullPaintDC(HDC hdc
) {
2323 paintState
= painting
;
2324 rcPaint
= GetClientRectangle();
2325 paintingAllText
= true;
2326 AutoSurface
surfaceWindow(hdc
, this);
2327 if (surfaceWindow
) {
2328 Paint(surfaceWindow
, rcPaint
);
2329 surfaceWindow
->Release();
2331 paintState
= notPainting
;
2334 static bool CompareDevCap(HDC hdc
, HDC hOtherDC
, int nIndex
) {
2335 return ::GetDeviceCaps(hdc
, nIndex
) == ::GetDeviceCaps(hOtherDC
, nIndex
);
2338 bool ScintillaWin::IsCompatibleDC(HDC hOtherDC
) {
2339 HDC hdc
= ::GetDC(MainHWND());
2341 CompareDevCap(hdc
, hOtherDC
, TECHNOLOGY
) &&
2342 CompareDevCap(hdc
, hOtherDC
, LOGPIXELSY
) &&
2343 CompareDevCap(hdc
, hOtherDC
, LOGPIXELSX
) &&
2344 CompareDevCap(hdc
, hOtherDC
, BITSPIXEL
) &&
2345 CompareDevCap(hdc
, hOtherDC
, PLANES
);
2346 ::ReleaseDC(MainHWND(), hdc
);
2347 return isCompatible
;
2350 DWORD
ScintillaWin::EffectFromState(DWORD grfKeyState
) {
2351 // These are the Wordpad semantics.
2353 if (inDragDrop
== ddDragging
) // Internal defaults to move
2354 dwEffect
= DROPEFFECT_MOVE
;
2356 dwEffect
= DROPEFFECT_COPY
;
2357 if (grfKeyState
& MK_ALT
)
2358 dwEffect
= DROPEFFECT_MOVE
;
2359 if (grfKeyState
& MK_CONTROL
)
2360 dwEffect
= DROPEFFECT_COPY
;
2364 /// Implement IUnknown
2365 STDMETHODIMP
ScintillaWin::QueryInterface(REFIID riid
, PVOID
*ppv
) {
2367 if (riid
== IID_IUnknown
)
2368 *ppv
= reinterpret_cast<IDropTarget
*>(&dt
);
2369 if (riid
== IID_IDropSource
)
2370 *ppv
= reinterpret_cast<IDropSource
*>(&ds
);
2371 if (riid
== IID_IDropTarget
)
2372 *ppv
= reinterpret_cast<IDropTarget
*>(&dt
);
2373 if (riid
== IID_IDataObject
)
2374 *ppv
= reinterpret_cast<IDataObject
*>(&dob
);
2376 return E_NOINTERFACE
;
2380 STDMETHODIMP_(ULONG
) ScintillaWin::AddRef() {
2384 STDMETHODIMP_(ULONG
) ScintillaWin::Release() {
2388 /// Implement IDropTarget
2389 STDMETHODIMP
ScintillaWin::DragEnter(LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
2390 POINTL
, PDWORD pdwEffect
) {
2391 if (pIDataSource
== NULL
)
2393 FORMATETC fmtu
= {CF_UNICODETEXT
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2394 HRESULT hrHasUText
= pIDataSource
->QueryGetData(&fmtu
);
2395 hasOKText
= (hrHasUText
== S_OK
);
2397 FORMATETC fmte
= {CF_TEXT
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2398 HRESULT hrHasText
= pIDataSource
->QueryGetData(&fmte
);
2399 hasOKText
= (hrHasText
== S_OK
);
2402 *pdwEffect
= DROPEFFECT_NONE
;
2406 *pdwEffect
= EffectFromState(grfKeyState
);
2410 STDMETHODIMP
ScintillaWin::DragOver(DWORD grfKeyState
, POINTL pt
, PDWORD pdwEffect
) {
2412 if (!hasOKText
|| pdoc
->IsReadOnly()) {
2413 *pdwEffect
= DROPEFFECT_NONE
;
2417 *pdwEffect
= EffectFromState(grfKeyState
);
2419 // Update the cursor.
2420 POINT rpt
= {pt
.x
, pt
.y
};
2421 ::ScreenToClient(MainHWND(), &rpt
);
2422 SetDragPosition(SPositionFromLocation(Point(rpt
.x
, rpt
.y
), false, false, UserVirtualSpace()));
2426 errorStatus
= SC_STATUS_FAILURE
;
2431 STDMETHODIMP
ScintillaWin::DragLeave() {
2433 SetDragPosition(SelectionPosition(invalidPosition
));
2436 errorStatus
= SC_STATUS_FAILURE
;
2441 STDMETHODIMP
ScintillaWin::Drop(LPDATAOBJECT pIDataSource
, DWORD grfKeyState
,
2442 POINTL pt
, PDWORD pdwEffect
) {
2444 *pdwEffect
= EffectFromState(grfKeyState
);
2446 if (pIDataSource
== NULL
)
2449 SetDragPosition(SelectionPosition(invalidPosition
));
2451 STGMEDIUM medium
= {0, {0}, 0};
2454 bool dataAllocated
= false;
2456 FORMATETC fmtu
= {CF_UNICODETEXT
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2457 HRESULT hr
= pIDataSource
->GetData(&fmtu
, &medium
);
2458 if (SUCCEEDED(hr
) && medium
.hGlobal
) {
2459 wchar_t *udata
= static_cast<wchar_t *>(::GlobalLock(medium
.hGlobal
));
2460 if (IsUnicodeMode()) {
2461 int tlen
= ::GlobalSize(medium
.hGlobal
);
2462 // Convert UTF-16 to UTF-8
2463 int dataLen
= UTF8Length(udata
, tlen
/2);
2464 data
= new char[dataLen
+1];
2465 UTF8FromUTF16(udata
, tlen
/2, data
, dataLen
);
2466 dataAllocated
= true;
2468 // Convert UTF-16 to ANSI
2470 // Default Scintilla behavior in Unicode mode
2471 // CF_UNICODETEXT available, but not in Unicode mode
2472 // Convert from Unicode to current Scintilla code page
2473 UINT cpDest
= CodePageOfDocument();
2474 int tlen
= ::WideCharToMultiByte(cpDest
, 0, udata
, -1,
2475 NULL
, 0, NULL
, NULL
) - 1; // subtract 0 terminator
2476 data
= new char[tlen
+ 1];
2477 memset(data
, 0, (tlen
+1));
2478 ::WideCharToMultiByte(cpDest
, 0, udata
, -1,
2479 data
, tlen
+ 1, NULL
, NULL
);
2480 dataAllocated
= true;
2485 FORMATETC fmte
= {CF_TEXT
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2486 hr
= pIDataSource
->GetData(&fmte
, &medium
);
2487 if (SUCCEEDED(hr
) && medium
.hGlobal
) {
2488 data
= static_cast<char *>(::GlobalLock(medium
.hGlobal
));
2492 if (data
&& convertPastes
) {
2493 // Convert line endings of the drop into our local line-endings mode
2494 int len
= static_cast<int>(strlen(data
));
2495 char *convertedText
= Document::TransformLineEnds(&len
, data
, len
, pdoc
->eolMode
);
2498 data
= convertedText
;
2499 dataAllocated
= true;
2503 //Platform::DebugPrintf("Bad data format: 0x%x\n", hres);
2507 FORMATETC fmtr
= {cfColumnSelect
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
2508 HRESULT hrRectangular
= pIDataSource
->QueryGetData(&fmtr
);
2510 POINT rpt
= {pt
.x
, pt
.y
};
2511 ::ScreenToClient(MainHWND(), &rpt
);
2512 SelectionPosition movePos
= SPositionFromLocation(Point(rpt
.x
, rpt
.y
), false, false, UserVirtualSpace());
2514 DropAt(movePos
, data
, *pdwEffect
== DROPEFFECT_MOVE
, hrRectangular
== S_OK
);
2516 ::GlobalUnlock(medium
.hGlobal
);
2519 if (medium
.pUnkForRelease
!= NULL
)
2520 medium
.pUnkForRelease
->Release();
2522 ::GlobalFree(medium
.hGlobal
);
2529 errorStatus
= SC_STATUS_FAILURE
;
2534 /// Implement important part of IDataObject
2535 STDMETHODIMP
ScintillaWin::GetData(FORMATETC
*pFEIn
, STGMEDIUM
*pSTM
) {
2536 bool formatOK
= (pFEIn
->cfFormat
== CF_TEXT
) ||
2537 ((pFEIn
->cfFormat
== CF_UNICODETEXT
) && IsUnicodeMode());
2540 (pFEIn
->dwAspect
& DVASPECT_CONTENT
) == 0 ||
2541 pFEIn
->lindex
!= -1 ||
2542 (pFEIn
->tymed
& TYMED_HGLOBAL
) == 0
2544 //Platform::DebugPrintf("DOB GetData No %d %x %x fmt=%x\n", lenDrag, pFEIn, pSTM, pFEIn->cfFormat);
2545 return DATA_E_FORMATETC
;
2547 pSTM
->tymed
= TYMED_HGLOBAL
;
2548 //Platform::DebugPrintf("DOB GetData OK %d %x %x\n", lenDrag, pFEIn, pSTM);
2551 if (pFEIn
->cfFormat
== CF_UNICODETEXT
) {
2552 int uchars
= UTF16Length(drag
.s
, drag
.len
);
2553 text
.Allocate(2 * uchars
);
2555 UTF16FromUTF8(drag
.s
, drag
.len
, static_cast<wchar_t *>(text
.ptr
), uchars
);
2558 text
.Allocate(drag
.len
);
2560 memcpy(static_cast<char *>(text
.ptr
), drag
.s
, drag
.len
);
2563 pSTM
->hGlobal
= text
? text
.Unlock() : 0;
2564 pSTM
->pUnkForRelease
= 0;
2568 bool ScintillaWin::Register(HINSTANCE hInstance_
) {
2570 hInstance
= hInstance_
;
2573 // Register the Scintilla class
2576 // Register Scintilla as a wide character window
2577 WNDCLASSEXW wndclass
;
2578 wndclass
.cbSize
= sizeof(wndclass
);
2579 wndclass
.style
= CS_GLOBALCLASS
| CS_HREDRAW
| CS_VREDRAW
;
2580 wndclass
.lpfnWndProc
= ScintillaWin::SWndProc
;
2581 wndclass
.cbClsExtra
= 0;
2582 wndclass
.cbWndExtra
= sizeof(ScintillaWin
*);
2583 wndclass
.hInstance
= hInstance
;
2584 wndclass
.hIcon
= NULL
;
2585 wndclass
.hCursor
= NULL
;
2586 wndclass
.hbrBackground
= NULL
;
2587 wndclass
.lpszMenuName
= NULL
;
2588 wndclass
.lpszClassName
= L
"Scintilla";
2589 wndclass
.hIconSm
= 0;
2590 result
= ::RegisterClassExW(&wndclass
) != 0;
2593 // Register Scintilla as a normal character window
2594 WNDCLASSEX wndclass
;
2595 wndclass
.cbSize
= sizeof(wndclass
);
2596 wndclass
.style
= CS_GLOBALCLASS
| CS_HREDRAW
| CS_VREDRAW
;
2597 wndclass
.lpfnWndProc
= ScintillaWin::SWndProc
;
2598 wndclass
.cbClsExtra
= 0;
2599 wndclass
.cbWndExtra
= sizeof(ScintillaWin
*);
2600 wndclass
.hInstance
= hInstance
;
2601 wndclass
.hIcon
= NULL
;
2602 wndclass
.hCursor
= NULL
;
2603 wndclass
.hbrBackground
= NULL
;
2604 wndclass
.lpszMenuName
= NULL
;
2605 wndclass
.lpszClassName
= scintillaClassName
;
2606 wndclass
.hIconSm
= 0;
2607 result
= ::RegisterClassEx(&wndclass
) != 0;
2611 // Register the CallTip class
2612 WNDCLASSEX wndclassc
;
2613 wndclassc
.cbSize
= sizeof(wndclassc
);
2614 wndclassc
.style
= CS_GLOBALCLASS
| CS_HREDRAW
| CS_VREDRAW
;
2615 wndclassc
.cbClsExtra
= 0;
2616 wndclassc
.cbWndExtra
= sizeof(ScintillaWin
*);
2617 wndclassc
.hInstance
= hInstance
;
2618 wndclassc
.hIcon
= NULL
;
2619 wndclassc
.hbrBackground
= NULL
;
2620 wndclassc
.lpszMenuName
= NULL
;
2621 wndclassc
.lpfnWndProc
= ScintillaWin::CTWndProc
;
2622 wndclassc
.hCursor
= ::LoadCursor(NULL
, IDC_ARROW
);
2623 wndclassc
.lpszClassName
= callClassName
;
2624 wndclassc
.hIconSm
= 0;
2626 result
= ::RegisterClassEx(&wndclassc
) != 0;
2632 bool ScintillaWin::Unregister() {
2633 bool result
= ::UnregisterClass(scintillaClassName
, hInstance
) != 0;
2634 if (::UnregisterClass(callClassName
, hInstance
) == 0)
2639 bool ScintillaWin::HasCaretSizeChanged() {
2641 ( (0 != vs
.caretWidth
) && (sysCaretWidth
!= vs
.caretWidth
) )
2642 || ((0 != vs
.lineHeight
) && (sysCaretHeight
!= vs
.lineHeight
))
2649 BOOL
ScintillaWin::CreateSystemCaret() {
2650 sysCaretWidth
= vs
.caretWidth
;
2651 if (0 == sysCaretWidth
) {
2654 sysCaretHeight
= vs
.lineHeight
;
2655 int bitmapSize
= (((sysCaretWidth
+ 15) & ~15) >> 3) *
2657 char *bits
= new char[bitmapSize
];
2658 memset(bits
, 0, bitmapSize
);
2659 sysCaretBitmap
= ::CreateBitmap(sysCaretWidth
, sysCaretHeight
, 1,
2660 1, reinterpret_cast<BYTE
*>(bits
));
2662 BOOL retval
= ::CreateCaret(
2663 MainHWND(), sysCaretBitmap
,
2664 sysCaretWidth
, sysCaretHeight
);
2665 ::ShowCaret(MainHWND());
2669 BOOL
ScintillaWin::DestroySystemCaret() {
2670 ::HideCaret(MainHWND());
2671 BOOL retval
= ::DestroyCaret();
2672 if (sysCaretBitmap
) {
2673 ::DeleteObject(sysCaretBitmap
);
2679 sptr_t PASCAL
ScintillaWin::CTWndProc(
2680 HWND hWnd
, UINT iMessage
, WPARAM wParam
, sptr_t lParam
) {
2681 // Find C++ object associated with window.
2682 ScintillaWin
*sciThis
= reinterpret_cast<ScintillaWin
*>(PointerFromWindow(hWnd
));
2684 // ctp will be zero if WM_CREATE not seen yet
2686 if (iMessage
== WM_CREATE
) {
2687 // Associate CallTip object with window
2688 CREATESTRUCT
*pCreate
= reinterpret_cast<CREATESTRUCT
*>(lParam
);
2689 SetWindowPointer(hWnd
, pCreate
->lpCreateParams
);
2692 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2695 if (iMessage
== WM_NCDESTROY
) {
2696 ::SetWindowLong(hWnd
, 0, 0);
2697 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2698 } else if (iMessage
== WM_PAINT
) {
2700 ::BeginPaint(hWnd
, &ps
);
2701 Surface
*surfaceWindow
= Surface::Allocate();
2702 if (surfaceWindow
) {
2703 surfaceWindow
->Init(ps
.hdc
, hWnd
);
2704 surfaceWindow
->SetUnicodeMode(SC_CP_UTF8
== sciThis
->ct
.codePage
);
2705 surfaceWindow
->SetDBCSMode(sciThis
->ct
.codePage
);
2706 sciThis
->ct
.PaintCT(surfaceWindow
);
2707 surfaceWindow
->Release();
2708 delete surfaceWindow
;
2710 ::EndPaint(hWnd
, &ps
);
2712 } else if ((iMessage
== WM_NCLBUTTONDOWN
) || (iMessage
== WM_NCLBUTTONDBLCLK
)) {
2714 pt
.x
= static_cast<short>(LOWORD(lParam
));
2715 pt
.y
= static_cast<short>(HIWORD(lParam
));
2716 ScreenToClient(hWnd
, &pt
);
2717 sciThis
->ct
.MouseClick(Point(pt
.x
, pt
.y
));
2718 sciThis
->CallTipClick();
2720 } else if (iMessage
== WM_LBUTTONDOWN
) {
2721 // This does not fire due to the hit test code
2722 sciThis
->ct
.MouseClick(Point::FromLong(lParam
));
2723 sciThis
->CallTipClick();
2725 } else if (iMessage
== WM_SETCURSOR
) {
2726 ::SetCursor(::LoadCursor(NULL
, IDC_ARROW
));
2728 } else if (iMessage
== WM_NCHITTEST
) {
2731 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2735 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2737 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2740 sptr_t
ScintillaWin::DirectFunction(
2741 ScintillaWin
*sci
, UINT iMessage
, uptr_t wParam
, sptr_t lParam
) {
2742 PLATFORM_ASSERT(::GetCurrentThreadId() == ::GetWindowThreadProcessId(sci
->MainHWND(), NULL
));
2743 return sci
->WndProc(iMessage
, wParam
, lParam
);
2747 #ifndef STATIC_BUILD
2748 __declspec(dllexport
)
2750 sptr_t __stdcall
Scintilla_DirectFunction(
2751 ScintillaWin
*sci
, UINT iMessage
, uptr_t wParam
, sptr_t lParam
) {
2752 return sci
->WndProc(iMessage
, wParam
, lParam
);
2755 sptr_t PASCAL
ScintillaWin::SWndProc(
2756 HWND hWnd
, UINT iMessage
, WPARAM wParam
, sptr_t lParam
) {
2757 //Platform::DebugPrintf("S W:%x M:%x WP:%x L:%x\n", hWnd, iMessage, wParam, lParam);
2759 // Find C++ object associated with window.
2760 ScintillaWin
*sci
= reinterpret_cast<ScintillaWin
*>(PointerFromWindow(hWnd
));
2761 // sci will be zero if WM_CREATE not seen yet
2764 if (iMessage
== WM_CREATE
) {
2765 // Create C++ object associated with window
2766 sci
= new ScintillaWin(hWnd
);
2767 SetWindowPointer(hWnd
, sci
);
2768 return sci
->WndProc(iMessage
, wParam
, lParam
);
2772 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2774 if (iMessage
== WM_NCDESTROY
) {
2780 ::SetWindowLong(hWnd
, 0, 0);
2781 return ::DefWindowProc(hWnd
, iMessage
, wParam
, lParam
);
2783 return sci
->WndProc(iMessage
, wParam
, lParam
);
2788 // This function is externally visible so it can be called from container when building statically.
2789 // Must be called once only.
2790 int Scintilla_RegisterClasses(void *hInstance
) {
2791 Platform_Initialise(hInstance
);
2792 bool result
= ScintillaWin::Register(reinterpret_cast<HINSTANCE
>(hInstance
));
2794 Scintilla_LinkLexers();
2799 // This function is externally visible so it can be called from container when building statically.
2800 int Scintilla_ReleaseResources() {
2801 bool result
= ScintillaWin::Unregister();
2802 Platform_Finalise();
2806 #ifndef STATIC_BUILD
2807 extern "C" int APIENTRY
DllMain(HINSTANCE hInstance
, DWORD dwReason
, LPVOID
) {
2808 //Platform::DebugPrintf("Scintilla::DllMain %d %d\n", hInstance, dwReason);
2809 if (dwReason
== DLL_PROCESS_ATTACH
) {
2810 if (!Scintilla_RegisterClasses(hInstance
))
2812 } else if (dwReason
== DLL_PROCESS_DETACH
) {
2813 Scintilla_ReleaseResources();