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