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>
16 #include <dos/dostags.h>
17 #include <stddef.h> /* offsetof() */
19 #include "IPC_Prefs.h"
22 #include "ProtoTypes.h"
24 #define CATCOMP_NUMBERS
29 #include "../../tools/Edit/strings.h"
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:";
41 /** Special table for word separation **/
42 UBYTE WordsSep
[MAX_SPLIT
] = "!-/:-?[-]^`{-¿×÷";
43 UBYTE SpaceType
[] = "\t\n\r \177";
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 **/
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 **/
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
)
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
)
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
)
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;
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
);
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() ) )
151 /* First: search in local directory */
152 CopyMem(File
, Path
, sizeof(File
)-1);
153 if(BNULL
== (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(BNULL
!= (fh
= Open( file
, MODE_OLDFILE
)))
164 fh
= Open(Path
, MODE_NEWFILE
);
166 /* Did we have a opened file? */
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
) )
181 /*** Close properly IFF handle ***/
182 void close_prefs( struct IFFHandle
* file
)
185 if( file
->iff_Stream
) Close((BPTR
) file
->iff_Stream
);
189 /*** Try to load a preference file ***/
190 UBYTE
load_prefs(PREFS
*prefs
, STRPTR filename
)
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
;
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
)
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
;
232 } else err
= RETURN_FAIL
;
236 int lock
= LockIBase(0);
237 info_screen(prefs
, IntuitionBase
->ActiveScreen
);
240 /* If user wants to use a custom font for its interface, try lo **
241 ** load it, otherwise use default screen font of parent screen: */
242 if(!prefs
->use_scrfont
||
243 !(prefs
->scrfont
= (void *) OpenDiskFont( &prefs
->attrscr
)) )
244 prefs
->scrfont
= prefs
->parent
->RastPort
.Font
;
245 /* Ditto with text font */
246 if(!prefs
->use_txtfont
||
247 !(prefs
->txtfont
= (void *) OpenDiskFont( &prefs
->attrtxt
)) )
248 prefs
->txtfont
= GfxBase
->DefaultFont
;
249 /* Makes valid pointers */
250 text_to_attr(prefs
->scrfont
, &prefs
->attrscr
);
251 text_to_attr(prefs
->txtfont
, &prefs
->attrtxt
);
252 /* Special characters that separate words */
253 unpack_separators(prefs
->wordssep
);
257 int lock
= LockIBase(0);
258 set_default_prefs(prefs
, IntuitionBase
->ActiveScreen
);
265 /*** Save a file where we found it, otherwise in ENVARC: ***/
266 UBYTE
save_prefs(PREFS
*prefs
)
271 if( (file
= open_prefs(Path
, MODE_SAVE
)) )
273 if( !PushChunk(file
, ID_PREF
, ID_FORM
, IFFSIZE_UNKNOWN
) )
275 if( !PushChunk(file
, ID_PREF
, ID_JANO
, IFFSIZE_UNKNOWN
) )
279 /* Save window dimension */
280 CopyMem(&Wnd
->LeftEdge
, &prefs
->left
, 4*sizeof(WORD
));
286 prefs
->width
= prefs
->txtfont
->tf_XSize
* 80;
289 prefs
->top
= IntuitionBase
->ActiveScreen
->BarHeight
+ 1;
290 prefs
->height
= IntuitionBase
->ActiveScreen
->Height
- prefs
->top
;
294 /* Write configuration file */
295 for(num
=0; num
< MAX_NUMFIELD
; num
++) {
297 size
= sizefields
[ num
];
298 src
= (STRPTR
)prefs
+ offsets
[ num
];
299 if(size
== 0) src
= *(STRPTR
*)src
, size
= strlen(src
)+1;
301 NumField
[0] = num
; NumField
[1] = size
;
302 if( WriteChunkBytes(file
, NumField
, 2) != 2 ||
303 WriteChunkBytes(file
, src
, size
) != size
) break;
314 /*** Ask for a new font, fixed or not ***/
315 struct TextFont
*change_fonts(struct TextAttr
*buf
, void *Wnd
, BOOL fixed
)
317 struct FontRequester
*fr
;
318 struct TextFont
*newfont
= NULL
;
320 if((fr
= (void *) AllocAslRequestTags(ASL_FontRequest
,
321 ASLFO_FixedWidthOnly
, fixed
,
322 ASLFO_SleepWindow
, TRUE
,
323 ASLFO_InitialName
, (IPTR
)buf
->ta_Name
,
324 ASLFO_InitialSize
, buf
->ta_YSize
,
325 ASLFO_Window
, (IPTR
)Wnd
,
328 if( AslRequest(fr
, NULL
) )
330 /* User may hit cancel! */
331 newfont
= (void *) OpenDiskFont( &fr
->fo_Attr
);
335 CopyMem(&fr
->fo_Attr
, buf
, sizeof(*buf
));
336 /* The ta_Name field will be freed with FreeAslRequest call ! */
337 buf
->ta_Name
= newfont
->tf_Message
.mn_Node
.ln_Name
;
340 ThrowError(Wnd
, ErrMsg(ERR_LOADFONT
));
343 /* Window will be reinitiated later... */
348 /*** Ask for new screen information ***/
350 ULONG
change_screen_mode(UBYTE
*Depth
, ULONG ModeID
)
352 /*** JanoPrefs wants some additionnal information ***/
353 ULONG
change_screen_mode(WORD
*whd
, ULONG ModeID
)
356 struct ScreenModeRequester
*smr
;
358 if((smr
= (void *) AllocAslRequestTags(ASL_ScreenModeRequest
,
359 ASLSM_DoWidth
, FALSE
,
360 ASLSM_DoHeight
, FALSE
,
361 ASLSM_DoAutoScroll
, FALSE
,
362 ASLSM_DoOverscanType
, FALSE
,
364 ASLSM_InitialDisplayID
, ModeID
,
365 ASLFR_Screen
, (IPTR
)Scr
,
368 if( AslRequest(smr
,NULL
) )
370 /* Extract some interresting information about screen */
372 *Depth
= smr
->sm_DisplayDepth
;
374 whd
[0] = smr
->sm_DisplayWidth
;
375 whd
[1] = smr
->sm_DisplayHeight
;
376 whd
[2] = smr
->sm_DisplayDepth
;
378 ModeID
= smr
->sm_DisplayID
;
379 } else ModeID
= INVALID_ID
;
386 #ifndef JANOPREF /** Following functions are used only by the editor **/
389 /*** Ask where to load/save a preferences file ***/
390 void ask_prefs(Project edit
, char save
, CONST_STRPTR title
)
395 arg
.file
= (STRPTR
) FilePart( arg
.dir
= Path
);
397 if((new = (STRPTR
) (save
? ask_save(Wnd
, &arg
, title
) : ask_load(Wnd
, &arg
, TRUE
, title
))))
399 CopyMemQuick(new, Path
, sizeof(Path
));
401 if(save
) save_prefs(&prefs
);
402 else if( load_prefs(&tmpprefs
, Path
) != RETURN_OK
)
403 ThrowError(Wnd
, ErrMsg(ERR_BADPREFSFILE
));
404 else update_prefs(edit
);
408 /*** Ask user for a new font (shortcut of gui) ***/
409 void ask_new_font( void )
411 struct TextFont
*newfont
;
413 if((newfont
= change_fonts(&prefs
.attrtxt
, Wnd
, TRUE
)))
415 if( prefs
.txtfont
) CloseFont(prefs
.txtfont
);
416 prefs
.use_txtfont
= TRUE
;
417 prefs
.txtfont
= newfont
;
418 /* Redraw interface */
419 SetFont(RP
, prefs
.txtfont
);
424 /*** Change screenmode (shortcut of gui) ***/
425 void ask_new_screen( void )
428 if((ModeID
= change_screen_mode(&prefs
.depth
, prefs
.modeid
)) != INVALID_ID
)
430 prefs
.modeid
= ModeID
;
431 prefs
.use_pub
= TRUE
;
432 /* Close everything */
434 if( setup() ) cleanup(ErrMsg(ERR_NOGUI
), RETURN_FAIL
);
439 /*** Close the pref window, making or not changes effective ***/
440 void update_prefs( Project edit
)
442 /* Let's change the settings: */
443 UBYTE flags
= 0, col
= 0, i
;
444 /* We are going to take in account changes wanted by the user. **
445 ** This can imply some deep changes in the interface, try to **
446 ** limit them as possible (i.e:closing screen or window). */
448 /* First, be sure that "parent" screen already exists */
449 if(prefs
.use_pub
== 0)
451 register struct Screen
*list
, *first
;
452 int lock
= LockIBase(0);
454 for(first
= list
= IntuitionBase
->ActiveScreen
; list
&& list
!= first
; list
=list
->NextScreen
)
455 if(list
== tmpprefs
.parent
) {
460 /** The screen hasn't been found! **/
461 if(first
&& NULL
!= (list
= (void *) LockPubScreen(NULL
)))
462 UnlockPubScreen(NULL
, list
);
464 tmpprefs
.parent
= list
;
467 /* Want to change the screen where the window is ? */
468 if(prefs
.use_pub
!= tmpprefs
.use_pub
||
469 (tmpprefs
.use_pub
==1 && tmpprefs
.modeid
!=prefs
.modeid
) ||
470 (prefs
.scrfont
!= tmpprefs
.scrfont
&& prefs
.use_pub
))
471 /* Close everything in this case */
472 CloseMainWnd(1), flags
= EDIT_ALL
;
473 else if(prefs
.backdrop
!= tmpprefs
.backdrop
)
474 /* Otherwise just the window */
475 CloseMainWnd(0), flags
= EDIT_ALL
;
477 /* User has changed the screen font, but the window re- **
478 ** mains on a pubscreen. Therefore, it can't be closed, **
479 ** but change the font that our interface uses anyway: */
480 if(prefs
.scrfont
!= tmpprefs
.scrfont
)
481 /* Just compute new menu size */
484 /* Look for color changes */
485 for(i
=0; i
<sizeof(Modif
); i
++)
486 if( (&prefs
.pen
.bg
)[i
] != (&tmpprefs
.pen
.bg
)[i
] ) col
|= Modif
[i
];
488 /* Text font has changed, no shutting required */
489 if( prefs
.txtfont
!= tmpprefs
.txtfont
) flags
|= EDIT_AREA
;
491 /* Tabstop changed, need to recompute precomputed tab */
492 if(edit
->tabsize
!= tmpprefs
.tabsize
)
493 init_tabstop(tmpprefs
.tabsize
), flags
|= EDIT_AREA
,
494 edit
->tabsize
= tmpprefs
.tabsize
;
496 /* Makes changes effective */
497 CopyMem(&tmpprefs
, &prefs
, sizeof(prefs
));
498 unpack_separators((STRPTR
)strcpy(prefs
.wordssep
= WordsSep
, tmpprefs
.wordssep
));
500 /* Requires to setup the main gui? */
503 if( setup() ) cleanup(ErrMsg(ERR_NOGUI
), RETURN_FAIL
);
504 else new_size(flags
| col
);
506 /* Pens number has changed? */
507 if( col
) load_pens();
508 /* It isn't required to "reboot" the programme! */
509 SetFont(RP
, prefs
.txtfont
);
510 new_size(flags
| col
);
514 /*** Find and launch JanoEditor preference tool ***/
515 void setup_winpref( void )
517 static UBYTE JPPath
[] = SYS_DIR PREF_DIR PREF_NAME
" >NIL:";
518 static IPTR systags
[] = {
519 SYS_Input
, (IPTR
) NULL
,
520 SYS_Output
, (IPTR
) NULL
,
524 struct FileLock
*lock
;
527 /* The pref may be already running */
528 if( !send_pref(&prefs
, CMD_SHOW
) )
530 JPPath
[ sizeof(SYS_DIR PREF_DIR PREF_NAME
)-1 ] = 0;
531 /* Search the preference editor */
532 if( !(lock
= (void *) Lock(path
= JPPath
, SHARED_LOCK
)) )
533 /* But maybe it is in the path */
534 path
= JPPath
+sizeof(SYS_DIR PREF_DIR
)-1;
536 if(lock
) UnLock((BPTR
)lock
);
537 JPPath
[ sizeof(SYS_DIR PREF_DIR PREF_NAME
)-1 ] = ' ';
539 /* Let's spawn the new process, the pref will be clever enough to **
540 ** ask Jano for it's internal preference it is currently using. */
541 if(SystemTagList(path
, (struct TagItem
*)systags
) != 0)
542 ThrowError(Wnd
, ErrMsg(ERR_NOPREFEDITOR
));