Removed obsolete structure field (modifmark in AskArgs) that sometimes led
[tangerine.git] / workbench / tools / Edit / Prefs.c
blobf39affdcca776219cabc8b180c4feee799c56f2f
1 /***************************************************************
2 **** prefs.c: Preference file and Inter-Process Communica- ****
3 **** tion with JanoPrefs. © T.Pierron, C.Guillaume ****
4 **** Free software under GNU license, started on 16/4/2000 ****
5 ***************************************************************/
7 #define ASL_V38_NAMES_ONLY
8 #include <intuition/intuition.h>
9 #include <intuition/screens.h>
10 #include <intuition/intuitionbase.h>
11 #include <libraries/asl.h>
12 #include <libraries/iffparse.h>
13 #include <graphics/gfxbase.h>
14 #include <graphics/modeid.h>
15 #include <dos/dos.h>
16 #include <dos/dostags.h>
17 #include <stddef.h> /* offsetof() */
18 #include "Jed.h"
19 #include "IPC_Prefs.h"
20 #include "Utility.h"
21 #include "Events.h"
22 #include "ProtoTypes.h"
24 #define CATCOMP_NUMBERS
25 #ifndef JANOPREF
26 #include "strings.h"
27 #else
28 #include "Utils.h"
29 #include "../../tools/Edit/strings.h"
30 #endif
31 extern struct IntuitionBase *IntuitionBase;
32 extern struct GfxBase * GfxBase;
33 extern struct Library * AslBase;
34 extern struct Library * IFFParseBase;
36 PREFS prefs, tmpprefs;
37 UBYTE File[] = APPNAME ".prefs";
38 UBYTE ENV[] = "ENVARC:";
39 UBYTE Path[100];
41 /** Special table for word separation **/
42 UBYTE WordsSep[MAX_SPLIT] = "!-/:-?[-]^`{-¿×÷";
43 UBYTE SpaceType[] = "\t\n\r \177";
44 UBYTE TypeChar[256];
46 /** Default pens number **/
47 struct pens DefaultPens = {
48 BACKGROUNDPEN, TEXTPEN, FILLPEN, HIGHLIGHTTEXTPEN, SHINEPEN, TEXTPEN,
49 SHINEPEN, SHADOWPEN, BACKGROUNDPEN, TEXTPEN, -4, BACKGROUNDPEN
52 /** Which part of editor to modify according to color changes **/
53 UBYTE Modif[] = {
54 EDIT_AREA, EDIT_AREA, EDIT_AREA, EDIT_AREA, 0, 0, EDIT_GUI, EDIT_GUI,
55 EDIT_GUI, EDIT_GUI, EDIT_GUI, EDIT_GUI
58 /** Little wrapper **/
59 #define OFFS(x) (UBYTE)(offsetof(PREFS,x))
61 /** Offset of structure PREFS **/
62 UBYTE offsets[] = {
63 OFFS(use_pub), OFFS(wordssep), OFFS(attrtxt), OFFS(attrtxt.ta_YSize),
64 OFFS(attrscr), OFFS(attrscr.ta_YSize), OFFS(left), OFFS(scrw),
65 OFFS(scrd), OFFS(modeid), OFFS(vmd), OFFS(pen)
67 /** And correspond size (0=null-terminated string) **/
68 UBYTE sizefields[] = {
69 12*sizeof(char), 0, 0, sizeof(prefs.attrtxt)-sizeof(STRPTR), 0,
70 sizeof(prefs.attrscr)-sizeof(STRPTR), 4*sizeof(prefs.left), sizeof(prefs.scrw),
71 sizeof(prefs.scrd), sizeof(prefs.modeid), sizeof(prefs.vmd), sizeof(prefs.pen)
74 UBYTE FontName[60];
76 /*** Convert a TextFont struct into a TextAttr ***/
77 void text_to_attr(struct TextFont *src, struct TextAttr *dest)
79 dest->ta_Name = src->tf_Message.mn_Node.ln_Name;
80 dest->ta_YSize = src->tf_YSize;
81 dest->ta_Style = FS_NORMAL;
82 dest->ta_Flags = src->tf_Flags;
85 /*** Extract some information from a Screen structure ***/
86 void info_screen(PREFS *prefs, struct Screen *Scr)
88 prefs->parent = Scr;
89 prefs->scrw = Scr->Width;
90 prefs->scrh = Scr->Height;
91 prefs->vmd = GetVPModeID( &Scr->ViewPort );
92 prefs->scrd = Scr->RastPort.BitMap->Depth;
95 /*** Unpack separators description string ***/
96 void unpack_separators(UBYTE *Fmt)
98 UBYTE *src,a,b;
99 memset(TypeChar,ALPHA,sizeof(TypeChar));
100 for(src=Fmt; *src; src++)
102 /* Avoid special character meaning */
103 if(*src == '\\' && src[1]) src++;
104 TypeChar[*src] = SEPARATOR;
105 /* Range of char specifier? */
106 if(src[1] == '-' && *src<src[2])
107 for(a=*src,b=src[2]; a<=b; a++)
108 TypeChar[a] = SEPARATOR;
110 /* Force space char type */
111 for(src=SpaceType; *src; src++)
112 TypeChar[*src] = SPACE;
115 /*** Set preference to default settings ***/
116 void set_default_prefs( PREFS *prefs, struct Screen *def )
118 memset(prefs, 0, sizeof(*prefs));
119 CopyMem(&DefaultPens, &prefs->pen, sizeof(prefs->pen));
120 prefs->auto_indent = 1;
121 prefs->matchcase = 0;
122 prefs->tabsize = 8;
123 prefs->scrfont = def->RastPort.Font;
124 prefs->txtfont = GfxBase->DefaultFont;
125 prefs->width = prefs->txtfont->tf_XSize * 80;
126 prefs->top = def->BarHeight + 1;
127 prefs->height = def->Height - prefs->top;
128 prefs->modeid = PAL_MONITOR_ID | HIRES_KEY;
130 /* Convert dynamic struct to static one */
131 text_to_attr(prefs->scrfont, &prefs->attrscr);
132 text_to_attr(prefs->txtfont, &prefs->attrtxt);
133 unpack_separators(prefs->wordssep = WordsSep);
134 info_screen(prefs, def);
135 init_tabstop(8);
138 /* Open preference file according to `mode' */
139 APTR open_prefs(STRPTR file, UBYTE mode)
141 struct IFFHandle * pref;
143 if( IFFParseBase != NULL && (pref = (APTR) AllocIFF() ) )
145 BPTR fh = 0;
146 switch( mode )
148 case MODE_USE:
149 if(file == NULL)
151 /* First: search in local directory */
152 CopyMem(File, Path, sizeof(File)-1);
153 if(NULL == (fh = Open( Path, MODE_OLDFILE )))
155 /* Otherwise, look in directory ENVARC */
156 CopyMem(ENV, Path,sizeof(ENV)-1);
157 CopyMem(File,Path+sizeof(ENV)-1,sizeof(File)-1);
158 fh = Open( Path, MODE_OLDFILE );
160 } else if(NULL != (fh = Open( file, MODE_OLDFILE )))
161 strcpy(Path, file);
162 break;
163 case MODE_SAVE:
164 fh = Open(Path, MODE_NEWFILE);
166 /* Did we have a opened file? */
167 if( fh )
169 pref->iff_Stream = (IPTR) fh;
170 /* Use DOS function for accessing it */
171 InitIFFasDOS( pref );
172 /* Open it through iffparse */
173 if( !OpenIFF( pref, mode == MODE_SAVE ? IFFF_WRITE : IFFF_READ) )
174 return pref;
176 FreeIFF( pref );
178 return NULL;
181 /*** Close properly IFF handle ***/
182 void close_prefs( struct IFFHandle * file )
184 CloseIFF( file );
185 if( file->iff_Stream ) Close((BPTR) file->iff_Stream );
186 FreeIFF( file );
189 /*** Try to load a preference file ***/
190 UBYTE load_prefs(PREFS *prefs, STRPTR filename)
192 APTR file;
193 UBYTE err = RETURN_OK;
195 /* Locate preference file */
196 if( (file = open_prefs(filename, MODE_USE)) )
198 /* Search for PREF/JANO chunk in this file */
199 if( !StopChunk(file, ID_PREF, ID_JANO) )
201 if( !ParseIFF(file, IFFPARSE_SCAN) )
203 struct ContextNode * cn = CurrentChunk(file);
204 STRPTR buffer = NULL;
205 UWORD ByteRead = 0;
207 if( cn->cn_Type == ID_PREF && cn->cn_ID == ID_JANO &&
208 (buffer = (STRPTR) AllocVec(cn->cn_Size, MEMF_PUBLIC)) &&
209 ReadChunkBytes(file, buffer, cn->cn_Size) == cn->cn_Size )
211 /* He have read the file, converts it into PREFS struct */
212 memset(prefs, 0, sizeof(*prefs));
213 prefs->wordssep = WordsSep;
214 prefs->attrtxt.ta_Name = FontName;
215 prefs->attrscr.ta_Name = FontName+30;
216 while(ByteRead < cn->cn_Size)
218 register STRPTR src;
219 src = buffer + ByteRead;
220 if(src[0] < MAX_NUMFIELD) {
221 register STRPTR dest = (STRPTR)prefs+offsets[*src];
222 if(sizefields[ *src ] == 0) dest = *(STRPTR *)dest;
223 CopyMem(src+2, dest, src[1]);
225 ByteRead += src[1]+2;
227 } else err = RETURN_FAIL;
228 if(buffer != NULL) FreeVec( buffer );
229 } else err = RETURN_FAIL;
230 } else err = RETURN_FAIL;
231 close_prefs(file);
232 } else err = RETURN_FAIL;
234 if(err == RETURN_OK)
236 info_screen(prefs, IntuitionBase->ActiveScreen);
238 /* If user wants to use a custom font for its interface, try lo **
239 ** load it, otherwise use default screen font of parent screen: */
240 if(!prefs->use_scrfont ||
241 !(prefs->scrfont = (void *) OpenDiskFont( &prefs->attrscr )) )
242 prefs->scrfont = prefs->parent->RastPort.Font;
243 /* Ditto with text font */
244 if(!prefs->use_txtfont ||
245 !(prefs->txtfont = (void *) OpenDiskFont( &prefs->attrtxt )) )
246 prefs->txtfont = GfxBase->DefaultFont;
247 /* Makes valid pointers */
248 text_to_attr(prefs->scrfont, &prefs->attrscr);
249 text_to_attr(prefs->txtfont, &prefs->attrtxt);
250 /* Special characters that separate words */
251 unpack_separators(prefs->wordssep);
253 else set_default_prefs(prefs, IntuitionBase->ActiveScreen);
254 /* All done */
255 return err;
258 /*** Save a file where we found it, otherwise in ENVARC: ***/
259 UBYTE save_prefs(PREFS *prefs)
261 APTR file;
262 UBYTE num, size;
263 UBYTE NumField[2];
264 if( (file = open_prefs(Path, MODE_SAVE)) )
266 if( !PushChunk(file, ID_PREF, ID_FORM, IFFSIZE_UNKNOWN) )
268 if( !PushChunk(file, ID_PREF, ID_JANO, IFFSIZE_UNKNOWN) )
270 if (Wnd)
272 /* Save window dimension */
273 CopyMem(&Wnd->LeftEdge, &prefs->left, 4*sizeof(WORD));
275 else
277 prefs->left = prefs->top = prefs->width = prefs->height = 0;
280 /* Write configuration file */
281 for(num=0; num < MAX_NUMFIELD; num++) {
282 register STRPTR src;
283 size = sizefields[ num ];
284 src = (STRPTR)prefs + offsets[ num ];
285 if(size == 0) src = *(STRPTR *)src, size = strlen(src)+1;
287 NumField[0] = num; NumField[1] = size;
288 if( WriteChunkBytes(file, NumField, 2) != 2 ||
289 WriteChunkBytes(file, src, size) != size ) break;
291 PopChunk( file );
293 PopChunk( file );
295 close_prefs(file);
297 return 0;
300 /*** Ask for a new font, fixed or not ***/
301 struct TextFont *change_fonts(struct TextAttr *buf, void *Wnd, BOOL fixed)
303 struct FontRequester *fr;
304 struct TextFont *newfont = NULL;
306 if((fr = (void *) AllocAslRequestTags(ASL_FontRequest,
307 ASLFO_FixedWidthOnly, fixed,
308 ASLFO_SleepWindow, TRUE,
309 ASLFO_InitialName, (ULONG)buf->ta_Name,
310 ASLFO_InitialSize, buf->ta_YSize,
311 ASLFO_Window, (ULONG)Wnd,
312 TAG_DONE)))
314 if( AslRequest(fr, NULL) )
316 /* User may hit cancel! */
317 newfont = (void *) OpenDiskFont( &fr->fo_Attr );
319 if( newfont )
321 CopyMem(&fr->fo_Attr, buf, sizeof(*buf));
322 /* The ta_Name field will be freed with FreeAslRequest call ! */
323 buf->ta_Name = newfont->tf_Message.mn_Node.ln_Name;
325 else
326 ThrowError(Wnd, ErrMsg(ERR_LOADFONT));
328 FreeAslRequest(fr);
329 /* Window will be reinitiated later... */
331 return newfont;
334 /*** Ask for new screen information ***/
335 #ifndef JANOPREF
336 ULONG change_screen_mode(UBYTE *Depth, ULONG ModeID)
337 #else
338 /*** JanoPrefs wants some additionnal information ***/
339 ULONG change_screen_mode(WORD *whd, ULONG ModeID)
340 #endif
342 struct ScreenModeRequester *smr;
344 if((smr = (void *) AllocAslRequestTags(ASL_ScreenModeRequest,
345 ASLSM_DoWidth, FALSE,
346 ASLSM_DoHeight, FALSE,
347 ASLSM_DoAutoScroll, FALSE,
348 ASLSM_DoOverscanType, FALSE,
349 ASLSM_DoDepth, TRUE,
350 ASLSM_InitialDisplayID, ModeID,
351 ASLFR_Screen, (ULONG)Scr,
352 TAG_DONE) ))
354 if( AslRequest(smr,NULL) )
356 /* Extract some interresting information about screen */
357 #ifndef JANOPREF
358 *Depth = smr->sm_DisplayDepth;
359 #else
360 whd[0] = smr->sm_DisplayWidth;
361 whd[1] = smr->sm_DisplayHeight;
362 whd[2] = smr->sm_DisplayDepth;
363 #endif
364 ModeID = smr->sm_DisplayID;
365 } else ModeID = INVALID_ID;
366 FreeAslRequest(smr);
367 return ModeID;
369 return INVALID_ID;
372 #ifndef JANOPREF /** Following functions are used only by the editor **/
373 #include "DiskIO.h"
375 /*** Ask where to load/save a preferences file ***/
376 void ask_prefs(Project edit, char save, CONST_STRPTR title )
378 STRPTR new;
379 AskArgs arg;
381 arg.file = (STRPTR) FilePart( arg.dir = Path );
383 if((new = (STRPTR) (save ? ask_save(Wnd, &arg, title) : ask_load(Wnd, &arg, TRUE, title))))
385 CopyMemQuick(new, Path, sizeof(Path));
386 FreeVec(new);
387 if(save) save_prefs(&prefs);
388 else if( load_prefs(&tmpprefs, Path) != RETURN_OK )
389 ThrowError(Wnd, ErrMsg(ERR_BADPREFSFILE));
390 else update_prefs(edit);
394 /*** Ask user for a new font (shortcut of gui) ***/
395 void ask_new_font( void )
397 struct TextFont *newfont;
399 if((newfont = change_fonts(&prefs.attrtxt, Wnd, TRUE)))
401 if( prefs.txtfont ) CloseFont(prefs.txtfont);
402 prefs.use_txtfont = TRUE;
403 prefs.txtfont = newfont;
404 /* Redraw interface */
405 SetFont(RP, prefs.txtfont);
406 new_size(EDIT_AREA);
410 /*** Change screenmode (shortcut of gui) ***/
411 void ask_new_screen( void )
413 ULONG ModeID;
414 if((ModeID = change_screen_mode(&prefs.depth, prefs.modeid)) != INVALID_ID )
416 prefs.modeid = ModeID;
417 prefs.use_pub = TRUE;
418 /* Close everything */
419 CloseMainWnd(1);
420 if( setup() ) cleanup(ErrMsg(ERR_NOGUI), RETURN_FAIL);
421 new_size(EDIT_ALL);
425 /*** Close the pref window, making or not changes effective ***/
426 void update_prefs( Project edit )
428 /* Let's change the settings: */
429 UBYTE flags = 0, col = 0, i;
430 /* We are going to take in account changes wanted by the user. **
431 ** This can imply some deep changes in the interface, try to **
432 ** limit them as possible (i.e:closing screen or window). */
434 /* First, be sure that "parent" screen already exists */
435 if(prefs.use_pub == 0)
437 register struct Screen *list, *first;
439 for(first = list = IntuitionBase->ActiveScreen; list && list != first; list=list->NextScreen)
440 if(list == tmpprefs.parent) {
441 first = NULL; break;
444 /** The screen hasn't been found! **/
445 if(first && NULL != (list = (void *) LockPubScreen(NULL)))
446 UnlockPubScreen(NULL, list);
448 tmpprefs.parent = list;
451 /* Want to change the screen where the window is ? */
452 if(prefs.use_pub != tmpprefs.use_pub ||
453 (tmpprefs.use_pub==1 && tmpprefs.modeid!=prefs.modeid) ||
454 (prefs.scrfont != tmpprefs.scrfont && prefs.use_pub))
455 /* Close everything in this case */
456 CloseMainWnd(1), flags = EDIT_ALL;
457 else if(prefs.backdrop != tmpprefs.backdrop)
458 /* Otherwise just the window */
459 CloseMainWnd(0), flags = EDIT_ALL;
460 else
461 /* User has changed the screen font, but the window re- **
462 ** mains on a pubscreen. Therefore, it can't be closed, **
463 ** but change the font that our interface uses anyway: */
464 if(prefs.scrfont != tmpprefs.scrfont)
465 /* Just compute new menu size */
466 flags = EDIT_GUI;
468 /* Look for color changes */
469 for(i=0; i<sizeof(Modif); i++)
470 if( (&prefs.pen.bg)[i] != (&tmpprefs.pen.bg)[i] ) col |= Modif[i];
472 /* Text font has changed, no shutting required */
473 if( prefs.txtfont != tmpprefs.txtfont ) flags |= EDIT_AREA;
475 /* Tabstop changed, need to recompute precomputed tab */
476 if(edit->tabsize != tmpprefs.tabsize)
477 init_tabstop(tmpprefs.tabsize), flags |= EDIT_AREA,
478 edit->tabsize = tmpprefs.tabsize;
480 /* Makes changes effective */
481 CopyMem(&tmpprefs, &prefs, sizeof(prefs));
482 unpack_separators((STRPTR)strcpy(prefs.wordssep = WordsSep, tmpprefs.wordssep));
484 /* Requires to setup the main gui? */
485 if(flags & EDIT_GUI)
487 if( setup() ) cleanup(ErrMsg(ERR_NOGUI), RETURN_FAIL);
488 else new_size(flags | col);
489 } else {
490 /* Pens number has changed? */
491 if( col ) load_pens();
492 /* It isn't required to "reboot" the programme! */
493 SetFont(RP, prefs.txtfont);
494 new_size(flags | col);
498 /*** Find and launch JanoEditor preference tool ***/
499 void setup_winpref( void )
501 static UBYTE JPPath[] = SYS_DIR PREF_DIR PREF_NAME " >NIL:";
502 static IPTR systags[] = {
503 SYS_Input, (IPTR) NULL,
504 SYS_Output, (IPTR) NULL,
505 SYS_Asynch, TRUE,
506 TAG_DONE
508 struct FileLock *lock;
509 UBYTE *path;
511 /* The pref may be already running */
512 if( !send_pref(&prefs, CMD_SHOW) )
514 JPPath[ sizeof(SYS_DIR PREF_DIR PREF_NAME)-1 ] = 0;
515 /* Search the preference editor in various places */
516 if( !(lock = (void *) Lock(path = JPPath+sizeof(SYS_DIR PREF_DIR)-1, SHARED_LOCK)) &&
517 !(lock = (void *) Lock(path = JPPath+sizeof(SYS_DIR)-1, SHARED_LOCK)) &&
518 !(lock = (void *) Lock(path = JPPath, SHARED_LOCK)) )
519 /* But maybe it is in the path */
520 path = JPPath+sizeof(SYS_DIR PREF_DIR)-1;
522 if(lock) UnLock((BPTR)lock);
523 JPPath[ sizeof(SYS_DIR PREF_DIR PREF_NAME)-1 ] = ' ';
525 /* Let's spawn the new process, the pref will be clever enough to **
526 ** ask Jano for it's internal preference it is currently using. */
527 if(SystemTagList(path, (struct TagItem *)systags) != 0)
528 ThrowError(Wnd, ErrMsg(ERR_NOPREFEDITOR));
531 #endif