home *** CD-ROM | disk | FTP | other *** search
/ M.u.C.S. Disc 2000 / MUCS2000.iso / anwend / bkite213 / develop_ / bsp_fsel.c < prev    next >
C/C++ Source or Header  |  1998-04-10  |  12KB  |  441 lines

  1. /*
  2.  * Beispiel-Programm zur Benutzung des Selectric-Protokolls mit BoxKite
  3.  * unter MiNT/MultiTOS/MagiC/MagiC Mac
  4.  * (c) Harald Becker, 12.5.1994. Übersetzt mit Pure C und DEFAULT.PRJ.
  5.  *
  6.  * Diesen Code dürfen Sie nach Belieben verwenden und ganz oder in in Auszügen
  7.  * in Ihre Programme aufnehmen.
  8.  * 
  9.  * HB 061095:
  10.  * Erweitert um eine Anwendung für den Message-Callback in BoxKite 1.7x
  11.  * Dazu wird hinter dem Fileselector ein kleines Fenster geöffnet,
  12.  * das über den Message-Callback gezeichnet wird. Es kann auch
  13.  * verschoben werden, falls das Betriebssystem das Verschieben hinten-
  14.  * liegender Fenster erlaubt.
  15.  *
  16.  * HB 131095:
  17.  * Inzwischen demonstriert das Programm alle drei möglichen Rückgabeformen.
  18.  * Die Auswahl erfolgt zur Compile-Zeit über die Konstante 'RETURN'.
  19.  *
  20.  * HB 200196:
  21.  * Das Binding für 'fsel_boxinput()' wurde so geändert, da₧ das global[]-
  22.  * Array explizit mit übergeben werden mu₧.
  23.  *
  24.  * HB 120897:
  25.  * Felder, die Dateinman aufnehmen, auf 255 Zeichen erweitert. Das schlie₧t
  26.  * insbesondere die Definition von XDTA ein.
  27.  *
  28.  * HB 030498
  29.  * In der Deklaration von 'fsel_boxinput()' wurde das global[]-Feld an den
  30.  * Anfang gestellt.
  31.  *
  32.  * HB 090998
  33.  * Die Deklaration von 'get_cookie()' geändert.
  34.  */
  35. #include <stdio.h>
  36. #include <aes.h>
  37. #include <tos.h>
  38. #include <string.h>
  39.  
  40. /*
  41.  * Diese Konstante steuert, welche Rückgabemethode das Beispielprogramm
  42.  * bei BoxKite anfordert. Mögliche Werte:
  43.  *
  44.  *     1: Rückgabe über ein Feld von Stringzeigern
  45.  *     2: Rückgabe über einen String (mit trennenden Leerzeichen)
  46.  *     3: Rückgabe über Funktionen
  47.  */
  48. #define RETURN 3
  49.  
  50. /*
  51.  * Diese Struktur wird von BoxKite gefüllt. Sie ist identisch mit der
  52.  * TOS-DTA, sieht jedoch Platz für lange Datenamen vor.
  53.  */
  54. typedef struct
  55. {    char            d_reserved[21];
  56.     unsigned char    d_attrib;
  57.     unsigned int    d_time;
  58.     unsigned int    d_date;
  59.     unsigned long    d_length;
  60.     char            d_fname[256];
  61. }
  62. XDTA;
  63.  
  64. /*
  65.  * Die Selectric-Struktur.
  66.  */
  67. typedef struct
  68. {    unsigned long    id;            /* Selectric ID (SLCT)        */
  69.     unsigned int    version;    /* version (BCD-Format)        */
  70.     struct
  71.     {    unsigned           : 7;    /* reserved                     */
  72.         unsigned pthsav    : 1;
  73.         unsigned stdest    : 1;
  74.         unsigned           : 1;
  75.         unsigned numsrt    : 1;   /* numerisches Sortieren     */
  76.         unsigned lower     : 1;
  77.         unsigned dclick    : 1;   /* Ordner mit Doppelklick    */
  78.         unsigned hidden    : 1;   /* versteckte Dateien        */
  79.         unsigned onoff     : 1;   /* Fileselector AN/AUS       */
  80.     } config;
  81.     int    sort;            /* sort-mode (neg. = rev.)    */
  82.     int    num_ext;        /* number of extensions        */
  83.     char *(*ext)[];        /* preset extensions        */
  84.     int    num_paths;        /* number of paths        */
  85.     char *(*paths)[];        /* preset paths            */
  86.     int    comm;            /* communication word        */
  87.     int    in_count;        /* input counter        */
  88.     void *in_ptr;        /* input pointer        */
  89.     int    out_count;        /* output counter        */
  90.     void *out_ptr;        /* output pointer        */
  91.     int    cdecl    (*get_first)(XDTA *dta, int attrib);
  92.     int    cdecl     (*get_next)(XDTA *dta);
  93.     int    cdecl    (*release_dir)(void);
  94. }
  95. SLCT_STR;
  96.  
  97. typedef struct
  98. {    long    id;
  99.     long    value;
  100. }
  101. COOKIE;
  102.  
  103. long Supexec(long (*codeptr)());
  104.  
  105. SLCT_STR *slct_cookie = NULL;
  106.  
  107. /*
  108.  * Prototyp des Message-Handlers.
  109.  */
  110. typedef void cdecl (* FSEL_CALLBACK)(int *msg);
  111.  
  112. /*
  113.  * Prototyp des erweiterten Bindings.
  114.  */
  115. int cdecl fsel_boxinput(int *global, char *path, char *name, int *button, char *label, FSEL_CALLBACK callback);
  116.  
  117. /*
  118.  * Variablen für die Rückgabe der Dateinamen.
  119.  */
  120. #if RETURN == 1        /* Felder für die Einzelnamen und Zeigerfeld */
  121.     char name1[256], name2[256], name3[256];
  122.     char *nameptrs[] = { name1, name2, name3 };
  123.  
  124. #elif RETURN == 2    /* Ein Feld für die Namensliste */
  125.     char stringbuf[1024];
  126.     
  127. #else                /* Prototypen der Rückgabefunktionen */
  128.     int    cdecl (*p_get_first)(XDTA *dta, int attrib);
  129.     int    cdecl (*p_get_next)(XDTA *dta);
  130.     int    cdecl (*p_release_dir)(void);
  131. #endif
  132.  
  133. int name_count;        /* Anzahl der gelieferten Namen */
  134.  
  135. int window;            /* Fensterkennung */
  136. OBJECT contents =     /* Fensterinhalt */
  137.     { -1, -1, -1, G_BOXCHAR, 0, 0, 0x2aff11f0, 1, 1, 1, 1 };
  138.  
  139. int xdesk, ydesk, wdesk, hdesk;
  140.  
  141. /*
  142.  * Gibt die Adresse des Cookie-Jar zurück. Mit Supexec() aufrufen.
  143.  */
  144. long get_cookiejar(void)
  145. {    return *((long *)0x05a0l);
  146. }
  147.  
  148. /*
  149.  * Durchsucht den Cookie Jar nach einem cookie mit gegebener id und
  150.  * liefert dessen Wert zurück.
  151.  */
  152. int get_cookie(long id, long *pval)
  153. {    long sav;
  154.     COOKIE *cookiejar;
  155.     int    i = 0;
  156.  
  157.     cookiejar = (COOKIE *)Supexec(get_cookiejar);
  158.  
  159.     if ( cookiejar )
  160.     {    while ( cookiejar[i].id )
  161.         {    if ( cookiejar[i].id == id )
  162.             {    *pval = cookiejar[i].value;
  163.                 return 1;
  164.             }
  165.             i++;
  166.         }
  167.     }
  168.     return 0;
  169. }
  170.  
  171. /*
  172.  * Prüft, ob am 'FSEL'-cookie ein Selectric-1.02-kompatibler Fileselector
  173.  * hängt. Im Erfolgsfall wird die Datenstruktur hinter dem Cookie für die
  174.  * gewünschte Rückgabeform initialisiert.
  175.  * Sollte mit Supexec aufgerufen werden, da der Speicher immerhin einem
  176.  * fremden Proze₧ gehört.
  177.  */
  178. long setup_selector(void)
  179. {    if ( slct_cookie && slct_cookie->id == 'SLCT' && slct_cookie->version >= 0x102 )
  180.     {
  181. #if RETURN == 1            /* Rückgabe über Zeigerfeld */
  182.         slct_cookie->comm = 1;
  183.         slct_cookie->out_count = 3;
  184.         slct_cookie->out_ptr = nameptrs;
  185.  
  186. #elif RETURN == 2        /* Rückgabe über Namensliste in einem String */
  187.         slct_cookie->comm = 3;
  188.         slct_cookie->out_count = 4;
  189.         slct_cookie->out_ptr = stringbuf;
  190.  
  191. #else                    /* Benutzung der Rückgabefunktionen */
  192.         slct_cookie->comm = 9;
  193.         p_get_first = slct_cookie->get_first;
  194.         p_get_next = slct_cookie->get_next;
  195.         p_release_dir = slct_cookie->release_dir;
  196.  
  197. #endif
  198.         return 1;
  199.     }
  200.     return 0;
  201. }
  202.  
  203. /*
  204.  * Liest die Anzahl der gelieferten Namen aus der FSEL-Struktur.
  205.  */
  206. long get_out_count(void)
  207. {    name_count = slct_cookie->out_count;
  208.     return 0;
  209. }
  210.  
  211. /*
  212.  * Fragt das aktuelle Laufwerk und den aktuellen Pfad ab.
  213.  */
  214. void getpath(char *p)
  215. {    int drv;
  216.  
  217.     drv = Dgetdrv();
  218.     *p++ = drv + 'A';
  219.     *p++ = ':';
  220.     Dgetpath(p, drv);
  221.     p += strlen(p) - 1;
  222.     if ( *p != '\\' )
  223.     {    p++;
  224.         *p++ = '\\';
  225.         *p = 0;
  226.     }
  227. }
  228.  
  229. /* 
  230.  * Die folgenden vier Funktionen befassen sich nur mit dem Zeichnen
  231.  * des Fensterinhaltes. Ich denke, die Methode hat sich inzwischen
  232.  * herumgesprochen.
  233.  */
  234. int min(int a, int b)
  235. {    return ( a < b ? a : b );
  236. }
  237.  
  238. int max(int a, int b)
  239. {    return ( a > b ? a : b );
  240. }
  241.  
  242. int rc_intersect(GRECT *p1, GRECT *p2)
  243. {    int tx, ty, tw, th;
  244.  
  245.     tw = min(p2->g_x + p2->g_w, p1->g_x + p1->g_w);
  246.     th = min(p2->g_y + p2->g_h, p1->g_y + p1->g_h);
  247.     tx = max(p2->g_x, p1->g_x);
  248.     ty = max(p2->g_y, p1->g_y);
  249.  
  250.     p2->g_x = tx;
  251.     p2->g_y = ty;
  252.     p2->g_w = tw - tx;
  253.     p2->g_h = th - ty;
  254.  
  255.     return( (tw > tx) && (th > ty) );
  256. }
  257.  
  258. void window_redraw(int handle, int x, int y, int w, int h)
  259. {    GRECT r1, r2, world;
  260.  
  261.     wind_update(BEG_UPDATE);
  262.  
  263.     r2.g_x = x;
  264.     r2.g_y = y;
  265.     r2.g_w = w;
  266.     r2.g_h = h;
  267.  
  268.     world.g_x = xdesk;
  269.     world.g_y = ydesk;
  270.     world.g_w = wdesk;
  271.     world.g_h = hdesk;
  272.  
  273.     wind_get(handle, WF_FIRSTXYWH, &r1.g_x, &r1.g_y, &r1.g_w, &r1.g_h);
  274.     while ( r1.g_w && r1.g_h )
  275.     {    if ( rc_intersect(&world, &r1) && rc_intersect(&r2, &r1) )
  276.             objc_draw(&contents, ROOT, MAX_DEPTH, r1.g_x, r1.g_y, r1.g_w, r1.g_h);
  277.         wind_get(handle, WF_NEXTXYWH, &r1.g_x, &r1.g_y, &r1.g_w, &r1.g_h);
  278.     }
  279.     wind_update(END_UPDATE);
  280. }
  281.  
  282. /* 
  283.  * Die Einsprungadresse dieser Funktion wird als Callback an BoxKite
  284.  * übergeben. 
  285.  * Wie man sieht, kann sie auch andere Messagetypen als WM_REDRAW
  286.  * behandeln. WM_MOVED ist sogar ratsam, da es immerhin Betriebssystem-
  287.  * versionen gibt, die das Verschieben von hintenliegenden Fenstern
  288.  * ermöglichen. Messages, die implizit neue Fenster öffnen oder vorhandene 
  289.  * nach oben bringen, sollten dagegen ignoriert oder aufgehoben und erst 
  290.  * nach der Rückkehr aus dem Fileselector behandelt werden.
  291.  * WM_TOPPED-Messages werden nicht an den Message-Callback durchgereicht.
  292.  */
  293. void cdecl message_handler(int *msg)
  294. {    switch ( msg[0] )
  295.     {    case WM_REDRAW:
  296.             wind_get(msg[3], WF_WORKXYWH, &contents.ob_x, &contents.ob_y, &contents.ob_width, &contents.ob_height);
  297.             window_redraw(msg[3], msg[4], msg[5], msg[6], msg[7]);
  298.             break;
  299.         case WM_MOVED:
  300.             wind_set(msg[3], WF_CURRXYWH, msg[4], msg[5], msg[6], msg[7]);
  301.             break;
  302.     }
  303. }
  304.  
  305. /*
  306.  * Ein alternatives Binding für fsel_exinput() (Die Funktionsnummer ist
  307.  * identisch!), das die Übergabe der Callback-Adresse erlaubt. Andere
  308.  * Fileselectoren sollten den überzähligen Parameter einfach ignorieren.
  309.  *
  310.  * Eine Assembler-Version dieses Bindings, die keine Annahmen über das
  311.  * Vorhandensein eines generellen GEM-Traps (hier: '_crystal') im
  312.  * verwendeten Entwicklungssystem macht, befindet sich im Quelltext in
  313.  * 'BOXINPUT.S' und als Objektdatei im DRI-Format in 'BOXINPUT.O'.
  314.  *
  315.  * Achtung! BoxKite benötigt Informationen aus dem 'global'-Array der
  316.  * Hauptapplikation. Die mitgelieferten GEM-Bindings von Entwicklungs-
  317.  * systemen übergeben dieses normalerweise automatisch. Da das vorliegende
  318.  * Binding weitgehend programmiersprachenunabhängig sein soll, wird es
  319.  * hier explizit übergeben.
  320.  */
  321. int cdecl fsel_boxinput(int *global, char *path, char *name, int *button, char *label, FSEL_CALLBACK callback)
  322. {    void *aespb[6], *addrin[6], *addrout[6];
  323.     int contrl[5], intin[16], intout[7];
  324.  
  325.     aespb[0] = contrl;
  326.     aespb[1] = global;
  327.     aespb[2] = intin;
  328.     aespb[3] = intout;
  329.     aespb[4] = addrin;
  330.     aespb[5] = addrout;
  331.  
  332.     contrl[0] = 91;
  333.     contrl[1] = 0;
  334.     contrl[2] = 2;
  335.     contrl[3] = 4;
  336.     contrl[4] = 0;
  337.  
  338.     addrin[0] = path;
  339.     addrin[1] = name;
  340.     addrin[2] = label;
  341.     addrin[3] = callback;
  342.  
  343.     _crystal((AESPB *)aespb);
  344.  
  345.     *button = intout[1];
  346.     return intout[0];
  347. }
  348.  
  349. int main(void)
  350. {    XDTA mydta;
  351.     char path[130], name[34], outbuf[300];
  352.     int exbtn, rv, d, i;
  353.  
  354.     appl_init();
  355.     wind_get(0, WF_WORKXYWH, &xdesk, &ydesk, &wdesk, &hdesk);
  356.  
  357.     if ( !get_cookie('FSEL', &slct_cookie) )
  358.     {    form_alert(1, "[1][Kein kompatibler Fileselector|installiert.][   Ok   ]");
  359.         appl_exit();
  360.         return 0;
  361.     }
  362.  
  363.     if ( !Supexec(setup_selector) )
  364.     {    form_alert(1, "[1][Kein kompatibler Fileselector|installiert.][   Ok   ]");
  365.         appl_exit();
  366.         return 0;
  367.     }
  368.  
  369.     Pdomain(1);            /* Damit auch wirklich lange Namen rauskommen */
  370.  
  371.     /*
  372.      * Ein Fenster hinter dem Fileselector öffenen, damit man sieht,
  373.      * da₧ auch etwas beim Message-Callback ankommt.
  374.      */
  375.     window = wind_create(NAME | MOVER, xdesk, ydesk, wdesk, hdesk);
  376.     if ( window < 0 )
  377.     {    form_alert(1, "[1][Das Fenster klemmt mal wieder!][   Ok   ]");
  378.         appl_exit();
  379.         return 0;
  380.     }
  381.     wind_set(window, WF_NAME, "Noch'n Fenster");
  382.     wind_open(window, xdesk + 50, ydesk + 50, 300, 200);
  383.     window_redraw(window, xdesk, ydesk, wdesk, hdesk);
  384.  
  385.     getpath(path);
  386.     strcat(path, "*.*");
  387.     *name = 0;
  388.  
  389. #if RETURN == 1            /* Rückgabe über Zeigerfeld */
  390.     do
  391.     {    Supexec(setup_selector);
  392.         rv = fsel_boxinput(_GemParBlk.global, path, name, &exbtn, "BoxKite", &message_handler);
  393.  
  394.         if ( rv && exbtn )
  395.         {    Supexec(get_out_count);
  396.             for ( i = 0; i < name_count; i++ )
  397.             {    sprintf(outbuf, "[1][Datei Nr: %d|%s][   Ok   ]", i + 1, nameptrs[i]);
  398.                 form_alert(1, outbuf);
  399.             }
  400.         }
  401.     }
  402.     while ( rv && exbtn );
  403.  
  404. #elif RETURN == 2        /* Rückgabe über einen String */
  405.     do
  406.     {    Supexec(setup_selector);
  407.         rv = fsel_boxinput(_GemParBlk.global, path, name, &exbtn, "BoxKite", &message_handler);
  408.  
  409.         if ( rv && exbtn )
  410.         {    sprintf(outbuf, "[1][%s][   Ok   ]", stringbuf);
  411.             form_alert(1, outbuf);
  412.         }
  413.     }
  414.     while ( rv && exbtn );
  415.  
  416. #else                    /* Rückgabe über Funktionen */
  417.     do
  418.     {    Supexec(setup_selector);
  419.         rv = fsel_boxinput(_GemParBlk.global, path, name, &exbtn, "BoxKite", &message_handler);
  420.         if ( rv && exbtn )
  421.         {    wind_update(BEG_UPDATE);
  422.             d = p_get_first(&mydta, 0xff);
  423.             i = 1;
  424.             while( !d )
  425.             {    sprintf(outbuf, "[1][Datei Nr %d:|%s %02x][   Ok   ]", i, mydta.d_fname, mydta.d_attrib);
  426.                 form_alert(1, outbuf);
  427.                 d = p_get_next(&mydta);
  428.                 i++;
  429.             }
  430.             p_release_dir();
  431.             wind_update(END_UPDATE);
  432.         }
  433.     }
  434.     while ( rv && exbtn );
  435. #endif
  436.     wind_close(window);
  437.     wind_delete(window);
  438.     appl_exit();
  439.     return 0;
  440. }
  441.