| To: vim_dev@googlegroups.com |
| Subject: Patch 7.4.866 |
| Fcc: outbox |
| From: Bram Moolenaar <Bram@moolenaar.net> |
| Mime-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| |
| Patch 7.4.866 |
| Problem: Crash when changing the 'tags' option from a remote command. |
| (Benjamin Fritz) |
| Solution: Instead of executing messages immediately, use a queue, like for |
| netbeans. (James Kolb) |
| Files: src/ex_docmd.c, src/getchar.c, src/gui_gtk_x11.c, src/gui_w48.c, |
| src/gui_x11.c, src/if_xcmdsrv.c, src/misc2.c, src/os_unix.c, |
| src/proto/if_xcmdsrv.pro, src/proto/misc2.pro, src/macros.h |
| |
| |
| |
| |
| |
| *** 9033,9043 **** |
| { |
| ui_delay(msec - done > 1000L ? 1000L : msec - done, TRUE); |
| ui_breakcheck(); |
| ! #ifdef FEAT_NETBEANS_INTG |
| ! /* Process the netbeans messages that may have been received in the |
| ! * call to ui_breakcheck() when the GUI is in use. This may occur when |
| ! * running a test case. */ |
| ! netbeans_parse_messages(); |
| #endif |
| } |
| } |
| --- 9033,9043 ---- |
| { |
| ui_delay(msec - done > 1000L ? 1000L : msec - done, TRUE); |
| ui_breakcheck(); |
| ! #ifdef MESSAGE_QUEUE |
| ! /* Process the netbeans and clientserver messages that may have been |
| ! * received in the call to ui_breakcheck() when the GUI is in use. This |
| ! * may occur when running a test case. */ |
| ! parse_queued_messages(); |
| #endif |
| } |
| } |
| |
| |
| |
| *** 3034,3042 **** |
| ) |
| { |
| |
| ! #if defined(FEAT_NETBEANS_INTG) |
| ! /* Process the queued netbeans messages. */ |
| ! netbeans_parse_messages(); |
| #endif |
| |
| if (got_int || (script_char = getc(scriptin[curscript])) < 0) |
| --- 3034,3041 ---- |
| ) |
| { |
| |
| ! #ifdef MESSAGE_QUEUE |
| ! parse_queued_messages(); |
| #endif |
| |
| if (got_int || (script_char = getc(scriptin[curscript])) < 0) |
| |
| |
| |
| *** 650,656 **** |
| xev.xproperty.atom = commProperty; |
| xev.xproperty.window = commWindow; |
| xev.xproperty.state = PropertyNewValue; |
| ! serverEventProc(GDK_WINDOW_XDISPLAY(widget->window), &xev); |
| } |
| return FALSE; |
| } |
| --- 650,656 ---- |
| xev.xproperty.atom = commProperty; |
| xev.xproperty.window = commWindow; |
| xev.xproperty.state = PropertyNewValue; |
| ! serverEventProc(GDK_WINDOW_XDISPLAY(widget->window), &xev, 0); |
| } |
| return FALSE; |
| } |
| |
| *** 5476,5484 **** |
| focus = gui.in_focus; |
| } |
| |
| ! #if defined(FEAT_NETBEANS_INTG) |
| ! /* Process any queued netbeans messages. */ |
| ! netbeans_parse_messages(); |
| #endif |
| |
| /* |
| --- 5476,5483 ---- |
| focus = gui.in_focus; |
| } |
| |
| ! #ifdef MESSAGE_QUEUE |
| ! parse_queued_messages(); |
| #endif |
| |
| /* |
| |
| |
| |
| *** 2016,2024 **** |
| s_need_activate = FALSE; |
| } |
| |
| ! #ifdef FEAT_NETBEANS_INTG |
| ! /* Process the queued netbeans messages. */ |
| ! netbeans_parse_messages(); |
| #endif |
| |
| /* |
| --- 2016,2023 ---- |
| s_need_activate = FALSE; |
| } |
| |
| ! #ifdef MESSAGE_QUEUE |
| ! parse_queued_messages(); |
| #endif |
| |
| /* |
| |
| |
| |
| *** 2895,2903 **** |
| focus = gui.in_focus; |
| } |
| |
| ! #if defined(FEAT_NETBEANS_INTG) |
| ! /* Process any queued netbeans messages. */ |
| ! netbeans_parse_messages(); |
| #endif |
| |
| /* |
| --- 2895,2902 ---- |
| focus = gui.in_focus; |
| } |
| |
| ! #ifdef MESSAGE_QUEUE |
| ! parse_queued_messages(); |
| #endif |
| |
| /* |
| |
| *** 3199,3205 **** |
| if (e->type == PropertyNotify && e->window == commWindow |
| && e->atom == commProperty && e->state == PropertyNewValue) |
| { |
| ! serverEventProc(gui.dpy, event); |
| } |
| } |
| #endif |
| --- 3198,3204 ---- |
| if (e->type == PropertyNotify && e->window == commWindow |
| && e->atom == commProperty && e->state == PropertyNewValue) |
| { |
| ! serverEventProc(gui.dpy, event, 0); |
| } |
| } |
| #endif |
| |
| |
| |
| *** 169,174 **** |
| --- 169,187 ---- |
| |
| typedef int (*EndCond) __ARGS((void *)); |
| |
| + struct x_cmdqueue |
| + { |
| + char_u *propInfo; |
| + int len; |
| + struct x_cmdqueue *next; |
| + struct x_cmdqueue *prev; |
| + }; |
| + |
| + typedef struct x_cmdqueue x_queue_T; |
| + |
| + /* dummy node, header for circular queue */ |
| + static x_queue_T head = {NULL, 0, NULL, NULL}; |
| + |
| /* |
| * Forward declarations for procedures defined later in this file: |
| */ |
| |
| *** 186,191 **** |
| --- 199,206 ---- |
| static int AppendPropCarefully __ARGS((Display *display, Window window, Atom property, char_u *value, int length)); |
| static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event)); |
| static int IsSerialName __ARGS((char_u *name)); |
| + static void save_in_queue __ARGS((char_u *buf, int len)); |
| + static void server_parse_message __ARGS((Display *dpy, char_u *propInfo, int numItems)); |
| |
| /* Private variables for the "server" functionality */ |
| static Atom registryProperty = None; |
| |
| *** 595,601 **** |
| while (TRUE) |
| { |
| while (XCheckWindowEvent(dpy, commWindow, PropertyChangeMask, &event)) |
| ! serverEventProc(dpy, &event); |
| |
| if (endCond(endData) != 0) |
| break; |
| --- 610,616 ---- |
| while (TRUE) |
| { |
| while (XCheckWindowEvent(dpy, commWindow, PropertyChangeMask, &event)) |
| ! serverEventProc(dpy, &event, 1); |
| |
| if (endCond(endData) != 0) |
| break; |
| |
| *** 1127,1148 **** |
| return OK; |
| } |
| |
| /* |
| * This procedure is invoked by the various X event loops throughout Vims when |
| * a property changes on the communication window. This procedure reads the |
| ! * property and handles command requests and responses. |
| */ |
| void |
| ! serverEventProc(dpy, eventPtr) |
| Display *dpy; |
| ! XEvent *eventPtr; /* Information about event. */ |
| { |
| char_u *propInfo; |
| ! char_u *p; |
| ! int result, actualFormat, code; |
| long_u numItems, bytesAfter; |
| Atom actualType; |
| - char_u *tofree; |
| |
| if (eventPtr != NULL) |
| { |
| --- 1142,1166 ---- |
| return OK; |
| } |
| |
| + |
| /* |
| * This procedure is invoked by the various X event loops throughout Vims when |
| * a property changes on the communication window. This procedure reads the |
| ! * property and enqueues command requests and responses. If immediate is true, |
| ! * it runs the event immediatly instead of enqueuing it. Immediate can cause |
| ! * unintended behavior and should only be used for code that blocks for a |
| ! * response. |
| */ |
| void |
| ! serverEventProc(dpy, eventPtr, immediate) |
| Display *dpy; |
| ! XEvent *eventPtr; /* Information about event. */ |
| ! int immediate; /* Run event immediately. Should mostly be 0. */ |
| { |
| char_u *propInfo; |
| ! int result, actualFormat; |
| long_u numItems, bytesAfter; |
| Atom actualType; |
| |
| if (eventPtr != NULL) |
| { |
| |
| *** 1168,1173 **** |
| --- 1186,1272 ---- |
| XFree(propInfo); |
| return; |
| } |
| + if (immediate) |
| + server_parse_message(dpy, propInfo, numItems); |
| + else |
| + save_in_queue(propInfo, numItems); |
| + } |
| + |
| + /* |
| + * Saves x clientserver commands in a queue so that they can be called when |
| + * vim is idle. |
| + */ |
| + static void |
| + save_in_queue(propInfo, len) |
| + char_u *propInfo; |
| + int len; |
| + { |
| + x_queue_T *node; |
| + |
| + node = (x_queue_T *)alloc(sizeof(x_queue_T)); |
| + if (node == NULL) |
| + return; /* out of memory */ |
| + node->propInfo = propInfo; |
| + node->len = len; |
| + |
| + if (head.next == NULL) /* initialize circular queue */ |
| + { |
| + head.next = &head; |
| + head.prev = &head; |
| + } |
| + |
| + /* insert node at tail of queue */ |
| + node->next = &head; |
| + node->prev = head.prev; |
| + head.prev->next = node; |
| + head.prev = node; |
| + } |
| + |
| + /* |
| + * Parses queued clientserver messages. |
| + */ |
| + void |
| + server_parse_messages() |
| + { |
| + char_u *p; |
| + x_queue_T *node; |
| + |
| + if (!X_DISPLAY) |
| + return; /* cannot happen? */ |
| + while (head.next != NULL && head.next != &head) |
| + { |
| + node = head.next; |
| + server_parse_message(X_DISPLAY, node->propInfo, node->len); |
| + head.next = node->next; |
| + node->next->prev = node->prev; |
| + vim_free(node); |
| + } |
| + } |
| + |
| + /* |
| + * Returns a non-zero value if there are clientserver messages waiting |
| + * int the queue. |
| + */ |
| + int |
| + server_waiting() |
| + { |
| + return head.next != NULL && head.next != &head; |
| + } |
| + |
| + /* |
| + * Prases a single clientserver message. A single message may contain multiple |
| + * commands. |
| + * "propInfo" will be freed. |
| + */ |
| + static void |
| + server_parse_message(dpy, propInfo, numItems) |
| + Display *dpy; |
| + char_u *propInfo; /* A string containing 0 or more X commands */ |
| + int numItems; /* The size of propInfo in bytes. */ |
| + { |
| + char_u *p; |
| + int code; |
| + char_u *tofree; |
| |
| /* |
| * Several commands and results could arrive in the property at |
| |
| *** 1248,1263 **** |
| if (script == NULL || name == NULL) |
| continue; |
| |
| ! if (serverName != NULL && STRICMP(name, serverName) == 0) |
| ! { |
| ! script = serverConvert(enc, script, &tofree); |
| ! if (asKeys) |
| ! server_to_input_buf(script); |
| ! else |
| ! { |
| ! char_u *res; |
| |
| ! res = eval_client_expr_to_string(script); |
| if (resWindow != None) |
| { |
| garray_T reply; |
| --- 1347,1362 ---- |
| if (script == NULL || name == NULL) |
| continue; |
| |
| ! if (serverName != NULL && STRICMP(name, serverName) == 0) |
| ! { |
| ! script = serverConvert(enc, script, &tofree); |
| ! if (asKeys) |
| ! server_to_input_buf(script); |
| ! else |
| ! { |
| ! char_u *res; |
| |
| ! res = eval_client_expr_to_string(script); |
| if (resWindow != None) |
| { |
| garray_T reply; |
| |
| *** 1290,1299 **** |
| reply.ga_data, reply.ga_len); |
| ga_clear(&reply); |
| } |
| ! vim_free(res); |
| ! } |
| ! vim_free(tofree); |
| ! } |
| } |
| else if (*p == 'r' && p[1] == 0) |
| { |
| --- 1389,1398 ---- |
| reply.ga_data, reply.ga_len); |
| ga_clear(&reply); |
| } |
| ! vim_free(res); |
| ! } |
| ! vim_free(tofree); |
| ! } |
| } |
| else if (*p == 'r' && p[1] == 0) |
| { |
| |
| |
| |
| *** 6328,6330 **** |
| --- 6328,6350 ---- |
| return FALSE; |
| } |
| #endif |
| + |
| + #if defined(MESSAGE_QUEUE) || defined(PROTO) |
| + /* |
| + * Process messages that have been queued for netbeans or clientserver. |
| + * These functions can call arbitrary vimscript and should only be called when |
| + * it is safe to do so. |
| + */ |
| + void |
| + parse_queued_messages() |
| + { |
| + # ifdef FEAT_NETBEANS_INTG |
| + /* Process the queued netbeans messages. */ |
| + netbeans_parse_messages(); |
| + # endif |
| + # ifdef FEAT_CLIENTSERVER |
| + /* Process the queued clientserver messages. */ |
| + server_parse_messages(); |
| + # endif |
| + } |
| + #endif |
| |
| |
| |
| *** 388,396 **** |
| { |
| int len; |
| |
| ! #ifdef FEAT_NETBEANS_INTG |
| ! /* Process the queued netbeans messages. */ |
| ! netbeans_parse_messages(); |
| #endif |
| |
| /* Check if window changed size while we were busy, perhaps the ":set |
| --- 388,395 ---- |
| { |
| int len; |
| |
| ! #ifdef MESSAGE_QUEUE |
| ! parse_queued_messages(); |
| #endif |
| |
| /* Check if window changed size while we were busy, perhaps the ":set |
| |
| *** 405,413 **** |
| if (!do_resize) /* return if not interrupted by resize */ |
| return 0; |
| handle_resize(); |
| ! #ifdef FEAT_NETBEANS_INTG |
| ! /* Process the queued netbeans messages. */ |
| ! netbeans_parse_messages(); |
| #endif |
| } |
| } |
| --- 404,411 ---- |
| if (!do_resize) /* return if not interrupted by resize */ |
| return 0; |
| handle_resize(); |
| ! #ifdef MESSAGE_QUEUE |
| ! parse_queued_messages(); |
| #endif |
| } |
| } |
| |
| *** 439,447 **** |
| while (do_resize) /* window changed size */ |
| handle_resize(); |
| |
| ! #ifdef FEAT_NETBEANS_INTG |
| ! /* Process the queued netbeans messages. */ |
| ! netbeans_parse_messages(); |
| #endif |
| /* |
| * We want to be interrupted by the winch signal |
| --- 437,444 ---- |
| while (do_resize) /* window changed size */ |
| handle_resize(); |
| |
| ! #ifdef MESSAGE_QUEUE |
| ! parse_queued_messages(); |
| #endif |
| /* |
| * We want to be interrupted by the winch signal |
| |
| *** 5208,5213 **** |
| --- 5205,5211 ---- |
| * When a GUI is being used, this will not be used for input -- webb |
| * Returns also, when a request from Sniff is waiting -- toni. |
| * Or when a Linux GPM mouse event is waiting. |
| + * Or when a clientserver message is on the queue. |
| */ |
| #if defined(__BEOS__) |
| int |
| |
| *** 5601,5606 **** |
| --- 5599,5609 ---- |
| if (finished || msec == 0) |
| break; |
| |
| + # ifdef FEAT_CLIENTSERVER |
| + if (server_waiting()) |
| + break; |
| + # endif |
| + |
| /* We're going to loop around again, find out for how long */ |
| if (msec > 0) |
| { |
| |
| *** 7106,7136 **** |
| |
| for (;;) |
| { |
| ! XtInputMask mask = XtAppPending(app_context); |
| |
| ! if (mask == 0 || vim_is_input_buf_full()) |
| break; |
| |
| ! if (mask & XtIMXEvent) |
| { |
| /* There is an event to process. */ |
| ! XtAppNextEvent(app_context, &event); |
| #ifdef FEAT_CLIENTSERVER |
| { |
| XPropertyEvent *e = (XPropertyEvent *)&event; |
| |
| if (e->type == PropertyNotify && e->window == commWindow |
| && e->atom == commProperty && e->state == PropertyNewValue) |
| ! serverEventProc(xterm_dpy, &event); |
| } |
| #endif |
| ! XtDispatchEvent(&event); |
| ! } |
| else |
| { |
| /* There is something else than an event to process. */ |
| ! XtAppProcessEvent(app_context, mask); |
| ! } |
| } |
| } |
| |
| --- 7109,7139 ---- |
| |
| for (;;) |
| { |
| ! XtInputMask mask = XtAppPending(app_context); |
| |
| ! if (mask == 0 || vim_is_input_buf_full()) |
| break; |
| |
| ! if (mask & XtIMXEvent) |
| { |
| /* There is an event to process. */ |
| ! XtAppNextEvent(app_context, &event); |
| #ifdef FEAT_CLIENTSERVER |
| { |
| XPropertyEvent *e = (XPropertyEvent *)&event; |
| |
| if (e->type == PropertyNotify && e->window == commWindow |
| && e->atom == commProperty && e->state == PropertyNewValue) |
| ! serverEventProc(xterm_dpy, &event, 0); |
| } |
| #endif |
| ! XtDispatchEvent(&event); |
| ! } |
| else |
| { |
| /* There is something else than an event to process. */ |
| ! XtAppProcessEvent(app_context, mask); |
| ! } |
| } |
| } |
| |
| |
| |
| |
| *** 7,11 **** |
| int serverSendReply __ARGS((char_u *name, char_u *str)); |
| int serverReadReply __ARGS((Display *dpy, Window win, char_u **str, int localLoop)); |
| int serverPeekReply __ARGS((Display *dpy, Window win, char_u **str)); |
| ! void serverEventProc __ARGS((Display *dpy, XEvent *eventPtr)); |
| /* vim: set ft=c : */ |
| --- 7,13 ---- |
| int serverSendReply __ARGS((char_u *name, char_u *str)); |
| int serverReadReply __ARGS((Display *dpy, Window win, char_u **str, int localLoop)); |
| int serverPeekReply __ARGS((Display *dpy, Window win, char_u **str)); |
| ! void serverEventProc __ARGS((Display *dpy, XEvent *eventPtr, int immediate)); |
| ! void server_parse_messages __ARGS((void)); |
| ! int server_waiting __ARGS((void)); |
| /* vim: set ft=c : */ |
| |
| |
| |
| *** 106,109 **** |
| --- 106,110 ---- |
| void put_time __ARGS((FILE *fd, time_t the_time)); |
| void time_to_bytes __ARGS((time_t the_time, char_u *buf)); |
| int has_non_ascii __ARGS((char_u *s)); |
| + void parse_queued_messages __ARGS((void)); |
| /* vim: set ft=c : */ |
| |
| |
| |
| *** 321,323 **** |
| --- 321,327 ---- |
| #else |
| # define PLINES_NOFILL(x) plines(x) |
| #endif |
| + |
| + #if defined(FEAT_NETBEANS_INTG) || defined(FEAT_CLIENTSERVER) |
| + # define MESSAGE_QUEUE |
| + #endif |
| |
| |
| |
| *** 743,744 **** |
| --- 743,746 ---- |
| { /* Add new patch number below this line */ |
| + /**/ |
| + 866, |
| /**/ |
| |
| -- |
| ALL: A witch! A witch! |
| WITCH: It's a fair cop. |
| ALL: Burn her! Burn her! Let's make her into a ladder. |
| "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD |
| |
| /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ |
| /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ |
| \\\ an exciting new programming language -- http://www.Zimbu.org /// |
| \\\ help me help AIDS victims -- http://ICCF-Holland.org /// |