comparison src/mbyte.c @ 2275:e4d849f4df03 vim73

Remove the old and not well supported GTK 1 code. (James Vega)
author Bram Moolenaar <bram@vim.org>
date Fri, 25 Jun 2010 05:37:59 +0200
parents 1bac28a53fae
children f42e0b5ff9e9
comparison
equal deleted inserted replaced
2274:7c31d761ffa9 2275:e4d849f4df03
98 #endif 98 #endif
99 #ifdef X_LOCALE 99 #ifdef X_LOCALE
100 #include <X11/Xlocale.h> 100 #include <X11/Xlocale.h>
101 #endif 101 #endif
102 102
103 #if defined(FEAT_GUI_GTK) && defined(FEAT_XIM) && defined(HAVE_GTK2) 103 #if defined(FEAT_GUI_GTK) && defined(FEAT_XIM)
104 # include <gdk/gdkkeysyms.h> 104 # include <gdk/gdkkeysyms.h>
105 # ifdef WIN3264 105 # ifdef WIN3264
106 # include <gdk/gdkwin32.h> 106 # include <gdk/gdkwin32.h>
107 # else 107 # else
108 # include <gdk/gdkx.h> 108 # include <gdk/gdkx.h>
5066 #ifdef FEAT_GUI_X11 5066 #ifdef FEAT_GUI_X11
5067 static XIMStyle input_style; 5067 static XIMStyle input_style;
5068 static int status_area_enabled = TRUE; 5068 static int status_area_enabled = TRUE;
5069 #endif 5069 #endif
5070 5070
5071 #ifdef FEAT_GUI_GTK
5072 # ifdef WIN3264
5073 # include <gdk/gdkwin32.h>
5074 # else
5075 # include <gdk/gdkx.h>
5076 # endif
5077 #else
5078 # ifdef PROTO
5079 /* Define a few things to be able to generate prototypes while not configured
5080 * for GTK. */
5081 # define GSList int
5082 # define gboolean int
5083 typedef int GdkEvent;
5084 typedef int GdkEventKey;
5085 # define GdkIC int
5086 # endif
5087 #endif
5088
5089 #if defined(FEAT_GUI_GTK) || defined(PROTO)
5090 static int preedit_buf_len = 0;
5091 static int xim_can_preediting INIT(= FALSE); /* XIM in showmode() */
5092 static int xim_input_style;
5093 #ifndef FEAT_GUI_GTK
5094 # define gboolean int
5095 #endif
5096 static gboolean use_status_area = 0;
5097
5098 static int im_xim_str2keycode __ARGS((unsigned int *code, unsigned int *state));
5099 static void im_xim_send_event_imactivate __ARGS((void));
5100
5101 /*
5102 * Convert string to keycode and state for XKeyEvent.
5103 * When string is valid return OK, when invalid return FAIL.
5104 *
5105 * See 'imactivatekey' documentation for the format.
5106 */
5107 static int
5108 im_xim_str2keycode(code, state)
5109 unsigned int *code;
5110 unsigned int *state;
5111 {
5112 int retval = OK;
5113 int len;
5114 unsigned keycode = 0, keystate = 0;
5115 Window window;
5116 Display *display;
5117 char_u *flag_end;
5118 char_u *str;
5119
5120 if (*p_imak != NUL)
5121 {
5122 len = STRLEN(p_imak);
5123 for (flag_end = p_imak + len - 1;
5124 flag_end > p_imak && *flag_end != '-'; --flag_end)
5125 ;
5126
5127 /* Parse modifier keys */
5128 for (str = p_imak; str < flag_end; ++str)
5129 {
5130 switch (*str)
5131 {
5132 case 's': case 'S':
5133 keystate |= ShiftMask;
5134 break;
5135 case 'l': case 'L':
5136 keystate |= LockMask;
5137 break;
5138 case 'c': case 'C':
5139 keystate |= ControlMask;
5140 break;
5141 case '1':
5142 keystate |= Mod1Mask;
5143 break;
5144 case '2':
5145 keystate |= Mod2Mask;
5146 break;
5147 case '3':
5148 keystate |= Mod3Mask;
5149 break;
5150 case '4':
5151 keystate |= Mod4Mask;
5152 break;
5153 case '5':
5154 keystate |= Mod5Mask;
5155 break;
5156 case '-':
5157 break;
5158 default:
5159 retval = FAIL;
5160 }
5161 }
5162 if (*str == '-')
5163 ++str;
5164
5165 /* Get keycode from string. */
5166 gui_get_x11_windis(&window, &display);
5167 if (display)
5168 keycode = XKeysymToKeycode(display, XStringToKeysym((char *)str));
5169 if (keycode == 0)
5170 retval = FAIL;
5171
5172 if (code != NULL)
5173 *code = keycode;
5174 if (state != NULL)
5175 *state = keystate;
5176 }
5177 return retval;
5178 }
5179
5180 static void
5181 im_xim_send_event_imactivate()
5182 {
5183 /* Force turn on preedit state by simulating keypress event.
5184 * Keycode and state is specified by 'imactivatekey'.
5185 */
5186 XKeyEvent ev;
5187
5188 gui_get_x11_windis(&ev.window, &ev.display);
5189 ev.root = RootWindow(ev.display, DefaultScreen(ev.display));
5190 ev.subwindow = None;
5191 ev.time = CurrentTime;
5192 ev.x = 1;
5193 ev.y = 1;
5194 ev.x_root = 1;
5195 ev.y_root = 1;
5196 ev.same_screen = 1;
5197 ev.type = KeyPress;
5198 if (im_xim_str2keycode(&ev.keycode, &ev.state) == OK)
5199 XSendEvent(ev.display, ev.window, 1, KeyPressMask, (XEvent*)&ev);
5200 }
5201
5202 /*
5203 * Return TRUE if 'imactivatekey' has a valid value.
5204 */
5205 int
5206 im_xim_isvalid_imactivate()
5207 {
5208 return im_xim_str2keycode(NULL, NULL) == OK;
5209 }
5210 #endif /* FEAT_GUI_GTK */
5211
5212 /* 5071 /*
5213 * Switch using XIM on/off. This is used by the code that changes "State". 5072 * Switch using XIM on/off. This is used by the code that changes "State".
5214 */ 5073 */
5215 void 5074 void
5216 im_set_active(active) 5075 im_set_active(active)
5230 active = TRUE; 5089 active = TRUE;
5231 #endif 5090 #endif
5232 5091
5233 /* Remember the active state, it is needed when Vim gets keyboard focus. */ 5092 /* Remember the active state, it is needed when Vim gets keyboard focus. */
5234 xim_is_active = active; 5093 xim_is_active = active;
5235
5236 #ifdef FEAT_GUI_GTK
5237 /* When 'imactivatekey' has valid key-string, try to control XIM preedit
5238 * state. When 'imactivatekey' has no or invalid string, try old XIM
5239 * focus control.
5240 */
5241 if (*p_imak != NUL)
5242 {
5243 /* BASIC STRATEGY:
5244 * Destroy old Input Context (XIC), and create new one. New XIC
5245 * would have a state of preedit that is off. When argument:active
5246 * is false, that's all. Else argument:active is true, send a key
5247 * event specified by 'imactivatekey' to activate XIM preedit state.
5248 */
5249
5250 xim_is_active = TRUE; /* Disable old XIM focus control */
5251 /* If we can monitor preedit state with preedit callback functions,
5252 * try least creation of new XIC.
5253 */
5254 if (xim_input_style & (int)GDK_IM_PREEDIT_CALLBACKS)
5255 {
5256 if (xim_can_preediting && !active)
5257 {
5258 /* Force turn off preedit state. With some IM
5259 * implementations, we cannot turn off preedit state by
5260 * simulating keypress event. It is why using such a method
5261 * that destroy old IC (input context), and create new one.
5262 * When create new IC, its preedit state is usually off.
5263 */
5264 xim_reset();
5265 xim_set_focus(FALSE);
5266 gdk_ic_destroy(xic);
5267 xim_init();
5268 xim_can_preediting = FALSE;
5269 }
5270 else if (!xim_can_preediting && active)
5271 im_xim_send_event_imactivate();
5272 }
5273 else
5274 {
5275 /* First, force destroy old IC, and create new one. It
5276 * simulates "turning off preedit state".
5277 */
5278 xim_set_focus(FALSE);
5279 gdk_ic_destroy(xic);
5280 xim_init();
5281 xim_can_preediting = FALSE;
5282
5283 /* 2nd, when requested to activate IM, simulate this by sending
5284 * the event.
5285 */
5286 if (active)
5287 {
5288 im_xim_send_event_imactivate();
5289 xim_can_preediting = TRUE;
5290 }
5291 }
5292 }
5293 else
5294 {
5295 # ifndef XIMPreeditUnKnown
5296 /* X11R5 doesn't have these, it looks safe enough to define here. */
5297 typedef unsigned long XIMPreeditState;
5298 # define XIMPreeditUnKnown 0L
5299 # define XIMPreeditEnable 1L
5300 # define XIMPreeditDisable (1L<<1)
5301 # define XNPreeditState "preeditState"
5302 # endif
5303 XIMPreeditState preedit_state = XIMPreeditUnKnown;
5304 XVaNestedList preedit_attr;
5305 XIC pxic;
5306
5307 preedit_attr = XVaCreateNestedList(0,
5308 XNPreeditState, &preedit_state,
5309 NULL);
5310 pxic = ((GdkICPrivate *)xic)->xic;
5311
5312 if (!XGetICValues(pxic, XNPreeditAttributes, preedit_attr, NULL))
5313 {
5314 XFree(preedit_attr);
5315 preedit_attr = XVaCreateNestedList(0,
5316 XNPreeditState,
5317 active ? XIMPreeditEnable : XIMPreeditDisable,
5318 NULL);
5319 XSetICValues(pxic, XNPreeditAttributes, preedit_attr, NULL);
5320 xim_can_preediting = active;
5321 xim_is_active = active;
5322 }
5323 XFree(preedit_attr);
5324 }
5325 if (xim_input_style & XIMPreeditCallbacks)
5326 {
5327 preedit_buf_len = 0;
5328 init_preedit_start_col();
5329 }
5330 #else
5331 # if 0
5332 /* When had tested kinput2 + canna + Athena GUI version with
5333 * 'imactivatekey' is "s-space", im_xim_send_event_imactivate() did not
5334 * work correctly. It just inserted one space. I don't know why we
5335 * couldn't switch state of XIM preediting. This is reason why these
5336 * codes are commented out.
5337 */
5338 /* First, force destroy old IC, and create new one. It simulates
5339 * "turning off preedit state".
5340 */
5341 xim_set_focus(FALSE);
5342 XDestroyIC(xic);
5343 xic = NULL;
5344 xim_init();
5345
5346 /* 2nd, when requested to activate IM, simulate this by sending the
5347 * event.
5348 */
5349 if (active)
5350 im_xim_send_event_imactivate();
5351 # endif
5352 #endif
5353 xim_set_preedit(); 5094 xim_set_preedit();
5354 } 5095 }
5355 5096
5356 /* 5097 /*
5357 * Adjust using XIM for gaining or losing keyboard focus. Also called when 5098 * Adjust using XIM for gaining or losing keyboard focus. Also called when
5371 if (focus && xim_is_active) 5112 if (focus && xim_is_active)
5372 { 5113 {
5373 if (!xim_has_focus) 5114 if (!xim_has_focus)
5374 { 5115 {
5375 xim_has_focus = TRUE; 5116 xim_has_focus = TRUE;
5376 #ifdef FEAT_GUI_GTK
5377 gdk_im_begin(xic, gui.drawarea->window);
5378 #else
5379 XSetICFocus(xic); 5117 XSetICFocus(xic);
5380 #endif
5381 } 5118 }
5382 } 5119 }
5383 else 5120 else
5384 { 5121 {
5385 if (xim_has_focus) 5122 if (xim_has_focus)
5386 { 5123 {
5387 xim_has_focus = FALSE; 5124 xim_has_focus = FALSE;
5388 #ifdef FEAT_GUI_GTK
5389 gdk_im_end();
5390 #else
5391 XUnsetICFocus(xic); 5125 XUnsetICFocus(xic);
5392 #endif
5393 } 5126 }
5394 } 5127 }
5395 } 5128 }
5396 5129
5397 void 5130 void
5411 if (xic == NULL) 5144 if (xic == NULL)
5412 return; 5145 return;
5413 5146
5414 xim_set_focus(TRUE); 5147 xim_set_focus(TRUE);
5415 5148
5416 #ifdef FEAT_GUI_GTK 5149 XVaNestedList attr_list;
5417 if (gdk_im_ready()) 5150 XRectangle spot_area;
5418 { 5151 XPoint over_spot;
5419 int attrmask; 5152 int line_space;
5420 GdkICAttr *attr; 5153
5421 5154 if (!xim_has_focus)
5422 if (!xic_attr) 5155 {
5423 return; 5156 /* hide XIM cursor */
5424 5157 over_spot.x = 0;
5425 attr = xic_attr; 5158 over_spot.y = -100; /* arbitrary invisible position */
5426 attrmask = 0; 5159 attr_list = (XVaNestedList) XVaCreateNestedList(0,
5427 5160 XNSpotLocation,
5428 # ifdef FEAT_XFONTSET 5161 &over_spot,
5429 if ((xim_input_style & (int)GDK_IM_PREEDIT_POSITION) 5162 NULL);
5430 && gui.fontset != NOFONTSET 5163 XSetICValues(xic, XNPreeditAttributes, attr_list, NULL);
5431 && gui.fontset->type == GDK_FONT_FONTSET) 5164 XFree(attr_list);
5432 { 5165 return;
5433 if (!xim_has_focus) 5166 }
5434 { 5167
5435 if (attr->spot_location.y >= 0) 5168 if (input_style & XIMPreeditPosition)
5436 { 5169 {
5437 attr->spot_location.x = 0;
5438 attr->spot_location.y = -100;
5439 attrmask |= (int)GDK_IC_SPOT_LOCATION;
5440 }
5441 }
5442 else
5443 {
5444 gint width, height;
5445
5446 if (attr->spot_location.x != TEXT_X(gui.col)
5447 || attr->spot_location.y != TEXT_Y(gui.row))
5448 {
5449 attr->spot_location.x = TEXT_X(gui.col);
5450 attr->spot_location.y = TEXT_Y(gui.row);
5451 attrmask |= (int)GDK_IC_SPOT_LOCATION;
5452 }
5453
5454 gdk_window_get_size(gui.drawarea->window, &width, &height);
5455 width -= 2 * gui.border_offset;
5456 height -= 2 * gui.border_offset;
5457 if (xim_input_style & (int)GDK_IM_STATUS_AREA)
5458 height -= gui.char_height;
5459 if (attr->preedit_area.width != width
5460 || attr->preedit_area.height != height)
5461 {
5462 attr->preedit_area.x = gui.border_offset;
5463 attr->preedit_area.y = gui.border_offset;
5464 attr->preedit_area.width = width;
5465 attr->preedit_area.height = height;
5466 attrmask |= (int)GDK_IC_PREEDIT_AREA;
5467 }
5468
5469 if (attr->preedit_fontset != gui.current_font)
5470 {
5471 attr->preedit_fontset = gui.current_font;
5472 attrmask |= (int)GDK_IC_PREEDIT_FONTSET;
5473 }
5474 }
5475 }
5476 # endif /* FEAT_XFONTSET */
5477
5478 if (xim_fg_color == INVALCOLOR) 5170 if (xim_fg_color == INVALCOLOR)
5479 { 5171 {
5480 xim_fg_color = gui.def_norm_pixel; 5172 xim_fg_color = gui.def_norm_pixel;
5481 xim_bg_color = gui.def_back_pixel; 5173 xim_bg_color = gui.def_back_pixel;
5482 } 5174 }
5483 if (attr->preedit_foreground.pixel != xim_fg_color) 5175 over_spot.x = TEXT_X(gui.col);
5484 { 5176 over_spot.y = TEXT_Y(gui.row);
5485 attr->preedit_foreground.pixel = xim_fg_color; 5177 spot_area.x = 0;
5486 attrmask |= (int)GDK_IC_PREEDIT_FOREGROUND; 5178 spot_area.y = 0;
5487 } 5179 spot_area.height = gui.char_height * Rows;
5488 if (attr->preedit_background.pixel != xim_bg_color) 5180 spot_area.width = gui.char_width * Columns;
5489 { 5181 line_space = gui.char_height;
5490 attr->preedit_background.pixel = xim_bg_color; 5182 attr_list = (XVaNestedList) XVaCreateNestedList(0,
5491 attrmask |= (int)GDK_IC_PREEDIT_BACKGROUND; 5183 XNSpotLocation, &over_spot,
5492 } 5184 XNForeground, (Pixel) xim_fg_color,
5493 5185 XNBackground, (Pixel) xim_bg_color,
5494 if (attrmask != 0) 5186 XNArea, &spot_area,
5495 gdk_ic_set_attr(xic, attr, (GdkICAttributesType)attrmask); 5187 XNLineSpace, line_space,
5496 } 5188 NULL);
5497 #else /* FEAT_GUI_GTK */ 5189 if (XSetICValues(xic, XNPreeditAttributes, attr_list, NULL))
5498 { 5190 EMSG(_("E284: Cannot set IC values"));
5499 XVaNestedList attr_list; 5191 XFree(attr_list);
5500 XRectangle spot_area; 5192 }
5501 XPoint over_spot;
5502 int line_space;
5503
5504 if (!xim_has_focus)
5505 {
5506 /* hide XIM cursor */
5507 over_spot.x = 0;
5508 over_spot.y = -100; /* arbitrary invisible position */
5509 attr_list = (XVaNestedList) XVaCreateNestedList(0,
5510 XNSpotLocation,
5511 &over_spot,
5512 NULL);
5513 XSetICValues(xic, XNPreeditAttributes, attr_list, NULL);
5514 XFree(attr_list);
5515 return;
5516 }
5517
5518 if (input_style & XIMPreeditPosition)
5519 {
5520 if (xim_fg_color == INVALCOLOR)
5521 {
5522 xim_fg_color = gui.def_norm_pixel;
5523 xim_bg_color = gui.def_back_pixel;
5524 }
5525 over_spot.x = TEXT_X(gui.col);
5526 over_spot.y = TEXT_Y(gui.row);
5527 spot_area.x = 0;
5528 spot_area.y = 0;
5529 spot_area.height = gui.char_height * Rows;
5530 spot_area.width = gui.char_width * Columns;
5531 line_space = gui.char_height;
5532 attr_list = (XVaNestedList) XVaCreateNestedList(0,
5533 XNSpotLocation, &over_spot,
5534 XNForeground, (Pixel) xim_fg_color,
5535 XNBackground, (Pixel) xim_bg_color,
5536 XNArea, &spot_area,
5537 XNLineSpace, line_space,
5538 NULL);
5539 if (XSetICValues(xic, XNPreeditAttributes, attr_list, NULL))
5540 EMSG(_("E284: Cannot set IC values"));
5541 XFree(attr_list);
5542 }
5543 }
5544 #endif /* FEAT_GUI_GTK */
5545 } 5193 }
5546 5194
5547 /* 5195 /*
5548 * Set up the status area. 5196 * Set up the status area.
5549 * 5197 *
5556 xim_set_status_area() 5204 xim_set_status_area()
5557 { 5205 {
5558 if (xic == NULL) 5206 if (xic == NULL)
5559 return; 5207 return;
5560 5208
5561 #ifdef FEAT_GUI_GTK 5209 XVaNestedList preedit_list = 0, status_list = 0, list = 0;
5562 # if defined(FEAT_XFONTSET) 5210 XRectangle pre_area, status_area;
5563 if (use_status_area) 5211
5564 { 5212 if (input_style & XIMStatusArea)
5565 GdkICAttr *attr; 5213 {
5566 int style; 5214 if (input_style & XIMPreeditArea)
5567 gint width, height;
5568 GtkWidget *widget;
5569 int attrmask;
5570
5571 if (!xic_attr)
5572 return;
5573
5574 attr = xic_attr;
5575 attrmask = 0;
5576 style = (int)gdk_ic_get_style(xic);
5577 if ((style & (int)GDK_IM_STATUS_MASK) == (int)GDK_IM_STATUS_AREA)
5578 { 5215 {
5579 if (gui.fontset != NOFONTSET 5216 XRectangle *needed_rect;
5580 && gui.fontset->type == GDK_FONT_FONTSET) 5217
5581 { 5218 /* to get status_area width */
5582 widget = gui.mainwin; 5219 status_list = XVaCreateNestedList(0, XNAreaNeeded,
5583 gdk_window_get_size(widget->window, &width, &height); 5220 &needed_rect, NULL);
5584 5221 XGetICValues(xic, XNStatusAttributes, status_list, NULL);
5585 attrmask |= (int)GDK_IC_STATUS_AREA; 5222 XFree(status_list);
5586 attr->status_area.x = 0; 5223
5587 attr->status_area.y = height - gui.char_height - 1; 5224 status_area.width = needed_rect->width;
5588 attr->status_area.width = width;
5589 attr->status_area.height = gui.char_height;
5590 }
5591 }
5592 if (attrmask != 0)
5593 gdk_ic_set_attr(xic, attr, (GdkICAttributesType)attrmask);
5594 }
5595 # endif
5596 #else
5597 {
5598 XVaNestedList preedit_list = 0, status_list = 0, list = 0;
5599 XRectangle pre_area, status_area;
5600
5601 if (input_style & XIMStatusArea)
5602 {
5603 if (input_style & XIMPreeditArea)
5604 {
5605 XRectangle *needed_rect;
5606
5607 /* to get status_area width */
5608 status_list = XVaCreateNestedList(0, XNAreaNeeded,
5609 &needed_rect, NULL);
5610 XGetICValues(xic, XNStatusAttributes, status_list, NULL);
5611 XFree(status_list);
5612
5613 status_area.width = needed_rect->width;
5614 }
5615 else
5616 status_area.width = gui.char_width * Columns;
5617
5618 status_area.x = 0;
5619 status_area.y = gui.char_height * Rows + gui.border_offset;
5620 if (gui.which_scrollbars[SBAR_BOTTOM])
5621 status_area.y += gui.scrollbar_height;
5622 #ifdef FEAT_MENU
5623 if (gui.menu_is_active)
5624 status_area.y += gui.menu_height;
5625 #endif
5626 status_area.height = gui.char_height;
5627 status_list = XVaCreateNestedList(0, XNArea, &status_area, NULL);
5628 } 5225 }
5629 else 5226 else
5630 { 5227 status_area.width = gui.char_width * Columns;
5631 status_area.x = 0; 5228
5632 status_area.y = gui.char_height * Rows + gui.border_offset; 5229 status_area.x = 0;
5633 if (gui.which_scrollbars[SBAR_BOTTOM]) 5230 status_area.y = gui.char_height * Rows + gui.border_offset;
5634 status_area.y += gui.scrollbar_height; 5231 if (gui.which_scrollbars[SBAR_BOTTOM])
5232 status_area.y += gui.scrollbar_height;
5635 #ifdef FEAT_MENU 5233 #ifdef FEAT_MENU
5636 if (gui.menu_is_active) 5234 if (gui.menu_is_active)
5637 status_area.y += gui.menu_height; 5235 status_area.y += gui.menu_height;
5638 #endif 5236 #endif
5639 status_area.width = 0; 5237 status_area.height = gui.char_height;
5640 status_area.height = gui.char_height; 5238 status_list = XVaCreateNestedList(0, XNArea, &status_area, NULL);
5641 } 5239 }
5642 5240 else
5643 if (input_style & XIMPreeditArea) /* off-the-spot */ 5241 {
5644 { 5242 status_area.x = 0;
5645 pre_area.x = status_area.x + status_area.width; 5243 status_area.y = gui.char_height * Rows + gui.border_offset;
5646 pre_area.y = gui.char_height * Rows + gui.border_offset; 5244 if (gui.which_scrollbars[SBAR_BOTTOM])
5647 pre_area.width = gui.char_width * Columns - pre_area.x; 5245 status_area.y += gui.scrollbar_height;
5648 if (gui.which_scrollbars[SBAR_BOTTOM])
5649 pre_area.y += gui.scrollbar_height;
5650 #ifdef FEAT_MENU 5246 #ifdef FEAT_MENU
5651 if (gui.menu_is_active) 5247 if (gui.menu_is_active)
5652 pre_area.y += gui.menu_height; 5248 status_area.y += gui.menu_height;
5653 #endif 5249 #endif
5654 pre_area.height = gui.char_height; 5250 status_area.width = 0;
5655 preedit_list = XVaCreateNestedList(0, XNArea, &pre_area, NULL); 5251 status_area.height = gui.char_height;
5656 } 5252 }
5657 else if (input_style & XIMPreeditPosition) /* over-the-spot */ 5253
5658 { 5254 if (input_style & XIMPreeditArea) /* off-the-spot */
5659 pre_area.x = 0; 5255 {
5660 pre_area.y = 0; 5256 pre_area.x = status_area.x + status_area.width;
5661 pre_area.height = gui.char_height * Rows; 5257 pre_area.y = gui.char_height * Rows + gui.border_offset;
5662 pre_area.width = gui.char_width * Columns; 5258 pre_area.width = gui.char_width * Columns - pre_area.x;
5663 preedit_list = XVaCreateNestedList(0, XNArea, &pre_area, NULL); 5259 if (gui.which_scrollbars[SBAR_BOTTOM])
5664 } 5260 pre_area.y += gui.scrollbar_height;
5665 5261 #ifdef FEAT_MENU
5666 if (preedit_list && status_list) 5262 if (gui.menu_is_active)
5667 list = XVaCreateNestedList(0, XNPreeditAttributes, preedit_list, 5263 pre_area.y += gui.menu_height;
5668 XNStatusAttributes, status_list, NULL); 5264 #endif
5669 else if (preedit_list) 5265 pre_area.height = gui.char_height;
5670 list = XVaCreateNestedList(0, XNPreeditAttributes, preedit_list, 5266 preedit_list = XVaCreateNestedList(0, XNArea, &pre_area, NULL);
5671 NULL); 5267 }
5672 else if (status_list) 5268 else if (input_style & XIMPreeditPosition) /* over-the-spot */
5673 list = XVaCreateNestedList(0, XNStatusAttributes, status_list, 5269 {
5674 NULL); 5270 pre_area.x = 0;
5675 else 5271 pre_area.y = 0;
5676 list = NULL; 5272 pre_area.height = gui.char_height * Rows;
5677 5273 pre_area.width = gui.char_width * Columns;
5678 if (list) 5274 preedit_list = XVaCreateNestedList(0, XNArea, &pre_area, NULL);
5679 { 5275 }
5680 XSetICValues(xic, XNVaNestedList, list, NULL); 5276
5681 XFree(list); 5277 if (preedit_list && status_list)
5682 } 5278 list = XVaCreateNestedList(0, XNPreeditAttributes, preedit_list,
5683 if (status_list) 5279 XNStatusAttributes, status_list, NULL);
5684 XFree(status_list); 5280 else if (preedit_list)
5685 if (preedit_list) 5281 list = XVaCreateNestedList(0, XNPreeditAttributes, preedit_list,
5686 XFree(preedit_list); 5282 NULL);
5687 } 5283 else if (status_list)
5688 #endif 5284 list = XVaCreateNestedList(0, XNStatusAttributes, status_list,
5689 } 5285 NULL);
5690 5286 else
5691 #if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK) 5287 list = NULL;
5288
5289 if (list)
5290 {
5291 XSetICValues(xic, XNVaNestedList, list, NULL);
5292 XFree(list);
5293 }
5294 if (status_list)
5295 XFree(status_list);
5296 if (preedit_list)
5297 XFree(preedit_list);
5298 }
5299
5300 #if defined(FEAT_GUI_X11)
5692 static char e_xim[] = N_("E285: Failed to create input context"); 5301 static char e_xim[] = N_("E285: Failed to create input context");
5693 #endif 5302 #endif
5694 5303
5695 #if defined(FEAT_GUI_X11) || defined(PROTO) 5304 #if defined(FEAT_GUI_X11) || defined(PROTO)
5696 # if defined(XtSpecificationRelease) && XtSpecificationRelease >= 6 && !defined(sun) 5305 # if defined(XtSpecificationRelease) && XtSpecificationRelease >= 6 && !defined(sun)
5996 return TRUE; 5605 return TRUE;
5997 } 5606 }
5998 5607
5999 #endif /* FEAT_GUI_X11 */ 5608 #endif /* FEAT_GUI_X11 */
6000 5609
6001 #if defined(FEAT_GUI_GTK) || defined(PROTO)
6002
6003 # ifdef FEAT_XFONTSET
6004 static char e_overthespot[] = N_("E290: over-the-spot style requires fontset");
6005 # endif
6006
6007 # ifdef PROTO
6008 typedef int GdkIC;
6009 # endif
6010
6011 void
6012 xim_decide_input_style()
6013 {
6014 /* GDK_IM_STATUS_CALLBACKS was disabled, enabled it to allow Japanese
6015 * OverTheSpot. */
6016 int supported_style = (int)GDK_IM_PREEDIT_NONE |
6017 (int)GDK_IM_PREEDIT_NOTHING |
6018 (int)GDK_IM_PREEDIT_POSITION |
6019 (int)GDK_IM_PREEDIT_CALLBACKS |
6020 (int)GDK_IM_STATUS_CALLBACKS |
6021 (int)GDK_IM_STATUS_AREA |
6022 (int)GDK_IM_STATUS_NONE |
6023 (int)GDK_IM_STATUS_NOTHING;
6024
6025 #ifdef XIM_DEBUG
6026 xim_log("xim_decide_input_style()\n");
6027 #endif
6028
6029 if (!gdk_im_ready())
6030 xim_input_style = 0;
6031 else
6032 {
6033 if (gtk_major_version > 1
6034 || (gtk_major_version == 1
6035 && (gtk_minor_version > 2
6036 || (gtk_minor_version == 2 && gtk_micro_version >= 3))))
6037 use_status_area = TRUE;
6038 else
6039 {
6040 EMSG(_("E291: Your GTK+ is older than 1.2.3. Status area disabled"));
6041 use_status_area = FALSE;
6042 }
6043 #ifdef FEAT_XFONTSET
6044 if (gui.fontset == NOFONTSET || gui.fontset->type != GDK_FONT_FONTSET)
6045 #endif
6046 supported_style &= ~((int)GDK_IM_PREEDIT_POSITION
6047 | (int)GDK_IM_STATUS_AREA);
6048 if (!use_status_area)
6049 supported_style &= ~(int)GDK_IM_STATUS_AREA;
6050 xim_input_style = (int)gdk_im_decide_style((GdkIMStyle)supported_style);
6051 }
6052 }
6053
6054 static void
6055 preedit_start_cbproc(XIC thexic UNUSED,
6056 XPointer client_data UNUSED,
6057 XPointer call_data UNUSED)
6058 {
6059 #ifdef XIM_DEBUG
6060 xim_log("xim_decide_input_style()\n");
6061 #endif
6062
6063 draw_feedback = NULL;
6064 xim_can_preediting = TRUE;
6065 xim_has_preediting = TRUE;
6066 gui_update_cursor(TRUE, FALSE);
6067 if (showmode() > 0)
6068 {
6069 setcursor();
6070 out_flush();
6071 }
6072 }
6073
6074 static void
6075 xim_back_delete(int n)
6076 {
6077 char_u str[3];
6078
6079 str[0] = CSI;
6080 str[1] = 'k';
6081 str[2] = 'b';
6082 while (n-- > 0)
6083 add_to_input_buf(str, 3);
6084 }
6085
6086 static GSList *key_press_event_queue = NULL;
6087 static gboolean processing_queued_event = FALSE;
6088
6089 static void
6090 preedit_draw_cbproc(XIC thexic UNUSED,
6091 XPointer client_data UNUSED,
6092 XPointer call_data)
6093 {
6094 XIMPreeditDrawCallbackStruct *draw_data;
6095 XIMText *text;
6096 char *src;
6097 GSList *event_queue;
6098
6099 #ifdef XIM_DEBUG
6100 xim_log("preedit_draw_cbproc()\n");
6101 #endif
6102
6103 draw_data = (XIMPreeditDrawCallbackStruct *) call_data;
6104 text = (XIMText *) draw_data->text;
6105
6106 if ((text == NULL && draw_data->chg_length == preedit_buf_len)
6107 || preedit_buf_len == 0)
6108 {
6109 init_preedit_start_col();
6110 vim_free(draw_feedback);
6111 draw_feedback = NULL;
6112 }
6113 if (draw_data->chg_length > 0)
6114 {
6115 int bs_cnt;
6116
6117 if (draw_data->chg_length > preedit_buf_len)
6118 bs_cnt = preedit_buf_len;
6119 else
6120 bs_cnt = draw_data->chg_length;
6121 xim_back_delete(bs_cnt);
6122 preedit_buf_len -= bs_cnt;
6123 }
6124 if (text != NULL)
6125 {
6126 int len;
6127 #ifdef FEAT_MBYTE
6128 char_u *buf = NULL;
6129 unsigned int nfeedback = 0;
6130 #endif
6131 char_u *ptr;
6132
6133 src = text->string.multi_byte;
6134 if (src != NULL && !text->encoding_is_wchar)
6135 {
6136 len = strlen(src);
6137 ptr = (char_u *)src;
6138 /* Avoid the enter for decision */
6139 if (*ptr == '\n')
6140 return;
6141
6142 #ifdef FEAT_MBYTE
6143 if (input_conv.vc_type != CONV_NONE
6144 && (buf = string_convert(&input_conv,
6145 (char_u *)src, &len)) != NULL)
6146 {
6147 /* Converted from 'termencoding' to 'encoding'. */
6148 add_to_input_buf_csi(buf, len);
6149 ptr = buf;
6150 }
6151 else
6152 #endif
6153 add_to_input_buf_csi((char_u *)src, len);
6154 /* Add count of character to preedit_buf_len */
6155 while (*ptr != NUL)
6156 {
6157 #ifdef FEAT_MBYTE
6158 if (draw_data->text->feedback != NULL)
6159 {
6160 if (draw_feedback == NULL)
6161 draw_feedback = (char *)alloc(draw_data->chg_first
6162 + text->length);
6163 else
6164 draw_feedback = vim_realloc(draw_feedback,
6165 draw_data->chg_first + text->length);
6166 if (draw_feedback != NULL)
6167 {
6168 draw_feedback[nfeedback + draw_data->chg_first]
6169 = draw_data->text->feedback[nfeedback];
6170 nfeedback++;
6171 }
6172 }
6173 if (has_mbyte)
6174 ptr += (*mb_ptr2len)(ptr);
6175 else
6176 #endif
6177 ptr++;
6178 preedit_buf_len++;
6179 }
6180 #ifdef FEAT_MBYTE
6181 vim_free(buf);
6182 #endif
6183 preedit_end_col = MAXCOL;
6184 }
6185 }
6186 if (text != NULL || draw_data->chg_length > 0)
6187 {
6188 event_queue = key_press_event_queue;
6189 processing_queued_event = TRUE;
6190 while (event_queue != NULL && processing_queued_event)
6191 {
6192 GdkEvent *ev = event_queue->data;
6193
6194 gboolean *ret;
6195 gtk_signal_emit_by_name((GtkObject*)gui.mainwin, "key_press_event",
6196 ev, &ret);
6197 gdk_event_free(ev);
6198 event_queue = event_queue->next;
6199 }
6200 processing_queued_event = FALSE;
6201 if (key_press_event_queue)
6202 {
6203 g_slist_free(key_press_event_queue);
6204 key_press_event_queue = NULL;
6205 }
6206 }
6207 if (gtk_main_level() > 0)
6208 gtk_main_quit();
6209 }
6210
6211 /*
6212 * Retrieve the highlighting attributes at column col in the preedit string.
6213 * Return -1 if not in preediting mode or if col is out of range.
6214 */
6215 int
6216 im_get_feedback_attr(int col)
6217 {
6218 if (draw_feedback != NULL && col < preedit_buf_len)
6219 {
6220 if (draw_feedback[col] & XIMReverse)
6221 return HL_INVERSE;
6222 else if (draw_feedback[col] & XIMUnderline)
6223 return HL_UNDERLINE;
6224 else
6225 return hl_attr(HLF_V);
6226 }
6227
6228 return -1;
6229 }
6230
6231 static void
6232 preedit_caret_cbproc(XIC thexic UNUSED,
6233 XPointer client_data UNUSED,
6234 XPointer call_data UNUSED)
6235 {
6236 #ifdef XIM_DEBUG
6237 xim_log("preedit_caret_cbproc()\n");
6238 #endif
6239 }
6240
6241 static void
6242 preedit_done_cbproc(XIC thexic UNUSED,
6243 XPointer client_data UNUSED,
6244 XPointer call_data UNUSED)
6245 {
6246 #ifdef XIM_DEBUG
6247 xim_log("preedit_done_cbproc()\n");
6248 #endif
6249
6250 vim_free(draw_feedback);
6251 draw_feedback = NULL;
6252 xim_can_preediting = FALSE;
6253 xim_has_preediting = FALSE;
6254 gui_update_cursor(TRUE, FALSE);
6255 if (showmode() > 0)
6256 {
6257 setcursor();
6258 out_flush();
6259 }
6260 }
6261
6262 void
6263 xim_reset(void)
6264 {
6265 char *text;
6266
6267 #ifdef XIM_DEBUG
6268 xim_log("xim_reset()\n");
6269 #endif
6270
6271 if (xic != NULL)
6272 {
6273 text = XmbResetIC(((GdkICPrivate *)xic)->xic);
6274 if (text != NULL && !(xim_input_style & (int)GDK_IM_PREEDIT_CALLBACKS))
6275 add_to_input_buf_csi((char_u *)text, strlen(text));
6276 else
6277 preedit_buf_len = 0;
6278 if (text != NULL)
6279 XFree(text);
6280 }
6281 }
6282
6283 int
6284 xim_queue_key_press_event(GdkEventKey *event, int down UNUSED)
6285 {
6286 #ifdef XIM_DEBUG
6287 xim_log("xim_queue_key_press_event()\n");
6288 #endif
6289
6290 if (preedit_buf_len <= 0)
6291 return FALSE;
6292 if (processing_queued_event)
6293 processing_queued_event = FALSE;
6294
6295 key_press_event_queue = g_slist_append(key_press_event_queue,
6296 gdk_event_copy((GdkEvent *)event));
6297 return TRUE;
6298 }
6299
6300 static void
6301 preedit_callback_setup(GdkIC *ic UNUSED)
6302 {
6303 XIC xxic;
6304 XVaNestedList preedit_attr;
6305 XIMCallback preedit_start_cb;
6306 XIMCallback preedit_draw_cb;
6307 XIMCallback preedit_caret_cb;
6308 XIMCallback preedit_done_cb;
6309
6310 xxic = ((GdkICPrivate*)xic)->xic;
6311 preedit_start_cb.callback = (XIMProc)preedit_start_cbproc;
6312 preedit_draw_cb.callback = (XIMProc)preedit_draw_cbproc;
6313 preedit_caret_cb.callback = (XIMProc)preedit_caret_cbproc;
6314 preedit_done_cb.callback = (XIMProc)preedit_done_cbproc;
6315 preedit_attr
6316 = XVaCreateNestedList(0,
6317 XNPreeditStartCallback, &preedit_start_cb,
6318 XNPreeditDrawCallback, &preedit_draw_cb,
6319 XNPreeditCaretCallback, &preedit_caret_cb,
6320 XNPreeditDoneCallback, &preedit_done_cb,
6321 NULL);
6322 XSetICValues(xxic, XNPreeditAttributes, preedit_attr, NULL);
6323 XFree(preedit_attr);
6324 }
6325
6326 static void
6327 reset_state_setup(GdkIC *ic UNUSED)
6328 {
6329 #ifdef USE_X11R6_XIM
6330 /* don't change the input context when we call reset */
6331 XSetICValues(((GdkICPrivate *)ic)->xic, XNResetState, XIMPreserveState,
6332 NULL);
6333 #endif
6334 }
6335
6336 void
6337 xim_init(void)
6338 {
6339 #ifdef XIM_DEBUG
6340 xim_log("xim_init()\n");
6341 #endif
6342
6343 xic = NULL;
6344 xic_attr = NULL;
6345
6346 if (!gdk_im_ready())
6347 {
6348 if (p_verbose > 0)
6349 {
6350 verbose_enter();
6351 EMSG(_("E292: Input Method Server is not running"));
6352 verbose_leave();
6353 }
6354 return;
6355 }
6356 if ((xic_attr = gdk_ic_attr_new()) != NULL)
6357 {
6358 #ifdef FEAT_XFONTSET
6359 gint width, height;
6360 #endif
6361 int mask;
6362 GdkColormap *colormap;
6363 GdkICAttr *attr = xic_attr;
6364 int attrmask = (int)GDK_IC_ALL_REQ;
6365 GtkWidget *widget = gui.drawarea;
6366
6367 attr->style = (GdkIMStyle)xim_input_style;
6368 attr->client_window = gui.mainwin->window;
6369
6370 if ((colormap = gtk_widget_get_colormap(widget)) !=
6371 gtk_widget_get_default_colormap())
6372 {
6373 attrmask |= (int)GDK_IC_PREEDIT_COLORMAP;
6374 attr->preedit_colormap = colormap;
6375 }
6376 attrmask |= (int)GDK_IC_PREEDIT_FOREGROUND;
6377 attrmask |= (int)GDK_IC_PREEDIT_BACKGROUND;
6378 attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
6379 attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
6380
6381 #ifdef FEAT_XFONTSET
6382 if ((xim_input_style & (int)GDK_IM_PREEDIT_MASK)
6383 == (int)GDK_IM_PREEDIT_POSITION)
6384 {
6385 if (gui.fontset == NOFONTSET
6386 || gui.fontset->type != GDK_FONT_FONTSET)
6387 {
6388 EMSG(_(e_overthespot));
6389 }
6390 else
6391 {
6392 gdk_window_get_size(widget->window, &width, &height);
6393
6394 attrmask |= (int)GDK_IC_PREEDIT_POSITION_REQ;
6395 attr->spot_location.x = TEXT_X(0);
6396 attr->spot_location.y = TEXT_Y(0);
6397 attr->preedit_area.x = gui.border_offset;
6398 attr->preedit_area.y = gui.border_offset;
6399 attr->preedit_area.width = width - 2*gui.border_offset;
6400 attr->preedit_area.height = height - 2*gui.border_offset;
6401 attr->preedit_fontset = gui.fontset;
6402 }
6403 }
6404
6405 if ((xim_input_style & (int)GDK_IM_STATUS_MASK)
6406 == (int)GDK_IM_STATUS_AREA)
6407 {
6408 if (gui.fontset == NOFONTSET
6409 || gui.fontset->type != GDK_FONT_FONTSET)
6410 {
6411 EMSG(_(e_overthespot));
6412 }
6413 else
6414 {
6415 gdk_window_get_size(gui.mainwin->window, &width, &height);
6416 attrmask |= (int)GDK_IC_STATUS_AREA_REQ;
6417 attr->status_area.x = 0;
6418 attr->status_area.y = height - gui.char_height - 1;
6419 attr->status_area.width = width;
6420 attr->status_area.height = gui.char_height;
6421 attr->status_fontset = gui.fontset;
6422 }
6423 }
6424 else if ((xim_input_style & (int)GDK_IM_STATUS_MASK)
6425 == (int)GDK_IM_STATUS_CALLBACKS)
6426 {
6427 /* FIXME */
6428 }
6429 #endif
6430
6431 xic = gdk_ic_new(attr, (GdkICAttributesType)attrmask);
6432
6433 if (xic == NULL)
6434 EMSG(_(e_xim));
6435 else
6436 {
6437 mask = (int)gdk_window_get_events(widget->window);
6438 mask |= (int)gdk_ic_get_events(xic);
6439 gdk_window_set_events(widget->window, (GdkEventMask)mask);
6440 if (xim_input_style & (int)GDK_IM_PREEDIT_CALLBACKS)
6441 preedit_callback_setup(xic);
6442 reset_state_setup(xic);
6443 }
6444 }
6445 }
6446
6447 void
6448 im_shutdown(void)
6449 {
6450 #ifdef XIM_DEBUG
6451 xim_log("im_shutdown()\n");
6452 #endif
6453
6454 if (xic != NULL)
6455 {
6456 gdk_im_end();
6457 gdk_ic_destroy(xic);
6458 xic = NULL;
6459 }
6460 xim_is_active = FALSE;
6461 xim_can_preediting = FALSE;
6462 preedit_start_col = MAXCOL;
6463 xim_has_preediting = FALSE;
6464 }
6465
6466 #endif /* FEAT_GUI_GTK */
6467
6468 int 5610 int
6469 xim_get_status_area_height() 5611 xim_get_status_area_height()
6470 { 5612 {
6471 #ifdef FEAT_GUI_GTK
6472 if (xim_input_style & (int)GDK_IM_STATUS_AREA)
6473 return gui.char_height;
6474 #else
6475 if (status_area_enabled) 5613 if (status_area_enabled)
6476 return gui.char_height; 5614 return gui.char_height;
6477 #endif
6478 return 0; 5615 return 0;
6479 } 5616 }
6480 5617
6481 /* 5618 /*
6482 * Get IM status. When IM is on, return TRUE. Else return FALSE. 5619 * Get IM status. When IM is on, return TRUE. Else return FALSE.
6485 * tear-off menu item). 5622 * tear-off menu item).
6486 */ 5623 */
6487 int 5624 int
6488 im_get_status() 5625 im_get_status()
6489 { 5626 {
6490 # ifdef FEAT_GUI_GTK
6491 if (xim_input_style & (int)GDK_IM_PREEDIT_CALLBACKS)
6492 return xim_can_preediting;
6493 # endif
6494 return xim_has_focus; 5627 return xim_has_focus;
6495 } 5628 }
6496 5629
6497 # endif /* !HAVE_GTK2 */ 5630 # endif /* !HAVE_GTK2 */
6498 5631