1 /* vi:set ts=8 sts=4 sw=4:
3 * VIM - Vi IMproved by Bram Moolenaar
4 * X command server by Flemming Madsen
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.
10 * if_xcmdsrv.c: Functions for passing commands through an X11 display.
17 #if defined(FEAT_CLIENTSERVER) || defined(PROTO)
20 # include <X11/Intrinsic.h>
21 # include <X11/Xatom.h>
24 # if defined(HAVE_SYS_SELECT_H) && \
25 (!defined(HAVE_SYS_TIME_H) || defined(SYS_SELECT_WITH_SYS_TIME))
26 # include <sys/select.h>
30 # ifdef HAVE_SYS_POLL_H
31 # include <sys/poll.h>
40 * This file provides procedures that implement the command server
41 * functionality of Vim when in contact with an X11 server.
43 * Adapted from TCL/TK's send command in tkSend.c of the tk 3.6 distribution.
44 * Adapted for use in Vim by Flemming Madsen. Protocol changed to that of tk 4
48 * Copyright (c) 1989-1993 The Regents of the University of California.
49 * All rights reserved.
51 * Permission is hereby granted, without written agreement and without
52 * license or royalty fees, to use, copy, modify, and distribute this
53 * software and its documentation for any purpose, provided that the
54 * above copyright notice and the following two paragraphs appear in
55 * all copies of this software.
57 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
58 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
59 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
60 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
63 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
64 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
65 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
66 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
71 * When a result is being awaited from a sent command, one of
72 * the following structures is present on a list of all outstanding
73 * sent commands. The information in the structure is used to
74 * process the result when it arrives. You're probably wondering
75 * how there could ever be multiple outstanding sent commands.
76 * This could happen if Vim instances invoke each other recursively.
77 * It's unlikely, but possible.
80 typedef struct PendingCommand
82 int serial
; /* Serial number expected in result. */
83 int code
; /* Result Code. 0 is OK */
84 char_u
*result
; /* String result for command (malloc'ed).
85 * NULL means command still pending. */
86 struct PendingCommand
*nextPtr
;
87 /* Next in list of all outstanding commands.
88 * NULL means end of list. */
91 static PendingCommand
*pendingCommands
= NULL
;
92 /* List of all commands currently
93 * being waited for. */
96 * The information below is used for communication between processes
97 * during "send" commands. Each process keeps a private window, never
98 * even mapped, with one property, "Comm". When a command is sent to
99 * an interpreter, the command is appended to the comm property of the
100 * communication window associated with the interp's process. Similarly,
101 * when a result is returned from a sent command, it is also appended
102 * to the comm property.
104 * Each command and each result takes the form of ASCII text. For a
105 * command, the text consists of a nul character followed by several
106 * nul-terminated ASCII strings. The first string consists of a
108 * "c" for an expression
111 * "n" for notification.
112 * Subsequent strings have the form "option value" where the following options
115 * -r commWindow serial
117 * This option means that a response should be sent to the window
118 * whose X identifier is "commWindow" (in hex), and the response should
119 * be identified with the serial number given by "serial" (in decimal).
120 * If this option isn't specified then the send is asynchronous and
121 * no response is sent.
124 * "Name" gives the name of the application for which the command is
125 * intended. This option must be present.
128 * Encoding name used for the text. This is the 'encoding' of the
129 * sender. The receiver may want to do conversion to his 'encoding'.
132 * "Script" is the script to be executed. This option must be
133 * present. Taken as a series of keystrokes in a "k" command where
134 * <Key>'s are expanded
136 * The options may appear in any order. The -n and -s options must be
137 * present, but -r may be omitted for asynchronous RPCs. For compatibility
138 * with future releases that may add new features, there may be additional
139 * options present; as long as they start with a "-" character, they will
142 * A result also consists of a zero character followed by several null-
143 * terminated ASCII strings. The first string consists of the single
144 * letter "r". Subsequent strings have the form "option value" where
145 * the following options are supported:
148 * Identifies the command for which this is the result. It is the
149 * same as the "serial" field from the -s option in the command. This
150 * option must be present.
153 * "Result" is the result string for the script, which may be either
154 * a result or an error message. If this field is omitted then it
155 * defaults to an empty string.
158 * 0: for OK. This is the default.
159 * 1: for error: Result is the last error
163 * Not applicable for Vim
165 * Options may appear in any order, and only the -s option must be
166 * present. As with commands, there may be additional options besides
167 * these; unknown options are ignored.
171 * Maximum size property that can be read at one time by
175 #define MAX_PROP_WORDS 100000
182 static garray_T serverReply
= { 0, 0, 0, 0, 0 };
183 enum ServerReplyOp
{ SROP_Find
, SROP_Add
, SROP_Delete
};
185 typedef int (*EndCond
) __ARGS((void *));
188 * Forward declarations for procedures defined later in this file:
191 static Window LookupName
__ARGS((Display
*dpy
, char_u
*name
, int delete, char_u
**loose
));
192 static int SendInit
__ARGS((Display
*dpy
));
193 static int DoRegisterName
__ARGS((Display
*dpy
, char_u
*name
));
194 static void DeleteAnyLingerer
__ARGS((Display
*dpy
, Window w
));
195 static int GetRegProp
__ARGS((Display
*dpy
, char_u
**regPropp
, long_u
*numItemsp
, int domsg
));
196 static int WaitForPend
__ARGS((void *p
));
197 static int WaitForReply
__ARGS((void *p
));
198 static int WindowValid
__ARGS((Display
*dpy
, Window w
));
199 static void ServerWait
__ARGS((Display
*dpy
, Window w
, EndCond endCond
, void *endData
, int localLoop
, int seconds
));
200 static struct ServerReply
*ServerReplyFind
__ARGS((Window w
, enum ServerReplyOp op
));
201 static int AppendPropCarefully
__ARGS((Display
*display
, Window window
, Atom property
, char_u
*value
, int length
));
202 static int x_error_check
__ARGS((Display
*dpy
, XErrorEvent
*error_event
));
203 static int IsSerialName
__ARGS((char_u
*name
));
205 /* Private variables for the "server" functionality */
206 static Atom registryProperty
= None
;
207 static Atom vimProperty
= None
;
208 static int got_x_error
= FALSE
;
210 static char_u
*empty_prop
= (char_u
*)""; /* empty GetRegProp() result */
213 * Associate an ASCII name with Vim. Try real hard to get a unique one.
214 * Returns FAIL or OK.
217 serverRegisterName(dpy
, name
)
218 Display
*dpy
; /* display to register with */
219 char_u
*name
; /* the name that will be used as a base */
225 res
= DoRegisterName(dpy
, name
);
231 if (res
< -1 || i
>= 1000)
233 MSG_ATTR(_("Unable to register a command server name"),
238 p
= alloc(STRLEN(name
) + 10);
244 sprintf((char *)p
, "%s%d", name
, i
++);
245 res
= DoRegisterName(dpy
, p
);
255 DoRegisterName(dpy
, name
)
260 XErrorHandler old_handler
;
261 #define MAX_NAME_LENGTH 100
262 char_u propInfo
[MAX_NAME_LENGTH
+ 20];
264 if (commProperty
== None
)
266 if (SendInit(dpy
) < 0)
271 * Make sure the name is unique, and append info about it to
272 * the registry property. It's important to lock the server
273 * here to prevent conflicting changes to the registry property.
274 * WARNING: Do not step through this while debugging, it will hangup the X
278 w
= LookupName(dpy
, name
, FALSE
, NULL
);
283 unsigned int dummyUns
;
287 * The name is currently registered. See if the commWindow
288 * associated with the name exists. If not, or if the commWindow
289 * is *our* commWindow, then just unregister the old name (this
290 * could happen if an application dies without cleaning up the
293 old_handler
= XSetErrorHandler(x_error_check
);
294 status
= XGetGeometry(dpy
, w
, &dummyWin
, &dummyInt
, &dummyInt
,
295 &dummyUns
, &dummyUns
, &dummyUns
, &dummyUns
);
296 (void)XSetErrorHandler(old_handler
);
297 if (status
!= Success
&& w
!= commWindow
)
303 (void)LookupName(dpy
, name
, /*delete=*/TRUE
, NULL
);
305 sprintf((char *)propInfo
, "%x %.*s", (int_u
)commWindow
,
306 MAX_NAME_LENGTH
, name
);
307 old_handler
= XSetErrorHandler(x_error_check
);
309 XChangeProperty(dpy
, RootWindow(dpy
, 0), registryProperty
, XA_STRING
, 8,
310 PropModeAppend
, propInfo
, STRLEN(propInfo
) + 1);
313 (void)XSetErrorHandler(old_handler
);
318 set_vim_var_string(VV_SEND_SERVER
, name
, -1);
320 serverName
= vim_strsave(name
);
322 need_maketitle
= TRUE
;
329 #if defined(FEAT_GUI) || defined(PROTO)
331 * Clean out new ID from registry and set it as comm win.
332 * Change any registered window ID.
335 serverChangeRegisteredWindow(dpy
, newwin
)
336 Display
*dpy
; /* Display to register with */
337 Window newwin
; /* Re-register to this ID */
339 char_u propInfo
[MAX_NAME_LENGTH
+ 20];
343 /* Always call SendInit() here, to make sure commWindow is marked as a Vim
345 if (SendInit(dpy
) < 0)
348 /* WARNING: Do not step through this while debugging, it will hangup the X
351 DeleteAnyLingerer(dpy
, newwin
);
352 if (serverName
!= NULL
)
354 /* Reinsert name if we was already registered */
355 (void)LookupName(dpy
, serverName
, /*delete=*/TRUE
, NULL
);
356 sprintf((char *)propInfo
, "%x %.*s",
357 (int_u
)newwin
, MAX_NAME_LENGTH
, serverName
);
358 XChangeProperty(dpy
, RootWindow(dpy
, 0), registryProperty
, XA_STRING
, 8,
359 PropModeAppend
, (char_u
*)propInfo
,
360 STRLEN(propInfo
) + 1);
367 * Send to an instance of Vim via the X display.
368 * Returns 0 for OK, negative for an error.
371 serverSendToVim(dpy
, name
, cmd
, result
, server
, asExpr
, localLoop
, silent
)
372 Display
*dpy
; /* Where to send. */
373 char_u
*name
; /* Where to send. */
374 char_u
*cmd
; /* What to send. */
375 char_u
**result
; /* Result of eval'ed expression */
376 Window
*server
; /* Actual ID of receiving app */
377 Bool asExpr
; /* Interpret as keystrokes or expr ? */
378 Bool localLoop
; /* Throw away everything but result */
379 int silent
; /* don't complain about no server */
385 static int serial
= 0; /* Running count of sent commands.
386 * Used to give each command a
387 * different serial number. */
388 PendingCommand pending
;
389 char_u
*loosename
= NULL
;
393 if (name
== NULL
|| *name
== NUL
)
394 name
= (char_u
*)"GVIM"; /* use a default name */
396 if (commProperty
== None
&& dpy
!= NULL
)
398 if (SendInit(dpy
) < 0)
402 /* Execute locally if no display or target is ourselves */
403 if (dpy
== NULL
|| (serverName
!= NULL
&& STRICMP(name
, serverName
) == 0))
409 ret
= eval_client_expr_to_string(cmd
);
413 *result
= vim_strsave((char_u
*)_(e_invexprmsg
));
419 return ret
== NULL
? -1 : 0;
422 server_to_input_buf(cmd
);
427 * Bind the server name to a communication window.
429 * Find any survivor with a serialno attached to the name if the
430 * original registrant of the wanted name is no longer present.
432 * Delete any lingering names from dead editors.
436 w
= LookupName(dpy
, name
, FALSE
, &loosename
);
437 /* Check that the window is hot */
440 if (!WindowValid(dpy
, w
))
442 LookupName(dpy
, loosename
? loosename
: name
,
443 /*DELETE=*/TRUE
, NULL
);
452 EMSG2(_(e_noserver
), name
);
455 else if (loosename
!= NULL
)
461 * Send the command to target interpreter by appending it to the
462 * comm window in the communication window.
463 * Length must be computed exactly!
466 length
= STRLEN(name
) + STRLEN(p_enc
) + STRLEN(cmd
) + 14;
468 length
= STRLEN(name
) + STRLEN(cmd
) + 10;
470 property
= (char_u
*)alloc((unsigned)length
+ 30);
473 sprintf((char *)property
, "%c%c%c-n %s%c-E %s%c-s %s",
474 0, asExpr
? 'c' : 'k', 0, name
, 0, p_enc
, 0, cmd
);
476 sprintf((char *)property
, "%c%c%c-n %s%c-s %s",
477 0, asExpr
? 'c' : 'k', 0, name
, 0, cmd
);
479 if (name
== loosename
)
481 /* Add a back reference to our comm window */
483 sprintf((char *)property
+ length
, "%c-r %x %d",
484 0, (int_u
)commWindow
, serial
);
485 /* Add length of what "-r %x %d" resulted in, skipping the NUL. */
486 length
+= STRLEN(property
+ length
+ 1) + 1;
488 res
= AppendPropCarefully(dpy
, w
, commProperty
, property
, length
+ 1);
492 EMSG(_("E248: Failed to send command to the destination program"));
496 if (!asExpr
) /* There is no answer for this - Keys are sent async */
500 * Register the fact that we're waiting for a command to
501 * complete (this is needed by SendEventProc and by
502 * AppendErrorProc to pass back the command's results).
504 pending
.serial
= serial
;
506 pending
.result
= NULL
;
507 pending
.nextPtr
= pendingCommands
;
508 pendingCommands
= &pending
;
510 ServerWait(dpy
, w
, WaitForPend
, &pending
, localLoop
, 600);
513 * Unregister the information about the pending command
514 * and return the result.
516 if (pendingCommands
== &pending
)
517 pendingCommands
= pending
.nextPtr
;
520 PendingCommand
*pcPtr
;
522 for (pcPtr
= pendingCommands
; pcPtr
!= NULL
; pcPtr
= pcPtr
->nextPtr
)
523 if (pcPtr
->nextPtr
== &pending
)
525 pcPtr
->nextPtr
= pending
.nextPtr
;
530 *result
= pending
.result
;
532 vim_free(pending
.result
);
534 return pending
.code
== 0 ? 0 : -1;
541 PendingCommand
*pending
= (PendingCommand
*) p
;
542 return pending
->result
!= NULL
;
546 * Return TRUE if window "w" exists and has a "Vim" property on it.
553 XErrorHandler old_handler
;
558 old_handler
= XSetErrorHandler(x_error_check
);
560 plist
= XListProperties(dpy
, w
, &numProp
);
562 XSetErrorHandler(old_handler
);
563 if (plist
== NULL
|| got_x_error
)
566 for (i
= 0; i
< numProp
; i
++)
567 if (plist
[i
] == vimProperty
)
577 * Enter a loop processing X events & polling chars until we see a result
580 ServerWait(dpy
, w
, endCond
, endData
, localLoop
, seconds
)
592 XPropertyEvent
*e
= (XPropertyEvent
*)&event
;
593 # define SEND_MSEC_POLL 50
596 while (endCond(endData
) == 0)
599 if (seconds
>= 0 && (now
- start
) >= seconds
)
604 if (!WindowValid(dpy
, w
))
607 * Sometimes the PropertyChange event doesn't come.
608 * This can be seen in eg: vim -c 'echo remote_expr("gvim", "3+2")'
610 serverEventProc(dpy
, NULL
);
614 /* Just look out for the answer without calling back into Vim */
618 fds
.fd
= ConnectionNumber(dpy
);
620 if (poll(&fds
, 1, SEND_MSEC_POLL
) < 0)
627 tv
.tv_usec
= SEND_MSEC_POLL
* 1000;
629 FD_SET(ConnectionNumber(dpy
), &fds
);
630 if (select(ConnectionNumber(dpy
) + 1, &fds
, NULL
, NULL
, &tv
) < 0)
633 while (XEventsQueued(dpy
, QueuedAfterReading
) > 0)
635 XNextEvent(dpy
, &event
);
636 if (event
.type
== PropertyNotify
&& e
->window
== commWindow
)
637 serverEventProc(dpy
, &event
);
644 ui_delay((long)SEND_MSEC_POLL
, TRUE
);
652 * Fetch a list of all the Vim instance names currently registered for the
655 * Returns a newline separated list in allocated memory or NULL.
658 serverGetVimNames(dpy
)
668 if (registryProperty
== None
)
670 if (SendInit(dpy
) < 0)
673 ga_init2(&ga
, 1, 100);
676 * Read the registry property.
678 if (GetRegProp(dpy
, ®Prop
, &numItems
, TRUE
) == FAIL
)
682 * Scan all of the names out of the property.
684 ga_init2(&ga
, 1, 100);
685 for (p
= regProp
; (long_u
)(p
- regProp
) < numItems
; p
++)
688 while (*p
!= 0 && !isspace(*p
))
693 sscanf((char *)entry
, "%x", &w
);
694 if (WindowValid(dpy
, (Window
)w
))
696 ga_concat(&ga
, p
+ 1);
697 ga_concat(&ga
, (char_u
*)"\n");
703 if (regProp
!= empty_prop
)
709 /* ----------------------------------------------------------
713 static struct ServerReply
*
714 ServerReplyFind(w
, op
)
716 enum ServerReplyOp op
;
718 struct ServerReply
*p
;
719 struct ServerReply e
;
722 p
= (struct ServerReply
*) serverReply
.ga_data
;
723 for (i
= 0; i
< serverReply
.ga_len
; i
++, p
++)
726 if (i
>= serverReply
.ga_len
)
729 if (p
== NULL
&& op
== SROP_Add
)
731 if (serverReply
.ga_growsize
== 0)
732 ga_init2(&serverReply
, sizeof(struct ServerReply
), 1);
733 if (ga_grow(&serverReply
, 1) == OK
)
735 p
= ((struct ServerReply
*) serverReply
.ga_data
)
736 + serverReply
.ga_len
;
738 ga_init2(&e
.strings
, 1, 100);
739 mch_memmove(p
, &e
, sizeof(e
));
740 serverReply
.ga_len
++;
743 else if (p
!= NULL
&& op
== SROP_Delete
)
745 ga_clear(&p
->strings
);
746 mch_memmove(p
, p
+ 1, (serverReply
.ga_len
- i
- 1) * sizeof(*p
));
747 serverReply
.ga_len
--;
754 * Convert string to windowid.
755 * Issue an error if the id is invalid.
763 sscanf((char *)str
, "0x%x", &id
);
765 EMSG2(_("E573: Invalid server id used: %s"), str
);
771 * Send a reply string (notification) to client with id "name".
772 * Return -1 if the window is invalid.
775 serverSendReply(name
, str
)
782 Display
*dpy
= X_DISPLAY
;
783 Window win
= serverStrToWin(name
);
785 if (commProperty
== None
)
787 if (SendInit(dpy
) < 0)
790 if (!WindowValid(dpy
, win
))
794 length
= STRLEN(p_enc
) + STRLEN(str
) + 14;
796 length
= STRLEN(str
) + 10;
798 if ((property
= (char_u
*)alloc((unsigned)length
+ 30)) != NULL
)
801 sprintf((char *)property
, "%cn%c-E %s%c-n %s%c-w %x",
802 0, 0, p_enc
, 0, str
, 0, (unsigned int)commWindow
);
804 sprintf((char *)property
, "%cn%c-n %s%c-w %x",
805 0, 0, str
, 0, (unsigned int)commWindow
);
807 /* Add length of what "%x" resulted in. */
808 length
+= STRLEN(property
+ length
);
809 res
= AppendPropCarefully(dpy
, win
, commProperty
, property
, length
+ 1);
820 Window
*w
= (Window
*) p
;
821 return ServerReplyFind(*w
, SROP_Find
) != NULL
;
825 * Wait for replies from id (win)
826 * Return 0 and the malloc'ed string when a reply is available.
827 * Return -1 if the window becomes invalid while waiting.
830 serverReadReply(dpy
, win
, str
, localLoop
)
838 struct ServerReply
*p
;
840 ServerWait(dpy
, win
, WaitForReply
, &win
, localLoop
, -1);
842 if ((p
= ServerReplyFind(win
, SROP_Find
)) != NULL
&& p
->strings
.ga_len
> 0)
844 *str
= vim_strsave(p
->strings
.ga_data
);
845 len
= STRLEN(*str
) + 1;
846 if (len
< p
->strings
.ga_len
)
848 s
= (char_u
*) p
->strings
.ga_data
;
849 mch_memmove(s
, s
+ len
, p
->strings
.ga_len
- len
);
850 p
->strings
.ga_len
-= len
;
854 /* Last string read. Remove from list */
855 ga_clear(&p
->strings
);
856 ServerReplyFind(win
, SROP_Delete
);
864 * Check for replies from id (win).
865 * Return TRUE and a non-malloc'ed string if there is. Else return FALSE.
868 serverPeekReply(dpy
, win
, str
)
873 struct ServerReply
*p
;
875 if ((p
= ServerReplyFind(win
, SROP_Find
)) != NULL
&& p
->strings
.ga_len
> 0)
878 *str
= p
->strings
.ga_data
;
881 if (!WindowValid(dpy
, win
))
888 * Initialize the communication channels for sending commands and receiving
895 XErrorHandler old_handler
;
898 * Create the window used for communication, and set up an
899 * event handler for it.
901 old_handler
= XSetErrorHandler(x_error_check
);
904 if (commProperty
== None
)
905 commProperty
= XInternAtom(dpy
, "Comm", False
);
906 if (vimProperty
== None
)
907 vimProperty
= XInternAtom(dpy
, "Vim", False
);
908 if (registryProperty
== None
)
909 registryProperty
= XInternAtom(dpy
, "VimRegistry", False
);
911 if (commWindow
== None
)
913 commWindow
= XCreateSimpleWindow(dpy
, XDefaultRootWindow(dpy
),
914 getpid(), 0, 10, 10, 0,
915 WhitePixel(dpy
, DefaultScreen(dpy
)),
916 WhitePixel(dpy
, DefaultScreen(dpy
)));
917 XSelectInput(dpy
, commWindow
, PropertyChangeMask
);
918 /* WARNING: Do not step through this while debugging, it will hangup
921 DeleteAnyLingerer(dpy
, commWindow
);
925 /* Make window recognizable as a vim window */
926 XChangeProperty(dpy
, commWindow
, vimProperty
, XA_STRING
,
927 8, PropModeReplace
, (char_u
*)VIM_VERSION_SHORT
,
928 (int)STRLEN(VIM_VERSION_SHORT
) + 1);
931 (void)XSetErrorHandler(old_handler
);
933 return got_x_error
? -1 : 0;
937 * Given a server name, see if the name exists in the registry for a
938 * particular display.
940 * If the given name is registered, return the ID of the window associated
941 * with the name. If the name isn't registered, then return 0.
944 * If the registry property is improperly formed, then it is deleted.
945 * If "delete" is non-zero, then if the named server is found it is
946 * removed from the registry property.
949 LookupName(dpy
, name
, delete, loose
)
950 Display
*dpy
; /* Display whose registry to check. */
951 char_u
*name
; /* Name of a server. */
952 int delete; /* If non-zero, delete info about name. */
953 char_u
**loose
; /* Do another search matching -999 if not found
954 Return result here if a match is found */
956 char_u
*regProp
, *entry
;
962 * Read the registry property.
964 if (GetRegProp(dpy
, ®Prop
, &numItems
, FALSE
) == FAIL
)
968 * Scan the property for the desired name.
970 returnValue
= (int_u
)None
;
971 entry
= NULL
; /* Not needed, but eliminates compiler warning. */
972 for (p
= regProp
; (long_u
)(p
- regProp
) < numItems
; )
975 while (*p
!= 0 && !isspace(*p
))
977 if (*p
!= 0 && STRICMP(name
, p
+ 1) == 0)
979 sscanf((char *)entry
, "%x", &returnValue
);
987 if (loose
!= NULL
&& returnValue
== (int_u
)None
&& !IsSerialName(name
))
989 for (p
= regProp
; (long_u
)(p
- regProp
) < numItems
; )
992 while (*p
!= 0 && !isspace(*p
))
994 if (*p
!= 0 && IsSerialName(p
+ 1)
995 && STRNICMP(name
, p
+ 1, STRLEN(name
)) == 0)
997 sscanf((char *)entry
, "%x", &returnValue
);
998 *loose
= vim_strsave(p
+ 1);
1008 * Delete the property, if that is desired (copy down the
1009 * remainder of the registry property to overlay the deleted
1010 * info, then rewrite the property).
1012 if (delete && returnValue
!= (int_u
)None
)
1019 count
= numItems
- (p
- regProp
);
1021 mch_memmove(entry
, p
, count
);
1022 XChangeProperty(dpy
, RootWindow(dpy
, 0), registryProperty
, XA_STRING
,
1023 8, PropModeReplace
, regProp
,
1024 (int)(numItems
- (p
- entry
)));
1028 if (regProp
!= empty_prop
)
1030 return (Window
)returnValue
;
1034 * Delete any lingering occurrence of window id. We promise that any
1035 * occurrence is not ours since it is not yet put into the registry (by us)
1037 * This is necessary in the following scenario:
1038 * 1. There is an old windowid for an exit'ed vim in the registry
1039 * 2. We get that id for our commWindow but only want to send, not register.
1040 * 3. The window will mistakenly be regarded valid because of own commWindow
1043 DeleteAnyLingerer(dpy
, win
)
1044 Display
*dpy
; /* Display whose registry to check. */
1045 Window win
; /* Window to remove */
1047 char_u
*regProp
, *entry
= NULL
;
1053 * Read the registry property.
1055 if (GetRegProp(dpy
, ®Prop
, &numItems
, FALSE
) == FAIL
)
1058 /* Scan the property for the window id. */
1059 for (p
= regProp
; (long_u
)(p
- regProp
) < numItems
; )
1063 sscanf((char *)p
, "%x", &wwin
);
1064 if ((Window
)wwin
== win
)
1068 /* Copy down the remainder to delete entry */
1073 lastHalf
= numItems
- (p
- regProp
);
1075 mch_memmove(entry
, p
, lastHalf
);
1076 numItems
= (entry
- regProp
) + lastHalf
;
1088 XChangeProperty(dpy
, RootWindow(dpy
, 0), registryProperty
,
1089 XA_STRING
, 8, PropModeReplace
, regProp
,
1090 (int)(p
- regProp
));
1094 if (regProp
!= empty_prop
)
1099 * Read the registry property. Delete it when it's formatted wrong.
1100 * Return the property in "regPropp". "empty_prop" is used when it doesn't
1102 * Return OK when successful.
1105 GetRegProp(dpy
, regPropp
, numItemsp
, domsg
)
1109 int domsg
; /* When TRUE give error message. */
1111 int result
, actualFormat
;
1114 XErrorHandler old_handler
;
1117 old_handler
= XSetErrorHandler(x_error_check
);
1118 got_x_error
= FALSE
;
1120 result
= XGetWindowProperty(dpy
, RootWindow(dpy
, 0), registryProperty
, 0L,
1121 (long)MAX_PROP_WORDS
, False
,
1122 XA_STRING
, &actualType
,
1123 &actualFormat
, numItemsp
, &bytesAfter
,
1127 (void)XSetErrorHandler(old_handler
);
1131 if (actualType
== None
)
1133 /* No prop yet. Logically equal to the empty list */
1135 *regPropp
= empty_prop
;
1139 /* If the property is improperly formed, then delete it. */
1140 if (result
!= Success
|| actualFormat
!= 8 || actualType
!= XA_STRING
)
1142 if (*regPropp
!= NULL
)
1144 XDeleteProperty(dpy
, RootWindow(dpy
, 0), registryProperty
);
1146 EMSG(_("E251: VIM instance registry property is badly formed. Deleted!"));
1153 * This procedure is invoked by the various X event loops throughout Vims when
1154 * a property changes on the communication window. This procedure reads the
1155 * property and handles command requests and responses.
1158 serverEventProc(dpy
, eventPtr
)
1160 XEvent
*eventPtr
; /* Information about event. */
1164 int result
, actualFormat
, code
;
1165 long_u numItems
, bytesAfter
;
1169 if (eventPtr
!= NULL
)
1171 if (eventPtr
->xproperty
.atom
!= commProperty
1172 || eventPtr
->xproperty
.state
!= PropertyNewValue
)
1177 * Read the comm property and delete it.
1180 result
= XGetWindowProperty(dpy
, commWindow
, commProperty
, 0L,
1181 (long)MAX_PROP_WORDS
, True
,
1182 XA_STRING
, &actualType
,
1183 &actualFormat
, &numItems
, &bytesAfter
,
1186 /* If the property doesn't exist or is improperly formed then ignore it. */
1187 if (result
!= Success
|| actualType
!= XA_STRING
|| actualFormat
!= 8)
1189 if (propInfo
!= NULL
)
1195 * Several commands and results could arrive in the property at
1196 * one time; each iteration through the outer loop handles a
1197 * single command or result.
1199 for (p
= propInfo
; (long_u
)(p
- propInfo
) < numItems
; )
1202 * Ignore leading NULs; each command or result starts with a
1203 * NUL so that no matter how badly formed a preceding command
1204 * is, we'll be able to tell that a new command/result is
1213 if ((*p
== 'c' || *p
== 'k') && (p
[1] == 0))
1216 char_u
*name
, *script
, *serial
, *end
, *res
;
1217 Bool asKeys
= *p
== 'k';
1222 * This is an incoming command from some other application.
1223 * Iterate over all of its options. Stop when we reach
1224 * the end of the property or something that doesn't look
1230 serial
= (char_u
*)"";
1233 while ((long_u
)(p
- propInfo
) < numItems
&& *p
== '-')
1238 end
= skipwhite(p
+ 2);
1240 while (vim_isxdigit(*end
))
1242 resWindow
= 16 * resWindow
+ (long_u
)hex2nr(*end
);
1245 if (end
== p
+ 2 || *end
!= ' ')
1249 p
= serial
= end
+ 1;
1250 clientWindow
= resWindow
; /* Remember in global */
1271 if (script
== NULL
|| name
== NULL
)
1275 * Initialize the result property, so that we're ready at any
1276 * time if we need to return an error.
1278 if (resWindow
!= None
)
1280 ga_init2(&reply
, 1, 100);
1282 ga_grow(&reply
, 50 + STRLEN(p_enc
));
1283 sprintf(reply
.ga_data
, "%cr%c-E %s%c-s %s%c-r ",
1284 0, 0, p_enc
, 0, serial
, 0);
1285 reply
.ga_len
= 14 + STRLEN(p_enc
) + STRLEN(serial
);
1287 ga_grow(&reply
, 50);
1288 sprintf(reply
.ga_data
, "%cr%c-s %s%c-r ", 0, 0, serial
, 0);
1289 reply
.ga_len
= 10 + STRLEN(serial
);
1293 if (serverName
!= NULL
&& STRICMP(name
, serverName
) == 0)
1295 script
= serverConvert(enc
, script
, &tofree
);
1297 server_to_input_buf(script
);
1299 res
= eval_client_expr_to_string(script
);
1302 if (resWindow
!= None
)
1305 ga_concat(&reply
, res
);
1306 else if (asKeys
== 0)
1308 ga_concat(&reply
, (char_u
*)_(e_invexprmsg
));
1309 ga_append(&reply
, 0);
1310 ga_concat(&reply
, (char_u
*)"-c 1");
1312 ga_append(&reply
, NUL
);
1313 (void)AppendPropCarefully(dpy
, resWindow
, commProperty
,
1314 reply
.ga_data
, reply
.ga_len
);
1319 else if (*p
== 'r' && p
[1] == 0)
1321 int serial
, gotSerial
;
1323 PendingCommand
*pcPtr
;
1327 * This is a reply to some command that we sent out. Iterate
1328 * over all of its options. Stop when we reach the end of the
1329 * property or something that doesn't look like an option.
1336 while ((long_u
)(p
- propInfo
) < numItems
&& *p
== '-')
1349 if (sscanf((char *)p
+ 2, " %d", &serial
) == 1)
1353 if (sscanf((char *)p
+ 2, " %d", &code
) != 1)
1366 * Give the result information to anyone who's
1369 for (pcPtr
= pendingCommands
; pcPtr
!= NULL
; pcPtr
= pcPtr
->nextPtr
)
1371 if (serial
!= pcPtr
->serial
|| pcPtr
->result
!= NULL
)
1377 res
= serverConvert(enc
, res
, &tofree
);
1379 res
= vim_strsave(res
);
1380 pcPtr
->result
= res
;
1383 pcPtr
->result
= vim_strsave((char_u
*)"");
1387 else if (*p
== 'n' && p
[1] == 0)
1393 struct ServerReply
*r
;
1397 * This is a (n)otification. Sent with serverreply_send in VimL.
1398 * Execute any autocommand and save it for later retrieval
1404 while ((long_u
)(p
- propInfo
) < numItems
&& *p
== '-')
1417 if (sscanf((char *)p
+ 2, " %x", &u
) == 1)
1431 str
= serverConvert(enc
, str
, &tofree
);
1432 if ((r
= ServerReplyFind(win
, SROP_Add
)) != NULL
)
1434 ga_concat(&(r
->strings
), str
);
1435 ga_append(&(r
->strings
), NUL
);
1441 sprintf((char *)winstr
, "0x%x", (unsigned int)win
);
1442 apply_autocmds(EVENT_REMOTEREPLY
, winstr
, str
, TRUE
, curbuf
);
1450 * Didn't recognize this thing. Just skip through the next
1451 * null character and try again.
1452 * Even if we get an 'r'(eply) we will throw it away as we
1453 * never specify (and thus expect) one
1464 * Append a given property to a given window, but set up an X error handler so
1465 * that if the append fails this procedure can return an error code rather
1466 * than having Xlib panic.
1467 * Return: 0 for OK, -1 for error
1470 AppendPropCarefully(dpy
, window
, property
, value
, length
)
1471 Display
*dpy
; /* Display on which to operate. */
1472 Window window
; /* Window whose property is to be modified. */
1473 Atom property
; /* Name of property. */
1474 char_u
*value
; /* Characters to append to property. */
1475 int length
; /* How much to append */
1477 XErrorHandler old_handler
;
1479 old_handler
= XSetErrorHandler(x_error_check
);
1480 got_x_error
= FALSE
;
1481 XChangeProperty(dpy
, window
, property
, XA_STRING
, 8,
1482 PropModeAppend
, value
, length
);
1484 (void) XSetErrorHandler(old_handler
);
1485 return got_x_error
? -1 : 0;
1490 * Another X Error handler, just used to check for errors.
1493 x_error_check(dpy
, error_event
)
1494 Display
*dpy UNUSED
;
1495 XErrorEvent
*error_event UNUSED
;
1502 * Check if "str" looks like it had a serial number appended.
1503 * Actually just checks if the name ends in a digit.
1509 int len
= STRLEN(str
);
1511 return (len
> 1 && vim_isdigit(str
[len
- 1]));
1513 #endif /* FEAT_CLIENTSERVER */