home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / unix / vim-6.2.tar.bz2 / vim-6.2.tar / vim62 / src / gui_gtk_x11.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-05-31  |  165.5 KB  |  6,481 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved        by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  * See README.txt for an overview of the Vim source code.
  8.  */
  9.  
  10. /*
  11.  * Porting to GTK+ was done by:
  12.  *
  13.  * (C) 1998,1999,2000 by Marcin Dalecki <dalecki@evision.ag>
  14.  *
  15.  * With GREAT support and continuous encouragements by Andy Kahn and of
  16.  * course Bram Moolenaar!
  17.  *
  18.  * Support for GTK+ 2 was added by:
  19.  *
  20.  * (C) 2002,2003  Jason Hildebrand  <jason@peaceworks.ca>
  21.  *          Daniel Elstner  <daniel.elstner@gmx.net>
  22.  */
  23.  
  24. #include "vim.h"
  25. #ifdef FEAT_GUI_GNOME
  26. /* Gnome redefines _() and N_().  Grrr... */
  27. # ifdef _
  28. #  undef _
  29. # endif
  30. # ifdef N_
  31. #  undef N_
  32. # endif
  33. # ifdef textdomain
  34. #  undef textdomain
  35. # endif
  36. # ifdef bindtextdomain
  37. #  undef bindtextdomain
  38. # endif
  39. # if defined(FEAT_GETTEXT) && !defined(ENABLE_NLS)
  40. #  define ENABLE_NLS    /* so the texts in the dialog boxes are translated */
  41. # endif
  42. # include <gnome.h>
  43. # include "version.h"
  44. #endif
  45.  
  46. #if !defined(FEAT_GUI_GTK) && defined(PROTO)
  47. /* When generating prototypes we don't want syntax errors. */
  48. # define GdkAtom int
  49. # define GdkEventExpose int
  50. # define GdkEventFocus int
  51. # define GdkEventVisibility int
  52. # define GdkEventProperty int
  53. # define GtkContainer int
  54. # define GtkTargetEntry int
  55. # define GtkType int
  56. # define GtkWidget int
  57. # define gint int
  58. # define gpointer int
  59. # define guint int
  60. # define GdkEventKey int
  61. # define GdkEventSelection int
  62. # define GtkSelectionData int
  63. # define GdkEventMotion int
  64. # define GdkEventButton int
  65. # define GdkDragContext int
  66. # define GdkEventConfigure int
  67. # define GdkEventClient int
  68. #else
  69. # include <gdk/gdkkeysyms.h>
  70. # include <gdk/gdk.h>
  71. # include <gdk/gdkx.h>
  72.  
  73. # include <gtk/gtk.h>
  74. # include "gui_gtk_f.h"
  75. #endif
  76.  
  77. #ifdef HAVE_X11_SUNKEYSYM_H
  78. # include <X11/Sunkeysym.h>
  79. #endif
  80.  
  81. /*
  82.  * Easy-to-use macro for multihead support.
  83.  */
  84. #ifdef HAVE_GTK_MULTIHEAD
  85. # define GET_X_ATOM(atom)    gdk_x11_atom_to_xatom_for_display( \
  86.                     gtk_widget_get_display(gui.mainwin), atom)
  87. #else
  88. # define GET_X_ATOM(atom)    ((Atom)(atom))
  89. #endif
  90.  
  91. /* Selection type distinguishers */
  92. enum
  93. {
  94.     TARGET_TYPE_NONE,
  95.     TARGET_UTF8_STRING,
  96.     TARGET_STRING,
  97.     TARGET_COMPOUND_TEXT,
  98.     TARGET_TEXT,
  99.     TARGET_TEXT_URI_LIST,
  100.     TARGET_TEXT_PLAIN,
  101.     TARGET_VIM
  102. };
  103.  
  104. /*
  105.  * Table of selection targets supported by Vim.
  106.  * Note: Order matters, preferred types should come first.
  107.  */
  108. static const GtkTargetEntry selection_targets[] =
  109. {
  110.     {VIM_ATOM_NAME,    0, TARGET_VIM},
  111. #ifdef FEAT_MBYTE
  112.     {"UTF8_STRING",    0, TARGET_UTF8_STRING},
  113. #endif
  114.     {"COMPOUND_TEXT",    0, TARGET_COMPOUND_TEXT},
  115.     {"TEXT",        0, TARGET_TEXT},
  116.     {"STRING",        0, TARGET_STRING}
  117. };
  118. #define N_SELECTION_TARGETS (sizeof(selection_targets) / sizeof(selection_targets[0]))
  119.  
  120. #ifdef FEAT_DND
  121. /*
  122.  * Table of DnD targets supported by Vim.
  123.  * Note: Order matters, preferred types should come first.
  124.  */
  125. static const GtkTargetEntry dnd_targets[] =
  126. {
  127.     {"text/uri-list",    0, TARGET_TEXT_URI_LIST},
  128. # ifdef FEAT_MBYTE
  129.     {"UTF8_STRING",    0, TARGET_UTF8_STRING},
  130. # endif
  131.     {"STRING",        0, TARGET_STRING},
  132.     {"text/plain",    0, TARGET_TEXT_PLAIN}
  133. };
  134. # define N_DND_TARGETS (sizeof(dnd_targets) / sizeof(dnd_targets[0]))
  135. #endif
  136.  
  137.  
  138. #ifdef HAVE_GTK2
  139. /*
  140.  * "Monospace" is a standard font alias that should be present
  141.  * on all proper Pango/fontconfig installations.
  142.  */
  143. # define DEFAULT_FONT    "Monospace 10"
  144.  
  145. #else /* !HAVE_GTK2 */
  146. /*
  147.  * This is the single only fixed width font in X11, which seems to be present
  148.  * on all servers and available in all the variants we need.
  149.  */
  150. # define DEFAULT_FONT    "-adobe-courier-medium-r-normal-*-14-*-*-*-m-*-*-*"
  151.  
  152. #endif /* !HAVE_GTK2 */
  153.  
  154. #if !(defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION))
  155. /*
  156.  * Atoms used to communicate save-yourself from the X11 session manager. There
  157.  * is no need to move them into the GUI struct, since they should be constant.
  158.  */
  159. static GdkAtom wm_protocols_atom = GDK_NONE;
  160. static GdkAtom save_yourself_atom = GDK_NONE;
  161. #endif
  162.  
  163. /*
  164.  * Atoms used to control/reference X11 selections.
  165.  */
  166. #ifdef FEAT_MBYTE
  167. static GdkAtom utf8_string_atom = GDK_NONE;
  168. #endif
  169. #ifndef HAVE_GTK2
  170. static GdkAtom compound_text_atom = GDK_NONE;
  171. static GdkAtom text_atom = GDK_NONE;
  172. #endif
  173. static GdkAtom vim_atom = GDK_NONE;    /* Vim's own special selection format */
  174.  
  175. /*
  176.  * Keycodes recognized by vim.
  177.  * NOTE: when changing this, the table in gui_x11.c probably needs the same
  178.  * change!
  179.  */
  180. static struct special_key
  181. {
  182.     guint key_sym;
  183.     char_u code0;
  184.     char_u code1;
  185. }
  186. const special_keys[] =
  187. {
  188.     {GDK_Up,        'k', 'u'},
  189.     {GDK_Down,        'k', 'd'},
  190.     {GDK_Left,        'k', 'l'},
  191.     {GDK_Right,        'k', 'r'},
  192.     {GDK_F1,        'k', '1'},
  193.     {GDK_F2,        'k', '2'},
  194.     {GDK_F3,        'k', '3'},
  195.     {GDK_F4,        'k', '4'},
  196.     {GDK_F5,        'k', '5'},
  197.     {GDK_F6,        'k', '6'},
  198.     {GDK_F7,        'k', '7'},
  199.     {GDK_F8,        'k', '8'},
  200.     {GDK_F9,        'k', '9'},
  201.     {GDK_F10,        'k', ';'},
  202.     {GDK_F11,        'F', '1'},
  203.     {GDK_F12,        'F', '2'},
  204.     {GDK_F13,        'F', '3'},
  205.     {GDK_F14,        'F', '4'},
  206.     {GDK_F15,        'F', '5'},
  207.     {GDK_F16,        'F', '6'},
  208.     {GDK_F17,        'F', '7'},
  209.     {GDK_F18,        'F', '8'},
  210.     {GDK_F19,        'F', '9'},
  211.     {GDK_F20,        'F', 'A'},
  212.     {GDK_F21,        'F', 'B'},
  213.     {GDK_Pause,        'F', 'B'}, /* Pause == F21 according to netbeans.txt */
  214.     {GDK_F22,        'F', 'C'},
  215.     {GDK_F23,        'F', 'D'},
  216.     {GDK_F24,        'F', 'E'},
  217.     {GDK_F25,        'F', 'F'},
  218.     {GDK_F26,        'F', 'G'},
  219.     {GDK_F27,        'F', 'H'},
  220.     {GDK_F28,        'F', 'I'},
  221.     {GDK_F29,        'F', 'J'},
  222.     {GDK_F30,        'F', 'K'},
  223.     {GDK_F31,        'F', 'L'},
  224.     {GDK_F32,        'F', 'M'},
  225.     {GDK_F33,        'F', 'N'},
  226.     {GDK_F34,        'F', 'O'},
  227.     {GDK_F35,        'F', 'P'},
  228. #ifdef SunXK_F36
  229.     {SunXK_F36,        'F', 'Q'},
  230.     {SunXK_F37,        'F', 'R'},
  231. #endif
  232.     {GDK_Help,        '%', '1'},
  233.     {GDK_Undo,        '&', '8'},
  234.     {GDK_BackSpace,    'k', 'b'},
  235.     {GDK_Insert,    'k', 'I'},
  236.     {GDK_Delete,    'k', 'D'},
  237.     {GDK_3270_BackTab,    'k', 'B'},
  238.     {GDK_Clear,        'k', 'C'},
  239.     {GDK_Home,        'k', 'h'},
  240.     {GDK_End,        '@', '7'},
  241.     {GDK_Prior,        'k', 'P'},
  242.     {GDK_Next,        'k', 'N'},
  243.     {GDK_Print,        '%', '9'},
  244.     /* Keypad keys: */
  245.     {GDK_KP_Left,    'k', 'l'},
  246.     {GDK_KP_Right,    'k', 'r'},
  247.     {GDK_KP_Up,        'k', 'u'},
  248.     {GDK_KP_Down,    'k', 'd'},
  249.     {GDK_KP_Insert,    KS_EXTRA, (char_u)KE_KINS},
  250.     {GDK_KP_Delete,    KS_EXTRA, (char_u)KE_KDEL},
  251.     {GDK_KP_Home,    'K', '1'},
  252.     {GDK_KP_End,    'K', '4'},
  253.     {GDK_KP_Prior,    'K', '3'},  /* page up */
  254.     {GDK_KP_Next,    'K', '5'},  /* page down */
  255.  
  256.     {GDK_KP_Add,    'K', '6'},
  257.     {GDK_KP_Subtract,    'K', '7'},
  258.     {GDK_KP_Divide,    'K', '8'},
  259.     {GDK_KP_Multiply,    'K', '9'},
  260.     {GDK_KP_Enter,    'K', 'A'},
  261.     {GDK_KP_Decimal,    'K', 'B'},
  262.  
  263.     {GDK_KP_0,        'K', 'C'},
  264.     {GDK_KP_1,        'K', 'D'},
  265.     {GDK_KP_2,        'K', 'E'},
  266.     {GDK_KP_3,        'K', 'F'},
  267.     {GDK_KP_4,        'K', 'G'},
  268.     {GDK_KP_5,        'K', 'H'},
  269.     {GDK_KP_6,        'K', 'I'},
  270.     {GDK_KP_7,        'K', 'J'},
  271.     {GDK_KP_8,        'K', 'K'},
  272.     {GDK_KP_9,        'K', 'L'},
  273.  
  274.     /* End of list marker: */
  275.     {0, 0, 0}
  276. };
  277.  
  278. /*
  279.  * Flags for command line options table below.
  280.  */
  281. #define ARG_FONT    1
  282. #define ARG_GEOMETRY    2
  283. #define ARG_REVERSE    3
  284. #define ARG_NOREVERSE    4
  285. #define ARG_BACKGROUND    5
  286. #define ARG_FOREGROUND    6
  287. #define ARG_ICONIC    7
  288. #define ARG_ROLE    8
  289. #define ARG_NETBEANS    9
  290. #define ARG_XRM        10    /* ignored */
  291. #define ARG_MENUFONT    11    /* ignored */
  292. #define ARG_INDEX_MASK    0x00ff
  293. #define ARG_HAS_VALUE    0x0100    /* a value is expected after the argument */
  294. #define ARG_NEEDS_GUI    0x0200    /* need to initialize the GUI for this      */
  295. #define ARG_FOR_GTK    0x0400    /* argument is handled by GTK+ or GNOME   */
  296. #define ARG_COMPAT_LONG    0x0800    /* accept -foo but substitute with --foo  */
  297. /*
  298.  * This table holds all the X GUI command line options allowed.  This includes
  299.  * the standard ones so that we can skip them when Vim is started without the
  300.  * GUI (but the GUI might start up later).
  301.  *
  302.  * When changing this, also update doc/gui_x11.txt and the usage message!!!
  303.  */
  304. typedef struct
  305. {
  306.     const char        *name;
  307.     unsigned int    flags;
  308. }
  309. cmdline_option_T;
  310.  
  311. static const cmdline_option_T cmdline_options[] =
  312. {
  313.     /* We handle these options ourselves */
  314.     {"-fn",        ARG_FONT|ARG_HAS_VALUE},
  315.     {"-font",        ARG_FONT|ARG_HAS_VALUE},
  316.     {"-geom",        ARG_GEOMETRY|ARG_HAS_VALUE},
  317.     {"-geometry",    ARG_GEOMETRY|ARG_HAS_VALUE},
  318.     {"-rv",        ARG_REVERSE},
  319.     {"-reverse",    ARG_REVERSE},
  320.     {"+rv",        ARG_NOREVERSE},
  321.     {"+reverse",    ARG_NOREVERSE},
  322.     {"-bg",        ARG_BACKGROUND|ARG_HAS_VALUE},
  323.     {"-background",    ARG_BACKGROUND|ARG_HAS_VALUE},
  324.     {"-fg",        ARG_FOREGROUND|ARG_HAS_VALUE},
  325.     {"-foreground",    ARG_FOREGROUND|ARG_HAS_VALUE},
  326.     {"-iconic",        ARG_ICONIC},
  327. #ifdef HAVE_GTK2
  328.     {"--role",        ARG_ROLE|ARG_HAS_VALUE},
  329. #endif
  330. #ifdef FEAT_NETBEANS_INTG
  331.     {"-nb",        ARG_NETBEANS},          /* non-standard value format */
  332.     {"-xrm",        ARG_XRM|ARG_HAS_VALUE},        /* not implemented */
  333.     {"-mf",        ARG_MENUFONT|ARG_HAS_VALUE},    /* not implemented */
  334.     {"-menufont",    ARG_MENUFONT|ARG_HAS_VALUE},    /* not implemented */
  335. #endif
  336. #if 0 /* not implemented; these arguments don't make sense for GTK+ */
  337.     {"-boldfont",    ARG_HAS_VALUE},
  338.     {"-italicfont",    ARG_HAS_VALUE},
  339.     {"-bw",        ARG_HAS_VALUE},
  340.     {"-borderwidth",    ARG_HAS_VALUE},
  341.     {"-sw",        ARG_HAS_VALUE},
  342.     {"-scrollbarwidth",    ARG_HAS_VALUE},
  343. #endif
  344.     /* Arguments handled by GTK (and GNOME) internally. */
  345.     {"--g-fatal-warnings",    ARG_FOR_GTK},
  346.     {"--gdk-debug",        ARG_FOR_GTK|ARG_HAS_VALUE},
  347.     {"--gdk-no-debug",        ARG_FOR_GTK|ARG_HAS_VALUE},
  348.     {"--gtk-debug",        ARG_FOR_GTK|ARG_HAS_VALUE},
  349.     {"--gtk-no-debug",        ARG_FOR_GTK|ARG_HAS_VALUE},
  350.     {"--gtk-module",        ARG_FOR_GTK|ARG_HAS_VALUE},
  351.     {"--sync",            ARG_FOR_GTK},
  352.     {"--display",        ARG_FOR_GTK|ARG_HAS_VALUE|ARG_COMPAT_LONG},
  353.     {"--name",            ARG_FOR_GTK|ARG_HAS_VALUE|ARG_COMPAT_LONG},
  354.     {"--class",            ARG_FOR_GTK|ARG_HAS_VALUE|ARG_COMPAT_LONG},
  355. #ifdef HAVE_GTK2
  356.     {"--screen",        ARG_FOR_GTK|ARG_HAS_VALUE},
  357.     {"--gxid-host",        ARG_FOR_GTK|ARG_HAS_VALUE},
  358.     {"--gxid-port",        ARG_FOR_GTK|ARG_HAS_VALUE},
  359. #else /* these don't seem to exist anymore */
  360.     {"--no-xshm",        ARG_FOR_GTK},
  361.     {"--xim-preedit",        ARG_FOR_GTK|ARG_HAS_VALUE},
  362.     {"--xim-status",        ARG_FOR_GTK|ARG_HAS_VALUE},
  363.     {"--gxid_host",        ARG_FOR_GTK|ARG_HAS_VALUE},
  364.     {"--gxid_port",        ARG_FOR_GTK|ARG_HAS_VALUE},
  365. #endif
  366. #ifdef FEAT_GUI_GNOME
  367.     {"--load-modules",        ARG_FOR_GTK|ARG_HAS_VALUE},
  368.     {"--sm-client-id",        ARG_FOR_GTK|ARG_HAS_VALUE},
  369.     {"--sm-config-prefix",    ARG_FOR_GTK|ARG_HAS_VALUE},
  370.     {"--sm-disable",        ARG_FOR_GTK},
  371.     {"--oaf-ior-fd",        ARG_FOR_GTK|ARG_HAS_VALUE},
  372.     {"--oaf-activate-iid",    ARG_FOR_GTK|ARG_HAS_VALUE},
  373.     {"--oaf-private",        ARG_FOR_GTK},
  374.     {"--enable-sound",        ARG_FOR_GTK},
  375.     {"--disable-sound",        ARG_FOR_GTK},
  376.     {"--espeaker",        ARG_FOR_GTK|ARG_HAS_VALUE},
  377.     {"-?",            ARG_FOR_GTK|ARG_NEEDS_GUI},
  378.     {"--help",            ARG_FOR_GTK|ARG_NEEDS_GUI},
  379.     {"--usage",            ARG_FOR_GTK|ARG_NEEDS_GUI},
  380. # if 0 /* conflicts with Vim's own --version argument */
  381.     {"--version",        ARG_FOR_GTK|ARG_NEEDS_GUI},
  382. # endif
  383.     {"--disable-crash-dialog",    ARG_FOR_GTK},
  384. #endif
  385.     {NULL, 0}
  386. };
  387.  
  388. static int    gui_argc = 0;
  389. static char **gui_argv = NULL;
  390.  
  391. #ifdef HAVE_GTK2
  392. static const char *role_argument = NULL;
  393. #endif
  394. #if defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION)
  395. static const char *restart_command = NULL;
  396. #endif
  397. static int found_iconic_arg = FALSE;
  398.  
  399. #ifdef FEAT_GUI_GNOME
  400. /*
  401.  * Can't use Gnome if --socketid given
  402.  */
  403. static int using_gnome = 0;
  404. #else
  405. # define using_gnome 0
  406. #endif
  407.  
  408. /*
  409.  * Parse the GUI related command-line arguments.  Any arguments used are
  410.  * deleted from argv, and *argc is decremented accordingly.  This is called
  411.  * when vim is started, whether or not the GUI has been started.
  412.  */
  413.     void
  414. gui_mch_prepare(int *argc, char **argv)
  415. {
  416.     const cmdline_option_T  *option;
  417.     int                i    = 0;
  418.     int                len = 0;
  419.  
  420. #if defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION)
  421.     /*
  422.      * Determine the command used to invoke Vim, to be passed as restart
  423.      * command to the session manager.    If argv[0] contains any directory
  424.      * components try building an absolute path, otherwise leave it as is.
  425.      */
  426.     restart_command = argv[0];
  427.  
  428.     if (strchr(argv[0], G_DIR_SEPARATOR) != NULL)
  429.     {
  430.     char_u buf[MAXPATHL];
  431.  
  432.     if (mch_FullName((char_u *)argv[0], buf, (int)sizeof(buf), TRUE) == OK)
  433.         /* Tiny leak; doesn't matter, and usually we don't even get here */
  434.         restart_command = (char *)vim_strsave(buf);
  435.     }
  436. #endif
  437.  
  438.     /*
  439.      * Move all the entries in argv which are relevant to GTK+ and GNOME
  440.      * into gui_argv.  Freed later in gui_mch_init().
  441.      */
  442.     gui_argc = 0;
  443.     gui_argv = (char **)alloc((unsigned)((*argc + 1) * sizeof(char *)));
  444.  
  445.     g_return_if_fail(gui_argv != NULL);
  446.  
  447.     gui_argv[gui_argc++] = argv[i++];
  448.  
  449.     while (i < *argc)
  450.     {
  451.     /* Don't waste CPU cycles on non-option arguments. */
  452.     if (argv[i][0] != '-' && argv[i][0] != '+')
  453.     {
  454.         ++i;
  455.         continue;
  456.     }
  457.  
  458.     /* Look for argv[i] in cmdline_options[] table. */
  459.     for (option = &cmdline_options[0]; option->name != NULL; ++option)
  460.     {
  461.         len = strlen(option->name);
  462.  
  463.         if (strncmp(argv[i], option->name, len) == 0)
  464.         {
  465.         if (argv[i][len] == '\0')
  466.             break;
  467.         /* allow --foo=bar style */
  468.         if (argv[i][len] == '=' && (option->flags & ARG_HAS_VALUE))
  469.             break;
  470. #ifdef FEAT_NETBEANS_INTG
  471.         /* darn, -nb has non-standard syntax */
  472.         if (argv[i][len] == ':'
  473.             && (option->flags & ARG_INDEX_MASK) == ARG_NETBEANS)
  474.             break;
  475. #endif
  476.         }
  477.         else if ((option->flags & ARG_COMPAT_LONG)
  478.             && strcmp(argv[i], option->name + 1) == 0)
  479.         {
  480.         /* Replace the standard X arguments "-name" and "-display"
  481.          * with their GNU-style long option counterparts. */
  482.         argv[i] = (char *)option->name;
  483.         break;
  484.         }
  485.     }
  486.     if (option->name == NULL) /* no match */
  487.     {
  488.         ++i;
  489.         continue;
  490.     }
  491.  
  492.     if (option->flags & ARG_FOR_GTK)
  493.     {
  494.         /* Move the argument into gui_argv, which
  495.          * will later be passed to gtk_init_check() */
  496.         gui_argv[gui_argc++] = argv[i];
  497.     }
  498.     else
  499.     {
  500.         char *value = NULL;
  501.  
  502.         /* Extract the option's value if there is one.
  503.          * Accept both "--foo bar" and "--foo=bar" style. */
  504.         if (option->flags & ARG_HAS_VALUE)
  505.         {
  506.         if (argv[i][len] == '=')
  507.             value = &argv[i][len + 1];
  508.         else if (i + 1 < *argc && strcmp(argv[i + 1], "--") != 0)
  509.             value = argv[i + 1];
  510.         }
  511.  
  512.         /* Check for options handled by Vim itself */
  513.         switch (option->flags & ARG_INDEX_MASK)
  514.         {
  515.         case ARG_REVERSE:
  516.             found_reverse_arg = TRUE;
  517.             break;
  518.         case ARG_NOREVERSE:
  519.             found_reverse_arg = FALSE;
  520.             break;
  521.         case ARG_FONT:
  522.             font_argument = value;
  523.             break;
  524.         case ARG_GEOMETRY:
  525.             if (value != NULL)
  526.             gui.geom = vim_strsave((char_u *)value);
  527.             break;
  528.         case ARG_BACKGROUND:
  529.             background_argument = value;
  530.             break;
  531.         case ARG_FOREGROUND:
  532.             foreground_argument = value;
  533.             break;
  534.         case ARG_ICONIC:
  535.             found_iconic_arg = TRUE;
  536.             break;
  537. #ifdef HAVE_GTK2
  538.         case ARG_ROLE:
  539.             role_argument = value; /* used later in gui_mch_open() */
  540.             break;
  541. #endif
  542. #ifdef FEAT_NETBEANS_INTG
  543.         case ARG_NETBEANS:
  544.             ++usingNetbeans;
  545.             gui.dofork = FALSE; /* don't fork() when starting GUI */
  546.             netbeansArg = argv[i];
  547.             break;
  548. #endif
  549.         default:
  550.             break;
  551.         }
  552.     }
  553.  
  554.     /* These arguments make gnome_program_init() print a message and exit.
  555.      * Must start the GUI for this, otherwise ":gui" will exit later! */
  556.     if (option->flags & ARG_NEEDS_GUI)
  557.         gui.starting = TRUE;
  558.  
  559.     /* Now remove the flag from the argument vector. */
  560.     if (--*argc > i)
  561.     {
  562.         int n_strip = 1;
  563.  
  564.         /* Move the argument's value as well, if there is one. */
  565.         if ((option->flags & ARG_HAS_VALUE)
  566.             && argv[i][len] != '='
  567.             && strcmp(argv[i + 1], "--") != 0)
  568.         {
  569.         ++n_strip;
  570.         --*argc;
  571.         if (option->flags & ARG_FOR_GTK)
  572.             gui_argv[gui_argc++] = argv[i + 1];
  573.         }
  574.  
  575.         if (*argc > i)
  576.         mch_memmove(&argv[i], &argv[i + n_strip],
  577.                 (*argc - i) * sizeof(char *));
  578.     }
  579.     argv[*argc] = NULL;
  580.     }
  581.  
  582.     gui_argv[gui_argc] = NULL;
  583. }
  584.  
  585. /*
  586.  * This should be maybe completely removed.
  587.  * Doesn't seem possible, since check_copy_area() relies on
  588.  * this information.  --danielk
  589.  */
  590. /*ARGSUSED*/
  591.     static gint
  592. visibility_event(GtkWidget *widget, GdkEventVisibility *event, gpointer data)
  593. {
  594.     gui.visibility = event->state;
  595.     /*
  596.      * When we do an gdk_window_copy_area(), and the window is partially
  597.      * obscured, we want to receive an event to tell us whether it worked
  598.      * or not.
  599.      */
  600.     if (gui.text_gc != NULL)
  601.     gdk_gc_set_exposures(gui.text_gc,
  602.                  gui.visibility != GDK_VISIBILITY_UNOBSCURED);
  603.     return FALSE;
  604. }
  605.  
  606. /*
  607.  * Redraw the corresponding portions of the screen.
  608.  */
  609. /*ARGSUSED*/
  610.     static gint
  611. expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
  612. {
  613.     /* Skip this when the GUI isn't set up yet, will redraw later. */
  614.     if (gui.starting)
  615.     return FALSE;
  616.  
  617.     out_flush();        /* make sure all output has been processed */
  618.     gui_redraw(event->area.x, event->area.y,
  619.            event->area.width, event->area.height);
  620.  
  621.     /* Clear the border areas if needed */
  622.     if (event->area.x < FILL_X(0))
  623.     gdk_window_clear_area(gui.drawarea->window, 0, 0, FILL_X(0), 0);
  624.     if (event->area.y < FILL_Y(0))
  625.     gdk_window_clear_area(gui.drawarea->window, 0, 0, 0, FILL_Y(0));
  626.     if (event->area.x > FILL_X(Columns))
  627.     gdk_window_clear_area(gui.drawarea->window,
  628.                   FILL_X((int)Columns), 0, 0, 0);
  629.     if (event->area.y > FILL_Y(Rows))
  630.     gdk_window_clear_area(gui.drawarea->window, 0, FILL_Y((int)Rows), 0, 0);
  631.  
  632.     return FALSE;
  633. }
  634.  
  635. #ifdef FEAT_CLIENTSERVER
  636. /*
  637.  * Handle changes to the "Comm" property
  638.  */
  639. /*ARGSUSED2*/
  640.     static gint
  641. property_event(GtkWidget *widget, GdkEventProperty *event, gpointer data)
  642. {
  643.     if (event->type == GDK_PROPERTY_NOTIFY
  644.         && event->state == (int)GDK_PROPERTY_NEW_VALUE
  645.         && GDK_WINDOW_XWINDOW(event->window) == commWindow
  646.         && GET_X_ATOM(event->atom) == commProperty)
  647.     {
  648.     XEvent xev;
  649.  
  650.     /* Translate to XLib */
  651.     xev.xproperty.type = PropertyNotify;
  652.     xev.xproperty.atom = commProperty;
  653.     xev.xproperty.window = commWindow;
  654.     xev.xproperty.state = PropertyNewValue;
  655.     serverEventProc(GDK_WINDOW_XDISPLAY(widget->window), &xev);
  656.  
  657.     if (gtk_main_level() > 0)
  658.         gtk_main_quit();
  659.     }
  660.     return FALSE;
  661. }
  662. #endif
  663.  
  664.  
  665. /****************************************************************************
  666.  * Focus handlers:
  667.  */
  668.  
  669.  
  670. /*
  671.  * This is a simple state machine:
  672.  * BLINK_NONE    not blinking at all
  673.  * BLINK_OFF    blinking, cursor is not shown
  674.  * BLINK_ON    blinking, cursor is shown
  675.  */
  676.  
  677. #define BLINK_NONE  0
  678. #define BLINK_OFF   1
  679. #define BLINK_ON    2
  680.  
  681. static int blink_state = BLINK_NONE;
  682. static long_u blink_waittime = 700;
  683. static long_u blink_ontime = 400;
  684. static long_u blink_offtime = 250;
  685. static guint blink_timer = 0;
  686.  
  687.     void
  688. gui_mch_set_blinking(long waittime, long on, long off)
  689. {
  690.     blink_waittime = waittime;
  691.     blink_ontime = on;
  692.     blink_offtime = off;
  693. }
  694.  
  695. /*
  696.  * Stop the cursor blinking.  Show the cursor if it wasn't shown.
  697.  */
  698.     void
  699. gui_mch_stop_blink(void)
  700. {
  701.     if (blink_timer)
  702.     {
  703.     gtk_timeout_remove(blink_timer);
  704.     blink_timer = 0;
  705.     }
  706.     if (blink_state == BLINK_OFF)
  707.     gui_update_cursor(TRUE, FALSE);
  708.     blink_state = BLINK_NONE;
  709. }
  710.  
  711. /*ARGSUSED*/
  712.     static gint
  713. blink_cb(gpointer data)
  714. {
  715.     if (blink_state == BLINK_ON)
  716.     {
  717.     gui_undraw_cursor();
  718.     blink_state = BLINK_OFF;
  719.     blink_timer = gtk_timeout_add((guint32)blink_offtime,
  720.                    (GtkFunction) blink_cb, NULL);
  721.     }
  722.     else
  723.     {
  724.     gui_update_cursor(TRUE, FALSE);
  725.     blink_state = BLINK_ON;
  726.     blink_timer = gtk_timeout_add((guint32)blink_ontime,
  727.                    (GtkFunction) blink_cb, NULL);
  728.     }
  729.  
  730.     return FALSE;        /* don't happen again */
  731. }
  732.  
  733. /*
  734.  * Start the cursor blinking.  If it was already blinking, this restarts the
  735.  * waiting time and shows the cursor.
  736.  */
  737.     void
  738. gui_mch_start_blink(void)
  739. {
  740.     if (blink_timer)
  741.     gtk_timeout_remove(blink_timer);
  742.     /* Only switch blinking on if none of the times is zero */
  743.     if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus)
  744.     {
  745.     blink_timer = gtk_timeout_add((guint32)blink_waittime,
  746.                    (GtkFunction) blink_cb, NULL);
  747.     blink_state = BLINK_ON;
  748.     gui_update_cursor(TRUE, FALSE);
  749.     }
  750. }
  751.  
  752. /*ARGSUSED*/
  753.     static gint
  754. enter_notify_event(GtkWidget *widget, GdkEventCrossing *event, gpointer data)
  755. {
  756.     if (blink_state == BLINK_NONE)
  757.     gui_mch_start_blink();
  758.  
  759.     /* make sure keyboard input goes there */
  760.     if (gtk_socket_id == 0 || !GTK_WIDGET_HAS_FOCUS(gui.drawarea))
  761.     gtk_widget_grab_focus(gui.drawarea);
  762.  
  763.     return FALSE;
  764. }
  765.  
  766. /*ARGSUSED*/
  767.     static gint
  768. leave_notify_event(GtkWidget *widget, GdkEventCrossing *event, gpointer data)
  769. {
  770.     if (blink_state != BLINK_NONE)
  771.     gui_mch_stop_blink();
  772.  
  773.     return FALSE;
  774. }
  775.  
  776. /*ARGSUSED*/
  777.     static gint
  778. focus_in_event(GtkWidget *widget, GdkEventFocus *event, gpointer data)
  779. {
  780.     gui_focus_change(TRUE);
  781.  
  782.     if (blink_state == BLINK_NONE)
  783.     gui_mch_start_blink();
  784.  
  785.     /* make sure keyboard input goes there */
  786.     if (gtk_socket_id == 0)
  787.     gtk_widget_grab_focus(gui.drawarea);
  788.  
  789.     return TRUE;
  790. }
  791.  
  792. /*ARGSUSED*/
  793.     static gint
  794. focus_out_event(GtkWidget *widget, GdkEventFocus *event, gpointer data)
  795. {
  796.     gui_focus_change(FALSE);
  797.  
  798.     if (blink_state != BLINK_NONE)
  799.     gui_mch_stop_blink();
  800.  
  801.     return TRUE;
  802. }
  803.  
  804.  
  805. #ifdef HAVE_GTK2
  806. /*
  807.  * Translate a GDK key value to UTF-8 independently of the current locale.
  808.  * The output is written to string, which must have room for at least 6 bytes
  809.  * plus the NUL terminator.  Returns the length in bytes.
  810.  *
  811.  * This function is used in the GTK+ 2 GUI only.  The GTK+ 1 code makes use
  812.  * of GdkEventKey::string instead.  But event->string is evil; see here why:
  813.  * http://developer.gnome.org/doc/API/2.0/gdk/gdk-Event-Structures.html#GdkEventKey
  814.  */
  815.     static int
  816. keyval_to_string(unsigned int keyval, unsigned int state, char_u *string)
  817. {
  818.     int        len;
  819.     guint32 uc;
  820.  
  821.     uc = gdk_keyval_to_unicode(keyval);
  822.     if (uc != 0)
  823.     {
  824.     /* Check for CTRL-foo */
  825.     if ((state & GDK_CONTROL_MASK) && uc >= 0x20 && uc < 0x80)
  826.     {
  827.         /* These mappings look arbitrary at the first glance, but in fact
  828.          * resemble quite exactly the behaviour of the GTK+ 1.2 GUI on my
  829.          * machine.  The only difference is BS vs. DEL for CTRL-8 (makes
  830.          * more sense and is consistent with usual terminal behaviour). */
  831.         if (uc >= '@')
  832.         string[0] = uc & 0x1F;
  833.         else if (uc == '2')
  834.         string[0] = NUL;
  835.         else if (uc >= '3' && uc <= '7')
  836.         string[0] = uc ^ 0x28;
  837.         else if (uc == '8')
  838.         string[0] = BS;
  839.         else if (uc == '?')
  840.         string[0] = DEL;
  841.         else
  842.         string[0] = uc;
  843.         len = 1;
  844.     }
  845.     else
  846.     {
  847.         /* Translate a normal key to UTF-8.  This doesn't work for dead
  848.          * keys of course, you _have_ to use an input method for that. */
  849.         len = utf_char2bytes((int)uc, string);
  850.     }
  851.     }
  852.     else
  853.     {
  854.     /* Translate keys which are represented by ASCII control codes in Vim.
  855.      * There are only a few of those; most control keys are translated to
  856.      * special terminal-like control sequences. */
  857.     len = 1;
  858.     switch (keyval)
  859.     {
  860.         case GDK_Tab: case GDK_KP_Tab: case GDK_ISO_Left_Tab:
  861.         string[0] = TAB;
  862.         break;
  863.         case GDK_Linefeed:
  864.         string[0] = NL;
  865.         break;
  866.         case GDK_Return: case GDK_ISO_Enter: case GDK_3270_Enter:
  867.         string[0] = CR;
  868.         break;
  869.         case GDK_Escape:
  870.         string[0] = ESC;
  871.         break;
  872.         default:
  873.         len = 0;
  874.         break;
  875.     }
  876.     }
  877.     string[len] = NUL;
  878.  
  879.     return len;
  880. }
  881. #endif /* HAVE_GTK2 */
  882.  
  883. /*
  884.  * Main keyboard handler:
  885.  */
  886. /*ARGSUSED*/
  887.     static gint
  888. key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
  889. {
  890. #ifdef HAVE_GTK2
  891.     /* 256 bytes is way over the top, but for safety let's reduce it only
  892.      * for GTK+ 2 where we know for sure how large the string might get.
  893.      * (That is, up to 6 bytes + NUL + CSI escapes + safety measure.) */
  894.     char_u    string[32], string2[32];
  895. #else
  896.     char_u    string[256], string2[256];
  897. #endif
  898.     guint    key_sym;
  899.     int        len;
  900.     int        i;
  901.     int        modifiers;
  902.     int        key;
  903.     guint    state;
  904.     char_u    *s, *d;
  905.  
  906.     key_sym = event->keyval;
  907.     state = event->state;
  908. #ifndef HAVE_GTK2 /* deprecated */
  909.     len = event->length;
  910.     g_assert(len <= sizeof(string));
  911. #endif
  912.  
  913. #ifndef HAVE_GTK2
  914.     /*
  915.      * It appears as if we always want to consume a key-press (there currently
  916.      * aren't any 'return FALSE's), so we always do this: when running in a
  917.      * GtkPlug and not a window, we must prevent emission of the key_press
  918.      * EVENT from continuing (which is 'beyond' the level of stopping mere
  919.      * signals by returning FALSE), otherwise things like tab/cursor-keys are
  920.      * processed by the GtkPlug default handler, which moves input focus away
  921.      * from us!
  922.      * Note: This should no longer be necessary with GTK+ 2.
  923.      */
  924.     if (gtk_socket_id != 0)
  925.     gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "key_press_event");
  926. #endif
  927.  
  928. #ifdef FEAT_XIM
  929.     if (xim_queue_key_press_event(event))
  930.     return TRUE;
  931. #endif
  932.  
  933. #ifdef FEAT_HANGULIN
  934.     if (key_sym == GDK_space && (state & GDK_SHIFT_MASK))
  935.     {
  936.     hangul_input_state_toggle();
  937.     return TRUE;
  938.     }
  939. #endif
  940.  
  941. #ifdef SunXK_F36
  942.     /*
  943.      * These keys have bogus lookup strings, and trapping them here is
  944.      * easier than trying to XRebindKeysym() on them with every possible
  945.      * combination of modifiers.
  946.      */
  947.     if (key_sym == SunXK_F36 || key_sym == SunXK_F37)
  948.     len = 0;
  949.     else
  950. #endif
  951.     {
  952. #ifdef HAVE_GTK2
  953.     len = keyval_to_string(key_sym, state, string2);
  954.  
  955.     /* Careful: convert_input() doesn't handle the NUL character.
  956.      * No need to convert pure ASCII anyway, thus the len > 1 check. */
  957.     if (len > 1 && input_conv.vc_type != CONV_NONE)
  958.         len = convert_input(string2, len, sizeof(string2));
  959.  
  960.     s = string2;
  961. #else
  962. # ifdef FEAT_MBYTE
  963.     if (input_conv.vc_type != CONV_NONE)
  964.     {
  965.         mch_memmove(string2, event->string, len);
  966.         len = convert_input(string2, len, sizeof(string2));
  967.         s = string2;
  968.     }
  969.     else
  970. # endif
  971.         s = (char_u *)event->string;
  972. #endif
  973.  
  974.     d = string;
  975.     for (i = 0; i < len; ++i)
  976.     {
  977.         *d++ = s[i];
  978.         if (d[-1] == CSI && d + 2 < string + sizeof(string))
  979.         {
  980.         /* Turn CSI into K_CSI. */
  981.         *d++ = KS_EXTRA;
  982.         *d++ = (int)KE_CSI;
  983.         }
  984.     }
  985.     len = d - string;
  986.     }
  987.  
  988.     /* Shift-Tab results in Left_Tab, but we want <S-Tab> */
  989.     if (key_sym == GDK_ISO_Left_Tab)
  990.     {
  991.     key_sym = GDK_Tab;
  992.     state |= GDK_SHIFT_MASK;
  993.     }
  994.  
  995. #ifndef HAVE_GTK2 /* for GTK+ 2, we handle this in keyval_to_string() */
  996.     if ((key_sym == GDK_2 || key_sym == GDK_at) && (state & GDK_CONTROL_MASK))
  997.     {
  998.     string[0] = NUL;    /* CTRL-2 and CTRL-@ is NUL */
  999.     len = 1;
  1000.     }
  1001.     else if (len == 0 && (key_sym == GDK_space || key_sym == GDK_Tab))
  1002.     {
  1003.     /* When there are modifiers, these keys get zero length; we need the
  1004.      * original key here to be able to add a modifier below. */
  1005.     string[0] = (key_sym & 0xff);
  1006.     len = 1;
  1007.     }
  1008. #endif
  1009.  
  1010. #ifdef FEAT_MENU
  1011.     /* If there is a menu and 'wak' is "yes", or 'wak' is "menu" and the key
  1012.      * is a menu shortcut, we ignore everything with the ALT modifier. */
  1013.     if ((state & GDK_MOD1_MASK)
  1014.         && gui.menu_is_active
  1015.         && (*p_wak == 'y'
  1016.         || (*p_wak == 'm'
  1017.             && len == 1
  1018.             && gui_is_menu_shortcut(string[0]))))
  1019. # ifdef HAVE_GTK2
  1020.     /* For GTK2 we return false to signify that we haven't handled the
  1021.      * keypress, so that gtk will handle the mnemonic or accelerator. */
  1022.     return FALSE;
  1023. # else
  1024.     return TRUE;
  1025. # endif
  1026. #endif
  1027.  
  1028.     /* Check for Alt/Meta key (Mod1Mask), but not for a BS, DEL or character
  1029.      * that already has the 8th bit set.
  1030.      * Don't do this for <S-M-Tab>, that should become K_S_TAB with ALT. */
  1031.     if (len == 1
  1032.         && (state & GDK_MOD1_MASK)
  1033.         && !(key_sym == GDK_BackSpace || key_sym == GDK_Delete)
  1034.         && (string[0] & 0x80) == 0
  1035.         && !(key_sym == GDK_Tab && (state & GDK_SHIFT_MASK)))
  1036.     {
  1037.     string[0] |= 0x80;
  1038.     state &= ~GDK_MOD1_MASK;    /* don't use it again */
  1039. #ifdef FEAT_MBYTE
  1040.     if (enc_utf8) /* convert to utf-8 */
  1041.     {
  1042.         string[1] = string[0] & 0xbf;
  1043.         string[0] = ((unsigned)string[0] >> 6) + 0xc0;
  1044.         if (string[1] == CSI)
  1045.         {
  1046.         string[2] = KS_EXTRA;
  1047.         string[3] = (int)KE_CSI;
  1048.         len = 4;
  1049.         }
  1050.         else
  1051.         len = 2;
  1052.     }
  1053. #endif
  1054.     }
  1055.  
  1056.     /* Check for special keys.    Also do this when len == 1 (key has an ASCII
  1057.      * value) to detect backspace, delete and keypad keys. */
  1058.     if (len == 0 || len == 1)
  1059.     {
  1060.     for (i = 0; special_keys[i].key_sym != 0; i++)
  1061.     {
  1062.         if (special_keys[i].key_sym == key_sym)
  1063.         {
  1064.         string[0] = CSI;
  1065.         string[1] = special_keys[i].code0;
  1066.         string[2] = special_keys[i].code1;
  1067.         len = -3;
  1068.         break;
  1069.         }
  1070.     }
  1071.     }
  1072.  
  1073.     if (len == 0)   /* Unrecognized key */
  1074.     return TRUE;
  1075.  
  1076.     /* Special keys (and a few others) may have modifiers */
  1077.     if (len == -3 || key_sym == GDK_space || key_sym == GDK_Tab
  1078.         || key_sym == GDK_Return || key_sym == GDK_Linefeed
  1079.         || key_sym == GDK_Escape || key_sym == GDK_KP_Tab
  1080.         || key_sym == GDK_ISO_Enter || key_sym == GDK_3270_Enter)
  1081.     {
  1082.     modifiers = 0;
  1083.     if (state & GDK_SHIFT_MASK)
  1084.         modifiers |= MOD_MASK_SHIFT;
  1085.     if (state & GDK_CONTROL_MASK)
  1086.         modifiers |= MOD_MASK_CTRL;
  1087.     if (state & GDK_MOD1_MASK)
  1088.         modifiers |= MOD_MASK_ALT;
  1089.  
  1090.     /*
  1091.      * For some keys a shift modifier is translated into another key
  1092.      * code.
  1093.      */
  1094.     if (len == -3)
  1095.         key = TO_SPECIAL(string[1], string[2]);
  1096.     else
  1097.         key = string[0];
  1098.  
  1099.     key = simplify_key(key, &modifiers);
  1100.     if (key == CSI)
  1101.         key = K_CSI;
  1102.     if (IS_SPECIAL(key))
  1103.     {
  1104.         string[0] = CSI;
  1105.         string[1] = K_SECOND(key);
  1106.         string[2] = K_THIRD(key);
  1107.         len = 3;
  1108.     }
  1109.     else
  1110.     {
  1111.         string[0] = key;
  1112.         len = 1;
  1113.     }
  1114.  
  1115.     if (modifiers != 0)
  1116.     {
  1117.         string2[0] = CSI;
  1118.         string2[1] = KS_MODIFIER;
  1119.         string2[2] = modifiers;
  1120.         add_to_input_buf(string2, 3);
  1121.     }
  1122.     }
  1123.  
  1124.     if (len == 1 && ((string[0] == Ctrl_C && ctrl_c_interrupts)
  1125.            || (string[0] == intr_char && intr_char != Ctrl_C)))
  1126.     {
  1127.     trash_input_buf();
  1128.     got_int = TRUE;
  1129.     }
  1130.  
  1131.     add_to_input_buf(string, len);
  1132.  
  1133.     /* blank out the pointer if necessary */
  1134.     if (p_mh)
  1135.     gui_mch_mousehide(TRUE);
  1136.  
  1137.     if (gtk_main_level() > 0)
  1138.     gtk_main_quit();
  1139.  
  1140.     return TRUE;
  1141. }
  1142.  
  1143. #if defined(FEAT_XIM) && defined(HAVE_GTK2)
  1144. /*ARGSUSED0*/
  1145.     static gboolean
  1146. key_release_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
  1147. {
  1148.     /*
  1149.      * GTK+ 2 input methods may do fancy stuff on key release events too.
  1150.      * With the default IM for instance, you can enter any UCS code point
  1151.      * by holding down CTRL-SHIFT and typing hexadecimal digits.
  1152.      */
  1153.     return xim_queue_key_press_event(event);
  1154. }
  1155. #endif
  1156.  
  1157.  
  1158. /****************************************************************************
  1159.  * Selection handlers:
  1160.  */
  1161.  
  1162. /*ARGSUSED*/
  1163.     static gint
  1164. selection_clear_event(GtkWidget        *widget,
  1165.               GdkEventSelection    *event,
  1166.               gpointer        user_data)
  1167. {
  1168.     if (event->selection == clip_plus.gtk_sel_atom)
  1169.     clip_lose_selection(&clip_plus);
  1170.     else
  1171.     clip_lose_selection(&clip_star);
  1172.  
  1173.     if (gtk_main_level() > 0)
  1174.     gtk_main_quit();
  1175.  
  1176.     return TRUE;
  1177. }
  1178.  
  1179. #define RS_NONE    0    /* selection_received_cb() not called yet */
  1180. #define RS_OK    1    /* selection_received_cb() called and OK */
  1181. #define RS_FAIL    2    /* selection_received_cb() called and failed */
  1182. static int received_selection = RS_NONE;
  1183.  
  1184. /*ARGSUSED*/
  1185.     static void
  1186. selection_received_cb(GtkWidget        *widget,
  1187.               GtkSelectionData    *data,
  1188.               guint        time_,
  1189.               gpointer        user_data)
  1190. {
  1191.     VimClipboard    *cbd;
  1192.     char_u        *text;
  1193.     char_u        *tmpbuf = NULL;
  1194. #ifdef HAVE_GTK2
  1195.     guchar        *tmpbuf_utf8 = NULL;
  1196. #endif
  1197.     int            len;
  1198.     int            motion_type;
  1199.  
  1200.     if (data->selection == clip_plus.gtk_sel_atom)
  1201.     cbd = &clip_plus;
  1202.     else
  1203.     cbd = &clip_star;
  1204.  
  1205.     text = (char_u *)data->data;
  1206.     len  = data->length;
  1207.     motion_type = MCHAR;
  1208.  
  1209.     if (text == NULL || len <= 0)
  1210.     {
  1211.     received_selection = RS_FAIL;
  1212.     /* clip_free_selection(cbd); ??? */
  1213.  
  1214.     if (gtk_main_level() > 0)
  1215.         gtk_main_quit();
  1216.  
  1217.     return;
  1218.     }
  1219.  
  1220.     if (data->type == vim_atom)
  1221.     {
  1222.     motion_type = *text++;
  1223.     --len;
  1224.     }
  1225. #ifdef HAVE_GTK2
  1226.     /* gtk_selection_data_get_text() handles all the nasty details
  1227.      * and targets and encodings etc.  This rocks so hard. */
  1228.     else
  1229.     {
  1230.     tmpbuf_utf8 = gtk_selection_data_get_text(data);
  1231.     if (tmpbuf_utf8 != NULL)
  1232.     {
  1233.         len = STRLEN(tmpbuf_utf8);
  1234.         if (input_conv.vc_type != CONV_NONE)
  1235.         {
  1236.         tmpbuf = string_convert(&input_conv, tmpbuf_utf8, &len);
  1237.         if (tmpbuf != NULL)
  1238.             text = tmpbuf;
  1239.         }
  1240.         else
  1241.         text = tmpbuf_utf8;
  1242.     }
  1243.     }
  1244. #else /* !HAVE_GTK2 */
  1245. # ifdef FEAT_MBYTE
  1246.     else if (data->type == utf8_string_atom)
  1247.     {
  1248.     vimconv_T conv;
  1249.  
  1250.     conv.vc_type = CONV_NONE;
  1251.     convert_setup(&conv, (char_u *)"utf-8", p_enc);
  1252.  
  1253.     if (conv.vc_type != CONV_NONE)
  1254.     {
  1255.         tmpbuf = string_convert(&conv, text, &len);
  1256.         convert_setup(&conv, NULL, NULL);
  1257.     }
  1258.     if (tmpbuf != NULL)
  1259.         text = tmpbuf;
  1260.     }
  1261. # endif
  1262.     else if (data->type == compound_text_atom || data->type == text_atom)
  1263.     {
  1264.     char        **list = NULL;
  1265.     int        count;
  1266.     int        i;
  1267.     unsigned    tmplen = 0;
  1268.  
  1269.     count = gdk_text_property_to_text_list(data->type, data->format,
  1270.                            data->data, data->length,
  1271.                            &list);
  1272.     for (i = 0; i < count; ++i)
  1273.         tmplen += strlen(list[i]);
  1274.  
  1275.     tmpbuf = alloc(tmplen + 1);
  1276.     if (tmpbuf != NULL)
  1277.     {
  1278.         tmpbuf[0] = NUL;
  1279.         for (i = 0; i < count; ++i)
  1280.         STRCAT(tmpbuf, list[i]);
  1281.         text = tmpbuf;
  1282.         len  = tmplen;
  1283.     }
  1284.  
  1285.     if (list != NULL)
  1286.         gdk_free_text_list(list);
  1287.     }
  1288. #endif /* !HAVE_GTK2 */
  1289.  
  1290.     clip_yank_selection(motion_type, text, (long)len, cbd);
  1291.     received_selection = RS_OK;
  1292.     vim_free(tmpbuf);
  1293. #ifdef HAVE_GTK2
  1294.     g_free(tmpbuf_utf8);
  1295. #endif
  1296.  
  1297.     if (gtk_main_level() > 0)
  1298.     gtk_main_quit();
  1299. }
  1300.  
  1301. /*
  1302.  * Prepare our selection data for passing it to the external selection
  1303.  * client.
  1304.  */
  1305. /*ARGSUSED*/
  1306.     static void
  1307. selection_get_cb(GtkWidget        *widget,
  1308.          GtkSelectionData   *selection_data,
  1309.          guint            info,
  1310.          guint            time_,
  1311.          gpointer        user_data)
  1312. {
  1313.     char_u        *string;
  1314.     char_u        *tmpbuf;
  1315.     long_u        tmplen;
  1316.     int            length;
  1317.     int            motion_type;
  1318.     GdkAtom        type;
  1319.     VimClipboard    *cbd;
  1320.  
  1321.     if (selection_data->selection == clip_plus.gtk_sel_atom)
  1322.     cbd = &clip_plus;
  1323.     else
  1324.     cbd = &clip_star;
  1325.  
  1326.     if (!cbd->owned)
  1327.     return;            /* Shouldn't ever happen */
  1328.  
  1329.     if (info != (guint)TARGET_STRING
  1330. #ifdef FEAT_MBYTE
  1331.         && info != (guint)TARGET_UTF8_STRING
  1332. #endif
  1333.         && info != (guint)TARGET_VIM
  1334.         && info != (guint)TARGET_COMPOUND_TEXT
  1335.         && info != (guint)TARGET_TEXT)
  1336.     return;
  1337.  
  1338.     /* get the selection from the '*'/'+' register */
  1339.     clip_get_selection(cbd);
  1340.  
  1341.     motion_type = clip_convert_selection(&string, &tmplen, cbd);
  1342.     if (motion_type < 0 || string == NULL)
  1343.     return;
  1344.     /* Due to int arguments we can't handle more than G_MAXINT.  Also
  1345.      * reserve one extra byte for NUL or the motion type; just in case.
  1346.      * (Not that pasting 2G of text is ever going to work, but... ;-) */
  1347.     length = MIN(tmplen, (long_u)(G_MAXINT - 1));
  1348.  
  1349.     if (info == (guint)TARGET_VIM)
  1350.     {
  1351.     tmpbuf = alloc((unsigned)length + 1);
  1352.     if (tmpbuf != NULL)
  1353.     {
  1354.         tmpbuf[0] = motion_type;
  1355.         mch_memmove(tmpbuf + 1, string, (size_t)length);
  1356.     }
  1357.     /* For our own format, the first byte contains the motion type */
  1358.     ++length;
  1359.     vim_free(string);
  1360.     string = tmpbuf;
  1361.     type = vim_atom;
  1362.     }
  1363. #ifdef HAVE_GTK2
  1364.     /* gtk_selection_data_set_text() handles everything for us.  This is
  1365.      * so easy and simple and cool, it'd be insane not to use it. */
  1366.     else
  1367.     {
  1368.     if (output_conv.vc_type != CONV_NONE)
  1369.     {
  1370.         tmpbuf = string_convert(&output_conv, string, &length);
  1371.         vim_free(string);
  1372.         if (tmpbuf == NULL)
  1373.         return;
  1374.         string = tmpbuf;
  1375.     }
  1376.     /* Validate the string to avoid runtime warnings */
  1377.     if (g_utf8_validate((const char *)string, (gssize)length, NULL))
  1378.     {
  1379.         gtk_selection_data_set_text(selection_data,
  1380.                     (const char *)string, length);
  1381.     }
  1382.     vim_free(string);
  1383.     return;
  1384.     }
  1385. #else /* !HAVE_GTK2 */
  1386. # ifdef FEAT_MBYTE
  1387.     else if (info == (guint)TARGET_UTF8_STRING)
  1388.     {
  1389.     vimconv_T conv;
  1390.  
  1391.     conv.vc_type = CONV_NONE;
  1392.     convert_setup(&conv, p_enc, (char_u *)"utf-8");
  1393.  
  1394.     if (conv.vc_type != CONV_NONE)
  1395.     {
  1396.         tmpbuf = string_convert(&conv, string, &length);
  1397.         convert_setup(&conv, NULL, NULL);
  1398.         vim_free(string);
  1399.         string = tmpbuf;
  1400.     }
  1401.     type = utf8_string_atom;
  1402.     }
  1403. # endif
  1404.     else if (info == (guint)TARGET_COMPOUND_TEXT
  1405.         || info == (guint)TARGET_TEXT)
  1406.     {
  1407.     int format;
  1408.  
  1409.     /* Copy the string to ensure NUL-termination */
  1410.     tmpbuf = vim_strnsave(string, length);
  1411.     vim_free(string);
  1412.     if (tmpbuf != NULL)
  1413.     {
  1414.         gdk_string_to_compound_text((const char *)tmpbuf,
  1415.                     &type, &format, &string, &length);
  1416.         vim_free(tmpbuf);
  1417.         selection_data->type = type;
  1418.         selection_data->format = format;
  1419.         gtk_selection_data_set(selection_data, type, format, string, length);
  1420.         gdk_free_compound_text(string);
  1421.     }
  1422.     return;
  1423.     }
  1424.     else
  1425.     {
  1426.     type = GDK_TARGET_STRING;
  1427.     }
  1428. #endif /* !HAVE_GTK2 */
  1429.  
  1430.     if (string != NULL)
  1431.     {
  1432.     selection_data->type = selection_data->target;
  1433.     selection_data->format = 8;    /* 8 bits per char */
  1434.  
  1435.     gtk_selection_data_set(selection_data, type, 8, string, length);
  1436.     vim_free(string);
  1437.     }
  1438. }
  1439.  
  1440. /*
  1441.  * Check if the GUI can be started.  Called before gvimrc is sourced.
  1442.  * Return OK or FAIL.
  1443.  */
  1444.     int
  1445. gui_mch_init_check(void)
  1446. {
  1447. #ifndef HAVE_GTK2
  1448.     /* This is needed to make the locale handling consistant between the GUI
  1449.      * and the rest of VIM. */
  1450.     gtk_set_locale();
  1451. #endif
  1452.  
  1453. #ifdef FEAT_GUI_GNOME
  1454.     if (gtk_socket_id == 0)
  1455.     using_gnome = 1;
  1456. #endif
  1457.  
  1458.     /* Don't use gtk_init() or gnome_init(), it exits on failure. */
  1459.     if (!gtk_init_check(&gui_argc, &gui_argv))
  1460.     {
  1461.     gui.dying = TRUE;
  1462.     EMSG(_(e_opendisp));
  1463.     return FAIL;
  1464.     }
  1465.  
  1466.     return OK;
  1467. }
  1468.  
  1469.  
  1470. /****************************************************************************
  1471.  * Mouse handling callbacks
  1472.  */
  1473.  
  1474.  
  1475. static guint mouse_click_timer = 0;
  1476. static int mouse_timed_out = TRUE;
  1477.  
  1478. /*
  1479.  * Timer used to recognize multiple clicks of the mouse button
  1480.  */
  1481.     static gint
  1482. mouse_click_timer_cb(gpointer data)
  1483. {
  1484.     /* we don't use this information currently */
  1485.     int *timed_out = (int *) data;
  1486.  
  1487.     *timed_out = TRUE;
  1488.     return FALSE;        /* don't happen again */
  1489. }
  1490.  
  1491. static guint motion_repeat_timer  = 0;
  1492. static int   motion_repeat_offset = FALSE;
  1493. static gint  motion_repeat_timer_cb(gpointer);
  1494.  
  1495.     static void
  1496. process_motion_notify(int x, int y, GdkModifierType state)
  1497. {
  1498.     int        button;
  1499.     int_u   vim_modifiers;
  1500.  
  1501.     button = (state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK |
  1502.                GDK_BUTTON3_MASK | GDK_BUTTON4_MASK |
  1503.                GDK_BUTTON5_MASK))
  1504.           ? MOUSE_DRAG : ' ';
  1505.  
  1506.     /* If our pointer is currently hidden, then we should show it. */
  1507.     gui_mch_mousehide(FALSE);
  1508.  
  1509.     /* Just moving the rodent above the drawing area without any button
  1510.      * being pressed. */
  1511.     if (button != MOUSE_DRAG)
  1512.     {
  1513.     gui_mouse_moved(x, y);
  1514.     return;
  1515.     }
  1516.  
  1517.     /* translate modifier coding between the main engine and GTK */
  1518.     vim_modifiers = 0x0;
  1519.     if (state & GDK_SHIFT_MASK)
  1520.     vim_modifiers |= MOUSE_SHIFT;
  1521.     if (state & GDK_CONTROL_MASK)
  1522.     vim_modifiers |= MOUSE_CTRL;
  1523.     if (state & GDK_MOD1_MASK)
  1524.     vim_modifiers |= MOUSE_ALT;
  1525.  
  1526.     /* inform the editor engine about the occurence of this event */
  1527.     gui_send_mouse_event(button, x, y, FALSE, vim_modifiers);
  1528.  
  1529.     if (gtk_main_level() > 0)
  1530.     gtk_main_quit();
  1531.  
  1532.     /*
  1533.      * Auto repeat timer handling.
  1534.      */
  1535.     if (x < 0 || y < 0
  1536.         || x >= gui.drawarea->allocation.width
  1537.         || y >= gui.drawarea->allocation.height)
  1538.     {
  1539.  
  1540.     int dx;
  1541.     int dy;
  1542.     int offshoot;
  1543.     int delay = 10;
  1544.  
  1545.     /* Calculate the maximal distance of the cursor from the drawing area.
  1546.      * (offshoot can't become negative here!).
  1547.      */
  1548.     dx = x < 0 ? -x : x - gui.drawarea->allocation.width;
  1549.     dy = y < 0 ? -y : y - gui.drawarea->allocation.height;
  1550.  
  1551.     offshoot = dx > dy ? dx : dy;
  1552.  
  1553.     /* Make a linearly declaying timer delay with a threshold of 5 at a
  1554.      * distance of 127 pixels from the main window.
  1555.      *
  1556.      * One could think endlessly about the most ergonomic variant here.
  1557.      * For example it could make sense to calculate the distance from the
  1558.      * drags start instead...
  1559.      *
  1560.      * Maybe a parabolic interpolation would suite us better here too...
  1561.      */
  1562.     if (offshoot > 127)
  1563.     {
  1564.         /* 5 appears to be somehow near to my perceptual limits :-). */
  1565.         delay = 5;
  1566.     }
  1567.     else
  1568.     {
  1569.         delay = (130 * (127 - offshoot)) / 127 + 5;
  1570.     }
  1571.  
  1572.     /* shoot again */
  1573.     if (!motion_repeat_timer)
  1574.         motion_repeat_timer = gtk_timeout_add((guint32)delay,
  1575.                         motion_repeat_timer_cb, NULL);
  1576.     }
  1577. }
  1578.  
  1579. /*
  1580.  * Timer used to recognize multiple clicks of the mouse button.
  1581.  */
  1582. /*ARGSUSED0*/
  1583.     static gint
  1584. motion_repeat_timer_cb(gpointer data)
  1585. {
  1586.     int            x;
  1587.     int            y;
  1588.     GdkModifierType state;
  1589.  
  1590.     gdk_window_get_pointer(gui.drawarea->window, &x, &y, &state);
  1591.  
  1592.     if (!(state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK |
  1593.            GDK_BUTTON3_MASK | GDK_BUTTON4_MASK |
  1594.            GDK_BUTTON5_MASK)))
  1595.     {
  1596.     motion_repeat_timer = 0;
  1597.     return FALSE;
  1598.     }
  1599.  
  1600.     /* If there already is a mouse click in the input buffer, wait another
  1601.      * time (otherwise we would create a backlog of clicks) */
  1602.     if (vim_used_in_input_buf() > 10)
  1603.     return TRUE;
  1604.  
  1605.     motion_repeat_timer = 0;
  1606.  
  1607.     /*
  1608.      * Fake a motion event.
  1609.      * Trick: Pretend the mouse moved to the next character on every other
  1610.      * event, otherwise drag events will be discarded, because they are still
  1611.      * in the same character.
  1612.      */
  1613.     if (motion_repeat_offset)
  1614.     x += gui.char_width;
  1615.  
  1616.     motion_repeat_offset = !motion_repeat_offset;
  1617.     process_motion_notify(x, y, state);
  1618.  
  1619.     /* Don't happen again.  We will get reinstalled in the synthetic event
  1620.      * if needed -- thus repeating should still work. */
  1621.     return FALSE;
  1622. }
  1623.  
  1624. /*ARGSUSED2*/
  1625.     static gint
  1626. motion_notify_event(GtkWidget *widget, GdkEventMotion *event, gpointer data)
  1627. {
  1628.     if (event->is_hint)
  1629.     {
  1630.     int        x;
  1631.     int        y;
  1632.     GdkModifierType    state;
  1633.  
  1634.     gdk_window_get_pointer(widget->window, &x, &y, &state);
  1635.     process_motion_notify(x, y, state);
  1636.     }
  1637.     else
  1638.     {
  1639.     process_motion_notify((int)event->x, (int)event->y,
  1640.                   (GdkModifierType)event->state);
  1641.     }
  1642.  
  1643.     return TRUE; /* handled */
  1644. }
  1645.  
  1646.  
  1647. /*
  1648.  * Mouse button handling.  Note please that we are capturing multiple click's
  1649.  * by our own timeout mechanism instead of the one provided by GTK+ itself.
  1650.  * This is due to the way the generic VIM code is recognizing multiple clicks.
  1651.  */
  1652. /*ARGSUSED2*/
  1653.     static gint
  1654. button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
  1655. {
  1656.     int button;
  1657.     int repeated_click = FALSE;
  1658.     int x, y;
  1659.     int_u vim_modifiers;
  1660.  
  1661.     /* Make sure we have focus now we've been selected */
  1662.     if (gtk_socket_id != 0 && !GTK_WIDGET_HAS_FOCUS(widget))
  1663.     gtk_widget_grab_focus(widget);
  1664.  
  1665.     /*
  1666.      * Don't let additional events about multiple clicks send by GTK to us
  1667.      * after the initial button press event confuse us.
  1668.      */
  1669.     if (event->type != GDK_BUTTON_PRESS)
  1670.     return FALSE;
  1671.  
  1672.     x = event->x;
  1673.     y = event->y;
  1674.  
  1675.     /* Handle multiple clicks */
  1676.     if (!mouse_timed_out && mouse_click_timer)
  1677.     {
  1678.     gtk_timeout_remove(mouse_click_timer);
  1679.     mouse_click_timer = 0;
  1680.     repeated_click = TRUE;
  1681.     }
  1682.  
  1683.     mouse_timed_out = FALSE;
  1684.     mouse_click_timer = gtk_timeout_add((guint32)p_mouset,
  1685.                   mouse_click_timer_cb, &mouse_timed_out);
  1686.  
  1687.     switch (event->button)
  1688.     {
  1689.     case 1:
  1690.     button = MOUSE_LEFT;
  1691.     break;
  1692.     case 2:
  1693.     button = MOUSE_MIDDLE;
  1694.     break;
  1695.     case 3:
  1696.     button = MOUSE_RIGHT;
  1697.     break;
  1698. #ifndef HAVE_GTK2
  1699.     case 4:
  1700.     button = MOUSE_4;
  1701.     break;
  1702.     case 5:
  1703.     button = MOUSE_5;
  1704.     break;
  1705. #endif
  1706.     default:
  1707.     return FALSE;        /* Unknown button */
  1708.     }
  1709.  
  1710. #ifdef FEAT_XIM
  1711.     /* cancel any preediting */
  1712.     if (preedit_start_col != MAXCOL)
  1713.     xim_reset();
  1714. #endif
  1715.  
  1716.     vim_modifiers = 0x0;
  1717.     if (event->state & GDK_SHIFT_MASK)
  1718.     vim_modifiers |= MOUSE_SHIFT;
  1719.     if (event->state & GDK_CONTROL_MASK)
  1720.     vim_modifiers |= MOUSE_CTRL;
  1721.     if (event->state & GDK_MOD1_MASK)
  1722.     vim_modifiers |= MOUSE_ALT;
  1723.  
  1724.     gui_send_mouse_event(button, x, y, repeated_click, vim_modifiers);
  1725.     if (gtk_main_level() > 0)
  1726.     gtk_main_quit(); /* make sure the above will be handled immediately */
  1727.  
  1728.     return TRUE;
  1729. }
  1730.  
  1731. #ifdef HAVE_GTK2
  1732. /*
  1733.  * GTK+ 2 doesn't handle mouse buttons 4, 5, 6 and 7 the same way as GTK+ 1.
  1734.  * Instead, it abstracts scrolling via the new GdkEventScroll.
  1735.  */
  1736. /*ARGSUSED2*/
  1737.     static gboolean
  1738. scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data)
  1739. {
  1740.     int        button;
  1741.     int_u   vim_modifiers = 0;
  1742.  
  1743.     if (gtk_socket_id != 0 && !GTK_WIDGET_HAS_FOCUS(widget))
  1744.     gtk_widget_grab_focus(widget);
  1745.  
  1746.     switch (event->direction)
  1747.     {
  1748.     case GDK_SCROLL_UP:
  1749.         button = MOUSE_4;
  1750.         break;
  1751.     case GDK_SCROLL_DOWN:
  1752.         button = MOUSE_5;
  1753.         break;
  1754.     default: /* We don't care about left and right...  Yet. */
  1755.         return FALSE;
  1756.     }
  1757.  
  1758. # ifdef FEAT_XIM
  1759.     /* cancel any preediting */
  1760.     if (preedit_start_col != MAXCOL)
  1761.     xim_reset();
  1762. # endif
  1763.  
  1764.     if (event->state & GDK_SHIFT_MASK)
  1765.     vim_modifiers |= MOUSE_SHIFT;
  1766.     if (event->state & GDK_CONTROL_MASK)
  1767.     vim_modifiers |= MOUSE_CTRL;
  1768.     if (event->state & GDK_MOD1_MASK)
  1769.     vim_modifiers |= MOUSE_ALT;
  1770.  
  1771.     gui_send_mouse_event(button, (int)event->x, (int)event->y,
  1772.                             FALSE, vim_modifiers);
  1773.  
  1774.     if (gtk_main_level() > 0)
  1775.     gtk_main_quit(); /* make sure the above will be handled immediately */
  1776.  
  1777.     return TRUE;
  1778. }
  1779. #endif /* HAVE_GTK2 */
  1780.  
  1781.  
  1782. /*ARGSUSED*/
  1783.     static gint
  1784. button_release_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
  1785. {
  1786.     int x, y;
  1787.     int_u vim_modifiers;
  1788.  
  1789.     /* Remove any motion "machine gun" timers used for automatic further
  1790.        extension of allocation areas if outside of the applications window
  1791.        area .*/
  1792.     if (motion_repeat_timer)
  1793.     {
  1794.     gtk_timeout_remove(motion_repeat_timer);
  1795.     motion_repeat_timer = 0;
  1796.     }
  1797.  
  1798.     x = event->x;
  1799.     y = event->y;
  1800.  
  1801.     vim_modifiers = 0x0;
  1802.     if (event->state & GDK_SHIFT_MASK)
  1803.     vim_modifiers |= MOUSE_SHIFT;
  1804.     if (event->state & GDK_CONTROL_MASK)
  1805.     vim_modifiers |= MOUSE_CTRL;
  1806.     if (event->state & GDK_MOD1_MASK)
  1807.     vim_modifiers |= MOUSE_ALT;
  1808.  
  1809.     gui_send_mouse_event(MOUSE_RELEASE, x, y, FALSE, vim_modifiers);
  1810.     if (gtk_main_level() > 0)
  1811.     gtk_main_quit();    /* make sure it will be handled immediately */
  1812.  
  1813.     return TRUE;
  1814. }
  1815.  
  1816.  
  1817. #ifdef FEAT_DND
  1818. /****************************************************************************
  1819.  * Drag aNd Drop support handlers.
  1820.  */
  1821.  
  1822.     static void
  1823. drag_handle_uri_list(GdkDragContext    *context,
  1824.              GtkSelectionData    *data,
  1825.              guint        time_,
  1826.              GdkModifierType    state)
  1827. {
  1828.     char_u  **fnames;
  1829.     int        redo_dirs = FALSE;
  1830.     int        i;
  1831.     int        n;
  1832.     char_u  *start;
  1833.     char_u  *copy;
  1834.     char_u  *names;
  1835.     int        nfiles = 0;
  1836.     int        url = FALSE;
  1837.  
  1838.     names = data->data;
  1839.     copy = alloc((unsigned)(data->length + 1));
  1840.     if (copy == NULL)
  1841.     return;
  1842.     /*
  1843.      * Count how many items there may be and separate them with a NUL.
  1844.      * Apparently the items are separated with \r\n.  This is not documented,
  1845.      * thus be careful not to go past the end.    Also allow separation with NUL
  1846.      * characters.
  1847.      */
  1848.     start = copy;
  1849.     for (i = 0; i < data->length; ++i)
  1850.     {
  1851.     if (names[i] == NUL || names[i] == '\n' || names[i] == '\r')
  1852.     {
  1853.         if (start > copy && start[-1] != NUL)
  1854.         {
  1855.         ++nfiles;
  1856.         *start++ = NUL;
  1857.         }
  1858.     }
  1859.     else if (names[i] == '%' && i + 2 < data->length
  1860.                           && hexhex2nr(names + i + 1) > 0)
  1861.     {
  1862.         *start++ = hexhex2nr(names + i + 1);
  1863.         i += 2;
  1864.     }
  1865.     else
  1866.         *start++ = names[i];
  1867.     }
  1868.     if (start > copy && start[-1] != NUL)
  1869.     {
  1870.     *start = NUL;    /* last item didn't have \r or \n */
  1871.     ++nfiles;
  1872.     }
  1873.  
  1874.     fnames = (char_u **)alloc((unsigned)(nfiles * sizeof(char_u *)));
  1875.     if (fnames == NULL)
  1876.     {
  1877.     vim_free(copy);
  1878.     return;
  1879.     }
  1880.     url = FALSE;    /* Set when a non-file URL was found. */
  1881.     start = copy;
  1882.     for (n = 0; n < nfiles; ++n)
  1883.     {
  1884.     if (STRNCMP(start, "file://localhost", 16) == 0)
  1885.         start += 16;
  1886.     else
  1887.     {
  1888.         if (STRNCMP(start, "file:", 5) != 0)
  1889.         url = TRUE;
  1890.         else
  1891.         {
  1892.         start += 5;
  1893.         while (start[0] == '/' && start[1] == '/')
  1894.             ++start;
  1895.         }
  1896.     }
  1897.     fnames[n] = vim_strsave(start);
  1898.     start += STRLEN(start) + 1;
  1899.     }
  1900.  
  1901.     /* accept */
  1902.     gtk_drag_finish(context, TRUE, FALSE, time_);
  1903.  
  1904.     /* Special handling when all items are real files. */
  1905.     if (url == FALSE)
  1906.     {
  1907.     if (nfiles == 1)
  1908.     {
  1909.         if (fnames[0] != NULL && mch_isdir(fnames[0]))
  1910.         {
  1911.         /* Handle dropping a directory on Vim. */
  1912.         if (mch_chdir((char *)fnames[0]) == 0)
  1913.         {
  1914.             vim_free(fnames[0]);
  1915.             fnames[0] = NULL;
  1916.             redo_dirs = TRUE;
  1917.         }
  1918.         }
  1919.     }
  1920.     else
  1921.     {
  1922.         /* Ignore any directories */
  1923.         for (i = 0; i < nfiles; ++i)
  1924.         {
  1925.         if (fnames[i] != NULL && mch_isdir(fnames[i]))
  1926.         {
  1927.             vim_free(fnames[i]);
  1928.             fnames[i] = NULL;
  1929.         }
  1930.         }
  1931.     }
  1932.  
  1933.     if (state & GDK_SHIFT_MASK)
  1934.     {
  1935.         /* Shift held down, change to first file's directory */
  1936.         if (fnames[0] != NULL && vim_chdirfile(fnames[0]) == OK)
  1937.         redo_dirs = TRUE;
  1938.     }
  1939.     else
  1940.     {
  1941.         char_u    dirname[MAXPATHL];
  1942.         char_u    *s;
  1943.  
  1944.         /* Shorten dropped file names. */
  1945.         if (mch_dirname(dirname, MAXPATHL) == OK)
  1946.         for (i = 0; i < nfiles; ++i)
  1947.             if (fnames[i] != NULL)
  1948.             {
  1949.             s = shorten_fname(fnames[i], dirname);
  1950.             if (s != NULL && (s = vim_strsave(s)) != NULL)
  1951.             {
  1952.                 vim_free(fnames[i]);
  1953.                 fnames[i] = s;
  1954.             }
  1955.             }
  1956.     }
  1957.     }
  1958.     vim_free(copy);
  1959.  
  1960.     /* Handle the drop, :edit or :split to get to the file */
  1961.     handle_drop(nfiles, fnames, (state & GDK_CONTROL_MASK) != 0);
  1962.  
  1963.     if (redo_dirs)
  1964.     shorten_fnames(TRUE);
  1965.  
  1966.     /* Update the screen display */
  1967.     update_screen(NOT_VALID);
  1968. # ifdef FEAT_MENU
  1969.     gui_update_menus(0);
  1970. # endif
  1971.     setcursor();
  1972.     out_flush();
  1973.     gui_update_cursor(FALSE, FALSE);
  1974.     gui_mch_flush();
  1975. }
  1976.  
  1977.     static void
  1978. drag_handle_text(GdkDragContext        *context,
  1979.          GtkSelectionData   *data,
  1980.          guint            time_,
  1981.          GdkModifierType    state)
  1982. {
  1983.     char_u  dropkey[6] = {CSI, KS_MODIFIER, 0, CSI, KS_EXTRA, (char_u)KE_DROP};
  1984.     char_u  *text;
  1985.     int        len;
  1986. # ifdef FEAT_MBYTE
  1987.     char_u  *tmpbuf = NULL;
  1988. # endif
  1989.  
  1990.     text = data->data;
  1991.     len  = data->length;
  1992.  
  1993. # ifdef FEAT_MBYTE
  1994.     if (data->type == utf8_string_atom)
  1995.     {
  1996. #  ifdef HAVE_GTK2
  1997.     if (input_conv.vc_type != CONV_NONE)
  1998.         tmpbuf = string_convert(&input_conv, text, &len);
  1999. #  else
  2000.     vimconv_T conv;
  2001.  
  2002.     conv.vc_type = CONV_NONE;
  2003.     convert_setup(&conv, (char_u *)"utf-8", p_enc);
  2004.  
  2005.     if (conv.vc_type != CONV_NONE)
  2006.     {
  2007.         tmpbuf = string_convert(&conv, text, &len);
  2008.         convert_setup(&conv, NULL, NULL);
  2009.     }
  2010. #  endif
  2011.     if (tmpbuf != NULL)
  2012.         text = tmpbuf;
  2013.     }
  2014. # endif /* FEAT_MBYTE */
  2015.  
  2016.     dnd_yank_drag_data(text, (long)len);
  2017.     gtk_drag_finish(context, TRUE, FALSE, time_); /* accept */
  2018. # ifdef FEAT_MBYTE
  2019.     vim_free(tmpbuf);
  2020. # endif
  2021.  
  2022.     if (state & GDK_SHIFT_MASK)
  2023.     dropkey[2] |= MOD_MASK_SHIFT;
  2024.     if (state & GDK_CONTROL_MASK)
  2025.     dropkey[2] |= MOD_MASK_CTRL;
  2026.     if (state & GDK_MOD1_MASK)
  2027.     dropkey[2] |= MOD_MASK_ALT;
  2028.  
  2029.     if (dropkey[2] != 0)
  2030.     add_to_input_buf(dropkey, (int)sizeof(dropkey));
  2031.     else
  2032.     add_to_input_buf(dropkey + 3, (int)(sizeof(dropkey) - 3));
  2033.  
  2034.     if (gtk_main_level() > 0)
  2035.     gtk_main_quit();
  2036. }
  2037.  
  2038. /*
  2039.  * DND receiver.
  2040.  */
  2041. /*ARGSUSED2*/
  2042.     static void
  2043. drag_data_received_cb(GtkWidget        *widget,
  2044.               GdkDragContext    *context,
  2045.               gint        x,
  2046.               gint        y,
  2047.               GtkSelectionData    *data,
  2048.               guint        info,
  2049.               guint        time_,
  2050.               gpointer        user_data)
  2051. {
  2052.     GdkModifierType state;
  2053.  
  2054.     /* Guard against trash */
  2055.     if (data->data == NULL
  2056.         || data->length <= 0
  2057.         || data->format != 8
  2058.         || data->data[data->length] != '\0')
  2059.     {
  2060.     gtk_drag_finish(context, FALSE, FALSE, time_);
  2061.     return;
  2062.     }
  2063.  
  2064.     /* Get the current modifier state for proper distinguishment between
  2065.      * different operations later. */
  2066.     gdk_window_get_pointer(widget->window, NULL, NULL, &state);
  2067.  
  2068.     /* Not sure about the role of "text/plain" here... */
  2069.     if (info == (guint)TARGET_TEXT_URI_LIST)
  2070.     drag_handle_uri_list(context, data, time_, state);
  2071.     else
  2072.     drag_handle_text(context, data, time_, state);
  2073.  
  2074. }
  2075. #endif /* FEAT_DND */
  2076.  
  2077.  
  2078. #if defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION)
  2079. /*
  2080.  * GnomeClient interact callback.  Check for unsaved buffers that cannot
  2081.  * be abandoned and pop up a dialog asking the user for confirmation if
  2082.  * necessary.
  2083.  */
  2084. /*ARGSUSED0*/
  2085.     static void
  2086. sm_client_check_changed_any(GnomeClient        *client,
  2087.                 gint        key,
  2088.                 GnomeDialogType type,
  2089.                 gpointer        data)
  2090. {
  2091.     cmdmod_T    save_cmdmod;
  2092.     gboolean    shutdown_cancelled;
  2093.  
  2094.     save_cmdmod = cmdmod;
  2095.  
  2096. # ifdef FEAT_BROWSE
  2097.     cmdmod.browse = TRUE;
  2098. # endif
  2099. # if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  2100.     cmdmod.confirm = TRUE;
  2101. # endif
  2102.     /*
  2103.      * If there are changed buffers, present the user with
  2104.      * a dialog if possible, otherwise give an error message.
  2105.      */
  2106.     shutdown_cancelled = check_changed_any(FALSE);
  2107.  
  2108.     exiting = FALSE;
  2109.     cmdmod = save_cmdmod;
  2110.     setcursor(); /* position the cursor */
  2111.     out_flush();
  2112.     /*
  2113.      * If the user hit the [Cancel] button the whole shutdown
  2114.      * will be cancelled.  Wow, quite powerful feature (:
  2115.      */
  2116.     gnome_interaction_key_return(key, shutdown_cancelled);
  2117. }
  2118.  
  2119. /*
  2120.  * Generate a script that can be used to restore the current editing session.
  2121.  * Save the value of v:this_session before running :mksession in order to make
  2122.  * automagic session save fully transparent.  Return TRUE on success.
  2123.  */
  2124.     static int
  2125. write_session_file(char_u *filename)
  2126. {
  2127.     char_u        *escaped_filename;
  2128.     char        *mksession_cmdline;
  2129.     unsigned int    save_ssop_flags;
  2130.     int            failed;
  2131.  
  2132.     /*
  2133.      * Build an ex command line to create a script that restores the current
  2134.      * session if executed.  Escape the filename to avoid nasty surprises.
  2135.      */
  2136.     escaped_filename = vim_strsave_escaped(filename, escape_chars);
  2137.     if (escaped_filename == NULL)
  2138.     return FALSE;
  2139.     mksession_cmdline = g_strconcat("mksession ", (char *)escaped_filename, NULL);
  2140.     vim_free(escaped_filename);
  2141.     /*
  2142.      * Use a reasonable hardcoded set of 'sessionoptions' flags to avoid
  2143.      * unpredictable effects when the session is saved automatically.  Also,
  2144.      * we definitely need SSOP_GLOBALS to be able to restore v:this_session.
  2145.      * Don't use SSOP_BUFFERS to prevent the buffer list from becoming
  2146.      * enormously large if the GNOME session feature is used regularly.
  2147.      */
  2148.     save_ssop_flags = ssop_flags;
  2149.     ssop_flags = (SSOP_BLANK|SSOP_CURDIR|SSOP_FOLDS|SSOP_GLOBALS
  2150.           |SSOP_HELP|SSOP_OPTIONS|SSOP_WINSIZE);
  2151.  
  2152.     do_cmdline_cmd((char_u *)"let Save_VV_this_session = v:this_session");
  2153.     failed = (do_cmdline_cmd((char_u *)mksession_cmdline) == FAIL);
  2154.     do_cmdline_cmd((char_u *)"let v:this_session = Save_VV_this_session");
  2155.     do_unlet((char_u *)"Save_VV_this_session");
  2156.  
  2157.     ssop_flags = save_ssop_flags;
  2158.     g_free(mksession_cmdline);
  2159.     /*
  2160.      * Reopen the file and append a command to restore v:this_session,
  2161.      * as if this save never happened.    This is to avoid conflicts with
  2162.      * the user's own sessions.  FIXME: It's probably less hackish to add
  2163.      * a "stealth" flag to 'sessionoptions' -- gotta ask Bram.
  2164.      */
  2165.     if (!failed)
  2166.     {
  2167.     FILE *fd;
  2168.  
  2169.     fd = open_exfile(filename, TRUE, APPENDBIN);
  2170.  
  2171.     failed = (fd == NULL
  2172.            || put_line(fd, "let v:this_session = Save_VV_this_session") == FAIL
  2173.            || put_line(fd, "unlet Save_VV_this_session") == FAIL);
  2174.  
  2175.     if (fd != NULL && fclose(fd) != 0)
  2176.         failed = TRUE;
  2177.  
  2178.     if (failed)
  2179.         mch_remove(filename);
  2180.     }
  2181.  
  2182.     return !failed;
  2183. }
  2184.  
  2185. /*
  2186.  * "save_yourself" signal handler.  Initiate an interaction to ask the user
  2187.  * for confirmation if necessary.  Save the current editing session and tell
  2188.  * the session manager how to restart Vim.
  2189.  */
  2190. /*ARGSUSED1*/
  2191.     static gboolean
  2192. sm_client_save_yourself(GnomeClient        *client,
  2193.             gint            phase,
  2194.             GnomeSaveStyle        save_style,
  2195.             gboolean        shutdown,
  2196.             GnomeInteractStyle  interact_style,
  2197.             gboolean        fast,
  2198.             gpointer        data)
  2199. {
  2200.     static const char    suffix[] = "-session.vim";
  2201.     char        *session_file;
  2202.     unsigned int    len;
  2203.     gboolean        success;
  2204.  
  2205.     /* Always request an interaction if possible.  check_changed_any()
  2206.      * won't actually show a dialog unless any buffers have been modified.
  2207.      * There doesn't seem to be an obvious way to check that without
  2208.      * automatically firing the dialog.  Anyway, it works just fine. */
  2209.     if (interact_style == GNOME_INTERACT_ANY)
  2210.     gnome_client_request_interaction(client, GNOME_DIALOG_NORMAL,
  2211.                      &sm_client_check_changed_any,
  2212.                      NULL);
  2213.     out_flush();
  2214.     ml_sync_all(FALSE, FALSE); /* preserve all swap files */
  2215.  
  2216.     /* The path is unique for each session save.  We do neither know nor care
  2217.      * which session script will actually be used later.  This decision is in
  2218.      * the domain of the session manager. */
  2219.     session_file = gnome_config_get_real_path(
  2220.             gnome_client_get_config_prefix(client));
  2221.     len = strlen(session_file);
  2222.  
  2223.     if (len > 0 && session_file[len-1] == G_DIR_SEPARATOR)
  2224.     --len; /* get rid of the superfluous trailing '/' */
  2225.  
  2226.     session_file = g_renew(char, session_file, len + sizeof(suffix));
  2227.     memcpy(session_file + len, suffix, sizeof(suffix));
  2228.  
  2229.     success = write_session_file((char_u *)session_file);
  2230.  
  2231.     if (success)
  2232.     {
  2233.     const char  *argv[8];
  2234.     int        i;
  2235.  
  2236.     /* Tell the session manager how to wipe out the stored session data.
  2237.      * This isn't as dangerous as it looks, don't worry :)    session_file
  2238.      * is a unique absolute filename.  Usually it'll be something like
  2239.      * `/home/user/.gnome2/vim-XXXXXX-session.vim'. */
  2240.     i = 0;
  2241.     argv[i++] = "rm";
  2242.     argv[i++] = session_file;
  2243.     argv[i] = NULL;
  2244.  
  2245.     gnome_client_set_discard_command(client, i, (char **)argv);
  2246.  
  2247.     /* Tell the session manager how to restore the just saved session.
  2248.      * This is easily done thanks to Vim's -S option.  Pass the -f flag
  2249.      * since there's no need to fork -- it might even cause confusion.
  2250.      * Also pass the window role to give the WM something to match on.
  2251.      * The role is set in gui_mch_open(), thus should _never_ be NULL. */
  2252.     i = 0;
  2253.     argv[i++] = restart_command;
  2254.     argv[i++] = "-f";
  2255.     argv[i++] = "-g";
  2256. # ifdef HAVE_GTK2
  2257.     argv[i++] = "--role";
  2258.     argv[i++] = gtk_window_get_role(GTK_WINDOW(gui.mainwin));
  2259. # endif
  2260.     argv[i++] = "-S";
  2261.     argv[i++] = session_file;
  2262.     argv[i] = NULL;
  2263.  
  2264.     gnome_client_set_restart_command(client, i, (char **)argv);
  2265.     gnome_client_set_clone_command(client, 0, NULL);
  2266.     }
  2267.  
  2268.     g_free(session_file);
  2269.  
  2270.     return success;
  2271. }
  2272.  
  2273. /*
  2274.  * Called when the session manager wants us to die.  There isn't much to save
  2275.  * here since "save_yourself" has been emitted before (unless serious trouble
  2276.  * is happening).
  2277.  */
  2278. /*ARGSUSED0*/
  2279.     static void
  2280. sm_client_die(GnomeClient *client, gpointer data)
  2281. {
  2282.     /* Don't write messages to the GUI anymore */
  2283.     full_screen = FALSE;
  2284.  
  2285.     STRNCPY(IObuff, _("Vim: Received \"die\" request from session manager\n"),
  2286.         IOSIZE);
  2287.     IObuff[IOSIZE - 1] = NUL;
  2288.     preserve_exit();
  2289. }
  2290.  
  2291. /*
  2292.  * Connect our signal handlers to be notified on session save and shutdown.
  2293.  */
  2294.     static void
  2295. setup_save_yourself(void)
  2296. {
  2297.     GnomeClient *client;
  2298.  
  2299.     client = gnome_master_client();
  2300.  
  2301.     if (client != NULL)
  2302.     {
  2303.     /* Must use the deprecated gtk_signal_connect() for compatibility
  2304.      * with GNOME 1.  Arrgh, zombies! */
  2305.     gtk_signal_connect(GTK_OBJECT(client), "save_yourself",
  2306.                GTK_SIGNAL_FUNC(&sm_client_save_yourself), NULL);
  2307.     gtk_signal_connect(GTK_OBJECT(client), "die",
  2308.                GTK_SIGNAL_FUNC(&sm_client_die), NULL);
  2309.     }
  2310. }
  2311.  
  2312. #else /* !(FEAT_GUI_GNOME && FEAT_SESSION) */
  2313.  
  2314. # ifdef USE_XSMP
  2315. /*
  2316.  * GTK tells us that XSMP needs attention
  2317.  */
  2318. /*ARGSUSED*/
  2319.     static gboolean
  2320. local_xsmp_handle_requests(source, condition, data)
  2321.     GIOChannel        *source;
  2322.     GIOCondition    condition;
  2323.     gpointer        data;
  2324. {
  2325.     if (condition == G_IO_IN)
  2326.     {
  2327.     /* Do stuff; maybe close connection */
  2328.     if (xsmp_handle_requests() == FAIL)
  2329.         g_io_channel_unref((GIOChannel *)data);
  2330.     return TRUE;
  2331.     }
  2332.     /* Error */
  2333.     g_io_channel_unref((GIOChannel *)data);
  2334.     xsmp_close();
  2335.     return TRUE;
  2336. }
  2337. # endif /* USE_XSMP */
  2338.  
  2339. /*
  2340.  * Setup the WM_PROTOCOLS to indicate we want the WM_SAVE_YOURSELF event.
  2341.  * This is an ugly use of X functions.    GTK doesn't offer an alternative.
  2342.  */
  2343.     static void
  2344. setup_save_yourself(void)
  2345. {
  2346.     Atom    *existing_atoms = NULL;
  2347.     int        count = 0;
  2348.  
  2349. #ifdef USE_XSMP
  2350.     if (xsmp_icefd != -1)
  2351.     {
  2352.     /*
  2353.      * Use XSMP is preference to legacy WM_SAVE_YOURSELF;
  2354.      * set up GTK IO monitor
  2355.      */
  2356.     GIOChannel *g_io = g_io_channel_unix_new(xsmp_icefd);
  2357.  
  2358.     g_io_add_watch(g_io, G_IO_IN | G_IO_ERR | G_IO_HUP,
  2359.                   local_xsmp_handle_requests, (gpointer)g_io);
  2360.     }
  2361.     else
  2362. #endif
  2363.     {
  2364.     /* Fall back to old method */
  2365.  
  2366.     /* first get the existing value */
  2367.     if (XGetWMProtocols(GDK_WINDOW_XDISPLAY(gui.mainwin->window),
  2368.             GDK_WINDOW_XWINDOW(gui.mainwin->window),
  2369.             &existing_atoms, &count))
  2370.     {
  2371.         Atom    *new_atoms;
  2372.         Atom    save_yourself_xatom;
  2373.         int    i;
  2374.  
  2375.         save_yourself_xatom = GET_X_ATOM(save_yourself_atom);
  2376.  
  2377.         /* check if WM_SAVE_YOURSELF isn't there yet */
  2378.         for (i = 0; i < count; ++i)
  2379.         if (existing_atoms[i] == save_yourself_xatom)
  2380.             break;
  2381.  
  2382.         if (i == count)
  2383.         {
  2384.         /* allocate an Atoms array which is one item longer */
  2385.         new_atoms = (Atom *)alloc((unsigned)((count + 1)
  2386.                                  * sizeof(Atom)));
  2387.         if (new_atoms != NULL)
  2388.         {
  2389.             memcpy(new_atoms, existing_atoms, count * sizeof(Atom));
  2390.             new_atoms[count] = save_yourself_xatom;
  2391.             XSetWMProtocols(GDK_WINDOW_XDISPLAY(gui.mainwin->window),
  2392.                 GDK_WINDOW_XWINDOW(gui.mainwin->window),
  2393.                 new_atoms, count + 1);
  2394.             vim_free(new_atoms);
  2395.         }
  2396.         }
  2397.         XFree(existing_atoms);
  2398.     }
  2399.     }
  2400. }
  2401.  
  2402. # ifdef HAVE_GTK2
  2403. /*
  2404.  * Installing a global event filter seems to be the only way to catch
  2405.  * client messages of type WM_PROTOCOLS without overriding GDK's own
  2406.  * client message event filter.  Well, that's still better than trying
  2407.  * to guess what the GDK filter had done if it had been invoked instead
  2408.  * (This is what we did for GTK+ 1.2, see below).
  2409.  *
  2410.  * GTK2_FIXME:    This doesn't seem to work.  For some reason we never
  2411.  * receive WM_SAVE_YOURSELF even though everything is set up correctly.
  2412.  * I have the nasty feeling modern session managers just don't send this
  2413.  * deprecated message anymore.    Addition: confirmed by several people.
  2414.  *
  2415.  * The GNOME session support is much cooler anyway.  Unlike this ugly
  2416.  * WM_SAVE_YOURSELF hack it actually stores the session...  And yes,
  2417.  * it should work with KDE as well.
  2418.  */
  2419. /*ARGSUSED1*/
  2420.     static GdkFilterReturn
  2421. global_event_filter(GdkXEvent *xev, GdkEvent *event, gpointer data)
  2422. {
  2423.     XEvent *xevent = (XEvent *)xev;
  2424.  
  2425.     if (xevent != NULL
  2426.         && xevent->type == ClientMessage
  2427.         && xevent->xclient.message_type == GET_X_ATOM(wm_protocols_atom)
  2428.         && xevent->xclient.data.l[0] == GET_X_ATOM(save_yourself_atom))
  2429.     {
  2430.     out_flush();
  2431.     ml_sync_all(FALSE, FALSE); /* preserve all swap files */
  2432.     /*
  2433.      * Set the window's WM_COMMAND property, to let the window manager
  2434.      * know we are done saving ourselves.  We don't want to be
  2435.      * restarted, thus set argv to NULL.
  2436.      */
  2437.     XSetCommand(GDK_WINDOW_XDISPLAY(gui.mainwin->window),
  2438.             GDK_WINDOW_XWINDOW(gui.mainwin->window),
  2439.             NULL, 0);
  2440.     return GDK_FILTER_REMOVE;
  2441.     }
  2442.  
  2443.     return GDK_FILTER_CONTINUE;
  2444. }
  2445.  
  2446. # else /* !HAVE_GTK2 */
  2447.  
  2448. /*
  2449.  * GDK handler for X ClientMessage events.
  2450.  */
  2451. /*ARGSUSED2*/
  2452.     static GdkFilterReturn
  2453. gdk_wm_protocols_filter(GdkXEvent *xev, GdkEvent *event, gpointer data)
  2454. {
  2455.     /* From example in gdkevents.c/gdk_wm_protocols_filter */
  2456.     XEvent *xevent = (XEvent *)xev;
  2457.  
  2458.     if (xevent != NULL)
  2459.     {
  2460.     if (xevent->xclient.data.l[0] == GET_X_ATOM(save_yourself_atom))
  2461.     {
  2462.         out_flush();
  2463.         ml_sync_all(FALSE, FALSE);        /* preserve all swap files */
  2464.  
  2465.         /* Set the window's WM_COMMAND property, to let the window manager
  2466.          * know we are done saving ourselves.  We don't want to be
  2467.          * restarted, thus set argv to NULL. */
  2468.         XSetCommand(GDK_WINDOW_XDISPLAY(gui.mainwin->window),
  2469.             GDK_WINDOW_XWINDOW(gui.mainwin->window),
  2470.             NULL, 0);
  2471.     }
  2472.     /*
  2473.      * Functionality from gdkevents.c/gdk_wm_protocols_filter;
  2474.      * Registering this filter apparently overrides the default GDK one,
  2475.      * so we need to perform its functionality.  There seems no way to
  2476.      * register for WM_PROTOCOLS, and only process the WM_SAVE_YOURSELF
  2477.      * bit; it's all or nothing.  Update: No, there is a way -- but it
  2478.      * only works with GTK+ 2 apparently.  See above.
  2479.      */
  2480.     else if (xevent->xclient.data.l[0] == GET_X_ATOM(gdk_wm_delete_window))
  2481.     {
  2482.         event->any.type = GDK_DELETE;
  2483.         return GDK_FILTER_TRANSLATE;
  2484.     }
  2485.     }
  2486.  
  2487.     return GDK_FILTER_REMOVE;
  2488. }
  2489. # endif /* !HAVE_GTK2 */
  2490.  
  2491. #endif /* !(FEAT_GUI_GNOME && FEAT_SESSION) */
  2492.  
  2493.  
  2494. /*
  2495.  * Setup the window icon & xcmdsrv comm after the main window has been realized.
  2496.  */
  2497. /*ARGSUSED*/
  2498.     static void
  2499. mainwin_realize(GtkWidget *widget, gpointer data)
  2500. {
  2501. /* If you get an error message here, you still need to unpack the runtime
  2502.  * archive! */
  2503. #ifdef magick
  2504. # undef magick
  2505. #endif
  2506. #ifdef HAVE_GTK2
  2507.   /* A bit hackish, but avoids casting later and allows optimization */
  2508. # define static static const
  2509. #endif
  2510. #define magick vim32x32
  2511. #include "../runtime/vim32x32.xpm"
  2512. #undef magick
  2513. #define magick vim16x16
  2514. #include "../runtime/vim16x16.xpm"
  2515. #undef magick
  2516. #define magick vim48x48
  2517. #include "../runtime/vim48x48.xpm"
  2518. #undef magick
  2519. #ifdef HAVE_GTK2
  2520. # undef static
  2521. #endif
  2522.  
  2523.     /* When started with "--echo-wid" argument, write window ID on stdout. */
  2524.     if (echo_wid_arg)
  2525.     {
  2526.     printf("WID: %ld\n", (long)GDK_WINDOW_XWINDOW(gui.mainwin->window));
  2527.     fflush(stdout);
  2528.     }
  2529.  
  2530.     if (vim_strchr(p_go, GO_ICON) != NULL)
  2531.     {
  2532.     /*
  2533.      * Add an icon to the main window. For fun and convenience of the user.
  2534.      */
  2535. #ifdef HAVE_GTK2
  2536.     GList *icons = NULL;
  2537.  
  2538.     icons = g_list_prepend(icons, gdk_pixbuf_new_from_xpm_data(vim16x16));
  2539.     icons = g_list_prepend(icons, gdk_pixbuf_new_from_xpm_data(vim32x32));
  2540.     icons = g_list_prepend(icons, gdk_pixbuf_new_from_xpm_data(vim48x48));
  2541.  
  2542.     gtk_window_set_icon_list(GTK_WINDOW(gui.mainwin), icons);
  2543.  
  2544.     g_list_foreach(icons, (GFunc)&g_object_unref, NULL);
  2545.     g_list_free(icons);
  2546.  
  2547. #else /* !HAVE_GTK2 */
  2548.  
  2549.     GdkPixmap   *icon;
  2550.     GdkBitmap   *icon_mask = NULL;
  2551.     char        **magick = vim32x32;
  2552.     Display        *xdisplay;
  2553.     Window        root_window;
  2554.     XIconSize   *size;
  2555.     int        number_sizes;
  2556.     /*
  2557.      * Adjust the icon to the preferences of the actual window manager.
  2558.      * This is once again a workaround for a defficiency in GTK+ 1.2.
  2559.      */
  2560.     xdisplay = GDK_WINDOW_XDISPLAY(gui.mainwin->window);
  2561.     root_window = XRootWindow(xdisplay, DefaultScreen(xdisplay));
  2562.     if (XGetIconSizes(xdisplay, root_window, &size, &number_sizes))
  2563.     {
  2564.         if (number_sizes > 0)
  2565.         {
  2566.         if (size->max_height >= 48 && size->max_height >= 48)
  2567.             magick = vim48x48;
  2568.         else if (size->max_height >= 32 && size->max_height >= 32)
  2569.             magick = vim32x32;
  2570.         else if (size->max_height >= 16 && size->max_height >= 16)
  2571.             magick = vim16x16;
  2572.         }
  2573.         XFree(size);
  2574.     }
  2575.     icon = gdk_pixmap_create_from_xpm_d(gui.mainwin->window,
  2576.                         &icon_mask, NULL, magick);
  2577.     if (icon != NULL)
  2578.         /* Note: for some reason gdk_window_set_icon() doesn't acquire
  2579.          * a reference on the pixmap, thus we _have_ to leak it. */
  2580.         gdk_window_set_icon(gui.mainwin->window, NULL, icon, icon_mask);
  2581.  
  2582. #endif /* !HAVE_GTK2 */
  2583.     }
  2584.  
  2585. #if !(defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION))
  2586.     /* Register a handler for WM_SAVE_YOURSELF with GDK's low-level X I/F */
  2587. # ifdef HAVE_GTK2
  2588.     gdk_window_add_filter(NULL, &global_event_filter, NULL);
  2589. # else
  2590.     gdk_add_client_message_filter(wm_protocols_atom,
  2591.                   &gdk_wm_protocols_filter, NULL);
  2592. # endif
  2593. #endif
  2594.     /* Setup to indicate to the window manager that we want to catch the
  2595.      * WM_SAVE_YOURSELF event.    For GNOME, this connects to the session
  2596.      * manager instead. */
  2597. #if defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION)
  2598.     if (using_gnome)
  2599. #endif
  2600.     setup_save_yourself();
  2601.  
  2602. #ifdef FEAT_CLIENTSERVER
  2603.     if (serverName == NULL && serverDelayedStartName != NULL)
  2604.     {
  2605.     /* This is a :gui command in a plain vim with no previous server */
  2606.     commWindow = GDK_WINDOW_XWINDOW(gui.mainwin->window);
  2607.  
  2608.     (void)serverRegisterName(GDK_WINDOW_XDISPLAY(gui.mainwin->window),
  2609.                  serverDelayedStartName);
  2610.     }
  2611.     else
  2612.     {
  2613.     /*
  2614.      * Cannot handle "XLib-only" windows with gtk event routines, we'll
  2615.      * have to change the "server" registration to that of the main window
  2616.      * If we have not registered a name yet, remember the window
  2617.      */
  2618.     serverChangeRegisteredWindow(GDK_WINDOW_XDISPLAY(gui.mainwin->window),
  2619.                      GDK_WINDOW_XWINDOW(gui.mainwin->window));
  2620.     }
  2621.     gtk_widget_add_events(gui.mainwin, GDK_PROPERTY_CHANGE_MASK);
  2622.     gtk_signal_connect(GTK_OBJECT(gui.mainwin), "property_notify_event",
  2623.                GTK_SIGNAL_FUNC(property_event), NULL);
  2624. #endif
  2625. }
  2626.  
  2627.     static GdkCursor *
  2628. create_blank_pointer(void)
  2629. {
  2630.     GdkWindow    *root_window = NULL;
  2631.     GdkPixmap    *blank_mask;
  2632.     GdkCursor    *cursor;
  2633.     GdkColor    color = { 0, 0, 0, 0 };
  2634.     char    blank_data[] = { 0x0 };
  2635.  
  2636. #ifdef HAVE_GTK_MULTIHEAD
  2637.     root_window = gtk_widget_get_root_window(gui.mainwin);
  2638. #endif
  2639.  
  2640.     /* Create a pseudo blank pointer, which is in fact one pixel by one pixel
  2641.      * in size. */
  2642.     blank_mask = gdk_bitmap_create_from_data(root_window, blank_data, 1, 1);
  2643.     cursor = gdk_cursor_new_from_pixmap(blank_mask, blank_mask,
  2644.                     &color, &color, 0, 0);
  2645.     gdk_bitmap_unref(blank_mask);
  2646.  
  2647.     return cursor;
  2648. }
  2649.  
  2650. #ifdef HAVE_GTK_MULTIHEAD
  2651. /*ARGSUSED1*/
  2652.     static void
  2653. mainwin_screen_changed_cb(GtkWidget  *widget,
  2654.               GdkScreen  *previous_screen,
  2655.               gpointer   data)
  2656. {
  2657.     if (!gtk_widget_has_screen(widget))
  2658.     return;
  2659.  
  2660.     /*
  2661.      * Recreate the invisble mouse cursor.
  2662.      */
  2663.     if (gui.blank_pointer != NULL)
  2664.     gdk_cursor_unref(gui.blank_pointer);
  2665.  
  2666.     gui.blank_pointer = create_blank_pointer();
  2667.  
  2668.     if (gui.pointer_hidden && gui.drawarea->window != NULL)
  2669.     gdk_window_set_cursor(gui.drawarea->window, gui.blank_pointer);
  2670.  
  2671.     /*
  2672.      * Create a new PangoContext for this screen, and initialize it
  2673.      * with the current font if necessary.
  2674.      */
  2675.     if (gui.text_context != NULL)
  2676.     g_object_unref(gui.text_context);
  2677.  
  2678.     gui.text_context = gtk_widget_create_pango_context(widget);
  2679.     pango_context_set_base_dir(gui.text_context, PANGO_DIRECTION_LTR);
  2680.  
  2681.     if (gui.norm_font != NULL)
  2682.     {
  2683.     gui_mch_init_font(p_guifont, 0);
  2684.     gui_set_shellsize(FALSE, FALSE);
  2685.     }
  2686. }
  2687. #endif /* HAVE_GTK_MULTIHEAD */
  2688.  
  2689. /*
  2690.  * After the drawing area comes up, we calculate all colors and create the
  2691.  * dummy blank cursor.
  2692.  *
  2693.  * Don't try to set any VIM scrollbar sizes anywhere here. I'm relying on the
  2694.  * fact that the main VIM engine doesn't take them into account anywhere.
  2695.  */
  2696. /*ARGSUSED1*/
  2697.     static void
  2698. drawarea_realize_cb(GtkWidget *widget, gpointer data)
  2699. {
  2700.     GtkWidget *sbar;
  2701.  
  2702. #ifdef FEAT_XIM
  2703.     xim_init();
  2704. #endif
  2705.     gui_mch_new_colors();
  2706.     gui.text_gc = gdk_gc_new(gui.drawarea->window);
  2707.  
  2708.     gui.blank_pointer = create_blank_pointer();
  2709.     if (gui.pointer_hidden)
  2710.     gdk_window_set_cursor(widget->window, gui.blank_pointer);
  2711.  
  2712.     /* get the actual size of the scrollbars, if they are realized */
  2713.     sbar = firstwin->w_scrollbars[SBAR_LEFT].id;
  2714.     if (!sbar || (!gui.which_scrollbars[SBAR_LEFT]
  2715.                     && firstwin->w_scrollbars[SBAR_RIGHT].id))
  2716.     sbar = firstwin->w_scrollbars[SBAR_RIGHT].id;
  2717.     if (sbar && GTK_WIDGET_REALIZED(sbar) && sbar->allocation.width)
  2718.     gui.scrollbar_width = sbar->allocation.width;
  2719.  
  2720.     sbar = gui.bottom_sbar.id;
  2721.     if (sbar && GTK_WIDGET_REALIZED(sbar) && sbar->allocation.height)
  2722.     gui.scrollbar_height = sbar->allocation.height;
  2723. }
  2724.  
  2725. /*
  2726.  * Properly clean up on shutdown.
  2727.  */
  2728. /*ARGSUSED0*/
  2729.     static void
  2730. drawarea_unrealize_cb(GtkWidget *widget, gpointer data)
  2731. {
  2732.     /* Don't write messages to the GUI anymore */
  2733.     full_screen = FALSE;
  2734.  
  2735. #ifdef FEAT_XIM
  2736.     im_shutdown();
  2737. #endif
  2738. #ifdef HAVE_GTK2
  2739.     if (gui.ascii_glyphs != NULL)
  2740.     {
  2741.     pango_glyph_string_free(gui.ascii_glyphs);
  2742.     gui.ascii_glyphs = NULL;
  2743.     }
  2744.     if (gui.ascii_font != NULL)
  2745.     {
  2746.     g_object_unref(gui.ascii_font);
  2747.     gui.ascii_font = NULL;
  2748.     }
  2749.     g_object_unref(gui.text_context);
  2750.     gui.text_context = NULL;
  2751.  
  2752.     g_object_unref(gui.text_gc);
  2753.     gui.text_gc = NULL;
  2754.  
  2755.     gdk_cursor_unref(gui.blank_pointer);
  2756.     gui.blank_pointer = NULL;
  2757. #else
  2758.     gdk_gc_unref(gui.text_gc);
  2759.     gui.text_gc = NULL;
  2760.  
  2761.     gdk_cursor_destroy(gui.blank_pointer);
  2762.     gui.blank_pointer = NULL;
  2763. #endif
  2764. }
  2765.  
  2766. /*ARGSUSED0*/
  2767.     static void
  2768. drawarea_style_set_cb(GtkWidget    *widget,
  2769.               GtkStyle    *previous_style,
  2770.               gpointer    data)
  2771. {
  2772.     gui_mch_new_colors();
  2773. }
  2774.  
  2775. /*
  2776.  * Callback routine for the "delete_event" signal on the toplevel window.
  2777.  * Tries to vim gracefully, or refuses to exit with changed buffers.
  2778.  */
  2779. /*ARGSUSED*/
  2780.     static gint
  2781. delete_event_cb(GtkWidget *widget, GdkEventAny *event, gpointer data)
  2782. {
  2783.     gui_shell_closed();
  2784.     return TRUE;
  2785. }
  2786.  
  2787. #ifdef FEAT_TOOLBAR
  2788.  
  2789. # ifdef HAVE_GTK2
  2790. /*
  2791.  * This extra effort wouldn't be necessary if we only used stock icons in the
  2792.  * toolbar, as we do for all builtin icons.  But user-defined toolbar icons
  2793.  * shouldn't be treated differently, thus we do need this.
  2794.  */
  2795.     static void
  2796. icon_size_changed_foreach(GtkWidget *widget, gpointer user_data)
  2797. {
  2798.     if (GTK_IS_IMAGE(widget))
  2799.     {
  2800.     GtkImage *image = (GtkImage *)widget;
  2801.  
  2802.     /* User-defined icons are stored in a GtkIconSet */
  2803.     if (gtk_image_get_storage_type(image) == GTK_IMAGE_ICON_SET)
  2804.     {
  2805.         GtkIconSet    *icon_set;
  2806.         GtkIconSize    icon_size;
  2807.  
  2808.         gtk_image_get_icon_set(image, &icon_set, &icon_size);
  2809.         icon_size = (GtkIconSize)(long)user_data;
  2810.  
  2811.         gtk_icon_set_ref(icon_set);
  2812.         gtk_image_set_from_icon_set(image, icon_set, icon_size);
  2813.         gtk_icon_set_unref(icon_set);
  2814.     }
  2815.     }
  2816.     else if (GTK_IS_CONTAINER(widget))
  2817.     {
  2818.     gtk_container_foreach((GtkContainer *)widget,
  2819.                   &icon_size_changed_foreach,
  2820.                   user_data);
  2821.     }
  2822. }
  2823. # endif /* HAVE_GTK2 */
  2824.  
  2825.     static void
  2826. set_toolbar_style(GtkToolbar *toolbar)
  2827. {
  2828.     GtkToolbarStyle style;
  2829. # ifdef HAVE_GTK2
  2830.     GtkIconSize        size;
  2831.     GtkIconSize        oldsize;
  2832. # endif
  2833.  
  2834. # ifdef HAVE_GTK2
  2835.     if ((toolbar_flags & (TOOLBAR_TEXT | TOOLBAR_ICONS | TOOLBAR_HORIZ))
  2836.               == (TOOLBAR_TEXT | TOOLBAR_ICONS | TOOLBAR_HORIZ))
  2837.     style = GTK_TOOLBAR_BOTH_HORIZ;
  2838.     else
  2839. # endif
  2840.     if ((toolbar_flags & (TOOLBAR_TEXT | TOOLBAR_ICONS))
  2841.               == (TOOLBAR_TEXT | TOOLBAR_ICONS))
  2842.     style = GTK_TOOLBAR_BOTH;
  2843.     else if (toolbar_flags & TOOLBAR_TEXT)
  2844.     style = GTK_TOOLBAR_TEXT;
  2845.     else
  2846.     style = GTK_TOOLBAR_ICONS;
  2847.  
  2848.     gtk_toolbar_set_style(toolbar, style);
  2849.     gtk_toolbar_set_tooltips(toolbar, (toolbar_flags & TOOLBAR_TOOLTIPS) != 0);
  2850.  
  2851. # ifdef HAVE_GTK2
  2852.     switch (tbis_flags)
  2853.     {
  2854.     case TBIS_TINY:        size = GTK_ICON_SIZE_MENU;        break;
  2855.     case TBIS_SMALL:    size = GTK_ICON_SIZE_SMALL_TOOLBAR;    break;
  2856.     case TBIS_MEDIUM:   size = GTK_ICON_SIZE_BUTTON;    break;
  2857.     case TBIS_LARGE:    size = GTK_ICON_SIZE_LARGE_TOOLBAR;    break;
  2858.     default:        size = GTK_ICON_SIZE_INVALID;    break;
  2859.     }
  2860.     oldsize = gtk_toolbar_get_icon_size(toolbar);
  2861.  
  2862.     if (size == GTK_ICON_SIZE_INVALID)
  2863.     {
  2864.     /* Let global user preferences decide the icon size. */
  2865.     gtk_toolbar_unset_icon_size(toolbar);
  2866.     size = gtk_toolbar_get_icon_size(toolbar);
  2867.     }
  2868.     if (size != oldsize)
  2869.     {
  2870.     gtk_container_foreach(GTK_CONTAINER(toolbar),
  2871.                   &icon_size_changed_foreach,
  2872.                   GINT_TO_POINTER((int)size));
  2873.     }
  2874.     gtk_toolbar_set_icon_size(toolbar, size);
  2875. # endif
  2876. }
  2877.  
  2878. #endif /* FEAT_TOOLBAR */
  2879.  
  2880. /*
  2881.  * Initialize the GUI.    Create all the windows, set up all the callbacks etc.
  2882.  * Returns OK for success, FAIL when the GUI can't be started.
  2883.  */
  2884.     int
  2885. gui_mch_init(void)
  2886. {
  2887.     GtkWidget *vbox;
  2888.  
  2889. #ifdef FEAT_GUI_GNOME
  2890.     /* Initialize the GNOME libraries.    gnome_program_init()/gnome_init()
  2891.      * exits on failure, but that's a non-issue because we already called
  2892.      * gtk_init_check() in gui_mch_init_check(). */
  2893.     if (using_gnome)
  2894. # ifdef HAVE_GTK2
  2895.     gnome_program_init(VIMPACKAGE, VIM_VERSION_SHORT,
  2896.                LIBGNOMEUI_MODULE, gui_argc, gui_argv, NULL);
  2897. # else
  2898.     gnome_init(VIMPACKAGE, VIM_VERSION_SHORT, gui_argc, gui_argv);
  2899. # endif
  2900. #endif
  2901.     vim_free(gui_argv);
  2902.     gui_argv = NULL;
  2903.  
  2904. #ifdef HAVE_GTK2
  2905. # if GLIB_CHECK_VERSION(2,1,3)
  2906.     /* Set the human-readable application name */
  2907.     g_set_application_name("Vim");
  2908. # endif
  2909.     /*
  2910.      * Force UTF-8 output no matter what the value of 'encoding' is.
  2911.      * did_set_string_option() in option.c prohibits changing 'termencoding'
  2912.      * to something else than UTF-8 if the GUI is in use.
  2913.      */
  2914.     set_option_value((char_u *)"termencoding", 0L, (char_u *)"utf-8", 0);
  2915.  
  2916. # ifdef FEAT_TOOLBAR
  2917.     gui_gtk_register_stock_icons();
  2918. # endif
  2919.     /* FIXME: Need to install the classic icons and a gtkrc.classic file.
  2920.      * The hard part is deciding install locations and the Makefile magic. */
  2921. # if 0
  2922.     gtk_rc_parse("gtkrc");
  2923. # endif
  2924. #endif
  2925.  
  2926.     /* Initialize values */
  2927.     gui.border_width = 2;
  2928.     gui.scrollbar_width = SB_DEFAULT_WIDTH;
  2929.     gui.scrollbar_height = SB_DEFAULT_WIDTH;
  2930.     gui.fgcolor = g_new0(GdkColor, 1);
  2931.     gui.bgcolor = g_new0(GdkColor, 1);
  2932.  
  2933.     /* Initialise atoms */
  2934. #ifdef FEAT_MBYTE
  2935.     utf8_string_atom = gdk_atom_intern("UTF8_STRING", FALSE);
  2936. #endif
  2937. #ifndef HAVE_GTK2
  2938.     compound_text_atom = gdk_atom_intern("COMPOUND_TEXT", FALSE);
  2939.     text_atom = gdk_atom_intern("TEXT", FALSE);
  2940. #endif
  2941.  
  2942.     /* Set default foreground and background colors. */
  2943.     gui.norm_pixel = gui.def_norm_pixel;
  2944.     gui.back_pixel = gui.def_back_pixel;
  2945.  
  2946.     if (gtk_socket_id != 0)
  2947.     {
  2948.     GtkWidget *plug;
  2949.  
  2950.     /* Use GtkSocket from another app. */
  2951. #ifdef HAVE_GTK_MULTIHEAD
  2952.     plug = gtk_plug_new_for_display(gdk_display_get_default(),
  2953.                     gtk_socket_id);
  2954. #else
  2955.     plug = gtk_plug_new(gtk_socket_id);
  2956. #endif
  2957.     if (plug != NULL && GTK_PLUG(plug)->socket_window != NULL)
  2958.     {
  2959.         gui.mainwin = plug;
  2960.     }
  2961.     else
  2962.     {
  2963.         g_warning("Connection to GTK+ socket (ID %u) failed",
  2964.               (unsigned int)gtk_socket_id);
  2965.         /* Pretend we never wanted it if it failed (get own window) */
  2966.         gtk_socket_id = 0;
  2967.     }
  2968.     }
  2969.  
  2970.     if (gtk_socket_id == 0)
  2971.     {
  2972. #ifdef FEAT_GUI_GNOME
  2973.     if (using_gnome)
  2974.     {
  2975.         gui.mainwin = gnome_app_new("Vim", NULL);
  2976. # ifdef USE_XSMP
  2977.         /* Use the GNOME save-yourself functionality now. */
  2978.         xsmp_close();
  2979. # endif
  2980.     }
  2981.     else
  2982. #endif
  2983.         gui.mainwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  2984.     }
  2985.  
  2986.     gtk_widget_set_name(gui.mainwin, "vim-main-window");
  2987.  
  2988. #ifdef HAVE_GTK2
  2989.     /* Create the PangoContext used for drawing all text. */
  2990.     gui.text_context = gtk_widget_create_pango_context(gui.mainwin);
  2991.     pango_context_set_base_dir(gui.text_context, PANGO_DIRECTION_LTR);
  2992. #endif
  2993.  
  2994. #ifndef HAVE_GTK2
  2995.     gtk_window_set_policy(GTK_WINDOW(gui.mainwin), TRUE, TRUE, TRUE);
  2996. #endif
  2997.     gtk_container_border_width(GTK_CONTAINER(gui.mainwin), 0);
  2998.     gtk_widget_add_events(gui.mainwin, GDK_VISIBILITY_NOTIFY_MASK);
  2999.  
  3000.     gtk_signal_connect(GTK_OBJECT(gui.mainwin), "delete_event",
  3001.                GTK_SIGNAL_FUNC(&delete_event_cb), NULL);
  3002.  
  3003.     gtk_signal_connect(GTK_OBJECT(gui.mainwin), "realize",
  3004.                GTK_SIGNAL_FUNC(&mainwin_realize), NULL);
  3005. #ifdef HAVE_GTK_MULTIHEAD
  3006.     g_signal_connect(G_OBJECT(gui.mainwin), "screen_changed",
  3007.              G_CALLBACK(&mainwin_screen_changed_cb), NULL);
  3008. #endif
  3009. #ifdef HAVE_GTK2
  3010.     gui.accel_group = gtk_accel_group_new();
  3011.     gtk_window_add_accel_group(GTK_WINDOW(gui.mainwin), gui.accel_group);
  3012. #else
  3013.     gui.accel_group = gtk_accel_group_get_default();
  3014. #endif
  3015.  
  3016.     vbox = gtk_vbox_new(FALSE, 0);
  3017.  
  3018. #ifdef FEAT_GUI_GNOME
  3019.     if (using_gnome)
  3020.     {
  3021. # if defined(HAVE_GTK2) && defined(FEAT_MENU)
  3022.     /* automagically restore menubar/toolbar placement */
  3023.     gnome_app_enable_layout_config(GNOME_APP(gui.mainwin), TRUE);
  3024. # endif
  3025.     gnome_app_set_contents(GNOME_APP(gui.mainwin), vbox);
  3026.     }
  3027.     else
  3028. #endif
  3029.     {
  3030.     gtk_container_add(GTK_CONTAINER(gui.mainwin), vbox);
  3031.     gtk_widget_show(vbox);
  3032.     }
  3033.  
  3034. #ifdef FEAT_MENU
  3035.     /*
  3036.      * Create the menubar and handle
  3037.      */
  3038.     gui.menubar = gtk_menu_bar_new();
  3039.     gtk_widget_set_name(gui.menubar, "vim-menubar");
  3040.  
  3041. # ifdef FEAT_GUI_GNOME
  3042.     if (using_gnome)
  3043.     {
  3044. #  ifdef HAVE_GTK2
  3045.     BonoboDockItem *dockitem;
  3046.  
  3047.     gnome_app_set_menus(GNOME_APP(gui.mainwin), GTK_MENU_BAR(gui.menubar));
  3048.     dockitem = gnome_app_get_dock_item_by_name(GNOME_APP(gui.mainwin),
  3049.                            GNOME_APP_MENUBAR_NAME);
  3050.     gui.menubar_h = GTK_WIDGET(dockitem);
  3051. #  else
  3052.     gui.menubar_h = gnome_dock_item_new("VimMainMenu",
  3053.                         GNOME_DOCK_ITEM_BEH_EXCLUSIVE |
  3054.                         GNOME_DOCK_ITEM_BEH_NEVER_VERTICAL);
  3055.     gtk_container_add(GTK_CONTAINER(gui.menubar_h), gui.menubar);
  3056.  
  3057.     gnome_dock_add_item(GNOME_DOCK(GNOME_APP(gui.mainwin)->dock),
  3058.                 GNOME_DOCK_ITEM(gui.menubar_h),
  3059.                 GNOME_DOCK_TOP, /* placement */
  3060.                 1,    /* band_num */
  3061.                 0,    /* band_position */
  3062.                 0,    /* offset */
  3063.                 TRUE);
  3064.     gtk_widget_show(gui.menubar);
  3065. #  endif
  3066.     }
  3067.     else
  3068. # endif    /* FEAT_GUI_GNOME */
  3069.     {
  3070.     if (vim_strchr(p_go, GO_MENUS) != NULL)
  3071.         gtk_widget_show(gui.menubar);
  3072.     gtk_box_pack_start(GTK_BOX(vbox), gui.menubar, FALSE, FALSE, 0);
  3073.     }
  3074. #endif    /* FEAT_MENU */
  3075.  
  3076. #ifdef FEAT_TOOLBAR
  3077.     /*
  3078.      * Create the toolbar and handle
  3079.      */
  3080. # ifdef HAVE_GTK2
  3081.     /* some aesthetics on the toolbar */
  3082.     gtk_rc_parse_string(
  3083.         "style \"vim-toolbar-style\" {\n"
  3084.         "  GtkToolbar::button_relief = GTK_RELIEF_NONE\n"
  3085.         "}\n"
  3086.         "widget \"*.vim-toolbar\" style \"vim-toolbar-style\"\n");
  3087.     gui.toolbar = gtk_toolbar_new();
  3088.     gtk_widget_set_name(gui.toolbar, "vim-toolbar");
  3089. # else
  3090.     gui.toolbar = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL,
  3091.                   GTK_TOOLBAR_ICONS);
  3092.     gtk_toolbar_set_button_relief(GTK_TOOLBAR(gui.toolbar), GTK_RELIEF_NONE);
  3093. # endif
  3094.     set_toolbar_style(GTK_TOOLBAR(gui.toolbar));
  3095.  
  3096. # ifdef FEAT_GUI_GNOME
  3097.     if (using_gnome)
  3098.     {
  3099. #  ifdef HAVE_GTK2
  3100.     BonoboDockItem *dockitem;
  3101.  
  3102.     gnome_app_set_toolbar(GNOME_APP(gui.mainwin), GTK_TOOLBAR(gui.toolbar));
  3103.     dockitem = gnome_app_get_dock_item_by_name(GNOME_APP(gui.mainwin),
  3104.                            GNOME_APP_TOOLBAR_NAME);
  3105.     gui.toolbar_h = GTK_WIDGET(dockitem);
  3106.     gtk_container_set_border_width(GTK_CONTAINER(gui.toolbar), 0);
  3107. #  else
  3108.     GtkWidget *dockitem;
  3109.  
  3110.     dockitem = gnome_dock_item_new("VimToolBar",
  3111.                        GNOME_DOCK_ITEM_BEH_EXCLUSIVE);
  3112.     gtk_container_add(GTK_CONTAINER(dockitem), GTK_WIDGET(gui.toolbar));
  3113.     gui.toolbar_h = dockitem;
  3114.  
  3115.     gnome_dock_add_item(GNOME_DOCK(GNOME_APP(gui.mainwin)->dock),
  3116.                 GNOME_DOCK_ITEM(dockitem),
  3117.                 GNOME_DOCK_TOP,    /* placement */
  3118.                 1,    /* band_num */
  3119.                 1,    /* band_position */
  3120.                 0,    /* offset */
  3121.                 TRUE);
  3122.     gtk_container_border_width(GTK_CONTAINER(gui.toolbar), 2);
  3123.     gtk_widget_show(gui.toolbar);
  3124. #  endif
  3125.     }
  3126.     else
  3127. # endif    /* FEAT_GUI_GNOME */
  3128.     {
  3129. # ifndef HAVE_GTK2
  3130.     gtk_container_border_width(GTK_CONTAINER(gui.toolbar), 1);
  3131. # endif
  3132.     if (vim_strchr(p_go, GO_TOOLBAR) != NULL
  3133.         && (toolbar_flags & (TOOLBAR_TEXT | TOOLBAR_ICONS)))
  3134.         gtk_widget_show(gui.toolbar);
  3135.     gtk_box_pack_start(GTK_BOX(vbox), gui.toolbar, FALSE, FALSE, 0);
  3136.     }
  3137. #endif /* FEAT_TOOLBAR */
  3138.  
  3139.     gui.formwin = gtk_form_new();
  3140.     gtk_container_border_width(GTK_CONTAINER(gui.formwin), 0);
  3141.     gtk_widget_set_events(gui.formwin, GDK_EXPOSURE_MASK);
  3142.  
  3143.     gui.drawarea = gtk_drawing_area_new();
  3144.  
  3145.     /* Determine which events we will filter. */
  3146.     gtk_widget_set_events(gui.drawarea,
  3147.               GDK_EXPOSURE_MASK |
  3148.               GDK_ENTER_NOTIFY_MASK |
  3149.               GDK_LEAVE_NOTIFY_MASK |
  3150.               GDK_BUTTON_PRESS_MASK |
  3151.               GDK_BUTTON_RELEASE_MASK |
  3152. #ifdef HAVE_GTK2
  3153.               GDK_SCROLL_MASK |
  3154. #endif
  3155.               GDK_KEY_PRESS_MASK |
  3156.               GDK_KEY_RELEASE_MASK |
  3157.               GDK_POINTER_MOTION_MASK |
  3158.               GDK_POINTER_MOTION_HINT_MASK);
  3159.  
  3160.     gtk_widget_show(gui.drawarea);
  3161.     gtk_form_put(GTK_FORM(gui.formwin), gui.drawarea, 0, 0);
  3162.     gtk_widget_show(gui.formwin);
  3163.     gtk_box_pack_start(GTK_BOX(vbox), gui.formwin, TRUE, TRUE, 0);
  3164.  
  3165.     /* For GtkSockets, key-presses must go to the focus widget (drawarea)
  3166.      * and not the window. */
  3167.     gtk_signal_connect((gtk_socket_id == 0) ? GTK_OBJECT(gui.mainwin)
  3168.                         : GTK_OBJECT(gui.drawarea),
  3169.                "key_press_event",
  3170.                GTK_SIGNAL_FUNC(key_press_event), NULL);
  3171. #if defined(FEAT_XIM) && defined(HAVE_GTK2)
  3172.     /* Also forward key release events for the benefit of GTK+ 2 input
  3173.      * modules.  Try CTRL-SHIFT-xdigits to enter a Unicode code point. */
  3174.     g_signal_connect((gtk_socket_id == 0) ? G_OBJECT(gui.mainwin)
  3175.                       : G_OBJECT(gui.drawarea),
  3176.              "key_release_event",
  3177.              G_CALLBACK(&key_release_event), NULL);
  3178. #endif
  3179.     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "realize",
  3180.                GTK_SIGNAL_FUNC(drawarea_realize_cb), NULL);
  3181.     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "unrealize",
  3182.                GTK_SIGNAL_FUNC(drawarea_unrealize_cb), NULL);
  3183.  
  3184.     gtk_signal_connect_after(GTK_OBJECT(gui.drawarea), "style_set",
  3185.                  GTK_SIGNAL_FUNC(&drawarea_style_set_cb), NULL);
  3186.  
  3187.     gui.visibility = GDK_VISIBILITY_UNOBSCURED;
  3188.  
  3189. #if !(defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION))
  3190.     wm_protocols_atom = gdk_atom_intern("WM_PROTOCOLS", FALSE);
  3191.     save_yourself_atom = gdk_atom_intern("WM_SAVE_YOURSELF", FALSE);
  3192. #endif
  3193.  
  3194.     if (gtk_socket_id != 0)
  3195.     /* make sure keybord input can go to the drawarea */
  3196.     GTK_WIDGET_SET_FLAGS(gui.drawarea, GTK_CAN_FOCUS);
  3197.  
  3198.     /*
  3199.      * Set clipboard specific atoms
  3200.      */
  3201.     vim_atom = gdk_atom_intern(VIM_ATOM_NAME, FALSE);
  3202.     clip_star.gtk_sel_atom = GDK_SELECTION_PRIMARY;
  3203.     clip_plus.gtk_sel_atom = gdk_atom_intern("CLIPBOARD", FALSE);
  3204.  
  3205.     /*
  3206.      * Start out by adding the configured border width into the border offset.
  3207.      */
  3208.     gui.border_offset = gui.border_width;
  3209.  
  3210.     gtk_signal_connect(GTK_OBJECT(gui.mainwin), "visibility_notify_event",
  3211.                GTK_SIGNAL_FUNC(visibility_event), NULL);
  3212.     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "expose_event",
  3213.                GTK_SIGNAL_FUNC(expose_event), NULL);
  3214.  
  3215.     /*
  3216.      * Only install these enter/leave callbacks when 'p' in 'guioptions'.
  3217.      * Only needed for some window managers.
  3218.      */
  3219.     if (vim_strchr(p_go, GO_POINTER) != NULL)
  3220.     {
  3221.     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "leave_notify_event",
  3222.                GTK_SIGNAL_FUNC(leave_notify_event), NULL);
  3223.     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "enter_notify_event",
  3224.                GTK_SIGNAL_FUNC(enter_notify_event), NULL);
  3225.     }
  3226.  
  3227.     gtk_signal_connect(GTK_OBJECT(gui.mainwin), "focus_out_event",
  3228.                GTK_SIGNAL_FUNC(focus_out_event), NULL);
  3229.     gtk_signal_connect(GTK_OBJECT(gui.mainwin), "focus_in_event",
  3230.                GTK_SIGNAL_FUNC(focus_in_event), NULL);
  3231.  
  3232.     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "motion_notify_event",
  3233.                GTK_SIGNAL_FUNC(motion_notify_event), NULL);
  3234.     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "button_press_event",
  3235.                GTK_SIGNAL_FUNC(button_press_event), NULL);
  3236.     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "button_release_event",
  3237.                GTK_SIGNAL_FUNC(button_release_event), NULL);
  3238. #ifdef HAVE_GTK2
  3239.     g_signal_connect(G_OBJECT(gui.drawarea), "scroll_event",
  3240.              G_CALLBACK(&scroll_event), NULL);
  3241. #endif
  3242.  
  3243.     /*
  3244.      * Add selection handler functions.
  3245.      */
  3246.     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "selection_clear_event",
  3247.                GTK_SIGNAL_FUNC(selection_clear_event), NULL);
  3248.     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "selection_received",
  3249.                GTK_SIGNAL_FUNC(selection_received_cb), NULL);
  3250.  
  3251.     /*
  3252.      * Add selection targets for PRIMARY and CLIPBOARD selections.
  3253.      */
  3254.     gtk_selection_add_targets(gui.drawarea,
  3255.                   (GdkAtom)GDK_SELECTION_PRIMARY,
  3256.                   selection_targets, N_SELECTION_TARGETS);
  3257.     gtk_selection_add_targets(gui.drawarea,
  3258.                   (GdkAtom)clip_plus.gtk_sel_atom,
  3259.                   selection_targets, N_SELECTION_TARGETS);
  3260.  
  3261.     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "selection_get",
  3262.                GTK_SIGNAL_FUNC(selection_get_cb), NULL);
  3263.  
  3264.     /* Pretend we don't have input focus, we will get an event if we do. */
  3265.     gui.in_focus = FALSE;
  3266.  
  3267. #ifdef FEAT_NETBEANS_INTG
  3268.     if (usingNetbeans)
  3269.     netbeans_gtk_connect();
  3270. # endif
  3271.  
  3272.     return OK;
  3273. }
  3274.  
  3275. #if (defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION)) || defined(PROTO)
  3276. /*
  3277.  * This is called from gui_start() after a fork() has been done.
  3278.  * We have to tell the session manager our new PID.
  3279.  */
  3280.     void
  3281. gui_mch_forked(void)
  3282. {
  3283.     if (using_gnome)
  3284.     {
  3285.     GnomeClient *client;
  3286.  
  3287.     client = gnome_master_client();
  3288.  
  3289.     if (client != NULL)
  3290.         gnome_client_set_process_id(client, getpid());
  3291.     }
  3292. }
  3293. #endif /* FEAT_GUI_GNOME && FEAT_SESSION */
  3294.  
  3295. /*
  3296.  * Called when the foreground or background color has been changed.
  3297.  * This used to change the graphics contexts directly but we are
  3298.  * currently manipulating them where desired.
  3299.  */
  3300.     void
  3301. gui_mch_new_colors(void)
  3302. {
  3303.     if (gui.drawarea != NULL && gui.drawarea->window != NULL)
  3304.     {
  3305.     GdkColor color = { 0, 0, 0, 0 };
  3306.  
  3307.     color.pixel = gui.back_pixel;
  3308.     gdk_window_set_background(gui.drawarea->window, &color);
  3309.     }
  3310. }
  3311.  
  3312. #if defined(FEAT_MENU) || defined(FEAT_TOOLBAR)
  3313.     static int
  3314. get_item_dimensions(GtkWidget *widget, GtkOrientation orientation)
  3315. {
  3316.     GtkOrientation item_orientation = GTK_ORIENTATION_HORIZONTAL;
  3317.  
  3318. #ifdef FEAT_GUI_GNOME
  3319.     if (using_gnome && widget != NULL)
  3320.     {
  3321. # ifdef HAVE_GTK2
  3322.     BonoboDockItem *dockitem;
  3323.  
  3324.     widget     = gtk_widget_get_parent(widget);
  3325.     dockitem = BONOBO_DOCK_ITEM(widget);
  3326.  
  3327.     if (dockitem == NULL || dockitem->is_floating)
  3328.         return 0;
  3329.     item_orientation = bonobo_dock_item_get_orientation(dockitem);
  3330. # else
  3331.     GnomeDockItem *dockitem;
  3332.  
  3333.     widget     = widget->parent;
  3334.     dockitem = GNOME_DOCK_ITEM(widget);
  3335.  
  3336.     if (dockitem == NULL || dockitem->is_floating)
  3337.         return 0;
  3338.     item_orientation = gnome_dock_item_get_orientation(dockitem);
  3339. # endif
  3340.     }
  3341. #endif
  3342.     if (widget != NULL
  3343.         && item_orientation == orientation
  3344.         && GTK_WIDGET_REALIZED(widget)
  3345.         && GTK_WIDGET_VISIBLE(widget))
  3346.     {
  3347.     if (orientation == GTK_ORIENTATION_HORIZONTAL)
  3348.         return widget->allocation.height;
  3349.     else
  3350.         return widget->allocation.width;
  3351.     }
  3352.     return 0;
  3353. }
  3354. #endif
  3355.  
  3356.     static int
  3357. get_menu_tool_width(void)
  3358. {
  3359.     int width = 0;
  3360.  
  3361. #ifdef FEAT_GUI_GNOME /* these are never vertical without GNOME */
  3362. # ifdef FEAT_MENU
  3363.     width += get_item_dimensions(gui.menubar, GTK_ORIENTATION_VERTICAL);
  3364. # endif
  3365. # ifdef FEAT_TOOLBAR
  3366.     width += get_item_dimensions(gui.toolbar, GTK_ORIENTATION_VERTICAL);
  3367. # endif
  3368. #endif
  3369.  
  3370.     return width;
  3371. }
  3372.  
  3373.     static int
  3374. get_menu_tool_height(void)
  3375. {
  3376.     int height = 0;
  3377.  
  3378. #ifdef FEAT_MENU
  3379.     height += get_item_dimensions(gui.menubar, GTK_ORIENTATION_HORIZONTAL);
  3380. #endif
  3381. #ifdef FEAT_TOOLBAR
  3382.     height += get_item_dimensions(gui.toolbar, GTK_ORIENTATION_HORIZONTAL);
  3383. #endif
  3384.  
  3385.     return height;
  3386. }
  3387.  
  3388.     static void
  3389. update_window_manager_hints(void)
  3390. {
  3391.     static int old_width  = 0;
  3392.     static int old_height = 0;
  3393.     static int old_char_width  = 0;
  3394.     static int old_char_height = 0;
  3395.  
  3396.     int width;
  3397.     int height;
  3398.  
  3399.     /* This also needs to be done when the main window isn't there yet,
  3400.      * otherwise the hints don't work. */
  3401.     width  = gui_get_base_width();
  3402.     height = gui_get_base_height();
  3403. # ifdef HAVE_GTK2
  3404.     width  += get_menu_tool_width();
  3405.     height += get_menu_tool_height();
  3406. # endif
  3407.  
  3408.     /* Avoid an expose event when the size didn't change. */
  3409.     if (width != old_width
  3410.         || height != old_height
  3411.         || gui.char_width != old_char_width
  3412.         || gui.char_height != old_char_height)
  3413.     {
  3414.     GdkGeometry    geometry;
  3415.     GdkWindowHints    geometry_mask;
  3416.  
  3417.     geometry.width_inc   = gui.char_width;
  3418.     geometry.height_inc  = gui.char_height;
  3419.     geometry.base_width  = width;
  3420.     geometry.base_height = height;
  3421.     geometry.min_width   = width  + MIN_COLUMNS * gui.char_width;
  3422.     geometry.min_height  = height + MIN_LINES   * gui.char_height;
  3423.     geometry_mask         = GDK_HINT_BASE_SIZE|GDK_HINT_RESIZE_INC
  3424.                    |GDK_HINT_MIN_SIZE;
  3425. # ifdef HAVE_GTK2
  3426.     /* Using gui.formwin as geometry widget doesn't work as expected
  3427.      * with GTK+ 2 -- dunno why.  Presumably all the resizing hacks
  3428.      * in Vim confuse GTK+. */
  3429.     gtk_window_set_geometry_hints(GTK_WINDOW(gui.mainwin), gui.mainwin,
  3430.                       &geometry, geometry_mask);
  3431. # else
  3432.     gtk_window_set_geometry_hints(GTK_WINDOW(gui.mainwin), gui.formwin,
  3433.                       &geometry, geometry_mask);
  3434. # endif
  3435.     old_width  = width;
  3436.     old_height = height;
  3437.     old_char_width    = gui.char_width;
  3438.     old_char_height = gui.char_height;
  3439.     }
  3440. }
  3441.  
  3442. /*
  3443.  * This signal informs us about the need to rearrange our sub-widgets.
  3444.  */
  3445. /*ARGSUSED*/
  3446.     static gint
  3447. form_configure_event(GtkWidget *widget, GdkEventConfigure *event,
  3448.              gpointer data)
  3449. {
  3450.     gtk_form_freeze(GTK_FORM(gui.formwin));
  3451.     gui_resize_shell(event->width, event->height);
  3452.     gtk_form_thaw(GTK_FORM(gui.formwin));
  3453.  
  3454.     return TRUE;
  3455. }
  3456.  
  3457. /*
  3458.  * Function called when window already closed.
  3459.  * We can't do much more here than to trying to preserve what had been done,
  3460.  * since the window is already inevitably going away.
  3461.  */
  3462. /*ARGSUSED0*/
  3463.     static void
  3464. mainwin_destroy_cb(GtkObject *object, gpointer data)
  3465. {
  3466.     /* Don't write messages to the GUI anymore */
  3467.     full_screen = FALSE;
  3468.  
  3469.     gui.mainwin  = NULL;
  3470.     gui.drawarea = NULL;
  3471.  
  3472.     if (!exiting) /* only do anything if the destroy was unexpected */
  3473.     {
  3474.     STRNCPY(IObuff, _("Vim: Main window unexpectedly destroyed\n"),
  3475.         IOSIZE);
  3476.     IObuff[IOSIZE - 1] = NUL;
  3477.     preserve_exit();
  3478.     }
  3479. }
  3480.  
  3481. /*
  3482.  * Open the GUI window which was created by a call to gui_mch_init().
  3483.  */
  3484.     int
  3485. gui_mch_open(void)
  3486. {
  3487.     guicolor_T fg_pixel = INVALCOLOR;
  3488.     guicolor_T bg_pixel = INVALCOLOR;
  3489.  
  3490. #ifdef HAVE_GTK2
  3491.     /*
  3492.      * Allow setting a window role on the command line, or invent one
  3493.      * if none was specified.  This is mainly useful for GNOME session
  3494.      * support; allowing the WM to restore window placement.
  3495.      */
  3496.     if (role_argument != NULL)
  3497.     {
  3498.     gtk_window_set_role(GTK_WINDOW(gui.mainwin), role_argument);
  3499.     }
  3500.     else
  3501.     {
  3502.     char *role;
  3503.  
  3504.     /* Invent a unique-enough ID string for the role */
  3505.     role = g_strdup_printf("vim-%u-%u-%u",
  3506.                    (unsigned)mch_get_pid(),
  3507.                    (unsigned)g_random_int(),
  3508.                    (unsigned)time(NULL));
  3509.  
  3510.     gtk_window_set_role(GTK_WINDOW(gui.mainwin), role);
  3511.     g_free(role);
  3512.     }
  3513. #endif
  3514.  
  3515.     if (gui_win_x != -1 && gui_win_y != -1)
  3516. #ifdef HAVE_GTK2
  3517.     gtk_window_move(GTK_WINDOW(gui.mainwin), gui_win_x, gui_win_y);
  3518. #else
  3519.     gtk_widget_set_uposition(gui.mainwin, gui_win_x, gui_win_y);
  3520. #endif
  3521.  
  3522.     /* Determine user specified geometry, if present. */
  3523.     if (gui.geom != NULL)
  3524.     {
  3525.     int        mask;
  3526.     unsigned int    w, h;
  3527.     int        x = 0;
  3528.     int        y = 0;
  3529.  
  3530.     mask = XParseGeometry((char *)gui.geom, &x, &y, &w, &h);
  3531.  
  3532.     if (mask & WidthValue)
  3533.         Columns = w;
  3534.     if (mask & HeightValue)
  3535.         Rows = h;
  3536.     if (mask & (XValue | YValue))
  3537. #ifdef HAVE_GTK2
  3538.         gtk_window_move(GTK_WINDOW(gui.mainwin), x, y);
  3539. #else
  3540.         gtk_widget_set_uposition(gui.mainwin, x, y);
  3541. #endif
  3542.     vim_free(gui.geom);
  3543.     gui.geom = NULL;
  3544.     }
  3545.  
  3546.     gtk_form_set_size(GTK_FORM(gui.formwin),
  3547.         (guint)(gui_get_base_width() + Columns * gui.char_width),
  3548.         (guint)(gui_get_base_height() + Rows * gui.char_height));
  3549.     update_window_manager_hints();
  3550.  
  3551.     if (foreground_argument != NULL)
  3552.     fg_pixel = gui_get_color((char_u *)foreground_argument);
  3553.     if (fg_pixel == INVALCOLOR)
  3554.     fg_pixel = gui_get_color((char_u *)"Black");
  3555.  
  3556.     if (background_argument != NULL)
  3557.     bg_pixel = gui_get_color((char_u *)background_argument);
  3558.     if (bg_pixel == INVALCOLOR)
  3559.     bg_pixel = gui_get_color((char_u *)"White");
  3560.  
  3561.     if (found_reverse_arg)
  3562.     {
  3563.     gui.def_norm_pixel = bg_pixel;
  3564.     gui.def_back_pixel = fg_pixel;
  3565.     }
  3566.     else
  3567.     {
  3568.     gui.def_norm_pixel = fg_pixel;
  3569.     gui.def_back_pixel = bg_pixel;
  3570.     }
  3571.  
  3572.     /* Get the colors from the "Normal" and "Menu" group (set in syntax.c or
  3573.      * in a vimrc file) */
  3574.     set_normal_colors();
  3575.  
  3576.     /* Check that none of the colors are the same as the background color */
  3577.     gui_check_colors();
  3578.  
  3579.     /* Get the colors for the highlight groups (gui_check_colors() might have
  3580.      * changed them). */
  3581.     highlight_gui_started();    /* re-init colors and fonts */
  3582.  
  3583.     gtk_signal_connect(GTK_OBJECT(gui.mainwin), "destroy",
  3584.                GTK_SIGNAL_FUNC(mainwin_destroy_cb), NULL);
  3585.  
  3586. #ifdef FEAT_HANGULIN
  3587.     hangul_keyboard_set();
  3588. #endif
  3589.  
  3590.     /*
  3591.      * Notify the fixed area about the need to resize the contents of the
  3592.      * gui.formwin, which we use for random positioning of the included
  3593.      * components.
  3594.      *
  3595.      * We connect this signal deferred finally after anything is in place,
  3596.      * since this is intended to handle resizements coming from the window
  3597.      * manager upon us and should not interfere with what VIM is requesting
  3598.      * upon startup.
  3599.      */
  3600.     gtk_signal_connect(GTK_OBJECT(gui.formwin), "configure_event",
  3601.                GTK_SIGNAL_FUNC(form_configure_event), NULL);
  3602.  
  3603. #ifdef FEAT_DND
  3604.     /*
  3605.      * Set up for receiving DND items.
  3606.      */
  3607.     gtk_drag_dest_set(gui.drawarea,
  3608.               GTK_DEST_DEFAULT_ALL,
  3609.               dnd_targets, N_DND_TARGETS,
  3610.               GDK_ACTION_COPY);
  3611.  
  3612.     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "drag_data_received",
  3613.                GTK_SIGNAL_FUNC(drag_data_received_cb), NULL);
  3614. #endif
  3615.  
  3616. #ifdef HAVE_GTK2
  3617.     /* With GTK+ 2, we need to iconify the window before calling show()
  3618.      * to avoid mapping the window for a short time.  This is just as one
  3619.      * would expect it to work, but it's different in GTK+ 1.  The funny
  3620.      * thing is that iconifying after show() _does_ work with GTK+ 1.
  3621.      * (BTW doing this in the "realize" handler makes no difference.) */
  3622.     if (found_iconic_arg && gtk_socket_id == 0)
  3623.         gui_mch_iconify();
  3624. #endif
  3625.  
  3626.     {
  3627. #if defined(FEAT_GUI_GNOME) && defined(HAVE_GTK2) && defined(FEAT_MENU)
  3628.     unsigned long menu_handler = 0;
  3629. # ifdef FEAT_TOOLBAR
  3630.     unsigned long tool_handler = 0;
  3631. # endif
  3632.     /*
  3633.      * Urgh hackish :/  For some reason BonoboDockLayout always forces a
  3634.      * show when restoring the saved layout configuration.    We can't just
  3635.      * hide the widgets again after gtk_widget_show(gui.mainwin) since it's
  3636.      * a toplevel window and thus will be realized immediately.  Instead,
  3637.      * connect signal handlers to hide the widgets just after they've been
  3638.      * marked visible, but before the main window is realized.
  3639.      */
  3640.     if (using_gnome && vim_strchr(p_go, GO_MENUS) == NULL)
  3641.         menu_handler = g_signal_connect_after(gui.menubar_h, "show",
  3642.                           G_CALLBACK(>k_widget_hide),
  3643.                           NULL);
  3644. # ifdef FEAT_TOOLBAR
  3645.     if (using_gnome && vim_strchr(p_go, GO_TOOLBAR) == NULL
  3646.         && (toolbar_flags & (TOOLBAR_TEXT | TOOLBAR_ICONS)))
  3647.         tool_handler = g_signal_connect_after(gui.toolbar_h, "show",
  3648.                           G_CALLBACK(>k_widget_hide),
  3649.                           NULL);
  3650. # endif
  3651. #endif
  3652.     gtk_widget_show(gui.mainwin);
  3653.  
  3654. #if defined(FEAT_GUI_GNOME) && defined(HAVE_GTK2) && defined(FEAT_MENU)
  3655.     if (menu_handler != 0)
  3656.         g_signal_handler_disconnect(gui.menubar_h, menu_handler);
  3657. # ifdef FEAT_TOOLBAR
  3658.     if (tool_handler != 0)
  3659.         g_signal_handler_disconnect(gui.toolbar_h, tool_handler);
  3660. # endif
  3661. #endif
  3662.     }
  3663.  
  3664. #ifndef HAVE_GTK2
  3665.     /* With GTK+ 1, we need to iconify the window after calling show().
  3666.      * See the comment above for details. */
  3667.     if (found_iconic_arg && gtk_socket_id == 0)
  3668.         gui_mch_iconify();
  3669. #endif
  3670.  
  3671.     return OK;
  3672. }
  3673.  
  3674.  
  3675. /*ARGSUSED0*/
  3676.     void
  3677. gui_mch_exit(int rc)
  3678. {
  3679.     if (gui.mainwin != NULL)
  3680.     gtk_widget_destroy(gui.mainwin);
  3681.  
  3682.     if (gtk_main_level() > 0)
  3683.     gtk_main_quit();
  3684. }
  3685.  
  3686. /*
  3687.  * Get the position of the top left corner of the window.
  3688.  */
  3689.     int
  3690. gui_mch_get_winpos(int *x, int *y)
  3691. {
  3692. #ifdef HAVE_GTK2
  3693.     gtk_window_get_position(GTK_WINDOW(gui.mainwin), x, y);
  3694. #else
  3695.     /* For some people this must be gdk_window_get_origin() for a correct
  3696.      * result.    Where is the documentation! */
  3697.     gdk_window_get_root_origin(gui.mainwin->window, x, y);
  3698. #endif
  3699.     return OK;
  3700. }
  3701.  
  3702. /*
  3703.  * Set the position of the top left corner of the window to the given
  3704.  * coordinates.
  3705.  */
  3706.     void
  3707. gui_mch_set_winpos(int x, int y)
  3708. {
  3709. #ifdef HAVE_GTK2
  3710.     gtk_window_move(GTK_WINDOW(gui.mainwin), x, y);
  3711. #else
  3712.     gdk_window_move(gui.mainwin->window, x, y);
  3713. #endif
  3714. }
  3715.  
  3716. #ifdef HAVE_GTK2
  3717. static int resize_idle_installed = FALSE;
  3718. /*
  3719.  * Idle handler to force resize.  Used by gui_mch_set_shellsize() to ensure
  3720.  * the shell size doesn't exceed the window size, i.e. if the window manager
  3721.  * ignored our size request.  Usually this happens if the window is maximized.
  3722.  *
  3723.  * FIXME: It'd be nice if we could find a little more orthodox solution.
  3724.  * See also the rant below in gui_mch_set_shellsize().
  3725.  */
  3726. /*ARGSUSED0*/
  3727.     static gboolean
  3728. force_shell_resize_idle(gpointer data)
  3729. {
  3730.     if (gui.mainwin != NULL
  3731.         && GTK_WIDGET_REALIZED(gui.mainwin)
  3732.         && GTK_WIDGET_VISIBLE(gui.mainwin))
  3733.     {
  3734.     int width;
  3735.     int height;
  3736.  
  3737.     gtk_window_get_size(GTK_WINDOW(gui.mainwin), &width, &height);
  3738.  
  3739.     width  -= get_menu_tool_width();
  3740.     height -= get_menu_tool_height();
  3741.  
  3742.     gui_resize_shell(width, height);
  3743.     }
  3744.  
  3745.     resize_idle_installed = FALSE;
  3746.     return FALSE; /* don't call me again */
  3747. }
  3748. #endif /* HAVE_GTK2 */
  3749.  
  3750. /*
  3751.  * Set the windows size.
  3752.  */
  3753. /*ARGSUSED2*/
  3754.     void
  3755. gui_mch_set_shellsize(int width, int height,
  3756.               int min_width,  int min_height,
  3757.               int base_width, int base_height)
  3758. {
  3759. #ifndef HAVE_GTK2
  3760.     /* Hack: When the form already is at the desired size, the window might
  3761.      * have been resized with the mouse.  Force a resize by setting a
  3762.      * different size first. */
  3763.     if (GTK_FORM(gui.formwin)->width == width
  3764.         && GTK_FORM(gui.formwin)->height == height)
  3765.     {
  3766.     gtk_form_set_size(GTK_FORM(gui.formwin), width + 1, height + 1);
  3767.     gui_mch_update();
  3768.     }
  3769.     gtk_form_set_size(GTK_FORM(gui.formwin), width, height);
  3770. #endif
  3771.  
  3772.     /* give GTK+ a chance to put all widget's into place */
  3773.     gui_mch_update();
  3774.  
  3775.     /* this will cause the proper resizement to happen too */
  3776.     update_window_manager_hints();
  3777.  
  3778. #ifdef HAVE_GTK2
  3779.     /* With GTK+ 2, changing the size of the form widget doesn't resize
  3780.      * the window.  So lets do it the other way around and resize the
  3781.      * main window instead. */
  3782.     width  += get_menu_tool_width();
  3783.     height += get_menu_tool_height();
  3784.  
  3785.     gtk_window_resize(GTK_WINDOW(gui.mainwin), width, height);
  3786.  
  3787.     if (!resize_idle_installed)
  3788.     {
  3789.     g_idle_add_full(GDK_PRIORITY_EVENTS + 10,
  3790.             &force_shell_resize_idle, NULL, NULL);
  3791.     resize_idle_installed = TRUE;
  3792.     }
  3793.     /*
  3794.      * Wait until all events are processed to prevent a crash because the
  3795.      * real size of the drawing area doesn't reflect Vim's internal ideas.
  3796.      *
  3797.      * This is obviously a hack and only necessary because the entire GUI
  3798.      * code of Vim is a hack as well.  The root cause of the problem is that
  3799.      * Vim tries really hard to ignore the asynchronous nature of X.  The
  3800.      * whole *concept* of the GUI code is badly broken beyond repair.  It's
  3801.      * almost a philosophical issue: instead of trying to control everything
  3802.      * Vim should rather try to cooperate for a change.
  3803.      */
  3804.     gui_mch_update();
  3805. #endif
  3806. }
  3807.  
  3808.  
  3809. /*
  3810.  * The screen size is used to make sure the initial window doesn't get bigger
  3811.  * than the screen.  This subtracts some room for menubar, toolbar and window
  3812.  * decorations.
  3813.  */
  3814.     void
  3815. gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
  3816. {
  3817. #ifdef HAVE_GTK_MULTIHEAD
  3818.     GdkScreen* screen;
  3819.  
  3820.     if (gui.mainwin != NULL && gtk_widget_has_screen(gui.mainwin))
  3821.     screen = gtk_widget_get_screen(gui.mainwin);
  3822.     else
  3823.     screen = gdk_screen_get_default();
  3824.  
  3825.     *screen_w = gdk_screen_get_width(screen);
  3826.     *screen_h = gdk_screen_get_height(screen) - p_ghr;
  3827. #else
  3828.     *screen_w = gdk_screen_width();
  3829.     /* Subtract 'guiheadroom' from the height to allow some room for the
  3830.      * window manager (task list and window title bar). */
  3831.     *screen_h = gdk_screen_height() - p_ghr;
  3832. #endif
  3833.  
  3834.     /*
  3835.      * FIXME: dirty trick: Because the gui_get_base_height() doesn't include
  3836.      * the toolbar and menubar for GTK, we subtract them from the screen
  3837.      * hight, so that the window size can be made to fit on the screen.
  3838.      * This should be completely changed later.
  3839.      */
  3840.     *screen_w -= get_menu_tool_width();
  3841.     *screen_h -= get_menu_tool_height();
  3842. }
  3843.  
  3844. #if defined(FEAT_TITLE) || defined(PROTO)
  3845. /*ARGSUSED*/
  3846.     void
  3847. gui_mch_settitle(char_u *title, char_u *icon)
  3848. {
  3849. # ifdef HAVE_GTK2
  3850.     if (title != NULL && output_conv.vc_type != CONV_NONE)
  3851.     title = string_convert(&output_conv, title, NULL);
  3852. # endif
  3853.  
  3854.     gtk_window_set_title(GTK_WINDOW(gui.mainwin), (const char *)title);
  3855.  
  3856. # ifdef HAVE_GTK2
  3857.     if (output_conv.vc_type != CONV_NONE)
  3858.     vim_free(title);
  3859. # endif
  3860. }
  3861. #endif /* FEAT_TITLE */
  3862.  
  3863. #if defined(FEAT_MENU) || defined(PROTO)
  3864.     void
  3865. gui_mch_enable_menu(int showit)
  3866. {
  3867.     GtkWidget *widget;
  3868.  
  3869. # ifdef FEAT_GUI_GNOME
  3870.     if (using_gnome)
  3871.     widget = gui.menubar_h;
  3872.     else
  3873. # endif
  3874.     widget = gui.menubar;
  3875.  
  3876.     if (!showit != !GTK_WIDGET_VISIBLE(widget))
  3877.     {
  3878.     if (showit)
  3879.         gtk_widget_show(widget);
  3880.     else
  3881.         gtk_widget_hide(widget);
  3882.  
  3883.     update_window_manager_hints();
  3884.     }
  3885. }
  3886. #endif /* FEAT_MENU */
  3887.  
  3888. #if defined(FEAT_TOOLBAR) || defined(PROTO)
  3889.     void
  3890. gui_mch_show_toolbar(int showit)
  3891. {
  3892.     GtkWidget *widget;
  3893.  
  3894.     if (gui.toolbar == NULL)
  3895.     return;
  3896.  
  3897. # ifdef FEAT_GUI_GNOME
  3898.     if (using_gnome)
  3899.     widget = gui.toolbar_h;
  3900.     else
  3901. # endif
  3902.     widget = gui.toolbar;
  3903.  
  3904.     if (showit)
  3905.     set_toolbar_style(GTK_TOOLBAR(gui.toolbar));
  3906.  
  3907.     if (!showit != !GTK_WIDGET_VISIBLE(widget))
  3908.     {
  3909.     if (showit)
  3910.         gtk_widget_show(widget);
  3911.     else
  3912.         gtk_widget_hide(widget);
  3913.  
  3914.     update_window_manager_hints();
  3915.     }
  3916. }
  3917. #endif /* FEAT_TOOLBAR */
  3918.  
  3919. #ifndef HAVE_GTK2
  3920. /*
  3921.  * Get a font structure for highlighting.
  3922.  * "cbdata" is a pointer to the global gui structure.
  3923.  */
  3924. /*ARGSUSED*/
  3925.     static void
  3926. font_sel_ok(GtkWidget *wgt, gpointer cbdata)
  3927. {
  3928.     gui_T *vw = (gui_T *)cbdata;
  3929.     GtkFontSelectionDialog *fs = (GtkFontSelectionDialog *)vw->fontdlg;
  3930.  
  3931.     if (vw->fontname)
  3932.     g_free(vw->fontname);
  3933.  
  3934.     vw->fontname = (char_u *)gtk_font_selection_dialog_get_font_name(fs);
  3935.     gtk_widget_hide(vw->fontdlg);
  3936.     if (gtk_main_level() > 0)
  3937.     gtk_main_quit();
  3938. }
  3939.  
  3940. /*ARGSUSED*/
  3941.     static void
  3942. font_sel_cancel(GtkWidget *wgt, gpointer cbdata)
  3943. {
  3944.     gui_T *vw = (gui_T *)cbdata;
  3945.  
  3946.     gtk_widget_hide(vw->fontdlg);
  3947.     if (gtk_main_level() > 0)
  3948.     gtk_main_quit();
  3949. }
  3950.  
  3951. /*ARGSUSED*/
  3952.     static void
  3953. font_sel_destroy(GtkWidget *wgt, gpointer cbdata)
  3954. {
  3955.     gui_T *vw = (gui_T *)cbdata;
  3956.  
  3957.     vw->fontdlg = NULL;
  3958.     if (gtk_main_level() > 0)
  3959.     gtk_main_quit();
  3960. }
  3961. #endif /* !HAVE_GTK2 */
  3962.  
  3963. #ifdef HAVE_GTK2
  3964. /*
  3965.  * Check if a given font is a CJK font. This is done in a very crude manner. It
  3966.  * just see if U+04E00 for zh and ja and U+AC00 for ko are covered in a given
  3967.  * font. Consequently, this function cannot  be used as a general purpose check
  3968.  * for CJK-ness for which fontconfig APIs should be used.  This is only used by
  3969.  * gui_mch_init_font() to deal with 'CJK fixed width fonts'.
  3970.  */
  3971.     static int
  3972. is_cjk_font(PangoFontDescription *font_desc)
  3973. {
  3974.     static const char * const cjk_langs[] =
  3975.     {"zh_CN", "zh_TW", "zh_HK", "ja", "ko"};
  3976.  
  3977.     PangoFont    *font;
  3978.     unsigned    i;
  3979.     int        is_cjk = FALSE;
  3980.  
  3981.     font = pango_context_load_font(gui.text_context, font_desc);
  3982.  
  3983.     if (font == NULL)
  3984.     return FALSE;
  3985.  
  3986.     for (i = 0; !is_cjk && i < G_N_ELEMENTS(cjk_langs); ++i)
  3987.     {
  3988.     PangoCoverage    *coverage;
  3989.     gunichar    uc;
  3990.  
  3991.     coverage = pango_font_get_coverage(
  3992.         font, pango_language_from_string(cjk_langs[i]));
  3993.  
  3994.     if (coverage != NULL)
  3995.     {
  3996.         uc = (cjk_langs[i][0] == 'k') ? 0xAC00 : 0x4E00;
  3997.         is_cjk = (pango_coverage_get(coverage, uc) == PANGO_COVERAGE_EXACT);
  3998.         pango_coverage_unref(coverage);
  3999.     }
  4000.     }
  4001.  
  4002.     g_object_unref(font);
  4003.  
  4004.     return is_cjk;
  4005. }
  4006. #endif /* HAVE_GTK2 */
  4007.  
  4008.     int
  4009. gui_mch_adjust_charsize(void)
  4010. {
  4011. #ifdef HAVE_GTK2
  4012.     PangoFontMetrics    *metrics;
  4013.     int            ascent;
  4014.     int            descent;
  4015.  
  4016.     metrics = pango_context_get_metrics(gui.text_context, gui.norm_font,
  4017.                 pango_context_get_language(gui.text_context));
  4018.     ascent  = pango_font_metrics_get_ascent(metrics);
  4019.     descent = pango_font_metrics_get_descent(metrics);
  4020.  
  4021.     pango_font_metrics_unref(metrics);
  4022.  
  4023.     gui.char_height = (ascent + descent + PANGO_SCALE - 1) / PANGO_SCALE
  4024.               + p_linespace;
  4025.     gui.char_ascent = PANGO_PIXELS(ascent + p_linespace * PANGO_SCALE / 2);
  4026.  
  4027. #else /* !HAVE_GTK2 */
  4028.  
  4029.     gui.char_height = gui.current_font->ascent + gui.current_font->descent
  4030.               + p_linespace;
  4031.     gui.char_ascent = gui.current_font->ascent + p_linespace / 2;
  4032.  
  4033. #endif /* !HAVE_GTK2 */
  4034.  
  4035.     /* A not-positive value of char_height may crash Vim.  Only happens
  4036.      * if 'linespace' is negative (which does make sense sometimes). */
  4037.     gui.char_ascent = MAX(gui.char_ascent, 0);
  4038.     gui.char_height = MAX(gui.char_height, gui.char_ascent + 1);
  4039.  
  4040.     return OK;
  4041. }
  4042.  
  4043. #if defined(FEAT_XFONTSET) || defined(PROTO)
  4044. /*
  4045.  * Try to load the requested fontset.
  4046.  */
  4047. /*ARGSUSED2*/
  4048.     GuiFontset
  4049. gui_mch_get_fontset(char_u *name, int report_error, int fixed_width)
  4050. {
  4051.     GdkFont *font;
  4052.  
  4053.     if (!gui.in_use || name == NULL)
  4054.     return NOFONT;
  4055.  
  4056.     font = gdk_fontset_load((gchar *)name);
  4057.  
  4058.     if (font == NULL)
  4059.     {
  4060.     if (report_error)
  4061.         EMSG2(_(e_fontset), name);
  4062.     return NOFONT;
  4063.     }
  4064.     /* TODO: check if the font is fixed width. */
  4065.  
  4066.     /* reference this font as being in use */
  4067.     gdk_font_ref(font);
  4068.  
  4069.     return (GuiFontset)font;
  4070. }
  4071. #endif /* FEAT_XFONTSET */
  4072.  
  4073. #ifndef HAVE_GTK2
  4074. /*
  4075.  * Put up a font dialog and return the selected font name in allocated memory.
  4076.  * "oldval" is the previous value.
  4077.  * Return NULL when cancelled.
  4078.  */
  4079.     char_u *
  4080. gui_mch_font_dialog(char_u *oldval)
  4081. {
  4082.     char_u *fontname = NULL;
  4083.  
  4084.     if (!gui.fontdlg)
  4085.     {
  4086.     GtkFontSelectionDialog    *fsd = NULL;
  4087.  
  4088.     gui.fontdlg = gtk_font_selection_dialog_new(_("Font Selection"));
  4089.     fsd = GTK_FONT_SELECTION_DIALOG(gui.fontdlg);
  4090.     gtk_window_set_modal(GTK_WINDOW(gui.fontdlg), TRUE);
  4091.     gtk_window_set_transient_for(GTK_WINDOW(gui.fontdlg),
  4092.         GTK_WINDOW(gui.mainwin));
  4093.     gtk_signal_connect(GTK_OBJECT(gui.fontdlg), "destroy",
  4094.         GTK_SIGNAL_FUNC(font_sel_destroy), &gui);
  4095.     gtk_signal_connect(GTK_OBJECT(fsd->ok_button), "clicked",
  4096.         GTK_SIGNAL_FUNC(font_sel_ok), &gui);
  4097.     gtk_signal_connect(GTK_OBJECT(fsd->cancel_button), "clicked",
  4098.         GTK_SIGNAL_FUNC(font_sel_cancel), &gui);
  4099.     }
  4100.  
  4101.     if (oldval != NULL && *oldval != NUL)
  4102.     gtk_font_selection_dialog_set_font_name(
  4103.         GTK_FONT_SELECTION_DIALOG(gui.fontdlg), (char *)oldval);
  4104.  
  4105.     if (gui.fontname)
  4106.     {
  4107.     g_free(gui.fontname);
  4108.     gui.fontname = NULL;
  4109.     }
  4110.     gtk_window_position(GTK_WINDOW(gui.fontdlg), GTK_WIN_POS_MOUSE);
  4111.     gtk_widget_show(gui.fontdlg);
  4112.     {
  4113.     static gchar    *spacings[] = {"c", "m", NULL};
  4114.  
  4115.     /* In GTK 1.2.3 this must be after the gtk_widget_show() call,
  4116.      * otherwise everything is blocked for ten seconds. */
  4117.     gtk_font_selection_dialog_set_filter(
  4118.         GTK_FONT_SELECTION_DIALOG(gui.fontdlg),
  4119.         GTK_FONT_FILTER_BASE,
  4120.         GTK_FONT_ALL, NULL, NULL,
  4121.         NULL, NULL, spacings, NULL);
  4122.     }
  4123.  
  4124.     /* Wait for the font dialog to be closed. */
  4125.     while (gui.fontdlg && GTK_WIDGET_DRAWABLE(gui.fontdlg))
  4126.     gtk_main_iteration_do(TRUE);
  4127.  
  4128.     if (gui.fontname != NULL)
  4129.     {
  4130.     fontname = vim_strsave(gui.fontname);
  4131.     g_free(gui.fontname);
  4132.     gui.fontname = NULL;
  4133.     }
  4134.     return fontname;
  4135. }
  4136. #endif /* !HAVE_GTK2 */
  4137.  
  4138. #ifdef HAVE_GTK2
  4139. /*
  4140.  * Put up a font dialog and return the selected font name in allocated memory.
  4141.  * "oldval" is the previous value.  Return NULL when cancelled.
  4142.  * This should probably go into gui_gtk.c.  Hmm.
  4143.  * FIXME:
  4144.  * The GTK2 font selection dialog has no filtering API.  So we could either
  4145.  * a) implement our own (possibly copying the code from somewhere else) or
  4146.  * b) just live with it.
  4147.  */
  4148.     char_u *
  4149. gui_mch_font_dialog(char_u *oldval)
  4150. {
  4151.     GtkWidget    *dialog;
  4152.     int        response;
  4153.     char_u    *fontname = NULL;
  4154.  
  4155.     dialog = gtk_font_selection_dialog_new(NULL);
  4156.  
  4157.     gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gui.mainwin));
  4158.     gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog), TRUE);
  4159.  
  4160.     if (oldval != NULL && oldval[0] != NUL)
  4161.     {
  4162.     if (output_conv.vc_type != CONV_NONE)
  4163.         oldval = string_convert(&output_conv, oldval, NULL);
  4164.  
  4165.     gtk_font_selection_dialog_set_font_name(
  4166.         GTK_FONT_SELECTION_DIALOG(dialog), (const char *)oldval);
  4167.  
  4168.     if (output_conv.vc_type != CONV_NONE)
  4169.         vim_free(oldval);
  4170.     }
  4171.  
  4172.     response = gtk_dialog_run(GTK_DIALOG(dialog));
  4173.  
  4174.     if (response == GTK_RESPONSE_OK)
  4175.     {
  4176.     char *name;
  4177.  
  4178.     name = gtk_font_selection_dialog_get_font_name(
  4179.                 GTK_FONT_SELECTION_DIALOG(dialog));
  4180.     if (name != NULL)
  4181.     {
  4182.         if (input_conv.vc_type != CONV_NONE)
  4183.         fontname = string_convert(&input_conv, (char_u *)name, NULL);
  4184.         else
  4185.         fontname = vim_strsave((char_u *)name);
  4186.         g_free(name);
  4187.     }
  4188.     }
  4189.  
  4190.     if (response != GTK_RESPONSE_NONE)
  4191.     gtk_widget_destroy(dialog);
  4192.  
  4193.     return fontname;
  4194. }
  4195.  
  4196. /*
  4197.  * Some monospace fonts don't support a bold weight, and fall back
  4198.  * silently to the regular weight.  But this is no good since our text
  4199.  * drawing function can emulate bold by overstriking.  So let's try
  4200.  * to detect whether bold weight is actually available and emulate it
  4201.  * otherwise.
  4202.  *
  4203.  * Note that we don't need to check for italic style since Xft can
  4204.  * emulate italic on its own, provided you have a proper fontconfig
  4205.  * setup.  We wouldn't be able to emulate it in Vim anyway.
  4206.  */
  4207.     static void
  4208. get_styled_font_variants(void)
  4209. {
  4210.     PangoFontDescription    *bold_font_desc;
  4211.     PangoFont            *plain_font;
  4212.     PangoFont            *bold_font;
  4213.  
  4214.     gui.font_can_bold = FALSE;
  4215.  
  4216.     plain_font = pango_context_load_font(gui.text_context, gui.norm_font);
  4217.  
  4218.     if (plain_font == NULL)
  4219.     return;
  4220.  
  4221.     bold_font_desc = pango_font_description_copy_static(gui.norm_font);
  4222.     pango_font_description_set_weight(bold_font_desc, PANGO_WEIGHT_BOLD);
  4223.  
  4224.     bold_font = pango_context_load_font(gui.text_context, bold_font_desc);
  4225.     /*
  4226.      * The comparison relies on the unique handle nature of a PangoFont*,
  4227.      * i.e. it's assumed that a different PangoFont* won't refer to the
  4228.      * same font.  Seems to work, and failing here isn't critical anyway.
  4229.      */
  4230.     if (bold_font != NULL)
  4231.     {
  4232.     gui.font_can_bold = (bold_font != plain_font);
  4233.     g_object_unref(bold_font);
  4234.     }
  4235.  
  4236.     pango_font_description_free(bold_font_desc);
  4237.     g_object_unref(plain_font);
  4238. }
  4239.  
  4240. #else /* !HAVE_GTK2 */
  4241.  
  4242. /*
  4243.  * There is only one excuse I can give for the following attempt to manage font
  4244.  * styles:
  4245.  *
  4246.  * I HATE THE BRAIN DEAD WAY X11 IS HANDLING FONTS (--mdcki)
  4247.  * (Me too. --danielk)
  4248.  */
  4249.     static void
  4250. get_styled_font_variants(char_u * font_name)
  4251. {
  4252.     char    *chunk[32];
  4253.     char    *sdup;
  4254.     char    *tmp;
  4255.     int        len, i;
  4256.     GuiFont    *styled_font[3];
  4257.  
  4258.     styled_font[0] = &gui.bold_font;
  4259.     styled_font[1] = &gui.ital_font;
  4260.     styled_font[2] = &gui.boldital_font;
  4261.  
  4262.     /* First free whatever was freviously there. */
  4263.     for (i = 0; i < 3; ++i)
  4264.     if (*styled_font[i])
  4265.     {
  4266.         gdk_font_unref(*styled_font[i]);
  4267.         *styled_font[i] = NULL;
  4268.     }
  4269.  
  4270.     if ((sdup = g_strdup((const char *)font_name)) == NULL)
  4271.     return;
  4272.  
  4273.     /* split up the whole */
  4274.     i = 0;
  4275.     for (tmp = sdup; *tmp != '\0'; ++tmp)
  4276.     {
  4277.     if (*tmp == '-')
  4278.     {
  4279.         *tmp = '\0';
  4280.  
  4281.         if (i == 32)
  4282.         break;
  4283.  
  4284.         chunk[i] = tmp + 1;
  4285.         ++i;
  4286.     }
  4287.     }
  4288.  
  4289.     if (i == 14)
  4290.     {
  4291.     GdkFont        *font = NULL;
  4292.     const char    *bold_chunk[3]        = { "bold", NULL,    "bold" };
  4293.     const char    *italic_chunk[3]    = { NULL,    "o",    "o" };
  4294.  
  4295.     /* font name was complete */
  4296.     len = strlen((const char *)font_name) + 32;
  4297.  
  4298.     for (i = 0; i < 3; ++i)
  4299.     {
  4300.         char *styled_name;
  4301.         int j;
  4302.  
  4303.         styled_name = (char *)alloc(len);
  4304.         if (styled_name == NULL)
  4305.         {
  4306.         g_free(sdup);
  4307.         return;
  4308.         }
  4309.  
  4310.         *styled_name = '\0';
  4311.  
  4312.         for (j = 0; j < 14; ++j)
  4313.         {
  4314.         strcat(styled_name, "-");
  4315.         if (j == 2 && bold_chunk[i] != NULL)
  4316.             strcat(styled_name, bold_chunk[i]);
  4317.         else if (j == 3 && italic_chunk[i] != NULL)
  4318.             strcat(styled_name, italic_chunk[i]);
  4319.         else
  4320.             strcat(styled_name, chunk[j]);
  4321.         }
  4322.  
  4323.         font = gui_mch_get_font((char_u *)styled_name, FALSE);
  4324.         if (font != NULL)
  4325.         *styled_font[i] = font;
  4326.  
  4327.         vim_free(styled_name);
  4328.     }
  4329.     }
  4330.  
  4331.     g_free(sdup);
  4332. }
  4333. #endif /* !HAVE_GTK2 */
  4334.  
  4335. #ifdef HAVE_GTK2
  4336. /*
  4337.  * Create a map from ASCII characters in the range [32,126] to glyphs
  4338.  * of the current font.  This is used by gui_gtk2_draw_string() to skip
  4339.  * the itemize and shaping process for the most common case.
  4340.  */
  4341.     static void
  4342. ascii_glyph_table_init(void)
  4343. {
  4344.     char_u        ascii_chars[128];
  4345.     PangoAttrList   *attr_list;
  4346.     GList        *item_list;
  4347.     int            i;
  4348.  
  4349.     if (gui.ascii_glyphs != NULL)
  4350.     pango_glyph_string_free(gui.ascii_glyphs);
  4351.     if (gui.ascii_font != NULL)
  4352.     g_object_unref(gui.ascii_font);
  4353.  
  4354.     gui.ascii_glyphs = NULL;
  4355.     gui.ascii_font   = NULL;
  4356.  
  4357.     /* For safety, fill in question marks for the control characters. */
  4358.     for (i = 0; i < 32; ++i)
  4359.     ascii_chars[i] = '?';
  4360.     for (; i < 127; ++i)
  4361.     ascii_chars[i] = i;
  4362.     ascii_chars[i] = '?';
  4363.  
  4364.     attr_list = pango_attr_list_new();
  4365.     item_list = pango_itemize(gui.text_context, (const char *)ascii_chars,
  4366.                   0, sizeof(ascii_chars), attr_list, NULL);
  4367.  
  4368.     if (item_list != NULL && item_list->next == NULL) /* play safe */
  4369.     {
  4370.     PangoItem   *item;
  4371.     int        width;
  4372.  
  4373.     item  = (PangoItem *)item_list->data;
  4374.     width = gui.char_width * PANGO_SCALE;
  4375.  
  4376.     gui.ascii_font = item->analysis.font;
  4377.     g_object_ref(gui.ascii_font);
  4378.  
  4379.     gui.ascii_glyphs = pango_glyph_string_new();
  4380.  
  4381.     pango_shape((const char *)ascii_chars, sizeof(ascii_chars),
  4382.             &item->analysis, gui.ascii_glyphs);
  4383.  
  4384.     g_return_if_fail(gui.ascii_glyphs->num_glyphs == sizeof(ascii_chars));
  4385.  
  4386.     for (i = 0; i < gui.ascii_glyphs->num_glyphs; ++i)
  4387.     {
  4388.         PangoGlyphGeometry *geom;
  4389.  
  4390.         geom = &gui.ascii_glyphs->glyphs[i].geometry;
  4391.         geom->x_offset += MAX(0, width - geom->width) / 2;
  4392.         geom->width = width;
  4393.     }
  4394.     }
  4395.  
  4396.     g_list_foreach(item_list, (GFunc)&pango_item_free, NULL);
  4397.     g_list_free(item_list);
  4398.     pango_attr_list_unref(attr_list);
  4399. }
  4400. #endif /* HAVE_GTK2 */
  4401.  
  4402. /*
  4403.  * Initialize Vim to use the font or fontset with the given name.
  4404.  * Return FAIL if the font could not be loaded, OK otherwise.
  4405.  */
  4406. /*ARGSUSED1*/
  4407.     int
  4408. gui_mch_init_font(char_u *font_name, int fontset)
  4409. {
  4410. #ifdef HAVE_GTK2
  4411.     PangoFontDescription    *font_desc;
  4412.     PangoLayout            *layout;
  4413.     int                width;
  4414.  
  4415.     /* If font_name is NULL, this means to use the default, which should
  4416.      * be present on all proper Pango/fontconfig installations. */
  4417.     if (font_name == NULL)
  4418.     font_name = (char_u *)DEFAULT_FONT;
  4419.  
  4420.     font_desc = gui_mch_get_font(font_name, FALSE);
  4421.  
  4422.     if (font_desc == NULL)
  4423.     return FAIL;
  4424.  
  4425.     gui_mch_free_font(gui.norm_font);
  4426.     gui.norm_font = font_desc;
  4427.  
  4428.     pango_context_set_font_description(gui.text_context, font_desc);
  4429.  
  4430.     layout = pango_layout_new(gui.text_context);
  4431.     pango_layout_set_text(layout, "MW", 2);
  4432.     pango_layout_get_size(layout, &width, NULL);
  4433.     /*
  4434.      * Set char_width to half the width obtained from pango_layout_get_size()
  4435.      * for CJK fixed_width/bi-width fonts.  An unpatched version of Xft leads
  4436.      * Pango to use the same width for both non-CJK characters (e.g. Latin
  4437.      * letters and numbers) and CJK characters.  This results in 's p a c e d
  4438.      * o u t' rendering when a CJK 'fixed width' font is used. To work around
  4439.      * that, divide the width returned by Pango by 2 if cjk_width is equal to
  4440.      * width for CJK fonts.
  4441.      *
  4442.      * For related bugs, see:
  4443.      * http://bugzilla.gnome.org/show_bug.cgi?id=106618
  4444.      * http://bugzilla.gnome.org/show_bug.cgi?id=106624
  4445.      *
  4446.      * With this, for all four of the following cases, Vim works fine:
  4447.      *       guifont=CJK_fixed_width_font
  4448.      *       guifont=Non_CJK_fixed_font
  4449.      *       guifont=Non_CJK_fixed_font,CJK_Fixed_font
  4450.      *       guifont=Non_CJK_fixed_font guifontwide=CJK_fixed_font
  4451.      */
  4452.     if (is_cjk_font(gui.norm_font))
  4453.     {
  4454.     int cjk_width;
  4455.  
  4456.     /* Measure the text extent of U+4E00 and U+4E8C */
  4457.     pango_layout_set_text(layout, "\344\270\200\344\272\214", -1);
  4458.     pango_layout_get_size(layout, &cjk_width, NULL);
  4459.  
  4460.     if (width == cjk_width)  /* Xft not patched */
  4461.         width /= 2;
  4462.     }
  4463.     g_object_unref(layout);
  4464.  
  4465.     gui.char_width = (width / 2 + PANGO_SCALE - 1) / PANGO_SCALE;
  4466.  
  4467.     /* A zero width may cause a crash.    Happens for semi-invalid fontsets. */
  4468.     if (gui.char_width <= 0)
  4469.     gui.char_width = 8;
  4470.  
  4471.     gui_mch_adjust_charsize();
  4472.  
  4473.     /* Set the fontname, which will be used for information purposes */
  4474.     hl_set_font_name(font_name);
  4475.  
  4476.     get_styled_font_variants();
  4477.     ascii_glyph_table_init();
  4478.  
  4479.     /* Avoid unnecessary overhead if 'guifontwide' is equal to 'guifont'. */
  4480.     if (gui.wide_font != NULL
  4481.     && pango_font_description_equal(gui.norm_font, gui.wide_font))
  4482.     {
  4483.     pango_font_description_free(gui.wide_font);
  4484.     gui.wide_font = NULL;
  4485.     }
  4486.  
  4487. #else /* !HAVE_GTK2 */
  4488.  
  4489.     GdkFont    *font = NULL;
  4490.  
  4491. # ifdef FEAT_XFONTSET
  4492.     /* Try loading a fontset.  If this fails we try loading a normal font. */
  4493.     if (fontset && font_name != NULL)
  4494.     font = gui_mch_get_fontset(font_name, TRUE, TRUE);
  4495.  
  4496.     if (font == NULL)
  4497. # endif
  4498.     {
  4499.     /* If font_name is NULL, this means to use the default, which should
  4500.      * be present on all X11 servers. */
  4501.     if (font_name == NULL)
  4502.         font_name = (char_u *)DEFAULT_FONT;
  4503.     font = gui_mch_get_font(font_name, FALSE);
  4504.     }
  4505.  
  4506.     if (font == NULL)
  4507.     return FAIL;
  4508.  
  4509.     gui_mch_free_font(gui.norm_font);
  4510. # ifdef FEAT_XFONTSET
  4511.     gui_mch_free_fontset(gui.fontset);
  4512.     if (font->type == GDK_FONT_FONTSET)
  4513.     {
  4514.     gui.norm_font = NOFONT;
  4515.     gui.fontset = (GuiFontset)font;
  4516.     /* Use two bytes, this works around the problem that the result would
  4517.      * be zero if no 8-bit font was found. */
  4518.     gui.char_width = gdk_string_width(font, "xW") / 2;
  4519.     }
  4520.     else
  4521. # endif
  4522.     {
  4523.     gui.norm_font = font;
  4524. # ifdef FEAT_XFONTSET
  4525.     gui.fontset = NOFONTSET;
  4526. # endif
  4527.     gui.char_width = ((XFontStruct *)
  4528.                       GDK_FONT_XFONT(font))->max_bounds.width;
  4529.     }
  4530.  
  4531.     /* A zero width may cause a crash.    Happens for semi-invalid fontsets. */
  4532.     if (gui.char_width <= 0)
  4533.     gui.char_width = 8;
  4534.  
  4535.     gui.char_height = font->ascent + font->descent + p_linespace;
  4536.     gui.char_ascent = font->ascent + p_linespace / 2;
  4537.  
  4538.     /* A not-positive value of char_height may crash Vim.  Only happens
  4539.      * if 'linespace' is negative (which does make sense sometimes). */
  4540.     gui.char_ascent = MAX(gui.char_ascent, 0);
  4541.     gui.char_height = MAX(gui.char_height, gui.char_ascent + 1);
  4542.  
  4543.     /* Set the fontname, which will be used for information purposes */
  4544.     hl_set_font_name(font_name);
  4545.  
  4546.     if (font->type != GDK_FONT_FONTSET)
  4547.     get_styled_font_variants(font_name);
  4548.  
  4549.     /* Synchronize the fonts used in user input dialogs, since otherwise
  4550.      * search/replace will be esp. annoying in case of international font
  4551.      * usage.
  4552.      */
  4553.     gui_gtk_synch_fonts();
  4554.  
  4555. # ifdef FEAT_XIM
  4556.     /* Adjust input management behaviour to the capabilities of the new
  4557.      * fontset */
  4558.     xim_decide_input_style();
  4559.     if (xim_get_status_area_height())
  4560.     {
  4561.     /* Status area is required.  Just create the empty container so that
  4562.      * mainwin will allocate the extra space for status area. */
  4563.     GtkWidget *alignment = gtk_alignment_new((gfloat)0.5, (gfloat)0.5,
  4564.                             (gfloat)1.0, (gfloat)1.0);
  4565.  
  4566.     gtk_widget_set_usize(alignment, 20, gui.char_height + 2);
  4567.     gtk_box_pack_end(GTK_BOX(GTK_BIN(gui.mainwin)->child),
  4568.              alignment, FALSE, FALSE, 0);
  4569.     gtk_widget_show(alignment);
  4570.     }
  4571. # endif
  4572. #endif /* !HAVE_GTK2 */
  4573.  
  4574.     /* Preserve the logical dimensions of the screen. */
  4575.     update_window_manager_hints();
  4576.  
  4577.     return OK;
  4578. }
  4579.  
  4580. /*
  4581.  * Get a reference to the font "name".
  4582.  * Return zero for failure.
  4583.  */
  4584.     GuiFont
  4585. gui_mch_get_font(char_u *name, int report_error)
  4586. {
  4587. #ifdef HAVE_GTK2
  4588.     PangoFontDescription    *font;
  4589. #else
  4590.     GdkFont            *font;
  4591. #endif
  4592.  
  4593.     /* can't do this when GUI is not running */
  4594.     if (!gui.in_use || name == NULL)
  4595.     return NULL;
  4596.  
  4597. #ifdef HAVE_GTK2
  4598.     if (output_conv.vc_type != CONV_NONE)
  4599.     {
  4600.     char_u *buf;
  4601.  
  4602.     buf = string_convert(&output_conv, name, NULL);
  4603.     if (buf != NULL)
  4604.     {
  4605.         font = pango_font_description_from_string((const char *)buf);
  4606.         vim_free(buf);
  4607.     }
  4608.     else
  4609.         font = NULL;
  4610.     }
  4611.     else
  4612.     font = pango_font_description_from_string((const char *)name);
  4613.  
  4614.     if (font != NULL)
  4615.     {
  4616.     PangoFont *real_font;
  4617.  
  4618.     /* pango_context_load_font() bails out if no font size is set */
  4619.     if (pango_font_description_get_size(font) <= 0)
  4620.         pango_font_description_set_size(font, 10 * PANGO_SCALE);
  4621.  
  4622.     real_font = pango_context_load_font(gui.text_context, font);
  4623.  
  4624.     if (real_font == NULL)
  4625.     {
  4626.         pango_font_description_free(font);
  4627.         font = NULL;
  4628.     }
  4629.     else
  4630.         g_object_unref(real_font);
  4631.     }
  4632. #else
  4633.     font = gdk_font_load((const gchar *)name);
  4634. #endif
  4635.  
  4636.     if (font == NULL)
  4637.     {
  4638.     if (report_error)
  4639.         EMSG2(_(e_font), name);
  4640.     return NULL;
  4641.     }
  4642.  
  4643. #ifdef HAVE_GTK2
  4644.     /*
  4645.      * The fixed-width check has been disabled for GTK+ 2.  Rationale:
  4646.      *
  4647.      *     - The check tends to report false positives, particularly
  4648.      *       in non-Latin locales or with old X fonts.
  4649.      *     - Thanks to our fixed-width hack in gui_gtk2_draw_string(),
  4650.      *       GTK+ 2 Vim is actually capable of displaying variable width
  4651.      *       fonts.  Those will just be spaced out like in AA xterm.
  4652.      *     - Failing here for the default font causes GUI startup to fail
  4653.      *       even with wiped out configuration files.
  4654.      *     - The font dialog displays all fonts unfiltered, and it's rather
  4655.      *       annoying if 95% of the listed fonts produce an error message.
  4656.      */
  4657. # if 0
  4658.     {
  4659.     /* Check that this is a mono-spaced font.  Naturally, this is a bit
  4660.      * hackish -- fixed-width isn't really suitable for i18n text :/ */
  4661.     PangoLayout    *layout;
  4662.     unsigned int    i;
  4663.     int        last_width   = -1;
  4664.     const char    test_chars[] = { 'W', 'i', ',', 'x' }; /* arbitrary */
  4665.  
  4666.     layout = pango_layout_new(gui.text_context);
  4667.     pango_layout_set_font_description(layout, font);
  4668.  
  4669.     for (i = 0; i < G_N_ELEMENTS(test_chars); ++i)
  4670.     {
  4671.         int width;
  4672.  
  4673.         pango_layout_set_text(layout, &test_chars[i], 1);
  4674.         pango_layout_get_size(layout, &width, NULL);
  4675.  
  4676.         if (last_width >= 0 && width != last_width)
  4677.         {
  4678.         pango_font_description_free(font);
  4679.         font = NULL;
  4680.         break;
  4681.         }
  4682.  
  4683.         last_width = width;
  4684.     }
  4685.  
  4686.     g_object_unref(layout);
  4687.     }
  4688. # endif
  4689. #else /* !HAVE_GTK2 */
  4690.     {
  4691.     XFontStruct *xfont;
  4692.  
  4693.     /* reference this font as being in use */
  4694.     gdk_font_ref(font);
  4695.  
  4696.     /* Check that this is a mono-spaced font.
  4697.      */
  4698.     xfont = (XFontStruct *) GDK_FONT_XFONT(font);
  4699.  
  4700.     if (xfont->max_bounds.width != xfont->min_bounds.width)
  4701.     {
  4702.         gdk_font_unref(font);
  4703.         font = NULL;
  4704.     }
  4705.     }
  4706. #endif /* !HAVE_GTK2 */
  4707.  
  4708. #if !defined(HAVE_GTK2) || 0 /* disabled for GTK+ 2, see above */
  4709.     if (font == NULL && report_error)
  4710.     EMSG2(_(e_fontwidth), name);
  4711. #endif
  4712.  
  4713.     return font;
  4714. }
  4715.  
  4716. #if !defined(HAVE_GTK2) || defined(PROTO)
  4717. /*
  4718.  * Set the current text font.
  4719.  * Since we create all GC on demand, we use just gui.current_font to
  4720.  * indicate the desired current font.
  4721.  */
  4722.     void
  4723. gui_mch_set_font(GuiFont font)
  4724. {
  4725.     gui.current_font = font;
  4726. }
  4727. #endif
  4728.  
  4729. #if defined(FEAT_XFONTSET) || defined(PROTO)
  4730. /*
  4731.  * Set the current text fontset.
  4732.  */
  4733.     void
  4734. gui_mch_set_fontset(GuiFontset fontset)
  4735. {
  4736.     gui.current_font = fontset;
  4737. }
  4738. #endif
  4739.  
  4740. /*
  4741.  * If a font is not going to be used, free its structure.
  4742.  */
  4743.     void
  4744. gui_mch_free_font(GuiFont font)
  4745. {
  4746.     if (font != NOFONT)
  4747. #ifdef HAVE_GTK2
  4748.     pango_font_description_free(font);
  4749. #else
  4750.     gdk_font_unref(font);
  4751. #endif
  4752. }
  4753.  
  4754. #if defined(FEAT_XFONTSET) || defined(PROTO)
  4755. /*
  4756.  * If a fontset is not going to be used, free its structure.
  4757.  */
  4758.     void
  4759. gui_mch_free_fontset(GuiFontset fontset)
  4760. {
  4761.     if (fontset != NOFONTSET)
  4762.     gdk_font_unref(fontset);
  4763. }
  4764. #endif
  4765.  
  4766.  
  4767. /*
  4768.  * Return the Pixel value (color) for the given color name.  This routine was
  4769.  * pretty much taken from example code in the Silicon Graphics OSF/Motif
  4770.  * Programmer's Guide.
  4771.  * Return INVALCOLOR for error.
  4772.  */
  4773.     guicolor_T
  4774. gui_mch_get_color(char_u *name)
  4775. {
  4776.     /* A number of colors that some X11 systems don't have */
  4777.     static const char *const vimnames[][2] =
  4778.     {
  4779.     {"LightRed",     "#FFBBBB"},
  4780.     {"LightGreen",     "#88FF88"},
  4781.     {"LightMagenta", "#FFBBFF"},
  4782.     {"DarkCyan",     "#008888"},
  4783.     {"DarkBlue",     "#0000BB"},
  4784.     {"DarkRed",     "#BB0000"},
  4785.     {"DarkMagenta",  "#BB00BB"},
  4786.     {"DarkGrey",     "#BBBBBB"},
  4787.     {"DarkYellow",     "#BBBB00"},
  4788.     {NULL, NULL}
  4789.     };
  4790.  
  4791.     if (!gui.in_use)        /* can't do this when GUI not running */
  4792.     return INVALCOLOR;
  4793.  
  4794.     while (name != NULL)
  4795.     {
  4796.     GdkColor    color;
  4797.     int        parsed;
  4798.     int        i;
  4799.  
  4800.     parsed = gdk_color_parse((const char *)name, &color);
  4801.  
  4802. #ifndef HAVE_GTK2 /* ohh, lovely GTK+ 2, eases our pain :) */
  4803.     /*
  4804.      * Since we have already called gtk_set_locale here the bugger
  4805.      * XParseColor will accept only explicit color names in the language
  4806.      * of the current locale.  However this will interferre with:
  4807.      * 1. Vim's global startup files
  4808.      * 2. Explicit color names in .vimrc
  4809.      *
  4810.      * Therefore we first try to parse the color in the current locale and
  4811.      * if it fails, we fall back to the portable "C" one.
  4812.      */
  4813.     if (!parsed)
  4814.     {
  4815.         char *current;
  4816.  
  4817.         current = setlocale(LC_ALL, NULL);
  4818.         if (current != NULL)
  4819.         {
  4820.         char *saved;
  4821.  
  4822.         saved = g_strdup(current);
  4823.         setlocale(LC_ALL, "C");
  4824.  
  4825.         parsed = gdk_color_parse((const gchar *)name, &color);
  4826.  
  4827.         setlocale(LC_ALL, saved);
  4828.         gtk_set_locale();
  4829.  
  4830.         g_free(saved);
  4831.         }
  4832.     }
  4833. #endif /* !HAVE_GTK2 */
  4834.  
  4835.     if (parsed)
  4836.     {
  4837. #ifdef HAVE_GTK2
  4838.         gdk_colormap_alloc_color(gtk_widget_get_colormap(gui.drawarea),
  4839.                      &color, FALSE, TRUE);
  4840. #else
  4841.         gdk_color_alloc(gtk_widget_get_colormap(gui.drawarea), &color);
  4842. #endif
  4843.         return (guicolor_T)color.pixel;
  4844.     }
  4845.     /* add a few builtin names and try again */
  4846.     for (i = 0; ; ++i)
  4847.     {
  4848.         if (vimnames[i][0] == NULL)
  4849.         {
  4850.         name = NULL;
  4851.         break;
  4852.         }
  4853.         if (STRICMP(name, vimnames[i][0]) == 0)
  4854.         {
  4855.         name = (char_u *)vimnames[i][1];
  4856.         break;
  4857.         }
  4858.     }
  4859.     }
  4860.  
  4861.     return INVALCOLOR;
  4862. }
  4863.  
  4864. /*
  4865.  * Set the current text foreground color.
  4866.  */
  4867.     void
  4868. gui_mch_set_fg_color(guicolor_T color)
  4869. {
  4870.     gui.fgcolor->pixel = (unsigned long)color;
  4871. }
  4872.  
  4873. /*
  4874.  * Set the current text background color.
  4875.  */
  4876.     void
  4877. gui_mch_set_bg_color(guicolor_T color)
  4878. {
  4879.     gui.bgcolor->pixel = (unsigned long)color;
  4880. }
  4881.  
  4882. #ifdef HAVE_GTK2
  4883. /*
  4884.  * Function-like convenience macro for the sake of efficiency.
  4885.  */
  4886. #define INSERT_PANGO_ATTR(Attribute, AttrList, Start, End)  \
  4887.     G_STMT_START{                        \
  4888.     PangoAttribute *tmp_attr_;                \
  4889.     tmp_attr_ = (Attribute);                \
  4890.     tmp_attr_->start_index = (Start);            \
  4891.     tmp_attr_->end_index = (End);                \
  4892.     pango_attr_list_insert((AttrList), tmp_attr_);        \
  4893.     }G_STMT_END
  4894.  
  4895.     static void
  4896. apply_wide_font_attr(char_u *s, int len, PangoAttrList *attr_list)
  4897. {
  4898.     char_u  *start = NULL;
  4899.     char_u  *p;
  4900.     int        uc;
  4901.  
  4902.     for (p = s; p < s + len; p += utf_byte2len(*p))
  4903.     {
  4904.     uc = utf_ptr2char(p);
  4905.  
  4906.     if (start == NULL)
  4907.     {
  4908.         if (uc >= 0x100 && utf_char2cells(uc) == 2)
  4909.         start = p;
  4910.     }
  4911.     else if (uc < 0x100 /* optimization shortcut */
  4912.          || (utf_char2cells(uc) != 2 && !utf_iscomposing(uc)))
  4913.     {
  4914.         INSERT_PANGO_ATTR(pango_attr_font_desc_new(gui.wide_font),
  4915.                   attr_list, start - s, p - s);
  4916.         start = NULL;
  4917.     }
  4918.     }
  4919.  
  4920.     if (start != NULL)
  4921.     INSERT_PANGO_ATTR(pango_attr_font_desc_new(gui.wide_font),
  4922.               attr_list, start - s, len);
  4923. }
  4924.  
  4925.     static int
  4926. count_cluster_cells(char_u *s, PangoItem *item,
  4927.             PangoGlyphString* glyphs, int i,
  4928.             int *cluster_width,
  4929.             int *last_glyph_rbearing)
  4930. {
  4931.     char_u  *p;
  4932.     int        next;    /* glyph start index of next cluster */
  4933.     int        start, end; /* string segment of current cluster */
  4934.     int        width;    /* real cluster width in Pango units */
  4935.     int        uc;
  4936.     int        cellcount = 0;
  4937.  
  4938.     width = glyphs->glyphs[i].geometry.width;
  4939.  
  4940.     for (next = i + 1; next < glyphs->num_glyphs; ++next)
  4941.     {
  4942.     if (glyphs->glyphs[next].attr.is_cluster_start)
  4943.         break;
  4944.     else if (glyphs->glyphs[next].geometry.width > width)
  4945.         width = glyphs->glyphs[next].geometry.width;
  4946.     }
  4947.  
  4948.     start = item->offset + glyphs->log_clusters[i];
  4949.     end   = item->offset + ((next < glyphs->num_glyphs) ?
  4950.                 glyphs->log_clusters[next] : item->length);
  4951.  
  4952.     for (p = s + start; p < s + end; p += utf_byte2len(*p))
  4953.     {
  4954.     uc = utf_ptr2char(p);
  4955.     if (uc < 0x100)
  4956.         ++cellcount;
  4957.     else if (!utf_iscomposing(uc))
  4958.         cellcount += utf_char2cells(uc);
  4959.     }
  4960.  
  4961.     if (last_glyph_rbearing != NULL
  4962.         && cellcount > 0 && next == glyphs->num_glyphs)
  4963.     {
  4964.     PangoRectangle ink_rect;
  4965.     /*
  4966.      * If a certain combining mark had to be taken from a non-monospace
  4967.      * font, we have to compensate manually by adapting x_offset according
  4968.      * to the ink extents of the previous glyph.
  4969.      */
  4970.     pango_font_get_glyph_extents(item->analysis.font,
  4971.                      glyphs->glyphs[i].glyph,
  4972.                      &ink_rect, NULL);
  4973.  
  4974.     if (PANGO_RBEARING(ink_rect) > 0)
  4975.         *last_glyph_rbearing = PANGO_RBEARING(ink_rect);
  4976.     }
  4977.  
  4978.     if (cellcount > 0)
  4979.     *cluster_width = width;
  4980.  
  4981.     return cellcount;
  4982. }
  4983.  
  4984. /*
  4985.  * If there are only combining characters in the cluster, we cannot just
  4986.  * change the width of the previous glyph since there is none.    Therefore
  4987.  * some guesswork is needed.
  4988.  *
  4989.  * If ink_rect.x is negative Pango apparently has taken care of the composing
  4990.  * by itself.  Actually setting x_offset = 0 should be sufficient then, but due
  4991.  * to problems with composing from different fonts we still need to fine-tune
  4992.  * x_offset to avoid uglyness.
  4993.  *
  4994.  * If ink_rect.x is not negative, force overstriking by pointing x_offset to
  4995.  * the position of the previous glyph.    Apparently this happens only with old
  4996.  * X fonts which don't provide the special combining information needed by
  4997.  * Pango.
  4998.  */
  4999.     static void
  5000. setup_zero_width_cluster(PangoItem *item, PangoGlyphInfo *glyph,
  5001.              int last_cellcount, int last_cluster_width,
  5002.              int last_glyph_rbearing)
  5003. {
  5004.     PangoRectangle  ink_rect;
  5005.     PangoRectangle  logical_rect;
  5006.     int            width;
  5007.  
  5008.     width = last_cellcount * gui.char_width * PANGO_SCALE;
  5009.     glyph->geometry.x_offset = -width + MAX(0, width - last_cluster_width) / 2;
  5010.     glyph->geometry.width = 0;
  5011.  
  5012.     pango_font_get_glyph_extents(item->analysis.font,
  5013.                  glyph->glyph,
  5014.                  &ink_rect, &logical_rect);
  5015.     if (ink_rect.x < 0)
  5016.     {
  5017.     glyph->geometry.x_offset += last_glyph_rbearing;
  5018.     glyph->geometry.y_offset  = logical_rect.height
  5019.         - (gui.char_height - p_linespace) * PANGO_SCALE;
  5020.     }
  5021. }
  5022.  
  5023.     static void
  5024. draw_glyph_string(int row, int col, int num_cells, int flags,
  5025.           PangoFont *font, PangoGlyphString *glyphs)
  5026. {
  5027.     if (!(flags & DRAW_TRANSP))
  5028.     {
  5029.     gdk_gc_set_foreground(gui.text_gc, gui.bgcolor);
  5030.  
  5031.     gdk_draw_rectangle(gui.drawarea->window,
  5032.                gui.text_gc,
  5033.                TRUE,
  5034.                FILL_X(col),
  5035.                FILL_Y(row),
  5036.                num_cells * gui.char_width,
  5037.                gui.char_height);
  5038.     }
  5039.  
  5040.     gdk_gc_set_foreground(gui.text_gc, gui.fgcolor);
  5041.  
  5042.     gdk_draw_glyphs(gui.drawarea->window,
  5043.             gui.text_gc,
  5044.             font,
  5045.             TEXT_X(col),
  5046.             TEXT_Y(row),
  5047.             glyphs);
  5048.  
  5049.     /* redraw the contents with an offset of 1 to emulate bold */
  5050.     if ((flags & DRAW_BOLD) && !gui.font_can_bold)
  5051.     gdk_draw_glyphs(gui.drawarea->window,
  5052.             gui.text_gc,
  5053.             font,
  5054.             TEXT_X(col) + 1,
  5055.             TEXT_Y(row),
  5056.             glyphs);
  5057. }
  5058.  
  5059. #endif /* HAVE_GTK2 */
  5060.  
  5061. #if defined(HAVE_GTK2) || defined(PROTO)
  5062.     int
  5063. gui_gtk2_draw_string(int row, int col, char_u *s, int len, int flags)
  5064. {
  5065.     GdkRectangle    area;            /* area for clip mask      */
  5066.     char_u        *conv_buf = NULL;   /* result of UTF-8 conversion */
  5067.     PangoGlyphString    *glyphs;        /* glyphs of current item      */
  5068.     int            column_offset = 0;  /* column offset in cells      */
  5069.     int            i;
  5070.  
  5071.     if (gui.text_context == NULL || gui.drawarea->window == NULL)
  5072.     return len;
  5073.  
  5074.     if (output_conv.vc_type != CONV_NONE)
  5075.     {
  5076.     /*
  5077.      * Convert characters from 'encoding' to 'termencoding', which is set
  5078.      * to UTF-8 by gui_mch_init().    did_set_string_option() in option.c
  5079.      * prohibits changing this to something else than UTF-8 if the GUI is
  5080.      * in use.
  5081.      */
  5082.     conv_buf = string_convert(&output_conv, s, &len);
  5083.     s = conv_buf;
  5084.  
  5085.     g_return_val_if_fail(conv_buf != NULL, len);
  5086.     }
  5087.  
  5088.     /*
  5089.      * Restrict all drawing to the current screen line in order to prevent
  5090.      * fuzzy font lookups from messing up the screen.
  5091.      */
  5092.     area.x = gui.border_offset;
  5093.     area.y = FILL_Y(row);
  5094.     area.width    = gui.num_cols * gui.char_width;
  5095.     area.height = gui.char_height;
  5096.  
  5097.     gdk_gc_set_clip_origin(gui.text_gc, 0, 0);
  5098.     gdk_gc_set_clip_rectangle(gui.text_gc, &area);
  5099.  
  5100.     glyphs = pango_glyph_string_new();
  5101.  
  5102.     /*
  5103.      * Optimization hack:  If possible, skip the itemize and shaping process
  5104.      * for pure ASCII strings.    This optimization is particularly effective
  5105.      * because Vim draws space characters to clear parts of the screen.
  5106.      */
  5107.     if (!(flags & DRAW_ITALIC)
  5108.         && !((flags & DRAW_BOLD) && gui.font_can_bold)
  5109.         && gui.ascii_glyphs != NULL)
  5110.     {
  5111.     char_u *p;
  5112.  
  5113.     for (p = s; p < s + len; ++p)
  5114.         if (*p & 0x80) goto not_ascii;
  5115.  
  5116.     pango_glyph_string_set_size(glyphs, len);
  5117.  
  5118.     for (i = 0; i < len; ++i)
  5119.     {
  5120.         glyphs->glyphs[i] = gui.ascii_glyphs->glyphs[s[i]];
  5121.         glyphs->log_clusters[i] = i;
  5122.     }
  5123.  
  5124.     draw_glyph_string(row, col, len, flags, gui.ascii_font, glyphs);
  5125.  
  5126.     column_offset = len;
  5127.     }
  5128.     else
  5129. not_ascii:
  5130.     {
  5131.     PangoAttrList    *attr_list;
  5132.     GList        *item_list;
  5133.     int        cluster_width;
  5134.     int        last_glyph_rbearing;
  5135.     int        cells = 0;  /* cells occupied by current cluster */
  5136.  
  5137.     /* original width of the current cluster */
  5138.     cluster_width = PANGO_SCALE * gui.char_width;
  5139.  
  5140.     /* right bearing of the last non-composing glyph */
  5141.     last_glyph_rbearing = PANGO_SCALE * gui.char_width;
  5142.  
  5143.     attr_list = pango_attr_list_new();
  5144.  
  5145.     /* If 'guifontwide' is set then use that for double-width characters.
  5146.      * Otherwise just go with 'guifont' and let Pango do its thing. */
  5147.     if (gui.wide_font != NULL)
  5148.         apply_wide_font_attr(s, len, attr_list);
  5149.  
  5150.     if ((flags & DRAW_BOLD) && gui.font_can_bold)
  5151.         INSERT_PANGO_ATTR(pango_attr_weight_new(PANGO_WEIGHT_BOLD),
  5152.                   attr_list, 0, len);
  5153.     if (flags & DRAW_ITALIC)
  5154.         INSERT_PANGO_ATTR(pango_attr_style_new(PANGO_STYLE_ITALIC),
  5155.                   attr_list, 0, len);
  5156.     /*
  5157.      * Break the text into segments with consistent directional level
  5158.      * and shaping engine.    Pure Latin text needs only a single segment,
  5159.      * so there's no need to worry about the loop's efficiency.  Better
  5160.      * try to optimize elsewhere, e.g. reducing exposes and stuff :)
  5161.      */
  5162.     item_list = pango_itemize(gui.text_context,
  5163.                   (const char *)s, 0, len, attr_list, NULL);
  5164.  
  5165.     while (item_list != NULL)
  5166.     {
  5167.         PangoItem    *item;
  5168.         int        item_cells = 0; /* item length in cells */
  5169.  
  5170.         item = (PangoItem *)item_list->data;
  5171.         item_list = g_list_delete_link(item_list, item_list);
  5172.         /*
  5173.          * Increment the bidirectional embedding level by 1 if it is not
  5174.          * even.  An odd number means the output will be RTL, but we don't
  5175.          * want that since Vim handles right-to-left text on its own.  It
  5176.          * would probably be sufficient to just set level = 0, but you can
  5177.          * never know :)
  5178.          *
  5179.          * Unfortunately we can't take advantage of Pango's ability to
  5180.          * render both LTR and RTL at the same time.  In order to support
  5181.          * that, Vim's main screen engine would have to make use of Pango
  5182.          * functionality.
  5183.          */
  5184.         item->analysis.level = (item->analysis.level + 1) & (~1U);
  5185.  
  5186.         pango_shape((const char *)s + item->offset, item->length,
  5187.             &item->analysis, glyphs);
  5188.         /*
  5189.          * Fixed-width hack: iterate over the array and assign a fixed
  5190.          * width to each glyph, thus overriding the choice made by the
  5191.          * shaping engine.    We use utf_char2cells() to determine the
  5192.          * number of cells needed.
  5193.          *
  5194.          * Also perform all kind of dark magic to get composing
  5195.          * characters right (and pretty too of course).
  5196.          */
  5197.         for (i = 0; i < glyphs->num_glyphs; ++i)
  5198.         {
  5199.         PangoGlyphInfo *glyph;
  5200.  
  5201.         glyph = &glyphs->glyphs[i];
  5202.  
  5203.         if (glyph->attr.is_cluster_start)
  5204.         {
  5205.             int cellcount;
  5206.  
  5207.             cellcount = count_cluster_cells(
  5208.             s, item, glyphs, i, &cluster_width,
  5209.             (item_list != NULL) ? &last_glyph_rbearing : NULL);
  5210.  
  5211.             if (cellcount > 0)
  5212.             {
  5213.             int width;
  5214.  
  5215.             width = cellcount * gui.char_width * PANGO_SCALE;
  5216.             glyph->geometry.x_offset +=
  5217.                         MAX(0, width - cluster_width) / 2;
  5218.             glyph->geometry.width = width;
  5219.             }
  5220.             else
  5221.             {
  5222.             /* If there are only combining characters in the
  5223.              * cluster, we cannot just change the width of the
  5224.              * previous glyph since there is none.    Therefore
  5225.              * some guesswork is needed. */
  5226.             setup_zero_width_cluster(item, glyph, cells,
  5227.                          cluster_width,
  5228.                          last_glyph_rbearing);
  5229.             }
  5230.  
  5231.             item_cells += cellcount;
  5232.             cells = cellcount;
  5233.         }
  5234.         else if (i > 0) /* i == 0 "cannot happen" */
  5235.         {
  5236.             int width;
  5237.  
  5238.             /* There is a previous glyph, so we deal with combining
  5239.              * characters the canonical way.  That is, setting the
  5240.              * width of the previous glyph to 0. */
  5241.             glyphs->glyphs[i - 1].geometry.width = 0;
  5242.  
  5243.             width = cells * gui.char_width * PANGO_SCALE;
  5244.             glyph->geometry.x_offset +=
  5245.                         MAX(0, width - cluster_width) / 2;
  5246.             glyph->geometry.width = width;
  5247.         }
  5248.         else
  5249.         {
  5250.             glyph->geometry.width = 0;
  5251.         }
  5252.         }
  5253.  
  5254.         /*** Aaaaand action! ***/
  5255.         draw_glyph_string(row, col + column_offset, item_cells,
  5256.                   flags, item->analysis.font, glyphs);
  5257.  
  5258.         pango_item_free(item);
  5259.  
  5260.         column_offset += item_cells;
  5261.     }
  5262.  
  5263.     pango_attr_list_unref(attr_list);
  5264.     }
  5265.  
  5266.     if (flags & DRAW_UNDERL)
  5267.     gdk_draw_line(gui.drawarea->window,
  5268.               gui.text_gc,
  5269.               FILL_X(col),
  5270.               FILL_Y(row + 1) - 1,
  5271.               FILL_X(col + column_offset) - 1,
  5272.               FILL_Y(row + 1) - 1);
  5273.  
  5274.     pango_glyph_string_free(glyphs);
  5275.     vim_free(conv_buf);
  5276.  
  5277.     gdk_gc_set_clip_rectangle(gui.text_gc, NULL);
  5278.  
  5279.     return column_offset;
  5280. }
  5281. #endif /* HAVE_GTK2 */
  5282.  
  5283. #if !defined(HAVE_GTK2) || defined(PROTO)
  5284.     void
  5285. gui_mch_draw_string(int row, int col, char_u *s, int len, int flags)
  5286. {
  5287.     static XChar2b    *buf = NULL;
  5288.     static int        buflen = 0;
  5289.     int            is_wide;
  5290.     XChar2b        *text;
  5291.     int            textlen;
  5292.     XFontStruct        *xfont;
  5293.     char_u        *p;
  5294. # ifdef FEAT_MBYTE
  5295.     unsigned        c;
  5296. # endif
  5297.     int            width;
  5298.  
  5299.     if (gui.current_font == NULL || gui.drawarea->window == NULL)
  5300.     return;
  5301.  
  5302.     /*
  5303.      * Yeah yeah apparently the font support in GTK+ 1.2 only cares for either:
  5304.      * asians or 8-bit fonts. It is broken there, but no wonder the whole font
  5305.      * stuff is broken in X11 in first place. And the internationalization API
  5306.      * isn't something you would really like to use.
  5307.      */
  5308.  
  5309.     xfont = (XFontStruct *)((GdkFontPrivate*)gui.current_font)->xfont;
  5310.     is_wide = ((xfont->min_byte1 != 0 || xfont->max_byte1 != 0)
  5311. # ifdef FEAT_XFONTSET
  5312.         && gui.fontset == NOFONTSET
  5313. # endif
  5314.         );
  5315.  
  5316.     if (is_wide)
  5317.     {
  5318.     /* Convert a byte sequence to 16 bit characters for the Gdk functions.
  5319.      * Need a buffer for the 16 bit characters.  Keep it between calls,
  5320.      * because allocating it each time is slow. */
  5321.     if (buflen < len)
  5322.     {
  5323.         XtFree((char *)buf);
  5324.         buf = (XChar2b *)XtMalloc(len * sizeof(XChar2b));
  5325.         buflen = len;
  5326.     }
  5327.  
  5328.     p = s;
  5329.     textlen = 0;
  5330.     width = 0;
  5331.     while (p < s + len)
  5332.     {
  5333. # ifdef FEAT_MBYTE
  5334.         if (enc_utf8)
  5335.         {
  5336.         c = utf_ptr2char(p);
  5337.         if (c >= 0x10000)    /* show chars > 0xffff as ? */
  5338.             c = 0xbf;
  5339.         buf[textlen].byte1 = c >> 8;
  5340.         buf[textlen].byte2 = c;
  5341.         p += utf_ptr2len_check(p);
  5342.         width += utf_char2cells(c);
  5343.         }
  5344.         else
  5345. # endif
  5346.         {
  5347.         buf[textlen].byte1 = '\0';    /* high eight bits */
  5348.         buf[textlen].byte2 = *p;    /* low eight bits */
  5349.         ++p;
  5350.         ++width;
  5351.         }
  5352.         ++textlen;
  5353.     }
  5354.     text = buf;
  5355.     textlen = textlen * 2;
  5356.     }
  5357.     else
  5358.     {
  5359.     text = (XChar2b *)s;
  5360.     textlen = len;
  5361. # ifdef FEAT_MBYTE
  5362.     if (has_mbyte)
  5363.     {
  5364.         width = 0;
  5365.         for (p = s; p < s + len; p += (*mb_ptr2len_check)(p))
  5366.         width += (*mb_ptr2cells)(p);
  5367.     }
  5368.     else
  5369. # endif
  5370.         width = len;
  5371.     }
  5372.  
  5373.     if (!(flags & DRAW_TRANSP))
  5374.     {
  5375.     gdk_gc_set_foreground(gui.text_gc, gui.bgcolor);
  5376.     gdk_draw_rectangle(gui.drawarea->window,
  5377.                gui.text_gc,
  5378.                TRUE,
  5379.                FILL_X(col), FILL_Y(row),
  5380.                width * gui.char_width, gui.char_height);
  5381.     }
  5382.     gdk_gc_set_foreground(gui.text_gc, gui.fgcolor);
  5383.     gdk_draw_text(gui.drawarea->window,
  5384.           gui.current_font,
  5385.           gui.text_gc,
  5386.           TEXT_X(col), TEXT_Y(row),
  5387.           (const gchar *)text, textlen);
  5388.  
  5389.     /* redraw the contents with an offset of 1 to emulate bold */
  5390.     if (flags & DRAW_BOLD)
  5391.     gdk_draw_text(gui.drawarea->window,
  5392.               gui.current_font,
  5393.               gui.text_gc,
  5394.               TEXT_X(col) + 1, TEXT_Y(row),
  5395.               (const gchar *)text, textlen);
  5396.  
  5397.     if (flags & DRAW_UNDERL)
  5398.     {
  5399.     gdk_draw_line(gui.drawarea->window,
  5400.               gui.text_gc, FILL_X(col),
  5401.     FILL_Y(row + 1) - 1, FILL_X(col + width) - 1, FILL_Y(row + 1) - 1);
  5402.     }
  5403. }
  5404. #endif /* !HAVE_GTK2 */
  5405.  
  5406. /*
  5407.  * Return OK if the key with the termcap name "name" is supported.
  5408.  */
  5409.     int
  5410. gui_mch_haskey(char_u *name)
  5411. {
  5412.     int i;
  5413.  
  5414.     for (i = 0; special_keys[i].key_sym != 0; i++)
  5415.     if (name[0] == special_keys[i].code0
  5416.         && name[1] == special_keys[i].code1)
  5417.         return OK;
  5418.     return FAIL;
  5419. }
  5420.  
  5421. #if defined(FEAT_TITLE) \
  5422.     || (defined(FEAT_XIM) && !defined(HAVE_GTK2)) \
  5423.     || defined(PROTO)
  5424. /*
  5425.  * Return the text window-id and display.  Only required for X-based GUI's
  5426.  */
  5427.     int
  5428. gui_get_x11_windis(Window *win, Display **dis)
  5429. {
  5430.     if (gui.mainwin != NULL && gui.mainwin->window != NULL)
  5431.     {
  5432.     *dis = GDK_WINDOW_XDISPLAY(gui.mainwin->window);
  5433.     *win = GDK_WINDOW_XWINDOW(gui.mainwin->window);
  5434.     return OK;
  5435.     }
  5436.  
  5437.     *dis = NULL;
  5438.     *win = 0;
  5439.     return FAIL;
  5440. }
  5441. #endif
  5442.  
  5443. #if defined(FEAT_CLIENTSERVER) \
  5444.     || (defined(FEAT_X11) && defined(FEAT_CLIPBOARD)) || defined(PROTO)
  5445.  
  5446.     Display *
  5447. gui_mch_get_display(void)
  5448. {
  5449.     if (gui.mainwin != NULL && gui.mainwin->window != NULL)
  5450.     return GDK_WINDOW_XDISPLAY(gui.mainwin->window);
  5451.     else
  5452.     return NULL;
  5453. }
  5454. #endif
  5455.  
  5456.     void
  5457. gui_mch_beep(void)
  5458. {
  5459. #ifdef HAVE_GTK_MULTIHEAD
  5460.     GdkDisplay *display;
  5461.  
  5462.     if (gui.mainwin != NULL && GTK_WIDGET_REALIZED(gui.mainwin))
  5463.     display = gtk_widget_get_display(gui.mainwin);
  5464.     else
  5465.     display = gdk_display_get_default();
  5466.  
  5467.     if (display != NULL)
  5468.     gdk_display_beep(display);
  5469. #else
  5470.     gdk_beep();
  5471. #endif
  5472. }
  5473.  
  5474.     void
  5475. gui_mch_flash(int msec)
  5476. {
  5477.     GdkGCValues    values;
  5478.     GdkGC    *invert_gc;
  5479.  
  5480.     if (gui.drawarea->window == NULL)
  5481.     return;
  5482.  
  5483.     values.foreground.pixel = gui.norm_pixel ^ gui.back_pixel;
  5484.     values.background.pixel = gui.norm_pixel ^ gui.back_pixel;
  5485.     values.function = GDK_XOR;
  5486.     invert_gc = gdk_gc_new_with_values(gui.drawarea->window,
  5487.                        &values,
  5488.                        GDK_GC_FOREGROUND |
  5489.                        GDK_GC_BACKGROUND |
  5490.                        GDK_GC_FUNCTION);
  5491.     gdk_gc_set_exposures(invert_gc,
  5492.              gui.visibility != GDK_VISIBILITY_UNOBSCURED);
  5493.     /*
  5494.      * Do a visual beep by changing back and forth in some undetermined way,
  5495.      * the foreground and background colors.  This is due to the fact that
  5496.      * there can't be really any prediction about the effects of XOR on
  5497.      * arbitrary X11 servers. However this seems to be enough for what we
  5498.      * intend it to do.
  5499.      */
  5500.     gdk_draw_rectangle(gui.drawarea->window, invert_gc,
  5501.                TRUE,
  5502.                0, 0,
  5503.                FILL_X((int)Columns) + gui.border_offset,
  5504.                FILL_Y((int)Rows) + gui.border_offset);
  5505.  
  5506.     gui_mch_flush();
  5507.     ui_delay((long)msec, TRUE);    /* wait so many msec */
  5508.  
  5509.     gdk_draw_rectangle(gui.drawarea->window, invert_gc,
  5510.                TRUE,
  5511.                0, 0,
  5512.                FILL_X((int)Columns) + gui.border_offset,
  5513.                FILL_Y((int)Rows) + gui.border_offset);
  5514.  
  5515.     gdk_gc_destroy(invert_gc);
  5516. }
  5517.  
  5518. /*
  5519.  * Invert a rectangle from row r, column c, for nr rows and nc columns.
  5520.  */
  5521.     void
  5522. gui_mch_invert_rectangle(int r, int c, int nr, int nc)
  5523. {
  5524.     GdkGCValues values;
  5525.     GdkGC *invert_gc;
  5526.     GdkColor foreground;
  5527.     GdkColor background;
  5528.  
  5529.     if (gui.drawarea->window == NULL)
  5530.     return;
  5531.  
  5532.     foreground.pixel = gui.norm_pixel ^ gui.back_pixel;
  5533.     background.pixel = gui.norm_pixel ^ gui.back_pixel;
  5534.  
  5535.     values.foreground = foreground;
  5536.     values.background = background;
  5537.     values.function = GDK_XOR;
  5538.     invert_gc = gdk_gc_new_with_values(gui.drawarea->window,
  5539.                        &values,
  5540.                        GDK_GC_FOREGROUND |
  5541.                        GDK_GC_BACKGROUND |
  5542.                        GDK_GC_FUNCTION);
  5543.     gdk_gc_set_exposures(invert_gc, gui.visibility != GDK_VISIBILITY_UNOBSCURED);
  5544.     gdk_draw_rectangle(gui.drawarea->window, invert_gc,
  5545.                TRUE,
  5546.                FILL_X(c), FILL_Y(r),
  5547.                (nc) * gui.char_width, (nr) * gui.char_height);
  5548.     gdk_gc_destroy(invert_gc);
  5549. }
  5550.  
  5551. /*
  5552.  * Iconify the GUI window.
  5553.  */
  5554.     void
  5555. gui_mch_iconify(void)
  5556. {
  5557. #ifdef HAVE_GTK2
  5558.     gtk_window_iconify(GTK_WINDOW(gui.mainwin));
  5559. #else
  5560.     XIconifyWindow(GDK_WINDOW_XDISPLAY(gui.mainwin->window),
  5561.            GDK_WINDOW_XWINDOW(gui.mainwin->window),
  5562.            DefaultScreen(GDK_WINDOW_XDISPLAY(gui.mainwin->window)));
  5563. #endif
  5564. }
  5565.  
  5566. #if defined(FEAT_EVAL) || defined(PROTO)
  5567. /*
  5568.  * Bring the Vim window to the foreground.
  5569.  */
  5570.     void
  5571. gui_mch_set_foreground(void)
  5572. {
  5573. # ifdef HAVE_GTK2
  5574.     gtk_window_present(GTK_WINDOW(gui.mainwin));
  5575. # else
  5576.     gdk_window_raise(gui.mainwin->window);
  5577. # endif
  5578. }
  5579. #endif
  5580.  
  5581. /*
  5582.  * Draw a cursor without focus.
  5583.  */
  5584.     void
  5585. gui_mch_draw_hollow_cursor(guicolor_T color)
  5586. {
  5587.     int        i = 1;
  5588.  
  5589.     if (gui.drawarea->window == NULL)
  5590.     return;
  5591.  
  5592.     gui_mch_set_fg_color(color);
  5593.  
  5594.     gdk_gc_set_foreground(gui.text_gc, gui.fgcolor);
  5595. #ifdef FEAT_MBYTE
  5596.     if (mb_lefthalve(gui.row, gui.col))
  5597.     i = 2;
  5598. #endif
  5599.     gdk_draw_rectangle(gui.drawarea->window, gui.text_gc,
  5600.         FALSE,
  5601.         FILL_X(gui.col), FILL_Y(gui.row),
  5602.         i * gui.char_width - 1, gui.char_height - 1);
  5603. }
  5604.  
  5605. /*
  5606.  * Draw part of a cursor, "w" pixels wide, and "h" pixels high, using
  5607.  * color "color".
  5608.  */
  5609.     void
  5610. gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
  5611. {
  5612.     if (gui.drawarea->window == NULL)
  5613.     return;
  5614.  
  5615.     gui_mch_set_fg_color(color);
  5616.  
  5617.     gdk_gc_set_foreground(gui.text_gc, gui.fgcolor);
  5618.     gdk_draw_rectangle(gui.drawarea->window, gui.text_gc,
  5619.         TRUE,
  5620. #ifdef FEAT_RIGHTLEFT
  5621.         /* vertical line should be on the right of current point */
  5622.         CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w :
  5623. #endif
  5624.         FILL_X(gui.col),
  5625.         FILL_Y(gui.row) + gui.char_height - h,
  5626.         w, h);
  5627. }
  5628.  
  5629.  
  5630. /*
  5631.  * Catch up with any queued X11 events.  This may put keyboard input into the
  5632.  * input buffer, call resize call-backs, trigger timers etc.  If there is
  5633.  * nothing in the X11 event queue (& no timers pending), then we return
  5634.  * immediately.
  5635.  */
  5636.     void
  5637. gui_mch_update(void)
  5638. {
  5639.     while (gtk_events_pending() && !vim_is_input_buf_full())
  5640.     gtk_main_iteration_do(FALSE);
  5641. }
  5642.  
  5643.     static gint
  5644. input_timer_cb(gpointer data)
  5645. {
  5646.     int *timed_out = (int *) data;
  5647.  
  5648.     /* Just inform the caller about the occurence of it */
  5649.     *timed_out = TRUE;
  5650.  
  5651.     if (gtk_main_level() > 0)
  5652.     gtk_main_quit();
  5653.  
  5654.     return FALSE;        /* don't happen again */
  5655. }
  5656.  
  5657. #ifdef FEAT_SNIFF
  5658. /*
  5659.  * Callback function, used when data is available on the SNiFF connection.
  5660.  */
  5661. /* ARGSUSED */
  5662.     static void
  5663. sniff_request_cb(
  5664.     gpointer    data,
  5665.     gint    source_fd,
  5666.     GdkInputCondition condition)
  5667. {
  5668.     static char_u bytes[3] = {CSI, (int)KS_EXTRA, (int)KE_SNIFF};
  5669.  
  5670.     add_to_input_buf(bytes, 3);
  5671.  
  5672.     if (gtk_main_level() > 0)
  5673.     gtk_main_quit();
  5674. }
  5675. #endif
  5676.  
  5677. /*
  5678.  * GUI input routine called by gui_wait_for_chars().  Waits for a character
  5679.  * from the keyboard.
  5680.  *  wtime == -1     Wait forever.
  5681.  *  wtime == 0        This should never happen.
  5682.  *  wtime > 0        Wait wtime milliseconds for a character.
  5683.  * Returns OK if a character was found to be available within the given time,
  5684.  * or FAIL otherwise.
  5685.  */
  5686.     int
  5687. gui_mch_wait_for_chars(long wtime)
  5688. {
  5689.     int focus;
  5690.     guint timer;
  5691.     static int timed_out;
  5692. #ifdef FEAT_SNIFF
  5693.     static int    sniff_on = 0;
  5694.     static gint    sniff_input_id = 0;
  5695. #endif
  5696.  
  5697. #ifdef FEAT_SNIFF
  5698.     if (sniff_on && !want_sniff_request)
  5699.     {
  5700.     if (sniff_input_id)
  5701.         gdk_input_remove(sniff_input_id);
  5702.     sniff_on = 0;
  5703.     }
  5704.     else if (!sniff_on && want_sniff_request)
  5705.     {
  5706.     /* Add fd_from_sniff to watch for available data in main loop. */
  5707.     sniff_input_id = gdk_input_add(fd_from_sniff,
  5708.                    GDK_INPUT_READ, sniff_request_cb, NULL);
  5709.     sniff_on = 1;
  5710.     }
  5711. #endif
  5712.  
  5713.     timed_out = FALSE;
  5714.  
  5715.     /* this timeout makes sure that we will return if no characters arrived in
  5716.      * time */
  5717.  
  5718.     if (wtime > 0)
  5719.     timer = gtk_timeout_add((guint32)wtime, input_timer_cb, &timed_out);
  5720.     else
  5721.     timer = 0;
  5722.  
  5723.     focus = gui.in_focus;
  5724.  
  5725.     do
  5726.     {
  5727.     /* Stop or start blinking when focus changes */
  5728.     if (gui.in_focus != focus)
  5729.     {
  5730.         if (gui.in_focus)
  5731.         gui_mch_start_blink();
  5732.         else
  5733.         gui_mch_stop_blink();
  5734.         focus = gui.in_focus;
  5735.     }
  5736.  
  5737.     /*
  5738.      * Loop in GTK+ processing  until a timeout or input occurs.
  5739.      */
  5740.     gtk_main();
  5741.  
  5742.     /* Got char, return immediately */
  5743.     if (input_available())
  5744.     {
  5745.         if (timer != 0 && !timed_out)
  5746.         gtk_timeout_remove(timer);
  5747.         return OK;
  5748.     }
  5749.     } while (wtime < 0 || !timed_out);
  5750.  
  5751.     /*
  5752.      * Flush all eventually pending (drawing) events.
  5753.      */
  5754.     gui_mch_update();
  5755.  
  5756.     return FAIL;
  5757. }
  5758.  
  5759.  
  5760. /****************************************************************************
  5761.  * Output drawing routines.
  5762.  ****************************************************************************/
  5763.  
  5764.  
  5765. /* Flush any output to the screen */
  5766.     void
  5767. gui_mch_flush(void)
  5768. {
  5769. #ifdef HAVE_GTK_MULTIHEAD
  5770.     if (gui.mainwin != NULL && GTK_WIDGET_REALIZED(gui.mainwin))
  5771.     gdk_display_sync(gtk_widget_get_display(gui.mainwin));
  5772. #else
  5773.     gdk_flush(); /* historical misnomer: calls XSync(), not XFlush() */
  5774. #endif
  5775. #ifdef HAVE_GTK2
  5776.     /* This happens to actually do what gui_mch_flush() is supposed to do,
  5777.      * according to the comment above. */
  5778.     if (gui.drawarea != NULL && gui.drawarea->window != NULL)
  5779.     gdk_window_process_updates(gui.drawarea->window, FALSE);
  5780. #endif
  5781. }
  5782.  
  5783. /*
  5784.  * Clear a rectangular region of the screen from text pos (row1, col1) to
  5785.  * (row2, col2) inclusive.
  5786.  */
  5787.     void
  5788. gui_mch_clear_block(int row1, int col1, int row2, int col2)
  5789. {
  5790.     GdkColor color;
  5791.  
  5792.     if (gui.drawarea->window == NULL)
  5793.     return;
  5794.  
  5795.     color.pixel = gui.back_pixel;
  5796.  
  5797.     gdk_gc_set_foreground(gui.text_gc, &color);
  5798.  
  5799.     /* Clear one extra pixel at the far right, for when bold characters have
  5800.      * spilled over to the window border. */
  5801.     gdk_draw_rectangle(gui.drawarea->window, gui.text_gc, TRUE,
  5802.                FILL_X(col1), FILL_Y(row1),
  5803.                (col2 - col1 + 1) * gui.char_width
  5804.                               + (col2 == Columns - 1),
  5805.                (row2 - row1 + 1) * gui.char_height);
  5806. }
  5807.  
  5808.     void
  5809. gui_mch_clear_all(void)
  5810. {
  5811.     if (gui.drawarea->window != NULL)
  5812.     gdk_window_clear(gui.drawarea->window);
  5813. }
  5814.  
  5815. /*
  5816.  * Redraw any text revealed by scrolling up/down.
  5817.  */
  5818.     static void
  5819. check_copy_area(void)
  5820. {
  5821.     GdkEvent    *event;
  5822.     int        expose_count;
  5823.  
  5824.     if (gui.visibility != GDK_VISIBILITY_PARTIAL)
  5825.     return;
  5826.  
  5827.     /* Avoid redrawing the cursor while scrolling or it'll end up where
  5828.      * we don't want it to be.    I'm not sure if it's correct to call
  5829.      * gui_dont_update_cursor() at this point but it works as a quick
  5830.      * fix for now. */
  5831.     gui_dont_update_cursor();
  5832.  
  5833.     do
  5834.     {
  5835.     /* Wait to check whether the scroll worked or not. */
  5836.     event = gdk_event_get_graphics_expose(gui.drawarea->window);
  5837.  
  5838.     if (event == NULL)
  5839.         break; /* received NoExpose event */
  5840.  
  5841.     gui_redraw(event->expose.area.x, event->expose.area.y,
  5842.            event->expose.area.width, event->expose.area.height);
  5843.  
  5844.     expose_count = event->expose.count;
  5845.     gdk_event_free(event);
  5846.     }
  5847.     while (expose_count > 0); /* more events follow */
  5848.  
  5849.     gui_can_update_cursor();
  5850. }
  5851.  
  5852. /*
  5853.  * Delete the given number of lines from the given row, scrolling up any
  5854.  * text further down within the scroll region.
  5855.  */
  5856.     void
  5857. gui_mch_delete_lines(int row, int num_lines)
  5858. {
  5859.     if (gui.visibility == GDK_VISIBILITY_FULLY_OBSCURED)
  5860.     return;            /* Can't see the window */
  5861.  
  5862.     gdk_gc_set_foreground(gui.text_gc, gui.fgcolor);
  5863.     gdk_gc_set_background(gui.text_gc, gui.bgcolor);
  5864.  
  5865.     /* copy one extra pixel, for when bold has spilled over */
  5866.     gdk_window_copy_area(gui.drawarea->window, gui.text_gc,
  5867.         FILL_X(gui.scroll_region_left), FILL_Y(row),
  5868.         gui.drawarea->window,
  5869.         FILL_X(gui.scroll_region_left),
  5870.         FILL_Y(row + num_lines),
  5871.         gui.char_width * (gui.scroll_region_right
  5872.                         - gui.scroll_region_left + 1) + 1,
  5873.         gui.char_height * (gui.scroll_region_bot - row - num_lines + 1));
  5874.  
  5875.     gui_clear_block(gui.scroll_region_bot - num_lines + 1,
  5876.                                gui.scroll_region_left,
  5877.             gui.scroll_region_bot, gui.scroll_region_right);
  5878.     check_copy_area();
  5879. }
  5880.  
  5881. /*
  5882.  * Insert the given number of lines before the given row, scrolling down any
  5883.  * following text within the scroll region.
  5884.  */
  5885.     void
  5886. gui_mch_insert_lines(int row, int num_lines)
  5887. {
  5888.     if (gui.visibility == GDK_VISIBILITY_FULLY_OBSCURED)
  5889.     return;            /* Can't see the window */
  5890.  
  5891.     gdk_gc_set_foreground(gui.text_gc, gui.fgcolor);
  5892.     gdk_gc_set_background(gui.text_gc, gui.bgcolor);
  5893.  
  5894.     /* copy one extra pixel, for when bold has spilled over */
  5895.     gdk_window_copy_area(gui.drawarea->window, gui.text_gc,
  5896.         FILL_X(gui.scroll_region_left), FILL_Y(row + num_lines),
  5897.         gui.drawarea->window,
  5898.         FILL_X(gui.scroll_region_left), FILL_Y(row),
  5899.         gui.char_width * (gui.scroll_region_right
  5900.                         - gui.scroll_region_left + 1) + 1,
  5901.         gui.char_height * (gui.scroll_region_bot - row - num_lines + 1));
  5902.  
  5903.     gui_clear_block(row, gui.scroll_region_left,
  5904.                 row + num_lines - 1, gui.scroll_region_right);
  5905.     check_copy_area();
  5906. }
  5907.  
  5908. /*
  5909.  * X Selection stuff, for cutting and pasting text to other windows.
  5910.  */
  5911.     void
  5912. clip_mch_request_selection(VimClipboard *cbd)
  5913. {
  5914.     GdkAtom    target;
  5915.     unsigned    i;
  5916.     int        nbytes;
  5917.     char_u    *buffer;
  5918.  
  5919.     for (i = 0; i < N_SELECTION_TARGETS; ++i)
  5920.     {
  5921.     received_selection = RS_NONE;
  5922.     target = gdk_atom_intern(selection_targets[i].target, FALSE);
  5923.  
  5924.     gtk_selection_convert(gui.drawarea,
  5925.                   cbd->gtk_sel_atom, target,
  5926.                   (guint32)GDK_CURRENT_TIME);
  5927.  
  5928.     while (received_selection == RS_NONE)
  5929.         gtk_main();    /* wait for selection_received_cb */
  5930.  
  5931.     if (received_selection != RS_FAIL)
  5932.         return;
  5933.     }
  5934.  
  5935.     /* Final fallback position - use the X CUT_BUFFER0 store */
  5936.     nbytes = 0;
  5937.     buffer = (char_u *)XFetchBuffer(GDK_WINDOW_XDISPLAY(gui.mainwin->window),
  5938.                     &nbytes, 0);
  5939.     if (nbytes > 0)
  5940.     {
  5941.     /* Got something */
  5942.     clip_yank_selection(MCHAR, buffer, (long)nbytes, cbd);
  5943.     if (p_verbose > 0)
  5944.         smsg((char_u *)_("Used CUT_BUFFER0 instead of empty selection"));
  5945.     }
  5946.     if (buffer != NULL)
  5947.     XFree(buffer);
  5948. }
  5949.  
  5950. /*
  5951.  * Disown the selection.
  5952.  */
  5953. /*ARGSUSED*/
  5954.     void
  5955. clip_mch_lose_selection(VimClipboard *cbd)
  5956. {
  5957.     /* WEIRD: when using NULL to actually disown the selection, we lose the
  5958.      * selection the first time we own it. */
  5959.     /*
  5960.     gtk_selection_owner_set(NULL, cbd->gtk_sel_atom, (guint32)GDK_CURRENT_TIME);
  5961.     gui_mch_update();
  5962.      */
  5963. }
  5964.  
  5965. /*
  5966.  * Own the selection and return OK if it worked.
  5967.  */
  5968.     int
  5969. clip_mch_own_selection(VimClipboard *cbd)
  5970. {
  5971.     int success;
  5972.  
  5973.     success = gtk_selection_owner_set(gui.drawarea, cbd->gtk_sel_atom,
  5974.                       (guint32)GDK_CURRENT_TIME);
  5975.     gui_mch_update();
  5976.     return (success) ? OK : FAIL;
  5977. }
  5978.  
  5979. /*
  5980.  * Send the current selection to the clipboard.  Do nothing for X because we
  5981.  * will fill in the selection only when requested by another app.
  5982.  */
  5983. /*ARGSUSED*/
  5984.     void
  5985. clip_mch_set_selection(VimClipboard *cbd)
  5986. {
  5987. }
  5988.  
  5989.  
  5990. #if defined(FEAT_MENU) || defined(PROTO)
  5991. /*
  5992.  * Make a menu item appear either active or not active (grey or not grey).
  5993.  */
  5994.     void
  5995. gui_mch_menu_grey(vimmenu_T *menu, int grey)
  5996. {
  5997.     if (menu->id == NULL)
  5998.     return;
  5999.  
  6000.     if (menu_is_separator(menu->name))
  6001.     grey = TRUE;
  6002.  
  6003.     gui_mch_menu_hidden(menu, FALSE);
  6004.     /* Be clever about bitfields versus true booleans here! */
  6005.     if (!GTK_WIDGET_SENSITIVE(menu->id) == !grey)
  6006.     {
  6007.     gtk_widget_set_sensitive(menu->id, !grey);
  6008.     gui_mch_update();
  6009.     }
  6010. }
  6011.  
  6012. /*
  6013.  * Make menu item hidden or not hidden.
  6014.  */
  6015.     void
  6016. gui_mch_menu_hidden(vimmenu_T *menu, int hidden)
  6017. {
  6018.     if (menu->id == 0)
  6019.     return;
  6020.  
  6021.     if (hidden)
  6022.     {
  6023.     if (GTK_WIDGET_VISIBLE(menu->id))
  6024.     {
  6025.         gtk_widget_hide(menu->id);
  6026.         gui_mch_update();
  6027.     }
  6028.     }
  6029.     else
  6030.     {
  6031.     if (!GTK_WIDGET_VISIBLE(menu->id))
  6032.     {
  6033.         gtk_widget_show(menu->id);
  6034.         gui_mch_update();
  6035.     }
  6036.     }
  6037. }
  6038.  
  6039. /*
  6040.  * This is called after setting all the menus to grey/hidden or not.
  6041.  */
  6042.     void
  6043. gui_mch_draw_menubar(void)
  6044. {
  6045.     /* just make sure that the visual changes get effect immediately */
  6046.     gui_mch_update();
  6047. }
  6048. #endif /* FEAT_MENU */
  6049.  
  6050. /*
  6051.  * Scrollbar stuff.
  6052.  */
  6053.     void
  6054. gui_mch_enable_scrollbar(scrollbar_T *sb, int flag)
  6055. {
  6056.     if (sb->id == NULL)
  6057.     return;
  6058.  
  6059.     if (flag)
  6060.     gtk_widget_show(sb->id);
  6061.     else
  6062.     gtk_widget_hide(sb->id);
  6063.  
  6064.     update_window_manager_hints();
  6065. }
  6066.  
  6067.  
  6068. /*
  6069.  * Return the RGB value of a pixel as long.
  6070.  */
  6071.     long_u
  6072. gui_mch_get_rgb(guicolor_T pixel)
  6073. {
  6074.     GdkColor color;
  6075. #ifndef HAVE_GTK2
  6076.     GdkColorContext *cc;
  6077.  
  6078.     cc = gdk_color_context_new(gtk_widget_get_visual(gui.drawarea),
  6079.                    gtk_widget_get_colormap(gui.drawarea));
  6080.     color.pixel = pixel;
  6081.     gdk_color_context_query_color(cc, &color);
  6082.  
  6083.     gdk_color_context_free(cc);
  6084. #else
  6085.     gdk_colormap_query_color(gtk_widget_get_colormap(gui.drawarea),
  6086.                  (unsigned long)pixel, &color);
  6087. #endif
  6088.  
  6089.     return (((unsigned)color.red   & 0xff00) << 8)
  6090.      |  ((unsigned)color.green & 0xff00)
  6091.      | (((unsigned)color.blue  & 0xff00) >> 8);
  6092. }
  6093.  
  6094. /*
  6095.  * Get current y mouse coordinate in text window.
  6096.  * Return -1 when unknown.
  6097.  */
  6098.     int
  6099. gui_mch_get_mouse_x(void)
  6100. {
  6101.     int win_x;
  6102.  
  6103.     gdk_window_get_pointer(gui.drawarea->window, &win_x, NULL, NULL);
  6104.     return win_x;
  6105. }
  6106.  
  6107.     int
  6108. gui_mch_get_mouse_y(void)
  6109. {
  6110.     int win_y;
  6111.  
  6112.     gdk_window_get_pointer(gui.drawarea->window, NULL, &win_y, NULL);
  6113.     return win_y;
  6114. }
  6115.  
  6116.     void
  6117. gui_mch_setmouse(int x, int y)
  6118. {
  6119.     /* Sorry for the Xlib call, but we can't avoid it, since there is no
  6120.      * internal GDK mechanism present to accomplish this.  (and for good
  6121.      * reason...) */
  6122.     XWarpPointer(GDK_WINDOW_XDISPLAY(gui.drawarea->window),
  6123.          (Window)0, GDK_WINDOW_XWINDOW(gui.drawarea->window),
  6124.          0, 0, 0U, 0U, x, y);
  6125. }
  6126.  
  6127.  
  6128. #ifdef FEAT_MOUSESHAPE
  6129. /* The last set mouse pointer shape is remembered, to be used when it goes
  6130.  * from hidden to not hidden. */
  6131. static int last_shape = 0;
  6132. #endif
  6133.  
  6134. /*
  6135.  * Use the blank mouse pointer or not.
  6136.  *
  6137.  * hide: TRUE = use blank ptr, FALSE = use parent ptr
  6138.  */
  6139.     void
  6140. gui_mch_mousehide(int hide)
  6141. {
  6142.     if (gui.pointer_hidden != hide)
  6143.     {
  6144.     gui.pointer_hidden = hide;
  6145.     if (gui.drawarea->window && gui.blank_pointer != NULL)
  6146.     {
  6147.         if (hide)
  6148.         gdk_window_set_cursor(gui.drawarea->window, gui.blank_pointer);
  6149.         else
  6150. #ifdef FEAT_MOUSESHAPE
  6151.         mch_set_mouse_shape(last_shape);
  6152. #else
  6153.         gdk_window_set_cursor(gui.drawarea->window, NULL);
  6154. #endif
  6155.     }
  6156.     }
  6157. }
  6158.  
  6159. #if defined(FEAT_MOUSESHAPE) || defined(PROTO)
  6160.  
  6161. /* Table for shape IDs.  Keep in sync with the mshape_names[] table in
  6162.  * misc2.c! */
  6163. static const int mshape_ids[] =
  6164. {
  6165.     GDK_LEFT_PTR,        /* arrow */
  6166.     GDK_CURSOR_IS_PIXMAP,    /* blank */
  6167.     GDK_XTERM,            /* beam */
  6168.     GDK_SB_V_DOUBLE_ARROW,    /* updown */
  6169.     GDK_SIZING,            /* udsizing */
  6170.     GDK_SB_H_DOUBLE_ARROW,    /* leftright */
  6171.     GDK_SIZING,            /* lrsizing */
  6172.     GDK_WATCH,            /* busy */
  6173.     GDK_X_CURSOR,        /* no */
  6174.     GDK_CROSSHAIR,        /* crosshair */
  6175.     GDK_HAND1,            /* hand1 */
  6176.     GDK_HAND2,            /* hand2 */
  6177.     GDK_PENCIL,            /* pencil */
  6178.     GDK_QUESTION_ARROW,        /* question */
  6179.     GDK_RIGHT_PTR,        /* right-arrow */
  6180.     GDK_CENTER_PTR,        /* up-arrow */
  6181.     GDK_LEFT_PTR        /* last one */
  6182. };
  6183.  
  6184.     void
  6185. mch_set_mouse_shape(int shape)
  6186. {
  6187.     int           id;
  6188.     GdkCursor       *c;
  6189.  
  6190.     if (gui.drawarea->window == NULL)
  6191.     return;
  6192.  
  6193.     if (shape == MSHAPE_HIDE || gui.pointer_hidden)
  6194.     gdk_window_set_cursor(gui.drawarea->window, gui.blank_pointer);
  6195.     else
  6196.     {
  6197.     if (shape >= MSHAPE_NUMBERED)
  6198.     {
  6199.         id = shape - MSHAPE_NUMBERED;
  6200.         if (id >= GDK_LAST_CURSOR)
  6201.         id = GDK_LEFT_PTR;
  6202.         else
  6203.         id &= ~1;    /* they are always even (why?) */
  6204.     }
  6205.     else
  6206.         id = mshape_ids[shape];
  6207. # ifdef HAVE_GTK_MULTIHEAD
  6208.     c = gdk_cursor_new_for_display(
  6209.         gtk_widget_get_display(gui.drawarea), id);
  6210. # else
  6211.     c = gdk_cursor_new(id);
  6212. # endif
  6213.     gdk_window_set_cursor(gui.drawarea->window, c);
  6214.     gdk_cursor_destroy(c); /* Unref, actually.  Bloody GTK+ 1. */
  6215.     }
  6216.     if (shape != MSHAPE_HIDE)
  6217.     last_shape = shape;
  6218. }
  6219. #endif /* FEAT_MOUSESHAPE */
  6220.  
  6221.  
  6222. #if defined(FEAT_SIGN_ICONS) || defined(PROTO)
  6223. /*
  6224.  * Signs are currently always 2 chars wide.  With GTK+ 2, the image will be
  6225.  * scaled down if the current font is not big enough, or scaled up if the image
  6226.  * size is less than 3/4 of the maximum sign size.  With GTK+ 1, the pixmap
  6227.  * will be cut off if the current font is not big enough, or centered if it's
  6228.  * too small.
  6229.  */
  6230. # define SIGN_WIDTH  (2 * gui.char_width)
  6231. # define SIGN_HEIGHT (gui.char_height)
  6232. # define SIGN_ASPECT ((double)SIGN_HEIGHT / (double)SIGN_WIDTH)
  6233.  
  6234. # ifdef HAVE_GTK2
  6235.  
  6236.     void
  6237. gui_mch_drawsign(int row, int col, int typenr)
  6238. {
  6239.     GdkPixbuf *sign;
  6240.  
  6241.     sign = (GdkPixbuf *)sign_get_image(typenr);
  6242.  
  6243.     if (sign != NULL && gui.drawarea != NULL && gui.drawarea->window != NULL)
  6244.     {
  6245.     int width;
  6246.     int height;
  6247.     int xoffset;
  6248.     int yoffset;
  6249.     int need_scale;
  6250.  
  6251.     width  = gdk_pixbuf_get_width(sign);
  6252.     height = gdk_pixbuf_get_height(sign);
  6253.     /*
  6254.      * Decide whether we need to scale.  Allow one pixel of border
  6255.      * width to be cut off, in order to avoid excessive scaling for
  6256.      * tiny differences in font size.
  6257.      */
  6258.     need_scale = (width > SIGN_WIDTH + 2
  6259.               || height > SIGN_HEIGHT + 2
  6260.               || (width < 3 * SIGN_WIDTH / 4
  6261.               && height < 3 * SIGN_HEIGHT / 4));
  6262.     if (need_scale)
  6263.     {
  6264.         double aspect;
  6265.  
  6266.         /* Keep the original aspect ratio */
  6267.         aspect = (double)height / (double)width;
  6268.         width  = (double)SIGN_WIDTH * SIGN_ASPECT / aspect;
  6269.         width  = MIN(width, SIGN_WIDTH);
  6270.         height = (double)width * aspect;
  6271.  
  6272.         /* This doesn't seem to be worth caching, and doing so
  6273.          * would complicate the code quite a bit. */
  6274.         sign = gdk_pixbuf_scale_simple(sign, width, height,
  6275.                        GDK_INTERP_BILINEAR);
  6276.         if (sign == NULL)
  6277.         return; /* out of memory */
  6278.     }
  6279.  
  6280.     /* The origin is the upper-left corner of the pixmap.  Therefore
  6281.      * these offset may become negative if the pixmap is smaller than
  6282.      * the 2x1 cells reserved for the sign icon. */
  6283.     xoffset = (width  - SIGN_WIDTH)  / 2;
  6284.     yoffset = (height - SIGN_HEIGHT) / 2;
  6285.  
  6286.     gdk_gc_set_foreground(gui.text_gc, gui.bgcolor);
  6287.  
  6288.     gdk_draw_rectangle(gui.drawarea->window,
  6289.                gui.text_gc,
  6290.                TRUE,
  6291.                FILL_X(col),
  6292.                FILL_Y(row),
  6293.                SIGN_WIDTH,
  6294.                SIGN_HEIGHT);
  6295.  
  6296. #  if GTK_CHECK_VERSION(2,1,1)
  6297.     gdk_draw_pixbuf(gui.drawarea->window,
  6298.             NULL,
  6299.             sign,
  6300.             MAX(0, xoffset),
  6301.             MAX(0, yoffset),
  6302.             FILL_X(col) - MIN(0, xoffset),
  6303.             FILL_Y(row) - MIN(0, yoffset),
  6304.             MIN(width,  SIGN_WIDTH),
  6305.             MIN(height, SIGN_HEIGHT),
  6306.             GDK_RGB_DITHER_NORMAL,
  6307.             0, 0);
  6308. #  else
  6309.     gdk_pixbuf_render_to_drawable_alpha(sign,
  6310.                         gui.drawarea->window,
  6311.                         MAX(0, xoffset),
  6312.                         MAX(0, yoffset),
  6313.                         FILL_X(col) - MIN(0, xoffset),
  6314.                         FILL_Y(row) - MIN(0, yoffset),
  6315.                         MIN(width,    SIGN_WIDTH),
  6316.                         MIN(height, SIGN_HEIGHT),
  6317.                         GDK_PIXBUF_ALPHA_BILEVEL,
  6318.                         127,
  6319.                         GDK_RGB_DITHER_NORMAL,
  6320.                         0, 0);
  6321. #  endif
  6322.     if (need_scale)
  6323.         g_object_unref(sign);
  6324.     }
  6325. }
  6326.  
  6327.     void *
  6328. gui_mch_register_sign(char_u *signfile)
  6329. {
  6330.     if (signfile[0] != NUL && signfile[0] != '-' && gui.in_use)
  6331.     {
  6332.     GdkPixbuf   *sign;
  6333.     GError        *error = NULL;
  6334.     char_u        *message;
  6335.  
  6336.     sign = gdk_pixbuf_new_from_file((const char *)signfile, &error);
  6337.  
  6338.     if (error == NULL)
  6339.         return sign;
  6340.  
  6341.     message = (char_u *)error->message;
  6342.  
  6343.     if (message != NULL && input_conv.vc_type != CONV_NONE)
  6344.         message = string_convert(&input_conv, message, NULL);
  6345.  
  6346.     if (message != NULL)
  6347.     {
  6348.         /* The error message is already translated and will be more
  6349.          * descriptive than anything we could possibly do ourselves. */
  6350.         EMSG2("E255: %s", message);
  6351.  
  6352.         if (input_conv.vc_type != CONV_NONE)
  6353.         vim_free(message);
  6354.     }
  6355.     g_error_free(error);
  6356.     }
  6357.  
  6358.     return NULL;
  6359. }
  6360.  
  6361.     void
  6362. gui_mch_destroy_sign(void *sign)
  6363. {
  6364.     if (sign != NULL)
  6365.     g_object_unref(sign);
  6366. }
  6367.  
  6368. # else /* !HAVE_GTK2 */
  6369.  
  6370. typedef struct
  6371. {
  6372.     GdkPixmap *pixmap;
  6373.     GdkBitmap *mask;
  6374. }
  6375. signicon_T;
  6376.  
  6377.     void
  6378. gui_mch_drawsign(int row, int col, int typenr)
  6379. {
  6380.     signicon_T *sign;
  6381.  
  6382.     sign = (signicon_T *)sign_get_image(typenr);
  6383.  
  6384.     if (sign != NULL && sign->pixmap != NULL
  6385.     && gui.drawarea != NULL && gui.drawarea->window != NULL)
  6386.     {
  6387.     int width;
  6388.     int height;
  6389.     int xoffset;
  6390.     int yoffset;
  6391.  
  6392.     gdk_window_get_size(sign->pixmap, &width, &height);
  6393.  
  6394.     /* The origin is the upper-left corner of the pixmap.  Therefore
  6395.      * these offset may become negative if the pixmap is smaller than
  6396.      * the 2x1 cells reserved for the sign icon. */
  6397.     xoffset = (width  - SIGN_WIDTH)  / 2;
  6398.     yoffset = (height - SIGN_HEIGHT) / 2;
  6399.  
  6400.     gdk_gc_set_foreground(gui.text_gc, gui.bgcolor);
  6401.  
  6402.     gdk_draw_rectangle(gui.drawarea->window,
  6403.                gui.text_gc,
  6404.                TRUE,
  6405.                FILL_X(col),
  6406.                FILL_Y(row),
  6407.                SIGN_WIDTH,
  6408.                SIGN_HEIGHT);
  6409.  
  6410.     /* Set the clip mask for bilevel transparency */
  6411.     if (sign->mask != NULL)
  6412.     {
  6413.         gdk_gc_set_clip_origin(gui.text_gc,
  6414.                    FILL_X(col) - xoffset,
  6415.                    FILL_Y(row) - yoffset);
  6416.         gdk_gc_set_clip_mask(gui.text_gc, sign->mask);
  6417.     }
  6418.  
  6419.     gdk_draw_pixmap(gui.drawarea->window,
  6420.             gui.text_gc,
  6421.             sign->pixmap,
  6422.             MAX(0, xoffset),
  6423.             MAX(0, yoffset),
  6424.             FILL_X(col) - MIN(0, xoffset),
  6425.             FILL_Y(row) - MIN(0, yoffset),
  6426.             MIN(width,  SIGN_WIDTH),
  6427.             MIN(height, SIGN_HEIGHT));
  6428.  
  6429.     gdk_gc_set_clip_mask(gui.text_gc, NULL);
  6430.     }
  6431. }
  6432.  
  6433.     void *
  6434. gui_mch_register_sign(char_u *signfile)
  6435. {
  6436.     signicon_T *sign = NULL;
  6437.  
  6438.     if (signfile[0] != NUL && signfile[0] != '-'
  6439.         && gui.drawarea != NULL && gui.drawarea->window != NULL)
  6440.     {
  6441.     sign = (signicon_T *)alloc(sizeof(signicon_T));
  6442.  
  6443.     if (sign != NULL) /* NULL == OOM == "cannot really happen" */
  6444.     {
  6445.         sign->mask = NULL;
  6446.         sign->pixmap = gdk_pixmap_colormap_create_from_xpm(
  6447.             gui.drawarea->window, NULL,
  6448.             &sign->mask, NULL,
  6449.             (const char *)signfile);
  6450.  
  6451.         if (sign->pixmap == NULL)
  6452.         {
  6453.         vim_free(sign);
  6454.         sign = NULL;
  6455.         EMSG(_(e_signdata));
  6456.         }
  6457.     }
  6458.     }
  6459.     return sign;
  6460. }
  6461.  
  6462.     void
  6463. gui_mch_destroy_sign(void *sign)
  6464. {
  6465.     if (sign != NULL)
  6466.     {
  6467.     signicon_T *signicon = (signicon_T *)sign;
  6468.  
  6469.     if (signicon->pixmap != NULL)
  6470.         gdk_pixmap_unref(signicon->pixmap);
  6471.     if (signicon->mask != NULL)
  6472.         gdk_bitmap_unref(signicon->mask);
  6473.  
  6474.     vim_free(signicon);
  6475.     }
  6476. }
  6477. # endif /* !HAVE_GTK2 */
  6478.  
  6479. #endif /* FEAT_SIGN_ICONS */
  6480.  
  6481.