~ubuntu-branches/debian/stretch/alpine/stretch

« back to all changes in this revision

Viewing changes to pico/osdep/mswin_tw.c

  • Committer: Bazaar Package Importer
  • Author(s): Asheesh Laroia
  • Date: 2007-02-17 13:17:42 UTC
  • Revision ID: james.westby@ubuntu.com-20070217131742-99x5c6cpg1pbkdhw
Tags: upstream-0.82+dfsg
ImportĀ upstreamĀ versionĀ 0.82+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * ========================================================================
 
3
 * Copyright 2006-2007 University of Washington
 
4
 *
 
5
 * Licensed under the Apache License, Version 2.0 (the "License");
 
6
 * you may not use this file except in compliance with the License.
 
7
 * You may obtain a copy of the License at
 
8
 *
 
9
 *     http://www.apache.org/licenses/LICENSE-2.0
 
10
 *
 
11
 * ========================================================================
 
12
 */
 
13
#define STRICT
 
14
#define UNICODE
 
15
#define _UNICODE
 
16
#include <windows.h>
 
17
#include <windowsx.h>
 
18
#include <tchar.h>
 
19
 
 
20
/*
 
21
  article entitled "About Rich Edit Controls" here (remove all spaces from url):
 
22
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/
 
23
      platform/commctls/richedit/richeditcontrols/aboutricheditcontrols.asp
 
24
 
 
25
  Rich Edit version DLL
 
26
  1.0   Riched32.dll
 
27
  2.0   Riched20.dll
 
28
  3.0   Riched20.dll
 
29
  4.1   Msftedit.dll
 
30
 
 
31
  The following list describes which versions of Rich Edit are included in
 
32
    which releases of Microsoft Windows.
 
33
  Windows XP SP1  Includes Rich Edit 4.1, Rich Edit 3.0, and a Rich Edit 1.0 emulator.
 
34
  Windows XP      Includes Rich Edit 3.0 with a Rich Edit 1.0 emulator.
 
35
  Windows Me      Includes Rich Edit 1.0 and 3.0.
 
36
  Windows 2000    Includes Rich Edit 3.0 with a Rich Edit 1.0 emulator.
 
37
  Windows NT 4.0  Includes Rich Edit 1.0 and 2.0.
 
38
  Windows 98      Includes Rich Edit 1.0 and 2.0.
 
39
  Windows 95      Includes only Rich Edit 1.0. However, Riched20.dll is
 
40
                    compatible with Windows 95 and may be installed by an
 
41
                    application that requires it.
 
42
 
 
43
  We're using richedit v2 since it is the first to have Unicode support. Does
 
44
    potentially limit us to Win98 unless we install riched20.dll or it's
 
45
    already there.
 
46
 */
 
47
#define _RICHEDIT_VER   0x0200
 
48
#include <richedit.h>
 
49
#include "resource.h"
 
50
 
 
51
#include "mswin_tw.h"
 
52
 
 
53
/*
 
54
 * Globals
 
55
 */
 
56
static const TCHAR g_mswin_tw_class_name[] = TEXT("PineTWClass");
 
57
 
 
58
// Maximum amount of text allowed in these textwindows.
 
59
//  Set via a EM_EXLIMITTEXT message.
 
60
static const LPARAM g_max_text = 8 * 1024 * 1024 - 1;
 
61
 
 
62
/*
 
63
 * Function prototypes
 
64
 */
 
65
static LRESULT CALLBACK mswin_tw_wndproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
 
66
static UINT Edit_ExSetSel(HWND hwnd_edit, LONG cpMin, LONG cpMax);
 
67
static UINT Edit_ExGetTextLen(HWND hwnd_edit, DWORD flags);
 
68
static BOOL Edit_ExIsReadOnly(HWND hwnd_edit);
 
69
 
 
70
/*
 
71
 * mswin_tw_create() - Create a mswin textwindow.
 
72
 */
 
73
int
 
