/*  Module WSREPORT.C
    Written by Steve Mar 1992

    Write a log of one or all the applications window server resources.
*/
#include <plib.h>
#include <wlib.h>
#include <hwif.h>

GLREF_D VOID *DatApp1;
GLREF_D WSERV_SPEC *wserv_channel;

#define MAX_OBJ 256
#define G_SEG_SEL_MAX_ROM 63

typedef struct
    {
    G_FONT_INFO info;
    UBYTE *addr;
    P_RECT area;
    UWORD bytewid;
    UWORD segment;
    UWORD work_spc_size;
    UWORD work_spc_wid;
    UBYTE *width_table;
    } G_FONT;

typedef struct
    {
    UWORD seg;
    UBYTE *addr;
    UWORD bytewid;
    } BM_DATA;

typedef struct
    {
    UBYTE flags;
    UBYTE filler;
    BM_DATA bm_data;
    VOID *region;
    P_POINT size;
    TEXT name[14];
    } BITMAP;

typedef union
    {
    G_FONT *font;
    BITMAP *bit;
    } IFOB;

typedef struct 
    {
    UBYTE type;
    UBYTE usage;
    IFOB addr;
    UINT self_index;
    } SHARED_HEADER;

typedef struct s_shared_data /* Bitmap and font header structure */
    {
    SHARED_HEADER head;
    UWORD checksum;
    struct s_shared_data *next;
    struct s_shared_data **prev;
    } S_SHARED_DATA;

typedef struct s_window
    {
    UBYTE type;
    UBYTE status;
    UWORD flags;
    P_POINT origin;
    P_RECT abs;
    P_RECT rel;
    struct s_window *parent;
    struct s_window *child;
    struct s_window *sibling;
    VOID *region;
    VOID *area;
    UWORD self_index;
    } S_WINDOW;

typedef struct s_gcb
    {
    UBYTE type;
    UBYTE style;
    BM_DATA bm_data;
    UBYTE gmode;
    UBYTE textmode;
    P_POINT origin;
    VOID *region;
    UWORD draws_to;
    G_FONT *font;
    BM_DATA extra_bm_data;
    P_RECT extra_rect;
    } S_GCB;

typedef union
    {
    S_WINDOW win;
    S_GCB gcb;
    S_SHARED_DATA shared;
    } OBJECT;

#define MAX_DEV_EVENTS 8
#define DEQ_ENTRY_SIZE 16
typedef struct
    {
    UWORD ready;
    UBYTE front;
    UBYTE n_entries;
    UBYTE buffer[DEQ_ENTRY_SIZE][MAX_DEV_EVENTS];
    } S_DEQ;

typedef struct
    {
    UBYTE *read_addr;
    UWORD flags;
    UBYTE *gcb;
    UWORD os_id;
    UBYTE SelfIndex;
    BYTE error;
    VOID *clock;
    S_WINDOW *capture;
    VOID *redrawq;
    VOID *invalid_area;
    S_WINDOW *redraw_win;
    VOID *redraw_region;
    S_WINDOW *cursor_win;
    W_CURSOR cursor;
    UWORD root_handle;
    S_GCB *tempgcb;
    S_WINDOW *front_window;
    VOID *alert;
    TEXT busy_txt[W_BUSY_MSG_MAX_LEN+1];
    UBYTE busy_corner;
    VOID *bit_list;
    S_GCB *static_gcb;
    UBYTE *ipcbuf;
    WORD death_stat;
    UBYTE *cmd_buf;
    UWORD open_mode;
    ULONG open_addr;
    S_DEQ deq;
    UINT status[2];
    UWORD tab_size;
    OBJECT *obj_tab[MAX_OBJ];
    } WS_CCB;

typedef struct
    {
    WORD WservStaticInitGcb;
    WORD WservStaticFontTable;
    WORD WservStaticClients[WS_MAX_CLIENTS];
    WORD WservStaticRomSegments[G_SEG_SEL_MAX_ROM];
    WORD WservStaticFontTabSize;
    WORD WservStaticBitmapTab;
    WORD WservStaticBitmapTabSize;
    WORD WservStaticIconTab;
    WORD WservStaticIconTabSize;
    } WSERV_STATICS;

GLREF_D P_DEVICE p_file;
LOCAL_D VOID *FileCB=NULL;
LOCAL_D WSERV_STATICS *wsDatApp;
LOCAL_D WS_CCB *ClientCCBs[WS_MAX_CLIENTS];
LOCAL_D WS_CCB ccb;

LOCAL_C VOID wsRead(VOID *to,VOID *from,UINT len)
    {
    p_pcpyfr(wserv_channel->link.local.wserv_pid,from,to,len);
    }

LOCAL_C VOID fWrite(TEXT *str,...)
    {
    INT len;
    TEXT buf[128];

    len=p_atob(&buf[0],str,&str+1);
    f_write(FileCB,&buf[0],len);
    }

