OSDN Git Service

Compiler warnings removal Numerous tweaks to remove compiler warnings where solution...
[tortoisegit/TortoiseGitJp.git] / ext / scintilla / win32 / ScintillaWin.cxx
1 // Scintilla source code edit control\r
2 /** @file ScintillaWin.cxx\r
3  ** Windows specific subclass of ScintillaBase.\r
4  **/\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
7 \r
8 #include <stdlib.h>\r
9 #include <string.h>\r
10 #include <stdio.h>\r
11 #include <ctype.h>\r
12 #include <assert.h>\r
13 #include <limits.h>\r
14 \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
20 \r
21 #include "Platform.h"\r
22 \r
23 #include "Scintilla.h"\r
24 #include "SString.h"\r
25 #ifdef SCI_LEXER\r
26 #include "SciLexer.h"\r
27 #include "PropSet.h"\r
28 #include "Accessor.h"\r
29 #include "KeyWords.h"\r
30 #endif\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
37 #include "KeyMap.h"\r
38 #include "Indicator.h"\r
39 #include "XPM.h"\r
40 #include "LineMarker.h"\r
41 #include "Style.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
48 #include "Editor.h"\r
49 #include "ScintillaBase.h"\r
50 #include "UniConversion.h"\r
51 \r
52 #ifdef SCI_LEXER\r
53 #include "ExternalLexer.h"\r
54 #endif\r
55 \r
56 #ifndef SPI_GETWHEELSCROLLLINES\r
57 #define SPI_GETWHEELSCROLLLINES   104\r
58 #endif\r
59 \r
60 #ifndef WM_UNICHAR\r
61 #define WM_UNICHAR                      0x0109\r
62 #endif\r
63 \r
64 #ifndef UNICODE_NOCHAR\r
65 #define UNICODE_NOCHAR                  0xFFFF\r
66 #endif\r
67 \r
68 #ifndef WM_IME_STARTCOMPOSITION\r
69 #include <imm.h>\r
70 #endif\r
71 \r
72 #include <commctrl.h>\r
73 #ifndef __BORLANDC__\r
74 #ifndef __DMC__\r
75 #include <zmouse.h>\r
76 #endif\r
77 #endif\r
78 #include <ole2.h>\r
79 \r
80 #ifndef MK_ALT\r
81 #define MK_ALT 32\r
82 #endif\r
83 \r
84 #define SC_WIN_IDLE 5001\r
85 \r
86 // Functions imported from PlatWin\r
87 extern bool IsNT();\r
88 extern void Platform_Initialise(void *hInstance);\r
89 extern void Platform_Finalise();\r
90 \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
94  */\r
95 #define TOTAL_CONTROL\r
96 \r
97 // GCC has trouble with the standard COM ABI so do it the old C way with explicit vtables.\r
98 \r
99 const TCHAR scintillaClassName[] = TEXT("Scintilla");\r
100 const TCHAR callClassName[] = TEXT("CallTip");\r
101 \r
102 #ifdef SCI_NAMESPACE\r
103 using namespace Scintilla;\r
104 #endif\r
105 \r
106 class ScintillaWin;     // Forward declaration for COM interface subobjects\r
107 \r
108 /**\r
109  */\r
110 class FormatEnumerator {\r
111 public:\r
112         void **vtbl;\r
113         int ref;\r
114         int pos;\r
115         CLIPFORMAT formats[2];\r
116         int formatsLen;\r
117         FormatEnumerator(int pos_, CLIPFORMAT formats_[], int formatsLen_);\r
118 };\r
119 \r
120 /**\r
121  */\r
122 class DropSource {\r
123 public:\r
124         void **vtbl;\r
125         ScintillaWin *sci;\r
126         DropSource();\r
127 };\r
128 \r
129 /**\r
130  */\r
131 class DataObject {\r
132 public:\r
133         void **vtbl;\r
134         ScintillaWin *sci;\r
135         DataObject();\r
136 };\r
137 \r
138 /**\r
139  */\r
140 class DropTarget {\r
141 public:\r
142         void **vtbl;\r
143         ScintillaWin *sci;\r
144         DropTarget();\r
145 };\r
146 \r
147 /**\r
148  */\r
149 class ScintillaWin :\r
150         public ScintillaBase {\r
151 \r
152         bool lastKeyDownConsumed;\r
153 \r
154         bool capturedMouse;\r
155 \r
156         unsigned int linesPerScroll;    ///< Intellimouse support\r
157         int wheelDelta; ///< Wheel delta from roll\r
158 \r
159         HRGN hRgnUpdate;\r
160 \r
161         bool hasOKText;\r
162 \r
163         CLIPFORMAT cfColumnSelect;\r
164         CLIPFORMAT cfLineSelect;\r
165 \r
166         HRESULT hrOle;\r
167         DropSource ds;\r
168         DataObject dob;\r
169         DropTarget dt;\r
170 \r
171         static HINSTANCE hInstance;\r
172 \r
173         ScintillaWin(HWND hwnd);\r
174         ScintillaWin(const ScintillaWin &) : ScintillaBase() {}\r
175         virtual ~ScintillaWin();\r
176         ScintillaWin &operator=(const ScintillaWin &) { return *this; }\r
177 \r
178         virtual void Initialise();\r
179         virtual void Finalise();\r
180         HWND MainHWND();\r
181 \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
188 \r
189         enum { invalidTimerID, standardTimerID, idleTimerID };\r
190 \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
220 \r
221         // DBCS\r
222         void ImeStartComposition();\r
223         void ImeEndComposition();\r
224 \r
225         void AddCharBytes(char b0, char b1);\r
226 \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
232         void FullPaint();\r
233         void FullPaintDC(HDC dc);\r
234         bool IsCompatibleDC(HDC dc);\r
235         DWORD EffectFromState(DWORD grfKeyState);\r
236 \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
240 \r
241         void InsertPasteText(const char *text, int len, int selStart, bool isRectangular, bool isLine);\r
242 \r
243 public:\r
244         // Public for benefit of Scintilla_DirectFunction\r
245         virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);\r
246 \r
247         /// Implement IUnknown\r
248         STDMETHODIMP QueryInterface(REFIID riid, PVOID *ppv);\r
249         STDMETHODIMP_(ULONG)AddRef();\r
250         STDMETHODIMP_(ULONG)Release();\r
251 \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
259 \r
260         /// Implement important part of IDataObject\r
261         STDMETHODIMP GetData(FORMATETC *pFEIn, STGMEDIUM *pSTM);\r
262 \r
263         // External Lexers\r
264 #ifdef SCI_LEXER\r
265         void SetLexerLanguage(const char *languageName);\r
266         void SetLexer(uptr_t wParam);\r
267 #endif\r
268 \r
269         static bool Register(HINSTANCE hInstance_);\r
270         static bool Unregister();\r
271 \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
277         }\r
278 \r
279 private:\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
285         int sysCaretWidth;\r
286         int sysCaretHeight;\r
287         bool keysAlwaysUnicode;\r
288 };\r
289 \r
290 HINSTANCE ScintillaWin::hInstance = 0;\r
291 \r
292 ScintillaWin::ScintillaWin(HWND hwnd) {\r
293 \r
294         lastKeyDownConsumed = false;\r
295 \r
296         capturedMouse = false;\r
297         linesPerScroll = 0;\r
298         wheelDelta = 0;   // Wheel delta from roll\r
299 \r
300         hRgnUpdate = 0;\r
301 \r
302         hasOKText = false;\r
303 \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
308 \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
312 \r
313         hrOle = E_FAIL;\r
314 \r
315         wMain = hwnd;\r
316 \r
317         dob.sci = this;\r
318         ds.sci = this;\r
319         dt.sci = this;\r
320 \r
321         sysCaretBitmap = 0;\r
322         sysCaretWidth = 0;\r
323         sysCaretHeight = 0;\r
324 \r
325         keysAlwaysUnicode = false;\r
326 \r
327         Initialise();\r
328 }\r
329 \r
330 ScintillaWin::~ScintillaWin() {}\r
331 \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
337 }\r
338 \r
339 void ScintillaWin::Finalise() {\r
340         ScintillaBase::Finalise();\r
341         SetTicking(false);\r
342         SetIdle(false);\r
343         DestroySystemCaret();\r
344         ::RevokeDragDrop(MainHWND());\r
345         if (SUCCEEDED(hrOle)) {\r
346                 ::OleUninitialize();\r
347         }\r
348 }\r
349 \r
350 HWND ScintillaWin::MainHWND() {\r
351         return reinterpret_cast<HWND>(wMain.GetID());\r
352 }\r
353 \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
359 }\r
360 \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
369                          pDataObject,\r
370                          pDropSource,\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
376                         ClearSelection();\r
377                 }\r
378         }\r
379         inDragDrop = ddNone;\r
380         SetDragPosition(invalidPosition);\r
381 }\r
382 \r
383 // Avoid warnings everywhere for old style casts by concentrating them here\r
384 static WORD LoWord(DWORD l) {\r
385         return LOWORD(l);\r
386 }\r
387 \r
388 static WORD HiWord(DWORD l) {\r
389         return HIWORD(l);\r
390 }\r
391 \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
398         if (!res)\r
399                 return 0;\r
400         return atoi(sCodePage);\r
401 }\r
402 \r
403 #ifndef VK_OEM_2\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
409 #endif\r
410 \r
411 /** Map the key codes to their equivalent SCK_ form. */\r
412 static int KeyTranslate(int keyIn) {\r
413 //PLATFORM_ASSERT(!keyIn);\r
414         switch (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
441         }\r
442 }\r
443 \r
444 LRESULT ScintillaWin::WndPaint(uptr_t wParam) {\r
445         //ElapsedTime et;\r
446 \r
447         // Redirect assertions to debug output and save current state\r
448         bool assertsPopup = Platform::ShowAssertionPopUps(false);\r
449         paintState = painting;\r
450         PAINTSTRUCT ps;\r
451         PAINTSTRUCT *pps;\r
452 \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
458         if (IsOcxCtrl) {\r
459                 pps = reinterpret_cast<PAINTSTRUCT*>(wParam);\r
460         } else {\r
461                 ::GetUpdateRgn(MainHWND(), hRgnUpdate, FALSE);\r
462                 pps = &ps;\r
463                 ::BeginPaint(MainHWND(), pps);\r
464         }\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
472                 } else {\r
473                         //Platform::DebugPrintf("Performing partial paint %d .. %d\n", rcPaint.top, rcPaint.bottom);\r
474                 }\r
475                 Paint(surfaceWindow, rcPaint);\r
476                 surfaceWindow->Release();\r
477         }\r
478         if (hRgnUpdate) {\r
479                 ::DeleteRgn(hRgnUpdate);\r
480                 hRgnUpdate = 0;\r
481         }\r
482 \r
483         if(!IsOcxCtrl)\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
487                 FullPaint();\r
488         }\r
489         paintState = notPainting;\r
490 \r
491         // Restore debug output state\r
492         Platform::ShowAssertionPopUps(assertsPopup);\r
493 \r
494         //Platform::DebugPrintf("Paint took %g\n", et.Duration());\r
495         return 0l;\r
496 }\r
497 \r
498 sptr_t ScintillaWin::HandleComposition(uptr_t wParam, sptr_t lParam) {\r
499 #ifdef __DMC__\r
500         // Digital Mars compiler does not include Imm library\r
501         return 0;\r
502 #else\r
503         if (lParam & GCS_RESULTSTR) {\r
504                 HIMC hIMC = ::ImmGetContext(MainHWND());\r
505                 if (hIMC) {\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
517                         } else {\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
523                                 }\r
524                         }\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
533                 }\r
534                 return 0;\r
535         }\r
536         return ::DefWindowProc(MainHWND(), WM_IME_COMPOSITION, wParam, lParam);\r
537 #endif\r
538 }\r
539 \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
566         }\r
567         return iMessage;\r
568 }\r
569 \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
574 \r
575         UINT cp;\r
576         if (bci)\r
577                 cp = ci.ciACP;\r
578         else\r
579                 cp = documentCodePage;\r
580 \r
581         CPINFO cpi;\r
582         if (!IsValidCodePage(cp) && !GetCPInfo(cp, &cpi))\r
583                 cp = CP_ACP;\r
584 \r
585         return cp;\r
586 }\r
587 \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
592 \r
593         case WM_CREATE:\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
598                 break;\r
599 \r
600         case WM_COMMAND:\r
601 #ifdef TOTAL_CONTROL\r
602                 Command(LoWord(wParam));\r
603 #endif\r
604                 break;\r
605 \r
606         case WM_PAINT:\r
607                 return WndPaint(wParam);\r
608 \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
613                         }\r
614                         FullPaintDC(hdc);\r
615                 }\r
616                 break;\r
617 \r
618         case WM_VSCROLL:\r
619                 ScrollMessage(wParam);\r
620                 break;\r
621 \r
622         case WM_HSCROLL:\r
623                 HorizontalScrollMessage(wParam);\r
624                 break;\r
625 \r
626         case WM_SIZE: {\r
627                         //Platform::DebugPrintf("Scintilla WM_SIZE %d %d\n", LoWord(lParam), HiWord(lParam));\r
628                         ChangeSize();\r
629                 }\r
630                 break;\r
631 \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
639                 }\r
640 \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
648                                 linesToScroll = 1;\r
649                         }\r
650                         linesToScroll *= (wheelDelta / WHEEL_DELTA);\r
651                         if (wheelDelta >= 0)\r
652                                 wheelDelta = wheelDelta % WHEEL_DELTA;\r
653                         else\r
654                                 wheelDelta = - (-wheelDelta % WHEEL_DELTA);\r
655 \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
661                                 } else {\r
662                                         KeyCommand(SCI_ZOOMOUT);\r
663                                 }\r
664                         } else {\r
665                                 // Scroll\r
666                                 ScrollTo(topLine + linesToScroll);\r
667                         }\r
668                 }\r
669                 return 0;\r
670 \r
671         case WM_TIMER:\r
672                 if (wParam == standardTimerID && timer.ticking) {\r
673                         Tick();\r
674                 } else if (wParam == idleTimerID && idler.state) {\r
675                         SendMessage(MainHWND(), SC_WIN_IDLE, 0, 1);\r
676                 } else {\r
677                         return 1;\r
678                 }\r
679                 break;\r
680 \r
681         case SC_WIN_IDLE:\r
682                 // wParam=dwTickCountInitial, or 0 to initialize.  lParam=bSkipUserInputTest\r
683                 if (idler.state) {\r
684                         if (lParam || (WAIT_TIMEOUT==MsgWaitForMultipleObjects(0,0,0,0, QS_INPUT|QS_HOTKEY))) {\r
685                                 if (Idle()) {\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
688 \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
692 \r
693                                         DWORD dwCurrent = GetTickCount();\r
694                                         DWORD dwStart = wParam ? wParam : dwCurrent;\r
695 \r
696                                         if (dwCurrent >= dwStart && dwCurrent > 200 && dwCurrent - 200 < dwStart)\r
697                                                 PostMessage(MainHWND(), SC_WIN_IDLE, dwStart, 0);\r
698                                 } else {\r
699                                         SetIdle(false);\r
700                                 }\r
701                         }\r
702                 }\r
703                 break;\r
704 \r
705         case WM_GETMINMAXINFO:\r
706                 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);\r
707 \r
708         case WM_LBUTTONDOWN: {\r
709 #ifndef __DMC__\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
715 #endif\r
716                 //\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
726                 }\r
727                 break;\r
728 \r
729         case WM_MOUSEMOVE:\r
730                 ButtonMove(Point::FromLong(lParam));\r
731                 break;\r
732 \r
733         case WM_LBUTTONUP:\r
734                 ButtonUp(Point::FromLong(lParam),\r
735                         ::GetMessageTime(),\r
736                         (wParam & MK_CONTROL) != 0);\r
737                 break;\r
738 \r
739         case WM_RBUTTONDOWN:\r
740                 if (!PointInSelection(Point::FromLong(lParam)))\r
741                         SetEmptySelection(PositionFromLocation(Point::FromLong(lParam)));\r
742                 break;\r
743 \r
744         case WM_SETCURSOR:\r
745                 if (LoWord(lParam) == HTCLIENT) {\r
746                         if (inDragDrop == ddDragging) {\r
747                                 DisplayCursor(Window::cursorUp);\r
748                         } else {\r
749                                 // Display regular (drag) cursor over selection\r
750                                 POINT pt;\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
759                                 } else {\r
760                                         DisplayCursor(Window::cursorText);\r
761                                 }\r
762                         }\r
763                         return TRUE;\r
764                 } else {\r
765                         return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);\r
766                 }\r
767 \r
768         case WM_CHAR:\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
774                                         char utfval[4];\r
775                                         unsigned int len = UTF8Length(wcs, 1);\r
776                                         UTF8FromUTF16(wcs, 1, utfval, len);\r
777                                         AddCharUTF(utfval, len);\r
778                                 } else {\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
785                                 }\r
786                         } else {\r
787                                 if (IsUnicodeMode()) {\r
788                                         AddCharBytes('\0', LOBYTE(wParam));\r
789                                 } else {\r
790                                         AddChar(LOBYTE(wParam));\r
791                                 }\r
792                         }\r
793                 }\r
794                 return 0;\r
795 \r
796         case WM_UNICHAR:\r
797                 if (wParam == UNICODE_NOCHAR) {\r
798                         return IsUnicodeMode() ? 1 : 0;\r
799                 } else if (lastKeyDownConsumed) {\r
800                         return 1;\r
801                 } else {\r
802                         if (IsUnicodeMode()) {\r
803                                 char utfval[4];\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
808                                 return 1;\r
809                         } else {\r
810                                 return 0;\r
811                         }\r
812                 }\r
813 \r
814         case WM_SYSKEYDOWN:\r
815         case WM_KEYDOWN: {\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
825                         }\r
826                         break;\r
827                 }\r
828 \r
829         case WM_IME_KEYDOWN:\r
830                 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);\r
831 \r
832         case WM_KEYUP:\r
833                 //Platform::DebugPrintf("S keyup %d %x %x\n",iMessage, wParam, lParam);\r
834                 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);\r
835 \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
841                 break;\r
842 \r
843         case WM_GETDLGCODE:\r
844                 return DLGC_HASSETSEL | DLGC_WANTALLKEYS;\r
845 \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
850                         if (!wParam ||\r
851                                 !(::IsChild(wThis,wOther) || (wOther == wCT))) {\r
852                                 SetFocusState(false);\r
853                                 DestroySystemCaret();\r
854                         }\r
855                 }\r
856                 //RealizeWindowPalette(true);\r
857                 break;\r
858 \r
859         case WM_SETFOCUS:\r
860                 SetFocusState(true);\r
861                 RealizeWindowPalette(false);\r
862                 DestroySystemCaret();\r
863                 CreateSystemCaret();\r
864                 break;\r
865 \r
866         case WM_SYSCOLORCHANGE:\r
867                 //Platform::DebugPrintf("Setting Changed\n");\r
868                 InvalidateStyleData();\r
869                 break;\r
870 \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
875                 }\r
876                 break;\r
877 \r
878         case WM_QUERYNEWPALETTE:\r
879                 //Platform::DebugPrintf("** Query palette\n");\r
880                 RealizeWindowPalette(false);\r
881                 break;\r
882 \r
883         case WM_IME_STARTCOMPOSITION:   // dbcs\r
884                 ImeStartComposition();\r
885                 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);\r
886 \r
887         case WM_IME_ENDCOMPOSITION:     // dbcs\r
888                 ImeEndComposition();\r
889                 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);\r
890 \r
891         case WM_IME_COMPOSITION:\r
892                 return HandleComposition(wParam, lParam);\r
893 \r
894         case WM_IME_CHAR: {\r
895                         AddCharBytes(HIBYTE(wParam), LOBYTE(wParam));\r
896                         return 0;\r
897                 }\r
898 \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
909                         }\r
910                         ContextMenu(pt);\r
911                         return 0;\r
912                 }\r
913 #endif\r
914                 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);\r
915 \r
916         case WM_INPUTLANGCHANGE:\r
917                 //::SetThreadLocale(LOWORD(lParam));\r
918                 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);\r
919 \r
920         case WM_INPUTLANGCHANGEREQUEST:\r
921                 return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);\r
922 \r
923         case WM_ERASEBKGND:\r
924                 return 1;   // Avoid any background erasure as whole window painted.\r
925 \r
926         case WM_CAPTURECHANGED:\r
927                 capturedMouse = false;\r
928                 return 0;\r
929 \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
932 \r
933         case WM_MOVE:\r
934         case WM_MOUSEACTIVATE:\r
935         case WM_NCHITTEST:\r
936         case WM_NCCALCSIZE:\r
937         case WM_NCPAINT:\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
946 \r
947         case EM_LINEFROMCHAR:\r
948                 if (static_cast<int>(wParam) < 0) {\r
949                         wParam = SelectionStart();\r
950                 }\r
951                 return pdoc->LineFromPosition(wParam);\r
952 \r
953         case EM_EXLINEFROMCHAR:\r
954                 return pdoc->LineFromPosition(lParam);\r
955 \r
956         case EM_GETSEL:\r
957                 if (wParam) {\r
958                         *reinterpret_cast<int *>(wParam) = SelectionStart();\r
959                 }\r
960                 if (lParam) {\r
961                         *reinterpret_cast<int *>(lParam) = SelectionEnd();\r
962                 }\r
963                 return MAKELONG(SelectionStart(), SelectionEnd());\r
964 \r
965         case EM_EXGETSEL: {\r
966                         if (lParam == 0) {\r
967                                 return 0;\r
968                         }\r
969                         CharacterRange *pCR = reinterpret_cast<CharacterRange *>(lParam);\r
970                         pCR->cpMin = SelectionStart();\r
971                         pCR->cpMax = SelectionEnd();\r
972                 }\r
973                 break;\r
974 \r
975         case EM_SETSEL: {\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
980                         }\r
981                         if (nStart == -1) {\r
982                                 nStart = nEnd;  // Remove selection\r
983                         }\r
984                         if (nStart > nEnd) {\r
985                                 SetSelection(nEnd, nStart);\r
986                         } else {\r
987                                 SetSelection(nStart, nEnd);\r
988                         }\r
989                         EnsureCaretVisible();\r
990                 }\r
991                 break;\r
992 \r
993         case EM_EXSETSEL: {\r
994                         if (lParam == 0) {\r
995                                 return 0;\r
996                         }\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
1001                         } else {\r
1002                                 SetSelection(pCR->cpMin, pCR->cpMax);\r
1003                         }\r
1004                         EnsureCaretVisible();\r
1005                         return pdoc->LineFromPosition(SelectionStart());\r
1006                 }\r
1007 \r
1008         case SCI_GETDIRECTFUNCTION:\r
1009                 return reinterpret_cast<sptr_t>(DirectFunction);\r
1010 \r
1011         case SCI_GETDIRECTPOINTER:\r
1012                 return reinterpret_cast<sptr_t>(this);\r
1013 \r
1014         case SCI_GRABFOCUS:\r
1015                 ::SetFocus(MainHWND());\r
1016                 break;\r
1017 \r
1018         case SCI_SETKEYSUNICODE:\r
1019                 keysAlwaysUnicode = wParam != 0;\r
1020                 break;\r
1021 \r
1022         case SCI_GETKEYSUNICODE:\r
1023                 return keysAlwaysUnicode;\r
1024 \r
1025 #ifdef SCI_LEXER\r
1026         case SCI_LOADLEXERLIBRARY:\r
1027                 LexerManager::GetInstance()->Load(reinterpret_cast<const char*>(lParam));\r
1028                 break;\r
1029 #endif\r
1030 \r
1031         default:\r
1032                 return ScintillaBase::WndProc(iMessage, wParam, lParam);\r
1033         }\r
1034         return 0l;\r
1035 }\r
1036 \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
1041 }\r
1042 \r
1043 sptr_t ScintillaWin::DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {\r
1044         return ::DefWindowProc(MainHWND(), iMessage, wParam, lParam);\r
1045 }\r
1046 \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
1053                 } else {\r
1054                         ::KillTimer(MainHWND(), reinterpret_cast<uptr_t>(timer.tickerID));\r
1055                         timer.tickerID = 0;\r
1056                 }\r
1057         }\r
1058         timer.ticksToWait = caret.period;\r
1059 }\r
1060 \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
1066                 if (on) {\r
1067                         idler.idlerID = ::SetTimer(MainHWND(), idleTimerID, 10, NULL)\r
1068                                 ? reinterpret_cast<IdlerID>(idleTimerID) : 0;\r
1069                 } else {\r
1070                         ::KillTimer(MainHWND(), reinterpret_cast<uptr_t>(idler.idlerID));\r
1071                         idler.idlerID = 0;\r
1072                 }\r
1073                 idler.state = idler.idlerID != 0;\r
1074         }\r
1075         return idler.state;\r
1076 }\r
1077 \r
1078 void ScintillaWin::SetMouseCapture(bool on) {\r
1079         if (mouseDownCaptures) {\r
1080                 if (on) {\r
1081                         ::SetCapture(MainHWND());\r
1082                 } else {\r
1083                         ::ReleaseCapture();\r
1084                 }\r
1085         }\r
1086         capturedMouse = on;\r
1087 }\r
1088 \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
1093 }\r
1094 \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
1099                         contains = false;\r
1100                 } else {\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
1103                         if (hRgnRange) {\r
1104                                 HRGN hRgnDest = ::CreateRectRgn(0, 0, 0, 0);\r
1105                                 if (hRgnDest) {\r
1106                                         int combination = ::CombineRgn(hRgnDest, hRgnRange, hRgnUpdate, RGN_DIFF);\r
1107                                         if (combination != NULLREGION) {\r
1108                                                 contains = false;\r
1109                                         }\r
1110                                         ::DeleteRgn(hRgnDest);\r
1111                                 }\r
1112                                 ::DeleteRgn(hRgnRange);\r
1113                         }\r
1114                 }\r
1115         }\r
1116         return contains;\r
1117 }\r
1118 \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
1124 }\r
1125 \r
1126 void ScintillaWin::UpdateSystemCaret() {\r
1127         if (hasFocus) {\r
1128                 if (HasCaretSizeChanged()) {\r
1129                         DestroySystemCaret();\r
1130                         CreateSystemCaret();\r
1131                 }\r
1132                 Point pos = LocationFromPosition(currentPos);\r
1133                 ::SetCaretPos(pos.x, pos.y);\r
1134         }\r
1135 }\r
1136 \r
1137 int ScintillaWin::SetScrollInfo(int nBar, LPCSCROLLINFO lpsi, BOOL bRedraw) {\r
1138         return ::SetScrollInfo(MainHWND(), nBar, lpsi, bRedraw);\r
1139 }\r
1140 \r
1141 bool ScintillaWin::GetScrollInfo(int nBar, LPSCROLLINFO lpsi) {\r
1142         return ::GetScrollInfo(MainHWND(), nBar, lpsi) ? true : false;\r
1143 }\r
1144 \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
1149         };\r
1150         sci.fMask = SIF_POS;\r
1151         GetScrollInfo(barType, &sci);\r
1152         if (sci.nPos != pos) {\r
1153                 DwellEnd(true);\r
1154                 sci.nPos = pos;\r
1155                 SetScrollInfo(barType, &sci, TRUE);\r
1156         }\r
1157 }\r
1158 \r
1159 void ScintillaWin::SetVerticalScrollPos() {\r
1160         ChangeScrollPos(SB_VERT, topLine);\r
1161 }\r
1162 \r
1163 void ScintillaWin::SetHorizontalScrollPos() {\r
1164         ChangeScrollPos(SB_HORZ, xOffset);\r
1165 }\r
1166 \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
1171         };\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
1184                 sci.nMin = 0;\r
1185                 sci.nMax = vertEndPreferred;\r
1186                 sci.nPage = nPage;\r
1187                 sci.nPos = 0;\r
1188                 sci.nTrackPos = 1;\r
1189                 SetScrollInfo(SB_VERT, &sci, TRUE);\r
1190                 modified = true;\r
1191         }\r
1192 \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
1207                 sci.nMin = 0;\r
1208                 sci.nMax = horizEndPreferred;\r
1209                 sci.nPage = pageWidth;\r
1210                 sci.nPos = 0;\r
1211                 sci.nTrackPos = 1;\r
1212                 SetScrollInfo(SB_HORZ, &sci, TRUE);\r
1213                 modified = true;\r
1214                 if (scrollWidth < static_cast<int>(pageWidth)) {\r
1215                         HorizontalScrollTo(0);\r
1216                 }\r
1217         }\r
1218         return modified;\r
1219 }\r
1220 \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
1225 }\r
1226 \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
1231 }\r
1232 \r
1233 int ScintillaWin::GetCtrlID() {\r
1234         return ::GetDlgCtrlID(reinterpret_cast<HWND>(wMain.GetID()));\r
1235 }\r
1236 \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
1242 }\r
1243 \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
1249 }\r
1250 \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
1256                           WM_LBUTTONDBLCLK,\r
1257                           shift ? MK_SHIFT : 0,\r
1258                           MAKELPARAM(pt.x, pt.y));\r
1259 }\r
1260 \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
1267         }\r
1268 }\r
1269 \r
1270 void ScintillaWin::CopyAllowLine() {\r
1271         SelectionText selectedText;\r
1272         CopySelectionRange(&selectedText, true);\r
1273         CopyToClipboard(selectedText);\r
1274 }\r
1275 \r
1276 bool ScintillaWin::CanPaste() {\r
1277         if (!Editor::CanPaste())\r
1278                 return false;\r
1279         if (::IsClipboardFormatAvailable(CF_TEXT))\r
1280                 return true;\r
1281         if (IsUnicodeMode())\r
1282                 return ::IsClipboardFormatAvailable(CF_UNICODETEXT) != 0;\r
1283         return false;\r
1284 }\r
1285 \r
1286 class GlobalMemory {\r
1287         HGLOBAL hand;\r
1288 public:\r
1289         void *ptr;\r
1290         GlobalMemory() : hand(0), ptr(0) {\r
1291         }\r
1292         GlobalMemory(HGLOBAL hand_) : hand(hand_), ptr(0) {\r
1293                 if (hand) {\r
1294                         ptr = ::GlobalLock(hand);\r
1295                 }\r
1296         }\r
1297         ~GlobalMemory() {\r
1298                 PLATFORM_ASSERT(!ptr);\r
1299         }\r
1300         void Allocate(size_t bytes) {\r
1301                 hand = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, bytes);\r
1302                 if (hand) {\r
1303                         ptr = ::GlobalLock(hand);\r
1304                 }\r
1305         }\r
1306         HGLOBAL Unlock() {\r
1307                 PLATFORM_ASSERT(ptr);\r
1308                 HGLOBAL handCopy = hand;\r
1309                 ::GlobalUnlock(hand);\r
1310                 ptr = 0;\r
1311                 hand = 0;\r
1312                 return handCopy;\r
1313         }\r
1314         void SetClip(UINT uFormat) {\r
1315                 ::SetClipboardData(uFormat, Unlock());\r
1316         }\r
1317         operator bool() {\r
1318                 return ptr != 0;\r
1319         }\r
1320         SIZE_T Size() {\r
1321                 return ::GlobalSize(hand);\r
1322         }\r
1323 };\r
1324 \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
1328         } else {\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
1334                 }\r
1335                 if (isLine) {\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
1343                         }\r
1344                         if (currentPos == insertPos) {\r
1345                                 SetEmptySelection(currentPos + len);\r
1346                         }\r
1347                 } else if (pdoc->InsertString(currentPos, text, len)) {\r
1348                         SetEmptySelection(currentPos + len);\r
1349                 }\r
1350                 delete []convertedText;\r
1351         }\r
1352 }\r
1353 \r
1354 void ScintillaWin::Paste() {\r
1355         if (!::OpenClipboard(MainHWND()))\r
1356                 return;\r
1357         pdoc->BeginUndoAction();\r
1358         bool isLine = SelectionEmpty() && (::IsClipboardFormatAvailable(cfLineSelect) != 0);\r
1359         ClearSelection();\r
1360         int selStart = SelectionStart();\r
1361         bool isRectangular = ::IsClipboardFormatAvailable(cfColumnSelect) != 0;\r
1362 \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
1367                 if (uptr) {\r
1368                         unsigned int len;\r
1369                         char *putf;\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
1375                                 if (putf) {\r
1376                                         UTF8FromUTF16(uptr, bytes / 2, putf, len);\r
1377                                 }\r
1378                         } else {\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
1386                                 if (putf) {\r
1387                                         ::WideCharToMultiByte(cpDest, 0, uptr, -1,\r
1388                                                               putf, len + 1, NULL, NULL);\r
1389                                 }\r
1390                         }\r
1391 \r
1392                         if (putf) {\r
1393                                 InsertPasteText(putf, len, selStart, isRectangular, isLine);\r
1394                                 delete []putf;\r
1395                         }\r
1396                 }\r
1397                 memUSelection.Unlock();\r
1398         } else {\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
1403                         if (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
1408                                                 len = i;\r
1409                                 }\r
1410 \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
1414 \r
1415                                         unsigned int ulen = ::MultiByteToWideChar(CP_ACP, 0,\r
1416                                                             ptr, len, uptr, len+1);\r
1417 \r
1418                                         unsigned int mlen = UTF8Length(uptr, ulen);\r
1419                                         char *putf = new char[mlen + 1];\r
1420                                         if (putf) {\r
1421                                                 // CP_UTF8 not available on Windows 95, so use UTF8FromUTF16()\r
1422                                                 UTF8FromUTF16(uptr, ulen, putf, mlen);\r
1423                                         }\r
1424 \r
1425                                         delete []uptr;\r
1426 \r
1427                                         if (putf) {\r
1428                                                 InsertPasteText(putf, mlen, selStart, isRectangular, isLine);\r
1429                                                 delete []putf;\r
1430                                         }\r
1431                                 } else {\r
1432                                         InsertPasteText(ptr, len, selStart, isRectangular, isLine);\r
1433                                 }\r
1434                         }\r
1435                         memSelection.Unlock();\r
1436                 }\r
1437         }\r
1438         ::CloseClipboard();\r
1439         pdoc->EndUndoAction();\r
1440         NotifyChange();\r
1441         Redraw();\r
1442 }\r
1443 \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
1449                                              MainHWND(), 0,\r
1450                                              GetWindowInstance(MainHWND()),\r
1451                                              this);\r
1452                 ct.wDraw = ct.wCallTip;\r
1453         }\r
1454 #endif\r
1455 }\r
1456 \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
1460         if (!label[0])\r
1461                 ::AppendMenuA(hmenuPopup, MF_SEPARATOR, 0, "");\r
1462         else if (enabled)\r
1463                 ::AppendMenuA(hmenuPopup, MF_STRING, cmd, label);\r
1464         else\r
1465                 ::AppendMenuA(hmenuPopup, MF_STRING | MF_DISABLED | MF_GRAYED, cmd, label);\r
1466 #endif\r
1467 }\r
1468 \r
1469 void ScintillaWin::ClaimSelection() {\r
1470         // Windows does not have a primary selection\r
1471 }\r
1472 \r
1473 #ifdef SCI_LEXER\r
1474 \r
1475 /*\r
1476 \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
1480   relevant DLLs...\r
1481 \r
1482 */\r
1483 \r
1484 void ScintillaWin::SetLexer(uptr_t wParam) {\r
1485         lexLanguage = wParam;\r
1486         lexCurrent = LexerModule::Find(lexLanguage);\r
1487         if (!lexCurrent)\r
1488                 lexCurrent = LexerModule::Find(SCLEX_NULL);\r
1489 }\r
1490 \r
1491 void ScintillaWin::SetLexerLanguage(const char *languageName) {\r
1492         lexLanguage = SCLEX_CONTAINER;\r
1493         lexCurrent = LexerModule::Find(languageName);\r
1494         if (!lexCurrent)\r
1495                 lexCurrent = LexerModule::Find(SCLEX_NULL);\r
1496         if (lexCurrent)\r
1497                 lexLanguage = lexCurrent->GetLanguage();\r
1498 }\r
1499 \r
1500 #endif\r
1501 \r
1502 /// Implement IUnknown\r
1503 \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
1507         *ppv = NULL;\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
1512         if (!*ppv)\r
1513                 return E_NOINTERFACE;\r
1514         FormatEnumerator_AddRef(fe);\r
1515         return S_OK;\r
1516 }\r
1517 STDMETHODIMP_(ULONG)FormatEnumerator_AddRef(FormatEnumerator *fe) {\r
1518         return ++fe->ref;\r
1519 }\r
1520 STDMETHODIMP_(ULONG)FormatEnumerator_Release(FormatEnumerator *fe) {\r
1521         fe->ref--;\r
1522         if (fe->ref > 0)\r
1523                 return fe->ref;\r
1524         delete fe;\r
1525         return 0;\r
1526 }\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
1535                 rgelt->ptd = 0;\r
1536                 rgelt->dwAspect = DVASPECT_CONTENT;\r
1537                 rgelt->lindex = -1;\r
1538                 rgelt->tymed = TYMED_HGLOBAL;\r
1539                 fe->pos++;\r
1540                 putPos++;\r
1541         }\r
1542         if (pceltFetched)\r
1543                 *pceltFetched = putPos;\r
1544         return putPos ? S_OK : S_FALSE;\r
1545 }\r
1546 STDMETHODIMP FormatEnumerator_Skip(FormatEnumerator *fe, ULONG celt) {\r
1547         fe->pos += celt;\r
1548         return S_OK;\r
1549 }\r
1550 STDMETHODIMP FormatEnumerator_Reset(FormatEnumerator *fe) {\r
1551         fe->pos = 0;\r
1552         return S_OK;\r
1553 }\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
1558 }\r
1559 \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
1568 };\r
1569 \r
1570 FormatEnumerator::FormatEnumerator(int pos_, CLIPFORMAT formats_[], int formatsLen_) {\r
1571         vtbl = vtFormatEnumerator;\r
1572         ref = 0;   // First QI adds first reference...\r
1573         pos = pos_;\r
1574         formatsLen = formatsLen_;\r
1575         for (int i=0;i<formatsLen;i++)\r
1576                 formats[i] = formats_[i];\r
1577 }\r
1578 \r
1579 /// Implement IUnknown\r
1580 STDMETHODIMP DropSource_QueryInterface(DropSource *ds, REFIID riid, PVOID *ppv) {\r
1581         return ds->sci->QueryInterface(riid, ppv);\r
1582 }\r
1583 STDMETHODIMP_(ULONG)DropSource_AddRef(DropSource *ds) {\r
1584         return ds->sci->AddRef();\r
1585 }\r
1586 STDMETHODIMP_(ULONG)DropSource_Release(DropSource *ds) {\r
1587         return ds->sci->Release();\r
1588 }\r
1589 \r
1590 /// Implement IDropSource\r
1591 STDMETHODIMP DropSource_QueryContinueDrag(DropSource *, BOOL fEsc, DWORD grfKeyState) {\r
1592         if (fEsc)\r
1593                 return DRAGDROP_S_CANCEL;\r
1594         if (!(grfKeyState & MK_LBUTTON))\r
1595                 return DRAGDROP_S_DROP;\r
1596         return S_OK;\r
1597 }\r
1598 \r
1599 STDMETHODIMP DropSource_GiveFeedback(DropSource *, DWORD) {\r
1600         return DRAGDROP_S_USEDEFAULTCURSORS;\r
1601 }\r
1602 \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
1609 };\r
1610 \r
1611 DropSource::DropSource() {\r
1612         vtbl = vtDropSource;\r
1613         sci = 0;\r
1614 }\r
1615 \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
1620 }\r
1621 STDMETHODIMP_(ULONG)DataObject_AddRef(DataObject *pd) {\r
1622         return pd->sci->AddRef();\r
1623 }\r
1624 STDMETHODIMP_(ULONG)DataObject_Release(DataObject *pd) {\r
1625         return pd->sci->Release();\r
1626 }\r
1627 /// Implement IDataObject\r
1628 STDMETHODIMP DataObject_GetData(DataObject *pd, FORMATETC *pFEIn, STGMEDIUM *pSTM) {\r
1629         return pd->sci->GetData(pFEIn, pSTM);\r
1630 }\r
1631 \r
1632 STDMETHODIMP DataObject_GetDataHere(DataObject *, FORMATETC *, STGMEDIUM *) {\r
1633         //Platform::DebugPrintf("DOB GetDataHere\n");\r
1634         return E_NOTIMPL;\r
1635 }\r
1636 \r
1637 STDMETHODIMP DataObject_QueryGetData(DataObject *pd, FORMATETC *pFE) {\r
1638         if (pd->sci->DragIsRectangularOK(pFE->cfFormat) &&\r
1639             pFE->ptd == 0 &&\r
1640             (pFE->dwAspect & DVASPECT_CONTENT) != 0 &&\r
1641             pFE->lindex == -1 &&\r
1642             (pFE->tymed & TYMED_HGLOBAL) != 0\r
1643         ) {\r
1644                 return S_OK;\r
1645         }\r
1646 \r
1647         bool formatOK = (pFE->cfFormat == CF_TEXT) ||\r
1648                 ((pFE->cfFormat == CF_UNICODETEXT) && pd->sci->IsUnicodeMode());\r
1649         if (!formatOK ||\r
1650             pFE->ptd != 0 ||\r
1651             (pFE->dwAspect & DVASPECT_CONTENT) == 0 ||\r
1652             pFE->lindex != -1 ||\r
1653             (pFE->tymed & TYMED_HGLOBAL) == 0\r
1654         ) {\r
1655                 //Platform::DebugPrintf("DOB QueryGetData No %x\n",pFE->cfFormat);\r
1656                 //return DATA_E_FORMATETC;\r
1657                 return S_FALSE;\r
1658         }\r
1659         //Platform::DebugPrintf("DOB QueryGetData OK %x\n",pFE->cfFormat);\r
1660         return S_OK;\r
1661 }\r
1662 \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
1667         else\r
1668                 pFEOut->cfFormat = CF_TEXT;\r
1669         pFEOut->ptd = 0;\r
1670         pFEOut->dwAspect = DVASPECT_CONTENT;\r
1671         pFEOut->lindex = -1;\r
1672         pFEOut->tymed = TYMED_HGLOBAL;\r
1673         return S_OK;\r
1674 }\r
1675 \r
1676 STDMETHODIMP DataObject_SetData(DataObject *, FORMATETC *, STGMEDIUM *, BOOL) {\r
1677         //Platform::DebugPrintf("DOB SetData\n");\r
1678         return E_FAIL;\r
1679 }\r
1680 \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
1684                 *ppEnum = 0;\r
1685                 return E_FAIL;\r
1686         }\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
1691         } else {\r
1692                 CLIPFORMAT formats[] = {CF_TEXT};\r
1693                 pfe = new FormatEnumerator(0, formats, 1);\r
1694         }\r
1695         return FormatEnumerator_QueryInterface(pfe, IID_IEnumFORMATETC,\r
1696                                                reinterpret_cast<void **>(ppEnum));\r
1697 }\r
1698 \r
1699 STDMETHODIMP DataObject_DAdvise(DataObject *, FORMATETC *, DWORD, IAdviseSink *, PDWORD) {\r
1700         //Platform::DebugPrintf("DOB DAdvise\n");\r
1701         return E_FAIL;\r
1702 }\r
1703 \r
1704 STDMETHODIMP DataObject_DUnadvise(DataObject *, DWORD) {\r
1705         //Platform::DebugPrintf("DOB DUnadvise\n");\r
1706         return E_FAIL;\r
1707 }\r
1708 \r
1709 STDMETHODIMP DataObject_EnumDAdvise(DataObject *, IEnumSTATDATA **) {\r
1710         //Platform::DebugPrintf("DOB EnumDAdvise\n");\r
1711         return E_FAIL;\r
1712 }\r
1713 \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
1727 };\r
1728 \r
1729 DataObject::DataObject() {\r
1730         vtbl = vtDataObject;\r
1731         sci = 0;\r
1732 }\r
1733 \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
1738 }\r
1739 STDMETHODIMP_(ULONG)DropTarget_AddRef(DropTarget *dt) {\r
1740         return dt->sci->AddRef();\r
1741 }\r
1742 STDMETHODIMP_(ULONG)DropTarget_Release(DropTarget *dt) {\r
1743         return dt->sci->Release();\r
1744 }\r
1745 \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
1750 }\r
1751 STDMETHODIMP DropTarget_DragOver(DropTarget *dt, DWORD grfKeyState, POINTL pt, PDWORD pdwEffect) {\r
1752         return dt->sci->DragOver(grfKeyState, pt, pdwEffect);\r
1753 }\r
1754 STDMETHODIMP DropTarget_DragLeave(DropTarget *dt) {\r
1755         return dt->sci->DragLeave();\r
1756 }\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
1760 }\r
1761 \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
1770 };\r
1771 \r
1772 DropTarget::DropTarget() {\r
1773         vtbl = vtDropTarget;\r
1774         sci = 0;\r
1775 }\r
1776 \r
1777 /**\r
1778  * DBCS: support Input Method Editor (IME).\r
1779  * Called when IME Window opened.\r
1780  */\r
1781 void ScintillaWin::ImeStartComposition() {\r
1782 #ifndef __DMC__\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
1792 \r
1793                 ::ImmSetCompositionWindow(hIMC, &CompForm);\r
1794 \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
1803                                 sizeZoomed = 2;\r
1804                         AutoSurface surface(this);\r
1805                         int deviceHeight = sizeZoomed;\r
1806                         if (surface) {\r
1807                                 deviceHeight = (sizeZoomed * surface->LogPixelsY()) / 72;\r
1808                         }\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
1817 \r
1818                         ::ImmSetCompositionFontA(hIMC, &lf);\r
1819                 }\r
1820                 ::ImmReleaseContext(MainHWND(), hIMC);\r
1821                 // Caret is displayed in IME window. So, caret in Scintilla is useless.\r
1822                 DropCaret();\r
1823         }\r
1824 #endif\r
1825 }\r
1826 \r
1827 /** Called when IME Window closed. */\r
1828 void ScintillaWin::ImeEndComposition() {\r
1829         ShowCaretAtCurrentPosition();\r
1830 }\r
1831 \r
1832 void ScintillaWin::AddCharBytes(char b0, char b1) {\r
1833 \r
1834         int inputCodePage = InputCodePage();\r
1835         if (inputCodePage && IsUnicodeMode()) {\r
1836                 char utfval[4]="\0\0\0";\r
1837                 char ansiChars[3];\r
1838                 wchar_t wcs[2];\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
1844                 } else {\r
1845                         ansiChars[0] = b1;\r
1846                         ansiChars[1] = '\0';\r
1847                         ::MultiByteToWideChar(inputCodePage, 0, ansiChars, 1, wcs, 1);\r
1848                 }\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
1853         } else if (b0) {\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
1859         } else {\r
1860                 AddChar(b1);\r
1861         }\r
1862 }\r
1863 \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
1867 }\r
1868 \r
1869 void ScintillaWin::CopyToClipboard(const SelectionText &selectedText) {\r
1870         if (!::OpenClipboard(MainHWND()))\r
1871                 return ;\r
1872         ::EmptyClipboard();\r
1873 \r
1874         GlobalMemory uniText;\r
1875 \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
1880                 if (uniText) {\r
1881                         UTF16FromUTF8(selectedText.s, selectedText.len, static_cast<wchar_t *>(uniText.ptr), uchars);\r
1882                 }\r
1883         } else {\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
1889                 if (uniText) {\r
1890                         ::MultiByteToWideChar(cpSrc, 0, selectedText.s, selectedText.len,\r
1891                                 static_cast<wchar_t *>(uniText.ptr), selectedText.len);\r
1892                 }\r
1893         }\r
1894 \r
1895         if (uniText) {\r
1896                 if (!IsNT()) {\r
1897                         // Copy ANSI text to clipboard on Windows 9x\r
1898                         // Convert from Unicode text, so other ANSI programs can\r
1899                         // paste the text\r
1900                         // Windows NT, 2k, XP automatically generates CF_TEXT\r
1901                         GlobalMemory ansiText;\r
1902                         ansiText.Allocate(selectedText.len);\r
1903                         if (ansiText) {\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
1907                         }\r
1908                 }\r
1909                 uniText.SetClip(CF_UNICODETEXT);\r
1910         } else {\r
1911                 // There was a failure - try to copy at least ANSI text\r
1912                 GlobalMemory ansiText;\r
1913                 ansiText.Allocate(selectedText.len);\r
1914                 if (ansiText) {\r
1915                         memcpy(static_cast<char *>(ansiText.ptr), selectedText.s, selectedText.len);\r
1916                         ansiText.SetClip(CF_TEXT);\r
1917                 }\r
1918         }\r
1919 \r
1920         if (selectedText.rectangular) {\r
1921                 ::SetClipboardData(cfColumnSelect, 0);\r
1922         }\r
1923 \r
1924         if (selectedText.lineCopy) {\r
1925                 ::SetClipboardData(cfLineSelect, 0);\r
1926         }\r
1927 \r
1928         ::CloseClipboard();\r
1929 }\r
1930 \r
1931 void ScintillaWin::ScrollMessage(WPARAM wParam) {\r
1932         //DWORD dwStart = timeGetTime();\r
1933         //Platform::DebugPrintf("Scroll %x %d\n", wParam, lParam);\r
1934 \r
1935         SCROLLINFO sci;\r
1936         memset(&sci, 0, sizeof(sci));\r
1937         sci.cbSize = sizeof(sci);\r
1938         sci.fMask = SIF_ALL;\r
1939 \r
1940         GetScrollInfo(SB_VERT, &sci);\r
1941 \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
1944 \r
1945         int topLineNew = topLine;\r
1946         switch (LoWord(wParam)) {\r
1947         case SB_LINEUP:\r
1948                 topLineNew -= 1;\r
1949                 break;\r
1950         case SB_LINEDOWN:\r
1951                 topLineNew += 1;\r
1952                 break;\r
1953         case SB_PAGEUP:\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
1960         }\r
1961         ScrollTo(topLineNew);\r
1962 }\r
1963 \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
1969         case SB_LINEUP:\r
1970                 xPos -= 20;\r
1971                 break;\r
1972         case SB_LINEDOWN:       // May move past the logical end\r
1973                 xPos += 20;\r
1974                 break;\r
1975         case SB_PAGEUP:\r
1976                 xPos -= pageWidth;\r
1977                 break;\r
1978         case SB_PAGEDOWN:\r
1979                 xPos += pageWidth;\r
1980                 if (xPos > scrollWidth - rcText.Width()) {      // Hit the end exactly\r
1981                         xPos = scrollWidth - rcText.Width();\r
1982                 }\r
1983                 break;\r
1984         case SB_TOP:\r
1985                 xPos = 0;\r
1986                 break;\r
1987         case SB_BOTTOM:\r
1988                 xPos = scrollWidth;\r
1989                 break;\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
1993                         SCROLLINFO si;\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
1998                         }\r
1999                 }\r
2000                 break;\r
2001         }\r
2002         HorizontalScrollTo(xPos);\r
2003 }\r
2004 \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
2013                 if (changes > 0)\r
2014                         Redraw();\r
2015                 surfaceWindow->Release();\r
2016         }\r
2017         ::ReleaseDC(MainHWND(), hdc);\r
2018 }\r
2019 \r
2020 /**\r
2021  * Redraw all of text area.\r
2022  * This paint will not be abandoned.\r
2023  */\r
2024 void ScintillaWin::FullPaint() {\r
2025         HDC hdc = ::GetDC(MainHWND());\r
2026         FullPaintDC(hdc);\r
2027         ::ReleaseDC(MainHWND(), hdc);\r
2028 }\r
2029 \r
2030 /**\r
2031  * Redraw all of text area on the specified DC.\r
2032  * This paint will not be abandoned.\r
2033  */\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
2042         }\r
2043         paintState = notPainting;\r
2044 }\r
2045 \r
2046 static bool CompareDevCap(HDC hdc, HDC hOtherDC, int nIndex) {\r
2047         return ::GetDeviceCaps(hdc, nIndex) == ::GetDeviceCaps(hOtherDC, nIndex);\r
2048 }\r
2049 \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
2060 }\r
2061 \r
2062 DWORD ScintillaWin::EffectFromState(DWORD grfKeyState) {\r
2063         // These are the Wordpad semantics.\r
2064         DWORD dwEffect;\r
2065         if (inDragDrop == ddDragging)   // Internal defaults to move\r
2066                 dwEffect = DROPEFFECT_MOVE;\r
2067         else\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
2073         return dwEffect;\r
2074 }\r
2075 \r
2076 /// Implement IUnknown\r
2077 STDMETHODIMP ScintillaWin::QueryInterface(REFIID riid, PVOID *ppv) {\r
2078         *ppv = NULL;\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
2087         if (!*ppv)\r
2088                 return E_NOINTERFACE;\r
2089         return S_OK;\r
2090 }\r
2091 \r
2092 STDMETHODIMP_(ULONG) ScintillaWin::AddRef() {\r
2093         return 1;\r
2094 }\r
2095 \r
2096 STDMETHODIMP_(ULONG) ScintillaWin::Release() {\r
2097         return 1;\r
2098 }\r
2099 \r
2100 /// Implement IDropTarget\r
2101 STDMETHODIMP ScintillaWin::DragEnter(LPDATAOBJECT pIDataSource, DWORD grfKeyState,\r
2102                                      POINTL, PDWORD pdwEffect) {\r
2103         if (pIDataSource == NULL)\r
2104                 return E_POINTER;\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
2108         if (!hasOKText) {\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
2112         }\r
2113         if (!hasOKText) {\r
2114                 *pdwEffect = DROPEFFECT_NONE;\r
2115                 return S_OK;\r
2116         }\r
2117 \r
2118         *pdwEffect = EffectFromState(grfKeyState);\r
2119         return S_OK;\r
2120 }\r
2121 \r
2122 STDMETHODIMP ScintillaWin::DragOver(DWORD grfKeyState, POINTL pt, PDWORD pdwEffect) {\r
2123         if (!hasOKText || pdoc->IsReadOnly()) {\r
2124                 *pdwEffect = DROPEFFECT_NONE;\r
2125                 return S_OK;\r
2126         }\r
2127 \r
2128         *pdwEffect = EffectFromState(grfKeyState);\r
2129 \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
2134 \r
2135         return S_OK;\r
2136 }\r
2137 \r
2138 STDMETHODIMP ScintillaWin::DragLeave() {\r
2139         SetDragPosition(invalidPosition);\r
2140         return S_OK;\r
2141 }\r
2142 \r
2143 STDMETHODIMP ScintillaWin::Drop(LPDATAOBJECT pIDataSource, DWORD grfKeyState,\r
2144                                 POINTL pt, PDWORD pdwEffect) {\r
2145         *pdwEffect = EffectFromState(grfKeyState);\r
2146 \r
2147         if (pIDataSource == NULL)\r
2148                 return E_POINTER;\r
2149 \r
2150         SetDragPosition(invalidPosition);\r
2151 \r
2152         STGMEDIUM medium={0,{0},0};\r
2153 \r
2154         char *data = 0;\r
2155         bool dataAllocated = false;\r
2156 \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
2166                         if (data) {\r
2167                                 UTF8FromUTF16(udata, tlen/2, data, dataLen);\r
2168                                 dataAllocated = true;\r
2169                         }\r
2170                 } else {\r
2171                         // Convert UTF-16 to ANSI\r
2172                         //\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
2181                         if (data) {\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
2186                         }\r
2187                 }\r
2188         }\r
2189 \r
2190         if (!data) {\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
2195                 }\r
2196         }\r
2197 \r
2198         if (!data) {\r
2199                 //Platform::DebugPrintf("Bad data format: 0x%x\n", hres);\r
2200                 return hr;\r
2201         }\r
2202 \r
2203         FORMATETC fmtr = {cfColumnSelect, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};\r
2204         HRESULT hrRectangular = pIDataSource->QueryGetData(&fmtr);\r
2205 \r
2206         POINT rpt = {pt.x, pt.y};\r
2207         ::ScreenToClient(MainHWND(), &rpt);\r
2208         int movePos = PositionFromLocation(Point(rpt.x, rpt.y));\r
2209 \r
2210         DropAt(movePos, data, *pdwEffect == DROPEFFECT_MOVE, hrRectangular == S_OK);\r
2211 \r
2212         ::GlobalUnlock(medium.hGlobal);\r
2213 \r
2214         // Free data\r
2215         if (medium.pUnkForRelease != NULL)\r
2216                 medium.pUnkForRelease->Release();\r
2217         else\r
2218                 ::GlobalFree(medium.hGlobal);\r
2219 \r
2220         if (dataAllocated)\r
2221                 delete []data;\r
2222 \r
2223         return S_OK;\r
2224 }\r
2225 \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
2230         if (!formatOK ||\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
2235         ) {\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
2238         }\r
2239         pSTM->tymed = TYMED_HGLOBAL;\r
2240         //Platform::DebugPrintf("DOB GetData OK %d %x %x\n", lenDrag, pFEIn, pSTM);\r
2241 \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
2246                 if (text) {\r
2247                         UTF16FromUTF8(drag.s, drag.len, static_cast<wchar_t *>(text.ptr), uchars);\r
2248                 }\r
2249         } else {\r
2250                 text.Allocate(drag.len);\r
2251                 if (text) {\r
2252                         memcpy(static_cast<char *>(text.ptr), drag.s, drag.len);\r
2253                 }\r
2254         }\r
2255         pSTM->hGlobal = text ? text.Unlock() : 0;\r
2256         pSTM->pUnkForRelease = 0;\r
2257         return S_OK;\r
2258 }\r
2259 \r
2260 bool ScintillaWin::Register(HINSTANCE hInstance_) {\r
2261 \r
2262         hInstance = hInstance_;\r
2263         bool result;\r
2264 \r
2265         // Register the Scintilla class\r
2266         if (IsNT()) {\r
2267 \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
2283         } else {\r
2284 \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
2300         }\r
2301 \r
2302         if (result) {\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
2317 \r
2318                 result = ::RegisterClassEx(&wndclassc) != 0;\r
2319         }\r
2320 \r
2321         return result;\r
2322 }\r
2323 \r
2324 bool ScintillaWin::Unregister() {\r
2325         bool result = ::UnregisterClass(scintillaClassName, hInstance) != 0;\r
2326         if (::UnregisterClass(callClassName, hInstance) == 0)\r
2327                 result = false;\r
2328         return result;\r
2329 }\r
2330 \r
2331 bool ScintillaWin::HasCaretSizeChanged() {\r
2332         if (\r
2333                 ( (0 != vs.caretWidth) && (sysCaretWidth != vs.caretWidth) )\r
2334                 || (0 != vs.lineHeight) && (sysCaretHeight != vs.lineHeight)\r
2335                 ) {\r
2336                 return true;\r
2337         }\r
2338         return false;\r
2339 }\r
2340 \r
2341 BOOL ScintillaWin::CreateSystemCaret() {\r
2342         sysCaretWidth = vs.caretWidth;\r
2343         if (0 == sysCaretWidth) {\r
2344                 sysCaretWidth = 1;\r
2345         }\r
2346         sysCaretHeight = vs.lineHeight;\r
2347         int bitmapSize = (((sysCaretWidth + 15) & ~15) >> 3) *\r
2348                 sysCaretHeight;\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
2353         delete []bits;\r
2354         BOOL retval = ::CreateCaret(\r
2355                 MainHWND(), sysCaretBitmap,\r
2356                 sysCaretWidth, sysCaretHeight);\r
2357         ::ShowCaret(MainHWND());\r
2358         return retval;\r
2359 }\r
2360 \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
2367         }\r
2368         return retval;\r
2369 }\r
2370 \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
2375 }\r
2376 static void SetWindowPointer(HWND hWnd, void *ptr) {\r
2377         ::SetWindowLongPtr(hWnd, 0, reinterpret_cast<LONG_PTR>(ptr));\r
2378 }\r
2379 #else\r
2380 static void *PointerFromWindow(HWND hWnd) {\r
2381         return reinterpret_cast<void *>(::GetWindowLong(hWnd, 0));\r
2382 }\r
2383 static void SetWindowPointer(HWND hWnd, void *ptr) {\r
2384         ::SetWindowLong(hWnd, 0, reinterpret_cast<LONG>(ptr));\r
2385 }\r
2386 #endif\r
2387 \r
2388 sptr_t PASCAL ScintillaWin::CTWndProc(\r
2389     HWND hWnd, UINT iMessage, WPARAM wParam, sptr_t lParam) {\r
2390 \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
2399                         return 0;\r
2400                 } else {\r
2401                         return ::DefWindowProc(hWnd, iMessage, wParam, lParam);\r
2402                 }\r
2403         } else {\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
2408                         PAINTSTRUCT ps;\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
2418                         }\r
2419                         ::EndPaint(hWnd, &ps);\r
2420                         return 0;\r
2421                 } else if ((iMessage == WM_NCLBUTTONDOWN) || (iMessage == WM_NCLBUTTONDBLCLK)) {\r
2422                         POINT pt;\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
2428                         return 0;\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
2433                         return 0;\r
2434                 } else if (iMessage == WM_SETCURSOR) {\r
2435                         ::SetCursor(::LoadCursor(NULL,IDC_ARROW));\r
2436                         return 0;\r
2437                 } else if (iMessage == WM_NCHITTEST) {\r
2438                         return HTCAPTION;\r
2439                 } else {\r
2440                         return ::DefWindowProc(hWnd, iMessage, wParam, lParam);\r
2441                 }\r
2442         }\r
2443 }\r
2444 \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
2449 }\r
2450 \r
2451 extern "C"\r
2452 #ifndef STATIC_BUILD\r
2453 __declspec(dllexport)\r
2454 #endif\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
2458 }\r
2459 \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
2463 \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
2467         if (sci == 0) {\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
2473                 } else {\r
2474                         return ::DefWindowProc(hWnd, iMessage, wParam, lParam);\r
2475                 }\r
2476         } else {\r
2477                 if (iMessage == WM_NCDESTROY) {\r
2478                         sci->Finalise();\r
2479                         delete sci;\r
2480                         ::SetWindowLong(hWnd, 0, 0);\r
2481                         return ::DefWindowProc(hWnd, iMessage, wParam, lParam);\r
2482                 } else {\r
2483                         return sci->WndProc(iMessage, wParam, lParam);\r
2484                 }\r
2485         }\r
2486 }\r
2487 \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
2493 #ifdef SCI_LEXER\r
2494         Scintilla_LinkLexers();\r
2495 #endif\r
2496         return result;\r
2497 }\r
2498 \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
2503         return result;\r
2504 }\r
2505 \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
2511                         return FALSE;\r
2512         } else if (dwReason == DLL_PROCESS_DETACH) {\r
2513                 Scintilla_ReleaseResources();\r
2514         }\r
2515         return TRUE;\r
2516 }\r
2517 #endif\r