74
mswin_tw_create(MSWIN_TEXTWINDOW *mswin_tw, LPCTSTR title)
 
75
{
 
76
    int width, height;
 
77
    static int s_mswin_tw_class_registered = 0;
 
78
 
 
79
    mswin_tw->hwnd = NULL;
 
80
    mswin_tw->hwnd_edit = NULL;
 
81
 
 
82
    if(!s_mswin_tw_class_registered)
 
83
    {
 
84
        WNDCLASS  wndclass;
 
85
 
 
86
        LoadLibrary(TEXT("riched20.dll"));
 
87
 
 
88
        memset(&wndclass, 0, sizeof(wndclass));
 
89
        wndclass.style =         CS_BYTEALIGNWINDOW;
 
90
        wndclass.lpfnWndProc =   mswin_tw_wndproc;
 
91
        wndclass.cbClsExtra =    0;
 
92
        wndclass.cbWndExtra =    sizeof(ULONG_PTR);
 
93
        wndclass.hInstance =     mswin_tw->hInstance ;
 
94
        wndclass.hIcon =         LoadIcon (mswin_tw->hInstance, MAKEINTRESOURCE( ALPINEICON));
 
95
        wndclass.hCursor =       LoadCursor (NULL, IDC_ARROW);
 
96
        wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
 
97
        wndclass.lpszMenuName =  MAKEINTRESOURCE(TEXTWINMENU);
 
98
        wndclass.lpszClassName = g_mswin_tw_class_name ;
 
99
 
 
100
        RegisterClass(&wndclass);
 
101
 
 
102
        s_mswin_tw_class_registered = 1;
 
103
    }
 
104
 
 
105
    // If we're passed CW_USEDEFAULT as the position, then use right/bottom
 
106
    //  as the width/height. Otherwise use the full rect.
 
107
    width = (mswin_tw->rcSize.left == CW_USEDEFAULT) ?
 
108
        mswin_tw->rcSize.right : mswin_tw->rcSize.right - mswin_tw->rcSize.left;
 
109
    height = (mswin_tw->rcSize.top == CW_USEDEFAULT) ?
 
110
        mswin_tw->rcSize.bottom : mswin_tw->rcSize.bottom - mswin_tw->rcSize.top;
 
111
 
 
112
    mswin_tw->hwnd = CreateWindow(
 
113
                g_mswin_tw_class_name, title,
 
114
                WS_OVERLAPPEDWINDOW,
 
115
                mswin_tw->rcSize.left,
 
116
                mswin_tw->rcSize.top,
 
117
                width,
 
118
                height,
 
119
                HWND_DESKTOP, NULL,
 
120
                mswin_tw->hInstance, mswin_tw);
 
121
    if(!mswin_tw->hwnd)
 
122
        return 0;
 
123
 
 
124
    return 1;
 
125
}
 
126
 
 
127
/*
 
128
 * mswin_tw_close() - close the mswin textwindow.
 
129
 */
 
130
void
 
131
mswin_tw_close(MSWIN_TEXTWINDOW *mswin_tw)
 
132
{
 
133
    if(mswin_tw && mswin_tw->hwnd)
 
134
        DestroyWindow(mswin_tw->hwnd);
 
135
}
 
136
 
 
137
/*
 
138
 * mswin_tw_showwindow() - show the main hwnd (SW_SHOWNORMAL, etc.).
 
139
 */
 
140
void
 
141
mswin_tw_showwindow(MSWIN_TEXTWINDOW *mswin_tw, int nCmdShow)
 
142
{
 
143
    if(mswin_tw && mswin_tw->hwnd)
 
144
        ShowWindow(mswin_tw->hwnd, nCmdShow);
 
145
}
 
146
 
 
147
/*
 
148
 * mswin_tw_setfont() - Sets the hfont for the entire edit control.
 
149
 */
 
150
void
 
151
mswin_tw_setfont(MSWIN_TEXTWINDOW *mswin_tw, HFONT hfont)
 
