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(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
)))
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 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
);
258 /*** Save a file where we found it, otherwise in ENVARC: ***/
259 UBYTE
save_prefs(PREFS
*prefs
)
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
) )
272 /* Save window dimension */
273 CopyMem(&Wnd
->LeftEdge
, &prefs
->left
, 4*sizeof(WORD
));
277 prefs
->left
= prefs
->top
= prefs
->width
= prefs
->height
= 0;
280 /* Write configuration file */
281 for(num
=0; num
< MAX_NUMFIELD
; num
++) {
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;
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
,
314 if( AslRequest(fr
, NULL
) )
316 /* User may hit cancel! */
317 newfont
= (void *) OpenDiskFont( &fr
->fo_Attr
);
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
;
326 ThrowError(Wnd
, ErrMsg(ERR_LOADFONT
));
329 /* Window will be reinitiated later... */
334 /*** Ask for new screen information ***/
336 ULONG
change_screen_mode(UBYTE
*Depth
, ULONG ModeID
)
338 /*** JanoPrefs wants some additionnal information ***/
339 ULONG
change_screen_mode(WORD
*whd
, ULONG ModeID
)
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
,
350 ASLSM_InitialDisplayID
, ModeID
,
351 ASLFR_Screen
, (ULONG
)Scr
,
354 if( AslRequest(smr
,NULL
) )
356 /* Extract some interresting information about screen */
358 *Depth
= smr
->sm_DisplayDepth
;
360 whd
[0] = smr
->sm_DisplayWidth
;
361 whd
[1] = smr
->sm_DisplayHeight
;
362 whd
[2] = smr
->sm_DisplayDepth
;
364 ModeID
= smr
->sm_DisplayID
;
365 } else ModeID
= INVALID_ID
;
372 #ifndef JANOPREF /** Following functions are used only by the editor **/
375 /*** Ask where to load/save a preferences file ***/
376 void ask_prefs(Project edit
, char save
, CONST_STRPTR title
)
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
));
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
);
410 /*** Change screenmode (shortcut of gui) ***/
411 void ask_new_screen( void )
414 if((ModeID
= change_screen_mode(&prefs
.depth
, prefs
.modeid
)) != INVALID_ID
)
416 prefs
.modeid
= ModeID
;
417 prefs
.use_pub
= TRUE
;
418 /* Close everything */
420 if( setup() ) cleanup(ErrMsg(ERR_NOGUI
), RETURN_FAIL
);
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
) {
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
;
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 */
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? */
487 if( setup() ) cleanup(ErrMsg(ERR_NOGUI
), RETURN_FAIL
);
488 else new_size(flags
| col
);
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
,
508 struct FileLock
*lock
;
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
));