#include #include #include /* ** S C R E E N I M A G E P R I N T E R (SCRIMPER) ** ** Copyright 1986 By Perry S. Kivolowitz ** ** The author grants permission to duplicate and reproduce ** this software provided that no commercial gain can be ** had as a consequence of use or reproduction of this ** software and that this and other identifying informat- ** be left intact. ** ** This software is provided as a service to the readers ** of Amazing Computing and does not imply any commitment ** on behalf of the author to provide support nor can the ** author be held liable for the consequences of use or ** misuse of this software. ** */ /* ** Overview ** ** This program dynamically builds a list of screens each time its ** title bar is selected (note that the window this program creates ** is only as large as its title bar). The list of screens is dis- ** played when the right mouse button is depressed (and sometimes ** when it's just feeling lonely too). Select a screen as you would ** select an item from a menu. ** ** Something to note is the way the screen selection menu centers ** each item. This is done by the routine ``massage_left_edges.'' ** ** After a screen has been selected, the screen selection menu is ** replaced with a function selection menu. There are currently ** three things which scrimper allows you to do: ** ** (1) Bring the selected screen to front. ** ** This is kind of neat especially when you have many ** screens open at once. This gives you a sort of direct ** access capability instead of many repititions of ``screen ** to front.'' ** ** When the selected screen comes to the front if you push ** the left mouse button, the current front most screen be- ** comes the actual front screen. ** ** If you click the right mouse button, the screen SCRIMPER ** was run from will come back to the front. This is very ** useful for quickly checking the status of program running ** on another screen and whipping back to the original ** screen. ** ** (2) The selected screen can be printed. ** ** The selected screen will be brought to the front for half ** a second (literally) just for you to make sure you sel- ** ected the right screen. Then the screen SCRIMPER was run ** from comes back to the front and a requester asks if you ** really want to print the screen. ** ** If yes, SCRIMPER will try to create a copy of the screen ** in its own dynamically allocated memory. If it can, you ** are free to modify or even delete the screen without af- ** fecting the printout. If SCRIMPER can't allocate enough ** CHIP memory, it will ask you (with a requester) if you ** still want to print the screen even though SCRIMPER will ** have to use the *LIVE* copy. If that's ok, unpredictable ** results will occur if you modify or delete the screen ** while SCRIMPER is printing. ** ** What's neat here is that you can print any screen. Even ** if your program has no screen dump capability. If it does ** (for example, DPaint) SCRIMPER is *still very useful* ** since it will baby sit the printer rather than forcing ** (for example) DPaint to do so. ** ** (3) Go Back To Screen Select ** ** This is the way to tell SCRIMPER to forget that you ** selected a screen. ** ** Known Bugs: ** ** (1) Assumes 640 wide screen. ** ** (2) If printer trouble arises and the user aborts by cancelling ** the print out from the System Requester, AmigaDos loses 2K ** of memory and sometimes tosses its cookies. ** ** ** Suggested Improvements ** ** (1) Allow variable density printing. The printer driver sup- ** ports this directly. Very neat C-A! ** ** (2) Allow sections of a screen to be printed. IE: allow user ** to sweep out a box over a screen and print only what's ** inside. ** ** (3) Adjust for 320 wide screen dynamically. ** ** Compilation Information ** ** This code was developed using Manx C Beta 1.99E, 1.99F, and Manx ** C 3.20A (a final release). ** ** Defining PRINTF causes printf's to be loaded which increases the ** size of the executable to 9160 from 6520 bytes (approximately). ** By not defining PRINTF you can be confident of SCRIMPER working ** from the WORKBENCH. ** ** Link with printer.o ** ** ** STRONG SUGGESTION: Avoid burning out your print head and ribbon ** by making the background color of the screen ** white - I did and got used to it. */ #define WWIDTH 640 #define MAX_SCREENS 20 #define SIZE_MI (sizeof(struct MenuItem)) #define SIZE_IT (sizeof(struct IntuiText)) extern void *OpenLibrary(); extern void *GetMsg(); extern void *OpenWindow(); extern void *ItemAddress(); int is_cli = 0; int which_screen = 0; char *window_title = "SCReen IMage PrintER V0.6 (PSKivolowitz)"; extern char *calloc(); struct IntuitionBase *IntuitionBase; struct GfxBase *GfxBase; struct Window *w; struct Screen *s[MAX_SCREENS]; char *stitles[MAX_SCREENS]; struct IntuiMessage *message; int screen_count = 0; extern generic_cleanup(); extern screen_init() , screen_pick(); extern func_init() , func_pick(); struct IntuiText print_scrn_it = { 0 , 1 , JAM2 , 0 , 0 , NULL , (UBYTE *) "print selected screen" , NULL }; struct IntuiText back_2_scrn_it = { 0 , 1 , JAM2 , 0 , 0 , NULL , (UBYTE *) "return to screen selection" , NULL }; struct IntuiText scrn_2_frnt_it = { 0 , 1 , JAM2 , 0 , 0 , NULL , (UBYTE *) "selected screen to front" , NULL }; struct MenuItem back_to_screen_select = { NULL , -5 , 22 , 0 , 11 , ITEMTEXT | ITEMENABLED | HIGHCOMP , 0 , (APTR) &back_2_scrn_it , NULL , NULL , NULL }; struct MenuItem print_screen = { &back_to_screen_select , -5 , 11 , 0 , 11 , ITEMENABLED | ITEMTEXT | HIGHCOMP , 0 , (APTR) &print_scrn_it , NULL , NULL , NULL }; struct MenuItem screen_to_front = { &print_screen , -5 , 0 , 0 , 11 , ITEMTEXT | ITEMENABLED | HIGHCOMP , 0 , (APTR) &scrn_2_frnt_it , NULL , NULL , NULL }; struct Menu function_menu = { NULL , 10 , 0 , 130 , 10 , MENUENABLED , "Select Function" , &screen_to_front }; struct Menu screen_menu = { NULL , 10 , 0 , 120 , 10 , MENUENABLED , "Select Screen" , NULL }; struct jmptbl { struct Menu *menu; int (*init)(); int (*cleanup)(); int (*pick)(); }; struct jmptbl scrn_jmptbl = { &screen_menu , screen_init , generic_cleanup , screen_pick }; struct jmptbl func_jmptbl = { &function_menu , func_init , generic_cleanup , func_pick }; struct NewWindow nw = { 0,10, WWIDTH,10, -1,-1, ACTIVEWINDOW | INACTIVEWINDOW | CLOSEWINDOW | MENUPICK , WINDOWDEPTH | WINDOWDRAG | NOCAREREFRESH | WINDOWCLOSE , NULL,NULL, NULL , NULL,NULL,0,0,0,0,WBENCHSCREEN }; #define IBPtr struct IntuitionBase * alloc_menu_item(p , i , s) register struct MenuItem **p; register char *s; { *p = (struct MenuItem *) calloc(1 , SIZE_MI); if (*p) { (*p)->NextItem = NULL; (*p)->Height = w->WScreen->Font->ta_YSize; (*p)->TopEdge = i * (*p)->Height; (*p)->LeftEdge = -5; (*p)->Flags = ITEMTEXT | ITEMENABLED | HIGHCOMP; (*p)->Command = NULL; (*p)->SubItem = NULL; (*p)->NextSelect = NULL; (*p)->MutualExclude = (long) ~(1 << i); alloc_intuitext(&((*p)->ItemFill) , s); if (!(*p)->ItemFill) *p = NULL; else (*p)->Width = IntuiTextLength((*p)->ItemFill); } } alloc_intuitext(p , s) register struct IntuiText **p; register char *s; { register char *d = NULL; register int length = strlen(s) + 1; if (length & 1) length++; *p = (struct IntuiText *) calloc(1 , SIZE_IT); if (*p) { d = calloc(1 , length); if (d) { (*p)->FrontPen = 0; (*p)->BackPen = 1; (*p)->LeftEdge = 0; (*p)->TopEdge = 0; (*p)->DrawMode = JAM2; (*p)->ITextFont = NULL; (*p)->NextText = NULL; (*p)->IText = (UBYTE *) d; strcpy(d , s); } else *p = NULL; } } #define EVEN(S) ((S) & 1 ? (S) + 1 : (S)) get_screens() { register int i = 0; Forbid(); s[0] = w->WScreen; stitles[0] = calloc(1 , EVEN(strlen(s[0]->Title)+1)); screen_count = 1; if (stitles[0]) { strcpy(stitles[0] , s[0]->Title); while (s[i++]->NextScreen) { s[i] = s[i-1]->NextScreen; stitles[i] = calloc(1 , EVEN(strlen(s[i]->Title)+1)); if (stitles[i]) strcpy(stitles[i] , s[i]->Title); else { Permit(); return((int) FALSE); } screen_count++; } } Permit(); return((int) TRUE); } build_menu(menu , scrn) register struct Menu *menu; register struct Screen *scrn; { register int i; register struct MenuItem *p; if (get_screens()) { alloc_menu_item(&menu->FirstItem , 0 , stitles[0]); if (!menu->FirstItem) return((int) FALSE); p = menu->FirstItem; for (i = 1; i < screen_count; i++) { alloc_menu_item(&(p->NextItem) , i , stitles[i]); if (!p->NextItem) return((int) FALSE); p = p->NextItem; } return((int) TRUE); } return((int) FALSE); } main() { extern void massage_left_edges(); is_cli = 1; IntuitionBase = (IBPtr) OpenLibrary("intuition.library" , 0L); if (!IntuitionBase) { #ifdef PRINTF if (is_cli) printf("could not open intuition library\n"); #endif exit(1); } GfxBase = (struct GfxBase *) OpenLibrary("graphics.library" , 0L); if (!GfxBase) { #ifdef PRINTF if (is_cli) printf("could not open graphics library\n"); #endif CloseLibrary(IntuitionBase); exit(1); } if (! (w = (struct Window *) OpenWindow(&nw))) { #ifdef PRINTF if (is_cli) printf("could not open dummy window\n"); #endif CloseLibrary(GfxBase); CloseLibrary(IntuitionBase); exit(1); } SetWindowTitles(w , window_title , -1L); set_widths(&function_menu); massage_left_edges(&function_menu); while (message = (struct IntuiMessage *) GetMsg(w->UserPort)) ReplyMsg(message); while (getmenu(&scrn_jmptbl)) ; out: while (message = (struct IntuiMessage *) GetMsg(w->UserPort)) ReplyMsg(message); SetWindowTitles(w , NULL , NULL); CloseWindow(w); CloseLibrary(GfxBase); CloseLibrary(IntuitionBase); exit(0); } screen_pick(code) USHORT code; { which_screen = ITEMNUM(code); return(getmenu(&func_jmptbl)); } freeall() { register int i; register struct MenuItem *p = screen_menu.FirstItem; register struct IntuiText *t; register struct MenuItem *pnext; for (i = 0; i < screen_count; i++) if (stitles[i]) free(stitles[i]); while (p) { if (p->ItemFill) { t = (struct IntuiText *) p->ItemFill; if (t) { if (t->IText) free(t->IText); free(t); } } pnext = p->NextItem; free(p); p = pnext; } screen_menu.FirstItem = NULL; screen_count = 0; } void massage_left_edges(menu) register struct Menu *menu; { register int max_width = 0; register struct MenuItem *p = menu->FirstItem; if (!p) return; while (p) { if (p->Width > max_width) max_width = p->Width; p = p->NextItem; } p = menu->FirstItem; while (p) { ((struct IntuiText *) (p->ItemFill))->LeftEdge = (max_width - p->Width) / 2; p->Width = max_width; p = p->NextItem; } } set_widths(menu) register struct Menu *menu; { register struct MenuItem *p = menu->FirstItem; while (p) { p->Width = IntuiTextLength(p->ItemFill); p = p->NextItem; } } func_pick(code) USHORT code; { register struct Screen *scrn; extern struct Screen *verify_screen_pointer(); register ULONG class; if (scrn = verify_screen_pointer()) switch (ITEMNUM(code)) { case 2: return((int) TRUE); case 1: ClearMenuStrip(w); dump_screen(scrn,0,0,scrn->Width,scrn->Height); return((int) TRUE); case 0: if (scrn == w->WScreen) break; ScreenToFront(scrn); Wait(1L << w->UserPort->mp_SigBit); message = (struct IntuiMessage *) GetMsg(w->UserPort); if (message) { class = message->Class; ReplyMsg(message); if (class != INACTIVEWINDOW) ScreenToFront(w->WScreen); if (class == CLOSEWINDOW) return((int) FALSE); } return((int) TRUE); } DisplayBeep(w->WScreen); return((int) TRUE); } struct Screen *verify_screen_pointer() { register struct Screen *hoped_for; register struct Screen *p; if (! (hoped_for = s[which_screen])) return(NULL); p = s[0]; while (p) { if (p == hoped_for) return(hoped_for); p = p->NextScreen; } return(NULL); } func_init() { ClearMenuStrip(w); SetMenuStrip(w , &function_menu); return((int) TRUE); } generic_cleanup() { ClearMenuStrip(w); freeall(); } screen_init() { if (!build_menu(&screen_menu , NULL)) return((int) FALSE); massage_left_edges(&screen_menu); SetMenuStrip(w , &screen_menu); return((int) TRUE); } getmenu(jmptbl) register struct jmptbl *jmptbl; { register struct MenuItem *mi; register ULONG class; register USHORT code , code_save; register int ret_val; if (! (*jmptbl->init)()) return((int) FALSE); while (1) { message = (struct IntuiMessage *) GetMsg(w->UserPort); if (!message) { Wait(1L << w->UserPort->mp_SigBit); continue; } class = message->Class; code = message->Code; ReplyMsg(message); switch (class) { case CLOSEWINDOW: (*jmptbl->cleanup)(); return((int) FALSE); case INACTIVEWINDOW: case ACTIVEWINDOW: (*jmptbl->cleanup)(); return((int) TRUE); case MENUPICK: if (code == MENUNULL) continue; while (code != MENUNULL) { mi = (struct MenuItem *) ItemAddress(jmptbl->menu , (long) code); code_save = code; code = mi->NextSelect; } ret_val = (*jmptbl->pick)(code_save); (*jmptbl->cleanup)(); return(ret_val); } } }