152
{
 
153
    if(mswin_tw && mswin_tw->hwnd_edit)
 
154
        SetWindowFont(mswin_tw->hwnd_edit, hfont, TRUE);
 
155
}
 
156
 
 
157
/*
 
158
 * mswin_tw_setcolor() - Set colors for entire edit control. If we're
 
159
 *  passed -1 for mswin_tw, then set the colors for all textwindows.
 
160
 */
 
161
void
 
162
mswin_tw_setcolor(MSWIN_TEXTWINDOW *mswin_tw,
 
163
    COLORREF TextColor, COLORREF BackColor)
 
164
{
 
165
    if(mswin_tw == (MSWIN_TEXTWINDOW *)-1)
 
166
    {
 
167
        HWND hwnd = NULL;
 
168
 
 
169
        while(hwnd = FindWindowEx(NULL, hwnd, g_mswin_tw_class_name, NULL))
 
170
        {
 
171
            mswin_tw = (MSWIN_TEXTWINDOW *)(LONG_PTR)GetWindowLongPtr(
 
172
                hwnd, GWLP_USERDATA);
 
173
            if(mswin_tw)
 
174
            {
 
175
                mswin_tw_setcolor(mswin_tw, TextColor, BackColor);
 
176
            }
 
177
        }
 
178
    }
 
179
    else if(mswin_tw && mswin_tw->hwnd_edit)
 
180
    {
 
181
        CHARFORMAT2W cf2;
 
182
 
 
183
        memset(&cf2, 0, sizeof(cf2));
 
184
        cf2.cbSize = sizeof(cf2);
 
185
        cf2.dwMask = CFM_COLOR;
 
186
        cf2.crTextColor = TextColor;
 
187
 
 
188
        SendMessage(mswin_tw->hwnd_edit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf2);
 
189
        SendMessage(mswin_tw->hwnd_edit, EM_SETBKGNDCOLOR, 0, BackColor);
 
190
    }
 
191
}
 
192
 
 
193
/*
 
194
 * mswin_tw_puts_lptstr() - Stuffs a LPTSTR string at the end of our edit
 
195
 *  control.
 
196
 */
 
197
int
 
198
mswin_tw_puts_lptstr(MSWIN_TEXTWINDOW *mswin_tw, LPTSTR msg)
 
199
{
 
200
    if(mswin_tw && mswin_tw->hwnd_edit)
 
201
    {
 
202
        POINT pt;
 
203
        RECT rc;
 
204
        TCHAR lf_str[] = TEXT("\n");
 
205
 
 
206
        Edit_ExSetSel(mswin_tw->hwnd_edit, -1, -1);
 
207
        Edit_ReplaceSel(mswin_tw->hwnd_edit, msg);
 
208
 
 
209
        Edit_ReplaceSel(mswin_tw->hwnd_edit, lf_str);
 
210
 
 
211
        Edit_ScrollCaret(mswin_tw->hwnd_edit);
 
212
        return 1;
 
213
    }
 
214
 
 
215
    return 0;
 
216
}
 
217
 
 
218
/*
 
219
 * mswin_tw_printf() - printf version of mswin_tw_puts_lptstr.
 
220
 */
 
221
int
 
222
mswin_tw_printf(MSWIN_TEXTWINDOW *mswin_tw, LPCTSTR fmt, ...)
 
223
{
 
224
    TCHAR msg[1024];
 
225
    va_list  vlist;
 
226
 
 
227
    va_start(vlist, fmt);
 
228
    _vsntprintf(msg, ARRAYSIZE(msg), fmt, vlist);
 
229
    va_end(vlist);
 
230
 
 
231
    msg[ARRAYSIZE(msg) - 1] = 0;
 
232
    return mswin_tw_puts_lptstr(mswin_tw, msg);
 
233
}
 
234
 
 
235
/*
 
236
 * mswin_tw_gettextlength() - Returns the number of TCHARs in the edit control.
 
237
 */
 
238
UINT
 
239
mswin_tw_gettextlength(MSWIN_TEXTWINDOW *mswin_tw)
 
