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)) \
18 && !defined(MAC_CLIENTSERVER)
21 # include <X11/Intrinsic.h>
22 # include <X11/Xatom.h>
25 # if defined(HAVE_SYS_SELECT_H) && \
26 (!defined(HAVE_SYS_TIME_H) || defined(SYS_SELECT_WITH_SYS_TIME))
27 # include <sys/select.h>
31 # ifdef HAVE_SYS_POLL_H
32 # include <sys/poll.h>
41 * This file provides procedures that implement the command server
42 * functionality of Vim when in contact with an X11 server.
44 * Adapted from TCL/TK's send command in tkSend.c of the tk 3.6 distribution.
45 * Adapted for use in Vim by Flemming Madsen. Protocol changed to that of tk 4
49 * Copyright (c) 1989-1993 The Regents of the University of California.
50 * All rights reserved.
52 * Permission is hereby granted, without written agreement and without
53 * license or royalty fees, to use, copy, modify, and distribute this
54 * software and its documentation for any purpose, provided that the
55 * above copyright notice and the following two paragraphs appear in
56 * all copies of this software.
58 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
59 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
60 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
61 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
64 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
65 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
66 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
67 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
72 * When a result is being awaited from a sent command, one of
73 * the following structures is present on a list of all outstanding
74 * sent commands. The information in the structure is used to
75 * process the result when it arrives. You're probably wondering
76 * how there could ever be multiple outstanding sent commands.
77 * This could happen if Vim instances invoke each other recursively.
78 * It's unlikely, but possible.
81 typedef struct PendingCommand
83 int serial
; /* Serial number expected in result. */
84 int code
; /* Result Code. 0 is OK */
85 char_u
*result
; /* String result for command (malloc'ed).
86 * NULL means command still pending. */
87 struct PendingCommand
*nextPtr
;
88 /* Next in list of all outstanding commands.
89 * NULL means end of list. */
92 static PendingCommand
*pendingCommands
= NULL
;
93 /* List of all commands currently
94 * being waited for. */
97 * The information below is used for communication between processes
98 * during "send" commands. Each process keeps a private window, never
99 * even mapped, with one property, "Comm". When a command is sent to
100 * an interpreter, the command is appended to the comm property of the
101 * communication window associated with the interp's process. Similarly,
102 * when a result is returned from a sent command, it is also appended
103 * to the comm property.
105 * Each command and each result takes the form of ASCII text. For a
106 * command, the text consists of a nul character followed by several
107 * nul-terminated ASCII strings. The first string consists of a
109 * "c" for an expression
112 * "n" for notification.
113 * Subsequent strings have the form "option value" where the following options
116 * -r commWindow serial
118 * This option means that a response should be sent to the window
119 * whose X identifier is "commWindow" (in hex), and the response should
120 * be identified with the serial number given by "serial" (in decimal).
121 * If this option isn't specified then the send is asynchronous and
122 * no response is sent.
125 * "Name" gives the name of the application for which the command is
126 * intended. This option must be present.
129 * Encoding name used for the text. This is the 'encoding' of the
130 * sender. The receiver may want to do conversion to his 'encoding'.
133 * "Script" is the script to be executed. This option must be
134 * present. Taken as a series of keystrokes in a "k" command where
135 * <Key>'s are expanded
137 * The options may appear in any order. The -n and -s options must be
138 * present, but -r may be omitted for asynchronous RPCs. For compatibility
139 * with future releases that may add new features, there may be additional
140 * options present; as long as they start with a "-" character, they will
143 * A result also consists of a zero character followed by several null-
144 * terminated ASCII strings. The first string consists of the single
145 * letter "r". Subsequent strings have the form "option value" where
146 * the following options are supported:
149 * Identifies the command for which this is the result. It is the
150 * same as the "serial" field from the -s option in the command. This
151 * option must be present.
154 * "Result" is the result string for the script, which may be either
155 * a result or an error message. If this field is omitted then it
156 * defaults to an empty string.
159 * 0: for OK. This is the default.
160 * 1: for error: Result is the last error
164 * Not applicable for Vim
166 * Options may appear in any order, and only the -s option must be
167 * present. As with commands, there may be additional options besides
168 * these; unknown options are ignored.
172 * Maximum size property that can be read at one time by
176 #define MAX_PROP_WORDS 100000
183 static garray_T serverReply
= { 0, 0, 0, 0, 0 };
184 enum ServerReplyOp
{ SROP_Find
, SROP_Add
, SROP_Delete
};
186 typedef int (*EndCond
) __ARGS((void *));
189 * Forward declarations for procedures defined later in this file:
192 static Window LookupName
__ARGS((Display
*dpy
, char_u
*name
, int delete, char_u
**loose
));
193 static int SendInit
__ARGS((Display
*dpy
));
194 static int DoRegisterName
__ARGS((Display
*dpy
, char_u
*name
));
195 static void DeleteAnyLingerer
__ARGS((Display
*dpy
, Window w
));
196 static int GetRegProp
__ARGS((Display
*dpy
, char_u
**regPropp
, long_u
*numItemsp
, int domsg
));
197 static int WaitForPend
__ARGS((void *p
));
198 static int WaitForReply
__ARGS((void *p
));
199 static int WindowValid
__ARGS((Display
*dpy
, Window w
));
200 static void ServerWait
__ARGS((Display
*dpy
, Window w
, EndCond endCond
, void *endData
, int localLoop
, int seconds
));
201 static struct ServerReply
*ServerReplyFind
__ARGS((Window w
, enum ServerReplyOp op
));
202 static int AppendPropCarefully
__ARGS((Display
*display
, Window window
, Atom property
, char_u
*value
, int length
));
203 static int x_error_check
__ARGS((Display
*dpy
, XErrorEvent
*error_event
));
204 static int IsSerialName
__ARGS((char_u
*name
));
206 /* Private variables for the "server" functionality */
207 static Atom registryProperty
= None
;
208 static Atom vimProperty
= None
;
209 static int got_x_error
= FALSE
;
211 static char_u
*empty_prop
= (char_u
*)""; /* empty GetRegProp() result */
214 * Associate an ASCII name with Vim. Try real hard to get a unique one.
215 * Returns FAIL or OK.
218 serverRegisterName(dpy
, name
)
219 Display
*dpy
; /* display to register with */
220 char_u
*name
; /* the name that will be used as a base */
226 res
= DoRegisterName(dpy
, name
);
232 if (res
< -1 || i
>= 1000)
234 MSG_ATTR(_("Unable to register a command server name"),
239 p
= alloc(STRLEN(name
) + 10);
245 sprintf((char *)p
, "%s%d", name
, i
++);
246 res
= DoRegisterName(dpy
, p
);
256 DoRegisterName(dpy
, name
)
261 XErrorHandler old_handler
;
262 #define MAX_NAME_LENGTH 100
263 char_u propInfo
[MAX_NAME_LENGTH
+ 20];
265 if (commProperty
== None
)
267 if (SendInit(dpy
) < 0)
272 * Make sure the name is unique, and append info about it to
273 * the registry property. It's important to lock the server
274 * here to prevent conflicting changes to the registry property.
275 * WARNING: Do not step through this while debugging, it will hangup the X
279 w
= LookupName(dpy
, name
, FALSE
, NULL
);
284 unsigned int dummyUns
;
288 * The name is currently registered. See if the commWindow
289 * associated with the name exists. If not, or if the commWindow
290 * is *our* commWindow, then just unregister the old name (this
291 * could happen if an application dies without cleaning up the
294 old_handler
= XSetErrorHandler(x_error_check
);
295 status
= XGetGeometry(dpy
, w
, &dummyWin
, &dummyInt
, &dummyInt
,
296 &dummyUns
, &dummyUns
, &dummyUns
, &dummyUns
);
297 (void)XSetErrorHandler(old_handler
);
298 if (status
!= Success
&& w
!= commWindow
)
304 (void)LookupName(dpy
, name
, /*delete=*/TRUE
, NULL
);
306 sprintf((char *)propInfo
, "%x %.*s", (int_u
)commWindow
,
307 MAX_NAME_LENGTH
, name
);
308 old_handler
= XSetErrorHandler(x_error_check
);
310 XChangeProperty(dpy
, RootWindow(dpy
, 0), registryProperty
, XA_STRING
, 8,
311 PropModeAppend
, propInfo
, STRLEN(propInfo
) + 1);
314 (void)XSetErrorHandler(old_handler
);
319 set_vim_var_string(VV_SEND_SERVER
, name
, -1);
321 serverName
= vim_strsave(name
);
323 need_maketitle
= TRUE
;
330 #if defined(FEAT_GUI) || defined(PROTO)
332 * Clean out new ID from registry and set it as comm win.
333 * Change any registered window ID.
336 serverChangeRegisteredWindow(dpy
, newwin
)
337 Display
*dpy
; /* Display to register with */
338 Window newwin
; /* Re-register to this ID */
340 char_u propInfo
[MAX_NAME_LENGTH
+ 20];
344 /* Always call SendInit() here, to make sure commWindow is marked as a Vim
346 if (SendInit(dpy
) < 0)
349 /* WARNING: Do not step through this while debugging, it will hangup the X
352 DeleteAnyLingerer(dpy
, newwin
);
353 if (serverName
!= NULL
)
355 /* Reinsert name if we was already registered */
356 (void)LookupName(dpy
, serverName
, /*delete=*/TRUE
, NULL
);
357 sprintf((char *)propInfo
, "%x %.*s",
358 (int_u
)newwin
, MAX_NAME_LENGTH
, serverName
);
359 XChangeProperty(dpy
, RootWindow(dpy
, 0), registryProperty
, XA_STRING
, 8,
360 PropModeAppend
, (char_u
*)propInfo
,
361 STRLEN(propInfo
) + 1);
368 * Send to an instance of Vim via the X display.
369 * Returns 0 for OK, negative for an error.
372 serverSendToVim(dpy
, name
, cmd
, result
, server
, asExpr
, localLoop
, silent
)
373 Display
*dpy
; /* Where to send. */
374 char_u
*name
; /* Where to send. */
375 char_u
*cmd
; /* What to send. */
376 char_u
**result
; /* Result of eval'ed expression */
377 Window
*server
; /* Actual ID of receiving app */
378 Bool asExpr
; /* Interpret as keystrokes or expr ? */
379 Bool localLoop
; /* Throw away everything but result */
380 int silent
; /* don't complain about no server */
386 static int serial
= 0; /* Running count of sent commands.
387 * Used to give each command a
388 * different serial number. */
389 PendingCommand pending
;
390 char_u
*loosename
= NULL
;
394 if (name
== NULL
|| *name
== NUL
)
395 name
= (char_u
*)"GVIM"; /* use a default name */
397 if (commProperty
== None
&& dpy
!= NULL
)
399 if (SendInit(dpy
) < 0)
403 /* Execute locally if no display or target is ourselves */
404 if (dpy
== NULL
|| (serverName
!= NULL
&& STRICMP(name
, serverName
) == 0))
410 ret
= eval_client_expr_to_string(cmd
);
414 *result
= vim_strsave((char_u
*)_(e_invexprmsg
));
420 return ret
== NULL
? -1 : 0;
423 server_to_input_buf(cmd
);
428 * Bind the server name to a communication window.
430 * Find any survivor with a serialno attached to the name if the
431 * original registrant of the wanted name is no longer present.
433 * Delete any lingering names from dead editors.
437 w
= LookupName(dpy
, name
, FALSE
, &loosename
);
438 /* Check that the window is hot */
441 if (!WindowValid(dpy
, w
))
443 LookupName(dpy
, loosename
? loosename
: name
,
444 /*DELETE=*/TRUE
, NULL
);
453 EMSG2(_(e_noserver
), name
);
456 else if (loosename
!= NULL
)
462 * Send the command to target interpreter by appending it to the
463 * comm window in the communication window.
464 * Length must be computed exactly!
467 length
= STRLEN(name
) + STRLEN(p_enc
) + STRLEN(cmd
) + 14;
469 length
= STRLEN(name
) + STRLEN(cmd
) + 10;
471 property
= (char_u
*)alloc((unsigned)length
+ 30);
474 sprintf((char *)property
, "%c%c%c-n %s%c-E %s%c-s %s",
475 0, asExpr
? 'c' : 'k', 0, name
, 0, p_enc
, 0, cmd
);
477 sprintf((char *)property
, "%c%c%c-n %s%c-s %s",
478 0, asExpr
? 'c' : 'k', 0, name
, 0, cmd
);
480 if (name
== loosename
)
482 /* Add a back reference to our comm window */
484 sprintf((char *)property
+ length
, "%c-r %x %d",
485 0, (int_u
)commWindow
, serial
);
486 /* Add length of what "-r %x %d" resulted in, skipping the NUL. */
487 length
+= STRLEN(property
+ length
+ 1) + 1;
489 res
= AppendPropCarefully(dpy
, w
, commProperty
, property
, length
+ 1);
493 EMSG(_("E248: Failed to send command to the destination program"));
497 if (!asExpr
) /* There is no answer for this - Keys are sent async */
501 * Register the fact that we're waiting for a command to
502 * complete (this is needed by SendEventProc and by
503 * AppendErrorProc to pass back the command's results).
505 pending
.serial
= serial
;
507 pending
.result
= NULL
;
508 pending
.nextPtr
= pendingCommands
;
509 pendingCommands
= &pending
;
511 ServerWait(dpy
, w
, WaitForPend
, &pending
, localLoop
, 600);
514 * Unregister the information about the pending command
515 * and return the result.
517 if (pendingCommands
== &pending
)
518 pendingCommands
= pending
.nextPtr
;
521 PendingCommand
*pcPtr
;
523 for (pcPtr
= pendingCommands
; pcPtr
!= NULL
; pcPtr
= pcPtr
->nextPtr
)
524 if (pcPtr
->nextPtr
== &pending
)
526 pcPtr
->nextPtr
= pending
.nextPtr
;
531 *result
= pending
.result
;
533 vim_free(pending
.result
);
535 return pending
.code
== 0 ? 0 : -1;
542 PendingCommand
*pending
= (PendingCommand
*) p
;
543 return pending
->result
!= NULL
;
547 * Return TRUE if window "w" exists and has a "Vim" property on it.
554 XErrorHandler old_handler
;
559 old_handler
= XSetErrorHandler(x_error_check
);
561 plist
= XListProperties(dpy
, w
, &numProp
);
563 XSetErrorHandler(old_handler
);
564 if (plist
== NULL
|| got_x_error
)
567 for (i
= 0; i
< numProp
; i
++)
568 if (plist
[i
] == vimProperty
)
578 * Enter a loop processing X events & polling chars until we see a result
581 ServerWait(dpy
, w
, endCond
, endData
, localLoop
, seconds
)
593 XPropertyEvent
*e
= (XPropertyEvent
*)&event
;
594 # define SEND_MSEC_POLL 50
597 while (endCond(endData
) == 0)
600 if (seconds
>= 0 && (now
- start
) >= seconds
)
605 if (!WindowValid(dpy
, w
))
608 * Sometimes the PropertyChange event doesn't come.
609 * This can be seen in eg: vim -c 'echo remote_expr("gvim", "3+2")'
611 serverEventProc(dpy
, NULL
);
615 /* Just look out for the answer without calling back into Vim */
619 fds
.fd
= ConnectionNumber(dpy
);
621 if (poll(&fds
, 1, SEND_MSEC_POLL
) < 0)
628 tv
.tv_usec
= SEND_MSEC_POLL
* 1000;
630 FD_SET(ConnectionNumber(dpy
), &fds
);
631 if (select(ConnectionNumber(dpy
) + 1, &fds
, NULL
, NULL
, &tv
) < 0)
634 while (XEventsQueued(dpy
, QueuedAfterReading
) > 0)
636 XNextEvent(dpy
, &event
);
637 if (event
.type
== PropertyNotify
&& e
->window
== commWindow
)
638 serverEventProc(dpy
, &event
);
645 ui_delay((long)SEND_MSEC_POLL
, TRUE
);
653 * Fetch a list of all the Vim instance names currently registered for the
656 * Returns a newline separated list in allocated memory or NULL.
659 serverGetVimNames(dpy
)
669 if (registryProperty
== None
)
671 if (SendInit(dpy
) < 0)
674 ga_init2(&ga
, 1, 100);
677 * Read the registry property.
679 if (GetRegProp(dpy
, ®Prop
, &numItems
, TRUE
) == FAIL
)
683 * Scan all of the names out of the property.
685 ga_init2(&ga
, 1, 100);
686 for (p
= regProp
; (p
- regProp
) < numItems
; p
++)
689 while (*p
!= 0 && !isspace(*p
))
694 sscanf((char *)entry
, "%x", &w
);
695 if (WindowValid(dpy
, (Window
)w
))
697 ga_concat(&ga
, p
+ 1);
698 ga_concat(&ga
, (char_u
*)"\n");
704 if (regProp
!= empty_prop
)
710 /* ----------------------------------------------------------
714 static struct ServerReply
*
715 ServerReplyFind(w
, op
)
717 enum ServerReplyOp op
;
719 struct ServerReply
*p
;
720 struct ServerReply e
;
723 p
= (struct ServerReply
*) serverReply
.ga_data
;
724 for (i
= 0; i
< serverReply
.ga_len
; i
++, p
++)
727 if (i
>= serverReply
.ga_len
)
730 if (p
== NULL
&& op
== SROP_Add
)
732 if (serverReply
.ga_growsize
== 0)
733 ga_init2(&serverReply
, sizeof(struct ServerReply
), 1);
734 if (ga_grow(&serverReply
, 1) == OK
)
736 p
= ((struct ServerReply
*) serverReply
.ga_data
)
737 + serverReply
.ga_len
;
739 ga_init2(&e
.strings
, 1, 100);
740 mch_memmove(p
, &e
, sizeof(e
));
741 serverReply
.ga_len
++;
744 else if (p
!= NULL
&& op
== SROP_Delete
)
746 ga_clear(&p
->strings
);
747 mch_memmove(p
, p
+ 1, (serverReply
.ga_len
- i
- 1) * sizeof(*p
));
748 serverReply
.ga_len
--;
755 * Convert string to windowid.
756 * Issue an error if the id is invalid.
764 sscanf((char *)str
, "0x%x", &id
);
766 EMSG2(_("E573: Invalid server id used: %s"), str
);
772 * Send a reply string (notification) to client with id "name".
773 * Return -1 if the window is invalid.
776 serverSendReply(name
, str
)
783 Display
*dpy
= X_DISPLAY
;
784 Window win
= serverStrToWin(name
);
786 if (commProperty
== None
)
788 if (SendInit(dpy
) < 0)
791 if (!WindowValid(dpy
, win
))
795 length
= STRLEN(p_enc
) + STRLEN(str
) + 14;
797 length
= STRLEN(str
) + 10;
799 if ((property
= (char_u
*)alloc((unsigned)length
+ 30)) != NULL
)
802 sprintf((char *)property
, "%cn%c-E %s%c-n %s%c-w %x",
803 0, 0, p_enc
, 0, str
, 0, (unsigned int)commWindow
);
805 sprintf((char *)property
, "%cn%c-n %s%c-w %x",
806 0, 0, str
, 0, (unsigned int)commWindow
);
808 /* Add length of what "%x" resulted in. */
809 length
+= STRLEN(property
+ length
);
810 res
= AppendPropCarefully(dpy
, win
, commProperty
, property
, length
+ 1);
821 Window
*w
= (Window
*) p
;
822 return ServerReplyFind(*w
, SROP_Find
) != NULL
;
826 * Wait for replies from id (win)
827 * Return 0 and the malloc'ed string when a reply is available.
828 * Return -1 if the window becomes invalid while waiting.
831 serverReadReply(dpy
, win
, str
, localLoop
)
839 struct ServerReply
*p
;
841 ServerWait(dpy
, win
, WaitForReply
, &win
, localLoop
, -1);
843 if ((p
= ServerReplyFind(win
, SROP_Find
)) != NULL
&& p
->strings
.ga_len
> 0)
845 *str
= vim_strsave(p
->strings
.ga_data
);
846 len
= STRLEN(*str
) + 1;
847 if (len
< p
->strings
.ga_len
)
849 s
= (char_u
*) p
->strings
.ga_data
;
850 mch_memmove(s
, s
+ len
, p
->strings
.ga_len
- len
);
851 p
->strings
.ga_len
-= len
;
855 /* Last string read. Remove from list */
856 ga_clear(&p
->strings
);
857 ServerReplyFind(win
, SROP_Delete
);
865 * Check for replies from id (win).
866 * Return TRUE and a non-malloc'ed string if there is. Else return FALSE.
869 serverPeekReply(dpy
, win
, str
)
874 struct ServerReply
*p
;
876 if ((p
= ServerReplyFind(win
, SROP_Find
)) != NULL
&& p
->strings
.ga_len
> 0)
879 *str
= p
->strings
.ga_data
;
882 if (!WindowValid(dpy
, win
))
889 * Initialize the communication channels for sending commands and receiving
896 XErrorHandler old_handler
;
899 * Create the window used for communication, and set up an
900 * event handler for it.
902 old_handler
= XSetErrorHandler(x_error_check
);
905 if (commProperty
== None
)
906 commProperty
= XInternAtom(dpy
, "Comm", False
);
907 if (vimProperty
== None
)
908 vimProperty
= XInternAtom(dpy
, "Vim", False
);
909 if (registryProperty
== None
)
910 registryProperty
= XInternAtom(dpy
, "VimRegistry", False
);
912 if (commWindow
== None
)
914 commWindow
= XCreateSimpleWindow(dpy
, XDefaultRootWindow(dpy
),
915 getpid(), 0, 10, 10, 0,
916 WhitePixel(dpy
, DefaultScreen(dpy
)),
917 WhitePixel(dpy
, DefaultScreen(dpy
)));
918 XSelectInput(dpy
, commWindow
, PropertyChangeMask
);
919 /* WARNING: Do not step through this while debugging, it will hangup
922 DeleteAnyLingerer(dpy
, commWindow
);
926 /* Make window recognizable as a vim window */
927 XChangeProperty(dpy
, commWindow
, vimProperty
, XA_STRING
,
928 8, PropModeReplace
, (char_u
*)VIM_VERSION_SHORT
,
929 (int)STRLEN(VIM_VERSION_SHORT
) + 1);
932 (void)XSetErrorHandler(old_handler
);
934 return got_x_error
? -1 : 0;
938 * Given a server name, see if the name exists in the registry for a
939 * particular display.
941 * If the given name is registered, return the ID of the window associated
942 * with the name. If the name isn't registered, then return 0.
945 * If the registry property is improperly formed, then it is deleted.
946 * If "delete" is non-zero, then if the named server is found it is
947 * removed from the registry property.
950 LookupName(dpy
, name
, delete, loose
)
951 Display
*dpy
; /* Display whose registry to check. */
952 char_u
*name
; /* Name of a server. */
953 int delete; /* If non-zero, delete info about name. */
954 char_u
**loose
; /* Do another search matching -999 if not found
955 Return result here if a match is found */
957 char_u
*regProp
, *entry
;
963 * Read the registry property.
965 if (GetRegProp(dpy
, ®Prop
, &numItems
, FALSE
) == FAIL
)
969 * Scan the property for the desired name.
971 returnValue
= (int_u
)None
;
972 entry
= NULL
; /* Not needed, but eliminates compiler warning. */
973 for (p
= regProp
; (p
- regProp
) < numItems
; )
976 while (*p
!= 0 && !isspace(*p
))
978 if (*p
!= 0 && STRICMP(name
, p
+ 1) == 0)
980 sscanf((char *)entry
, "%x", &returnValue
);
988 if (loose
!= NULL
&& returnValue
== (int_u
)None
&& !IsSerialName(name
))
990 for (p
= regProp
; (p
- regProp
) < numItems
; )
993 while (*p
!= 0 && !isspace(*p
))
995 if (*p
!= 0 && IsSerialName(p
+ 1)
996 && STRNICMP(name
, p
+ 1, STRLEN(name
)) == 0)
998 sscanf((char *)entry
, "%x", &returnValue
);
999 *loose
= vim_strsave(p
+ 1);
1009 * Delete the property, if that is desired (copy down the
1010 * remainder of the registry property to overlay the deleted
1011 * info, then rewrite the property).
1013 if (delete && returnValue
!= (int_u
)None
)
1020 count
= numItems
- (p
- regProp
);
1022 mch_memmove(entry
, p
, count
);
1023 XChangeProperty(dpy
, RootWindow(dpy
, 0), registryProperty
, XA_STRING
,
1024 8, PropModeReplace
, regProp
,
1025 (int)(numItems
- (p
- entry
)));
1029 if (regProp
!= empty_prop
)
1031 return (Window
)returnValue
;
1035 * Delete any lingering occurrence of window id. We promise that any
1036 * occurrence is not ours since it is not yet put into the registry (by us)
1038 * This is necessary in the following scenario:
1039 * 1. There is an old windowid for an exit'ed vim in the registry
1040 * 2. We get that id for our commWindow but only want to send, not register.
1041 * 3. The window will mistakenly be regarded valid because of own commWindow
1044 DeleteAnyLingerer(dpy
, win
)
1045 Display
*dpy
; /* Display whose registry to check. */
1046 Window win
; /* Window to remove */
1048 char_u
*regProp
, *entry
= NULL
;
1054 * Read the registry property.
1056 if (GetRegProp(dpy
, ®Prop
, &numItems
, FALSE
) == FAIL
)
1059 /* Scan the property for the window id. */
1060 for (p
= regProp
; (p
- regProp
) < numItems
; )
1064 sscanf((char *)p
, "%x", &wwin
);
1065 if ((Window
)wwin
== win
)
1069 /* Copy down the remainder to delete entry */
1074 lastHalf
= numItems
- (p
- regProp
);
1076 mch_memmove(entry
, p
, lastHalf
);
1077 numItems
= (entry
- regProp
) + lastHalf
;
1089 XChangeProperty(dpy
, RootWindow(dpy
, 0), registryProperty
,
1090 XA_STRING
, 8, PropModeReplace
, regProp
,
1091 (int)(p
- regProp
));
1095 if (regProp
!= empty_prop
)
1100 * Read the registry property. Delete it when it's formatted wrong.
1101 * Return the property in "regPropp". "empty_prop" is used when it doesn't
1103 * Return OK when successful.
1106 GetRegProp(dpy
, regPropp
, numItemsp
, domsg
)
1110 int domsg
; /* When TRUE give error message. */
1112 int result
, actualFormat
;
1115 XErrorHandler old_handler
;
1118 old_handler
= XSetErrorHandler(x_error_check
);
1119 got_x_error
= FALSE
;
1121 result
= XGetWindowProperty(dpy
, RootWindow(dpy
, 0), registryProperty
, 0L,
1122 (long)MAX_PROP_WORDS
, False
,
1123 XA_STRING
, &actualType
,
1124 &actualFormat
, numItemsp
, &bytesAfter
,
1128 (void)XSetErrorHandler(old_handler
);
1132 if (actualType
== None
)
1134 /* No prop yet. Logically equal to the empty list */
1136 *regPropp
= empty_prop
;
1140 /* If the property is improperly formed, then delete it. */
1141 if (result
!= Success
|| actualFormat
!= 8 || actualType
!= XA_STRING
)
1143 if (*regPropp
!= NULL
)
1145 XDeleteProperty(dpy
, RootWindow(dpy
, 0), registryProperty
);
1147 EMSG(_("E251: VIM instance registry property is badly formed. Deleted!"));
1154 * This procedure is invoked by the various X event loops throughout Vims when
1155 * a property changes on the communication window. This procedure reads the
1156 * property and handles command requests and responses.
1159 serverEventProc(dpy
, eventPtr
)
1161 XEvent
*eventPtr
; /* Information about event. */
1165 int result
, actualFormat
, code
;
1166 long_u numItems
, bytesAfter
;
1170 if (eventPtr
!= NULL
)
1172 if (eventPtr
->xproperty
.atom
!= commProperty
1173 || eventPtr
->xproperty
.state
!= PropertyNewValue
)
1178 * Read the comm property and delete it.
1181 result
= XGetWindowProperty(dpy
, commWindow
, commProperty
, 0L,
1182 (long)MAX_PROP_WORDS
, True
,
1183 XA_STRING
, &actualType
,
1184 &actualFormat
, &numItems
, &bytesAfter
,
1187 /* If the property doesn't exist or is improperly formed then ignore it. */
1188 if (result
!= Success
|| actualType
!= XA_STRING
|| actualFormat
!= 8)
1190 if (propInfo
!= NULL
)
1196 * Several commands and results could arrive in the property at
1197 * one time; each iteration through the outer loop handles a
1198 * single command or result.
1200 for (p
= propInfo
; (p
- propInfo
) < numItems
; )
1203 * Ignore leading NULs; each command or result starts with a
1204 * NUL so that no matter how badly formed a preceding command
1205 * is, we'll be able to tell that a new command/result is
1214 if ((*p
== 'c' || *p
== 'k') && (p
[1] == 0))
1217 char_u
*name
, *script
, *serial
, *end
, *res
;
1218 Bool asKeys
= *p
== 'k';
1223 * This is an incoming command from some other application.
1224 * Iterate over all of its options. Stop when we reach
1225 * the end of the property or something that doesn't look
1231 serial
= (char_u
*)"";
1234 while (p
- propInfo
< numItems
&& *p
== '-')
1239 end
= skipwhite(p
+ 2);
1241 while (vim_isxdigit(*end
))
1243 resWindow
= 16 * resWindow
+ (long_u
)hex2nr(*end
);
1246 if (end
== p
+ 2 || *end
!= ' ')
1250 p
= serial
= end
+ 1;
1251 clientWindow
= resWindow
; /* Remember in global */
1272 if (script
== NULL
|| name
== NULL
)
1276 * Initialize the result property, so that we're ready at any
1277 * time if we need to return an error.
1279 if (resWindow
!= None
)
1281 ga_init2(&reply
, 1, 100);
1283 ga_grow(&reply
, 50 + STRLEN(p_enc
));
1284 sprintf(reply
.ga_data
, "%cr%c-E %s%c-s %s%c-r ",
1285 0, 0, p_enc
, 0, serial
, 0);
1286 reply
.ga_len
= 14 + STRLEN(p_enc
) + STRLEN(serial
);
1288 ga_grow(&reply
, 50);
1289 sprintf(reply
.ga_data
, "%cr%c-s %s%c-r ", 0, 0, serial
, 0);
1290 reply
.ga_len
= 10 + STRLEN(serial
);
1294 if (serverName
!= NULL
&& STRICMP(name
, serverName
) == 0)
1296 script
= serverConvert(enc
, script
, &tofree
);
1298 server_to_input_buf(script
);
1300 res
= eval_client_expr_to_string(script
);
1303 if (resWindow
!= None
)
1306 ga_concat(&reply
, res
);
1307 else if (asKeys
== 0)
1309 ga_concat(&reply
, (char_u
*)_(e_invexprmsg
));
1310 ga_append(&reply
, 0);
1311 ga_concat(&reply
, (char_u
*)"-c 1");
1313 ga_append(&reply
, NUL
);
1314 (void)AppendPropCarefully(dpy
, resWindow
, commProperty
,
1315 reply
.ga_data
, reply
.ga_len
);
1320 else if (*p
== 'r' && p
[1] == 0)
1322 int serial
, gotSerial
;
1324 PendingCommand
*pcPtr
;
1328 * This is a reply to some command that we sent out. Iterate
1329 * over all of its options. Stop when we reach the end of the
1330 * property or something that doesn't look like an option.
1337 while ((p
-propInfo
) < numItems
&& *p
== '-')
1350 if (sscanf((char *)p
+ 2, " %d", &serial
) == 1)
1354 if (sscanf((char *)p
+ 2, " %d", &code
) != 1)
1367 * Give the result information to anyone who's
1370 for (pcPtr
= pendingCommands
; pcPtr
!= NULL
; pcPtr
= pcPtr
->nextPtr
)
1372 if (serial
!= pcPtr
->serial
|| pcPtr
->result
!= NULL
)
1378 res
= serverConvert(enc
, res
, &tofree
);
1380 res
= vim_strsave(res
);
1381 pcPtr
->result
= res
;
1384 pcPtr
->result
= vim_strsave((char_u
*)"");
1388 else if (*p
== 'n' && p
[1] == 0)
1394 struct ServerReply
*r
;
1398 * This is a (n)otification. Sent with serverreply_send in VimL.
1399 * Execute any autocommand and save it for later retrieval
1405 while ((p
-propInfo
) < numItems
&& *p
== '-')
1418 if (sscanf((char *)p
+ 2, " %x", &u
) == 1)
1432 str
= serverConvert(enc
, str
, &tofree
);
1433 if ((r
= ServerReplyFind(win
, SROP_Add
)) != NULL
)
1435 ga_concat(&(r
->strings
), str
);
1436 ga_append(&(r
->strings
), NUL
);
1442 sprintf((char *)winstr
, "0x%x", (unsigned int)win
);
1443 apply_autocmds(EVENT_REMOTEREPLY
, winstr
, str
, TRUE
, curbuf
);
1451 * Didn't recognize this thing. Just skip through the next
1452 * null character and try again.
1453 * Even if we get an 'r'(eply) we will throw it away as we
1454 * never specify (and thus expect) one
1465 * Append a given property to a given window, but set up an X error handler so
1466 * that if the append fails this procedure can return an error code rather
1467 * than having Xlib panic.
1468 * Return: 0 for OK, -1 for error
1471 AppendPropCarefully(dpy
, window
, property
, value
, length
)
1472 Display
*dpy
; /* Display on which to operate. */
1473 Window window
; /* Window whose property is to be modified. */
1474 Atom property
; /* Name of property. */
1475 char_u
*value
; /* Characters to append to property. */
1476 int length
; /* How much to append */
1478 XErrorHandler old_handler
;
1480 old_handler
= XSetErrorHandler(x_error_check
);
1481 got_x_error
= FALSE
;
1482 XChangeProperty(dpy
, window
, property
, XA_STRING
, 8,
1483 PropModeAppend
, value
, length
);
1485 (void) XSetErrorHandler(old_handler
);
1486 return got_x_error
? -1 : 0;
1491 * Another X Error handler, just used to check for errors.
1495 x_error_check(dpy
, error_event
)
1497 XErrorEvent
*error_event
;
1504 * Check if "str" looks like it had a serial number appended.
1505 * Actually just checks if the name ends in a digit.
1511 int len
= STRLEN(str
);
1513 return (len
> 1 && vim_isdigit(str
[len
- 1]));
1515 #endif /* FEAT_CLIENTSERVER */