1 // Scintilla source code edit control
\r
2 /** @file ScintillaWin.cxx
\r
3 ** Windows specific subclass of ScintillaBase.
\r
5 // Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
\r
6 // The License.txt file describes the conditions under which this software may be distributed.
\r
15 #define _WIN32_WINNT 0x0500
\r
16 #include <windows.h>
\r
17 #include <commctrl.h>
\r
18 #include <richedit.h>
\r
19 #include <windowsx.h>
\r
21 #include "Platform.h"
\r
23 #include "Scintilla.h"
\r
24 #include "SString.h"
\r
26 #include "SciLexer.h"
\r
27 #include "PropSet.h"
\r
28 #include "Accessor.h"
\r
29 #include "KeyWords.h"
\r
31 #include "SplitVector.h"
\r
32 #include "Partitioning.h"
\r
33 #include "RunStyles.h"
\r
34 #include "ContractionState.h"
\r
35 #include "CellBuffer.h"
\r
36 #include "CallTip.h"
\r
38 #include "Indicator.h"
\r
40 #include "LineMarker.h"
\r
42 #include "AutoComplete.h"
\r
43 #include "ViewStyle.h"
\r
44 #include "CharClassify.h"
\r
45 #include "Decoration.h"
\r
46 #include "Document.h"
\r
47 #include "PositionCache.h"
\r
49 #include "ScintillaBase.h"
\r
50 #include "UniConversion.h"
\r
53 #include "ExternalLexer.h"
\r
56 #ifndef SPI_GETWHEELSCROLLLINES
\r
57 #define SPI_GETWHEELSCROLLLINES 104
\r
61 #define WM_UNICHAR 0x0109
\r
64 #ifndef UNICODE_NOCHAR
\r
65 #define UNICODE_NOCHAR 0xFFFF
\r
68 #ifndef WM_IME_STARTCOMPOSITION
\r
72 #include <commctrl.h>
\r
73 #ifndef __BORLANDC__
\r
84 #define SC_WIN_IDLE 5001
\r
86 // Functions imported from PlatWin
\r
88 extern void Platform_Initialise(void *hInstance);
\r
89 extern void Platform_Finalise();
\r
91 /** TOTAL_CONTROL ifdef surrounds code that will only work when ScintillaWin
\r
92 * is derived from ScintillaBase (all features) rather than directly from Editor
\r
93 * (lightweight editor).
\r
95 #define TOTAL_CONTROL
\r
97 // GCC has trouble with the standard COM ABI so do it the old C way with explicit vtables.
\r
99 const TCHAR scintillaClassName[] = TEXT("Scintilla");
\r
100 const TCHAR callClassName[] = TEXT("CallTip");
\r
102 #ifdef SCI_NAMESPACE
\r
103 using namespace Scintilla;
\r
106 class ScintillaWin; // Forward declaration for COM interface subobjects
\r
110 class FormatEnumerator {
\r
115 CLIPFORMAT formats[2];
\r
117 FormatEnumerator(int pos_, CLIPFORMAT formats_[], int formatsLen_);
\r
149 class ScintillaWin :
\r
150 public ScintillaBase {
\r
152 bool lastKeyDownConsumed;
\r
154 bool capturedMouse;
\r
156 unsigned int linesPerScroll; ///< Intellimouse support
\r
157 int wheelDelta; ///< Wheel delta from roll
\r
163 CLIPFORMAT cfColumnSelect;
\r
164 CLIPFORMAT cfLineSelect;
\r
171 static HINSTANCE hInstance;
\r
173 ScintillaWin(HWND hwnd);
\r
174 ScintillaWin(const ScintillaWin &) : ScintillaBase() {}
\r
175 virtual ~ScintillaWin();
\r
176 ScintillaWin &operator=(const ScintillaWin &) { return *this; }
\r
178 virtual void Initialise();
\r
179 virtual void Finalise();
\r
182 static sptr_t DirectFunction(
\r
183 ScintillaWin *sci, UINT iMessage, uptr_t wParam, sptr_t lParam);
\r
184 static sptr_t PASCAL SWndProc(
\r
185 HWND hWnd, UINT iMessage, WPARAM wParam, sptr_t lParam);
\r
186 static sptr_t PASCAL CTWndProc(
\r
187 HWND hWnd, UINT iMessage, WPARAM wParam, sptr_t lParam);
\r
189 enum { invalidTimerID, standardTimerID, idleTimerID };
\r
191 virtual bool DragThreshold(Point ptStart, Point ptNow);
\r
192 virtual void StartDrag();
\r
193 sptr_t WndPaint(uptr_t wParam);
\r
194 sptr_t HandleComposition(uptr_t wParam, sptr_t lParam);
\r
195 virtual bool ValidCodePage(int codePage) const;
\r
196 virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
\r
197 virtual bool SetIdle(bool on);
\r
198 virtual void SetTicking(bool on);
\r
199 virtual void SetMouseCapture(bool on);
\r
200 virtual bool HaveMouseCapture();
\r
201 virtual bool PaintContains(PRectangle rc);
\r
202 virtual void ScrollText(int linesToMove);
\r
203 virtual void UpdateSystemCaret();
\r
204 virtual void SetVerticalScrollPos();
\r
205 virtual void SetHorizontalScrollPos();
\r
206 virtual bool ModifyScrollBars(int nMax, int nPage);
\r
207 virtual void NotifyChange();
\r
208 virtual void NotifyFocus(bool focus);
\r
209 virtual int GetCtrlID();
\r
210 virtual void NotifyParent(SCNotification scn);
\r
211 virtual void NotifyParent(SCNotification * scn);
\r
212 virtual void NotifyDoubleClick(Point pt, bool shift, bool ctrl, bool alt);
\r
213 virtual void Copy();
\r
214 virtual void CopyAllowLine();
\r
215 virtual bool CanPaste();
\r
216 virtual void Paste();
\r
217 virtual void CreateCallTipWindow(PRectangle rc);
\r
218 virtual void AddToPopUp(const char *label, int cmd = 0, bool enabled = true);
\r
219 virtual void ClaimSelection();
\r
222 void ImeStartComposition();
\r
223 void ImeEndComposition();
\r
225 void AddCharBytes(char b0, char b1);
\r
227 void GetIntelliMouseParameters();
\r
228 virtual void CopyToClipboard(const SelectionText &selectedText);
\r
229 void ScrollMessage(WPARAM wParam);
\r
230 void HorizontalScrollMessage(WPARAM wParam);
\r
231 void RealizeWindowPalette(bool inBackGround);
\r
233 void FullPaintDC(HDC dc);
\r
234 bool IsCompatibleDC(HDC dc);
\r
235 DWORD EffectFromState(DWORD grfKeyState);
\r
237 virtual int SetScrollInfo(int nBar, LPCSCROLLINFO lpsi, BOOL bRedraw);
\r
238 virtual bool GetScrollInfo(int nBar, LPSCROLLINFO lpsi);
\r
239 void ChangeScrollPos(int barType, int pos);
\r
241 void InsertPasteText(const char *text, int len, int selStart, bool isRectangular, bool isLine);
\r
244 // Public for benefit of Scintilla_DirectFunction
\r
245 virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
\r
247 /// Implement IUnknown
\r
248 STDMETHODIMP QueryInterface(REFIID riid, PVOID *ppv);
\r
249 STDMETHODIMP_(ULONG)AddRef();
\r
250 STDMETHODIMP_(ULONG)Release();
\r
252 /// Implement IDropTarget
\r
253 STDMETHODIMP DragEnter(LPDATAOBJECT pIDataSource, DWORD grfKeyState,
\r
254 POINTL pt, PDWORD pdwEffect);
\r
255 STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, PDWORD pdwEffect);
\r
256 STDMETHODIMP DragLeave();
\r
257 STDMETHODIMP Drop(LPDATAOBJECT pIDataSource, DWORD grfKeyState,
\r
258 POINTL pt, PDWORD pdwEffect);
\r
260 /// Implement important part of IDataObject
\r
261 STDMETHODIMP GetData(FORMATETC *pFEIn, STGMEDIUM *pSTM);
\r
265 void SetLexerLanguage(const char *languageName);
\r
266 void SetLexer(uptr_t wParam);
\r
269 static bool Register(HINSTANCE hInstance_);
\r
270 static bool Unregister();
\r
272 friend class DropSource;
\r
273 friend class DataObject;
\r
274 friend class DropTarget;
\r
275 bool DragIsRectangularOK(CLIPFORMAT fmt) {
\r
276 return drag.rectangular && (fmt == cfColumnSelect);
\r
280 // For use in creating a system caret
\r
281 bool HasCaretSizeChanged();
\r
282 BOOL CreateSystemCaret();
\r
283 BOOL DestroySystemCaret();
\r
284 HBITMAP sysCaretBitmap;
\r
286 int sysCaretHeight;
\r
287 bool keysAlwaysUnicode;
\r
290 HINSTANCE ScintillaWin::hInstance = 0;
\r
292 ScintillaWin::ScintillaWin(HWND hwnd) {
\r
294 lastKeyDownConsumed = false;
\r
296 capturedMouse = false;
\r
297 linesPerScroll = 0;
\r
298 wheelDelta = 0; // Wheel delta from roll
\r
304 // There does not seem to be a real standard for indicating that the clipboard
\r
305 // contains a rectangular selection, so copy Developer Studio.
\r
306 cfColumnSelect = static_cast<CLIPFORMAT>(
\r
307 ::RegisterClipboardFormat(TEXT("MSDEVColumnSelect")));
\r
309 // Likewise for line-copy (copies a full line when no text is selected)
\r
310 cfLineSelect = static_cast<CLIPFORMAT>(
\r
311 ::RegisterClipboardFormat(TEXT("MSDEVLineSelect")));
\r
321 sysCaretBitmap = 0;
\r
323 sysCaretHeight = 0;
\r
325 keysAlwaysUnicode = false;
\r
330 ScintillaWin::~ScintillaWin() {}
\r
332 void ScintillaWin::Initialise() {
\r
333 // Initialize COM. If the app has already done this it will have
\r
334 // no effect. If the app hasnt, we really shouldnt ask them to call
\r
335 // it just so this internal feature works.
\r
336 hrOle = ::OleInitialize(NULL);
\r
339 void ScintillaWin::Finalise() {
\r
340 ScintillaBase::Finalise();
\r
343 DestroySystemCaret();
\r
344 ::RevokeDragDrop(MainHWND());
\r
345 if (SUCCEEDED(hrOle)) {
\r
346 ::OleUninitialize();
\r
350 HWND ScintillaWin::MainHWND() {
\r
351 return reinterpret_cast<HWND>(wMain.GetID());
\r
354 bool ScintillaWin::DragThreshold(Point ptStart, Point ptNow) {
\r
355 int xMove = abs(ptStart.x - ptNow.x);
\r
356 int yMove = abs(ptStart.y - ptNow.y);
\r
357 return (xMove > ::GetSystemMetrics(SM_CXDRAG)) ||
\r
358 (yMove > ::GetSystemMetrics(SM_CYDRAG));
\r
361 void ScintillaWin::StartDrag() {
\r
362 inDragDrop = ddDragging;
\r
363 DWORD dwEffect = 0;
\r
364 dropWentOutside = true;
\r
365 IDataObject *pDataObject = reinterpret_cast<IDataObject *>(&dob);
\r
366 IDropSource *pDropSource = reinterpret_cast<IDropSource *>(&ds);
\r
367 //Platform::DebugPrintf("About to DoDragDrop %x %x\n", pDataObject, pDropSource);
\r
368 HRESULT hr = ::DoDragDrop(
\r
371 DROPEFFECT_COPY | DROPEFFECT_MOVE, &dwEffect);
\r
372 //Platform::DebugPrintf("DoDragDrop = %x\n", hr);
\r
373 if (SUCCEEDED(hr)) {
\r
374 if ((hr == DRAGDROP_S_DROP) && (dwEffect == DROPEFFECT_MOVE) && dropWentOutside) {
\r
375 // Remove dragged out text
\r
379 inDragDrop = ddNone;
\r
380 SetDragPosition(invalidPosition);
\r
383 // Avoid warnings everywhere for old style casts by concentrating them here
\r
384 static WORD LoWord(DWORD l) {
\r
388 static WORD HiWord(DWORD l) {
\r
392 static int InputCodePage() {
\r
393 HKL inputLocale = ::GetKeyboardLayout(0);
\r
394 LANGID inputLang = LOWORD(inputLocale);
\r
395 char sCodePage[10];
\r
396 int res = ::GetLocaleInfoA(MAKELCID(inputLang, SORT_DEFAULT),
\r
397 LOCALE_IDEFAULTANSICODEPAGE, sCodePage, sizeof(sCodePage));
\r
400 return atoi(sCodePage);
\r
404 static const int VK_OEM_2=0xbf;
\r
405 static const int VK_OEM_3=0xc0;
\r
406 static const int VK_OEM_4=0xdb;
\r
407 static const int VK_OEM_5=0xdc;
\r
408 static const int VK_OEM_6=0xdd;
\r
411 /** Map the key codes to their equivalent SCK_ form. */
\r
412 static int KeyTranslate(int keyIn) {
\r
413 //PLATFORM_ASSERT(!keyIn);
\r
415 case VK_DOWN: return SCK_DOWN;
\r
416 case VK_UP: return SCK_UP;
\r
417 case VK_LEFT: return SCK_LEFT;
\r
418 case VK_RIGHT: return SCK_RIGHT;
\r
419 case VK_HOME: return SCK_HOME;
\r
420 case VK_END: return SCK_END;
\r
421 case VK_PRIOR: return SCK_PRIOR;
\r
422 case VK_NEXT: return SCK_NEXT;
\r
423 case VK_DELETE: return SCK_DELETE;
\r
424 case VK_INSERT: return SCK_INSERT;
\r
425 case VK_ESCAPE: return SCK_ESCAPE;
\r
426 case VK_BACK: return SCK_BACK;
\r
427 case VK_TAB: return SCK_TAB;
\r
428 case VK_RETURN: return SCK_RETURN;
\r
429 case VK_ADD: return SCK_ADD;
\r
430 case VK_SUBTRACT: return SCK_SUBTRACT;
\r
431 case VK_DIVIDE: return SCK_DIVIDE;
\r
432 case VK_LWIN: return SCK_WIN;
\r
433 case VK_RWIN: return SCK_RWIN;
\r
434 case VK_APPS: return SCK_MENU;
\r
435 case VK_OEM_2: return '/';
\r
436 case VK_OEM_3: return '`';
\r
437 case VK_OEM_4: return '[';
\r
438 case VK_OEM_5: return '\\';
\r
439 case VK_OEM_6: return ']';
\r
440 default: return keyIn;
\r
444 LRESULT ScintillaWin::WndPaint(uptr_t wParam) {
\r
447 // Redirect assertions to debug output and save current state
\r
448 bool assertsPopup = Platform::ShowAssertionPopUps(false);
\r
449 paintState = painting;
\r
453 bool IsOcxCtrl = (wParam != 0); // if wParam != 0, it contains
\r
454 // a PAINSTRUCT* from the OCX
\r
455 // Removed since this interferes with reporting other assertions as it occurs repeatedly
\r
456 //PLATFORM_ASSERT(hRgnUpdate == NULL);
\r
457 hRgnUpdate = ::CreateRectRgn(0, 0, 0, 0);
\r
459 pps = reinterpret_cast<PAINTSTRUCT*>(wParam);
\r
461 ::GetUpdateRgn(MainHWND(), hRgnUpdate, FALSE);
\r
463 ::BeginPaint(MainHWND(), pps);
\r
465 AutoSurface surfaceWindow(pps->hdc, this);
\r
466 if (surfaceWindow) {
\r
467 rcPaint = PRectangle(pps->rcPaint.left, pps->rcPaint.top, pps->rcPaint.right, pps->rcPaint.bottom);
\r
468 PRectangle rcClient = GetClientRectangle();
\r
469 paintingAllText = rcPaint.Contains(rcClient);
\r
470 if (paintingAllText) {
\r
471 //Platform::DebugPrintf("Performing full text paint\n");
\r
473 //Platform::DebugPrintf("Performing partial paint %d .. %d\n", rcPaint.top, rcPaint.bottom);
\r
475 Paint(surfaceWindow, rcPaint);
\r
476 surfaceWindow->Release();
\r
479 ::DeleteRgn(hRgnUpdate);
\r
484 ::EndPaint(MainHWND(), pps);
\r
485 if (paintState == paintAbandoned) {
\r
486 // Painting area was insufficient to cover new styling or brace highlight positions
\r
489 paintState = notPainting;
\r
491 // Restore debug output state
\r
492 Platform::ShowAssertionPopUps(assertsPopup);
\r
494 //Platform::DebugPrintf("Paint took %g\n", et.Duration());
\r
498 sptr_t ScintillaWin::HandleComposition(uptr_t wParam, sptr_t lParam) {
\r
500 // Digital Mars compiler does not include Imm library
\r
503 if (lParam & GCS_RESULTSTR) {
\r
504 HIMC hIMC = ::ImmGetContext(MainHWND());
\r
506 const int maxLenInputIME = 200;
\r
507 wchar_t wcs[maxLenInputIME];
\r
508 LONG bytes = ::ImmGetCompositionStringW(hIMC,
\r
509 GCS_RESULTSTR, wcs, (maxLenInputIME-1)*2);
\r
510 int wides = bytes / 2;
\r
511 if (IsUnicodeMode()) {
\r
512 char utfval[maxLenInputIME * 3];
\r
513 unsigned int len = UTF8Length(wcs, wides);
\r
514 UTF8FromUTF16(wcs, wides, utfval, len);
\r
515 utfval[len] = '\0';
\r
516 AddCharUTF(utfval, len);
\r
518 char dbcsval[maxLenInputIME * 2];
\r
519 int size = ::WideCharToMultiByte(InputCodePage(),
\r
520 0, wcs, wides, dbcsval, sizeof(dbcsval) - 1, 0, 0);
\r
521 for (int i=0; i<size; i++) {
\r
522 AddChar(dbcsval[i]);
\r
525 // Set new position after converted
\r
526 Point pos = LocationFromPosition(currentPos);
\r
527 COMPOSITIONFORM CompForm;
\r
528 CompForm.dwStyle = CFS_POINT;
\r
529 CompForm.ptCurrentPos.x = pos.x;
\r
530 CompForm.ptCurrentPos.y = pos.y;
\r
531 ::ImmSetCompositionWindow(hIMC, &CompForm);
\r
532 ::ImmReleaseContext(MainHWND(), hIMC);
\r
536 return ::DefWindowProc(MainHWND(), WM_IME_COMPOSITION, wParam, lParam);
\r
540 // Translate message IDs from WM_* and EM_* to SCI_* so can partly emulate Windows Edit control
\r
541 static unsigned int SciMessageFromEM(unsigned int iMessage) {
\r
542 switch (iMessage) {
\r
543 case EM_CANPASTE: return SCI_CANPASTE;
\r
544 case EM_CANUNDO: return SCI_CANUNDO;
\r
545 case EM_EMPTYUNDOBUFFER: return SCI_EMPTYUNDOBUFFER;
\r
546 case EM_FINDTEXTEX: return SCI_FINDTEXT;
\r
547 case EM_FORMATRANGE: return SCI_FORMATRANGE;
\r
548 case EM_GETFIRSTVISIBLELINE: return SCI_GETFIRSTVISIBLELINE;
\r
549 case EM_GETLINECOUNT: return SCI_GETLINECOUNT;
\r
550 case EM_GETSELTEXT: return SCI_GETSELTEXT;
\r
551 case EM_GETTEXTRANGE: return SCI_GETTEXTRANGE;
\r
552 case EM_HIDESELECTION: return SCI_HIDESELECTION;
\r
553 case EM_LINEINDEX: return SCI_POSITIONFROMLINE;
\r
554 case EM_LINESCROLL: return SCI_LINESCROLL;
\r
555 case EM_REPLACESEL: return SCI_REPLACESEL;
\r
556 case EM_SCROLLCARET: return SCI_SCROLLCARET;
\r
557 case EM_SETREADONLY: return SCI_SETREADONLY;
\r
558 case WM_CLEAR: return SCI_CLEAR;
\r
559 case WM_COPY: return SCI_COPY;
\r
560 case WM_CUT: return SCI_CUT;
\r
561 case WM_GETTEXT: return SCI_GETTEXT;
\r
562 case WM_SETTEXT: return SCI_SETTEXT;
\r
563 case WM_GETTEXTLENGTH: return SCI_GETTEXTLENGTH;
\r
564 case WM_PASTE: return SCI_PASTE;
\r
565 case WM_UNDO: return SCI_UNDO;
\r
570 static UINT CodePageFromCharSet(DWORD characterSet, UINT documentCodePage) {
\r
571 CHARSETINFO ci = { 0, 0, { { 0, 0, 0, 0 }, { 0, 0 } } };
\r
572 BOOL bci = ::TranslateCharsetInfo((DWORD*)characterSet,
\r
573 &ci, TCI_SRCCHARSET);
\r
579 cp = documentCodePage;
\r
582 if (!IsValidCodePage(cp) && !GetCPInfo(cp, &cpi))
\r
588 sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
\r
589 //Platform::DebugPrintf("S M:%x WP:%x L:%x\n", iMessage, wParam, lParam);
\r
590 iMessage = SciMessageFromEM(iMessage);
\r
591 switch (iMessage) {
\r
594 ctrlID = ::GetDlgCtrlID(reinterpret_cast<HWND>(wMain.GetID()));
\r
595 // Get Intellimouse scroll line parameters
\r
596 GetIntelliMouseParameters();
\r
597 ::RegisterDragDrop(MainHWND(), reinterpret_cast<IDropTarget *>(&dt));
\r
601 #ifdef TOTAL_CONTROL
\r
602 Command(LoWord(wParam));
\r
607 return WndPaint(wParam);
\r
609 case WM_PRINTCLIENT: {
\r
610 HDC hdc = reinterpret_cast<HDC>(wParam);
\r
611 if (!IsCompatibleDC(hdc)) {
\r
612 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
\r
619 ScrollMessage(wParam);
\r
623 HorizontalScrollMessage(wParam);
\r
627 //Platform::DebugPrintf("Scintilla WM_SIZE %d %d\n", LoWord(lParam), HiWord(lParam));
\r
632 case WM_MOUSEWHEEL:
\r
633 // Don't handle datazoom.
\r
634 // (A good idea for datazoom would be to "fold" or "unfold" details.
\r
635 // i.e. if datazoomed out only class structures are visible, when datazooming in the control
\r
636 // structures appear, then eventually the individual statements...)
\r
637 if (wParam & MK_SHIFT) {
\r
638 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
\r
641 // Either SCROLL or ZOOM. We handle the wheel steppings calculation
\r
642 wheelDelta -= static_cast<short>(HiWord(wParam));
\r
643 if (abs(wheelDelta) >= WHEEL_DELTA && linesPerScroll > 0) {
\r
644 int linesToScroll = linesPerScroll;
\r
645 if (linesPerScroll == WHEEL_PAGESCROLL)
\r
646 linesToScroll = LinesOnScreen() - 1;
\r
647 if (linesToScroll == 0) {
\r
650 linesToScroll *= (wheelDelta / WHEEL_DELTA);
\r
651 if (wheelDelta >= 0)
\r
652 wheelDelta = wheelDelta % WHEEL_DELTA;
\r
654 wheelDelta = - (-wheelDelta % WHEEL_DELTA);
\r
656 if (wParam & MK_CONTROL) {
\r
657 // Zoom! We play with the font sizes in the styles.
\r
658 // Number of steps/line is ignored, we just care if sizing up or down
\r
659 if (linesToScroll < 0) {
\r
660 KeyCommand(SCI_ZOOMIN);
\r
662 KeyCommand(SCI_ZOOMOUT);
\r
666 ScrollTo(topLine + linesToScroll);
\r
672 if (wParam == standardTimerID && timer.ticking) {
\r
674 } else if (wParam == idleTimerID && idler.state) {
\r
675 SendMessage(MainHWND(), SC_WIN_IDLE, 0, 1);
\r
682 // wParam=dwTickCountInitial, or 0 to initialize. lParam=bSkipUserInputTest
\r
684 if (lParam || (WAIT_TIMEOUT==MsgWaitForMultipleObjects(0,0,0,0, QS_INPUT|QS_HOTKEY))) {
\r
686 // User input was given priority above, but all events do get a turn. Other
\r
687 // messages, notifications, etc. will get interleaved with the idle messages.
\r
689 // However, some things like WM_PAINT are a lower priority, and will not fire
\r
690 // when there's a message posted. So, several times a second, we stop and let
\r
691 // the low priority events have a turn (after which the timer will fire again).
\r
693 DWORD dwCurrent = GetTickCount();
\r
694 DWORD dwStart = wParam ? wParam : dwCurrent;
\r
696 if (dwCurrent >= dwStart && dwCurrent > 200 && dwCurrent - 200 < dwStart)
\r
697 PostMessage(MainHWND(), SC_WIN_IDLE, dwStart, 0);
\r
705 case WM_GETMINMAXINFO:
\r
706 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
\r
708 case WM_LBUTTONDOWN: {
\r
710 // Digital Mars compiler does not include Imm library
\r
711 // For IME, set the composition string as the result string.
\r
712 HIMC hIMC = ::ImmGetContext(MainHWND());
\r
713 ::ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
\r
714 ::ImmReleaseContext(MainHWND(), hIMC);
\r
717 //Platform::DebugPrintf("Buttdown %d %x %x %x %x %x\n",iMessage, wParam, lParam,
\r
718 // Platform::IsKeyDown(VK_SHIFT),
\r
719 // Platform::IsKeyDown(VK_CONTROL),
\r
720 // Platform::IsKeyDown(VK_MENU));
\r
721 ButtonDown(Point::FromLong(lParam), ::GetMessageTime(),
\r
722 (wParam & MK_SHIFT) != 0,
\r
723 (wParam & MK_CONTROL) != 0,
\r
724 Platform::IsKeyDown(VK_MENU));
\r
725 ::SetFocus(MainHWND());
\r
730 ButtonMove(Point::FromLong(lParam));
\r
734 ButtonUp(Point::FromLong(lParam),
\r
735 ::GetMessageTime(),
\r
736 (wParam & MK_CONTROL) != 0);
\r
739 case WM_RBUTTONDOWN:
\r
740 if (!PointInSelection(Point::FromLong(lParam)))
\r
741 SetEmptySelection(PositionFromLocation(Point::FromLong(lParam)));
\r
745 if (LoWord(lParam) == HTCLIENT) {
\r
746 if (inDragDrop == ddDragging) {
\r
747 DisplayCursor(Window::cursorUp);
\r
749 // Display regular (drag) cursor over selection
\r
751 ::GetCursorPos(&pt);
\r
752 ::ScreenToClient(MainHWND(), &pt);
\r
753 if (PointInSelMargin(Point(pt.x, pt.y))) {
\r
754 DisplayCursor(Window::cursorReverseArrow);
\r
755 } else if (PointInSelection(Point(pt.x, pt.y)) && !SelectionEmpty()) {
\r
756 DisplayCursor(Window::cursorArrow);
\r
757 } else if (PointIsHotspot(Point(pt.x, pt.y))) {
\r
758 DisplayCursor(Window::cursorHand);
\r
760 DisplayCursor(Window::cursorText);
\r
765 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
\r
769 if (((wParam >= 128) || !iscntrl(wParam)) || !lastKeyDownConsumed) {
\r
770 if (::IsWindowUnicode(MainHWND()) || keysAlwaysUnicode) {
\r
771 wchar_t wcs[2] = {wParam, 0};
\r
772 if (IsUnicodeMode()) {
\r
773 // For a wide character version of the window:
\r
775 unsigned int len = UTF8Length(wcs, 1);
\r
776 UTF8FromUTF16(wcs, 1, utfval, len);
\r
777 AddCharUTF(utfval, len);
\r
779 UINT cpDest = CodePageFromCharSet(
\r
780 vs.styles[STYLE_DEFAULT].characterSet, pdoc->dbcsCodePage);
\r
781 char inBufferCP[20];
\r
782 int size = ::WideCharToMultiByte(cpDest,
\r
783 0, wcs, 1, inBufferCP, sizeof(inBufferCP) - 1, 0, 0);
\r
784 AddCharUTF(inBufferCP, size);
\r
787 if (IsUnicodeMode()) {
\r
788 AddCharBytes('\0', LOBYTE(wParam));
\r
790 AddChar(LOBYTE(wParam));
\r
797 if (wParam == UNICODE_NOCHAR) {
\r
798 return IsUnicodeMode() ? 1 : 0;
\r
799 } else if (lastKeyDownConsumed) {
\r
802 if (IsUnicodeMode()) {
\r
804 wchar_t wcs[2] = {static_cast<wchar_t>(wParam), 0};
\r
805 unsigned int len = UTF8Length(wcs, 1);
\r
806 UTF8FromUTF16(wcs, 1, utfval, len);
\r
807 AddCharUTF(utfval, len);
\r
814 case WM_SYSKEYDOWN:
\r
816 //Platform::DebugPrintf("S keydown %d %x %x %x %x\n",iMessage, wParam, lParam, ::IsKeyDown(VK_SHIFT), ::IsKeyDown(VK_CONTROL));
\r
817 lastKeyDownConsumed = false;
\r
818 int ret = KeyDown(KeyTranslate(wParam),
\r
819 Platform::IsKeyDown(VK_SHIFT),
\r
820 Platform::IsKeyDown(VK_CONTROL),
\r
821 Platform::IsKeyDown(VK_MENU),
\r
822 &lastKeyDownConsumed);
\r
823 if (!ret && !lastKeyDownConsumed) {
\r
824 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
\r
829 case WM_IME_KEYDOWN:
\r
830 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
\r
833 //Platform::DebugPrintf("S keyup %d %x %x\n",iMessage, wParam, lParam);
\r
834 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
\r
836 case WM_SETTINGCHANGE:
\r
837 //Platform::DebugPrintf("Setting Changed\n");
\r
838 InvalidateStyleData();
\r
839 // Get Intellimouse scroll line parameters
\r
840 GetIntelliMouseParameters();
\r
843 case WM_GETDLGCODE:
\r
844 return DLGC_HASSETSEL | DLGC_WANTALLKEYS;
\r
846 case WM_KILLFOCUS: {
\r
847 HWND wOther = reinterpret_cast<HWND>(wParam);
\r
848 HWND wThis = MainHWND();
\r
849 HWND wCT = reinterpret_cast<HWND>(ct.wCallTip.GetID());
\r
851 !(::IsChild(wThis,wOther) || (wOther == wCT))) {
\r
852 SetFocusState(false);
\r
853 DestroySystemCaret();
\r
856 //RealizeWindowPalette(true);
\r
860 SetFocusState(true);
\r
861 RealizeWindowPalette(false);
\r
862 DestroySystemCaret();
\r
863 CreateSystemCaret();
\r
866 case WM_SYSCOLORCHANGE:
\r
867 //Platform::DebugPrintf("Setting Changed\n");
\r
868 InvalidateStyleData();
\r
871 case WM_PALETTECHANGED:
\r
872 if (wParam != reinterpret_cast<uptr_t>(MainHWND())) {
\r
873 //Platform::DebugPrintf("** Palette Changed\n");
\r
874 RealizeWindowPalette(true);
\r
878 case WM_QUERYNEWPALETTE:
\r
879 //Platform::DebugPrintf("** Query palette\n");
\r
880 RealizeWindowPalette(false);
\r
883 case WM_IME_STARTCOMPOSITION: // dbcs
\r
884 ImeStartComposition();
\r
885 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
\r
887 case WM_IME_ENDCOMPOSITION: // dbcs
\r
888 ImeEndComposition();
\r
889 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
\r
891 case WM_IME_COMPOSITION:
\r
892 return HandleComposition(wParam, lParam);
\r
894 case WM_IME_CHAR: {
\r
895 AddCharBytes(HIBYTE(wParam), LOBYTE(wParam));
\r
899 case WM_CONTEXTMENU:
\r
900 #ifdef TOTAL_CONTROL
\r
901 if (displayPopupMenu) {
\r
902 Point pt = Point::FromLong(lParam);
\r
903 if ((pt.x == -1) && (pt.y == -1)) {
\r
904 // Caused by keyboard so display menu near caret
\r
905 pt = LocationFromPosition(currentPos);
\r
906 POINT spt = {pt.x, pt.y};
\r
907 ::ClientToScreen(MainHWND(), &spt);
\r
908 pt = Point(spt.x, spt.y);
\r
914 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
\r
916 case WM_INPUTLANGCHANGE:
\r
917 //::SetThreadLocale(LOWORD(lParam));
\r
918 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
\r
920 case WM_INPUTLANGCHANGEREQUEST:
\r
921 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
\r
923 case WM_ERASEBKGND:
\r
924 return 1; // Avoid any background erasure as whole window painted.
\r
926 case WM_CAPTURECHANGED:
\r
927 capturedMouse = false;
\r
930 // These are not handled in Scintilla and its faster to dispatch them here.
\r
931 // Also moves time out to here so profile doesn't count lots of empty message calls.
\r
934 case WM_MOUSEACTIVATE:
\r
936 case WM_NCCALCSIZE:
\r
938 case WM_NCMOUSEMOVE:
\r
939 case WM_NCLBUTTONDOWN:
\r
940 case WM_IME_SETCONTEXT:
\r
941 case WM_IME_NOTIFY:
\r
942 case WM_SYSCOMMAND:
\r
943 case WM_WINDOWPOSCHANGING:
\r
944 case WM_WINDOWPOSCHANGED:
\r
945 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
\r
947 case EM_LINEFROMCHAR:
\r
948 if (static_cast<int>(wParam) < 0) {
\r
949 wParam = SelectionStart();
\r
951 return pdoc->LineFromPosition(wParam);
\r
953 case EM_EXLINEFROMCHAR:
\r
954 return pdoc->LineFromPosition(lParam);
\r
958 *reinterpret_cast<int *>(wParam) = SelectionStart();
\r
961 *reinterpret_cast<int *>(lParam) = SelectionEnd();
\r
963 return MAKELONG(SelectionStart(), SelectionEnd());
\r
965 case EM_EXGETSEL: {
\r
969 CharacterRange *pCR = reinterpret_cast<CharacterRange *>(lParam);
\r
970 pCR->cpMin = SelectionStart();
\r
971 pCR->cpMax = SelectionEnd();
\r
976 int nStart = static_cast<int>(wParam);
\r
977 int nEnd = static_cast<int>(lParam);
\r
978 if (nStart == 0 && nEnd == -1) {
\r
979 nEnd = pdoc->Length();
\r
981 if (nStart == -1) {
\r
982 nStart = nEnd; // Remove selection
\r
984 if (nStart > nEnd) {
\r
985 SetSelection(nEnd, nStart);
\r
987 SetSelection(nStart, nEnd);
\r
989 EnsureCaretVisible();
\r
993 case EM_EXSETSEL: {
\r
997 CharacterRange *pCR = reinterpret_cast<CharacterRange *>(lParam);
\r
998 selType = selStream;
\r
999 if (pCR->cpMin == 0 && pCR->cpMax == -1) {
\r
1000 SetSelection(pCR->cpMin, pdoc->Length());
\r
1002 SetSelection(pCR->cpMin, pCR->cpMax);
\r
1004 EnsureCaretVisible();
\r
1005 return pdoc->LineFromPosition(SelectionStart());
\r
1008 case SCI_GETDIRECTFUNCTION:
\r
1009 return reinterpret_cast<sptr_t>(DirectFunction);
\r
1011 case SCI_GETDIRECTPOINTER:
\r
1012 return reinterpret_cast<sptr_t>(this);
\r
1014 case SCI_GRABFOCUS:
\r
1015 ::SetFocus(MainHWND());
\r
1018 case SCI_SETKEYSUNICODE:
\r
1019 keysAlwaysUnicode = wParam != 0;
\r
1022 case SCI_GETKEYSUNICODE:
\r
1023 return keysAlwaysUnicode;
\r
1026 case SCI_LOADLEXERLIBRARY:
\r
1027 LexerManager::GetInstance()->Load(reinterpret_cast<const char*>(lParam));
\r
1032 return ScintillaBase::WndProc(iMessage, wParam, lParam);
\r
1037 bool ScintillaWin::ValidCodePage(int codePage) const {
\r
1038 return codePage == 0 || codePage == SC_CP_UTF8 ||
\r
1039 codePage == 932 || codePage == 936 || codePage == 949 ||
\r
1040 codePage == 950 || codePage == 1361;
\r
1043 sptr_t ScintillaWin::DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
\r
1044 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);
\r
1047 void ScintillaWin::SetTicking(bool on) {
\r
1048 if (timer.ticking != on) {
\r
1049 timer.ticking = on;
\r
1050 if (timer.ticking) {
\r
1051 timer.tickerID = ::SetTimer(MainHWND(), standardTimerID, timer.tickSize, NULL)
\r
1052 ? reinterpret_cast<TickerID>(standardTimerID) : 0;
\r
1054 ::KillTimer(MainHWND(), reinterpret_cast<uptr_t>(timer.tickerID));
\r
1055 timer.tickerID = 0;
\r
1058 timer.ticksToWait = caret.period;
\r
1061 bool ScintillaWin::SetIdle(bool on) {
\r
1062 // On Win32 the Idler is implemented as a Timer on the Scintilla window. This
\r
1063 // takes advantage of the fact that WM_TIMER messages are very low priority,
\r
1064 // and are only posted when the message queue is empty, i.e. during idle time.
\r
1065 if (idler.state != on) {
\r
1067 idler.idlerID = ::SetTimer(MainHWND(), idleTimerID, 10, NULL)
\r
1068 ? reinterpret_cast<IdlerID>(idleTimerID) : 0;
\r
1070 ::KillTimer(MainHWND(), reinterpret_cast<uptr_t>(idler.idlerID));
\r
1071 idler.idlerID = 0;
\r
1073 idler.state = idler.idlerID != 0;
\r
1075 return idler.state;
\r
1078 void ScintillaWin::SetMouseCapture(bool on) {
\r
1079 if (mouseDownCaptures) {
\r
1081 ::SetCapture(MainHWND());
\r
1083 ::ReleaseCapture();
\r
1086 capturedMouse = on;
\r
1089 bool ScintillaWin::HaveMouseCapture() {
\r
1090 // Cannot just see if GetCapture is this window as the scroll bar also sets capture for the window
\r
1091 return capturedMouse;
\r
1092 //return capturedMouse && (::GetCapture() == MainHWND());
\r
1095 bool ScintillaWin::PaintContains(PRectangle rc) {
\r
1096 bool contains = true;
\r
1097 if ((paintState == painting) && (!rc.Empty())) {
\r
1098 if (!rcPaint.Contains(rc)) {
\r
1101 // In bounding rectangle so check more accurately using region
\r
1102 HRGN hRgnRange = ::CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
\r
1104 HRGN hRgnDest = ::CreateRectRgn(0, 0, 0, 0);
\r
1106 int combination = ::CombineRgn(hRgnDest, hRgnRange, hRgnUpdate, RGN_DIFF);
\r
1107 if (combination != NULLREGION) {
\r
1110 ::DeleteRgn(hRgnDest);
\r
1112 ::DeleteRgn(hRgnRange);
\r
1119 void ScintillaWin::ScrollText(int linesToMove) {
\r
1120 //Platform::DebugPrintf("ScintillaWin::ScrollText %d\n", linesToMove);
\r
1121 ::ScrollWindow(MainHWND(), 0,
\r
1122 vs.lineHeight * linesToMove, 0, 0);
\r
1123 ::UpdateWindow(MainHWND());
\r
1126 void ScintillaWin::UpdateSystemCaret() {
\r
1128 if (HasCaretSizeChanged()) {
\r
1129 DestroySystemCaret();
\r
1130 CreateSystemCaret();
\r
1132 Point pos = LocationFromPosition(currentPos);
\r
1133 ::SetCaretPos(pos.x, pos.y);
\r
1137 int ScintillaWin::SetScrollInfo(int nBar, LPCSCROLLINFO lpsi, BOOL bRedraw) {
\r
1138 return ::SetScrollInfo(MainHWND(), nBar, lpsi, bRedraw);
\r
1141 bool ScintillaWin::GetScrollInfo(int nBar, LPSCROLLINFO lpsi) {
\r
1142 return ::GetScrollInfo(MainHWND(), nBar, lpsi) ? true : false;
\r
1145 // Change the scroll position but avoid repaint if changing to same value
\r
1146 void ScintillaWin::ChangeScrollPos(int barType, int pos) {
\r
1147 SCROLLINFO sci = {
\r
1148 sizeof(sci),0,0,0,0,0,0
\r
1150 sci.fMask = SIF_POS;
\r
1151 GetScrollInfo(barType, &sci);
\r
1152 if (sci.nPos != pos) {
\r
1155 SetScrollInfo(barType, &sci, TRUE);
\r
1159 void ScintillaWin::SetVerticalScrollPos() {
\r
1160 ChangeScrollPos(SB_VERT, topLine);
\r
1163 void ScintillaWin::SetHorizontalScrollPos() {
\r
1164 ChangeScrollPos(SB_HORZ, xOffset);
\r
1167 bool ScintillaWin::ModifyScrollBars(int nMax, int nPage) {
\r
1168 bool modified = false;
\r
1169 SCROLLINFO sci = {
\r
1170 sizeof(sci),0,0,0,0,0,0
\r
1172 sci.fMask = SIF_PAGE | SIF_RANGE;
\r
1173 GetScrollInfo(SB_VERT, &sci);
\r
1174 int vertEndPreferred = nMax;
\r
1175 if (!verticalScrollBarVisible)
\r
1176 vertEndPreferred = 0;
\r
1177 if ((sci.nMin != 0) ||
\r
1178 (sci.nMax != vertEndPreferred) ||
\r
1179 (sci.nPage != static_cast<unsigned int>(nPage)) ||
\r
1180 (sci.nPos != 0)) {
\r
1181 //Platform::DebugPrintf("Scroll info changed %d %d %d %d %d\n",
\r
1182 // sci.nMin, sci.nMax, sci.nPage, sci.nPos, sci.nTrackPos);
\r
1183 sci.fMask = SIF_PAGE | SIF_RANGE;
\r
1185 sci.nMax = vertEndPreferred;
\r
1186 sci.nPage = nPage;
\r
1188 sci.nTrackPos = 1;
\r
1189 SetScrollInfo(SB_VERT, &sci, TRUE);
\r
1193 PRectangle rcText = GetTextRectangle();
\r
1194 int horizEndPreferred = scrollWidth;
\r
1195 if (horizEndPreferred < 0)
\r
1196 horizEndPreferred = 0;
\r
1197 if (!horizontalScrollBarVisible || (wrapState != eWrapNone))
\r
1198 horizEndPreferred = 0;
\r
1199 unsigned int pageWidth = rcText.Width();
\r
1200 sci.fMask = SIF_PAGE | SIF_RANGE;
\r
1201 GetScrollInfo(SB_HORZ, &sci);
\r
1202 if ((sci.nMin != 0) ||
\r
1203 (sci.nMax != horizEndPreferred) ||
\r
1204 (sci.nPage != pageWidth) ||
\r
1205 (sci.nPos != 0)) {
\r
1206 sci.fMask = SIF_PAGE | SIF_RANGE;
\r
1208 sci.nMax = horizEndPreferred;
\r
1209 sci.nPage = pageWidth;
\r
1211 sci.nTrackPos = 1;
\r
1212 SetScrollInfo(SB_HORZ, &sci, TRUE);
\r
1214 if (scrollWidth < static_cast<int>(pageWidth)) {
\r
1215 HorizontalScrollTo(0);
\r
1221 void ScintillaWin::NotifyChange() {
\r
1222 ::SendMessage(::GetParent(MainHWND()), WM_COMMAND,
\r
1223 MAKELONG(GetCtrlID(), SCEN_CHANGE),
\r
1224 reinterpret_cast<LPARAM>(MainHWND()));
\r
1227 void ScintillaWin::NotifyFocus(bool focus) {
\r
1228 ::SendMessage(::GetParent(MainHWND()), WM_COMMAND,
\r
1229 MAKELONG(GetCtrlID(), focus ? SCEN_SETFOCUS : SCEN_KILLFOCUS),
\r
1230 reinterpret_cast<LPARAM>(MainHWND()));
\r
1233 int ScintillaWin::GetCtrlID() {
\r
1234 return ::GetDlgCtrlID(reinterpret_cast<HWND>(wMain.GetID()));
\r
1237 void ScintillaWin::NotifyParent(SCNotification scn) {
\r
1238 scn.nmhdr.hwndFrom = MainHWND();
\r
1239 scn.nmhdr.idFrom = GetCtrlID();
\r
1240 ::SendMessage(::GetParent(MainHWND()), WM_NOTIFY,
\r
1241 GetCtrlID(), reinterpret_cast<LPARAM>(&scn));
\r
1244 void ScintillaWin::NotifyParent(SCNotification * scn) {
\r
1245 scn->nmhdr.hwndFrom = MainHWND();
\r
1246 scn->nmhdr.idFrom = GetCtrlID();
\r
1247 ::SendMessage(::GetParent(MainHWND()), WM_NOTIFY,
\r
1248 GetCtrlID(), reinterpret_cast<LPARAM>(scn));
\r
1251 void ScintillaWin::NotifyDoubleClick(Point pt, bool shift, bool ctrl, bool alt) {
\r
1252 //Platform::DebugPrintf("ScintillaWin Double click 0\n");
\r
1253 ScintillaBase::NotifyDoubleClick(pt, shift, ctrl, alt);
\r
1254 // Send myself a WM_LBUTTONDBLCLK, so the container can handle it too.
\r
1255 ::SendMessage(MainHWND(),
\r
1257 shift ? MK_SHIFT : 0,
\r
1258 MAKELPARAM(pt.x, pt.y));
\r
1261 void ScintillaWin::Copy() {
\r
1262 //Platform::DebugPrintf("Copy\n");
\r
1263 if (currentPos != anchor) {
\r
1264 SelectionText selectedText;
\r
1265 CopySelectionRange(&selectedText);
\r
1266 CopyToClipboard(selectedText);
\r
1270 void ScintillaWin::CopyAllowLine() {
\r
1271 SelectionText selectedText;
\r
1272 CopySelectionRange(&selectedText, true);
\r
1273 CopyToClipboard(selectedText);
\r
1276 bool ScintillaWin::CanPaste() {
\r
1277 if (!Editor::CanPaste())
\r
1279 if (::IsClipboardFormatAvailable(CF_TEXT))
\r
1281 if (IsUnicodeMode())
\r
1282 return ::IsClipboardFormatAvailable(CF_UNICODETEXT) != 0;
\r
1286 class GlobalMemory {
\r
1290 GlobalMemory() : hand(0), ptr(0) {
\r
1292 GlobalMemory(HGLOBAL hand_) : hand(hand_), ptr(0) {
\r
1294 ptr = ::GlobalLock(hand);
\r
1298 PLATFORM_ASSERT(!ptr);
\r
1300 void Allocate(size_t bytes) {
\r
1301 hand = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, bytes);
\r
1303 ptr = ::GlobalLock(hand);
\r
1306 HGLOBAL Unlock() {
\r
1307 PLATFORM_ASSERT(ptr);
\r
1308 HGLOBAL handCopy = hand;
\r
1309 ::GlobalUnlock(hand);
\r
1314 void SetClip(UINT uFormat) {
\r
1315 ::SetClipboardData(uFormat, Unlock());
\r
1321 return ::GlobalSize(hand);
\r
1325 void ScintillaWin::InsertPasteText(const char *text, int len, int selStart, bool isRectangular, bool isLine) {
\r
1326 if (isRectangular) {
\r
1327 PasteRectangular(selStart, text, len);
\r
1329 char *convertedText = 0;
\r
1330 if (convertPastes) {
\r
1331 // Convert line endings of the paste into our local line-endings mode
\r
1332 convertedText = Document::TransformLineEnds(&len, text, len, pdoc->eolMode);
\r
1333 text = convertedText;
\r
1336 int insertPos = pdoc->LineStart(pdoc->LineFromPosition(currentPos));
\r
1337 pdoc->InsertString(insertPos, text, len);
\r
1338 // add the newline if necessary
\r
1339 if ((len > 0) && (text[len-1] != '\n' && text[len-1] != '\r')) {
\r
1340 const char *endline = StringFromEOLMode(pdoc->eolMode);
\r
1341 pdoc->InsertString(insertPos + len, endline, strlen(endline));
\r
1342 len += strlen(endline);
\r
1344 if (currentPos == insertPos) {
\r
1345 SetEmptySelection(currentPos + len);
\r
1347 } else if (pdoc->InsertString(currentPos, text, len)) {
\r
1348 SetEmptySelection(currentPos + len);
\r
1350 delete []convertedText;
\r
1354 void ScintillaWin::Paste() {
\r
1355 if (!::OpenClipboard(MainHWND()))
\r
1357 pdoc->BeginUndoAction();
\r
1358 bool isLine = SelectionEmpty() && (::IsClipboardFormatAvailable(cfLineSelect) != 0);
\r
1360 int selStart = SelectionStart();
\r
1361 bool isRectangular = ::IsClipboardFormatAvailable(cfColumnSelect) != 0;
\r
1363 // Always use CF_UNICODETEXT if available
\r
1364 GlobalMemory memUSelection(::GetClipboardData(CF_UNICODETEXT));
\r
1365 if (memUSelection) {
\r
1366 wchar_t *uptr = static_cast<wchar_t *>(memUSelection.ptr);
\r
1370 // Default Scintilla behaviour in Unicode mode
\r
1371 if (IsUnicodeMode()) {
\r
1372 unsigned int bytes = memUSelection.Size();
\r
1373 len = UTF8Length(uptr, bytes / 2);
\r
1374 putf = new char[len + 1];
\r
1376 UTF8FromUTF16(uptr, bytes / 2, putf, len);
\r
1379 // CF_UNICODETEXT available, but not in Unicode mode
\r
1380 // Convert from Unicode to current Scintilla code page
\r
1381 UINT cpDest = CodePageFromCharSet(
\r
1382 vs.styles[STYLE_DEFAULT].characterSet, pdoc->dbcsCodePage);
\r
1383 len = ::WideCharToMultiByte(cpDest, 0, uptr, -1,
\r
1384 NULL, 0, NULL, NULL) - 1; // subtract 0 terminator
\r
1385 putf = new char[len + 1];
\r
1387 ::WideCharToMultiByte(cpDest, 0, uptr, -1,
\r
1388 putf, len + 1, NULL, NULL);
\r
1393 InsertPasteText(putf, len, selStart, isRectangular, isLine);
\r
1397 memUSelection.Unlock();
\r
1399 // CF_UNICODETEXT not available, paste ANSI text
\r
1400 GlobalMemory memSelection(::GetClipboardData(CF_TEXT));
\r
1401 if (memSelection) {
\r
1402 char *ptr = static_cast<char *>(memSelection.ptr);
\r
1404 unsigned int bytes = memSelection.Size();
\r
1405 unsigned int len = bytes;
\r
1406 for (unsigned int i = 0; i < bytes; i++) {
\r
1407 if ((len == bytes) && (0 == ptr[i]))
\r
1411 // In Unicode mode, convert clipboard text to UTF-8
\r
1412 if (IsUnicodeMode()) {
\r
1413 wchar_t *uptr = new wchar_t[len+1];
\r
1415 unsigned int ulen = ::MultiByteToWideChar(CP_ACP, 0,
\r
1416 ptr, len, uptr, len+1);
\r
1418 unsigned int mlen = UTF8Length(uptr, ulen);
\r
1419 char *putf = new char[mlen + 1];
\r
1421 // CP_UTF8 not available on Windows 95, so use UTF8FromUTF16()
\r
1422 UTF8FromUTF16(uptr, ulen, putf, mlen);
\r
1428 InsertPasteText(putf, mlen, selStart, isRectangular, isLine);
\r
1432 InsertPasteText(ptr, len, selStart, isRectangular, isLine);
\r
1435 memSelection.Unlock();
\r
1438 ::CloseClipboard();
\r
1439 pdoc->EndUndoAction();
\r
1444 void ScintillaWin::CreateCallTipWindow(PRectangle) {
\r
1445 #ifdef TOTAL_CONTROL
\r
1446 if (!ct.wCallTip.Created()) {
\r
1447 ct.wCallTip = ::CreateWindow(callClassName, TEXT("ACallTip"),
\r
1448 WS_POPUP, 100, 100, 150, 20,
\r
1450 GetWindowInstance(MainHWND()),
\r
1452 ct.wDraw = ct.wCallTip;
\r
1457 void ScintillaWin::AddToPopUp(const char *label, int cmd, bool enabled) {
\r
1458 #ifdef TOTAL_CONTROL
\r
1459 HMENU hmenuPopup = reinterpret_cast<HMENU>(popup.GetID());
\r
1461 ::AppendMenuA(hmenuPopup, MF_SEPARATOR, 0, "");
\r
1463 ::AppendMenuA(hmenuPopup, MF_STRING, cmd, label);
\r
1465 ::AppendMenuA(hmenuPopup, MF_STRING | MF_DISABLED | MF_GRAYED, cmd, label);
\r
1469 void ScintillaWin::ClaimSelection() {
\r
1470 // Windows does not have a primary selection
\r
1477 Initial Windows-Only implementation of the external lexer
\r
1478 system in ScintillaWin class. Intention is to create a LexerModule
\r
1479 subclass (?) to have lex and fold methods which will call out to their
\r
1484 void ScintillaWin::SetLexer(uptr_t wParam) {
\r
1485 lexLanguage = wParam;
\r
1486 lexCurrent = LexerModule::Find(lexLanguage);
\r
1488 lexCurrent = LexerModule::Find(SCLEX_NULL);
\r
1491 void ScintillaWin::SetLexerLanguage(const char *languageName) {
\r
1492 lexLanguage = SCLEX_CONTAINER;
\r
1493 lexCurrent = LexerModule::Find(languageName);
\r
1495 lexCurrent = LexerModule::Find(SCLEX_NULL);
\r
1497 lexLanguage = lexCurrent->GetLanguage();
\r
1502 /// Implement IUnknown
\r
1504 STDMETHODIMP_(ULONG)FormatEnumerator_AddRef(FormatEnumerator *fe);
\r
1505 STDMETHODIMP FormatEnumerator_QueryInterface(FormatEnumerator *fe, REFIID riid, PVOID *ppv) {
\r
1506 //Platform::DebugPrintf("EFE QI");
\r
1508 if (riid == IID_IUnknown)
\r
1509 *ppv = reinterpret_cast<IEnumFORMATETC *>(fe);
\r
1510 if (riid == IID_IEnumFORMATETC)
\r
1511 *ppv = reinterpret_cast<IEnumFORMATETC *>(fe);
\r
1513 return E_NOINTERFACE;
\r
1514 FormatEnumerator_AddRef(fe);
\r
1517 STDMETHODIMP_(ULONG)FormatEnumerator_AddRef(FormatEnumerator *fe) {
\r
1520 STDMETHODIMP_(ULONG)FormatEnumerator_Release(FormatEnumerator *fe) {
\r
1527 /// Implement IEnumFORMATETC
\r
1528 STDMETHODIMP FormatEnumerator_Next(FormatEnumerator *fe, ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched) {
\r
1529 //Platform::DebugPrintf("EFE Next %d %d", fe->pos, celt);
\r
1530 if (rgelt == NULL) return E_POINTER;
\r
1531 // We only support one format, so this is simple.
\r
1532 unsigned int putPos = 0;
\r
1533 while ((fe->pos < fe->formatsLen) && (putPos < celt)) {
\r
1534 rgelt->cfFormat = fe->formats[fe->pos];
\r
1536 rgelt->dwAspect = DVASPECT_CONTENT;
\r
1537 rgelt->lindex = -1;
\r
1538 rgelt->tymed = TYMED_HGLOBAL;
\r
1543 *pceltFetched = putPos;
\r
1544 return putPos ? S_OK : S_FALSE;
\r
1546 STDMETHODIMP FormatEnumerator_Skip(FormatEnumerator *fe, ULONG celt) {
\r
1550 STDMETHODIMP FormatEnumerator_Reset(FormatEnumerator *fe) {
\r
1554 STDMETHODIMP FormatEnumerator_Clone(FormatEnumerator *fe, IEnumFORMATETC **ppenum) {
\r
1555 FormatEnumerator *pfe = new FormatEnumerator(fe->pos, fe->formats, fe->formatsLen);
\r
1556 return FormatEnumerator_QueryInterface(pfe, IID_IEnumFORMATETC,
\r
1557 reinterpret_cast<void **>(ppenum));
\r
1560 static void *vtFormatEnumerator[] = {
\r
1561 (void *)(FormatEnumerator_QueryInterface),
\r
1562 (void *)(FormatEnumerator_AddRef),
\r
1563 (void *)(FormatEnumerator_Release),
\r
1564 (void *)(FormatEnumerator_Next),
\r
1565 (void *)(FormatEnumerator_Skip),
\r
1566 (void *)(FormatEnumerator_Reset),
\r
1567 (void *)(FormatEnumerator_Clone)
\r
1570 FormatEnumerator::FormatEnumerator(int pos_, CLIPFORMAT formats_[], int formatsLen_) {
\r
1571 vtbl = vtFormatEnumerator;
\r
1572 ref = 0; // First QI adds first reference...
\r
1574 formatsLen = formatsLen_;
\r
1575 for (int i=0;i<formatsLen;i++)
\r
1576 formats[i] = formats_[i];
\r
1579 /// Implement IUnknown
\r
1580 STDMETHODIMP DropSource_QueryInterface(DropSource *ds, REFIID riid, PVOID *ppv) {
\r
1581 return ds->sci->QueryInterface(riid, ppv);
\r
1583 STDMETHODIMP_(ULONG)DropSource_AddRef(DropSource *ds) {
\r
1584 return ds->sci->AddRef();
\r
1586 STDMETHODIMP_(ULONG)DropSource_Release(DropSource *ds) {
\r
1587 return ds->sci->Release();
\r
1590 /// Implement IDropSource
\r
1591 STDMETHODIMP DropSource_QueryContinueDrag(DropSource *, BOOL fEsc, DWORD grfKeyState) {
\r
1593 return DRAGDROP_S_CANCEL;
\r
1594 if (!(grfKeyState & MK_LBUTTON))
\r
1595 return DRAGDROP_S_DROP;
\r
1599 STDMETHODIMP DropSource_GiveFeedback(DropSource *, DWORD) {
\r
1600 return DRAGDROP_S_USEDEFAULTCURSORS;
\r
1603 static void *vtDropSource[] = {
\r
1604 (void *)(DropSource_QueryInterface),
\r
1605 (void *)(DropSource_AddRef),
\r
1606 (void *)(DropSource_Release),
\r
1607 (void *)(DropSource_QueryContinueDrag),
\r
1608 (void *)(DropSource_GiveFeedback)
\r
1611 DropSource::DropSource() {
\r
1612 vtbl = vtDropSource;
\r
1616 /// Implement IUnkown
\r
1617 STDMETHODIMP DataObject_QueryInterface(DataObject *pd, REFIID riid, PVOID *ppv) {
\r
1618 //Platform::DebugPrintf("DO QI %x\n", pd);
\r
1619 return pd->sci->QueryInterface(riid, ppv);
\r
1621 STDMETHODIMP_(ULONG)DataObject_AddRef(DataObject *pd) {
\r
1622 return pd->sci->AddRef();
\r
1624 STDMETHODIMP_(ULONG)DataObject_Release(DataObject *pd) {
\r
1625 return pd->sci->Release();
\r
1627 /// Implement IDataObject
\r
1628 STDMETHODIMP DataObject_GetData(DataObject *pd, FORMATETC *pFEIn, STGMEDIUM *pSTM) {
\r
1629 return pd->sci->GetData(pFEIn, pSTM);
\r
1632 STDMETHODIMP DataObject_GetDataHere(DataObject *, FORMATETC *, STGMEDIUM *) {
\r
1633 //Platform::DebugPrintf("DOB GetDataHere\n");
\r
1637 STDMETHODIMP DataObject_QueryGetData(DataObject *pd, FORMATETC *pFE) {
\r
1638 if (pd->sci->DragIsRectangularOK(pFE->cfFormat) &&
\r
1640 (pFE->dwAspect & DVASPECT_CONTENT) != 0 &&
\r
1641 pFE->lindex == -1 &&
\r
1642 (pFE->tymed & TYMED_HGLOBAL) != 0
\r
1647 bool formatOK = (pFE->cfFormat == CF_TEXT) ||
\r
1648 ((pFE->cfFormat == CF_UNICODETEXT) && pd->sci->IsUnicodeMode());
\r
1651 (pFE->dwAspect & DVASPECT_CONTENT) == 0 ||
\r
1652 pFE->lindex != -1 ||
\r
1653 (pFE->tymed & TYMED_HGLOBAL) == 0
\r
1655 //Platform::DebugPrintf("DOB QueryGetData No %x\n",pFE->cfFormat);
\r
1656 //return DATA_E_FORMATETC;
\r
1659 //Platform::DebugPrintf("DOB QueryGetData OK %x\n",pFE->cfFormat);
\r
1663 STDMETHODIMP DataObject_GetCanonicalFormatEtc(DataObject *pd, FORMATETC *, FORMATETC *pFEOut) {
\r
1664 //Platform::DebugPrintf("DOB GetCanon\n");
\r
1665 if (pd->sci->IsUnicodeMode())
\r
1666 pFEOut->cfFormat = CF_UNICODETEXT;
\r
1668 pFEOut->cfFormat = CF_TEXT;
\r
1670 pFEOut->dwAspect = DVASPECT_CONTENT;
\r
1671 pFEOut->lindex = -1;
\r
1672 pFEOut->tymed = TYMED_HGLOBAL;
\r
1676 STDMETHODIMP DataObject_SetData(DataObject *, FORMATETC *, STGMEDIUM *, BOOL) {
\r
1677 //Platform::DebugPrintf("DOB SetData\n");
\r
1681 STDMETHODIMP DataObject_EnumFormatEtc(DataObject *pd, DWORD dwDirection, IEnumFORMATETC **ppEnum) {
\r
1682 //Platform::DebugPrintf("DOB EnumFormatEtc %d\n", dwDirection);
\r
1683 if (dwDirection != DATADIR_GET) {
\r
1687 FormatEnumerator *pfe;
\r
1688 if (pd->sci->IsUnicodeMode()) {
\r
1689 CLIPFORMAT formats[] = {CF_UNICODETEXT, CF_TEXT};
\r
1690 pfe = new FormatEnumerator(0, formats, 2);
\r
1692 CLIPFORMAT formats[] = {CF_TEXT};
\r
1693 pfe = new FormatEnumerator(0, formats, 1);
\r
1695 return FormatEnumerator_QueryInterface(pfe, IID_IEnumFORMATETC,
\r
1696 reinterpret_cast<void **>(ppEnum));
\r
1699 STDMETHODIMP DataObject_DAdvise(DataObject *, FORMATETC *, DWORD, IAdviseSink *, PDWORD) {
\r
1700 //Platform::DebugPrintf("DOB DAdvise\n");
\r
1704 STDMETHODIMP DataObject_DUnadvise(DataObject *, DWORD) {
\r
1705 //Platform::DebugPrintf("DOB DUnadvise\n");
\r
1709 STDMETHODIMP DataObject_EnumDAdvise(DataObject *, IEnumSTATDATA **) {
\r
1710 //Platform::DebugPrintf("DOB EnumDAdvise\n");
\r
1714 static void *vtDataObject[] = {
\r
1715 (void *)(DataObject_QueryInterface),
\r
1716 (void *)(DataObject_AddRef),
\r
1717 (void *)(DataObject_Release),
\r
1718 (void *)(DataObject_GetData),
\r
1719 (void *)(DataObject_GetDataHere),
\r
1720 (void *)(DataObject_QueryGetData),
\r
1721 (void *)(DataObject_GetCanonicalFormatEtc),
\r
1722 (void *)(DataObject_SetData),
\r
1723 (void *)(DataObject_EnumFormatEtc),
\r
1724 (void *)(DataObject_DAdvise),
\r
1725 (void *)(DataObject_DUnadvise),
\r
1726 (void *)(DataObject_EnumDAdvise)
\r
1729 DataObject::DataObject() {
\r
1730 vtbl = vtDataObject;
\r
1734 /// Implement IUnknown
\r
1735 STDMETHODIMP DropTarget_QueryInterface(DropTarget *dt, REFIID riid, PVOID *ppv) {
\r
1736 //Platform::DebugPrintf("DT QI %x\n", dt);
\r
1737 return dt->sci->QueryInterface(riid, ppv);
\r
1739 STDMETHODIMP_(ULONG)DropTarget_AddRef(DropTarget *dt) {
\r
1740 return dt->sci->AddRef();
\r
1742 STDMETHODIMP_(ULONG)DropTarget_Release(DropTarget *dt) {
\r
1743 return dt->sci->Release();
\r
1746 /// Implement IDropTarget by forwarding to Scintilla
\r
1747 STDMETHODIMP DropTarget_DragEnter(DropTarget *dt, LPDATAOBJECT pIDataSource, DWORD grfKeyState,
\r
1748 POINTL pt, PDWORD pdwEffect) {
\r
1749 return dt->sci->DragEnter(pIDataSource, grfKeyState, pt, pdwEffect);
\r
1751 STDMETHODIMP DropTarget_DragOver(DropTarget *dt, DWORD grfKeyState, POINTL pt, PDWORD pdwEffect) {
\r
1752 return dt->sci->DragOver(grfKeyState, pt, pdwEffect);
\r
1754 STDMETHODIMP DropTarget_DragLeave(DropTarget *dt) {
\r
1755 return dt->sci->DragLeave();
\r
1757 STDMETHODIMP DropTarget_Drop(DropTarget *dt, LPDATAOBJECT pIDataSource, DWORD grfKeyState,
\r
1758 POINTL pt, PDWORD pdwEffect) {
\r
1759 return dt->sci->Drop(pIDataSource, grfKeyState, pt, pdwEffect);
\r
1762 static void *vtDropTarget[] = {
\r
1763 (void *)(DropTarget_QueryInterface),
\r
1764 (void *)(DropTarget_AddRef),
\r
1765 (void *)(DropTarget_Release),
\r
1766 (void *)(DropTarget_DragEnter),
\r
1767 (void *)(DropTarget_DragOver),
\r
1768 (void *)(DropTarget_DragLeave),
\r
1769 (void *)(DropTarget_Drop)
\r
1772 DropTarget::DropTarget() {
\r
1773 vtbl = vtDropTarget;
\r
1778 * DBCS: support Input Method Editor (IME).
\r
1779 * Called when IME Window opened.
\r
1781 void ScintillaWin::ImeStartComposition() {
\r
1783 // Digital Mars compiler does not include Imm library
\r
1784 if (caret.active) {
\r
1785 // Move IME Window to current caret position
\r
1786 HIMC hIMC = ::ImmGetContext(MainHWND());
\r
1787 Point pos = LocationFromPosition(currentPos);
\r
1788 COMPOSITIONFORM CompForm;
\r
1789 CompForm.dwStyle = CFS_POINT;
\r
1790 CompForm.ptCurrentPos.x = pos.x;
\r
1791 CompForm.ptCurrentPos.y = pos.y;
\r
1793 ::ImmSetCompositionWindow(hIMC, &CompForm);
\r
1795 // Set font of IME window to same as surrounded text.
\r
1796 if (stylesValid) {
\r
1797 // Since the style creation code has been made platform independent,
\r
1798 // The logfont for the IME is recreated here.
\r
1799 int styleHere = (pdoc->StyleAt(currentPos)) & 31;
\r
1800 LOGFONTA lf = {0,0,0,0,0,0,0,0,0,0,0,0,0, ""};
\r
1801 int sizeZoomed = vs.styles[styleHere].size + vs.zoomLevel;
\r
1802 if (sizeZoomed <= 2) // Hangs if sizeZoomed <= 1
\r
1804 AutoSurface surface(this);
\r
1805 int deviceHeight = sizeZoomed;
\r
1807 deviceHeight = (sizeZoomed * surface->LogPixelsY()) / 72;
\r
1809 // The negative is to allow for leading
\r
1810 lf.lfHeight = -(abs(deviceHeight));
\r
1811 lf.lfWeight = vs.styles[styleHere].bold ? FW_BOLD : FW_NORMAL;
\r
1812 lf.lfItalic = static_cast<BYTE>(vs.styles[styleHere].italic ? 1 : 0);
\r
1813 lf.lfCharSet = DEFAULT_CHARSET;
\r
1814 lf.lfFaceName[0] = '\0';
\r
1815 if (vs.styles[styleHere].fontName)
\r
1816 strcpy(lf.lfFaceName, vs.styles[styleHere].fontName);
\r
1818 ::ImmSetCompositionFontA(hIMC, &lf);
\r
1820 ::ImmReleaseContext(MainHWND(), hIMC);
\r
1821 // Caret is displayed in IME window. So, caret in Scintilla is useless.
\r
1827 /** Called when IME Window closed. */
\r
1828 void ScintillaWin::ImeEndComposition() {
\r
1829 ShowCaretAtCurrentPosition();
\r
1832 void ScintillaWin::AddCharBytes(char b0, char b1) {
\r
1834 int inputCodePage = InputCodePage();
\r
1835 if (inputCodePage && IsUnicodeMode()) {
\r
1836 char utfval[4]="\0\0\0";
\r
1837 char ansiChars[3];
\r
1839 if (b0) { // Two bytes from IME
\r
1840 ansiChars[0] = b0;
\r
1841 ansiChars[1] = b1;
\r
1842 ansiChars[2] = '\0';
\r
1843 ::MultiByteToWideChar(inputCodePage, 0, ansiChars, 2, wcs, 1);
\r
1845 ansiChars[0] = b1;
\r
1846 ansiChars[1] = '\0';
\r
1847 ::MultiByteToWideChar(inputCodePage, 0, ansiChars, 1, wcs, 1);
\r
1849 unsigned int len = UTF8Length(wcs, 1);
\r
1850 UTF8FromUTF16(wcs, 1, utfval, len);
\r
1851 utfval[len] = '\0';
\r
1852 AddCharUTF(utfval, len ? len : 1);
\r
1854 char dbcsChars[3];
\r
1855 dbcsChars[0] = b0;
\r
1856 dbcsChars[1] = b1;
\r
1857 dbcsChars[2] = '\0';
\r
1858 AddCharUTF(dbcsChars, 2, true);
\r
1864 void ScintillaWin::GetIntelliMouseParameters() {
\r
1865 // This retrieves the number of lines per scroll as configured inthe Mouse Properties sheet in Control Panel
\r
1866 ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &linesPerScroll, 0);
\r
1869 void ScintillaWin::CopyToClipboard(const SelectionText &selectedText) {
\r
1870 if (!::OpenClipboard(MainHWND()))
\r
1872 ::EmptyClipboard();
\r
1874 GlobalMemory uniText;
\r
1876 // Default Scintilla behaviour in Unicode mode
\r
1877 if (IsUnicodeMode()) {
\r
1878 int uchars = UTF16Length(selectedText.s, selectedText.len);
\r
1879 uniText.Allocate(2 * uchars);
\r
1881 UTF16FromUTF8(selectedText.s, selectedText.len, static_cast<wchar_t *>(uniText.ptr), uchars);
\r
1884 // Not Unicode mode
\r
1885 // Convert to Unicode using the current Scintilla code page
\r
1886 UINT cpSrc = CodePageFromCharSet(
\r
1887 selectedText.characterSet, selectedText.codePage);
\r
1888 uniText.Allocate(2 * selectedText.len);
\r
1890 ::MultiByteToWideChar(cpSrc, 0, selectedText.s, selectedText.len,
\r
1891 static_cast<wchar_t *>(uniText.ptr), selectedText.len);
\r
1897 // Copy ANSI text to clipboard on Windows 9x
\r
1898 // Convert from Unicode text, so other ANSI programs can
\r
1900 // Windows NT, 2k, XP automatically generates CF_TEXT
\r
1901 GlobalMemory ansiText;
\r
1902 ansiText.Allocate(selectedText.len);
\r
1904 ::WideCharToMultiByte(CP_ACP, 0, static_cast<wchar_t *>(uniText.ptr), -1,
\r
1905 static_cast<char *>(ansiText.ptr), selectedText.len, NULL, NULL);
\r
1906 ansiText.SetClip(CF_TEXT);
\r
1909 uniText.SetClip(CF_UNICODETEXT);
\r
1911 // There was a failure - try to copy at least ANSI text
\r
1912 GlobalMemory ansiText;
\r
1913 ansiText.Allocate(selectedText.len);
\r
1915 memcpy(static_cast<char *>(ansiText.ptr), selectedText.s, selectedText.len);
\r
1916 ansiText.SetClip(CF_TEXT);
\r
1920 if (selectedText.rectangular) {
\r
1921 ::SetClipboardData(cfColumnSelect, 0);
\r
1924 if (selectedText.lineCopy) {
\r
1925 ::SetClipboardData(cfLineSelect, 0);
\r
1928 ::CloseClipboard();
\r
1931 void ScintillaWin::ScrollMessage(WPARAM wParam) {
\r
1932 //DWORD dwStart = timeGetTime();
\r
1933 //Platform::DebugPrintf("Scroll %x %d\n", wParam, lParam);
\r
1936 memset(&sci, 0, sizeof(sci));
\r
1937 sci.cbSize = sizeof(sci);
\r
1938 sci.fMask = SIF_ALL;
\r
1940 GetScrollInfo(SB_VERT, &sci);
\r
1942 //Platform::DebugPrintf("ScrollInfo %d mask=%x min=%d max=%d page=%d pos=%d track=%d\n", b,sci.fMask,
\r
1943 //sci.nMin, sci.nMax, sci.nPage, sci.nPos, sci.nTrackPos);
\r
1945 int topLineNew = topLine;
\r
1946 switch (LoWord(wParam)) {
\r
1954 topLineNew -= LinesToScroll(); break;
\r
1955 case SB_PAGEDOWN: topLineNew += LinesToScroll(); break;
\r
1956 case SB_TOP: topLineNew = 0; break;
\r
1957 case SB_BOTTOM: topLineNew = MaxScrollPos(); break;
\r
1958 case SB_THUMBPOSITION: topLineNew = sci.nTrackPos; break;
\r
1959 case SB_THUMBTRACK: topLineNew = sci.nTrackPos; break;
\r
1961 ScrollTo(topLineNew);
\r
1964 void ScintillaWin::HorizontalScrollMessage(WPARAM wParam) {
\r
1965 int xPos = xOffset;
\r
1966 PRectangle rcText = GetTextRectangle();
\r
1967 int pageWidth = rcText.Width() * 2 / 3;
\r
1968 switch (LoWord(wParam)) {
\r
1972 case SB_LINEDOWN: // May move past the logical end
\r
1976 xPos -= pageWidth;
\r
1979 xPos += pageWidth;
\r
1980 if (xPos > scrollWidth - rcText.Width()) { // Hit the end exactly
\r
1981 xPos = scrollWidth - rcText.Width();
\r
1988 xPos = scrollWidth;
\r
1990 case SB_THUMBPOSITION:
\r
1991 case SB_THUMBTRACK: {
\r
1992 // 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 =]
\r
1994 si.cbSize = sizeof(si);
\r
1995 si.fMask = SIF_TRACKPOS;
\r
1996 if (GetScrollInfo(SB_HORZ, &si)) {
\r
1997 xPos = si.nTrackPos;
\r
2002 HorizontalScrollTo(xPos);
\r
2005 void ScintillaWin::RealizeWindowPalette(bool inBackGround) {
\r
2006 RefreshStyleData();
\r
2007 HDC hdc = ::GetDC(MainHWND());
\r
2008 // Select a stock font to prevent warnings from BoundsChecker
\r
2009 ::SelectObject(hdc, GetStockFont(DEFAULT_GUI_FONT));
\r
2010 AutoSurface surfaceWindow(hdc, this);
\r
2011 if (surfaceWindow) {
\r
2012 int changes = surfaceWindow->SetPalette(&palette, inBackGround);
\r
2015 surfaceWindow->Release();
\r
2017 ::ReleaseDC(MainHWND(), hdc);
\r
2021 * Redraw all of text area.
\r
2022 * This paint will not be abandoned.
\r
2024 void ScintillaWin::FullPaint() {
\r
2025 HDC hdc = ::GetDC(MainHWND());
\r
2027 ::ReleaseDC(MainHWND(), hdc);
\r
2031 * Redraw all of text area on the specified DC.
\r
2032 * This paint will not be abandoned.
\r
2034 void ScintillaWin::FullPaintDC(HDC hdc) {
\r
2035 paintState = painting;
\r
2036 rcPaint = GetClientRectangle();
\r
2037 paintingAllText = true;
\r
2038 AutoSurface surfaceWindow(hdc, this);
\r
2039 if (surfaceWindow) {
\r
2040 Paint(surfaceWindow, rcPaint);
\r
2041 surfaceWindow->Release();
\r
2043 paintState = notPainting;
\r
2046 static bool CompareDevCap(HDC hdc, HDC hOtherDC, int nIndex) {
\r
2047 return ::GetDeviceCaps(hdc, nIndex) == ::GetDeviceCaps(hOtherDC, nIndex);
\r
2050 bool ScintillaWin::IsCompatibleDC(HDC hOtherDC) {
\r
2051 HDC hdc = ::GetDC(MainHWND());
\r
2052 bool isCompatible =
\r
2053 CompareDevCap(hdc, hOtherDC, TECHNOLOGY) &&
\r
2054 CompareDevCap(hdc, hOtherDC, LOGPIXELSY) &&
\r
2055 CompareDevCap(hdc, hOtherDC, LOGPIXELSX) &&
\r
2056 CompareDevCap(hdc, hOtherDC, BITSPIXEL) &&
\r
2057 CompareDevCap(hdc, hOtherDC, PLANES);
\r
2058 ::ReleaseDC(MainHWND(), hdc);
\r
2059 return isCompatible;
\r
2062 DWORD ScintillaWin::EffectFromState(DWORD grfKeyState) {
\r
2063 // These are the Wordpad semantics.
\r
2065 if (inDragDrop == ddDragging) // Internal defaults to move
\r
2066 dwEffect = DROPEFFECT_MOVE;
\r
2068 dwEffect = DROPEFFECT_COPY;
\r
2069 if (grfKeyState & MK_ALT)
\r
2070 dwEffect = DROPEFFECT_MOVE;
\r
2071 if (grfKeyState & MK_CONTROL)
\r
2072 dwEffect = DROPEFFECT_COPY;
\r
2076 /// Implement IUnknown
\r
2077 STDMETHODIMP ScintillaWin::QueryInterface(REFIID riid, PVOID *ppv) {
\r
2079 if (riid == IID_IUnknown)
\r
2080 *ppv = reinterpret_cast<IDropTarget *>(&dt);
\r
2081 if (riid == IID_IDropSource)
\r
2082 *ppv = reinterpret_cast<IDropSource *>(&ds);
\r
2083 if (riid == IID_IDropTarget)
\r
2084 *ppv = reinterpret_cast<IDropTarget *>(&dt);
\r
2085 if (riid == IID_IDataObject)
\r
2086 *ppv = reinterpret_cast<IDataObject *>(&dob);
\r
2088 return E_NOINTERFACE;
\r
2092 STDMETHODIMP_(ULONG) ScintillaWin::AddRef() {
\r
2096 STDMETHODIMP_(ULONG) ScintillaWin::Release() {
\r
2100 /// Implement IDropTarget
\r
2101 STDMETHODIMP ScintillaWin::DragEnter(LPDATAOBJECT pIDataSource, DWORD grfKeyState,
\r
2102 POINTL, PDWORD pdwEffect) {
\r
2103 if (pIDataSource == NULL)
\r
2105 FORMATETC fmtu = {CF_UNICODETEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
\r
2106 HRESULT hrHasUText = pIDataSource->QueryGetData(&fmtu);
\r
2107 hasOKText = (hrHasUText == S_OK);
\r
2109 FORMATETC fmte = {CF_TEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
\r
2110 HRESULT hrHasText = pIDataSource->QueryGetData(&fmte);
\r
2111 hasOKText = (hrHasText == S_OK);
\r
2114 *pdwEffect = DROPEFFECT_NONE;
\r
2118 *pdwEffect = EffectFromState(grfKeyState);
\r
2122 STDMETHODIMP ScintillaWin::DragOver(DWORD grfKeyState, POINTL pt, PDWORD pdwEffect) {
\r
2123 if (!hasOKText || pdoc->IsReadOnly()) {
\r
2124 *pdwEffect = DROPEFFECT_NONE;
\r
2128 *pdwEffect = EffectFromState(grfKeyState);
\r
2130 // Update the cursor.
\r
2131 POINT rpt = {pt.x, pt.y};
\r
2132 ::ScreenToClient(MainHWND(), &rpt);
\r
2133 SetDragPosition(PositionFromLocation(Point(rpt.x, rpt.y)));
\r
2138 STDMETHODIMP ScintillaWin::DragLeave() {
\r
2139 SetDragPosition(invalidPosition);
\r
2143 STDMETHODIMP ScintillaWin::Drop(LPDATAOBJECT pIDataSource, DWORD grfKeyState,
\r
2144 POINTL pt, PDWORD pdwEffect) {
\r
2145 *pdwEffect = EffectFromState(grfKeyState);
\r
2147 if (pIDataSource == NULL)
\r
2150 SetDragPosition(invalidPosition);
\r
2152 STGMEDIUM medium={0,{0},0};
\r
2155 bool dataAllocated = false;
\r
2157 FORMATETC fmtu = {CF_UNICODETEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
\r
2158 HRESULT hr = pIDataSource->GetData(&fmtu, &medium);
\r
2159 if (SUCCEEDED(hr) && medium.hGlobal) {
\r
2160 wchar_t *udata = static_cast<wchar_t *>(::GlobalLock(medium.hGlobal));
\r
2161 if (IsUnicodeMode()) {
\r
2162 int tlen = ::GlobalSize(medium.hGlobal);
\r
2163 // Convert UTF-16 to UTF-8
\r
2164 int dataLen = UTF8Length(udata, tlen/2);
\r
2165 data = new char[dataLen+1];
\r
2167 UTF8FromUTF16(udata, tlen/2, data, dataLen);
\r
2168 dataAllocated = true;
\r
2171 // Convert UTF-16 to ANSI
\r
2173 // Default Scintilla behavior in Unicode mode
\r
2174 // CF_UNICODETEXT available, but not in Unicode mode
\r
2175 // Convert from Unicode to current Scintilla code page
\r
2176 UINT cpDest = CodePageFromCharSet(
\r
2177 vs.styles[STYLE_DEFAULT].characterSet, pdoc->dbcsCodePage);
\r
2178 int tlen = ::WideCharToMultiByte(cpDest, 0, udata, -1,
\r
2179 NULL, 0, NULL, NULL) - 1; // subtract 0 terminator
\r
2180 data = new char[tlen + 1];
\r
2182 memset(data, 0, (tlen+1));
\r
2183 ::WideCharToMultiByte(cpDest, 0, udata, -1,
\r
2184 data, tlen + 1, NULL, NULL);
\r
2185 dataAllocated = true;
\r
2191 FORMATETC fmte = {CF_TEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
\r
2192 hr = pIDataSource->GetData(&fmte, &medium);
\r
2193 if (SUCCEEDED(hr) && medium.hGlobal) {
\r
2194 data = static_cast<char *>(::GlobalLock(medium.hGlobal));
\r
2199 //Platform::DebugPrintf("Bad data format: 0x%x\n", hres);
\r
2203 FORMATETC fmtr = {cfColumnSelect, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
\r
2204 HRESULT hrRectangular = pIDataSource->QueryGetData(&fmtr);
\r
2206 POINT rpt = {pt.x, pt.y};
\r
2207 ::ScreenToClient(MainHWND(), &rpt);
\r
2208 int movePos = PositionFromLocation(Point(rpt.x, rpt.y));
\r
2210 DropAt(movePos, data, *pdwEffect == DROPEFFECT_MOVE, hrRectangular == S_OK);
\r
2212 ::GlobalUnlock(medium.hGlobal);
\r
2215 if (medium.pUnkForRelease != NULL)
\r
2216 medium.pUnkForRelease->Release();
\r
2218 ::GlobalFree(medium.hGlobal);
\r
2220 if (dataAllocated)
\r
2226 /// Implement important part of IDataObject
\r
2227 STDMETHODIMP ScintillaWin::GetData(FORMATETC *pFEIn, STGMEDIUM *pSTM) {
\r
2228 bool formatOK = (pFEIn->cfFormat == CF_TEXT) ||
\r
2229 ((pFEIn->cfFormat == CF_UNICODETEXT) && IsUnicodeMode());
\r
2231 pFEIn->ptd != 0 ||
\r
2232 (pFEIn->dwAspect & DVASPECT_CONTENT) == 0 ||
\r
2233 pFEIn->lindex != -1 ||
\r
2234 (pFEIn->tymed & TYMED_HGLOBAL) == 0
\r
2236 //Platform::DebugPrintf("DOB GetData No %d %x %x fmt=%x\n", lenDrag, pFEIn, pSTM, pFEIn->cfFormat);
\r
2237 return DATA_E_FORMATETC;
\r
2239 pSTM->tymed = TYMED_HGLOBAL;
\r
2240 //Platform::DebugPrintf("DOB GetData OK %d %x %x\n", lenDrag, pFEIn, pSTM);
\r
2242 GlobalMemory text;
\r
2243 if (pFEIn->cfFormat == CF_UNICODETEXT) {
\r
2244 int uchars = UTF16Length(drag.s, drag.len);
\r
2245 text.Allocate(2 * uchars);
\r
2247 UTF16FromUTF8(drag.s, drag.len, static_cast<wchar_t *>(text.ptr), uchars);
\r
2250 text.Allocate(drag.len);
\r
2252 memcpy(static_cast<char *>(text.ptr), drag.s, drag.len);
\r
2255 pSTM->hGlobal = text ? text.Unlock() : 0;
\r
2256 pSTM->pUnkForRelease = 0;
\r
2260 bool ScintillaWin::Register(HINSTANCE hInstance_) {
\r
2262 hInstance = hInstance_;
\r
2265 // Register the Scintilla class
\r
2268 // Register Scintilla as a wide character window
\r
2269 WNDCLASSEXW wndclass;
\r
2270 wndclass.cbSize = sizeof(wndclass);
\r
2271 wndclass.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW;
\r
2272 wndclass.lpfnWndProc = ScintillaWin::SWndProc;
\r
2273 wndclass.cbClsExtra = 0;
\r
2274 wndclass.cbWndExtra = sizeof(ScintillaWin *);
\r
2275 wndclass.hInstance = hInstance;
\r
2276 wndclass.hIcon = NULL;
\r
2277 wndclass.hCursor = NULL;
\r
2278 wndclass.hbrBackground = NULL;
\r
2279 wndclass.lpszMenuName = NULL;
\r
2280 wndclass.lpszClassName = L"Scintilla";
\r
2281 wndclass.hIconSm = 0;
\r
2282 result = ::RegisterClassExW(&wndclass) != 0;
\r
2285 // Register Scintilla as a normal character window
\r
2286 WNDCLASSEX wndclass;
\r
2287 wndclass.cbSize = sizeof(wndclass);
\r
2288 wndclass.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW;
\r
2289 wndclass.lpfnWndProc = ScintillaWin::SWndProc;
\r
2290 wndclass.cbClsExtra = 0;
\r
2291 wndclass.cbWndExtra = sizeof(ScintillaWin *);
\r
2292 wndclass.hInstance = hInstance;
\r
2293 wndclass.hIcon = NULL;
\r
2294 wndclass.hCursor = NULL;
\r
2295 wndclass.hbrBackground = NULL;
\r
2296 wndclass.lpszMenuName = NULL;
\r
2297 wndclass.lpszClassName = scintillaClassName;
\r
2298 wndclass.hIconSm = 0;
\r
2299 result = ::RegisterClassEx(&wndclass) != 0;
\r
2303 // Register the CallTip class
\r
2304 WNDCLASSEX wndclassc;
\r
2305 wndclassc.cbSize = sizeof(wndclassc);
\r
2306 wndclassc.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW;
\r
2307 wndclassc.cbClsExtra = 0;
\r
2308 wndclassc.cbWndExtra = sizeof(ScintillaWin *);
\r
2309 wndclassc.hInstance = hInstance;
\r
2310 wndclassc.hIcon = NULL;
\r
2311 wndclassc.hbrBackground = NULL;
\r
2312 wndclassc.lpszMenuName = NULL;
\r
2313 wndclassc.lpfnWndProc = ScintillaWin::CTWndProc;
\r
2314 wndclassc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
\r
2315 wndclassc.lpszClassName = callClassName;
\r
2316 wndclassc.hIconSm = 0;
\r
2318 result = ::RegisterClassEx(&wndclassc) != 0;
\r
2324 bool ScintillaWin::Unregister() {
\r
2325 bool result = ::UnregisterClass(scintillaClassName, hInstance) != 0;
\r
2326 if (::UnregisterClass(callClassName, hInstance) == 0)
\r
2331 bool ScintillaWin::HasCaretSizeChanged() {
\r
2333 ( (0 != vs.caretWidth) && (sysCaretWidth != vs.caretWidth) )
\r
2334 || (0 != vs.lineHeight) && (sysCaretHeight != vs.lineHeight)
\r
2341 BOOL ScintillaWin::CreateSystemCaret() {
\r
2342 sysCaretWidth = vs.caretWidth;
\r
2343 if (0 == sysCaretWidth) {
\r
2344 sysCaretWidth = 1;
\r
2346 sysCaretHeight = vs.lineHeight;
\r
2347 int bitmapSize = (((sysCaretWidth + 15) & ~15) >> 3) *
\r
2349 char *bits = new char[bitmapSize];
\r
2350 memset(bits, 0, bitmapSize);
\r
2351 sysCaretBitmap = ::CreateBitmap(sysCaretWidth, sysCaretHeight, 1,
\r
2352 1, reinterpret_cast<BYTE *>(bits));
\r
2354 BOOL retval = ::CreateCaret(
\r
2355 MainHWND(), sysCaretBitmap,
\r
2356 sysCaretWidth, sysCaretHeight);
\r
2357 ::ShowCaret(MainHWND());
\r
2361 BOOL ScintillaWin::DestroySystemCaret() {
\r
2362 ::HideCaret(MainHWND());
\r
2363 BOOL retval = ::DestroyCaret();
\r
2364 if (sysCaretBitmap) {
\r
2365 ::DeleteObject(sysCaretBitmap);
\r
2366 sysCaretBitmap = 0;
\r
2371 // Take care of 32/64 bit pointers
\r
2372 #ifdef GetWindowLongPtr
\r
2373 static void *PointerFromWindow(HWND hWnd) {
\r
2374 return reinterpret_cast<void *>(::GetWindowLongPtr(hWnd, 0));
\r
2376 static void SetWindowPointer(HWND hWnd, void *ptr) {
\r
2377 ::SetWindowLongPtr(hWnd, 0, reinterpret_cast<LONG_PTR>(ptr));
\r
2380 static void *PointerFromWindow(HWND hWnd) {
\r
2381 return reinterpret_cast<void *>(::GetWindowLong(hWnd, 0));
\r
2383 static void SetWindowPointer(HWND hWnd, void *ptr) {
\r
2384 ::SetWindowLong(hWnd, 0, reinterpret_cast<LONG>(ptr));
\r
2388 sptr_t PASCAL ScintillaWin::CTWndProc(
\r
2389 HWND hWnd, UINT iMessage, WPARAM wParam, sptr_t lParam) {
\r
2391 // Find C++ object associated with window.
\r
2392 ScintillaWin *sciThis = reinterpret_cast<ScintillaWin *>(PointerFromWindow(hWnd));
\r
2393 // ctp will be zero if WM_CREATE not seen yet
\r
2394 if (sciThis == 0) {
\r
2395 if (iMessage == WM_CREATE) {
\r
2396 // Associate CallTip object with window
\r
2397 CREATESTRUCT *pCreate = reinterpret_cast<CREATESTRUCT *>(lParam);
\r
2398 SetWindowPointer(hWnd, pCreate->lpCreateParams);
\r
2401 return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
\r
2404 if (iMessage == WM_NCDESTROY) {
\r
2405 ::SetWindowLong(hWnd, 0, 0);
\r
2406 return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
\r
2407 } else if (iMessage == WM_PAINT) {
\r
2409 ::BeginPaint(hWnd, &ps);
\r
2410 Surface *surfaceWindow = Surface::Allocate();
\r
2411 if (surfaceWindow) {
\r
2412 surfaceWindow->Init(ps.hdc, hWnd);
\r
2413 surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == sciThis->ct.codePage);
\r
2414 surfaceWindow->SetDBCSMode(sciThis->ct.codePage);
\r
2415 sciThis->ct.PaintCT(surfaceWindow);
\r
2416 surfaceWindow->Release();
\r
2417 delete surfaceWindow;
\r
2419 ::EndPaint(hWnd, &ps);
\r
2421 } else if ((iMessage == WM_NCLBUTTONDOWN) || (iMessage == WM_NCLBUTTONDBLCLK)) {
\r
2423 pt.x = static_cast<short>(LOWORD(lParam));
\r
2424 pt.y = static_cast<short>(HIWORD(lParam));
\r
2425 ScreenToClient(hWnd, &pt);
\r
2426 sciThis->ct.MouseClick(Point(pt.x, pt.y));
\r
2427 sciThis->CallTipClick();
\r
2429 } else if (iMessage == WM_LBUTTONDOWN) {
\r
2430 // This does not fire due to the hit test code
\r
2431 sciThis->ct.MouseClick(Point::FromLong(lParam));
\r
2432 sciThis->CallTipClick();
\r
2434 } else if (iMessage == WM_SETCURSOR) {
\r
2435 ::SetCursor(::LoadCursor(NULL,IDC_ARROW));
\r
2437 } else if (iMessage == WM_NCHITTEST) {
\r
2440 return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
\r
2445 sptr_t ScintillaWin::DirectFunction(
\r
2446 ScintillaWin *sci, UINT iMessage, uptr_t wParam, sptr_t lParam) {
\r
2447 PLATFORM_ASSERT(::GetCurrentThreadId() == ::GetWindowThreadProcessId(sci->MainHWND(), NULL));
\r
2448 return sci->WndProc(iMessage, wParam, lParam);
\r
2452 #ifndef STATIC_BUILD
\r
2453 __declspec(dllexport)
\r
2455 sptr_t __stdcall Scintilla_DirectFunction(
\r
2456 ScintillaWin *sci, UINT iMessage, uptr_t wParam, sptr_t lParam) {
\r
2457 return sci->WndProc(iMessage, wParam, lParam);
\r
2460 sptr_t PASCAL ScintillaWin::SWndProc(
\r
2461 HWND hWnd, UINT iMessage, WPARAM wParam, sptr_t lParam) {
\r
2462 //Platform::DebugPrintf("S W:%x M:%x WP:%x L:%x\n", hWnd, iMessage, wParam, lParam);
\r
2464 // Find C++ object associated with window.
\r
2465 ScintillaWin *sci = reinterpret_cast<ScintillaWin *>(PointerFromWindow(hWnd));
\r
2466 // sci will be zero if WM_CREATE not seen yet
\r
2468 if (iMessage == WM_CREATE) {
\r
2469 // Create C++ object associated with window
\r
2470 sci = new ScintillaWin(hWnd);
\r
2471 SetWindowPointer(hWnd, sci);
\r
2472 return sci->WndProc(iMessage, wParam, lParam);
\r
2474 return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
\r
2477 if (iMessage == WM_NCDESTROY) {
\r
2480 ::SetWindowLong(hWnd, 0, 0);
\r
2481 return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
\r
2483 return sci->WndProc(iMessage, wParam, lParam);
\r
2488 // This function is externally visible so it can be called from container when building statically.
\r
2489 // Must be called once only.
\r
2490 bool Scintilla_RegisterClasses(void *hInstance) {
\r
2491 Platform_Initialise(hInstance);
\r
2492 bool result = ScintillaWin::Register(reinterpret_cast<HINSTANCE>(hInstance));
\r
2494 Scintilla_LinkLexers();
\r
2499 // This function is externally visible so it can be called from container when building statically.
\r
2500 bool Scintilla_ReleaseResources() {
\r
2501 bool result = ScintillaWin::Unregister();
\r
2502 Platform_Finalise();
\r
2506 #ifndef STATIC_BUILD
\r
2507 extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID) {
\r
2508 //Platform::DebugPrintf("Scintilla::DllMain %d %d\n", hInstance, dwReason);
\r
2509 if (dwReason == DLL_PROCESS_ATTACH) {
\r
2510 if (!Scintilla_RegisterClasses(hInstance))
\r
2512 } else if (dwReason == DLL_PROCESS_DETACH) {
\r
2513 Scintilla_ReleaseResources();
\r