240
{
 
241
    if(mswin_tw && mswin_tw->hwnd_edit)
 
242
        return (UINT)Edit_ExGetTextLen(mswin_tw->hwnd_edit, GTL_USECRLF);
 
243
 
 
244
    return 0;
 
245
}
 
246
 
 
247
/*
 
248
 * mswin_tw_gettext() - Return value is the number of TCHARs copied into the
 
249
 *  output buffer.
 
250
 */
 
251
UINT
 
252
mswin_tw_gettext(MSWIN_TEXTWINDOW *mswin_tw, LPTSTR lptstr_ret, int lptstr_len)
 
253
{
 
254
    if(mswin_tw && mswin_tw->hwnd_edit)
 
255
    {
 
256
        GETTEXTEX gt;
 
257
        LRESULT lresult;
 
258
 
 
259
        gt.cb = lptstr_len * sizeof(TCHAR);
 
260
        gt.flags = GT_DEFAULT | GT_USECRLF;
 
261
        gt.codepage = 1200;
 
262
        gt.lpDefaultChar = NULL;
 
263
        gt.lpUsedDefChar = NULL;
 
264
 
 
265
        lptstr_ret[0] = 0;
 
266
        lresult = SendMessage(mswin_tw->hwnd_edit, EM_GETTEXTEX,
 
267
            (WPARAM)&gt, (LPARAM)lptstr_ret);
 
268
        return (int)lresult;
 
269
    }
 
270
 
 
271
    return 0;
 
272
}
 
273
 
 
274
/*
 
275
 * mswin_tw_setsel() - Set edit control selection.
 
276
 */
 
277
void
 
278
mswin_tw_setsel(MSWIN_TEXTWINDOW *mswin_tw, LONG min, LONG max)
 
279
{
 
280
    if(mswin_tw && mswin_tw->hwnd_edit)
 
281
    {
 
282
        Edit_ExSetSel(mswin_tw->hwnd_edit, min, max);
 
283
    }
 
284
}
 
285
 
 
286
/*
 
287
 * mswin_tw_clear() - Clear all text from edit control.
 
288
 */
 
289
void mswin_tw_clear(MSWIN_TEXTWINDOW *mswin_tw)
 
290
{
 
291
    if(mswin_tw && mswin_tw->hwnd_edit)
 
292
    {
 
293
        SETTEXTEX stex;
 
294
 
 
295
        stex.flags = ST_DEFAULT;
 
296
        stex.codepage = 1200;       // Unicode (see richedit.h)
 
297
 
 
298
        SendMessage(mswin_tw->hwnd_edit, EM_SETTEXTEX,
 
299
            (WPARAM)&stex, (LPARAM)TEXT(""));
 
300
 
 
301
        if(mswin_tw->clear_callback)
 
302
            mswin_tw->clear_callback(mswin_tw);
 
303
    }
 
304
}
 
305
 
 
306
/*
 
307
 * MySetWindowLongPtr() - Little wrapper routine which calls the
 
308
 *  Windows SetWindowLongPtr() and removes the stupid warning which is
 
309
 *  just seriously lame.
 
310
 */
 
311
static LONG_PTR
 
312
MySetWindowLongPtr(HWND hwnd, int nIndex, void *NewLongPtr)
 
313
{
 
314
// warning C4244: 'function': conversion from 'LONG_PTR' to 'LONG',
 
315
//  possible loss of data
 
316
#pragma warning(push)
 
317
#pragma warning(disable: 4244)
 
318
    return SetWindowLongPtr(hwnd, nIndex, (LONG_PTR)NewLongPtr);
 
319
#pragma warning(pop)
 
320
}
 
321
 
 
322
/*
 
323
 * mswin_tw_wm_command() - WM_CONTEXTMENU handler for textwindows
 
324
 */
 
325
static void
 
326
mswin_tw_wm_contextmenu(MSWIN_TEXTWINDOW *mswin_tw, HWND hwnd, HWND hwndContext,
 
327
    int xPos, int yPos)
 
