[BACK]Return to gui_x11.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / vim

Annotation of src/usr.bin/vim/gui_x11.c, Revision 1.1.1.1

1.1       downsj      1: /* $OpenBSD$   */
                      2: /* vi:set ts=4 sw=4:
                      3:  *
                      4:  * VIM - Vi IMproved           by Bram Moolenaar
                      5:  *                             GUI/Motif support by Robert Webb
                      6:  *
                      7:  * Do ":help uganda"  in Vim to read copying and usage conditions.
                      8:  * Do ":help credits" in Vim to see a list of people who contributed.
                      9:  */
                     10:
                     11: #include <X11/keysym.h>
                     12: #include <X11/Xatom.h>
                     13: #include <X11/StringDefs.h>
                     14: #include <X11/Intrinsic.h>
                     15: #include <X11/Shell.h>
                     16:
                     17: #include "vim.h"
                     18: #include "globals.h"
                     19: #include "proto.h"
                     20: #include "option.h"
                     21: #include "ops.h"
                     22:
                     23: #define VIM_NAME       "vim"
                     24: #define VIM_CLASS      "Vim"
                     25:
                     26: /* Default resource values */
                     27: #define DFLT_FONT              "7x13"
                     28: #define DFLT_MENU_BG_COLOR     "gray77"
                     29: #define DFLT_MENU_FG_COLOR     "black"
                     30: #define DFLT_SCROLL_BG_COLOR   "gray60"
                     31: #define DFLT_SCROLL_FG_COLOR   "gray77"
                     32:
                     33: Widget vimShell = (Widget)NULL;
                     34:
                     35: static XtAppContext app_context;
                     36: static Atom   Atom_WM_DELETE_WINDOW;
                     37:
                     38: static Pixel gui_x11_get_color            __ARGS((char_u *));
                     39: static void  gui_x11_set_color            __ARGS((GC, Pixel));
                     40: static void  gui_x11_set_font             __ARGS((GC, Font));
                     41: static void  gui_x11_check_copy_area      __ARGS((void));
                     42: static void  gui_x11_update_menus_recurse __ARGS((GuiMenu *, int));
                     43:
                     44: static void  gui_x11_request_selection_cb __ARGS((Widget, XtPointer,
                     45:                                                  Atom *, Atom *, XtPointer,
                     46:                                                  long_u *, int *));
                     47:
                     48: static Boolean  gui_x11_convert_selection_cb __ARGS((Widget, Atom *, Atom *,
                     49:                                                     Atom *, XtPointer *,
                     50:                                                     long_u *, int *));
                     51:
                     52: static void  gui_x11_lose_ownership_cb __ARGS((Widget, Atom *));
                     53:
                     54: static void  gui_x11_wm_protocol_handler __ARGS((Widget, XtPointer,
                     55:                                            XEvent *, Boolean *));
                     56:
                     57: static void gui_x11_invert_area         __ARGS((int, int, int, int));
                     58: static void gui_x11_yank_selection      __ARGS((int, int, int, int));
                     59: static void gui_x11_get_word_boundaries __ARGS((GuiSelection *, int, int));
                     60: static int  gui_x11_get_line_end        __ARGS((int));
                     61: static void gui_x11_update_selection    __ARGS((GuiSelection *, int, int, int,
                     62:                                                int));
                     63:
                     64: #define char_class(c)  (c <= ' ' ? ' ' : iswordchar(c))
                     65:
                     66: #define invert_rectangle(r, c, nr, nc)                             \
                     67:            XFillRectangle(gui.dpy, gui.wid, gui.invert_gc,         \
                     68:                    FILL_X(c), FILL_Y(r), (nc) * gui.char_width,    \
                     69:                    (nr) * gui.char_height)
                     70:
                     71:
                     72: static struct
                     73: {
                     74:    KeySym  key_sym;
                     75:    char_u  vim_code0;
                     76:    char_u  vim_code1;
                     77: } special_keys[] =
                     78: {
                     79:    {XK_Up,         'k', 'u'},
                     80:    {XK_Down,       'k', 'd'},
                     81:    {XK_Left,       'k', 'l'},
                     82:    {XK_Right,      'k', 'r'},
                     83:
                     84:    {XK_F1,         'k', '1'},
                     85:    {XK_F2,         'k', '2'},
                     86:    {XK_F3,         'k', '3'},
                     87:    {XK_F4,         'k', '4'},
                     88:    {XK_F5,         'k', '5'},
                     89:    {XK_F6,         'k', '6'},
                     90:    {XK_F7,         'k', '7'},
                     91:    {XK_F8,         'k', '8'},
                     92:    {XK_F9,         'k', '9'},
                     93:    {XK_F10,        'k', ';'},
                     94:
                     95:    {XK_F11,        'F', '1'},
                     96:    {XK_F12,        'F', '2'},
                     97:    {XK_F13,        'F', '3'},
                     98:    {XK_F14,        'F', '4'},
                     99:    {XK_F15,        'F', '5'},
                    100:    {XK_F16,        'F', '6'},
                    101:    {XK_F17,        'F', '7'},
                    102:    {XK_F18,        'F', '8'},
                    103:    {XK_F19,        'F', '9'},
                    104:    {XK_F20,        'F', 'A'},
                    105:
                    106:    {XK_F21,        'F', 'B'},
                    107:    {XK_F22,        'F', 'C'},
                    108:    {XK_F23,        'F', 'D'},
                    109:    {XK_F24,        'F', 'E'},
                    110:    {XK_F25,        'F', 'F'},
                    111:    {XK_F26,        'F', 'G'},
                    112:    {XK_F27,        'F', 'H'},
                    113:    {XK_F28,        'F', 'I'},
                    114:    {XK_F29,        'F', 'J'},
                    115:    {XK_F30,        'F', 'K'},
                    116:
                    117:    {XK_F31,        'F', 'L'},
                    118:    {XK_F32,        'F', 'M'},
                    119:    {XK_F33,        'F', 'N'},
                    120:    {XK_F34,        'F', 'O'},
                    121:    {XK_F35,        'F', 'P'},      /* keysymdef.h defines up to F35 */
                    122:
                    123:    {XK_Help,       '%', '1'},
                    124:    {XK_Undo,       '&', '8'},
                    125:    {XK_BackSpace,  'k', 'b'},
                    126:    {XK_Insert,     'k', 'I'},
                    127:    {XK_Delete,     'k', 'D'},
                    128:    {XK_Home,       'k', 'h'},
                    129:    {XK_End,        '@', '7'},
                    130:    {XK_Prior,      'k', 'P'},
                    131:    {XK_Next,       'k', 'N'},
                    132:    {XK_Print,      '%', '9'},
                    133:
                    134:    /* Keypad keys: */
                    135: #ifdef XK_KP_Left
                    136:    {XK_KP_Left,    'k', 'l'},
                    137:    {XK_KP_Right,   'k', 'r'},
                    138:    {XK_KP_Up,      'k', 'u'},
                    139:    {XK_KP_Down,    'k', 'd'},
                    140:    {XK_KP_Insert,  'k', 'I'},
                    141:    {XK_KP_Delete,  'k', 'D'},
                    142:    {XK_KP_Home,    'k', 'h'},
                    143:    {XK_KP_End,     '@', '7'},
                    144:    {XK_KP_Prior,   'k', 'P'},
                    145:    {XK_KP_Next,    'k', 'N'},
                    146: #endif
                    147:
                    148:    /* End of list marker: */
                    149:    {(KeySym)0,     0, 0}
                    150: };
                    151:
                    152: #define XtNboldColor       "boldColor"
                    153: #define XtCBoldColor       "BoldColor"
                    154: #define XtNitalicColor     "italicColor"
                    155: #define XtCItalicColor     "ItalicColor"
                    156: #define XtNunderlineColor  "underlineColor"
                    157: #define XtCUnderlineColor  "UnderlineColor"
                    158: #define XtNcursorColor     "cursorColor"
                    159: #define XtCCursorColor     "CursorColor"
                    160: #define XtNboldFont            "boldFont"
                    161: #define XtCBoldFont            "BoldFont"
                    162: #define XtNitalicFont      "italicFont"
                    163: #define XtCItalicFont      "ItalicFont"
                    164: #define XtNboldItalicFont  "boldItalicFont"
                    165: #define XtCBoldItalicFont  "BoldItalicFont"
                    166: #define XtNscrollbarWidth  "scrollbarWidth"
                    167: #define XtCScrollbarWidth  "ScrollbarWidth"
                    168: #define XtNmenuHeight      "menuHeight"
                    169: #define XtCMenuHeight      "MenuHeight"
                    170:
                    171: /* Resources for setting the foreground and background colors of menus */
                    172: #define XtNmenuBackground  "menuBackground"
                    173: #define XtCMenuBackground  "MenuBackground"
                    174: #define XtNmenuForeground  "menuForeground"
                    175: #define XtCMenuForeground  "MenuForeground"
                    176:
                    177: /* Resources for setting the foreground and background colors of scrollbars */
                    178: #define XtNscrollBackground    "scrollBackground"
                    179: #define XtCScrollBackground    "ScrollBackground"
                    180: #define XtNscrollForeground    "scrollForeground"
                    181: #define XtCScrollForeground    "ScrollForeground"
                    182:
                    183: /*
                    184:  * X Resources:
                    185:  */
                    186: static XtResource vim_resources[] =
                    187: {
                    188:    {
                    189:        XtNforeground,
                    190:        XtCForeground,
                    191:        XtRPixel,
                    192:        sizeof(Pixel),
                    193:        XtOffsetOf(Gui, norm_pixel),
                    194:        XtRString,
                    195:        XtDefaultForeground
                    196:    },
                    197:    {
                    198:        XtNbackground,
                    199:        XtCBackground,
                    200:        XtRPixel,
                    201:        sizeof(Pixel),
                    202:        XtOffsetOf(Gui, back_pixel),
                    203:        XtRString,
                    204:        XtDefaultBackground
                    205:    },
                    206:    {
                    207:        XtNboldColor,
                    208:        XtCBoldColor,
                    209:        XtRPixel,
                    210:        sizeof(Pixel),
                    211:        XtOffsetOf(Gui, bold_pixel),
                    212:        XtRString,
                    213:        XtDefaultForeground
                    214:    },
                    215:    {
                    216:        XtNitalicColor,
                    217:        XtCItalicColor,
                    218:        XtRPixel,
                    219:        sizeof(Pixel),
                    220:        XtOffsetOf(Gui, ital_pixel),
                    221:        XtRString,
                    222:        XtDefaultForeground
                    223:    },
                    224:    {
                    225:        XtNunderlineColor,
                    226:        XtCUnderlineColor,
                    227:        XtRPixel,
                    228:        sizeof(Pixel),
                    229:        XtOffsetOf(Gui, underline_pixel),
                    230:        XtRString,
                    231:        XtDefaultForeground
                    232:    },
                    233:    {
                    234:        XtNcursorColor,
                    235:        XtCCursorColor,
                    236:        XtRPixel,
                    237:        sizeof(Pixel),
                    238:        XtOffsetOf(Gui, cursor_pixel),
                    239:        XtRString,
                    240:        XtDefaultForeground
                    241:    },
                    242:    {
                    243:        XtNfont,
                    244:        XtCFont,
                    245:        XtRString,
                    246:        sizeof(String *),
                    247:        XtOffsetOf(Gui, dflt_font),
                    248:        XtRImmediate,
                    249:        XtDefaultFont
                    250:    },
                    251:    {
                    252:        XtNboldFont,
                    253:        XtCBoldFont,
                    254:        XtRString,
                    255:        sizeof(String *),
                    256:        XtOffsetOf(Gui, dflt_bold_fn),
                    257:        XtRImmediate,
                    258:        ""
                    259:    },
                    260:    {
                    261:        XtNitalicFont,
                    262:        XtCItalicFont,
                    263:        XtRString,
                    264:        sizeof(String *),
                    265:        XtOffsetOf(Gui, dflt_ital_fn),
                    266:        XtRImmediate,
                    267:        ""
                    268:    },
                    269:    {
                    270:        XtNboldItalicFont,
                    271:        XtCBoldItalicFont,
                    272:        XtRString,
                    273:        sizeof(String *),
                    274:        XtOffsetOf(Gui, dflt_boldital_fn),
                    275:        XtRImmediate,
                    276:        ""
                    277:    },
                    278:    {
                    279:        XtNgeometry,
                    280:        XtCGeometry,
                    281:        XtRString,
                    282:        sizeof(String *),
                    283:        XtOffsetOf(Gui, geom),
                    284:        XtRImmediate,
                    285:        ""
                    286:    },
                    287:    {
                    288:        XtNreverseVideo,
                    289:        XtCReverseVideo,
                    290:        XtRBool,
                    291:        sizeof(Bool),
                    292:        XtOffsetOf(Gui, rev_video),
                    293:        XtRImmediate,
                    294:        (XtPointer) False
                    295:    },
                    296:    {
                    297:        XtNborderWidth,
                    298:        XtCBorderWidth,
                    299:        XtRInt,
                    300:        sizeof(int),
                    301:        XtOffsetOf(Gui, border_width),
                    302:        XtRImmediate,
                    303:        (XtPointer) 2
                    304:    },
                    305:    {
                    306:        XtNscrollbarWidth,
                    307:        XtCScrollbarWidth,
                    308:        XtRInt,
                    309:        sizeof(int),
                    310:        XtOffsetOf(Gui, scrollbar_width),
                    311:        XtRImmediate,
                    312:        (XtPointer) SB_DEFAULT_WIDTH
                    313:    },
                    314:    {
                    315:        XtNmenuHeight,
                    316:        XtCMenuHeight,
                    317:        XtRInt,
                    318:        sizeof(int),
                    319:        XtOffsetOf(Gui, menu_height),
                    320:        XtRImmediate,
                    321:        (XtPointer) MENU_DEFAULT_HEIGHT
                    322:    },
                    323:    {
                    324:        XtNmenuForeground,
                    325:        XtCMenuForeground,
                    326:        XtRPixel,
                    327:        sizeof(Pixel),
                    328:        XtOffsetOf(Gui, menu_fg_pixel),
                    329:        XtRString,
                    330:        DFLT_MENU_FG_COLOR
                    331:    },
                    332:    {
                    333:        XtNmenuBackground,
                    334:        XtCMenuBackground,
                    335:        XtRPixel,
                    336:        sizeof(Pixel),
                    337:        XtOffsetOf(Gui, menu_bg_pixel),
                    338:        XtRString,
                    339:        DFLT_MENU_BG_COLOR
                    340:    },
                    341:    {
                    342:        XtNscrollForeground,
                    343:        XtCScrollForeground,
                    344:        XtRPixel,
                    345:        sizeof(Pixel),
                    346:        XtOffsetOf(Gui, scroll_fg_pixel),
                    347:        XtRString,
                    348:        DFLT_SCROLL_FG_COLOR
                    349:    },
                    350:    {
                    351:        XtNscrollBackground,
                    352:        XtCScrollBackground,
                    353:        XtRPixel,
                    354:        sizeof(Pixel),
                    355:        XtOffsetOf(Gui, scroll_bg_pixel),
                    356:        XtRString,
                    357:        DFLT_SCROLL_BG_COLOR
                    358:    },
                    359: };
                    360:
                    361: /*
                    362:  * This table holds all the X GUI command line options allowed.  This includes
                    363:  * the standard ones so that we can skip them when vim is started without the
                    364:  * GUI (but the GUI might start up later).
                    365:  * When changing this, also update doc/vim_gui.txt and the usage message!!!
                    366:  */
                    367: static XrmOptionDescRec cmdline_options[] =
                    368: {
                    369:    /* We handle these options ourselves */
                    370:    {"-bg",             ".background",      XrmoptionSepArg,    NULL},
                    371:    {"-background",     ".background",      XrmoptionSepArg,    NULL},
                    372:    {"-fg",             ".foreground",      XrmoptionSepArg,    NULL},
                    373:    {"-foreground",     ".foreground",      XrmoptionSepArg,    NULL},
                    374:    {"-bold",           ".boldColor",       XrmoptionSepArg,    NULL},
                    375:    {"-italic",         ".italicColor",     XrmoptionSepArg,    NULL},
                    376:    {"-ul",             ".underlineColor",  XrmoptionSepArg,    NULL},
                    377:    {"-underline",      ".underlineColor",  XrmoptionSepArg,    NULL},
                    378:    {"-cursor",         ".cursorColor",     XrmoptionSepArg,    NULL},
                    379:    {"-fn",             ".font",            XrmoptionSepArg,    NULL},
                    380:    {"-font",           ".font",            XrmoptionSepArg,    NULL},
                    381:    {"-boldfont",       ".boldFont",        XrmoptionSepArg,    NULL},
                    382:    {"-italicfont",     ".italicFont",      XrmoptionSepArg,    NULL},
                    383:    {"-geom",           ".geometry",        XrmoptionSepArg,    NULL},
                    384:    {"-geometry",       ".geometry",        XrmoptionSepArg,    NULL},
                    385:    {"-reverse",        "*reverseVideo",    XrmoptionNoArg,     "True"},
                    386:    {"-rv",             "*reverseVideo",    XrmoptionNoArg,     "True"},
                    387:    {"+reverse",        "*reverseVideo",    XrmoptionNoArg,     "False"},
                    388:    {"+rv",             "*reverseVideo",    XrmoptionNoArg,     "False"},
                    389:    {"-display",        ".display",         XrmoptionSepArg,    NULL},
                    390:    {"-iconic",         "*iconic",          XrmoptionNoArg,     "True"},
                    391:    {"-name",           ".name",            XrmoptionSepArg,    NULL},
                    392:    {"-bw",             ".borderWidth",     XrmoptionSepArg,    NULL},
                    393:    {"-borderwidth",    ".borderWidth",     XrmoptionSepArg,    NULL},
                    394:    {"-sw",             ".scrollbarWidth",  XrmoptionSepArg,    NULL},
                    395:    {"-scrollbarwidth", ".scrollbarWidth",  XrmoptionSepArg,    NULL},
                    396:    {"-mh",             ".menuHeight",      XrmoptionSepArg,    NULL},
                    397:    {"-menuheight",     ".menuHeight",      XrmoptionSepArg,    NULL},
                    398:    {"-xrm",            NULL,               XrmoptionResArg,    NULL}
                    399: };
                    400:
                    401: static int gui_argc = 0;
                    402: static char **gui_argv = NULL;
                    403:
                    404: /*
                    405:  * Call-back routines.
                    406:  */
                    407:
                    408:    void
                    409: gui_x11_timer_cb(timed_out, interval_id)
                    410:    XtPointer   timed_out;
                    411:    XtIntervalId *interval_id;
                    412: {
                    413:    *((int *)timed_out) = TRUE;
                    414: }
                    415:
                    416:    void
                    417: gui_x11_visibility_cb(w, dud, event, bool)
                    418:    Widget      w;
                    419:    XtPointer   dud;
                    420:    XEvent      *event;
                    421:    Boolean     *bool;
                    422: {
                    423:    if (event->type != VisibilityNotify)
                    424:        return;
                    425:
                    426:    gui.visibility = event->xvisibility.state;
                    427:
                    428:    /*
                    429:     * When we do an XCopyArea(), and the window is partially obscured, we want
                    430:     * to receive an event to tell us whether it worked or not.
                    431:     */
                    432:    XSetGraphicsExposures(gui.dpy, gui.text_gc,
                    433:        gui.visibility != VisibilityUnobscured);
                    434: }
                    435:
                    436:    void
                    437: gui_x11_expose_cb(w, dud, event, bool)
                    438:    Widget      w;
                    439:    XtPointer   dud;
                    440:    XEvent      *event;
                    441:    Boolean     *bool;
                    442: {
                    443:    XExposeEvent    *gevent;
                    444:
                    445:    if (event->type != Expose)
                    446:        return;
                    447:
                    448:    gevent = (XExposeEvent *)event;
                    449:    gui_redraw(gevent->x, gevent->y, gevent->width, gevent->height);
                    450:
                    451:    /* Clear the border areas if needed */
                    452:    if (gevent->x < FILL_X(0))
                    453:        XClearArea(gui.dpy, gui.wid, 0, 0, FILL_X(0), 0, False);
                    454:    if (gevent->y < FILL_Y(0))
                    455:        XClearArea(gui.dpy, gui.wid, 0, 0, 0, FILL_Y(0), False);
                    456:    if (gevent->x > FILL_X(Columns))
                    457:        XClearArea(gui.dpy, gui.wid, FILL_X(Columns), 0, 0, 0, False);
                    458:    if (gevent->y > FILL_Y(Rows))
                    459:        XClearArea(gui.dpy, gui.wid, 0, FILL_Y(Rows), 0, 0, False);
                    460:
                    461:    if (gui.selection.state != SELECT_CLEARED)
                    462:        gui_x11_redraw_selection(gevent->x, gevent->y, gevent->width,
                    463:                gevent->height);
                    464: }
                    465:
                    466:    void
                    467: gui_x11_resize_window_cb(w, dud, event, bool)
                    468:    Widget      w;
                    469:    XtPointer   dud;
                    470:    XEvent      *event;
                    471:    Boolean     *bool;
                    472: {
                    473:    if (event->type != ConfigureNotify)
                    474:        return;
                    475:
                    476:    gui_resize_window(event->xconfigure.width, event->xconfigure.height);
                    477:
                    478:    /* Make sure the border strips on the right and bottom get cleared. */
                    479:    XClearArea(gui.dpy, gui.wid,    FILL_X(Columns), 0, 0, 0, False);
                    480:    XClearArea(gui.dpy, gui.wid, 0, FILL_Y(Rows),       0, 0, False);
                    481: }
                    482:
                    483:    void
                    484: gui_x11_focus_change_cb(w, data, event, bool)
                    485:    Widget      w;
                    486:    XtPointer   data;
                    487:    XEvent      *event;
                    488:    Boolean     *bool;
                    489: {
                    490:    if (event->type == FocusIn)
                    491:        gui.in_focus = TRUE;
                    492:    else
                    493:        gui.in_focus = FALSE;
                    494:    if (gui.row == gui.cursor_row && gui.col == gui.cursor_col)
                    495:        INVALIDATE_CURSOR();
                    496:    gui_update_cursor();
                    497: }
                    498:
                    499:    void
                    500: gui_x11_key_hit_cb(w, dud, event, bool)
                    501:    Widget      w;
                    502:    XtPointer   dud;
                    503:    XEvent      *event;
                    504:    Boolean     *bool;
                    505: {
                    506:    XKeyPressedEvent    *ev_press;
                    507:    char_u  string[3], string2[3];
                    508:    KeySym  key_sym;
                    509:    int     num, i;
                    510:
                    511:    ev_press = (XKeyPressedEvent *)event;
                    512:
                    513:    num = XLookupString(ev_press, (char *)string, sizeof(string),
                    514:            &key_sym, NULL);
                    515:
                    516:    if (key_sym == XK_space)
                    517:        string[0] = ' ';        /* Otherwise Ctrl-Space doesn't work */
                    518:
                    519:    /* Check for Alt/Meta key (Mod1Mask) */
                    520:    if (num == 1 && (ev_press->state & Mod1Mask))
                    521:    {
                    522:        /*
                    523:         * Before we set the 8th bit, check to make sure the user doesn't
                    524:         * already have a mapping defined for this sequence. We determine this
                    525:         * by checking to see if the input would be the same without the
                    526:         * Alt/Meta key.
                    527:         */
                    528:        ev_press->state &= ~Mod1Mask;
                    529:        if (XLookupString(ev_press, (char *)string2, sizeof(string2),
                    530:                &key_sym, NULL) == 1 && string[0] == string2[0])
                    531:            string[0] |= 0x80;
                    532:        ev_press->state |= Mod1Mask;
                    533:    }
                    534:
                    535: #if 0
                    536:    if (num == 1 && string[0] == CSI) /* this doesn't work yet */
                    537:    {
                    538:        string[1] = CSI;
                    539:        string[2] = CSI;
                    540:        num = 3;
                    541:    }
                    542: #endif
                    543:
                    544:    /* Check for special keys, making sure BS and DEL are recognised. */
                    545:    if (num == 0 || key_sym == XK_BackSpace || key_sym == XK_Delete)
                    546:    {
                    547:        for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
                    548:        {
                    549:            if (special_keys[i].key_sym == key_sym)
                    550:            {
                    551:                string[0] = CSI;
                    552:                string[1] = special_keys[i].vim_code0;
                    553:                string[2] = special_keys[i].vim_code1;
                    554:                num = 3;
                    555:            }
                    556:        }
                    557:    }
                    558:
                    559:    /* Unrecognised key */
                    560:    if (num == 0)
                    561:        return;
                    562:
                    563:    /* Special keys (and a few others) may have modifiers */
                    564:    if (num == 3 || key_sym == XK_space || key_sym == XK_Tab
                    565:        || key_sym == XK_Return || key_sym == XK_Linefeed
                    566:        || key_sym == XK_Escape)
                    567:    {
                    568:        string2[0] = CSI;
                    569:        string2[1] = KS_MODIFIER;
                    570:        string2[2] = 0;
                    571:        if (ev_press->state & ShiftMask)
                    572:            string2[2] |= MOD_MASK_SHIFT;
                    573:        if (ev_press->state & ControlMask)
                    574:            string2[2] |= MOD_MASK_CTRL;
                    575:        if (ev_press->state & Mod1Mask)
                    576:            string2[2] |= MOD_MASK_ALT;
                    577:        if (string2[2] != 0)
                    578:            add_to_input_buf(string2, 3);
                    579:    }
                    580:    if (num == 1 && string[0] == Ctrl('C'))
                    581:    {
                    582:        trash_input_buf();
                    583:        got_int = TRUE;
                    584:    }
                    585:    add_to_input_buf(string, num);
                    586: }
                    587:
                    588:    void
                    589: gui_x11_mouse_cb(w, dud, event, bool)
                    590:    Widget      w;
                    591:    XtPointer   dud;
                    592:    XEvent      *event;
                    593:    Boolean     *bool;
                    594: {
                    595:    static XtIntervalId timer = (XtIntervalId)0;
                    596:    static int  timed_out = TRUE;
                    597:
                    598:    int         button;
                    599:    int         repeated_click = FALSE;
                    600:    int         x, y;
                    601:    int_u       x_modifiers;
                    602:    int_u       vim_modifiers;
                    603:    int         checkfor;
                    604:
                    605:    if (event->type == MotionNotify)
                    606:    {
                    607:        x = event->xmotion.x;
                    608:        y = event->xmotion.y;
                    609:        button = MOUSE_DRAG;
                    610:        x_modifiers = event->xmotion.state;
                    611:    }
                    612:    else
                    613:    {
                    614:        x = event->xbutton.x;
                    615:        y = event->xbutton.y;
                    616:        if (event->type == ButtonPress)
                    617:        {
                    618:            /* Handle multiple clicks */
                    619:            if (!timed_out)
                    620:            {
                    621:                XtRemoveTimeOut(timer);
                    622:                repeated_click = TRUE;
                    623:            }
                    624:            timed_out = FALSE;
                    625:            timer = XtAppAddTimeOut(app_context, (long_u)p_mouset,
                    626:                        gui_x11_timer_cb, &timed_out);
                    627:            switch (event->xbutton.button)
                    628:            {
                    629:                case Button1:   button = MOUSE_LEFT;    break;
                    630:                case Button2:   button = MOUSE_MIDDLE;  break;
                    631:                case Button3:   button = MOUSE_RIGHT;   break;
                    632:                default:
                    633:                    return;     /* Unknown button */
                    634:            }
                    635:        }
                    636:        else if (event->type == ButtonRelease)
                    637:            button = MOUSE_RELEASE;
                    638:        else
                    639:            return;     /* Unknown mouse event type */
                    640:
                    641:        x_modifiers = event->xbutton.state;
                    642:    }
                    643:
                    644:    vim_modifiers = 0x0;
                    645:    if (x_modifiers & ShiftMask)
                    646:        vim_modifiers |= MOUSE_SHIFT;
                    647:    if (x_modifiers & ControlMask)
                    648:        vim_modifiers |= MOUSE_CTRL;
                    649:    if (x_modifiers & Mod1Mask)     /* Alt or Meta key */
                    650:        vim_modifiers |= MOUSE_ALT;
                    651:
                    652:    /* If an x11 selection is in progress, finish it */
                    653:    if (gui.selection.state == SELECT_IN_PROGRESS)
                    654:    {
                    655:        gui_x11_process_selection(button, x, y, repeated_click, vim_modifiers);
                    656:        return;
                    657:    }
                    658:
                    659:    /* Determine which mouse settings to look for based on the current mode */
                    660:    switch (State)
                    661:    {
                    662:        case NORMAL_BUSY:
                    663:        case NORMAL:        checkfor = MOUSE_NORMAL;    break;
                    664:        case VISUAL:        checkfor = MOUSE_VISUAL;    break;
                    665:        case REPLACE:
                    666:        case INSERT:        checkfor = MOUSE_INSERT;    break;
                    667:        case HITRETURN:     checkfor = MOUSE_RETURN;    break;
                    668:
                    669:            /*
                    670:             * On the command line, use the X11 selection on all lines but the
                    671:             * command line.
                    672:             */
                    673:        case CMDLINE:
                    674:            if (Y_2_ROW(y) < cmdline_row)
                    675:                checkfor = ' ';
                    676:            else
                    677:                checkfor = MOUSE_COMMAND;
                    678:            break;
                    679:
                    680:        default:
                    681:            checkfor = ' ';
                    682:            break;
                    683:    };
                    684:    /*
                    685:     * Allow selection of text in the command line in "normal" modes.
                    686:     */
                    687:    if ((State == NORMAL || State == NORMAL_BUSY ||
                    688:                                       State == INSERT || State == REPLACE) &&
                    689:                                            Y_2_ROW(y) >= gui.num_rows - p_ch)
                    690:        checkfor = ' ';
                    691:
                    692:    /*
                    693:     * If the mouse settings say to not use the mouse, use the X11 selection.
                    694:     * But if Visual is active, assume that only the Visual area will be
                    695:     * selected.
                    696:     */
                    697:    if (!mouse_has(checkfor) && !VIsual_active)
                    698:    {
                    699:        /* If the selection is done, allow the right button to extend it */
                    700:        if (gui.selection.state == SELECT_DONE && button == MOUSE_RIGHT)
                    701:        {
                    702:            gui_x11_process_selection(button, x, y, repeated_click,
                    703:                    vim_modifiers);
                    704:            return;
                    705:        }
                    706:
                    707:        /* Allow the left button to start the selection */
                    708:        else if (button == MOUSE_LEFT)
                    709:        {
                    710:            gui_x11_start_selection(button, x, y, repeated_click,
                    711:                    vim_modifiers);
                    712:            return;
                    713:        }
                    714:    }
                    715:
                    716:    if (gui.selection.state != SELECT_CLEARED)
                    717:        gui_mch_clear_selection();
                    718:    gui_send_mouse_event(button, x, y, repeated_click, vim_modifiers);
                    719: }
                    720:
                    721: /*
                    722:  * End of call-back routines
                    723:  */
                    724:
                    725: /*
                    726:  * Parse the GUI related command-line arguments.  Any arguments used are
                    727:  * deleted from argv, and *argc is decremented accordingly.  This is called
                    728:  * when vim is started, whether or not the GUI has been started.
                    729:  */
                    730:    void
                    731: gui_mch_prepare(argc, argv)
                    732:    int     *argc;
                    733:    char    **argv;
                    734: {
                    735:    int     arg;
                    736:    int     i;
                    737:
                    738:    /*
                    739:     * Move all the entries in argv which are relevant to X into gui_argv.
                    740:     */
                    741:    gui_argc = 0;
                    742:    gui_argv = (char **)lalloc(*argc * sizeof(char *), FALSE);
                    743:    if (gui_argv == NULL)
                    744:        return;
                    745:    gui_argv[gui_argc++] = argv[0];
                    746:    arg = 1;
                    747:    while (arg < *argc)
                    748:    {
                    749:        /* Look for argv[arg] in cmdline_options[] table */
                    750:        for (i = 0; i < XtNumber(cmdline_options); i++)
                    751:            if (strcmp(argv[arg], cmdline_options[i].option) == 0)
                    752:                break;
                    753:
                    754:        if (i < XtNumber(cmdline_options))
                    755:        {
                    756:            /* Found match in table, so move it into gui_argv */
                    757:            gui_argv[gui_argc++] = argv[arg];
                    758:            if (--*argc > arg)
                    759:            {
                    760:                vim_memmove(&argv[arg], &argv[arg + 1], (*argc - arg)
                    761:                                                    * sizeof(char *));
                    762:                if (cmdline_options[i].argKind != XrmoptionNoArg)
                    763:                {
                    764:                    /* Move the options argument as well */
                    765:                    gui_argv[gui_argc++] = argv[arg];
                    766:                    if (--*argc > arg)
                    767:                        vim_memmove(&argv[arg], &argv[arg + 1], (*argc - arg)
                    768:                                                            * sizeof(char *));
                    769:                }
                    770:            }
                    771:        }
                    772:        else
                    773:            arg++;
                    774:    }
                    775: }
                    776:
                    777: /*
                    778:  * Initialise the X GUI.  Create all the windows, set up all the call-backs
                    779:  * etc.
                    780:  */
                    781:    int
                    782: gui_mch_init()
                    783: {
                    784:    Widget      AppShell;
                    785:    long_u      gc_mask;
                    786:    XGCValues   gc_vals;
                    787:    Pixel       tmp_pixel;
                    788:    int         x, y, mask;
                    789:    unsigned    w, h;
                    790:
                    791:    XtToolkitInitialize();
                    792:    app_context = XtCreateApplicationContext();
                    793:    gui.dpy = XtOpenDisplay(app_context, 0, VIM_NAME, VIM_CLASS,
                    794:        cmdline_options, XtNumber(cmdline_options),
                    795: #ifndef XtSpecificationRelease
                    796:        (Cardinal*)&gui_argc, gui_argv);
                    797: #else
                    798: #if XtSpecificationRelease == 4
                    799:        (Cardinal*)&gui_argc, gui_argv);
                    800: #else
                    801:        &gui_argc, gui_argv);
                    802: #endif
                    803: #endif
                    804:
                    805:    vim_free(gui_argv);
                    806:
                    807:    if (gui.dpy == NULL)
                    808:    {
                    809:        x = full_screen;
                    810:        full_screen = FALSE;            /* use fprintf() */
                    811:        EMSG("cannot open display");
                    812:        full_screen = x;
                    813:        return FAIL;
                    814:    }
                    815:
                    816:    /* Uncomment this to enable synchronous mode for debugging */
                    817:    /* XSynchronize(gui.dpy, True); */
                    818:
                    819:    /*
                    820:     * So converters work.
                    821:     */
                    822:    XtInitializeWidgetClass(applicationShellWidgetClass);
                    823:    XtInitializeWidgetClass(topLevelShellWidgetClass);
                    824:
                    825:    /*
                    826:     * The applicationShell is created as an unrealized
                    827:     * parent for multiple topLevelShells.  The topLevelShells
                    828:     * are created as popup children of the applicationShell.
                    829:     * This is a recommendation of Paul Asente & Ralph Swick in
                    830:     * _X_Window_System_Toolkit_ p. 677.
                    831:     */
                    832:    AppShell = XtVaAppCreateShell(VIM_NAME, VIM_CLASS,
                    833:            applicationShellWidgetClass, gui.dpy,
                    834:            NULL);
                    835:
                    836:    /*
                    837:     * Get the application resources
                    838:     */
                    839:    XtVaGetApplicationResources(AppShell, &gui,
                    840:        vim_resources, XtNumber(vim_resources), NULL);
                    841:
                    842:    /*
                    843:     * Check validity of resources
                    844:     */
                    845:    if (gui.border_width < 0)
                    846:        gui.border_width = 0;
                    847:
                    848:    /* For reverse video, swap foreground and background colours */
                    849:    if (gui.rev_video)
                    850:    {
                    851:        tmp_pixel = gui.norm_pixel;
                    852:        gui.norm_pixel = gui.back_pixel;
                    853:        gui.back_pixel = tmp_pixel;
                    854:    }
                    855:
                    856:    /* Create shell widget to put vim in */
                    857:    vimShell = XtVaCreatePopupShell("VIM",
                    858:        topLevelShellWidgetClass, AppShell,
                    859:        XtNborderWidth, 0,
                    860:        NULL);
                    861:
                    862:    /*
                    863:     * Check that none of the colours are the same as the background color
                    864:     */
                    865:    if (gui.norm_pixel == gui.back_pixel)
                    866:    {
                    867:        gui.norm_pixel = gui_x11_get_color((char_u *)"White");
                    868:        if (gui.norm_pixel == gui.back_pixel)
                    869:            gui.norm_pixel = gui_x11_get_color((char_u *)"Black");
                    870:    }
                    871:    if (gui.bold_pixel == gui.back_pixel)
                    872:        gui.bold_pixel = gui.norm_pixel;
                    873:    if (gui.ital_pixel == gui.back_pixel)
                    874:        gui.ital_pixel = gui.norm_pixel;
                    875:    if (gui.underline_pixel == gui.back_pixel)
                    876:        gui.underline_pixel = gui.norm_pixel;
                    877:    if (gui.cursor_pixel == gui.back_pixel)
                    878:        gui.cursor_pixel = gui.norm_pixel;
                    879:
                    880:    /*
                    881:     * Set up the GCs.  The font attributes will be set in gui_init_font().
                    882:     */
                    883:
                    884:    gc_mask = GCForeground | GCBackground;
                    885:    gc_vals.foreground = gui.norm_pixel;
                    886:    gc_vals.background = gui.back_pixel;
                    887:    gui.text_gc = XCreateGC(gui.dpy, DefaultRootWindow(gui.dpy), gc_mask,
                    888:            &gc_vals);
                    889:
                    890:    gc_vals.foreground = gui.back_pixel;
                    891:    gc_vals.background = gui.norm_pixel;
                    892:    gui.back_gc = XCreateGC(gui.dpy, DefaultRootWindow(gui.dpy), gc_mask,
                    893:            &gc_vals);
                    894:
                    895:    gc_mask |= GCFunction;
                    896:    gc_vals.foreground = gui.norm_pixel ^ gui.back_pixel;
                    897:    gc_vals.background = gui.norm_pixel ^ gui.back_pixel;
                    898:    gc_vals.function   = GXxor;
                    899:    gui.invert_gc = XCreateGC(gui.dpy, DefaultRootWindow(gui.dpy), gc_mask,
                    900:            &gc_vals);
                    901:
                    902:    gui.visibility = VisibilityUnobscured;
                    903:    gui.selection.atom = XInternAtom(gui.dpy, "VIM_SELECTION", False);
                    904:
                    905:    /*
                    906:     * Set up the fonts.  This call will also set the window to the correct
                    907:     * size for the used font.
                    908:     */
                    909:    gui.norm_font = NULL;
                    910:    gui.bold_font = NULL;
                    911:    gui.ital_font = NULL;
                    912:    gui.boldital_font = NULL;
                    913:    if (gui_init_font() == FAIL)
                    914:        return FAIL;
                    915:
                    916:    /* Now adapt the supplied(?) geometry-settings */
                    917:    /* Added by Kjetil Jacobsen <kjetilja@stud.cs.uit.no> */
                    918:    if (gui.geom != NULL && *gui.geom != NUL)
                    919:    {
                    920:        mask = XParseGeometry((char *)gui.geom, &x, &y, &w, &h);
                    921:        if (mask & WidthValue)
                    922:            Columns = w;
                    923:        if (mask & HeightValue)
                    924:            Rows = h;
                    925:        /*
                    926:         * Set the (x,y) position of the main window only if specified in the
                    927:         * users geometry, so we get good defaults when they don't. This needs
                    928:         * to be done before the shell is popped up.
                    929:         */
                    930:        if (mask & (XValue|YValue))
                    931:            XtVaSetValues(vimShell, XtNgeometry, gui.geom, NULL);
                    932:    }
                    933:    gui.num_cols = Columns;
                    934:    gui.num_rows = Rows;
                    935:    gui_reset_scroll_region();
                    936:
                    937:    gui_mch_create_widgets();
                    938:
                    939:    /* Configure the desired scrollbars */
                    940:    gui_init_which_components(NULL);
                    941:
                    942:    /* Actually open the window */
                    943:    XtPopup(vimShell, XtGrabNone);
                    944:
                    945:    gui_mch_set_winsize();
                    946:
                    947:    gui.wid = gui_mch_get_wid();
                    948:
                    949:    /* Add a callback for the Close item on the window managers menu */
                    950:    Atom_WM_DELETE_WINDOW = XInternAtom(gui.dpy, "WM_DELETE_WINDOW", False);
                    951:    XSetWMProtocols(gui.dpy, XtWindow(vimShell), &Atom_WM_DELETE_WINDOW, 1);
                    952:    XtAddEventHandler(vimShell, NoEventMask, True, gui_x11_wm_protocol_handler,
                    953:                                                             NULL);
                    954:
                    955: #ifdef ENABLE_EDITRES
                    956:    /*
                    957:     * Enable editres protocol (see editres(1))
                    958:     * Usually will need to add -lXmu to the linker line as well.
                    959:     */
                    960:    {
                    961:        extern void _XEditResCheckMessages();
                    962:        XtAddEventHandler(vimShell, 0, True, _XEditResCheckMessages,
                    963:                (XtPointer)NULL);
                    964:    }
                    965: #endif
                    966:
                    967:    return OK;
                    968: }
                    969:
                    970:    void
                    971: gui_mch_exit()
                    972: {
                    973:    XtCloseDisplay(gui.dpy);
                    974: }
                    975:
                    976: /*
                    977:  * While unmanaging and re-managing scrollbars etc, we don't want the resize
                    978:  * callback to be called, so this function is used to disable this callback,
                    979:  * and then re-enable it afterwards.  XSync() makes sure we don't register the
                    980:  * callback before the server has finished processing any resize events we have
                    981:  * created, otherwise we can get in a loop where the window flashes between two
                    982:  * sizes, since resize_window_cb() calls set_winsize().
                    983:  */
                    984:    void
                    985: gui_x11_use_resize_callback(widget, enabled)
                    986:    Widget  widget;
                    987:    int     enabled;
                    988: {
                    989:    if (enabled)
                    990:    {
                    991:        XSync(gui.dpy, False);
                    992:        XtAddEventHandler(widget, StructureNotifyMask, FALSE,
                    993:            gui_x11_resize_window_cb, (XtPointer)0);
                    994:        XtAddEventHandler(widget, ExposureMask, FALSE, gui_x11_expose_cb,
                    995:            (XtPointer)0);
                    996:    }
                    997:    else
                    998:    {
                    999:        XtRemoveEventHandler(widget, StructureNotifyMask, FALSE,
                   1000:            gui_x11_resize_window_cb, (XtPointer)0);
                   1001:        XtRemoveEventHandler(widget, ExposureMask, FALSE, gui_x11_expose_cb,
                   1002:            (XtPointer)0);
                   1003:        XSync(gui.dpy, False);
                   1004:    }
                   1005: }
                   1006:
                   1007: /*
                   1008:  * Initialise vim to use the font with the given name. Return FAIL if the font
                   1009:  * could not be loaded, OK otherwise.
                   1010:  */
                   1011:    int
                   1012: gui_mch_init_font(font_name)
                   1013:    char_u      *font_name;
                   1014: {
                   1015:    XFontStruct *font = NULL;
                   1016:
                   1017:    if (font_name == NULL)
                   1018:    {
                   1019:        /*
                   1020:         * If none of the fonts in 'font' could be loaded, try the one set in
                   1021:         * the X resource, and finally just try using DFLT_FONT, which will
                   1022:         * hopefully always be there.
                   1023:         */
                   1024:        font = XLoadQueryFont(gui.dpy, (char *)gui.dflt_font);
                   1025:        if (font == NULL)
                   1026:            font_name = (char_u *)DFLT_FONT;
                   1027:        font_name = (char_u *)DFLT_FONT;
                   1028:    }
                   1029:    if (font == NULL)
                   1030:        font = XLoadQueryFont(gui.dpy, (char *)font_name);
                   1031:    if (font == NULL)
                   1032:        return FAIL;
                   1033:    if (font->max_bounds.width != font->min_bounds.width)
                   1034:    {
                   1035:        sprintf((char *)IObuff, "Font \"%s\" is not fixed-width",
                   1036:                                                           (char *)font_name);
                   1037:        emsg(IObuff);
                   1038:        XFreeFont(gui.dpy, font);
                   1039:        return FAIL;
                   1040:    }
                   1041:    if (gui.norm_font != NULL)
                   1042:        XFreeFont(gui.dpy, gui.norm_font);
                   1043:    gui.norm_font = font;
                   1044:    gui.char_width = font->max_bounds.width;
                   1045:    gui.char_height = font->ascent + font->descent;
                   1046:    gui.char_ascent = font->ascent;
                   1047:
                   1048: #ifdef DEBUG
                   1049:    printf("Font Information for '%s':\n", font_name);
                   1050:    printf("  w = %d, h = %d, ascent = %d, descent = %d\n", gui.char_width,
                   1051:           gui.char_height, gui.char_ascent, font->descent);
                   1052:    printf("  max ascent = %d, max descent = %d, max h = %d\n",
                   1053:           font->max_bounds.ascent, font->max_bounds.descent,
                   1054:           font->max_bounds.ascent + font->max_bounds.descent);
                   1055:    printf("  min lbearing = %d, min rbearing = %d\n",
                   1056:           font->min_bounds.lbearing, font->min_bounds.rbearing);
                   1057:    printf("  max lbearing = %d, max rbearing = %d\n",
                   1058:           font->max_bounds.lbearing, font->max_bounds.rbearing);
                   1059:    printf("  leftink = %d, rightink = %d\n",
                   1060:           (font->min_bounds.lbearing < 0),
                   1061:           (font->max_bounds.rbearing > gui.char_width));
                   1062:    printf("\n");
                   1063: #endif
                   1064:
                   1065:    /*
                   1066:     * Try to load other fonts for bold, italic, and bold-italic.
                   1067:     * We should also try to work out what font to use for these when they are
                   1068:     * not specified by X resources, but we don't yet.
                   1069:     */
                   1070:    if (gui.dflt_bold_fn != NULL && *gui.dflt_bold_fn != NUL)
                   1071:        gui.bold_font = XLoadQueryFont(gui.dpy, (char *)gui.dflt_bold_fn);
                   1072:    if (gui.dflt_ital_fn != NULL && *gui.dflt_ital_fn != NUL)
                   1073:        gui.ital_font = XLoadQueryFont(gui.dpy, (char *)gui.dflt_ital_fn);
                   1074:    if (gui.dflt_boldital_fn != NULL && *gui.dflt_boldital_fn != NUL)
                   1075:        gui.boldital_font = XLoadQueryFont(gui.dpy, (char *)gui.dflt_boldital_fn);
                   1076:
                   1077:    /* Must set the appropriate fonts for all the GCs */
                   1078:    gui_x11_set_font(gui.text_gc, gui.norm_font->fid);
                   1079:    gui_x11_set_font(gui.back_gc, gui.norm_font->fid);
                   1080:
                   1081:    /*
                   1082:     * Set the window sizes if the window is already visible.
                   1083:     */
                   1084:    if (vimShell != (Widget)NULL && XtIsRealized(vimShell))
                   1085:    {
                   1086:        WIN     *wp;
                   1087:
                   1088:        gui_mch_set_winsize();
                   1089:
                   1090:        /* Force the scrollbar heights to get updated when a font is changed */
                   1091:        if (gui.which_scrollbars[SB_LEFT])
                   1092:        {
                   1093:            for (wp = firstwin; wp; wp = wp->w_next)
                   1094:                wp->w_scrollbar.update[SB_LEFT] = SB_UPDATE_HEIGHT;
                   1095:            gui_mch_update_scrollbars(SB_UPDATE_HEIGHT, SB_LEFT);
                   1096:        }
                   1097:        if (gui.which_scrollbars[SB_RIGHT])
                   1098:        {
                   1099:            for (wp = firstwin; wp; wp = wp->w_next)
                   1100:                wp->w_scrollbar.update[SB_RIGHT] = SB_UPDATE_HEIGHT;
                   1101:            gui_mch_update_scrollbars(SB_UPDATE_HEIGHT, SB_RIGHT);
                   1102:        }
                   1103:    }
                   1104:
                   1105:    return OK;
                   1106: }
                   1107:
                   1108: /*
                   1109:  * Return OK if the key with the termcap name "name" is supported.
                   1110:  */
                   1111:    int
                   1112: gui_mch_haskey(name)
                   1113:    char_u  *name;
                   1114: {
                   1115:    int i;
                   1116:
                   1117:    for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
                   1118:        if (name[0] == special_keys[i].vim_code0 &&
                   1119:                                         name[1] == special_keys[i].vim_code1)
                   1120:            return OK;
                   1121:    return FAIL;
                   1122: }
                   1123:
                   1124: /*
                   1125:  * Return the text window-id and display.  Only required for X-based GUI's
                   1126:  */
                   1127:    int
                   1128: gui_get_x11_windis(win, dis)
                   1129:    Window  *win;
                   1130:    Display **dis;
                   1131: {
                   1132:    *win = XtWindow(vimShell);
                   1133:    *dis = gui.dpy;
                   1134:    return OK;
                   1135: }
                   1136:
                   1137:    void
                   1138: gui_mch_beep()
                   1139: {
                   1140:    XBell(gui.dpy, 0);
                   1141: }
                   1142:
                   1143:    void
                   1144: gui_mch_flash()
                   1145: {
                   1146:    /* Do a visual beep by reversing the foreground and background colors */
                   1147:    XFillRectangle(gui.dpy, gui.wid, gui.invert_gc, 0, 0,
                   1148:            FILL_X(Columns) + gui.border_offset,
                   1149:            FILL_Y(Rows) + gui.border_offset);
                   1150:    XSync(gui.dpy, False);
                   1151:    mch_delay(20L, TRUE);       /* wait 1/50 of a second */
                   1152:    XFillRectangle(gui.dpy, gui.wid, gui.invert_gc, 0, 0,
                   1153:            FILL_X(Columns) + gui.border_offset,
                   1154:            FILL_Y(Rows) + gui.border_offset);
                   1155: }
                   1156:
                   1157: /*
                   1158:  * Iconify the GUI window.
                   1159:  */
                   1160:    void
                   1161: gui_mch_iconify()
                   1162: {
                   1163:    XIconifyWindow(gui.dpy, XtWindow(vimShell), DefaultScreen(gui.dpy));
                   1164: }
                   1165:
                   1166: /*
                   1167:  * Return the Pixel value (color) for the given color name.  This routine was
                   1168:  * pretty much taken from example code in the Silicon Graphics OSF/Motif
                   1169:  * Programmer's Guide.
                   1170:  */
                   1171:    static Pixel
                   1172: gui_x11_get_color(name)
                   1173:    char_u *name;
                   1174: {
                   1175:    XrmValue    from, to;
                   1176:
                   1177:    from.size = STRLEN(name) + 1;
                   1178:    if (from.size < sizeof(String))
                   1179:        from.size = sizeof(String);
                   1180:    from.addr = (char *)name;
                   1181:    to.addr = NULL;
                   1182:    XtConvert(vimShell, XtRString, &from, XtRPixel, &to);
                   1183:    if (to.addr != NULL)
                   1184:        return (Pixel) *((Pixel *)to.addr);
                   1185:    else
                   1186:        return (Pixel)NULL;
                   1187: }
                   1188:
                   1189: /*
                   1190:  * Set the current text font (gc should be either gui.text_gc or gui.back_gc)
                   1191:  */
                   1192:    static void
                   1193: gui_x11_set_font(gc, fid)
                   1194:    GC      gc;
                   1195:    Font    fid;
                   1196: {
                   1197:    static Font prev_text_fid = (Font) -1;
                   1198:    static Font prev_back_fid = (Font) -1;
                   1199:
                   1200:    if (gc == gui.text_gc && fid != prev_text_fid)
                   1201:    {
                   1202:        XSetFont(gui.dpy, gc, fid);
                   1203:        prev_text_fid = fid;
                   1204:    }
                   1205:    else if (gc == gui.back_gc && fid != prev_back_fid)
                   1206:    {
                   1207:        XSetFont(gui.dpy, gc, fid);
                   1208:        prev_back_fid = fid;
                   1209:    }
                   1210: }
                   1211:
                   1212: /*
                   1213:  * Set the current text color (gc should be either gui.text_gc or gui.back_gc)
                   1214:  */
                   1215:    static void
                   1216: gui_x11_set_color(gc, pixel)
                   1217:    GC      gc;
                   1218:    Pixel   pixel;
                   1219: {
                   1220:    static Pixel prev_text_pixel = (Pixel) -1;
                   1221:    static Pixel prev_back_pixel = (Pixel) -1;
                   1222:
                   1223:    if (gc == gui.text_gc && pixel != prev_text_pixel)
                   1224:    {
                   1225:        XSetForeground(gui.dpy, gc, pixel);
                   1226:        prev_text_pixel = pixel;
                   1227:    }
                   1228:    else if (gc == gui.back_gc && pixel != prev_back_pixel)
                   1229:    {
                   1230:        XSetBackground(gui.dpy, gc, pixel);
                   1231:        prev_back_pixel = pixel;
                   1232:    }
                   1233: }
                   1234:
                   1235: /*
                   1236:  * Draw the cursor.
                   1237:  */
                   1238:    void
                   1239: gui_mch_draw_cursor()
                   1240: {
                   1241:    /* Only write to the screen after LinePointers[] has been initialized */
                   1242:    if (screen_cleared && NextScreen != NULL)
                   1243:    {
                   1244:        /* Clear the selection if we are about to write over it */
                   1245:        if (gui.selection.state == SELECT_DONE
                   1246:                && gui.row >= gui.selection.start.lnum
                   1247:                && gui.row <= gui.selection.end.lnum)
                   1248:            gui_mch_clear_selection();
                   1249:
                   1250:        if (gui.row < screen_Rows && gui.col < screen_Columns)
                   1251:            gui_mch_outstr_nowrap(LinePointers[gui.row] + gui.col,
                   1252:                                                              1, FALSE, TRUE);
                   1253:        if (!gui.in_focus)
                   1254:        {
                   1255:            gui_x11_set_color(gui.text_gc, gui.cursor_pixel);
                   1256:            XDrawRectangle(gui.dpy, gui.wid, gui.text_gc, FILL_X(gui.col),
                   1257:                    FILL_Y(gui.row), gui.char_width - 1, gui.char_height - 1);
                   1258:        }
                   1259:    }
                   1260: }
                   1261:
                   1262: /*
                   1263:  * Catch up with any queued X events.  This may put keyboard input into the
                   1264:  * input buffer, call resize call-backs, trigger timers etc.  If there is
                   1265:  * nothing in the X event queue (& no timers pending), then we return
                   1266:  * immediately.
                   1267:  */
                   1268:    void
                   1269: gui_mch_update()
                   1270: {
                   1271:    while(XtAppPending(app_context) && !is_input_buf_full())
                   1272:        XtAppProcessEvent(app_context, XtIMAll);
                   1273: }
                   1274:
                   1275: /*
                   1276:  * The main GUI input routine. Waits for a character from the keyboard.
                   1277:  * wtime == -1     Wait forever.
                   1278:  * wtime == 0      Don't wait.
                   1279:  * wtime > 0       Wait wtime milliseconds for a character.
                   1280:  * Returns OK if a character was found to be available within the given time,
                   1281:  * or FAIL otherwise.
                   1282:  */
                   1283:    int
                   1284: gui_mch_wait_for_chars(wtime)
                   1285:    int     wtime;
                   1286: {
                   1287:    XtIntervalId    timer = (XtIntervalId)0;
                   1288:    XtIntervalId    updatescript_timer = (XtIntervalId)0;
                   1289:    /*
                   1290:     * Make these static, in case gui_x11_timer_cb is called after leaving
                   1291:     * this function (otherwise a random value on the stack may be changed).
                   1292:     */
                   1293:    static int      timed_out;
                   1294:    static int      do_updatescript;
                   1295:
                   1296:    timed_out = FALSE;
                   1297:    do_updatescript = FALSE;
                   1298:
                   1299:    /*
                   1300:     * If we're going to wait a bit, update the menus for the current State.
                   1301:     */
                   1302:    if (wtime != 0)
                   1303:        gui_x11_update_menus(0);
                   1304:    gui_mch_update();
                   1305:    if (!is_input_buf_empty())  /* Got char, return immediately */
                   1306:        return OK;
                   1307:    else if (wtime == 0)        /* Don't wait for char */
                   1308:        return FAIL;
                   1309:    else if (wtime > 0)
                   1310:    {
                   1311:        timer = XtAppAddTimeOut(app_context, (long_u)wtime, gui_x11_timer_cb,
                   1312:            &timed_out);
                   1313:    }
                   1314:    else
                   1315:    {
                   1316:        /* We are waiting for ever, so update swap files after p_ut msec's */
                   1317:        updatescript_timer = XtAppAddTimeOut(app_context, (long_u)p_ut,
                   1318:                                          gui_x11_timer_cb, &do_updatescript);
                   1319:    }
                   1320:
                   1321:    while (!timed_out)
                   1322:    {
                   1323:        /*
                   1324:         * Don't use gui_mch_update() because then we will spin-lock until a
                   1325:         * char arrives, instead we use XtAppProcessEvent() to hang until an
                   1326:         * event arrives.  No need to check for input_buf_full because we are
                   1327:         * returning as soon as it contains a single char.  Note that
                   1328:         * XtAppNextEvent() may not be used because it will not return after a
                   1329:         * timer event has arrived -- webb
                   1330:         */
                   1331:        XtAppProcessEvent(app_context, XtIMAll);
                   1332:
                   1333:        /*
                   1334:         * If no characters arrive within 'updatetime' milli-seconds, flush all
                   1335:         * the swap files to disk.
                   1336:         */
                   1337:        if (do_updatescript)
                   1338:        {
                   1339:            updatescript(0);
                   1340:            do_updatescript = FALSE;
                   1341:            updatescript_timer = (XtIntervalId)0;
                   1342:        }
                   1343:        if (!is_input_buf_empty())
                   1344:        {
                   1345:            if (timer != (XtIntervalId)0 && !timed_out)
                   1346:                XtRemoveTimeOut(timer);
                   1347:            if (updatescript_timer != (XtIntervalId)0 && !do_updatescript)
                   1348:                XtRemoveTimeOut(updatescript_timer);
                   1349:            return OK;
                   1350:        }
                   1351:    }
                   1352:    return FAIL;
                   1353: }
                   1354:
                   1355: /*
                   1356:  * Output routines.
                   1357:  */
                   1358:
                   1359: /* Flush any output to the screen */
                   1360:    void
                   1361: gui_mch_flush()
                   1362: {
                   1363:    XFlush(gui.dpy);
                   1364: }
                   1365:
                   1366: /*
                   1367:  * Clear a rectangular region of the screen from text pos (row1, col1) to
                   1368:  * (row2, col2) inclusive.
                   1369:  */
                   1370:    void
                   1371: gui_mch_clear_block(row1, col1, row2, col2)
                   1372:    int     row1;
                   1373:    int     col1;
                   1374:    int     row2;
                   1375:    int     col2;
                   1376: {
                   1377:    /* Clear the selection if we are about to write over it */
                   1378:    if (gui.selection.state == SELECT_DONE
                   1379:            && row2 >= gui.selection.start.lnum
                   1380:            && row1 <= gui.selection.end.lnum)
                   1381:        gui_mch_clear_selection();
                   1382:
                   1383:    XFillRectangle(gui.dpy, gui.wid, gui.back_gc, FILL_X(col1),
                   1384:        FILL_Y(row1), (col2 - col1 + 1) * gui.char_width,
                   1385:        (row2 - row1 + 1) * gui.char_height);
                   1386:
                   1387:    /* Invalidate cursor if it was in this block */
                   1388:    if (gui.cursor_row >= row1 && gui.cursor_row <= row2
                   1389:     && gui.cursor_col >= col1 && gui.cursor_col <= col2)
                   1390:        INVALIDATE_CURSOR();
                   1391: }
                   1392:
                   1393: /*
                   1394:  * Output the given string at the current cursor position. If the string is
                   1395:  * too long to fit on the line, then it is truncated.  wrap_cursor may be
                   1396:  * TRUE if the cursor position should be wrapped when the end of the line is
                   1397:  * reached, however the string will still be truncated and not continue on the
                   1398:  * next line.  is_cursor should only be TRUE when this function is being called
                   1399:  * to actually draw the cursor.
                   1400:  */
                   1401:    void
                   1402: gui_mch_outstr_nowrap(s, len, wrap_cursor, is_cursor)
                   1403:    char_u  *s;
                   1404:    int     len;
                   1405:    int     wrap_cursor;
                   1406:    int     is_cursor;
                   1407: {
                   1408:    GC      text_gc;
                   1409:    long_u  highlight_mask;
                   1410:
                   1411:    if (len == 0)
                   1412:        return;
                   1413:
                   1414:    if (len < 0)
                   1415:        len = STRLEN(s);
                   1416:
                   1417:    if (is_cursor && gui.in_focus)
                   1418:        highlight_mask = gui.highlight_mask | HL_INVERSE;
                   1419:    else
                   1420:        highlight_mask = gui.highlight_mask;
                   1421:
                   1422:    if (highlight_mask & (HL_INVERSE | HL_STANDOUT))
                   1423:        text_gc = gui.back_gc;
                   1424:    else
                   1425:        text_gc = gui.text_gc;
                   1426:
                   1427:    /* Set the font */
                   1428:    if ((highlight_mask & (HL_BOLD | HL_STANDOUT)) && gui.bold_font != NULL)
                   1429:        if ((highlight_mask & HL_ITAL) && gui.boldital_font != NULL)
                   1430:            gui_x11_set_font(text_gc, gui.boldital_font->fid);
                   1431:        else
                   1432:            gui_x11_set_font(text_gc, gui.bold_font->fid);
                   1433:    else if ((highlight_mask & HL_ITAL) && gui.ital_font != NULL)
                   1434:        gui_x11_set_font(text_gc, gui.ital_font->fid);
                   1435:    else
                   1436:        gui_x11_set_font(text_gc, gui.norm_font->fid);
                   1437:
                   1438:    /* Set the color */
                   1439:    if (is_cursor && gui.in_focus)
                   1440:        gui_x11_set_color(text_gc, gui.cursor_pixel);
                   1441:    else if (highlight_mask & (HL_BOLD | HL_STANDOUT))
                   1442:        gui_x11_set_color(text_gc, gui.bold_pixel);
                   1443:    else if (highlight_mask & HL_ITAL)
                   1444:        gui_x11_set_color(text_gc, gui.ital_pixel);
                   1445:    else if (highlight_mask & HL_UNDERLINE)
                   1446:        gui_x11_set_color(text_gc, gui.underline_pixel);
                   1447:    else
                   1448:        gui_x11_set_color(text_gc, gui.norm_pixel);
                   1449:
                   1450:    /* Clear the selection if we are about to write over it */
                   1451:    if (gui.selection.state == SELECT_DONE
                   1452:            && gui.row >= gui.selection.start.lnum
                   1453:            && gui.row <= gui.selection.end.lnum)
                   1454:        gui_mch_clear_selection();
                   1455:
                   1456:    /* Draw the text */
                   1457:    XDrawImageString(gui.dpy, gui.wid, text_gc,
                   1458:        TEXT_X(gui.col), TEXT_Y(gui.row), (char *)s, len);
                   1459:
                   1460:    /* No bold font, so fake it */
                   1461:    if ((highlight_mask & (HL_BOLD | HL_STANDOUT)) && gui.bold_font == NULL)
                   1462:        XDrawString(gui.dpy, gui.wid, text_gc,
                   1463:            TEXT_X(gui.col) + 1, TEXT_Y(gui.row), (char *)s, len);
                   1464:
                   1465:    /* Underline the text */
                   1466:    if ((highlight_mask & HL_UNDERLINE)
                   1467:     || ((highlight_mask & HL_ITAL) && gui.ital_font == NULL))
                   1468:        XDrawLine(gui.dpy, gui.wid, text_gc, FILL_X(gui.col),
                   1469:            FILL_Y(gui.row + 1) - 1, FILL_X(gui.col + len) - 1,
                   1470:            FILL_Y(gui.row + 1) - 1);
                   1471:
                   1472:    if (!is_cursor)
                   1473:    {
                   1474:        /* Invalidate the old physical cursor position if we wrote over it */
                   1475:        if (gui.cursor_row == gui.row && gui.cursor_col >= gui.col
                   1476:         && gui.cursor_col < gui.col + len)
                   1477:            INVALIDATE_CURSOR();
                   1478:
                   1479:        /* Update the cursor position */
                   1480:        gui.col += len;
                   1481:        if (wrap_cursor && gui.col >= Columns)
                   1482:        {
                   1483:            gui.col = 0;
                   1484:            gui.row++;
                   1485:        }
                   1486:    }
                   1487: }
                   1488:
                   1489: /*
                   1490:  * Delete the given number of lines from the given row, scrolling up any
                   1491:  * text further down within the scroll region.
                   1492:  */
                   1493:    void
                   1494: gui_mch_delete_lines(row, num_lines)
                   1495:    int     row;
                   1496:    int     num_lines;
                   1497: {
                   1498:    if (gui.visibility == VisibilityFullyObscured)
                   1499:        return;     /* Can't see the window */
                   1500:
                   1501:    if (num_lines <= 0)
                   1502:        return;
                   1503:
                   1504:    if (row + num_lines > gui.scroll_region_bot)
                   1505:    {
                   1506:        /* Scrolled out of region, just blank the lines out */
                   1507:        gui_mch_clear_block(row, 0, gui.scroll_region_bot, Columns - 1);
                   1508:    }
                   1509:    else
                   1510:    {
                   1511:        XCopyArea(gui.dpy, gui.wid, gui.wid, gui.text_gc,
                   1512:            FILL_X(0), FILL_Y(row + num_lines),
                   1513:            gui.char_width * Columns,
                   1514:            gui.char_height * (gui.scroll_region_bot - row - num_lines + 1),
                   1515:            FILL_X(0), FILL_Y(row));
                   1516:
                   1517:        /* Update gui.cursor_row if the cursor scrolled or copied over */
                   1518:        if (gui.cursor_row >= row)
                   1519:        {
                   1520:            if (gui.cursor_row < row + num_lines)
                   1521:                INVALIDATE_CURSOR();
                   1522:            else if (gui.cursor_row <= gui.scroll_region_bot)
                   1523:                gui.cursor_row -= num_lines;
                   1524:        }
                   1525:
                   1526:        gui_mch_clear_block(gui.scroll_region_bot - num_lines + 1, 0,
                   1527:            gui.scroll_region_bot, Columns - 1);
                   1528:        gui_x11_check_copy_area();
                   1529:    }
                   1530: }
                   1531:
                   1532: /*
                   1533:  * Insert the given number of lines before the given row, scrolling down any
                   1534:  * following text within the scroll region.
                   1535:  */
                   1536:    void
                   1537: gui_mch_insert_lines(row, num_lines)
                   1538:    int     row;
                   1539:    int     num_lines;
                   1540: {
                   1541:    if (gui.visibility == VisibilityFullyObscured)
                   1542:        return;     /* Can't see the window */
                   1543:
                   1544:    if (num_lines <= 0)
                   1545:        return;
                   1546:
                   1547:    if (row + num_lines > gui.scroll_region_bot)
                   1548:    {
                   1549:        /* Scrolled out of region, just blank the lines out */
                   1550:        gui_mch_clear_block(row, 0, gui.scroll_region_bot, Columns - 1);
                   1551:    }
                   1552:    else
                   1553:    {
                   1554:        XCopyArea(gui.dpy, gui.wid, gui.wid, gui.text_gc,
                   1555:            FILL_X(0), FILL_Y(row),
                   1556:            gui.char_width * Columns,
                   1557:            gui.char_height * (gui.scroll_region_bot - row - num_lines + 1),
                   1558:            FILL_X(0), FILL_Y(row + num_lines));
                   1559:
                   1560:        /* Update gui.cursor_row if the cursor scrolled or copied over */
                   1561:        if (gui.cursor_row >= gui.row)
                   1562:        {
                   1563:            if (gui.cursor_row <= gui.scroll_region_bot - num_lines)
                   1564:                gui.cursor_row += num_lines;
                   1565:            else if (gui.cursor_row <= gui.scroll_region_bot)
                   1566:                INVALIDATE_CURSOR();
                   1567:        }
                   1568:
                   1569:        gui_mch_clear_block(row, 0, row + num_lines - 1, Columns - 1);
                   1570:        gui_x11_check_copy_area();
                   1571:    }
                   1572: }
                   1573:
                   1574: /*
                   1575:  * Scroll the text between gui.scroll_region_top & gui.scroll_region_bot by the
                   1576:  * number of lines given.  Positive scrolls down (text goes up) and negative
                   1577:  * scrolls up (text goes down).
                   1578:  */
                   1579:    static void
                   1580: gui_x11_check_copy_area()
                   1581: {
                   1582:    XEvent                  event;
                   1583:    XGraphicsExposeEvent    *gevent;
                   1584:
                   1585:    if (gui.visibility != VisibilityPartiallyObscured)
                   1586:        return;
                   1587:
                   1588:    XFlush(gui.dpy);
                   1589:
                   1590:    /* Wait to check whether the scroll worked or not */
                   1591:    for (;;)
                   1592:    {
                   1593:        if (XCheckTypedEvent(gui.dpy, NoExpose, &event))
                   1594:            return;     /* The scroll worked. */
                   1595:
                   1596:        if (XCheckTypedEvent(gui.dpy, GraphicsExpose, &event))
                   1597:        {
                   1598:            gevent = (XGraphicsExposeEvent *)&event;
                   1599:            gui_redraw(gevent->x, gevent->y, gevent->width, gevent->height);
                   1600:            if (gevent->count == 0)
                   1601:                return;         /* This was the last expose event */
                   1602:        }
                   1603:        XSync(gui.dpy, False);
                   1604:    }
                   1605: }
                   1606:
                   1607: /*
                   1608:  * X Selection stuff, for cutting and pasting text to other windows.
                   1609:  */
                   1610:
                   1611:    static void
                   1612: gui_x11_request_selection_cb(w, success, selection, type, value, length, format)
                   1613:    Widget      w;
                   1614:    XtPointer   success;
                   1615:    Atom        *selection;
                   1616:    Atom        *type;
                   1617:    XtPointer   value;
                   1618:    long_u      *length;
                   1619:    int         *format;
                   1620: {
                   1621:    int     motion_type;
                   1622:    long_u  len;
                   1623:    char_u  *p;
                   1624:
                   1625:    if (value == NULL || *length == 0)
                   1626:    {
                   1627:        gui_free_selection();   /* ??? */
                   1628:        *(int *)success = FALSE;
                   1629:        return;
                   1630:    }
                   1631:    motion_type = MCHAR;
                   1632:    p = (char_u *)value;
                   1633:    len = *length;
                   1634:    if (*type == gui.selection.atom)
                   1635:    {
                   1636:        motion_type = *p++;
                   1637:        len--;
                   1638:    }
                   1639:    gui_yank_selection(motion_type, p, len);
                   1640:
                   1641:    XtFree((char *)value);
                   1642:    *(int *)success = TRUE;
                   1643: }
                   1644:
                   1645:    void
                   1646: gui_request_selection()
                   1647: {
                   1648:    XEvent  event;
                   1649:    Atom    type = gui.selection.atom;
                   1650:    int     success;
                   1651:    int     i;
                   1652:
                   1653:    for (i = 0; i < 2; i++)
                   1654:    {
                   1655:        XtGetSelectionValue(vimShell, XA_PRIMARY, type,
                   1656:            gui_x11_request_selection_cb, (XtPointer)&success, CurrentTime);
                   1657:
                   1658:        /* Do we need this?: */
                   1659:        XFlush(gui.dpy);
                   1660:
                   1661:        /*
                   1662:         * Wait for result of selection request, otherwise if we type more
                   1663:         * characters, then they will appear before the one that requested the
                   1664:         * paste!  Don't worry, we will catch up with any other events later.
                   1665:         */
                   1666:        for (;;)
                   1667:        {
                   1668:            if (XCheckTypedEvent(gui.dpy, SelectionNotify, &event))
                   1669:                break;
                   1670:
                   1671:            /* Do we need this?: */
                   1672:            XSync(gui.dpy, False);
                   1673:        }
                   1674:        XtDispatchEvent(&event);
                   1675:
                   1676:        if (success)
                   1677:            return;
                   1678:        type = XA_STRING;
                   1679:    }
                   1680: }
                   1681:
                   1682:    static Boolean
                   1683: gui_x11_convert_selection_cb(w, selection, target, type, value, length, format)
                   1684:    Widget      w;
                   1685:    Atom        *selection;
                   1686:    Atom        *target;
                   1687:    Atom        *type;
                   1688:    XtPointer   *value;
                   1689:    long_u      *length;
                   1690:    int         *format;
                   1691: {
                   1692:    char_u  *string;
                   1693:    char_u  *result;
                   1694:    int     motion_type;
                   1695:
                   1696:    if (!gui.selection.owned)
                   1697:        return False;       /* Shouldn't ever happen */
                   1698:
                   1699:    if (*target == gui.selection.atom)
                   1700:    {
                   1701:        gui_get_selection();
                   1702:        motion_type = gui_convert_selection(&string, length);
                   1703:        if (motion_type < 0)
                   1704:            return False;
                   1705:
                   1706:        (*length)++;
                   1707:        *value = XtMalloc(*length);
                   1708:        result = (char_u *)*value;
                   1709:        if (result == NULL)
                   1710:            return False;
                   1711:        result[0] = motion_type;
                   1712:        vim_memmove(result + 1, string, (size_t)(*length - 1));
                   1713:        *type = *target;
                   1714:        *format = 8;        /* 8 bits per char */
                   1715:        return True;
                   1716:    }
                   1717:    else if (*target == XA_STRING)
                   1718:    {
                   1719:        gui_get_selection();
                   1720:        motion_type = gui_convert_selection(&string, length);
                   1721:        if (motion_type < 0)
                   1722:            return False;
                   1723:
                   1724:        *value = XtMalloc(*length);
                   1725:        result = (char_u *)*value;
                   1726:        if (result == NULL)
                   1727:            return False;
                   1728:        vim_memmove(result, string, (size_t)(*length));
                   1729:        *type = *target;
                   1730:        *format = 8;        /* 8 bits per char */
                   1731:        return True;
                   1732:    }
                   1733:    else
                   1734:        return False;
                   1735: }
                   1736:
                   1737:    static void
                   1738: gui_x11_lose_ownership_cb(w, selection)
                   1739:    Widget  w;
                   1740:    Atom    *selection;
                   1741: {
                   1742:    gui_lose_selection();
                   1743: }
                   1744:
                   1745:    void
                   1746: gui_mch_lose_selection()
                   1747: {
                   1748:    XtDisownSelection(vimShell, XA_PRIMARY, CurrentTime);
                   1749:    gui_mch_clear_selection();
                   1750: }
                   1751:
                   1752:    int
                   1753: gui_mch_own_selection()
                   1754: {
                   1755:    if (XtOwnSelection(vimShell, XA_PRIMARY, CurrentTime,
                   1756:            gui_x11_convert_selection_cb, gui_x11_lose_ownership_cb,
                   1757:            NULL) == False)
                   1758:        return FAIL;
                   1759:
                   1760:    return OK;
                   1761: }
                   1762:
                   1763: /*
                   1764:  * Menu stuff.
                   1765:  */
                   1766:
                   1767:    void
                   1768: gui_x11_menu_cb(w, client_data, call_data)
                   1769:    Widget      w;
                   1770:    XtPointer   client_data, call_data;
                   1771: {
                   1772:    gui_menu_cb((GuiMenu *)client_data);
                   1773: }
                   1774:
                   1775: /*
                   1776:  * Used recursively by gui_x11_update_menus (see below)
                   1777:  */
                   1778:    static void
                   1779: gui_x11_update_menus_recurse(menu, mode)
                   1780:    GuiMenu *menu;
                   1781:    int     mode;
                   1782: {
                   1783:    while (menu)
                   1784:    {
                   1785:        if (menu->modes & mode)
                   1786:        {
                   1787:            if (vim_strchr(p_guioptions, GO_GREY) != NULL)
                   1788:                XtSetSensitive(menu->id, True);
                   1789:            else
                   1790:                XtManageChild(menu->id);
                   1791:            gui_x11_update_menus_recurse(menu->children, mode);
                   1792:        }
                   1793:        else
                   1794:        {
                   1795:            if (vim_strchr(p_guioptions, GO_GREY) != NULL)
                   1796:                XtSetSensitive(menu->id, False);
                   1797:            else
                   1798:                XtUnmanageChild(menu->id);
                   1799:        }
                   1800:        menu = menu->next;
                   1801:    }
                   1802: }
                   1803:
                   1804: /*
                   1805:  * Make sure only the valid menu items appear for this mode.  If
                   1806:  * force_menu_update is not TRUE, then we only do this if the mode has changed
                   1807:  * since last time.  If "modes" is not 0, then we use these modes instead.
                   1808:  */
                   1809:    void
                   1810: gui_x11_update_menus(modes)
                   1811:    int     modes;
                   1812: {
                   1813:    static int prev_mode = -1;
                   1814:
                   1815:    int mode = 0;
                   1816:
                   1817:    if (modes != 0x0)
                   1818:        mode = modes;
                   1819:    else if (VIsual_active)
                   1820:        mode = MENU_VISUAL_MODE;
                   1821:    else if (State & NORMAL)
                   1822:        mode = MENU_NORMAL_MODE;
                   1823:    else if (State & INSERT)
                   1824:        mode = MENU_INSERT_MODE;
                   1825:    else if (State & CMDLINE)
                   1826:        mode = MENU_CMDLINE_MODE;
                   1827:
                   1828:    if (force_menu_update || mode != prev_mode)
                   1829:    {
                   1830:        gui_x11_update_menus_recurse(gui.root_menu, mode);
                   1831:        prev_mode = mode;
                   1832:        force_menu_update = FALSE;
                   1833:    }
                   1834: }
                   1835:
                   1836: /*
                   1837:  * Function called when window closed.  Preserve files and exit.
                   1838:  * Should put up a requester!
                   1839:  */
                   1840: /*ARGSUSED*/
                   1841:    static void
                   1842: gui_x11_wm_protocol_handler(w, client_data, event, bool)
                   1843:    Widget      w;
                   1844:    XtPointer   client_data;
                   1845:    XEvent      *event;
                   1846:    Boolean     *bool;
                   1847: {
                   1848:    /*
                   1849:     * On some HPUX system with Motif 1.2 this function is somehow called when
                   1850:     * starting up.  This if () avoids an unexpected exit.
                   1851:     */
                   1852:    if (event->type != ClientMessage ||
                   1853:           ((XClientMessageEvent *)event)->data.l[0] != Atom_WM_DELETE_WINDOW)
                   1854:        return;
                   1855:
                   1856:    STRCPY(IObuff, "Vim: Window closed\n");
                   1857:    preserve_exit();                /* preserve files and exit */
                   1858: }
                   1859:
                   1860: /*
                   1861:  * Compare two screen positions ala strcmp()
                   1862:  */
                   1863:    static int
                   1864: gui_x11_compare_pos(row1, col1, row2, col2)
                   1865:    short_u     row1;
                   1866:    short_u     col1;
                   1867:    short_u     row2;
                   1868:    short_u     col2;
                   1869: {
                   1870:    if (row1 > row2) return( 1);
                   1871:    if (row1 < row2) return(-1);
                   1872:    if (col1 > col2) return( 1);
                   1873:    if (col1 < col2) return(-1);
                   1874:                     return( 0);
                   1875: }
                   1876:
                   1877: /*
                   1878:  * Start out the selection
                   1879:  */
                   1880:    void
                   1881: gui_x11_start_selection(button, x, y, repeated_click, modifiers)
                   1882:     int     button;
                   1883:    int     x;
                   1884:    int     y;
                   1885:    int     repeated_click;
                   1886:    int_u   modifiers;
                   1887: {
                   1888:    GuiSelection    *gs = &gui.selection;
                   1889:
                   1890:    if (gs->state == SELECT_DONE)
                   1891:        gui_mch_clear_selection();
                   1892:
                   1893:    gs->start.lnum  = Y_2_ROW(y);
                   1894:    gs->start.col   = X_2_COL(x);
                   1895:    gs->end         = gs->start;
                   1896:    gs->origin_row  = gs->start.lnum;
                   1897:    gs->state       = SELECT_IN_PROGRESS;
                   1898:
                   1899:    if (repeated_click)
                   1900:    {
                   1901:        if (++(gs->mode) > SELECT_MODE_LINE)
                   1902:            gs->mode = SELECT_MODE_CHAR;
                   1903:    }
                   1904:    else
                   1905:        gs->mode = SELECT_MODE_CHAR;
                   1906:
                   1907:    /* clear the cursor until the selection is made */
                   1908:    gui_undraw_cursor();
                   1909:
                   1910:    switch (gs->mode)
                   1911:    {
                   1912:        case SELECT_MODE_CHAR:
                   1913:            gs->origin_start_col = gs->start.col;
                   1914:            gs->word_end_col = gui_x11_get_line_end(gs->start.lnum);
                   1915:            break;
                   1916:
                   1917:        case SELECT_MODE_WORD:
                   1918:            gui_x11_get_word_boundaries(gs, gs->start.lnum, gs->start.col);
                   1919:            gs->origin_start_col = gs->word_start_col;
                   1920:            gs->origin_end_col   = gs->word_end_col;
                   1921:
                   1922:            gui_x11_invert_area(gs->start.lnum, gs->word_start_col,
                   1923:                                gs->end.lnum, gs->word_end_col);
                   1924:            gs->start.col = gs->word_start_col;
                   1925:            gs->end.col   = gs->word_end_col;
                   1926:            break;
                   1927:
                   1928:        case SELECT_MODE_LINE:
                   1929:            gui_x11_invert_area(gs->start.lnum, 0, gs->start.lnum,
                   1930:                    gui.num_cols);
                   1931:            gs->start.col = 0;
                   1932:            gs->end.col   = gui.num_cols;
                   1933:            break;
                   1934:    }
                   1935:
                   1936:    gs->prev = gs->start;
                   1937:
                   1938: #ifdef DEBUG_SELECTION
                   1939:    printf("Selection started at (%u,%u)\n", gs->start.lnum, gs->start.col);
                   1940: #endif
                   1941: }
                   1942:
                   1943: /*
                   1944:  * Continue processing the selection
                   1945:  */
                   1946:    void
                   1947: gui_x11_process_selection(button, x, y, repeated_click, modifiers)
                   1948:     int     button;
                   1949:    int     x;
                   1950:    int     y;
                   1951:    int     repeated_click;
                   1952:    int_u   modifiers;
                   1953: {
                   1954:    GuiSelection    *gs = &gui.selection;
                   1955:    int             row, col;
                   1956:    int             diff;
                   1957:
                   1958:    if (button == MOUSE_RELEASE)
                   1959:    {
                   1960:        /* Check to make sure we have something selected */
                   1961:        if (gs->start.lnum == gs->end.lnum && gs->start.col == gs->end.col)
                   1962:        {
                   1963:            gui_update_cursor();
                   1964:            gs->state = SELECT_CLEARED;
                   1965:            return;
                   1966:        }
                   1967:
                   1968: #ifdef DEBUG_SELECTION
                   1969:        printf("Selection ended: (%u,%u) to (%u,%u)\n", gs->start.lnum,
                   1970:                gs->start.col, gs->end.lnum, gs->end.col);
                   1971: #endif
                   1972:        gui_free_selection();
                   1973:        gui_own_selection();
                   1974:        gui_x11_yank_selection(gs->start.lnum, gs->start.col, gs->end.lnum,
                   1975:                gs->end.col);
                   1976:        gui_update_cursor();
                   1977:
                   1978:        gs->state = SELECT_DONE;
                   1979:        return;
                   1980:    }
                   1981:
                   1982:    row = Y_2_ROW(y);
                   1983:    col = X_2_COL(x);
                   1984:
                   1985:    row = check_row(row);
                   1986:    col = check_col(col);
                   1987:
                   1988:    if (col == gs->prev.col && row == gs->prev.lnum)
                   1989:        return;
                   1990:
                   1991:    /*
                   1992:     * When extending the selection with the right mouse button, swap the
                   1993:     * start and end if the position is before half the selection
                   1994:     */
                   1995:    if (gs->state == SELECT_DONE && button == MOUSE_RIGHT)
                   1996:    {
                   1997:        /*
                   1998:         * If the click is before the start, or the click is inside the
                   1999:         * selection and the start is the closest side, set the origin to the
                   2000:         * end of the selection.
                   2001:         */
                   2002:        if (gui_x11_compare_pos(row, col, gs->start.lnum, gs->start.col) < 0 ||
                   2003:                (gui_x11_compare_pos(row, col, gs->end.lnum, gs->end.col) < 0 &&
                   2004:                 (((gs->start.lnum == gs->end.lnum &&
                   2005:                    gs->end.col - col > col - gs->start.col)) ||
                   2006:                  ((diff = (gs->end.lnum - row) - (row - gs->start.lnum)) > 0 ||
                   2007:                   (diff == 0 && col < (gs->start.col + gs->end.col) / 2)))))
                   2008:        {
                   2009:            gs->origin_row = gs->end.lnum;
                   2010:            gs->origin_start_col = gs->end.col - 1;
                   2011:            gs->origin_end_col = gs->end.col;
                   2012:        }
                   2013:        else
                   2014:        {
                   2015:            gs->origin_row = gs->start.lnum;
                   2016:            gs->origin_start_col = gs->start.col;
                   2017:            gs->origin_end_col = gs->start.col;
                   2018:        }
                   2019:        if (gs->mode == SELECT_MODE_WORD)
                   2020:        {
                   2021:            gui_x11_get_word_boundaries(gs, gs->origin_row,
                   2022:                                                        gs->origin_start_col);
                   2023:            gs->origin_start_col = gs->word_start_col;
                   2024:            gs->origin_end_col   = gs->word_end_col;
                   2025:        }
                   2026:    }
                   2027:
                   2028:    /* set state, for when using the right mouse button */
                   2029:    gs->state = SELECT_IN_PROGRESS;
                   2030:
                   2031: #ifdef DEBUG_SELECTION
                   2032:    printf("Selection extending to (%d,%d)\n", row, col);
                   2033: #endif
                   2034:
                   2035:    switch (gs->mode)
                   2036:    {
                   2037:        case SELECT_MODE_CHAR:
                   2038:            /* If we're on a different line, find where the line ends */
                   2039:            if (row != gs->prev.lnum)
                   2040:                gs->word_end_col = gui_x11_get_line_end(row);
                   2041:
                   2042:            /* See if we are before or after the origin of the selection */
                   2043:            if (gui_x11_compare_pos(row, col, gs->origin_row,
                   2044:                                                   gs->origin_start_col) >= 0)
                   2045:            {
                   2046:                if (col >= (int)gs->word_end_col)
                   2047:                    gui_x11_update_selection(gs, gs->origin_row,
                   2048:                            gs->origin_start_col, row, gui.num_cols);
                   2049:                else
                   2050:                    gui_x11_update_selection(gs, gs->origin_row,
                   2051:                            gs->origin_start_col, row, col + 1);
                   2052:            }
                   2053:            else
                   2054:            {
                   2055:                if (col >= (int)gs->word_end_col)
                   2056:                    gui_x11_update_selection(gs, row, gs->word_end_col,
                   2057:                            gs->origin_row, gs->origin_start_col + 1);
                   2058:                else
                   2059:                    gui_x11_update_selection(gs, row, col, gs->origin_row,
                   2060:                            gs->origin_start_col + 1);
                   2061:            }
                   2062:            break;
                   2063:
                   2064:        case SELECT_MODE_WORD:
                   2065:            /* If we are still within the same word, do nothing */
                   2066:            if (row == gs->prev.lnum && col >= (int)gs->word_start_col
                   2067:                    && col < (int)gs->word_end_col)
                   2068:                return;
                   2069:
                   2070:            /* Get new word boundaries */
                   2071:            gui_x11_get_word_boundaries(gs, row, col);
                   2072:
                   2073:            /* Handle being after the origin point of selection */
                   2074:            if (gui_x11_compare_pos(row, col, gs->origin_row,
                   2075:                    gs->origin_start_col) >= 0)
                   2076:                gui_x11_update_selection(gs, gs->origin_row,
                   2077:                        gs->origin_start_col, row, gs->word_end_col);
                   2078:            else
                   2079:                gui_x11_update_selection(gs, row, gs->word_start_col,
                   2080:                        gs->origin_row, gs->origin_end_col);
                   2081:            break;
                   2082:
                   2083:        case SELECT_MODE_LINE:
                   2084:            if (row == gs->prev.lnum)
                   2085:                return;
                   2086:
                   2087:            if (gui_x11_compare_pos(row, col, gs->origin_row,
                   2088:                    gs->origin_start_col) >= 0)
                   2089:                gui_x11_update_selection(gs, gs->origin_row, 0, row,
                   2090:                        gui.num_cols);
                   2091:            else
                   2092:                gui_x11_update_selection(gs, row, 0, gs->origin_row,
                   2093:                        gui.num_cols);
                   2094:            break;
                   2095:    }
                   2096:
                   2097:    gs->prev.lnum = row;
                   2098:    gs->prev.col  = col;
                   2099:
                   2100: #ifdef DEBUG_SELECTION
                   2101:        printf("Selection is: (%u,%u) to (%u,%u)\n", gs->start.lnum,
                   2102:                gs->start.col, gs->end.lnum, gs->end.col);
                   2103: #endif
                   2104: }
                   2105:
                   2106: /*
                   2107:  * Called after an Expose event to redraw the selection
                   2108:  */
                   2109:    void
                   2110: gui_x11_redraw_selection(x, y, w, h)
                   2111:    int     x;
                   2112:    int     y;
                   2113:    int     w;
                   2114:    int     h;
                   2115: {
                   2116:    GuiSelection    *gs = &gui.selection;
                   2117:    int             row1, col1, row2, col2;
                   2118:    int             row;
                   2119:    int             start;
                   2120:    int             end;
                   2121:
                   2122:    if (gs->state == SELECT_CLEARED)
                   2123:        return;
                   2124:
                   2125:    row1 = Y_2_ROW(y);
                   2126:    col1 = X_2_COL(x);
                   2127:    row2 = Y_2_ROW(y + h - 1);
                   2128:    col2 = X_2_COL(x + w - 1);
                   2129:
                   2130:    /* Limit the rows that need to be re-drawn */
                   2131:    if (gs->start.lnum > row1)
                   2132:        row1 = gs->start.lnum;
                   2133:    if (gs->end.lnum < row2)
                   2134:        row2 = gs->end.lnum;
                   2135:
                   2136:    /* Look at each row that might need to be re-drawn */
                   2137:    for (row = row1; row <= row2; row++)
                   2138:    {
                   2139:        /* For the first selection row, use the starting selection column */
                   2140:        if (row == gs->start.lnum)
                   2141:            start = gs->start.col;
                   2142:        else
                   2143:            start = 0;
                   2144:
                   2145:        /* For the last selection row, use the ending selection column */
                   2146:        if (row == gs->end.lnum)
                   2147:            end = gs->end.col;
                   2148:        else
                   2149:            end = gui.num_cols;
                   2150:
                   2151:        if (col1 > start)
                   2152:            start = col1;
                   2153:
                   2154:        if (col2 < end)
                   2155:            end = col2 + 1;
                   2156:
                   2157:        if (end > start)
                   2158:            invert_rectangle(row, start, 1, end - start);
                   2159:    }
                   2160: }
                   2161:
                   2162: /*
                   2163:  * Called from outside to clear selected region from the display
                   2164:  */
                   2165:    void
                   2166: gui_mch_clear_selection()
                   2167: {
                   2168:    GuiSelection    *gs = &gui.selection;
                   2169:
                   2170:    if (gs->state == SELECT_CLEARED)
                   2171:        return;
                   2172:
                   2173:    gui_x11_invert_area(gs->start.lnum, gs->start.col, gs->end.lnum,
                   2174:            gs->end.col);
                   2175:    gs->state = SELECT_CLEARED;
                   2176: }
                   2177:
                   2178: /*
                   2179:  * Invert a region of the display between a starting and ending row and column
                   2180:  */
                   2181:    static void
                   2182: gui_x11_invert_area(row1, col1, row2, col2)
                   2183:    int     row1;
                   2184:    int     col1;
                   2185:    int     row2;
                   2186:    int     col2;
                   2187: {
                   2188:    /* Swap the from and to positions so the from is always before */
                   2189:    if (gui_x11_compare_pos(row1, col1, row2, col2) > 0)
                   2190:    {
                   2191:        int tmp_row, tmp_col;
                   2192:        tmp_row = row1;
                   2193:        tmp_col = col1;
                   2194:        row1    = row2;
                   2195:        col1    = col2;
                   2196:        row2    = tmp_row;
                   2197:        col2    = tmp_col;
                   2198:    }
                   2199:
                   2200:    /* If all on the same line, do it the easy way */
                   2201:    if (row1 == row2)
                   2202:    {
                   2203:        invert_rectangle(row1, col1, 1, col2 - col1);
                   2204:        return;
                   2205:    }
                   2206:
                   2207:    /* Handle a piece of the first line */
                   2208:    if (col1 > 0)
                   2209:    {
                   2210:        invert_rectangle(row1, col1, 1, gui.num_cols - col1);
                   2211:        row1++;
                   2212:    }
                   2213:
                   2214:    /* Handle a piece of the last line */
                   2215:    if (col2 < gui.num_cols - 1)
                   2216:    {
                   2217:        invert_rectangle(row2, 0, 1, col2);
                   2218:        row2--;
                   2219:    }
                   2220:
                   2221:    /* Handle the rectangle thats left */
                   2222:    if (row2 >= row1)
                   2223:        invert_rectangle(row1, 0, row2 - row1 + 1, gui.num_cols);
                   2224: }
                   2225:
                   2226: /*
                   2227:  * Yank the currently selected area into the special selection buffer so it
                   2228:  * will be available for pasting.
                   2229:  */
                   2230:    static void
                   2231: gui_x11_yank_selection(row1, col1, row2, col2)
                   2232:    int     row1;
                   2233:    int     col1;
                   2234:    int     row2;
                   2235:    int     col2;
                   2236: {
                   2237:    char_u  *buffer;
                   2238:    char_u  *bufp;
                   2239:    int     row;
                   2240:    int     start_col;
                   2241:    int     end_col;
                   2242:    int     line_end_col;
                   2243:    int     add_newline_flag = FALSE;
                   2244:
                   2245:    /* Create a temporary buffer for storing the text */
                   2246:    buffer = lalloc((row2 - row1 + 1) * gui.num_cols + 1, TRUE);
                   2247:    if (buffer == NULL)
                   2248:        return;                 /* Should there be an error message here? */
                   2249:
                   2250:    /* Process each row in the selection */
                   2251:    for (bufp = buffer, row = row1; row <= row2; row++)
                   2252:    {
                   2253:        if (row == row1)
                   2254:            start_col = col1;
                   2255:        else
                   2256:            start_col = 0;
                   2257:
                   2258:        if (row == row2)
                   2259:            end_col = col2;
                   2260:        else
                   2261:            end_col = gui.num_cols;
                   2262:
                   2263:        line_end_col = gui_x11_get_line_end(row);
                   2264:
                   2265:        /* See if we need to nuke some trailing whitespace */
                   2266:        if (end_col >= gui.num_cols && (row < row2 || end_col > line_end_col))
                   2267:        {
                   2268:            /* Get rid of trailing whitespace */
                   2269:            end_col = line_end_col;
                   2270:            if (end_col < start_col)
                   2271:                end_col = start_col;
                   2272:
                   2273:            /* If the last line extended to the end, add an extra newline */
                   2274:            if (row == row2)
                   2275:                add_newline_flag = TRUE;
                   2276:        }
                   2277:
                   2278:        /* If after the first row, we need to always add a newline */
                   2279:        if (row > row1)
                   2280:            *bufp++ = NL;
                   2281:
                   2282:        if (gui.row < screen_Rows && end_col <= screen_Columns)
                   2283:        {
                   2284:            STRNCPY(bufp, &LinePointers[row][start_col], end_col - start_col);
                   2285:            bufp += end_col - start_col;
                   2286:        }
                   2287:    }
                   2288:
                   2289:    /* Add a newline at the end if the selection ended there */
                   2290:    if (add_newline_flag)
                   2291:        *bufp++ = NL;
                   2292:
                   2293:    gui_yank_selection(MCHAR, buffer, bufp - buffer);
                   2294:    vim_free(buffer);
                   2295: }
                   2296:
                   2297: /*
                   2298:  * Find the starting and ending positions of the word at the given row and
                   2299:  * column.
                   2300:  */
                   2301:    static void
                   2302: gui_x11_get_word_boundaries(gs, row, col)
                   2303:    GuiSelection    *gs;
                   2304:    int             row;
                   2305:    int             col;
                   2306: {
                   2307:    char    start_class;
                   2308:    int     temp_col;
                   2309:
                   2310:    if (row >= screen_Rows || col >= screen_Columns)
                   2311:        return;
                   2312:
                   2313:    start_class = char_class(LinePointers[row][col]);
                   2314:
                   2315:    temp_col = col;
                   2316:    for ( ; temp_col > 0; temp_col--)
                   2317:        if (char_class(LinePointers[row][temp_col - 1]) != start_class)
                   2318:            break;
                   2319:
                   2320:    gs->word_start_col = temp_col;
                   2321:
                   2322:    temp_col = col;
                   2323:    for ( ; temp_col < screen_Columns; temp_col++)
                   2324:        if (char_class(LinePointers[row][temp_col]) != start_class)
                   2325:            break;
                   2326:    gs->word_end_col = temp_col;
                   2327:
                   2328: #ifdef DEBUG_SELECTION
                   2329:    printf("Current word: col %u to %u\n", gs->word_start_col,
                   2330:            gs->word_end_col);
                   2331: #endif
                   2332: }
                   2333:
                   2334: /*
                   2335:  * Find the column position for the last non-whitespace character on the given
                   2336:  * line.
                   2337:  */
                   2338:    static int
                   2339: gui_x11_get_line_end(row)
                   2340:    int         row;
                   2341: {
                   2342:    int     i;
                   2343:
                   2344:    if (row >= screen_Rows)
                   2345:        return 0;
                   2346:    for (i = screen_Columns; i > 0; i--)
                   2347:        if (LinePointers[row][i - 1] != ' ')
                   2348:            break;
                   2349:    return i;
                   2350: }
                   2351:
                   2352: /*
                   2353:  * Update the currently selected region by adding and/or subtracting from the
                   2354:  * beginning or end and inverting the changed area(s).
                   2355:  */
                   2356:    static void
                   2357: gui_x11_update_selection(gs, row1, col1, row2, col2)
                   2358:    GuiSelection    *gs;
                   2359:    int             row1;
                   2360:    int             col1;
                   2361:    int             row2;
                   2362:    int             col2;
                   2363: {
                   2364:    /* See if we changed at the beginning of the selection */
                   2365:    if (row1 != gs->start.lnum || col1 != gs->start.col)
                   2366:    {
                   2367:        gui_x11_invert_area(row1, col1, gs->start.lnum, gs->start.col);
                   2368:        gs->start.lnum = row1;
                   2369:        gs->start.col  = col1;
                   2370:    }
                   2371:
                   2372:    /* See if we changed at the end of the selection */
                   2373:    if (row2 != gs->end.lnum || col2 != gs->end.col)
                   2374:    {
                   2375:        gui_x11_invert_area(row2, col2, gs->end.lnum, gs->end.col);
                   2376:        gs->end.lnum = row2;
                   2377:        gs->end.col  = col2;
                   2378:    }
                   2379: }