home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / NDK / NDK_3.1 / Examples1 / intuition / attachdemo.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-27  |  18.9 KB  |  920 lines

  1. /*
  2.  * attachdemo.c - demonstrates handling attached screens
  3.  *
  4.  * (c) Copyright 1992-1999 Amiga, Inc.  All rights reserved.
  5.  *
  6.  * This software is provided as-is and is subject to change; no warranties
  7.  * are made.  All use is at your own risk.  No liability or responsibility
  8.  * is assumed.
  9.  *
  10.  */
  11.  
  12. /*----------------------------------------------------------------------*/
  13.  
  14. #include <exec/types.h>
  15. #include <graphics/displayinfo.h>
  16. #include <graphics/gfxbase.h>
  17. #include <intuition/intuition.h>
  18. #include <intuition/intuitionbase.h>
  19.  
  20. #include <clib/exec_protos.h>
  21. #include <clib/graphics_protos.h>
  22. #include <clib/intuition_protos.h>
  23. #include <clib/gadtools_protos.h>
  24.  
  25. #include <stdlib.h>
  26. #include <stdio.h>
  27.  
  28. /*----------------------------------------------------------------------*/
  29.  
  30. struct ScreenDescriptor
  31. {
  32.     LONG sd_Top;    /* Top edge in non-lace coords */
  33.     LONG sd_Open;    /* If screen is supposed to be open */
  34.     LONG sd_Lace;    /* If screen is supposed to be lace */
  35.     LONG sd_Size;    /* Screen's intended size (see below) */
  36.     LONG sd_Drag;    /* If screen is supposed to be draggable */
  37.     LONG sd_IsLace;    /* If screen was actually last lace */
  38. };
  39.  
  40. #define SIZE_NORMAL    0
  41. #define SIZE_TALL    1
  42. #define SIZE_WIDE    2
  43. #define SIZE_HUGE    3
  44.  
  45. /*----------------------------------------------------------------------*/
  46.  
  47. void error_exit( STRPTR errorstring );
  48. void CloseWindowSafely( struct Window *win );
  49. void StripIntuiMessages( struct MsgPort *mp, struct Window *win );
  50. struct Screen *findPanelScreen( void );
  51. struct Window *openPanel( void );
  52. void closePanel( void );
  53. void handleGadget( struct Gadget *gad, UWORD code );
  54. void jiggleScreen( struct Screen *sc, ULONG flags );
  55.  
  56. /*----------------------------------------------------------------------*/
  57.  
  58. struct GfxBase *GfxBase = NULL;
  59. struct IntuitionBase *IntuitionBase = NULL;
  60. struct Library *GadToolsBase = NULL;
  61. struct MsgPort *sharedport = NULL;
  62. void *panel_vi = NULL;
  63. struct Gadget *panel_gadgets = NULL;
  64. struct Window *panel_win = NULL;
  65. struct Screen *panel_screen = NULL;
  66.  
  67. struct Screen *parent_sc = NULL;
  68. struct Screen *child_sc = NULL;
  69. struct ScreenDescriptor parent_desc =
  70. {
  71.     0,            /* sd_Top */
  72.     FALSE,        /* sd_Open */
  73.     FALSE,        /* sd_Lace */
  74.     SIZE_NORMAL,    /* sd_Size */
  75.     TRUE,        /* sd_Drag */
  76. };
  77.  
  78. struct ScreenDescriptor child_desc =
  79. {
  80.     80,            /* sd_Top */
  81.     TRUE,        /* sd_Open */
  82.     FALSE,        /* sd_Lace */
  83.     SIZE_NORMAL,    /* sd_Size */
  84.     TRUE,        /* sd_Drag */
  85. };
  86.  
  87. /*----------------------------------------------------------------------*/
  88.  
  89. struct TextAttr Topaz80 =
  90. {
  91.     "topaz.font",
  92.     8,
  93.     FS_NORMAL,
  94.     FPF_DESIGNED|FPF_ROMFONT,
  95. };
  96.  
  97. /*----------------------------------------------------------------------*/
  98.  
  99. #define CHILD_MAGIC    ( (APTR)0x0FACE0FF )
  100. #define PARENT_MAGIC    ( (APTR)0x8FACE0FF )
  101.  
  102. #define GAD_PARENT_OPEN    0    /* settable */
  103. #define GAD_PARENT_LACE    1
  104. #define GAD_PARENT_SIZE    2
  105. #define GAD_PARENT_DRAG    3
  106.  
  107. #define GAD_CHILD_OPEN    4    /* settable */
  108. #define GAD_CHILD_LACE    5
  109. #define GAD_CHILD_SIZE    6
  110. #define GAD_CHILD_DRAG    7
  111.  
  112. #define GAD_FORWARD    8
  113. #define GAD_BACK    9
  114. #define GAD_CFORWARD    10
  115. #define GAD_CBACK    11
  116.  
  117. #define GAD_MOVEPARENT    12
  118. #define GAD_MOVECHILD    13
  119. #define GAD_FMOVEPARENT    14
  120. #define GAD_FMOVECHILD    15
  121.  
  122. #define GAD_HOMEPARENT    16
  123. #define GAD_HOMECHILD    17
  124.  
  125. #define NUM_SETTABLE    2
  126.  
  127. struct Gadget *mygad[ NUM_SETTABLE ];
  128.  
  129. UWORD pens[] =
  130. {
  131.     0, /* DETAILPEN */
  132.     1, /* BLOCKPEN    */
  133.     1, /* TEXTPEN    */
  134.     2, /* SHINEPEN    */
  135.     1, /* SHADOWPEN    */
  136.     3, /* FILLPEN    */
  137.     1, /* FILLTEXTPEN    */
  138.     0, /* BACKGROUNDPEN    */
  139.     2, /* HIGHLIGHTTEXTPEN    */
  140.  
  141.     1, /* BARDETAILPEN    */
  142.     2, /* BARBLOCKPEN    */
  143.     1, /* BARTRIMPEN    */
  144.  
  145.     (UWORD)~0,
  146. };
  147.  
  148. /*----------------------------------------------------------------------*/
  149.  
  150. STRPTR OpenLabels[] =
  151. {
  152.     "Closed",
  153.     "Open",
  154.     NULL,
  155. };
  156.  
  157. STRPTR LaceLabels[] =
  158. {
  159.     "Non-Laced",
  160.     "Interlaced",
  161.     NULL,
  162. };
  163.  
  164. STRPTR SizeLabels[] =
  165. {
  166.     "Normal",
  167.     "Tall",
  168.     "Wide",
  169.     "Huge",
  170.     NULL,
  171. };
  172.  
  173. STRPTR DragLabels[] =
  174. {
  175.     "Non-Drag",
  176.     "Draggable",
  177.     NULL,
  178. };
  179.  
  180. LONG scwidth[ 4 ] =
  181. {
  182.     640, 640, 960, 960,    /* normal, tall, wide, huge */
  183. };
  184.  
  185. LONG cheight[ 4 ] =
  186. {
  187.  
  188.     120, 380, 120, 380,    /* normal, tall, wide, huge */
  189. };
  190.  
  191. LONG pheight[ 4 ] =
  192. {
  193.  
  194.     200, 400, 200, 400,    /* normal, tall, wide, huge */
  195. };
  196.  
  197. /*----------------------------------------------------------------------*/
  198.  
  199. struct Screen *
  200. openMyScreen( BOOL isparent )
  201. {
  202.     struct Screen *sc;
  203.     LONG top, drag, width, height, id;
  204.     STRPTR title;
  205.     ULONG attachtag;
  206.     APTR userdata;
  207.     struct Screen *attachdata = NULL;
  208.  
  209.     if ( isparent )
  210.     {
  211.     top = parent_desc.sd_Top;
  212.     drag = parent_desc.sd_Drag;
  213.     width = scwidth[ parent_desc.sd_Size ];
  214.     if ( parent_desc.sd_Lace )
  215.     {
  216.         title = "Laced Parent";
  217.         height = 2*pheight[ parent_desc.sd_Size ];
  218.         top *= 2;
  219.         id = HIRESLACE_KEY;
  220.     }
  221.     else
  222.     {
  223.         title = "Non-laced Parent";
  224.         height = pheight[ parent_desc.sd_Size ];
  225.         id = HIRES_KEY;
  226.     }
  227.     attachtag = SA_FrontChild;
  228.     attachdata = child_sc;
  229.     userdata = CHILD_MAGIC;
  230.     }
  231.     else
  232.     {
  233.     top = child_desc.sd_Top;
  234.     drag = child_desc.sd_Drag;
  235.     width = scwidth[ child_desc.sd_Size ];
  236.     if ( child_desc.sd_Lace )
  237.     {
  238.         title = "Laced Child";
  239.         height = cheight[ child_desc.sd_Size ]*2;
  240.         top *= 2;
  241.         id = HIRESLACE_KEY;
  242.     }
  243.     else
  244.     {
  245.         title = "Non-laced Child";
  246.         height = cheight[ child_desc.sd_Size ];
  247.         id = HIRES_KEY;
  248.     }
  249.     attachtag = SA_Parent;
  250.     attachdata = parent_sc;
  251.     userdata = PARENT_MAGIC;
  252.     }
  253.  
  254.     if ( sc = OpenScreenTags( NULL,
  255.     SA_DisplayID, id,
  256.     SA_Top, top,
  257.     SA_Title, title,
  258.     SA_Width, width,
  259.     SA_Height, height,
  260.     SA_Overscan, OSCAN_TEXT,
  261.     /*  Other tags can go here: */
  262.     SA_Depth, 2,
  263.     SA_Pens, pens,
  264.     SA_Draggable, drag,
  265.     SA_AutoScroll, TRUE,
  266.     SA_Font, &Topaz80,
  267.     attachtag, attachdata,
  268.     TAG_DONE ) )
  269.     {
  270.     sc->UserData = userdata;
  271.     }
  272.     return( sc );
  273. }
  274.  
  275. struct Screen *
  276. closeMyScreen( struct Screen *sc )
  277. {
  278.     if ( sc )
  279.     {
  280.     if ( panel_screen == sc )
  281.     {
  282.         closePanel();
  283.     }
  284.     CloseScreen( sc );
  285.     }
  286.     return( ( struct Screen * )NULL );
  287. }
  288.  
  289. /*----------------------------------------------------------------------*/
  290.  
  291. void
  292. main( void )
  293.  
  294. {
  295.     BOOL done = FALSE;
  296.     struct IntuiMessage *imsg;
  297.     ULONG imsgClass;
  298.     UWORD imsgCode;
  299.     APTR imsgIAddress;
  300.  
  301.     if ( !( GfxBase = ( struct GfxBase * )
  302.     OpenLibrary( "graphics.library", 39L ) ) )
  303.     {
  304.     error_exit( "Couldn't open Gfx V39\n" );
  305.     }
  306.  
  307.     if ( !( IntuitionBase = ( struct IntuitionBase * )
  308.     OpenLibrary( "intuition.library", 39L ) ) )
  309.     {
  310.     error_exit( "Couldn't open Intuition V39\n" );
  311.     }
  312.  
  313.     if ( !( GadToolsBase =
  314.     OpenLibrary( "gadtools.library", 39L ) ) )
  315.     {
  316.     error_exit( "Couldn't open GadTools V39\n" );
  317.     }
  318.  
  319.     if ( !( sharedport = CreateMsgPort() ) )
  320.     {
  321.     error_exit( "No port\n" );
  322.     }
  323.  
  324.     if ( child_desc.sd_Open )
  325.     {
  326.     child_sc = openMyScreen( FALSE );
  327.     child_desc.sd_IsLace = child_desc.sd_Lace;
  328.     }
  329.  
  330.     if ( parent_desc.sd_Open )
  331.     {
  332.     parent_sc = openMyScreen( TRUE );
  333.     parent_desc.sd_IsLace = parent_desc.sd_Lace;
  334.     }
  335.  
  336.     openPanel();
  337.  
  338.     while ( !done )
  339.     {
  340.     Wait( 1 << sharedport->mp_SigBit );
  341.     while ( imsg = GT_GetIMsg( sharedport ) )
  342.     {
  343.         imsgClass = imsg->Class;
  344.         imsgCode = imsg->Code;
  345.         imsgIAddress = imsg->IAddress;
  346.         GT_ReplyIMsg( imsg );
  347.  
  348.         switch ( imsgClass )
  349.         {
  350.         case IDCMP_CLOSEWINDOW:
  351.             done = TRUE;
  352.             break;
  353.  
  354.         case IDCMP_REFRESHWINDOW:
  355.             /* Only the panel-window has IDCMP_REFRESHWINDOW set */
  356.             GT_BeginRefresh( panel_win );
  357.             GT_EndRefresh( panel_win, TRUE );
  358.             break;
  359.  
  360.         case IDCMP_GADGETUP:
  361.             handleGadget( imsgIAddress, imsgCode );
  362.             break;
  363.         }
  364.     }
  365.     }
  366.     error_exit( NULL );
  367. }
  368.  
  369.  
  370. /*----------------------------------------------------------------------*/
  371.  
  372. void error_exit( STRPTR errorstring )
  373.  
  374. {
  375.     closePanel();
  376.  
  377.     closeMyScreen( child_sc );
  378.  
  379.     closeMyScreen( parent_sc );
  380.  
  381.     if ( sharedport )
  382.     {
  383.     DeleteMsgPort( sharedport );
  384.     }
  385.  
  386.     if ( GadToolsBase )
  387.     {
  388.     CloseLibrary( GadToolsBase );
  389.     }
  390.  
  391.     if ( IntuitionBase )
  392.     {
  393.     CloseLibrary( ( struct Library * )IntuitionBase );
  394.     }
  395.  
  396.     if ( GfxBase )
  397.     {
  398.     CloseLibrary( GfxBase );
  399.     }
  400.  
  401.     if ( errorstring )
  402.     {
  403.     printf( errorstring );
  404.     exit( 20 );
  405.     }
  406.  
  407.     exit( 0 );
  408. }
  409.  
  410.  
  411. /*----------------------------------------------------------------------*/
  412.  
  413. /* these functions close an Intuition window
  414.  * that shares a port with other Intuition
  415.  * windows or IPC customers.
  416.  *
  417.  * We are careful to set the UserPort to
  418.  * null before closing, and to free
  419.  * any messages that it might have been
  420.  * sent.
  421.  */
  422.  
  423. void CloseWindowSafely( win )
  424. struct Window *win;
  425. {
  426.     /* we forbid here to keep out of race conditions with Intuition */
  427.     Forbid();
  428.  
  429.     /* send back any messages for this window
  430.      * that have not yet been processed
  431.      */
  432.     StripIntuiMessages( win->UserPort, win );
  433.  
  434.     /* clear UserPort so Intuition will not free it */
  435.     win->UserPort = NULL;
  436.  
  437.     /* tell Intuition to stop sending more messages */
  438.     ModifyIDCMP( win, 0L );
  439.  
  440.     /* turn multitasking back on */
  441.     Permit();
  442.  
  443.     /* and really close the window */
  444.     CloseWindow( win );
  445. }
  446.  
  447. /* remove and reply all IntuiMessages on a port that
  448.  * have been sent to a particular window
  449.  * ( note that we don't rely on the ln_Succ pointer
  450.  *  of a message after we have replied it )
  451.  */
  452. void StripIntuiMessages( mp, win )
  453. struct MsgPort *mp;
  454. struct Window *win;
  455. {
  456.     struct IntuiMessage *msg;
  457.     struct Node *succ;
  458.  
  459.     msg = ( struct IntuiMessage * ) mp->mp_MsgList.lh_Head;
  460.  
  461.     while( succ =  msg->ExecMessage.mn_Node.ln_Succ ) {
  462.  
  463.     if( msg->IDCMPWindow ==  win ) {
  464.  
  465.         /* Intuition is about to free this message.
  466.          * Make sure that we have politely sent it back.
  467.          */
  468.         Remove( ( struct Node * )msg );
  469.  
  470.         ReplyMsg( ( struct Message * )msg );
  471.     }
  472.  
  473.     msg = ( struct IntuiMessage * ) succ;
  474.     }
  475. }
  476.  
  477. /*----------------------------------------------------------------------*/
  478.  
  479. struct Window *openPanel( void )
  480. {
  481.     struct NewGadget ng;
  482.     struct Gadget *gad;
  483.     LONG topborder;
  484.     int settable = 0;
  485.  
  486.     panel_screen = findPanelScreen();
  487.  
  488.     topborder = panel_screen->WBorTop + panel_screen->Font->ta_YSize + 1;
  489.  
  490.     if ( panel_vi = GetVisualInfo( panel_screen,
  491.     TAG_DONE ) )
  492.     {
  493.     gad = CreateContext( &panel_gadgets );
  494.  
  495.     ng.ng_LeftEdge = 90;
  496.     ng.ng_TopEdge = 2+topborder;
  497.     ng.ng_GadgetText = "Parent";
  498.     ng.ng_Width = 120;
  499.     ng.ng_Height = 14;
  500.     ng.ng_TextAttr = &Topaz80;
  501.     ng.ng_VisualInfo = panel_vi;
  502.     ng.ng_GadgetID = GAD_PARENT_OPEN;
  503.     ng.ng_UserData = &parent_desc.sd_Open;
  504.     ng.ng_Flags = NULL;
  505.  
  506.     mygad[ settable++ ] = gad = CreateGadget( CYCLE_KIND, gad, &ng,
  507.         GTCY_Labels, OpenLabels,
  508.         GTCY_Active, parent_desc.sd_Open,
  509.         TAG_DONE );
  510.     ng.ng_GadgetText = NULL;
  511.     ng.ng_UserData = 0;
  512.  
  513.     ng.ng_LeftEdge += 130;
  514.     ng.ng_GadgetID++;
  515.     gad = CreateGadget( CYCLE_KIND, gad, &ng,
  516.         GTCY_Labels, LaceLabels,
  517.         GTCY_Active, parent_desc.sd_Lace,
  518.         TAG_DONE );
  519.  
  520.     ng.ng_LeftEdge += 130;
  521.     ng.ng_GadgetID++;
  522.     gad = CreateGadget( CYCLE_KIND, gad, &ng,
  523.         GTCY_Labels, SizeLabels,
  524.         GTCY_Active, parent_desc.sd_Size,
  525.         TAG_DONE );
  526.  
  527.     ng.ng_LeftEdge += 130;
  528.     ng.ng_GadgetID++;
  529.     gad = CreateGadget( CYCLE_KIND, gad, &ng,
  530.         GTCY_Labels, DragLabels,
  531.         GTCY_Active, parent_desc.sd_Drag,
  532.         TAG_DONE );
  533.  
  534.     ng.ng_LeftEdge = 90;
  535.     ng.ng_TopEdge += 18;
  536.     ng.ng_GadgetText = "Child";
  537.     ng.ng_GadgetID++;
  538.     ng.ng_UserData = &child_desc.sd_Open;
  539.  
  540.     mygad[ settable++ ] = gad = CreateGadget( CYCLE_KIND, gad, &ng,
  541.         GTCY_Labels, OpenLabels,
  542.         GTCY_Active, child_desc.sd_Open,
  543.         TAG_DONE );
  544.     ng.ng_GadgetText = NULL;
  545.     ng.ng_UserData = NULL;
  546.  
  547.     ng.ng_LeftEdge += 130;
  548.     ng.ng_GadgetID++;
  549.     gad = CreateGadget( CYCLE_KIND, gad, &ng,
  550.         GTCY_Labels, LaceLabels,
  551.         GTCY_Active, child_desc.sd_Lace,
  552.         TAG_DONE );
  553.  
  554.     ng.ng_LeftEdge += 130;
  555.     ng.ng_GadgetID++;
  556.     gad = CreateGadget( CYCLE_KIND, gad, &ng,
  557.         GTCY_Labels, SizeLabels,
  558.         GTCY_Active, child_desc.sd_Size,
  559.         TAG_DONE );
  560.  
  561.     ng.ng_LeftEdge += 130;
  562.     ng.ng_GadgetID++;
  563.     gad = CreateGadget( CYCLE_KIND, gad, &ng,
  564.         GTCY_Labels, DragLabels,
  565.         GTCY_Active, child_desc.sd_Drag,
  566.         TAG_DONE );
  567.  
  568.     ng.ng_LeftEdge = 90;
  569.     ng.ng_TopEdge += 18;
  570.     ng.ng_GadgetText = "Forward";
  571.     ng.ng_GadgetID++;
  572.     ng.ng_UserData = SDEPTH_TOFRONT;
  573.     gad = CreateGadget( BUTTON_KIND, gad, &ng,
  574.         TAG_DONE );
  575.  
  576.     ng.ng_LeftEdge += 130;
  577.     ng.ng_GadgetText = "Back";
  578.     ng.ng_GadgetID++;
  579.     ng.ng_UserData = ( APTR )( SDEPTH_TOBACK );
  580.     gad = CreateGadget( BUTTON_KIND, gad, &ng,
  581.         TAG_DONE );
  582.  
  583.     ng.ng_LeftEdge += 130;
  584.     ng.ng_GadgetText = "Child Forward";
  585.     ng.ng_GadgetID++;
  586.     ng.ng_UserData = ( APTR )( SDEPTH_TOFRONT|SDEPTH_CHILDONLY );
  587.     gad = CreateGadget( BUTTON_KIND, gad, &ng,
  588.         TAG_DONE );
  589.  
  590.     ng.ng_LeftEdge += 130;
  591.     ng.ng_GadgetText = "Child Back";
  592.     ng.ng_GadgetID++;
  593.     ng.ng_UserData = ( APTR )( SDEPTH_TOBACK|SDEPTH_CHILDONLY );
  594.     gad = CreateGadget( BUTTON_KIND, gad, &ng,
  595.         TAG_DONE );
  596.  
  597.     ng.ng_LeftEdge = 90;
  598.     ng.ng_TopEdge += 18;
  599.     ng.ng_GadgetText = "Move Parent";
  600.     ng.ng_GadgetID++;
  601.     gad = CreateGadget( BUTTON_KIND, gad, &ng,
  602.         TAG_DONE );
  603.  
  604.     ng.ng_LeftEdge += 130;
  605.     ng.ng_GadgetText = "Move Child";
  606.     ng.ng_GadgetID++;
  607.     gad = CreateGadget( BUTTON_KIND, gad, &ng,
  608.         TAG_DONE );
  609.  
  610.     ng.ng_LeftEdge += 130;
  611.     ng.ng_GadgetText = "FMove Parent";
  612.     ng.ng_GadgetID++;
  613.     gad = CreateGadget( BUTTON_KIND, gad, &ng,
  614.         TAG_DONE );
  615.  
  616.     ng.ng_LeftEdge += 130;
  617.     ng.ng_GadgetText = "FMove Child";
  618.     ng.ng_GadgetID++;
  619.     gad = CreateGadget( BUTTON_KIND, gad, &ng,
  620.         TAG_DONE );
  621.  
  622.     ng.ng_LeftEdge = 90;
  623.     ng.ng_TopEdge += 18;
  624.     ng.ng_UserData = 0;
  625.     ng.ng_GadgetText = "Home Parent";
  626.     ng.ng_GadgetID++;
  627.     gad = CreateGadget( BUTTON_KIND, gad, &ng,
  628.         TAG_DONE );
  629.  
  630.     ng.ng_LeftEdge += 130;
  631.     ng.ng_GadgetText = "Home Child";
  632.     ng.ng_GadgetID++;
  633.     gad = CreateGadget( BUTTON_KIND, gad, &ng,
  634.         TAG_DONE );
  635.  
  636.     if ( gad )
  637.     {
  638.         if ( panel_win = OpenWindowTags( NULL,
  639.         WA_Width, 640,
  640.         WA_Height, 105,
  641.         WA_Top, 11,
  642.         WA_Activate, TRUE,
  643.         WA_CloseGadget, TRUE,
  644.         WA_DragBar, TRUE,
  645.         WA_SizeGadget, TRUE,
  646.         WA_DepthGadget, TRUE,
  647.         WA_SimpleRefresh, TRUE,
  648.         WA_Title, "Control Panel",
  649.         WA_Gadgets, panel_gadgets,
  650.         WA_CustomScreen, panel_screen,
  651.         TAG_DONE ) )
  652.         {
  653.         /* whew! all is OK */
  654.         panel_win->UserPort = sharedport;
  655.         ModifyIDCMP( panel_win, IDCMP_CLOSEWINDOW | IDCMP_VANILLAKEY |
  656.             CYCLEIDCMP | BUTTONIDCMP | IDCMP_REFRESHWINDOW );
  657.         GT_RefreshWindow( panel_win, NULL );
  658.         return( panel_win );
  659.         }
  660.         FreeGadgets( panel_gadgets );
  661.         panel_gadgets = NULL;
  662.     }
  663.     FreeVisualInfo( panel_vi );
  664.     panel_vi = NULL;
  665.     }
  666.     return( NULL );
  667. }
  668.  
  669. /*----------------------------------------------------------------------*/
  670.  
  671. void closePanel( void )
  672. {
  673.     if ( panel_win )
  674.     {
  675.     CloseWindowSafely( panel_win ); panel_win = NULL;
  676.     FreeGadgets( panel_gadgets ); panel_gadgets = NULL;
  677.     FreeVisualInfo( panel_vi ); panel_vi = NULL;
  678.     panel_screen = NULL;
  679.     }
  680. }
  681.  
  682. /*----------------------------------------------------------------------*/
  683.  
  684. struct Screen *findPanelScreen( void )
  685. {
  686.     struct Screen *sc;
  687.  
  688.     ULONG lock = LockIBase( NULL );
  689.     for ( sc = IntuitionBase->FirstScreen; sc; sc = sc->NextScreen )
  690.     {
  691.     if ( ( sc->UserData == CHILD_MAGIC ) || ( sc->UserData == PARENT_MAGIC ) )
  692.     {
  693.         break;
  694.     }
  695.     }
  696.     UnlockIBase( lock );
  697.     return( sc );
  698. }
  699.  
  700. /*----------------------------------------------------------------------*/
  701.  
  702. void handleGadget( struct Gadget *gad, UWORD code )
  703. {
  704.     BOOL undo = FALSE;    /* Set to true if gadget states need to be corrected */
  705.     BOOL rethinkp = FALSE;
  706.     BOOL rethinkc = FALSE;
  707.  
  708.     switch ( gad->GadgetID )
  709.     {
  710.     case GAD_PARENT_OPEN:
  711.         if ( !code )    /* request to close */
  712.         {
  713.         /* Only close parent if child still around */
  714.         if ( ( parent_sc ) && ( child_sc ) )
  715.         {
  716.             parent_desc.sd_Open = FALSE;
  717.             rethinkp = TRUE;
  718.         }
  719.         else
  720.         {
  721.             undo = TRUE;
  722.         }
  723.         }
  724.         else        /* request to open */
  725.         {
  726.         if ( !parent_sc )
  727.         {
  728.             parent_desc.sd_Open = TRUE;
  729.             rethinkp = TRUE;
  730.         }
  731.         }
  732.         break;
  733.  
  734.     case GAD_PARENT_LACE:
  735.         parent_desc.sd_Lace = code;
  736.         rethinkp = TRUE;
  737.         break;
  738.  
  739.     case GAD_PARENT_SIZE:
  740.         parent_desc.sd_Size = code;
  741.         rethinkp = TRUE;
  742.         break;
  743.  
  744.     case GAD_PARENT_DRAG:
  745.         parent_desc.sd_Drag = code;
  746.         rethinkp = TRUE;
  747.         break;
  748.  
  749.     case GAD_CHILD_OPEN:
  750.         if ( !code )    /* request to close */
  751.         {
  752.         /* Only close child if parent still around */
  753.         if ( ( child_sc ) && ( parent_sc ) )
  754.         {
  755.             child_desc.sd_Open = FALSE;
  756.             rethinkc = TRUE;
  757.         }
  758.         else
  759.         {
  760.             undo = TRUE;
  761.         }
  762.         }
  763.         else        /* request to open */
  764.         {
  765.         if ( !child_sc )
  766.         {
  767.             child_desc.sd_Open = TRUE;
  768.             rethinkc = TRUE;
  769.         }
  770.         }
  771.         break;
  772.  
  773.     case GAD_CHILD_LACE:
  774.         child_desc.sd_Lace = code;
  775.         rethinkc = TRUE;
  776.         break;
  777.  
  778.     case GAD_CHILD_SIZE:
  779.         child_desc.sd_Size = code;
  780.         rethinkc = TRUE;
  781.         break;
  782.  
  783.     case GAD_CHILD_DRAG:
  784.         child_desc.sd_Drag = code;
  785.         rethinkc = TRUE;
  786.         break;
  787.  
  788.     case GAD_FORWARD:
  789.     case GAD_BACK:
  790.     case GAD_CFORWARD:
  791.     case GAD_CBACK:
  792.         if ( child_sc )
  793.         {
  794.         /* The appropriate screen-depth code is in gad->UserData */
  795.         ScreenDepth( child_sc, ( ULONG )gad->UserData, NULL );
  796.         }
  797.         break;
  798.  
  799.     case GAD_MOVECHILD:
  800.     case GAD_FMOVECHILD:
  801.         if ( child_sc )
  802.         {
  803.         jiggleScreen( child_sc, ( gad->GadgetID == GAD_FMOVECHILD ) ?
  804.             SPOS_FORCEDRAG : 0 );
  805.         }
  806.         break;
  807.  
  808.     case GAD_MOVEPARENT:
  809.     case GAD_FMOVEPARENT:
  810.         if ( parent_sc )
  811.         {
  812.         jiggleScreen( parent_sc, ( gad->GadgetID == GAD_FMOVEPARENT ) ?
  813.             SPOS_FORCEDRAG : 0 );
  814.         }
  815.         break;
  816.  
  817.     case GAD_HOMEPARENT:
  818.         if ( parent_sc )
  819.         {
  820.         ScreenPosition( parent_sc, SPOS_ABSOLUTE, 0, 0, 0, 0 );
  821.         }
  822.         break;
  823.  
  824.     case GAD_HOMECHILD:
  825.         if ( child_sc )
  826.         {
  827.         ScreenPosition( child_sc, SPOS_ABSOLUTE, 0, 0, 0, 0 );
  828.         }
  829.         break;
  830.     }
  831.     if ( rethinkp )
  832.     {
  833.     if ( parent_sc )
  834.     {
  835.         parent_desc.sd_Top = parent_sc->TopEdge;
  836.         if ( parent_desc.sd_IsLace )
  837.         {
  838.         parent_desc.sd_Top /= 2;
  839.         }
  840.         parent_sc = closeMyScreen( parent_sc );
  841.     }
  842.     if ( parent_desc.sd_Open )
  843.     {
  844.         parent_sc = openMyScreen( TRUE );
  845.         parent_desc.sd_IsLace = parent_desc.sd_Lace;
  846.     }
  847.     }
  848.  
  849.     if ( rethinkc )
  850.     {
  851.     if ( child_sc )
  852.     {
  853.         child_desc.sd_Top = child_sc->TopEdge;
  854.         if ( child_desc.sd_IsLace )
  855.         {
  856.         child_desc.sd_Top /= 2;
  857.         }
  858.         child_sc = closeMyScreen( child_sc );
  859.     }
  860.     if ( child_desc.sd_Open )
  861.     {
  862.         child_sc = openMyScreen( FALSE );
  863.         child_desc.sd_IsLace = child_desc.sd_Lace;
  864.     }
  865.     }
  866.  
  867.     if ( undo && panel_win )
  868.     {
  869.     int i;
  870.     for ( i = 0; i < NUM_SETTABLE; i++ )
  871.     {
  872.         LONG *longptr;
  873.         if ( longptr = mygad[ i ]->UserData )
  874.         {
  875.         GT_SetGadgetAttrs( mygad[ i ], panel_win, NULL,
  876.             GTCY_Active, *longptr,
  877.             TAG_DONE );
  878.         }
  879.     }
  880.     }
  881.  
  882.     if ( ( !panel_win ) || ( panel_win->WScreen != findPanelScreen() ) )
  883.     {
  884.     closePanel();
  885.     openPanel();
  886.     }
  887. }
  888.  
  889. /*----------------------------------------------------------------------*/
  890.  
  891. void jiggleScreen( struct Screen *sc, ULONG flags )
  892. {
  893.     LONG i, step;
  894.  
  895.     step = 2;
  896.     for ( i = 0; i < 40; i++ )
  897.     {
  898.     ScreenPosition( sc, flags, 0, step, 0, 0 );
  899.     if ( i == 9 )
  900.     {
  901.         step = -2;
  902.     }
  903.     else if ( i == 29 )
  904.     {
  905.         step = 2;
  906.     }
  907.     }
  908.     step = -2;
  909.     for ( i = 0; i < 40; i++ )
  910.     {
  911.     ScreenPosition( sc, flags, step, 0, 0, 0 );
  912.     if ( i == 19 )
  913.     {
  914.         step = 2;
  915.     }
  916.     }
  917. }
  918.  
  919. /*----------------------------------------------------------------------*/
  920.