328
{
 
329
   HMENU hMenu;
 
330
 
 
331
    hMenu = CreatePopupMenu();
 
332
    if(hMenu)
 
333
    {
 
334
        int i;
 
335
        CHARRANGE cr;
 
336
        MENUITEMINFO mitem;
 
337
        static const struct
 
338
        {
 
339
            UINT wID;
 
340
            LPTSTR dwTypeData;
 
341
        } s_popup_menu[] =
 
342
        {
 
343
            { IDM_EDIT_COPY,        TEXT("&Copy")        },
 
344
            { IDM_EDIT_COPY_APPEND, TEXT("Copy &Append") },
 
345
            { IDM_EDIT_CLEAR,       TEXT("Clea&r")       },
 
346
        };
 
347
 
 
348
        memset(&mitem, 0, sizeof(MENUITEMINFO));
 
349
        mitem.cbSize = sizeof(MENUITEMINFO);
 
350
        mitem.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
 
351
        mitem.fType = MFT_STRING;
 
352
 
 
353
        SendMessage(mswin_tw->hwnd_edit, EM_EXGETSEL, (WPARAM)0, (LPARAM)&cr);
 
354
 
 
355
        for(i = 0; i < ARRAYSIZE(s_popup_menu); i++)
 
356
        {
 
357
            switch(s_popup_menu[i].wID)
 
358
            {
 
359
            case IDM_EDIT_CLEAR:
 
360
                // Only enable it if there is a clear callback set.
 
361
                mitem.fState = (mswin_tw->clear_callback) ? 
 
362
                    MFS_ENABLED : MFS_GRAYED;
 
363
                break;
 
364
            case IDM_EDIT_COPY:
 
365
            case IDM_EDIT_COPY_APPEND:
 
366
                // Only enable if there is a selection.
 
367
                mitem.fState = (cr.cpMax > cr.cpMin) ? 
 
368
                    MFS_ENABLED : MFS_GRAYED;
 
369
                break;
 
370
            default:
 
371
                mitem.fState = MFS_ENABLED;
 
372
                break;
 
373
            }
 
374
            
 
375
            mitem.wID = s_popup_menu[i].wID;
 
376
            mitem.dwTypeData = s_popup_menu[i].dwTypeData;
 
377
            mitem.cch = (UINT)_tcslen(s_popup_menu[i].dwTypeData);
 
378
            InsertMenuItem(hMenu, i, FALSE, &mitem);
 
379
        }
 
380
 
 
381
        TrackPopupMenu(hMenu,
 
382
               TPM_LEFTALIGN | TPM_TOPALIGN |
 
383
               TPM_RIGHTBUTTON | TPM_LEFTBUTTON,
 
384
               xPos, yPos, 0, hwnd, NULL);
 
385
 
 
386
        DestroyMenu(hMenu);
 
387
    }
 
388
}
 
389
 
 
390
/*
 
391
 * mswin_tw_wm_command() - WM_COMMAND handler for textwindows
 
392
 */
 
393
static void
 