LOCAL_C VOID ReportWindow(S_WINDOW *pWin,UINT inset)
    {
    S_WINDOW *pNext,win;
    static TEXT *back[4]={"None","Clr","Set","Bit"};

    for(pNext=pWin;pNext;)
        {
        wsRead(&win,pNext,sizeof(S_WINDOW));
        if (win.self_index>ccb.tab_size ||
              &ccb.obj_tab[win.self_index]->win!=pNext)
            break;
        fWrite("%- *fWindow(%d) %s%sisible %s,{{%d,%d},%d,%d}",inset,
                win.self_index,
                win.status&W_UNINITIALISED?"Uninitialised ":"",
                win.status&W_SET_INVISIBLE?"Inv":"V",
                back[win.status&3],
                win.rel.tl.x,win.rel.tl.y,
                win.rel.br.x-win.rel.tl.x,
                win.rel.br.y-win.rel.tl.y);
        ReportWindow(win.child,inset+1);
        pNext=win.sibling;
        }
    }

LOCAL_C VOID ReportClient(VOID *client)
    {
    UINT j;
    OBJECT object;
    BITMAP bitmap;
    G_FONT font;
    TEXT name[34];

    wsRead(&ccb,client,sizeof(ccb));
    f_leave(p_pname(ccb.os_id,&name[0]));
    fWrite(&name[0]);
    fWrite("--------------");
    fWrite("Client slot %d",ccb.SelfIndex);
    fWrite(ccb.read_addr?"Read outstanding":"No read outstanding");
    fWrite("Flags 0x%x",ccb.flags);
    if (ccb.error)
        fWrite("Pending error %d",ccb.error);
    fWrite(ccb.redrawq ? "Redraws-pending":"No Redraws-pending");
    fWrite("PID=0x%x",ccb.os_id);
    fWrite("");
    ReportWindow(ccb.front_window,0);
    for(j=2;j<ccb.tab_size;j++)
        {
        wsRead(&object,ccb.obj_tab[j],sizeof(OBJECT));
        switch(object.win.type)
            {
            case 0x2:
                fWrite("GC(%d) draws to %d",j,object.gcb.draws_to);
            case 0x1:
                break;
            case 0x4:
                wsRead(&bitmap,object.shared.head.addr.bit,sizeof(bitmap));
                fWrite("Bitmap(%d) {%d,%d}",j,
                                    bitmap.size.x,
                                    bitmap.size.y);
                break;
            case 0x8:
                wsRead(&font,object.shared.head.addr.font,sizeof(font));
                p_bcpy(&name[0],&font.info.name[0],32);
                name[32]=0;
                fWrite("Font(%d) \"%s\",{low=%d,hi=%d,hgt=%d}",j,&name[0],
                                        font.info.low_ch,font.info.high_ch,
                                        font.info.height);
                break;
            case 0x10:
                fWrite("MouseIcon(%d)",j);
                break;
            case 0x20:
                fWrite("Clock(%d)",j);
                break;
            case 0x40:
                fWrite("Winbit(%d)",j);
                break;
            }
        }
    }

#pragma save,ENTER_CALL
LOCAL_C INT report(TEXT *fName,UINT index)
    {
    UINT i;
    INT pri,pid;

    hEnsurePath(fName);
    f_open(&FileCB,fName,P_FTEXT|P_FUPDATE|P_FREPLACE);
    pid=p_getpid();
    pri=p_getpri(pid);
    p_setpri(pid,E_PRIORITY_WSERV+1);
    p_sound(-5,320);
    if (index)
        ReportClient(ClientCCBs[index]);
    else for(i=1;i<WS_MAX_CLIENTS;i++)
        {
        if (ClientCCBs[i]==0)
            fWrite("Client slot %d :- empty",i);
        else
            ReportClient(ClientCCBs[i]);
        fWrite("");
        }
    p_setpri(pid,pri);
    return(0);
    }
#pragma restore

GLDEF_C VOID wsReport(HANDLE pid)
/* Log one or all the window server clients resources.
   If pid==0  Log all clients resources.
   If pid==-1 Log the foreground clients resources.
   Else log the client with process id PID's resources.
*/
    {
    H_DI_FSEL fsel;
    static TEXT fName[128]="\030LOC::M:\\OPL\\WSREPORT.LIS";
    UINT index,nodlg;
    UWORD buf[25];

    wsRead(&wsDatApp,&DatApp1,2);
    wsRead(&ClientCCBs[0],&wsDatApp->WservStaticClients[0],
                                                     sizeof(ClientCCBs));
    index=nodlg=0;
    if (pid==-1)    /* Log the foreground clients resources */
        {
        wGetProcessList(&buf[0]);
        pid=buf[0];
        nodlg=TRUE; /* Log to the last file name used with no query */
        }
    if (pid)    /* Find the client index of the process to log */
        FOREVER
            {
            index++;
            if (index==WS_MAX_CLIENTS)
                {
                wInfoMsg("Not a window server client");
                return;
                }
            if (ClientCCBs[index])
                {
                wsRead(&ccb,ClientCCBs[index],sizeof(ccb));
                if (ccb.os_id==pid)
                    break;
                }
            }
    fsel.fname= &fName[0];
    fsel.flags=H_FILE_SET_DEFEXT|H_FILE_NEW_EDITOR;
    if (nodlg==TRUE ||
        (uOpenDialog("Select file to write report to")>=0 &&
         uAddDialogItem(H_DIALOG_FSEL,"File",&fsel)>=0 &&
         uRunDialog()>0))
        {
        wsRead(&wsDatApp,&DatApp1,2);
        fName[fName[0]+1]=0;
        uErrorValue(p_enter3(report,&fName[1],index));
        p_close(FileCB);
        FileCB=NULL;
        }
    }

