| /* | |
| * Outdated !!! | |
| * | |
| * The edit control is under reconstruction | |
| * New documentation will be provided when I'm done | |
| * | |
| * Please contact me before you send in bug fixes, as the code | |
| * might have changed already. However, keep reporting those | |
| * bugs ... I might not know about them, yet. | |
| * | |
| * Frans van Dorsselaer | |
| * dorssel@MolPhys.LeidenUniv.nl | |
| */ | |
| This file gives some information about the code in edit.c. If you want to | |
| change, add, or fix code, please read this text. If you're not interested | |
| in doing actual work on edit.c only C & D will be of interest to you. | |
| A) basic policy | |
| B) special functions | |
| C) not implemented / implementation ideas / implementation problems | |
| D) known bugs / features | |
| A) Basic Policy | |
| All messages are handled by EditWndProc(), which is the only external | |
| function call. All other functions are static (local to edit.c). | |
| All Windows Messages (WM_XXX) are 32-bit, since the edit control is now a | |
| 32-bit registered class. The message are dealt with through the helper | |
| functions EDIT_WM_XXX(). | |
| The edit control messages can be either 16 or 32 bit, depending on the type | |
| of application that sends the message. Wherever possible EditWndProc() | |
| converts the 16-bit message parameters to parameters corresponding to their | |
| 32-bit counterparts. The message is then handled by the appropriate | |
| EDIT_EM_XXX() helper function. Sometimes it is not possible to handle the | |
| 16-bit and 32-bit versions in the same way, in which case both helper | |
| functions EDIT_EM_XXX16() and EDIT_EM_XXX() are defined. | |
| All other functions are called EDIT_XXX(). | |
| Note: Sometimes a function is internally used a bit different than the specs | |
| of a similar function. For instance EDIT_SetSel() is used internally and | |
| should not be mixed up with EDIT_EM_SetSel(), a message handler that _does_ | |
| conform to the specs of EM_SETSEL. | |
| The code has been made in such a way, that functions try to call other | |
| (documented) functions if that is sufficient. This might sometimes not be | |
| the most efficient way, but it keeps the code clear. This way I tried to | |
| keep the number of functions that rely on the internal EDITSTATE structure | |
| as low as possible. For instance EDIT_WM_Cut() simply calls EDIT_WM_Copy() | |
| and EDIT_WM_Clear(). The latter two are well documented message handlers, | |
| so as long as they are right EDIT_WM_Cut() will never have to change again. | |
| Example: | |
| The best thing to do, when you want to know the offset of line 3, is calling | |
| EDIT_EM_LineIndex(). Again this is a well documented message handler. | |
| Don't look at es->LineDefs[2].offset. It would just be another reference to | |
| the internal structure, and that would make it more difficult to change | |
| things. Refer to EDIT_WM_???? and EDIT_EM_????? functions as much as | |
| possible. | |
| The WND * pointer is used internally whenever possible. Although it is not | |
| the real HWND, it improves performance enough to use it. | |
| All displaying is done by invalidating regions / rects. Only | |
| EDIT_EM_LineScroll() uses direct painting. This way things become much | |
| faster. Although sometimes the response time might appear to be slow, it | |
| would be much slower even, when everything would be painted instantly. This | |
| is especially true for scrollbar tracking and selection changes.. | |
| The text buffer is a kind of tricky. Initially the edit control allocates a | |
| HLOCAL32 buffer (32 bit linear memory handler). However, 16 bit application | |
| might send a EM_GETHANDLE message and expect a HLOCAL16 (16 bit SEG:OFF | |
| handler). From that moment on we have to keep using this 16 bit memory | |
| handler, because it is supposed to be valid at all times after EM_GETHANDLE. | |
| What we do is create a HLOCAL16 buffer, copy the text, and do pointer | |
| conversion. | |
| B) Special functions | |
| Several helper functions try to make your life easier when dealing with the | |
| allocated buffer. In principle Windows can move memory blocks around unless | |
| they are locked. Currently, WINE doesn't do this, but it might in the | |
| future. | |
| For this reason there is a nice EDIT_GetPointer() function, which locks the | |
| heap buffer *only once*, no matter how often it is called. It then returns a | |
| nice 32-bit pointer to linear memory. Calling EDIT_GetPointer() is very fast | |
| if the buffer is already locked, so you can call it whenever you feel it | |
| *might* be useful. | |
| At the end of EditWndProc(), EDIT_ReleasePointer() is automatically called | |
| which cleans up the initialized pointer. So you don't have to worry about | |
| unlocking the memory block. This way, the buffer gets locked / unlock only | |
| once every message, although EDIT_GetPointer() may actually have been called | |
| a hundred times. Only when the actual HLOCAL is needed (for example to | |
| ReAlloc), an extra call (besides the cleanup at the end of EditWndProc()) to | |
| EDIT_ReleasePointer() is needed. Look for instance in EDIT_MakeFit(). | |
| This brings us to EDIT_MakeFit(). It automatically re-allocates the buffer | |
| if the size parameter > buffersize. If everything is successful TRUE is | |
| returned, otherwise FALSE. Only when the buffer contents may grow you need | |
| to call EDIT_MakeFit(). Currently this is only in EDIT_ReplaceSel() and | |
| EDIT_WM_SetText(). | |
| EDIT_GetPointer(), EDIT_ReleasePointer and EDIT_MakeFit() are aware of the | |
| HLOCAL32 / HLOCAL16 business. | |
| EDIT_BuildLineDefs() is the most important function in edit.c. It builds | |
| the internal EDITSTATE structure. As soon as text *might* have changed, or | |
| when the appearance of the text on the screen *might* have changed, call | |
| this function ! This includes changes of screen size, change of the font, | |
| clipboard actions, etc. etc. Most other functions that rely on EDITSTATE, | |
| rely on the stuff this function builds. | |
| C) Not Implemented / Implementation Ideas / Implementation Problems | |
| Styles: | |
| - ES_CENTER | |
| - ES_RIGHT | |
| - ES_NUMBER (new since win95) | |
| - ES_OEMCONVERT | |
| - ES_WANTRETURN | |
| None of these should be difficult to include. I just didn't have the time | |
| yet. Feel free ... | |
| - ES_AUTOVSCROLL (every multi line control *is* auto vscroll) | |
| - ES_AUTOHSCROLL (every single line control *is* auto hscroll) | |
| (for multi line controls it works : wordwrap) | |
| Much, much more difficult. It comes down to this: When there is no | |
| autoscrolling, the edit control should first check whether the new text | |
| (after a typed key for instance) would fit. If not, an EN_MAXTEXT should be | |
| sent. However, currently this would require the actual change to be made, | |
| then call EDIT_BuildLineDefs() and then find out that the new text doesn't | |
| fit. After all this, things should be put back in the state before the | |
| changes. Given the fact that even normal UNDO doesn't work ... | |
| Messages: | |
| - EM_SETRECT | |
| - EM_SETRECTNP | |
| - EM_SETMARGINS (new since win95) | |
| - EM_FMTLINES | |
| These shouldn't be really difficult either. They just confine the visual | |
| output to something different than the client rectangle. Currently the | |
| client area is used everywhere in the code. At some points this should | |
| really be so (GetClientRect32()), whereas at other points it should be the | |
| format rectangle (EDIT_EM_GetRect()). Both functions are now used, but | |
| inconsistently and mixed up ! If you implement the formatting rectangle / | |
| margins, be sure to check all references to RECT's, and how they are / | |
| should be obtained. | |
| - EM_FMTLINES | |
| This means: insert or remove the soft linebreak character (\r\r\n). Probably | |
| invented by MS to suit their implementation of the edit control. However, | |
| with WINE's implementation I've never come up with occasions where it is | |
| actually useful (we never insert \r\r\n, and applications always request | |
| removal). If you are a purist ... implementation shouldn't be difficult. | |
| Take care to check if the text still fits the buffer after insertion. If | |
| not, notify with EN_ERRSPACE. | |
| - WM_UNDO (=EM_UNDO) | |
| I'm working on it. It is, however, not trivial. Luckily the only function | |
| where actual text changes is EM_REPLACESEL, so this is the only spot where | |
| we have to worry about UNDO capabilities. Before you try: contact me. I | |
| already have ideas and might start implementing it myself really soon. | |
| - EM_SETWORDBREAKPROC | |
| Not really difficult. It used to work, but since we moved to 32 bits there | |
| are now two kinds of callback functions. And I don't know the 32-bit specs | |
| for the WordBreakProc() ... Look it up and uncomment the code that is still | |
| there for 16 bit callback. | |
| - EM_SCROLL | |
| Supposed to be the same as WM_VSCROLL, but not quite. In other words: | |
| poorly documented. Somebody that knows ? | |
| D) Known bugs / Features | |
| - The control still calls GetTabbedTextExtent() and TabbedTextOut() in | |
| their 16 bit version (since the 32 bit versions don't yet exist). | |
| Therefore the tab list is 16 bits (should be 32). | |
| - Scrollbar tracking is broken. | |
| - Lots of API calls are to 16 bit functions, because their 32 bit | |
| versions haven't been implemented yet (e.g. clipboard). | |
| - Turning on WordWrap with 16-bit Notepad leaves part of the horizontal | |
| scrollbar visible (problem with WM_ERASEBKGND ???). | |
| - FIXME's (grep for them). | |
| I am working on Undo capabilities. If you want to do things, other than bug | |
| fixes, please mail me so we can synchronize. | |
| Frans van Dorsselaer | |
| dorssel@rulhm1.LeidenUniv.nl |