394
mswin_tw_wm_command(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
 
395
{
 
396
    MSWIN_TEXTWINDOW *mswin_tw;
 
397
 
 
398
    mswin_tw = (MSWIN_TEXTWINDOW *)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_USERDATA);
 
399
 
 
400
    switch(id)
 
401
    {
 
402
    case IDM_FILE_CLOSE:
 
403
        DestroyWindow(hwnd);
 
404
        break;
 
405
 
 
406
    case IDM_FILE_PRINT:
 
407
        if(mswin_tw->print_callback)
 
408
            mswin_tw->print_callback(mswin_tw);
 
409
        break;
 
410
 
 
411
    case IDM_EDIT_COPY:
 
412
        SendMessage(mswin_tw->hwnd_edit, WM_COPY, 0, 0);
 
413
        break;
 
414
 
 
415
    case IDM_EDIT_CLEAR:
 
416
        mswin_tw_clear(mswin_tw);
 
417
        break;
 
418
 
 
419
    case IDM_EDIT_COPY_APPEND:
 
420
    {
 
421
        CHARRANGE cr;
 
422
        CHARRANGE cr_temp;
 
423
        int text_len0, text_len1;
 
424
        HWND hwnd_edit = mswin_tw->hwnd_edit;
 
425
        BOOL EditIsReadOnly = Edit_ExIsReadOnly(hwnd_edit);
 
426
 
 
427
        SetWindowRedraw(hwnd_edit, FALSE);
 
428
        Edit_SetReadOnly(hwnd_edit, FALSE);
 
429
 
 
430
        // Get current selection.
 
431
        SendMessage(hwnd_edit, EM_EXGETSEL, (WPARAM)0, (LPARAM)&cr);
 
432
 
 
433
        // Get current length.
 
434
        text_len0 = Edit_ExGetTextLen(hwnd_edit, 0);
 
435
 
 
436
        // Paste current clip right before our new selection.
 
437
        Edit_ExSetSel(hwnd_edit, cr.cpMin, cr.cpMin);
 
438
        SendMessage(hwnd_edit, WM_PASTE, 0, 0);
 
439
 
 
440
        // Get new length.
 
441
        text_len1 = Edit_ExGetTextLen(hwnd_edit, 0);
 
442
 
 
443
        // Select new and old clip and copy em.
 
444
        Edit_ExSetSel(hwnd_edit, cr.cpMin, cr.cpMax + text_len1 - text_len0);
 
445
        SendMessage(hwnd_edit, WM_COPY, 0, 0);
 
446
 
 
447
        // Undo our paste and restore original selection.
 
448
        SendMessage(hwnd_edit, WM_UNDO, 0, 0);
 
449
        SendMessage(hwnd_edit, EM_EXSETSEL, (WPARAM)0, (LPARAM)&cr);
 
450
 
 
451
        // Set back to read only.
 
452
        Edit_SetReadOnly(hwnd_edit, EditIsReadOnly);
 
453
        SetWindowRedraw(hwnd_edit, TRUE);
 
454
        break;
 
455
    }
 
456
 
 
457
    case IDM_EDIT_SEL_ALL:
 
458
        Edit_ExSetSel(mswin_tw->hwnd_edit, 0, -1);
 
459
        break;
 
460
    }
 
461
}
 
462
 
 
463
/*
 
464
 * mswin_tw_wm_notify() - WM_NOTIFY handler for textwindows
 
465
 */
 
466
static LRESULT
 
467
mswin_tw_wm_notify(HWND hwnd, int idCtrl, NMHDR *nmhdr)
 
