Mercurial > vim
annotate src/gui_beval.c @ 7842:cf744110897d v7.4.1218
commit https://github.com/vim/vim/commit/779a7759ad03e6a3fb616828793512644390655a
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Jan 30 23:26:34 2016 +0100
patch 7.4.1218
Problem: Missing change in configure. More changes for function style.
Solution: Avoid the typos.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sat, 30 Jan 2016 23:30:05 +0100 |
parents | 81794242a275 |
children | 3456e2ebebd4 |
rev | line source |
---|---|
7 | 1 /* vi:set ts=8 sts=4 sw=4: |
2 * | |
3 * VIM - Vi IMproved by Bram Moolenaar | |
4 * Visual Workshop integration by Gordon Prieur | |
5 * | |
6 * Do ":help uganda" in Vim to read copying and usage conditions. | |
7 * Do ":help credits" in Vim to see a list of people who contributed. | |
8 * See README.txt for an overview of the Vim source code. | |
9 */ | |
10 | |
11 #include "vim.h" | |
12 | |
13 #if defined(FEAT_BEVAL) || defined(PROTO) | |
14 | |
192 | 15 /* |
16 * Common code, invoked when the mouse is resting for a moment. | |
17 */ | |
18 void | |
7821
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
19 general_beval_cb(BalloonEval *beval, int state UNUSED) |
192 | 20 { |
2251
646d34788036
Fix a few compiler warnings. Fix crash with encrypted undo file.
Bram Moolenaar <bram@vim.org>
parents:
1887
diff
changeset
|
21 #ifdef FEAT_EVAL |
192 | 22 win_T *wp; |
23 int col; | |
634 | 24 int use_sandbox; |
192 | 25 linenr_T lnum; |
26 char_u *text; | |
27 static char_u *result = NULL; | |
28 long winnr = 0; | |
791 | 29 char_u *bexpr; |
30 buf_T *save_curbuf; | |
6297 | 31 size_t len; |
2251
646d34788036
Fix a few compiler warnings. Fix crash with encrypted undo file.
Bram Moolenaar <bram@vim.org>
parents:
1887
diff
changeset
|
32 # ifdef FEAT_WINDOWS |
192 | 33 win_T *cw; |
2251
646d34788036
Fix a few compiler warnings. Fix crash with encrypted undo file.
Bram Moolenaar <bram@vim.org>
parents:
1887
diff
changeset
|
34 # endif |
640 | 35 #endif |
865 | 36 static int recursive = FALSE; |
192 | 37 |
38 /* Don't do anything when 'ballooneval' is off, messages scrolled the | |
39 * windows up or we have no beval area. */ | |
40 if (!p_beval || balloonEval == NULL || msg_scrolled > 0) | |
41 return; | |
42 | |
865 | 43 /* Don't do this recursively. Happens when the expression evaluation |
44 * takes a long time and invokes something that checks for CTRL-C typed. */ | |
45 if (recursive) | |
46 return; | |
47 recursive = TRUE; | |
48 | |
192 | 49 #ifdef FEAT_EVAL |
791 | 50 if (get_beval_info(balloonEval, TRUE, &wp, &lnum, &text, &col) == OK) |
192 | 51 { |
791 | 52 bexpr = (*wp->w_buffer->b_p_bexpr == NUL) ? p_bexpr |
53 : wp->w_buffer->b_p_bexpr; | |
54 if (*bexpr != NUL) | |
55 { | |
640 | 56 # ifdef FEAT_WINDOWS |
791 | 57 /* Convert window pointer to number. */ |
58 for (cw = firstwin; cw != wp; cw = cw->w_next) | |
59 ++winnr; | |
640 | 60 # endif |
192 | 61 |
791 | 62 set_vim_var_nr(VV_BEVAL_BUFNR, (long)wp->w_buffer->b_fnum); |
63 set_vim_var_nr(VV_BEVAL_WINNR, winnr); | |
64 set_vim_var_nr(VV_BEVAL_LNUM, (long)lnum); | |
65 set_vim_var_nr(VV_BEVAL_COL, (long)(col + 1)); | |
66 set_vim_var_string(VV_BEVAL_TEXT, text, -1); | |
67 vim_free(text); | |
634 | 68 |
791 | 69 /* |
70 * Temporarily change the curbuf, so that we can determine whether | |
1228 | 71 * the buffer-local balloonexpr option was set insecurely. |
791 | 72 */ |
73 save_curbuf = curbuf; | |
74 curbuf = wp->w_buffer; | |
75 use_sandbox = was_set_insecurely((char_u *)"balloonexpr", | |
76 *curbuf->b_p_bexpr == NUL ? 0 : OPT_LOCAL); | |
77 curbuf = save_curbuf; | |
78 if (use_sandbox) | |
79 ++sandbox; | |
80 ++textlock; | |
634 | 81 |
791 | 82 vim_free(result); |
83 result = eval_to_string(bexpr, NULL, TRUE); | |
84 | |
6297 | 85 /* Remove one trailing newline, it is added when the result was a |
86 * list and it's hardly every useful. If the user really wants a | |
87 * trailing newline he can add two and one remains. */ | |
88 if (result != NULL) | |
89 { | |
90 len = STRLEN(result); | |
91 if (len > 0 && result[len - 1] == NL) | |
92 result[len - 1] = NUL; | |
93 } | |
94 | |
791 | 95 if (use_sandbox) |
96 --sandbox; | |
97 --textlock; | |
192 | 98 |
791 | 99 set_vim_var_string(VV_BEVAL_TEXT, NULL, -1); |
100 if (result != NULL && result[0] != NUL) | |
101 { | |
102 gui_mch_post_balloon(beval, result); | |
865 | 103 recursive = FALSE; |
791 | 104 return; |
105 } | |
192 | 106 } |
107 } | |
108 #endif | |
109 #ifdef FEAT_NETBEANS_INTG | |
110 if (bevalServers & BEVAL_NETBEANS) | |
111 netbeans_beval_cb(beval, state); | |
112 #endif | |
113 #ifdef FEAT_SUN_WORKSHOP | |
114 if (bevalServers & BEVAL_WORKSHOP) | |
115 workshop_beval_cb(beval, state); | |
116 #endif | |
865 | 117 |
118 recursive = FALSE; | |
192 | 119 } |
120 | |
121 /* on Win32 only get_beval_info() is required */ | |
7 | 122 #if !defined(FEAT_GUI_W32) || defined(PROTO) |
123 | |
124 #ifdef FEAT_GUI_GTK | |
125 # include <gdk/gdkkeysyms.h> | |
126 # include <gtk/gtk.h> | |
127 #else | |
128 # include <X11/keysym.h> | |
129 # ifdef FEAT_GUI_MOTIF | |
130 # include <Xm/PushB.h> | |
131 # include <Xm/Separator.h> | |
132 # include <Xm/List.h> | |
133 # include <Xm/Label.h> | |
134 # include <Xm/AtomMgr.h> | |
135 # include <Xm/Protocols.h> | |
136 # else | |
137 /* Assume Athena */ | |
138 # include <X11/Shell.h> | |
680 | 139 # ifdef FEAT_GUI_NEXTAW |
140 # include <X11/neXtaw/Label.h> | |
141 # else | |
142 # include <X11/Xaw/Label.h> | |
143 # endif | |
7 | 144 # endif |
145 #endif | |
146 | |
147 #include "gui_beval.h" | |
148 | |
149 #ifndef FEAT_GUI_GTK | |
150 extern Widget vimShell; | |
151 | |
152 /* | |
153 * Currently, we assume that there can be only one BalloonEval showing | |
154 * on-screen at any given moment. This variable will hold the currently | |
155 * showing BalloonEval or NULL if none is showing. | |
156 */ | |
157 static BalloonEval *current_beval = NULL; | |
158 #endif | |
159 | |
160 #ifdef FEAT_GUI_GTK | |
7801
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
6297
diff
changeset
|
161 static void addEventHandler(GtkWidget *, BalloonEval *); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
6297
diff
changeset
|
162 static void removeEventHandler(BalloonEval *); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
6297
diff
changeset
|
163 static gint target_event_cb(GtkWidget *, GdkEvent *, gpointer); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
6297
diff
changeset
|
164 static gint mainwin_event_cb(GtkWidget *, GdkEvent *, gpointer); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
6297
diff
changeset
|
165 static void pointer_event(BalloonEval *, int, int, unsigned); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
6297
diff
changeset
|
166 static void key_event(BalloonEval *, unsigned, int); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
6297
diff
changeset
|
167 static gint timeout_cb(gpointer); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
6297
diff
changeset
|
168 static gint balloon_expose_event_cb(GtkWidget *, GdkEventExpose *, gpointer); |
7 | 169 #else |
7801
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
6297
diff
changeset
|
170 static void addEventHandler(Widget, BalloonEval *); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
6297
diff
changeset
|
171 static void removeEventHandler(BalloonEval *); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
6297
diff
changeset
|
172 static void pointerEventEH(Widget, XtPointer, XEvent *, Boolean *); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
6297
diff
changeset
|
173 static void pointerEvent(BalloonEval *, XEvent *); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
6297
diff
changeset
|
174 static void timerRoutine(XtPointer, XtIntervalId *); |
7 | 175 #endif |
7801
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
6297
diff
changeset
|
176 static void cancelBalloon(BalloonEval *); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
6297
diff
changeset
|
177 static void requestBalloon(BalloonEval *); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
6297
diff
changeset
|
178 static void drawBalloon(BalloonEval *); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
6297
diff
changeset
|
179 static void undrawBalloon(BalloonEval *beval); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
6297
diff
changeset
|
180 static void createBalloonEvalWindow(BalloonEval *); |
7 | 181 |
182 | |
183 | |
184 /* | |
185 * Create a balloon-evaluation area for a Widget. | |
186 * There can be either a "mesg" for a fixed string or "mesgCB" to generate a | |
187 * message by calling this callback function. | |
188 * When "mesg" is not NULL it must remain valid for as long as the balloon is | |
189 * used. It is not freed here. | |
190 * Returns a pointer to the resulting object (NULL when out of memory). | |
191 */ | |
192 BalloonEval * | |
7821
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
193 gui_mch_create_beval_area( |
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
194 void *target, |
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
195 char_u *mesg, |
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
196 void (*mesgCB)(BalloonEval *, int), |
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
197 void *clientData) |
7 | 198 { |
199 #ifndef FEAT_GUI_GTK | |
200 char *display_name; /* get from gui.dpy */ | |
201 int screen_num; | |
202 char *p; | |
203 #endif | |
204 BalloonEval *beval; | |
205 | |
206 if (mesg != NULL && mesgCB != NULL) | |
207 { | |
208 EMSG(_("E232: Cannot create BalloonEval with both message and callback")); | |
209 return NULL; | |
210 } | |
211 | |
212 beval = (BalloonEval *)alloc(sizeof(BalloonEval)); | |
213 if (beval != NULL) | |
214 { | |
215 #ifdef FEAT_GUI_GTK | |
216 beval->target = GTK_WIDGET(target); | |
217 beval->balloonShell = NULL; | |
218 beval->timerID = 0; | |
219 #else | |
220 beval->target = (Widget)target; | |
221 beval->balloonShell = NULL; | |
222 beval->timerID = (XtIntervalId)NULL; | |
223 beval->appContext = XtWidgetToApplicationContext((Widget)target); | |
224 #endif | |
225 beval->showState = ShS_NEUTRAL; | |
226 beval->x = 0; | |
227 beval->y = 0; | |
228 beval->msg = mesg; | |
229 beval->msgCB = mesgCB; | |
230 beval->clientData = clientData; | |
231 | |
232 /* | |
233 * Set up event handler which will keep its eyes on the pointer, | |
234 * and when the pointer rests in a certain spot for a given time | |
235 * interval, show the beval. | |
236 */ | |
237 addEventHandler(beval->target, beval); | |
238 createBalloonEvalWindow(beval); | |
239 | |
240 #ifndef FEAT_GUI_GTK | |
241 /* | |
242 * Now create and save the screen width and height. Used in drawing. | |
243 */ | |
244 display_name = DisplayString(gui.dpy); | |
245 p = strrchr(display_name, '.'); | |
246 if (p != NULL) | |
247 screen_num = atoi(++p); | |
248 else | |
249 screen_num = 0; | |
250 beval->screen_width = DisplayWidth(gui.dpy, screen_num); | |
251 beval->screen_height = DisplayHeight(gui.dpy, screen_num); | |
252 #endif | |
253 } | |
254 | |
255 return beval; | |
256 } | |
257 | |
258 #if defined(FEAT_BEVAL_TIP) || defined(PROTO) | |
259 /* | |
1228 | 260 * Destroy a balloon-eval and free its associated memory. |
7 | 261 */ |
262 void | |
7821
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
263 gui_mch_destroy_beval_area(BalloonEval *beval) |
7 | 264 { |
265 cancelBalloon(beval); | |
266 removeEventHandler(beval); | |
267 /* Children will automatically be destroyed */ | |
268 # ifdef FEAT_GUI_GTK | |
269 gtk_widget_destroy(beval->balloonShell); | |
270 # else | |
271 XtDestroyWidget(beval->balloonShell); | |
272 # endif | |
273 vim_free(beval); | |
274 } | |
275 #endif | |
276 | |
277 void | |
7821
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
278 gui_mch_enable_beval_area(BalloonEval *beval) |
7 | 279 { |
280 if (beval != NULL) | |
281 addEventHandler(beval->target, beval); | |
282 } | |
283 | |
284 void | |
7821
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
285 gui_mch_disable_beval_area(BalloonEval *beval) |
7 | 286 { |
287 if (beval != NULL) | |
288 removeEventHandler(beval); | |
289 } | |
290 | |
291 #if defined(FEAT_BEVAL_TIP) || defined(PROTO) | |
292 /* | |
293 * This function returns the BalloonEval * associated with the currently | |
294 * displayed tooltip. Returns NULL if there is no tooltip currently showing. | |
295 * | |
296 * Assumption: Only one tooltip can be shown at a time. | |
297 */ | |
298 BalloonEval * | |
7821
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
299 gui_mch_currently_showing_beval(void) |
7 | 300 { |
301 return current_beval; | |
302 } | |
303 #endif | |
304 #endif /* !FEAT_GUI_W32 */ | |
305 | |
192 | 306 #if defined(FEAT_SUN_WORKSHOP) || defined(FEAT_NETBEANS_INTG) \ |
307 || defined(FEAT_EVAL) || defined(PROTO) | |
7 | 308 /* |
309 * Get the text and position to be evaluated for "beval". | |
192 | 310 * If "getword" is true the returned text is not the whole line but the |
311 * relevant word in allocated memory. | |
7 | 312 * Returns OK or FAIL. |
313 */ | |
314 int | |
7821
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
315 get_beval_info( |
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
316 BalloonEval *beval, |
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
317 int getword, |
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
318 win_T **winp, |
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
319 linenr_T *lnump, |
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
320 char_u **textp, |
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
321 int *colp) |
7 | 322 { |
323 win_T *wp; | |
324 int row, col; | |
325 char_u *lbuf; | |
326 linenr_T lnum; | |
327 | |
192 | 328 *textp = NULL; |
7 | 329 row = Y_2_ROW(beval->y); |
330 col = X_2_COL(beval->x); | |
640 | 331 #ifdef FEAT_WINDOWS |
7 | 332 wp = mouse_find_win(&row, &col); |
640 | 333 #else |
334 wp = firstwin; | |
335 #endif | |
7 | 336 if (wp != NULL && row < wp->w_height && col < W_WIDTH(wp)) |
337 { | |
338 /* Found a window and the cursor is in the text. Now find the line | |
339 * number. */ | |
340 if (!mouse_comp_pos(wp, &row, &col, &lnum)) | |
341 { | |
342 /* Not past end of the file. */ | |
343 lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE); | |
344 if (col <= win_linetabsize(wp, lbuf, (colnr_T)MAXCOL)) | |
345 { | |
346 /* Not past end of line. */ | |
192 | 347 if (getword) |
7 | 348 { |
349 /* For Netbeans we get the relevant part of the line | |
350 * instead of the whole line. */ | |
351 int len; | |
352 pos_T *spos = NULL, *epos = NULL; | |
353 | |
354 if (VIsual_active) | |
355 { | |
356 if (lt(VIsual, curwin->w_cursor)) | |
357 { | |
358 spos = &VIsual; | |
359 epos = &curwin->w_cursor; | |
360 } | |
361 else | |
362 { | |
363 spos = &curwin->w_cursor; | |
364 epos = &VIsual; | |
365 } | |
366 } | |
367 | |
3877 | 368 col = vcol2col(wp, lnum, col); |
7 | 369 |
370 if (VIsual_active | |
371 && wp->w_buffer == curwin->w_buffer | |
372 && (lnum == spos->lnum | |
373 ? col >= (int)spos->col | |
374 : lnum > spos->lnum) | |
375 && (lnum == epos->lnum | |
376 ? col <= (int)epos->col | |
377 : lnum < epos->lnum)) | |
378 { | |
379 /* Visual mode and pointing to the line with the | |
380 * Visual selection: return selected text, with a | |
381 * maximum of one line. */ | |
382 if (spos->lnum != epos->lnum || spos->col == epos->col) | |
383 return FAIL; | |
384 | |
385 lbuf = ml_get_buf(curwin->w_buffer, VIsual.lnum, FALSE); | |
3877 | 386 len = epos->col - spos->col; |
387 if (*p_sel != 'e') | |
388 len += MB_PTR2LEN(lbuf + epos->col); | |
389 lbuf = vim_strnsave(lbuf + spos->col, len); | |
7 | 390 lnum = spos->lnum; |
391 col = spos->col; | |
392 } | |
393 else | |
394 { | |
395 /* Find the word under the cursor. */ | |
396 ++emsg_off; | |
397 len = find_ident_at_pos(wp, lnum, (colnr_T)col, &lbuf, | |
398 FIND_IDENT + FIND_STRING + FIND_EVAL); | |
399 --emsg_off; | |
400 if (len == 0) | |
401 return FAIL; | |
402 lbuf = vim_strnsave(lbuf, len); | |
403 } | |
404 } | |
192 | 405 |
406 *winp = wp; | |
407 *lnump = lnum; | |
408 *textp = lbuf; | |
409 *colp = col; | |
7 | 410 beval->ts = wp->w_buffer->b_p_ts; |
411 return OK; | |
412 } | |
413 } | |
414 } | |
415 | |
416 return FAIL; | |
417 } | |
418 | |
419 # if !defined(FEAT_GUI_W32) || defined(PROTO) | |
420 | |
421 /* | |
422 * Show a balloon with "mesg". | |
423 */ | |
424 void | |
7821
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
425 gui_mch_post_balloon(BalloonEval *beval, char_u *mesg) |
7 | 426 { |
427 beval->msg = mesg; | |
428 if (mesg != NULL) | |
429 drawBalloon(beval); | |
430 else | |
431 undrawBalloon(beval); | |
432 } | |
433 # endif /* FEAT_GUI_W32 */ | |
434 #endif /* FEAT_SUN_WORKSHOP || FEAT_NETBEANS_INTG || PROTO */ | |
435 | |
436 #if !defined(FEAT_GUI_W32) || defined(PROTO) | |
437 #if defined(FEAT_BEVAL_TIP) || defined(PROTO) | |
438 /* | |
439 * Hide the given balloon. | |
440 */ | |
441 void | |
7821
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
442 gui_mch_unpost_balloon(BalloonEval *beval) |
7 | 443 { |
444 undrawBalloon(beval); | |
445 } | |
446 #endif | |
447 | |
448 #ifdef FEAT_GUI_GTK | |
449 /* | |
450 * We can unconditionally use ANSI-style prototypes here since | |
451 * GTK+ requires an ANSI C compiler anyway. | |
452 */ | |
453 static void | |
454 addEventHandler(GtkWidget *target, BalloonEval *beval) | |
455 { | |
456 /* | |
457 * Connect to the generic "event" signal instead of the individual | |
458 * signals for each event type, because the former is emitted earlier. | |
459 * This allows us to catch events independently of the signal handlers | |
460 * in gui_gtk_x11.c. | |
461 */ | |
462 /* Should use GTK_OBJECT() here, but that causes a lint warning... */ | |
463 gtk_signal_connect((GtkObject*)(target), "event", | |
464 GTK_SIGNAL_FUNC(target_event_cb), | |
465 beval); | |
466 /* | |
467 * Nasty: Key press events go to the main window thus the drawing area | |
468 * will never see them. This means we have to connect to the main window | |
469 * as well in order to catch those events. | |
470 */ | |
471 if (gtk_socket_id == 0 && gui.mainwin != NULL | |
472 && gtk_widget_is_ancestor(target, gui.mainwin)) | |
473 { | |
474 gtk_signal_connect((GtkObject*)(gui.mainwin), "event", | |
475 GTK_SIGNAL_FUNC(mainwin_event_cb), | |
476 beval); | |
477 } | |
478 } | |
479 | |
480 static void | |
481 removeEventHandler(BalloonEval *beval) | |
482 { | |
137 | 483 /* LINTED: avoid warning: dubious operation on enum */ |
7 | 484 gtk_signal_disconnect_by_func((GtkObject*)(beval->target), |
485 GTK_SIGNAL_FUNC(target_event_cb), | |
486 beval); | |
487 | |
488 if (gtk_socket_id == 0 && gui.mainwin != NULL | |
489 && gtk_widget_is_ancestor(beval->target, gui.mainwin)) | |
490 { | |
137 | 491 /* LINTED: avoid warning: dubious operation on enum */ |
7 | 492 gtk_signal_disconnect_by_func((GtkObject*)(gui.mainwin), |
493 GTK_SIGNAL_FUNC(mainwin_event_cb), | |
494 beval); | |
495 } | |
496 } | |
497 | |
498 static gint | |
499 target_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data) | |
500 { | |
501 BalloonEval *beval = (BalloonEval *)data; | |
502 | |
503 switch (event->type) | |
504 { | |
505 case GDK_ENTER_NOTIFY: | |
506 pointer_event(beval, (int)event->crossing.x, | |
507 (int)event->crossing.y, | |
508 event->crossing.state); | |
509 break; | |
510 case GDK_MOTION_NOTIFY: | |
511 if (event->motion.is_hint) | |
512 { | |
513 int x; | |
514 int y; | |
515 GdkModifierType state; | |
516 /* | |
517 * GDK_POINTER_MOTION_HINT_MASK is set, thus we cannot obtain | |
518 * the coordinates from the GdkEventMotion struct directly. | |
519 */ | |
520 gdk_window_get_pointer(widget->window, &x, &y, &state); | |
521 pointer_event(beval, x, y, (unsigned int)state); | |
522 } | |
523 else | |
524 { | |
525 pointer_event(beval, (int)event->motion.x, | |
526 (int)event->motion.y, | |
527 event->motion.state); | |
528 } | |
529 break; | |
530 case GDK_LEAVE_NOTIFY: | |
531 /* | |
532 * Ignore LeaveNotify events that are not "normal". | |
533 * Apparently we also get it when somebody else grabs focus. | |
534 */ | |
535 if (event->crossing.mode == GDK_CROSSING_NORMAL) | |
536 cancelBalloon(beval); | |
537 break; | |
538 case GDK_BUTTON_PRESS: | |
539 case GDK_SCROLL: | |
540 cancelBalloon(beval); | |
541 break; | |
542 case GDK_KEY_PRESS: | |
543 key_event(beval, event->key.keyval, TRUE); | |
544 break; | |
545 case GDK_KEY_RELEASE: | |
546 key_event(beval, event->key.keyval, FALSE); | |
547 break; | |
548 default: | |
549 break; | |
550 } | |
551 | |
552 return FALSE; /* continue emission */ | |
553 } | |
554 | |
555 static gint | |
1884 | 556 mainwin_event_cb(GtkWidget *widget UNUSED, GdkEvent *event, gpointer data) |
7 | 557 { |
558 BalloonEval *beval = (BalloonEval *)data; | |
559 | |
560 switch (event->type) | |
561 { | |
562 case GDK_KEY_PRESS: | |
563 key_event(beval, event->key.keyval, TRUE); | |
564 break; | |
565 case GDK_KEY_RELEASE: | |
566 key_event(beval, event->key.keyval, FALSE); | |
567 break; | |
568 default: | |
569 break; | |
570 } | |
571 | |
572 return FALSE; /* continue emission */ | |
573 } | |
574 | |
575 static void | |
576 pointer_event(BalloonEval *beval, int x, int y, unsigned state) | |
577 { | |
578 int distance; | |
579 | |
580 distance = ABS(x - beval->x) + ABS(y - beval->y); | |
581 | |
582 if (distance > 4) | |
583 { | |
584 /* | |
585 * Moved out of the balloon location: cancel it. | |
586 * Remember button state | |
587 */ | |
588 beval->state = state; | |
589 cancelBalloon(beval); | |
590 | |
591 /* Mouse buttons are pressed - no balloon now */ | |
592 if (!(state & ((int)GDK_BUTTON1_MASK | (int)GDK_BUTTON2_MASK | |
593 | (int)GDK_BUTTON3_MASK))) | |
594 { | |
595 beval->x = x; | |
596 beval->y = y; | |
597 | |
598 if (state & (int)GDK_MOD1_MASK) | |
599 { | |
600 /* | |
601 * Alt is pressed -- enter super-evaluate-mode, | |
602 * where there is no time delay | |
603 */ | |
604 if (beval->msgCB != NULL) | |
605 { | |
606 beval->showState = ShS_PENDING; | |
607 (*beval->msgCB)(beval, state); | |
608 } | |
609 } | |
610 else | |
611 { | |
612 beval->timerID = gtk_timeout_add((guint32)p_bdlay, | |
613 &timeout_cb, beval); | |
614 } | |
615 } | |
616 } | |
617 } | |
618 | |
619 static void | |
620 key_event(BalloonEval *beval, unsigned keyval, int is_keypress) | |
621 { | |
622 if (beval->showState == ShS_SHOWING && beval->msgCB != NULL) | |
623 { | |
624 switch (keyval) | |
625 { | |
626 case GDK_Shift_L: | |
627 case GDK_Shift_R: | |
628 beval->showState = ShS_UPDATE_PENDING; | |
629 (*beval->msgCB)(beval, (is_keypress) | |
630 ? (int)GDK_SHIFT_MASK : 0); | |
631 break; | |
632 case GDK_Control_L: | |
633 case GDK_Control_R: | |
634 beval->showState = ShS_UPDATE_PENDING; | |
635 (*beval->msgCB)(beval, (is_keypress) | |
636 ? (int)GDK_CONTROL_MASK : 0); | |
637 break; | |
638 default: | |
667 | 639 /* Don't do this for key release, we apparently get these with |
640 * focus changes in some GTK version. */ | |
641 if (is_keypress) | |
642 cancelBalloon(beval); | |
7 | 643 break; |
644 } | |
645 } | |
646 else | |
647 cancelBalloon(beval); | |
648 } | |
649 | |
650 static gint | |
651 timeout_cb(gpointer data) | |
652 { | |
653 BalloonEval *beval = (BalloonEval *)data; | |
654 | |
655 beval->timerID = 0; | |
656 /* | |
657 * If the timer event happens then the mouse has stopped long enough for | |
658 * a request to be started. The request will only send to the debugger if | |
659 * there the mouse is pointing at real data. | |
660 */ | |
661 requestBalloon(beval); | |
662 | |
663 return FALSE; /* don't call me again */ | |
664 } | |
665 | |
666 static gint | |
1884 | 667 balloon_expose_event_cb(GtkWidget *widget, |
668 GdkEventExpose *event, | |
669 gpointer data UNUSED) | |
7 | 670 { |
671 gtk_paint_flat_box(widget->style, widget->window, | |
672 GTK_STATE_NORMAL, GTK_SHADOW_OUT, | |
673 &event->area, widget, "tooltip", | |
674 0, 0, -1, -1); | |
675 | |
676 return FALSE; /* continue emission */ | |
677 } | |
678 | |
679 #else /* !FEAT_GUI_GTK */ | |
680 | |
681 static void | |
7821
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
682 addEventHandler(Widget target, BalloonEval *beval) |
7 | 683 { |
684 XtAddEventHandler(target, | |
685 PointerMotionMask | EnterWindowMask | | |
686 LeaveWindowMask | ButtonPressMask | KeyPressMask | | |
687 KeyReleaseMask, | |
688 False, | |
689 pointerEventEH, (XtPointer)beval); | |
690 } | |
691 | |
692 static void | |
7821
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
693 removeEventHandler(BalloonEval *beval) |
7 | 694 { |
695 XtRemoveEventHandler(beval->target, | |
696 PointerMotionMask | EnterWindowMask | | |
697 LeaveWindowMask | ButtonPressMask | KeyPressMask | | |
698 KeyReleaseMask, | |
699 False, | |
700 pointerEventEH, (XtPointer)beval); | |
701 } | |
702 | |
703 | |
704 /* | |
705 * The X event handler. All it does is call the real event handler. | |
706 */ | |
707 static void | |
7821
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
708 pointerEventEH( |
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
709 Widget w UNUSED, |
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
710 XtPointer client_data, |
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
711 XEvent *event, |
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
712 Boolean *unused UNUSED) |
7 | 713 { |
714 BalloonEval *beval = (BalloonEval *)client_data; | |
715 pointerEvent(beval, event); | |
716 } | |
717 | |
718 | |
719 /* | |
720 * The real event handler. Called by pointerEventEH() whenever an event we are | |
1228 | 721 * interested in occurs. |
7 | 722 */ |
723 | |
724 static void | |
7821
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
725 pointerEvent(BalloonEval *beval, XEvent *event) |
7 | 726 { |
4352 | 727 Position distance; /* a measure of how much the pointer moved */ |
7 | 728 Position delta; /* used to compute distance */ |
729 | |
730 switch (event->type) | |
731 { | |
732 case EnterNotify: | |
733 case MotionNotify: | |
734 delta = event->xmotion.x - beval->x; | |
735 if (delta < 0) | |
736 delta = -delta; | |
737 distance = delta; | |
738 delta = event->xmotion.y - beval->y; | |
739 if (delta < 0) | |
740 delta = -delta; | |
741 distance += delta; | |
742 if (distance > 4) | |
743 { | |
744 /* | |
745 * Moved out of the balloon location: cancel it. | |
746 * Remember button state | |
747 */ | |
748 beval->state = event->xmotion.state; | |
749 if (beval->state & (Button1Mask|Button2Mask|Button3Mask)) | |
750 { | |
751 /* Mouse buttons are pressed - no balloon now */ | |
752 cancelBalloon(beval); | |
753 } | |
754 else if (beval->state & (Mod1Mask|Mod2Mask|Mod3Mask)) | |
755 { | |
756 /* | |
757 * Alt is pressed -- enter super-evaluate-mode, | |
758 * where there is no time delay | |
759 */ | |
760 beval->x = event->xmotion.x; | |
761 beval->y = event->xmotion.y; | |
762 beval->x_root = event->xmotion.x_root; | |
763 beval->y_root = event->xmotion.y_root; | |
764 cancelBalloon(beval); | |
765 if (beval->msgCB != NULL) | |
766 { | |
767 beval->showState = ShS_PENDING; | |
768 (*beval->msgCB)(beval, beval->state); | |
769 } | |
770 } | |
771 else | |
772 { | |
773 beval->x = event->xmotion.x; | |
774 beval->y = event->xmotion.y; | |
775 beval->x_root = event->xmotion.x_root; | |
776 beval->y_root = event->xmotion.y_root; | |
777 cancelBalloon(beval); | |
778 beval->timerID = XtAppAddTimeOut( beval->appContext, | |
779 (long_u)p_bdlay, timerRoutine, beval); | |
780 } | |
781 } | |
782 break; | |
783 | |
784 /* | |
785 * Motif and Athena version: Keystrokes will be caught by the | |
786 * "textArea" widget, and handled in gui_x11_key_hit_cb(). | |
787 */ | |
788 case KeyPress: | |
789 if (beval->showState == ShS_SHOWING && beval->msgCB != NULL) | |
790 { | |
791 Modifiers modifier; | |
792 KeySym keysym; | |
793 | |
794 XtTranslateKeycode(gui.dpy, | |
795 event->xkey.keycode, event->xkey.state, | |
796 &modifier, &keysym); | |
797 if (keysym == XK_Shift_L || keysym == XK_Shift_R) | |
798 { | |
799 beval->showState = ShS_UPDATE_PENDING; | |
800 (*beval->msgCB)(beval, ShiftMask); | |
801 } | |
802 else if (keysym == XK_Control_L || keysym == XK_Control_R) | |
803 { | |
804 beval->showState = ShS_UPDATE_PENDING; | |
805 (*beval->msgCB)(beval, ControlMask); | |
806 } | |
807 else | |
808 cancelBalloon(beval); | |
809 } | |
810 else | |
811 cancelBalloon(beval); | |
812 break; | |
813 | |
814 case KeyRelease: | |
815 if (beval->showState == ShS_SHOWING && beval->msgCB != NULL) | |
816 { | |
817 Modifiers modifier; | |
818 KeySym keysym; | |
819 | |
820 XtTranslateKeycode(gui.dpy, event->xkey.keycode, | |
821 event->xkey.state, &modifier, &keysym); | |
822 if ((keysym == XK_Shift_L) || (keysym == XK_Shift_R)) { | |
823 beval->showState = ShS_UPDATE_PENDING; | |
824 (*beval->msgCB)(beval, 0); | |
825 } | |
826 else if ((keysym == XK_Control_L) || (keysym == XK_Control_R)) | |
827 { | |
828 beval->showState = ShS_UPDATE_PENDING; | |
829 (*beval->msgCB)(beval, 0); | |
830 } | |
831 else | |
832 cancelBalloon(beval); | |
833 } | |
834 else | |
835 cancelBalloon(beval); | |
836 break; | |
837 | |
838 case LeaveNotify: | |
839 /* Ignore LeaveNotify events that are not "normal". | |
840 * Apparently we also get it when somebody else grabs focus. | |
841 * Happens for me every two seconds (some clipboard tool?) */ | |
842 if (event->xcrossing.mode == NotifyNormal) | |
843 cancelBalloon(beval); | |
844 break; | |
845 | |
846 case ButtonPress: | |
847 cancelBalloon(beval); | |
848 break; | |
849 | |
850 default: | |
851 break; | |
852 } | |
853 } | |
854 | |
855 static void | |
7821
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
856 timerRoutine(XtPointer dx, XtIntervalId *id UNUSED) |
7 | 857 { |
858 BalloonEval *beval = (BalloonEval *)dx; | |
859 | |
860 beval->timerID = (XtIntervalId)NULL; | |
861 | |
862 /* | |
863 * If the timer event happens then the mouse has stopped long enough for | |
864 * a request to be started. The request will only send to the debugger if | |
865 * there the mouse is pointing at real data. | |
866 */ | |
867 requestBalloon(beval); | |
868 } | |
869 | |
870 #endif /* !FEAT_GUI_GTK */ | |
871 | |
872 static void | |
7821
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
873 requestBalloon(BalloonEval *beval) |
7 | 874 { |
875 if (beval->showState != ShS_PENDING) | |
876 { | |
877 /* Determine the beval to display */ | |
878 if (beval->msgCB != NULL) | |
879 { | |
880 beval->showState = ShS_PENDING; | |
881 (*beval->msgCB)(beval, beval->state); | |
882 } | |
883 else if (beval->msg != NULL) | |
884 drawBalloon(beval); | |
885 } | |
886 } | |
887 | |
888 #ifdef FEAT_GUI_GTK | |
889 /* | |
890 * Convert the string to UTF-8 if 'encoding' is not "utf-8". | |
891 * Replace any non-printable characters and invalid bytes sequences with | |
892 * "^X" or "<xx>" escapes, and apply SpecialKey highlighting to them. | |
893 * TAB and NL are passed through unscathed. | |
894 */ | |
2275
e4d849f4df03
Remove the old and not well supported GTK 1 code. (James Vega)
Bram Moolenaar <bram@vim.org>
parents:
2251
diff
changeset
|
895 # define IS_NONPRINTABLE(c) (((c) < 0x20 && (c) != TAB && (c) != NL) \ |
7 | 896 || (c) == DEL) |
897 static void | |
944 | 898 set_printable_label_text(GtkLabel *label, char_u *text) |
7 | 899 { |
900 char_u *convbuf = NULL; | |
901 char_u *buf; | |
902 char_u *p; | |
903 char_u *pdest; | |
904 unsigned int len; | |
905 int charlen; | |
906 int uc; | |
907 PangoAttrList *attr_list; | |
908 | |
909 /* Convert to UTF-8 if it isn't already */ | |
910 if (output_conv.vc_type != CONV_NONE) | |
911 { | |
944 | 912 convbuf = string_convert(&output_conv, text, NULL); |
7 | 913 if (convbuf != NULL) |
944 | 914 text = convbuf; |
7 | 915 } |
916 | |
917 /* First let's see how much we need to allocate */ | |
918 len = 0; | |
944 | 919 for (p = text; *p != NUL; p += charlen) |
7 | 920 { |
921 if ((*p & 0x80) == 0) /* be quick for ASCII */ | |
922 { | |
923 charlen = 1; | |
924 len += IS_NONPRINTABLE(*p) ? 2 : 1; /* nonprintable: ^X */ | |
925 } | |
926 else | |
927 { | |
474 | 928 charlen = utf_ptr2len(p); |
7 | 929 uc = utf_ptr2char(p); |
930 | |
931 if (charlen != utf_char2len(uc)) | |
932 charlen = 1; /* reject overlong sequences */ | |
933 | |
934 if (charlen == 1 || uc < 0xa0) /* illegal byte or */ | |
935 len += 4; /* control char: <xx> */ | |
936 else if (!utf_printable(uc)) | |
937 /* Note: we assume here that utf_printable() doesn't | |
938 * care about characters outside the BMP. */ | |
939 len += 6; /* nonprintable: <xxxx> */ | |
940 else | |
941 len += charlen; | |
942 } | |
943 } | |
944 | |
945 attr_list = pango_attr_list_new(); | |
946 buf = alloc(len + 1); | |
947 | |
948 /* Now go for the real work */ | |
949 if (buf != NULL) | |
950 { | |
951 attrentry_T *aep; | |
952 PangoAttribute *attr; | |
953 guicolor_T pixel; | |
954 GdkColor color = { 0, 0, 0, 0 }; | |
955 | |
956 /* Look up the RGB values of the SpecialKey foreground color. */ | |
957 aep = syn_gui_attr2entry(hl_attr(HLF_8)); | |
958 pixel = (aep != NULL) ? aep->ae_u.gui.fg_color : INVALCOLOR; | |
959 if (pixel != INVALCOLOR) | |
960 gdk_colormap_query_color(gtk_widget_get_colormap(gui.drawarea), | |
961 (unsigned long)pixel, &color); | |
962 | |
963 pdest = buf; | |
944 | 964 p = text; |
7 | 965 while (*p != NUL) |
966 { | |
967 /* Be quick for ASCII */ | |
968 if ((*p & 0x80) == 0 && !IS_NONPRINTABLE(*p)) | |
969 { | |
970 *pdest++ = *p++; | |
971 } | |
972 else | |
973 { | |
474 | 974 charlen = utf_ptr2len(p); |
7 | 975 uc = utf_ptr2char(p); |
976 | |
977 if (charlen != utf_char2len(uc)) | |
978 charlen = 1; /* reject overlong sequences */ | |
979 | |
980 if (charlen == 1 || uc < 0xa0 || !utf_printable(uc)) | |
981 { | |
982 int outlen; | |
983 | |
984 /* Careful: we can't just use transchar_byte() here, | |
985 * since 'encoding' is not necessarily set to "utf-8". */ | |
986 if (*p & 0x80 && charlen == 1) | |
987 { | |
988 transchar_hex(pdest, *p); /* <xx> */ | |
989 outlen = 4; | |
990 } | |
991 else if (uc >= 0x80) | |
992 { | |
993 /* Note: we assume here that utf_printable() doesn't | |
994 * care about characters outside the BMP. */ | |
995 transchar_hex(pdest, uc); /* <xx> or <xxxx> */ | |
996 outlen = (uc < 0x100) ? 4 : 6; | |
997 } | |
998 else | |
999 { | |
1000 transchar_nonprint(pdest, *p); /* ^X */ | |
1001 outlen = 2; | |
1002 } | |
1003 if (pixel != INVALCOLOR) | |
1004 { | |
1005 attr = pango_attr_foreground_new( | |
1006 color.red, color.green, color.blue); | |
1007 attr->start_index = pdest - buf; | |
1008 attr->end_index = pdest - buf + outlen; | |
1009 pango_attr_list_insert(attr_list, attr); | |
1010 } | |
1011 pdest += outlen; | |
1012 p += charlen; | |
1013 } | |
1014 else | |
1015 { | |
1016 do | |
1017 *pdest++ = *p++; | |
1018 while (--charlen != 0); | |
1019 } | |
1020 } | |
1021 } | |
1022 *pdest = NUL; | |
1023 } | |
1024 | |
1025 vim_free(convbuf); | |
1026 | |
1027 gtk_label_set_text(label, (const char *)buf); | |
1028 vim_free(buf); | |
1029 | |
1030 gtk_label_set_attributes(label, attr_list); | |
1031 pango_attr_list_unref(attr_list); | |
1032 } | |
2275
e4d849f4df03
Remove the old and not well supported GTK 1 code. (James Vega)
Bram Moolenaar <bram@vim.org>
parents:
2251
diff
changeset
|
1033 # undef IS_NONPRINTABLE |
7 | 1034 |
1035 /* | |
1036 * Draw a balloon. | |
1037 */ | |
1038 static void | |
1039 drawBalloon(BalloonEval *beval) | |
1040 { | |
1041 if (beval->msg != NULL) | |
1042 { | |
1043 GtkRequisition requisition; | |
1044 int screen_w; | |
1045 int screen_h; | |
1046 int x; | |
1047 int y; | |
1048 int x_offset = EVAL_OFFSET_X; | |
1049 int y_offset = EVAL_OFFSET_Y; | |
1050 PangoLayout *layout; | |
1051 # ifdef HAVE_GTK_MULTIHEAD | |
1052 GdkScreen *screen; | |
1053 | |
1054 screen = gtk_widget_get_screen(beval->target); | |
1055 gtk_window_set_screen(GTK_WINDOW(beval->balloonShell), screen); | |
1056 screen_w = gdk_screen_get_width(screen); | |
1057 screen_h = gdk_screen_get_height(screen); | |
1058 # else | |
1059 screen_w = gdk_screen_width(); | |
1060 screen_h = gdk_screen_height(); | |
1061 # endif | |
1062 gtk_widget_ensure_style(beval->balloonShell); | |
1063 gtk_widget_ensure_style(beval->balloonLabel); | |
1064 | |
1065 set_printable_label_text(GTK_LABEL(beval->balloonLabel), beval->msg); | |
1066 /* | |
1067 * Dirty trick: Enable wrapping mode on the label's layout behind its | |
1068 * back. This way GtkLabel won't try to constrain the wrap width to a | |
1069 * builtin maximum value of about 65 Latin characters. | |
1070 */ | |
1071 layout = gtk_label_get_layout(GTK_LABEL(beval->balloonLabel)); | |
2275
e4d849f4df03
Remove the old and not well supported GTK 1 code. (James Vega)
Bram Moolenaar <bram@vim.org>
parents:
2251
diff
changeset
|
1072 # ifdef PANGO_WRAP_WORD_CHAR |
7 | 1073 pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); |
2275
e4d849f4df03
Remove the old and not well supported GTK 1 code. (James Vega)
Bram Moolenaar <bram@vim.org>
parents:
2251
diff
changeset
|
1074 # else |
7 | 1075 pango_layout_set_wrap(layout, PANGO_WRAP_WORD); |
2275
e4d849f4df03
Remove the old and not well supported GTK 1 code. (James Vega)
Bram Moolenaar <bram@vim.org>
parents:
2251
diff
changeset
|
1076 # endif |
7 | 1077 pango_layout_set_width(layout, |
1078 /* try to come up with some reasonable width */ | |
1079 PANGO_SCALE * CLAMP(gui.num_cols * gui.char_width, | |
1080 screen_w / 2, | |
1081 MAX(20, screen_w - 20))); | |
1082 | |
1083 /* Calculate the balloon's width and height. */ | |
1084 gtk_widget_size_request(beval->balloonShell, &requisition); | |
1085 | |
1086 /* Compute position of the balloon area */ | |
1087 gdk_window_get_origin(beval->target->window, &x, &y); | |
1088 x += beval->x; | |
1089 y += beval->y; | |
1090 | |
1091 /* Get out of the way of the mouse pointer */ | |
1092 if (x + x_offset + requisition.width > screen_w) | |
1093 y_offset += 15; | |
1094 if (y + y_offset + requisition.height > screen_h) | |
1095 y_offset = -requisition.height - EVAL_OFFSET_Y; | |
1096 | |
1097 /* Sanitize values */ | |
1098 x = CLAMP(x + x_offset, 0, MAX(0, screen_w - requisition.width)); | |
1099 y = CLAMP(y + y_offset, 0, MAX(0, screen_h - requisition.height)); | |
1100 | |
1101 /* Show the balloon */ | |
1102 gtk_widget_set_uposition(beval->balloonShell, x, y); | |
1103 gtk_widget_show(beval->balloonShell); | |
1104 | |
1105 beval->showState = ShS_SHOWING; | |
1106 } | |
1107 } | |
1108 | |
1109 /* | |
1110 * Undraw a balloon. | |
1111 */ | |
1112 static void | |
1113 undrawBalloon(BalloonEval *beval) | |
1114 { | |
1115 if (beval->balloonShell != NULL) | |
1116 gtk_widget_hide(beval->balloonShell); | |
1117 beval->showState = ShS_NEUTRAL; | |
1118 } | |
1119 | |
1120 static void | |
1121 cancelBalloon(BalloonEval *beval) | |
1122 { | |
1123 if (beval->showState == ShS_SHOWING | |
1124 || beval->showState == ShS_UPDATE_PENDING) | |
1125 undrawBalloon(beval); | |
1126 | |
1127 if (beval->timerID != 0) | |
1128 { | |
1129 gtk_timeout_remove(beval->timerID); | |
1130 beval->timerID = 0; | |
1131 } | |
1132 beval->showState = ShS_NEUTRAL; | |
1133 } | |
1134 | |
1135 static void | |
1136 createBalloonEvalWindow(BalloonEval *beval) | |
1137 { | |
1138 beval->balloonShell = gtk_window_new(GTK_WINDOW_POPUP); | |
1139 | |
1140 gtk_widget_set_app_paintable(beval->balloonShell, TRUE); | |
1141 gtk_window_set_policy(GTK_WINDOW(beval->balloonShell), FALSE, FALSE, TRUE); | |
1142 gtk_widget_set_name(beval->balloonShell, "gtk-tooltips"); | |
1143 gtk_container_border_width(GTK_CONTAINER(beval->balloonShell), 4); | |
1144 | |
1145 gtk_signal_connect((GtkObject*)(beval->balloonShell), "expose_event", | |
1146 GTK_SIGNAL_FUNC(balloon_expose_event_cb), NULL); | |
1147 beval->balloonLabel = gtk_label_new(NULL); | |
1148 | |
1149 gtk_label_set_line_wrap(GTK_LABEL(beval->balloonLabel), FALSE); | |
1150 gtk_label_set_justify(GTK_LABEL(beval->balloonLabel), GTK_JUSTIFY_LEFT); | |
1151 gtk_misc_set_alignment(GTK_MISC(beval->balloonLabel), 0.5f, 0.5f); | |
1152 gtk_widget_set_name(beval->balloonLabel, "vim-balloon-label"); | |
1153 gtk_widget_show(beval->balloonLabel); | |
1154 | |
1155 gtk_container_add(GTK_CONTAINER(beval->balloonShell), beval->balloonLabel); | |
1156 } | |
1157 | |
1158 #else /* !FEAT_GUI_GTK */ | |
1159 | |
1160 /* | |
1161 * Draw a balloon. | |
1162 */ | |
1163 static void | |
7821
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
1164 drawBalloon(BalloonEval *beval) |
7 | 1165 { |
1166 Dimension w; | |
1167 Dimension h; | |
1168 Position tx; | |
1169 Position ty; | |
1170 | |
1171 if (beval->msg != NULL) | |
1172 { | |
1173 /* Show the Balloon */ | |
1174 | |
1175 /* Calculate the label's width and height */ | |
1176 #ifdef FEAT_GUI_MOTIF | |
1177 XmString s; | |
1178 | |
1179 /* For the callback function we parse NL characters to create a | |
1180 * multi-line label. This doesn't work for all languages, but | |
1181 * XmStringCreateLocalized() doesn't do multi-line labels... */ | |
1182 if (beval->msgCB != NULL) | |
1183 s = XmStringCreateLtoR((char *)beval->msg, XmFONTLIST_DEFAULT_TAG); | |
1184 else | |
1185 s = XmStringCreateLocalized((char *)beval->msg); | |
1186 { | |
1187 XmFontList fl; | |
1188 | |
1189 fl = gui_motif_fontset2fontlist(&gui.tooltip_fontset); | |
6003 | 1190 if (fl == NULL) |
7 | 1191 { |
6003 | 1192 XmStringFree(s); |
1193 return; | |
7 | 1194 } |
6003 | 1195 XmStringExtent(fl, s, &w, &h); |
1196 XmFontListFree(fl); | |
7 | 1197 } |
1198 w += gui.border_offset << 1; | |
1199 h += gui.border_offset << 1; | |
1200 XtVaSetValues(beval->balloonLabel, XmNlabelString, s, NULL); | |
1201 XmStringFree(s); | |
1202 #else /* Athena */ | |
1203 /* Assume XtNinternational == True */ | |
1204 XFontSet fset; | |
1205 XFontSetExtents *ext; | |
1206 | |
1207 XtVaGetValues(beval->balloonLabel, XtNfontSet, &fset, NULL); | |
1208 ext = XExtentsOfFontSet(fset); | |
1209 h = ext->max_ink_extent.height; | |
1210 w = XmbTextEscapement(fset, | |
1211 (char *)beval->msg, | |
1212 (int)STRLEN(beval->msg)); | |
1213 w += gui.border_offset << 1; | |
1214 h += gui.border_offset << 1; | |
1215 XtVaSetValues(beval->balloonLabel, XtNlabel, beval->msg, NULL); | |
1216 #endif | |
1217 | |
1218 /* Compute position of the balloon area */ | |
1219 tx = beval->x_root + EVAL_OFFSET_X; | |
1220 ty = beval->y_root + EVAL_OFFSET_Y; | |
1221 if ((tx + w) > beval->screen_width) | |
1222 tx = beval->screen_width - w; | |
1223 if ((ty + h) > beval->screen_height) | |
1224 ty = beval->screen_height - h; | |
1225 #ifdef FEAT_GUI_MOTIF | |
1226 XtVaSetValues(beval->balloonShell, | |
1227 XmNx, tx, | |
1228 XmNy, ty, | |
1229 NULL); | |
1230 #else | |
1231 /* Athena */ | |
1232 XtVaSetValues(beval->balloonShell, | |
1233 XtNx, tx, | |
1234 XtNy, ty, | |
1235 NULL); | |
1236 #endif | |
1844 | 1237 /* Set tooltip colors */ |
1238 { | |
1239 Arg args[2]; | |
1240 | |
1241 #ifdef FEAT_GUI_MOTIF | |
1242 args[0].name = XmNbackground; | |
1243 args[0].value = gui.tooltip_bg_pixel; | |
1244 args[1].name = XmNforeground; | |
1245 args[1].value = gui.tooltip_fg_pixel; | |
1246 #else /* Athena */ | |
1247 args[0].name = XtNbackground; | |
1248 args[0].value = gui.tooltip_bg_pixel; | |
1249 args[1].name = XtNforeground; | |
1250 args[1].value = gui.tooltip_fg_pixel; | |
1251 #endif | |
1252 XtSetValues(beval->balloonLabel, &args[0], XtNumber(args)); | |
1253 } | |
7 | 1254 |
1255 XtPopup(beval->balloonShell, XtGrabNone); | |
1256 | |
1257 beval->showState = ShS_SHOWING; | |
1258 | |
1259 current_beval = beval; | |
1260 } | |
1261 } | |
1262 | |
1263 /* | |
1264 * Undraw a balloon. | |
1265 */ | |
1266 static void | |
7821
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
1267 undrawBalloon(BalloonEval *beval) |
7 | 1268 { |
1269 if (beval->balloonShell != (Widget)0) | |
1270 XtPopdown(beval->balloonShell); | |
1271 beval->showState = ShS_NEUTRAL; | |
1272 | |
1273 current_beval = NULL; | |
1274 } | |
1275 | |
1276 static void | |
7821
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
1277 cancelBalloon(BalloonEval *beval) |
7 | 1278 { |
1279 if (beval->showState == ShS_SHOWING | |
1280 || beval->showState == ShS_UPDATE_PENDING) | |
1281 undrawBalloon(beval); | |
1282 | |
1283 if (beval->timerID != (XtIntervalId)NULL) | |
1284 { | |
1285 XtRemoveTimeOut(beval->timerID); | |
1286 beval->timerID = (XtIntervalId)NULL; | |
1287 } | |
1288 beval->showState = ShS_NEUTRAL; | |
1289 } | |
1290 | |
1291 | |
1292 static void | |
7821
81794242a275
commit https://github.com/vim/vim/commit/66f948e928d5e0cd3123af902aa8ac1613534c94
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
1293 createBalloonEvalWindow(BalloonEval *beval) |
7 | 1294 { |
1295 Arg args[12]; | |
1296 int n; | |
1297 | |
1298 n = 0; | |
1299 #ifdef FEAT_GUI_MOTIF | |
1300 XtSetArg(args[n], XmNallowShellResize, True); n++; | |
1301 beval->balloonShell = XtAppCreateShell("balloonEval", "BalloonEval", | |
1302 overrideShellWidgetClass, gui.dpy, args, n); | |
1303 #else | |
1304 /* Athena */ | |
1305 XtSetArg(args[n], XtNallowShellResize, True); n++; | |
1306 beval->balloonShell = XtAppCreateShell("balloonEval", "BalloonEval", | |
1307 overrideShellWidgetClass, gui.dpy, args, n); | |
1308 #endif | |
1309 | |
1310 n = 0; | |
1311 #ifdef FEAT_GUI_MOTIF | |
1312 { | |
1313 XmFontList fl; | |
1314 | |
1315 fl = gui_motif_fontset2fontlist(&gui.tooltip_fontset); | |
1316 XtSetArg(args[n], XmNforeground, gui.tooltip_fg_pixel); n++; | |
1317 XtSetArg(args[n], XmNbackground, gui.tooltip_bg_pixel); n++; | |
1318 XtSetArg(args[n], XmNfontList, fl); n++; | |
1319 XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; | |
1320 beval->balloonLabel = XtCreateManagedWidget("balloonLabel", | |
1321 xmLabelWidgetClass, beval->balloonShell, args, n); | |
1322 } | |
1323 #else /* FEAT_GUI_ATHENA */ | |
1324 XtSetArg(args[n], XtNforeground, gui.tooltip_fg_pixel); n++; | |
1325 XtSetArg(args[n], XtNbackground, gui.tooltip_bg_pixel); n++; | |
1326 XtSetArg(args[n], XtNinternational, True); n++; | |
1327 XtSetArg(args[n], XtNfontSet, gui.tooltip_fontset); n++; | |
1328 beval->balloonLabel = XtCreateManagedWidget("balloonLabel", | |
1329 labelWidgetClass, beval->balloonShell, args, n); | |
1330 #endif | |
1331 } | |
1332 | |
1333 #endif /* !FEAT_GUI_GTK */ | |
1334 #endif /* !FEAT_GUI_W32 */ | |
1335 | |
1336 #endif /* FEAT_BEVAL */ |