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 */