468
{
 
469
    HWND hwnd_edit = nmhdr->hwndFrom;
 
470
 
 
471
    if(nmhdr->code == EN_MSGFILTER)
 
472
    {
 
473
        MSGFILTER *msg_filter = (MSGFILTER *)nmhdr;
 
474
 
 
475
        if(msg_filter->msg == WM_KEYDOWN)
 
476
        {
 
477
            if(msg_filter->wParam == 'E')
 
478
            {
 
479
                int control_down = GetKeyState(VK_CONTROL) < 0;
 
480
                int shift_down = GetKeyState(VK_SHIFT) < 0;
 
481
 
 
482
                // Ctrl+Shift+E toggles the readonly attribute on the text
 
483
                //  buffer.
 
484
                if(control_down && shift_down)
 
485
                    Edit_SetReadOnly(hwnd_edit, !Edit_ExIsReadOnly(hwnd_edit));
 
486
                return TRUE;
 
487
            }
 
488
        }
 
489
        else if(msg_filter->msg == WM_CHAR)
 
490
        {
 
491
            // Only override these keys if this buffer is readonly.
 
492
            if(Edit_ExIsReadOnly(hwnd_edit))
 
493
            {
 
494
                switch(msg_filter->wParam)
 
495
                {
 
496
                case 'k':
 
497
                    SendMessage(hwnd_edit, EM_SCROLL, SB_LINEUP, 0);
 
498
                    return TRUE;
 
499
                case 'j':
 
500
                    SendMessage(hwnd_edit, EM_SCROLL, SB_LINEDOWN, 0);
 
501
                    return TRUE;
 
502
                case '-':
 
503
                case 'b':
 
504
                    SendMessage(hwnd_edit, EM_SCROLL, SB_PAGEUP, 0);
 
505
                    return TRUE;
 
506
                case ' ':
 
507
                case 'f':
 
508
                    SendMessage(hwnd_edit, EM_SCROLL, SB_PAGEDOWN, 0);
 
509
                    return TRUE;
 
510
                }
 
511
            }
 
512
        }
 
513
    }
 
514
    else if(nmhdr->code == EN_LINK)
 
515
    {
 
516
        ENLINK *enlink = (ENLINK *)nmhdr;
 
517
 
 
518
        if(enlink->msg == WM_LBUTTONDOWN)
 
519
        {
 
520
            TEXTRANGE tr;
 
521
            TCHAR link_buf[1024];
 
522
 
 
523
            link_buf[0] = 0;
 
524
            tr.lpstrText = link_buf;
 
525
 
 
526
            tr.chrg = enlink->chrg;
 
527
            if(tr.chrg.cpMax - tr.chrg.cpMin > ARRAYSIZE(link_buf))
 
528
                tr.chrg.cpMax = tr.chrg.cpMin + ARRAYSIZE(link_buf);
 
529
 
 
530
            SendMessage(hwnd_edit, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
 
531
            ShellExecute(hwnd, TEXT("Open"), link_buf, NULL,  NULL,  SW_SHOWNORMAL);
 
532
            return TRUE;
 
533
        }
 
534
    }
 
535
 
 
536
    return FALSE;
 
537
}
 
538
 
 
539
/*
 
540
 * mswin_tw_wndproc() - Main window proc for mswin textwindows.
 
541
 */
 
542
static LRESULT CALLBACK
 
543
mswin_tw_wndproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
 
544
{
 
545
    MSWIN_TEXTWINDOW *mswin_tw;
 
546
 
 
547
    mswin_tw = (MSWIN_TEXTWINDOW *)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_USERDATA);
 
548
 
 
549
    switch(msg)
 
550
    {
 
551
    case WM_CREATE:
 
552
    {
 
553
        CREATESTRUCT *pcs = (CREATESTRUCT *)lp;
 
554
 
 
555
        mswin_tw = (MSWIN_TEXTWINDOW *)pcs->lpCreateParams;
 
556
 
 
557
        MySetWindowLongPtr(hwnd, GWLP_USERDATA, mswin_tw);
 
558
 
 
559
        mswin_tw->hwnd_edit = CreateWindowEx(
 
560
                        WS_EX_CLIENTEDGE, RICHEDIT_CLASS, 0,
 
561
                        WS_VISIBLE | WS_CHILD |
 
562
                        WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
 
563
                        WS_VSCROLL | WS_HSCROLL |
 
564
                        ES_MULTILINE | ES_READONLY | ES_NOHIDESEL,
 
565
                        0, 0, 1, 1,
 
566
                        hwnd, 0, mswin_tw->hInstance, 0);
 
567
 
 
568
        // We want link and key event notifications.
 
569
        SendMessage(mswin_tw->hwnd_edit, EM_SETEVENTMASK,
 
570
            0, (ENM_KEYEVENTS | ENM_LINK));
 
571
 
 
572
        // Specifies the maximum amount of text that can be entered.
 
573
        SendMessage(mswin_tw->hwnd_edit, EM_EXLIMITTEXT, 0, g_max_text);
 
574
 
 
575
        // Enable automatic detection of URLs by our rich edit control.
 
576
        SendMessage(mswin_tw->hwnd_edit, EM_AUTOURLDETECT, TRUE, 0);
 
577
        break;
 
578
    }
 
579
 
 
580
    case WM_CONTEXTMENU:
 
581
        mswin_tw_wm_contextmenu(mswin_tw, hwnd, (HWND)wp, GET_X_LPARAM(lp), GET_Y_LPARAM(lp));
 
582
        break;
 
583
 
 
584
    case WM_NOTIFY:
 
585
        return mswin_tw_wm_notify(hwnd, (int)wp, (NMHDR *)lp);
 
586
 
 
587
    case WM_COMMAND:
 
588
        HANDLE_WM_COMMAND(hwnd, wp, lp, mswin_tw_wm_command);
 
589
        break;
 
590
 
 
591
    case WM_SETFOCUS:
 
592
        SetFocus(mswin_tw->hwnd_edit);
 
593
        return TRUE;
 
594
 
 
595
    case WM_SIZE:
 
596
        MoveWindow(mswin_tw->hwnd_edit, 0, 0, LOWORD(lp), HIWORD(lp), TRUE);
 
597
        break;
 
598
 
 
599
    case WM_WINDOWPOSCHANGED:
 
600
        if(!IsIconic(hwnd))
 
601
        {
 
602
            WINDOWPOS *wpos = (WINDOWPOS *)lp;
 
603
 
 
604
            mswin_tw->rcSize.left = wpos->x;
 
605
            mswin_tw->rcSize.top = wpos->y;
 
606
            mswin_tw->rcSize.right = wpos->x + wpos->cx;
 
607
            mswin_tw->rcSize.bottom = wpos->y + wpos->cy;
 
608
        }
 
609
        break;
 
610
 
 
611
    case WM_DESTROY:
 
612
        mswin_tw->hwnd = NULL;
 
613
        mswin_tw->hwnd_edit = NULL;
 
614
 
 
615
        if(mswin_tw->close_callback)
 
616
            mswin_tw->close_callback(mswin_tw);
 
617
        return TRUE;
 
618
 
 
619
    default:
 
620
        break;
 
621
    }
 
622
 
 
623
    return DefWindowProc(hwnd, msg, wp, lp);
 
624
}
 
