0
|
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))
|
14
|
725 type_string = (char *) XSTRING_DATA (type);
|
0
|
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
|
14
|
819 stderr_out ("rebuilding widechar map for %s\n", XSTRING_DATA (current_buffer->name));
|
0
|
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 {
|
14
|
1614 Bufbyte *str = XSTRING_DATA (pathname_directory);
|
|
1615 Bytecount size = XSTRING_LENGTH (pathname_directory);
|
0
|
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
|
14
|
1672 && strcmp ((char*) XSTRING_DATA (buffer_name),
|
|
1673 (char*) XSTRING_DATA (XBUFFER (binfo->emacs_buffer)->name)))
|
0
|
1674 rename_the_buffer (buffer_name);
|
|
1675 }
|
|
1676
|
|
1677 if (modifying_p)
|
|
1678 {
|
|
1679 run_hook (Venergize_kernel_modification_hook);
|
|
1680 /* Make sure buffer is current after the hook */
|
|
1681 Fset_buffer (binfo->emacs_buffer);
|
|
1682 }
|
|
1683
|
|
1684 modified_buffer_flag = Fbuffer_modified_p (binfo->emacs_buffer);
|
|
1685
|
|
1686 /* enables buffer edits */
|
|
1687 restore_buffer_state_cons =
|
|
1688 Fcons (make_opaque_ptr ((void *) cbu->bufferId),
|
|
1689 Fcons (XBUFFER (binfo->emacs_buffer)->read_only, Qt));
|
|
1690 record_unwind_protect (restore_buffer_state, restore_buffer_state_cons);
|
|
1691 XBUFFER (binfo->emacs_buffer)->read_only = Qnil;
|
|
1692
|
|
1693 /* any changes here should take place "underneath" these hooks, I think */
|
|
1694 specbind (Qenergize_buffer_modified_hook, Qnil);
|
|
1695 specbind (Qfirst_change_hook, Qnil);
|
|
1696 specbind (Qbefore_change_functions, Qnil);
|
|
1697 specbind (Qbefore_change_function, Qnil); /* #### */
|
|
1698 /* As energize does not use the after-change-function it's not useful to
|
|
1699 bind it to NIL */
|
|
1700 /* specbind (Qafter_change_functions, Qnil); */
|
|
1701 /* specbind (Qafter_change_function, Qnil); #### */
|
|
1702 specbind (Qinhibit_read_only, Qt);
|
|
1703 record_unwind_protect (restore_inside_parse_buffer,
|
|
1704 make_int (inside_parse_buffer));
|
|
1705 inside_parse_buffer = 1;
|
|
1706 specbind (Qbuffer_undo_list, Qt);
|
|
1707
|
|
1708 XBUFFER (binfo->emacs_buffer)->undo_list = Qt;
|
|
1709
|
|
1710 /* BufposForEnergizePos uses the current-buffer */
|
|
1711 from = BufposForEnergizePos (delete_from, binfo);
|
|
1712 to = BufposForEnergizePos (delete_to, binfo);
|
|
1713
|
|
1714 /* See if we should get the characters from the file directly.
|
|
1715 Only protocol 0.10+ will do this.
|
|
1716 */
|
|
1717 #ifdef ENERGIZE_V2_HEADERS
|
|
1718 get_chars_from_file = 0;
|
|
1719 #else
|
|
1720 if (cbu->flags != 0xff)
|
|
1721 get_chars_from_file = cbu->flags & CBFileYourself;
|
|
1722 else
|
|
1723 get_chars_from_file = binfo->flags & CBFileYourself;
|
|
1724 #endif
|
|
1725
|
|
1726 /* Even when we get the chars from a file there is an empty text string */
|
|
1727 if (get_chars_from_file)
|
|
1728 {
|
|
1729 text = CGetVstring (conn, &text_len);
|
|
1730 text = NULL;
|
|
1731 text_len = 0;
|
|
1732 }
|
|
1733 else
|
|
1734 {
|
|
1735 text = CGetVstring (conn, &text_len);
|
|
1736 }
|
|
1737
|
|
1738 /* updates the visited file modtime */
|
|
1739 if (modifying_p && (from != to || text_len)
|
|
1740 /* but only when we do not read the file ourselves */
|
|
1741 && !get_chars_from_file)
|
|
1742 Fset_buffer_modtime (binfo->emacs_buffer, Qnil);
|
|
1743
|
|
1744 if (!modifying_p)
|
|
1745 {
|
|
1746 /* clears the buffer in case we re-use a non-energize buffer */
|
|
1747 previous_point = 1;
|
|
1748 Fset_buffer (binfo->emacs_buffer);
|
|
1749 buffer_delete_range (current_buffer, BUF_BEG (current_buffer),
|
|
1750 BUF_Z (current_buffer), 0);
|
|
1751 }
|
|
1752 else
|
|
1753 {
|
|
1754 #if 1
|
|
1755 display_window = Fget_buffer_window (binfo->emacs_buffer, Qnil, Qnil);
|
|
1756 #endif
|
|
1757 previous_point = BUF_PT (current_buffer);
|
|
1758
|
|
1759 #if 1
|
|
1760 if (!NILP (display_window))
|
|
1761 display_start =
|
|
1762 XINT (Fmarker_position (XWINDOW (display_window)->start));
|
|
1763 #endif
|
|
1764
|
|
1765 if (from != to)
|
|
1766 {
|
|
1767 struct buffer *buf = XBUFFER (binfo->emacs_buffer);
|
|
1768
|
|
1769 Fset_buffer (binfo->emacs_buffer);
|
|
1770 Fwiden (Fcurrent_buffer ());
|
|
1771 if (!NILP (binfo->output_mark)
|
|
1772 && marker_position (binfo->output_mark) >= from)
|
|
1773 Fset_marker (binfo->output_mark, make_int (from),
|
|
1774 binfo->emacs_buffer);
|
|
1775 if (((to - from) == text_len) && !get_chars_from_file &&
|
|
1776 !string_buffer_compare (text, text_len, buf, from))
|
|
1777 /* the new text is the same as the old text, don't clear
|
|
1778 the undo list*/
|
|
1779 {
|
|
1780 Fsetcdr (Fcdr (restore_buffer_state_cons), Qnil);
|
|
1781 no_text_deleted = 1;
|
|
1782 destroy_all_energize_extents (buf);
|
|
1783 }
|
|
1784 else
|
|
1785 {
|
|
1786 /* Do not keep window start if we actually delete text */
|
|
1787 should_keep_window_start = 0;
|
|
1788 Fset_buffer (binfo->emacs_buffer);
|
|
1789 destroy_all_energize_extents (buf);
|
|
1790 if (!get_chars_from_file)
|
|
1791 buffer_delete_range (current_buffer, from, to, 0);
|
|
1792 }
|
|
1793
|
|
1794 /* Do not clear the undo list if getting the chars from the file */
|
|
1795 if (get_chars_from_file)
|
|
1796 Fsetcdr (Fcdr (restore_buffer_state_cons), Qnil);
|
|
1797 }
|
|
1798 else if (!text_len && !get_chars_from_file)
|
|
1799 /* if there is no text and we didn't delete anything,
|
|
1800 don't clear the undo_list slot */
|
|
1801 Fsetcdr (Fcdr (restore_buffer_state_cons), Qnil);
|
|
1802
|
|
1803 }
|
|
1804
|
|
1805 /* buffer type */
|
|
1806 if (cbu->flags != 0xff && cbu->flags != binfo->flags)
|
|
1807 {
|
|
1808 if (!modifying_p)
|
|
1809 {
|
|
1810 if (cbu->flags == CBUserInput)
|
|
1811 {
|
|
1812 Lisp_Object buffer_local_variable_name =
|
|
1813 Qenergize_user_input_buffer_mark;
|
|
1814 binfo->output_mark = Fmake_marker ();
|
|
1815 Fset_marker (binfo->output_mark, make_int (1),
|
|
1816 binfo->emacs_buffer);
|
|
1817 /* make sure that this guy doesn't get GC'd out from under us */
|
|
1818 Fmake_local_variable (buffer_local_variable_name);
|
|
1819 Fput (buffer_local_variable_name, Qpermanent_local, Qt);
|
|
1820 Fset (buffer_local_variable_name, binfo->output_mark);
|
|
1821 /* Make sure buffer is current after the hook */
|
|
1822 Fset_buffer (binfo->emacs_buffer);
|
|
1823 }
|
|
1824 }
|
|
1825 binfo->flags = cbu->flags;
|
|
1826 }
|
|
1827
|
|
1828 if (get_chars_from_file && text_len != 0)
|
|
1829 /* I think this is always true, but let's make sure - jwz */
|
|
1830 abort ();
|
|
1831
|
|
1832 if (text_len)
|
|
1833 {
|
|
1834 if (!NILP (binfo->output_mark))
|
|
1835 {
|
|
1836 Fset_buffer (binfo->emacs_buffer);
|
|
1837 if (XMARKER (binfo->output_mark)->buffer)
|
|
1838 Fgoto_char (binfo->output_mark, Fcurrent_buffer ());
|
|
1839 else
|
|
1840 /* This should not happen */
|
|
1841 Fgoto_char (make_int (BUF_ZV (XBUFFER (binfo->emacs_buffer))),
|
|
1842 Fcurrent_buffer ());
|
|
1843
|
|
1844 if (BUF_PT (current_buffer) <= previous_point)
|
|
1845 {
|
|
1846 #if 1
|
|
1847 display_start += text_len;
|
|
1848 #endif
|
|
1849 previous_point += text_len;
|
|
1850 }
|
|
1851 buffer_insert_raw_string (current_buffer, text, text_len);
|
|
1852 Fset_marker (binfo->output_mark, make_int (BUF_PT (current_buffer)),
|
|
1853 binfo->emacs_buffer);
|
|
1854 }
|
|
1855 else if (modifying_p)
|
|
1856 {
|
|
1857 Fgoto_char (make_int (from), Fcurrent_buffer ());
|
|
1858 if (!no_text_deleted)
|
|
1859 buffer_insert_raw_string (current_buffer, text, text_len);
|
|
1860 }
|
|
1861 else
|
|
1862 buffer_insert_raw_string (current_buffer, text, text_len);
|
|
1863
|
|
1864 previous_point = XINT (Fgoto_char (make_int (previous_point)),
|
|
1865 Fcurrent_buffer ());
|
|
1866 }
|
|
1867 else if (get_chars_from_file && !modifying_p)
|
|
1868 {
|
|
1869 /* !modifying_p means the buffer is being created - read the text
|
|
1870 from the file. */
|
|
1871 Finsert_file_contents_internal (Fbuffer_file_name (binfo->emacs_buffer),
|
|
1872 /* #### coding system not correct */
|
|
1873 Qt, Qnil, Qnil, Qnil, Qnil, Qnil));
|
|
1874 }
|
|
1875
|
|
1876 if (!relative_p)
|
|
1877 extent_offset = 0;
|
|
1878 else if (!NILP (binfo->output_mark))
|
|
1879 extent_offset = EnergizePosForBufpos (XINT (Fmarker_position
|
|
1880 (binfo->output_mark)),
|
|
1881 binfo);
|
|
1882 else
|
|
1883 extent_offset = EnergizePosForBufpos (BUF_Z(XBUFFER(binfo->emacs_buffer)),
|
|
1884 binfo);
|
|
1885
|
|
1886 #if 1
|
|
1887 if (text_len || !text)
|
|
1888 hack_window_point (display_window,
|
|
1889 make_int (previous_point),
|
|
1890 make_int (display_start),
|
|
1891 should_keep_window_start,
|
|
1892 binfo);
|
|
1893 #endif
|
|
1894
|
|
1895
|
|
1896 /* Classes, generics and extents */
|
|
1897 /* make sure that we have enough room in the hash table */
|
|
1898 expand_hashtable (binfo->id_to_object,
|
|
1899 cbu->nClass + cbu->nGeneric + cbu->nExtent);
|
|
1900 read_energize_class_data (conn, cbu->nClass, binfo, modifying_p);
|
|
1901 read_energize_generic_data (conn, cbu->nGeneric, binfo, modifying_p);
|
|
1902 read_energize_extent_data (conn, cbu->nExtent, binfo, modifying_p, extent_offset);
|
|
1903
|
|
1904 /* Restore the modified bit */
|
|
1905 Fset_buffer_modified_p (modified_buffer_flag, binfo->emacs_buffer);
|
|
1906
|
|
1907 if (get_chars_from_file && modifying_p)
|
|
1908 {
|
|
1909 /* modifying_p means the buffer already exists and the extents are
|
|
1910 being re-written. It may be that the file has changed on disk,
|
|
1911 and the extents no longer correspond to the text in the buffer,
|
|
1912 which would be bad. So, check the file on disk, and if it has
|
|
1913 changed, offer to revert.
|
|
1914
|
|
1915 As this runs lisp code which may prompt the user, and consequently
|
|
1916 may accept process output, be careful to do this after we have
|
|
1917 finished reading the current request from the Energize connection.
|
|
1918 */
|
|
1919 if (NILP (Fverify_visited_file_modtime (binfo->emacs_buffer)))
|
|
1920 {
|
|
1921 call1 (Qenergize_auto_revert_buffer, binfo->emacs_buffer);
|
|
1922 hack_window_point (display_window,
|
|
1923 make_int (previous_point),
|
|
1924 make_int (display_start),
|
|
1925 1,
|
|
1926 binfo);
|
|
1927 }
|
|
1928 }
|
|
1929
|
|
1930
|
|
1931 /* restore modified hooks and globals, and return the previous buffer */
|
|
1932 UNGCPRO;
|
|
1933 unbind_to (speccount, Qnil);
|
|
1934 }
|
|
1935
|
|
1936
|
|
1937 static void
|
|
1938 cleanly_destroy_all_widgets (int count, LWLIB_ID *ids)
|
|
1939 {
|
|
1940 /* This just calls lw_destroy_all_widgets, but is careful to make sure that
|
|
1941 this doesn't cause the frames to shrink. If one deletes psheets
|
|
1942 (children of the "control" area of the MainWindow) without first
|
|
1943 unmanaging the MainWindow, the frame resizes. So first unmanage all
|
|
1944 the MainWindows of all applicable frames, then remanage them. This is
|
|
1945 nasty, but...
|
|
1946 */
|
|
1947 Lisp_Object frmcons, devcons, concons;
|
|
1948 int i, j;
|
|
1949
|
|
1950 if (count == 0)
|
|
1951 return;
|
|
1952
|
|
1953 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
|
|
1954 {
|
|
1955 Lisp_Object frame = XCAR (frmcons);
|
|
1956 struct frame *f = XFRAME (frame);
|
|
1957
|
|
1958 if (!FRAME_X_P (f))
|
|
1959 continue;
|
|
1960 /* Optimization: only unmanage the MainWindow if this frame is
|
|
1961 displaying one of the psheets in question. (Special casing
|
|
1962 the debugger panel as usual...)
|
|
1963 */
|
|
1964 for (i = 0; i < count; i++)
|
|
1965 if (ids [i] == debuggerpanel_sheet)
|
|
1966 {
|
|
1967 XtUnmanageChild (FRAME_X_CONTAINER_WIDGET (f));
|
|
1968 goto next_frame;
|
|
1969 }
|
|
1970 else
|
|
1971 for (j = 0; j < FRAME_X_CURRENT_PSHEET_COUNT (f); j++)
|
|
1972 if (ids [i] == FRAME_X_CURRENT_PSHEETS (f) [j])
|
|
1973 {
|
|
1974 XtUnmanageChild (FRAME_X_CONTAINER_WIDGET (f));
|
|
1975 goto next_frame;
|
|
1976 }
|
|
1977 next_frame: ;
|
|
1978 }
|
|
1979
|
|
1980 for (i = 0; i < count; i++)
|
|
1981 {
|
|
1982 lw_destroy_all_widgets (ids [i]);
|
|
1983 if (ids [i] == debuggerpanel_sheet)
|
|
1984 {
|
|
1985 debuggerpanel_sheet = 0;
|
|
1986 desired_debuggerpanel_exposed_p = 0;
|
|
1987 }
|
|
1988 }
|
|
1989
|
|
1990 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
|
|
1991 {
|
|
1992 Lisp_Object frame = XCAR (frmcons);
|
|
1993 struct frame *f = XFRAME (frame);
|
|
1994
|
|
1995 if (!FRAME_X_P (f))
|
|
1996 continue;
|
|
1997 XtManageChild (FRAME_X_CONTAINER_WIDGET (f));
|
|
1998 }
|
|
1999 }
|
|
2000
|
|
2001
|
|
2002 /* kill an Energize buffer */
|
|
2003 static void
|
|
2004 forget_buffer (BufferInfo *binfo)
|
|
2005 {
|
|
2006 int i;
|
|
2007 Lisp_Object buffer = binfo->emacs_buffer;
|
|
2008
|
|
2009 remove_buffer_info (binfo->id, buffer, binfo->editor);
|
|
2010 Venergize_buffers_list = Fdelq (buffer, Venergize_buffers_list);
|
|
2011
|
|
2012 /* if there was an associated frame */
|
|
2013 if (!NILP (binfo->frame))
|
|
2014 Fdelete_frame (binfo->frame, Qt);
|
|
2015
|
|
2016 if (binfo->n_p_sheets > 0)
|
|
2017 {
|
|
2018 /* Also delete the dialog boxes associated with the buffer. */
|
|
2019 cleanly_destroy_all_widgets (binfo->n_p_sheets,
|
|
2020 (LWLIB_ID *) binfo->p_sheet_ids);
|
|
2021 }
|
|
2022
|
|
2023 free_buffer_info (binfo);
|
|
2024
|
|
2025 XBUFFER (buffer)->undo_list = Qnil;
|
|
2026 /* flush the buffer SOE before flushing the extents */
|
|
2027 free_buffer_cached_stack (XBUFFER (buffer));
|
|
2028 XBUFFER (buffer)->extents = Qnil;
|
|
2029 }
|
|
2030
|
|
2031 /********************** Request-related utilities ************************/
|
|
2032
|
|
2033 /* outputs a single extent in the connection buffer */
|
|
2034 static void
|
|
2035 write_energize_extent_data (Connection *conn, Energize_Extent_Data *ext,
|
|
2036 unsigned int start, unsigned int end)
|
|
2037 {
|
|
2038 switch (ext->extentType)
|
|
2039 {
|
|
2040 case CEAttribute:
|
|
2041 CWriteExtent (conn, CEAttribute, ext->id, start, end,
|
|
2042 (EId)ext->u.attr.attrValue);
|
|
2043 break;
|
|
2044
|
|
2045 case CEAbbreviation:
|
|
2046 CWriteExtent (conn, CEAbbreviation, ext->id, start, end,
|
|
2047 (EId)ext->u.abbrev.isOpened);
|
|
2048 break;
|
|
2049
|
|
2050 case CEGeneric:
|
|
2051 CWriteExtent (conn, CEGeneric, ext->id, start, end, 0);
|
|
2052 break;
|
|
2053
|
|
2054 case CEWriteProtect:
|
|
2055 CWriteExtent (conn, CEWriteProtect, ext->id, start, end, 0);
|
|
2056 break;
|
|
2057 }
|
|
2058 }
|
|
2059
|
|
2060 /* Function called by map_extents in SaveBufferToEnergize. Outputs the
|
|
2061 extents for the extents corresponding to Energize objects, and
|
|
2062 increments the n_extents count. */
|
|
2063
|
|
2064 static int
|
|
2065 write_energize_extent_data_mapper (EXTENT extent, void *arg)
|
|
2066 {
|
|
2067 binfo_and_n_extents *bane = (binfo_and_n_extents*)arg;
|
|
2068 Lisp_Object extent_obj;
|
|
2069 Energize_Extent_Data *ext;
|
|
2070
|
|
2071 XSETEXTENT (extent_obj, extent);
|
|
2072 ext = extent_to_data (extent_obj);
|
|
2073 if (ext)
|
|
2074 {
|
|
2075 Bufpos first = XINT (Fextent_start_position (extent_obj));
|
|
2076 Bufpos last = XINT (Fextent_end_position (extent_obj));
|
|
2077 write_energize_extent_data (bane->binfo->editor->conn, ext,
|
|
2078 EnergizePosForBufpos (first, bane->binfo),
|
|
2079 EnergizePosForBufpos (last, bane->binfo));
|
|
2080 bane->n_extents += 1;
|
|
2081 }
|
|
2082 return 0;
|
|
2083 }
|
|
2084
|
|
2085 /* Sends a BufferSaved request to energize for binfo */
|
|
2086 static void
|
|
2087 write_energize_buffer_data (BufferInfo *binfo)
|
|
2088 {
|
|
2089 Connection *conn = binfo->editor->conn;
|
|
2090 EId bufferId = binfo->id;
|
|
2091 CBuffer *cbu;
|
|
2092 CEditorRequest *req;
|
|
2093 struct buffer *cur_buff = current_buffer;
|
|
2094 int speccount = specpdl_depth ();
|
|
2095 Lisp_Object file_name;
|
|
2096
|
|
2097 binfo_and_n_extents bane;
|
|
2098
|
|
2099 /* selects the buffer as current */
|
|
2100 Fset_buffer (binfo->emacs_buffer);
|
|
2101
|
|
2102 /* write header */
|
|
2103 cbu = CWriteBufferSavedHeader (conn);
|
|
2104 cbu->bufferId = bufferId;
|
|
2105 cbu->flags = 0;
|
|
2106 cbu->nClass = 0;
|
|
2107 cbu->nGeneric = 0;
|
|
2108
|
|
2109 /* file name */
|
|
2110 file_name = current_buffer->filename;
|
|
2111 if (STRINGP (file_name))
|
14
|
2112 CWriteVstring0 (conn, XSTRING_DATA (file_name));
|
0
|
2113 else
|
|
2114 CWriteVstring0 (conn, "");
|
|
2115 CWriteVstring0 (conn, ""); /* directory name */
|
|
2116 CWriteVstring0 (conn, ""); /* buffer name */
|
|
2117
|
|
2118 /* write the text */
|
|
2119 #ifndef ENERGIZE_V2_HEADERS
|
|
2120 if (binfo->flags & CBFileYourself)
|
|
2121 {
|
|
2122 /* Only the 0.10+ protocol will ask us to write the file directly. */
|
|
2123 Lisp_Object start;
|
|
2124 Lisp_Object end;
|
|
2125 XSETINT (start, BUF_BEG (current_buffer));
|
|
2126 XSETINT (end, BUF_Z (current_buffer));
|
|
2127 Fwrite_region_internal (start, end,
|
|
2128 Fbuffer_file_name (binfo->emacs_buffer),
|
|
2129 /* #### coding system not correct */
|
|
2130 Qnil, Qt, Qnil);
|
|
2131 CNeedOutputSize (conn, 9);
|
|
2132 CWriteVstringLen (conn, NULL, 0);
|
|
2133 }
|
|
2134 else
|
|
2135 #endif /* ENERGIZE_V2_HEADERS */
|
|
2136 {
|
|
2137 Lisp_Object string = make_string_from_buffer (current_buffer,
|
|
2138 BUF_BEG (current_buffer),
|
|
2139 BUF_Z (current_buffer));
|
14
|
2140 CNeedOutputSize (conn, XSTRING_LENGTH (string) + 9);
|
|
2141 CWriteVstringLen (conn, XSTRING_DATA (string), XSTRING_LENGTH (string));
|
0
|
2142 }
|
|
2143
|
|
2144 /* write the extents */
|
|
2145 bane.binfo = binfo;
|
|
2146 bane.n_extents = 0;
|
|
2147
|
|
2148 /* Only write the extents when not filing ourselves */
|
|
2149 #ifndef ENERGIZE_V2_HEADERS
|
|
2150 if (!(binfo->flags & CBFileYourself))
|
|
2151 #endif
|
|
2152 {
|
|
2153 map_extents (BUF_BEG (current_buffer), BUF_Z (current_buffer),
|
|
2154 write_energize_extent_data_mapper, &bane,
|
|
2155 binfo->emacs_buffer, 0, ME_END_CLOSED);
|
|
2156
|
|
2157 }
|
|
2158
|
|
2159 /* update nextent in request's header */
|
|
2160 req = (CEditorRequest *)conn->header;
|
|
2161 req->buffersaved.buffer.nExtent = bane.n_extents;
|
|
2162 CWriteLength (conn);
|
|
2163 CWriteRequestBuffer (conn);
|
|
2164
|
|
2165 /* sets the flags so that we will warn Energize about more modifications */
|
|
2166 binfo->modified_state = 0;
|
|
2167
|
|
2168 /* Mark the buffer as non editable so that we will ask Energize about it
|
|
2169 before modifying it again */
|
|
2170 binfo->editable = 0;
|
|
2171
|
|
2172 /* restores the buffer as current */
|
|
2173 set_buffer_internal (cur_buff);
|
|
2174 unbind_to (speccount, Qnil);
|
|
2175 }
|
|
2176
|
|
2177 static unsigned long
|
|
2178 energize_extent_data_id (Energize_Extent_Data *ext)
|
|
2179 {
|
|
2180 return ext ? ext->id : 0;
|
|
2181 }
|
|
2182
|
|
2183
|
|
2184 /********************** Menu ("keywords") operations **********************/
|
|
2185
|
|
2186 static int
|
|
2187 something_answered_p (void* arg)
|
|
2188 {
|
|
2189 struct reply_wait* rw = (struct reply_wait*)arg;
|
|
2190 return rw->answered_p || !energize_connection || !energize_connection->conn;
|
|
2191 }
|
|
2192
|
|
2193
|
|
2194 static void
|
|
2195 push_wait (struct reply_wait* rw)
|
|
2196 {
|
|
2197 rw->next = global_reply_wait;
|
|
2198 global_reply_wait = rw;
|
|
2199 }
|
|
2200
|
|
2201 static Lisp_Object
|
|
2202 remove_wait (Lisp_Object obj)
|
|
2203 {
|
|
2204 struct reply_wait* gw;
|
|
2205 struct reply_wait* previous;
|
|
2206 struct reply_wait* rw = (struct reply_wait *) get_opaque_ptr (obj);
|
|
2207
|
|
2208 for (previous = 0, gw = global_reply_wait;
|
|
2209 gw != rw;
|
|
2210 previous = gw, gw = gw->next);
|
|
2211 if (previous)
|
|
2212 previous->next = gw->next;
|
|
2213 else
|
|
2214 global_reply_wait = gw->next;
|
|
2215 return Qnil;
|
|
2216 }
|
|
2217
|
|
2218 static struct reply_wait*
|
|
2219 find_wait_reply (int serial)
|
|
2220 {
|
|
2221 struct reply_wait* gw;
|
|
2222 for (gw = global_reply_wait; gw && gw->serial != serial; gw = gw->next);
|
|
2223 return gw;
|
|
2224 }
|
|
2225
|
|
2226
|
|
2227 static int
|
|
2228 wait_for_reply (struct reply_wait* rw)
|
|
2229 {
|
|
2230 int speccount = specpdl_depth ();
|
|
2231 rw->answered_p = 0;
|
|
2232 push_wait (rw);
|
|
2233 record_unwind_protect (remove_wait, make_opaque_ptr (rw));
|
|
2234 wait_delaying_user_input (something_answered_p, rw);
|
|
2235 unbind_to (speccount, Qnil);
|
|
2236 return rw->answered_p;
|
|
2237 }
|
|
2238
|
|
2239 /* gets the menu for the buffer/extent pair at the head of the request buffer.
|
|
2240 returns the propose choice request if succeeds, nil otherwise (kernel
|
|
2241 connection closed, or not connected)
|
|
2242 */
|
|
2243
|
|
2244 static Lisp_Object
|
|
2245 get_energize_menu (Lisp_Object buffer, Lisp_Object extent_obj, int selection_p,
|
|
2246 Lisp_Object only_name)
|
|
2247 {
|
|
2248 Connection* conn;
|
|
2249 EId buffer_id;
|
|
2250 EId extent_id;
|
|
2251 Lisp_Object result;
|
|
2252 struct reply_wait rw;
|
|
2253 struct gcpro gcpro1, gcpro2;
|
|
2254
|
|
2255 if (!get_energize_connection_and_buffer_id (buffer,
|
|
2256 (void **) &conn,
|
|
2257 (long *) &buffer_id))
|
|
2258 return Qnil;
|
|
2259
|
|
2260 if (EXTENTP (extent_obj))
|
|
2261 extent_id = energize_extent_data_id (extent_to_data (extent_obj));
|
|
2262 else
|
|
2263 extent_id = 0;
|
|
2264
|
|
2265 CWriteQueryChoicesRequest (conn, buffer_id, extent_id);
|
|
2266 conn->header->data =
|
|
2267 selection_p ? CEChasCharSelection | CEChasObjectSelection : 0;
|
|
2268 conn->header->serial = ++request_serial_number;
|
|
2269 CWriteRequestBuffer (conn);
|
|
2270
|
|
2271 /* wait for the acknowledge */
|
|
2272 rw.serial = request_serial_number;
|
|
2273 rw.objectId = buffer_id;
|
|
2274 rw.genericId = extent_id;
|
|
2275 rw.menu_result = Qnil;
|
|
2276 rw.only_name = only_name;
|
|
2277
|
|
2278 GCPRO2 (rw.menu_result, rw.only_name);
|
|
2279 wait_for_reply (&rw);
|
|
2280 result = rw.menu_result;
|
|
2281 UNGCPRO;
|
|
2282 return result;
|
|
2283 }
|
|
2284
|
|
2285
|
|
2286 static void
|
|
2287 execute_energize_menu (Lisp_Object buffer, Energize_Extent_Data* ext,
|
|
2288 char* name, EId item_id, EId flags,
|
|
2289 Lisp_Object selection, Lisp_Object no_confirm)
|
|
2290 {
|
|
2291 Connection* conn;
|
|
2292 EId buffer_id;
|
|
2293 EId extent_id;
|
|
2294 BufferInfo* binfo;
|
|
2295 struct reply_wait rw;
|
|
2296
|
|
2297 if (!get_energize_connection_and_buffer_id (buffer, (void**)&conn,
|
|
2298 (long*)&buffer_id))
|
|
2299 return;
|
|
2300
|
|
2301 extent_id = energize_extent_data_id (ext);
|
|
2302
|
|
2303 if ((flags & CKBuffer) && !NILP (Fbuffer_modified_p (buffer)))
|
|
2304 {
|
|
2305 /* saves buffer if requested and needed */
|
|
2306 binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection);
|
|
2307 if (binfo)
|
|
2308 write_energize_buffer_data (binfo);
|
|
2309 }
|
|
2310
|
|
2311 CWriteExecuteChoicesRequest (conn, buffer_id, extent_id, item_id, 0, 0);
|
|
2312 /* send the menu name */
|
|
2313 if (energize_connection->minor >= 7)
|
|
2314 CWriteVstring0 (conn, name);
|
|
2315 conn->header->serial = ++request_serial_number;
|
|
2316 conn->header->data = 0;
|
|
2317 if (STRINGP (selection))
|
|
2318 {
|
|
2319 conn->header->data |= CEChasCharSelection;
|
14
|
2320 CWriteVstringLen (conn, XSTRING_DATA (selection),
|
|
2321 XSTRING_LENGTH (selection));
|
0
|
2322 }
|
|
2323 else if (VECTORP (selection))
|
|
2324 {
|
|
2325 int i;
|
|
2326 EId data;
|
|
2327 conn->header->data |= CEChasObjectSelection;
|
|
2328
|
|
2329 /* writes the length */
|
|
2330 data = vector_length (XVECTOR (selection));
|
|
2331 CWrite (conn, EId, &data);
|
|
2332
|
|
2333 /* writes the elements */
|
|
2334 for (i = 0; i < vector_length (XVECTOR (selection)); i++)
|
|
2335 {
|
|
2336 if (CONSP (vector_data (XVECTOR (selection)) [i]))
|
|
2337 data = lisp_to_word (vector_data (XVECTOR (selection)) [i]);
|
|
2338 else
|
|
2339 data = XINT (vector_data (XVECTOR (selection)) [i]);
|
|
2340 CWrite (conn, EId, &data);
|
|
2341 }
|
|
2342 }
|
|
2343 else if (CONSP (selection))
|
|
2344 {
|
|
2345 Lisp_Object type = Fcar (selection);
|
|
2346 Lisp_Object value = Fcdr (selection);
|
|
2347 if (EQ (type, intern ("ENERGIZE_OBJECT"))
|
|
2348 && STRINGP (value))
|
|
2349 {
|
|
2350 conn->header->data |= CEChasObjectSelection;
|
14
|
2351 CWriteN (conn, char, XSTRING_DATA (value),
|
|
2352 XSTRING_LENGTH (value));
|
0
|
2353 }
|
|
2354 }
|
|
2355 else if (!NILP (selection))
|
|
2356 error ("unrecognized energize selection");
|
|
2357
|
|
2358 if (!NILP (no_confirm))
|
|
2359 conn->header->data |= CECnoConfirm;
|
|
2360 CWriteLength (conn);
|
|
2361 CWriteRequestBuffer (conn);
|
|
2362
|
|
2363 /* wait for the acknowledge */
|
|
2364 rw.serial = request_serial_number;
|
|
2365 rw.objectId = buffer_id;
|
|
2366 rw.genericId = extent_id;
|
|
2367 rw.itemId = item_id;
|
|
2368 rw.message = 0;
|
|
2369
|
|
2370 if (wait_for_reply (&rw) && !rw.status)
|
|
2371 {
|
|
2372 char message [128];
|
|
2373 if (energize_connection && energize_connection->conn)
|
|
2374 sprintf (message, IDENTITY_CRISIS " command failed: %.80s",
|
|
2375 (rw.message ? rw.message : "(null)"));
|
|
2376 else
|
|
2377 sprintf (message, "Connection to " IDENTITY_CRISIS " was closed.");
|
|
2378 if (rw.message)
|
|
2379 xfree (rw.message);
|
|
2380 error (message);
|
|
2381 }
|
|
2382 else
|
|
2383 {
|
|
2384 if (rw.message)
|
|
2385 xfree (rw.message);
|
|
2386 if (!energize_connection)
|
|
2387 error ("Connection to " IDENTITY_CRISIS " was closed.");
|
|
2388 }
|
|
2389 }
|
|
2390
|
|
2391 /* Returns a list of vectors representing the menu choices. Next request
|
|
2392 in connection must be a ProposeChoices. The list is
|
|
2393 (buffer extent <item1> ... <itemN>). <itemI> is (name id1 id2 flags).
|
|
2394 Idi is (high . low). We build the list in reverse order and nreverse
|
|
2395 it. If (only_name != 0), we only return the item of named only_name as
|
|
2396 a vector. */
|
|
2397
|
|
2398 static Lisp_Object
|
|
2399 list_choices (Lisp_Object buffer, Lisp_Object extent_obj,
|
|
2400 Lisp_Object only_name, CProposeChoicesRequest* creq)
|
|
2401 {
|
|
2402 Connection *conn;
|
|
2403 int i;
|
|
2404 Lisp_Object item_list;
|
|
2405 Lisp_Object item;
|
|
2406 struct Lisp_Vector *v;
|
|
2407 struct gcpro gcpro1, gcpro2, gcpro3;
|
|
2408 CChoice *choice;
|
|
2409 ReqLen name_length;
|
|
2410 char *name;
|
|
2411 char *arg_name;
|
|
2412
|
|
2413 if (energize_connection && energize_connection->conn)
|
|
2414 conn = energize_connection->conn;
|
|
2415 else
|
|
2416 return Qnil;
|
|
2417
|
|
2418 if (!creq || creq->head.reqType != ProposeChoicesRType)
|
|
2419 {
|
|
2420 CSkipRequest (conn);
|
|
2421 return Qnil;
|
|
2422 }
|
|
2423
|
|
2424 item = Qnil;
|
|
2425 item_list = Qnil;
|
|
2426
|
|
2427 GCPRO3 (only_name, item_list, item);
|
|
2428
|
|
2429 for (i = 0; i < (int)(creq->nChoices); i++)
|
|
2430 {
|
|
2431 choice = CGet (conn, CChoice);
|
|
2432 name = CGetVstring (conn, &name_length);
|
|
2433 if (!name_length)
|
|
2434 continue;
|
|
2435
|
|
2436 /* the argument, if passed, is another string after the NUL (!)
|
|
2437 * this is a quick hack to provide cheap arguments to menus entries */
|
|
2438 arg_name = strchr (name, 0240);
|
|
2439 if (arg_name)
|
|
2440 {
|
|
2441 *arg_name= 0;
|
|
2442 arg_name += 1;
|
|
2443 }
|
|
2444
|
|
2445 if (!NILP (only_name))
|
|
2446 {
|
14
|
2447 if (!strcmp ((char*) XSTRING_DATA (only_name), name))
|
0
|
2448 {
|
|
2449 if (NILP (item))
|
|
2450 {
|
|
2451 item = make_vector (5, Qnil);
|
|
2452 v = XVECTOR (item);
|
|
2453 v->contents [0] = only_name;
|
|
2454 }
|
|
2455 v->contents [1] = word_to_lisp (choice->choiceId);
|
|
2456 v->contents [2] = Qnil;
|
|
2457 v->contents [3] = make_int (choice->flags);
|
|
2458 v->contents [4] = arg_name ? build_string (arg_name) : Qnil;
|
|
2459 }
|
|
2460 }
|
|
2461 else
|
|
2462 {
|
|
2463 item = make_vector (5, Qnil);
|
|
2464 v = XVECTOR (item);
|
|
2465 v->contents [0] = build_string (name);
|
|
2466 v->contents [1] = word_to_lisp (choice->choiceId);
|
|
2467 v->contents [2] = Qnil;
|
|
2468 v->contents [3] = make_int (choice->flags);
|
|
2469 v->contents [4] = arg_name ? build_string (arg_name) : Qnil;
|
|
2470 item_list = Fcons (item, item_list); /* pushes in the list */
|
|
2471 }
|
|
2472 }
|
|
2473
|
|
2474 if (NILP (only_name))
|
|
2475 item_list = Fcons (buffer, Fcons (extent_obj, Fnreverse (item_list)));
|
|
2476 UNGCPRO;
|
|
2477
|
|
2478 return NILP (only_name) ? item_list : item;
|
|
2479 }
|
|
2480
|
|
2481 DEFUN ("energize-list-menu", Fenergize_list_menu,
|
|
2482 Senergize_list_menu, 3, 4, 0 /*
|
|
2483 Request the set of menu options from the Energize server that are
|
|
2484 appropriate to the buffer and the extent. Extent can be (), in which case
|
|
2485 the options are requested for the whole buffer. Selection-p tells
|
|
2486 if the selection is available on the dislpay emacs is using.
|
|
2487 Returns the options as
|
|
2488 a list that can be passed to energize-activate-menu. Items
|
|
2489 in the list can also be passed to energize-execute-menu-item.
|
|
2490 The list is (buffer extent or () <item1> ... <itemN>).
|
|
2491 where <itemI> is (name id1 id2 flags); idI is (high . low).
|
|
2492 If optional argument only-name is provided only the item with name only-name
|
|
2493 is returned, or () if no such item exists.
|
|
2494 */ )
|
|
2495 (buffer, extent_obj, selection_p, only_name)
|
|
2496 Lisp_Object buffer, extent_obj, selection_p, only_name;
|
|
2497 {
|
|
2498 Lisp_Object res;
|
|
2499 CHECK_BUFFER (buffer);
|
|
2500
|
|
2501 if (!energize_connection || !energize_connection->conn) return Qnil;
|
|
2502
|
|
2503 if (!NILP (only_name))
|
|
2504 CHECK_STRING (only_name);
|
|
2505
|
|
2506 res = get_energize_menu (buffer, extent_obj, !NILP (selection_p),
|
|
2507 only_name);
|
|
2508 notify_delayed_requests ();
|
|
2509 return res;
|
|
2510 }
|
|
2511
|
|
2512 DEFUN ("energize-execute-menu-item", Fenergize_execute_menu_item,
|
|
2513 Senergize_execute_menu_item, 3, 5, 0 /*
|
|
2514 Item is a vector received by energize-list-menu. Sends a request to
|
|
2515 execute the code associated to this menu inside the Energize server.
|
|
2516 Optional fourth argument is a string or a vector to be used as the selection
|
|
2517 for entry disabled because they need the selection.
|
|
2518 Optional fifth argument, if non NIL, tells Energize to not request
|
|
2519 confirmation before executing the command.
|
|
2520 */ )
|
|
2521 (buffer, extent_obj, item, selection, no_confirm)
|
|
2522 Lisp_Object buffer, extent_obj, item, selection, no_confirm;
|
|
2523 {
|
|
2524 struct Lisp_Vector *v;
|
|
2525
|
|
2526 if (!energize_connection || !energize_connection->conn) return Qnil;
|
|
2527
|
|
2528 CHECK_BUFFER (buffer);
|
|
2529 CHECK_VECTOR (item);
|
|
2530 v = XVECTOR (item);
|
|
2531
|
|
2532 if (vector_length (v) != 4)
|
|
2533 error ("Bad menu item to energize-execute-menu-item");
|
|
2534
|
|
2535 /* ignore the flags for now */
|
|
2536 execute_energize_menu (buffer, extent_to_data (extent_obj),
|
14
|
2537 (char*) XSTRING_DATA (v->contents [0]),
|
0
|
2538 lisp_to_word (v->contents [1]),
|
|
2539 XINT (v->contents [3]),
|
|
2540 selection,
|
|
2541 no_confirm);
|
|
2542
|
|
2543 return Qt;
|
|
2544 }
|
|
2545
|
|
2546 DEFUN ("energize-execute-command-internal", Fenergize_execute_command_internal,
|
|
2547 Senergize_execute_command_internal, 3, 5, 0 /*
|
|
2548 Command is a string naming an energize command. Sends a request to
|
|
2549 execute this command inside the Energize server.
|
|
2550 Optional fourth argument is a string or a vector to be used as the selection.
|
|
2551 Optional fifth argument, if non NIL, tells Energize to not request
|
|
2552 confirmation before executing the command.
|
|
2553
|
|
2554 See also 'energize-list-menu'.
|
|
2555 */ )
|
|
2556 (buffer, extent_obj, command, selection, no_confirm)
|
|
2557 Lisp_Object buffer, extent_obj, command, selection, no_confirm;
|
|
2558 {
|
|
2559 if (!energize_connection || !energize_connection->conn) return Qnil;
|
|
2560
|
|
2561 CHECK_BUFFER (buffer);
|
|
2562 CHECK_STRING (command);
|
|
2563
|
|
2564 execute_energize_menu (buffer, extent_to_data (extent_obj),
|
14
|
2565 (char*) XSTRING_DATA (command), 0, 0, selection,
|
0
|
2566 no_confirm);
|
|
2567
|
|
2568 return Qt;
|
|
2569 }
|
|
2570
|
|
2571 /********************************* kill buffer interface ****************/
|
|
2572
|
|
2573 DEFUN ("energize-buffer-type-internal",
|
|
2574 Fenergize_buffer_type, Senergize_buffer_type,
|
|
2575 1, 1, 0 /*
|
|
2576 Return a symbol denoting the buffer type if buffer is an Energize
|
|
2577 buffer, else it returns NIL.
|
|
2578 */ )
|
|
2579 (buffer)
|
|
2580 Lisp_Object buffer;
|
|
2581 {
|
|
2582 if (!energize_connection) return Qnil;
|
|
2583
|
|
2584 CHECK_BUFFER (buffer);
|
|
2585 return get_buffer_type_for_emacs_buffer (buffer, energize_connection);
|
|
2586 }
|
|
2587
|
|
2588 DEFUN ("set-energize-buffer-type-internal",
|
|
2589 Fset_energize_buffer_type_internal,
|
|
2590 Sset_energize_buffer_type_internal, 2, 2, 0 /*
|
|
2591 Return the type symbol which is the new buffer-type, if the buffer is
|
|
2592 an Energize buffer and the type is non-NIL symbol, else it returns NIL.
|
|
2593 */ )
|
|
2594 (buffer, type)
|
|
2595 Lisp_Object buffer, type;
|
|
2596 {
|
|
2597 BufferInfo *binfo;
|
|
2598
|
|
2599 if (!energize_connection || (NILP (type))) return Qnil;
|
|
2600
|
|
2601 CHECK_BUFFER (buffer);
|
|
2602 CHECK_SYMBOL (type);
|
|
2603
|
|
2604 if (!(binfo =
|
|
2605 get_buffer_info_for_emacs_buffer (buffer, energize_connection)))
|
|
2606 return Qnil;
|
|
2607 else
|
|
2608 return
|
|
2609 set_buffer_type_for_emacs_buffer (buffer, energize_connection, type);
|
|
2610 }
|
|
2611
|
|
2612 DEFUN ("energize-buffer-p", Fenergize_buffer_p, Senergize_buffer_p, 1, 1, 0 /*
|
|
2613 Whether buffer is an Energize buffer.
|
|
2614 */ )
|
|
2615 (buffer)
|
|
2616 Lisp_Object buffer;
|
|
2617 {
|
|
2618 BufferInfo *binfo;
|
|
2619
|
|
2620 if (!energize_connection) return Qnil;
|
|
2621
|
|
2622 CHECK_BUFFER (buffer);
|
|
2623 if (!(binfo =
|
|
2624 get_buffer_info_for_emacs_buffer (buffer, energize_connection)))
|
|
2625 return Qnil;
|
|
2626 else
|
|
2627 return Qt;
|
|
2628 }
|
|
2629
|
|
2630 DEFUN ("energize-buffer-id", Fenergize_buffer_id, Senergize_buffer_id, 1, 1, 0 /*
|
|
2631 Return (high . low) if buffer is an Energize buffer, otherwise nil.
|
|
2632 */ )
|
|
2633 (buffer)
|
|
2634 Lisp_Object buffer;
|
|
2635 {
|
|
2636 BufferInfo *binfo;
|
|
2637
|
|
2638 if (!energize_connection) return Qnil;
|
|
2639
|
|
2640 CHECK_BUFFER (buffer);
|
|
2641 if (!(binfo =
|
|
2642 get_buffer_info_for_emacs_buffer (buffer, energize_connection)))
|
|
2643 return Qnil;
|
|
2644 else
|
|
2645 return word_to_lisp (binfo->id);
|
|
2646 }
|
|
2647
|
|
2648 DEFUN ("energize-request-kill-buffer", Fenergize_request_kill_buffer,
|
|
2649 Senergize_request_kill_buffer, 1, 1, 0 /*
|
|
2650 Sends a request to energize for killing buffer.
|
|
2651 */ )
|
|
2652 (buffer)
|
|
2653 Lisp_Object buffer;
|
|
2654 {
|
|
2655 BufferInfo *binfo;
|
|
2656
|
|
2657 if (!energize_connection) return Qnil;
|
|
2658
|
|
2659 CHECK_BUFFER (buffer);
|
|
2660 if (!(binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection)))
|
|
2661 return Qnil;
|
|
2662
|
|
2663 /* Tell Energize about it if connected */
|
|
2664 if (energize_connection->conn)
|
|
2665 {
|
|
2666 CWriteKillBufferHeader (energize_connection->conn, binfo->id);
|
|
2667 CWriteRequestBuffer (energize_connection->conn);
|
|
2668 }
|
|
2669
|
|
2670 /* Clears the internal state */
|
|
2671 forget_buffer (binfo);
|
|
2672
|
|
2673 return Qnil;
|
|
2674 }
|
|
2675
|
|
2676 /******************** Handle requests from the kernel *********************/
|
|
2677
|
|
2678 #ifdef EMACS_BTL
|
|
2679 #include "cadillac-btl-extern.h"
|
|
2680 #endif
|
|
2681
|
|
2682 /* turn logging on or off, etc. */
|
|
2683 static void
|
|
2684 handle_logging_request (Editor *editor, CLoggingRequest *creq)
|
|
2685 /* I'm a lumberjack and I'm ok... */
|
|
2686 {
|
|
2687 ReqLen name_len;
|
|
2688 char* data_filename = CGetVstring (editor->conn, &name_len);
|
|
2689
|
|
2690 #ifdef EMACS_BTL
|
|
2691 {
|
|
2692 char *execname =
|
|
2693 (STRINGP (Vinvocation_directory))?
|
14
|
2694 ((char *) XSTRING_DATA (Vinvocation_directory)):0;
|
0
|
2695
|
|
2696 switch (creq->type)
|
|
2697 {
|
|
2698 case CLRInitBTL:
|
|
2699 cadillac_terminate_logging (); /* #### rename me */
|
|
2700 cadillac_initialize_backtrace_logging /* #### rename me */
|
|
2701 (data_filename, execname, (long) creq->limit, (long) creq->interval);
|
|
2702 break;
|
|
2703
|
|
2704 case CLRInitPCL:
|
|
2705 cadillac_terminate_logging (); /* #### rename me */
|
|
2706 cadillac_initialize_pc_logging /* #### rename me */
|
|
2707 (data_filename, execname, (long) creq->limit, (long) creq->interval);
|
|
2708 break;
|
|
2709
|
|
2710 case CLRStart:
|
|
2711 cadillac_start_logging (); /* #### rename me */
|
|
2712 break;
|
|
2713
|
|
2714 case CLRStop:
|
|
2715 cadillac_stop_logging (); /* #### rename me */
|
|
2716 break;
|
|
2717
|
|
2718 case CLRTerminate:
|
|
2719 cadillac_terminate_logging (); /* #### rename me */
|
|
2720 break;
|
|
2721
|
|
2722 case CLRSetLogSignal:
|
|
2723 cadillac_set_log_signal (creq->signal); /* #### rename me */
|
|
2724 break;
|
|
2725
|
|
2726 default:
|
|
2727 error ("Bad logging request type %d", creq->type);
|
|
2728 }
|
|
2729 }
|
|
2730 #else
|
|
2731 message ("Logging request, but no such code in image.");
|
|
2732 #endif
|
|
2733 }
|
|
2734
|
|
2735
|
|
2736
|
|
2737 /* creates a new buffer */
|
|
2738 static void
|
|
2739 handle_new_buffer_request (Editor *editor, CNewBufferRequest *creq)
|
|
2740 {
|
|
2741 read_energize_buffer_data (editor->conn, &creq->buffer, editor, 0, 0,
|
|
2742 creq->transientId, 0);
|
|
2743 if (!NILP (Venergize_create_buffer_hook))
|
|
2744 {
|
|
2745 CBuffer *cbu = &creq->buffer;
|
|
2746 BufferInfo *binfo = get_buffer_info_for_id (cbu->bufferId, editor);
|
|
2747 Lisp_Object buffer;
|
|
2748 if (binfo)
|
|
2749 {
|
|
2750 Lisp_Object prev_frame;
|
|
2751 buffer = binfo->emacs_buffer;
|
|
2752 if (!NILP (binfo->frame))
|
|
2753 {
|
|
2754 prev_frame = Fselected_frame (Qnil);
|
|
2755 Fselect_frame (binfo->frame);
|
|
2756 }
|
|
2757 va_run_hook_with_args (Qenergize_create_buffer_hook, 1, buffer);
|
|
2758 if (!NILP (binfo->frame))
|
|
2759 Fselect_frame (prev_frame);
|
|
2760 }
|
|
2761 }
|
|
2762 }
|
|
2763
|
|
2764 /* Modifies the contents of a buffer */
|
|
2765 static void
|
|
2766 handle_modify_buffer_request (Editor *editor, CModifyBufferRequest *creq)
|
|
2767 {
|
|
2768 read_energize_buffer_data (editor->conn, &creq->newData, editor,
|
|
2769 creq->startPosition, creq->endPosition,
|
|
2770 0, creq->head.data);
|
|
2771 }
|
|
2772
|
|
2773 static void
|
|
2774 make_buffer_and_extent_visible (Lisp_Object list, Lisp_Object go_there)
|
|
2775 {
|
|
2776 call2 (Qenergize_make_many_buffers_visible, list, go_there);
|
|
2777 }
|
|
2778
|
|
2779 /* pops a buffer and scroll to a extent: calls to lisp */
|
|
2780 static void
|
|
2781 handle_ensure_visible_request (Editor *editor, CEnsureVisibleRequest *creq)
|
|
2782 {
|
|
2783 BufferInfo *binfo;
|
|
2784 Energize_Extent_Data *ext;
|
|
2785 Lisp_Object buffer_extent_list;
|
|
2786 struct gcpro gcpro1;
|
|
2787
|
|
2788 buffer_extent_list = Qnil;
|
|
2789 GCPRO1 (buffer_extent_list);
|
|
2790
|
|
2791 binfo = get_buffer_info_for_id (creq->bufferId, editor);
|
|
2792 if (!binfo)
|
|
2793 {
|
|
2794 message ("EnsureVisibleRequest: unknown buffer");
|
|
2795 goto finished;
|
|
2796 }
|
|
2797
|
|
2798 if (!NILP (binfo->frame))
|
|
2799 {
|
|
2800 /* ignore ensure visible for postit note buffers */
|
|
2801 goto finished;
|
|
2802 }
|
|
2803
|
|
2804 if (creq->extentId)
|
|
2805 {
|
|
2806 ext = get_extent_data (creq->extentId, binfo);
|
|
2807 if (!ext)
|
|
2808 message ("EnsureVisibleRequest: ignoring unknown extent");
|
|
2809 }
|
|
2810 else
|
|
2811 ext = 0;
|
|
2812
|
|
2813 buffer_extent_list = Fcons (ext ? data_to_extent (ext) : Qnil, Qnil);
|
|
2814 buffer_extent_list = Fcons (binfo->emacs_buffer, buffer_extent_list);
|
|
2815
|
|
2816 make_buffer_and_extent_visible (buffer_extent_list, creq->head.data ? Qt : Qnil);
|
|
2817
|
|
2818 finished:
|
|
2819 CSkipRequest (editor->conn);
|
|
2820 UNGCPRO;
|
|
2821 }
|
|
2822
|
|
2823 static void
|
|
2824 handle_ensure_many_visible_request (Editor *editor,
|
|
2825 CEnsureManyVisibleRequest *creq)
|
|
2826 {
|
|
2827 BufferInfo *binfo;
|
|
2828 Energize_Extent_Data *ext;
|
|
2829 Lisp_Object buffer_extent_list;
|
|
2830 int n;
|
|
2831 EId buffer_id;
|
|
2832 EId extent_id;
|
|
2833 struct gcpro gcpro1;
|
|
2834
|
|
2835 buffer_extent_list = Qnil;
|
|
2836 GCPRO1 (buffer_extent_list);
|
|
2837
|
|
2838 for (n = creq->head.data,
|
|
2839 buffer_id = creq->bufferId,
|
|
2840 extent_id = creq->extentId;
|
|
2841 n;
|
|
2842 n--,
|
|
2843 buffer_id = n ? *(CGet (editor->conn, EId)) : 0,
|
|
2844 extent_id = n ? *(CGet (editor->conn, EId)) : 0)
|
|
2845 {
|
|
2846 binfo = get_buffer_info_for_id (buffer_id, editor);
|
|
2847 if (!binfo)
|
|
2848 {
|
|
2849 message ("EnsureManyVisibleRequest: ignoring unknown buffer");
|
|
2850 continue;
|
|
2851 }
|
|
2852
|
|
2853 if (!NILP (binfo->frame))
|
|
2854 {
|
|
2855 /* silently ignore ensure visible for postit note buffers */
|
|
2856 continue;
|
|
2857 }
|
|
2858
|
|
2859 if (extent_id)
|
|
2860 {
|
|
2861 ext = get_extent_data (extent_id, binfo);
|
|
2862 if (!ext)
|
|
2863 message ("EnsureManyVisibleRequest: ignoring unknown extent");
|
|
2864 }
|
|
2865 else
|
|
2866 ext = 0;
|
|
2867
|
|
2868 /* cons in reverse order and reverse the list before
|
|
2869 calling make_buffer_and_extent_visible */
|
|
2870 buffer_extent_list = Fcons (binfo->emacs_buffer, buffer_extent_list);
|
|
2871 buffer_extent_list = Fcons (ext ? data_to_extent (ext) : Qnil,
|
|
2872 buffer_extent_list);
|
|
2873 }
|
|
2874 buffer_extent_list = Fnreverse (buffer_extent_list);
|
|
2875 make_buffer_and_extent_visible (buffer_extent_list, Qt);
|
|
2876
|
|
2877 UNGCPRO;
|
|
2878 }
|
|
2879
|
|
2880 /* Update the cached menus, ie update the menubar for now. */
|
|
2881 static void
|
|
2882 handle_propose_choices_request (Editor *editor, CProposeChoicesRequest *req)
|
|
2883 {
|
|
2884 BufferInfo* binfo;
|
|
2885 Lisp_Object buffer = Qnil;
|
|
2886 Lisp_Object extent = Qnil;
|
|
2887 Lisp_Object choices = Qnil;
|
|
2888 struct gcpro gcpro1, gcpro2, gcpro3;
|
|
2889 struct reply_wait* rw;
|
|
2890
|
|
2891 GCPRO3 (buffer, extent, choices);
|
|
2892
|
|
2893 /* get the buffer */
|
|
2894 binfo = get_buffer_info_for_id (req->objectId, editor);
|
|
2895 if (binfo)
|
|
2896 buffer = binfo->emacs_buffer;
|
|
2897 else
|
|
2898 buffer = Qnil;
|
|
2899
|
|
2900 /* get the extent */
|
|
2901 if (binfo && req->genericId)
|
|
2902 {
|
|
2903 Energize_Extent_Data* ext = get_extent_data (req->genericId, binfo);
|
|
2904 if (ext)
|
|
2905 extent = data_to_extent (ext);
|
|
2906 else
|
|
2907 extent = Qnil;
|
|
2908 }
|
|
2909 else
|
|
2910 extent = Qnil;
|
|
2911
|
|
2912 /* find if we were waiting for a reply */
|
|
2913 rw = find_wait_reply (req->head.serial);
|
|
2914
|
|
2915 /* handle the request */
|
|
2916 if (rw && rw->objectId == req->objectId && rw->genericId == req->genericId)
|
|
2917 {
|
|
2918 /* It's a reply for a get_energize_menu call */
|
|
2919 rw->answered_p = True;
|
|
2920 rw->status = 1;
|
|
2921 rw->menu_result = list_choices (buffer, extent, rw->only_name, req);
|
|
2922 }
|
|
2923 else
|
|
2924 {
|
|
2925 /* It's a menu update, call the hook */
|
|
2926 choices = list_choices (buffer, extent, Qnil, req);
|
|
2927 va_run_hook_with_args (Qenergize_menu_update_hook, 1, choices);
|
|
2928 }
|
|
2929 UNGCPRO;
|
|
2930 }
|
|
2931
|
|
2932 /* Kills a buffer */
|
|
2933 static void
|
|
2934 unmodify_buffer_and_kill_it (Lisp_Object buffer)
|
|
2935 {
|
|
2936 int speccount = specpdl_depth ();
|
|
2937
|
|
2938 if (!BUFFER_LIVE_P (XBUFFER (buffer)))
|
|
2939 return;
|
|
2940
|
|
2941 Fset_buffer_modified_p (Qnil, buffer);
|
|
2942
|
|
2943 /* kill it. This will call the Energize hook to do the right thing */
|
|
2944 Fkill_buffer (buffer);
|
|
2945 }
|
|
2946
|
|
2947 static void
|
|
2948 handle_kill_buffer_request (Editor *editor, CKillBufferRequest *creq)
|
|
2949 {
|
|
2950 BufferInfo *binfo;
|
|
2951
|
|
2952 if (!(binfo = get_buffer_info_for_id (creq->bufferId, editor)))
|
|
2953 {
|
|
2954 message ("KillBufferVisibleRequest: unregistered buffer");
|
|
2955 return;
|
|
2956 }
|
|
2957
|
|
2958 unmodify_buffer_and_kill_it (binfo->emacs_buffer);
|
|
2959 }
|
|
2960
|
|
2961 static void
|
|
2962 handle_remove_extents_request (Editor *editor, CRemoveExtentsRequest *creq)
|
|
2963 {
|
|
2964 BufferInfo *binfo;
|
|
2965 int i;
|
|
2966 EId *ids;
|
|
2967 Lisp_Object restore_buffer_state_cons;
|
|
2968 int speccount = specpdl_depth ();
|
|
2969
|
|
2970 if (!(binfo = get_buffer_info_for_id (creq->bufferId, editor)))
|
|
2971 {
|
|
2972 message ("RemoveExtentsRequest: unregistered buffer");
|
|
2973 CSkipRequest (editor->conn);
|
|
2974 return;
|
|
2975 }
|
|
2976
|
|
2977 /* enable buffer edits */
|
|
2978 restore_buffer_state_cons =
|
|
2979 Fcons (make_opaque_ptr ((void *) creq->bufferId),
|
|
2980 Fcons (XBUFFER (binfo->emacs_buffer)->read_only, Qnil));
|
|
2981
|
|
2982 record_unwind_protect (restore_buffer_state, restore_buffer_state_cons);
|
|
2983
|
|
2984 XBUFFER (binfo->emacs_buffer)->read_only = Qnil;
|
|
2985
|
|
2986 /* save old hook values */
|
|
2987 specbind (Qenergize_buffer_modified_hook, Qnil);
|
|
2988
|
|
2989 ids = CGetN (editor->conn, EId, creq->nExtent);
|
|
2990 for (i = 0; i < creq->nExtent; i++)
|
|
2991 {
|
|
2992 Energize_Extent_Data *ext = get_extent_data (ids [i], binfo);
|
|
2993 if (ext)
|
|
2994 free_Energize_Extent_Data (ext, binfo, OFT_STANDALONE);
|
|
2995 }
|
|
2996
|
|
2997 /* restore modified hooks and globals */
|
|
2998 unbind_to (speccount, Qnil);
|
|
2999 }
|
|
3000
|
|
3001 #ifndef ENERGIZE_V2_HEADERS
|
|
3002 static Lisp_Object
|
|
3003 save_to_energize_unwind (Lisp_Object closure)
|
|
3004 {
|
|
3005 BITS32 buffer_id = (BITS32) cons_to_long (closure);
|
|
3006 /* If the buffer ID is not 0, then the call to save-buffer
|
|
3007 didn't complete normally - so tell Energize the save was aborted. */
|
|
3008 if (buffer_id)
|
|
3009 {
|
|
3010 Editor *editor = energize_connection;
|
|
3011 if (editor && editor->conn) /* Maybe the kernel has gone away. */
|
|
3012 {
|
|
3013 CWriteBufferSaveAbortedHeader (editor->conn, buffer_id);
|
|
3014 CWriteRequestBuffer (editor->conn);
|
|
3015 }
|
|
3016 }
|
|
3017 return Qnil;
|
|
3018 }
|
|
3019 #endif /* ENERGIZE_V2_HEADERS */
|
|
3020
|
|
3021
|
|
3022 /* handles a request to save a buffer from the kernel */
|
|
3023 static void
|
|
3024 handle_save_buffer_request (Editor *editor, CSaveBufferRequest *creq)
|
|
3025 {
|
|
3026 BufferInfo *binfo;
|
|
3027 int speccount = specpdl_depth ();
|
|
3028 struct gcpro gcpro1;
|
|
3029 Lisp_Object closure = Qnil;
|
|
3030
|
|
3031 if (!(binfo = get_buffer_info_for_id (creq->bufferId, editor)))
|
|
3032 {
|
|
3033 message ("Server attempt to save a non registered buffer");
|
|
3034 return;
|
|
3035 }
|
|
3036
|
|
3037 if (!EQ (binfo->emacs_buffer, Fcurrent_buffer ()))
|
|
3038 {
|
|
3039 record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
|
|
3040 Fset_buffer (binfo->emacs_buffer);
|
|
3041 }
|
|
3042
|
|
3043 GCPRO1 (closure);
|
|
3044 if (creq->head.data == CSExecuteSave)
|
|
3045 {
|
|
3046 #ifndef ENERGIZE_V2_HEADERS
|
|
3047 Lisp_Object closure = make_opaque_ptr ((void *) creq->bufferId);
|
|
3048 record_unwind_protect (save_to_energize_unwind, closure);
|
|
3049 #endif /* ENERGIZE_V2_HEADERS */
|
|
3050 call0 (intern ("save-buffer"));
|
|
3051 #ifndef ENERGIZE_V2_HEADERS
|
|
3052 /* clear out the id to tell the unwind-protect form that the save
|
|
3053 completed normally. */
|
|
3054 set_opaque_ptr (closure, 0);
|
|
3055 #endif /* ENERGIZE_V2_HEADERS */
|
|
3056 }
|
|
3057 else
|
|
3058 write_energize_buffer_data (binfo);
|
|
3059
|
|
3060 UNGCPRO;
|
|
3061 unbind_to (speccount, Qnil);
|
|
3062 }
|
|
3063
|
|
3064 static void
|
|
3065 handle_set_modified_flag_request (Editor* editor,
|
|
3066 CSetModifiedFlagRequest* creq)
|
|
3067 {
|
|
3068 BufferInfo *binfo;
|
|
3069 int speccount = specpdl_depth ();
|
|
3070
|
|
3071 if (!(binfo = get_buffer_info_for_id (creq->bufferId, editor)))
|
|
3072 {
|
|
3073 message ("Server attempt to set modified flag of a non registered buffer");
|
|
3074 return;
|
|
3075 }
|
|
3076
|
|
3077 record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
|
|
3078 specbind (Qenergize_buffer_modified_hook, Qnil);
|
|
3079
|
|
3080 /* Only set buffer modified time in older protocols
|
|
3081 as we handle the file timestamps ourselves now for
|
|
3082 CBFileYourself buffers. */
|
|
3083 #ifndef ENERGIZE_V2_HEADERS
|
|
3084 if ((energize_connection->minor < 10) && !(binfo->flags & CBFileYourself))
|
|
3085 #endif
|
|
3086 {
|
|
3087 Fset_buffer_modtime (binfo->emacs_buffer, Qnil);
|
|
3088 }
|
|
3089
|
|
3090 Fset_buffer_modified_p (creq->state ? Qt : Qnil, binfo->emacs_buffer);
|
|
3091 binfo->modified_state = creq->state;
|
|
3092 /* Mark the buffer so that we ask permission to Energize when the
|
|
3093 * user tries to modify it again */
|
|
3094 binfo->editable = 0;
|
|
3095 if (!creq->state)
|
|
3096 mark_all_extents_as_unmodified (binfo);
|
|
3097 unbind_to (speccount, Qnil);
|
|
3098 }
|
|
3099
|
|
3100
|
|
3101 /* handles requests regarding p_sheet associated to buffers */
|
|
3102 static void
|
|
3103 add_in_list_of_ids (int** ids, int* n_ids, int id)
|
|
3104 {
|
|
3105 if (*n_ids == 0)
|
|
3106 {
|
|
3107 *n_ids = 1;
|
|
3108 *ids = (int*)xmalloc (sizeof (int));
|
|
3109 }
|
|
3110 else
|
|
3111 {
|
|
3112 *n_ids += 1;
|
|
3113 *ids = (int*)xrealloc (*ids, sizeof (int) * (*n_ids));
|
|
3114 }
|
|
3115 (*ids) [(*n_ids) - 1] = id;
|
|
3116 }
|
|
3117
|
|
3118 static void
|
|
3119 remove_from_list_of_ids (int** ids, int* n_ids, int id)
|
|
3120 {
|
|
3121 int i;
|
|
3122 if (*n_ids)
|
|
3123 {
|
|
3124 /* look for id in *ids */
|
|
3125 for (i = 0; i < (*n_ids) && (*ids) [i] != id; i++);
|
|
3126 /* shift the remaining ones */
|
|
3127 for (; i < (*n_ids) - 1; i++)
|
|
3128 (*ids) [i] = (*ids) [i + 1];
|
|
3129 /* decrease the count */
|
|
3130 *n_ids -= 1;
|
|
3131 /* free array if empty */
|
|
3132 if (!*n_ids)
|
|
3133 {
|
|
3134 xfree (*ids);
|
|
3135 *ids = 0;
|
|
3136 }
|
|
3137 }
|
|
3138 }
|
|
3139
|
|
3140 extern void make_psheets_desired (struct frame *, Lisp_Object);
|
|
3141
|
|
3142 static void
|
|
3143 handle_buffer_sheet_request (Editor *editor, CSheetRequest *sreq,
|
|
3144 EId buffer_id)
|
|
3145 {
|
|
3146 BufferInfo *binfo;
|
|
3147 char *name;
|
|
3148 Connection *conn = editor->conn;
|
|
3149
|
|
3150 if (!(binfo = get_buffer_info_for_id (buffer_id, editor)))
|
|
3151 {
|
|
3152 message ("Server attempt to use p_sheet in a non registered buffer");
|
|
3153 CSkipRequest (conn);
|
|
3154 return;
|
|
3155 }
|
|
3156
|
|
3157 name = CGetVstring (conn, (ReqLen *) 0);
|
|
3158 switch ((CSheetRSubtype) sreq->head.data)
|
|
3159 {
|
|
3160 case CSCreate:
|
|
3161 lw_register_widget (name, name, sreq->sheetId, NULL, NULL,
|
|
3162 handle_sheet_control_change, NULL);
|
|
3163 add_in_list_of_ids (&binfo->p_sheet_ids, &binfo->n_p_sheets,
|
|
3164 sreq->sheetId);
|
|
3165 if (!strcmp (name, DEBUGGER_PSHEET_NAME))
|
|
3166 debuggerpanel_sheet = sreq->sheetId;
|
|
3167 break;
|
|
3168
|
|
3169 case CSDelete:
|
|
3170 remove_from_list_of_ids (&binfo->p_sheet_ids, &binfo->n_p_sheets,
|
|
3171 sreq->sheetId);
|
|
3172 cleanly_destroy_all_widgets (1, &sreq->sheetId);
|
|
3173 if (sreq->sheetId == debuggerpanel_sheet)
|
|
3174 {
|
|
3175 desired_debuggerpanel_exposed_p = 0;
|
|
3176 debuggerpanel_sheet = 0;
|
|
3177 }
|
|
3178 break;
|
|
3179
|
|
3180 case CSHide:
|
|
3181 {
|
|
3182 Lisp_Object frmcons, devcons, concons;
|
|
3183
|
|
3184 if (sreq->sheetId == debuggerpanel_sheet)
|
|
3185 desired_debuggerpanel_exposed_p = 0;
|
|
3186 else
|
|
3187 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
|
|
3188 {
|
|
3189 struct frame *frame = XFRAME (Fcar (frmcons));
|
|
3190 if (FRAME_X_P (frame))
|
|
3191 make_psheets_desired (frame, Qnil);
|
|
3192 }
|
|
3193 }
|
|
3194 break;
|
|
3195
|
|
3196 case CSShow:
|
|
3197 if (sreq->sheetId == debuggerpanel_sheet)
|
|
3198 desired_debuggerpanel_exposed_p = 1;
|
|
3199 else
|
|
3200 {
|
|
3201 Lisp_Object frmcons, devcons, concons;
|
|
3202
|
|
3203 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
|
|
3204 {
|
|
3205 struct frame *frame = XFRAME (Fcar (frmcons));
|
|
3206 if (FRAME_X_P (frame))
|
|
3207 {
|
|
3208 struct window *window =
|
|
3209 XWINDOW (FRAME_SELECTED_WINDOW (frame));
|
|
3210 if (EQ (window->buffer, binfo->emacs_buffer))
|
|
3211 make_psheets_desired (frame, binfo->emacs_buffer);
|
|
3212 }
|
|
3213 }
|
|
3214 }
|
|
3215 break;
|
|
3216 }
|
|
3217 }
|
|
3218
|
|
3219
|
|
3220
|
|
3221 /* show busy */
|
|
3222
|
|
3223 static void
|
|
3224 show_all_menubars_busy (int busy)
|
|
3225 {
|
|
3226 Lisp_Object frmcons, devcons, concons;
|
|
3227
|
|
3228 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
|
|
3229 {
|
|
3230 struct frame *f = XFRAME (XCAR (frmcons));
|
|
3231 if (FRAME_X_P (f))
|
|
3232 {
|
|
3233 if (FRAME_X_MENUBAR_WIDGET (f))
|
|
3234 lw_show_busy (FRAME_X_MENUBAR_WIDGET (f), busy);
|
|
3235 }
|
|
3236 }
|
|
3237 }
|
|
3238
|
|
3239 static void
|
|
3240 handle_show_busy_request (Editor *editor, CGenericRequest *preq)
|
|
3241 {
|
|
3242 /* call the show busy routine of the library for the menubar of
|
|
3243 * all frames */
|
|
3244 ReqLen len;
|
|
3245
|
|
3246 char* why = CGetVstring (editor->conn, &len);
|
|
3247
|
|
3248 show_all_menubars_busy (preq->head.data);
|
|
3249 Venergize_kernel_busy = preq->head.data ? Qt : Qnil;
|
|
3250 va_run_hook_with_args (Qenergize_kernel_busy_hook, 1, build_string (why));
|
|
3251 }
|
|
3252
|
|
3253 /* This request creates, destroys, raises, or lowers a psheet or dialog box.
|
|
3254 */
|
|
3255 static void
|
|
3256 handle_sheet_request (Connection* conn, CSheetRequest* sreq, Widget parent)
|
|
3257 {
|
|
3258 char* name = CGetVstring (conn, NULL);
|
|
3259
|
|
3260 switch ((CSheetRSubtype)sreq->head.data)
|
|
3261 {
|
|
3262 case CSCreate:
|
|
3263 lw_create_widget (name, name, sreq->sheetId, 0, parent,
|
|
3264 !sreq->bufferId, 0, handle_sheet_control_change, 0);
|
|
3265 break;
|
|
3266 case CSDelete:
|
|
3267 cleanly_destroy_all_widgets (1, &sreq->sheetId);
|
|
3268 break;
|
|
3269
|
|
3270 case CSShow:
|
|
3271 lw_pop_up_all_widgets (sreq->sheetId);
|
|
3272 break;
|
|
3273
|
|
3274 case CSHide:
|
|
3275 lw_pop_down_all_widgets (sreq->sheetId);
|
|
3276 break;
|
|
3277 }
|
|
3278 }
|
|
3279
|
|
3280 /* This request changes slot values in the psheets/dialog boxes. */
|
|
3281 static void
|
|
3282 handle_set_control_request (Connection* conn, CGenericRequest* creq)
|
|
3283 {
|
|
3284 CSetControlRequest* sreq = &creq->setcontrol;
|
|
3285 widget_value val;
|
|
3286 widget_value* contents;
|
|
3287
|
|
3288 unsigned long i;
|
|
3289 unsigned long n = sreq->nChoices;
|
|
3290
|
|
3291 if (n > 0)
|
|
3292 {
|
|
3293 contents = (widget_value *) xmalloc (n * sizeof (widget_value));
|
|
3294 memset (contents, 0, (n * sizeof (widget_value)));
|
|
3295 }
|
|
3296 else
|
|
3297 contents = NULL;
|
|
3298 memset (&val, 0, sizeof (val));
|
|
3299 val.name = CGetVstring (conn, NULL);
|
|
3300 val.enabled = !(sreq->flags & CKInactive);
|
|
3301 val.selected = !!(sreq->flags & CKSelected);
|
|
3302 val.change = VISIBLE_CHANGE;
|
|
3303 val.contents = contents;
|
|
3304
|
|
3305 for (i = 0; i < n; i++)
|
|
3306 {
|
|
3307 widget_value* cur = &contents [i];
|
|
3308 CChoice* choice = CGet (conn, CChoice);
|
|
3309 cur->name = CGetVstring (conn, NULL);
|
|
3310 cur->value = cur->name;
|
|
3311 cur->key = NULL;
|
|
3312 cur->enabled = !(choice->flags & CKInactive);
|
|
3313 cur->selected = !!(choice->flags & CKSelected);
|
|
3314 cur->change = VISIBLE_CHANGE;
|
|
3315 cur->contents = NULL;
|
|
3316 cur->call_data = NULL;
|
|
3317 cur->next = i == n - 1 ? NULL : &contents [i + 1];
|
|
3318 cur->toolkit_data = NULL;
|
|
3319 if ((i == 0 && n == 1) || cur->selected)
|
|
3320 {
|
|
3321 val.value = cur->name;
|
|
3322 if (!*val.value)
|
|
3323 val.value = NULL;
|
|
3324 }
|
|
3325 }
|
|
3326 lw_modify_all_widgets (sreq->sheetId, &val, True);
|
|
3327
|
|
3328 if (contents)
|
|
3329 xfree (contents);
|
|
3330 }
|
|
3331
|
|
3332 static void
|
|
3333 handle_sheet_control_change (Widget widget, EId sheet_id, void* arg)
|
|
3334 {
|
|
3335 Connection* conn;
|
|
3336 widget_value* val;
|
|
3337 widget_value* cur;
|
|
3338 widget_value* this_val = NULL;
|
|
3339 widget_value* cancel = NULL;
|
|
3340 char* this_name;
|
|
3341 int delete_window_p = (((int) arg) == -1);
|
|
3342
|
|
3343
|
|
3344 if (!energize_connection)
|
|
3345 return;
|
|
3346
|
|
3347 conn = energize_connection->conn;
|
|
3348 if (!conn)
|
|
3349 return;
|
|
3350
|
|
3351 this_name = XtName (widget);
|
|
3352 val = lw_get_all_values (sheet_id);
|
|
3353
|
|
3354 if (delete_window_p)
|
|
3355 /* Complete and utter kludge. If this dbox was dismissed with the
|
|
3356 WM close box (WM_DELETE_WINDOW, meaning the widget was destroyed)
|
|
3357 then we look for a likely "cancel" button and pretend the user
|
|
3358 clicked on that. Really the protocol should be extended for this.
|
|
3359 */
|
|
3360 for (cur = val; cur; cur = cur->next)
|
|
3361 {
|
|
3362 char *v = cur->value;
|
|
3363 if (v &&
|
|
3364 ((strlen (v) >= 6 && !strncmp (v, "cancel", 6)) ||
|
|
3365 (strlen (v) >= 5 && !strncmp (v, "abort", 5))))
|
|
3366 cancel = cur;
|
|
3367 }
|
|
3368
|
|
3369 /* first send all the edited widgets */
|
|
3370 for (cur = val; cur; cur = cur->next)
|
|
3371 {
|
|
3372 /* do not send the widget that ran the callback */
|
|
3373 if (!strcmp (cur->name, this_name))
|
|
3374 this_val = cur;
|
|
3375 else if (cur == cancel)
|
|
3376 ;
|
|
3377 /* send the edited widgets */
|
|
3378 else if (cur->edited)
|
|
3379 {
|
|
3380 char* value = cur->value;
|
|
3381 unsigned int flags = 0;
|
|
3382
|
|
3383 if (!cur->enabled)
|
|
3384 flags |= CKInactive;
|
|
3385 if (cur->selected)
|
|
3386 flags |= CKSelected;
|
|
3387
|
|
3388 /* the kernel is brain dead and expect "1" and "0" as values
|
|
3389 for the checkbox objects. So if value is NULL, make it be "0"
|
|
3390 or "1" depending on the selected state. This is until we fix
|
|
3391 the kernel. */
|
|
3392 if (!value)
|
|
3393 value = cur->selected ? "1" : "0";
|
|
3394
|
|
3395 CWriteSetControlRequest (conn, sheet_id, 0, cur->name, 1);
|
|
3396 CWriteChoice (conn, 0, flags, value, 0);
|
|
3397 CWriteLength (conn);
|
|
3398 }
|
|
3399 }
|
|
3400
|
|
3401 if (delete_window_p && !this_val)
|
|
3402 {
|
|
3403 this_val = cancel;
|
|
3404 /* if (! this_val) abort (); */
|
|
3405 }
|
|
3406
|
|
3407 /* Then send the widget that ran the callback */
|
|
3408 if (this_val)
|
|
3409 {
|
|
3410 CWriteSetControlRequest (conn, sheet_id, 0, this_val->name, 1);
|
|
3411 CWriteChoice (conn, 0, 0, this_val->value, 0);
|
|
3412 CWriteLength (conn);
|
|
3413 CWriteRequestBuffer (conn);
|
|
3414 }
|
|
3415 }
|
|
3416
|
|
3417 /******************** Low level connection stuff ************************/
|
|
3418 static void
|
|
3419 add_in_connection_input_buffer (Connection *conn, char *s, int l)
|
|
3420 {
|
|
3421 /* Should be in connection.c */
|
|
3422 if (conn->inread >= conn->infill)
|
|
3423 conn->inread = conn->infill = conn->inbuffer;
|
|
3424
|
|
3425 CNeedInputSize (conn, l);
|
|
3426 memcpy (conn->infill, s, l);
|
|
3427 conn->infill += l;
|
|
3428 }
|
|
3429
|
|
3430 static Lisp_Object
|
|
3431 process_one_energize_request (void)
|
|
3432 {
|
|
3433 Editor *editor = energize_connection;
|
|
3434 CEditorRequest *req;
|
|
3435 int res = 0;
|
|
3436
|
|
3437 if (!editor) return make_int (res);
|
|
3438
|
|
3439 if (!editor->conn)
|
|
3440 {
|
|
3441 close_energize_connection ();
|
|
3442 return make_int (res);
|
|
3443 }
|
|
3444
|
|
3445 req = CReadEditorRequest (editor->conn);
|
|
3446 if (!req)
|
|
3447 {
|
|
3448 switch (errno)
|
|
3449 {
|
|
3450 case EWOULDBLOCK:
|
|
3451 /* message ("ProcessEnergizeRequest: internal error EWOULDBLOCK"); */
|
|
3452 res = -1;
|
|
3453 break;
|
|
3454
|
|
3455 case 0:
|
|
3456 case ECONNRESET:
|
|
3457 message ("Connection to " IDENTITY_CRISIS " was closed.");
|
|
3458 close_energize_connection ();
|
|
3459 break;
|
|
3460
|
|
3461 default:
|
|
3462 message
|
|
3463 ("System error on connection to " IDENTITY_CRISIS ", closing.");
|
|
3464 close_energize_connection ();
|
|
3465 break;
|
|
3466 }
|
|
3467 }
|
|
3468 else
|
|
3469 {
|
|
3470 res = 1;
|
|
3471 switch (req->head.reqType)
|
|
3472 {
|
|
3473 case RefuseConnectionRType:
|
|
3474 message (IDENTITY_CRISIS " connection refused");
|
|
3475 close_energize_connection ();
|
|
3476 break;
|
|
3477
|
|
3478 case AcceptConnectionRType:
|
|
3479 {
|
|
3480 CProtocol* proto = CGet (editor->conn, CProtocol);
|
|
3481 editor->major = proto->major;
|
|
3482 editor->minor = proto->minor;
|
|
3483 message (IDENTITY_CRISIS " connection accepted");
|
|
3484 CSkipRequest (editor->conn);
|
|
3485 }
|
|
3486 break;
|
|
3487
|
|
3488 case NewBufferRType:
|
|
3489 handle_new_buffer_request (editor, &req->newbuffer);
|
|
3490 break;
|
|
3491
|
|
3492 case QueryBufferRType:
|
|
3493 {
|
|
3494 EId buffer_id;
|
|
3495 struct reply_wait* rw = find_wait_reply (req->head.serial);
|
|
3496 CGetVstring (editor->conn, 0); /* skip directory */
|
|
3497 CGetVstring (editor->conn, 0); /* skip file */
|
|
3498 buffer_id = *CGet (editor->conn, EId);
|
|
3499 if (rw)
|
|
3500 {
|
|
3501 rw->answered_p = 1;
|
|
3502 rw->status = req->head.data;
|
|
3503 rw->objectId = buffer_id;
|
|
3504 }
|
|
3505 }
|
|
3506 break;
|
|
3507
|
|
3508 case EnsureVisibleRType:
|
|
3509 handle_ensure_visible_request (editor, &req->ensurevisible);
|
|
3510 break;
|
|
3511
|
|
3512 case EnsureManyVisibleRType:
|
|
3513 handle_ensure_many_visible_request (editor, &req->ensuremanyvisible);
|
|
3514 break;
|
|
3515
|
|
3516 case ModifyBufferRType:
|
|
3517 handle_modify_buffer_request (editor, &req->modifybuffer);
|
|
3518 break;
|
|
3519
|
|
3520 case ProposeChoicesRType:
|
|
3521 handle_propose_choices_request (editor,
|
|
3522 &req->generic.proposechoices);
|
|
3523 break;
|
|
3524
|
|
3525 case ChoiceExecutedRType:
|
|
3526 {
|
|
3527 struct reply_wait* rw = find_wait_reply (req->head.serial);
|
|
3528 CChoiceExecutedRequest* ce = &req->generic.choiceexecuted;
|
|
3529 if (rw)
|
|
3530 {
|
|
3531 rw->answered_p = 1;
|
|
3532 rw->status = ce->head.data;
|
|
3533 rw->message = CMakeVstring (editor->conn, 0);
|
|
3534 }
|
|
3535 }
|
|
3536 break;
|
|
3537
|
|
3538 case KillBufferRType:
|
|
3539 handle_kill_buffer_request (editor, &req->killbuffer);
|
|
3540 break;
|
|
3541
|
|
3542 case ModifiedBufferRType:
|
|
3543 {
|
|
3544 struct reply_wait* rw = find_wait_reply (req->head.serial);
|
|
3545 if (rw)
|
|
3546 {
|
|
3547 rw->answered_p = 1;
|
|
3548 if (rw->objectId == req->modifiedbuffer.bufferId)
|
|
3549 rw->status = req->modifiedbuffer.state;
|
|
3550 else
|
|
3551 rw->status = CMBufferLocked;
|
|
3552 }
|
|
3553 }
|
|
3554 break;
|
|
3555
|
|
3556 case SetModifiedFlagRType:
|
|
3557 handle_set_modified_flag_request (editor, &req->setmodifiedflag);
|
|
3558 break;
|
|
3559
|
|
3560 case RemoveExtentsRType:
|
|
3561 handle_remove_extents_request (editor, &req->removeextents);
|
|
3562 break;
|
|
3563
|
|
3564 case RenumberExtentsRType:
|
|
3565 /* HandleDuplicateExtentRequest (editor, req); */
|
|
3566 break;
|
|
3567
|
|
3568 #if 0
|
|
3569 case DialogRType:
|
|
3570 /* HandleDialogRequest (editor, req, CurrentBuffer (editor)); */
|
|
3571 break;
|
|
3572 #endif
|
|
3573
|
|
3574 case SaveBufferRType:
|
|
3575 handle_save_buffer_request (editor, &req->savebuffer);
|
|
3576 break;
|
|
3577
|
|
3578 case SheetRType:{
|
|
3579 EId buffer_id = req->generic.sheet.bufferId;
|
|
3580 if (!buffer_id)
|
|
3581 buffer_id = buffer_id_of_sheet (req->generic.sheet.sheetId);
|
|
3582 if (buffer_id)
|
|
3583 handle_buffer_sheet_request (editor, &req->generic.sheet,
|
|
3584 buffer_id);
|
|
3585 else
|
|
3586 {
|
|
3587 CSheetRSubtype type = (CSheetRSubtype)req->head.data;
|
|
3588 if (type == CSDelete || type ==CSHide)
|
|
3589 /* #### ??? this does nothing. */
|
|
3590 Fselect_frame (Fselected_frame (Qnil));
|
|
3591 handle_sheet_request (editor->conn, &req->generic.sheet,
|
|
3592 FRAME_X_SHELL_WIDGET
|
|
3593 (XFRAME (Fselected_frame (Qnil))));
|
|
3594 }
|
|
3595 }
|
|
3596 break;
|
|
3597
|
|
3598 case SetControlRType:
|
|
3599 handle_set_control_request (editor->conn, (CGenericRequest*) req);
|
|
3600 break;
|
|
3601
|
|
3602 case OpenPostitRType:
|
|
3603 case KillPostitRType:
|
|
3604 message ("Don't know what to do with postit requests.");
|
|
3605 break;
|
|
3606
|
|
3607 case ShowBusyRType:
|
|
3608 handle_show_busy_request (editor, (CGenericRequest*)req);
|
|
3609 break;
|
|
3610
|
|
3611 case LoggingRType:
|
|
3612 handle_logging_request (editor, (CLoggingRequest*)req);
|
|
3613 break;
|
|
3614
|
|
3615 #ifndef ENERGIZE_V2_HEADERS
|
|
3616 case KernelEventRType:
|
|
3617 CSkipRequest (editor->conn);
|
|
3618 break;
|
|
3619 #endif
|
|
3620
|
|
3621 default:
|
|
3622 message("ProcessEnergizeRequest: can't handle request of type %d",
|
|
3623 req->head.reqType);
|
|
3624 }
|
|
3625
|
|
3626 }
|
|
3627
|
|
3628 return make_int (res);
|
|
3629 }
|
|
3630
|
|
3631 static int inside_process_energize_request_1;
|
|
3632
|
|
3633 /* this must be called ONLY by unwind_protect in process_energize_request_1 */
|
|
3634 static Lisp_Object
|
|
3635 post_handle_request (Lisp_Object ignored)
|
|
3636 {
|
|
3637 if (inside_process_energize_request_1 <= 0)
|
|
3638 abort ();
|
|
3639 inside_process_energize_request_1--;
|
|
3640 if (energize_connection && energize_connection->conn)
|
|
3641 CSkipRequest (energize_connection->conn);
|
|
3642 return Qnil;
|
|
3643 }
|
|
3644
|
|
3645 static Lisp_Object
|
|
3646 pop_conn (Lisp_Object arg)
|
|
3647 {
|
|
3648 Connection *old_conn = (Connection *) get_opaque_ptr (arg);
|
|
3649 if (! old_conn)
|
|
3650 abort ();
|
|
3651 if (! energize_connection)
|
|
3652 return Qnil;
|
|
3653 if (energize_connection->conn == old_conn)
|
|
3654 abort ();
|
|
3655
|
|
3656 if (CRequestDelayedP (energize_connection->conn))
|
|
3657 /* We don't call the CWait* functions any more so this shouldn't happen.
|
|
3658 But if it does someday, then we need to either copy the remaining
|
|
3659 bits from new_conn to old_conn, or loop processing requests until
|
|
3660 new_conn is drained.
|
|
3661 */
|
|
3662 abort ();
|
|
3663
|
|
3664 DeleteConnection (energize_connection->conn);
|
|
3665 energize_connection->conn = old_conn;
|
|
3666
|
|
3667 return Qnil;
|
|
3668 }
|
|
3669
|
|
3670 static Lisp_Object
|
|
3671 process_energize_request_1 ()
|
|
3672 {
|
|
3673 Lisp_Object result;
|
|
3674 int speccount = specpdl_depth ();
|
|
3675
|
|
3676 if (inside_process_energize_request_1)
|
|
3677 {
|
|
3678 /* When the energize process filter is called recursively, push a new
|
|
3679 connection object. The read-pointer of the connection buffer could
|
|
3680 be in the middle of a request. However, we know that the fd itself
|
|
3681 is always pointing between requests. So making a new connection is
|
|
3682 a way of skipping past the one request we were in the process of
|
|
3683 reading when we allowed process output to be handled recursively.
|
|
3684 */
|
|
3685 Connection *old_conn = energize_connection->conn;
|
|
3686 Connection *new_conn =
|
|
3687 make_energize_connection ((void *) energize_connection,
|
|
3688 old_conn->fdin, old_conn->fdout);
|
|
3689 energize_connection->conn = new_conn;
|
|
3690 record_unwind_protect (pop_conn, make_opaque_ptr (old_conn));
|
|
3691 }
|
|
3692
|
|
3693 /* this must come after pop_conn() to get the right connection object */
|
|
3694 record_unwind_protect (post_handle_request, Qnil);
|
|
3695
|
|
3696 inside_process_energize_request_1++;
|
|
3697
|
|
3698 result = process_one_energize_request ();
|
|
3699 notify_delayed_requests ();
|
|
3700
|
|
3701 /* decrements inside_process_energize_request_1 and possibly replaces
|
|
3702 energize_connection->conn with old_conn.
|
|
3703 */
|
|
3704 unbind_to (speccount, Qnil);
|
|
3705
|
|
3706 return result;
|
|
3707 }
|
|
3708
|
|
3709
|
|
3710 /******** Initialize Energize-related state and set up connection ********/
|
|
3711
|
|
3712 static void
|
|
3713 setup_connection (Editor *ed, unsigned int id1, unsigned int id2)
|
|
3714 {
|
|
3715 CEditorRequest *req = CWriteEditorRequest (ed->conn, QueryConnectionRType);
|
|
3716
|
|
3717 /* these 2 slots are ignored */
|
|
3718 req->generic.queryconnection.major = 0;
|
|
3719 req->generic.queryconnection.minor = 0;
|
|
3720
|
|
3721 req->generic.queryconnection.cadillacId1 = id1;
|
|
3722 req->generic.queryconnection.cadillacId2 = id2;
|
|
3723 req->generic.queryconnection.nProtocols = 1;
|
|
3724 /* first numerical arg is major protocol number, second is minor */
|
|
3725 CWriteProtocol (ed->conn, 0, 10, "editor");
|
|
3726 CWriteLength (ed->conn);
|
|
3727 CWriteRequestBuffer (ed->conn);
|
|
3728 }
|
|
3729
|
|
3730 /* this is used as the readMethod of the energize connection, so that
|
|
3731 the connection library won't do some buffering that messes us up.
|
|
3732 It does this buffering only if conn->readMethod == read, so using
|
|
3733 another function turns it off.
|
|
3734 */
|
|
3735 static int
|
|
3736 my_read (int fd, char *buf, int nb)
|
|
3737 {
|
|
3738 return read (fd, buf, nb);
|
|
3739 }
|
|
3740
|
|
3741 static Connection *
|
|
3742 make_energize_connection (Editor *editor, int fdin, int fdout)
|
|
3743 {
|
|
3744 Connection *conn = NewConnection ((void *)editor, fdin, fdout);
|
|
3745 if (conn)
|
|
3746 conn->readMethod = my_read;
|
|
3747 return conn;
|
|
3748 }
|
|
3749
|
|
3750 DEFUN ("handle-energize-request", Fhandle_energize_request,
|
|
3751 Shandle_energize_request,
|
|
3752 2, 2, 0 /*
|
|
3753 Filter called when a request is available from Energize.
|
|
3754 */ )
|
|
3755 (proc, string)
|
|
3756 Lisp_Object proc, string;
|
|
3757 {
|
|
3758 if (!NILP (string))
|
|
3759 CHECK_STRING (string);
|
|
3760
|
|
3761 if (!energize_connection || !energize_connection->conn)
|
|
3762 {
|
|
3763 /* no need for a message here, Energize is dead */
|
|
3764 return make_int (0);
|
|
3765 }
|
|
3766 if (!energize_connection || (!EQ (energize_connection->proc, proc)))
|
|
3767 {
|
|
3768 message ("Got " IDENTITY_CRISIS " request but not from current connection ");
|
|
3769 return make_int (0);
|
|
3770 }
|
|
3771
|
|
3772 if (!NILP (string))
|
|
3773 add_in_connection_input_buffer (energize_connection->conn,
|
14
|
3774 (char *) XSTRING_DATA (string),
|
|
3775 XSTRING_LENGTH (string));
|
0
|
3776
|
|
3777 return process_energize_request_1 ();
|
|
3778 }
|
|
3779
|
|
3780
|
|
3781 Lisp_Object Venergize_process;
|
|
3782
|
|
3783 /* Opens a network connection to Energize.
|
|
3784 * server is a string. It can end up with :<uid> or :<username>
|
|
3785 * in which case the uid is added to the TCP port to get the connection */
|
|
3786 static void
|
|
3787 connect_to_energize (char *server_str, char *arg)
|
|
3788 {
|
|
3789 struct Lisp_Process *proc;
|
|
3790 Lisp_Object lp;
|
|
3791 Lisp_Object fil;
|
|
3792 char *host;
|
|
3793 unsigned int port;
|
|
3794 long flags;
|
|
3795 int id1;
|
|
3796 int id2;
|
|
3797
|
|
3798 if (CGetPortNumber (server_str, &host, &port))
|
|
3799 {
|
|
3800
|
|
3801 lp = Fopen_network_stream_internal (build_string ("energize"),
|
|
3802 Qnil,
|
|
3803 build_string (host),
|
|
3804 make_int (port));
|
|
3805 if (!NILP (lp))
|
|
3806 {
|
|
3807 int infd, outfd;
|
|
3808 /* Don't ask the user for confirmation when exiting Emacs */
|
|
3809 Fprocess_kill_without_query (lp, Qnil);
|
|
3810 proc = XPROCESS (lp);
|
|
3811 energize_connection = xnew (Editor);
|
|
3812 get_process_file_descriptors (proc, &infd, &outfd);
|
|
3813 energize_connection->conn =
|
|
3814 make_energize_connection (energize_connection, infd, outfd);
|
|
3815 energize_connection->proc = lp;
|
|
3816 energize_connection->binfo_hash = make_hashtable (10);
|
|
3817 energize_connection->image_table = 0;
|
|
3818 energize_connection->gc_save = Qnil;
|
|
3819 energize_connection->major = 0;
|
|
3820 energize_connection->minor = 0;
|
|
3821 peo = allocate_edit_options (10);
|
|
3822 request_serial_number = 0;
|
|
3823 global_reply_wait = 0;
|
|
3824
|
|
3825 if ((flags = fcntl (energize_connection->conn->fdin, F_GETFL, 0))
|
|
3826 == -1)
|
|
3827 abort ();
|
|
3828
|
|
3829 #ifdef O_NONBLOCK
|
|
3830 if (fcntl (energize_connection->conn->fdin, F_SETFL,
|
|
3831 flags & ~O_NONBLOCK)
|
|
3832 == -1)
|
|
3833 #else
|
|
3834 if (fcntl (energize_connection->conn->fdin, F_SETFL,
|
|
3835 flags & ~O_NDELAY)
|
|
3836 == -1)
|
|
3837 #endif
|
|
3838 abort ();
|
|
3839
|
|
3840 XSETSUBR (fil, &Shandle_energize_request);
|
|
3841 set_process_filter (lp, fil, 1);
|
|
3842
|
|
3843 Venergize_kernel_busy = Qnil;
|
|
3844
|
|
3845 id1 = 0;
|
|
3846 id2 = 0;
|
|
3847 if (arg)
|
|
3848 sscanf (arg, "%x,%x", &id1, &id2);
|
|
3849
|
|
3850 Venergize_buffers_list = Qnil;
|
|
3851
|
|
3852 setup_connection (energize_connection, id1, id2);
|
|
3853
|
|
3854 Venergize_process = lp;
|
|
3855 }
|
|
3856 else
|
|
3857 error ("couldn't connect to " IDENTITY_CRISIS " server");
|
|
3858 }
|
|
3859 else
|
|
3860 error ("couldn't determine " IDENTITY_CRISIS " server port number");
|
|
3861
|
|
3862
|
|
3863 #ifdef ENERGIZE_V2_HEADERS
|
|
3864 if (energize_connection->minor > 9)
|
|
3865 {
|
|
3866 close_energize_connection ();
|
|
3867 error ("This Emacs doesn't understand " IDENTITY_CRISIS " version 3.");
|
|
3868 }
|
|
3869
|
|
3870 #endif /* ENERGIZE_V2_HEADERS */
|
|
3871
|
|
3872 }
|
|
3873
|
|
3874
|
|
3875 /* Close the connection to energize.
|
|
3876 * Kills all the energize related buffer */
|
|
3877 static void
|
|
3878 close_energize_connection ()
|
|
3879 {
|
|
3880 Editor *ed = energize_connection;
|
|
3881
|
|
3882 if (ed)
|
|
3883 /* make this function as paranoid as we can */
|
|
3884 {
|
|
3885 /* cleanup the busy state */
|
|
3886 show_all_menubars_busy (False);
|
|
3887 Venergize_kernel_busy = Qnil;
|
|
3888 /* destroy all pop_up boxes */
|
|
3889 lw_destroy_all_pop_ups ();
|
|
3890
|
|
3891 if (ed->conn)
|
|
3892 DeleteConnection (ed->conn);
|
|
3893 ed->conn = 0;
|
|
3894
|
|
3895 if (ed->binfo_hash)
|
|
3896 {
|
|
3897 int speccount = specpdl_depth ();
|
|
3898
|
|
3899 /* we are flushing everything, so we just ignore any change
|
|
3900 hooks and don't make an effort to delete extents since they
|
|
3901 are all going away */
|
|
3902 specbind (Qenergize_buffer_modified_hook, Qnil);
|
|
3903 specbind (Qinhibit_quit, Qt);
|
|
3904 call0 (intern ("de-energize-all-buffers"));
|
|
3905 unbind_to (speccount, Qnil);
|
|
3906
|
|
3907 free_hashtable (ed->binfo_hash);
|
|
3908 ed->binfo_hash = 0;
|
|
3909 }
|
|
3910
|
|
3911 /* Do this after de-energize-all-buffers or frame sizes thrash. */
|
|
3912 debuggerpanel_sheet = 0;
|
|
3913 desired_debuggerpanel_exposed_p = 0;
|
|
3914
|
|
3915 free_edit_options (peo);
|
|
3916
|
|
3917 if (ZEROP (ed->proc)) abort ();
|
|
3918
|
|
3919 if (!NILP (ed->proc))
|
|
3920 Fdelete_process (ed->proc);
|
|
3921 ed->proc = Qnil;
|
|
3922
|
|
3923 Venergize_buffers_list = Qnil;
|
|
3924
|
|
3925 /* now kill buffers created to satisfy requests on old connection */
|
|
3926 xfree (ed);
|
|
3927 }
|
|
3928
|
|
3929 /* mark as closed */
|
|
3930 energize_connection = 0;
|
|
3931 Venergize_process = Qnil;
|
|
3932 }
|
|
3933
|
|
3934
|
|
3935 DEFUN ("connect-to-energize-internal",
|
|
3936 Fconnect_to_energize_internal, Sconnect_to_energize_internal, 0, 2, 0 /*
|
|
3937 Usage: (connect-to-energize-internal <server-name> <energizearg>)
|
|
3938 Energizearg representing two 32 bit Energize ids that will be passed
|
|
3939 to the Energize server when opening the Energize connection.
|
|
3940 Only one connection can be open at a time.
|
|
3941 */ )
|
|
3942
|
|
3943 (server_name, energize_arg)
|
|
3944 Lisp_Object server_name, energize_arg;
|
|
3945 {
|
|
3946 unsigned char *server;
|
|
3947 unsigned char *arg;
|
|
3948
|
|
3949 if (!NILP (energize_arg))
|
|
3950 {
|
|
3951 CHECK_STRING (energize_arg);
|
14
|
3952 arg = XSTRING_DATA (energize_arg);
|
0
|
3953 }
|
|
3954 else
|
|
3955 arg = 0;
|
|
3956
|
|
3957 if (!NILP (server_name))
|
|
3958 {
|
|
3959 CHECK_STRING (server_name);
|
14
|
3960 server = XSTRING_DATA (server_name);
|
0
|
3961 }
|
|
3962 else
|
|
3963 server = 0;
|
|
3964
|
|
3965 /* since we are going ahead with this, make sure that we are
|
|
3966 really and truly disconnected first */
|
|
3967 Fclose_connection_to_energize ();
|
|
3968
|
|
3969 connect_to_energize ((char *)server, (char *)arg);
|
|
3970 return Qnil;
|
|
3971 }
|
|
3972
|
|
3973 DEFUN ("close-connection-to-energize", Fclose_connection_to_energize,
|
|
3974 Sclose_connection_to_energize, 0, 0, 0 /*
|
|
3975 Close the open Energize connection, if any.
|
|
3976 */ )
|
|
3977 ()
|
|
3978 {
|
|
3979 if (!energize_connection) return Qnil;
|
|
3980
|
|
3981 close_energize_connection ();
|
|
3982 return Qnil;
|
|
3983 }
|
|
3984
|
|
3985
|
|
3986 /* Extents stuff; this used to be in extents.c */
|
|
3987
|
|
3988 static void
|
|
3989 set_extent_flags (EXTENT extent, Energize_Extent_Data *ext)
|
|
3990 {
|
|
3991 /* clear every flag */
|
|
3992 if (!EXTENT_LIVE_P (extent))
|
|
3993 return;
|
|
3994 extent_start_open_p (extent) = 0;
|
|
3995 extent_end_open_p (extent) = 1;
|
|
3996 extent_read_only_p (extent) = 0;
|
|
3997 set_extent_mouse_face (extent, Qnil);
|
|
3998 extent_unique_p (extent) = 0;
|
|
3999 extent_duplicable_p (extent) = 0;
|
|
4000 extent_invisible_p (extent) = 0;
|
|
4001
|
|
4002 set_extent_glyph (extent, 0, 0, GL_TEXT);
|
|
4003 set_extent_glyph (extent, 0, 1, GL_TEXT);
|
|
4004
|
|
4005 if (ext)
|
|
4006 {
|
|
4007 ext->warn_modify = 0;
|
|
4008
|
|
4009 switch (ext->extentType)
|
|
4010 {
|
|
4011 case CEAttribute:
|
|
4012 break;
|
|
4013
|
|
4014 case CEAbbreviation:
|
|
4015 break;
|
|
4016
|
|
4017 case CEWriteProtect:
|
|
4018 extent_read_only_p (extent) = 1;
|
|
4019 break;
|
|
4020
|
|
4021 case CEGeneric:
|
|
4022 {
|
|
4023 GLYPH begin_glyph = 0; /* always the class glyph */
|
|
4024 GLYPH end_glyph = 0; /* always the instance glyph */
|
|
4025
|
|
4026 /* if (ext->u.generic.gData->id)
|
|
4027 SET_EXTENT_FLAG (extent, EF_MENU);*/
|
|
4028
|
|
4029 if (ext->u.generic.gData->glyph)
|
|
4030 end_glyph = ext->u.generic.gData->glyph;
|
|
4031 if (ext->u.generic.gData->cl && ext->u.generic.gData->cl->glyph)
|
|
4032 begin_glyph = ext->u.generic.gData->cl->glyph;
|
|
4033
|
|
4034 #if 0
|
|
4035 if (begin_glyph && end_glyph)
|
|
4036 {
|
|
4037 begin_glyph = end_glyph;
|
|
4038 end_glyph = 0;
|
|
4039 }
|
|
4040 #endif
|
|
4041
|
|
4042 if (begin_glyph)
|
|
4043 set_extent_glyph (extent, begin_glyph, 0, GL_TEXT);
|
|
4044 if (end_glyph)
|
|
4045 set_extent_glyph (extent, end_glyph, 1, GL_TEXT);
|
|
4046
|
|
4047 if (ext->u.generic.gData->cl &&
|
|
4048 (ext->u.generic.gData->cl->flags & CCElectric))
|
|
4049 set_extent_mouse_face (extent, Qhighlight);
|
|
4050 if (ext->u.generic.gData->cl &&
|
|
4051 (ext->u.generic.gData->cl->flags & CCWarnModified))
|
|
4052 ext->warn_modify = 1;
|
|
4053 #if 0 /* #### some day (soon?)... */
|
|
4054 if (ext->u.generic.gData->cl &&
|
|
4055 (ext->u.generic.gData->cl->flags & CCColumn))
|
|
4056 SET_EXTENT_FLAG (extent, EF_COLUMN);
|
|
4057 #endif
|
|
4058 extent_duplicable_p (extent) = 1;
|
|
4059 extent_unique_p (extent) = 1;
|
|
4060 break;
|
|
4061 }
|
|
4062
|
|
4063 default:
|
|
4064 break;
|
|
4065 }
|
|
4066 }
|
|
4067 }
|
|
4068
|
|
4069 extern Lisp_Object Fset_extent_face (Lisp_Object extent, Lisp_Object name);
|
|
4070
|
|
4071 static void
|
|
4072 set_extent_attributes_index (EXTENT extent, Energize_Extent_Data *ext)
|
|
4073 {
|
|
4074 int graphic_attributes;
|
|
4075
|
|
4076 if (!ext)
|
|
4077 extent_face_id (extent) = -1;
|
|
4078 else
|
|
4079 {
|
|
4080 switch (ext->extentType)
|
|
4081 {
|
|
4082 case CEAttribute:
|
|
4083 graphic_attributes = ext->u.attr.attrValue;
|
|
4084 break;
|
|
4085
|
|
4086 case CEGeneric:
|
|
4087 graphic_attributes = ext->u.generic.gData->attribute;
|
|
4088 break;
|
|
4089
|
|
4090 case CEWriteProtect:
|
|
4091 /* this type has NO display attributes */
|
|
4092 extent_face_id (extent) = -1;
|
|
4093 return;
|
|
4094
|
|
4095 default:
|
|
4096 graphic_attributes = GA_NO_CHANGE;
|
|
4097 }
|
|
4098
|
|
4099 if (graphic_attributes >= GA_MAX)
|
|
4100 graphic_attributes = GA_NO_CHANGE;
|
|
4101
|
|
4102 {
|
|
4103 /* The Venergize_attributes_mapping global is an alist of the form
|
|
4104 ( (<kernel-attribute-number> . <emacs-face-name> ) ... )
|
|
4105 */
|
|
4106 Lisp_Object face = Fcdr (Fassq (make_int (graphic_attributes),
|
|
4107 Venergize_attributes_mapping));
|
|
4108 Lisp_Object e;
|
|
4109 XSETEXTENT (e, extent);
|
|
4110 if (NILP (face))
|
|
4111 message ("Unknown Energize attribute %d", graphic_attributes);
|
|
4112 else if (EQ (face, Qdefault))
|
|
4113 Fset_extent_face (e, Qnil);
|
|
4114 else
|
|
4115 Fset_extent_face (e, face);
|
|
4116 }
|
|
4117 }
|
|
4118 }
|
|
4119
|
|
4120 void
|
|
4121 restore_energize_extent_state (EXTENT extent)
|
|
4122 {
|
|
4123 Energize_Extent_Data *ext = energize_extent_data (extent);
|
|
4124 if (!ext) return;
|
|
4125 set_extent_flags (extent, ext);
|
|
4126 set_extent_attributes_index (extent, ext);
|
|
4127 }
|
|
4128
|
|
4129 DEFUN ("extent-to-generic-id", Fextent_to_generic_id, Sextent_to_generic_id,
|
|
4130 1, 1, 0 /*
|
|
4131 Return Energize ID of buffer of EXTENT.
|
|
4132 */ )
|
|
4133 (extent_obj)
|
|
4134 Lisp_Object extent_obj;
|
|
4135 {
|
|
4136 CHECK_EXTENT (extent_obj);
|
|
4137 return word_to_lisp (energize_extent_data_id
|
|
4138 (energize_extent_data (XEXTENT (extent_obj))));
|
|
4139 }
|
|
4140
|
|
4141
|
|
4142
|
|
4143 /* buffer modified routines */
|
|
4144 static void
|
|
4145 send_buffer_modification_state (Editor *editor, BufferInfo *binfo, int flag)
|
|
4146 {
|
|
4147 Connection *conn = editor->conn;
|
|
4148 EId bufferId = binfo->id;
|
|
4149
|
|
4150 if (conn)
|
|
4151 {
|
|
4152 int state = (flag)?(CMBufferSetModified):(CMBufferSetUnmodified);
|
|
4153 CWriteModifiedBufferHeader (conn, bufferId, state);
|
|
4154 CWriteRequestBuffer (conn);
|
|
4155 }
|
|
4156 }
|
|
4157
|
|
4158 /* returns 1 if buffer is locked (non-editable),
|
|
4159 0 if it isn't (editable), and -1 if it can't tell
|
|
4160 */
|
|
4161 static int
|
|
4162 check_buffer_lock (Editor *editor, BufferInfo *binfo)
|
|
4163 {
|
|
4164 Connection *conn = editor->conn;
|
|
4165 struct reply_wait rw;
|
|
4166
|
|
4167 /* If permision already granted by kernel dont' ask again */
|
|
4168 if (binfo->editable)
|
|
4169 return 0;
|
|
4170
|
|
4171 /* If can't ask say we do not know */
|
|
4172 if (!conn)
|
|
4173 return -1;
|
|
4174
|
|
4175 /* Ask the kernel */
|
|
4176 CWriteModifiedBufferHeader (conn, binfo->id, CMBufferQueryLock);
|
|
4177 conn->header->serial = ++request_serial_number;
|
|
4178 CWriteRequestBuffer (conn);
|
|
4179
|
|
4180 rw.serial = request_serial_number;
|
|
4181 rw.objectId = binfo->id;
|
|
4182 rw.status = -1;
|
|
4183
|
|
4184 if (!wait_for_reply (&rw))
|
|
4185 return -1;
|
|
4186
|
|
4187 if (rw.status == CMBufferLocked)
|
|
4188 {
|
|
4189 /* Buffer is locked by kernel so we cannot edit it */
|
|
4190 return 1;
|
|
4191 }
|
|
4192 else if (rw.status == CMBufferUnlocked)
|
|
4193 {
|
|
4194 /* Buffer is unlocked by kernel: edit permission granted! */
|
|
4195 binfo->editable = 1;
|
|
4196 return 0;
|
|
4197 }
|
|
4198 else
|
|
4199 {
|
|
4200 /* This should never happen */
|
|
4201 return -1;
|
|
4202 }
|
|
4203 }
|
|
4204
|
|
4205
|
|
4206 /* Ask the kernel if BUFFER is currently locked -- waits for answer */
|
|
4207 static Lisp_Object
|
|
4208 buffer_locked_p (Lisp_Object buffer)
|
|
4209 {
|
|
4210 BufferInfo *binfo;
|
|
4211
|
|
4212 if (!energize_connection)
|
|
4213 return Qnil;
|
|
4214
|
|
4215 if (NILP (buffer))
|
|
4216 XSETBUFFER (buffer, current_buffer);
|
|
4217
|
|
4218 CHECK_BUFFER (buffer);
|
|
4219
|
|
4220 binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection);
|
|
4221
|
|
4222 if (!binfo)
|
|
4223 {
|
|
4224 /* Not an Energize buffer, return Qnil: can edit buffer */
|
|
4225 return Qnil;
|
|
4226 }
|
|
4227 else
|
|
4228 {
|
|
4229 /* Energize buffer, check if editable */
|
|
4230 return check_buffer_lock (energize_connection, binfo) == 0 ? Qnil : Qt;
|
|
4231 }
|
|
4232 }
|
|
4233
|
|
4234
|
|
4235
|
|
4236 /* Called by map_extents function called by Fenergize_send_buffer_modified
|
|
4237 */
|
|
4238 static int
|
|
4239 notify_extent_modified (EXTENT extent, void *arg)
|
|
4240 {
|
|
4241 /* arg is a binfo_and_state */
|
|
4242 binfo_and_state *bans = (binfo_and_state*)arg;
|
|
4243 Energize_Extent_Data *ext;
|
|
4244 BufferInfo *binfo = bans->binfo;
|
|
4245 Connection *conn = binfo->editor->conn;
|
|
4246 EId *extent_id;
|
|
4247 Lisp_Object extent_obj;
|
|
4248
|
|
4249 XSETEXTENT (extent_obj, extent);
|
|
4250 if ((ext = extent_to_data (extent_obj))
|
|
4251 && ext->warn_modify
|
|
4252 && ext->extentType == CEGeneric
|
|
4253 && ext->u.generic.gData
|
|
4254 && ext->u.generic.gData->cl
|
|
4255 && (ext->u.generic.gData->cl->flags & CCWarnModified)
|
|
4256 && ext->u.generic.gData->modified_state != bans->state)
|
|
4257 {
|
|
4258 if (bans->tell_energize)
|
|
4259 {
|
|
4260 CWriteModifiedExtentsHeader (conn, binfo->id, bans->state, 1);
|
|
4261 extent_id = CPut (conn, EId);
|
|
4262 *extent_id = ext->id;
|
|
4263 CWriteLength (conn);
|
|
4264 CWriteRequestBuffer (conn);
|
|
4265 }
|
|
4266 ext->u.generic.gData->modified_state = bans->state;
|
|
4267 }
|
|
4268 return 0;
|
|
4269 }
|
|
4270
|
|
4271 static int
|
|
4272 ceiwme_lower_mf (EXTENT e, void *arg)
|
|
4273 {
|
|
4274 Lisp_Object extent;
|
|
4275 Energize_Extent_Data *ext;
|
|
4276 XSETEXTENT (extent, e);
|
|
4277 ext = extent_to_data (extent);
|
|
4278 if (ext && ext->warn_modify)
|
|
4279 *((EXTENT *) arg) = e;
|
|
4280 return 0;
|
|
4281 }
|
|
4282
|
|
4283 static int
|
|
4284 ceiwme_upper_mf (EXTENT e, void *arg)
|
|
4285 {
|
|
4286 Lisp_Object extent;
|
|
4287 Energize_Extent_Data *ext;
|
|
4288 XSETEXTENT (extent, e);
|
|
4289 ext = extent_to_data (extent);
|
|
4290 if (ext && ext->warn_modify)
|
|
4291 {
|
|
4292 *((EXTENT *) arg) = e;
|
|
4293 return 1;
|
|
4294 }
|
|
4295 else
|
|
4296 return 0;
|
|
4297 }
|
|
4298
|
|
4299 static void
|
|
4300 coerce_endpoints_to_be_inside_warn_on_modify_extents (Bufpos *from_ptr,
|
|
4301 Bufpos *to_ptr,
|
|
4302 struct buffer *b)
|
|
4303 {
|
|
4304 EXTENT lower_extent = 0;
|
|
4305 EXTENT upper_extent = 0;
|
|
4306 Bufpos lower_bound = *from_ptr;
|
|
4307 Bufpos upper_bound = *to_ptr;
|
|
4308 Lisp_Object tmp;
|
|
4309
|
|
4310 /* make sure that from <= to */
|
|
4311 {
|
|
4312 Bufpos tmp_int = max (lower_bound, upper_bound);
|
|
4313 *from_ptr = lower_bound = min (lower_bound, upper_bound);
|
|
4314 *to_ptr = upper_bound = tmp_int;
|
|
4315 }
|
|
4316
|
|
4317 if (!BUFFER_NOTIFY_BACKGROUND_BIT_SET_P (b))
|
|
4318 return;
|
|
4319
|
|
4320 map_extents (BUF_BEG (b), lower_bound, ceiwme_lower_mf,
|
|
4321 (void *) &lower_extent, make_buffer (b), 0, ME_END_CLOSED);
|
|
4322 if (!lower_extent)
|
|
4323 {
|
|
4324 lower_bound = BUF_BEG (b);
|
|
4325 map_extents (upper_bound, BUF_Z (b), ceiwme_upper_mf,
|
|
4326 (void *) &upper_extent, make_buffer (b), 0, ME_END_CLOSED);
|
|
4327 if (!upper_extent)
|
|
4328 upper_bound = BUF_Z (b);
|
|
4329 else
|
|
4330 {
|
|
4331 Bufpos xstart;
|
|
4332 XSETEXTENT (tmp, upper_extent);
|
|
4333 xstart = XINT (Fextent_start_position (tmp));
|
|
4334 upper_bound = max (upper_bound, xstart);
|
|
4335 }
|
|
4336 }
|
|
4337 /* I forget why, but if we found an lower bound, we don't need to find
|
|
4338 an upper bound */
|
|
4339 else
|
|
4340 {
|
|
4341 Bufpos xstart;
|
|
4342 XSETEXTENT (tmp, lower_extent);
|
|
4343 xstart = XINT (Fextent_start_position (tmp));
|
|
4344 lower_bound = min (lower_bound, xstart);
|
|
4345 }
|
|
4346
|
|
4347 *from_ptr = lower_bound;
|
|
4348 *to_ptr = upper_bound;
|
|
4349 return;
|
|
4350 }
|
|
4351
|
|
4352 static void
|
|
4353 mark_all_extents_as_unmodified (BufferInfo *binfo)
|
|
4354 {
|
|
4355 binfo_and_state bans;
|
|
4356 bans.binfo = binfo;
|
|
4357 bans.state = FALSE;
|
|
4358 bans.tell_energize = FALSE;
|
|
4359
|
|
4360 map_extents (BUF_BEG (XBUFFER (binfo->emacs_buffer)),
|
|
4361 BUF_Z (XBUFFER (binfo->emacs_buffer)),
|
|
4362 notify_extent_modified, &bans,
|
|
4363 binfo->emacs_buffer, 0, ME_END_CLOSED);
|
|
4364 }
|
|
4365
|
|
4366 /* Send the BufferModified events for the current buffer.
|
|
4367 * Handles both global buffer modified and extents modified. */
|
|
4368 DEFUN ("energize-send-buffer-modified", Fenergize_send_buffer_modified,
|
|
4369 Senergize_send_buffer_modified,
|
|
4370 3, 3, 0 /*
|
|
4371 Send a BufferModified request for the current buffer.
|
|
4372 */ )
|
|
4373 (state, from, to)
|
|
4374 Lisp_Object state, from, to; /* dont use ANSI arglists in DEFUNs */
|
|
4375 {
|
|
4376 int modifiedp = NILP (state)? 0 : 1;
|
|
4377 Lisp_Object buffer;
|
|
4378 BufferInfo *binfo;
|
|
4379 Bufpos from_int = XINT (from);
|
|
4380 Bufpos to_int = XINT (to);
|
|
4381
|
|
4382 if (!energize_connection || !energize_connection->conn) return Qnil;
|
|
4383
|
|
4384 XSETBUFFER (buffer, current_buffer);
|
|
4385
|
|
4386 Fenergize_barf_if_buffer_locked ();
|
|
4387
|
|
4388 if (binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection))
|
|
4389 {
|
|
4390 /* now make sure that from and to
|
|
4391 are inside some warn_on_modify extents somewhere */
|
|
4392 coerce_endpoints_to_be_inside_warn_on_modify_extents
|
|
4393 (&from_int, &to_int, current_buffer);
|
|
4394 XSETINT (from, from_int);
|
|
4395 XSETINT (to, to_int);
|
|
4396
|
|
4397 if (binfo->modified_state != modifiedp)
|
|
4398 {
|
|
4399 send_buffer_modification_state (energize_connection, binfo,
|
|
4400 modifiedp);
|
|
4401 binfo->modified_state = modifiedp;
|
|
4402 }
|
|
4403 #ifndef ENERGIZE_V2_HEADERS
|
|
4404 if (!(binfo->flags & CBFileYourself))
|
|
4405 #endif
|
|
4406 {
|
|
4407 if (modifiedp)
|
|
4408 {
|
|
4409 binfo_and_state bans;
|
|
4410 bans.binfo = binfo;
|
|
4411 bans.state = 1;
|
|
4412 bans.tell_energize = 1;
|
|
4413 map_extents (XINT (from), XINT (to),
|
|
4414 notify_extent_modified, &bans,
|
|
4415 binfo->emacs_buffer, 0,
|
|
4416 ME_END_CLOSED);
|
|
4417 }
|
|
4418 else
|
|
4419 mark_all_extents_as_unmodified (binfo);
|
|
4420 }
|
|
4421 }
|
|
4422 return Qnil;
|
|
4423 }
|
|
4424
|
|
4425 DEFUN ("energize-barf-if-buffer-locked", Fenergize_barf_if_buffer_locked,
|
|
4426 Senergize_barf_if_buffer_locked, 0, 0, 0 /*
|
|
4427 Error if the buffer is locked.
|
|
4428 */ )
|
|
4429 ()
|
|
4430 {
|
|
4431 Lisp_Object buffer;
|
|
4432 XSETBUFFER (buffer, current_buffer);
|
|
4433
|
|
4434 if (!energize_connection || !energize_connection->conn)
|
|
4435 return Qnil;
|
|
4436
|
|
4437 while (!NILP (buffer_locked_p (buffer)))
|
|
4438 {
|
|
4439 notify_delayed_requests ();
|
|
4440 Fsignal (Qbuffer_locked_by_energize, (Fcons (buffer, Qnil)));
|
|
4441 }
|
|
4442 return Qnil;
|
|
4443 }
|
|
4444
|
|
4445
|
|
4446 DEFUN ("energize-send-region", Fenergize_send_region,
|
|
4447 Senergize_send_region,
|
|
4448 2, 2, 0 /*
|
|
4449 Send region as user input
|
|
4450 */ )
|
|
4451 (start, end)
|
|
4452 Lisp_Object start, end;
|
|
4453 {
|
|
4454 BufferInfo *binfo;
|
|
4455 Lisp_Object b;
|
|
4456 CEditorRequest *req;
|
|
4457
|
|
4458 if (!energize_connection || !energize_connection->conn)
|
|
4459 error ("Not connected to " IDENTITY_CRISIS);
|
|
4460
|
|
4461 XSETBUFFER (b, current_buffer);
|
|
4462 if (binfo = get_buffer_info_for_emacs_buffer (b, energize_connection))
|
|
4463 {
|
|
4464 Bufpos st, en;
|
|
4465 Bufpos ceil;
|
|
4466
|
|
4467 get_buffer_range_char (current_buffer, start, end, &st, &en);
|
|
4468
|
|
4469 do
|
|
4470 {
|
|
4471 ceil = BUF_CEILING_OF (current_buffer, st);
|
|
4472
|
|
4473 req = CWriteEditorRequest (energize_connection->conn,
|
|
4474 UserTypedSomethingRType);
|
|
4475 req->usertypedsomething.bufferId = binfo->id;
|
|
4476 CWriteVstringLen
|
|
4477 (energize_connection->conn,
|
|
4478 (char *) BUF_BYTE_ADDRESS (current_buffer, st), ceil - st);
|
|
4479 CWriteLength (energize_connection->conn);
|
|
4480 CWriteRequestBuffer (energize_connection->conn);
|
|
4481 st = ceil;
|
|
4482 } while (st < en);
|
|
4483 return Qnil;
|
|
4484 }
|
|
4485 return Qnil;
|
|
4486 }
|
|
4487
|
|
4488 DEFUN ("connected-to-energize-p", Fconnected_to_energize_p,
|
|
4489 Sconnected_to_energize_p,
|
|
4490 0, 0, 0 /*
|
|
4491 Return nil if no connection to Energize.
|
|
4492 */ )
|
|
4493 ()
|
|
4494 {
|
|
4495 if (!energize_connection ||
|
|
4496 !energize_connection->conn ||
|
|
4497 !energize_connection->binfo_hash ||
|
|
4498 !PROCESSP (energize_connection->proc))
|
|
4499 return Qnil;
|
|
4500 else
|
|
4501 return Qt;
|
|
4502 }
|
|
4503
|
|
4504 DEFUN ("energize-user-input-buffer-mark", Fenergize_user_input_buffer_mark,
|
|
4505 Senergize_user_input_buffer_mark, 0, 1, 0 /*
|
|
4506 Return the mark associated to the given Energize buffer.
|
|
4507 */ )
|
|
4508 (buffer)
|
|
4509 Lisp_Object buffer;
|
|
4510 {
|
|
4511 BufferInfo *binfo;
|
|
4512
|
|
4513 XSETBUFFER (buffer, decode_buffer (buffer, 0));
|
|
4514 if (!energize_connection) return Qnil;
|
|
4515 if ((binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection)))
|
|
4516 return binfo->output_mark;
|
|
4517 else
|
|
4518 return Qnil;
|
|
4519 }
|
|
4520
|
|
4521 Lisp_Object
|
|
4522 energize_get_buffer_process (Lisp_Object buf)
|
|
4523 {
|
|
4524 BufferInfo *binfo;
|
|
4525
|
|
4526 if (!BUFFERP (buf)) return Qnil;
|
|
4527 if (!energize_connection) return Qnil;
|
|
4528 binfo = get_buffer_info_for_emacs_buffer (buf, energize_connection);
|
|
4529 if (!binfo) return Qnil;
|
|
4530 if (! binfo->buffer_type) return Qnil;
|
|
4531 if (!strcmp (binfo->buffer_type, "energize-debugger-buffer") ||
|
|
4532 !strcmp (binfo->buffer_type, "energize-log-file-buffer"))
|
|
4533 return Venergize_process;
|
|
4534 return Qnil;
|
|
4535 }
|
|
4536
|
|
4537
|
|
4538 static int
|
|
4539 get_energize_connection_and_buffer_id (Lisp_Object buffer, void **conn_ptr,
|
|
4540 long *buffer_id_ptr)
|
|
4541 {
|
|
4542 BufferInfo *binfo;
|
|
4543
|
|
4544 if (!energize_connection || !energize_connection->conn) return 0;
|
|
4545
|
|
4546 binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection);
|
|
4547
|
|
4548 *conn_ptr = (void *) energize_connection->conn;
|
|
4549 *buffer_id_ptr = (long) binfo ? binfo->id : 0;
|
|
4550 return 1;
|
|
4551 }
|
|
4552
|
|
4553 static int
|
|
4554 get_energize_connection_and_current_buffer_id (void **conn_ptr,
|
|
4555 long *buffer_id_ptr)
|
|
4556 {
|
|
4557 Lisp_Object lisp_buffer;
|
|
4558 XSETBUFFER (lisp_buffer, current_buffer);
|
|
4559
|
|
4560 return get_energize_connection_and_buffer_id (lisp_buffer, conn_ptr,
|
|
4561 buffer_id_ptr);
|
|
4562 }
|
|
4563
|
|
4564 int *
|
|
4565 get_psheets_for_buffer (Lisp_Object buffer, int *count_ptr)
|
|
4566 {
|
|
4567 BufferInfo *binfo;
|
|
4568
|
|
4569 if (!energize_connection || !energize_connection->conn) return 0;
|
|
4570
|
|
4571 binfo = get_buffer_info_for_emacs_buffer (buffer, energize_connection);
|
|
4572 if (!binfo) return 0;
|
|
4573
|
|
4574 if (count_ptr) *count_ptr = binfo->n_p_sheets;
|
|
4575 return binfo->p_sheet_ids;
|
|
4576 }
|
|
4577
|
|
4578 void
|
|
4579 notify_energize_sheet_hidden (EId id)
|
|
4580 {
|
|
4581 EId buffer_id = buffer_id_of_sheet (id);
|
|
4582 if (!buffer_id)
|
|
4583 return;
|
|
4584
|
|
4585 if (buffer_id && energize_connection && energize_connection->conn)
|
|
4586 {
|
|
4587 CWriteSheetRequest (energize_connection->conn,
|
|
4588 CSHide, id, buffer_id, "");
|
|
4589 CWriteRequestBuffer (energize_connection->conn);
|
|
4590 }
|
|
4591 }
|
|
4592
|
|
4593 DEFUN ("energize-query-buffer", Fenergize_query_buffer,
|
|
4594 Senergize_query_buffer, 1, 2, 0 /*
|
|
4595 Ask Energize to create a buffer containing the file filename.
|
|
4596 Returns the buffer or NIL if Energize cannot create the buffer.
|
|
4597 If second argument just-ask is T, just ask if Energize
|
|
4598 already knows about the file and returns T if yes, NIL otherwise.
|
|
4599 */ )
|
|
4600 (filename, just_ask)
|
|
4601 Lisp_Object filename, just_ask;
|
|
4602 {
|
|
4603 struct Lisp_String *filename_str;
|
|
4604 CEditorRequest *creq;
|
|
4605 char *dir_sep;
|
|
4606 struct reply_wait rw;
|
|
4607
|
|
4608 if (!energize_connection || !energize_connection->conn)
|
|
4609 return Qnil;
|
|
4610
|
|
4611 filename = Fexpand_file_name (filename, Qnil);
|
|
4612 filename_str = XSTRING (filename);
|
|
4613
|
|
4614 dir_sep = (char *) strrchr ((char *) string_data (filename_str), '/');
|
|
4615
|
|
4616 creq = CWriteEditorRequest (energize_connection->conn, QueryBufferRType);
|
|
4617 creq->head.data = !NILP (just_ask);
|
|
4618 creq->head.serial = ++request_serial_number;
|
|
4619 CWriteVstringLen (energize_connection->conn, (char *) string_data (filename_str),
|
|
4620 (dir_sep)? (dir_sep - (char *) string_data (filename_str)): 0);
|
|
4621 CWriteVstringLen (energize_connection->conn,
|
|
4622 (char *) string_data (filename_str), string_length (filename_str));
|
|
4623 CWriteLength (energize_connection->conn);
|
|
4624 CWriteRequestBuffer (energize_connection->conn);
|
|
4625
|
|
4626 rw.serial = request_serial_number;
|
|
4627 rw.objectId = 0;
|
|
4628
|
|
4629 if (!wait_for_reply (&rw))
|
|
4630 return Qnil;
|
|
4631
|
|
4632 if (rw.status)
|
|
4633 {
|
|
4634 if (rw.objectId)
|
|
4635 {
|
|
4636 BufferInfo* binfo = get_buffer_info_for_id (rw.objectId,
|
|
4637 energize_connection);
|
|
4638 return binfo ? binfo->emacs_buffer : Qt;
|
|
4639 }
|
|
4640 else
|
|
4641 return Qt;
|
|
4642 }
|
|
4643 else
|
|
4644 return Qnil;
|
|
4645 }
|
|
4646
|
|
4647
|
|
4648 DEFUN ("energize-protocol-level", Fenergize_protocol_level,
|
|
4649 Senergize_protocol_level, 0, 0, 0 /*
|
|
4650 Return the Energize protocol level.
|
|
4651 */ )
|
|
4652 ()
|
|
4653 {
|
|
4654 return
|
|
4655 energize_connection
|
|
4656 ? Fcons (make_int (energize_connection->major),
|
|
4657 make_int (energize_connection->minor))
|
|
4658 : Qnil;
|
|
4659 }
|
|
4660
|
|
4661
|
|
4662 DEFUN ("energize-psheets-visible-p", Fenergize_psheets_visible_p,
|
|
4663 Senergize_psheets_visible_p, 0, 1, 0 /*
|
|
4664 Whether the (optional) frame currently has open psheets.
|
|
4665 */ )
|
|
4666 (frame)
|
|
4667 Lisp_Object frame;
|
|
4668 {
|
|
4669 if (NILP (frame))
|
|
4670 XSETFRAME (frame, XFRAME(Fselected_frame(Qnil)));
|
|
4671 CHECK_FRAME (frame);
|
|
4672 if (FRAME_X_CURRENT_PSHEETS (XFRAME (frame)))
|
|
4673 return Qt;
|
|
4674 return Qnil;
|
|
4675 }
|
|
4676
|
|
4677 DEFUN ("energize-buffer-has-psheets-p", Fenergize_buffer_has_psheets_p,
|
|
4678 Senergize_buffer_has_psheets_p, 0, 1, 0 /*
|
|
4679 Whether the buffer has psheets associated with it.
|
|
4680 */ )
|
|
4681 (buf)
|
|
4682 Lisp_Object buf;
|
|
4683 {
|
|
4684 int count;
|
|
4685 if (NILP (buf))
|
|
4686 buf = Fcurrent_buffer ();
|
|
4687 CHECK_BUFFER (buf);
|
|
4688 if (get_psheets_for_buffer (buf, &count))
|
|
4689 return Qt;
|
|
4690 return Qnil;
|
|
4691 }
|
|
4692
|
|
4693
|
|
4694 void
|
|
4695 make_psheets_desired (struct frame *f, Lisp_Object buffer)
|
|
4696 {
|
|
4697 int count;
|
|
4698 int *psheets;
|
|
4699
|
|
4700 if (NILP (buffer) || !(psheets = get_psheets_for_buffer (buffer, &count)))
|
|
4701 {
|
|
4702 FRAME_X_DESIRED_PSHEETS (f) = 0;
|
|
4703 FRAME_X_DESIRED_PSHEET_COUNT (f) = 0;
|
|
4704 FRAME_X_DESIRED_PSHEET_BUFFER (f) = Qnil;
|
|
4705 }
|
|
4706 else
|
|
4707 {
|
|
4708 /* Do not show the debugger panel in this function. The
|
|
4709 * debugger panel should never be listed in the visible psheets. */
|
|
4710 extern int debuggerpanel_sheet;
|
|
4711
|
|
4712 if (count == 1 && psheets [0] == debuggerpanel_sheet)
|
|
4713 return;
|
|
4714
|
|
4715 FRAME_X_DESIRED_PSHEETS (f) = psheets;
|
|
4716 FRAME_X_DESIRED_PSHEET_COUNT (f) = count;
|
|
4717 FRAME_X_DESIRED_PSHEET_BUFFER (f) = buffer;
|
|
4718 }
|
|
4719
|
|
4720 /* Garbage the frame so that the sheets get recomputed right away and not
|
|
4721 the next time some display change happens. Possibly redisplay should
|
|
4722 notice this on its own without the garbaged flag. But once redisplay
|
|
4723 gets smarter about such things, all garbagers should be revisited.
|
|
4724 */
|
|
4725 MARK_FRAME_CHANGED (f);
|
|
4726 }
|
|
4727
|
|
4728 Lisp_Object
|
|
4729 desired_psheet_buffer (struct frame *f)
|
|
4730 {
|
|
4731 if (FRAME_X_P (f))
|
|
4732 return FRAME_X_DESIRED_PSHEET_BUFFER (f);
|
|
4733 else
|
|
4734 return Qnil;
|
|
4735 }
|
|
4736
|
|
4737 /* This function is invoked when the user clicks on the "sheet" button.
|
|
4738 */
|
|
4739 DEFUN ("energize-toggle-psheet", Fenergize_toggle_psheet,
|
|
4740 Senergize_toggle_psheet, 0, 0, "" /*
|
|
4741
|
|
4742 */ )
|
|
4743 ()
|
|
4744 {
|
|
4745 struct frame *frame = XFRAME(Fselected_frame(Qnil));
|
|
4746 Lisp_Object buffer = Fwindow_buffer (Fselected_window (Qnil));
|
|
4747 if (EQ (buffer, desired_psheet_buffer (frame)))
|
|
4748 make_psheets_desired (frame, Qnil);
|
|
4749 else
|
|
4750 make_psheets_desired (frame, buffer);
|
|
4751 return Qnil;
|
|
4752 }
|
|
4753
|
|
4754
|
|
4755 static void energize_show_menubar_of_buffer (Lisp_Object frame,
|
|
4756 Lisp_Object buffer,
|
|
4757 Lisp_Object psheets_too);
|
|
4758
|
|
4759 /* This is called when a buffer becomes visible in some window.
|
|
4760
|
|
4761 Show the menubar associated with this buffer, and show the psheets as
|
|
4762 well if this buffer is the last buffer whose psheets were visible in
|
|
4763 this frame.
|
|
4764 */
|
|
4765 void
|
|
4766 energize_buffer_shown_hook (struct window *window)
|
|
4767 {
|
|
4768 struct frame* frame = XFRAME (window->frame);
|
|
4769 Lisp_Object buffer = window->buffer;
|
|
4770 Lisp_Object pbuf;
|
|
4771
|
|
4772 if (! FRAME_X_P (frame)) return;
|
|
4773 pbuf = desired_psheet_buffer (frame);
|
|
4774
|
|
4775 if (!MINI_WINDOW_P (window))
|
|
4776 energize_show_menubar_of_buffer (window->frame, buffer,
|
|
4777 (EQ (buffer, pbuf) ? Qt : Qnil));
|
|
4778 }
|
|
4779
|
|
4780
|
|
4781 static int
|
|
4782 find_buffer_in_different_window (window, buffer, not_in)
|
|
4783 struct window* window;
|
|
4784 Lisp_Object buffer;
|
|
4785 struct window* not_in;
|
|
4786 {
|
|
4787 Lisp_Object child;
|
|
4788 if (!NILP (window->buffer))
|
|
4789 {
|
|
4790 /* a leaf window */
|
|
4791 return (EQ (window->buffer, buffer) && (window != not_in));
|
|
4792 }
|
|
4793 else
|
|
4794 {
|
|
4795 /* a non leaf window, visit either the hchild or the vchild */
|
|
4796 for (child = !NILP (window->vchild) ? window->vchild : window->hchild;
|
|
4797 !NILP (child);
|
|
4798 child = XWINDOW (child)->next)
|
|
4799 {
|
|
4800 if (find_buffer_in_different_window (XWINDOW (child), buffer,
|
|
4801 not_in))
|
|
4802 return 1;
|
|
4803 }
|
|
4804 return 0;
|
|
4805 }
|
|
4806 }
|
|
4807
|
|
4808 /* returns 1 if the buffer is only visible in window on frame f */
|
|
4809 static int
|
|
4810 buffer_only_visible_in_this_window_p (Lisp_Object buffer,
|
|
4811 struct frame* f,
|
|
4812 struct window* window)
|
|
4813 {
|
|
4814 return !find_buffer_in_different_window (XWINDOW (f->root_window), buffer,
|
|
4815 window);
|
|
4816 }
|
|
4817
|
|
4818 /* This is called just before a buffer which is visible becomes invisible,
|
|
4819 either because some other buffer is about to be made visible in its window,
|
|
4820 or because that window is being deleted.
|
|
4821
|
|
4822 If this buffer's psheets are visible, hide them.
|
|
4823 */
|
|
4824 void
|
|
4825 energize_buffer_hidden_hook (struct window *window)
|
|
4826 {
|
|
4827 struct frame *f = XFRAME (window->frame);
|
|
4828
|
|
4829 if (! FRAME_X_P (f)) return;
|
|
4830
|
|
4831 /* hides the p_sheet if we are changing the buffer of the
|
|
4832 * selected window of the frame and the p_sheet where displayed */
|
|
4833 if (EQ (window->buffer, desired_psheet_buffer (f))
|
|
4834 && buffer_only_visible_in_this_window_p (window->buffer, f, window))
|
|
4835 make_psheets_desired (f, Qnil);
|
|
4836 }
|
|
4837
|
|
4838
|
|
4839 /* This is called just before the selected window is no longer the selected
|
|
4840 window because some other window is being selected. The given window is
|
|
4841 not being deleted, it is merely no longer the selected one.
|
|
4842
|
|
4843 This doesn't do anything right now.
|
|
4844 */
|
|
4845 void
|
|
4846 energize_window_deselected_hook (struct window *window)
|
|
4847 {
|
|
4848 }
|
|
4849
|
|
4850
|
|
4851 /* This is called just after a window has been selected.
|
|
4852
|
|
4853 Show the menubar associated with this buffer; leave the psheets as
|
|
4854 they are.
|
|
4855 */
|
|
4856 void
|
|
4857 energize_window_selected_hook (struct window *window)
|
|
4858 {
|
|
4859 struct frame* frame = XFRAME (window->frame);
|
|
4860 Lisp_Object buffer = window->buffer;
|
|
4861
|
|
4862 if (FRAME_X_P (frame) && !MINI_WINDOW_P (window))
|
|
4863 energize_show_menubar_of_buffer (window->frame, buffer, Qnil);
|
|
4864 }
|
|
4865
|
|
4866
|
|
4867
|
|
4868 int current_debuggerpanel_exposed_p;
|
|
4869 int desired_debuggerpanel_exposed_p;
|
|
4870 int debuggerpanel_sheet;
|
|
4871
|
|
4872 static void
|
|
4873 energize_show_menubar_of_buffer (Lisp_Object frame,
|
|
4874 Lisp_Object buffer,
|
|
4875 Lisp_Object psheets_too)
|
|
4876 {
|
|
4877 struct frame *f = decode_x_frame (frame);
|
|
4878
|
|
4879 if (! NILP (psheets_too))
|
|
4880 {
|
|
4881 Lisp_Object buffer;
|
|
4882 XSETBUFFER (buffer, current_buffer);
|
|
4883 make_psheets_desired (f, buffer);
|
|
4884 }
|
|
4885 }
|
|
4886
|
|
4887
|
|
4888 /* edit-mode dialog box
|
|
4889 This stuff really sucks
|
|
4890 */
|
|
4891
|
|
4892 static struct editmode {
|
|
4893 int ok, external, view, edit, window, split;
|
|
4894 char *other;
|
|
4895 } editmode;
|
|
4896
|
|
4897 static void
|
|
4898 edit_mode_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
|
|
4899 {
|
|
4900 widget_value *data;
|
|
4901 char *name = (char *) client_data;
|
|
4902
|
|
4903 if ((int) client_data == -1) name = "cancel"; /* WM_DELETE_WINDOW */
|
|
4904
|
|
4905 if (!strcmp (XtName (widget), "otherText")) /* screw it */
|
|
4906 ;
|
|
4907 else if (!strcmp (name, "externalBox"))
|
|
4908 {
|
|
4909 /* make the text slot be active only if "other" is selected */
|
|
4910 data = malloc_widget_value ();
|
|
4911 data->name = "externalOther";
|
|
4912 if (! lw_get_some_values (id, data)) abort ();
|
|
4913 data->enabled = data->selected;
|
|
4914 data->name = "otherText";
|
|
4915 lw_modify_all_widgets (id, data, True);
|
|
4916 free_widget_value (data);
|
|
4917 }
|
|
4918 else if (!strcmp (name, "cancel"))
|
|
4919 {
|
|
4920 editmode.ok = -1;
|
|
4921 lw_destroy_all_widgets (id);
|
|
4922 }
|
|
4923 else if (!strcmp (name, "help"))
|
|
4924 {
|
|
4925 Lisp_Object v = Fmake_vector (make_int (3), Qt);
|
|
4926 vector_data (XVECTOR (v)) [0] = build_string ("ok");
|
|
4927 vector_data (XVECTOR (v)) [1] = list1 (Qignore);
|
|
4928 Fpopup_dialog_box (list2 (build_string ("dbx_editmode_help"), v));
|
|
4929 }
|
|
4930 else if (!strcmp (name, "ok"))
|
|
4931 {
|
|
4932 editmode.ok = 1;
|
|
4933 data = malloc_widget_value ();
|
|
4934 data->name = "externalEmacs";
|
|
4935 if (! lw_get_some_values (id, data)) abort ();
|
|
4936 if (data->selected) editmode.external = 0;
|
|
4937 data->name = "externalViXterm";
|
|
4938 if (! lw_get_some_values (id, data)) abort ();
|
|
4939 if (data->selected) editmode.external = 1;
|
|
4940 data->name = "externalViCmdtool";
|
|
4941 if (! lw_get_some_values (id, data)) abort ();
|
|
4942 if (data->selected) editmode.external = 2;
|
|
4943 data->name = "externalOther";
|
|
4944 if (! lw_get_some_values (id, data)) abort ();
|
|
4945 if (data->selected) editmode.external = 3;
|
|
4946 data->name = "otherText";
|
|
4947 if (! lw_get_some_values (id, data)) abort ();
|
|
4948 editmode.other = data->value;
|
|
4949
|
|
4950 data->name = "emacsView";
|
|
4951 if (! lw_get_some_values (id, data)) abort ();
|
|
4952 if (data->selected) editmode.view = 0;
|
|
4953 data->name = "viView";
|
|
4954 if (! lw_get_some_values (id, data)) abort ();
|
|
4955 if (data->selected) editmode.view = 1;
|
|
4956 data->name = "lessView";
|
|
4957 if (! lw_get_some_values (id, data)) abort ();
|
|
4958 if (data->selected) editmode.view = 2;
|
|
4959
|
|
4960 data->name = "editEmacs";
|
|
4961 if (! lw_get_some_values (id, data)) abort ();
|
|
4962 if (data->selected) editmode.edit = 0;
|
|
4963 data->name = "editVi";
|
|
4964 if (! lw_get_some_values (id, data)) abort ();
|
|
4965 if (data->selected) editmode.edit = 1;
|
|
4966
|
|
4967 data->name = "windowOne";
|
|
4968 if (! lw_get_some_values (id, data)) abort ();
|
|
4969 if (data->selected) editmode.window = 0;
|
|
4970 data->name = "windowSeveral";
|
|
4971 if (! lw_get_some_values (id, data)) abort ();
|
|
4972 if (data->selected) editmode.window = 1;
|
|
4973 data->name = "windowMany";
|
|
4974 if (! lw_get_some_values (id, data)) abort ();
|
|
4975 if (data->selected) editmode.window = 2;
|
|
4976
|
|
4977 data->name = "splitScreens";
|
|
4978 if (! lw_get_some_values (id, data)) abort ();
|
|
4979 editmode.split = !!data->selected;
|
|
4980
|
|
4981 free_widget_value (data);
|
|
4982 lw_destroy_all_widgets (id);
|
|
4983 }
|
|
4984 else
|
|
4985 {
|
|
4986 abort ();
|
|
4987 }
|
|
4988 }
|
|
4989
|
|
4990 static int
|
|
4991 editmode_done (void *arg)
|
|
4992 {
|
|
4993 return (editmode.ok != 0);
|
|
4994 }
|
|
4995
|
|
4996 extern LWLIB_ID new_lwlib_id (void);
|
|
4997
|
|
4998 DEFUN ("energize-edit-mode-prompt", Fenergize_edit_mode_prompt,
|
|
4999 Senergize_edit_mode_prompt, 6, 6, 0 /*
|
|
5000
|
|
5001 */ )
|
|
5002 (external, edit_mode, view_mode, other_text, window, split)
|
|
5003 Lisp_Object external, edit_mode, view_mode, other_text, window, split;
|
|
5004 {
|
|
5005 int dbox_id;
|
|
5006 struct frame *f = selected_frame ();
|
|
5007 widget_value *data;
|
|
5008 Widget parent, dbox;
|
|
5009 Lisp_Object frame = Qnil;
|
|
5010
|
|
5011 XSETFRAME (frame, f);
|
|
5012 CHECK_X_FRAME (frame);
|
|
5013 parent = FRAME_X_SHELL_WIDGET (f);
|
|
5014
|
|
5015 CHECK_INT (external);
|
|
5016 CHECK_INT (edit_mode);
|
|
5017 CHECK_INT (view_mode);
|
|
5018 CHECK_INT (window);
|
|
5019 CHECK_INT (split);
|
|
5020 CHECK_STRING (other_text);
|
|
5021
|
|
5022 editmode.ok = 0;
|
|
5023 editmode.external = XINT (external);
|
|
5024 editmode.view = XINT (view_mode);
|
|
5025 editmode.edit = XINT (edit_mode);
|
|
5026 editmode.window = XINT (window);
|
|
5027 editmode.split = XINT (split);
|
|
5028 editmode.other = 0;
|
|
5029
|
|
5030 data = malloc_widget_value ();
|
|
5031 data->name = "editmode";
|
|
5032 data->value = "editmode";
|
|
5033 data->enabled = 1;
|
|
5034
|
|
5035 dbox_id = new_lwlib_id ();
|
|
5036 dbox = lw_create_widget ("editmode", "editmode", dbox_id, data, parent,
|
|
5037 1, 0, edit_mode_callback, 0);
|
|
5038 data->value = 0;
|
|
5039
|
|
5040 data->name = "button1"; data->call_data = data->value = "ok";
|
|
5041 lw_modify_all_widgets (dbox_id, data, True);
|
|
5042 data->name = "button2"; data->call_data = data->value = "cancel";
|
|
5043 lw_modify_all_widgets (dbox_id, data, True);
|
|
5044 data->name = "button3"; data->call_data = data->value = "help";
|
|
5045 lw_modify_all_widgets (dbox_id, data, True);
|
|
5046 data->name = data->call_data = "externalBox";
|
|
5047 lw_modify_all_widgets (dbox_id, data, True);
|
|
5048 data->name = "otherText"; data->call_data = "otherText";
|
|
5049 lw_modify_all_widgets (dbox_id, data, True);
|
|
5050 data->name = "message"; data->value = "editmode";
|
|
5051 lw_modify_all_widgets (dbox_id, data, True);
|
|
5052
|
|
5053 data->selected = 1;
|
|
5054 switch (editmode.external)
|
|
5055 {
|
|
5056 case 0: data->name = "externalEmacs"; break;
|
|
5057 case 1: data->name = "externalViXterm"; break;
|
|
5058 case 2: data->name = "externalViCmdtool"; break;
|
|
5059 case 3: data->name = "externalOther"; break;
|
|
5060 default: abort ();
|
|
5061 }
|
|
5062 lw_modify_all_widgets (dbox_id, data, True);
|
|
5063 switch (editmode.view)
|
|
5064 {
|
|
5065 case 0: data->name = "emacsView"; break;
|
|
5066 case 1: data->name = "viView"; break;
|
|
5067 case 2: data->name = "lessView"; break;
|
|
5068 default: abort ();
|
|
5069 }
|
|
5070 lw_modify_all_widgets (dbox_id, data, True);
|
|
5071 switch (editmode.edit)
|
|
5072 {
|
|
5073 case 0: data->name = "editEmacs"; break;
|
|
5074 case 1: data->name = "editVi"; break;
|
|
5075 default: abort ();
|
|
5076 }
|
|
5077 lw_modify_all_widgets (dbox_id, data, True);
|
|
5078 switch (editmode.window)
|
|
5079 {
|
|
5080 case 0: data->name = "windowOne"; break;
|
|
5081 case 1: data->name = "windowSeveral"; break;
|
|
5082 case 2: data->name = "windowMany"; break;
|
|
5083 default: abort ();
|
|
5084 }
|
|
5085 lw_modify_all_widgets (dbox_id, data, True);
|
|
5086
|
|
5087 data->name = "otherText";
|
|
5088 data->selected = 0;
|
14
|
5089 data->value = (char *) XSTRING_DATA (other_text);
|
0
|
5090 data->enabled = (editmode.external == 3);
|
|
5091 lw_modify_all_widgets (dbox_id, data, True);
|
|
5092
|
|
5093 data->name = "splitScreens";
|
|
5094 data->enabled = 1;
|
|
5095 data->selected = editmode.split;
|
|
5096 data->value = 0;
|
|
5097 lw_modify_all_widgets (dbox_id, data, True);
|
|
5098
|
|
5099 free_widget_value (data);
|
|
5100
|
|
5101 lw_pop_up_all_widgets (dbox_id);
|
|
5102
|
|
5103 wait_delaying_user_input (editmode_done, 0);
|
|
5104
|
|
5105 if (editmode.ok == -1)
|
|
5106 return Fcons (external,
|
|
5107 list5 (edit_mode, view_mode, other_text, window, split));
|
|
5108 else if (editmode.ok == 1)
|
|
5109 return Fcons (make_int (editmode.external),
|
|
5110 list5 (make_int (editmode.view),
|
|
5111 make_int (editmode.edit),
|
|
5112 build_string (editmode.other ? editmode.other : ""),
|
|
5113 make_int (editmode.window),
|
|
5114 make_int (editmode.split)));
|
|
5115 else
|
|
5116 abort ();
|
|
5117 }
|
|
5118
|
|
5119 static LWLIB_ID search_id;
|
|
5120 static int last_search_up_p;
|
|
5121
|
|
5122 static void
|
|
5123 hide_search_dialog (Widget w, LWLIB_ID id)
|
|
5124 {
|
|
5125 #if 0
|
|
5126 /* I'd like to do this, but the widget occasionally gets FUCKED */
|
|
5127 XUnmapWindow (XtDisplay (w), XtWindow (w));
|
|
5128 #else
|
|
5129 lw_destroy_all_widgets (id);
|
|
5130 #endif
|
|
5131 }
|
|
5132
|
|
5133
|
|
5134 static void
|
|
5135 search_callback (Widget widget, LWLIB_ID id, XtPointer client_data)
|
|
5136 {
|
|
5137 Widget parent = widget;
|
|
5138 widget_value *data;
|
|
5139 char *name = (char *) client_data;
|
|
5140 Lisp_Object search, replace;
|
|
5141 Lisp_Object case_sensitive_p, regexp_p, direction, match_word_p;
|
|
5142 Lisp_Object device = Qnil;
|
|
5143
|
|
5144 if ((int) client_data == -1) name = "done"; /* WM_DELETE_WINDOW */
|
|
5145
|
|
5146 while (parent && XtClass (parent) != xmDialogShellWidgetClass)
|
|
5147 parent = XtParent (parent);
|
|
5148 if (! parent) abort ();
|
|
5149
|
|
5150 if (!strcmp (name, "done"))
|
|
5151 {
|
|
5152 hide_search_dialog (parent, id);
|
|
5153 return;
|
|
5154 }
|
|
5155 #if 0
|
|
5156 else if (!strcmp (name, "help"))
|
|
5157 {
|
|
5158 Lisp_Object v = Fmake_vector (3, Qt);
|
|
5159 vector_data (XVECTOR (v)) [0] = build_string ("ok");
|
|
5160 vector_data (XVECTOR (v)) [1] = list1 (Qignore);
|
|
5161 Fpopup_dialog_box (list2 (build_string ("dbx_search_help"), v));
|
|
5162 return;
|
|
5163 }
|
|
5164 #endif
|
|
5165
|
|
5166 {
|
|
5167 struct device *d = get_device_from_display (XtDisplay (widget));
|
|
5168 XSETDEVICE (device, d);
|
|
5169 DEVICE_X_MOUSE_TIMESTAMP (d) = DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d);
|
|
5170 }
|
|
5171
|
|
5172 if (!strcmp (name, "gotoStart"))
|
|
5173 {
|
|
5174 signal_special_Xt_user_event (device, Qcall_interactively,
|
|
5175 Qbeginning_of_buffer);
|
|
5176 }
|
|
5177 else if (!strcmp (name, "gotoEnd"))
|
|
5178 {
|
|
5179 signal_special_Xt_user_event (device, Qcall_interactively,
|
|
5180 Qend_of_buffer);
|
|
5181 }
|
|
5182 else if (!strcmp (name, "scrollForward"))
|
|
5183 {
|
|
5184 signal_special_Xt_user_event (device, Qcall_interactively,
|
|
5185 Qscroll_up);
|
|
5186 }
|
|
5187 else if (!strcmp (name, "scrollBack"))
|
|
5188 {
|
|
5189 signal_special_Xt_user_event (device, Qcall_interactively,
|
|
5190 Qdown_up);
|
|
5191 }
|
|
5192 else
|
|
5193 {
|
|
5194 data = malloc_widget_value ();
|
|
5195 data->name = "searchText";
|
|
5196 if (! lw_get_some_values (id, data)) abort ();
|
|
5197 search = build_string (data->value);
|
|
5198 data->name = "replaceText";
|
|
5199 if (! lw_get_some_values (id, data)) abort ();
|
|
5200 replace = build_string (data->value);
|
|
5201 data->name = "regexpSearch";
|
|
5202 if (! lw_get_some_values (id, data)) abort ();
|
|
5203 regexp_p = (data->selected ? Qt : Qnil);
|
|
5204 data->name = "caseSearch";
|
|
5205 if (! lw_get_some_values (id, data)) abort ();
|
|
5206 case_sensitive_p = (data->selected ? Qt : Qnil);
|
|
5207 data->name = "matchWord";
|
|
5208 if (! lw_get_some_values (id, data)) abort ();
|
|
5209 match_word_p = (data->selected ? Qt : Qnil);
|
|
5210
|
|
5211 data->name = "directionForward";
|
|
5212 if (! lw_get_some_values (id, data)) abort ();
|
|
5213 direction = data->selected ? Qt : Qnil;
|
|
5214
|
|
5215 if (!strcmp (name, "search"))
|
|
5216 replace = Qnil;
|
|
5217 else if (!strcmp (name, "replace"))
|
|
5218 ;
|
|
5219 else if (!strcmp (name, "replace_all"))
|
|
5220 {
|
|
5221 replace = list1 (replace);
|
|
5222 /* hide_search_dialog (parent, id); */
|
|
5223 }
|
|
5224 else
|
|
5225 abort ();
|
|
5226
|
|
5227 free_widget_value (data);
|
|
5228
|
|
5229 signal_special_Xt_user_event (device,
|
|
5230 intern ("energize-search-internal"),
|
|
5231 (NILP (replace)
|
|
5232 ? list5 (case_sensitive_p, match_word_p,
|
|
5233 regexp_p, direction, search)
|
|
5234 : list6 (case_sensitive_p, match_word_p,
|
|
5235 regexp_p, direction, search,
|
|
5236 replace)));
|
|
5237 }
|
|
5238 }
|
|
5239
|
|
5240
|
|
5241 DEFUN ("energize-search", Fenergize_search, Senergize_search, 0, 0, "" /*
|
|
5242 Pop up the search-and-replace dialog box.
|
|
5243 */ )
|
|
5244 ()
|
|
5245 {
|
|
5246 int dbox_id;
|
|
5247 struct frame *f = selected_frame ();
|
|
5248 widget_value *data;
|
|
5249 Widget parent, dbox;
|
|
5250 Lisp_Object frame = Qnil;
|
|
5251
|
|
5252 XSETFRAME (frame, f);
|
|
5253 CHECK_X_FRAME (frame);
|
|
5254 parent = FRAME_X_SHELL_WIDGET (f);
|
|
5255
|
|
5256 data = malloc_widget_value ();
|
|
5257
|
|
5258 dbox_id = (search_id ? search_id : new_lwlib_id());
|
|
5259 dbox = lw_create_widget ("search", "search", dbox_id, NULL, parent,
|
|
5260 1, 0, search_callback, 0);
|
|
5261 data->enabled = 1;
|
|
5262 data->value = 0;
|
|
5263
|
|
5264 data->name = "button1"; data->value = data->call_data = "search";
|
|
5265 lw_modify_all_widgets (dbox_id, data, True);
|
|
5266 data->name = "button2"; data->value = data->call_data = "replace";
|
|
5267 lw_modify_all_widgets (dbox_id, data, True);
|
|
5268 data->name = "button3"; data->value = data->call_data = "replace_all";
|
|
5269 lw_modify_all_widgets (dbox_id, data, True);
|
|
5270 data->name = "button4"; data->value = data->call_data = "done";
|
|
5271 lw_modify_all_widgets (dbox_id, data, True);
|
|
5272
|
|
5273 data->value = 0;
|
|
5274 data->name = data->call_data = "gotoStart";
|
|
5275 lw_modify_all_widgets (dbox_id, data, True);
|
|
5276 data->name = data->call_data = "gotoEnd";
|
|
5277 lw_modify_all_widgets (dbox_id, data, True);
|
|
5278 data->name = data->call_data = "scrollBack";
|
|
5279 lw_modify_all_widgets (dbox_id, data, True);
|
|
5280 data->name = data->call_data = "scrollForward";
|
|
5281 lw_modify_all_widgets (dbox_id, data, True);
|
|
5282
|
|
5283 data->value = 0;
|
|
5284 data->name = data->call_data = "caseSearch";
|
|
5285 data->selected = NILP (current_buffer->case_fold_search);
|
|
5286 lw_modify_all_widgets (dbox_id, data, True);
|
|
5287
|
|
5288 data->name = data->call_data = "directionForward";
|
|
5289 data->selected = 1;
|
|
5290 lw_modify_all_widgets (dbox_id, data, True);
|
|
5291 data->name = data->call_data = "directionBackward";
|
|
5292 data->selected = 0;
|
|
5293 lw_modify_all_widgets (dbox_id, data, True);
|
|
5294
|
|
5295 free_widget_value (data);
|
|
5296
|
|
5297 lw_pop_up_all_widgets (dbox_id);
|
|
5298 last_search_up_p = 0;
|
|
5299 if (search_id)
|
|
5300 {
|
|
5301 Widget w = lw_get_widget (dbox_id, parent, True);
|
|
5302 if (! w) abort ();
|
|
5303 XMapRaised (XtDisplay (w), XtWindow (w));
|
|
5304 }
|
|
5305 else
|
|
5306 {
|
|
5307 search_id = dbox_id;
|
|
5308 }
|
|
5309
|
|
5310 return Qnil;
|
|
5311 }
|
|
5312
|
|
5313
|
|
5314
|
|
5315 /*************** Definition of Emacs Lisp-callable functions ***************/
|
|
5316
|
|
5317 void
|
|
5318 syms_of_energize (void)
|
|
5319 {
|
|
5320 defsubr (&Senergize_send_buffer_modified);
|
|
5321 defsubr (&Senergize_list_menu);
|
|
5322 defsubr (&Senergize_execute_menu_item);
|
|
5323 defsubr (&Senergize_execute_command_internal);
|
|
5324 defsubr (&Sconnect_to_energize_internal);
|
|
5325 defsubr (&Sconnected_to_energize_p);
|
|
5326 defsubr (&Sclose_connection_to_energize);
|
|
5327 defsubr (&Shandle_energize_request);
|
|
5328 defsubr (&Senergize_buffer_p);
|
|
5329 defsubr (&Senergize_buffer_type);
|
|
5330 defsubr (&Sset_energize_buffer_type_internal);
|
|
5331 defsubr (&Senergize_buffer_id);
|
|
5332 defsubr (&Senergize_request_kill_buffer);
|
|
5333 defsubr (&Senergize_send_region);
|
|
5334 defsubr (&Senergize_user_input_buffer_mark);
|
|
5335 defsubr (&Senergize_update_menubar);
|
|
5336 defsubr (&Senergize_extent_menu_p);
|
|
5337 defsubr (&Senergize_query_buffer);
|
|
5338 defsubr (&Senergize_barf_if_buffer_locked);
|
|
5339 defsubr (&Senergize_psheets_visible_p);
|
|
5340 defsubr (&Senergize_buffer_has_psheets_p);
|
|
5341 defsubr (&Senergize_toggle_psheet);
|
|
5342 defsubr (&Senergize_protocol_level);
|
|
5343 defsubr (&Senergize_edit_mode_prompt);
|
|
5344 defsubr (&Senergize_search);
|
|
5345 defsubr (&Sextent_to_generic_id);
|
|
5346
|
|
5347 defsymbol (&Qenergize_create_buffer_hook, "energize-create-buffer-hook");
|
|
5348 defsymbol (&Qenergize_buffer_modified_hook, "energize-buffer-modified-hook");
|
|
5349
|
|
5350 defsymbol (&Qenergize_kernel_busy, "energize-kernel-busy");
|
|
5351
|
|
5352 defsymbol (&Qenergize_kernel_busy_hook, "energize-kernel-busy-hook");
|
|
5353 defsymbol (&Qenergize_menu_update_hook, "energize-menu-update-hook");
|
|
5354 defsymbol (&Qbuffer_locked_by_energize, "buffer-locked-by-energize");
|
|
5355 defsymbol (&Qenergize_user_input_buffer_mark,
|
|
5356 "energize-user-input-buffer-mark");
|
|
5357 defsymbol (&Qenergize_make_many_buffers_visible,
|
|
5358 "energize-make-many-buffers-visible");
|
|
5359 defsymbol (&Qenergize, "energize");
|
|
5360 defsymbol (&Qenergize_auto_revert_buffer, "energize-auto-revert-buffer");
|
|
5361 }
|
|
5362
|
|
5363 void
|
|
5364 vars_of_energize (void)
|
|
5365 {
|
|
5366 energize_connection = 0;
|
|
5367 inside_process_energize_request_1 = 0;
|
|
5368
|
|
5369 staticpro (&Venergize_buffers_list);
|
|
5370 Venergize_buffers_list = Qnil;
|
|
5371
|
|
5372 staticpro (&Vall_energize_pixmaps);
|
|
5373 Vall_energize_pixmaps = Qnil;
|
|
5374
|
|
5375 Fprovide (intern ("energize"));
|
|
5376
|
|
5377 search_id = 0;
|
|
5378
|
|
5379 DEFVAR_LISP ("energize-process", &Venergize_process /*
|
|
5380 The Lisp object representing the Energize connection, or nil
|
|
5381 */ );
|
|
5382 Venergize_process = Qnil;
|
|
5383
|
|
5384 DEFVAR_LISP ("energize-create-buffer-hook", &Venergize_create_buffer_hook /*
|
|
5385 Hook called when buffer is created by energize; takes
|
|
5386 BUFFER as its only argument.
|
|
5387 */ );
|
|
5388 Venergize_create_buffer_hook = Qnil;
|
|
5389
|
|
5390
|
|
5391 DEFVAR_LISP ("energize-kernel-modification-hook",
|
|
5392 &Venergize_kernel_modification_hook /*
|
|
5393 Hook called when a buffer is being modified by energize;
|
|
5394 takes no arguments.
|
|
5395 */ );
|
|
5396 Venergize_kernel_modification_hook = Qnil;
|
|
5397
|
|
5398 DEFVAR_BOOL ("ignore-kernel",
|
|
5399 &ignore_kernel /*
|
|
5400 Set when the kernel should be ignored -- for debugging.
|
|
5401 */ );
|
|
5402 ignore_kernel = 0;
|
|
5403
|
|
5404 DEFVAR_LISP ("energize-kernel-busy", &Venergize_kernel_busy /*
|
|
5405 True if the Energize kernel is busy.
|
|
5406 */ );
|
|
5407 Venergize_kernel_busy = Qnil;
|
|
5408 DEFVAR_LISP ("energize-kernel-busy-hook", &Venergize_kernel_busy_hook /*
|
|
5409 Hook called when the Energize kernel becomes busy or non busy.
|
|
5410 */ );
|
|
5411 Venergize_kernel_busy_hook = Qnil;
|
|
5412
|
|
5413 DEFVAR_LISP ("energize-menu-update-hook", &Venergize_menu_update_hook /*
|
|
5414 Hook called when the Energize kernel updates the menubar.
|
|
5415 */ );
|
|
5416 Venergize_menu_update_hook = Qnil;
|
|
5417
|
|
5418 DEFVAR_LISP ("energize-attributes-mapping", &Venergize_attributes_mapping /*
|
|
5419 A-list to map kernel attributes indexes to Emacs attributes
|
|
5420 */ );
|
|
5421 Venergize_attributes_mapping = Qnil;
|
|
5422
|
|
5423 DEFVAR_INT ("energize-extent-gc-threshold", &energize_extent_gc_threshold /*
|
|
5424 Number of extents in a ModifyBuffer request above which to do a GC
|
|
5425 */ );
|
|
5426 energize_extent_gc_threshold = 20;
|
|
5427
|
|
5428 pure_put (Qbuffer_locked_by_energize, Qerror_conditions,
|
|
5429 list2 (Qbuffer_locked_by_energize, Qerror));
|
|
5430 pure_put (Qbuffer_locked_by_energize, Qerror_message,
|
|
5431 build_string ("Buffer is currently locked by kernel"));
|
|
5432 }
|
|
5433
|
|
5434 void
|
|
5435 complex_vars_of_energize (void)
|
|
5436 {
|
|
5437 image_cache = make_strings_hashtable (50);
|
|
5438 }
|
|
5439
|
|
5440 #endif /* ENERGIZE */
|