perry@well.UUCP (Perry S. Kivolowitz) (03/17/86)
The following are two files which comprise the source code for a screen dumping utility which can be run from the workbench or from the cli. It is written for use with Manx C but should not require any changes to run with Lattice. I am posting the source here rather than net.sources since the entire distrbution is this one files. This code will appear in the third issue of Amazing Computing. Some of the interesting features: Snap shots of other peoples screens are made when possible. Menus (listing current screens)_ are whipped up dynamically. Allows direct access to screens. (see comment in scrimper). Comments: Could someone test this with extra memory and report the results? Could someone from Amiga see why 2k of memory is lost if a print is canceled after ``printer trouble''? IE: does the printer device forget to deallocate all its memory? Perry S. Kivolowitz, author of Miga-Mania (amazing computing). --------scrimper.c------------- #include <exec/types.h> #include <exec/memory.h> #include <intuition/intuition.h> /* ** 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); } } } -------------printer.c----------- #include <exec/types.h> #include <intuition/intuition.h> #include <devices/printer.h> /* ** 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. ** */ static struct IODRPReq request; static struct MsgPort *pport; extern struct Message *GetMsg(); extern struct MsgPort *CreatePort(); extern PLANEPTR AllocRaster(); extern struct Window *w; static struct BitMap bm; static struct RastPort rp; static int close_mask; static int rast_count; #define PPORT 0x0001 #define PRINTER 0x0004 static struct IntuiText no_port = { 0,1,JAM1,10,16,NULL,(UBYTE *) "Could Not Allocate Printer Port" , NULL }; static struct IntuiText no_lp = { 0,1,JAM1,20,16,NULL,(UBYTE *) "Could Not Open Printer" , NULL }; static struct IntuiText no_mem2 = { 0,1,JAM1,10,16,NULL,(UBYTE *) "asynchronous print. Continue?",NULL }; static struct IntuiText no_mem = { 0,1,JAM1,30,5,NULL,(UBYTE *) "Not enough chip memory for",&no_mem2 }; static struct IntuiText ru_sure = { 0,1,JAM1,22,5,NULL,(UBYTE *) "Print The Screen?" , NULL }; static struct IntuiText yes = { 0 , 1 , JAM1 , 6 , 4 , NULL , (UBYTE *) "Yes" , NULL }; static struct IntuiText ok = { 0 , 1 , JAM1 , 7 , 4 , NULL , (UBYTE *) "OK" , NULL }; static struct IntuiText no = { 0 , 1 , JAM1 , 7 , 4, NULL , (UBYTE *) "No" , NULL }; dump_screen(s , bx , by , width , height) struct Screen *s; { register struct IODRPReq *req = &request; struct RastPort *drp = &rp; int result; int i; if (s->FirstWindow == NULL) DisplayBeep(s); else { close_mask = 0; ScreenToFront(s); Delay(30L); ScreenToFront(w->WScreen); result = AutoRequest(w,&ru_sure,&yes,&no,0L,0L,200L,60L); if (!result) return; InitRastPort(&rp); InitBitMap(&bm,(long)s->BitMap.Depth,(long)width,(long)height); rp.BitMap = &bm; for (i = 0 , rast_count = 0; i < s->BitMap.Depth; i++) { bm.Planes[i] = AllocRaster((long) width,(long) height); if (!bm.Planes[i]) { free_rasters(width , height); result = AutoRequest(w,&no_mem, &yes,&no,0L,0L,300L,60L); if (!result) return; drp = &s->RastPort; break; } rast_count++; } if (drp == &rp) { Delay(60L); ClipBlit(&s->RastPort,(long)bx,(long)by,drp,0L,0L,(long)width,(long)height,0xC0L); bx = by = 0; } if ((pport = CreatePort(NULL , 0L)) == NULL) { (void) AutoRequest(w,&no_port,&ok,NULL,0L,0L,300L,60L); close_down_printer(width , height); return; } close_mask |= PPORT; if (OpenDevice("printer.device",0L,req,0L)) { (void) AutoRequest(w,&no_lp,&ok,NULL,0L,0L,300L,60L); close_down_printer(width , height); return; } close_mask |= PRINTER; req->io_Message.mn_ReplyPort = pport; req->io_Command = PRD_DUMPRPORT; req->io_RastPort = drp; req->io_ColorMap = s->ViewPort.ColorMap; req->io_Modes = s->ViewPort.Modes; req->io_SrcX = bx; req->io_SrcY = by; req->io_DestCols = req->io_SrcWidth = width; req->io_DestRows = req->io_SrcHeight = height; req->io_Special = 0x8C; DoIO(req); close_down_printer(width , height); } } close_down_printer(w , h) { struct Message *message; while (message = GetMsg(pport)) { ReplyMsg(message); } free_rasters(w , h); if (close_mask & PRINTER) CloseDevice(&request); if (close_mask & PPORT) DeletePort(pport); } free_rasters(width , height) { register int i; for (i = 0; i < rast_count; i++) FreeRaster(bm.Planes[i] , (long) width , (long) height); }