625
 
 
626
/*
 
627
 * Edit_ExGetTextLen() - Helper routine for getting count of chars.
 
628
 */
 
629
static UINT
 
630
Edit_ExGetTextLen(HWND hwnd_edit, DWORD flags)
 
631
{
 
632
    GETTEXTLENGTHEX gtl;
 
633
 
 
634
    gtl.flags = GTL_PRECISE | GTL_NUMCHARS | flags;
 
635
    gtl.codepage = 1200;        // Unicode (see richedit.h)
 
636
    return (UINT)SendMessage(hwnd_edit, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0);
 
637
}
 
638
 
 
639
/*
 
640
 * Edit_ExSetSel() - Helper routine for setting edit selection.
 
641
 */
 
642
static UINT
 
643
Edit_ExSetSel(HWND hwnd_edit, LONG cpMin, LONG cpMax)
 
644
{
 
645
    CHARRANGE cr;
 
646
 
 
647
    if(cpMin == -1)
 
648
        cpMin = Edit_ExGetTextLen(hwnd_edit, 0);
 
649
 
 
650
    cr.cpMin = cpMin;
 
651
    cr.cpMax = cpMax;
 
652
    return (UINT)SendMessage(hwnd_edit, EM_EXSETSEL, (WPARAM)0, (LPARAM)&cr);
 
653
}
 
654
 
 
655
/*
 
656
 * Edit_ExIsReadOnly() - TRUE if edit buffer is read only.
 
657
 */
 
658
static BOOL
 
659
Edit_ExIsReadOnly(HWND hwnd_edit)
 
660
{
 
661
    LRESULT edit_opts;
 
662
 
 
663
    edit_opts = SendMessage(hwnd_edit, EM_GETOPTIONS, 0, 0);
 
664
    return !!(edit_opts & ECO_READONLY);
 
665
}
 
666