home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / lucid / lemacs-19.6 / src / editorside.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-29  |  132.6 KB  |  4,821 lines

  1. /****************************************************************************
  2.  ***
  3.  ***    Copyright ⌐ 1990 by Sun/Lucid,  All Rights Reserved.
  4.  ***    Copyright ⌐ 1991-1993 by Lucid, Inc.  All Rights Reserved.
  5.  ***
  6.  *****************************************************************************/
  7.  
  8. #include "config.h"
  9.  
  10. #ifdef ENERGIZE     /* whole file */
  11.  
  12. #include "lisp.h"
  13. #include "events.h"
  14.  
  15. #include <stdio.h>
  16. #include <sys/time.h>
  17. #include <sys/types.h>        /* some typedefs are used in sys/file.h */
  18. #include <sys/file.h>
  19. #include <sys/fcntl.h>
  20. #include <sys/ioctl.h>        /* if not provided BLOCK_INPUT loses */
  21. #include <signal.h>        /* must be before xterm.c ?? */
  22. #include <string.h>
  23. #include <errno.h>
  24.  
  25. /* editing and buffer operations */
  26. #include "buffer.h" 
  27. #include "extents.h"
  28. #include "process.h"
  29.  
  30. /* screen management */
  31. #include "xterm.h"
  32. #include "screen.h"
  33. #include "window.h" 
  34.  
  35. #include <lwlib.h>
  36.  
  37. /* Display Context for the icons */ 
  38. #include <X11/Intrinsic.h>
  39. #include <X11/StringDefs.h>
  40. #include <Xm/DialogS.h>
  41.  
  42. /* Energize editor requests and I/O operations */
  43. #include "editorside.h"
  44.  
  45. #include <editorreq.h>
  46. #include <editorconn.h>
  47. #include <editoption.h>
  48.  
  49. #include "extents-data.h"
  50.  
  51.  
  52. extern void CWriteQueryChoicesRequest ();
  53. extern void CWriteExecuteChoicesRequest();
  54. extern void CWriteSheetRequest();
  55. extern void CWriteSetControlRequest();
  56. extern void CWriteChoice();
  57. extern void CWriteProtocol();
  58. extern int  CGetPortNumber();
  59. extern int  CReadSomeMore(Connection*, int);
  60. extern void NewPixmapImage();
  61. extern void NewAttributeImage();
  62.  
  63.  
  64. /************** Typedefs and Structs ***********************/
  65.  
  66. /* structure argument used by the next mapping function */
  67. typedef struct 
  68. {
  69.   BufferInfo *binfo;
  70.   int n_extents;
  71. } binfo_and_n_extents;
  72.  
  73. typedef struct 
  74. {
  75.   BufferInfo*     binfo;
  76.   int         state;
  77.   int        tell_energize;
  78. } binfo_and_state;
  79.  
  80. struct reply_wait {
  81.   int        serial;
  82.   EId        objectId;
  83.   EId        genericId;
  84.   EId        itemId;
  85.   char        answered_p;
  86.   char        status;
  87.   char*        message;
  88.   Lisp_Object    menu_result;
  89.   Lisp_Object    only_name;
  90.   struct reply_wait*    next;
  91. };
  92.  
  93. static struct reply_wait*
  94. global_reply_wait;
  95.  
  96. Lisp_Object Venergize_kernel_busy;
  97. Lisp_Object Qenergize_kernel_busy;
  98. Lisp_Object Venergize_attributes_mapping;
  99. Lisp_Object Venergize_kernel_busy_hook;
  100. Lisp_Object Venergize_menu_update_hook;
  101. Lisp_Object Qenergize_extent_data;
  102.  
  103. /*static int energize_font_lock_p;*/
  104.  
  105.  
  106. /************************ Functions ********************/
  107. extern Lisp_Object Venergize_kernel_busy;
  108. extern Lisp_Object make_extent_for_data
  109. (BufferInfo *binfo, Energize_Extent_Data *ext, int from, int to, int set_endpoints);
  110.  
  111. static int
  112. wait_for_reply (struct reply_wait* rw);
  113. static Energize_Extent_Data *extent_to_data (Lisp_Object extent_obj);
  114. static char *copy_string (char *s);
  115. Lisp_Object word_to_lisp (unsigned int item);
  116. unsigned int lisp_to_word (Lisp_Object obj);
  117. static void *get_object (EId id, BufferInfo *binfo);
  118. static void put_object (EId id, BufferInfo *binfo, void *object);
  119. static void remove_object (EId id, BufferInfo *binfo);
  120. static void free_object (void *key, void *contents, void *arg);
  121. static GDataClass *alloc_GDataclass (EId id, BufferInfo *binfo);
  122. static void free_GDataclass (GDataClass *cl, BufferInfo *binfo);
  123. static GenericData *alloc_GenericData (EId id, GDataClass *cl, 
  124.                                        BufferInfo *binfo);
  125. static void free_GenericData (GenericData *gen, BufferInfo *binfo);
  126. static Energize_Extent_Data *alloc_Energize_Extent_Data (EId id, BufferInfo *binfo);
  127. static void free_Energize_Extent_Data (Energize_Extent_Data *ext, BufferInfo *binfo, 
  128.                               enum Energize_Object_Free_Type free_type);
  129. void energize_extent_finalization (EXTENT extent);
  130. static BufferInfo *alloc_BufferInfo
  131. (EId id, Lisp_Object name, Lisp_Object filename, 
  132.  char *class_str, Editor *editor, Window win);
  133. static void free_buffer_info (BufferInfo *binfo);
  134. static BufferInfo *get_buffer_info_for_emacs_buffer (Lisp_Object emacs_buf, Editor *editor);
  135. static long get_energize_buffer_id (Lisp_Object emacs_buf);
  136. static char *kernel_buffer_type_to_elisp_type (char *kernel_type);
  137. static Lisp_Object get_buffer_type_for_emacs_buffer 
  138. (Lisp_Object emacs_buf, Editor *editor);
  139. static Lisp_Object set_buffer_type_for_emacs_buffer 
  140. (Lisp_Object emacs_buf, Editor *editor, Lisp_Object type);
  141. static BufferInfo *get_buffer_info_for_id (EId id, Editor *editor);
  142. static void put_buffer_info 
  143. (EId id, Lisp_Object emacs_buf, BufferInfo *binfo, Editor *editor);
  144. static void remove_buffer_info (EId id, Lisp_Object emacs_buf, Editor *editor);
  145. static void Post (char *msg);
  146. static void Post1 (char *msg, int a1);
  147. static void Post2 (char *msg, int a1, int a2);
  148. static EmacsPos EmacsPosForEnergizePos (EnergizePos energizePos);
  149. static EnergizePos EnergizePosForEmacsPos (EmacsPos emacs_pos);
  150. Lisp_Object Fenergize_update_menubar (Lisp_Object screen);
  151. Lisp_Object Fenergize_extent_menu_p (Lisp_Object extent_obj);
  152. void free_zombie_bitmaps (void);
  153. static void ParseClasses (Connection *conn, unsigned int number, 
  154.                           BufferInfo *binfo, unsigned int modify_ok);
  155. static void ParseGenerics (Connection *conn, unsigned int number, 
  156.                            BufferInfo *binfo, unsigned int modify_ok);
  157. static void insert_one_extent (CExtent *ptr, BufferInfo *binfo, int modify_ok);
  158. static void ParseExtents (Connection *conn, unsigned int number, 
  159.                           BufferInfo *binfo, unsigned int modify_ok, 
  160.                           int extent_offset);
  161. static int string_buffer_compare (char *string, int string_len, 
  162.                                   struct buffer *buf, int bufpos);
  163. static void rename_the_buffer (Lisp_Object new_name);
  164. static void ParseBuffer (Connection *conn, CBuffer *cbu, Editor *editor, 
  165.                          EnergizePos delete_from, EnergizePos delete_to, 
  166.                          Window win, int relative_p);
  167. static void forget_buffer (BufferInfo *binfo);
  168. static void WriteExtent (Connection *conn, Energize_Extent_Data *ext, 
  169.                   unsigned int start, unsigned int end);
  170. static char *get_buffer_as_string (unsigned int *len);
  171. static int write_an_extent (Lisp_Object extent_obj, void *arg);
  172. static void SaveBufferToEnergize (BufferInfo *binfo);
  173. static Lisp_Object
  174. get_energize_menu (Lisp_Object buffer, Lisp_Object extent_obj, int selection_p,
  175.            Lisp_Object only_name);
  176. static int something_answered_p (void *arg);
  177. void wait_delaying_user_input (int (*)(), void*);
  178. Lisp_Object Fenergize_request_menu (Lisp_Object buffer, Lisp_Object extent);
  179. Lisp_Object Fenergize_list_menu (Lisp_Object buffer, Lisp_Object extent_obj,
  180.                  Lisp_Object selection_p,
  181.                  Lisp_Object only_name);
  182. Lisp_Object Fenergize_execute_menu_item 
  183. (Lisp_Object buffer, Lisp_Object extent_obj, 
  184.  Lisp_Object item, Lisp_Object selection, Lisp_Object no_confirm);
  185. Lisp_Object Fenergize_buffer_type (Lisp_Object buffer);
  186. Lisp_Object Fset_energize_buffer_type_internal (Lisp_Object buffer, 
  187.                                                 Lisp_Object type);
  188. Lisp_Object Fenergize_buffer_p (Lisp_Object buffer);
  189. Lisp_Object Fenergize_buffer_id (Lisp_Object buffer);
  190. Lisp_Object Fenergize_request_kill_buffer (Lisp_Object buffer);
  191. static void HandleControlChange (Widget, EId sheet_id, void* arg);
  192. static void HandleLoggingRequest (Editor *editor, CLoggingRequest *creq);
  193. static void HandleNewBufferRequest (Editor *editor, CNewBufferRequest *creq);
  194. static void HandleModifyBufferRequest (Editor *editor, CModifyBufferRequest *creq);
  195. static void MakeBufferAndExtentVisible (Lisp_Object list, Lisp_Object go_there);
  196. static void HandleEnsureVisibleRequest (Editor *editor, CEnsureVisibleRequest *creq);
  197. static void HandleEnsureManyVisibleRequest (Editor *editor, CEnsureManyVisibleRequest *creq);
  198. static void HandleProposeChoicesRequest (Editor *editor, CProposeChoicesRequest *creq);
  199. static void unmodify_buffer_and_kill_it (Lisp_Object buffer);
  200. static void HandleKillBufferRequest (Editor *editor, CKillBufferRequest *creq);
  201. static void HandleRemoveExtentsRequest (Editor *editor, CRemoveExtentsRequest *creq);
  202. static void HandleSaveBufferRequest (Editor *editor, CSaveBufferRequest *creq);
  203. static void HandleSetModifiedFlagRequest (Editor *editor, CSetModifiedFlagRequest *creq);
  204. static void add_in_list_of_ids (int **ids, int *n_ids, int id);
  205. static void remove_from_list_of_ids (int **ids, int *n_ids, int id);
  206. static void HandleBufferSheetRequest (Editor *editor, CSheetRequest *sreq, EId buffer_id);
  207. static void HandlePostitRequest (Editor *editor, CGenericRequest *preq);
  208. static void HandleShowBusyRequest (Editor *editor, CGenericRequest *preq);
  209. static void add_in_connection_input_buffer (Connection *conn, char *s, int l);
  210. static Lisp_Object ProcessJustOneEnergizeRequest (void);
  211. static Lisp_Object ProcessEnergizeRequest1 (void);
  212. static void setup_connection (Editor *ed, unsigned int id1, unsigned int id2);
  213. static Connection *EditorSideConnection (Editor *editor, int fdin, int fdout);
  214. Lisp_Object Fhandle_energize_request (Lisp_Object proc, Lisp_Object string);
  215. static void ConnectToEnergize (char *server_str, char *arg);
  216. static void CloseConnection (void);
  217. Lisp_Object Fconnect_to_energize_internal (Lisp_Object server_name, 
  218.                                            Lisp_Object energize_arg);
  219. Lisp_Object Fclose_connection_to_energize (void);
  220. static void SendBufferModificationState (Editor *editor, BufferInfo *binfo, 
  221.                                          int flag);
  222. static int CheckBufferLock (Editor *editor, BufferInfo *binfo);
  223. static Lisp_Object buffer_locked_p (Lisp_Object buffer);
  224. static int notify_extent_modified (Lisp_Object extent_obj, void *arg);
  225. static int ceiwme_lower_mf (EXTENT extent, void *arg);
  226. static int ceiwme_upper_mf (EXTENT extent, void *arg);
  227. static void coerce_endpoints_to_be_inside_warn_on_modify_extents 
  228. (int *from_ptr,  int *to_ptr,  struct buffer *b);
  229. static void mark_all_extents_as_unmodified (BufferInfo *binfo);
  230. Lisp_Object Fsend_buffer_modified_request 
  231. (Lisp_Object state, Lisp_Object from, Lisp_Object to);
  232. Lisp_Object Fenergize_barf_if_buffer_locked (void);
  233. Lisp_Object Fenergize_send_region (Lisp_Object start, Lisp_Object end);
  234. Lisp_Object Fconnected_to_energize_p (void);
  235. Lisp_Object Fenergize_user_input_buffer_mark (void);
  236. Lisp_Object Fenergize_query_buffer (Lisp_Object filename, Lisp_Object just_ask);
  237. static int get_energize_connection_and_buffer_id (Lisp_Object buffer, void **conn_ptr, long *buffer_id_ptr);
  238. static int get_energize_connection_and_current_buffer_id (void **conn_ptr, long *buffer_id_ptr);
  239. int *get_psheets_for_buffer (Lisp_Object buffer, int *count_ptr);
  240. void notify_that_sheet_has_been_hidden (EId id);
  241. void syms_of_editorside (void);
  242.  
  243.  
  244.  
  245. /**************************** Variables *****************************/
  246.  
  247. /* debugging variable */
  248. int ignore_kernel;
  249.  
  250. Lisp_Object Venergize_kernel_modification_hook;
  251. Lisp_Object Venergize_create_buffer_hook;
  252.  
  253. Lisp_Object Venergize_buffer_modified_hook;
  254. Lisp_Object Qenergize_buffer_modified_hook;
  255. Lisp_Object Qfirst_change_function;
  256. Lisp_Object Qbefore_change_function;
  257. Lisp_Object Qafter_change_function;
  258. Lisp_Object Qbuffer_locked_by_kernel;
  259. Lisp_Object Qdefault_directory;
  260. Lisp_Object Qbuffer_file_name;
  261. Lisp_Object Qenergize_user_input_buffer_mark;
  262. Lisp_Object Qenergize_user_input_mode;
  263. Lisp_Object Qenergize_make_many_buffers_visible;
  264. Lisp_Object Qbuffer_undo_list;
  265.  
  266. extern Lisp_Object Qerror_conditions, Qerror_message;
  267.  
  268. int inside_parse_buffer;
  269. Lisp_Object Qinside_parse_buffer;
  270.  
  271. /* List of all buffers currently managed by Energize.  This is
  272. Staticpro'ed so that they don't get GC'ed from under us. */
  273. static Lisp_Object energize_buffers_list;
  274.  
  275. static Editor *energize_connection;
  276. static protocol_edit_options *peo;
  277.  
  278. static int request_serial_number;
  279.  
  280. extern int current_debuggerpanel_exposed_p;
  281. extern int desired_debuggerpanel_exposed_p;
  282. extern int debuggerpanel_sheet;
  283.  
  284. /* extern DisplayContext *display_context; */
  285.  
  286. /**************************** Macros *****************************/
  287.  
  288. #define max(A,B) ((A) > (B) ? (A) : (B))
  289. #define min(A,B) ((A) <= (B) ? (A) : (B))
  290. #define xnew(type) ((type*)xmalloc (sizeof (type)))
  291.  
  292. #define BUFFER_NOTIFY_BACKGROUND_BIT_SET_P(buffer) 1
  293.   
  294. #define get_extent_data(id,binfo) (Energize_Extent_Data*)get_object(id, binfo)
  295. #define get_class(id,binfo) (GDataClass*)get_object(id, binfo)
  296. #define get_generic(id,binfo) (GenericData*)get_object(id, binfo)
  297.  
  298. #define put_extent_data(id,binfo,obj) put_object(id, binfo, obj)
  299. #define put_class(id,binfo,obj) put_object(id, binfo, obj)
  300. #define put_generic(id,binfo,obj) put_object(id, binfo, obj)
  301.  
  302. #define remove_extent_data(id,binfo) remove_object(id, binfo)
  303. #define remove_class(id,binfo) remove_object(id, binfo)
  304. #define remove_generic(id,binfo) remove_object(id, binfo)
  305.  
  306. #define DEBUGGER_PSHEET_NAME  "DEBUGGER_P_SHEET"
  307.  
  308. /**************************** Utilities *****************************/
  309.  
  310. static int
  311. emacs_CWriteRequestBuffer (Connection* conn)
  312. {
  313.   int result;
  314.   signal (SIGPIPE, SIG_IGN);    /* don't kill emacs with SIGPIPE */
  315.   result = CWriteRequestBuffer (conn);    /* the real one; macroized later */
  316.   signal (SIGPIPE, SIG_DFL);
  317.   return result;
  318. }
  319.  
  320. #define CWriteRequestBuffer emacs_CWriteRequestBuffer
  321.  
  322.  
  323. static Energize_Extent_Data *
  324. extent_to_data (Lisp_Object extent_obj)
  325. {
  326.   Energize_Extent_Data *ext = 0;
  327.   
  328.   if (!EXTENTP (extent_obj)) 
  329.     return 0;
  330.   else
  331.     ext = energize_extent_data (XEXTENT (extent_obj));
  332.   
  333.   if (ext)
  334.     {
  335.       if (EQ (ext->extent, extent_obj))
  336.         return ext;
  337.       else 
  338.         abort ();
  339.     }
  340.   else
  341.     return 0;
  342. }
  343.  
  344.  
  345. /* duplicate a string */
  346. static char*
  347. copy_string (char *s)
  348. {
  349.   if (!s)
  350.     return 0;
  351.   else
  352.     {
  353.       int len = strlen (s);
  354.       char *res = (char *) xmalloc (len + 1);
  355.       return strcpy (res, s);
  356.     }
  357. }
  358.  
  359. /* Get objects from the hashtables */
  360. static void *
  361. get_object_internal (EId id, c_hashtable table)
  362. {
  363.   void *res;
  364.   void *found = gethash ((void*)id, table, &res);
  365.   
  366.   if (found) CHECK_OBJECT (res, 0);
  367.  
  368.   return found ? res : 0;
  369. }
  370.  
  371. static void *
  372. get_object (EId id, BufferInfo *binfo)
  373. {
  374.   return get_object_internal (id, binfo->id_to_object);
  375. }
  376.  
  377. static void
  378. put_object_internal (EId id, c_hashtable table, void *object)
  379. {
  380.   if (!PUT_ABLE_OBJECT (object))
  381.     error ("Can't put 0x%x in table", object);
  382.   CHECK_OBJECT (object, 0);
  383.   puthash ((void*)id, object, table);
  384. }
  385.  
  386. static void
  387. put_object (EId id, BufferInfo *binfo, void *object)
  388. {
  389.   put_object_internal (id, binfo->id_to_object, object);
  390.   return;
  391. }
  392.  
  393. static void
  394. remove_object_internal (EId id, c_hashtable table)
  395. {
  396.   void *res;
  397.  
  398.   if (gethash ((void*)id, table, &res))
  399.     {
  400.       if (OBJECT_FREE (res))
  401.         error ("Free'd object 0x%x still in table!", res);
  402.       remhash ((void*)id, table);
  403.     }
  404.   else if (id)
  405.     error ("EId %d not in table!", id);
  406. }
  407.  
  408. static void
  409. remove_object (EId id, BufferInfo *binfo)
  410. {
  411.   remove_object_internal (id, binfo->id_to_object);
  412.   return;
  413. }
  414.  
  415. /* maphash_function called by free_buffer_info */
  416. static void
  417. free_object (void *key, void *contents, void *arg)
  418. {
  419.   BufferInfo *binfo = arg;
  420.  
  421.   if (contents)
  422.     {
  423.       switch (OBJECT_SEAL (contents))
  424.         {
  425.         case BUF_INFO_SEAL:
  426.           break;
  427.         case EXTENT_SEAL:
  428.           free_Energize_Extent_Data ((Energize_Extent_Data *) contents, binfo, OFT_MAPHASH);
  429.           break;
  430.         case GDATA_CLASS_SEAL:
  431.           free_GDataclass ((GDataClass *) contents, binfo);
  432.           break;
  433.         case GDATA_SEAL:
  434.           free_GenericData ((GenericData *) contents, binfo);
  435.           break;
  436.         default:
  437.           error ("Bad argument 0x%x to free_object()", contents);
  438.           return;
  439.         }
  440.     }
  441. }
  442.  
  443. static GDataClass *
  444. alloc_GDataclass (EId id, BufferInfo *binfo)
  445. {
  446.   GDataClass *cl = xnew (GDataClass);
  447.   memset (cl, 0, sizeof (GDataClass));
  448.   cl->seal = GDATA_CLASS_SEAL;
  449.   cl->id = id;
  450.   put_class (cl->id, binfo, cl);
  451.   return cl;
  452.  
  453. static void
  454. free_GDataclass (GDataClass *cl, BufferInfo *binfo)
  455. {
  456.   if (cl)
  457.     {
  458.       remove_class (cl->id, binfo);
  459.       SET_OBJECT_FREE (cl);
  460.     }
  461.   return;
  462.  
  463.  
  464. static GenericData *
  465. alloc_GenericData (EId id, GDataClass *cl, BufferInfo *binfo)
  466. {
  467.   GenericData *gen = xnew (GenericData);
  468.   gen->seal = GDATA_SEAL;
  469.   gen->id = id;
  470.   gen->cl = cl;
  471. /*  gen->image = 0;*/
  472.   gen->flags = 0;
  473.   gen->modified_state = 0;
  474.   put_generic (gen->id, binfo, gen);
  475.   return gen;
  476. }
  477.           
  478. static void
  479. free_GenericData (GenericData *gen, BufferInfo *binfo)
  480. {
  481.   if (gen)
  482.     {
  483.       remove_generic (gen->id, binfo);
  484.       gen->cl = 0;
  485.       SET_OBJECT_FREE (gen);
  486.     }
  487.   return;
  488.  
  489. static Energize_Extent_Data *
  490. alloc_Energize_Extent_Data (EId id, BufferInfo *binfo)
  491. {              
  492.   Energize_Extent_Data *ext = xnew (Energize_Extent_Data);
  493.   ext->seal = EXTENT_SEAL;
  494.   ext->id = id;
  495.   ext->extent = 0;
  496.   put_extent_data (ext->id, binfo, ext);
  497.   return ext;
  498. }
  499.  
  500. static void
  501. free_Energize_Extent_Data 
  502. (Energize_Extent_Data *ext, BufferInfo *binfo, enum Energize_Object_Free_Type free_type)
  503. {              
  504.   if (ext)
  505.     {
  506.       Lisp_Object extent_obj = ext->extent;
  507.       ext->extent = 0;
  508.  
  509.       if (extent_obj && ext == energize_extent_data (XEXTENT (extent_obj)))
  510.         {
  511.           detach_extent (XEXTENT(extent_obj));
  512.       set_energize_extent_data (XEXTENT (extent_obj), 0);
  513.         }
  514.       remove_extent_data (ext->id, binfo);
  515.       ext->id = 0;
  516.  
  517.       /* don't free this "sub-guy" via maphash, as it will get taken care
  518.          of during the course of the maphash without our doing anything */
  519.       if (free_type != OFT_MAPHASH)
  520.         {
  521.           if (ext->extentType == CEGeneric)
  522.             free_GenericData (ext->u.generic.gData, binfo);
  523.         }
  524.  
  525.       SET_OBJECT_FREE (ext);
  526.     }
  527.   return;
  528. }
  529.  
  530. /* called from the GC when an extent is returned to the free list */
  531. void
  532. energize_extent_finalization (EXTENT extent)
  533. {
  534.   Energize_Extent_Data *ext = energize_extent_data (extent);
  535.   Lisp_Object buffer = extent->buffer;
  536.   BufferInfo *binfo;
  537.  
  538.   /* the if 0 case bypasses the freeing of extentData objects.  It's a big
  539.      memory leak but could be causing some problems. */
  540. #if 0
  541.   if (ext)
  542.     {
  543.       ext->extent = 0;
  544.       set_energize_extent_data (extent, 0);
  545.     }
  546.   return;
  547. #else
  548.   if (!ext || (!BUFFERP (buffer)))
  549.     return;
  550.  
  551.   binfo = 
  552.     energize_connection ?
  553.       get_buffer_info_for_emacs_buffer (buffer, energize_connection) : 0;
  554.     
  555.   if (binfo && ext)
  556.     free_Energize_Extent_Data (ext, binfo, OFT_GC);
  557.   else
  558.     ext->extent = 0;
  559.  
  560.   set_energize_extent_data (extent, 0);
  561.   return;
  562. #endif
  563. }
  564.  
  565. extern int find_file_compare_truenames;
  566.  
  567. static BufferInfo *
  568. alloc_BufferInfo (EId id, Lisp_Object name, Lisp_Object filename,
  569.           char *class_str, Editor *editor, Window win)
  570. {
  571.   BufferInfo *binfo = xnew (BufferInfo);
  572.   Widget nw = 0;
  573.   Lisp_Object buffer = Qnil;
  574.  
  575.   if (win){
  576.     char win_as_string [16];
  577.     nw = XtWindowToWidget (x_current_display, win);
  578.     if (nw)
  579.      nw = XtParent (nw);
  580.  
  581.     if (nw)
  582.       sprintf (win_as_string, "w%x", nw);
  583.     else
  584.       sprintf (win_as_string, "0x%x", win);
  585.  
  586.     binfo->screen =
  587.       Fx_create_screen (Qnil, build_string (win_as_string));
  588.   }else
  589.     binfo->screen = Qnil;
  590.  
  591.   /* try to re-use a buffer with the same file name if one already exists.
  592.    * If a buffer already exists but is modified we should do a dialog and
  593.    * ask the user what to do.  For now I'll just use a new buffer in that case.
  594.    * ParseBuffer will erase the buffer.
  595.    **/
  596.   if (!NILP (filename))
  597.     {
  598.       int offct = find_file_compare_truenames;
  599.       find_file_compare_truenames = 1;
  600.       buffer = Fget_file_buffer (filename);
  601.       find_file_compare_truenames = offct;
  602.  
  603.       if (!NILP (buffer) && !NILP (Fbuffer_modified_p (buffer)))
  604.     buffer = Qnil;
  605.     }
  606.  
  607.   if (NILP (buffer))
  608.     buffer = Fget_buffer_create (Fgenerate_new_buffer_name (name));
  609.  
  610.   binfo->seal = BUF_INFO_SEAL;
  611.   binfo->id = id;
  612.   binfo->flags = 0;
  613.   binfo->editor = editor;
  614.   binfo->id_to_object = make_hashtable (100);
  615.   binfo->emacs_buffer = buffer;
  616.   binfo->modified_state = 0;
  617.   binfo->editable = 0;
  618.   binfo->output_mark = Qnil;
  619.   binfo->buffer_type = kernel_buffer_type_to_elisp_type (class_str);
  620.   binfo->p_sheet_ids = 0;
  621.   binfo->n_p_sheets = 0;
  622.   binfo->note_ids = 0;
  623.   binfo->n_notes = 0;
  624.   put_buffer_info (id, binfo->emacs_buffer, binfo, editor);
  625.  
  626.   energize_buffers_list = Fcons (buffer, energize_buffers_list);
  627.  
  628. #if 0
  629.  *  if (nw){
  630.  *    Lisp_Object window = Fscreen_selected_window (binfo->screen);
  631.  *    Fset_window_buffer (window, binfo->emacs_buffer);
  632.  *    BLOCK_INPUT;
  633.  *    set_text_widget ((NoteWidget)nw,
  634.  *             XSCREEN(binfo->screen)->display.x->widget);
  635.  *    UNBLOCK_INPUT;
  636.  *  }
  637. #endif
  638.  
  639.   return binfo;
  640. }
  641.  
  642. /* free a buffer_info */
  643. static void
  644. free_buffer_info (BufferInfo *binfo)
  645. {
  646.   maphash (free_object, binfo->id_to_object, (void *)binfo);
  647.   free_hashtable (binfo->id_to_object);
  648.   if (energize_connection && energize_connection->binfo_hash) 
  649.     {
  650.       if (binfo->id)
  651.         remhash ((void *)binfo->id, energize_connection->binfo_hash);
  652.       if (binfo->emacs_buffer)
  653.         remhash ((void *)binfo->emacs_buffer, energize_connection->binfo_hash);
  654.     }
  655.   binfo->id = 0;
  656.   binfo->emacs_buffer = 0;
  657.   SET_OBJECT_FREE (binfo);
  658. }
  659.  
  660. /* hash for BufferInfo structures */
  661. static BufferInfo*
  662. get_buffer_info_for_emacs_buffer (Lisp_Object emacs_buf, Editor *editor)
  663. {
  664.   BufferInfo *res;
  665.   if (!editor || !editor->binfo_hash)
  666.     return 0;
  667.   else
  668.     return (gethash ((void *)emacs_buf, editor->binfo_hash, (void *)&res)
  669.         ? res : 0);
  670. }
  671.  
  672.  
  673. struct buffer_and_sheet_ids
  674. {
  675.   EId    buffer_id;
  676.   EId    sheet_id;
  677. };
  678.  
  679. static void
  680. find_sheet_id (void* key, void* contents, void* arg)
  681. {
  682.   BufferInfo* binfo = (BufferInfo*)contents;
  683.   EId buffer_id = (EId)key;
  684.   struct buffer_and_sheet_ids* result = (struct buffer_and_sheet_ids*)arg;
  685.   int i;
  686.  
  687.   if (!result->buffer_id)
  688.     for (i = 0; i < binfo->n_p_sheets; i++)
  689.       if (binfo->p_sheet_ids [i] == result->sheet_id)
  690.     {
  691.       result->buffer_id = buffer_id;
  692.       return;
  693.     }
  694. }
  695.  
  696. static EId
  697. buffer_id_of_sheet (EId id)
  698. {
  699.   Editor *editor = energize_connection;
  700.   struct buffer_and_sheet_ids basi;
  701.   if (!energize_connection)
  702.     return 0;
  703.  
  704.   basi.buffer_id = 0;
  705.   basi.sheet_id = id;
  706.   maphash (find_sheet_id, editor->binfo_hash, (void*)&basi);
  707.   return basi.buffer_id;
  708. }
  709.  
  710. static long
  711. get_energize_buffer_id (Lisp_Object emacs_buf)
  712. {
  713.   Editor *editor = energize_connection;
  714.   BufferInfo *res;
  715.   if (!editor || !editor->binfo_hash)
  716.     return -1;
  717.   else if (!gethash ((void *)emacs_buf, editor->binfo_hash, (void *)&res))
  718.     return -1;
  719.   else
  720.     return (long) res->id;
  721. }
  722.  
  723. static char *
  724. kernel_buffer_type_to_elisp_type (char *kernel_type)
  725. {
  726.   struct buffer_type_struct *bts = 
  727.     kernel_buffer_types_to_elisp_buffer_types_vector;
  728.   char *elisp_type = 0;
  729.  
  730.   if (!kernel_type)
  731.     return UNINITIALIZED_BUFFER_TYPE;
  732.  
  733.   while (bts->kernel_name)
  734.     {
  735.       if (!strcmp (bts->kernel_name, kernel_type))
  736.         {
  737.           elisp_type = bts->elisp_name;
  738.           break;
  739.         }
  740.       bts++;
  741.     }
  742.   
  743.   if (!elisp_type)
  744.     return kernel_type;
  745.   else
  746.     return elisp_type;
  747. }
  748.  
  749. static Lisp_Object
  750. get_buffer_type_for_emacs_buffer (Lisp_Object emacs_buf, Editor *editor)
  751. {
  752.   BufferInfo *binfo;
  753.   if (!(binfo = get_buffer_info_for_emacs_buffer (emacs_buf, editor)))
  754.     return Qnil;
  755.   else
  756.     {
  757.       if (!binfo->buffer_type) binfo->buffer_type = 
  758.         UNINITIALIZED_BUFFER_TYPE;
  759.  
  760.       return intern (binfo->buffer_type);
  761.     }
  762. }
  763.  
  764. static Lisp_Object
  765. set_buffer_type_for_emacs_buffer (Lisp_Object emacs_buf, Editor *editor,
  766.                                     Lisp_Object type)
  767. {
  768.   BufferInfo *binfo;
  769.   if (!(binfo = get_buffer_info_for_emacs_buffer (emacs_buf, editor)))
  770.     return Qnil;
  771.   else
  772.     {
  773.       char *type_string;
  774.  
  775.       if (NILP (type)) return Qnil;
  776.         
  777.       if (SYMBOLP (type))
  778.         XSET (type, Lisp_String, XSYMBOL (type)->name);
  779.  
  780.       if (STRINGP (type)) 
  781.         type_string = (char *)XSTRING (type)->data;
  782.  
  783.       type_string = copy_string (type_string);
  784.  
  785.       if (!type_string) return Qnil;
  786.  
  787.       binfo->buffer_type = type_string;
  788.  
  789.       return intern (binfo->buffer_type);
  790.     }
  791. }
  792.  
  793. static BufferInfo*
  794. get_buffer_info_for_id (EId id, Editor *editor)
  795. {
  796.   BufferInfo *res;
  797.   return (gethash ((void *)id, editor->binfo_hash, (void *)&res))?res:0;
  798. }
  799.  
  800. static void
  801. put_buffer_info (EId id, Lisp_Object emacs_buf, BufferInfo *binfo,
  802.                  Editor *editor)
  803. {
  804.   puthash ((void *)id, binfo, editor->binfo_hash);
  805.   puthash ((void *)emacs_buf, binfo, editor->binfo_hash);
  806. }
  807.  
  808. static void
  809. remove_buffer_info (EId id, Lisp_Object emacs_buf, Editor *editor)
  810. {
  811.   remhash ((void *)id, editor->binfo_hash);
  812.   remhash ((void *)emacs_buf, editor->binfo_hash);
  813. }
  814.  
  815. /* Display messages in minibuffer */
  816. static void
  817.   Post (char *msg) 
  818. {
  819.   message (msg, 0, 0, 0);
  820. }
  821.  
  822. static void
  823.   Post1 (char *msg, int a1) 
  824. {
  825.   message (msg, a1, 0, 0);
  826. }
  827.  
  828. static void
  829. Post2 (char *msg, int a1, int a2) 
  830. {
  831.   message (msg, a1, a2, 0);
  832. }
  833.  
  834.  
  835. /* Conversion between Energize and Emacs buffer positions */
  836.  
  837. static EmacsPos
  838. EmacsPosForEnergizePos (EnergizePos energizePos)
  839. {
  840.   return ((energizePos >= (1 << VALBITS))?Z:(energizePos + 1));
  841. }
  842.  
  843. static EnergizePos
  844. EnergizePosForEmacsPos (EmacsPos emacs_pos)
  845. {
  846.   return (emacs_pos - 1);
  847. }
  848.  
  849.  
  850. /* extent data */
  851.  
  852. Energize_Extent_Data *
  853. energize_extent_data (EXTENT extent)
  854. {
  855.   Lisp_Object data = extent->user_data;
  856.   if (!CONSP (data) ||
  857.       !EQ (XCONS (data)->car, Qenergize_extent_data))
  858.     return 0;
  859.   data = XCONS (data)->cdr;
  860.   if (!FIXNUMP (XCONS (data)->car) || !FIXNUMP (XCONS (data)->cdr))
  861.     abort ();
  862.   return ((Energize_Extent_Data *)
  863.       ((XUINT (XCONS (data)->car) << 16) | (XUINT (XCONS (data)->cdr))));
  864. }
  865.  
  866. void
  867. set_energize_extent_data (EXTENT extent, void *data)
  868. {
  869.   unsigned short high = ((unsigned int) data) >> 16;
  870.   unsigned short low = ((unsigned int) data) & 0xFFFF;
  871.   Lisp_Object old = extent->user_data;
  872.   if (old == 0)
  873.     extent->user_data = Qnil;
  874.   else if (NILP (old))
  875.     extent->user_data = Fcons (Qenergize_extent_data,
  876.                    Fcons (make_number (high), make_number (low)));
  877.   else if (!CONSP (old) || !EQ (XCONS (old)->car, Qenergize_extent_data))
  878.     abort ();
  879.   else
  880.     {
  881.       XFASTINT (XCONS (XCONS (old)->cdr)->car) = high;
  882.       XFASTINT (XCONS (XCONS (old)->cdr)->cdr) = low;
  883.     }
  884. }
  885.  
  886.  
  887.  
  888. extern int windows_or_buffers_changed;
  889.  
  890. extern void recompute_screen_menubar (struct screen *);
  891.  
  892. DEFUN ("energize-update-menubar", Fenergize_update_menubar,
  893.        Senergize_update_menubar, 0, 1, 0,
  894.        "Updates the menubar of optional SCREEN argument to reflect the \n\
  895. commands currently enabled by Energize.")
  896.      (screen)
  897.      Lisp_Object screen;
  898. {
  899.   struct screen* s;
  900.  
  901.   if (!energize_connection) return Qnil;
  902.   
  903.   if (NILP (screen))
  904.     s = selected_screen;
  905.   else
  906.     {
  907.       CHECK_SCREEN (screen, 0);
  908.       s = XSCREEN (screen);
  909.     }
  910.   
  911.   if (!SCREEN_IS_X (s))
  912.     error ("not an X screen");
  913.  
  914.   recompute_screen_menubar (selected_screen);
  915.   return Qnil;
  916. }
  917.  
  918.  
  919. /* Return true if the extent is an Energize extent that can have a menu */
  920. DEFUN ("energize-extent-menu-p", Fenergize_extent_menu_p,
  921.        Senergize_extent_menu_p, 1, 1, 0,
  922.        "Return true if the extent has a set of commands defined by Energize")
  923.      (extent_obj)
  924.      Lisp_Object extent_obj;
  925. {
  926.   CHECK_EXTENT (extent_obj, 0);
  927.  
  928.   if (NILP (Fconnected_to_energize_p())) 
  929.     return Qnil;
  930.   else
  931.     {
  932.       Energize_Extent_Data *ext = extent_to_data (extent_obj);
  933.       return (ext && ext->extentType == CEGeneric) ? Qt : Qnil;
  934.     }
  935. }
  936.  
  937.  
  938. /* Do what is needed so that the delayed requests will be notified by
  939. ** the event loop */
  940.  
  941. static void 
  942. notify_delayed_requests ()
  943. {
  944.   extern void mark_process_as_being_ready (struct Lisp_Process* process);
  945.  
  946.   if (energize_connection && !NILP (energize_connection->proc) && energize_connection->conn
  947.       && CRequestDelayedP (energize_connection->conn))
  948.     mark_process_as_being_ready (XPROCESS (energize_connection->proc));
  949. }
  950.  
  951.  
  952. /******************* IMAGE storage maintenance *******************/
  953.  
  954. /* called by redisplay() -- presumably by the time this is called,
  955.    all "dead" references into the x_bitmaps[] vector have been flushed
  956.    from the display state */
  957. void
  958. free_zombie_bitmaps ()
  959. {
  960. }
  961.  
  962.  
  963. extern struct x_pixmap *x_get_pixmap (Lisp_Object lisp_name, char *hash);
  964.  
  965. static c_hashtable image_cache;
  966.  
  967. /* Parses an image from the image language */
  968. static GLYPH
  969. ParseAnImage (Connection *conn, BufferInfo *binfo)
  970. {
  971.   ReqLen l;
  972.   char *s = CGetVstring (conn, &l);
  973.   char pix_name [255];
  974.   char buf [255];
  975.   int attr_number, pix_len;
  976.   char *file;
  977.   GLYPH result = 0;
  978.   /* I don't know if it's ok to pass the address of a short to gethash... */
  979.   int hashed = 0;
  980.  
  981.   if (s[0] != 'f')
  982.     return 0;
  983.  
  984.   if (gethash ((void *) s, image_cache, (void *) &hashed))
  985.     /* If we have already parsed this image spec (string=) then just return
  986.        the old glyph, instead of calling the lisp code, x_get_pixmap, and
  987.        XtGetSubResources again.  The result may be 0 if there is no pixmap
  988.        file name in the resource database.
  989.      */
  990.     return (GLYPH) hashed;
  991.  
  992.   if (3 != sscanf (s, "f %d p %d %s", &attr_number, &pix_len, pix_name))
  993.     {
  994.       sprintf (buf, "unparsable image: \"%s\"", s);
  995.       error (buf);
  996.     }
  997.  
  998.   if (pix_len != strlen (pix_name))
  999.     abort ();
  1000.  
  1001.   /* Read the pixmap file name for this image from the resource db */
  1002.   {
  1003.     XtResource resource [1];
  1004.     resource[0].resource_name = pix_name;
  1005.     resource[0].resource_class = XtCBitmap;
  1006.     resource[0].resource_type = XtRString;
  1007.     resource[0].resource_size = sizeof (char *);
  1008.     resource[0].resource_offset = 0;
  1009.     resource[0].default_type = XtRImmediate;
  1010.     resource[0].default_addr = 0;
  1011.     file = 0;
  1012.     BLOCK_INPUT;
  1013.     XtGetSubresources (selected_screen->display.x->widget, (XtPointer) &file,
  1014.                "image", "Image", resource, 1, NULL, 0);
  1015.     UNBLOCK_INPUT;
  1016.   }
  1017.  
  1018.   if (! file)
  1019.     result = 0;
  1020.   else
  1021.     {
  1022.       struct x_pixmap *p;
  1023.       sprintf (buf, "attribute%d", attr_number);
  1024.       p = x_get_pixmap (build_string (file), buf);
  1025.       result = p->glyph_id;
  1026.  
  1027.       if (p->depth == 0)
  1028.     /* if depth is >0 then this is an XPM, and its colors are not
  1029.        controlled by the fg/bg of a face.  So don't bother making a
  1030.        face for it. */
  1031.     {
  1032.       Lisp_Object face, face_id;
  1033.       /* run the lisp code to make a face for this image. */
  1034.       face = call1 (intern ("find-face"), intern (buf));
  1035.       if (NILP (face))
  1036.         {
  1037.           call1 (intern ("make-face"), intern (buf));
  1038.           face = call1 (intern ("find-face"), intern (buf));
  1039.           if (NILP (face)) error ("make-face is broken");
  1040.         }
  1041.       face_id = call1 (intern ("face-id"), face);
  1042.       CHECK_FIXNUM (face_id, 0);
  1043.       p->face_id = XINT (face_id);
  1044.     }
  1045.     }
  1046.  
  1047.   BLOCK_INPUT;
  1048.   /* CGetVstring returns a pointer into the connection buffer; we need to
  1049.      copy it to use it as a hash key. */
  1050.   s = strdup (s);
  1051.   UNBLOCK_INPUT;
  1052.  
  1053.   hashed = result;
  1054.   puthash ((void *) s, (void *) hashed, image_cache);
  1055.   return result;
  1056. }
  1057.  
  1058.  
  1059. /* Parses Classes from the connection buffer.  Defines them for
  1060.  * the buffer given as argument */
  1061. static void
  1062. ParseClasses (Connection *conn, unsigned int number, BufferInfo *binfo,
  1063.               unsigned int modify_ok)
  1064. {
  1065.   CClass *ptr;                  /* pointer to class data in buffer */
  1066.   GDataClass *cl;               /* unmodified class data */
  1067.   GLYPH g;
  1068.   int i;
  1069.   
  1070.   for (i = 0; i < number; i++)
  1071.     {
  1072.       ptr = CGet (conn, CClass);
  1073.       g = ParseAnImage (conn, binfo);
  1074.       cl = get_class (ptr->classId, binfo);
  1075.       
  1076.       if (!cl)
  1077.         cl = alloc_GDataclass (ptr->classId, binfo);
  1078.       else if (!modify_ok)
  1079.         Post1("Attempt to create class with existing Id %8x", ptr->classId);
  1080.       
  1081.       if (ignore_kernel) continue;
  1082.  
  1083.       /* if it did exist, we just clobber it */
  1084.       if (cl->flags != ptr->flags)
  1085.     {
  1086.       cl->flags = ptr->flags;
  1087.       BUF_FACECHANGE (XBUFFER (binfo->emacs_buffer))++;
  1088.     }
  1089.       if (cl->glyph != g)
  1090.         {
  1091.       cl->glyph = g;
  1092.       BUF_FACECHANGE (XBUFFER (binfo->emacs_buffer))++;
  1093.         }
  1094.     }
  1095. }
  1096.  
  1097. /* Parse GenericData form the connection buffer.  Defines them for the buffer
  1098.  * given as argument */
  1099. static void
  1100. ParseGenerics (Connection *conn, unsigned int number, 
  1101.                  BufferInfo *binfo, unsigned int modify_ok)
  1102. {
  1103.   CGeneric *ptr;
  1104.   GenericData *gen;
  1105.   GDataClass *cl;
  1106.   GLYPH g;
  1107.   int i;
  1108.   
  1109.   for (i = 0; i < number; i++)
  1110.     {
  1111.       ptr = CGet (conn, CGeneric);
  1112.       g = ParseAnImage (conn, binfo);
  1113.       gen = get_generic (ptr->genericId, binfo);
  1114.       cl = get_class (ptr->classId, binfo);
  1115.       
  1116.       if (!gen)
  1117.         { 
  1118.           /* create generic if it didn't already exist */
  1119.           
  1120.           if (!cl)
  1121.             {
  1122.               Post2 ("Attempt to create generic %8x with undefined class %8x",
  1123.                      ptr->genericId, ptr->classId);
  1124.               continue;
  1125.             }
  1126.           
  1127.           gen = alloc_GenericData (ptr->genericId, cl, binfo);
  1128.       gen->glyph = g;
  1129.       if (ptr->flags != 0xff) gen->flags = ptr->flags;
  1130.       gen->attribute = ptr->attribute;
  1131.         }
  1132.       else if (!modify_ok)
  1133.         Post1("Attempt to create generic with existing id %8x", 
  1134.               ptr->genericId);
  1135.       else{
  1136.     /* modify the generic */
  1137.     int modified = 0;
  1138.     if (cl != gen->cl)
  1139.       {
  1140.         modified = 1;
  1141.         gen->cl = cl;
  1142.       }
  1143.     if (gen->glyph != g)
  1144.       {
  1145.         modified = 1;
  1146.         gen->glyph = g;
  1147.       }
  1148.     if (ptr->flags != 0xff) 
  1149.       {
  1150.         modified = 1;
  1151.         gen->flags = ptr->flags;
  1152.       }
  1153.     if (gen->attribute != ptr->attribute)
  1154.       {
  1155.         modified = 1;
  1156.         gen->attribute = ptr->attribute;
  1157.       }
  1158.     if (modified)
  1159.       BUF_FACECHANGE (XBUFFER (binfo->emacs_buffer))++;
  1160.       }
  1161.     }
  1162. }
  1163.  
  1164. static void
  1165. insert_one_extent (CExtent* ptr, BufferInfo* binfo, int modify_ok)
  1166. {
  1167.   Energize_Extent_Data *ext;
  1168.   GenericData *gen;
  1169.   int extent_start;
  1170.   int extent_end;
  1171.   int set_extent_endpoints = 1;
  1172.  
  1173.   ext = get_extent_data (ptr->extentId, binfo);
  1174.   
  1175.   if (!ext)
  1176.     ext = alloc_Energize_Extent_Data (ptr->extentId, binfo);
  1177.   else if (!modify_ok) 
  1178.     Post1 ("Creating extent with existing id %8x", ptr->extentId);
  1179.  
  1180.   ext->extentType = ptr->extentType;
  1181.   
  1182.   if (ignore_kernel) return;
  1183.   
  1184.   switch (ptr->extentType)
  1185.     {
  1186.     case CEAttribute:
  1187.       ext->u.attr.attrValue = ptr->data;
  1188.       break;
  1189.       
  1190.     case CEAbbreviation:
  1191.       ext->u.abbrev.isOpened = ptr->data;
  1192.       break;
  1193.       
  1194.     case CEWriteProtect:
  1195.       break;
  1196.       
  1197.     case CEGeneric:
  1198.       gen = get_generic (ptr->data, binfo);
  1199.       if (!gen) 
  1200.     {
  1201.       Post1 ("NewExtents: Nonexistent generic data %8x", ptr->data);
  1202.       return;
  1203.     }
  1204.       ext->u.generic.gData = gen;
  1205.       break;
  1206.       
  1207.     default:
  1208.       Post1 ("Unknown extent type %d", ptr->extentType);
  1209.       break;
  1210.     }
  1211.   
  1212.   /* instruct redisplay to recompute the screen */
  1213.   BUF_FACECHANGE (XBUFFER (binfo->emacs_buffer))++;
  1214.   
  1215.   /* ptr->startPosition == ptr->endPosition == ~0 means to not change
  1216.    * the extent endpoints */
  1217.   if (ptr->startPosition == ~0 && ptr->endPosition == ~0)
  1218.     {
  1219.       set_extent_endpoints = 0;
  1220.       extent_start = ~0;
  1221.       extent_end = ~0;
  1222.     }
  1223.   else
  1224.     {
  1225.       struct buffer *b = XBUFFER (binfo->emacs_buffer);
  1226.       extent_start = EmacsPosForEnergizePos (ptr->startPosition);
  1227.       extent_end = EmacsPosForEnergizePos (ptr->endPosition);
  1228.       
  1229.       if (extent_end >= BUF_ZV (b))
  1230.     {
  1231.       extent_end = BUF_ZV (b) - 1;
  1232.       if (extent_start >= extent_end)
  1233.         extent_start = extent_end - 1;
  1234.     }
  1235.     }      
  1236.  
  1237.   /* no zero width extent */
  1238.   if (set_extent_endpoints && extent_start == extent_end)
  1239.     extent_end += 1;
  1240.  
  1241.   /* this function calls update_extent if the the ext->extent already
  1242.      exists */
  1243.  
  1244.   make_extent_for_data (binfo, ext, extent_start, extent_end,
  1245.             set_extent_endpoints);
  1246. }
  1247.  
  1248. /* Parse GenericData from the connection buffer.  Defines them for the buffer
  1249.  * given as argument.  Creates the Emacs extents while parsing.
  1250.  * Energize sends the extents ordered by increasing starting position.
  1251.  * Emacs is __much__ faster at inserting them in decreasing starting position
  1252.  * also for overlaps to work correctly the outmost extents have to be
  1253.  * inserted first.  This is what the recursive function is trying to do.
  1254.  */
  1255. static void
  1256. ParseExtents (Connection *conn, unsigned int number, 
  1257.               BufferInfo *binfo, unsigned int modify_ok, int extent_offset)
  1258. {
  1259.   CExtent* all_extents;
  1260.   int i;
  1261.  
  1262.   /* Gets the extents from the connection */
  1263.   all_extents = CGetN (conn, CExtent, number);
  1264.  
  1265.   /* adjusts the endpoints with the offset */
  1266.   for (i = 0; i < number; i++)
  1267.     {
  1268.       if (all_extents [i].startPosition != ~0)
  1269.     all_extents [i].startPosition += extent_offset;
  1270.       if (all_extents [i].endPosition != ~0)
  1271.     all_extents [i].endPosition += extent_offset;
  1272.     }
  1273.   
  1274.   /* inserts them all */
  1275.   for (i = number - 1; i >= 0; i--)
  1276.     {
  1277.       insert_one_extent (all_extents + i, binfo, modify_ok);
  1278.     }
  1279. }
  1280.  
  1281. /* Parses a CBuffer in the connection stream. If (delete_from != delete_to) 
  1282.    all characters in this range must be deleted.
  1283.    */
  1284.  
  1285. static int
  1286. string_buffer_compare (char *string, int string_len, 
  1287.                        struct buffer *buf, int bufpos)
  1288. {
  1289.   int first_section_length =
  1290.     (bufpos < BUF_GPT(buf))?(min (string_len, (BUF_GPT(buf) - bufpos))):0;
  1291.   int second_section_length = 
  1292.     ((bufpos + string_len) >= BUF_GPT(buf))?
  1293.       (string_len - first_section_length):0;
  1294.   
  1295.   /* degenerate case, which we consider to be "true" */
  1296.   if (string_len == 0) return 0;
  1297.  
  1298.   /* string won't fit in the buffer, so comparison fails */
  1299.   if (BUF_Z(buf) < (bufpos + string_len)) return -1;
  1300.  
  1301.   /* bad starting position, so comparison fails */
  1302.   if (bufpos < BUF_BEG (buf)) return -1;
  1303.  
  1304.   if (first_section_length > 0)
  1305.     /* there is a first section */
  1306.     {
  1307.       char *first_section_chars = (char *) BUF_CHAR_ADDRESS (buf, bufpos);
  1308.       int comp = strncmp (string, first_section_chars, first_section_length);
  1309.  
  1310.       if (comp) return comp;
  1311.     }
  1312.  
  1313.   if (second_section_length > 0)
  1314.     /* there is a second section */
  1315.     {
  1316.       char *second_section_chars = 
  1317.         (char *) BUF_CHAR_ADDRESS (buf, BUF_GPT(buf));
  1318.       int comp = strncmp (string + first_section_length, 
  1319.                           second_section_chars, second_section_length);
  1320.  
  1321.       if (comp) return comp;
  1322.     }
  1323.  
  1324.   return 0;
  1325. }
  1326.  
  1327. /* called by unwind protect, from within ParseBuffer and HandleRemoveExtents */
  1328. static Lisp_Object
  1329. restore_buffer_state (Lisp_Object state_cons)
  1330. {
  1331.   BufferInfo *binfo;
  1332.   Lisp_Object bufferId_cons = Fcar (state_cons);
  1333.   unsigned int bufferId = lisp_to_word (bufferId_cons);
  1334.   Lisp_Object buffer_modified_state = Fcar (Fcdr (state_cons));
  1335.   Lisp_Object clear_undo_list = Fcdr (Fcdr (state_cons));
  1336.   
  1337.   if (bufferId != 0)
  1338.     {
  1339.       if (energize_connection && (binfo = get_buffer_info_for_id (bufferId, energize_connection))
  1340.           && binfo->emacs_buffer)
  1341.     {
  1342.       /* Always ignore what Energize tells us about the buffer read-only
  1343.          state.  For files Emacs knows better and for non-file buffers
  1344.          Emacs is hacking the read-only state anyway so let it be. */
  1345.       XBUFFER(binfo->emacs_buffer)->read_only = buffer_modified_state;
  1346.           if (!NILP (clear_undo_list))
  1347.             XBUFFER(binfo->emacs_buffer)->undo_list = Qnil;
  1348.     }
  1349.     }
  1350.   else
  1351.     /* this is just temporary */
  1352.     Post("Bad bufferId cons cell!");
  1353.   return Qnil;
  1354. }
  1355.  
  1356. static void
  1357. rename_the_buffer (Lisp_Object new_name)
  1358. {
  1359.   int count = 0;
  1360.   char number [8];
  1361.   struct gcpro gcpro1;
  1362.   
  1363.   Lisp_Object name = new_name;
  1364.   GCPRO1 (name);
  1365.   while (!NILP (Fget_buffer (name)))
  1366.     {
  1367.       sprintf (number, "<%d>", ++count);
  1368.       name = concat2 (new_name, build_string (number));
  1369.     }
  1370.   Frename_buffer (name, Qnil);
  1371.   UNGCPRO;
  1372. }
  1373.  
  1374. Lisp_Object
  1375. safe_funcall_hook (Lisp_Object hook, int nargs, Lisp_Object arg1,
  1376.            Lisp_Object arg2, Lisp_Object arg3);
  1377.  
  1378. extern void del_range (int, int);
  1379.  
  1380. extern Lisp_Object Fdelete_extent (Lisp_Object);
  1381.  
  1382. static int
  1383. destroy_if_energize_extent (EXTENT ext, void* arg)
  1384. {
  1385.   if (energize_extent_data (ext))
  1386.     {
  1387.       Lisp_Object extent;
  1388.       XSET (extent, Lisp_Extent, ext);
  1389.       Fdelete_extent (extent);
  1390.     }
  1391.   return 0;
  1392. }
  1393.  
  1394. /*extern void process_extents_for_destruction (int, int, struct buffer *);*/
  1395. static void
  1396. destroy_all_energize_extents (struct buffer* buf)
  1397. {
  1398. /*  if (energize_font_lock_p)*/
  1399.     map_extents (BUF_BEG (buf), BUF_Z (buf), NULL, destroy_if_energize_extent,
  1400.          NULL, buf, 1);
  1401. /*  else
  1402.     process_extents_for_destruction (BUF_BEG (buf), BUF_Z (buf), buf);*/
  1403. }
  1404.  
  1405. static void
  1406. ParseBuffer (Connection *conn, CBuffer *cbu, Editor *editor, 
  1407.              EnergizePos delete_from, EnergizePos delete_to, Window win, int relative_p)
  1408. {
  1409.   char *name;
  1410.   ReqLen name_len;
  1411.   char *pathname_str;
  1412.   ReqLen pathname_len;
  1413.   char *buffer_class_str;
  1414.   ReqLen buffer_class_len;
  1415.   Lisp_Object pathname = Qnil;
  1416.   Lisp_Object pathname_directory = Qnil;
  1417.   Lisp_Object buffer_name = Qnil;
  1418.   Lisp_Object filename = Qnil;
  1419. #if 1
  1420.   Lisp_Object display_window = Qnil;
  1421. #endif
  1422.   BufferInfo *binfo;
  1423.   int modifying_p = 0;
  1424.   EmacsPos previous_point;
  1425.   EmacsPos from;
  1426.   EmacsPos to;
  1427. #if 1
  1428.   EmacsPos display_start = 1;
  1429. #endif
  1430.   char *text;
  1431.   ReqLen text_len;
  1432.   Lisp_Object modified_buffer_flag;
  1433.   int count = specpdl_ptr - specpdl;
  1434.   int extent_offset;
  1435.   Lisp_Object restore_buffer_state_cons;
  1436.   int should_keep_window_start = 1;
  1437.   int no_text_deleted = 0;
  1438.  
  1439.   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;  
  1440.  
  1441.   record_unwind_protect (save_restriction_restore, save_restriction_save ());
  1442.  
  1443.   Fwiden ();
  1444.  
  1445.   GCPRO4 (buffer_name, pathname, pathname_directory, filename);
  1446.  
  1447.   name = CGetVstring (conn, &name_len);
  1448.  
  1449.   /* read the pathname and buffer-class -- Editor Protocol > 0 */
  1450.   pathname_str = CGetVstring (conn, &pathname_len);
  1451.   buffer_class_str = CGetVstring (conn, &buffer_class_len);
  1452.  
  1453.   if (name_len)
  1454.     buffer_name = build_string (name);
  1455.   if (pathname_len)
  1456.     pathname = build_string (pathname_str);
  1457.   
  1458.   /* set up pathname_directory */
  1459.   if (!NILP (pathname))
  1460.     {
  1461.       if (NILP (Ffile_directory_p (pathname)))
  1462.         pathname_directory = Ffile_name_directory (pathname);
  1463.       else
  1464.         pathname_directory = pathname;
  1465.     }
  1466.  
  1467.   /* make sure that pathname_directory ends with a '/', if it exists */
  1468.   if (!NILP (pathname_directory))
  1469.     {
  1470.       char *str = (char *) XSTRING (pathname_directory)->data;
  1471.       int size = XSTRING (pathname_directory)->size;
  1472.       if (str[size - 1] != '/')
  1473.         {
  1474.           Lisp_Object tmp = make_string (str, size + 1);
  1475.           XSTRING (tmp)->data[size] = '/';
  1476.           pathname_directory = tmp;
  1477.         }
  1478.     }
  1479.  
  1480.  
  1481.   /* get or create the BufferInfo */
  1482.   if (binfo = get_buffer_info_for_id (cbu->bufferId, editor)) 
  1483.     modifying_p = 1;
  1484.   else
  1485.     {      
  1486.       if (NILP (buffer_name))
  1487.         {
  1488.           char *dummy = "*Unnamed Energize Buffer*";
  1489.           buffer_name = build_string (dummy);
  1490.         }
  1491.       /* create new buffer */
  1492.       binfo = alloc_BufferInfo (cbu->bufferId, buffer_name, pathname,
  1493.                 buffer_class_str, editor, win);
  1494.       XBUFFER (binfo->emacs_buffer)->read_only =
  1495.     cbu->flags == CBReadOnly ? Qt : Qnil;
  1496.     }
  1497.   
  1498.   /* remember where we were in which buffer before we change things */
  1499.   if (current_buffer != XBUFFER (binfo->emacs_buffer))
  1500.     {
  1501.       record_unwind_protect (save_excursion_restore, save_excursion_save ());
  1502.       Fset_buffer (binfo->emacs_buffer);
  1503.     }
  1504.  
  1505.   /* set default-directory */
  1506.   if (!NILP (pathname_directory))
  1507.     {
  1508.       if (!NILP (Ffile_directory_p (pathname_directory))
  1509.       && !NILP (Ffile_executable_p (pathname_directory)))
  1510.     Fset (Qdefault_directory, pathname_directory);
  1511.       else
  1512.           Fset (Qdefault_directory, Qnil);
  1513.     }
  1514.  
  1515.   /* set file name unless it's a directory */
  1516.   if (!NILP (pathname) && NILP (Ffile_directory_p (pathname)))
  1517.     {
  1518.       filename = Fexpand_file_name (pathname, Qnil);
  1519.       Fset (Qbuffer_file_name, filename);
  1520.     }
  1521.  
  1522.   /* set buffer name */
  1523.   if (!NILP (buffer_name))
  1524.     {
  1525.       if (modifying_p
  1526.       && strcmp ((char*)XSTRING (buffer_name)->data,
  1527.              (char*)
  1528.                      XSTRING (XBUFFER (binfo->emacs_buffer)->name)->data))
  1529.     rename_the_buffer (buffer_name);
  1530.     }
  1531.   
  1532.   if (modifying_p)
  1533.     {
  1534.       safe_funcall_hook (Venergize_kernel_modification_hook, 0, 0, 0, 0);
  1535.       /* Make sure buffer is current after the hook */
  1536.       Fset_buffer (binfo->emacs_buffer);
  1537.     }
  1538.  
  1539.   modified_buffer_flag = Fbuffer_modified_p (binfo->emacs_buffer);
  1540.  
  1541.   /* enables buffer edits */
  1542.   restore_buffer_state_cons =
  1543.     Fcons (word_to_lisp (cbu->bufferId),
  1544.        Fcons (XBUFFER(binfo->emacs_buffer)->read_only, Qt));
  1545.   record_unwind_protect (restore_buffer_state, restore_buffer_state_cons);
  1546.   XBUFFER(binfo->emacs_buffer)->read_only = Qnil;
  1547.   
  1548.   /* any changes here should take place "underneath" these hooks, I think */
  1549.   specbind (Qenergize_buffer_modified_hook, Qnil);
  1550.   specbind (Qfirst_change_function, Qnil);
  1551.   specbind (Qbefore_change_function, Qnil);
  1552.   /* As energize does not use the after-change-function it's not useful to
  1553.      bind it to NIL */
  1554.   /* specbind (Qafter_change_function, Qnil); */
  1555.   specbind (Qinside_parse_buffer, Qt);
  1556.   specbind (Qbuffer_undo_list, Qt);
  1557.  
  1558.   XBUFFER (binfo->emacs_buffer)->undo_list = Qt;
  1559.   
  1560.   /* EmacsPosForEnergizePos uses the current-buffer */
  1561.   from = EmacsPosForEnergizePos (delete_from);
  1562.   to = EmacsPosForEnergizePos (delete_to);
  1563.  
  1564.   /* get text */
  1565.   text = CGetVstring (conn, &text_len);
  1566.  
  1567.   if (modifying_p && (from != to || text_len))
  1568.     /* updates the visited file modtime */
  1569.     Fset_buffer_modtime (binfo->emacs_buffer, Qnil);
  1570.  
  1571.   if (!modifying_p)
  1572.     {
  1573.       /* clears the buffer in case we re-use a non-energize buffer */
  1574.       previous_point = 1;
  1575.       Fset_buffer (binfo->emacs_buffer);
  1576.       del_range (BEG, Z);
  1577.     }
  1578.   else
  1579.     {
  1580. #if 1
  1581.       display_window = Fget_buffer_window (binfo->emacs_buffer, Qnil, Qnil);
  1582. #endif
  1583.       previous_point = point;
  1584.  
  1585. #if 1
  1586.       if (!NILP (display_window))
  1587.         display_start = Fmarker_position (XWINDOW (display_window)->start);
  1588. #endif
  1589.  
  1590.       if (from != to)
  1591.         {
  1592.           struct buffer *buf = XBUFFER (binfo->emacs_buffer);
  1593.                         
  1594.       Fset_buffer (binfo->emacs_buffer);
  1595.           if (!NILP (binfo->output_mark)
  1596.               && marker_position (binfo->output_mark) >= from)
  1597.             Fset_marker (binfo->output_mark, make_number (from),
  1598.                          binfo->emacs_buffer);
  1599.           if (((to - from) == text_len) &&
  1600.               !string_buffer_compare (text, text_len, buf, from))
  1601.             /* the new text is the same as the old text, don't clear
  1602.                the undo list*/
  1603.             {
  1604.               Fsetcdr (Fcdr (restore_buffer_state_cons), Qnil);
  1605.               no_text_deleted = 1;
  1606.           destroy_all_energize_extents (buf);
  1607.             }
  1608.       else
  1609.             {
  1610.               /* Do not keep window start if we actually delete text */
  1611.               should_keep_window_start = 0;
  1612.           Fset_buffer (binfo->emacs_buffer);
  1613.           destroy_all_energize_extents (buf);
  1614.               del_range (from, to);
  1615.             }
  1616.         }
  1617.       else if (!text_len)
  1618.         /* if there is no text and we didn't delete anything, 
  1619.            don't clear the undo_list slot */
  1620.         Fsetcdr (Fcdr (restore_buffer_state_cons), Qnil);
  1621.     }
  1622.   
  1623.   /* buffer type */
  1624.   if (cbu->flags != 0xff && cbu->flags != binfo->flags)
  1625.     {
  1626.       if (!modifying_p)
  1627.     switch (cbu->flags)
  1628.       {
  1629.       case CBEditable:
  1630.         break;
  1631.         
  1632.       case CBReadOnly:
  1633.         /* handle it at the end !! */
  1634.         break;
  1635.         
  1636.       case CBUserInput:
  1637.         {
  1638.           Lisp_Object buffer_local_variable_name = 
  1639.         Qenergize_user_input_buffer_mark;
  1640.           binfo->output_mark = Fmake_marker ();    
  1641.           Fset_marker (binfo->output_mark, 1, binfo->emacs_buffer);
  1642.           /* make sure that this guy doesn't get GC'd out from under us */
  1643.           Fmake_local_variable (buffer_local_variable_name);
  1644.           Fput (buffer_local_variable_name, intern ("permanent-local"),
  1645.             Qt);
  1646.           Fset (buffer_local_variable_name, binfo->output_mark);
  1647.           call0 (Qenergize_user_input_mode);
  1648.           /* Make sure buffer is current after the hook */
  1649.           Fset_buffer (binfo->emacs_buffer);
  1650.         }
  1651.         break;
  1652.       }
  1653.       
  1654.       binfo->flags = cbu->flags;
  1655.     }
  1656.   
  1657.   if (!relative_p)
  1658.     extent_offset = 0;
  1659.   else if (!NILP (binfo->output_mark))
  1660.     extent_offset = Fmarker_position (binfo->output_mark) + text_len - 1;
  1661.   else
  1662.     extent_offset = BUF_Z (XBUFFER (binfo->emacs_buffer)) + text_len - 1;
  1663.   
  1664.   if (text_len)
  1665.     {
  1666.       if (!NILP (binfo->output_mark))
  1667.         {
  1668.       Fset_buffer (binfo->emacs_buffer);
  1669.           if (XMARKER (binfo->output_mark)->buffer)
  1670.             Fgoto_char (binfo->output_mark);
  1671.           else
  1672.         /* This should not happen */
  1673.         Fgoto_char (BUF_ZV (XBUFFER (binfo->emacs_buffer)));
  1674.           
  1675.           if (point <= previous_point)
  1676.         {
  1677. #if 1
  1678.               display_start += text_len;
  1679. #endif
  1680.           previous_point += text_len;
  1681.         }
  1682.       insert_raw_string (text, text_len);
  1683.       Fset_marker (binfo->output_mark, make_number (point),
  1684.                binfo->emacs_buffer);
  1685.         }
  1686.       else if (modifying_p)
  1687.         {
  1688.           Fgoto_char (from);
  1689.           if (!no_text_deleted)
  1690.             insert_raw_string (text, text_len);
  1691.         }
  1692.       else
  1693.         insert_raw_string (text, text_len);
  1694.       
  1695.       previous_point = Fgoto_char (previous_point);
  1696.       
  1697. #if 1
  1698.       if (!NILP (display_window))
  1699.         {
  1700.       
  1701.           Fset_marker (XWINDOW (display_window)->pointm, previous_point,
  1702.                        binfo->emacs_buffer);
  1703.       if (NILP (binfo->output_mark) && should_keep_window_start)
  1704.         {
  1705.           Fset_marker (XWINDOW (display_window)->start, display_start,
  1706.                binfo->emacs_buffer);
  1707.           XWINDOW (display_window)->force_start = Qt;
  1708.         }
  1709.         }
  1710. #endif
  1711.     }
  1712.     
  1713.   
  1714.   /* Classes, generics and extents */
  1715.   ParseClasses (conn, cbu->nClass, binfo, modifying_p);
  1716.   ParseGenerics (conn, cbu->nGeneric, binfo, modifying_p);
  1717.   ParseExtents (conn, cbu->nExtent, binfo, modifying_p, extent_offset);
  1718.   
  1719.   /* Restore the modified bit */
  1720.   Fset_buffer (binfo->emacs_buffer);
  1721.   Fset_buffer_modified_p (modified_buffer_flag);
  1722.   
  1723.   /* restore modified hooks and globals, and return the previous buffer */
  1724.   UNGCPRO;
  1725.   unbind_to (count, Qnil);
  1726.   inside_parse_buffer = 0;
  1727. }
  1728.  
  1729. /* kill an Energize buffer */
  1730. static void
  1731. forget_buffer (BufferInfo *binfo)
  1732. {
  1733.   int i;
  1734.   Lisp_Object buffer = binfo->emacs_buffer;
  1735.  
  1736.   remove_buffer_info (binfo->id, buffer, binfo->editor);
  1737.   energize_buffers_list = Fdelq (buffer, energize_buffers_list);
  1738.  
  1739.   /* if there was an associated screen */
  1740.   if (binfo->screen != Qnil)
  1741.     Fdelete_screen (binfo->screen);
  1742.  
  1743.   /* Also delete the dialog boxes associated to the buffer */
  1744.   BLOCK_INPUT;
  1745.   for (i = 0; i < binfo->n_p_sheets; i++)
  1746.     {
  1747.       lw_destroy_all_widgets (binfo->p_sheet_ids [i]);
  1748.       if (binfo->p_sheet_ids [i] == debuggerpanel_sheet)
  1749.     {
  1750.       debuggerpanel_sheet = 0;
  1751.       desired_debuggerpanel_exposed_p = 0;
  1752.     }
  1753.     }
  1754.   UNBLOCK_INPUT;
  1755.  
  1756.   free_buffer_info (binfo);
  1757.  
  1758.   XBUFFER(buffer)->undo_list = Qnil;
  1759.   /* flush the buffer SOE before flushing the extents */
  1760.   free_buffer_cached_stack (XBUFFER(buffer));
  1761.   XBUFFER(buffer)->extents = Qnil;
  1762. }
  1763.  
  1764. /********************** Request-related utilities ************************/
  1765.  
  1766. /* outputs a single extent in the connection buffer */
  1767. static void
  1768. WriteExtent 
  1769.   (Connection *conn, Energize_Extent_Data *ext, unsigned int start, unsigned int end)
  1770. {
  1771.   switch (ext->extentType)
  1772.     {
  1773.     case CEAttribute:
  1774.       CWriteExtent (conn, CEAttribute, ext->id, start, end,
  1775.                     (EId)ext->u.attr.attrValue);
  1776.       break;
  1777.       
  1778.     case CEAbbreviation:
  1779.       CWriteExtent (conn, CEAbbreviation, ext->id, start, end,
  1780.                     (EId)ext->u.abbrev.isOpened);
  1781.       break;
  1782.       
  1783.     case CEGeneric:
  1784.       CWriteExtent (conn, CEGeneric, ext->id, start, end, 0);
  1785.       break;
  1786.  
  1787.     case CEWriteProtect:
  1788.       CWriteExtent (conn, CEWriteProtect, ext->id, start, end, 0);
  1789.       break;
  1790.     }
  1791. }
  1792.  
  1793. extern void move_gap (int);
  1794.  
  1795. /* Utility to return a char* to the contents of the current buffer */
  1796. static char*
  1797. get_buffer_as_string (unsigned int *len)
  1798. {
  1799.   if (BEGV < GPT && ZV > GPT) move_gap (BEGV);
  1800.   if (len) *len = ZV - BEGV;
  1801.   return (char *)CHAR_ADDRESS (BEGV);
  1802. }
  1803.  
  1804. /* Function called by map_extents in SaveBufferToEnergize. Outputs the
  1805.    extents for the extents corresponding to Energize objects, and
  1806.    increments the n_extents count. */
  1807.  
  1808. static int
  1809. write_an_extent (Lisp_Object extent_obj, void *arg)
  1810. {
  1811.   binfo_and_n_extents *bane = (binfo_and_n_extents*)arg;
  1812.   Energize_Extent_Data *ext = extent_to_data (extent_obj);
  1813.   if (ext)
  1814.     {
  1815.       unsigned int first = XINT (Fextent_start_position (extent_obj));
  1816.       unsigned int last = XINT (Fextent_end_position (extent_obj));
  1817.       WriteExtent (bane->binfo->editor->conn, ext, EnergizePosForEmacsPos (first),
  1818.                    EnergizePosForEmacsPos (last));
  1819.       bane->n_extents += 1;
  1820.     }
  1821.   return 0;
  1822. }
  1823.  
  1824. /* Sends a BufferSaved request to energize for binfo */
  1825. static void
  1826. SaveBufferToEnergize (BufferInfo *binfo)
  1827. {
  1828.   Connection *conn = binfo->editor->conn;
  1829.   EId bufferId = binfo->id;
  1830.   CBuffer *cbu;
  1831.   CEditorRequest *req;
  1832.   char *text;
  1833.   int length;
  1834.   struct buffer *cur_buff = current_buffer;
  1835.   int count = specpdl_ptr - specpdl;
  1836.   Lisp_Object file_name;
  1837.   
  1838.   binfo_and_n_extents bane;
  1839.   
  1840.   /* selects the buffer as current */
  1841.   Fset_buffer (binfo->emacs_buffer);
  1842.   
  1843.   /* write header */
  1844.   cbu = CWriteBufferSavedHeader (conn);
  1845.   cbu->bufferId = bufferId;
  1846.   cbu->flags = 0;
  1847.   cbu->nClass = 0;
  1848.   cbu->nGeneric = 0;
  1849.  
  1850.   /* file name */
  1851.   file_name = current_buffer->filename;
  1852.   if (STRINGP (file_name))
  1853.     CWriteVstring0 (conn, (char *)XSTRING (file_name)->data);
  1854.   else
  1855.     CWriteVstring0 (conn, "");
  1856.   CWriteVstring0 (conn, "");    /* directory name */
  1857.   CWriteVstring0 (conn, "");    /* buffer name */
  1858.   
  1859.   /* write the text */
  1860.   CNeedOutputSize (conn, (Z - BEG) + 9);
  1861.   text = get_buffer_as_string ((unsigned int *) &length);
  1862.   CWriteVstringLen (conn, text, length);
  1863.   
  1864.   /* write the extents */
  1865.   bane.binfo = binfo;
  1866.   bane.n_extents = 0;
  1867.   map_extents (BUF_BEG (current_buffer), BUF_Z (current_buffer), 
  1868.            write_an_extent, 0, &bane, XBUFFER(binfo->emacs_buffer), 1);
  1869.   
  1870.   /* update nextent in request's header */
  1871.   req = (CEditorRequest *)conn->header;
  1872.   req->buffersaved.buffer.nExtent = bane.n_extents;
  1873.   CWriteLength (conn);
  1874.   CWriteRequestBuffer (conn);
  1875.   
  1876.   /* sets the flags so that we will warn Energize about more modifications */
  1877.   binfo->modified_state = 0;
  1878.  
  1879.   /* Mark the buffer as non editable so that we will ask Energize about it
  1880.      before modifying it again */
  1881.   binfo->editable = 0;
  1882.  
  1883.   /* restores the buffer as current */
  1884.   internal_set_buffer (cur_buff);
  1885.   unbind_to (count, Qnil);
  1886. }
  1887.  
  1888. unsigned long
  1889. generic_id_for_extent (Energize_Extent_Data *ext)
  1890. {
  1891.   return ext ? ext->id : 0;
  1892. }
  1893.  
  1894.  
  1895. /********************** Menu ("keywords") operations **********************/
  1896.  
  1897.  
  1898. /* gets the menu for the buffer/extent pair at the head of the request buffer.
  1899. ** returns the propose choice request if succeeds, 0 otherwise (kernel 
  1900. ** connection closed, or not connected) */
  1901.  
  1902. static Lisp_Object
  1903. get_energize_menu (Lisp_Object buffer, Lisp_Object extent_obj, int selection_p,
  1904.            Lisp_Object only_name)
  1905. {
  1906.   Connection*    conn;
  1907.   EId    buffer_id;
  1908.   EId    extent_id;
  1909.   int        result;
  1910.   struct reply_wait rw;
  1911.   struct gcpro gcpro1, gcpro2;
  1912.  
  1913.   if (!get_energize_connection_and_buffer_id (buffer,
  1914.                           (void**)&conn,
  1915.                           (long*)&buffer_id))
  1916.     return 0;
  1917.  
  1918.   if (EXTENTP (extent_obj))
  1919.     extent_id = generic_id_for_extent (extent_to_data (extent_obj));
  1920.   else
  1921.     extent_id = 0;
  1922.   
  1923.   CWriteQueryChoicesRequest (conn, buffer_id, extent_id);
  1924.   conn->header->data =
  1925.     selection_p ? CEChasCharSelection | CEChasObjectSelection : 0;
  1926.   conn->header->serial = ++request_serial_number;
  1927.   CWriteRequestBuffer (conn);
  1928.  
  1929.   /* wait for the acknowledge */
  1930.   rw.serial = request_serial_number;
  1931.   rw.objectId = buffer_id;
  1932.   rw.genericId = extent_id;
  1933.   rw.menu_result = Qnil;
  1934.   rw.only_name = only_name;
  1935.   
  1936.   GCPRO2 (rw.menu_result, rw.only_name);
  1937.   wait_for_reply (&rw);
  1938.   result = rw.menu_result;
  1939.   UNGCPRO;
  1940.   return result;
  1941. }
  1942.  
  1943. static int
  1944. something_answered_p (void* arg)
  1945. {
  1946.   struct reply_wait* rw = (struct reply_wait*)arg;
  1947.   return rw->answered_p || !energize_connection || !energize_connection->conn;
  1948. }
  1949.  
  1950.  
  1951. static void
  1952. push_wait (struct reply_wait* rw)
  1953. {
  1954.   rw->next = global_reply_wait;
  1955.   global_reply_wait = rw;
  1956. }
  1957.  
  1958. static Lisp_Object
  1959. remove_wait (Lisp_Object obj)
  1960. {
  1961.   struct reply_wait* gw;
  1962.   struct reply_wait* previous;
  1963.   struct reply_wait* rw = (struct reply_wait*)lisp_to_word (obj);
  1964.  
  1965.   for (previous = 0, gw = global_reply_wait;
  1966.        gw != rw;
  1967.        previous = gw, gw = gw->next);
  1968.   if (previous)
  1969.     previous->next = gw->next;
  1970.   else
  1971.     global_reply_wait = gw->next;
  1972.   return Qnil;
  1973. }
  1974.  
  1975. static struct reply_wait*
  1976. find_wait_reply (int serial)
  1977. {
  1978.   struct reply_wait* gw;
  1979.   for (gw = global_reply_wait; gw && gw->serial != serial; gw = gw->next);
  1980.   return gw;
  1981. }
  1982.  
  1983.  
  1984. static int
  1985. wait_for_reply (struct reply_wait* rw)
  1986. {
  1987.   int count = specpdl_ptr - specpdl;
  1988.   rw->answered_p = 0;
  1989.   push_wait (rw);
  1990.   record_unwind_protect (remove_wait, word_to_lisp ((int)rw));
  1991.   wait_delaying_user_input (something_answered_p, rw);
  1992.   unbind_to (count, Qnil);
  1993.   return rw->answered_p;
  1994. }
  1995.  
  1996. static void
  1997. execute_energize_menu (Lisp_Object buffer, Energize_Extent_Data* ext, char* name,
  1998.                EId item_id, EId flags, Lisp_Object selection,
  1999.                Lisp_Object no_confirm)
  2000. {
  2001.   Connection*    conn;
  2002.   EId    buffer_id;
  2003.   EId    extent_id;
  2004.   BufferInfo*    binfo;
  2005.   struct reply_wait rw;
  2006.   
  2007.   if (!get_energize_connection_and_buffer_id (buffer, (void**)&conn,
  2008.                           (long*)&buffer_id))
  2009.     return;
  2010.  
  2011.   extent_id = generic_id_for_extent (ext);
  2012.   
  2013.   if ((flags & CKBuffer) && Fbuffer_modified_p (buffer))
  2014.     {
  2015.       /* saves buffer if requested and needed */
  2016.       binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection);
  2017.       if (binfo)
  2018.     SaveBufferToEnergize (binfo);
  2019.     }
  2020.  
  2021.   CWriteExecuteChoicesRequest (conn, buffer_id, extent_id, item_id, 0, 0);
  2022.   /* send the menu name */
  2023.   if (energize_connection->minor >= 7)
  2024.     CWriteVstring0 (conn, name);
  2025.   conn->header->serial = ++request_serial_number;
  2026.   conn->header->data = 0;
  2027.   switch (XTYPE (selection))
  2028.     {
  2029.     case Lisp_String:
  2030.       conn->header->data |= CEChasCharSelection;
  2031.       CWriteVstringLen (conn, (char*)XSTRING (selection)->data,
  2032.             XSTRING (selection)->size);
  2033.       break;
  2034.     case Lisp_Vector:
  2035.       {
  2036.     int i;
  2037.     EId data;
  2038.     conn->header->data |= CEChasObjectSelection;
  2039.  
  2040.     /* writes the length */
  2041.     data = XVECTOR (selection)->size;
  2042.     CWrite (conn, EId, &data);    
  2043.  
  2044.     /* writes the elements */
  2045.     for (i = 0; i < XVECTOR (selection)->size; i++)
  2046.       {
  2047.         if (CONSP (XVECTOR (selection)->contents [i]))
  2048.           data = lisp_to_word (XVECTOR (selection)->contents [i]);
  2049.         else
  2050.           data = XVECTOR (selection)->contents [i];
  2051.         CWrite (conn, EId, &data);
  2052.       }
  2053.       }
  2054.       break;
  2055.  
  2056.     case Lisp_Cons:
  2057.       {
  2058.     Lisp_Object type = Fcar (selection);
  2059.     Lisp_Object value = Fcdr (selection);
  2060.     if (EQ (type, intern ("ENERGIZE_OBJECT"))
  2061.         && STRINGP (value))
  2062.       {
  2063.         conn->header->data |= CEChasObjectSelection;
  2064.         CWriteN (conn, char, XSTRING (value)->data,
  2065.              XSTRING (value)->size);
  2066.       }
  2067.       }
  2068.       break;
  2069.  
  2070.     default:
  2071.       if (!NILP (selection))
  2072.     error ("unrecognised energize selection");
  2073.     }
  2074.   if (!NILP (no_confirm))
  2075.     conn->header->data |= CECnoConfirm;
  2076.   CWriteLength (conn);
  2077.   CWriteRequestBuffer (conn);
  2078.  
  2079.   /* wait for the acknowledge */
  2080.   rw.serial = request_serial_number;
  2081.   rw.objectId = buffer_id;
  2082.   rw.genericId = extent_id;
  2083.   rw.itemId = item_id;
  2084.   rw.message = 0;
  2085.   
  2086.   if (wait_for_reply (&rw) && !rw.status)
  2087.     {
  2088.       char message [128];
  2089.       if (energize_connection && energize_connection->conn)
  2090.     sprintf (message, "Energize command failed: %.80s",
  2091.          (rw.message ? rw.message : "(null)"));
  2092.       else
  2093.     sprintf (message, "Connection to Energize was closed.");
  2094.       if (rw.message)
  2095.     xfree (rw.message);
  2096.       error (message);
  2097.     }
  2098.   else
  2099.     {
  2100.       if (rw.message)
  2101.     xfree (rw.message);
  2102.       if (!energize_connection)
  2103.     error ("Connection to Energize was closed.");
  2104.     }
  2105.  }
  2106.  
  2107. /* Returns a list of vectors representing the menu choices.  Next request
  2108.    in connection must be a ProposeChoices.  The list is 
  2109.    (buffer extent <item1> ... <itemN>).  <itemI> is (name id1 id2 flags).
  2110.    Idi is (high .  low).  We build the list in reverse order and nreverse
  2111.    it.  If (only_name != 0), we only return the item of named only_name as
  2112.    a vector.  */
  2113.  
  2114. static Lisp_Object
  2115. list_choices (Lisp_Object buffer, Lisp_Object extent_obj, 
  2116.               Lisp_Object only_name, CProposeChoicesRequest* creq)
  2117. {
  2118.   Connection *conn;
  2119.   int i;
  2120.   Lisp_Object item_list;
  2121.   Lisp_Object item;
  2122.   struct Lisp_Vector *v;
  2123.   struct gcpro gcpro1, gcpro2, gcpro3;
  2124.   CChoice *choice;
  2125.   ReqLen name_length;
  2126.   char *name;
  2127.   char *arg_name;
  2128.  
  2129.   if (energize_connection && energize_connection->conn)
  2130.     conn = energize_connection->conn;
  2131.   else
  2132.     return Qnil;
  2133.   
  2134.   if (!creq || creq->head.reqType != ProposeChoicesRType)
  2135.     {
  2136.       CSkipRequest (conn);
  2137.       return Qnil;
  2138.     }
  2139.   
  2140.   item = Qnil;
  2141.   item_list = Qnil;
  2142.   
  2143.   GCPRO3 (only_name, item_list, item);
  2144.   
  2145.   for (i = 0; i < (int)(creq->nChoices); i++)
  2146.     {
  2147.       choice = CGet (conn, CChoice);
  2148.       name = CGetVstring (conn, &name_length);
  2149.       if (!name_length)
  2150.     continue;
  2151.  
  2152.       /* the argument, if passed, is another string after the NUL (!)
  2153.        * this is a quick hack to provide cheap arguments to menus entries */
  2154.       arg_name = strchr (name, 0240);
  2155.       if (arg_name)
  2156.     {
  2157.       *arg_name= 0;
  2158.       arg_name += 1;
  2159.     }
  2160.  
  2161.       if (!NILP (only_name))
  2162.     {
  2163.       if (!strcmp ((char*)XSTRING(only_name)->data, name))
  2164.         {
  2165.           if (NILP (item))
  2166.         {
  2167.           item = Fmake_vector (5, Qnil);
  2168.           v = XVECTOR (item);
  2169.           v->contents [0] = only_name;
  2170.         }
  2171.               v->contents [1] = word_to_lisp (choice->choiceId);
  2172.               v->contents [2] = Qnil;
  2173.               v->contents [3] = choice->flags;
  2174.           v->contents [4] = arg_name ? build_string (arg_name) : Qnil;
  2175.         }
  2176.     }
  2177.       else
  2178.     {
  2179.       item = Fmake_vector (5, Qnil);
  2180.       v = XVECTOR (item);
  2181.       v->contents [0] = build_string (name);
  2182.       v->contents [1] = word_to_lisp (choice->choiceId);
  2183.       v->contents [2] = Qnil;
  2184.       v->contents [3] = choice->flags;
  2185.       v->contents [4] = arg_name ? build_string (arg_name) : Qnil;
  2186.       item_list = Fcons (item, item_list); /* pushes in the list */
  2187.         }
  2188.     }
  2189.   
  2190.   if (NILP (only_name))
  2191.     item_list = Fcons (buffer, Fcons (extent_obj, Fnreverse (item_list)));
  2192.   UNGCPRO;
  2193.   
  2194.   return NILP (only_name) ? item_list : item;
  2195. }
  2196.  
  2197. DEFUN ("energize-list-menu", Fenergize_list_menu,
  2198.        Senergize_list_menu, 3, 4, 0,
  2199.        "(energize-list-menu buffer extent selection-p [only-name])\n\
  2200. Request the set of menu options from the Energize server that are\n\
  2201. appropriate to the buffer and the extent.  Extent can be (), in which case\n\
  2202. the options are requested for the whole buffer.  Selection-p tells\n\
  2203. if the selection is available on the dislpay emacs is using. \n\
  2204. Returns the options as\n\
  2205. a list that can be passed to energize-activate-menu.  Items\n\
  2206. in the list can also be passed to energize-execute-menu-item.\n\
  2207. The list is (buffer extent or () <item1> ... <itemN>).\n\
  2208. where <itemI> is (name id1 id2 flags); idI is (high . low).\n\
  2209. If optional argument only-name is provided only the item with name only-name\n\
  2210. is returned, or () if no such item exists.")
  2211.      (buffer, extent_obj, selection_p, only_name)
  2212.      Lisp_Object buffer, extent_obj, selection_p, only_name;
  2213. {
  2214.   Lisp_Object res;
  2215.   CHECK_BUFFER (buffer, 1);
  2216.   
  2217.   if (!energize_connection || !energize_connection->conn) return Qnil;
  2218.  
  2219.   if (!NILP (only_name))
  2220.     CHECK_STRING (only_name, 1);
  2221.   
  2222.   res = get_energize_menu (buffer, extent_obj, selection_p != Qnil,
  2223.                only_name);
  2224.   notify_delayed_requests ();
  2225.   return res;
  2226. }
  2227.  
  2228. DEFUN ("energize-execute-menu-item", Fenergize_execute_menu_item,
  2229.        Senergize_execute_menu_item, 3, 5, 0,
  2230.        "(energize-execute-menu-item buffer extent item argument no-confirm)\n\
  2231. Item is a vector received by energize-list-menu.  Sends a request to\n\
  2232. execute the code associated to this menu inside the Energize server.\n\
  2233. Optional fourth argument is a string or a vector to be used as the selection\n\
  2234. for entry disabled because they need the selection.\n\
  2235. Optional fifth argument, if non NIL, tells Energize to not request \n\
  2236. confirmation before executing the command.")
  2237. (buffer, extent_obj, item, selection, no_confirm)
  2238. Lisp_Object buffer, extent_obj, item, selection, no_confirm;
  2239. {
  2240.   struct Lisp_Vector *v;
  2241.   
  2242.   if (!energize_connection || !energize_connection->conn) return Qnil;
  2243.  
  2244.   CHECK_BUFFER (buffer, 1);
  2245.   CHECK_VECTOR (item, 1);
  2246.   v = XVECTOR (item);
  2247.  
  2248.   if (v->size != 4)
  2249.     error ("Bad menu item to energize-execute-menu-item");
  2250.   
  2251.   /* ignore the flags for now */
  2252.   execute_energize_menu (buffer, extent_to_data (extent_obj),
  2253.              (char*)XSTRING (v->contents [0])->data,
  2254.              lisp_to_word (v->contents [1]),
  2255.              v->contents [3],
  2256.              selection,
  2257.              no_confirm);
  2258.  
  2259.   return Qt;
  2260. }
  2261.  
  2262. DEFUN ("energize-execute-command-internal", Fenergize_execute_command_internal,
  2263.        Senergize_execute_command_internal, 3, 5, 0,
  2264.        "(energize-execute-command-internal buffer extent command argument no-confirm)\n\
  2265. Command is a string naming an energize command.  Sends a request to\n\
  2266. execute this command inside the Energize server.\n\
  2267. Optional fourth argument is a string or a vector to be used as the selection.\n\
  2268. Optional fifth argument, if non NIL, tells Energize to not request \n\
  2269. confirmation before executing the command.\n\
  2270. \n\
  2271. See also 'energize-list-menu'.")
  2272. (buffer, extent_obj, command, selection, no_confirm)
  2273. Lisp_Object buffer, extent_obj, command, selection, no_confirm;
  2274. {
  2275.   if (!energize_connection || !energize_connection->conn) return Qnil;
  2276.  
  2277.   CHECK_BUFFER (buffer, 1);
  2278.   CHECK_STRING (command, 1);
  2279.   
  2280.   execute_energize_menu (buffer, extent_to_data (extent_obj),
  2281.              (char*)XSTRING (command)->data, 0, 0, selection,
  2282.              no_confirm);
  2283.  
  2284.   return Qt;
  2285. }
  2286.  
  2287. /********************************* kill buffer interface ****************/
  2288.  
  2289. DEFUN ("energize-buffer-type-internal",
  2290.        Fenergize_buffer_type, Senergize_buffer_type,
  2291.        1, 1, 0,
  2292.        "(energize-buffer-type buffer) returns a symbol denoting the buffer \n\
  2293. type if buffer is an Energize buffer, else it returns NIL.")
  2294.     (buffer)
  2295.     Lisp_Object buffer;
  2296. {
  2297.   if (!energize_connection) return Qnil;
  2298.   
  2299.   CHECK_BUFFER (buffer, 1);
  2300.   return get_buffer_type_for_emacs_buffer (buffer, energize_connection);
  2301. }
  2302.  
  2303. DEFUN ("set-energize-buffer-type-internal", 
  2304.        Fset_energize_buffer_type_internal, 
  2305.        Sset_energize_buffer_type_internal, 2, 2, 0,
  2306.  "(set-energize-buffer-type-internal buffer type) returns the type \n\
  2307. symbol which is the new buffer-type, if the buffer is an Energize buffer and\n\
  2308. the type is non-NIL symbol, else it returns NIL.")
  2309.    (buffer, type)
  2310.     Lisp_Object buffer, type;
  2311. {
  2312.   BufferInfo *binfo;
  2313.   
  2314.   if (!energize_connection || (type == Qnil)) return Qnil;
  2315.   
  2316.   CHECK_BUFFER (buffer, 1);
  2317.   CHECK_SYMBOL (type, 1);
  2318.   
  2319.   if (!(binfo =
  2320.     get_buffer_info_for_emacs_buffer (buffer, energize_connection))) 
  2321.     return Qnil;
  2322.   else 
  2323.     return
  2324.       set_buffer_type_for_emacs_buffer (buffer, energize_connection, type);
  2325. }
  2326.  
  2327. DEFUN ("energize-buffer-p", Fenergize_buffer_p, Senergize_buffer_p, 1, 1, 0,
  2328.        "(energize-buffer-p buffer) returns T if buffer is \n\
  2329. an Energize buffer, otherwise NIL.")
  2330.   (buffer)
  2331.   Lisp_Object buffer;
  2332. {
  2333.   BufferInfo *binfo;
  2334.   
  2335.   if (!energize_connection) return Qnil;
  2336.   
  2337.   CHECK_BUFFER (buffer, 1);
  2338.   if (!(binfo =
  2339.     get_buffer_info_for_emacs_buffer (buffer, energize_connection)))
  2340.     return Qnil;
  2341.   else
  2342.     return Qt;
  2343. }  
  2344.  
  2345. DEFUN ("energize-buffer-id", Fenergize_buffer_id, Senergize_buffer_id, 1, 1, 0,
  2346.        "(energize-buffer-id buffer)\n\
  2347. Returns (high . low) if buffer is an Energize buffer, () otherwise")
  2348.      (buffer)
  2349.      Lisp_Object buffer;
  2350. {
  2351.   BufferInfo *binfo;
  2352.   
  2353.   if (!energize_connection) return Qnil;
  2354.   
  2355.   CHECK_BUFFER (buffer, 1);
  2356.   if (!(binfo =
  2357.     get_buffer_info_for_emacs_buffer (buffer, energize_connection)))
  2358.     return Qnil;
  2359.   else
  2360.     return word_to_lisp (binfo->id);
  2361. }  
  2362.  
  2363. DEFUN ("energize-request-kill-buffer", Fenergize_request_kill_buffer,
  2364.        Senergize_request_kill_buffer, 1, 1, 0,
  2365.        "(energize-request-kill-buffer buffer)\n\
  2366. Sends a request to energize for killing buffer")
  2367.    (buffer)
  2368.    Lisp_Object buffer;
  2369. {
  2370.   BufferInfo *binfo;
  2371.   
  2372.   if (!energize_connection) return Qnil;
  2373.   
  2374.   CHECK_BUFFER (buffer, 1);
  2375.   if (!(binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection))) 
  2376.     return Qnil;
  2377.   
  2378.   /* Tell Energize about it if connected */
  2379.   if (energize_connection->conn)
  2380.     {
  2381.       CWriteKillBufferHeader (energize_connection->conn, binfo->id);
  2382.       CWriteRequestBuffer (energize_connection->conn);
  2383.     }
  2384.  
  2385.   /* Clears the internal state */
  2386.   forget_buffer (binfo);
  2387.  
  2388.   return Qnil;
  2389. }
  2390.  
  2391. /******************** Handle requests from the kernel *********************/
  2392.  
  2393. #ifdef EMACS_BTL
  2394. #include "cadillac-btl-extern.h"
  2395. #endif
  2396.  
  2397. /* turn logging on or off, etc. */
  2398. static void
  2399. HandleLoggingRequest (Editor *editor, CLoggingRequest *creq)
  2400.      /* I'm a lumberjack and I'm ok... */
  2401. {
  2402.   ReqLen name_len;
  2403.   char* data_filename = CGetVstring (editor->conn, &name_len);
  2404.  
  2405. #ifdef EMACS_BTL
  2406.   {
  2407.     extern Lisp_Object Vexecution_path;
  2408.     char *execname = 
  2409.       (STRINGP (Vexecution_path))?
  2410.         ((char *) XSTRING(Vexecution_path)->data):0;
  2411.  
  2412.     switch (creq->type)
  2413.       {
  2414.       case CLRInitBTL:
  2415.         cadillac_terminate_logging(); /* #### rename me */
  2416.         cadillac_initialize_backtrace_logging /* #### rename me */
  2417.           (data_filename, execname, (long) creq->limit, (long) creq->interval);
  2418.         break;
  2419.  
  2420.       case CLRInitPCL:
  2421.         cadillac_terminate_logging(); /* #### rename me */
  2422.         cadillac_initialize_pc_logging /* #### rename me */
  2423.           (data_filename, execname, (long) creq->limit, (long) creq->interval);
  2424.         break;
  2425.  
  2426.       case CLRStart:
  2427.         cadillac_start_logging(); /* #### rename me */
  2428.         break;
  2429.  
  2430.       case CLRStop:
  2431.         cadillac_stop_logging(); /* #### rename me */
  2432.         break;
  2433.  
  2434.       case CLRTerminate:
  2435.         cadillac_terminate_logging(); /* #### rename me */
  2436.         break;
  2437.         
  2438.       case CLRSetLogSignal:
  2439.         cadillac_set_log_signal(creq->signal); /* #### rename me */
  2440.         break;
  2441.         
  2442.       default:
  2443.         error ("Bad logging request type %d", creq->type);
  2444.       }
  2445.   }
  2446. #else
  2447.   Post ("Logging request, but no such code in image.");
  2448. #endif
  2449. }
  2450.  
  2451.  
  2452.  
  2453. /* creates a new buffer */
  2454. static void
  2455. HandleNewBufferRequest (Editor *editor, CNewBufferRequest *creq)
  2456. {
  2457.   ParseBuffer (editor->conn, &creq->buffer, editor, 0, 0, creq->transientId,
  2458.            0);
  2459.   if (!NILP (Venergize_create_buffer_hook))
  2460.     {
  2461.       CBuffer *cbu = &creq->buffer;
  2462.       BufferInfo *binfo = get_buffer_info_for_id (cbu->bufferId, editor);
  2463.       Lisp_Object buffer;
  2464.       if (binfo)
  2465.         {
  2466.       struct screen* prev_screen;
  2467.           buffer = binfo->emacs_buffer;
  2468.       if (!NILP (binfo->screen))
  2469.         {
  2470.           prev_screen = selected_screen;
  2471.           selected_screen = XSCREEN(binfo->screen);
  2472.         }
  2473.       safe_funcall_hook (Venergize_create_buffer_hook, 1, buffer, 0, 0);
  2474.       if (!NILP (binfo->screen))
  2475.         selected_screen = prev_screen;
  2476.         }
  2477.     }
  2478. }
  2479.  
  2480. /* Modifies the contents of a buffer */
  2481. static void
  2482. HandleModifyBufferRequest (Editor *editor, CModifyBufferRequest *creq)
  2483. {
  2484.   windows_or_buffers_changed++;
  2485.   ParseBuffer (editor->conn, &creq->newData, editor, creq->startPosition,
  2486.                creq->endPosition, 0, creq->head.data);
  2487. }
  2488.  
  2489. static void
  2490. MakeBufferAndExtentVisible (Lisp_Object list, Lisp_Object go_there)
  2491. {
  2492.   call2 (Qenergize_make_many_buffers_visible, list, go_there);
  2493. }
  2494.  
  2495. /* pops a buffer and scroll to a extent: calls to lisp */
  2496. static void
  2497. HandleEnsureVisibleRequest (Editor *editor, CEnsureVisibleRequest *creq)
  2498. {
  2499.   BufferInfo *binfo;
  2500.   Energize_Extent_Data *ext;
  2501.   Lisp_Object buffer_extent_list;
  2502.   struct gcpro gcpro1;
  2503.  
  2504.   buffer_extent_list = Qnil;
  2505.   GCPRO1 (buffer_extent_list);
  2506.   
  2507.   binfo = get_buffer_info_for_id (creq->bufferId, editor);
  2508.   if (!binfo)
  2509.     {
  2510.       Post ("EnsureVisibleRequest: unknown buffer");
  2511.       goto finished;
  2512.     }
  2513.   
  2514.   if (binfo->screen != Qnil)
  2515.     {
  2516.       /* ignore ensure visible for postit note buffers */
  2517.       goto finished;
  2518.     }
  2519.  
  2520.   if (creq->extentId)
  2521.     {
  2522.       ext = get_extent_data (creq->extentId, binfo);
  2523.       if (!ext)
  2524.     Post ("EnsureVisibleRequest: ignoring unknown extent");
  2525.     }
  2526.   else
  2527.     ext = 0;
  2528.   
  2529.   buffer_extent_list = Fcons (ext ? ext->extent : Qnil, Qnil);
  2530.   buffer_extent_list = Fcons (binfo->emacs_buffer, buffer_extent_list);
  2531.  
  2532.   MakeBufferAndExtentVisible (buffer_extent_list, creq->head.data ? Qt : Qnil);
  2533.   
  2534.  finished:
  2535.   CSkipRequest (editor->conn);
  2536.   UNGCPRO;
  2537. }
  2538.  
  2539. static void
  2540. HandleEnsureManyVisibleRequest (Editor *editor,
  2541.                 CEnsureManyVisibleRequest *creq)
  2542. {
  2543.   BufferInfo *binfo;
  2544.   Energize_Extent_Data *ext;
  2545.   Lisp_Object buffer_extent_list;
  2546.   int n;
  2547.   EId buffer_id;
  2548.   EId extent_id;
  2549.   struct gcpro gcpro1;
  2550.  
  2551.   buffer_extent_list = Qnil;
  2552.   GCPRO1 (buffer_extent_list);
  2553.   
  2554.   for (n = creq->head.data,
  2555.        buffer_id = creq->bufferId,
  2556.        extent_id = creq->extentId;
  2557.        n;
  2558.        n--,
  2559.        buffer_id = n ? *(CGet (editor->conn, EId)) : 0,
  2560.        extent_id = n ? *(CGet (editor->conn, EId)) : 0)
  2561.     {
  2562.       binfo = get_buffer_info_for_id (buffer_id, editor);
  2563.       if (!binfo)
  2564.     {
  2565.       Post ("EnsureManyVisibleRequest: ignoring unknown buffer");
  2566.       continue;
  2567.     }
  2568.       
  2569.       if (binfo->screen != Qnil)
  2570.     {
  2571.       /* silently ignore ensure visible for postit note buffers */
  2572.       continue;
  2573.     }
  2574.       
  2575.       if (extent_id)
  2576.     {
  2577.       ext = get_extent_data (extent_id, binfo);
  2578.       if (!ext)
  2579.         Post ("EnsureManyVisibleRequest: ignoring unknown extent");
  2580.     }
  2581.       else
  2582.     ext = 0;
  2583.  
  2584.       /* cons in reverse order and reverse the list before
  2585.      calling MakeBufferAndExtentVisible */
  2586.       buffer_extent_list = Fcons (binfo->emacs_buffer, buffer_extent_list);
  2587.       buffer_extent_list = Fcons (ext ? ext->extent : Qnil,
  2588.                   buffer_extent_list);
  2589.     }
  2590.   buffer_extent_list = Fnreverse (buffer_extent_list);
  2591.   MakeBufferAndExtentVisible (buffer_extent_list, Qt);
  2592.   
  2593.   UNGCPRO;
  2594. }
  2595.  
  2596. /* Update the cached menus, ie update the menubar for now. */
  2597. static void
  2598. HandleProposeChoicesRequest (Editor *editor, CProposeChoicesRequest *req)
  2599. {
  2600.   BufferInfo* binfo;
  2601.   Lisp_Object buffer = Qnil;
  2602.   Lisp_Object extent = Qnil;
  2603.   Lisp_Object choices = Qnil;
  2604.   struct gcpro gcpro1, gcpro2, gcpro3;
  2605.   struct reply_wait* rw;
  2606.  
  2607.   GCPRO3 (buffer, extent, choices);
  2608.   
  2609.   /* get the buffer */
  2610.   binfo = get_buffer_info_for_id (req->objectId, editor);
  2611.   if (binfo)
  2612.     buffer = binfo->emacs_buffer;
  2613.   else
  2614.     buffer = Qnil;
  2615.  
  2616.   /* get the extent */
  2617.   if (binfo && req->genericId)
  2618.     {
  2619.       Energize_Extent_Data* ext = get_extent_data (req->genericId, binfo);
  2620.       if (ext)
  2621.     extent = ext->extent;
  2622.       else
  2623.     extent = Qnil;
  2624.     }
  2625.   else
  2626.     extent = Qnil;
  2627.   
  2628.   /* find if we were waiting for a reply */
  2629.   rw = find_wait_reply (req->head.serial);
  2630.  
  2631.   /* handle the request */
  2632.   if (rw && rw->objectId == req->objectId && rw->genericId == req->genericId)
  2633.     {
  2634.       /* It's a reply for a get_energize_menu call */
  2635.       rw->answered_p = True;
  2636.       rw->status = 1;
  2637.       rw->menu_result = list_choices (buffer, extent, rw->only_name, req);
  2638.     }
  2639.   else
  2640.     {
  2641.       /* It's a menu update, call the hook */
  2642.       choices = list_choices (buffer, extent, Qnil, req);
  2643.       safe_funcall_hook (Venergize_menu_update_hook, 1, choices, Qnil, Qnil);
  2644.     }
  2645.   UNGCPRO;
  2646. }
  2647.  
  2648. /* Kills a buffer */
  2649. static void
  2650. unmodify_buffer_and_kill_it (Lisp_Object buffer)
  2651. {
  2652.   int count = specpdl_ptr - specpdl;
  2653.  
  2654.   if ((!BUFFERP (buffer)) || NILP (XBUFFER (buffer)->name)) 
  2655.     return;
  2656.   
  2657.   /* unmodify the buffer */
  2658.   if (buffer != Fcurrent_buffer ())
  2659.     {
  2660.       record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
  2661.       Fset_buffer (buffer);
  2662.     }
  2663.   Fset_buffer_modified_p (Qnil);
  2664.   unbind_to (count, Qnil);
  2665.   
  2666.   /* kill it.  This will call the Energize hook to do the right thing */
  2667.   Fkill_buffer (buffer);
  2668. }
  2669.  
  2670. static void
  2671. HandleKillBufferRequest (Editor *editor, CKillBufferRequest *creq)
  2672. {
  2673.   BufferInfo *binfo;
  2674.   
  2675.   if (!(binfo = get_buffer_info_for_id (creq->bufferId, editor)))
  2676.     {
  2677.       Post ("KillBufferVisibleRequest: unregistered buffer");
  2678.       return;
  2679.     }
  2680.  
  2681.   unmodify_buffer_and_kill_it (binfo->emacs_buffer);
  2682. }
  2683.  
  2684. static void
  2685. HandleRemoveExtentsRequest (Editor *editor, CRemoveExtentsRequest *creq)
  2686. {
  2687.   BufferInfo *binfo;
  2688.   int i;
  2689.   EId *ids;
  2690.   Lisp_Object restore_buffer_state_cons;
  2691.   int count = specpdl_ptr - specpdl;
  2692.   
  2693.   if (!(binfo = get_buffer_info_for_id (creq->bufferId, editor)))
  2694.     {
  2695.       Post ("RemoveExtentsRequest: unregistered buffer");
  2696.       CSkipRequest (editor->conn);
  2697.       return;
  2698.     }
  2699.  
  2700.   /* enable buffer edits */
  2701.   restore_buffer_state_cons =
  2702.     Fcons (word_to_lisp (creq->bufferId),
  2703.        Fcons (XBUFFER(binfo->emacs_buffer)->read_only, Qnil));
  2704.  
  2705.   record_unwind_protect (restore_buffer_state, restore_buffer_state_cons);
  2706.  
  2707.   XBUFFER(binfo->emacs_buffer)->read_only = Qnil;
  2708.  
  2709.   /* save old hook values */
  2710.   specbind (Qenergize_buffer_modified_hook, Qnil); 
  2711.   
  2712.   BUF_FACECHANGE (XBUFFER (binfo->emacs_buffer))++;
  2713.   windows_or_buffers_changed++;
  2714.   
  2715.   ids = CGetN (editor->conn, EId, creq->nExtent);
  2716.   for (i = 0; i < creq->nExtent; i++)
  2717.     {
  2718.       Energize_Extent_Data *ext = get_extent_data (ids [i], binfo);
  2719.       if (ext)
  2720.         free_Energize_Extent_Data (ext, binfo, OFT_STANDALONE);
  2721.     }
  2722.   
  2723.   /* restore modified hooks and globals */
  2724.   unbind_to (count, Qnil);
  2725. }
  2726.  
  2727. /* handles a request to save a buffer from the kernel */
  2728. static void
  2729. HandleSaveBufferRequest (Editor *editor, CSaveBufferRequest *creq)
  2730. {
  2731.   BufferInfo *binfo;
  2732.   int count = specpdl_ptr - specpdl;
  2733.  
  2734.   if (!(binfo = get_buffer_info_for_id (creq->bufferId, editor)))
  2735.     {
  2736.       Post("Server attempt to save a non registered buffer");
  2737.       return;
  2738.     }
  2739.   
  2740.   if (binfo->emacs_buffer != Fcurrent_buffer ())
  2741.     {
  2742.       record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
  2743.       Fset_buffer (binfo->emacs_buffer);
  2744.     }
  2745.  
  2746.   if (creq->head.data == CSExecuteSave)
  2747.     {
  2748.       Lisp_Object args[2];
  2749.       args [0] = intern ("save-buffer");
  2750.       args [1] = Qnil;
  2751.       Fapply (2, args);
  2752.     }
  2753.   else
  2754.     SaveBufferToEnergize (binfo);
  2755.   
  2756.   unbind_to (count, Qnil);
  2757. }
  2758.  
  2759. static void
  2760. HandleSetModifiedFlagRequest (Editor* editor, CSetModifiedFlagRequest* creq)
  2761. {
  2762.   BufferInfo *binfo;
  2763.   int count = specpdl_ptr - specpdl;
  2764.  
  2765.   if (!(binfo = get_buffer_info_for_id (creq->bufferId, editor)))
  2766.     {
  2767.       Post("Server attempt to set modified flag of a non registered buffer");
  2768.       return;
  2769.     }
  2770.   
  2771.   record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
  2772.   Fset_buffer (binfo->emacs_buffer);
  2773.   specbind (Qenergize_buffer_modified_hook, Qnil);
  2774.   Fset_buffer_modtime (binfo->emacs_buffer, Qnil);
  2775.   Fset_buffer_modified_p (creq->state ? Qt : Qnil);
  2776.   binfo->modified_state = creq->state;
  2777.   /* Mark the buffer so that we ask permission to Energize when the
  2778.    * user tries to modify it again */
  2779.   binfo->editable = 0;
  2780.   if (!creq->state)
  2781.     mark_all_extents_as_unmodified (binfo);
  2782.   unbind_to (count, Qnil);
  2783. }
  2784.  
  2785.  
  2786. /* handles requests regarding p_sheet associated to buffers */
  2787. static void
  2788. add_in_list_of_ids (int** ids, int* n_ids, int id){
  2789.   if (*n_ids == 0){
  2790.     *n_ids = 1;
  2791.     *ids = (int*)xmalloc (sizeof (int));
  2792.   }else{
  2793.     *n_ids += 1;
  2794.     *ids = (int*)xrealloc (*ids, sizeof (int) * (*n_ids));
  2795.   }
  2796.   (*ids) [(*n_ids) - 1] = id;
  2797. }
  2798.  
  2799. static void
  2800. remove_from_list_of_ids (int** ids, int* n_ids, int id){
  2801.   int i;
  2802.   if (*n_ids){
  2803.     /* look for id in *ids */
  2804.     for (i = 0; i < (*n_ids) && (*ids) [i] != id; i++);
  2805.     /* shift the remaining ones */
  2806.     for (; i < (*n_ids) - 1; i++)
  2807.       (*ids) [i] = (*ids) [i + 1];
  2808.     /* decrease the count */
  2809.     *n_ids -= 1;
  2810.     /* free array if empty */
  2811.     if (!*n_ids){
  2812.       xfree (*ids);
  2813.       *ids = 0;
  2814.     }
  2815.   }
  2816. }
  2817.  
  2818. extern void make_psheets_desired (struct screen *, Lisp_Object);
  2819.  
  2820. static void
  2821. HandleBufferSheetRequest (Editor *editor, CSheetRequest *sreq,
  2822.               EId buffer_id)
  2823. {
  2824.   BufferInfo *binfo;
  2825.   char* name;
  2826.   Connection* conn = editor->conn;
  2827.   
  2828.   if (!(binfo = get_buffer_info_for_id (buffer_id, editor)))
  2829.     {
  2830.       Post("Server attempt to use p_sheet in a non registered buffer");
  2831.       CSkipRequest (conn);
  2832.       return;
  2833.     }
  2834.   
  2835.   name = CGetVstring (conn, (ReqLen *) 0);
  2836.   switch ((CSheetRSubtype) sreq->head.data)
  2837.     {
  2838.     case CSCreate:
  2839.       BLOCK_INPUT;
  2840.       lw_register_widget (name, name, sreq->sheetId, NULL, NULL,
  2841.               HandleControlChange, NULL);
  2842.       UNBLOCK_INPUT;
  2843.       add_in_list_of_ids (&binfo->p_sheet_ids, &binfo->n_p_sheets,
  2844.               sreq->sheetId);
  2845.       if (!strcmp (name, DEBUGGER_PSHEET_NAME)) 
  2846.     debuggerpanel_sheet = sreq->sheetId;
  2847.       break;
  2848.       
  2849.     case CSDelete:
  2850.       remove_from_list_of_ids (&binfo->p_sheet_ids, &binfo->n_p_sheets,
  2851.                    sreq->sheetId);
  2852.       BLOCK_INPUT;
  2853.       lw_destroy_all_widgets (sreq->sheetId);
  2854.       UNBLOCK_INPUT;
  2855.       if (sreq->sheetId == debuggerpanel_sheet)
  2856.     {
  2857.       desired_debuggerpanel_exposed_p = 0;
  2858.       debuggerpanel_sheet = 0;
  2859.     }
  2860.       break;
  2861.       
  2862.     case CSHide:
  2863.       {
  2864.     struct screen *screen;
  2865.     Lisp_Object rest;
  2866.     
  2867.     BLOCK_INPUT;
  2868.     if (sreq->sheetId == debuggerpanel_sheet)
  2869.       desired_debuggerpanel_exposed_p = 0;
  2870.     else
  2871.       for (rest = Vscreen_list; rest != Qnil; rest = Fcdr(rest))
  2872.         {
  2873.           screen = XSCREEN(Fcar(rest));
  2874.           if (SCREEN_IS_X (screen))
  2875.         make_psheets_desired (screen, Qnil);
  2876.         }
  2877.     UNBLOCK_INPUT;
  2878.       }
  2879.       break;
  2880.       
  2881.     case CSShow:
  2882.       if (sreq->sheetId == debuggerpanel_sheet)
  2883.     desired_debuggerpanel_exposed_p = 1;
  2884.       else
  2885.     {
  2886.       struct screen *screen;
  2887.       struct window *window;
  2888.       Lisp_Object rest;
  2889.       for (rest = Vscreen_list; rest != Qnil; rest = Fcdr(rest))
  2890.         {
  2891.           screen = XSCREEN(Fcar(rest));
  2892.           if (SCREEN_IS_X (screen))
  2893.         {
  2894.           window = XWINDOW(screen->selected_window);
  2895.           if (window->buffer == binfo->emacs_buffer)
  2896.             make_psheets_desired (screen, binfo->emacs_buffer);
  2897.         }
  2898.         }
  2899.     }
  2900.       break;
  2901.     }
  2902. }
  2903.  
  2904.  
  2905. #if 0
  2906. static void
  2907. note_being_destroyed (Widget w, XtPointer call_data, XtPointer client_data)
  2908. {
  2909. #if 0
  2910.  *  NoteWidget nw = (NoteWidget)w;
  2911.  *  Widget tw = get_text_widget (nw);
  2912.  *  SCREEN_PTR s;
  2913.  *  Lisp_Object screen;
  2914.  *
  2915.  *  if (tw){
  2916.  *    s = (SCREEN_PTR)x_any_window_to_screen (XtWindow (tw));
  2917.  *    if (s){
  2918.  *      BLOCK_INPUT;
  2919.  *      set_text_widget (nw, 0);
  2920.  *      UNBLOCK_INPUT;
  2921.  *      XSET (screen, Lisp_Screen, s);
  2922.  *      Fdelete_screen (screen);
  2923.  *    }
  2924.  *  }
  2925. #endif
  2926. }
  2927. #endif
  2928.  
  2929. #if 0
  2930.  * static void
  2931.  * note_instantiated (EId bufferId, EId noteId, NoteWidget nw, void* arg)
  2932.  * {
  2933.  *   XtAddCallback ((Widget)nw, XtNdestroyCallback, note_being_destroyed, 0);
  2934.  *   XtVaSetValues ((Widget)nw, "forceXtLoop", 1, 0);
  2935.  * }
  2936. #endif
  2937.  
  2938. static void
  2939. HandlePostitRequest (Editor *editor, CGenericRequest *preq)
  2940. {
  2941. #if 0
  2942.  *   BufferInfo* binfo;
  2943.  *   Connection* conn = editor->conn;
  2944.  *   NoteWidget notew;
  2945.  *   
  2946.  *   switch (preq->head.reqType)
  2947.  *     {
  2948.  *     case OpenPostitRType:{
  2949.  *       if (!(binfo = get_buffer_info_for_id (preq->openpostit.bufferId,
  2950.  *                          editor)))
  2951.  *      {
  2952.  *        Post("Server attempt to use postit in a non registered buffer");
  2953.  *        CSkipRequest (conn);
  2954.  *        return;
  2955.  *      }
  2956.  *       
  2957.  *       BLOCK_INPUT;
  2958.  *       xc_create_note_window 
  2959.  *         (&preq->openpostit, conn, note_instantiated, 0,
  2960.  *          FONT_WIDTH (SCREEN_NORMAL_FACE (selected_screen).font),
  2961.  *          TOTAL_HEIGHT (SCREEN_NORMAL_FACE (selected_screen).font));
  2962.  *       UNBLOCK_INPUT;
  2963.  *       add_in_list_of_ids (&binfo->note_ids, &binfo->n_notes,
  2964.  *                preq->openpostit.bufferId);
  2965.  *     }
  2966.  *       break;
  2967.  *       
  2968.  *     case KillPostitRType:{
  2969.  *       if (!(binfo = get_buffer_info_for_id (preq->killpostit.bufferId,
  2970.  *                          editor)))
  2971.  *      {
  2972.  *        Post("Server attempt to kill postit in a non registered buffer");
  2973.  *        CSkipRequest (conn);
  2974.  *        return;
  2975.  *      }
  2976.  *       
  2977.  *       BLOCK_INPUT;
  2978.  *       xc_destroy_note (preq->killpostit.postitId);
  2979.  *       UNBLOCK_INPUT;
  2980.  *       remove_from_list_of_ids (&binfo->note_ids, &binfo->n_notes,
  2981.  *                     preq->killpostit.postitId);
  2982.  *       break;
  2983.  *     }}
  2984. #endif
  2985. }
  2986.  
  2987. /* show busy */
  2988. /* int needs_to_recompute_menubar_when_kernel_not_busy; */
  2989.  
  2990. static void
  2991. show_all_menubars_busy (int busy)
  2992. {
  2993.   struct screen* s;
  2994.   struct x_display* x;
  2995.   Lisp_Object tail;
  2996.  
  2997.   BLOCK_INPUT;
  2998.   for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr)
  2999.     {
  3000.       s = XSCREEN (XCONS (tail)->car);
  3001.       if (SCREEN_IS_X (s))
  3002.     {
  3003.       x = s->display.x;
  3004.       if (x->menubar_widget)
  3005.         lw_show_busy (x->menubar_widget, busy);
  3006.     }
  3007.     }
  3008.   UNBLOCK_INPUT;
  3009. }
  3010.  
  3011. static void
  3012. HandleShowBusyRequest (Editor *editor, CGenericRequest *preq)
  3013. {
  3014.   /* call the show busy routine of the  library for the menubar of
  3015.    * all screens */
  3016.   ReqLen len;
  3017.   extern Lisp_Object Venergize_kernel_busy;
  3018.  
  3019.   char* why = CGetVstring (editor->conn, &len);
  3020.  
  3021.   show_all_menubars_busy (preq->head.data);
  3022.   Venergize_kernel_busy = preq->head.data ? Qt : Qnil;
  3023.   safe_funcall_hook (Venergize_kernel_busy_hook, 1, build_string (why), Qnil,
  3024.              Qnil);
  3025.  
  3026.   /* update the menubars if needed and kernel is not busy */
  3027.   if (!preq->head.data /*&& needs_to_recompute_menubar_when_kernel_not_busy*/)
  3028.     {
  3029.       SCREEN_PTR s;
  3030.       Lisp_Object tail;
  3031.       
  3032. /*      needs_to_recompute_menubar_when_kernel_not_busy = 0;*/
  3033.       for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr)
  3034.     {
  3035.       if (!SCREENP (XCONS (tail)->car))
  3036.         continue;
  3037.       
  3038.       s = XSCREEN (XCONS (tail)->car);
  3039.       if (SCREEN_IS_X (s) &&
  3040.           ! MINI_WINDOW_P (XWINDOW (s->selected_window)))
  3041.         recompute_screen_menubar (s);
  3042.     }
  3043.     }
  3044. }
  3045.  
  3046. static void
  3047. HandleSheetRequest (Connection* conn, CSheetRequest* sreq, Widget parent)
  3048. {
  3049.   char* name = CGetVstring (conn, NULL);
  3050.  
  3051.   switch ((CSheetRSubtype)sreq->head.data)
  3052.     {
  3053.     case CSCreate:
  3054.       lw_create_widget (name, name, sreq->sheetId, 0, parent,
  3055.             !sreq->bufferId, 0, HandleControlChange, 0);
  3056.       break;
  3057.     case CSDelete:
  3058.       lw_destroy_all_widgets (sreq->sheetId);
  3059.       break;
  3060.       
  3061.     case CSShow:
  3062.       lw_pop_up_all_widgets (sreq->sheetId);
  3063.       break;
  3064.  
  3065.     case CSHide:
  3066.       lw_pop_down_all_widgets (sreq->sheetId);
  3067.       break;
  3068.     }
  3069. }
  3070.  
  3071. static void
  3072. HandleSetControlRequest (Connection* conn, CGenericRequest* creq)
  3073. {
  3074.   CSetControlRequest* sreq = &creq->setcontrol;
  3075.   widget_value val;
  3076.   widget_value* contents;
  3077.  
  3078.   unsigned long i;
  3079.   unsigned long n = sreq->nChoices;
  3080.   
  3081.   if (n > 0)
  3082.     {
  3083.       contents = (widget_value *) xmalloc (n * sizeof (widget_value));
  3084.       memset (contents, 0, (n * sizeof (widget_value)));
  3085.     }
  3086.   else 
  3087.     contents = NULL;
  3088.   memset (&val, 0, sizeof (val));
  3089.   val.name = CGetVstring (conn, NULL);
  3090.   val.enabled = !(sreq->flags & CKInactive);
  3091.   val.selected = !!(sreq->flags & CKSelected);
  3092.   val.change = VISIBLE_CHANGE;
  3093.   val.contents = contents;
  3094.  
  3095.   for (i = 0; i < n; i++)
  3096.     {
  3097.       widget_value* cur = &contents [i];
  3098.       CChoice* choice = CGet (conn, CChoice);
  3099.       cur->name = CGetVstring (conn, NULL);
  3100.       cur->value = cur->name;
  3101.       cur->key = NULL;
  3102.       cur->enabled = !(choice->flags & CKInactive);
  3103.       cur->selected = !!(choice->flags & CKSelected);
  3104.       cur->change = VISIBLE_CHANGE;
  3105.       cur->contents = NULL;
  3106.       cur->call_data = NULL;
  3107.       cur->next = i == n - 1 ? NULL : &contents [i + 1];
  3108.       cur->toolkit_data = NULL;
  3109.       if ((i == 0 && n == 1) || cur->selected)
  3110.     {
  3111.       val.value = cur->name;
  3112.       if (!*val.value)
  3113.         val.value = NULL;
  3114.     }
  3115.     }
  3116.   lw_modify_all_widgets (sreq->sheetId, &val, True);
  3117.   
  3118.   if (contents)
  3119.     xfree (contents);
  3120. }
  3121.     
  3122. static void
  3123. SendSheetStateChange (Connection* conn, EId buffer_id, EId sheet_id,
  3124.               int shown)
  3125. {
  3126.   CWriteSheetRequest (conn, shown ? CSShow : CSHide, sheet_id, buffer_id, "");
  3127. }
  3128.  
  3129. static void
  3130. HandleControlChange (Widget widget, EId sheet_id, void* arg)
  3131. {
  3132.   Connection*     conn;
  3133.   widget_value* val;
  3134.   widget_value* cur;
  3135.   widget_value* this_val = NULL;
  3136.   widget_value* cancel = NULL;
  3137.   char*     this_name;
  3138.   int delete_window_p = (((int) arg) == -1);
  3139.   
  3140.  
  3141.   if (!energize_connection)
  3142.     return;
  3143.  
  3144.   conn = energize_connection->conn;
  3145.   if (!conn)
  3146.     return;
  3147.  
  3148.   this_name = XtName (widget);
  3149.   val = lw_get_all_values (sheet_id);
  3150.  
  3151.   if (delete_window_p)
  3152.     /* Complete and utter kludge.  If this dbox was dismissed with the
  3153.        WM close box (WM_DELETE_WINDOW, meaning the widget was destroyed)
  3154.        then we look for a likely "cancel" button and pretend the user
  3155.        clicked on that.  Really the protocol should be extended for this.
  3156.      */
  3157.     for (cur = val; cur; cur = cur->next)
  3158.       {
  3159.     char *v = cur->value;
  3160.     if (v &&
  3161.         ((strlen (v) >= 6 && !strncmp (v, "cancel", 6)) ||
  3162.          (strlen (v) >= 5 && !strncmp (v, "abort", 5))))
  3163.       cancel = cur;
  3164.       }
  3165.  
  3166.   /* first send all the edited widgets */
  3167.   for (cur = val; cur; cur = cur->next)
  3168.     {
  3169.       /* do not send the widget that ran the callback */
  3170.       if (!strcmp (cur->name, this_name))
  3171.     this_val = cur;
  3172.       else if (cur == cancel)
  3173.     ;
  3174.       /* send the edited widgets */
  3175.       else if (cur->edited)
  3176.     {
  3177.       char* value = cur->value;
  3178.       unsigned int flags = 0;
  3179.  
  3180.       if (!cur->enabled)
  3181.         flags |= CKInactive;
  3182.       if (cur->selected)
  3183.         flags |= CKSelected;
  3184.  
  3185.       /* the kernel is brain dead and expect "1" and "0" as values
  3186.          for the checkbox objects.  So if value is NULL, make it be "0"
  3187.          or "1" depending on the selected state.  This is until we fix
  3188.          the kernel. */
  3189.       if (!value)
  3190.         value = cur->selected ? "1" : "0";
  3191.  
  3192.       CWriteSetControlRequest (conn, sheet_id, 0, cur->name, 1);
  3193.       CWriteChoice (conn, 0, flags, value, 0);
  3194.       CWriteLength (conn);
  3195.     }
  3196.     }
  3197.  
  3198.   if (delete_window_p && !this_val)
  3199.     {
  3200.       this_val = cancel;
  3201. /*      if (! this_val) abort (); */
  3202.     }
  3203.  
  3204.   /* Then send the widget that ran the callback */
  3205.   if (this_val)
  3206.     {
  3207.       CWriteSetControlRequest (conn, sheet_id, 0, this_val->name, 1);
  3208.       CWriteChoice (conn, 0, 0, this_val->value, 0);
  3209.       CWriteLength (conn);
  3210.       CWriteRequestBuffer (conn);
  3211.     }
  3212. }
  3213.  
  3214. /******************** Low level connection stuff ************************/
  3215. static void
  3216. add_in_connection_input_buffer (Connection *conn, char *s, int l)
  3217. {
  3218.   /* Should be in connection.c */
  3219.   if (conn->inread >= conn->infill) 
  3220.     conn->inread = conn->infill = conn->inbuffer;
  3221.   
  3222.   CNeedInputSize (conn, l);
  3223.   memcpy (conn->infill, s, l);
  3224.   conn->infill += l;
  3225. }
  3226.  
  3227. static Lisp_Object
  3228. ProcessJustOneEnergizeRequest ()
  3229. {
  3230.   Editor *editor = energize_connection;
  3231.   CEditorRequest *req;
  3232.   int res = 0;
  3233.   
  3234.   if (!editor) return make_number(res);
  3235.   
  3236.   if (!editor->conn)
  3237.     {
  3238.       CloseConnection();
  3239.       return make_number (res);
  3240.     }
  3241.   
  3242.   req = CReadEditorRequest(editor->conn);
  3243.   if (!req)
  3244.     {
  3245.       switch (errno)
  3246.         {
  3247.         case EWOULDBLOCK:
  3248.           /* Post("ProcessEnergizeRequest: internal error EWOULDBLOCK"); */
  3249.       res = -1;
  3250.           break;
  3251.           
  3252.         case 0:
  3253.     case ECONNRESET:
  3254.           Post ("Connection to Energize was closed.");
  3255.           CloseConnection ();
  3256.           break;
  3257.           
  3258.         default:
  3259.           Post
  3260.             ("System error on connection to Energize, closing.");
  3261.           CloseConnection ();
  3262.           break;
  3263.         }
  3264.     }
  3265.   else
  3266.     {
  3267.       res = 1;
  3268.       switch (req->head.reqType)
  3269.         {
  3270.         case RefuseConnectionRType:
  3271.           Post("Energize connection refused");
  3272.           CloseConnection ();
  3273.           break;
  3274.           
  3275.         case AcceptConnectionRType:
  3276.       {
  3277.         CProtocol* proto = CGet (editor->conn, CProtocol);
  3278.         editor->major = proto->major;
  3279.         editor->minor = proto->minor;
  3280.         Post("Energize connection accepted");
  3281.         CSkipRequest(editor->conn);
  3282.       }
  3283.           break;
  3284.           
  3285.         case NewBufferRType:
  3286.           HandleNewBufferRequest(editor, &req->newbuffer);
  3287.           break;
  3288.           
  3289.     case QueryBufferRType:
  3290.       {
  3291.         EId buffer_id;
  3292.         struct reply_wait* rw = find_wait_reply (req->head.serial);
  3293.         CGetVstring (editor->conn, 0); /* skip directory */
  3294.         CGetVstring (editor->conn, 0); /* skip file */
  3295.         buffer_id = *CGet (editor->conn, EId);
  3296.         if (rw)
  3297.           {
  3298.         rw->answered_p = 1;
  3299.         rw->status = req->head.data;
  3300.         rw->objectId = buffer_id;
  3301.           }
  3302.       }
  3303.       break;
  3304.  
  3305.         case EnsureVisibleRType:
  3306.           HandleEnsureVisibleRequest(editor, &req->ensurevisible);
  3307.           break;
  3308.           
  3309.         case EnsureManyVisibleRType:
  3310.           HandleEnsureManyVisibleRequest(editor, &req->ensuremanyvisible);
  3311.           break;
  3312.           
  3313.         case ModifyBufferRType:
  3314.           HandleModifyBufferRequest(editor, &req->modifybuffer);
  3315.           break;
  3316.           
  3317.         case ProposeChoicesRType:
  3318.       HandleProposeChoicesRequest (editor, &req->generic.proposechoices);
  3319.           break;
  3320.           
  3321.         case ChoiceExecutedRType:
  3322.       {
  3323.         struct reply_wait* rw = find_wait_reply (req->head.serial);
  3324.         CChoiceExecutedRequest* ce = &req->generic.choiceexecuted;
  3325.         if (rw)
  3326.           {
  3327.         rw->answered_p = 1;
  3328.         rw->status = ce->head.data;
  3329.         BLOCK_INPUT;
  3330.         rw->message = CMakeVstring (editor->conn, 0);
  3331.         UNBLOCK_INPUT;
  3332.           }
  3333.       }
  3334.           break;
  3335.           
  3336.         case KillBufferRType:
  3337.           HandleKillBufferRequest(editor, &req->killbuffer);
  3338.           break;
  3339.           
  3340.     case ModifiedBufferRType:
  3341.       {
  3342.         struct reply_wait* rw = find_wait_reply (req->head.serial);
  3343.         if (rw)
  3344.           {
  3345.         rw->answered_p = 1;
  3346.         if (rw->objectId == req->modifiedbuffer.bufferId)
  3347.           rw->status = req->modifiedbuffer.state;
  3348.         else
  3349.           rw->status = CMBufferLocked;
  3350.           }
  3351.       }
  3352.       break;
  3353.  
  3354.         case SetModifiedFlagRType:
  3355.           HandleSetModifiedFlagRequest(editor, &req->setmodifiedflag);
  3356.           break;
  3357.           
  3358.         case RemoveExtentsRType:
  3359.           HandleRemoveExtentsRequest (editor, &req->removeextents);
  3360.           break;
  3361.           
  3362.         case RenumberExtentsRType:
  3363.           /* HandleDuplicateExtentRequest(editor, req); */
  3364.           break;
  3365.           
  3366. #if 0
  3367.         case DialogRType:
  3368.           /* HandleDialogRequest(editor, req, CurrentBuffer(editor)); */
  3369.           break;
  3370. #endif
  3371.           
  3372.         case SaveBufferRType:
  3373.           HandleSaveBufferRequest (editor, &req->savebuffer);
  3374.           break;
  3375.           
  3376.         case SheetRType:{
  3377.       EId buffer_id = req->generic.sheet.bufferId;
  3378.       if (!buffer_id)
  3379.         buffer_id = buffer_id_of_sheet (req->generic.sheet.sheetId);
  3380.       if (buffer_id)
  3381.         HandleBufferSheetRequest (editor, &req->generic.sheet, buffer_id);
  3382.       else
  3383.         {
  3384.           CSheetRSubtype type = (CSheetRSubtype)req->head.data;
  3385.           if (type == CSDelete || type ==CSHide)
  3386.         select_screen (selected_screen);
  3387.           BLOCK_INPUT;
  3388.           HandleSheetRequest (editor->conn, &req->generic.sheet,
  3389.                   selected_screen->display.x->widget);
  3390.           UNBLOCK_INPUT;
  3391.         }
  3392.     }
  3393.           break;
  3394.       
  3395.         case SetControlRType:
  3396.       BLOCK_INPUT;
  3397.           HandleSetControlRequest (editor->conn, (CGenericRequest*) req);
  3398.       UNBLOCK_INPUT;
  3399.           break;
  3400.  
  3401.      case OpenPostitRType:
  3402.       case KillPostitRType:
  3403.        HandlePostitRequest (editor, (CGenericRequest*)req);
  3404.        break;
  3405.  
  3406.     case ShowBusyRType:
  3407.       HandleShowBusyRequest (editor, (CGenericRequest*)req);
  3408.       break;
  3409.  
  3410.     case LoggingRType:
  3411.       HandleLoggingRequest (editor, (CLoggingRequest*)req);
  3412.       break;
  3413.  
  3414.         default:
  3415.           Post1("ProcessEnergizeRequest: can't handle request of type %d", 
  3416.                 req->head.reqType);
  3417.         }
  3418.  
  3419.     }
  3420.  
  3421.   return make_number (res);
  3422. }
  3423.  
  3424. static int inside_ProcessEnergizeRequest1;
  3425.  
  3426. /* this must be called ONLY by unwind_protect in ProcessEnergizeRequest1 */
  3427. static Lisp_Object
  3428. post_handle_request (Lisp_Object ignored)
  3429. {
  3430.   if (inside_ProcessEnergizeRequest1 <= 0)
  3431.     abort ();
  3432.   inside_ProcessEnergizeRequest1--;
  3433.   if (energize_connection && energize_connection->conn)
  3434.     CSkipRequest (energize_connection->conn);
  3435.   return Qnil;
  3436. }
  3437.  
  3438. static Lisp_Object
  3439. pop_conn (Lisp_Object arg)
  3440. {
  3441.   Connection *old_conn = (Connection *) lisp_to_word (arg);
  3442.   if (! old_conn)
  3443.     abort ();
  3444.   if (! energize_connection)
  3445.     return Qnil;
  3446.   if (energize_connection->conn == old_conn)
  3447.     abort ();
  3448.  
  3449.   if (CRequestDelayedP (energize_connection->conn))
  3450.     /* We don't call the CWait* functions any more so this shouldn't happen.
  3451.        But if it does someday, then we need to either copy the remaining
  3452.        bits from new_conn to old_conn, or loop processing requests until
  3453.        new_conn is drained.
  3454.      */
  3455.     abort ();
  3456.  
  3457.   DeleteConnection (energize_connection->conn);
  3458.   energize_connection->conn = old_conn;
  3459.  
  3460.   return Qnil;
  3461. }
  3462.  
  3463. static Lisp_Object
  3464. ProcessEnergizeRequest1 ()
  3465.   Lisp_Object result;
  3466.   int count = specpdl_depth;
  3467.  
  3468.   if (inside_ProcessEnergizeRequest1)
  3469.     {
  3470.       /* When the energize process filter is called recursively, push a new
  3471.      connection object.  The read-pointer of the connection buffer could
  3472.      be in the middle of a request.  However, we know that the fd itself
  3473.      is always pointing between requests.  So making a new connection is
  3474.      a way of skipping past the one request we were in the process of
  3475.      reading when we allowed process output to be handled recursively.
  3476.        */
  3477.       Connection *old_conn = energize_connection->conn;
  3478.       Connection *new_conn =
  3479.     EditorSideConnection ((void *) energize_connection,
  3480.                   old_conn->fdin, old_conn->fdout);
  3481.       energize_connection->conn = new_conn;
  3482.       record_unwind_protect (pop_conn, word_to_lisp ((unsigned int) old_conn));
  3483.     }
  3484.  
  3485.   /* this must come after pop_conn() to get the right connection object */
  3486.   record_unwind_protect (post_handle_request, Qnil);
  3487.  
  3488.   inside_ProcessEnergizeRequest1++;
  3489.  
  3490.   result = ProcessJustOneEnergizeRequest ();
  3491.   notify_delayed_requests ();
  3492.  
  3493.   /* decrements inside_ProcessEnergizeRequest1 and possibly replaces
  3494.      energize_connection->conn with old_conn.
  3495.    */
  3496.   unbind_to (count, Qnil);
  3497.  
  3498.   return result;
  3499. }
  3500.  
  3501.  
  3502. /******** Initialize Energize-related state and set up connection ********/
  3503.  
  3504. static void
  3505. setup_connection (Editor *ed, unsigned int id1, unsigned int id2) 
  3506. {
  3507.   CEditorRequest *req = CWriteEditorRequest(ed->conn, QueryConnectionRType);
  3508.   
  3509.   /* these 2 slots are ignored */
  3510.   req->generic.queryconnection.major = 0;
  3511.   req->generic.queryconnection.minor = 0;
  3512.  
  3513.   req->generic.queryconnection.cadillacId1 = id1; /* #### */
  3514.   req->generic.queryconnection.cadillacId2 = id2;
  3515.   req->generic.queryconnection.nProtocols = 1;
  3516.   /* first numerical arg is major protocol number, second is minor */
  3517.   CWriteProtocol(ed->conn, 0, 8, "editor");
  3518.   CWriteLength (ed->conn);
  3519.   CWriteRequestBuffer (ed->conn);
  3520. }
  3521.  
  3522. /* this is used as the readMethod of the energize connection, so that 
  3523.    the connection library won't do some buffering that messes us up.
  3524.    It does this buffering only if conn->readMethod == read, so using
  3525.    another function turns it off.
  3526.  */
  3527. static int
  3528. my_read (int fd, char *buf, int nb)
  3529. {
  3530.   return read (fd, buf, nb);
  3531. }
  3532.  
  3533. static Connection *
  3534. EditorSideConnection (Editor *editor, int fdin, int fdout)
  3535. {
  3536.   Connection *conn = NewConnection ((void *)editor, fdin, fdout);
  3537.   if (conn)
  3538.     conn->readMethod = my_read;
  3539.   return conn;
  3540. }
  3541.  
  3542. DEFUN ("handle-energize-request", Fhandle_energize_request,
  3543.        Shandle_energize_request,
  3544.        2, 2, 0,
  3545.        "Filter called when a request is available from Energize.")
  3546.      (proc, string)
  3547.      Lisp_Object proc, string;
  3548. {
  3549.   if (!NILP (string))
  3550.     CHECK_STRING (string, 0);
  3551.   
  3552.   if (!energize_connection || !energize_connection->conn)
  3553.     {
  3554.       /* no need for a message here, Energize is dead */
  3555.       return make_number (0);
  3556.     }
  3557.   if (!energize_connection || (energize_connection->proc != proc))
  3558.     {
  3559.       Post("Got an Energize request but not from current connection ");
  3560.       return make_number (0);
  3561.     }
  3562.   
  3563.   if (!NILP (string))
  3564.     add_in_connection_input_buffer (energize_connection->conn,
  3565.                     (char *) XSTRING (string)->data,
  3566.                     XSTRING (string)->size);
  3567.   
  3568.   return ProcessEnergizeRequest1 ();
  3569. }
  3570.  
  3571.  
  3572. /* Opens a network connection to Energize.
  3573.  * server is a string.  It can end up with :<uid> or :<username>
  3574.  * in which case the uid is added to the TCP port to get the connection */
  3575. static void
  3576. ConnectToEnergize (char *server_str, char *arg)
  3577. {
  3578.   struct Lisp_Process *proc;
  3579.   Lisp_Object lp;
  3580.   Lisp_Object fil;
  3581.   char *host;
  3582.   unsigned int port;
  3583.   long flags;
  3584.   int id1;
  3585.   int id2;
  3586.  
  3587.   if (CGetPortNumber (server_str, &host, &port))
  3588.     {
  3589.       
  3590.       lp = Fopen_network_stream (build_string ("energize"),
  3591.                                  Qnil,
  3592.                                  build_string (host),
  3593.                                  make_number (port));
  3594.       if (lp)
  3595.         {
  3596.       /* Don't ask the user for confirmation when exiting Emacs */
  3597.       Fprocess_kill_without_query (lp, Qnil);
  3598.           proc = XPROCESS (lp);
  3599.           energize_connection = xnew (Editor);
  3600.           energize_connection->conn = EditorSideConnection (energize_connection, XFASTINT (proc->infd),
  3601.                                                 XFASTINT (proc->infd));
  3602.           energize_connection->proc = lp;
  3603.           energize_connection->binfo_hash = make_hashtable (10);
  3604.       energize_connection->image_table = 0;
  3605.           energize_connection->gc_save = Qnil;
  3606.           energize_connection->major = 0;
  3607.           energize_connection->minor = 0;
  3608.           peo = allocate_edit_options (10);
  3609.           request_serial_number = 0;
  3610.       global_reply_wait = 0;
  3611.  
  3612.           if ((flags = fcntl (energize_connection->conn->fdin, F_GETFL, 0)) == -1)
  3613.         abort(); /* perror ("get connection flags"); */
  3614.       
  3615. #ifdef O_NONBLOCK
  3616.       if (fcntl (energize_connection->conn->fdin, F_SETFL, flags & ~O_NONBLOCK) == -1)
  3617. #else
  3618.       if (fcntl (energize_connection->conn->fdin, F_SETFL, flags & ~O_NDELAY) == -1)
  3619. #endif
  3620.             abort(); /* perror ("set connection flags"); */
  3621.           
  3622.           XSET (fil, Lisp_Subr, &Shandle_energize_request);
  3623.           proc->filter = fil;
  3624.           proc->filter_does_read = Qt;
  3625.  
  3626.       Venergize_kernel_busy = Qnil;
  3627. /*      needs_to_recompute_menubar_when_kernel_not_busy = 0;*/
  3628.           
  3629.           id1 = 0;
  3630.           id2 = 0;
  3631.           if (arg)
  3632.             sscanf (arg, "%x,%x", &id1, &id2);
  3633.           
  3634.       energize_buffers_list = Qnil;
  3635.  
  3636.           setup_connection (energize_connection, id1, id2);
  3637.         }
  3638.       else
  3639.     error ("couldn't connect to Energize server");
  3640.     }
  3641.   else
  3642.     error ("couldn't determine Energize server port number");
  3643. }
  3644.  
  3645.  
  3646. /* Close the connection to energize.
  3647.  * Kills all the energize related buffer */
  3648. static void 
  3649. CloseConnection () 
  3650. {
  3651.   Editor *ed = energize_connection;
  3652.  
  3653.   if (ed)
  3654.     /* make this function as paranoid as we can */
  3655.     {
  3656.       BLOCK_INPUT;
  3657.       /* cleanup the busy state */
  3658.       show_all_menubars_busy (False);
  3659.       Venergize_kernel_busy = Qnil;
  3660.       /* destroy all pop_up boxes */
  3661.       lw_destroy_all_pop_ups ();
  3662.       UNBLOCK_INPUT;
  3663.  
  3664.       debuggerpanel_sheet = 0;
  3665.       desired_debuggerpanel_exposed_p = 0;
  3666.  
  3667.       if (ed->conn)
  3668.     DeleteConnection (ed->conn);
  3669.       ed->conn = 0;
  3670.       
  3671.       if (ed->binfo_hash)
  3672.         {
  3673.           int count = specpdl_ptr - specpdl;
  3674.       
  3675.           /* we are flushing everything, so we just ignore any change
  3676.              hooks and don't make an effort to delete extents since they
  3677.              are all going away */
  3678.           specbind (Qenergize_buffer_modified_hook, Qnil);
  3679.           specbind (intern ("inhibit-quit"), Qt);
  3680.       call0 (intern ("de-energize-all-buffers"));
  3681.           unbind_to (count, Qnil);
  3682.       
  3683.           free_hashtable (ed->binfo_hash);
  3684.           ed->binfo_hash = 0;
  3685.         }
  3686.       
  3687.       free_edit_options (peo);
  3688.       
  3689.       if (ed->proc) Fdelete_process (ed->proc);
  3690.       ed->proc = Qnil;
  3691.       
  3692.       energize_buffers_list = Qnil;
  3693.  
  3694.       /* now kill buffers created to satisfy requests on old connection */
  3695.       xfree (ed);
  3696.     }
  3697.   
  3698.   /* marked as close */
  3699.   energize_connection = 0;
  3700. }
  3701.  
  3702.  
  3703. DEFUN ("connect-to-energize-internal", 
  3704.        Fconnect_to_energize_internal, Sconnect_to_energize_internal, 0, 2, 0,
  3705.        "Usage: (connect-to-energize-internal <server-name> <energizearg>)\n\
  3706. Energizearg representing two 32 bit Energize ids that will be passed\n\
  3707. to the Energize server when opening the Energize connection.\n\
  3708. Only one connection can be open at a time.")
  3709.  
  3710.   (server_name, energize_arg)
  3711.   Lisp_Object server_name, energize_arg;
  3712. {
  3713.   unsigned char *server; 
  3714.   unsigned char *arg;
  3715.   
  3716.   if (!NILP(energize_arg))
  3717.     {
  3718.       CHECK_STRING (energize_arg, 1);
  3719.       arg = XSTRING (energize_arg)->data;
  3720.     }
  3721.   else
  3722.     arg = 0;
  3723.   
  3724.   if (!NILP(server_name))
  3725.     {
  3726.       CHECK_STRING (server_name, 1);
  3727.       server = XSTRING (server_name)->data;
  3728.     }
  3729.   else
  3730.     server = 0;
  3731.   
  3732.   /* since we are going ahead with this, make sure that we are
  3733.      really and truly disconnected first */
  3734.   Fclose_connection_to_energize ();
  3735.  
  3736.   ConnectToEnergize ((char *)server, (char *)arg);
  3737.   return Qnil;
  3738. }
  3739.  
  3740. DEFUN ("close-connection-to-energize", Fclose_connection_to_energize, 
  3741.        Sclose_connection_to_energize, 0, 0, 0,
  3742.        "Close the open Energize connection, if any.")
  3743.      ()
  3744. {
  3745.   if (!energize_connection) return Qnil;
  3746.  
  3747.   CloseConnection();
  3748.   return Qnil;
  3749. }
  3750.  
  3751.  
  3752. /* buffer modified routines */
  3753. static void
  3754. SendBufferModificationState (Editor *editor, BufferInfo *binfo, int flag)
  3755. {
  3756.   Connection *conn = editor->conn;
  3757.   EId bufferId = binfo->id;
  3758.   
  3759.   if (conn)
  3760.     {
  3761.       int state = (flag)?(CMBufferSetModified):(CMBufferSetUnmodified);
  3762.       CWriteModifiedBufferHeader (conn, bufferId, state);
  3763.       CWriteRequestBuffer (conn);
  3764.     }
  3765. }
  3766.  
  3767. /* returns 1 if buffer is locked (non-editable),
  3768. **  0 if it isn't (editable), and -1 if it can't tell */
  3769. static int
  3770. CheckBufferLock (Editor *editor, BufferInfo *binfo)
  3771. {
  3772.   Connection *conn = editor->conn;
  3773.   struct reply_wait rw;
  3774.   
  3775.   /* If permision already granted by kernel dont' ask again */
  3776.   if (binfo->editable)
  3777.     return 0;
  3778.  
  3779.   /* If can't ask say we do not know */
  3780.   if (!conn)
  3781.     return -1;
  3782.  
  3783.   /* Ask the kernel */
  3784.   CWriteModifiedBufferHeader (conn, binfo->id, CMBufferQueryLock);
  3785.   conn->header->serial = ++request_serial_number;
  3786.   CWriteRequestBuffer (conn);
  3787.   
  3788.   rw.serial = request_serial_number;
  3789.   rw.objectId = binfo->id;
  3790.   rw.status = -1;
  3791.   
  3792.   if (!wait_for_reply (&rw))
  3793.     return -1;
  3794.   
  3795.   if (rw.status == CMBufferLocked)
  3796.     {
  3797.       /* Buffer is locked by kernel so we cannot edit it */
  3798.       return 1;
  3799.     }
  3800.   else if (rw.status == CMBufferUnlocked)
  3801.     {
  3802.       /* Buffer is unlocked by kernel: edit permission granted! */
  3803.       binfo->editable = 1;
  3804.       return 0;
  3805.     }
  3806.   else
  3807.     {
  3808.       /* This should never happen */
  3809.       return -1;
  3810.     }     
  3811. }
  3812.  
  3813.  
  3814. /* Ask the kernel if BUFFER is currently locked -- waits for answer */
  3815. static Lisp_Object 
  3816. buffer_locked_p (Lisp_Object buffer)
  3817. {
  3818.   BufferInfo *binfo;
  3819.  
  3820.   if (!energize_connection)
  3821.     return Qnil;
  3822.   
  3823.   if (NILP (buffer))
  3824.     XSET (buffer, Lisp_Buffer, current_buffer);
  3825.  
  3826.   CHECK_BUFFER (buffer, 0);
  3827.   
  3828.   binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection);
  3829.  
  3830.   if (!binfo)
  3831.     {
  3832.       /* Not an Energize buffer, return Qnil: can edit buffer */
  3833.       return Qnil;
  3834.     }
  3835.   else 
  3836.     {
  3837.       /* Energize buffer, check if editable */
  3838.       return CheckBufferLock (energize_connection, binfo) == 0 ? Qnil : Qt;
  3839.     }
  3840. }
  3841.  
  3842.  
  3843.  
  3844. /* Called by map_extents function called by Fsend_buffer_modified_request
  3845.  */
  3846. static int
  3847. notify_extent_modified (Lisp_Object extent_obj, void *arg)
  3848. {
  3849.   /* arg is a binfo_and_state */
  3850.   binfo_and_state *bans = (binfo_and_state*)arg;
  3851.   Energize_Extent_Data *ext;
  3852.   BufferInfo *binfo = bans->binfo;
  3853.   Connection *conn = binfo->editor->conn;
  3854.   EId *extent_id;
  3855.   
  3856.   if (!EXTENTP (extent_obj) ||  
  3857.       !(EXTENT_FLAGS (XEXTENT(extent_obj)) & EF_WARN_MODIFY))
  3858.     return 0;
  3859.  
  3860.   if ((ext = extent_to_data (extent_obj))
  3861.       && ext->extentType == CEGeneric
  3862.       && ext->u.generic.gData
  3863.       && ext->u.generic.gData->cl
  3864.       && (ext->u.generic.gData->cl->flags & CCWarnModified)
  3865.       && ext->u.generic.gData->modified_state != bans->state)
  3866.     {
  3867.       if (bans->tell_energize)
  3868.     {
  3869.       CWriteModifiedExtentsHeader (conn, binfo->id, bans->state, 1);
  3870.       extent_id = CPut (conn, EId);
  3871.       *extent_id = ext->id;
  3872.       CWriteLength (conn);
  3873.       CWriteRequestBuffer (conn);
  3874.     }
  3875.       ext->u.generic.gData->modified_state = bans->state;
  3876.     }
  3877.   return 0;
  3878. }
  3879.  
  3880. static int
  3881. ceiwme_lower_mf (EXTENT extent, void *arg)
  3882. {
  3883.   if (EXTENT_FLAGS (extent) & EF_WARN_MODIFY)
  3884.     *((EXTENT *) arg) = extent;
  3885.   return 0;
  3886. }
  3887.  
  3888. static int
  3889. ceiwme_upper_mf (EXTENT extent, void *arg)
  3890. {
  3891.   if (EXTENT_FLAGS (extent) & EF_WARN_MODIFY)
  3892.     {
  3893.       *((EXTENT *) arg) = extent;
  3894.       return 1;
  3895.     }
  3896.   else
  3897.     return 0;
  3898. }
  3899.  
  3900. static void
  3901. coerce_endpoints_to_be_inside_warn_on_modify_extents (from_ptr, to_ptr, b)
  3902.      int *from_ptr;
  3903.      int *to_ptr;
  3904.      struct buffer *b;
  3905. {
  3906.   EXTENT lower_extent = 0;
  3907.   EXTENT upper_extent = 0;
  3908.   int lower_bound = *from_ptr;
  3909.   int upper_bound = *to_ptr;
  3910.   Lisp_Object tmp;
  3911.   
  3912.   /* make sure that from <= to */
  3913.   { 
  3914.     int tmp_int = max (lower_bound, upper_bound);
  3915.     *from_ptr = lower_bound = min (lower_bound, upper_bound);
  3916.     *to_ptr = upper_bound = tmp_int;
  3917.   }
  3918.   
  3919.   if (!BUFFER_NOTIFY_BACKGROUND_BIT_SET_P(b)) 
  3920.     return;
  3921.   
  3922.   map_extents (BUF_BEG(b), lower_bound, 0, ceiwme_lower_mf, 
  3923.                (void *) &lower_extent, b, 1);
  3924.   if (!lower_extent)
  3925.     {
  3926.       lower_bound = BUF_BEG (b);
  3927.       map_extents (upper_bound, BUF_Z(b), 0, ceiwme_upper_mf, 
  3928.                    (void *) &upper_extent, b, 1);
  3929.       if (!upper_extent)
  3930.         upper_bound = BUF_Z (b);
  3931.       else
  3932.         {
  3933.           int xstart;
  3934.           XSET (tmp, Lisp_Extent, upper_extent);
  3935.           xstart = XINT (Fextent_start_position (tmp));
  3936.           upper_bound = max (upper_bound, xstart);
  3937.         }
  3938.     }
  3939.   /* I forget why, but if we found an lower bound, we don't need to find
  3940.      an upper bound */
  3941.   else
  3942.     {
  3943.       int xstart;
  3944.       XSET (tmp, Lisp_Extent, lower_extent);
  3945.       xstart = XINT (Fextent_start_position (tmp));
  3946.       lower_bound = min (lower_bound, xstart);
  3947.     }
  3948.  
  3949.   *from_ptr = lower_bound;
  3950.   *to_ptr = upper_bound;
  3951.   return;
  3952. }
  3953.  
  3954. static void
  3955. mark_all_extents_as_unmodified (BufferInfo *binfo){
  3956.   binfo_and_state bans;
  3957.   bans.binfo = binfo;
  3958.   bans.state = FALSE;
  3959.   bans.tell_energize = FALSE;
  3960.   
  3961.   map_extents (BUF_BEG (XBUFFER (binfo->emacs_buffer)),
  3962.            BUF_Z (XBUFFER (binfo->emacs_buffer)),
  3963.            notify_extent_modified, 0, &bans, 
  3964.                XBUFFER(binfo->emacs_buffer), 1);
  3965. }
  3966.  
  3967. /* Send the BufferModified events for the current buffer.
  3968.  * Handles both global buffer modified and extents modified. */
  3969. DEFUN ("send-buffer-modified-request", Fsend_buffer_modified_request,
  3970.        Ssend_buffer_modified_request,
  3971.        3, 3, 0,
  3972.        "Send a BufferModified request for the current buffer.")
  3973.      (state, from, to)
  3974.      Lisp_Object state, from, to; /* dont use ANSI arglists in DEFUNs */
  3975. {
  3976.   int modifiedp = NILP (state)? 0 : 1;
  3977.   Lisp_Object buffer;
  3978.   BufferInfo *binfo;
  3979.   int from_int = XINT (from);
  3980.   int to_int = XINT (to);
  3981.   
  3982.   if (!energize_connection || !energize_connection->conn) return Qnil;
  3983.   
  3984.   XSET (buffer, Lisp_Buffer, current_buffer);
  3985.  
  3986.   Fenergize_barf_if_buffer_locked ();
  3987.  
  3988.   if (binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection))
  3989.     {
  3990.       /* now make sure that from and to
  3991.      are inside some warn_on_modify extents somewhere */
  3992.       coerce_endpoints_to_be_inside_warn_on_modify_extents
  3993.         (&from_int, &to_int, current_buffer);
  3994.       XSET (from, Lisp_Int, from_int);
  3995.       XSET (to, Lisp_Int, to_int);
  3996.   
  3997.       if (binfo->modified_state != modifiedp)
  3998.         {
  3999.           SendBufferModificationState (energize_connection, binfo, modifiedp);
  4000.           binfo->modified_state = modifiedp;
  4001.         }
  4002.       if (modifiedp)
  4003.     {
  4004.       binfo_and_state bans;
  4005.       bans.binfo = binfo;
  4006.       bans.state = TRUE;
  4007.       bans.tell_energize = TRUE;
  4008.       map_extents (from, to, notify_extent_modified, 0, &bans,
  4009.                XBUFFER(binfo->emacs_buffer), 1);
  4010.     }
  4011.       else
  4012.     mark_all_extents_as_unmodified (binfo);
  4013.     }
  4014.   return Qnil;
  4015. }
  4016.  
  4017. DEFUN ("energize-barf-if-buffer-locked", Fenergize_barf_if_buffer_locked,
  4018.        Senergize_barf_if_buffer_locked, 0, 0, 0,
  4019.        "Error if the buffer is locked.")
  4020.      ()
  4021. {
  4022.   Lisp_Object buffer;
  4023.   XSET (buffer, Lisp_Buffer, current_buffer);
  4024.   
  4025.   if (!energize_connection || !energize_connection->conn)
  4026.     return Qnil;
  4027.  
  4028.   while (!NILP (buffer_locked_p (buffer)))
  4029.     {
  4030.       notify_delayed_requests ();
  4031.       Fsignal (Qbuffer_locked_by_kernel, (Fcons (buffer, Qnil)));
  4032.     }  
  4033.   return Qnil;
  4034. }
  4035.  
  4036.  
  4037. DEFUN ("energize-send-region", Fenergize_send_region,
  4038.        Senergize_send_region,
  4039.        2, 2, 0,
  4040.        "Send region as user input")
  4041.      (start, end)
  4042.      Lisp_Object start, end;
  4043. {
  4044.   BufferInfo *binfo;
  4045.   Lisp_Object b;
  4046.   int start1;
  4047.   CEditorRequest *req;
  4048.   
  4049.   if (!energize_connection || !energize_connection->conn) 
  4050.     error ("Not connected to Energize");
  4051.   
  4052.   XSET (b, Lisp_Buffer, current_buffer);
  4053.   if (binfo = get_buffer_info_for_emacs_buffer (b, energize_connection))
  4054.     {
  4055.       validate_region (&start, &end);
  4056.       
  4057.       if (XINT (start) < GPT && XINT (end) > GPT) move_gap (start);
  4058.       
  4059.       start1 = XINT (start);
  4060.       req = CWriteEditorRequest (energize_connection->conn, UserTypedSomethingRType);
  4061.       req->usertypedsomething.bufferId = binfo->id;
  4062.       CWriteVstringLen 
  4063.         (energize_connection->conn, (char *) CHAR_ADDRESS (start1), XINT (end) - start1);
  4064.       CWriteLength (energize_connection->conn);
  4065.       CWriteRequestBuffer (energize_connection->conn);
  4066.       return Qnil;
  4067.     }
  4068.   return Qnil;
  4069. }
  4070.  
  4071. DEFUN ("connected-to-energize-p", Fconnected_to_energize_p,
  4072.        Sconnected_to_energize_p,
  4073.        0, 0, 0, 
  4074. "Returns nil if no connection to Energize.")
  4075.      ()
  4076. {
  4077.   if (!energize_connection || !energize_connection->conn || !energize_connection->binfo_hash || 
  4078.       !energize_connection->proc || (XTYPE (energize_connection->proc != Lisp_Process)))
  4079.     return Qnil;
  4080.   else 
  4081.     return Qt;
  4082. }
  4083.  
  4084. DEFUN ("energize-user-input-buffer-mark", Fenergize_user_input_buffer_mark,
  4085.        Senergize_user_input_buffer_mark, 0, 0, 0,
  4086.        "Returns the mark associated to the current (user input) buffer")
  4087.      ()
  4088. {
  4089.   BufferInfo *binfo;
  4090.   Lisp_Object b;
  4091.   
  4092.   if (!energize_connection) return Qnil;
  4093.   
  4094.   XSET (b, Lisp_Buffer, current_buffer);
  4095.   if ((binfo = get_buffer_info_for_emacs_buffer (b, energize_connection)))
  4096.     return binfo->output_mark;
  4097.   else
  4098.     return Qnil;
  4099. }
  4100.  
  4101. DEFUN ("energize-query-buffer", Fenergize_query_buffer,
  4102.        Senergize_query_buffer, 1, 2, 0,
  4103.        "(energize-query-buffer filename just-ask)\n\
  4104. Ask Energize to create a buffer containing the file filename.\n\
  4105. Returns the buffer or NIL if Energize cannot create the buffer.\n\
  4106. If second argument just-ask is T, just ask if Energize\n\
  4107. already knows about the file and returns T if yes, NIL otherwise.")
  4108.      (filename, just_ask)
  4109.      Lisp_Object filename, just_ask;
  4110. {
  4111.   struct Lisp_String *filename_str;
  4112.   CEditorRequest *creq;
  4113.   char *dir_sep;
  4114.   struct reply_wait rw;
  4115.   
  4116.   if (!energize_connection || !energize_connection->conn)
  4117.     return Qnil;
  4118.  
  4119.   filename = Fexpand_file_name (filename, Qnil);
  4120.   filename_str = XSTRING (filename);
  4121.  
  4122.   dir_sep = (char *) strrchr ((char *)filename_str->data, '/');
  4123.   
  4124.   creq = CWriteEditorRequest (energize_connection->conn, QueryBufferRType);
  4125.   creq->head.data = !NILP (just_ask);
  4126.   creq->head.serial = ++request_serial_number;
  4127.   CWriteVstringLen (energize_connection->conn, (char *) filename_str->data,
  4128.             (dir_sep)? (dir_sep - (char *) filename_str->data): 0);
  4129.   CWriteVstringLen (energize_connection->conn, 
  4130.             (char *) filename_str->data, filename_str->size);
  4131.   CWriteLength (energize_connection->conn);
  4132.   CWriteRequestBuffer (energize_connection->conn);
  4133.   
  4134.   rw.serial = request_serial_number;
  4135.   rw.objectId = 0;
  4136.   
  4137.   if (!wait_for_reply (&rw))
  4138.     return Qnil;
  4139.  
  4140.   if (rw.status)
  4141.     {
  4142.       if (rw.objectId)
  4143.     {
  4144.       BufferInfo* binfo = get_buffer_info_for_id (rw.objectId, energize_connection);
  4145.       return binfo ? binfo->emacs_buffer : Qt;
  4146.     }
  4147.       else
  4148.     return Qt;
  4149.     }
  4150.   else
  4151.     return Qnil;
  4152. }
  4153.  
  4154.  
  4155. DEFUN ("energize-psheets-visible-p", Fenergize_psheets_visible_p,
  4156.        Senergize_psheets_visible_p, 0, 1, 0,
  4157.        "Whether the (optional) screen currently has open psheets.")
  4158.      (screen)
  4159.      Lisp_Object screen;
  4160. {
  4161.   if (NILP (screen))
  4162.     XSET (screen, Lisp_Screen, selected_screen);
  4163.   CHECK_SCREEN (screen, 0);
  4164.   if (XSCREEN (screen)->display.x->current_psheets)
  4165.     return Qt;
  4166.   return Qnil;
  4167. }
  4168.  
  4169. DEFUN ("energize-buffer-has-psheets-p", Fenergize_buffer_has_psheets_p,
  4170.        Senergize_buffer_has_psheets_p, 0, 1, 0,
  4171.        "Whether the buffer has psheets associated with it.")
  4172.      (buf)
  4173.      Lisp_Object buf;
  4174. {
  4175.   int count;
  4176.   if (NILP (buf))
  4177.     buf = Fcurrent_buffer ();
  4178.   CHECK_BUFFER (buf, 0);
  4179.   if (get_psheets_for_buffer (buf, &count))
  4180.     return Qt;
  4181.   return Qnil;
  4182. }
  4183.  
  4184. DEFUN ("energize-protocol-level", Fenergize_protocol_level,
  4185.        Senergize_protocol_level, 0, 0, 0,
  4186.        "Returns the Energize protocol level.")
  4187.      ()
  4188. {
  4189.   return
  4190.     energize_connection
  4191.       ? Fcons (energize_connection->major, energize_connection->minor)
  4192.     : Qnil;
  4193. }
  4194.  
  4195.  
  4196. static int
  4197. get_energize_connection_and_buffer_id (Lisp_Object buffer, void **conn_ptr,
  4198.                        long *buffer_id_ptr)
  4199. {
  4200.   BufferInfo *binfo;
  4201.  
  4202.   if (!energize_connection || !energize_connection->conn) return 0;
  4203.   
  4204.   binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection);
  4205.   
  4206.   *conn_ptr = (void *) energize_connection->conn;
  4207.   *buffer_id_ptr = (long) binfo ? binfo->id : 0;
  4208.   return 1;
  4209. }
  4210.  
  4211. static int
  4212. get_energize_connection_and_current_buffer_id (void **conn_ptr,
  4213.                            long *buffer_id_ptr)
  4214. {
  4215.   Lisp_Object lisp_buffer;
  4216.   XSET (lisp_buffer, Lisp_Buffer, current_buffer);
  4217.  
  4218.   return get_energize_connection_and_buffer_id (lisp_buffer, conn_ptr,
  4219.                         buffer_id_ptr);
  4220. }
  4221.  
  4222. int *
  4223. get_psheets_for_buffer (Lisp_Object buffer, int *count_ptr)
  4224. {
  4225.   BufferInfo *binfo;
  4226.  
  4227.   if (!energize_connection || !energize_connection->conn) return 0;
  4228.   
  4229.   binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection);
  4230.   if (!binfo) return 0;
  4231.  
  4232.   if (count_ptr) *count_ptr = binfo->n_p_sheets;
  4233.   return binfo->p_sheet_ids;
  4234. }
  4235.  
  4236. void
  4237. notify_that_sheet_has_been_hidden (EId id)
  4238. {
  4239.   EId buffer_id = buffer_id_of_sheet (id);
  4240.   if (!buffer_id)
  4241.     return;
  4242.  
  4243.   if (buffer_id && energize_connection && energize_connection->conn)
  4244.     {
  4245.       SendSheetStateChange (energize_connection->conn, buffer_id, id, 0);
  4246.       CWriteRequestBuffer (energize_connection->conn);
  4247.     }
  4248. }
  4249.  
  4250.  
  4251. /* edit-mode dialog box 
  4252.  */
  4253.  
  4254. extern int dbox_up_p;
  4255. extern unsigned int popup_id_tick;
  4256. extern Lisp_Object Fpopup_dialog_box (Lisp_Object);
  4257.  
  4258. static struct editmode {
  4259.   int ok, external, view, edit, window, split;
  4260.   char *other;
  4261. } editmode;
  4262.  
  4263. static void
  4264. edit_mode_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
  4265. {
  4266.   widget_value *data;
  4267.   char *name = (char *) client_data;
  4268.  
  4269.   if ((int) client_data == -1) name = "cancel";    /* WM_DELETE_WINDOW */
  4270.  
  4271.   if (!strcmp (XtName (widget), "otherText")) /* screw it */
  4272.     ;
  4273.   else if (!strcmp (name, "externalBox"))
  4274.     {
  4275.       /* make the text slot be active only if "other" is selected */
  4276.       BLOCK_INPUT;
  4277.       data = malloc_widget_value ();
  4278.       data->name = "externalOther";
  4279.       if (! lw_get_some_values (id, data)) abort ();
  4280.       data->enabled = data->selected;
  4281.       data->name = "otherText";
  4282.       lw_modify_all_widgets (id, data, True);
  4283.       free_widget_value (data);
  4284.       UNBLOCK_INPUT;
  4285.     }
  4286.   else if (!strcmp (name, "cancel"))
  4287.     {
  4288.       editmode.ok = -1;
  4289.       lw_destroy_all_widgets (id);
  4290.     }
  4291.   else if (!strcmp (name, "help"))
  4292.     {
  4293.       Lisp_Object v = Fmake_vector (3, Qt);
  4294.       XVECTOR (v)->contents [0] = build_string ("ok");
  4295.       XVECTOR (v)->contents [1] = list1 (intern ("ignore"));
  4296.       Fpopup_dialog_box (list2 (build_string ("dbx_editmode_help"), v));
  4297.     }
  4298.   else if (!strcmp (name, "ok"))
  4299.     {
  4300.       BLOCK_INPUT;
  4301.       editmode.ok = 1;
  4302.       data = malloc_widget_value ();
  4303.       data->name = "externalEmacs";
  4304.       if (! lw_get_some_values (id, data)) abort ();
  4305.       if (data->selected) editmode.external = 0;
  4306.       data->name = "externalViXterm";
  4307.       if (! lw_get_some_values (id, data)) abort ();
  4308.       if (data->selected) editmode.external = 1;
  4309.       data->name = "externalViCmdtool";
  4310.       if (! lw_get_some_values (id, data)) abort ();
  4311.       if (data->selected) editmode.external = 2;
  4312.       data->name = "externalOther";
  4313.       if (! lw_get_some_values (id, data)) abort ();
  4314.       if (data->selected) editmode.external = 3;
  4315.       data->name = "otherText";
  4316.       if (! lw_get_some_values (id, data)) abort ();
  4317.       editmode.other = data->value;
  4318.  
  4319.       data->name = "emacsView";
  4320.       if (! lw_get_some_values (id, data)) abort ();
  4321.       if (data->selected) editmode.view = 0;
  4322.       data->name = "viView";
  4323.       if (! lw_get_some_values (id, data)) abort ();
  4324.       if (data->selected) editmode.view = 1;
  4325.       data->name = "lessView";
  4326.       if (! lw_get_some_values (id, data)) abort ();
  4327.       if (data->selected) editmode.view = 2;
  4328.  
  4329.       data->name = "editEmacs";
  4330.       if (! lw_get_some_values (id, data)) abort ();
  4331.       if (data->selected) editmode.edit = 0;
  4332.       data->name = "editVi";
  4333.       if (! lw_get_some_values (id, data)) abort ();
  4334.       if (data->selected) editmode.edit = 1;
  4335.  
  4336.       data->name = "windowOne";
  4337.       if (! lw_get_some_values (id, data)) abort ();
  4338.       if (data->selected) editmode.window = 0;
  4339.       data->name = "windowSeveral";
  4340.       if (! lw_get_some_values (id, data)) abort ();
  4341.       if (data->selected) editmode.window = 1;
  4342.       data->name = "windowMany";
  4343.       if (! lw_get_some_values (id, data)) abort ();
  4344.       if (data->selected) editmode.window = 2;
  4345.  
  4346.       data->name = "splitScreens";
  4347.       if (! lw_get_some_values (id, data)) abort ();
  4348.       editmode.split = !!data->selected;
  4349.  
  4350.       free_widget_value (data);
  4351.       lw_destroy_all_widgets (id);
  4352.       UNBLOCK_INPUT;
  4353.     }
  4354.   else
  4355.     {
  4356.       abort ();
  4357.     }
  4358. }
  4359.  
  4360. static int
  4361. editmode_done (void *arg)
  4362. {
  4363.   return (editmode.ok != 0);
  4364. }
  4365.  
  4366. DEFUN ("energize-edit-mode-prompt", Fenergize_edit_mode_prompt,
  4367.        Senergize_edit_mode_prompt, 6, 6, 0, "")
  4368.      (external, edit_mode, view_mode, other_text, window, split)
  4369.      Lisp_Object external, edit_mode, view_mode, other_text, window, split;
  4370. {
  4371.   int dbox_id;
  4372.   struct screen *s = selected_screen;
  4373.   widget_value *data;
  4374.   Widget parent, dbox;
  4375.  
  4376.   if (!SCREEN_IS_X (s)) error ("not an X screen");
  4377.   parent = s->display.x->widget;
  4378.  
  4379.   CHECK_FIXNUM (external, 0);
  4380.   CHECK_FIXNUM (edit_mode, 0);
  4381.   CHECK_FIXNUM (view_mode, 0);
  4382.   CHECK_FIXNUM (window, 0);
  4383.   CHECK_FIXNUM (split, 0);
  4384.   CHECK_STRING (other_text, 0);
  4385.  
  4386.   editmode.ok = 0;
  4387.   editmode.external = XINT (external);
  4388.   editmode.view = XINT (view_mode);
  4389.   editmode.edit = XINT (edit_mode);
  4390.   editmode.window = XINT (window);
  4391.   editmode.split = XINT (split);
  4392.   editmode.other = 0;
  4393.  
  4394.   BLOCK_INPUT;
  4395.   data = malloc_widget_value ();
  4396.   data->name = "editmode";
  4397.   data->value = "editmode";
  4398.   data->enabled = 1;
  4399.  
  4400.   dbox_id = ++popup_id_tick;
  4401.   dbox = lw_create_widget ("editmode", "editmode", dbox_id, data, parent,
  4402.                1, 0, edit_mode_callback, 0);
  4403.   data->value = 0;
  4404.  
  4405.   data->name = "button1"; data->call_data = data->value = "ok";
  4406.   lw_modify_all_widgets (dbox_id, data, True);
  4407.   data->name = "button2"; data->call_data = data->value = "cancel";
  4408.   lw_modify_all_widgets (dbox_id, data, True);
  4409.   data->name = "button3"; data->call_data = data->value = "help";
  4410.   lw_modify_all_widgets (dbox_id, data, True);
  4411.   data->name = data->call_data = "externalBox";
  4412.   lw_modify_all_widgets (dbox_id, data, True);
  4413.   data->name = "otherText"; data->call_data = "otherText";
  4414.   lw_modify_all_widgets (dbox_id, data, True);
  4415.   data->name = "message"; data->value = "editmode";
  4416.   lw_modify_all_widgets (dbox_id, data, True);
  4417.  
  4418.   data->selected = 1;
  4419.   switch (editmode.external)
  4420.     {
  4421.     case 0: data->name = "externalEmacs"; break;
  4422.     case 1: data->name = "externalViXterm"; break;
  4423.     case 2: data->name = "externalViCmdtool"; break;
  4424.     case 3: data->name = "externalOther"; break;
  4425.     default: abort ();
  4426.     }
  4427.   lw_modify_all_widgets (dbox_id, data, True);
  4428.   switch (editmode.view)
  4429.     {
  4430.     case 0: data->name = "emacsView"; break;
  4431.     case 1: data->name = "viView"; break;
  4432.     case 2: data->name = "lessView"; break;
  4433.     default: abort ();
  4434.     }
  4435.   lw_modify_all_widgets (dbox_id, data, True);
  4436.   switch (editmode.edit)
  4437.     {
  4438.     case 0: data->name = "editEmacs"; break;
  4439.     case 1: data->name = "editVi"; break;
  4440.     default: abort ();
  4441.     }
  4442.   lw_modify_all_widgets (dbox_id, data, True);
  4443.   switch (editmode.window)
  4444.     {
  4445.     case 0: data->name = "windowOne"; break;
  4446.     case 1: data->name = "windowSeveral"; break;
  4447.     case 2: data->name = "windowMany"; break;
  4448.     default: abort ();
  4449.     }
  4450.   lw_modify_all_widgets (dbox_id, data, True);
  4451.   
  4452.   data->name = "otherText";
  4453.   data->selected = 0;
  4454.   data->value = (char *) XSTRING (other_text)->data;
  4455.   data->enabled = (editmode.external == 3);
  4456.   lw_modify_all_widgets (dbox_id, data, True);
  4457.  
  4458.   data->name = "splitScreens";
  4459.   data->enabled = 1;
  4460.   data->selected = editmode.split;
  4461.   data->value = 0;
  4462.   lw_modify_all_widgets (dbox_id, data, True);
  4463.  
  4464.   free_widget_value (data);
  4465.  
  4466.   dbox_up_p++;
  4467.   lw_pop_up_all_widgets (dbox_id);
  4468.   UNBLOCK_INPUT;
  4469.  
  4470.   wait_delaying_user_input (editmode_done, 0);
  4471.  
  4472.   if (editmode.ok == -1)
  4473.     return Fcons (external,
  4474.           list5 (edit_mode, view_mode, other_text, window, split));
  4475.   else if (editmode.ok == 1)
  4476.     return Fcons (make_number (editmode.external),
  4477.           list5 (make_number (editmode.view),
  4478.              make_number (editmode.edit),
  4479.              build_string (editmode.other ? editmode.other : ""),
  4480.              make_number (editmode.window),
  4481.              make_number (editmode.split)));
  4482.   else
  4483.     abort ();
  4484. }
  4485.  
  4486. extern Time mouse_timestamp;
  4487. extern Time global_mouse_timestamp;
  4488.  
  4489. static LWLIB_ID search_id;
  4490. static int last_search_up_p;
  4491.  
  4492. static void
  4493. hide_search_dialog (Widget w, LWLIB_ID id)
  4494. {
  4495. #if 0
  4496.   /* I'd like to do this, but the widget occasionally gets FUCKED */
  4497.   XUnmapWindow (XtDisplay (w), XtWindow (w));
  4498. #else
  4499.   lw_destroy_all_widgets (id);
  4500. #endif
  4501. }
  4502.  
  4503.  
  4504. static void
  4505. search_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
  4506. {
  4507.   Widget parent = widget;
  4508.   Lisp_Object event;
  4509.   widget_value *data;
  4510.   char *name = (char *) client_data;
  4511.   Lisp_Object search, replace;
  4512.   Lisp_Object case_sensitive_p, regexp_p, direction;
  4513.  
  4514.   if ((int) client_data == -1) name = "done";    /* WM_DELETE_WINDOW */
  4515.  
  4516.   while (parent && XtClass (parent) != xmDialogShellWidgetClass)
  4517.     parent = XtParent (parent);
  4518.   if (! parent) abort ();
  4519.  
  4520.   if (!strcmp (name, "done"))
  4521.     {
  4522.       hide_search_dialog (parent, id);
  4523.       return;
  4524.     }
  4525.   else if (!strcmp (name, "gotoStart"))
  4526.     {
  4527.       event = Fallocate_event ();
  4528.       XEVENT (event)->event_type = menu_event;
  4529.       XEVENT (event)->event.eval.function = Qcall_interactively;
  4530.       XEVENT (event)->event.eval.object = intern ("beginning-of-buffer");
  4531.       mouse_timestamp = global_mouse_timestamp;
  4532.       enqueue_command_event (event);
  4533.       return;
  4534.     }
  4535.   else if (!strcmp (name, "gotoEnd"))
  4536.     {
  4537.       event = Fallocate_event ();
  4538.       XEVENT (event)->event_type = menu_event;
  4539.       XEVENT (event)->event.eval.function = Qcall_interactively;
  4540.       XEVENT (event)->event.eval.object = intern ("end-of-buffer");
  4541.       mouse_timestamp = global_mouse_timestamp;
  4542.       enqueue_command_event (event);
  4543.       return;
  4544.     }
  4545.   else if (!strcmp (name, "scrollForward"))
  4546.     {
  4547.       event = Fallocate_event ();
  4548.       XEVENT (event)->event_type = menu_event;
  4549.       XEVENT (event)->event.eval.function = Qcall_interactively;
  4550.       XEVENT (event)->event.eval.object = intern ("scroll-up");
  4551.       mouse_timestamp = global_mouse_timestamp;
  4552.       enqueue_command_event (event);
  4553.       return;
  4554.     }
  4555.   else if (!strcmp (name, "scrollBack"))
  4556.     {
  4557.       event = Fallocate_event ();
  4558.       XEVENT (event)->event_type = menu_event;
  4559.       XEVENT (event)->event.eval.function = Qcall_interactively;
  4560.       XEVENT (event)->event.eval.object = intern ("scroll-down");
  4561.       mouse_timestamp = global_mouse_timestamp;
  4562.       enqueue_command_event (event);
  4563.       return;
  4564.     }
  4565. #if 0
  4566.   else if (!strcmp (name, "help"))
  4567.     {
  4568.       Lisp_Object v = Fmake_vector (3, Qt);
  4569.       XVECTOR (v)->contents [0] = build_string ("ok");
  4570.       XVECTOR (v)->contents [1] = list1 (intern ("ignore"));
  4571.       Fpopup_dialog_box (list2 (build_string ("dbx_search_help"), v));
  4572.       return;
  4573.     }
  4574. #endif
  4575.  
  4576.   BLOCK_INPUT;
  4577.   data = malloc_widget_value ();
  4578.   data->name = "searchText";
  4579.   if (! lw_get_some_values (id, data)) abort ();
  4580.   search = build_string (data->value);
  4581.   data->name = "replaceText";
  4582.   if (! lw_get_some_values (id, data)) abort ();
  4583.   replace = build_string (data->value);
  4584.   data->name = "regexpSearch";
  4585.   if (! lw_get_some_values (id, data)) abort ();
  4586.   regexp_p = (data->selected ? Qt : Qnil);
  4587.   data->name = "caseSearch";
  4588.   if (! lw_get_some_values (id, data)) abort ();
  4589.   case_sensitive_p = (data->selected ? Qt : Qnil);
  4590.  
  4591.   data->name = "directionForward";
  4592.   if (! lw_get_some_values (id, data)) abort ();
  4593.   direction = data->selected ? Qt : Qnil;
  4594.  
  4595.   if (!strcmp (name, "search"))
  4596.     replace = Qnil;
  4597.   else if (!strcmp (name, "replace"))
  4598.     ;
  4599.   else if (!strcmp (name, "replace_all"))
  4600.     {
  4601.       replace = list1 (replace);
  4602. /*      hide_search_dialog (parent, id); */
  4603.     }
  4604.   else
  4605.     abort ();
  4606.  
  4607.   free_widget_value (data);
  4608.   UNBLOCK_INPUT;
  4609.  
  4610.   event = Fallocate_event ();
  4611.   XEVENT (event)->event_type = menu_event;
  4612.   XEVENT (event)->event.eval.function = intern ("energize-search-internal");
  4613.   XEVENT (event)->event.eval.object =
  4614.     (NILP (replace)
  4615.      ? list4 (case_sensitive_p, regexp_p, direction, search)
  4616.      : list5 (case_sensitive_p, regexp_p, direction, search, replace));
  4617.  
  4618.   mouse_timestamp = global_mouse_timestamp;
  4619.   enqueue_command_event (event);
  4620. }
  4621.  
  4622.  
  4623. DEFUN ("energize-search", Fenergize_search, Senergize_search, 0, 0, "",
  4624.        "Pop up the search-and-replace dialog box.")
  4625.      ()
  4626. {
  4627.   int dbox_id;
  4628.   struct screen *s = selected_screen;
  4629.   widget_value *data;
  4630.   Widget parent, dbox;
  4631.  
  4632.   if (!SCREEN_IS_X (s)) error ("not an X screen");
  4633.   parent = s->display.x->widget;
  4634.  
  4635.   BLOCK_INPUT;
  4636.   data = malloc_widget_value ();
  4637.  
  4638.   dbox_id = (search_id ? search_id : (++popup_id_tick));
  4639.   dbox = lw_create_widget ("search", "search", dbox_id, NULL, parent,
  4640.                1, 0, search_callback, 0);
  4641.   data->enabled = 1;
  4642.   data->value = 0;
  4643.  
  4644.   data->name = "button1"; data->value = data->call_data = "search";
  4645.   lw_modify_all_widgets (dbox_id, data, True);
  4646.   data->name = "button2"; data->value = data->call_data = "replace";
  4647.   lw_modify_all_widgets (dbox_id, data, True);
  4648.   data->name = "button3"; data->value = data->call_data = "replace_all";
  4649.   lw_modify_all_widgets (dbox_id, data, True);
  4650.   data->name = "button4"; data->value = data->call_data = "done";
  4651.   lw_modify_all_widgets (dbox_id, data, True);
  4652.  
  4653.   data->value = 0;
  4654.   data->name = data->call_data = "gotoStart";
  4655.   lw_modify_all_widgets (dbox_id, data, True);
  4656.   data->name = data->call_data = "gotoEnd";
  4657.   lw_modify_all_widgets (dbox_id, data, True);
  4658.   data->name = data->call_data = "scrollBack";
  4659.   lw_modify_all_widgets (dbox_id, data, True);
  4660.   data->name = data->call_data = "scrollForward";
  4661.   lw_modify_all_widgets (dbox_id, data, True);
  4662.  
  4663.   data->value = 0;
  4664.   data->name = data->call_data = "caseSearch";
  4665.   data->selected = NILP (current_buffer->case_fold_search);
  4666.   lw_modify_all_widgets (dbox_id, data, True);
  4667.  
  4668.   data->name = data->call_data = "directionForward";
  4669.   data->selected = 1;
  4670.   lw_modify_all_widgets (dbox_id, data, True);
  4671.   data->name = data->call_data = "directionBackward";
  4672.   data->selected = 0;
  4673.   lw_modify_all_widgets (dbox_id, data, True);
  4674.   
  4675.   free_widget_value (data);
  4676.  
  4677.   lw_pop_up_all_widgets (dbox_id);
  4678.   last_search_up_p = 0;
  4679.   if (search_id)
  4680.     {
  4681.       Widget w = lw_get_widget (dbox_id, parent, True);
  4682.       if (! w) abort ();
  4683.       XMapRaised (XtDisplay (w), XtWindow (w));
  4684.     }
  4685.   else
  4686.     {
  4687.       search_id = dbox_id;
  4688.       dbox_up_p++;
  4689.     }
  4690.   UNBLOCK_INPUT;
  4691.  
  4692.   return Qnil;
  4693. }
  4694.  
  4695.  
  4696.  
  4697. /*************** Definition of Emacs Lisp-callable functions ***************/
  4698.  
  4699. void
  4700. syms_of_editorside() 
  4701. {
  4702.   energize_connection = 0;
  4703.   inside_ProcessEnergizeRequest1 = 0;
  4704.  
  4705.   image_cache = make_strings_hashtable (50);
  4706.  
  4707.   staticpro (&energize_buffers_list);
  4708.   energize_buffers_list = Qnil;
  4709.  
  4710.   defsubr(&Ssend_buffer_modified_request);
  4711.   defsubr(&Senergize_list_menu);
  4712.   defsubr(&Senergize_execute_menu_item);
  4713.   defsubr(&Senergize_execute_command_internal);
  4714.   defsubr(&Sconnect_to_energize_internal);
  4715.   defsubr(&Sconnected_to_energize_p);
  4716.   defsubr(&Sclose_connection_to_energize);
  4717.   defsubr(&Shandle_energize_request);
  4718.   defsubr(&Senergize_buffer_p);
  4719.   defsubr(&Senergize_buffer_type);
  4720.   defsubr(&Sset_energize_buffer_type_internal);
  4721.   defsubr(&Senergize_buffer_id);
  4722.   defsubr(&Senergize_request_kill_buffer);
  4723.   defsubr(&Senergize_send_region);
  4724.   defsubr(&Senergize_user_input_buffer_mark);
  4725.   defsubr(&Senergize_update_menubar);
  4726.   defsubr(&Senergize_extent_menu_p);
  4727.   defsubr(&Senergize_query_buffer);
  4728.   defsubr(&Senergize_barf_if_buffer_locked);
  4729.   defsubr(&Senergize_psheets_visible_p);
  4730.   defsubr(&Senergize_buffer_has_psheets_p);
  4731.   defsubr(&Senergize_protocol_level);
  4732.   defsubr(&Senergize_edit_mode_prompt);
  4733.   defsubr(&Senergize_search);
  4734.  
  4735.   search_id = 0;
  4736.  
  4737.   DEFVAR_BOOL ("   inside-parse-buffer", &inside_parse_buffer,
  4738.                "internal variable used to control extent deletion.");
  4739.   inside_parse_buffer = 0;
  4740.   Qinside_parse_buffer = intern ("   inside-parse-buffer");
  4741.  
  4742.   DEFVAR_LISP ("energize-create-buffer-hook", &Venergize_create_buffer_hook,
  4743.                "Hook called when buffer is created by energize; takes \n\
  4744. BUFFER as its only argument.");
  4745.   Venergize_create_buffer_hook = Qnil;
  4746.   
  4747.   DEFVAR_LISP ("energize-buffer-modified-hook", 
  4748.                &Venergize_buffer_modified_hook,
  4749.                "Hook to call when Energize buffer is modified.");
  4750.   Venergize_buffer_modified_hook = Qnil;
  4751.   Qenergize_buffer_modified_hook = intern ("energize-buffer-modified-hook");
  4752.   
  4753.   DEFVAR_LISP ("energize-kernel-modification-hook", 
  4754.                &Venergize_kernel_modification_hook,
  4755.                "Hook called when a buffer is being modified by energize;\n\
  4756. takes no arguments.");
  4757.   Venergize_kernel_modification_hook = Qnil;
  4758.   
  4759.   DEFVAR_BOOL ("ignore-kernel", 
  4760.                &ignore_kernel,
  4761.                "Set when the kernel should be ignored -- for debugging.");
  4762.   ignore_kernel = 0;
  4763.   
  4764.   DEFVAR_LISP ("energize-kernel-busy", &Venergize_kernel_busy,
  4765.                "True if the Energize kernel is busy.");
  4766.   Venergize_kernel_busy = Qnil;
  4767.   Qenergize_kernel_busy = intern ("energize-kernel-busy");
  4768.  
  4769.   DEFVAR_LISP ("energize-kernel-busy-hook", &Venergize_kernel_busy_hook,
  4770.                "Hook called when the Energize kernel becomes busy or non busy.");
  4771.   Venergize_kernel_busy_hook = Qnil;
  4772.  
  4773.   DEFVAR_LISP ("energize-menu-update-hook", &Venergize_menu_update_hook,
  4774.                "Hook called when the Energize kernel updates the menubar.");
  4775.   Venergize_menu_update_hook = Qnil;
  4776.  
  4777.   DEFVAR_LISP ("energize-attributes-mapping", &Venergize_attributes_mapping,
  4778.            "A-list to map kernel attributes indexes to Emacs attributes");
  4779.   Venergize_attributes_mapping = Qnil;
  4780.  
  4781. /*  DEFVAR_INT ("energize-font-lock-p", &energize_font_lock_p,
  4782.                "Set to true enable to use Energize with font-lock");
  4783.   energize_font_lock_p = 1;
  4784.  */
  4785.  
  4786.   Qbefore_change_function = intern ("before-change-function");
  4787.  
  4788.   Qafter_change_function = intern ("after-change-function");
  4789.  
  4790.   Qfirst_change_function = intern ("first-change-function");
  4791.  
  4792.   Qbuffer_locked_by_kernel = intern ("buffer-locked-by-kernel");
  4793.  
  4794.   Qdefault_directory = intern ("default-directory");
  4795.  
  4796.   Qbuffer_file_name = intern ("buffer-file-name");
  4797.  
  4798.   Qenergize_user_input_buffer_mark = 
  4799.     intern ("energize-user-input-buffer-mark");
  4800.  
  4801.   Qenergize_user_input_mode = intern ("energize-user-input-mode");
  4802.  
  4803.   Qenergize_make_many_buffers_visible
  4804.     = intern ("energize-make-many-buffers-visible");
  4805.  
  4806.   Qenergize_extent_data = intern ("energize-extent-data");
  4807.  
  4808.   Qbuffer_undo_list = intern ("buffer-undo-list");
  4809.  
  4810.   Fput (Qbuffer_locked_by_kernel, Qerror_conditions,
  4811.     Fcons (Qbuffer_locked_by_kernel, Fcons (Qerror, Qnil)));
  4812.   Fput (Qbuffer_locked_by_kernel, Qerror_message,
  4813.     build_string ("Buffer is currently locked by kernel"));
  4814. }
  4815.  
  4816. #endif /* ENERGIZE */
  4817.