home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / unix / tkUnixCursor.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  11.6 KB  |  408 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tkUnixCursor.c --
  3.  *
  4.  *    This file contains X specific cursor manipulation routines.
  5.  *
  6.  * Copyright (c) 1995 Sun Microsystems, Inc.
  7.  *
  8.  * See the file "license.terms" for information on usage and redistribution
  9.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  10.  *
  11.  * SCCS: @(#) tkUnixCursor.c 1.4 96/10/08 09:33:08
  12.  */
  13.  
  14. #include "tkPort.h"
  15. #include "tkInt.h"
  16.  
  17. /*
  18.  * The following data structure is a superset of the TkCursor structure
  19.  * defined in tkCursor.c.  Each system specific cursor module will define
  20.  * a different cursor structure.  All of these structures must have the
  21.  * same header consisting of the fields in TkCursor.
  22.  */
  23.  
  24.  
  25.  
  26. typedef struct {
  27.     TkCursor info;        /* Generic cursor info used by tkCursor.c */
  28.     Display *display;        /* Display for which cursor is valid. */
  29. } TkUnixCursor;
  30.  
  31. /*
  32.  * The table below is used to map from the name of a cursor to its
  33.  * index in the official cursor font:
  34.  */
  35.  
  36. static struct CursorName {
  37.     char        *name;
  38.     unsigned int    shape;
  39. } cursorNames[] = {
  40.     {"X_cursor",        XC_X_cursor},
  41.     {"arrow",            XC_arrow},
  42.     {"based_arrow_down",    XC_based_arrow_down},
  43.     {"based_arrow_up",        XC_based_arrow_up},
  44.     {"boat",            XC_boat},
  45.     {"bogosity",        XC_bogosity},
  46.     {"bottom_left_corner",    XC_bottom_left_corner},
  47.     {"bottom_right_corner",    XC_bottom_right_corner},
  48.     {"bottom_side",        XC_bottom_side},
  49.     {"bottom_tee",        XC_bottom_tee},
  50.     {"box_spiral",        XC_box_spiral},
  51.     {"center_ptr",        XC_center_ptr},
  52.     {"circle",            XC_circle},
  53.     {"clock",            XC_clock},
  54.     {"coffee_mug",        XC_coffee_mug},
  55.     {"cross",            XC_cross},
  56.     {"cross_reverse",        XC_cross_reverse},
  57.     {"crosshair",        XC_crosshair},
  58.     {"diamond_cross",        XC_diamond_cross},
  59.     {"dot",            XC_dot},
  60.     {"dotbox",            XC_dotbox},
  61.     {"double_arrow",        XC_double_arrow},
  62.     {"draft_large",        XC_draft_large},
  63.     {"draft_small",        XC_draft_small},
  64.     {"draped_box",        XC_draped_box},
  65.     {"exchange",        XC_exchange},
  66.     {"fleur",            XC_fleur},
  67.     {"gobbler",            XC_gobbler},
  68.     {"gumby",            XC_gumby},
  69.     {"hand1",            XC_hand1},
  70.     {"hand2",            XC_hand2},
  71.     {"heart",            XC_heart},
  72.     {"icon",            XC_icon},
  73.     {"iron_cross",        XC_iron_cross},
  74.     {"left_ptr",        XC_left_ptr},
  75.     {"left_side",        XC_left_side},
  76.     {"left_tee",        XC_left_tee},
  77.     {"leftbutton",        XC_leftbutton},
  78.     {"ll_angle",        XC_ll_angle},
  79.     {"lr_angle",        XC_lr_angle},
  80.     {"man",            XC_man},
  81.     {"middlebutton",        XC_middlebutton},
  82.     {"mouse",            XC_mouse},
  83.     {"pencil",            XC_pencil},
  84.     {"pirate",            XC_pirate},
  85.     {"plus",            XC_plus},
  86.     {"question_arrow",        XC_question_arrow},
  87.     {"right_ptr",        XC_right_ptr},
  88.     {"right_side",        XC_right_side},
  89.     {"right_tee",        XC_right_tee},
  90.     {"rightbutton",        XC_rightbutton},
  91.     {"rtl_logo",        XC_rtl_logo},
  92.     {"sailboat",        XC_sailboat},
  93.     {"sb_down_arrow",        XC_sb_down_arrow},
  94.     {"sb_h_double_arrow",    XC_sb_h_double_arrow},
  95.     {"sb_left_arrow",        XC_sb_left_arrow},
  96.     {"sb_right_arrow",        XC_sb_right_arrow},
  97.     {"sb_up_arrow",        XC_sb_up_arrow},
  98.     {"sb_v_double_arrow",    XC_sb_v_double_arrow},
  99.     {"shuttle",            XC_shuttle},
  100.     {"sizing",            XC_sizing},
  101.     {"spider",            XC_spider},
  102.     {"spraycan",        XC_spraycan},
  103.     {"star",            XC_star},
  104.     {"target",            XC_target},
  105.     {"tcross",            XC_tcross},
  106.     {"top_left_arrow",        XC_top_left_arrow},
  107.     {"top_left_corner",        XC_top_left_corner},
  108.     {"top_right_corner",    XC_top_right_corner},
  109.     {"top_side",        XC_top_side},
  110.     {"top_tee",            XC_top_tee},
  111.     {"trek",            XC_trek},
  112.     {"ul_angle",        XC_ul_angle},
  113.     {"umbrella",        XC_umbrella},
  114.     {"ur_angle",        XC_ur_angle},
  115.     {"watch",            XC_watch},
  116.     {"xterm",            XC_xterm},
  117.     {NULL,            0}
  118. };
  119.  
  120. /*
  121.  * Font to use for cursors:
  122.  */
  123.  
  124. #ifndef CURSORFONT
  125. #define CURSORFONT "cursor"
  126. #endif
  127.  
  128.  
  129. /*
  130.  *----------------------------------------------------------------------
  131.  *
  132.  * TkGetCursorByName --
  133.  *
  134.  *    Retrieve a cursor by name.  Parse the cursor name into fields
  135.  *    and create a cursor, either from the standard cursor font or
  136.  *    from bitmap files.
  137.  *
  138.  * Results:
  139.  *    Returns a new cursor, or NULL on errors.  
  140.  *
  141.  * Side effects:
  142.  *    Allocates a new cursor.
  143.  *
  144.  *----------------------------------------------------------------------
  145.  */
  146.  
  147. TkCursor *
  148. TkGetCursorByName(interp, tkwin, string)
  149.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  150.     Tk_Window tkwin;        /* Window in which cursor will be used. */
  151.     Tk_Uid string;        /* Description of cursor.  See manual entry
  152.                  * for details on legal syntax. */
  153. {
  154.     TkUnixCursor *cursorPtr = NULL;
  155.     Cursor cursor = None;
  156.     int argc;
  157.     char **argv = NULL;
  158.     Pixmap source = None;
  159.     Pixmap mask = None;
  160.     Display *display = Tk_Display(tkwin);
  161.  
  162.     if (Tcl_SplitList(interp, string, &argc, &argv) != TCL_OK) {
  163.     return NULL;
  164.     }
  165.     if (argc == 0) {
  166.     goto badString;
  167.     }
  168.     if (argv[0][0] != '@') {
  169.     XColor fg, bg;
  170.     unsigned int maskIndex;
  171.     register struct CursorName *namePtr;
  172.     TkDisplay *dispPtr;
  173.  
  174.     /*
  175.      * The cursor is to come from the standard cursor font.  If one
  176.      * arg, it is cursor name (use black and white for fg and bg).
  177.      * If two args, they are name and fg color (ignore mask).  If
  178.      * three args, they are name, fg, bg.  Some of the code below
  179.      * is stolen from the XCreateFontCursor Xlib procedure.
  180.      */
  181.  
  182.     if (argc > 3) {
  183.         goto badString;
  184.     }
  185.     for (namePtr = cursorNames; ; namePtr++) {
  186.         if (namePtr->name == NULL) {
  187.         goto badString;
  188.         }
  189.         if ((namePtr->name[0] == argv[0][0])
  190.             && (strcmp(namePtr->name, argv[0]) == 0)) {
  191.         break;
  192.         }
  193.     }
  194.     maskIndex = namePtr->shape + 1;
  195.     if (argc == 1) {
  196.         fg.red = fg.green = fg.blue = 0;
  197.         bg.red = bg.green = bg.blue = 65535;
  198.     } else {
  199.         if (XParseColor(display, Tk_Colormap(tkwin), argv[1],
  200.             &fg) == 0) {
  201.         Tcl_AppendResult(interp, "invalid color name \"", argv[1],
  202.             "\"", (char *) NULL);
  203.         goto cleanup;
  204.         }
  205.         if (argc == 2) {
  206.         bg.red = bg.green = bg.blue = 0;
  207.         maskIndex = namePtr->shape;
  208.         } else {
  209.         if (XParseColor(display, Tk_Colormap(tkwin), argv[2],
  210.             &bg) == 0) {
  211.             Tcl_AppendResult(interp, "invalid color name \"", argv[2],
  212.                 "\"", (char *) NULL);
  213.             goto cleanup;
  214.         }
  215.         }
  216.     }
  217.     dispPtr = ((TkWindow *) tkwin)->dispPtr;
  218.     if (dispPtr->cursorFont == None) {
  219.         dispPtr->cursorFont = XLoadFont(display, CURSORFONT);
  220.         if (dispPtr->cursorFont == None) {
  221.         interp->result = "couldn't load cursor font";
  222.         goto cleanup;
  223.         }
  224.     }
  225.     cursor = XCreateGlyphCursor(display, dispPtr->cursorFont,
  226.         dispPtr->cursorFont, namePtr->shape, maskIndex,
  227.         &fg, &bg);
  228.     } else {
  229.     int width, height, maskWidth, maskHeight;
  230.     int xHot, yHot, dummy1, dummy2;
  231.     XColor fg, bg;
  232.  
  233.         /*
  234.          * Prevent file system access in safe interpreters.
  235.          */
  236.  
  237.         if (Tcl_IsSafe(interp)) {
  238.             Tcl_AppendResult(interp, "can't get cursor from a file in",
  239.                     " a safe interpreter", (char *) NULL);
  240.             cursorPtr = NULL;
  241.             goto cleanup;
  242.         }
  243.         
  244.     /*
  245.      * The cursor is to be created by reading bitmap files.  There
  246.      * should be either two elements in the list (source, color) or
  247.      * four (source mask fg bg).
  248.      */
  249.  
  250.     if ((argc != 2) && (argc != 4)) {
  251.         goto badString;
  252.     }
  253.     if (XReadBitmapFile(display,
  254.         RootWindowOfScreen(Tk_Screen(tkwin)), &argv[0][1],
  255.         (unsigned int *) &width, (unsigned int *) &height,
  256.         &source, &xHot, &yHot) != BitmapSuccess) {
  257.         Tcl_AppendResult(interp, "cleanup reading bitmap file \"",
  258.             &argv[0][1], "\"", (char *) NULL);
  259.         goto cleanup;
  260.     }
  261.     if ((xHot < 0) || (yHot < 0) || (xHot >= width) || (yHot >= height)) {
  262.         Tcl_AppendResult(interp, "bad hot spot in bitmap file \"",
  263.             &argv[0][1], "\"", (char *) NULL);
  264.         goto cleanup;
  265.     }
  266.     if (argc == 2) {
  267.         if (XParseColor(display, Tk_Colormap(tkwin), argv[1],
  268.             &fg) == 0) {
  269.         Tcl_AppendResult(interp, "invalid color name \"",
  270.             argv[1], "\"", (char *) NULL);
  271.         goto cleanup;
  272.         }
  273.         cursor = XCreatePixmapCursor(display, source, source,
  274.             &fg, &fg, (unsigned) xHot, (unsigned) yHot);
  275.     } else {
  276.         if (XReadBitmapFile(display,
  277.             RootWindowOfScreen(Tk_Screen(tkwin)), argv[1],
  278.             (unsigned int *) &maskWidth, (unsigned int *) &maskHeight,
  279.             &mask, &dummy1, &dummy2) != BitmapSuccess) {
  280.         Tcl_AppendResult(interp, "cleanup reading bitmap file \"",
  281.             argv[1], "\"", (char *) NULL);
  282.         goto cleanup;
  283.         }
  284.         if ((maskWidth != width) && (maskHeight != height)) {
  285.         interp->result =
  286.             "source and mask bitmaps have different sizes";
  287.         goto cleanup;
  288.         }
  289.         if (XParseColor(display, Tk_Colormap(tkwin), argv[2],
  290.             &fg) == 0) {
  291.         Tcl_AppendResult(interp, "invalid color name \"", argv[2],
  292.             "\"", (char *) NULL);
  293.         goto cleanup;
  294.         }
  295.         if (XParseColor(display, Tk_Colormap(tkwin), argv[3],
  296.             &bg) == 0) {
  297.         Tcl_AppendResult(interp, "invalid color name \"", argv[3],
  298.             "\"", (char *) NULL);
  299.         goto cleanup;
  300.         }
  301.         cursor = XCreatePixmapCursor(display, source, mask,
  302.             &fg, &bg, (unsigned) xHot, (unsigned) yHot);
  303.     }
  304.     }
  305.  
  306.     if (cursor != None) {
  307.     cursorPtr = (TkUnixCursor *) ckalloc(sizeof(TkUnixCursor));
  308.     cursorPtr->info.cursor = (Tk_Cursor) cursor;
  309.     cursorPtr->display = display;
  310.     }
  311.  
  312.     cleanup:
  313.     if (argv != NULL) {
  314.     ckfree((char *) argv);
  315.     }
  316.     if (source != None) {
  317.     Tk_FreePixmap(display, source);
  318.     }
  319.     if (mask != None) {
  320.     Tk_FreePixmap(display, mask);
  321.     }
  322.     return (TkCursor *) cursorPtr;
  323.  
  324.  
  325.     badString:
  326.     Tcl_AppendResult(interp, "bad cursor spec \"", string, "\"",
  327.         (char *) NULL);
  328.     return NULL;
  329. }
  330.  
  331. /*
  332.  *----------------------------------------------------------------------
  333.  *
  334.  * TkCreateCursorFromData --
  335.  *
  336.  *    Creates a cursor from the source and mask bits.
  337.  *
  338.  * Results:
  339.  *    Returns a new cursor, or NULL on errors.
  340.  *
  341.  * Side effects:
  342.  *    Allocates a new cursor.
  343.  *
  344.  *----------------------------------------------------------------------
  345.  */
  346.  
  347. TkCursor *
  348. TkCreateCursorFromData(tkwin, source, mask, width, height, xHot, yHot,
  349.     fgColor, bgColor)
  350.     Tk_Window tkwin;        /* Window in which cursor will be used. */
  351.     char *source;        /* Bitmap data for cursor shape. */
  352.     char *mask;            /* Bitmap data for cursor mask. */
  353.     int width, height;        /* Dimensions of cursor. */
  354.     int xHot, yHot;        /* Location of hot-spot in cursor. */
  355.     XColor fgColor;        /* Foreground color for cursor. */
  356.     XColor bgColor;        /* Background color for cursor. */
  357. {
  358.     Cursor cursor;
  359.     Pixmap sourcePixmap, maskPixmap;
  360.     TkUnixCursor *cursorPtr = NULL;
  361.     Display *display = Tk_Display(tkwin);
  362.  
  363.     sourcePixmap = XCreateBitmapFromData(display,
  364.         RootWindowOfScreen(Tk_Screen(tkwin)), source, (unsigned) width,
  365.         (unsigned) height);
  366.     maskPixmap = XCreateBitmapFromData(display, 
  367.         RootWindowOfScreen(Tk_Screen(tkwin)), mask, (unsigned) width,
  368.         (unsigned) height);
  369.     cursor = XCreatePixmapCursor(display, sourcePixmap,
  370.         maskPixmap, &fgColor, &bgColor, (unsigned) xHot, (unsigned) yHot);
  371.     Tk_FreePixmap(display, sourcePixmap);
  372.     Tk_FreePixmap(display, maskPixmap);
  373.  
  374.     if (cursor != None) {
  375.     cursorPtr = (TkUnixCursor *) ckalloc(sizeof(TkUnixCursor));
  376.     cursorPtr->info.cursor = (Tk_Cursor) cursor;
  377.     cursorPtr->display = display;
  378.     }
  379.     return (TkCursor *) cursorPtr;
  380. }
  381.  
  382. /*
  383.  *----------------------------------------------------------------------
  384.  *
  385.  * TkFreeCursor --
  386.  *
  387.  *    This procedure is called to release a cursor allocated by
  388.  *    TkGetCursorByName.
  389.  *
  390.  * Results:
  391.  *    None.
  392.  *
  393.  * Side effects:
  394.  *    The cursor data structure is deallocated.
  395.  *
  396.  *----------------------------------------------------------------------
  397.  */
  398.  
  399. void
  400. TkFreeCursor(cursorPtr)
  401.     TkCursor *cursorPtr;
  402. {
  403.     TkUnixCursor *unixCursorPtr = (TkUnixCursor *) cursorPtr;
  404.     XFreeCursor(unixCursorPtr->display, (Cursor) unixCursorPtr->info.cursor);
  405.     Tk_FreeXId(unixCursorPtr->display, (XID) unixCursorPtr->info.cursor);
  406.     ckfree((char *) unixCursorPtr);
  407. }
  408.